aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/accessibility/braille/braille_console.c13
-rw-r--r--drivers/acpi/dispatcher/dsobject.c2
-rw-r--r--drivers/acpi/glue.c5
-rw-r--r--drivers/acpi/processor_core.c2
-rw-r--r--drivers/acpi/processor_perflib.c2
-rw-r--r--drivers/acpi/sbshc.c7
-rw-r--r--drivers/acpi/sleep/proc.c10
-rw-r--r--drivers/acpi/tables.c2
-rw-r--r--drivers/ata/Kconfig8
-rw-r--r--drivers/ata/ahci.c46
-rw-r--r--drivers/ata/ata_piix.c186
-rw-r--r--drivers/ata/libata-core.c252
-rw-r--r--drivers/ata/libata-eh.c375
-rw-r--r--drivers/ata/libata-scsi.c112
-rw-r--r--drivers/ata/libata-sff.c5
-rw-r--r--drivers/ata/libata.h5
-rw-r--r--drivers/ata/pata_bf54x.c34
-rw-r--r--drivers/ata/pata_marvell.c51
-rw-r--r--drivers/ata/pata_sil680.c5
-rw-r--r--drivers/ata/sata_fsl.c26
-rw-r--r--drivers/ata/sata_inic162x.c11
-rw-r--r--drivers/ata/sata_mv.c31
-rw-r--r--drivers/ata/sata_nv.c43
-rw-r--r--drivers/ata/sata_promise.c16
-rw-r--r--drivers/ata/sata_qstor.c12
-rw-r--r--drivers/ata/sata_sil.c16
-rw-r--r--drivers/ata/sata_sil24.c12
-rw-r--r--drivers/ata/sata_sis.c28
-rw-r--r--drivers/ata/sata_svw.c10
-rw-r--r--drivers/ata/sata_uli.c24
-rw-r--r--drivers/ata/sata_via.c24
-rw-r--r--drivers/ata/sata_vsc.c10
-rw-r--r--drivers/base/base.h2
-rw-r--r--drivers/base/class.c136
-rw-r--r--drivers/base/core.c6
-rw-r--r--drivers/block/aoe/aoeblk.c6
-rw-r--r--drivers/block/aoe/aoecmd.c19
-rw-r--r--drivers/block/aoe/aoedev.c2
-rw-r--r--drivers/block/cciss.c8
-rw-r--r--drivers/block/cciss_scsi.c151
-rw-r--r--drivers/block/cciss_scsi.h4
-rw-r--r--drivers/block/cpqarray.c2
-rw-r--r--drivers/block/floppy.c31
-rw-r--r--drivers/block/nbd.c4
-rw-r--r--drivers/block/pktcdvd.c4
-rw-r--r--drivers/block/ps3disk.c11
-rw-r--r--drivers/block/virtio_blk.c14
-rw-r--r--drivers/block/xen-blkfront.c76
-rw-r--r--drivers/bluetooth/bpa10x.c2
-rw-r--r--drivers/bluetooth/btusb.c36
-rw-r--r--drivers/cdrom/cdrom.c2
-rw-r--r--drivers/cdrom/gdrom.c4
-rw-r--r--drivers/char/random.c25
-rw-r--r--drivers/char/tty_io.c14
-rw-r--r--drivers/clocksource/acpi_pm.c53
-rw-r--r--drivers/crypto/talitos.c6
-rw-r--r--drivers/dma/dw_dmac.c2
-rw-r--r--drivers/firmware/iscsi_ibft.c3
-rw-r--r--drivers/gpu/drm/radeon/radeon_cp.c4
-rw-r--r--drivers/hwmon/abituguru3.c3
-rw-r--r--drivers/hwmon/ad7414.c2
-rw-r--r--drivers/hwmon/atxp1.c18
-rw-r--r--drivers/hwmon/it87.c74
-rw-r--r--drivers/i2c/busses/i2c-powermac.c4
-rw-r--r--drivers/i2c/busses/i2c-sh_mobile.c271
-rw-r--r--drivers/i2c/i2c-dev.c4
-rw-r--r--drivers/ide/Kconfig34
-rw-r--r--drivers/ide/arm/palm_bk3710.c8
-rw-r--r--drivers/ide/ide-cd.c8
-rw-r--r--drivers/ide/ide-disk.c29
-rw-r--r--drivers/ide/ide-dma.c2
-rw-r--r--drivers/ide/ide-probe.c4
-rw-r--r--drivers/ide/ide-tape.c10
-rw-r--r--drivers/ide/mips/Makefile1
-rw-r--r--drivers/ide/mips/swarm.c196
-rw-r--r--drivers/ide/pci/hpt366.c31
-rw-r--r--drivers/infiniband/core/cm.c2
-rw-r--r--drivers/infiniband/core/mad.c5
-rw-r--r--drivers/infiniband/hw/amso1100/c2_provider.c1
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_provider.c9
-rw-r--r--drivers/infiniband/hw/ehca/ehca_classes.h14
-rw-r--r--drivers/infiniband/hw/ehca/ehca_cq.c3
-rw-r--r--drivers/infiniband/hw/ehca/ehca_iverbs.h2
-rw-r--r--drivers/infiniband/hw/ehca/ehca_qp.c225
-rw-r--r--drivers/infiniband/hw/ehca/ehca_reqs.c211
-rw-r--r--drivers/infiniband/hw/ipath/ipath_rc.c3
-rw-r--r--drivers/infiniband/hw/ipath/ipath_ruc.c3
-rw-r--r--drivers/infiniband/hw/ipath/ipath_verbs.c7
-rw-r--r--drivers/infiniband/hw/mlx4/qp.c9
-rw-r--r--drivers/infiniband/hw/mthca/mthca_catas.c15
-rw-r--r--drivers/infiniband/hw/mthca/mthca_eq.c51
-rw-r--r--drivers/infiniband/hw/mthca/mthca_main.c59
-rw-r--r--drivers/infiniband/hw/nes/nes.c95
-rw-r--r--drivers/infiniband/hw/nes/nes.h2
-rw-r--r--drivers/infiniband/hw/nes/nes_cm.c52
-rw-r--r--drivers/infiniband/hw/nes/nes_hw.c205
-rw-r--r--drivers/infiniband/hw/nes/nes_hw.h6
-rw-r--r--drivers/infiniband/hw/nes/nes_nic.c122
-rw-r--r--drivers/infiniband/hw/nes/nes_verbs.c3
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib.h10
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_cm.c88
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_ib.c30
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c77
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_multicast.c62
-rw-r--r--drivers/input/mouse/bcm5974.c87
-rw-r--r--drivers/input/serio/i8042-x86ia64io.h2
-rw-r--r--drivers/input/touchscreen/jornada720_ts.c4
-rw-r--r--drivers/leds/leds-fsg.c28
-rw-r--r--drivers/leds/leds-pca955x.c70
-rw-r--r--drivers/md/bitmap.c45
-rw-r--r--drivers/md/dm-crypt.c109
-rw-r--r--drivers/md/dm-exception-store.c29
-rw-r--r--drivers/md/dm-ioctl.c10
-rw-r--r--drivers/md/dm-mpath.c66
-rw-r--r--drivers/md/dm-mpath.h2
-rw-r--r--drivers/md/dm-raid1.c4
-rw-r--r--drivers/md/dm-stripe.c4
-rw-r--r--drivers/md/dm-table.c97
-rw-r--r--drivers/md/dm.c52
-rw-r--r--drivers/md/dm.h10
-rw-r--r--drivers/md/linear.c10
-rw-r--r--drivers/md/md.c25
-rw-r--r--drivers/md/multipath.c8
-rw-r--r--drivers/md/raid0.c10
-rw-r--r--drivers/md/raid1.c13
-rw-r--r--drivers/md/raid10.c14
-rw-r--r--drivers/md/raid5.c75
-rw-r--r--drivers/media/common/saa7146_video.c4
-rw-r--r--drivers/media/common/tuners/mt2131.c2
-rw-r--r--drivers/media/common/tuners/mt2131.h2
-rw-r--r--drivers/media/common/tuners/mt2131_priv.h2
-rw-r--r--drivers/media/common/tuners/mxl5005s.c4
-rw-r--r--drivers/media/common/tuners/mxl5005s.h2
-rw-r--r--drivers/media/common/tuners/tuner-simple.c33
-rw-r--r--drivers/media/common/tuners/tuner-xc2028.h1
-rw-r--r--drivers/media/common/tuners/xc5000.c2
-rw-r--r--drivers/media/common/tuners/xc5000.h2
-rw-r--r--drivers/media/common/tuners/xc5000_priv.h2
-rw-r--r--drivers/media/dvb/b2c2/flexcop-fe-tuner.c4
-rw-r--r--drivers/media/dvb/b2c2/flexcop-i2c.c12
-rw-r--r--drivers/media/dvb/bt8xx/dst.c4
-rw-r--r--drivers/media/dvb/dvb-core/dmxdev.c17
-rw-r--r--drivers/media/dvb/dvb-core/dvb_ca_en50221.c4
-rw-r--r--drivers/media/dvb/dvb-core/dvb_demux.c16
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.c8
-rw-r--r--drivers/media/dvb/dvb-usb/cxusb.c2
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_devices.c9
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-ids.h1
-rw-r--r--drivers/media/dvb/frontends/au8522.c47
-rw-r--r--drivers/media/dvb/frontends/au8522.h11
-rw-r--r--drivers/media/dvb/frontends/cx22702.c2
-rw-r--r--drivers/media/dvb/frontends/cx22702.h2
-rw-r--r--drivers/media/dvb/frontends/cx24123.c6
-rw-r--r--drivers/media/dvb/frontends/cx24123.h2
-rw-r--r--drivers/media/dvb/frontends/s5h1409.c3
-rw-r--r--drivers/media/dvb/frontends/s5h1409.h2
-rw-r--r--drivers/media/dvb/frontends/s5h1411.c3
-rw-r--r--drivers/media/dvb/frontends/s5h1411.h2
-rw-r--r--drivers/media/dvb/frontends/s5h1420.c14
-rw-r--r--drivers/media/dvb/frontends/s5h1420.h8
-rw-r--r--drivers/media/dvb/frontends/tda10048.c4
-rw-r--r--drivers/media/dvb/frontends/tda10048.h2
-rw-r--r--drivers/media/dvb/siano/sms-cards.c6
-rw-r--r--drivers/media/dvb/siano/sms-cards.h2
-rw-r--r--drivers/media/dvb/siano/smscoreapi.c2
-rw-r--r--drivers/media/dvb/siano/smscoreapi.h2
-rw-r--r--drivers/media/dvb/siano/smsdvb.c2
-rw-r--r--drivers/media/dvb/siano/smsusb.c2
-rw-r--r--drivers/media/dvb/ttpci/budget-patch.c3
-rw-r--r--drivers/media/dvb/ttpci/budget.c3
-rw-r--r--drivers/media/radio/Makefile4
-rw-r--r--drivers/media/radio/dsbr100.c2
-rw-r--r--drivers/media/radio/miropcm20-radio.c266
-rw-r--r--drivers/media/radio/miropcm20-rds-core.c211
-rw-r--r--drivers/media/radio/miropcm20-rds-core.h19
-rw-r--r--drivers/media/radio/miropcm20-rds.c136
-rw-r--r--drivers/media/radio/radio-aimslab.c3
-rw-r--r--drivers/media/radio/radio-aztech.c3
-rw-r--r--drivers/media/radio/radio-cadet.c2
-rw-r--r--drivers/media/radio/radio-gemtek-pci.c2
-rw-r--r--drivers/media/radio/radio-gemtek.c3
-rw-r--r--drivers/media/radio/radio-maestro.c3
-rw-r--r--drivers/media/radio/radio-maxiradio.c28
-rw-r--r--drivers/media/radio/radio-rtrack2.c3
-rw-r--r--drivers/media/radio/radio-sf16fmi.c2
-rw-r--r--drivers/media/radio/radio-si470x.c4
-rw-r--r--drivers/media/radio/radio-terratec.c3
-rw-r--r--drivers/media/radio/radio-trust.c3
-rw-r--r--drivers/media/radio/radio-zoltrix.c3
-rw-r--r--drivers/media/video/Kconfig2
-rw-r--r--drivers/media/video/Makefile4
-rw-r--r--drivers/media/video/au0828/Kconfig1
-rw-r--r--drivers/media/video/au0828/au0828-cards.c9
-rw-r--r--drivers/media/video/au0828/au0828-cards.h3
-rw-r--r--drivers/media/video/au0828/au0828-core.c4
-rw-r--r--drivers/media/video/au0828/au0828-dvb.c25
-rw-r--r--drivers/media/video/au0828/au0828-i2c.c2
-rw-r--r--drivers/media/video/au0828/au0828-reg.h2
-rw-r--r--drivers/media/video/au0828/au0828.h2
-rw-r--r--drivers/media/video/bt8xx/bttv-cards.c73
-rw-r--r--drivers/media/video/bt8xx/bttv-driver.c3
-rw-r--r--drivers/media/video/bt8xx/bttv-risc.c3
-rw-r--r--drivers/media/video/bt8xx/bttvp.h5
-rw-r--r--drivers/media/video/btcx-risc.c4
-rw-r--r--drivers/media/video/btcx-risc.h2
-rw-r--r--drivers/media/video/bw-qcam.c3
-rw-r--r--drivers/media/video/c-qcam.c3
-rw-r--r--drivers/media/video/cafe_ccic.c1
-rw-r--r--drivers/media/video/cpia.c2
-rw-r--r--drivers/media/video/cpia2/cpia2_usb.c5
-rw-r--r--drivers/media/video/cpia2/cpia2_v4l.c4
-rw-r--r--drivers/media/video/cx18/cx18-av-firmware.c16
-rw-r--r--drivers/media/video/cx18/cx18-cards.c2
-rw-r--r--drivers/media/video/cx18/cx18-driver.c6
-rw-r--r--drivers/media/video/cx18/cx18-dvb.c2
-rw-r--r--drivers/media/video/cx18/cx18-dvb.h2
-rw-r--r--drivers/media/video/cx18/cx18-irq.c2
-rw-r--r--drivers/media/video/cx18/cx18-queue.c129
-rw-r--r--drivers/media/video/cx18/cx18-queue.h2
-rw-r--r--drivers/media/video/cx23885/cx23885-417.c2
-rw-r--r--drivers/media/video/cx23885/cx23885-cards.c2
-rw-r--r--drivers/media/video/cx23885/cx23885-core.c4
-rw-r--r--drivers/media/video/cx23885/cx23885-dvb.c2
-rw-r--r--drivers/media/video/cx23885/cx23885-i2c.c2
-rw-r--r--drivers/media/video/cx23885/cx23885-reg.h2
-rw-r--r--drivers/media/video/cx23885/cx23885-vbi.c2
-rw-r--r--drivers/media/video/cx23885/cx23885-video.c4
-rw-r--r--drivers/media/video/cx23885/cx23885.h2
-rw-r--r--drivers/media/video/cx25840/cx25840-core.c2
-rw-r--r--drivers/media/video/dabusb.c1
-rw-r--r--drivers/media/video/em28xx/em28xx-audio.c12
-rw-r--r--drivers/media/video/em28xx/em28xx-cards.c55
-rw-r--r--drivers/media/video/em28xx/em28xx-dvb.c9
-rw-r--r--drivers/media/video/et61x251/et61x251_core.c1
-rw-r--r--drivers/media/video/gspca/conex.c28
-rw-r--r--drivers/media/video/gspca/etoms.c30
-rw-r--r--drivers/media/video/gspca/gspca.c122
-rw-r--r--drivers/media/video/gspca/gspca.h21
-rw-r--r--drivers/media/video/gspca/mars.c41
-rw-r--r--drivers/media/video/gspca/ov519.c1167
-rw-r--r--drivers/media/video/gspca/pac207.c87
-rw-r--r--drivers/media/video/gspca/pac7311.c1111
-rw-r--r--drivers/media/video/gspca/pac_common.h60
-rw-r--r--drivers/media/video/gspca/sonixb.c594
-rw-r--r--drivers/media/video/gspca/sonixj.c548
-rw-r--r--drivers/media/video/gspca/spca500.c20
-rw-r--r--drivers/media/video/gspca/spca501.c16
-rw-r--r--drivers/media/video/gspca/spca505.c16
-rw-r--r--drivers/media/video/gspca/spca506.c20
-rw-r--r--drivers/media/video/gspca/spca508.c21
-rw-r--r--drivers/media/video/gspca/spca561.c729
-rw-r--r--drivers/media/video/gspca/stk014.c20
-rw-r--r--drivers/media/video/gspca/sunplus.c167
-rw-r--r--drivers/media/video/gspca/t613.c41
-rw-r--r--drivers/media/video/gspca/tv8532.c20
-rw-r--r--drivers/media/video/gspca/vc032x.c31
-rw-r--r--drivers/media/video/gspca/zc3xx.c89
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.c2
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.h1
-rw-r--r--drivers/media/video/ivtv/ivtv-irq.c29
-rw-r--r--drivers/media/video/ivtv/ivtv-queue.h2
-rw-r--r--drivers/media/video/ivtv/ivtv-streams.c2
-rw-r--r--drivers/media/video/ivtv/ivtv-vbi.c4
-rw-r--r--drivers/media/video/ivtv/ivtv-version.h2
-rw-r--r--drivers/media/video/ks0127.c31
-rw-r--r--drivers/media/video/meye.c2
-rw-r--r--drivers/media/video/mxb.c12
-rw-r--r--drivers/media/video/ov511.c20
-rw-r--r--drivers/media/video/pms.c13
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-devattr.c2
-rw-r--r--drivers/media/video/pwc/pwc-ctrl.c18
-rw-r--r--drivers/media/video/s2255drv.c3
-rw-r--r--drivers/media/video/saa7115.c5
-rw-r--r--drivers/media/video/se401.c2
-rw-r--r--drivers/media/video/sn9c102/sn9c102_core.c1
-rw-r--r--drivers/media/video/sn9c102/sn9c102_devtable.h21
-rw-r--r--drivers/media/video/stv680.c2
-rw-r--r--drivers/media/video/usbvideo/ibmcam.c6
-rw-r--r--drivers/media/video/usbvideo/vicam.c2
-rw-r--r--drivers/media/video/uvc/uvc_ctrl.c2
-rw-r--r--drivers/media/video/v4l2-dev.c5
-rw-r--r--drivers/media/video/v4l2-ioctl.c4
-rw-r--r--drivers/media/video/vivi.c52
-rw-r--r--drivers/media/video/w9966.c2
-rw-r--r--drivers/media/video/w9968cf.c2
-rw-r--r--drivers/media/video/wm8739.c4
-rw-r--r--drivers/media/video/zc0301/zc0301_core.c1
-rw-r--r--drivers/media/video/zc0301/zc0301_sensor.h19
-rw-r--r--drivers/media/video/zoran_card.c2
-rw-r--r--drivers/media/video/zoran_driver.c15
-rw-r--r--drivers/memstick/core/memstick.c10
-rw-r--r--drivers/memstick/core/mspro_block.c35
-rw-r--r--drivers/memstick/host/jmb38x_ms.c39
-rw-r--r--drivers/mfd/Kconfig4
-rw-r--r--drivers/mfd/asic3.c2
-rw-r--r--drivers/misc/acer-wmi.c3
-rw-r--r--drivers/misc/eeepc-laptop.c16
-rw-r--r--drivers/misc/fujitsu-laptop.c7
-rw-r--r--drivers/misc/hp-wmi.c91
-rw-r--r--drivers/misc/sgi-gru/grufile.c3
-rw-r--r--drivers/misc/thinkpad_acpi.c1
-rw-r--r--drivers/mmc/card/block.c25
-rw-r--r--drivers/mmc/card/mmc_test.c4
-rw-r--r--drivers/mmc/host/at91_mci.c20
-rw-r--r--drivers/mmc/host/atmel-mci.c18
-rw-r--r--drivers/mmc/host/tmio_mmc.h4
-rw-r--r--drivers/mtd/ftl.c24
-rw-r--r--drivers/mtd/mtd_blkdevs.c16
-rw-r--r--drivers/mtd/mtdchar.c16
-rw-r--r--drivers/mtd/nand/tmio_nand.c8
-rw-r--r--drivers/net/bnx2.h2
-rw-r--r--drivers/net/bnx2x.h5
-rw-r--r--drivers/net/bnx2x_main.c34
-rw-r--r--drivers/net/e100.c4
-rw-r--r--drivers/net/e1000/e1000_hw.c23
-rw-r--r--drivers/net/e1000e/e1000.h5
-rw-r--r--drivers/net/e1000e/ethtool.c9
-rw-r--r--drivers/net/e1000e/ich8lan.c78
-rw-r--r--drivers/net/e1000e/netdev.c72
-rw-r--r--drivers/net/e1000e/param.c30
-rw-r--r--drivers/net/forcedeth.c24
-rw-r--r--drivers/net/hp-plus.c8
-rw-r--r--drivers/net/ixgbe/ixgbe_main.c6
-rw-r--r--drivers/net/mlx4/mr.c10
-rw-r--r--drivers/net/netxen/netxen_nic_main.c10
-rw-r--r--drivers/net/niu.c56
-rw-r--r--drivers/net/pcmcia/axnet_cs.c1
-rw-r--r--drivers/net/pcmcia/pcnet_cs.c2
-rw-r--r--drivers/net/usb/pegasus.c11
-rw-r--r--drivers/net/wireless/ath9k/beacon.c13
-rw-r--r--drivers/net/wireless/ath9k/core.c11
-rw-r--r--drivers/net/wireless/ath9k/core.h2
-rw-r--r--drivers/net/wireless/ath9k/hw.c8
-rw-r--r--drivers/net/wireless/ath9k/main.c40
-rw-r--r--drivers/net/wireless/ath9k/recv.c5
-rw-r--r--drivers/net/wireless/ath9k/xmit.c10
-rw-r--r--drivers/net/wireless/b43/rfkill.c18
-rw-r--r--drivers/net/wireless/b43legacy/rfkill.c18
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c14
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.c3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c35
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c77
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fh.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rx.c5
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c29
-rw-r--r--drivers/net/wireless/libertas/if_cs.c13
-rw-r--r--drivers/net/wireless/orinoco.c10
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00reg.h5
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c1
-rw-r--r--drivers/pci/hotplug/fakephp.c6
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c2
-rw-r--r--drivers/pci/intel-iommu.c23
-rw-r--r--drivers/pci/pci-sysfs.c19
-rw-r--r--drivers/pci/pcie/aspm.c2
-rw-r--r--drivers/pci/probe.c18
-rw-r--r--drivers/pci/search.c6
-rw-r--r--drivers/pci/setup-bus.c11
-rw-r--r--drivers/pcmcia/ds.c23
-rw-r--r--drivers/pcmcia/soc_common.c6
-rw-r--r--drivers/pnp/Makefile5
-rw-r--r--drivers/pnp/pnpacpi/core.c2
-rw-r--r--drivers/pnp/pnpacpi/rsparser.c2
-rw-r--r--drivers/pnp/pnpbios/core.c2
-rw-r--r--drivers/rtc/rtc-cmos.c38
-rw-r--r--drivers/rtc/rtc-dev.c15
-rw-r--r--drivers/rtc/rtc-lib.c5
-rw-r--r--drivers/s390/block/dasd_proc.c3
-rw-r--r--drivers/s390/block/dcssblk.c4
-rw-r--r--drivers/s390/cio/ccwgroup.c4
-rw-r--r--drivers/s390/cio/chp.c7
-rw-r--r--drivers/s390/cio/cio.c5
-rw-r--r--drivers/s390/cio/css.c32
-rw-r--r--drivers/s390/cio/device_fsm.c7
-rw-r--r--drivers/s390/cio/qdio_setup.c55
-rw-r--r--drivers/s390/scsi/zfcp_aux.c150
-rw-r--r--drivers/s390/scsi/zfcp_ccw.c51
-rw-r--r--drivers/s390/scsi/zfcp_dbf.c75
-rw-r--r--drivers/s390/scsi/zfcp_dbf.h1
-rw-r--r--drivers/s390/scsi/zfcp_def.h179
-rw-r--r--drivers/s390/scsi/zfcp_erp.c229
-rw-r--r--drivers/s390/scsi/zfcp_ext.h27
-rw-r--r--drivers/s390/scsi/zfcp_fc.c252
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c616
-rw-r--r--drivers/s390/scsi/zfcp_fsf.h75
-rw-r--r--drivers/s390/scsi/zfcp_qdio.c67
-rw-r--r--drivers/s390/scsi/zfcp_scsi.c28
-rw-r--r--drivers/s390/scsi/zfcp_sysfs.c60
-rw-r--r--drivers/scsi/Kconfig10
-rw-r--r--drivers/scsi/aacraid/aachba.c2
-rw-r--r--drivers/scsi/device_handler/scsi_dh_alua.c12
-rw-r--r--drivers/scsi/device_handler/scsi_dh_emc.c9
-rw-r--r--drivers/scsi/device_handler/scsi_dh_hp_sw.c2
-rw-r--r--drivers/scsi/device_handler/scsi_dh_rdac.c8
-rw-r--r--drivers/scsi/gdth.c60
-rw-r--r--drivers/scsi/gdth.h2
-rw-r--r--drivers/scsi/gdth_proc.c66
-rw-r--r--drivers/scsi/gdth_proc.h3
-rw-r--r--drivers/scsi/hosts.c2
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c2
-rw-r--r--drivers/scsi/ide-scsi.c2
-rw-r--r--drivers/scsi/ipr.c3
-rw-r--r--drivers/scsi/ips.c2
-rw-r--r--drivers/scsi/libiscsi.c19
-rw-r--r--drivers/scsi/libsas/sas_ata.c10
-rw-r--r--drivers/scsi/libsas/sas_internal.h2
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c30
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.c6
-rw-r--r--drivers/scsi/ncr53c8xx.c4
-rw-r--r--drivers/scsi/qla1280.c4
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c9
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h13
-rw-r--r--drivers/scsi/qla2xxx/qla_fw.h71
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h4
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c14
-rw-r--r--drivers/scsi/qla2xxx/qla_inline.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_iocb.c30
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c18
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c6
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c11
-rw-r--r--drivers/scsi/qla2xxx/qla_sup.c338
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h2
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c4
-rw-r--r--drivers/scsi/qlogicpti.c1
-rw-r--r--drivers/scsi/scsi.c105
-rw-r--r--drivers/scsi/scsi_error.c92
-rw-r--r--drivers/scsi/scsi_lib.c59
-rw-r--r--drivers/scsi/scsi_netlink.c523
-rw-r--r--drivers/scsi/scsi_priv.h7
-rw-r--r--drivers/scsi/scsi_proc.c8
-rw-r--r--drivers/scsi/scsi_scan.c23
-rw-r--r--drivers/scsi/scsi_sysfs.c8
-rw-r--r--drivers/scsi/scsi_tgt_lib.c8
-rw-r--r--drivers/scsi/scsi_transport_fc.c60
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c4
-rw-r--r--drivers/scsi/sd.c122
-rw-r--r--drivers/scsi/sg.c667
-rw-r--r--drivers/scsi/sr.c7
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_glue.c4
-rw-r--r--drivers/scsi/tmscsim.c4
-rw-r--r--drivers/serial/8250.c16
-rw-r--r--drivers/serial/8250.h1
-rw-r--r--drivers/serial/atmel_serial.c32
-rw-r--r--drivers/serial/imx.c27
-rw-r--r--drivers/spi/orion_spi.c2
-rw-r--r--drivers/spi/pxa2xx_spi.c116
-rw-r--r--drivers/spi/spi_mpc83xx.c26
-rw-r--r--drivers/spi/spi_s3c24xx.c6
-rw-r--r--drivers/ssb/main.c1
-rw-r--r--drivers/usb/core/hcd.c3
-rw-r--r--drivers/usb/core/hub.c39
-rw-r--r--drivers/usb/gadget/fsl_usb2_udc.c2
-rw-r--r--drivers/usb/gadget/omap_udc.c4
-rw-r--r--drivers/usb/host/ehci-hcd.c26
-rw-r--r--drivers/usb/host/ehci-sched.c32
-rw-r--r--drivers/usb/host/ohci-omap.c2
-rw-r--r--drivers/usb/musb/Kconfig1
-rw-r--r--drivers/usb/musb/musb_core.c4
-rw-r--r--drivers/usb/musb/omap2430.c4
-rw-r--r--drivers/usb/musb/omap2430.h4
-rw-r--r--drivers/usb/serial/console.c2
-rw-r--r--drivers/usb/serial/cp2101.c3
-rw-r--r--drivers/usb/serial/ftdi_sio.c3
-rw-r--r--drivers/usb/serial/ftdi_sio.h5
-rw-r--r--drivers/usb/serial/option.c2
-rw-r--r--drivers/usb/serial/sierra.c12
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c2
-rw-r--r--drivers/usb/serial/usb-serial.c4
-rw-r--r--drivers/usb/storage/Kconfig12
-rw-r--r--drivers/usb/storage/Makefile3
-rw-r--r--drivers/usb/storage/unusual_devs.h30
-rw-r--r--drivers/usb/storage/usb.c2
-rw-r--r--drivers/video/atmel_lcdfb.c94
-rw-r--r--drivers/video/cirrusfb.c59
-rw-r--r--drivers/video/console/fbcon.c6
-rw-r--r--drivers/video/console/fbcon.h2
-rw-r--r--drivers/video/tdfxfb.c9
-rw-r--r--drivers/watchdog/geodewdt.c6
-rw-r--r--drivers/watchdog/ibmasr.c1
-rw-r--r--drivers/watchdog/pnx4008_wdt.c4
-rw-r--r--drivers/watchdog/rc32434_wdt.c6
-rw-r--r--drivers/watchdog/rdc321x_wdt.c6
-rw-r--r--drivers/watchdog/wdt285.c15
-rw-r--r--drivers/xen/balloon.c2
486 files changed, 10323 insertions, 7505 deletions
diff --git a/drivers/accessibility/braille/braille_console.c b/drivers/accessibility/braille/braille_console.c
index 0a5f6b2114c..d672cfe7ca5 100644
--- a/drivers/accessibility/braille/braille_console.c
+++ b/drivers/accessibility/braille/braille_console.c
@@ -376,6 +376,8 @@ int braille_register_console(struct console *console, int index,
console->flags |= CON_ENABLED;
console->index = index;
braille_co = console;
+ register_keyboard_notifier(&keyboard_notifier_block);
+ register_vt_notifier(&vt_notifier_block);
return 0;
}
@@ -383,15 +385,8 @@ int braille_unregister_console(struct console *console)
{
if (braille_co != console)
return -EINVAL;
+ unregister_keyboard_notifier(&keyboard_notifier_block);
+ unregister_vt_notifier(&vt_notifier_block);
braille_co = NULL;
return 0;
}
-
-static int __init braille_init(void)
-{
- register_keyboard_notifier(&keyboard_notifier_block);
- register_vt_notifier(&vt_notifier_block);
- return 0;
-}
-
-console_initcall(braille_init);
diff --git a/drivers/acpi/dispatcher/dsobject.c b/drivers/acpi/dispatcher/dsobject.c
index 1022e38994c..0f280589921 100644
--- a/drivers/acpi/dispatcher/dsobject.c
+++ b/drivers/acpi/dispatcher/dsobject.c
@@ -496,7 +496,7 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
arg = arg->common.next;
}
- ACPI_ERROR((AE_INFO,
+ ACPI_WARNING((AE_INFO,
"Package List length (%X) larger than NumElements count (%X), truncated\n",
i, element_count));
} else if (i < element_count) {
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 084109507c9..8dd3336efd7 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -165,8 +165,11 @@ static int acpi_bind_one(struct device *dev, acpi_handle handle)
"firmware_node");
ret = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
"physical_node");
- if (acpi_dev->wakeup.flags.valid)
+ if (acpi_dev->wakeup.flags.valid) {
device_set_wakeup_capable(dev, true);
+ device_set_wakeup_enable(dev,
+ acpi_dev->wakeup.state.enabled);
+ }
}
return 0;
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index d3f0a62efcc..ee68ac54c0d 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -138,7 +138,7 @@ static struct dmi_system_id __cpuinitdata processor_idle_dmi_table[] = {
{
set_no_mwait, "Extensa 5220", {
DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
- DMI_MATCH(DMI_SYS_VENDOR, "ACER"),
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_VERSION, "0100"),
DMI_MATCH(DMI_BOARD_NAME, "Columbia") }, NULL},
{},
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index 80e32093e97..80c251ec6d2 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -71,7 +71,7 @@ static DEFINE_MUTEX(performance_mutex);
* 1 -> ignore _PPC totally -> forced by user through boot param
*/
static int ignore_ppc = -1;
-module_param(ignore_ppc, uint, 0644);
+module_param(ignore_ppc, int, 0644);
MODULE_PARM_DESC(ignore_ppc, "If the frequency of your machine gets wrongly" \
"limited by BIOS, this should help");
diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c
index bcf2c70fca8..a4e3767b8c6 100644
--- a/drivers/acpi/sbshc.c
+++ b/drivers/acpi/sbshc.c
@@ -107,6 +107,13 @@ 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;
+ /*
+ * After the timeout happens, OS will try to check the status of SMbus.
+ * If the status is what OS expected, it will be regarded as the bogus
+ * timeout.
+ */
+ if (smb_check_done(hc))
+ return 0;
else
return -ETIME;
}
diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c
index 4ebbba2b6b1..bf5b04de02d 100644
--- a/drivers/acpi/sleep/proc.c
+++ b/drivers/acpi/sleep/proc.c
@@ -377,6 +377,14 @@ acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset)
return 0;
}
+static void physical_device_enable_wakeup(struct acpi_device *adev)
+{
+ struct device *dev = acpi_get_physical_device(adev->handle);
+
+ if (dev && device_can_wakeup(dev))
+ device_set_wakeup_enable(dev, adev->wakeup.state.enabled);
+}
+
static ssize_t
acpi_system_write_wakeup_device(struct file *file,
const char __user * buffer,
@@ -411,6 +419,7 @@ acpi_system_write_wakeup_device(struct file *file,
}
}
if (found_dev) {
+ physical_device_enable_wakeup(found_dev);
list_for_each_safe(node, next, &acpi_wakeup_device_list) {
struct acpi_device *dev = container_of(node,
struct
@@ -428,6 +437,7 @@ acpi_system_write_wakeup_device(struct file *file,
dev->pnp.bus_id, found_dev->pnp.bus_id);
dev->wakeup.state.enabled =
found_dev->wakeup.state.enabled;
+ physical_device_enable_wakeup(dev);
}
}
}
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index c3419182c9a..775c97a282b 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -300,6 +300,8 @@ int __init acpi_table_init(void)
static int __init acpi_parse_apic_instance(char *str)
{
+ if (!str)
+ return -EINVAL;
acpi_apic_instance = simple_strtoul(str, NULL, 0);
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index ae8494944c4..f17cd4b572f 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -448,8 +448,10 @@ config PATA_MARVELL
tristate "Marvell PATA support via legacy mode"
depends on PCI
help
- This option enables limited support for the Marvell 88SE6145 ATA
- controller.
+ This option enables limited support for the Marvell 88SE61xx ATA
+ controllers. If you wish to use only the SATA ports then select
+ the AHCI driver alone. If you wish to the use the PATA port or
+ both SATA and PATA include this driver.
If unsure, say N.
@@ -661,7 +663,7 @@ config HAVE_PATA_PLATFORM
config PATA_PLATFORM
tristate "Generic platform device PATA support"
- depends on EMBEDDED || ARCH_RPC || PPC || HAVE_PATA_PLATFORM
+ depends on EMBEDDED || PPC || HAVE_PATA_PLATFORM
help
This option enables support for generic directly connected ATA
devices commonly found on embedded systems.
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index c729e6988bb..aeadd00411a 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -267,8 +267,8 @@ struct ahci_port_priv {
* per PM slot */
};
-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_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
+static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc);
@@ -316,6 +316,7 @@ static struct device_attribute *ahci_shost_attrs[] = {
static struct device_attribute *ahci_sdev_attrs[] = {
&dev_attr_sw_activity,
+ &dev_attr_unload_heads,
NULL
};
@@ -420,7 +421,7 @@ static const struct ata_port_info ahci_port_info[] = {
/* board_ahci_mv */
{
AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI |
- AHCI_HFLAG_MV_PATA),
+ AHCI_HFLAG_MV_PATA | AHCI_HFLAG_NO_PMP),
.flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA,
.pio_mask = 0x1f, /* pio0-4 */
@@ -487,7 +488,9 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, 0x3a05), board_ahci }, /* ICH10 */
{ PCI_VDEVICE(INTEL, 0x3a25), board_ahci }, /* ICH10 */
{ PCI_VDEVICE(INTEL, 0x3b24), board_ahci }, /* PCH RAID */
+ { PCI_VDEVICE(INTEL, 0x3b25), board_ahci }, /* PCH RAID */
{ PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */
+ { PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH RAID */
/* 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,
@@ -610,6 +613,15 @@ module_param(ahci_em_messages, int, 0444);
MODULE_PARM_DESC(ahci_em_messages,
"Set AHCI Enclosure Management Message type (0 = disabled, 1 = LED");
+#if defined(CONFIG_PATA_MARVELL) || defined(CONFIG_PATA_MARVELL_MODULE)
+static int marvell_enable;
+#else
+static int marvell_enable = 1;
+#endif
+module_param(marvell_enable, int, 0644);
+MODULE_PARM_DESC(marvell_enable, "Marvell SATA via AHCI (1 = enabled)");
+
+
static inline int ahci_nr_ports(u32 cap)
{
return (cap & 0x1f) + 1;
@@ -732,6 +744,8 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
"MV_AHCI HACK: port_map %x -> %x\n",
port_map,
port_map & mv);
+ dev_printk(KERN_ERR, &pdev->dev,
+ "Disabling your PATA port. Use the boot option 'ahci.marvell_enable=0' to avoid this.\n");
port_map &= mv;
}
@@ -807,10 +821,10 @@ static unsigned ahci_scr_offset(struct ata_port *ap, unsigned int sc_reg)
return 0;
}
-static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
+static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
{
- void __iomem *port_mmio = ahci_port_base(ap);
- int offset = ahci_scr_offset(ap, sc_reg);
+ void __iomem *port_mmio = ahci_port_base(link->ap);
+ int offset = ahci_scr_offset(link->ap, sc_reg);
if (offset) {
*val = readl(port_mmio + offset);
@@ -819,10 +833,10 @@ static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
return -EINVAL;
}
-static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
{
- void __iomem *port_mmio = ahci_port_base(ap);
- int offset = ahci_scr_offset(ap, sc_reg);
+ void __iomem *port_mmio = ahci_port_base(link->ap);
+ int offset = ahci_scr_offset(link->ap, sc_reg);
if (offset) {
writel(val, port_mmio + offset);
@@ -960,7 +974,7 @@ static void ahci_disable_alpm(struct ata_port *ap)
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)));
+ ahci_scr_write(&ap->link, SCR_ERROR, ((1 << 16) | (1 << 18)));
/*
* Clear flag to indicate that we should ignore all PhyRdy
@@ -1924,8 +1938,8 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
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);
+ ahci_scr_read(&ap->link, SCR_ERROR, &serror);
+ ahci_scr_write(&ap->link, SCR_ERROR, serror);
host_ehi->serror |= serror;
/* some controllers set IRQ_IF_ERR on device errors, ignore it */
@@ -2014,7 +2028,7 @@ static void ahci_port_intr(struct ata_port *ap)
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)));
+ ahci_scr_write(&ap->link, SCR_ERROR, ((1 << 16) | (1 << 18)));
}
if (unlikely(status & PORT_IRQ_ERROR)) {
@@ -2533,6 +2547,12 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ /* The AHCI driver can only drive the SATA ports, the PATA driver
+ can drive them all so if both drivers are selected make sure
+ AHCI stays out of the way */
+ if (pdev->vendor == PCI_VENDOR_ID_MARVELL && !marvell_enable)
+ return -ENODEV;
+
/* acquire resources */
rc = pcim_enable_device(pdev);
if (rc)
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index b1d08a8f500..e9e32ed6b1a 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -165,8 +165,10 @@ 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);
static u8 piix_vmw_bmdma_status(struct ata_port *ap);
-static int piix_sidpr_scr_read(struct ata_port *ap, unsigned int reg, u32 *val);
-static int piix_sidpr_scr_write(struct ata_port *ap, unsigned int reg, u32 val);
+static int piix_sidpr_scr_read(struct ata_link *link,
+ unsigned int reg, u32 *val);
+static int piix_sidpr_scr_write(struct ata_link *link,
+ unsigned int reg, u32 val);
#ifdef CONFIG_PM
static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
static int piix_pci_device_resume(struct pci_dev *pdev);
@@ -278,12 +280,15 @@ static const struct pci_device_id piix_pci_tbl[] = {
/* SATA Controller IDE (PCH) */
{ 0x8086, 0x3b20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
/* SATA Controller IDE (PCH) */
+ { 0x8086, 0x3b21, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+ /* SATA Controller IDE (PCH) */
{ 0x8086, 0x3b26, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
/* SATA Controller IDE (PCH) */
+ { 0x8086, 0x3b28, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
+ /* SATA Controller IDE (PCH) */
{ 0x8086, 0x3b2d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
/* SATA Controller IDE (PCH) */
{ 0x8086, 0x3b2e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
-
{ } /* terminate list */
};
@@ -582,6 +587,7 @@ static const struct ich_laptop ich_laptop[] = {
{ 0x27DF, 0x1025, 0x0110 }, /* ICH7 on Acer 3682WLMi */
{ 0x27DF, 0x1043, 0x1267 }, /* ICH7 on Asus W5F */
{ 0x27DF, 0x103C, 0x30A1 }, /* ICH7 on HP Compaq nc2400 */
+ { 0x27DF, 0x1071, 0xD221 }, /* ICH7 on Hercules EC-900 */
{ 0x24CA, 0x1025, 0x0061 }, /* ICH4 on ACER Aspire 2023WLMi */
{ 0x24CA, 0x1025, 0x003d }, /* ICH4 on ACER TM290 */
{ 0x266F, 0x1025, 0x0066 }, /* ICH6 on ACER Aspire 1694WLMi */
@@ -885,23 +891,9 @@ static void ich_set_dmamode(struct ata_port *ap, struct ata_device *adev)
* Serial ATA Index/Data Pair Superset Registers access
*
* Beginning from ICH8, there's a sane way to access SCRs using index
- * and data register pair located at BAR5. This creates an
- * interesting problem of mapping two SCRs to one port.
- *
- * Although they have separate SCRs, the master and slave aren't
- * independent enough to be treated as separate links - e.g. softreset
- * resets both. Also, there's no protocol defined for hard resetting
- * singled device sharing the virtual port (no defined way to acquire
- * device signature). This is worked around by merging the SCR values
- * into one sensible value and requesting follow-up SRST after
- * hardreset.
- *
- * SCR merging is perfomed in nibbles which is the unit contents in
- * SCRs are organized. If two values are equal, the value is used.
- * When they differ, merge table which lists precedence of possible
- * values is consulted and the first match or the last entry when
- * nothing matches is used. When there's no merge table for the
- * specific nibble, value from the first port is used.
+ * and data register pair located at BAR5 which means that we have
+ * separate SCRs for master and slave. This is handled using libata
+ * slave_link facility.
*/
static const int piix_sidx_map[] = {
[SCR_STATUS] = 0,
@@ -909,120 +901,38 @@ static const int piix_sidx_map[] = {
[SCR_CONTROL] = 1,
};
-static void piix_sidpr_sel(struct ata_device *dev, unsigned int reg)
+static void piix_sidpr_sel(struct ata_link *link, unsigned int reg)
{
- struct ata_port *ap = dev->link->ap;
+ struct ata_port *ap = link->ap;
struct piix_host_priv *hpriv = ap->host->private_data;
- iowrite32(((ap->port_no * 2 + dev->devno) << 8) | piix_sidx_map[reg],
+ iowrite32(((ap->port_no * 2 + link->pmp) << 8) | piix_sidx_map[reg],
hpriv->sidpr + PIIX_SIDPR_IDX);
}
-static int piix_sidpr_read(struct ata_device *dev, unsigned int reg)
-{
- struct piix_host_priv *hpriv = dev->link->ap->host->private_data;
-
- piix_sidpr_sel(dev, reg);
- return ioread32(hpriv->sidpr + PIIX_SIDPR_DATA);
-}
-
-static void piix_sidpr_write(struct ata_device *dev, unsigned int reg, u32 val)
-{
- struct piix_host_priv *hpriv = dev->link->ap->host->private_data;
-
- piix_sidpr_sel(dev, reg);
- iowrite32(val, hpriv->sidpr + PIIX_SIDPR_DATA);
-}
-
-static u32 piix_merge_scr(u32 val0, u32 val1, const int * const *merge_tbl)
-{
- u32 val = 0;
- int i, mi;
-
- for (i = 0, mi = 0; i < 32 / 4; i++) {
- u8 c0 = (val0 >> (i * 4)) & 0xf;
- u8 c1 = (val1 >> (i * 4)) & 0xf;
- u8 merged = c0;
- const int *cur;
-
- /* if no merge preference, assume the first value */
- cur = merge_tbl[mi];
- if (!cur)
- goto done;
- mi++;
-
- /* if two values equal, use it */
- if (c0 == c1)
- goto done;
-
- /* choose the first match or the last from the merge table */
- while (*cur != -1) {
- if (c0 == *cur || c1 == *cur)
- break;
- cur++;
- }
- if (*cur == -1)
- cur--;
- merged = *cur;
- done:
- val |= merged << (i * 4);
- }
-
- return val;
-}
-
-static int piix_sidpr_scr_read(struct ata_port *ap, unsigned int reg, u32 *val)
+static int piix_sidpr_scr_read(struct ata_link *link,
+ unsigned int reg, u32 *val)
{
- const int * const sstatus_merge_tbl[] = {
- /* DET */ (const int []){ 1, 3, 0, 4, 3, -1 },
- /* SPD */ (const int []){ 2, 1, 0, -1 },
- /* IPM */ (const int []){ 6, 2, 1, 0, -1 },
- NULL,
- };
- const int * const scontrol_merge_tbl[] = {
- /* DET */ (const int []){ 1, 0, 4, 0, -1 },
- /* SPD */ (const int []){ 0, 2, 1, 0, -1 },
- /* IPM */ (const int []){ 0, 1, 2, 3, 0, -1 },
- NULL,
- };
- u32 v0, v1;
+ struct piix_host_priv *hpriv = link->ap->host->private_data;
if (reg >= ARRAY_SIZE(piix_sidx_map))
return -EINVAL;
- if (!(ap->flags & ATA_FLAG_SLAVE_POSS)) {
- *val = piix_sidpr_read(&ap->link.device[0], reg);
- return 0;
- }
-
- v0 = piix_sidpr_read(&ap->link.device[0], reg);
- v1 = piix_sidpr_read(&ap->link.device[1], reg);
-
- switch (reg) {
- case SCR_STATUS:
- *val = piix_merge_scr(v0, v1, sstatus_merge_tbl);
- break;
- case SCR_ERROR:
- *val = v0 | v1;
- break;
- case SCR_CONTROL:
- *val = piix_merge_scr(v0, v1, scontrol_merge_tbl);
- break;
- }
-
+ piix_sidpr_sel(link, reg);
+ *val = ioread32(hpriv->sidpr + PIIX_SIDPR_DATA);
return 0;
}
-static int piix_sidpr_scr_write(struct ata_port *ap, unsigned int reg, u32 val)
+static int piix_sidpr_scr_write(struct ata_link *link,
+ unsigned int reg, u32 val)
{
+ struct piix_host_priv *hpriv = link->ap->host->private_data;
+
if (reg >= ARRAY_SIZE(piix_sidx_map))
return -EINVAL;
- piix_sidpr_write(&ap->link.device[0], reg, val);
-
- if (ap->flags & ATA_FLAG_SLAVE_POSS)
- piix_sidpr_write(&ap->link.device[1], reg, val);
-
+ piix_sidpr_sel(link, reg);
+ iowrite32(val, hpriv->sidpr + PIIX_SIDPR_DATA);
return 0;
}
@@ -1363,28 +1273,28 @@ static const int *__devinit piix_init_sata_map(struct pci_dev *pdev,
return map;
}
-static void __devinit piix_init_sidpr(struct ata_host *host)
+static int __devinit piix_init_sidpr(struct ata_host *host)
{
struct pci_dev *pdev = to_pci_dev(host->dev);
struct piix_host_priv *hpriv = host->private_data;
- struct ata_device *dev0 = &host->ports[0]->link.device[0];
+ struct ata_link *link0 = &host->ports[0]->link;
u32 scontrol;
- int i;
+ int i, rc;
/* check for availability */
for (i = 0; i < 4; i++)
if (hpriv->map[i] == IDE)
- return;
+ return 0;
if (!(host->ports[0]->flags & PIIX_FLAG_SIDPR))
- return;
+ return 0;
if (pci_resource_start(pdev, PIIX_SIDPR_BAR) == 0 ||
pci_resource_len(pdev, PIIX_SIDPR_BAR) != PIIX_SIDPR_LEN)
- return;
+ return 0;
if (pcim_iomap_regions(pdev, 1 << PIIX_SIDPR_BAR, DRV_NAME))
- return;
+ return 0;
hpriv->sidpr = pcim_iomap_table(pdev)[PIIX_SIDPR_BAR];
@@ -1392,7 +1302,7 @@ static void __devinit piix_init_sidpr(struct ata_host *host)
* Give it a test drive by inhibiting power save modes which
* we'll do anyway.
*/
- scontrol = piix_sidpr_read(dev0, SCR_CONTROL);
+ piix_sidpr_scr_read(link0, SCR_CONTROL, &scontrol);
/* if IPM is already 3, SCR access is probably working. Don't
* un-inhibit power save modes as BIOS might have inhibited
@@ -1400,18 +1310,30 @@ static void __devinit piix_init_sidpr(struct ata_host *host)
*/
if ((scontrol & 0xf00) != 0x300) {
scontrol |= 0x300;
- piix_sidpr_write(dev0, SCR_CONTROL, scontrol);
- scontrol = piix_sidpr_read(dev0, SCR_CONTROL);
+ piix_sidpr_scr_write(link0, SCR_CONTROL, scontrol);
+ piix_sidpr_scr_read(link0, SCR_CONTROL, &scontrol);
if ((scontrol & 0xf00) != 0x300) {
dev_printk(KERN_INFO, host->dev, "SCR access via "
"SIDPR is available but doesn't work\n");
- return;
+ return 0;
}
}
- host->ports[0]->ops = &piix_sidpr_sata_ops;
- host->ports[1]->ops = &piix_sidpr_sata_ops;
+ /* okay, SCRs available, set ops and ask libata for slave_link */
+ for (i = 0; i < 2; i++) {
+ struct ata_port *ap = host->ports[i];
+
+ ap->ops = &piix_sidpr_sata_ops;
+
+ if (ap->flags & ATA_FLAG_SLAVE_POSS) {
+ rc = ata_slave_link_init(ap);
+ if (rc)
+ return rc;
+ }
+ }
+
+ return 0;
}
static void piix_iocfg_bit18_quirk(struct pci_dev *pdev)
@@ -1499,7 +1421,7 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
* off.
*/
if (pdev->vendor == PCI_VENDOR_ID_INTEL && pdev->device == 0x2652) {
- int rc = piix_disable_ahci(pdev);
+ rc = piix_disable_ahci(pdev);
if (rc)
return rc;
}
@@ -1521,7 +1443,9 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
/* initialize controller */
if (port_flags & ATA_FLAG_SATA) {
piix_init_pcs(host, piix_map_db_table[ent->driver_data]);
- piix_init_sidpr(host);
+ rc = piix_init_sidpr(host);
+ if (rc)
+ return rc;
}
/* apply IOCFG bit18 quirk */
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 79e3a8e7a84..1ee9499bd34 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -163,6 +163,67 @@ MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
+/*
+ * Iterator helpers. Don't use directly.
+ *
+ * LOCKING:
+ * Host lock or EH context.
+ */
+struct ata_link *__ata_port_next_link(struct ata_port *ap,
+ struct ata_link *link, bool dev_only)
+{
+ /* NULL link indicates start of iteration */
+ if (!link) {
+ if (dev_only && sata_pmp_attached(ap))
+ return ap->pmp_link;
+ return &ap->link;
+ }
+
+ /* we just iterated over the host master link, what's next? */
+ if (link == &ap->link) {
+ if (!sata_pmp_attached(ap)) {
+ if (unlikely(ap->slave_link) && !dev_only)
+ return ap->slave_link;
+ return NULL;
+ }
+ return ap->pmp_link;
+ }
+
+ /* slave_link excludes PMP */
+ if (unlikely(link == ap->slave_link))
+ return NULL;
+
+ /* iterate to the next PMP link */
+ if (++link < ap->pmp_link + ap->nr_pmp_links)
+ return link;
+ return NULL;
+}
+
+/**
+ * ata_dev_phys_link - find physical link for a device
+ * @dev: ATA device to look up physical link for
+ *
+ * Look up physical link which @dev is attached to. Note that
+ * this is different from @dev->link only when @dev is on slave
+ * link. For all other cases, it's the same as @dev->link.
+ *
+ * LOCKING:
+ * Don't care.
+ *
+ * RETURNS:
+ * Pointer to the found physical link.
+ */
+struct ata_link *ata_dev_phys_link(struct ata_device *dev)
+{
+ struct ata_port *ap = dev->link->ap;
+
+ if (!ap->slave_link)
+ return dev->link;
+ if (!dev->devno)
+ return &ap->link;
+ return ap->slave_link;
+}
+
/**
* ata_force_cbl - force cable type according to libata.force
* @ap: ATA port of interest
@@ -206,7 +267,8 @@ void ata_force_cbl(struct ata_port *ap)
* the host link and all fan-out ports connected via PMP. If the
* device part is specified as 0 (e.g. 1.00:), it specifies the
* first fan-out link not the host link. Device number 15 always
- * points to the host link whether PMP is attached or not.
+ * points to the host link whether PMP is attached or not. If the
+ * controller has slave link, device number 16 points to it.
*
* LOCKING:
* EH context.
@@ -214,12 +276,11 @@ void ata_force_cbl(struct ata_port *ap)
static void ata_force_link_limits(struct ata_link *link)
{
bool did_spd = false;
- int linkno, i;
+ int linkno = link->pmp;
+ int i;
if (ata_is_host_link(link))
- linkno = 15;
- else
- linkno = link->pmp;
+ linkno += 15;
for (i = ata_force_tbl_size - 1; i >= 0; i--) {
const struct ata_force_ent *fe = &ata_force_tbl[i];
@@ -266,9 +327,9 @@ static void ata_force_xfermask(struct ata_device *dev)
int alt_devno = devno;
int i;
- /* allow n.15 for the first device attached to host port */
- if (ata_is_host_link(dev->link) && devno == 0)
- alt_devno = 15;
+ /* allow n.15/16 for devices attached to host port */
+ if (ata_is_host_link(dev->link))
+ alt_devno += 15;
for (i = ata_force_tbl_size - 1; i >= 0; i--) {
const struct ata_force_ent *fe = &ata_force_tbl[i];
@@ -320,9 +381,9 @@ static void ata_force_horkage(struct ata_device *dev)
int alt_devno = devno;
int i;
- /* allow n.15 for the first device attached to host port */
- if (ata_is_host_link(dev->link) && devno == 0)
- alt_devno = 15;
+ /* allow n.15/16 for devices attached to host port */
+ if (ata_is_host_link(dev->link))
+ alt_devno += 15;
for (i = 0; i < ata_force_tbl_size; i++) {
const struct ata_force_ent *fe = &ata_force_tbl[i];
@@ -2681,7 +2742,7 @@ static void sata_print_link_status(struct ata_link *link)
return;
sata_scr_read(link, SCR_CONTROL, &scontrol);
- if (ata_link_online(link)) {
+ if (ata_phys_link_online(link)) {
tmp = (sstatus >> 4) & 0xf;
ata_link_printk(link, KERN_INFO,
"SATA link up %s (SStatus %X SControl %X)\n",
@@ -3372,6 +3433,12 @@ int ata_wait_ready(struct ata_link *link, unsigned long deadline,
unsigned long nodev_deadline = ata_deadline(start, ATA_TMOUT_FF_WAIT);
int warned = 0;
+ /* Slave readiness can't be tested separately from master. On
+ * M/S emulation configuration, this function should be called
+ * only on the master and it will handle both master and slave.
+ */
+ WARN_ON(link == link->ap->slave_link);
+
if (time_after(nodev_deadline, deadline))
nodev_deadline = deadline;
@@ -3593,7 +3660,7 @@ int ata_std_prereset(struct ata_link *link, unsigned long deadline)
}
/* no point in trying softreset on offline link */
- if (ata_link_offline(link))
+ if (ata_phys_link_offline(link))
ehc->i.action &= ~ATA_EH_SOFTRESET;
return 0;
@@ -3671,7 +3738,7 @@ int sata_link_hardreset(struct ata_link *link, const unsigned long *timing,
if (rc)
goto out;
/* if link is offline nothing more to do */
- if (ata_link_offline(link))
+ if (ata_phys_link_offline(link))
goto out;
/* Link is online. From this point, -ENODEV too is an error. */
@@ -4868,10 +4935,8 @@ int sata_scr_valid(struct ata_link *link)
int sata_scr_read(struct ata_link *link, int reg, u32 *val)
{
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 link->ap->ops->scr_read(link, reg, val);
return -EOPNOTSUPP;
}
@@ -4897,10 +4962,8 @@ int sata_scr_read(struct ata_link *link, int reg, u32 *val)
int sata_scr_write(struct ata_link *link, int reg, u32 val)
{
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 link->ap->ops->scr_write(link, reg, val);
return -EOPNOTSUPP;
}
@@ -4925,13 +4988,12 @@ int sata_scr_write(struct ata_link *link, int reg, u32 val)
int sata_scr_write_flush(struct ata_link *link, int reg, u32 val)
{
if (ata_is_host_link(link)) {
- struct ata_port *ap = link->ap;
int rc;
if (sata_scr_valid(link)) {
- rc = ap->ops->scr_write(ap, reg, val);
+ rc = link->ap->ops->scr_write(link, reg, val);
if (rc == 0)
- rc = ap->ops->scr_read(ap, reg, &val);
+ rc = link->ap->ops->scr_read(link, reg, &val);
return rc;
}
return -EOPNOTSUPP;
@@ -4941,7 +5003,7 @@ int sata_scr_write_flush(struct ata_link *link, int reg, u32 val)
}
/**
- * ata_link_online - test whether the given link is online
+ * ata_phys_link_online - test whether the given link is online
* @link: ATA link to test
*
* Test whether @link is online. Note that this function returns
@@ -4952,20 +5014,20 @@ int sata_scr_write_flush(struct ata_link *link, int reg, u32 val)
* None.
*
* RETURNS:
- * 1 if the port online status is available and online.
+ * True if the port online status is available and online.
*/
-int ata_link_online(struct ata_link *link)
+bool ata_phys_link_online(struct ata_link *link)
{
u32 sstatus;
if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0 &&
(sstatus & 0xf) == 0x3)
- return 1;
- return 0;
+ return true;
+ return false;
}
/**
- * ata_link_offline - test whether the given link is offline
+ * ata_phys_link_offline - test whether the given link is offline
* @link: ATA link to test
*
* Test whether @link is offline. Note that this function
@@ -4976,16 +5038,68 @@ int ata_link_online(struct ata_link *link)
* None.
*
* RETURNS:
- * 1 if the port offline status is available and offline.
+ * True if the port offline status is available and offline.
*/
-int ata_link_offline(struct ata_link *link)
+bool ata_phys_link_offline(struct ata_link *link)
{
u32 sstatus;
if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0 &&
(sstatus & 0xf) != 0x3)
- return 1;
- return 0;
+ return true;
+ return false;
+}
+
+/**
+ * ata_link_online - test whether the given link is online
+ * @link: ATA link to test
+ *
+ * Test whether @link is online. This is identical to
+ * ata_phys_link_online() when there's no slave link. When
+ * there's a slave link, this function should only be called on
+ * the master link and will return true if any of M/S links is
+ * online.
+ *
+ * LOCKING:
+ * None.
+ *
+ * RETURNS:
+ * True if the port online status is available and online.
+ */
+bool ata_link_online(struct ata_link *link)
+{
+ struct ata_link *slave = link->ap->slave_link;
+
+ WARN_ON(link == slave); /* shouldn't be called on slave link */
+
+ return ata_phys_link_online(link) ||
+ (slave && ata_phys_link_online(slave));
+}
+
+/**
+ * ata_link_offline - test whether the given link is offline
+ * @link: ATA link to test
+ *
+ * Test whether @link is offline. This is identical to
+ * ata_phys_link_offline() when there's no slave link. When
+ * there's a slave link, this function should only be called on
+ * the master link and will return true if both M/S links are
+ * offline.
+ *
+ * LOCKING:
+ * None.
+ *
+ * RETURNS:
+ * True if the port offline status is available and offline.
+ */
+bool ata_link_offline(struct ata_link *link)
+{
+ struct ata_link *slave = link->ap->slave_link;
+
+ WARN_ON(link == slave); /* shouldn't be called on slave link */
+
+ return ata_phys_link_offline(link) &&
+ (!slave || ata_phys_link_offline(slave));
}
#ifdef CONFIG_PM
@@ -5127,11 +5241,11 @@ int ata_port_start(struct ata_port *ap)
*/
void ata_dev_init(struct ata_device *dev)
{
- struct ata_link *link = dev->link;
+ struct ata_link *link = ata_dev_phys_link(dev);
struct ata_port *ap = link->ap;
unsigned long flags;
- /* SATA spd limit is bound to the first device */
+ /* SATA spd limit is bound to the attached device, reset together */
link->sata_spd_limit = link->hw_sata_spd_limit;
link->sata_spd = 0;
@@ -5264,6 +5378,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan);
INIT_LIST_HEAD(&ap->eh_done_q);
init_waitqueue_head(&ap->eh_wait_q);
+ init_completion(&ap->park_req_pending);
init_timer_deferrable(&ap->fastdrain_timer);
ap->fastdrain_timer.function = ata_eh_fastdrain_timerfn;
ap->fastdrain_timer.data = (unsigned long)ap;
@@ -5294,6 +5409,7 @@ static void ata_host_release(struct device *gendev, void *res)
scsi_host_put(ap->scsi_host);
kfree(ap->pmp_link);
+ kfree(ap->slave_link);
kfree(ap);
host->ports[i] = NULL;
}
@@ -5414,6 +5530,68 @@ struct ata_host *ata_host_alloc_pinfo(struct device *dev,
return host;
}
+/**
+ * ata_slave_link_init - initialize slave link
+ * @ap: port to initialize slave link for
+ *
+ * Create and initialize slave link for @ap. This enables slave
+ * link handling on the port.
+ *
+ * In libata, a port contains links and a link contains devices.
+ * There is single host link but if a PMP is attached to it,
+ * there can be multiple fan-out links. On SATA, there's usually
+ * a single device connected to a link but PATA and SATA
+ * controllers emulating TF based interface can have two - master
+ * and slave.
+ *
+ * However, there are a few controllers which don't fit into this
+ * abstraction too well - SATA controllers which emulate TF
+ * interface with both master and slave devices but also have
+ * separate SCR register sets for each device. These controllers
+ * need separate links for physical link handling
+ * (e.g. onlineness, link speed) but should be treated like a
+ * traditional M/S controller for everything else (e.g. command
+ * issue, softreset).
+ *
+ * slave_link is libata's way of handling this class of
+ * controllers without impacting core layer too much. For
+ * anything other than physical link handling, the default host
+ * link is used for both master and slave. For physical link
+ * handling, separate @ap->slave_link is used. All dirty details
+ * are implemented inside libata core layer. From LLD's POV, the
+ * only difference is that prereset, hardreset and postreset are
+ * called once more for the slave link, so the reset sequence
+ * looks like the following.
+ *
+ * prereset(M) -> prereset(S) -> hardreset(M) -> hardreset(S) ->
+ * softreset(M) -> postreset(M) -> postreset(S)
+ *
+ * Note that softreset is called only for the master. Softreset
+ * resets both M/S by definition, so SRST on master should handle
+ * both (the standard method will work just fine).
+ *
+ * LOCKING:
+ * Should be called before host is registered.
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+int ata_slave_link_init(struct ata_port *ap)
+{
+ struct ata_link *link;
+
+ WARN_ON(ap->slave_link);
+ WARN_ON(ap->flags & ATA_FLAG_PMP);
+
+ link = kzalloc(sizeof(*link), GFP_KERNEL);
+ if (!link)
+ return -ENOMEM;
+
+ ata_link_init(ap, link, 1);
+ ap->slave_link = link;
+ return 0;
+}
+
static void ata_host_stop(struct device *gendev, void *res)
{
struct ata_host *host = dev_get_drvdata(gendev);
@@ -5640,6 +5818,8 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
/* init sata_spd_limit to the current value */
sata_link_init_spd(&ap->link);
+ if (ap->slave_link)
+ sata_link_init_spd(ap->slave_link);
/* print per-port info to dmesg */
xfer_mask = ata_pack_xfermask(ap->pio_mask, ap->mwdma_mask,
@@ -6260,10 +6440,12 @@ EXPORT_SYMBOL_GPL(ata_base_port_ops);
EXPORT_SYMBOL_GPL(sata_port_ops);
EXPORT_SYMBOL_GPL(ata_dummy_port_ops);
EXPORT_SYMBOL_GPL(ata_dummy_port_info);
+EXPORT_SYMBOL_GPL(__ata_port_next_link);
EXPORT_SYMBOL_GPL(ata_std_bios_param);
EXPORT_SYMBOL_GPL(ata_host_init);
EXPORT_SYMBOL_GPL(ata_host_alloc);
EXPORT_SYMBOL_GPL(ata_host_alloc_pinfo);
+EXPORT_SYMBOL_GPL(ata_slave_link_init);
EXPORT_SYMBOL_GPL(ata_host_start);
EXPORT_SYMBOL_GPL(ata_host_register);
EXPORT_SYMBOL_GPL(ata_host_activate);
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index c1db2f234d2..a93247cc395 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -33,6 +33,7 @@
*/
#include <linux/kernel.h>
+#include <linux/blkdev.h>
#include <linux/pci.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
@@ -79,6 +80,8 @@ enum {
*/
ATA_EH_PRERESET_TIMEOUT = 10000,
ATA_EH_FASTDRAIN_INTERVAL = 3000,
+
+ ATA_EH_UA_TRIES = 5,
};
/* The following table determines how we sequence resets. Each entry
@@ -457,29 +460,29 @@ static void ata_eh_clear_action(struct ata_link *link, struct ata_device *dev,
* RETURNS:
* EH_HANDLED or EH_NOT_HANDLED
*/
-enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
+enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
{
struct Scsi_Host *host = cmd->device->host;
struct ata_port *ap = ata_shost_to_port(host);
unsigned long flags;
struct ata_queued_cmd *qc;
- enum scsi_eh_timer_return ret;
+ enum blk_eh_timer_return ret;
DPRINTK("ENTER\n");
if (ap->ops->error_handler) {
- ret = EH_NOT_HANDLED;
+ ret = BLK_EH_NOT_HANDLED;
goto out;
}
- ret = EH_HANDLED;
+ ret = BLK_EH_HANDLED;
spin_lock_irqsave(ap->lock, flags);
qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc) {
WARN_ON(qc->scsicmd != cmd);
qc->flags |= ATA_QCFLAG_EH_SCHEDULED;
qc->err_mask |= AC_ERR_TIMEOUT;
- ret = EH_NOT_HANDLED;
+ ret = BLK_EH_NOT_HANDLED;
}
spin_unlock_irqrestore(ap->lock, flags);
@@ -831,7 +834,7 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
* Note that ATA_QCFLAG_FAILED is unconditionally set after
* this function completes.
*/
- scsi_req_abort_cmd(qc->scsicmd);
+ blk_abort_request(qc->scsicmd->request);
}
/**
@@ -1357,6 +1360,37 @@ static int ata_eh_read_log_10h(struct ata_device *dev,
}
/**
+ * atapi_eh_tur - perform ATAPI TEST_UNIT_READY
+ * @dev: target ATAPI device
+ * @r_sense_key: out parameter for sense_key
+ *
+ * Perform ATAPI TEST_UNIT_READY.
+ *
+ * LOCKING:
+ * EH context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, AC_ERR_* mask on failure.
+ */
+static unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key)
+{
+ u8 cdb[ATAPI_CDB_LEN] = { TEST_UNIT_READY, 0, 0, 0, 0, 0 };
+ struct ata_taskfile tf;
+ unsigned int err_mask;
+
+ ata_tf_init(dev, &tf);
+
+ tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+ tf.command = ATA_CMD_PACKET;
+ tf.protocol = ATAPI_PROT_NODATA;
+
+ err_mask = ata_exec_internal(dev, &tf, cdb, DMA_NONE, NULL, 0, 0);
+ if (err_mask == AC_ERR_DEV)
+ *r_sense_key = tf.feature >> 4;
+ return err_mask;
+}
+
+/**
* atapi_eh_request_sense - perform ATAPI REQUEST_SENSE
* @dev: device to perform REQUEST_SENSE to
* @sense_buf: result sense data buffer (SCSI_SENSE_BUFFERSIZE bytes long)
@@ -1756,7 +1790,7 @@ static unsigned int ata_eh_speed_down_verdict(struct ata_device *dev)
static unsigned int ata_eh_speed_down(struct ata_device *dev,
unsigned int eflags, unsigned int err_mask)
{
- struct ata_link *link = dev->link;
+ struct ata_link *link = ata_dev_phys_link(dev);
int xfer_ok = 0;
unsigned int verdict;
unsigned int action = 0;
@@ -1880,7 +1914,8 @@ static void ata_eh_link_autopsy(struct ata_link *link)
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) || qc->dev->link != link)
+ if (!(qc->flags & ATA_QCFLAG_FAILED) ||
+ ata_dev_phys_link(qc->dev) != link)
continue;
/* inherit upper level err_mask */
@@ -1967,6 +2002,23 @@ void ata_eh_autopsy(struct ata_port *ap)
ata_port_for_each_link(link, ap)
ata_eh_link_autopsy(link);
+ /* Handle the frigging slave link. Autopsy is done similarly
+ * but actions and flags are transferred over to the master
+ * link and handled from there.
+ */
+ if (ap->slave_link) {
+ struct ata_eh_context *mehc = &ap->link.eh_context;
+ struct ata_eh_context *sehc = &ap->slave_link->eh_context;
+
+ ata_eh_link_autopsy(ap->slave_link);
+
+ ata_eh_about_to_do(ap->slave_link, NULL, ATA_EH_ALL_ACTIONS);
+ mehc->i.action |= sehc->i.action;
+ mehc->i.dev_action[1] |= sehc->i.dev_action[1];
+ mehc->i.flags |= sehc->i.flags;
+ ata_eh_done(ap->slave_link, NULL, ATA_EH_ALL_ACTIONS);
+ }
+
/* Autopsy of fanout ports can affect host link autopsy.
* Perform host link autopsy last.
*/
@@ -2001,7 +2053,8 @@ static void ata_eh_link_report(struct ata_link *link)
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) || qc->dev->link != link ||
+ if (!(qc->flags & ATA_QCFLAG_FAILED) ||
+ ata_dev_phys_link(qc->dev) != link ||
((qc->flags & ATA_QCFLAG_QUIET) &&
qc->err_mask == AC_ERR_DEV))
continue;
@@ -2068,7 +2121,7 @@ static void ata_eh_link_report(struct ata_link *link)
char cdb_buf[70] = "";
if (!(qc->flags & ATA_QCFLAG_FAILED) ||
- qc->dev->link != link || !qc->err_mask)
+ ata_dev_phys_link(qc->dev) != link || !qc->err_mask)
continue;
if (qc->dma_dir != DMA_NONE) {
@@ -2160,12 +2213,14 @@ void ata_eh_report(struct ata_port *ap)
}
static int ata_do_reset(struct ata_link *link, ata_reset_fn_t reset,
- unsigned int *classes, unsigned long deadline)
+ unsigned int *classes, unsigned long deadline,
+ bool clear_classes)
{
struct ata_device *dev;
- ata_link_for_each_dev(dev, link)
- classes[dev->devno] = ATA_DEV_UNKNOWN;
+ if (clear_classes)
+ ata_link_for_each_dev(dev, link)
+ classes[dev->devno] = ATA_DEV_UNKNOWN;
return reset(link, classes, deadline);
}
@@ -2187,17 +2242,20 @@ int ata_eh_reset(struct ata_link *link, int classify,
ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
{
struct ata_port *ap = link->ap;
+ struct ata_link *slave = ap->slave_link;
struct ata_eh_context *ehc = &link->eh_context;
+ struct ata_eh_context *sehc = &slave->eh_context;
unsigned int *classes = ehc->classes;
unsigned int lflags = link->flags;
int verbose = !(ehc->i.flags & ATA_EHI_QUIET);
int max_tries = 0, try = 0;
+ struct ata_link *failed_link;
struct ata_device *dev;
unsigned long deadline, now;
ata_reset_fn_t reset;
unsigned long flags;
u32 sstatus;
- int nr_known, rc;
+ int nr_unknown, rc;
/*
* Prepare to reset
@@ -2252,8 +2310,30 @@ int ata_eh_reset(struct ata_link *link, int classify,
}
if (prereset) {
- rc = prereset(link,
- ata_deadline(jiffies, ATA_EH_PRERESET_TIMEOUT));
+ unsigned long deadline = ata_deadline(jiffies,
+ ATA_EH_PRERESET_TIMEOUT);
+
+ if (slave) {
+ sehc->i.action &= ~ATA_EH_RESET;
+ sehc->i.action |= ehc->i.action;
+ }
+
+ rc = prereset(link, deadline);
+
+ /* If present, do prereset on slave link too. Reset
+ * is skipped iff both master and slave links report
+ * -ENOENT or clear ATA_EH_RESET.
+ */
+ if (slave && (rc == 0 || rc == -ENOENT)) {
+ int tmp;
+
+ tmp = prereset(slave, deadline);
+ if (tmp != -ENOENT)
+ rc = tmp;
+
+ ehc->i.action |= sehc->i.action;
+ }
+
if (rc) {
if (rc == -ENOENT) {
ata_link_printk(link, KERN_DEBUG,
@@ -2302,25 +2382,51 @@ int ata_eh_reset(struct ata_link *link, int classify,
else
ehc->i.flags |= ATA_EHI_DID_SOFTRESET;
- rc = ata_do_reset(link, reset, classes, deadline);
- if (rc && rc != -EAGAIN)
+ rc = ata_do_reset(link, reset, classes, deadline, true);
+ if (rc && rc != -EAGAIN) {
+ failed_link = link;
goto fail;
+ }
+
+ /* hardreset slave link if existent */
+ if (slave && reset == hardreset) {
+ int tmp;
+
+ if (verbose)
+ ata_link_printk(slave, KERN_INFO,
+ "hard resetting link\n");
+ ata_eh_about_to_do(slave, NULL, ATA_EH_RESET);
+ tmp = ata_do_reset(slave, reset, classes, deadline,
+ false);
+ switch (tmp) {
+ case -EAGAIN:
+ rc = -EAGAIN;
+ case 0:
+ break;
+ default:
+ failed_link = slave;
+ rc = tmp;
+ goto fail;
+ }
+ }
+
+ /* perform follow-up SRST if necessary */
if (reset == hardreset &&
ata_eh_followup_srst_needed(link, rc, classes)) {
- /* okay, let's do follow-up softreset */
reset = softreset;
if (!reset) {
ata_link_printk(link, KERN_ERR,
"follow-up softreset required "
"but no softreset avaliable\n");
+ failed_link = link;
rc = -EINVAL;
goto fail;
}
ata_eh_about_to_do(link, NULL, ATA_EH_RESET);
- rc = ata_do_reset(link, reset, classes, deadline);
+ rc = ata_do_reset(link, reset, classes, deadline, true);
}
} else {
if (verbose)
@@ -2341,7 +2447,7 @@ int ata_eh_reset(struct ata_link *link, int classify,
dev->pio_mode = XFER_PIO_0;
dev->flags &= ~ATA_DFLAG_SLEEPING;
- if (ata_link_offline(link))
+ if (ata_phys_link_offline(ata_dev_phys_link(dev)))
continue;
/* apply class override */
@@ -2354,6 +2460,8 @@ int ata_eh_reset(struct ata_link *link, int classify,
/* record current link speed */
if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0)
link->sata_spd = (sstatus >> 4) & 0xf;
+ if (slave && sata_scr_read(slave, SCR_STATUS, &sstatus) == 0)
+ slave->sata_spd = (sstatus >> 4) & 0xf;
/* thaw the port */
if (ata_is_host_link(link))
@@ -2366,12 +2474,17 @@ int ata_eh_reset(struct ata_link *link, int classify,
* reset and here. This race is mediated by cross checking
* link onlineness and classification result later.
*/
- if (postreset)
+ if (postreset) {
postreset(link, classes);
+ if (slave)
+ postreset(slave, classes);
+ }
/* clear cached SError */
spin_lock_irqsave(link->ap->lock, flags);
link->eh_info.serror = 0;
+ if (slave)
+ slave->eh_info.serror = 0;
spin_unlock_irqrestore(link->ap->lock, flags);
/* Make sure onlineness and classification result correspond.
@@ -2381,19 +2494,21 @@ int ata_eh_reset(struct ata_link *link, int classify,
* link onlineness and classification result, those conditions
* can be reliably detected and retried.
*/
- nr_known = 0;
+ nr_unknown = 0;
ata_link_for_each_dev(dev, link) {
/* convert all ATA_DEV_UNKNOWN to ATA_DEV_NONE */
- if (classes[dev->devno] == ATA_DEV_UNKNOWN)
+ if (classes[dev->devno] == ATA_DEV_UNKNOWN) {
classes[dev->devno] = ATA_DEV_NONE;
- else
- nr_known++;
+ if (ata_phys_link_online(ata_dev_phys_link(dev)))
+ nr_unknown++;
+ }
}
- if (classify && !nr_known && ata_link_online(link)) {
+ if (classify && nr_unknown) {
if (try < max_tries) {
ata_link_printk(link, KERN_WARNING, "link online but "
"device misclassified, retrying\n");
+ failed_link = link;
rc = -EAGAIN;
goto fail;
}
@@ -2404,6 +2519,8 @@ int ata_eh_reset(struct ata_link *link, int classify,
/* reset successful, schedule revalidation */
ata_eh_done(link, NULL, ATA_EH_RESET);
+ if (slave)
+ ata_eh_done(slave, NULL, ATA_EH_RESET);
ehc->last_reset = jiffies;
ehc->i.action |= ATA_EH_REVALIDATE;
@@ -2411,6 +2528,8 @@ int ata_eh_reset(struct ata_link *link, int classify,
out:
/* clear hotplug flag */
ehc->i.flags &= ~ATA_EHI_HOTPLUGGED;
+ if (slave)
+ sehc->i.flags &= ~ATA_EHI_HOTPLUGGED;
spin_lock_irqsave(ap->lock, flags);
ap->pflags &= ~ATA_PFLAG_RESETTING;
@@ -2431,7 +2550,7 @@ int ata_eh_reset(struct ata_link *link, int classify,
if (time_before(now, deadline)) {
unsigned long delta = deadline - now;
- ata_link_printk(link, KERN_WARNING,
+ ata_link_printk(failed_link, KERN_WARNING,
"reset failed (errno=%d), retrying in %u secs\n",
rc, DIV_ROUND_UP(jiffies_to_msecs(delta), 1000));
@@ -2439,13 +2558,92 @@ int ata_eh_reset(struct ata_link *link, int classify,
delta = schedule_timeout_uninterruptible(delta);
}
- if (rc == -EPIPE || try == max_tries - 1)
+ if (try == max_tries - 1) {
sata_down_spd_limit(link);
+ if (slave)
+ sata_down_spd_limit(slave);
+ } else if (rc == -EPIPE)
+ sata_down_spd_limit(failed_link);
+
if (hardreset)
reset = hardreset;
goto retry;
}
+static inline void ata_eh_pull_park_action(struct ata_port *ap)
+{
+ struct ata_link *link;
+ struct ata_device *dev;
+ unsigned long flags;
+
+ /*
+ * This function can be thought of as an extended version of
+ * ata_eh_about_to_do() specially crafted to accommodate the
+ * requirements of ATA_EH_PARK handling. Since the EH thread
+ * does not leave the do {} while () loop in ata_eh_recover as
+ * long as the timeout for a park request to *one* device on
+ * the port has not expired, and since we still want to pick
+ * up park requests to other devices on the same port or
+ * timeout updates for the same device, we have to pull
+ * ATA_EH_PARK actions from eh_info into eh_context.i
+ * ourselves at the beginning of each pass over the loop.
+ *
+ * Additionally, all write accesses to &ap->park_req_pending
+ * through INIT_COMPLETION() (see below) or complete_all()
+ * (see ata_scsi_park_store()) are protected by the host lock.
+ * As a result we have that park_req_pending.done is zero on
+ * exit from this function, i.e. when ATA_EH_PARK actions for
+ * *all* devices on port ap have been pulled into the
+ * respective eh_context structs. If, and only if,
+ * park_req_pending.done is non-zero by the time we reach
+ * wait_for_completion_timeout(), another ATA_EH_PARK action
+ * has been scheduled for at least one of the devices on port
+ * ap and we have to cycle over the do {} while () loop in
+ * ata_eh_recover() again.
+ */
+
+ spin_lock_irqsave(ap->lock, flags);
+ INIT_COMPLETION(ap->park_req_pending);
+ ata_port_for_each_link(link, ap) {
+ ata_link_for_each_dev(dev, link) {
+ struct ata_eh_info *ehi = &link->eh_info;
+
+ link->eh_context.i.dev_action[dev->devno] |=
+ ehi->dev_action[dev->devno] & ATA_EH_PARK;
+ ata_eh_clear_action(link, dev, ehi, ATA_EH_PARK);
+ }
+ }
+ spin_unlock_irqrestore(ap->lock, flags);
+}
+
+static void ata_eh_park_issue_cmd(struct ata_device *dev, int park)
+{
+ struct ata_eh_context *ehc = &dev->link->eh_context;
+ struct ata_taskfile tf;
+ unsigned int err_mask;
+
+ ata_tf_init(dev, &tf);
+ if (park) {
+ ehc->unloaded_mask |= 1 << dev->devno;
+ tf.command = ATA_CMD_IDLEIMMEDIATE;
+ tf.feature = 0x44;
+ tf.lbal = 0x4c;
+ tf.lbam = 0x4e;
+ tf.lbah = 0x55;
+ } else {
+ ehc->unloaded_mask &= ~(1 << dev->devno);
+ tf.command = ATA_CMD_CHK_POWER;
+ }
+
+ tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
+ tf.protocol |= ATA_PROT_NODATA;
+ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
+ if (park && (err_mask || tf.lbal != 0xc4)) {
+ ata_dev_printk(dev, KERN_ERR, "head unload failed!\n");
+ ehc->unloaded_mask &= ~(1 << dev->devno);
+ }
+}
+
static int ata_eh_revalidate_and_attach(struct ata_link *link,
struct ata_device **r_failed_dev)
{
@@ -2472,7 +2670,7 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link,
if ((action & ATA_EH_REVALIDATE) && ata_dev_enabled(dev)) {
WARN_ON(dev->class == ATA_DEV_PMP);
- if (ata_link_offline(link)) {
+ if (ata_phys_link_offline(ata_dev_phys_link(dev))) {
rc = -EIO;
goto err;
}
@@ -2610,6 +2808,53 @@ int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
return rc;
}
+/**
+ * atapi_eh_clear_ua - Clear ATAPI UNIT ATTENTION after reset
+ * @dev: ATAPI device to clear UA for
+ *
+ * Resets and other operations can make an ATAPI device raise
+ * UNIT ATTENTION which causes the next operation to fail. This
+ * function clears UA.
+ *
+ * LOCKING:
+ * EH context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+static int atapi_eh_clear_ua(struct ata_device *dev)
+{
+ int i;
+
+ for (i = 0; i < ATA_EH_UA_TRIES; i++) {
+ u8 sense_buffer[SCSI_SENSE_BUFFERSIZE];
+ u8 sense_key = 0;
+ unsigned int err_mask;
+
+ err_mask = atapi_eh_tur(dev, &sense_key);
+ if (err_mask != 0 && err_mask != AC_ERR_DEV) {
+ ata_dev_printk(dev, KERN_WARNING, "TEST_UNIT_READY "
+ "failed (err_mask=0x%x)\n", err_mask);
+ return -EIO;
+ }
+
+ if (!err_mask || sense_key != UNIT_ATTENTION)
+ return 0;
+
+ err_mask = atapi_eh_request_sense(dev, sense_buffer, sense_key);
+ if (err_mask) {
+ ata_dev_printk(dev, KERN_WARNING, "failed to clear "
+ "UNIT ATTENTION (err_mask=0x%x)\n", err_mask);
+ return -EIO;
+ }
+ }
+
+ ata_dev_printk(dev, KERN_WARNING,
+ "UNIT ATTENTION persists after %d tries\n", ATA_EH_UA_TRIES);
+
+ return 0;
+}
+
static int ata_link_nr_enabled(struct ata_link *link)
{
struct ata_device *dev;
@@ -2697,7 +2942,7 @@ static int ata_eh_handle_dev_fail(struct ata_device *dev, int err)
/* This is the last chance, better to slow
* down than lose it.
*/
- sata_down_spd_limit(dev->link);
+ sata_down_spd_limit(ata_dev_phys_link(dev));
ata_down_xfermask_limit(dev, ATA_DNXFER_PIO);
}
}
@@ -2707,7 +2952,7 @@ static int ata_eh_handle_dev_fail(struct ata_device *dev, int err)
ata_dev_disable(dev);
/* detach if offline */
- if (ata_link_offline(dev->link))
+ if (ata_phys_link_offline(ata_dev_phys_link(dev)))
ata_eh_detach_dev(dev);
/* schedule probe if necessary */
@@ -2755,7 +3000,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
struct ata_device *dev;
int nr_failed_devs;
int rc;
- unsigned long flags;
+ unsigned long flags, deadline;
DPRINTK("ENTER\n");
@@ -2829,6 +3074,56 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
}
}
+ do {
+ unsigned long now;
+
+ /*
+ * clears ATA_EH_PARK in eh_info and resets
+ * ap->park_req_pending
+ */
+ ata_eh_pull_park_action(ap);
+
+ deadline = jiffies;
+ ata_port_for_each_link(link, ap) {
+ ata_link_for_each_dev(dev, link) {
+ struct ata_eh_context *ehc = &link->eh_context;
+ unsigned long tmp;
+
+ if (dev->class != ATA_DEV_ATA)
+ continue;
+ if (!(ehc->i.dev_action[dev->devno] &
+ ATA_EH_PARK))
+ continue;
+ tmp = dev->unpark_deadline;
+ if (time_before(deadline, tmp))
+ deadline = tmp;
+ else if (time_before_eq(tmp, jiffies))
+ continue;
+ if (ehc->unloaded_mask & (1 << dev->devno))
+ continue;
+
+ ata_eh_park_issue_cmd(dev, 1);
+ }
+ }
+
+ now = jiffies;
+ if (time_before_eq(deadline, now))
+ break;
+
+ deadline = wait_for_completion_timeout(&ap->park_req_pending,
+ deadline - now);
+ } while (deadline);
+ ata_port_for_each_link(link, ap) {
+ ata_link_for_each_dev(dev, link) {
+ if (!(link->eh_context.unloaded_mask &
+ (1 << dev->devno)))
+ continue;
+
+ ata_eh_park_issue_cmd(dev, 0);
+ ata_eh_done(link, dev, ATA_EH_PARK);
+ }
+ }
+
/* the rest */
ata_port_for_each_link(link, ap) {
struct ata_eh_context *ehc = &link->eh_context;
@@ -2852,6 +3147,20 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
ehc->i.flags &= ~ATA_EHI_SETMODE;
}
+ /* If reset has been issued, clear UA to avoid
+ * disrupting the current users of the device.
+ */
+ if (ehc->i.flags & ATA_EHI_DID_RESET) {
+ ata_link_for_each_dev(dev, link) {
+ if (dev->class != ATA_DEV_ATAPI)
+ continue;
+ rc = atapi_eh_clear_ua(dev);
+ if (rc)
+ goto dev_fail;
+ }
+ }
+
+ /* configure link power saving */
if (ehc->i.action & ATA_EH_LPM)
ata_link_for_each_dev(dev, link)
ata_dev_enable_pm(dev, ap->pm_policy);
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index b9d3ba423cb..59fe051957e 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -183,6 +183,105 @@ DEVICE_ATTR(link_power_management_policy, S_IRUGO | S_IWUSR,
ata_scsi_lpm_show, ata_scsi_lpm_put);
EXPORT_SYMBOL_GPL(dev_attr_link_power_management_policy);
+static ssize_t ata_scsi_park_show(struct device *device,
+ struct device_attribute *attr, char *buf)
+{
+ struct scsi_device *sdev = to_scsi_device(device);
+ struct ata_port *ap;
+ struct ata_link *link;
+ struct ata_device *dev;
+ unsigned long flags;
+ unsigned int uninitialized_var(msecs);
+ int rc = 0;
+
+ ap = ata_shost_to_port(sdev->host);
+
+ spin_lock_irqsave(ap->lock, flags);
+ dev = ata_scsi_find_dev(ap, sdev);
+ if (!dev) {
+ rc = -ENODEV;
+ goto unlock;
+ }
+ if (dev->flags & ATA_DFLAG_NO_UNLOAD) {
+ rc = -EOPNOTSUPP;
+ goto unlock;
+ }
+
+ link = dev->link;
+ if (ap->pflags & ATA_PFLAG_EH_IN_PROGRESS &&
+ link->eh_context.unloaded_mask & (1 << dev->devno) &&
+ time_after(dev->unpark_deadline, jiffies))
+ msecs = jiffies_to_msecs(dev->unpark_deadline - jiffies);
+ else
+ msecs = 0;
+
+unlock:
+ spin_unlock_irq(ap->lock);
+
+ return rc ? rc : snprintf(buf, 20, "%u\n", msecs);
+}
+
+static ssize_t ata_scsi_park_store(struct device *device,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct scsi_device *sdev = to_scsi_device(device);
+ struct ata_port *ap;
+ struct ata_device *dev;
+ long int input;
+ unsigned long flags;
+ int rc;
+
+ rc = strict_strtol(buf, 10, &input);
+ if (rc || input < -2)
+ return -EINVAL;
+ if (input > ATA_TMOUT_MAX_PARK) {
+ rc = -EOVERFLOW;
+ input = ATA_TMOUT_MAX_PARK;
+ }
+
+ ap = ata_shost_to_port(sdev->host);
+
+ spin_lock_irqsave(ap->lock, flags);
+ dev = ata_scsi_find_dev(ap, sdev);
+ if (unlikely(!dev)) {
+ rc = -ENODEV;
+ goto unlock;
+ }
+ if (dev->class != ATA_DEV_ATA) {
+ rc = -EOPNOTSUPP;
+ goto unlock;
+ }
+
+ if (input >= 0) {
+ if (dev->flags & ATA_DFLAG_NO_UNLOAD) {
+ rc = -EOPNOTSUPP;
+ goto unlock;
+ }
+
+ dev->unpark_deadline = ata_deadline(jiffies, input);
+ dev->link->eh_info.dev_action[dev->devno] |= ATA_EH_PARK;
+ ata_port_schedule_eh(ap);
+ complete(&ap->park_req_pending);
+ } else {
+ switch (input) {
+ case -1:
+ dev->flags &= ~ATA_DFLAG_NO_UNLOAD;
+ break;
+ case -2:
+ dev->flags |= ATA_DFLAG_NO_UNLOAD;
+ break;
+ }
+ }
+unlock:
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ return rc ? rc : len;
+}
+DEVICE_ATTR(unload_heads, S_IRUGO | S_IWUSR,
+ ata_scsi_park_show, ata_scsi_park_store);
+EXPORT_SYMBOL_GPL(dev_attr_unload_heads);
+
static void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq)
{
cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
@@ -269,6 +368,12 @@ DEVICE_ATTR(sw_activity, S_IWUGO | S_IRUGO, ata_scsi_activity_show,
ata_scsi_activity_store);
EXPORT_SYMBOL_GPL(dev_attr_sw_activity);
+struct device_attribute *ata_common_sdev_attrs[] = {
+ &dev_attr_unload_heads,
+ NULL
+};
+EXPORT_SYMBOL_GPL(ata_common_sdev_attrs);
+
static void ata_scsi_invalid_field(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
{
@@ -954,6 +1059,9 @@ static int atapi_drain_needed(struct request *rq)
static int ata_scsi_dev_config(struct scsi_device *sdev,
struct ata_device *dev)
{
+ if (!ata_id_has_unload(dev->id))
+ dev->flags |= ATA_DFLAG_NO_UNLOAD;
+
/* configure max sectors */
blk_queue_max_sectors(sdev->request_queue, dev->max_sectors);
@@ -977,6 +1085,10 @@ static int ata_scsi_dev_config(struct scsi_device *sdev,
blk_queue_dma_drain(q, atapi_drain_needed, buf, ATAPI_MAX_DRAIN);
} else {
+ if (ata_id_is_ssd(dev->id))
+ queue_flag_set_unlocked(QUEUE_FLAG_NONROT,
+ sdev->request_queue);
+
/* ATA devices must be sector aligned */
blk_queue_update_dma_alignment(sdev->request_queue,
ATA_SECT_SIZE - 1);
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index 304fdc6f1dc..2a4c516894f 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -1315,11 +1315,6 @@ fsm_start:
break;
case HSM_ST_ERR:
- /* make sure qc->err_mask is available to
- * know what's wrong and recover
- */
- WARN_ON(!(qc->err_mask & (AC_ERR_DEV | AC_ERR_HSM)));
-
ap->hsm_task_state = HSM_ST_IDLE;
/* complete taskfile transaction */
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index ade5c75b614..fe2839e5877 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -70,6 +70,7 @@ extern int atapi_passthru16;
extern int libata_fua;
extern int libata_noacpi;
extern int libata_allow_tpm;
+extern struct ata_link *ata_dev_phys_link(struct ata_device *dev);
extern void ata_force_cbl(struct ata_port *ap);
extern u64 ata_tf_to_lba(const struct ata_taskfile *tf);
extern u64 ata_tf_to_lba48(const struct ata_taskfile *tf);
@@ -107,6 +108,8 @@ extern void ata_qc_issue(struct ata_queued_cmd *qc);
extern void __ata_qc_complete(struct ata_queued_cmd *qc);
extern int atapi_check_dma(struct ata_queued_cmd *qc);
extern void swap_buf_le16(u16 *buf, unsigned int buf_words);
+extern bool ata_phys_link_online(struct ata_link *link);
+extern bool ata_phys_link_offline(struct ata_link *link);
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);
@@ -152,7 +155,7 @@ extern int ata_bus_probe(struct ata_port *ap);
/* libata-eh.c */
extern unsigned long ata_internal_cmd_timeout(struct ata_device *dev, u8 cmd);
extern void ata_internal_cmd_timed_out(struct ata_device *dev, u8 cmd);
-extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
+extern enum blk_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);
diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c
index d3932901a3b..1266924c11f 100644
--- a/drivers/ata/pata_bf54x.c
+++ b/drivers/ata/pata_bf54x.c
@@ -1632,6 +1632,8 @@ static int __devinit bfin_atapi_probe(struct platform_device *pdev)
return -ENODEV;
}
+ dev_set_drvdata(&pdev->dev, host);
+
return 0;
}
@@ -1648,6 +1650,7 @@ static int __devexit bfin_atapi_remove(struct platform_device *pdev)
struct ata_host *host = dev_get_drvdata(dev);
ata_host_detach(host);
+ dev_set_drvdata(&pdev->dev, NULL);
peripheral_free_list(atapi_io_port);
@@ -1655,27 +1658,44 @@ static int __devexit bfin_atapi_remove(struct platform_device *pdev)
}
#ifdef CONFIG_PM
-int bfin_atapi_suspend(struct platform_device *pdev, pm_message_t state)
+static int bfin_atapi_suspend(struct platform_device *pdev, pm_message_t state)
{
- return 0;
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ if (host)
+ return ata_host_suspend(host, state);
+ else
+ return 0;
}
-int bfin_atapi_resume(struct platform_device *pdev)
+static int bfin_atapi_resume(struct platform_device *pdev)
{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ int ret;
+
+ if (host) {
+ ret = bfin_reset_controller(host);
+ if (ret) {
+ printk(KERN_ERR DRV_NAME ": Error during HW init\n");
+ return ret;
+ }
+ ata_host_resume(host);
+ }
+
return 0;
}
+#else
+#define bfin_atapi_suspend NULL
+#define bfin_atapi_resume NULL
#endif
static struct platform_driver bfin_atapi_driver = {
.probe = bfin_atapi_probe,
.remove = __devexit_p(bfin_atapi_remove),
+ .suspend = bfin_atapi_suspend,
+ .resume = bfin_atapi_resume,
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
-#ifdef CONFIG_PM
- .suspend = bfin_atapi_suspend,
- .resume = bfin_atapi_resume,
-#endif
},
};
diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c
index 24a011b2502..0d87eec8496 100644
--- a/drivers/ata/pata_marvell.c
+++ b/drivers/ata/pata_marvell.c
@@ -20,29 +20,30 @@
#include <linux/ata.h>
#define DRV_NAME "pata_marvell"
-#define DRV_VERSION "0.1.4"
+#define DRV_VERSION "0.1.6"
/**
- * marvell_pre_reset - check for 40/80 pin
- * @link: link
- * @deadline: deadline jiffies for the operation
+ * marvell_pata_active - check if PATA is active
+ * @pdev: PCI device
*
- * Perform the PATA port setup we need.
+ * Returns 1 if the PATA port may be active. We know how to check this
+ * for the 6145 but not the other devices
*/
-static int marvell_pre_reset(struct ata_link *link, unsigned long deadline)
+static int marvell_pata_active(struct pci_dev *pdev)
{
- struct ata_port *ap = link->ap;
- struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int i;
u32 devices;
void __iomem *barp;
- int i;
- /* Check if our port is enabled */
+ /* We don't yet know how to do this for other devices */
+ if (pdev->device != 0x6145)
+ return 1;
barp = pci_iomap(pdev, 5, 0x10);
if (barp == NULL)
return -ENOMEM;
+
printk("BAR5:");
for(i = 0; i <= 0x0F; i++)
printk("%02X:%02X ", i, ioread8(barp + i));
@@ -51,9 +52,27 @@ static int marvell_pre_reset(struct ata_link *link, unsigned long deadline)
devices = ioread32(barp + 0x0C);
pci_iounmap(pdev, barp);
- if ((pdev->device == 0x6145) && (ap->port_no == 0) &&
- (!(devices & 0x10))) /* PATA enable ? */
- return -ENOENT;
+ if (devices & 0x10)
+ return 1;
+ return 0;
+}
+
+/**
+ * marvell_pre_reset - check for 40/80 pin
+ * @link: link
+ * @deadline: deadline jiffies for the operation
+ *
+ * Perform the PATA port setup we need.
+ */
+
+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);
+
+ if (pdev->device == 0x6145 && ap->port_no == 0 &&
+ !marvell_pata_active(pdev)) /* PATA enable ? */
+ return -ENOENT;
return ata_sff_prereset(link, deadline);
}
@@ -128,6 +147,12 @@ static int marvell_init_one (struct pci_dev *pdev, const struct pci_device_id *i
if (pdev->device == 0x6101)
ppi[1] = &ata_dummy_port_info;
+#if defined(CONFIG_AHCI) || defined(CONFIG_AHCI_MODULE)
+ if (!marvell_pata_active(pdev)) {
+ printk(KERN_INFO DRV_NAME ": PATA port not active, deferring to AHCI driver.\n");
+ return -ENODEV;
+ }
+#endif
return ata_pci_sff_init_one(pdev, ppi, &marvell_sht, NULL);
}
diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c
index 720b8645f58..a598bb36aaf 100644
--- a/drivers/ata/pata_sil680.c
+++ b/drivers/ata/pata_sil680.c
@@ -230,7 +230,7 @@ static u8 sil680_init_chip(struct pci_dev *pdev, int *try_mmio)
tmpbyte & 1, tmpbyte & 0x30);
*try_mmio = 0;
-#ifdef CONFIG_PPC_MERGE
+#ifdef CONFIG_PPC
if (machine_is(cell))
*try_mmio = (tmpbyte & 1) || pci_resource_start(pdev, 5);
#endif
@@ -322,9 +322,6 @@ static int __devinit sil680_init_one(struct pci_dev *pdev,
/* 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;
diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c
index 3924e7209a4..1a56db92ff7 100644
--- a/drivers/ata/sata_fsl.c
+++ b/drivers/ata/sata_fsl.c
@@ -469,10 +469,10 @@ static bool sata_fsl_qc_fill_rtf(struct ata_queued_cmd *qc)
return true;
}
-static int sata_fsl_scr_write(struct ata_port *ap, unsigned int sc_reg_in,
- u32 val)
+static int sata_fsl_scr_write(struct ata_link *link,
+ unsigned int sc_reg_in, u32 val)
{
- struct sata_fsl_host_priv *host_priv = ap->host->private_data;
+ struct sata_fsl_host_priv *host_priv = link->ap->host->private_data;
void __iomem *ssr_base = host_priv->ssr_base;
unsigned int sc_reg;
@@ -493,10 +493,10 @@ static int sata_fsl_scr_write(struct ata_port *ap, unsigned int sc_reg_in,
return 0;
}
-static int sata_fsl_scr_read(struct ata_port *ap, unsigned int sc_reg_in,
- u32 *val)
+static int sata_fsl_scr_read(struct ata_link *link,
+ unsigned int sc_reg_in, u32 *val)
{
- struct sata_fsl_host_priv *host_priv = ap->host->private_data;
+ struct sata_fsl_host_priv *host_priv = link->ap->host->private_data;
void __iomem *ssr_base = host_priv->ssr_base;
unsigned int sc_reg;
@@ -645,12 +645,12 @@ static int sata_fsl_port_start(struct ata_port *ap)
* Workaround for 8315DS board 3gbps link-up issue,
* currently limit SATA port to GEN1 speed
*/
- sata_fsl_scr_read(ap, SCR_CONTROL, &temp);
+ sata_fsl_scr_read(&ap->link, SCR_CONTROL, &temp);
temp &= ~(0xF << 4);
temp |= (0x1 << 4);
- sata_fsl_scr_write(ap, SCR_CONTROL, temp);
+ sata_fsl_scr_write(&ap->link, SCR_CONTROL, temp);
- sata_fsl_scr_read(ap, SCR_CONTROL, &temp);
+ sata_fsl_scr_read(&ap->link, SCR_CONTROL, &temp);
dev_printk(KERN_WARNING, dev, "scr_control, speed limited to %x\n",
temp);
#endif
@@ -868,7 +868,7 @@ issue_srst:
ioread32(CQ + hcr_base),
ioread32(CA + hcr_base), ioread32(CC + hcr_base));
- sata_fsl_scr_read(ap, SCR_ERROR, &Serror);
+ sata_fsl_scr_read(&ap->link, SCR_ERROR, &Serror);
DPRINTK("HStatus = 0x%x\n", ioread32(hcr_base + HSTATUS));
DPRINTK("HControl = 0x%x\n", ioread32(hcr_base + HCONTROL));
@@ -972,9 +972,9 @@ static void sata_fsl_error_intr(struct ata_port *ap)
* Handle & Clear SError
*/
- sata_fsl_scr_read(ap, SCR_ERROR, &SError);
+ sata_fsl_scr_read(&ap->link, SCR_ERROR, &SError);
if (unlikely(SError & 0xFFFF0000)) {
- sata_fsl_scr_write(ap, SCR_ERROR, SError);
+ sata_fsl_scr_write(&ap->link, SCR_ERROR, SError);
}
DPRINTK("error_intr,hStat=0x%x,CE=0x%x,DE =0x%x,SErr=0x%x\n",
@@ -1091,7 +1091,7 @@ static void sata_fsl_host_intr(struct ata_port *ap)
hstatus = ioread32(hcr_base + HSTATUS);
- sata_fsl_scr_read(ap, SCR_ERROR, &SError);
+ sata_fsl_scr_read(&ap->link, SCR_ERROR, &SError);
if (unlikely(SError & 0xFFFF0000)) {
DPRINTK("serror @host_intr : 0x%x\n", SError);
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c
index 3ead02fe379..fbbd87c96f1 100644
--- a/drivers/ata/sata_inic162x.c
+++ b/drivers/ata/sata_inic162x.c
@@ -96,6 +96,7 @@ enum {
PORT_SCR = 0x20,
/* HOST_CTL bits */
+ HCTL_LEDEN = (1 << 3), /* enable LED operation */
HCTL_IRQOFF = (1 << 8), /* global IRQ off */
HCTL_FTHD0 = (1 << 10), /* fifo threshold 0 */
HCTL_FTHD1 = (1 << 11), /* fifo threshold 1*/
@@ -268,9 +269,9 @@ static void inic_reset_port(void __iomem *port_base)
writeb(0xff, port_base + PORT_IRQ_STAT);
}
-static int inic_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val)
+static int inic_scr_read(struct ata_link *link, unsigned sc_reg, u32 *val)
{
- void __iomem *scr_addr = inic_port_base(ap) + PORT_SCR;
+ void __iomem *scr_addr = inic_port_base(link->ap) + PORT_SCR;
void __iomem *addr;
if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
@@ -285,9 +286,9 @@ static int inic_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val)
return 0;
}
-static int inic_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
+static int inic_scr_write(struct ata_link *link, unsigned sc_reg, u32 val)
{
- void __iomem *scr_addr = inic_port_base(ap) + PORT_SCR;
+ void __iomem *scr_addr = inic_port_base(link->ap) + PORT_SCR;
if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
return -EINVAL;
@@ -540,7 +541,7 @@ static unsigned int inic_qc_issue(struct ata_queued_cmd *qc)
void __iomem *port_base = inic_port_base(ap);
/* fire up the ADMA engine */
- writew(HCTL_FTHD0, port_base + HOST_CTL);
+ writew(HCTL_FTHD0 | HCTL_LEDEN, port_base + HOST_CTL);
writew(IDMA_CTL_GO, port_base + PORT_IDMA_CTL);
writeb(0, port_base + PORT_CPB_PTQFIFO);
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index 13c1d2af18a..2b24ae58b52 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -493,10 +493,10 @@ struct mv_hw_ops {
void (*reset_bus)(struct ata_host *host, void __iomem *mmio);
};
-static int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val);
-static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
-static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val);
-static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
+static int mv_scr_read(struct ata_link *link, unsigned int sc_reg_in, u32 *val);
+static int mv_scr_write(struct ata_link *link, unsigned int sc_reg_in, u32 val);
+static int mv5_scr_read(struct ata_link *link, unsigned int sc_reg_in, u32 *val);
+static int mv5_scr_write(struct ata_link *link, unsigned int sc_reg_in, u32 val);
static int mv_port_start(struct ata_port *ap);
static void mv_port_stop(struct ata_port *ap);
static int mv_qc_defer(struct ata_queued_cmd *qc);
@@ -667,7 +667,8 @@ static const struct pci_device_id mv_pci_tbl[] = {
{ PCI_VDEVICE(MARVELL, 0x5041), chip_504x },
{ PCI_VDEVICE(MARVELL, 0x5080), chip_5080 },
{ PCI_VDEVICE(MARVELL, 0x5081), chip_508x },
- /* RocketRAID 1740/174x have different identifiers */
+ /* RocketRAID 1720/174x have different identifiers */
+ { PCI_VDEVICE(TTI, 0x1720), chip_6042 },
{ PCI_VDEVICE(TTI, 0x1740), chip_508x },
{ PCI_VDEVICE(TTI, 0x1742), chip_508x },
@@ -1069,23 +1070,23 @@ static unsigned int mv_scr_offset(unsigned int sc_reg_in)
return ofs;
}
-static int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
+static int mv_scr_read(struct ata_link *link, unsigned int sc_reg_in, u32 *val)
{
unsigned int ofs = mv_scr_offset(sc_reg_in);
if (ofs != 0xffffffffU) {
- *val = readl(mv_ap_base(ap) + ofs);
+ *val = readl(mv_ap_base(link->ap) + ofs);
return 0;
} else
return -EINVAL;
}
-static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
+static int mv_scr_write(struct ata_link *link, unsigned int sc_reg_in, u32 val)
{
unsigned int ofs = mv_scr_offset(sc_reg_in);
if (ofs != 0xffffffffU) {
- writelfl(val, mv_ap_base(ap) + ofs);
+ writelfl(val, mv_ap_base(link->ap) + ofs);
return 0;
} else
return -EINVAL;
@@ -2250,11 +2251,11 @@ static unsigned int mv5_scr_offset(unsigned int sc_reg_in)
return ofs;
}
-static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
+static int mv5_scr_read(struct ata_link *link, unsigned int sc_reg_in, u32 *val)
{
- struct mv_host_priv *hpriv = ap->host->private_data;
+ struct mv_host_priv *hpriv = link->ap->host->private_data;
void __iomem *mmio = hpriv->base;
- void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
+ void __iomem *addr = mv5_phy_base(mmio, link->ap->port_no);
unsigned int ofs = mv5_scr_offset(sc_reg_in);
if (ofs != 0xffffffffU) {
@@ -2264,11 +2265,11 @@ static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
return -EINVAL;
}
-static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
+static int mv5_scr_write(struct ata_link *link, unsigned int sc_reg_in, u32 val)
{
- struct mv_host_priv *hpriv = ap->host->private_data;
+ struct mv_host_priv *hpriv = link->ap->host->private_data;
void __iomem *mmio = hpriv->base;
- void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
+ void __iomem *addr = mv5_phy_base(mmio, link->ap->port_no);
unsigned int ofs = mv5_scr_offset(sc_reg_in);
if (ofs != 0xffffffffU) {
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index 858f70610ed..fae3841de0d 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -302,8 +302,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_link *link, unsigned int sc_reg, u32 *val);
+static int nv_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
static void nv_nf2_freeze(struct ata_port *ap);
static void nv_nf2_thaw(struct ata_port *ap);
@@ -405,28 +405,45 @@ static struct scsi_host_template nv_swncq_sht = {
.slave_configure = nv_swncq_slave_config,
};
-static struct ata_port_operations nv_generic_ops = {
+/* OSDL bz3352 reports that some nv controllers can't determine device
+ * signature reliably and nv_hardreset is implemented to work around
+ * the problem. This was reported on nf3 and it's unclear whether any
+ * other controllers are affected. However, the workaround has been
+ * applied to all variants and there isn't much to gain by trying to
+ * find out exactly which ones are affected at this point especially
+ * because NV has moved over to ahci for newer controllers.
+ */
+static struct ata_port_operations nv_common_ops = {
.inherits = &ata_bmdma_port_ops,
.hardreset = nv_hardreset,
.scr_read = nv_scr_read,
.scr_write = nv_scr_write,
};
+/* OSDL bz11195 reports that link doesn't come online after hardreset
+ * on generic nv's and there have been several other similar reports
+ * on linux-ide. Disable hardreset for generic nv's.
+ */
+static struct ata_port_operations nv_generic_ops = {
+ .inherits = &nv_common_ops,
+ .hardreset = ATA_OP_NULL,
+};
+
static struct ata_port_operations nv_nf2_ops = {
- .inherits = &nv_generic_ops,
+ .inherits = &nv_common_ops,
.freeze = nv_nf2_freeze,
.thaw = nv_nf2_thaw,
};
static struct ata_port_operations nv_ck804_ops = {
- .inherits = &nv_generic_ops,
+ .inherits = &nv_common_ops,
.freeze = nv_ck804_freeze,
.thaw = nv_ck804_thaw,
.host_stop = nv_ck804_host_stop,
};
static struct ata_port_operations nv_adma_ops = {
- .inherits = &nv_generic_ops,
+ .inherits = &nv_common_ops,
.check_atapi_dma = nv_adma_check_atapi_dma,
.sff_tf_read = nv_adma_tf_read,
@@ -450,7 +467,7 @@ static struct ata_port_operations nv_adma_ops = {
};
static struct ata_port_operations nv_swncq_ops = {
- .inherits = &nv_generic_ops,
+ .inherits = &nv_common_ops,
.qc_defer = ata_std_qc_defer,
.qc_prep = nv_swncq_qc_prep,
@@ -1494,21 +1511,21 @@ static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance)
return ret;
}
-static int nv_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
+static int nv_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
{
if (sc_reg > SCR_CONTROL)
return -EINVAL;
- *val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
+ *val = ioread32(link->ap->ioaddr.scr_addr + (sc_reg * 4));
return 0;
}
-static int nv_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int nv_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL)
return -EINVAL;
- iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+ iowrite32(val, link->ap->ioaddr.scr_addr + (sc_reg * 4));
return 0;
}
@@ -2201,9 +2218,9 @@ static void nv_swncq_host_interrupt(struct ata_port *ap, u16 fis)
if (!pp->qc_active)
return;
- if (ap->ops->scr_read(ap, SCR_ERROR, &serror))
+ if (ap->ops->scr_read(&ap->link, SCR_ERROR, &serror))
return;
- ap->ops->scr_write(ap, SCR_ERROR, serror);
+ ap->ops->scr_write(&ap->link, SCR_ERROR, serror);
if (ata_stat & ATA_ERR) {
ata_ehi_clear_desc(ehi);
diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c
index 030665ba76b..750d8cdc00c 100644
--- a/drivers/ata/sata_promise.c
+++ b/drivers/ata/sata_promise.c
@@ -137,8 +137,8 @@ struct pdc_port_priv {
dma_addr_t pkt_dma;
};
-static int pdc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
-static int pdc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int pdc_sata_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
+static int pdc_sata_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
static int pdc_ata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
static int pdc_common_port_start(struct ata_port *ap);
static int pdc_sata_port_start(struct ata_port *ap);
@@ -386,19 +386,21 @@ static int pdc_sata_cable_detect(struct ata_port *ap)
return ATA_CBL_SATA;
}
-static int pdc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
+static int pdc_sata_scr_read(struct ata_link *link,
+ unsigned int sc_reg, u32 *val)
{
if (sc_reg > SCR_CONTROL)
return -EINVAL;
- *val = readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+ *val = readl(link->ap->ioaddr.scr_addr + (sc_reg * 4));
return 0;
}
-static int pdc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int pdc_sata_scr_write(struct ata_link *link,
+ unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL)
return -EINVAL;
- writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+ writel(val, link->ap->ioaddr.scr_addr + (sc_reg * 4));
return 0;
}
@@ -731,7 +733,7 @@ static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc,
if (sata_scr_valid(&ap->link)) {
u32 serror;
- pdc_sata_scr_read(ap, SCR_ERROR, &serror);
+ pdc_sata_scr_read(&ap->link, SCR_ERROR, &serror);
ehi->serror |= serror;
}
diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c
index 1600107047c..a000c86ac85 100644
--- a/drivers/ata/sata_qstor.c
+++ b/drivers/ata/sata_qstor.c
@@ -111,8 +111,8 @@ struct qs_port_priv {
qs_state_t state;
};
-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_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
+static int qs_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
static int qs_ata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
static int qs_port_start(struct ata_port *ap);
static void qs_host_stop(struct ata_host *host);
@@ -242,11 +242,11 @@ static int qs_prereset(struct ata_link *link, unsigned long deadline)
return ata_sff_prereset(link, deadline);
}
-static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
+static int qs_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
{
if (sc_reg > SCR_CONTROL)
return -EINVAL;
- *val = readl(ap->ioaddr.scr_addr + (sc_reg * 8));
+ *val = readl(link->ap->ioaddr.scr_addr + (sc_reg * 8));
return 0;
}
@@ -256,11 +256,11 @@ static void qs_error_handler(struct ata_port *ap)
ata_std_error_handler(ap);
}
-static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int qs_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL)
return -EINVAL;
- writel(val, ap->ioaddr.scr_addr + (sc_reg * 8));
+ writel(val, link->ap->ioaddr.scr_addr + (sc_reg * 8));
return 0;
}
diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c
index 88bf4212590..031d7b7dee3 100644
--- a/drivers/ata/sata_sil.c
+++ b/drivers/ata/sata_sil.c
@@ -115,8 +115,8 @@ static int sil_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
static int sil_pci_device_resume(struct pci_dev *pdev);
#endif
static void sil_dev_config(struct ata_device *dev);
-static 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_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
+static int sil_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
static int sil_set_mode(struct ata_link *link, struct ata_device **r_failed);
static void sil_freeze(struct ata_port *ap);
static void sil_thaw(struct ata_port *ap);
@@ -317,9 +317,9 @@ static inline void __iomem *sil_scr_addr(struct ata_port *ap,
return NULL;
}
-static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
+static int sil_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
{
- void __iomem *mmio = sil_scr_addr(ap, sc_reg);
+ void __iomem *mmio = sil_scr_addr(link->ap, sc_reg);
if (mmio) {
*val = readl(mmio);
@@ -328,9 +328,9 @@ static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
return -EINVAL;
}
-static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int sil_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
{
- void __iomem *mmio = sil_scr_addr(ap, sc_reg);
+ void __iomem *mmio = sil_scr_addr(link->ap, sc_reg);
if (mmio) {
writel(val, mmio);
@@ -352,8 +352,8 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
* controllers continue to assert IRQ as long as
* SError bits are pending. Clear SError immediately.
*/
- sil_scr_read(ap, SCR_ERROR, &serror);
- sil_scr_write(ap, SCR_ERROR, serror);
+ sil_scr_read(&ap->link, SCR_ERROR, &serror);
+ sil_scr_write(&ap->link, SCR_ERROR, serror);
/* Sometimes spurious interrupts occur, double check
* it's PHYRDY CHG.
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index 84ffcc26a74..4621807a1a6 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -340,8 +340,8 @@ struct sil24_port_priv {
};
static void sil24_dev_config(struct ata_device *dev);
-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 int sil24_scr_read(struct ata_link *link, unsigned sc_reg, u32 *val);
+static int sil24_scr_write(struct ata_link *link, unsigned sc_reg, u32 val);
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);
@@ -504,9 +504,9 @@ static int sil24_scr_map[] = {
[SCR_ACTIVE] = 3,
};
-static int sil24_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val)
+static int sil24_scr_read(struct ata_link *link, unsigned sc_reg, u32 *val)
{
- void __iomem *scr_addr = sil24_port_base(ap) + PORT_SCONTROL;
+ void __iomem *scr_addr = sil24_port_base(link->ap) + PORT_SCONTROL;
if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {
void __iomem *addr;
@@ -517,9 +517,9 @@ static int sil24_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val)
return -EINVAL;
}
-static int sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
+static int sil24_scr_write(struct ata_link *link, unsigned sc_reg, u32 val)
{
- void __iomem *scr_addr = sil24_port_base(ap) + PORT_SCONTROL;
+ void __iomem *scr_addr = sil24_port_base(link->ap) + PORT_SCONTROL;
if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {
void __iomem *addr;
diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c
index 1010b3069bd..9c43b4e7c4a 100644
--- a/drivers/ata/sata_sis.c
+++ b/drivers/ata/sata_sis.c
@@ -64,8 +64,8 @@ enum {
};
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_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
+static int sis_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
static const struct pci_device_id sis_pci_tbl[] = {
{ PCI_VDEVICE(SI, 0x0180), sis_180 }, /* SiS 964/180 */
@@ -134,10 +134,11 @@ static unsigned int get_scr_cfg_addr(struct ata_port *ap, unsigned int sc_reg)
return addr;
}
-static u32 sis_scr_cfg_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
+static u32 sis_scr_cfg_read(struct ata_link *link,
+ 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);
+ struct pci_dev *pdev = to_pci_dev(link->ap->host->dev);
+ unsigned int cfg_addr = get_scr_cfg_addr(link->ap, sc_reg);
u32 val2 = 0;
u8 pmr;
@@ -158,10 +159,11 @@ static u32 sis_scr_cfg_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
return 0;
}
-static int sis_scr_cfg_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int sis_scr_cfg_write(struct ata_link *link,
+ 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);
+ struct pci_dev *pdev = to_pci_dev(link->ap->host->dev);
+ unsigned int cfg_addr = get_scr_cfg_addr(link->ap, sc_reg);
u8 pmr;
if (sc_reg == SCR_ERROR) /* doesn't exist in PCI cfg space */
@@ -178,8 +180,9 @@ static int sis_scr_cfg_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
return 0;
}
-static int sis_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
+static int sis_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
{
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u8 pmr;
@@ -187,7 +190,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, val);
+ return sis_scr_cfg_read(link, sc_reg, val);
pci_read_config_byte(pdev, SIS_PMR, &pmr);
@@ -202,8 +205,9 @@ static int sis_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
return 0;
}
-static int sis_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int sis_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
{
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u8 pmr;
@@ -213,7 +217,7 @@ static int sis_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
pci_read_config_byte(pdev, SIS_PMR, &pmr);
if (ap->flags & SIS_FLAG_CFGSCR)
- return sis_scr_cfg_write(ap, sc_reg, val);
+ return sis_scr_cfg_write(link, sc_reg, val);
else {
iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4));
if ((pdev->device == 0x0182) || (pdev->device == 0x0183) ||
diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c
index fb13b82aacb..609d147813a 100644
--- a/drivers/ata/sata_svw.c
+++ b/drivers/ata/sata_svw.c
@@ -123,20 +123,22 @@ static int k2_sata_check_atapi_dma(struct ata_queued_cmd *qc)
}
}
-static int k2_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
+static int k2_sata_scr_read(struct ata_link *link,
+ unsigned int sc_reg, u32 *val)
{
if (sc_reg > SCR_CONTROL)
return -EINVAL;
- *val = readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+ *val = readl(link->ap->ioaddr.scr_addr + (sc_reg * 4));
return 0;
}
-static int k2_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int k2_sata_scr_write(struct ata_link *link,
+ unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL)
return -EINVAL;
- writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+ writel(val, link->ap->ioaddr.scr_addr + (sc_reg * 4));
return 0;
}
diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c
index db529b84994..019575bb3e0 100644
--- a/drivers/ata/sata_uli.c
+++ b/drivers/ata/sata_uli.c
@@ -57,8 +57,8 @@ struct uli_priv {
};
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_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
+static int uli_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
static const struct pci_device_id uli_pci_tbl[] = {
{ PCI_VDEVICE(AL, 0x5289), uli_5289 },
@@ -107,39 +107,39 @@ 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_link *link, 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);
+ struct pci_dev *pdev = to_pci_dev(link->ap->host->dev);
+ unsigned int cfg_addr = get_scr_cfg_addr(link->ap, sc_reg);
u32 val;
pci_read_config_dword(pdev, cfg_addr, &val);
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_link *link, 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);
+ struct pci_dev *pdev = to_pci_dev(link->ap->host->dev);
+ unsigned int cfg_addr = get_scr_cfg_addr(link->ap, scr);
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_link *link, unsigned int sc_reg, u32 *val)
{
if (sc_reg > SCR_CONTROL)
return -EINVAL;
- *val = uli_scr_cfg_read(ap, sc_reg);
+ *val = uli_scr_cfg_read(link, sc_reg);
return 0;
}
-static int uli_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int uli_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL) //SCR_CONTROL=2, SCR_ERROR=1, SCR_STATUS=0
return -EINVAL;
- uli_scr_cfg_write(ap, sc_reg, val);
+ uli_scr_cfg_write(link, sc_reg, val);
return 0;
}
diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c
index 96deeb354e1..1cfa74535d9 100644
--- a/drivers/ata/sata_via.c
+++ b/drivers/ata/sata_via.c
@@ -68,8 +68,8 @@ enum {
};
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 int svia_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
+static int svia_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
static void svia_noop_freeze(struct ata_port *ap);
static int vt6420_prereset(struct ata_link *link, unsigned long deadline);
static int vt6421_pata_cable_detect(struct ata_port *ap);
@@ -152,19 +152,19 @@ MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, svia_pci_tbl);
MODULE_VERSION(DRV_VERSION);
-static int svia_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
+static int svia_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
{
if (sc_reg > SCR_CONTROL)
return -EINVAL;
- *val = ioread32(ap->ioaddr.scr_addr + (4 * sc_reg));
+ *val = ioread32(link->ap->ioaddr.scr_addr + (4 * sc_reg));
return 0;
}
-static int svia_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int svia_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL)
return -EINVAL;
- iowrite32(val, ap->ioaddr.scr_addr + (4 * sc_reg));
+ iowrite32(val, link->ap->ioaddr.scr_addr + (4 * sc_reg));
return 0;
}
@@ -210,20 +210,20 @@ static int vt6420_prereset(struct ata_link *link, unsigned long deadline)
goto skip_scr;
/* Resume phy. This is the old SATA resume sequence */
- svia_scr_write(ap, SCR_CONTROL, 0x300);
- svia_scr_read(ap, SCR_CONTROL, &scontrol); /* flush */
+ svia_scr_write(link, SCR_CONTROL, 0x300);
+ svia_scr_read(link, SCR_CONTROL, &scontrol); /* flush */
/* wait for phy to become ready, if necessary */
do {
msleep(200);
- svia_scr_read(ap, SCR_STATUS, &sstatus);
+ svia_scr_read(link, SCR_STATUS, &sstatus);
if ((sstatus & 0xf) != 1)
break;
} while (time_before(jiffies, timeout));
/* open code sata_print_link_status() */
- svia_scr_read(ap, SCR_STATUS, &sstatus);
- svia_scr_read(ap, SCR_CONTROL, &scontrol);
+ svia_scr_read(link, SCR_STATUS, &sstatus);
+ svia_scr_read(link, SCR_CONTROL, &scontrol);
online = (sstatus & 0xf) == 0x3;
@@ -232,7 +232,7 @@ static int vt6420_prereset(struct ata_link *link, unsigned long deadline)
online ? "up" : "down", sstatus, scontrol);
/* SStatus is read one more time */
- svia_scr_read(ap, SCR_STATUS, &sstatus);
+ svia_scr_read(link, SCR_STATUS, &sstatus);
if (!online) {
/* tell EH to bail */
diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c
index f3d635c0a2e..c57cdff9e6b 100644
--- a/drivers/ata/sata_vsc.c
+++ b/drivers/ata/sata_vsc.c
@@ -98,20 +98,22 @@ enum {
VSC_SATA_INT_PHY_CHANGE),
};
-static int vsc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
+static int vsc_sata_scr_read(struct ata_link *link,
+ unsigned int sc_reg, u32 *val)
{
if (sc_reg > SCR_CONTROL)
return -EINVAL;
- *val = readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+ *val = readl(link->ap->ioaddr.scr_addr + (sc_reg * 4));
return 0;
}
-static int vsc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int vsc_sata_scr_write(struct ata_link *link,
+ unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL)
return -EINVAL;
- writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+ writel(val, link->ap->ioaddr.scr_addr + (sc_reg * 4));
return 0;
}
diff --git a/drivers/base/base.h b/drivers/base/base.h
index 31dc0cd84af..0a5f055dffb 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -54,7 +54,7 @@ struct driver_private {
*/
struct class_private {
struct kset class_subsys;
- struct list_head class_devices;
+ struct klist class_devices;
struct list_head class_interfaces;
struct kset class_dirs;
struct mutex class_mutex;
diff --git a/drivers/base/class.c b/drivers/base/class.c
index cc5e28c8885..eb85e431230 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -135,6 +135,20 @@ static void remove_class_attrs(struct class *cls)
}
}
+static void klist_class_dev_get(struct klist_node *n)
+{
+ struct device *dev = container_of(n, struct device, knode_class);
+
+ get_device(dev);
+}
+
+static void klist_class_dev_put(struct klist_node *n)
+{
+ struct device *dev = container_of(n, struct device, knode_class);
+
+ put_device(dev);
+}
+
int __class_register(struct class *cls, struct lock_class_key *key)
{
struct class_private *cp;
@@ -145,7 +159,7 @@ int __class_register(struct class *cls, struct lock_class_key *key)
cp = kzalloc(sizeof(*cp), GFP_KERNEL);
if (!cp)
return -ENOMEM;
- INIT_LIST_HEAD(&cp->class_devices);
+ klist_init(&cp->class_devices, klist_class_dev_get, klist_class_dev_put);
INIT_LIST_HEAD(&cp->class_interfaces);
kset_init(&cp->class_dirs);
__mutex_init(&cp->class_mutex, "struct class mutex", key);
@@ -269,6 +283,71 @@ char *make_class_name(const char *name, struct kobject *kobj)
#endif
/**
+ * class_dev_iter_init - initialize class device iterator
+ * @iter: class iterator to initialize
+ * @class: the class we wanna iterate over
+ * @start: the device to start iterating from, if any
+ * @type: device_type of the devices to iterate over, NULL for all
+ *
+ * Initialize class iterator @iter such that it iterates over devices
+ * of @class. If @start is set, the list iteration will start there,
+ * otherwise if it is NULL, the iteration starts at the beginning of
+ * the list.
+ */
+void class_dev_iter_init(struct class_dev_iter *iter, struct class *class,
+ struct device *start, const struct device_type *type)
+{
+ struct klist_node *start_knode = NULL;
+
+ if (start)
+ start_knode = &start->knode_class;
+ klist_iter_init_node(&class->p->class_devices, &iter->ki, start_knode);
+ iter->type = type;
+}
+EXPORT_SYMBOL_GPL(class_dev_iter_init);
+
+/**
+ * class_dev_iter_next - iterate to the next device
+ * @iter: class iterator to proceed
+ *
+ * Proceed @iter to the next device and return it. Returns NULL if
+ * iteration is complete.
+ *
+ * The returned device is referenced and won't be released till
+ * iterator is proceed to the next device or exited. The caller is
+ * free to do whatever it wants to do with the device including
+ * calling back into class code.
+ */
+struct device *class_dev_iter_next(struct class_dev_iter *iter)
+{
+ struct klist_node *knode;
+ struct device *dev;
+
+ while (1) {
+ knode = klist_next(&iter->ki);
+ if (!knode)
+ return NULL;
+ dev = container_of(knode, struct device, knode_class);
+ if (!iter->type || iter->type == dev->type)
+ return dev;
+ }
+}
+EXPORT_SYMBOL_GPL(class_dev_iter_next);
+
+/**
+ * class_dev_iter_exit - finish iteration
+ * @iter: class iterator to finish
+ *
+ * Finish an iteration. Always call this function after iteration is
+ * complete whether the iteration ran till the end or not.
+ */
+void class_dev_iter_exit(struct class_dev_iter *iter)
+{
+ klist_iter_exit(&iter->ki);
+}
+EXPORT_SYMBOL_GPL(class_dev_iter_exit);
+
+/**
* class_for_each_device - device iterator
* @class: the class we're iterating
* @start: the device to start with in the list, if any.
@@ -283,13 +362,13 @@ char *make_class_name(const char *name, struct kobject *kobj)
* We check the return of @fn each time. If it returns anything
* other than 0, we break out and return that value.
*
- * Note, we hold class->class_mutex in this function, so it can not be
- * re-acquired in @fn, otherwise it will self-deadlocking. For
- * example, calls to add or remove class members would be verboten.
+ * @fn is allowed to do anything including calling back into class
+ * code. There's no locking restriction.
*/
int class_for_each_device(struct class *class, struct device *start,
void *data, int (*fn)(struct device *, void *))
{
+ struct class_dev_iter iter;
struct device *dev;
int error = 0;
@@ -301,20 +380,13 @@ int class_for_each_device(struct class *class, struct device *start,
return -EINVAL;
}
- mutex_lock(&class->p->class_mutex);
- list_for_each_entry(dev, &class->p->class_devices, node) {
- if (start) {
- if (start == dev)
- start = NULL;
- continue;
- }
- dev = get_device(dev);
+ class_dev_iter_init(&iter, class, start, NULL);
+ while ((dev = class_dev_iter_next(&iter))) {
error = fn(dev, data);
- put_device(dev);
if (error)
break;
}
- mutex_unlock(&class->p->class_mutex);
+ class_dev_iter_exit(&iter);
return error;
}
@@ -337,16 +409,15 @@ EXPORT_SYMBOL_GPL(class_for_each_device);
*
* Note, you will need to drop the reference with put_device() after use.
*
- * We hold class->class_mutex in this function, so it can not be
- * re-acquired in @match, otherwise it will self-deadlocking. For
- * example, calls to add or remove class members would be verboten.
+ * @fn is allowed to do anything including calling back into class
+ * code. There's no locking restriction.
*/
struct device *class_find_device(struct class *class, struct device *start,
void *data,
int (*match)(struct device *, void *))
{
+ struct class_dev_iter iter;
struct device *dev;
- int found = 0;
if (!class)
return NULL;
@@ -356,29 +427,23 @@ struct device *class_find_device(struct class *class, struct device *start,
return NULL;
}
- mutex_lock(&class->p->class_mutex);
- list_for_each_entry(dev, &class->p->class_devices, node) {
- if (start) {
- if (start == dev)
- start = NULL;
- continue;
- }
- dev = get_device(dev);
+ class_dev_iter_init(&iter, class, start, NULL);
+ while ((dev = class_dev_iter_next(&iter))) {
if (match(dev, data)) {
- found = 1;
+ get_device(dev);
break;
- } else
- put_device(dev);
+ }
}
- mutex_unlock(&class->p->class_mutex);
+ class_dev_iter_exit(&iter);
- return found ? dev : NULL;
+ return dev;
}
EXPORT_SYMBOL_GPL(class_find_device);
int class_interface_register(struct class_interface *class_intf)
{
struct class *parent;
+ struct class_dev_iter iter;
struct device *dev;
if (!class_intf || !class_intf->class)
@@ -391,8 +456,10 @@ int class_interface_register(struct class_interface *class_intf)
mutex_lock(&parent->p->class_mutex);
list_add_tail(&class_intf->node, &parent->p->class_interfaces);
if (class_intf->add_dev) {
- list_for_each_entry(dev, &parent->p->class_devices, node)
+ class_dev_iter_init(&iter, parent, NULL, NULL);
+ while ((dev = class_dev_iter_next(&iter)))
class_intf->add_dev(dev, class_intf);
+ class_dev_iter_exit(&iter);
}
mutex_unlock(&parent->p->class_mutex);
@@ -402,6 +469,7 @@ int class_interface_register(struct class_interface *class_intf)
void class_interface_unregister(struct class_interface *class_intf)
{
struct class *parent = class_intf->class;
+ struct class_dev_iter iter;
struct device *dev;
if (!parent)
@@ -410,8 +478,10 @@ void class_interface_unregister(struct class_interface *class_intf)
mutex_lock(&parent->p->class_mutex);
list_del_init(&class_intf->node);
if (class_intf->remove_dev) {
- list_for_each_entry(dev, &parent->p->class_devices, node)
+ class_dev_iter_init(&iter, parent, NULL, NULL);
+ while ((dev = class_dev_iter_next(&iter)))
class_intf->remove_dev(dev, class_intf);
+ class_dev_iter_exit(&iter);
}
mutex_unlock(&parent->p->class_mutex);
diff --git a/drivers/base/core.c b/drivers/base/core.c
index d021c98605b..b98cb1416a2 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -536,7 +536,6 @@ void device_initialize(struct device *dev)
klist_init(&dev->klist_children, klist_children_get,
klist_children_put);
INIT_LIST_HEAD(&dev->dma_pools);
- INIT_LIST_HEAD(&dev->node);
init_MUTEX(&dev->sem);
spin_lock_init(&dev->devres_lock);
INIT_LIST_HEAD(&dev->devres_head);
@@ -916,7 +915,8 @@ int device_add(struct device *dev)
if (dev->class) {
mutex_lock(&dev->class->p->class_mutex);
/* tie the class to the device */
- list_add_tail(&dev->node, &dev->class->p->class_devices);
+ klist_add_tail(&dev->knode_class,
+ &dev->class->p->class_devices);
/* notify any interfaces that the device is here */
list_for_each_entry(class_intf,
@@ -1032,7 +1032,7 @@ void device_del(struct device *dev)
if (class_intf->remove_dev)
class_intf->remove_dev(dev, class_intf);
/* remove the device from the class list */
- list_del_init(&dev->node);
+ klist_del(&dev->knode_class);
mutex_unlock(&dev->class->p->class_mutex);
}
device_remove_file(dev, &uevent_attr);
diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c
index 0c39782b266..aa69556c348 100644
--- a/drivers/block/aoe/aoeblk.c
+++ b/drivers/block/aoe/aoeblk.c
@@ -109,12 +109,12 @@ static const struct attribute_group attr_group = {
static int
aoedisk_add_sysfs(struct aoedev *d)
{
- return sysfs_create_group(&d->gd->dev.kobj, &attr_group);
+ return sysfs_create_group(&disk_to_dev(d->gd)->kobj, &attr_group);
}
void
aoedisk_rm_sysfs(struct aoedev *d)
{
- sysfs_remove_group(&d->gd->dev.kobj, &attr_group);
+ sysfs_remove_group(&disk_to_dev(d->gd)->kobj, &attr_group);
}
static int
@@ -276,7 +276,7 @@ aoeblk_gdalloc(void *vp)
gd->first_minor = d->sysminor * AOE_PARTITIONS;
gd->fops = &aoe_bdops;
gd->private_data = d;
- gd->capacity = d->ssize;
+ set_capacity(gd, d->ssize);
snprintf(gd->disk_name, sizeof gd->disk_name, "etherd/e%ld.%d",
d->aoemajor, d->aoeminor);
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
index 2f1746295d0..961d29a53ca 100644
--- a/drivers/block/aoe/aoecmd.c
+++ b/drivers/block/aoe/aoecmd.c
@@ -645,7 +645,7 @@ aoecmd_sleepwork(struct work_struct *work)
unsigned long flags;
u64 ssize;
- ssize = d->gd->capacity;
+ ssize = get_capacity(d->gd);
bd = bdget_disk(d->gd, 0);
if (bd) {
@@ -707,7 +707,7 @@ ataid_complete(struct aoedev *d, struct aoetgt *t, unsigned char *id)
if (d->flags & (DEVFL_GDALLOC|DEVFL_NEWSIZE))
return;
if (d->gd != NULL) {
- d->gd->capacity = ssize;
+ set_capacity(d->gd, ssize);
d->flags |= DEVFL_NEWSIZE;
} else
d->flags |= DEVFL_GDALLOC;
@@ -756,12 +756,17 @@ diskstats(struct gendisk *disk, struct bio *bio, ulong duration, sector_t sector
unsigned long n_sect = bio->bi_size >> 9;
const int rw = bio_data_dir(bio);
struct hd_struct *part;
+ int cpu;
- part = get_part(disk, sector);
- all_stat_inc(disk, part, ios[rw], sector);
- all_stat_add(disk, part, ticks[rw], duration, sector);
- all_stat_add(disk, part, sectors[rw], n_sect, sector);
- all_stat_add(disk, part, io_ticks, duration, sector);
+ cpu = part_stat_lock();
+ part = disk_map_sector_rcu(disk, sector);
+
+ part_stat_inc(cpu, part, ios[rw]);
+ part_stat_add(cpu, part, ticks[rw], duration);
+ part_stat_add(cpu, part, sectors[rw], n_sect);
+ part_stat_add(cpu, part, io_ticks, duration);
+
+ part_stat_unlock();
}
void
diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c
index a1d813ab0d6..6a8038d115b 100644
--- a/drivers/block/aoe/aoedev.c
+++ b/drivers/block/aoe/aoedev.c
@@ -91,7 +91,7 @@ aoedev_downdev(struct aoedev *d)
}
if (d->gd)
- d->gd->capacity = 0;
+ set_capacity(d->gd, 0);
d->flags &= ~DEVFL_UP;
}
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index b73116ef923..1e1f9153000 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -3460,8 +3460,8 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
hba[i]->intr[SIMPLE_MODE_INT], dac ? "" : " not");
hba[i]->cmd_pool_bits =
- kmalloc(((hba[i]->nr_cmds + BITS_PER_LONG -
- 1) / BITS_PER_LONG) * sizeof(unsigned long), GFP_KERNEL);
+ kmalloc(DIV_ROUND_UP(hba[i]->nr_cmds, BITS_PER_LONG)
+ * sizeof(unsigned long), GFP_KERNEL);
hba[i]->cmd_pool = (CommandList_struct *)
pci_alloc_consistent(hba[i]->pdev,
hba[i]->nr_cmds * sizeof(CommandList_struct),
@@ -3493,8 +3493,8 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
/* command and error info recs zeroed out before
they are used */
memset(hba[i]->cmd_pool_bits, 0,
- ((hba[i]->nr_cmds + BITS_PER_LONG -
- 1) / BITS_PER_LONG) * sizeof(unsigned long));
+ DIV_ROUND_UP(hba[i]->nr_cmds, BITS_PER_LONG)
+ * sizeof(unsigned long));
hba[i]->num_luns = 0;
hba[i]->highest_lun = -1;
diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c
index e1233aabda7..a3fd87b4144 100644
--- a/drivers/block/cciss_scsi.c
+++ b/drivers/block/cciss_scsi.c
@@ -365,7 +365,7 @@ struct scsi2map {
static int
cciss_scsi_add_entry(int ctlr, int hostno,
- unsigned char *scsi3addr, int devtype,
+ struct cciss_scsi_dev_t *device,
struct scsi2map *added, int *nadded)
{
/* assumes hba[ctlr]->scsi_ctlr->lock is held */
@@ -384,12 +384,12 @@ cciss_scsi_add_entry(int ctlr, int hostno,
lun = 0;
/* Is this device a non-zero lun of a multi-lun device */
/* byte 4 of the 8-byte LUN addr will contain the logical unit no. */
- if (scsi3addr[4] != 0) {
+ if (device->scsi3addr[4] != 0) {
/* Search through our list and find the device which */
/* has the same 8 byte LUN address, excepting byte 4. */
/* Assign the same bus and target for this new LUN. */
/* Use the logical unit number from the firmware. */
- memcpy(addr1, scsi3addr, 8);
+ memcpy(addr1, device->scsi3addr, 8);
addr1[4] = 0;
for (i = 0; i < n; i++) {
sd = &ccissscsi[ctlr].dev[i];
@@ -399,7 +399,7 @@ cciss_scsi_add_entry(int ctlr, int hostno,
if (memcmp(addr1, addr2, 8) == 0) {
bus = sd->bus;
target = sd->target;
- lun = scsi3addr[4];
+ lun = device->scsi3addr[4];
break;
}
}
@@ -420,8 +420,12 @@ cciss_scsi_add_entry(int ctlr, int hostno,
added[*nadded].lun = sd->lun;
(*nadded)++;
- memcpy(&sd->scsi3addr[0], scsi3addr, 8);
- sd->devtype = devtype;
+ memcpy(sd->scsi3addr, device->scsi3addr, 8);
+ memcpy(sd->vendor, device->vendor, sizeof(sd->vendor));
+ memcpy(sd->revision, device->revision, sizeof(sd->revision));
+ memcpy(sd->device_id, device->device_id, sizeof(sd->device_id));
+ sd->devtype = device->devtype;
+
ccissscsi[ctlr].ndevices++;
/* initially, (before registering with scsi layer) we don't
@@ -487,6 +491,22 @@ static void fixup_botched_add(int ctlr, char *scsi3addr)
CPQ_TAPE_UNLOCK(ctlr, flags);
}
+static int device_is_the_same(struct cciss_scsi_dev_t *dev1,
+ struct cciss_scsi_dev_t *dev2)
+{
+ return dev1->devtype == dev2->devtype &&
+ memcmp(dev1->scsi3addr, dev2->scsi3addr,
+ sizeof(dev1->scsi3addr)) == 0 &&
+ memcmp(dev1->device_id, dev2->device_id,
+ sizeof(dev1->device_id)) == 0 &&
+ memcmp(dev1->vendor, dev2->vendor,
+ sizeof(dev1->vendor)) == 0 &&
+ memcmp(dev1->model, dev2->model,
+ sizeof(dev1->model)) == 0 &&
+ memcmp(dev1->revision, dev2->revision,
+ sizeof(dev1->revision)) == 0;
+}
+
static int
adjust_cciss_scsi_table(int ctlr, int hostno,
struct cciss_scsi_dev_t sd[], int nsds)
@@ -532,7 +552,7 @@ adjust_cciss_scsi_table(int ctlr, int hostno,
for (j=0;j<nsds;j++) {
if (SCSI3ADDR_EQ(sd[j].scsi3addr,
csd->scsi3addr)) {
- if (sd[j].devtype == csd->devtype)
+ if (device_is_the_same(&sd[j], csd))
found=2;
else
found=1;
@@ -548,22 +568,26 @@ adjust_cciss_scsi_table(int ctlr, int hostno,
cciss_scsi_remove_entry(ctlr, hostno, i,
removed, &nremoved);
/* remove ^^^, hence i not incremented */
- }
- else if (found == 1) { /* device is different kind */
+ } else if (found == 1) { /* device is different in some way */
changes++;
- printk("cciss%d: device c%db%dt%dl%d type changed "
- "(device type now %s).\n",
- ctlr, hostno, csd->bus, csd->target, csd->lun,
- scsi_device_type(csd->devtype));
+ printk("cciss%d: device c%db%dt%dl%d has changed.\n",
+ ctlr, hostno, csd->bus, csd->target, csd->lun);
cciss_scsi_remove_entry(ctlr, hostno, i,
removed, &nremoved);
/* remove ^^^, hence i not incremented */
- if (cciss_scsi_add_entry(ctlr, hostno,
- &sd[j].scsi3addr[0], sd[j].devtype,
+ if (cciss_scsi_add_entry(ctlr, hostno, &sd[j],
added, &nadded) != 0)
/* we just removed one, so add can't fail. */
BUG();
csd->devtype = sd[j].devtype;
+ memcpy(csd->device_id, sd[j].device_id,
+ sizeof(csd->device_id));
+ memcpy(csd->vendor, sd[j].vendor,
+ sizeof(csd->vendor));
+ memcpy(csd->model, sd[j].model,
+ sizeof(csd->model));
+ memcpy(csd->revision, sd[j].revision,
+ sizeof(csd->revision));
} else /* device is same as it ever was, */
i++; /* so just move along. */
}
@@ -577,7 +601,7 @@ adjust_cciss_scsi_table(int ctlr, int hostno,
csd = &ccissscsi[ctlr].dev[j];
if (SCSI3ADDR_EQ(sd[i].scsi3addr,
csd->scsi3addr)) {
- if (sd[i].devtype == csd->devtype)
+ if (device_is_the_same(&sd[i], csd))
found=2; /* found device */
else
found=1; /* found a bug. */
@@ -586,16 +610,14 @@ adjust_cciss_scsi_table(int ctlr, int hostno,
}
if (!found) {
changes++;
- if (cciss_scsi_add_entry(ctlr, hostno,
-
- &sd[i].scsi3addr[0], sd[i].devtype,
+ if (cciss_scsi_add_entry(ctlr, hostno, &sd[i],
added, &nadded) != 0)
break;
} else if (found == 1) {
/* should never happen... */
changes++;
- printk("cciss%d: device unexpectedly changed type\n",
- ctlr);
+ printk(KERN_WARNING "cciss%d: device "
+ "unexpectedly changed\n", ctlr);
/* but if it does happen, we just ignore that device */
}
}
@@ -1012,7 +1034,8 @@ cciss_scsi_interpret_error(CommandList_struct *cp)
static int
cciss_scsi_do_inquiry(ctlr_info_t *c, unsigned char *scsi3addr,
- unsigned char *buf, unsigned char bufsize)
+ unsigned char page, unsigned char *buf,
+ unsigned char bufsize)
{
int rc;
CommandList_struct *cp;
@@ -1032,8 +1055,8 @@ cciss_scsi_do_inquiry(ctlr_info_t *c, unsigned char *scsi3addr,
ei = cp->err_info;
cdb[0] = CISS_INQUIRY;
- cdb[1] = 0;
- cdb[2] = 0;
+ cdb[1] = (page != 0);
+ cdb[2] = page;
cdb[3] = 0;
cdb[4] = bufsize;
cdb[5] = 0;
@@ -1053,6 +1076,25 @@ cciss_scsi_do_inquiry(ctlr_info_t *c, unsigned char *scsi3addr,
return rc;
}
+/* Get the device id from inquiry page 0x83 */
+static int cciss_scsi_get_device_id(ctlr_info_t *c, unsigned char *scsi3addr,
+ unsigned char *device_id, int buflen)
+{
+ int rc;
+ unsigned char *buf;
+
+ if (buflen > 16)
+ buflen = 16;
+ buf = kzalloc(64, GFP_KERNEL);
+ if (!buf)
+ return -1;
+ rc = cciss_scsi_do_inquiry(c, scsi3addr, 0x83, buf, 64);
+ if (rc == 0)
+ memcpy(device_id, &buf[8], buflen);
+ kfree(buf);
+ return rc != 0;
+}
+
static int
cciss_scsi_do_report_phys_luns(ctlr_info_t *c,
ReportLunData_struct *buf, int bufsize)
@@ -1142,25 +1184,21 @@ cciss_update_non_disk_devices(int cntl_num, int hostno)
ctlr_info_t *c;
__u32 num_luns=0;
unsigned char *ch;
- /* unsigned char found[CCISS_MAX_SCSI_DEVS_PER_HBA]; */
- struct cciss_scsi_dev_t currentsd[CCISS_MAX_SCSI_DEVS_PER_HBA];
+ struct cciss_scsi_dev_t *currentsd, *this_device;
int ncurrent=0;
int reportlunsize = sizeof(*ld_buff) + CISS_MAX_PHYS_LUN * 8;
int i;
c = (ctlr_info_t *) hba[cntl_num];
ld_buff = kzalloc(reportlunsize, GFP_KERNEL);
- if (ld_buff == NULL) {
- printk(KERN_ERR "cciss: out of memory\n");
- return;
- }
inq_buff = kmalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL);
- if (inq_buff == NULL) {
- printk(KERN_ERR "cciss: out of memory\n");
- kfree(ld_buff);
- return;
+ currentsd = kzalloc(sizeof(*currentsd) *
+ (CCISS_MAX_SCSI_DEVS_PER_HBA+1), GFP_KERNEL);
+ if (ld_buff == NULL || inq_buff == NULL || currentsd == NULL) {
+ printk(KERN_ERR "cciss: out of memory\n");
+ goto out;
}
-
+ this_device = &currentsd[CCISS_MAX_SCSI_DEVS_PER_HBA];
if (cciss_scsi_do_report_phys_luns(c, ld_buff, reportlunsize) == 0) {
ch = &ld_buff->LUNListLength[0];
num_luns = ((ch[0]<<24) | (ch[1]<<16) | (ch[2]<<8) | ch[3]) / 8;
@@ -1179,23 +1217,34 @@ cciss_update_non_disk_devices(int cntl_num, int hostno)
/* adjust our table of devices */
- for(i=0; i<num_luns; i++)
- {
- int devtype;
-
+ for (i = 0; i < num_luns; i++) {
/* for each physical lun, do an inquiry */
if (ld_buff->LUN[i][3] & 0xC0) continue;
memset(inq_buff, 0, OBDR_TAPE_INQ_SIZE);
memcpy(&scsi3addr[0], &ld_buff->LUN[i][0], 8);
- if (cciss_scsi_do_inquiry(hba[cntl_num], scsi3addr, inq_buff,
- (unsigned char) OBDR_TAPE_INQ_SIZE) != 0) {
+ if (cciss_scsi_do_inquiry(hba[cntl_num], scsi3addr, 0, inq_buff,
+ (unsigned char) OBDR_TAPE_INQ_SIZE) != 0)
/* Inquiry failed (msg printed already) */
- devtype = 0; /* so we will skip this device. */
- } else /* what kind of device is this? */
- devtype = (inq_buff[0] & 0x1f);
-
- switch (devtype)
+ continue; /* so we will skip this device. */
+
+ this_device->devtype = (inq_buff[0] & 0x1f);
+ this_device->bus = -1;
+ this_device->target = -1;
+ this_device->lun = -1;
+ memcpy(this_device->scsi3addr, scsi3addr, 8);
+ memcpy(this_device->vendor, &inq_buff[8],
+ sizeof(this_device->vendor));
+ memcpy(this_device->model, &inq_buff[16],
+ sizeof(this_device->model));
+ memcpy(this_device->revision, &inq_buff[32],
+ sizeof(this_device->revision));
+ memset(this_device->device_id, 0,
+ sizeof(this_device->device_id));
+ cciss_scsi_get_device_id(hba[cntl_num], scsi3addr,
+ this_device->device_id, sizeof(this_device->device_id));
+
+ switch (this_device->devtype)
{
case 0x05: /* CD-ROM */ {
@@ -1220,15 +1269,10 @@ cciss_update_non_disk_devices(int cntl_num, int hostno)
if (ncurrent >= CCISS_MAX_SCSI_DEVS_PER_HBA) {
printk(KERN_INFO "cciss%d: %s ignored, "
"too many devices.\n", cntl_num,
- scsi_device_type(devtype));
+ scsi_device_type(this_device->devtype));
break;
}
- memcpy(&currentsd[ncurrent].scsi3addr[0],
- &scsi3addr[0], 8);
- currentsd[ncurrent].devtype = devtype;
- currentsd[ncurrent].bus = -1;
- currentsd[ncurrent].target = -1;
- currentsd[ncurrent].lun = -1;
+ currentsd[ncurrent] = *this_device;
ncurrent++;
break;
default:
@@ -1240,6 +1284,7 @@ cciss_update_non_disk_devices(int cntl_num, int hostno)
out:
kfree(inq_buff);
kfree(ld_buff);
+ kfree(currentsd);
return;
}
diff --git a/drivers/block/cciss_scsi.h b/drivers/block/cciss_scsi.h
index d9c2c586502..7b750245ae7 100644
--- a/drivers/block/cciss_scsi.h
+++ b/drivers/block/cciss_scsi.h
@@ -66,6 +66,10 @@ struct cciss_scsi_dev_t {
int devtype;
int bus, target, lun; /* as presented to the OS */
unsigned char scsi3addr[8]; /* as presented to the HW */
+ unsigned char device_id[16]; /* from inquiry pg. 0x83 */
+ unsigned char vendor[8]; /* bytes 8-15 of inquiry data */
+ unsigned char model[16]; /* bytes 16-31 of inquiry data */
+ unsigned char revision[4]; /* bytes 32-35 of inquiry data */
};
struct cciss_scsi_hba_t {
diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
index 09c14341e6e..3d967525e9a 100644
--- a/drivers/block/cpqarray.c
+++ b/drivers/block/cpqarray.c
@@ -424,7 +424,7 @@ static int __init cpqarray_register_ctlr( int i, struct pci_dev *pdev)
hba[i]->pci_dev, NR_CMDS * sizeof(cmdlist_t),
&(hba[i]->cmd_pool_dhandle));
hba[i]->cmd_pool_bits = kcalloc(
- (NR_CMDS+BITS_PER_LONG-1)/BITS_PER_LONG, sizeof(unsigned long),
+ DIV_ROUND_UP(NR_CMDS, BITS_PER_LONG), sizeof(unsigned long),
GFP_KERNEL);
if (!hba[i]->cmd_pool_bits || !hba[i]->cmd_pool)
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 395f8ea7981..cf64ddf5d83 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -423,8 +423,15 @@ static struct floppy_raw_cmd *raw_cmd, default_raw_cmd;
* 1581's logical side 0 is on physical side 1, whereas the Sharp's logical
* side 0 is on physical side 0 (but with the misnamed sector IDs).
* 'stretch' should probably be renamed to something more general, like
- * 'options'. Other parameters should be self-explanatory (see also
- * setfdprm(8)).
+ * 'options'.
+ *
+ * Bits 2 through 9 of 'stretch' tell the number of the first sector.
+ * The LSB (bit 2) is flipped. For most disks, the first sector
+ * is 1 (represented by 0x00<<2). For some CP/M and music sampler
+ * disks (such as Ensoniq EPS 16plus) it is 0 (represented as 0x01<<2).
+ * For Amstrad CPC disks it is 0xC1 (represented as 0xC0<<2).
+ *
+ * Other parameters should be self-explanatory (see also setfdprm(8)).
*/
/*
Size
@@ -1355,20 +1362,20 @@ static void fdc_specify(void)
}
/* Convert step rate from microseconds to milliseconds and 4 bits */
- srt = 16 - (DP->srt * scale_dtr / 1000 + NOMINAL_DTR - 1) / NOMINAL_DTR;
+ srt = 16 - DIV_ROUND_UP(DP->srt * scale_dtr / 1000, NOMINAL_DTR);
if (slow_floppy) {
srt = srt / 4;
}
SUPBOUND(srt, 0xf);
INFBOUND(srt, 0);
- hlt = (DP->hlt * scale_dtr / 2 + NOMINAL_DTR - 1) / NOMINAL_DTR;
+ hlt = DIV_ROUND_UP(DP->hlt * scale_dtr / 2, NOMINAL_DTR);
if (hlt < 0x01)
hlt = 0x01;
else if (hlt > 0x7f)
hlt = hlt_max_code;
- hut = (DP->hut * scale_dtr / 16 + NOMINAL_DTR - 1) / NOMINAL_DTR;
+ hut = DIV_ROUND_UP(DP->hut * scale_dtr / 16, NOMINAL_DTR);
if (hut < 0x1)
hut = 0x1;
else if (hut > 0xf)
@@ -2236,9 +2243,9 @@ static void setup_format_params(int track)
}
}
}
- if (_floppy->stretch & FD_ZEROBASED) {
+ if (_floppy->stretch & FD_SECTBASEMASK) {
for (count = 0; count < F_SECT_PER_TRACK; count++)
- here[count].sect--;
+ here[count].sect += FD_SECTBASE(_floppy) - 1;
}
}
@@ -2385,7 +2392,7 @@ static void rw_interrupt(void)
#ifdef FLOPPY_SANITY_CHECK
if (nr_sectors / ssize >
- (in_sector_offset + current_count_sectors + ssize - 1) / ssize) {
+ DIV_ROUND_UP(in_sector_offset + current_count_sectors, ssize)) {
DPRINT("long rw: %x instead of %lx\n",
nr_sectors, current_count_sectors);
printk("rs=%d s=%d\n", R_SECTOR, SECTOR);
@@ -2649,7 +2656,7 @@ static int make_raw_rw_request(void)
}
HEAD = fsector_t / _floppy->sect;
- if (((_floppy->stretch & (FD_SWAPSIDES | FD_ZEROBASED)) ||
+ if (((_floppy->stretch & (FD_SWAPSIDES | FD_SECTBASEMASK)) ||
TESTF(FD_NEED_TWADDLE)) && fsector_t < _floppy->sect)
max_sector = _floppy->sect;
@@ -2679,7 +2686,7 @@ static int make_raw_rw_request(void)
CODE2SIZE;
SECT_PER_TRACK = _floppy->sect << 2 >> SIZECODE;
SECTOR = ((fsector_t % _floppy->sect) << 2 >> SIZECODE) +
- ((_floppy->stretch & FD_ZEROBASED) ? 0 : 1);
+ FD_SECTBASE(_floppy);
/* tracksize describes the size which can be filled up with sectors
* of size ssize.
@@ -3311,7 +3318,7 @@ static inline int set_geometry(unsigned int cmd, struct floppy_struct *g,
g->head <= 0 ||
g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) ||
/* check if reserved bits are set */
- (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_ZEROBASED)) != 0)
+ (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0)
return -EINVAL;
if (type) {
if (!capable(CAP_SYS_ADMIN))
@@ -3356,7 +3363,7 @@ static inline int set_geometry(unsigned int cmd, struct floppy_struct *g,
if (DRS->maxblock > user_params[drive].sect ||
DRS->maxtrack ||
((user_params[drive].sect ^ oldStretch) &
- (FD_SWAPSIDES | FD_ZEROBASED)))
+ (FD_SWAPSIDES | FD_SECTBASEMASK)))
invalidate_drive(bdev);
else
process_fd_request();
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 1778e4a2c67..7b3351260d5 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -403,7 +403,7 @@ static int nbd_do_it(struct nbd_device *lo)
BUG_ON(lo->magic != LO_MAGIC);
lo->pid = current->pid;
- ret = sysfs_create_file(&lo->disk->dev.kobj, &pid_attr.attr);
+ ret = sysfs_create_file(&disk_to_dev(lo->disk)->kobj, &pid_attr.attr);
if (ret) {
printk(KERN_ERR "nbd: sysfs_create_file failed!");
return ret;
@@ -412,7 +412,7 @@ static int nbd_do_it(struct nbd_device *lo)
while ((req = nbd_read_stat(lo)) != NULL)
nbd_end_request(req);
- sysfs_remove_file(&lo->disk->dev.kobj, &pid_attr.attr);
+ sysfs_remove_file(&disk_to_dev(lo->disk)->kobj, &pid_attr.attr);
return 0;
}
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index 29b7a648cc6..0e077150568 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -2544,7 +2544,7 @@ static int pkt_make_request(struct request_queue *q, struct bio *bio)
if (last_zone != zone) {
BUG_ON(last_zone != zone + pd->settings.size);
first_sectors = last_zone - bio->bi_sector;
- bp = bio_split(bio, bio_split_pool, first_sectors);
+ bp = bio_split(bio, first_sectors);
BUG_ON(!bp);
pkt_make_request(q, &bp->bio1);
pkt_make_request(q, &bp->bio2);
@@ -2911,7 +2911,7 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev)
if (!disk->queue)
goto out_mem2;
- pd->pkt_dev = MKDEV(disk->major, disk->first_minor);
+ pd->pkt_dev = MKDEV(pktdev_major, idx);
ret = pkt_new_dev(pd, dev);
if (ret)
goto out_new_dev;
diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c
index d797e209951..936466f62af 100644
--- a/drivers/block/ps3disk.c
+++ b/drivers/block/ps3disk.c
@@ -199,7 +199,8 @@ static void ps3disk_do_request(struct ps3_storage_device *dev,
if (blk_fs_request(req)) {
if (ps3disk_submit_request_sg(dev, req))
break;
- } else if (req->cmd_type == REQ_TYPE_FLUSH) {
+ } else if (req->cmd_type == REQ_TYPE_LINUX_BLOCK &&
+ req->cmd[0] == REQ_LB_OP_FLUSH) {
if (ps3disk_submit_flush_request(dev, req))
break;
} else {
@@ -257,7 +258,8 @@ static irqreturn_t ps3disk_interrupt(int irq, void *data)
return IRQ_HANDLED;
}
- if (req->cmd_type == REQ_TYPE_FLUSH) {
+ if (req->cmd_type == REQ_TYPE_LINUX_BLOCK &&
+ req->cmd[0] == REQ_LB_OP_FLUSH) {
read = 0;
num_sectors = req->hard_cur_sectors;
op = "flush";
@@ -405,7 +407,8 @@ static void ps3disk_prepare_flush(struct request_queue *q, struct request *req)
dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__);
- req->cmd_type = REQ_TYPE_FLUSH;
+ req->cmd_type = REQ_TYPE_LINUX_BLOCK;
+ req->cmd[0] = REQ_LB_OP_FLUSH;
}
static unsigned long ps3disk_mask;
@@ -538,7 +541,7 @@ static int ps3disk_remove(struct ps3_system_bus_device *_dev)
struct ps3disk_private *priv = dev->sbd.core.driver_data;
mutex_lock(&ps3disk_mask_mutex);
- __clear_bit(priv->gendisk->first_minor / PS3DISK_MINORS,
+ __clear_bit(MINOR(disk_devt(priv->gendisk)) / PS3DISK_MINORS,
&ps3disk_mask);
mutex_unlock(&ps3disk_mask_mutex);
del_gendisk(priv->gendisk);
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 42251095134..6ec5fc05278 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -47,20 +47,20 @@ static void blk_done(struct virtqueue *vq)
spin_lock_irqsave(&vblk->lock, flags);
while ((vbr = vblk->vq->vq_ops->get_buf(vblk->vq, &len)) != NULL) {
- int uptodate;
+ int error;
switch (vbr->status) {
case VIRTIO_BLK_S_OK:
- uptodate = 1;
+ error = 0;
break;
case VIRTIO_BLK_S_UNSUPP:
- uptodate = -ENOTTY;
+ error = -ENOTTY;
break;
default:
- uptodate = 0;
+ error = -EIO;
break;
}
- end_dequeued_request(vbr->req, uptodate);
+ __blk_end_request(vbr->req, error, blk_rq_bytes(vbr->req));
list_del(&vbr->list);
mempool_free(vbr, vblk->pool);
}
@@ -84,11 +84,11 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
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;
+ vbr->out_hdr.ioprio = req_get_ioprio(vbr->req);
} 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;
+ vbr->out_hdr.ioprio = req_get_ioprio(vbr->req);
} else {
/* We don't put anything else in the queue. */
BUG();
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index 3ca643cafcc..bff602ccccf 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -105,15 +105,17 @@ static DEFINE_SPINLOCK(blkif_io_lock);
#define GRANT_INVALID_REF 0
#define PARTS_PER_DISK 16
+#define PARTS_PER_EXT_DISK 256
#define BLKIF_MAJOR(dev) ((dev)>>8)
#define BLKIF_MINOR(dev) ((dev) & 0xff)
-#define DEV_NAME "xvd" /* name in /dev */
+#define EXT_SHIFT 28
+#define EXTENDED (1<<EXT_SHIFT)
+#define VDEV_IS_EXTENDED(dev) ((dev)&(EXTENDED))
+#define BLKIF_MINOR_EXT(dev) ((dev)&(~EXTENDED))
-/* Information about our VBDs. */
-#define MAX_VBDS 64
-static LIST_HEAD(vbds_list);
+#define DEV_NAME "xvd" /* name in /dev */
static int get_id_from_freelist(struct blkfront_info *info)
{
@@ -386,31 +388,60 @@ static int xlvbd_barrier(struct blkfront_info *info)
}
-static int xlvbd_alloc_gendisk(int minor, blkif_sector_t capacity,
- int vdevice, u16 vdisk_info, u16 sector_size,
- struct blkfront_info *info)
+static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
+ struct blkfront_info *info,
+ u16 vdisk_info, u16 sector_size)
{
struct gendisk *gd;
int nr_minors = 1;
int err = -ENODEV;
+ unsigned int offset;
+ int minor;
+ int nr_parts;
BUG_ON(info->gd != NULL);
BUG_ON(info->rq != NULL);
- if ((minor % PARTS_PER_DISK) == 0)
- nr_minors = PARTS_PER_DISK;
+ if ((info->vdevice>>EXT_SHIFT) > 1) {
+ /* this is above the extended range; something is wrong */
+ printk(KERN_WARNING "blkfront: vdevice 0x%x is above the extended range; ignoring\n", info->vdevice);
+ return -ENODEV;
+ }
+
+ if (!VDEV_IS_EXTENDED(info->vdevice)) {
+ minor = BLKIF_MINOR(info->vdevice);
+ nr_parts = PARTS_PER_DISK;
+ } else {
+ minor = BLKIF_MINOR_EXT(info->vdevice);
+ nr_parts = PARTS_PER_EXT_DISK;
+ }
+
+ if ((minor % nr_parts) == 0)
+ nr_minors = nr_parts;
gd = alloc_disk(nr_minors);
if (gd == NULL)
goto out;
- if (nr_minors > 1)
- sprintf(gd->disk_name, "%s%c", DEV_NAME,
- 'a' + minor / PARTS_PER_DISK);
- else
- sprintf(gd->disk_name, "%s%c%d", DEV_NAME,
- 'a' + minor / PARTS_PER_DISK,
- minor % PARTS_PER_DISK);
+ offset = minor / nr_parts;
+
+ if (nr_minors > 1) {
+ if (offset < 26)
+ sprintf(gd->disk_name, "%s%c", DEV_NAME, 'a' + offset);
+ else
+ sprintf(gd->disk_name, "%s%c%c", DEV_NAME,
+ 'a' + ((offset / 26)-1), 'a' + (offset % 26));
+ } else {
+ if (offset < 26)
+ sprintf(gd->disk_name, "%s%c%d", DEV_NAME,
+ 'a' + offset,
+ minor & (nr_parts - 1));
+ else
+ sprintf(gd->disk_name, "%s%c%c%d", DEV_NAME,
+ 'a' + ((offset / 26) - 1),
+ 'a' + (offset % 26),
+ minor & (nr_parts - 1));
+ }
gd->major = XENVBD_MAJOR;
gd->first_minor = minor;
@@ -699,8 +730,13 @@ static int blkfront_probe(struct xenbus_device *dev,
err = xenbus_scanf(XBT_NIL, dev->nodename,
"virtual-device", "%i", &vdevice);
if (err != 1) {
- xenbus_dev_fatal(dev, err, "reading virtual-device");
- return err;
+ /* go looking in the extended area instead */
+ err = xenbus_scanf(XBT_NIL, dev->nodename, "virtual-device-ext",
+ "%i", &vdevice);
+ if (err != 1) {
+ xenbus_dev_fatal(dev, err, "reading virtual-device");
+ return err;
+ }
}
info = kzalloc(sizeof(*info), GFP_KERNEL);
@@ -861,9 +897,7 @@ static void blkfront_connect(struct blkfront_info *info)
if (err)
info->feature_barrier = 0;
- err = xlvbd_alloc_gendisk(BLKIF_MINOR(info->vdevice),
- sectors, info->vdevice,
- binfo, sector_size, info);
+ err = xlvbd_alloc_gendisk(sectors, info, binfo, sector_size);
if (err) {
xenbus_dev_fatal(info->xbdev, err, "xlvbd_add at %s",
info->xbdev->otherend);
diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c
index 1e55a658e6c..32f3a8ed8d3 100644
--- a/drivers/bluetooth/bpa10x.c
+++ b/drivers/bluetooth/bpa10x.c
@@ -256,7 +256,6 @@ static inline int bpa10x_submit_intr_urb(struct hci_dev *hdev)
BT_ERR("%s urb %p submission failed (%d)",
hdev->name, urb, -err);
usb_unanchor_urb(urb);
- kfree(buf);
}
usb_free_urb(urb);
@@ -298,7 +297,6 @@ static inline int bpa10x_submit_bulk_urb(struct hci_dev *hdev)
BT_ERR("%s urb %p submission failed (%d)",
hdev->name, urb, -err);
usb_unanchor_urb(urb);
- kfree(buf);
}
usb_free_urb(urb);
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 6a010681ecf..af472e05273 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -102,14 +102,19 @@ static struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x0a5c, 0x2101), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU },
/* Broadcom BCM2046 */
+ { USB_DEVICE(0x0a5c, 0x2146), .driver_info = BTUSB_RESET },
{ USB_DEVICE(0x0a5c, 0x2151), .driver_info = BTUSB_RESET },
+ /* Apple MacBook Pro with Broadcom chip */
+ { USB_DEVICE(0x05ac, 0x820f), .driver_info = BTUSB_RESET },
+
/* IBM/Lenovo ThinkPad with Broadcom chip */
{ USB_DEVICE(0x0a5c, 0x201e), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU },
{ USB_DEVICE(0x0a5c, 0x2110), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU },
/* Targus ACB10US */
{ USB_DEVICE(0x0a5c, 0x2100), .driver_info = BTUSB_RESET },
+ { USB_DEVICE(0x0a5c, 0x2154), .driver_info = BTUSB_RESET },
/* ANYCOM Bluetooth USB-200 and USB-250 */
{ USB_DEVICE(0x0a5c, 0x2111), .driver_info = BTUSB_RESET },
@@ -147,6 +152,9 @@ static struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x050d, 0x0012), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU },
{ USB_DEVICE(0x050d, 0x0013), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU },
+ /* Belkin F8T016 device */
+ { USB_DEVICE(0x050d, 0x016a), .driver_info = BTUSB_RESET },
+
/* Digianswer devices */
{ USB_DEVICE(0x08fd, 0x0001), .driver_info = BTUSB_DIGIANSWER },
{ USB_DEVICE(0x08fd, 0x0002), .driver_info = BTUSB_IGNORE },
@@ -169,6 +177,7 @@ static struct usb_device_id blacklist_table[] = {
struct btusb_data {
struct hci_dev *hdev;
struct usb_device *udev;
+ struct usb_interface *intf;
struct usb_interface *isoc;
spinlock_t lock;
@@ -267,7 +276,6 @@ static int btusb_submit_intr_urb(struct hci_dev *hdev)
BT_ERR("%s urb %p submission failed (%d)",
hdev->name, urb, -err);
usb_unanchor_urb(urb);
- kfree(buf);
}
usb_free_urb(urb);
@@ -350,7 +358,6 @@ static int btusb_submit_bulk_urb(struct hci_dev *hdev)
BT_ERR("%s urb %p submission failed (%d)",
hdev->name, urb, -err);
usb_unanchor_urb(urb);
- kfree(buf);
}
usb_free_urb(urb);
@@ -471,7 +478,6 @@ static int btusb_submit_isoc_urb(struct hci_dev *hdev)
BT_ERR("%s urb %p submission failed (%d)",
hdev->name, urb, -err);
usb_unanchor_urb(urb);
- kfree(buf);
}
usb_free_urb(urb);
@@ -516,7 +522,7 @@ static int btusb_open(struct hci_dev *hdev)
err = btusb_submit_intr_urb(hdev);
if (err < 0) {
- clear_bit(BTUSB_INTR_RUNNING, &hdev->flags);
+ clear_bit(BTUSB_INTR_RUNNING, &data->flags);
clear_bit(HCI_RUNNING, &hdev->flags);
}
@@ -532,8 +538,10 @@ static int btusb_close(struct hci_dev *hdev)
if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
return 0;
+ cancel_work_sync(&data->work);
+
clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
- usb_kill_anchored_urbs(&data->intr_anchor);
+ usb_kill_anchored_urbs(&data->isoc_anchor);
clear_bit(BTUSB_BULK_RUNNING, &data->flags);
usb_kill_anchored_urbs(&data->bulk_anchor);
@@ -821,6 +829,7 @@ static int btusb_probe(struct usb_interface *intf,
}
data->udev = interface_to_usbdev(intf);
+ data->intf = intf;
spin_lock_init(&data->lock);
@@ -889,7 +898,7 @@ static int btusb_probe(struct usb_interface *intf,
if (data->isoc) {
err = usb_driver_claim_interface(&btusb_driver,
- data->isoc, NULL);
+ data->isoc, data);
if (err < 0) {
hci_free_dev(hdev);
kfree(data);
@@ -921,13 +930,22 @@ static void btusb_disconnect(struct usb_interface *intf)
hdev = data->hdev;
- if (data->isoc)
- usb_driver_release_interface(&btusb_driver, data->isoc);
+ __hci_dev_hold(hdev);
- usb_set_intfdata(intf, NULL);
+ usb_set_intfdata(data->intf, NULL);
+
+ if (data->isoc)
+ usb_set_intfdata(data->isoc, NULL);
hci_unregister_dev(hdev);
+ if (intf == data->isoc)
+ usb_driver_release_interface(&btusb_driver, data->intf);
+ else if (data->isoc)
+ usb_driver_release_interface(&btusb_driver, data->isoc);
+
+ __hci_dev_put(hdev);
+
hci_free_dev(hdev);
}
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index 74031de517e..d47f2f80acc 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -2097,7 +2097,7 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf,
len = nr * CD_FRAMESIZE_RAW;
- ret = blk_rq_map_user(q, rq, ubuf, len);
+ ret = blk_rq_map_user(q, rq, NULL, ubuf, len, GFP_KERNEL);
if (ret)
break;
diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c
index 1231d95aa69..d6ba77a2dd7 100644
--- a/drivers/cdrom/gdrom.c
+++ b/drivers/cdrom/gdrom.c
@@ -624,14 +624,14 @@ static void gdrom_readdisk_dma(struct work_struct *work)
ctrl_outb(1, GDROM_DMA_STATUS_REG);
wait_event_interruptible_timeout(request_queue,
gd.transfer == 0, GDROM_DEFAULT_TIMEOUT);
- err = gd.transfer;
+ err = gd.transfer ? -EIO : 0;
gd.transfer = 0;
gd.pending = 0;
/* now seek to take the request spinlock
* before handling ending the request */
spin_lock(&gdrom_lock);
list_del_init(&req->queuelist);
- end_dequeued_request(req, 1 - err);
+ __blk_end_request(req, err, blk_rq_bytes(req));
}
spin_unlock(&gdrom_lock);
kfree(read_command);
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 1838aa3d24f..6af435b8986 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -407,7 +407,7 @@ struct entropy_store {
/* read-write data: */
spinlock_t lock;
unsigned add_ptr;
- int entropy_count;
+ int entropy_count; /* Must at no time exceed ->POOLBITS! */
int input_rotate;
};
@@ -520,6 +520,7 @@ static void mix_pool_bytes(struct entropy_store *r, const void *in, int bytes)
static void credit_entropy_bits(struct entropy_store *r, int nbits)
{
unsigned long flags;
+ int entropy_count;
if (!nbits)
return;
@@ -527,20 +528,20 @@ static void credit_entropy_bits(struct entropy_store *r, int nbits)
spin_lock_irqsave(&r->lock, flags);
DEBUG_ENT("added %d entropy credits to %s\n", nbits, r->name);
- r->entropy_count += nbits;
- if (r->entropy_count < 0) {
+ entropy_count = r->entropy_count;
+ entropy_count += nbits;
+ if (entropy_count < 0) {
DEBUG_ENT("negative entropy/overflow\n");
- r->entropy_count = 0;
- } else if (r->entropy_count > r->poolinfo->POOLBITS)
- r->entropy_count = r->poolinfo->POOLBITS;
+ entropy_count = 0;
+ } else if (entropy_count > r->poolinfo->POOLBITS)
+ entropy_count = r->poolinfo->POOLBITS;
+ r->entropy_count = entropy_count;
/* should we wake readers? */
- if (r == &input_pool &&
- r->entropy_count >= random_read_wakeup_thresh) {
+ if (r == &input_pool && entropy_count >= random_read_wakeup_thresh) {
wake_up_interruptible(&random_read_wait);
kill_fasync(&fasync, SIGIO, POLL_IN);
}
-
spin_unlock_irqrestore(&r->lock, flags);
}
@@ -660,10 +661,10 @@ void add_disk_randomness(struct gendisk *disk)
if (!disk || !disk->random)
return;
/* first major is 1, so we get >= 0x200 here */
- DEBUG_ENT("disk event %d:%d\n", disk->major, disk->first_minor);
+ DEBUG_ENT("disk event %d:%d\n",
+ MAJOR(disk_devt(disk)), MINOR(disk_devt(disk)));
- add_timer_randomness(disk->random,
- 0x100 + MKDEV(disk->major, disk->first_minor));
+ add_timer_randomness(disk->random, 0x100 + disk_devt(disk));
}
#endif
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index daeb8f76697..e4dce870954 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -695,13 +695,23 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line)
{
struct tty_driver *p, *res = NULL;
int tty_line = 0;
+ int len;
char *str;
+ for (str = name; *str; str++)
+ if ((*str >= '0' && *str <= '9') || *str == ',')
+ break;
+ if (!*str)
+ return NULL;
+
+ len = str - name;
+ tty_line = simple_strtoul(str, &str, 10);
+
mutex_lock(&tty_mutex);
/* Search through the tty devices to look for a match */
list_for_each_entry(p, &tty_drivers, tty_drivers) {
- str = name + strlen(p->name);
- tty_line = simple_strtoul(str, &str, 10);
+ if (strncmp(name, p->name, len) != 0)
+ continue;
if (*str == ',')
str++;
if (*str == '\0')
diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c
index 5ca1d80de18..71d2ac4e3f4 100644
--- a/drivers/clocksource/acpi_pm.c
+++ b/drivers/clocksource/acpi_pm.c
@@ -21,6 +21,7 @@
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/pci.h>
+#include <linux/delay.h>
#include <asm/io.h>
/*
@@ -151,13 +152,13 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_LE,
*/
static int verify_pmtmr_rate(void)
{
- u32 value1, value2;
+ cycle_t value1, value2;
unsigned long count, delta;
mach_prepare_counter();
- value1 = read_pmtmr();
+ value1 = clocksource_acpi_pm.read();
mach_countup(&count);
- value2 = read_pmtmr();
+ value2 = clocksource_acpi_pm.read();
delta = (value2 - value1) & ACPI_PM_MASK;
/* Check that the PMTMR delta is within 5% of what we expect */
@@ -175,10 +176,15 @@ static int verify_pmtmr_rate(void)
#define verify_pmtmr_rate() (0)
#endif
+/* Number of monotonicity checks to perform during initialization */
+#define ACPI_PM_MONOTONICITY_CHECKS 10
+/* Number of reads we try to get two different values */
+#define ACPI_PM_READ_CHECKS 10000
+
static int __init init_acpi_pm_clocksource(void)
{
- u32 value1, value2;
- unsigned int i;
+ cycle_t value1, value2;
+ unsigned int i, j = 0;
if (!pmtmr_ioport)
return -ENODEV;
@@ -187,24 +193,29 @@ static int __init init_acpi_pm_clocksource(void)
clocksource_acpi_pm.shift);
/* "verify" this timing source: */
- value1 = read_pmtmr();
- for (i = 0; i < 10000; i++) {
- value2 = read_pmtmr();
- if (value2 == value1)
- continue;
- if (value2 > value1)
- goto pm_good;
- if ((value2 < value1) && ((value2) < 0xFFF))
- goto pm_good;
- printk(KERN_INFO "PM-Timer had inconsistent results:"
- " 0x%#x, 0x%#x - aborting.\n", value1, value2);
- return -EINVAL;
+ for (j = 0; j < ACPI_PM_MONOTONICITY_CHECKS; j++) {
+ udelay(100 * j);
+ value1 = clocksource_acpi_pm.read();
+ for (i = 0; i < ACPI_PM_READ_CHECKS; i++) {
+ value2 = clocksource_acpi_pm.read();
+ if (value2 == value1)
+ continue;
+ if (value2 > value1)
+ break;
+ if ((value2 < value1) && ((value2) < 0xFFF))
+ break;
+ printk(KERN_INFO "PM-Timer had inconsistent results:"
+ " 0x%#llx, 0x%#llx - aborting.\n",
+ value1, value2);
+ return -EINVAL;
+ }
+ if (i == ACPI_PM_READ_CHECKS) {
+ printk(KERN_INFO "PM-Timer failed consistency check "
+ " (0x%#llx) - aborting.\n", value1);
+ return -ENODEV;
+ }
}
- printk(KERN_INFO "PM-Timer had no reasonable result:"
- " 0x%#x - aborting.\n", value1);
- return -ENODEV;
-pm_good:
if (verify_pmtmr_rate() != 0)
return -ENODEV;
diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
index ee827a7f7c6..b6ad3ac5916 100644
--- a/drivers/crypto/talitos.c
+++ b/drivers/crypto/talitos.c
@@ -1157,6 +1157,8 @@ static int aead_authenc_givencrypt(
edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_MODE0_ENCRYPT;
memcpy(req->giv, ctx->iv, crypto_aead_ivsize(authenc));
+ /* avoid consecutive packets going out with same IV */
+ *(__be64 *)req->giv ^= cpu_to_be64(req->seq);
return ipsec_esp(edesc, areq, req->giv, req->seq,
ipsec_esp_encrypt_done);
@@ -1449,6 +1451,8 @@ static int talitos_probe(struct of_device *ofdev,
priv->ofdev = ofdev;
+ INIT_LIST_HEAD(&priv->alg_list);
+
tasklet_init(&priv->done_task, talitos_done, (unsigned long)dev);
tasklet_init(&priv->error_task, talitos_error, (unsigned long)dev);
@@ -1575,8 +1579,6 @@ static int talitos_probe(struct of_device *ofdev,
}
/* register crypto algorithms the device supports */
- INIT_LIST_HEAD(&priv->alg_list);
-
for (i = 0; i < ARRAY_SIZE(driver_algs); i++) {
if (hw_supports(dev, driver_algs[i].desc_hdr_template)) {
struct talitos_crypto_alg *t_alg;
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 94df9177124..0778d99aea7 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -364,7 +364,7 @@ static void dw_dma_tasklet(unsigned long data)
int i;
status_block = dma_readl(dw, RAW.BLOCK);
- status_xfer = dma_readl(dw, RAW.BLOCK);
+ status_xfer = dma_readl(dw, RAW.XFER);
status_err = dma_readl(dw, RAW.ERROR);
dev_vdbg(dw->dma.dev, "tasklet: status_block=%x status_err=%x\n",
diff --git a/drivers/firmware/iscsi_ibft.c b/drivers/firmware/iscsi_ibft.c
index 8024e3bfd87..b91ef63126e 100644
--- a/drivers/firmware/iscsi_ibft.c
+++ b/drivers/firmware/iscsi_ibft.c
@@ -669,8 +669,7 @@ static int __init ibft_register_kobjects(struct ibft_table_header *header,
control = (void *)header + sizeof(*header);
end = (void *)control + control->hdr.length;
- eot_offset = (void *)header + header->length -
- (void *)control - sizeof(*header);
+ eot_offset = (void *)header + header->length - (void *)control;
rc = ibft_verify_hdr("control", (struct ibft_hdr *)control, id_control,
sizeof(*control));
diff --git a/drivers/gpu/drm/radeon/radeon_cp.c b/drivers/gpu/drm/radeon/radeon_cp.c
index 3331f88dcfb..248ab4a7d39 100644
--- a/drivers/gpu/drm/radeon/radeon_cp.c
+++ b/drivers/gpu/drm/radeon/radeon_cp.c
@@ -223,7 +223,7 @@ static int radeon_do_wait_for_fifo(drm_radeon_private_t * dev_priv, int entries)
return 0;
DRM_UDELAY(1);
}
- DRM_INFO("wait for fifo failed status : 0x%08X 0x%08X\n",
+ DRM_DEBUG("wait for fifo failed status : 0x%08X 0x%08X\n",
RADEON_READ(RADEON_RBBM_STATUS),
RADEON_READ(R300_VAP_CNTL_STATUS));
@@ -252,7 +252,7 @@ static int radeon_do_wait_for_idle(drm_radeon_private_t * dev_priv)
}
DRM_UDELAY(1);
}
- DRM_INFO("wait idle failed status : 0x%08X 0x%08X\n",
+ DRM_DEBUG("wait idle failed status : 0x%08X 0x%08X\n",
RADEON_READ(RADEON_RBBM_STATUS),
RADEON_READ(R300_VAP_CNTL_STATUS));
diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c
index d568c65c137..d9e7a49d6cb 100644
--- a/drivers/hwmon/abituguru3.c
+++ b/drivers/hwmon/abituguru3.c
@@ -279,7 +279,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
{ "OTES1 Fan", 36, 2, 60, 1, 0 },
{ NULL, 0, 0, 0, 0, 0 } }
},
- { 0x0011, NULL /* Abit AT8 32X, need DMI string */, {
+ { 0x0011, "AT8 32X(ATI RD580-ULI M1575)", {
{ "CPU Core", 0, 0, 10, 1, 0 },
{ "DDR", 1, 0, 20, 1, 0 },
{ "DDR VTT", 2, 0, 10, 1, 0 },
@@ -303,6 +303,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
{ "SYS Fan", 34, 2, 60, 1, 0 },
{ "AUX1 Fan", 35, 2, 60, 1, 0 },
{ "AUX2 Fan", 36, 2, 60, 1, 0 },
+ { "AUX3 Fan", 37, 2, 60, 1, 0 },
{ NULL, 0, 0, 0, 0, 0 } }
},
{ 0x0012, NULL /* Abit AN8 32X, need DMI string */, {
diff --git a/drivers/hwmon/ad7414.c b/drivers/hwmon/ad7414.c
index ce8d94fbfd7..bfda8c80ef2 100644
--- a/drivers/hwmon/ad7414.c
+++ b/drivers/hwmon/ad7414.c
@@ -69,7 +69,7 @@ static inline int ad7414_write(struct i2c_client *client, u8 reg, u8 value)
return i2c_smbus_write_byte_data(client, reg, value);
}
-struct ad7414_data *ad7414_update_device(struct device *dev)
+static struct ad7414_data *ad7414_update_device(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct ad7414_data *data = i2c_get_clientdata(client);
diff --git a/drivers/hwmon/atxp1.c b/drivers/hwmon/atxp1.c
index d191118ba0c..d6b490d3e36 100644
--- a/drivers/hwmon/atxp1.c
+++ b/drivers/hwmon/atxp1.c
@@ -31,7 +31,7 @@
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("System voltages control via Attansic ATXP1");
-MODULE_VERSION("0.6.2");
+MODULE_VERSION("0.6.3");
MODULE_AUTHOR("Sebastian Witt <se.witt@gmx.net>");
#define ATXP1_VID 0x00
@@ -289,16 +289,16 @@ static int atxp1_detect(struct i2c_client *new_client, int kind,
if (!((i2c_smbus_read_byte_data(new_client, 0x3e) == 0) &&
(i2c_smbus_read_byte_data(new_client, 0x3f) == 0) &&
(i2c_smbus_read_byte_data(new_client, 0xfe) == 0) &&
- (i2c_smbus_read_byte_data(new_client, 0xff) == 0) )) {
+ (i2c_smbus_read_byte_data(new_client, 0xff) == 0)))
+ return -ENODEV;
- /* No vendor ID, now checking if registers 0x10,0x11 (non-existent)
- * showing the same as register 0x00 */
- temp = i2c_smbus_read_byte_data(new_client, 0x00);
+ /* No vendor ID, now checking if registers 0x10,0x11 (non-existent)
+ * showing the same as register 0x00 */
+ temp = i2c_smbus_read_byte_data(new_client, 0x00);
- if (!((i2c_smbus_read_byte_data(new_client, 0x10) == temp) &&
- (i2c_smbus_read_byte_data(new_client, 0x11) == temp) ))
- return -ENODEV;
- }
+ if (!((i2c_smbus_read_byte_data(new_client, 0x10) == temp) &&
+ (i2c_smbus_read_byte_data(new_client, 0x11) == temp)))
+ return -ENODEV;
/* Get VRM */
temp = vid_which_vrm();
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 30cdb095677..d793cc01199 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -46,6 +46,8 @@
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
+#include <linux/string.h>
+#include <linux/dmi.h>
#include <asm/io.h>
#define DRVNAME "it87"
@@ -236,6 +238,8 @@ struct it87_sio_data {
/* Values read from Super-I/O config space */
u8 revision;
u8 vid_value;
+ /* Values set based on DMI strings */
+ u8 skip_pwm;
};
/* For each registered chip, we need to keep some data in memory.
@@ -273,10 +277,10 @@ struct it87_data {
static inline int has_16bit_fans(const struct it87_data *data)
{
/* IT8705F Datasheet 0.4.1, 3h == Version G.
- IT8712F Datasheet 0.9.1, section 8.3.5 indicates 7h == Version I.
+ IT8712F Datasheet 0.9.1, section 8.3.5 indicates 8h == Version J.
These are the first revisions with 16bit tachometer support. */
return (data->type == it87 && data->revision >= 0x03)
- || (data->type == it8712 && data->revision >= 0x07)
+ || (data->type == it8712 && data->revision >= 0x08)
|| data->type == it8716
|| data->type == it8718;
}
@@ -964,6 +968,7 @@ static int __init it87_find(unsigned short *address,
{
int err = -ENODEV;
u16 chip_type;
+ const char *board_vendor, *board_name;
superio_enter();
chip_type = force_id ? force_id : superio_inw(DEVID);
@@ -1022,6 +1027,24 @@ static int __init it87_find(unsigned short *address,
pr_info("it87: in7 is VCCH (+5V Stand-By)\n");
}
+ /* Disable specific features based on DMI strings */
+ board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
+ board_name = dmi_get_system_info(DMI_BOARD_NAME);
+ if (board_vendor && board_name) {
+ if (strcmp(board_vendor, "nVIDIA") == 0
+ && strcmp(board_name, "FN68PT") == 0) {
+ /* On the Shuttle SN68PT, FAN_CTL2 is apparently not
+ connected to a fan, but to something else. One user
+ has reported instant system power-off when changing
+ the PWM2 duty cycle, so we disable it.
+ I use the board name string as the trigger in case
+ the same board is ever used in other systems. */
+ pr_info("it87: Disabling pwm2 due to "
+ "hardware constraints\n");
+ sio_data->skip_pwm = (1 << 1);
+ }
+ }
+
exit:
superio_exit();
return err;
@@ -1168,25 +1191,33 @@ static int __devinit it87_probe(struct platform_device *pdev)
}
if (enable_pwm_interface) {
- if ((err = device_create_file(dev,
- &sensor_dev_attr_pwm1_enable.dev_attr))
- || (err = device_create_file(dev,
- &sensor_dev_attr_pwm2_enable.dev_attr))
- || (err = device_create_file(dev,
- &sensor_dev_attr_pwm3_enable.dev_attr))
- || (err = device_create_file(dev,
- &sensor_dev_attr_pwm1.dev_attr))
- || (err = device_create_file(dev,
- &sensor_dev_attr_pwm2.dev_attr))
- || (err = device_create_file(dev,
- &sensor_dev_attr_pwm3.dev_attr))
- || (err = device_create_file(dev,
- &dev_attr_pwm1_freq))
- || (err = device_create_file(dev,
- &dev_attr_pwm2_freq))
- || (err = device_create_file(dev,
- &dev_attr_pwm3_freq)))
- goto ERROR4;
+ if (!(sio_data->skip_pwm & (1 << 0))) {
+ if ((err = device_create_file(dev,
+ &sensor_dev_attr_pwm1_enable.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_pwm1.dev_attr))
+ || (err = device_create_file(dev,
+ &dev_attr_pwm1_freq)))
+ goto ERROR4;
+ }
+ if (!(sio_data->skip_pwm & (1 << 1))) {
+ if ((err = device_create_file(dev,
+ &sensor_dev_attr_pwm2_enable.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_pwm2.dev_attr))
+ || (err = device_create_file(dev,
+ &dev_attr_pwm2_freq)))
+ goto ERROR4;
+ }
+ if (!(sio_data->skip_pwm & (1 << 2))) {
+ if ((err = device_create_file(dev,
+ &sensor_dev_attr_pwm3_enable.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_pwm3.dev_attr))
+ || (err = device_create_file(dev,
+ &dev_attr_pwm3_freq)))
+ goto ERROR4;
+ }
}
if (data->type == it8712 || data->type == it8716
@@ -1546,6 +1577,7 @@ static int __init sm_it87_init(void)
unsigned short isa_address=0;
struct it87_sio_data sio_data;
+ memset(&sio_data, 0, sizeof(struct it87_sio_data));
err = it87_find(&isa_address, &sio_data);
if (err)
return err;
diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c
index 22f6d5c00d8..0e7b1c6724a 100644
--- a/drivers/i2c/busses/i2c-powermac.c
+++ b/drivers/i2c/busses/i2c-powermac.c
@@ -180,7 +180,7 @@ static const struct i2c_algorithm i2c_powermac_algorithm = {
};
-static int i2c_powermac_remove(struct platform_device *dev)
+static int __devexit i2c_powermac_remove(struct platform_device *dev)
{
struct i2c_adapter *adapter = platform_get_drvdata(dev);
struct pmac_i2c_bus *bus = i2c_get_adapdata(adapter);
@@ -200,7 +200,7 @@ static int i2c_powermac_remove(struct platform_device *dev)
}
-static int __devexit i2c_powermac_probe(struct platform_device *dev)
+static int __devinit i2c_powermac_probe(struct platform_device *dev)
{
struct pmac_i2c_bus *bus = dev->dev.platform_data;
struct device_node *parent = NULL;
diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c
index 840e634fa31..640cbb23732 100644
--- a/drivers/i2c/busses/i2c-sh_mobile.c
+++ b/drivers/i2c/busses/i2c-sh_mobile.c
@@ -31,13 +31,84 @@
#include <linux/clk.h>
#include <linux/io.h>
+/* Transmit operation: */
+/* */
+/* 0 byte transmit */
+/* BUS: S A8 ACK P */
+/* IRQ: DTE WAIT */
+/* ICIC: */
+/* ICCR: 0x94 0x90 */
+/* ICDR: A8 */
+/* */
+/* 1 byte transmit */
+/* BUS: S A8 ACK D8(1) ACK P */
+/* IRQ: DTE WAIT WAIT */
+/* ICIC: -DTE */
+/* ICCR: 0x94 0x90 */
+/* ICDR: A8 D8(1) */
+/* */
+/* 2 byte transmit */
+/* BUS: S A8 ACK D8(1) ACK D8(2) ACK P */
+/* IRQ: DTE WAIT WAIT WAIT */
+/* ICIC: -DTE */
+/* ICCR: 0x94 0x90 */
+/* ICDR: A8 D8(1) D8(2) */
+/* */
+/* 3 bytes or more, +---------+ gets repeated */
+/* */
+/* */
+/* Receive operation: */
+/* */
+/* 0 byte receive - not supported since slave may hold SDA low */
+/* */
+/* 1 byte receive [TX] | [RX] */
+/* BUS: S A8 ACK | D8(1) ACK P */
+/* IRQ: DTE WAIT | WAIT DTE */
+/* ICIC: -DTE | +DTE */
+/* ICCR: 0x94 0x81 | 0xc0 */
+/* ICDR: A8 | D8(1) */
+/* */
+/* 2 byte receive [TX]| [RX] */
+/* BUS: S A8 ACK | D8(1) ACK D8(2) ACK P */
+/* IRQ: DTE WAIT | WAIT WAIT DTE */
+/* ICIC: -DTE | +DTE */
+/* ICCR: 0x94 0x81 | 0xc0 */
+/* ICDR: A8 | D8(1) D8(2) */
+/* */
+/* 3 byte receive [TX] | [RX] */
+/* BUS: S A8 ACK | D8(1) ACK D8(2) ACK D8(3) ACK P */
+/* IRQ: DTE WAIT | WAIT WAIT WAIT DTE */
+/* ICIC: -DTE | +DTE */
+/* ICCR: 0x94 0x81 | 0xc0 */
+/* ICDR: A8 | D8(1) D8(2) D8(3) */
+/* */
+/* 4 bytes or more, this part is repeated +---------+ */
+/* */
+/* */
+/* Interrupt order and BUSY flag */
+/* ___ _ */
+/* SDA ___\___XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXAAAAAAAAA___/ */
+/* SCL \_/1\_/2\_/3\_/4\_/5\_/6\_/7\_/8\___/9\_____/ */
+/* */
+/* S D7 D6 D5 D4 D3 D2 D1 D0 P */
+/* ___ */
+/* WAIT IRQ ________________________________/ \___________ */
+/* TACK IRQ ____________________________________/ \_______ */
+/* DTE IRQ __________________________________________/ \_ */
+/* AL IRQ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
+/* _______________________________________________ */
+/* BUSY __/ \_ */
+/* */
+
enum sh_mobile_i2c_op {
OP_START = 0,
- OP_TX_ONLY,
+ OP_TX_FIRST,
+ OP_TX,
OP_TX_STOP,
OP_TX_TO_RX,
- OP_RX_ONLY,
+ OP_RX,
OP_RX_STOP,
+ OP_RX_STOP_DATA,
};
struct sh_mobile_i2c_data {
@@ -127,25 +198,34 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd,
spin_lock_irqsave(&pd->lock, flags);
switch (op) {
- case OP_START:
+ case OP_START: /* issue start and trigger DTE interrupt */
iowrite8(0x94, ICCR(pd));
break;
- case OP_TX_ONLY:
+ case OP_TX_FIRST: /* disable DTE interrupt and write data */
+ iowrite8(ICIC_WAITE | ICIC_ALE | ICIC_TACKE, ICIC(pd));
iowrite8(data, ICDR(pd));
break;
- case OP_TX_STOP:
+ case OP_TX: /* write data */
iowrite8(data, ICDR(pd));
- iowrite8(0x90, ICCR(pd));
- iowrite8(ICIC_ALE | ICIC_TACKE, ICIC(pd));
break;
- case OP_TX_TO_RX:
+ case OP_TX_STOP: /* write data and issue a stop afterwards */
iowrite8(data, ICDR(pd));
+ iowrite8(0x90, ICCR(pd));
+ break;
+ case OP_TX_TO_RX: /* select read mode */
iowrite8(0x81, ICCR(pd));
break;
- case OP_RX_ONLY:
+ case OP_RX: /* just read data */
ret = ioread8(ICDR(pd));
break;
- case OP_RX_STOP:
+ case OP_RX_STOP: /* enable DTE interrupt, issue stop */
+ iowrite8(ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE,
+ ICIC(pd));
+ iowrite8(0xc0, ICCR(pd));
+ break;
+ case OP_RX_STOP_DATA: /* enable DTE interrupt, read data, issue stop */
+ iowrite8(ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE,
+ ICIC(pd));
ret = ioread8(ICDR(pd));
iowrite8(0xc0, ICCR(pd));
break;
@@ -157,58 +237,120 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd,
return ret;
}
+static int sh_mobile_i2c_is_first_byte(struct sh_mobile_i2c_data *pd)
+{
+ if (pd->pos == -1)
+ return 1;
+
+ return 0;
+}
+
+static int sh_mobile_i2c_is_last_byte(struct sh_mobile_i2c_data *pd)
+{
+ if (pd->pos == (pd->msg->len - 1))
+ return 1;
+
+ return 0;
+}
+
+static void sh_mobile_i2c_get_data(struct sh_mobile_i2c_data *pd,
+ unsigned char *buf)
+{
+ switch (pd->pos) {
+ case -1:
+ *buf = (pd->msg->addr & 0x7f) << 1;
+ *buf |= (pd->msg->flags & I2C_M_RD) ? 1 : 0;
+ break;
+ default:
+ *buf = pd->msg->buf[pd->pos];
+ }
+}
+
+static int sh_mobile_i2c_isr_tx(struct sh_mobile_i2c_data *pd)
+{
+ unsigned char data;
+
+ if (pd->pos == pd->msg->len)
+ return 1;
+
+ sh_mobile_i2c_get_data(pd, &data);
+
+ if (sh_mobile_i2c_is_last_byte(pd))
+ i2c_op(pd, OP_TX_STOP, data);
+ else if (sh_mobile_i2c_is_first_byte(pd))
+ i2c_op(pd, OP_TX_FIRST, data);
+ else
+ i2c_op(pd, OP_TX, data);
+
+ pd->pos++;
+ return 0;
+}
+
+static int sh_mobile_i2c_isr_rx(struct sh_mobile_i2c_data *pd)
+{
+ unsigned char data;
+ int real_pos;
+
+ do {
+ if (pd->pos <= -1) {
+ sh_mobile_i2c_get_data(pd, &data);
+
+ if (sh_mobile_i2c_is_first_byte(pd))
+ i2c_op(pd, OP_TX_FIRST, data);
+ else
+ i2c_op(pd, OP_TX, data);
+ break;
+ }
+
+ if (pd->pos == 0) {
+ i2c_op(pd, OP_TX_TO_RX, 0);
+ break;
+ }
+
+ real_pos = pd->pos - 2;
+
+ if (pd->pos == pd->msg->len) {
+ if (real_pos < 0) {
+ i2c_op(pd, OP_RX_STOP, 0);
+ break;
+ }
+ data = i2c_op(pd, OP_RX_STOP_DATA, 0);
+ } else
+ data = i2c_op(pd, OP_RX, 0);
+
+ pd->msg->buf[real_pos] = data;
+ } while (0);
+
+ pd->pos++;
+ return pd->pos == (pd->msg->len + 2);
+}
+
static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id)
{
struct platform_device *dev = dev_id;
struct sh_mobile_i2c_data *pd = platform_get_drvdata(dev);
- struct i2c_msg *msg = pd->msg;
- unsigned char data, sr;
- int wakeup = 0;
+ unsigned char sr;
+ int wakeup;
sr = ioread8(ICSR(pd));
- pd->sr |= sr;
+ pd->sr |= sr; /* remember state */
dev_dbg(pd->dev, "i2c_isr 0x%02x 0x%02x %s %d %d!\n", sr, pd->sr,
- (msg->flags & I2C_M_RD) ? "read" : "write",
- pd->pos, msg->len);
+ (pd->msg->flags & I2C_M_RD) ? "read" : "write",
+ pd->pos, pd->msg->len);
if (sr & (ICSR_AL | ICSR_TACK)) {
- iowrite8(0, ICIC(pd)); /* disable interrupts */
- wakeup = 1;
- goto do_wakeup;
- }
+ /* don't interrupt transaction - continue to issue stop */
+ iowrite8(sr & ~(ICSR_AL | ICSR_TACK), ICSR(pd));
+ wakeup = 0;
+ } else if (pd->msg->flags & I2C_M_RD)
+ wakeup = sh_mobile_i2c_isr_rx(pd);
+ else
+ wakeup = sh_mobile_i2c_isr_tx(pd);
- if (pd->pos == msg->len) {
- i2c_op(pd, OP_RX_ONLY, 0);
- wakeup = 1;
- goto do_wakeup;
- }
+ if (sr & ICSR_WAIT) /* TODO: add delay here to support slow acks */
+ iowrite8(sr & ~ICSR_WAIT, ICSR(pd));
- if (pd->pos == -1) {
- data = (msg->addr & 0x7f) << 1;
- data |= (msg->flags & I2C_M_RD) ? 1 : 0;
- } else
- data = msg->buf[pd->pos];
-
- if ((pd->pos == -1) || !(msg->flags & I2C_M_RD)) {
- if (msg->flags & I2C_M_RD)
- i2c_op(pd, OP_TX_TO_RX, data);
- else if (pd->pos == (msg->len - 1)) {
- i2c_op(pd, OP_TX_STOP, data);
- wakeup = 1;
- } else
- i2c_op(pd, OP_TX_ONLY, data);
- } else {
- if (pd->pos == (msg->len - 1))
- data = i2c_op(pd, OP_RX_STOP, 0);
- else
- data = i2c_op(pd, OP_RX_ONLY, 0);
-
- msg->buf[pd->pos] = data;
- }
- pd->pos++;
-
- do_wakeup:
if (wakeup) {
pd->sr |= SW_DONE;
wake_up(&pd->wait);
@@ -219,6 +361,11 @@ static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id)
static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg)
{
+ if (usr_msg->len == 0 && (usr_msg->flags & I2C_M_RD)) {
+ dev_err(pd->dev, "Unsupported zero length i2c read\n");
+ return -EIO;
+ }
+
/* Initialize channel registers */
iowrite8(ioread8(ICCR(pd)) & ~ICCR_ICE, ICCR(pd));
@@ -233,9 +380,8 @@ static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg)
pd->pos = -1;
pd->sr = 0;
- /* Enable all interrupts except wait */
- iowrite8(ioread8(ICIC(pd)) | ICIC_ALE | ICIC_TACKE | ICIC_DTEE,
- ICIC(pd));
+ /* Enable all interrupts to begin with */
+ iowrite8(ICIC_WAITE | ICIC_ALE | ICIC_TACKE | ICIC_DTEE, ICIC(pd));
return 0;
}
@@ -268,25 +414,18 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
if (!k)
dev_err(pd->dev, "Transfer request timed out\n");
- retry_count = 10;
+ retry_count = 1000;
again:
val = ioread8(ICSR(pd));
dev_dbg(pd->dev, "val 0x%02x pd->sr 0x%02x\n", val, pd->sr);
- if ((val | pd->sr) & (ICSR_TACK | ICSR_AL)) {
- err = -EIO;
- break;
- }
-
/* the interrupt handler may wake us up before the
* transfer is finished, so poll the hardware
* until we're done.
*/
-
- if (!(!(val & ICSR_BUSY) && (val & ICSR_SCLM) &&
- (val & ICSR_SDAM))) {
- msleep(1);
+ if (val & ICSR_BUSY) {
+ udelay(10);
if (retry_count--)
goto again;
@@ -294,6 +433,12 @@ again:
dev_err(pd->dev, "Polling timed out\n");
break;
}
+
+ /* handle missing acknowledge and arbitration lost */
+ if ((val | pd->sr) & (ICSR_TACK | ICSR_AL)) {
+ err = -EIO;
+ break;
+ }
}
deactivate_ch(pd);
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index af4491fa7e3..307d976c9b6 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -583,8 +583,10 @@ static int __init i2c_dev_init(void)
goto out;
i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");
- if (IS_ERR(i2c_dev_class))
+ if (IS_ERR(i2c_dev_class)) {
+ res = PTR_ERR(i2c_dev_class);
goto out_unreg_chrdev;
+ }
res = i2c_add_driver(&i2cdev_driver);
if (res)
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index a34758d2951..052879a6f85 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -242,7 +242,7 @@ config BLK_DEV_IDEFLOPPY
module will be called ide-floppy.
config BLK_DEV_IDESCSI
- tristate "SCSI emulation support"
+ tristate "SCSI emulation support (DEPRECATED)"
depends on SCSI
select IDE_ATAPI
---help---
@@ -255,20 +255,6 @@ config BLK_DEV_IDESCSI
and will allow you to use a SCSI device driver instead of a native
ATAPI driver.
- This is useful if you have an ATAPI device for which no native
- driver has been written (for example, an ATAPI PD-CD drive);
- you can then use this emulation together with an appropriate SCSI
- device driver. In order to do this, say Y here and to "SCSI support"
- and "SCSI generic support", below. You must then provide the kernel
- command line "hdx=ide-scsi" (try "man bootparam" or see the
- documentation of your boot loader (lilo or loadlin) about how to
- pass options to the kernel at boot time) for devices if you want the
- native EIDE sub-drivers to skip over the native support, so that
- this SCSI emulation can be used instead.
-
- Note that this option does NOT allow you to attach SCSI devices to a
- box that doesn't have a SCSI host adapter installed.
-
If both this SCSI emulation and native ATAPI support are compiled
into the kernel, the native support will be used.
@@ -306,6 +292,20 @@ config IDE_GENERIC
tristate "generic/default IDE chipset support"
depends on ALPHA || X86 || IA64 || M32R || MIPS
help
+ This is the generic IDE driver. This driver attaches to the
+ fixed legacy ports (e.g. on PCs 0x1f0/0x170, 0x1e8/0x168 and
+ so on). Please note that if this driver is built into the
+ kernel or loaded before other ATA (IDE or libata) drivers
+ and the controller is located at legacy ports, this driver
+ may grab those ports and thus can prevent the controller
+ specific driver from attaching.
+
+ Also, currently, IDE generic doesn't allow IRQ sharing
+ meaning that the IRQs it grabs won't be available to other
+ controllers sharing those IRQs which usually makes drivers
+ for those controllers fail. Generally, it's not a good idea
+ to load IDE generic driver on modern systems.
+
If unsure, say N.
config BLK_DEV_PLATFORM
@@ -780,10 +780,6 @@ config BLK_DEV_IDEDMA_PMAC
to transfer data to and from memory. Saying Y is safe and improves
performance.
-config BLK_DEV_IDE_SWARM
- tristate "IDE for Sibyte evaluation boards"
- depends on SIBYTE_SB1xxx_SOC
-
config BLK_DEV_IDE_AU1XXX
bool "IDE for AMD Alchemy Au1200"
depends on SOC_AU1200
diff --git a/drivers/ide/arm/palm_bk3710.c b/drivers/ide/arm/palm_bk3710.c
index f788fa5a977..4fd91dcf1dc 100644
--- a/drivers/ide/arm/palm_bk3710.c
+++ b/drivers/ide/arm/palm_bk3710.c
@@ -343,11 +343,10 @@ static struct ide_port_info __devinitdata palm_bk3710_port_info = {
.mwdma_mask = ATA_MWDMA2,
};
-static int __devinit palm_bk3710_probe(struct platform_device *pdev)
+static int __init palm_bk3710_probe(struct platform_device *pdev)
{
struct clk *clk;
struct resource *mem, *irq;
- struct ide_host *host;
unsigned long base, rate;
int i, rc;
hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
@@ -390,6 +389,7 @@ static int __devinit palm_bk3710_probe(struct platform_device *pdev)
hw.io_ports_array[i] = base + IDE_PALM_ATA_PRI_REG_OFFSET + i;
hw.io_ports.ctl_addr = base + IDE_PALM_ATA_PRI_CTL_OFFSET;
hw.irq = irq->start;
+ hw.dev = &pdev->dev;
hw.chipset = ide_palm3710;
palm_bk3710_port_info.udma_mask = rate < 100000000 ? ATA_UDMA4 :
@@ -413,13 +413,11 @@ static struct platform_driver platform_bk_driver = {
.name = "palm_bk3710",
.owner = THIS_MODULE,
},
- .probe = palm_bk3710_probe,
- .remove = NULL,
};
static int __init palm_bk3710_init(void)
{
- return platform_driver_register(&platform_bk_driver);
+ return platform_driver_probe(&platform_bk_driver, palm_bk3710_probe);
}
module_init(palm_bk3710_init);
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index 49a8c589e34..03c2cb6a58b 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -1113,7 +1113,7 @@ static ide_startstop_t cdrom_start_rw(ide_drive_t *drive, struct request *rq)
if (write) {
/* disk has become write protected */
- if (cd->disk->policy) {
+ if (get_disk_ro(cd->disk)) {
cdrom_end_request(drive, 0);
return ide_stopped;
}
@@ -1661,7 +1661,9 @@ static int ide_cdrom_probe_capabilities(ide_drive_t *drive)
cdi->mask &= ~CDC_PLAY_AUDIO;
mechtype = buf[8 + 6] >> 5;
- if (mechtype == mechtype_caddy || mechtype == mechtype_popup)
+ if (mechtype == mechtype_caddy ||
+ mechtype == mechtype_popup ||
+ (drive->atapi_flags & IDE_AFLAG_NO_AUTOCLOSE))
cdi->mask |= CDC_CLOSE_TRAY;
if (cdi->sanyo_slot > 0) {
@@ -1859,6 +1861,8 @@ static const struct cd_list_entry ide_cd_quirks_list[] = {
{ "MATSHITADVD-ROM SR-8176", NULL, IDE_AFLAG_PLAY_AUDIO_OK },
{ "MATSHITADVD-ROM SR-8174", NULL, IDE_AFLAG_PLAY_AUDIO_OK },
{ "Optiarc DVD RW AD-5200A", NULL, IDE_AFLAG_PLAY_AUDIO_OK },
+ { "Optiarc DVD RW AD-7200A", NULL, IDE_AFLAG_PLAY_AUDIO_OK },
+ { "Optiarc DVD RW AD-7543A", NULL, IDE_AFLAG_NO_AUTOCLOSE },
{ NULL, NULL, 0 }
};
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index 68b9cf0138b..33ea8c04871 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -41,6 +41,12 @@
#include <asm/io.h>
#include <asm/div64.h>
+#if !defined(CONFIG_DEBUG_BLOCK_EXT_DEVT)
+#define IDE_DISK_MINORS (1 << PARTN_BITS)
+#else
+#define IDE_DISK_MINORS 0
+#endif
+
struct ide_disk_obj {
ide_drive_t *drive;
ide_driver_t *driver;
@@ -445,20 +451,6 @@ static void idedisk_check_hpa(ide_drive_t *drive)
}
}
-/*
- * Compute drive->capacity, the full capacity of the drive
- * Called with drive->id != NULL.
- *
- * To compute capacity, this uses either of
- *
- * 1. CHS value set by user (whatever user sets will be trusted)
- * 2. LBA value from target drive (require new ATA feature)
- * 3. LBA value from system BIOS (new one is OK, old one may break)
- * 4. CHS value from system BIOS (traditional style)
- *
- * in above order (i.e., if value of higher priority is available,
- * reset will be ignored).
- */
static void init_idedisk_capacity(ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
@@ -1165,8 +1157,7 @@ static int ide_disk_probe(ide_drive_t *drive)
if (!idkp)
goto failed;
- g = alloc_disk_node(1 << PARTN_BITS,
- hwif_to_node(drive->hwif));
+ g = alloc_disk_node(IDE_DISK_MINORS, hwif_to_node(drive->hwif));
if (!g)
goto out_free_idkp;
@@ -1192,9 +1183,11 @@ static int ide_disk_probe(ide_drive_t *drive)
} else
drive->attach = 1;
- g->minors = 1 << PARTN_BITS;
+ g->minors = IDE_DISK_MINORS;
g->driverfs_dev = &drive->gendev;
- g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0;
+ g->flags |= GENHD_FL_EXT_DEVT;
+ if (drive->removable)
+ g->flags |= GENHD_FL_REMOVABLE;
set_capacity(g, idedisk_capacity(drive));
g->fops = &idedisk_ops;
add_disk(g);
diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
index adc68275585..3fa07c0aeaa 100644
--- a/drivers/ide/ide-dma.c
+++ b/drivers/ide/ide-dma.c
@@ -211,7 +211,7 @@ int ide_build_dmatable (ide_drive_t *drive, struct request *rq)
xcount = bcount & 0xffff;
if (is_trm290)
xcount = ((xcount >> 2) - 1) << 16;
- if (xcount == 0x0000) {
+ else if (xcount == 0x0000) {
/*
* Most chipsets correctly interpret a length of 0x0000 as 64KB,
* but at least one (e.g. CS5530) misinterprets it as zero (!).
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 994e41099b4..70aa86c8807 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -1188,7 +1188,7 @@ static struct kobject *exact_match(dev_t dev, int *part, void *data)
{
struct gendisk *p = data;
*part &= (1 << PARTN_BITS) - 1;
- return &p->dev.kobj;
+ return &disk_to_dev(p)->kobj;
}
static int exact_lock(dev_t dev, void *data)
@@ -1492,7 +1492,7 @@ static struct device_attribute *ide_port_attrs[] = {
static int ide_sysfs_register_port(ide_hwif_t *hwif)
{
- int i, rc;
+ int i, uninitialized_var(rc);
for (i = 0; ide_port_attrs[i]; i++) {
rc = device_create_file(hwif->portdev, ide_port_attrs[i]);
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index 1bce84b5663..3833189144e 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -2338,7 +2338,7 @@ static void idetape_get_inquiry_results(ide_drive_t *drive)
{
idetape_tape_t *tape = drive->driver_data;
struct ide_atapi_pc pc;
- char fw_rev[6], vendor_id[10], product_id[18];
+ char fw_rev[4], vendor_id[8], product_id[16];
idetape_create_inquiry_cmd(&pc);
if (idetape_queue_pc_tail(drive, &pc)) {
@@ -2350,11 +2350,11 @@ static void idetape_get_inquiry_results(ide_drive_t *drive)
memcpy(product_id, &pc.buf[16], 16);
memcpy(fw_rev, &pc.buf[32], 4);
- ide_fixstring(vendor_id, 10, 0);
- ide_fixstring(product_id, 18, 0);
- ide_fixstring(fw_rev, 6, 0);
+ ide_fixstring(vendor_id, 8, 0);
+ ide_fixstring(product_id, 16, 0);
+ ide_fixstring(fw_rev, 4, 0);
- printk(KERN_INFO "ide-tape: %s <-> %s: %s %s rev %s\n",
+ printk(KERN_INFO "ide-tape: %s <-> %s: %.8s %.16s rev %.4s\n",
drive->name, tape->name, vendor_id, product_id, fw_rev);
}
diff --git a/drivers/ide/mips/Makefile b/drivers/ide/mips/Makefile
index 677c7b2bac9..5873fa0b876 100644
--- a/drivers/ide/mips/Makefile
+++ b/drivers/ide/mips/Makefile
@@ -1,4 +1,3 @@
-obj-$(CONFIG_BLK_DEV_IDE_SWARM) += swarm.o
obj-$(CONFIG_BLK_DEV_IDE_AU1XXX) += au1xxx-ide.o
EXTRA_CFLAGS := -Idrivers/ide
diff --git a/drivers/ide/mips/swarm.c b/drivers/ide/mips/swarm.c
deleted file mode 100644
index badf79fc9e3..00000000000
--- a/drivers/ide/mips/swarm.c
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Copyright (C) 2001, 2002, 2003 Broadcom Corporation
- * Copyright (C) 2004 MontaVista Software Inc.
- * Author: Manish Lachwani, mlachwani@mvista.com
- * Copyright (C) 2004 MIPS Technologies, Inc. All rights reserved.
- * Author: Maciej W. Rozycki <macro@mips.com>
- * Copyright (c) 2006, 2008 Maciej W. Rozycki
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You 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.
- */
-
-/*
- * Derived loosely from ide-pmac.c, so:
- * Copyright (C) 1998 Paul Mackerras.
- * Copyright (C) 1995-1998 Mark Lord
- */
-
-/*
- * Boards with SiByte processors so far have supported IDE devices via
- * the Generic Bus, PCI bus, and built-in PCMCIA interface. In all
- * cases, byte-swapping must be avoided for these devices (whereas
- * other PCI devices, for example, will require swapping). Any
- * SiByte-targetted kernel including IDE support will include this
- * file. Probing of a Generic Bus for an IDE device is controlled by
- * the definition of "SIBYTE_HAVE_IDE", which is provided by
- * <asm/sibyte/board.h> for Broadcom boards.
- */
-
-#include <linux/ide.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/platform_device.h>
-
-#include <asm/io.h>
-
-#include <asm/sibyte/board.h>
-#include <asm/sibyte/sb1250_genbus.h>
-#include <asm/sibyte/sb1250_regs.h>
-
-#define DRV_NAME "ide-swarm"
-
-static char swarm_ide_string[] = DRV_NAME;
-
-static struct resource swarm_ide_resource = {
- .name = "SWARM GenBus IDE",
- .flags = IORESOURCE_MEM,
-};
-
-static struct platform_device *swarm_ide_dev;
-
-static const struct ide_port_info swarm_port_info = {
- .name = DRV_NAME,
- .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA,
-};
-
-/*
- * swarm_ide_probe - if the board header indicates the existence of
- * Generic Bus IDE, allocate a HWIF for it.
- */
-static int __devinit swarm_ide_probe(struct device *dev)
-{
- u8 __iomem *base;
- struct ide_host *host;
- phys_t offset, size;
- int i, rc;
- hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
-
- if (!SIBYTE_HAVE_IDE)
- return -ENODEV;
-
- base = ioremap(A_IO_EXT_BASE, 0x800);
- offset = __raw_readq(base + R_IO_EXT_REG(R_IO_EXT_START_ADDR, IDE_CS));
- size = __raw_readq(base + R_IO_EXT_REG(R_IO_EXT_MULT_SIZE, IDE_CS));
- iounmap(base);
-
- offset = G_IO_START_ADDR(offset) << S_IO_ADDRBASE;
- size = (G_IO_MULT_SIZE(size) + 1) << S_IO_REGSIZE;
- if (offset < A_PHYS_GENBUS || offset >= A_PHYS_GENBUS_END) {
- printk(KERN_INFO DRV_NAME
- ": IDE interface at GenBus disabled\n");
- return -EBUSY;
- }
-
- printk(KERN_INFO DRV_NAME ": IDE interface at GenBus slot %i\n",
- IDE_CS);
-
- swarm_ide_resource.start = offset;
- swarm_ide_resource.end = offset + size - 1;
- if (request_resource(&iomem_resource, &swarm_ide_resource)) {
- printk(KERN_ERR DRV_NAME
- ": can't request I/O memory resource\n");
- return -EBUSY;
- }
-
- base = ioremap(offset, size);
-
- for (i = 0; i <= 7; i++)
- hw.io_ports_array[i] =
- (unsigned long)(base + ((0x1f0 + i) << 5));
- hw.io_ports.ctl_addr =
- (unsigned long)(base + (0x3f6 << 5));
- hw.irq = K_INT_GB_IDE;
- hw.chipset = ide_generic;
-
- rc = ide_host_add(&swarm_port_info, hws, &host);
- if (rc)
- goto err;
-
- dev_set_drvdata(dev, host);
-
- return 0;
-err:
- release_resource(&swarm_ide_resource);
- iounmap(base);
- return rc;
-}
-
-static struct device_driver swarm_ide_driver = {
- .name = swarm_ide_string,
- .bus = &platform_bus_type,
- .probe = swarm_ide_probe,
-};
-
-static void swarm_ide_platform_release(struct device *device)
-{
- struct platform_device *pldev;
-
- /* free device */
- pldev = to_platform_device(device);
- kfree(pldev);
-}
-
-static int __devinit swarm_ide_init_module(void)
-{
- struct platform_device *pldev;
- int err;
-
- printk(KERN_INFO "SWARM IDE driver\n");
-
- if (driver_register(&swarm_ide_driver)) {
- printk(KERN_ERR "Driver registration failed\n");
- err = -ENODEV;
- goto out;
- }
-
- if (!(pldev = kzalloc(sizeof (*pldev), GFP_KERNEL))) {
- err = -ENOMEM;
- goto out_unregister_driver;
- }
-
- pldev->name = swarm_ide_string;
- pldev->id = 0;
- pldev->dev.release = swarm_ide_platform_release;
-
- if (platform_device_register(pldev)) {
- err = -ENODEV;
- goto out_free_pldev;
- }
-
- if (!pldev->dev.driver) {
- /*
- * The driver was not bound to this device, there was
- * no hardware at this address. Unregister it, as the
- * release fuction will take care of freeing the
- * allocated structure
- */
- platform_device_unregister (pldev);
- }
-
- swarm_ide_dev = pldev;
-
- return 0;
-
-out_free_pldev:
- kfree(pldev);
-
-out_unregister_driver:
- driver_unregister(&swarm_ide_driver);
-out:
- return err;
-}
-
-module_init(swarm_ide_init_module);
diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c
index eb107eef0db..c37ab174381 100644
--- a/drivers/ide/pci/hpt366.c
+++ b/drivers/ide/pci/hpt366.c
@@ -613,6 +613,14 @@ static int check_in_drive_list(ide_drive_t *drive, const char **list)
return 0;
}
+static struct hpt_info *hpt3xx_get_info(struct device *dev)
+{
+ struct ide_host *host = dev_get_drvdata(dev);
+ struct hpt_info *info = (struct hpt_info *)host->host_priv;
+
+ return dev == host->dev[1] ? info + 1 : info;
+}
+
/*
* The Marvell bridge chips used on the HighPoint SATA cards do not seem
* to support the UltraDMA modes 1, 2, and 3 as well as any MWDMA modes...
@@ -621,9 +629,7 @@ static int check_in_drive_list(ide_drive_t *drive, const char **list)
static u8 hpt3xx_udma_filter(ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- struct ide_host *host = pci_get_drvdata(dev);
- struct hpt_info *info = host->host_priv + (hwif->dev == host->dev[1]);
+ struct hpt_info *info = hpt3xx_get_info(hwif->dev);
u8 mask = hwif->ultra_mask;
switch (info->chip_type) {
@@ -662,9 +668,7 @@ static u8 hpt3xx_udma_filter(ide_drive_t *drive)
static u8 hpt3xx_mdma_filter(ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- struct ide_host *host = pci_get_drvdata(dev);
- struct hpt_info *info = host->host_priv + (hwif->dev == host->dev[1]);
+ struct hpt_info *info = hpt3xx_get_info(hwif->dev);
switch (info->chip_type) {
case HPT372 :
@@ -700,8 +704,7 @@ static void hpt3xx_set_mode(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = drive->hwif;
struct pci_dev *dev = to_pci_dev(hwif->dev);
- struct ide_host *host = pci_get_drvdata(dev);
- struct hpt_info *info = host->host_priv + (hwif->dev == host->dev[1]);
+ struct hpt_info *info = hpt3xx_get_info(hwif->dev);
struct hpt_timings *t = info->timings;
u8 itr_addr = 0x40 + (drive->dn * 4);
u32 old_itr = 0;
@@ -744,8 +747,7 @@ static void hpt3xx_maskproc(ide_drive_t *drive, int mask)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = to_pci_dev(hwif->dev);
- struct ide_host *host = pci_get_drvdata(dev);
- struct hpt_info *info = host->host_priv + (hwif->dev == host->dev[1]);
+ struct hpt_info *info = hpt3xx_get_info(hwif->dev);
if (drive->quirk_list) {
if (info->chip_type >= HPT370) {
@@ -973,8 +975,7 @@ static int __devinit hpt37x_calibrate_dpll(struct pci_dev *dev, u16 f_low, u16 f
static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev)
{
unsigned long io_base = pci_resource_start(dev, 4);
- struct ide_host *host = pci_get_drvdata(dev);
- struct hpt_info *info = host->host_priv + (&dev->dev == host->dev[1]);
+ struct hpt_info *info = hpt3xx_get_info(&dev->dev);
const char *name = DRV_NAME;
u8 pci_clk, dpll_clk = 0; /* PCI and DPLL clock in MHz */
u8 chip_type;
@@ -1217,8 +1218,7 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev)
static u8 hpt3xx_cable_detect(ide_hwif_t *hwif)
{
struct pci_dev *dev = to_pci_dev(hwif->dev);
- struct ide_host *host = pci_get_drvdata(dev);
- struct hpt_info *info = host->host_priv + (hwif->dev == host->dev[1]);
+ struct hpt_info *info = hpt3xx_get_info(hwif->dev);
u8 chip_type = info->chip_type;
u8 scr1 = 0, ata66 = hwif->channel ? 0x01 : 0x02;
@@ -1262,8 +1262,7 @@ static u8 hpt3xx_cable_detect(ide_hwif_t *hwif)
static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
{
struct pci_dev *dev = to_pci_dev(hwif->dev);
- struct ide_host *host = pci_get_drvdata(dev);
- struct hpt_info *info = host->host_priv + (hwif->dev == host->dev[1]);
+ struct hpt_info *info = hpt3xx_get_info(hwif->dev);
int serialize = HPT_SERIALIZE_IO;
u8 chip_type = info->chip_type;
u8 new_mcr, old_mcr = 0;
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
index 922d35f4fc0..3cab0cedfca 100644
--- a/drivers/infiniband/core/cm.c
+++ b/drivers/infiniband/core/cm.c
@@ -3748,6 +3748,7 @@ error1:
cm_remove_port_fs(port);
}
device_unregister(cm_dev->device);
+ kfree(cm_dev);
}
static void cm_remove_one(struct ib_device *ib_device)
@@ -3776,6 +3777,7 @@ static void cm_remove_one(struct ib_device *ib_device)
cm_remove_port_fs(port);
}
device_unregister(cm_dev->device);
+ kfree(cm_dev);
}
static int __init ib_cm_init(void)
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
index 1adf2efd3cb..49c45feccd5 100644
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -1697,9 +1697,8 @@ static inline int rcv_has_same_gid(struct ib_mad_agent_private *mad_agent_priv,
u8 port_num = mad_agent_priv->agent.port_num;
u8 lmc;
- send_resp = ((struct ib_mad *)(wr->send_buf.mad))->
- mad_hdr.method & IB_MGMT_METHOD_RESP;
- rcv_resp = rwc->recv_buf.mad->mad_hdr.method & IB_MGMT_METHOD_RESP;
+ send_resp = ib_response_mad((struct ib_mad *)wr->send_buf.mad);
+ rcv_resp = ib_response_mad(rwc->recv_buf.mad);
if (send_resp == rcv_resp)
/* both requests, or both responses. GIDs different */
diff --git a/drivers/infiniband/hw/amso1100/c2_provider.c b/drivers/infiniband/hw/amso1100/c2_provider.c
index 2acf9b62cf9..69580e282af 100644
--- a/drivers/infiniband/hw/amso1100/c2_provider.c
+++ b/drivers/infiniband/hw/amso1100/c2_provider.c
@@ -272,7 +272,6 @@ static struct ib_qp *c2_create_qp(struct ib_pd *pd,
pr_debug("%s: Invalid QP type: %d\n", __func__,
init_attr->qp_type);
return ERR_PTR(-EINVAL);
- break;
}
if (err) {
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c
index eb778bfd6f6..ecff9804358 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_provider.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c
@@ -1155,13 +1155,11 @@ static int iwch_query_port(struct ib_device *ibdev,
u8 port, struct ib_port_attr *props)
{
PDBG("%s ibdev %p\n", __func__, ibdev);
+
+ memset(props, 0, sizeof(struct ib_port_attr));
props->max_mtu = IB_MTU_4096;
- props->lid = 0;
- props->lmc = 0;
- props->sm_lid = 0;
- props->sm_sl = 0;
+ props->active_mtu = IB_MTU_2048;
props->state = IB_PORT_ACTIVE;
- props->phys_state = 0;
props->port_cap_flags =
IB_PORT_CM_SUP |
IB_PORT_SNMP_TUNNEL_SUP |
@@ -1170,7 +1168,6 @@ static int iwch_query_port(struct ib_device *ibdev,
IB_PORT_VENDOR_CLASS_SUP | IB_PORT_BOOT_MGMT_SUP;
props->gid_tbl_len = 1;
props->pkey_tbl_len = 1;
- props->qkey_viol_cntr = 0;
props->active_width = 2;
props->active_speed = 2;
props->max_msg_sz = -1;
diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h
index 1ab919f836a..5d7b7855afb 100644
--- a/drivers/infiniband/hw/ehca/ehca_classes.h
+++ b/drivers/infiniband/hw/ehca/ehca_classes.h
@@ -164,6 +164,13 @@ struct ehca_qmap_entry {
u16 reported;
};
+struct ehca_queue_map {
+ struct ehca_qmap_entry *map;
+ unsigned int entries;
+ unsigned int tail;
+ unsigned int left_to_poll;
+};
+
struct ehca_qp {
union {
struct ib_qp ib_qp;
@@ -173,8 +180,9 @@ struct ehca_qp {
enum ehca_ext_qp_type ext_type;
enum ib_qp_state state;
struct ipz_queue ipz_squeue;
- struct ehca_qmap_entry *sq_map;
+ struct ehca_queue_map sq_map;
struct ipz_queue ipz_rqueue;
+ struct ehca_queue_map rq_map;
struct h_galpas galpas;
u32 qkey;
u32 real_qp_num;
@@ -204,6 +212,8 @@ struct ehca_qp {
atomic_t nr_events; /* events seen */
wait_queue_head_t wait_completion;
int mig_armed;
+ struct list_head sq_err_node;
+ struct list_head rq_err_node;
};
#define IS_SRQ(qp) (qp->ext_type == EQPT_SRQ)
@@ -233,6 +243,8 @@ struct ehca_cq {
/* mmap counter for resources mapped into user space */
u32 mm_count_queue;
u32 mm_count_galpa;
+ struct list_head sqp_err_list;
+ struct list_head rqp_err_list;
};
enum ehca_mr_flag {
diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c
index 5540b276a33..33647a95eb9 100644
--- a/drivers/infiniband/hw/ehca/ehca_cq.c
+++ b/drivers/infiniband/hw/ehca/ehca_cq.c
@@ -276,6 +276,9 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
for (i = 0; i < QP_HASHTAB_LEN; i++)
INIT_HLIST_HEAD(&my_cq->qp_hashtab[i]);
+ INIT_LIST_HEAD(&my_cq->sqp_err_list);
+ INIT_LIST_HEAD(&my_cq->rqp_err_list);
+
if (context) {
struct ipz_queue *ipz_queue = &my_cq->ipz_queue;
struct ehca_create_cq_resp resp;
diff --git a/drivers/infiniband/hw/ehca/ehca_iverbs.h b/drivers/infiniband/hw/ehca/ehca_iverbs.h
index a8a2ea585d2..8f7f282ead6 100644
--- a/drivers/infiniband/hw/ehca/ehca_iverbs.h
+++ b/drivers/infiniband/hw/ehca/ehca_iverbs.h
@@ -197,6 +197,8 @@ void ehca_poll_eqs(unsigned long data);
int ehca_calc_ipd(struct ehca_shca *shca, int port,
enum ib_rate path_rate, u32 *ipd);
+void ehca_add_to_err_list(struct ehca_qp *qp, int on_sq);
+
#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_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c
index b6bcee03673..4dbe2870e01 100644
--- a/drivers/infiniband/hw/ehca/ehca_qp.c
+++ b/drivers/infiniband/hw/ehca/ehca_qp.c
@@ -396,6 +396,50 @@ static void ehca_determine_small_queue(struct ehca_alloc_queue_parms *queue,
queue->is_small = (queue->page_size != 0);
}
+/* needs to be called with cq->spinlock held */
+void ehca_add_to_err_list(struct ehca_qp *qp, int on_sq)
+{
+ struct list_head *list, *node;
+
+ /* TODO: support low latency QPs */
+ if (qp->ext_type == EQPT_LLQP)
+ return;
+
+ if (on_sq) {
+ list = &qp->send_cq->sqp_err_list;
+ node = &qp->sq_err_node;
+ } else {
+ list = &qp->recv_cq->rqp_err_list;
+ node = &qp->rq_err_node;
+ }
+
+ if (list_empty(node))
+ list_add_tail(node, list);
+
+ return;
+}
+
+static void del_from_err_list(struct ehca_cq *cq, struct list_head *node)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&cq->spinlock, flags);
+
+ if (!list_empty(node))
+ list_del_init(node);
+
+ spin_unlock_irqrestore(&cq->spinlock, flags);
+}
+
+static void reset_queue_map(struct ehca_queue_map *qmap)
+{
+ int i;
+
+ qmap->tail = 0;
+ for (i = 0; i < qmap->entries; i++)
+ qmap->map[i].reported = 1;
+}
+
/*
* Create an ib_qp struct that is either a QP or an SRQ, depending on
* the value of the is_srq parameter. If init_attr and srq_init_attr share
@@ -407,12 +451,11 @@ static struct ehca_qp *internal_create_qp(
struct ib_srq_init_attr *srq_init_attr,
struct ib_udata *udata, int is_srq)
{
- struct ehca_qp *my_qp;
+ struct ehca_qp *my_qp, *my_srq = NULL;
struct ehca_pd *my_pd = container_of(pd, struct ehca_pd, ib_pd);
struct ehca_shca *shca = container_of(pd->device, struct ehca_shca,
ib_device);
struct ib_ucontext *context = NULL;
- u32 nr_qes;
u64 h_ret;
int is_llqp = 0, has_srq = 0;
int qp_type, max_send_sge, max_recv_sge, ret;
@@ -457,8 +500,7 @@ static struct ehca_qp *internal_create_qp(
/* handle SRQ base QPs */
if (init_attr->srq) {
- struct ehca_qp *my_srq =
- container_of(init_attr->srq, struct ehca_qp, ib_srq);
+ my_srq = container_of(init_attr->srq, struct ehca_qp, ib_srq);
has_srq = 1;
parms.ext_type = EQPT_SRQBASE;
@@ -716,15 +758,19 @@ static struct ehca_qp *internal_create_qp(
"and pages ret=%i", ret);
goto create_qp_exit2;
}
- nr_qes = my_qp->ipz_squeue.queue_length /
+
+ my_qp->sq_map.entries = my_qp->ipz_squeue.queue_length /
my_qp->ipz_squeue.qe_size;
- my_qp->sq_map = vmalloc(nr_qes *
+ my_qp->sq_map.map = vmalloc(my_qp->sq_map.entries *
sizeof(struct ehca_qmap_entry));
- if (!my_qp->sq_map) {
+ if (!my_qp->sq_map.map) {
ehca_err(pd->device, "Couldn't allocate squeue "
"map ret=%i", ret);
goto create_qp_exit3;
}
+ INIT_LIST_HEAD(&my_qp->sq_err_node);
+ /* to avoid the generation of bogus flush CQEs */
+ reset_queue_map(&my_qp->sq_map);
}
if (HAS_RQ(my_qp)) {
@@ -736,6 +782,25 @@ static struct ehca_qp *internal_create_qp(
"and pages ret=%i", ret);
goto create_qp_exit4;
}
+
+ my_qp->rq_map.entries = my_qp->ipz_rqueue.queue_length /
+ my_qp->ipz_rqueue.qe_size;
+ my_qp->rq_map.map = vmalloc(my_qp->rq_map.entries *
+ sizeof(struct ehca_qmap_entry));
+ if (!my_qp->rq_map.map) {
+ ehca_err(pd->device, "Couldn't allocate squeue "
+ "map ret=%i", ret);
+ goto create_qp_exit5;
+ }
+ INIT_LIST_HEAD(&my_qp->rq_err_node);
+ /* to avoid the generation of bogus flush CQEs */
+ reset_queue_map(&my_qp->rq_map);
+ } else if (init_attr->srq) {
+ /* this is a base QP, use the queue map of the SRQ */
+ my_qp->rq_map = my_srq->rq_map;
+ INIT_LIST_HEAD(&my_qp->rq_err_node);
+
+ my_qp->ipz_rqueue = my_srq->ipz_rqueue;
}
if (is_srq) {
@@ -799,7 +864,7 @@ static struct ehca_qp *internal_create_qp(
if (ret) {
ehca_err(pd->device,
"Couldn't assign qp to send_cq ret=%i", ret);
- goto create_qp_exit6;
+ goto create_qp_exit7;
}
}
@@ -825,25 +890,29 @@ static struct ehca_qp *internal_create_qp(
if (ib_copy_to_udata(udata, &resp, sizeof resp)) {
ehca_err(pd->device, "Copy to udata failed");
ret = -EINVAL;
- goto create_qp_exit7;
+ goto create_qp_exit8;
}
}
return my_qp;
-create_qp_exit7:
+create_qp_exit8:
ehca_cq_unassign_qp(my_qp->send_cq, my_qp->real_qp_num);
-create_qp_exit6:
+create_qp_exit7:
kfree(my_qp->mod_qp_parm);
+create_qp_exit6:
+ if (HAS_RQ(my_qp))
+ vfree(my_qp->rq_map.map);
+
create_qp_exit5:
if (HAS_RQ(my_qp))
ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue);
create_qp_exit4:
if (HAS_SQ(my_qp))
- vfree(my_qp->sq_map);
+ vfree(my_qp->sq_map.map);
create_qp_exit3:
if (HAS_SQ(my_qp))
@@ -1035,6 +1104,101 @@ static int prepare_sqe_rts(struct ehca_qp *my_qp, struct ehca_shca *shca,
return 0;
}
+static int calc_left_cqes(u64 wqe_p, struct ipz_queue *ipz_queue,
+ struct ehca_queue_map *qmap)
+{
+ void *wqe_v;
+ u64 q_ofs;
+ u32 wqe_idx;
+
+ /* convert real to abs address */
+ wqe_p = wqe_p & (~(1UL << 63));
+
+ wqe_v = abs_to_virt(wqe_p);
+
+ if (ipz_queue_abs_to_offset(ipz_queue, wqe_p, &q_ofs)) {
+ ehca_gen_err("Invalid offset for calculating left cqes "
+ "wqe_p=%#lx wqe_v=%p\n", wqe_p, wqe_v);
+ return -EFAULT;
+ }
+
+ wqe_idx = q_ofs / ipz_queue->qe_size;
+ if (wqe_idx < qmap->tail)
+ qmap->left_to_poll = (qmap->entries - qmap->tail) + wqe_idx;
+ else
+ qmap->left_to_poll = wqe_idx - qmap->tail;
+
+ return 0;
+}
+
+static int check_for_left_cqes(struct ehca_qp *my_qp, struct ehca_shca *shca)
+{
+ u64 h_ret;
+ void *send_wqe_p, *recv_wqe_p;
+ int ret;
+ unsigned long flags;
+ int qp_num = my_qp->ib_qp.qp_num;
+
+ /* this hcall is not supported on base QPs */
+ if (my_qp->ext_type != EQPT_SRQBASE) {
+ /* get send and receive wqe pointer */
+ h_ret = hipz_h_disable_and_get_wqe(shca->ipz_hca_handle,
+ my_qp->ipz_qp_handle, &my_qp->pf,
+ &send_wqe_p, &recv_wqe_p, 4);
+ if (h_ret != H_SUCCESS) {
+ ehca_err(&shca->ib_device, "disable_and_get_wqe() "
+ "failed ehca_qp=%p qp_num=%x h_ret=%li",
+ my_qp, qp_num, h_ret);
+ return ehca2ib_return_code(h_ret);
+ }
+
+ /*
+ * acquire lock to ensure that nobody is polling the cq which
+ * could mean that the qmap->tail pointer is in an
+ * inconsistent state.
+ */
+ spin_lock_irqsave(&my_qp->send_cq->spinlock, flags);
+ ret = calc_left_cqes((u64)send_wqe_p, &my_qp->ipz_squeue,
+ &my_qp->sq_map);
+ spin_unlock_irqrestore(&my_qp->send_cq->spinlock, flags);
+ if (ret)
+ return ret;
+
+
+ spin_lock_irqsave(&my_qp->recv_cq->spinlock, flags);
+ ret = calc_left_cqes((u64)recv_wqe_p, &my_qp->ipz_rqueue,
+ &my_qp->rq_map);
+ spin_unlock_irqrestore(&my_qp->recv_cq->spinlock, flags);
+ if (ret)
+ return ret;
+ } else {
+ spin_lock_irqsave(&my_qp->send_cq->spinlock, flags);
+ my_qp->sq_map.left_to_poll = 0;
+ spin_unlock_irqrestore(&my_qp->send_cq->spinlock, flags);
+
+ spin_lock_irqsave(&my_qp->recv_cq->spinlock, flags);
+ my_qp->rq_map.left_to_poll = 0;
+ spin_unlock_irqrestore(&my_qp->recv_cq->spinlock, flags);
+ }
+
+ /* this assures flush cqes being generated only for pending wqes */
+ if ((my_qp->sq_map.left_to_poll == 0) &&
+ (my_qp->rq_map.left_to_poll == 0)) {
+ spin_lock_irqsave(&my_qp->send_cq->spinlock, flags);
+ ehca_add_to_err_list(my_qp, 1);
+ spin_unlock_irqrestore(&my_qp->send_cq->spinlock, flags);
+
+ if (HAS_RQ(my_qp)) {
+ spin_lock_irqsave(&my_qp->recv_cq->spinlock, flags);
+ ehca_add_to_err_list(my_qp, 0);
+ spin_unlock_irqrestore(&my_qp->recv_cq->spinlock,
+ flags);
+ }
+ }
+
+ return 0;
+}
+
/*
* internal_modify_qp with circumvention to handle aqp0 properly
* smi_reset2init indicates if this is an internal reset-to-init-call for
@@ -1539,10 +1703,27 @@ static int internal_modify_qp(struct ib_qp *ibqp,
goto modify_qp_exit2;
}
}
+ if ((qp_new_state == IB_QPS_ERR) && (qp_cur_state != IB_QPS_ERR)) {
+ ret = check_for_left_cqes(my_qp, shca);
+ if (ret)
+ goto modify_qp_exit2;
+ }
if (statetrans == IB_QPST_ANY2RESET) {
ipz_qeit_reset(&my_qp->ipz_rqueue);
ipz_qeit_reset(&my_qp->ipz_squeue);
+
+ if (qp_cur_state == IB_QPS_ERR) {
+ del_from_err_list(my_qp->send_cq, &my_qp->sq_err_node);
+
+ if (HAS_RQ(my_qp))
+ del_from_err_list(my_qp->recv_cq,
+ &my_qp->rq_err_node);
+ }
+ reset_queue_map(&my_qp->sq_map);
+
+ if (HAS_RQ(my_qp))
+ reset_queue_map(&my_qp->rq_map);
}
if (attr_mask & IB_QP_QKEY)
@@ -1958,6 +2139,16 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
idr_remove(&ehca_qp_idr, my_qp->token);
write_unlock_irqrestore(&ehca_qp_idr_lock, flags);
+ /*
+ * SRQs will never get into an error list and do not have a recv_cq,
+ * so we need to skip them here.
+ */
+ if (HAS_RQ(my_qp) && !IS_SRQ(my_qp))
+ del_from_err_list(my_qp->recv_cq, &my_qp->rq_err_node);
+
+ if (HAS_SQ(my_qp))
+ del_from_err_list(my_qp->send_cq, &my_qp->sq_err_node);
+
/* now wait until all pending events have completed */
wait_event(my_qp->wait_completion, !atomic_read(&my_qp->nr_events));
@@ -1983,7 +2174,7 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
if (qp_type == IB_QPT_GSI) {
struct ib_event event;
ehca_info(dev, "device %s: port %x is inactive.",
- shca->ib_device.name, port_num);
+ shca->ib_device.name, port_num);
event.device = &shca->ib_device;
event.event = IB_EVENT_PORT_ERR;
event.element.port_num = port_num;
@@ -1991,11 +2182,15 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
ib_dispatch_event(&event);
}
- if (HAS_RQ(my_qp))
+ if (HAS_RQ(my_qp)) {
ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue);
+
+ vfree(my_qp->rq_map.map);
+ }
if (HAS_SQ(my_qp)) {
ipz_queue_dtor(my_pd, &my_qp->ipz_squeue);
- vfree(my_qp->sq_map);
+
+ vfree(my_qp->sq_map.map);
}
kmem_cache_free(qp_cache, my_qp);
atomic_dec(&shca->num_qps);
diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c
index 4426d82fe79..64928079eaf 100644
--- a/drivers/infiniband/hw/ehca/ehca_reqs.c
+++ b/drivers/infiniband/hw/ehca/ehca_reqs.c
@@ -53,9 +53,25 @@
/* in RC traffic, insert an empty RDMA READ every this many packets */
#define ACK_CIRC_THRESHOLD 2000000
+static u64 replace_wr_id(u64 wr_id, u16 idx)
+{
+ u64 ret;
+
+ ret = wr_id & ~QMAP_IDX_MASK;
+ ret |= idx & QMAP_IDX_MASK;
+
+ return ret;
+}
+
+static u16 get_app_wr_id(u64 wr_id)
+{
+ return wr_id & QMAP_IDX_MASK;
+}
+
static inline int ehca_write_rwqe(struct ipz_queue *ipz_rqueue,
struct ehca_wqe *wqe_p,
- struct ib_recv_wr *recv_wr)
+ struct ib_recv_wr *recv_wr,
+ u32 rq_map_idx)
{
u8 cnt_ds;
if (unlikely((recv_wr->num_sge < 0) ||
@@ -69,7 +85,7 @@ static inline int ehca_write_rwqe(struct ipz_queue *ipz_rqueue,
/* clear wqe header until sglist */
memset(wqe_p, 0, offsetof(struct ehca_wqe, u.ud_av.sg_list));
- wqe_p->work_request_id = recv_wr->wr_id;
+ wqe_p->work_request_id = replace_wr_id(recv_wr->wr_id, rq_map_idx);
wqe_p->nr_of_data_seg = recv_wr->num_sge;
for (cnt_ds = 0; cnt_ds < recv_wr->num_sge; cnt_ds++) {
@@ -146,6 +162,7 @@ static inline int ehca_write_swqe(struct ehca_qp *qp,
u64 dma_length;
struct ehca_av *my_av;
u32 remote_qkey = send_wr->wr.ud.remote_qkey;
+ struct ehca_qmap_entry *qmap_entry = &qp->sq_map.map[sq_map_idx];
if (unlikely((send_wr->num_sge < 0) ||
(send_wr->num_sge > qp->ipz_squeue.act_nr_of_sg))) {
@@ -158,11 +175,10 @@ static inline int ehca_write_swqe(struct ehca_qp *qp,
/* clear wqe header until sglist */
memset(wqe_p, 0, offsetof(struct ehca_wqe, u.ud_av.sg_list));
- wqe_p->work_request_id = send_wr->wr_id & ~QMAP_IDX_MASK;
- wqe_p->work_request_id |= sq_map_idx & QMAP_IDX_MASK;
+ wqe_p->work_request_id = replace_wr_id(send_wr->wr_id, sq_map_idx);
- qp->sq_map[sq_map_idx].app_wr_id = send_wr->wr_id & QMAP_IDX_MASK;
- qp->sq_map[sq_map_idx].reported = 0;
+ qmap_entry->app_wr_id = get_app_wr_id(send_wr->wr_id);
+ qmap_entry->reported = 0;
switch (send_wr->opcode) {
case IB_WR_SEND:
@@ -496,7 +512,9 @@ static int internal_post_recv(struct ehca_qp *my_qp,
struct ehca_wqe *wqe_p;
int wqe_cnt = 0;
int ret = 0;
+ u32 rq_map_idx;
unsigned long flags;
+ struct ehca_qmap_entry *qmap_entry;
if (unlikely(!HAS_RQ(my_qp))) {
ehca_err(dev, "QP has no RQ ehca_qp=%p qp_num=%x ext_type=%d",
@@ -524,8 +542,15 @@ static int internal_post_recv(struct ehca_qp *my_qp,
}
goto post_recv_exit0;
}
+ /*
+ * Get the index of the WQE in the recv queue. The same index
+ * is used for writing into the rq_map.
+ */
+ rq_map_idx = start_offset / my_qp->ipz_rqueue.qe_size;
+
/* write a RECV WQE into the QUEUE */
- ret = ehca_write_rwqe(&my_qp->ipz_rqueue, wqe_p, cur_recv_wr);
+ ret = ehca_write_rwqe(&my_qp->ipz_rqueue, wqe_p, cur_recv_wr,
+ rq_map_idx);
/*
* if something failed,
* reset the free entry pointer to the start value
@@ -540,6 +565,11 @@ static int internal_post_recv(struct ehca_qp *my_qp,
}
goto post_recv_exit0;
}
+
+ qmap_entry = &my_qp->rq_map.map[rq_map_idx];
+ qmap_entry->app_wr_id = get_app_wr_id(cur_recv_wr->wr_id);
+ qmap_entry->reported = 0;
+
wqe_cnt++;
} /* eof for cur_recv_wr */
@@ -596,10 +626,12 @@ static const u8 ib_wc_opcode[255] = {
/* internal function to poll one entry of cq */
static inline int ehca_poll_cq_one(struct ib_cq *cq, struct ib_wc *wc)
{
- int ret = 0;
+ int ret = 0, qmap_tail_idx;
struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq);
struct ehca_cqe *cqe;
struct ehca_qp *my_qp;
+ struct ehca_qmap_entry *qmap_entry;
+ struct ehca_queue_map *qmap;
int cqe_count = 0, is_error;
repoll:
@@ -674,27 +706,52 @@ repoll:
goto repoll;
wc->qp = &my_qp->ib_qp;
- if (!(cqe->w_completion_flags & WC_SEND_RECEIVE_BIT)) {
- struct ehca_qmap_entry *qmap_entry;
+ if (is_error) {
/*
- * We got a send completion and need to restore the original
- * wr_id.
+ * set left_to_poll to 0 because in error state, we will not
+ * get any additional CQEs
*/
- qmap_entry = &my_qp->sq_map[cqe->work_request_id &
- QMAP_IDX_MASK];
+ ehca_add_to_err_list(my_qp, 1);
+ my_qp->sq_map.left_to_poll = 0;
- if (qmap_entry->reported) {
- ehca_warn(cq->device, "Double cqe on qp_num=%#x",
- my_qp->real_qp_num);
- /* found a double cqe, discard it and read next one */
- goto repoll;
- }
- wc->wr_id = cqe->work_request_id & ~QMAP_IDX_MASK;
- wc->wr_id |= qmap_entry->app_wr_id;
- qmap_entry->reported = 1;
- } else
+ if (HAS_RQ(my_qp))
+ ehca_add_to_err_list(my_qp, 0);
+ my_qp->rq_map.left_to_poll = 0;
+ }
+
+ qmap_tail_idx = get_app_wr_id(cqe->work_request_id);
+ if (!(cqe->w_completion_flags & WC_SEND_RECEIVE_BIT))
+ /* We got a send completion. */
+ qmap = &my_qp->sq_map;
+ else
/* We got a receive completion. */
- wc->wr_id = cqe->work_request_id;
+ qmap = &my_qp->rq_map;
+
+ qmap_entry = &qmap->map[qmap_tail_idx];
+ if (qmap_entry->reported) {
+ ehca_warn(cq->device, "Double cqe on qp_num=%#x",
+ my_qp->real_qp_num);
+ /* found a double cqe, discard it and read next one */
+ goto repoll;
+ }
+
+ wc->wr_id = replace_wr_id(cqe->work_request_id, qmap_entry->app_wr_id);
+ qmap_entry->reported = 1;
+
+ /* this is a proper completion, we need to advance the tail pointer */
+ if (++qmap->tail == qmap->entries)
+ qmap->tail = 0;
+
+ /* if left_to_poll is decremented to 0, add the QP to the error list */
+ if (qmap->left_to_poll > 0) {
+ qmap->left_to_poll--;
+ if ((my_qp->sq_map.left_to_poll == 0) &&
+ (my_qp->rq_map.left_to_poll == 0)) {
+ ehca_add_to_err_list(my_qp, 1);
+ if (HAS_RQ(my_qp))
+ ehca_add_to_err_list(my_qp, 0);
+ }
+ }
/* eval ib_wc_opcode */
wc->opcode = ib_wc_opcode[cqe->optype]-1;
@@ -733,13 +790,88 @@ poll_cq_one_exit0:
return ret;
}
+static int generate_flush_cqes(struct ehca_qp *my_qp, struct ib_cq *cq,
+ struct ib_wc *wc, int num_entries,
+ struct ipz_queue *ipz_queue, int on_sq)
+{
+ int nr = 0;
+ struct ehca_wqe *wqe;
+ u64 offset;
+ struct ehca_queue_map *qmap;
+ struct ehca_qmap_entry *qmap_entry;
+
+ if (on_sq)
+ qmap = &my_qp->sq_map;
+ else
+ qmap = &my_qp->rq_map;
+
+ qmap_entry = &qmap->map[qmap->tail];
+
+ while ((nr < num_entries) && (qmap_entry->reported == 0)) {
+ /* generate flush CQE */
+ memset(wc, 0, sizeof(*wc));
+
+ offset = qmap->tail * ipz_queue->qe_size;
+ wqe = (struct ehca_wqe *)ipz_qeit_calc(ipz_queue, offset);
+ if (!wqe) {
+ ehca_err(cq->device, "Invalid wqe offset=%#lx on "
+ "qp_num=%#x", offset, my_qp->real_qp_num);
+ return nr;
+ }
+
+ wc->wr_id = replace_wr_id(wqe->work_request_id,
+ qmap_entry->app_wr_id);
+
+ if (on_sq) {
+ switch (wqe->optype) {
+ case WQE_OPTYPE_SEND:
+ wc->opcode = IB_WC_SEND;
+ break;
+ case WQE_OPTYPE_RDMAWRITE:
+ wc->opcode = IB_WC_RDMA_WRITE;
+ break;
+ case WQE_OPTYPE_RDMAREAD:
+ wc->opcode = IB_WC_RDMA_READ;
+ break;
+ default:
+ ehca_err(cq->device, "Invalid optype=%x",
+ wqe->optype);
+ return nr;
+ }
+ } else
+ wc->opcode = IB_WC_RECV;
+
+ if (wqe->wr_flag & WQE_WRFLAG_IMM_DATA_PRESENT) {
+ wc->ex.imm_data = wqe->immediate_data;
+ wc->wc_flags |= IB_WC_WITH_IMM;
+ }
+
+ wc->status = IB_WC_WR_FLUSH_ERR;
+
+ wc->qp = &my_qp->ib_qp;
+
+ /* mark as reported and advance tail pointer */
+ qmap_entry->reported = 1;
+ if (++qmap->tail == qmap->entries)
+ qmap->tail = 0;
+ qmap_entry = &qmap->map[qmap->tail];
+
+ wc++; nr++;
+ }
+
+ return nr;
+
+}
+
int ehca_poll_cq(struct ib_cq *cq, int num_entries, struct ib_wc *wc)
{
struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq);
int nr;
+ struct ehca_qp *err_qp;
struct ib_wc *current_wc = wc;
int ret = 0;
unsigned long flags;
+ int entries_left = num_entries;
if (num_entries < 1) {
ehca_err(cq->device, "Invalid num_entries=%d ehca_cq=%p "
@@ -749,15 +881,40 @@ int ehca_poll_cq(struct ib_cq *cq, int num_entries, struct ib_wc *wc)
}
spin_lock_irqsave(&my_cq->spinlock, flags);
- for (nr = 0; nr < num_entries; nr++) {
+
+ /* generate flush cqes for send queues */
+ list_for_each_entry(err_qp, &my_cq->sqp_err_list, sq_err_node) {
+ nr = generate_flush_cqes(err_qp, cq, current_wc, entries_left,
+ &err_qp->ipz_squeue, 1);
+ entries_left -= nr;
+ current_wc += nr;
+
+ if (entries_left == 0)
+ break;
+ }
+
+ /* generate flush cqes for receive queues */
+ list_for_each_entry(err_qp, &my_cq->rqp_err_list, rq_err_node) {
+ nr = generate_flush_cqes(err_qp, cq, current_wc, entries_left,
+ &err_qp->ipz_rqueue, 0);
+ entries_left -= nr;
+ current_wc += nr;
+
+ if (entries_left == 0)
+ break;
+ }
+
+ for (nr = 0; nr < entries_left; nr++) {
ret = ehca_poll_cq_one(cq, current_wc);
if (ret)
break;
current_wc++;
} /* eof for nr */
+ entries_left -= nr;
+
spin_unlock_irqrestore(&my_cq->spinlock, flags);
if (ret == -EAGAIN || !ret)
- ret = nr;
+ ret = num_entries - entries_left;
poll_cq_exit0:
return ret;
diff --git a/drivers/infiniband/hw/ipath/ipath_rc.c b/drivers/infiniband/hw/ipath/ipath_rc.c
index 97710522624..7b93cda1a4b 100644
--- a/drivers/infiniband/hw/ipath/ipath_rc.c
+++ b/drivers/infiniband/hw/ipath/ipath_rc.c
@@ -675,7 +675,8 @@ static void send_rc_ack(struct ipath_qp *qp)
hdr.lrh[0] = cpu_to_be16(lrh0);
hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid);
hdr.lrh[2] = cpu_to_be16(hwords + SIZE_OF_CRC);
- hdr.lrh[3] = cpu_to_be16(dd->ipath_lid);
+ hdr.lrh[3] = cpu_to_be16(dd->ipath_lid |
+ qp->remote_ah_attr.src_path_bits);
ohdr->bth[0] = cpu_to_be32(bth0);
ohdr->bth[1] = cpu_to_be32(qp->remote_qpn);
ohdr->bth[2] = cpu_to_be32(qp->r_ack_psn & IPATH_PSN_MASK);
diff --git a/drivers/infiniband/hw/ipath/ipath_ruc.c b/drivers/infiniband/hw/ipath/ipath_ruc.c
index af051f75766..fc0f6d9e603 100644
--- a/drivers/infiniband/hw/ipath/ipath_ruc.c
+++ b/drivers/infiniband/hw/ipath/ipath_ruc.c
@@ -618,7 +618,8 @@ void ipath_make_ruc_header(struct ipath_ibdev *dev, struct ipath_qp *qp,
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);
+ qp->s_hdr.lrh[3] = cpu_to_be16(dev->dd->ipath_lid |
+ qp->remote_ah_attr.src_path_bits);
bth0 |= ipath_get_pkey(dev->dd, qp->s_pkey_index);
bth0 |= extra_bytes << 20;
ohdr->bth[0] = cpu_to_be32(bth0 | (1 << 22));
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c
index b766e40e9eb..eabc4247860 100644
--- a/drivers/infiniband/hw/ipath/ipath_verbs.c
+++ b/drivers/infiniband/hw/ipath/ipath_verbs.c
@@ -340,9 +340,16 @@ static int ipath_post_one_send(struct ipath_qp *qp, struct ib_send_wr *wr)
int acc;
int ret;
unsigned long flags;
+ struct ipath_devdata *dd = to_idev(qp->ibqp.device)->dd;
spin_lock_irqsave(&qp->s_lock, flags);
+ if (qp->ibqp.qp_type != IB_QPT_SMI &&
+ !(dd->ipath_flags & IPATH_LINKACTIVE)) {
+ ret = -ENETDOWN;
+ goto bail;
+ }
+
/* Check that state is OK to post send. */
if (unlikely(!(ib_ipath_state_ops[qp->state] & IPATH_POST_SEND_OK)))
goto bail_inval;
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c
index f29dbb767e8..baa01deb243 100644
--- a/drivers/infiniband/hw/mlx4/qp.c
+++ b/drivers/infiniband/hw/mlx4/qp.c
@@ -1058,6 +1058,9 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
else
sqd_event = 0;
+ if (!ibqp->uobject && cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT)
+ context->rlkey |= (1 << 4);
+
/*
* Before passing a kernel QP to the HW, make sure that the
* ownership bits of the send queue are set and the SQ
@@ -1342,6 +1345,12 @@ static __be32 convert_access(int acc)
static void set_fmr_seg(struct mlx4_wqe_fmr_seg *fseg, struct ib_send_wr *wr)
{
struct mlx4_ib_fast_reg_page_list *mfrpl = to_mfrpl(wr->wr.fast_reg.page_list);
+ int i;
+
+ for (i = 0; i < wr->wr.fast_reg.page_list_len; ++i)
+ wr->wr.fast_reg.page_list->page_list[i] =
+ cpu_to_be64(wr->wr.fast_reg.page_list->page_list[i] |
+ MLX4_MTT_FLAG_PRESENT);
fseg->flags = convert_access(wr->wr.fast_reg.access_flags);
fseg->mem_key = cpu_to_be32(wr->wr.fast_reg.rkey);
diff --git a/drivers/infiniband/hw/mthca/mthca_catas.c b/drivers/infiniband/hw/mthca/mthca_catas.c
index cc440f90000..65ad359fdf1 100644
--- a/drivers/infiniband/hw/mthca/mthca_catas.c
+++ b/drivers/infiniband/hw/mthca/mthca_catas.c
@@ -149,18 +149,10 @@ void mthca_start_catas_poll(struct mthca_dev *dev)
((pci_resource_len(dev->pdev, 0) - 1) &
dev->catas_err.addr);
- if (!request_mem_region(addr, dev->catas_err.size * 4,
- DRV_NAME)) {
- mthca_warn(dev, "couldn't request catastrophic error region "
- "at 0x%lx/0x%x\n", addr, dev->catas_err.size * 4);
- return;
- }
-
dev->catas_err.map = ioremap(addr, dev->catas_err.size * 4);
if (!dev->catas_err.map) {
mthca_warn(dev, "couldn't map catastrophic error region "
"at 0x%lx/0x%x\n", addr, dev->catas_err.size * 4);
- release_mem_region(addr, dev->catas_err.size * 4);
return;
}
@@ -175,13 +167,8 @@ void mthca_stop_catas_poll(struct mthca_dev *dev)
{
del_timer_sync(&dev->catas_err.timer);
- if (dev->catas_err.map) {
+ if (dev->catas_err.map)
iounmap(dev->catas_err.map);
- release_mem_region(pci_resource_start(dev->pdev, 0) +
- ((pci_resource_len(dev->pdev, 0) - 1) &
- dev->catas_err.addr),
- dev->catas_err.size * 4);
- }
spin_lock_irq(&catas_lock);
list_del(&dev->catas_err.list);
diff --git a/drivers/infiniband/hw/mthca/mthca_eq.c b/drivers/infiniband/hw/mthca/mthca_eq.c
index cc6858f0b65..28f0e0c40d7 100644
--- a/drivers/infiniband/hw/mthca/mthca_eq.c
+++ b/drivers/infiniband/hw/mthca/mthca_eq.c
@@ -652,27 +652,13 @@ static int mthca_map_reg(struct mthca_dev *dev,
{
unsigned long base = pci_resource_start(dev->pdev, 0);
- if (!request_mem_region(base + offset, size, DRV_NAME))
- return -EBUSY;
-
*map = ioremap(base + offset, size);
- if (!*map) {
- release_mem_region(base + offset, size);
+ if (!*map)
return -ENOMEM;
- }
return 0;
}
-static void mthca_unmap_reg(struct mthca_dev *dev, unsigned long offset,
- unsigned long size, void __iomem *map)
-{
- unsigned long base = pci_resource_start(dev->pdev, 0);
-
- release_mem_region(base + offset, size);
- iounmap(map);
-}
-
static int mthca_map_eq_regs(struct mthca_dev *dev)
{
if (mthca_is_memfree(dev)) {
@@ -699,9 +685,7 @@ static int mthca_map_eq_regs(struct mthca_dev *dev)
dev->fw.arbel.eq_arm_base) + 4, 4,
&dev->eq_regs.arbel.eq_arm)) {
mthca_err(dev, "Couldn't map EQ arm register, aborting.\n");
- mthca_unmap_reg(dev, (pci_resource_len(dev->pdev, 0) - 1) &
- dev->fw.arbel.clr_int_base, MTHCA_CLR_INT_SIZE,
- dev->clr_base);
+ iounmap(dev->clr_base);
return -ENOMEM;
}
@@ -710,12 +694,8 @@ static int mthca_map_eq_regs(struct mthca_dev *dev)
MTHCA_EQ_SET_CI_SIZE,
&dev->eq_regs.arbel.eq_set_ci_base)) {
mthca_err(dev, "Couldn't map EQ CI register, aborting.\n");
- mthca_unmap_reg(dev, ((pci_resource_len(dev->pdev, 0) - 1) &
- dev->fw.arbel.eq_arm_base) + 4, 4,
- dev->eq_regs.arbel.eq_arm);
- mthca_unmap_reg(dev, (pci_resource_len(dev->pdev, 0) - 1) &
- dev->fw.arbel.clr_int_base, MTHCA_CLR_INT_SIZE,
- dev->clr_base);
+ iounmap(dev->eq_regs.arbel.eq_arm);
+ iounmap(dev->clr_base);
return -ENOMEM;
}
} else {
@@ -731,8 +711,7 @@ static int mthca_map_eq_regs(struct mthca_dev *dev)
&dev->eq_regs.tavor.ecr_base)) {
mthca_err(dev, "Couldn't map ecr register, "
"aborting.\n");
- mthca_unmap_reg(dev, MTHCA_CLR_INT_BASE, MTHCA_CLR_INT_SIZE,
- dev->clr_base);
+ iounmap(dev->clr_base);
return -ENOMEM;
}
}
@@ -744,22 +723,12 @@ static int mthca_map_eq_regs(struct mthca_dev *dev)
static void mthca_unmap_eq_regs(struct mthca_dev *dev)
{
if (mthca_is_memfree(dev)) {
- mthca_unmap_reg(dev, (pci_resource_len(dev->pdev, 0) - 1) &
- dev->fw.arbel.eq_set_ci_base,
- MTHCA_EQ_SET_CI_SIZE,
- dev->eq_regs.arbel.eq_set_ci_base);
- mthca_unmap_reg(dev, ((pci_resource_len(dev->pdev, 0) - 1) &
- dev->fw.arbel.eq_arm_base) + 4, 4,
- dev->eq_regs.arbel.eq_arm);
- mthca_unmap_reg(dev, (pci_resource_len(dev->pdev, 0) - 1) &
- dev->fw.arbel.clr_int_base, MTHCA_CLR_INT_SIZE,
- dev->clr_base);
+ iounmap(dev->eq_regs.arbel.eq_set_ci_base);
+ iounmap(dev->eq_regs.arbel.eq_arm);
+ iounmap(dev->clr_base);
} else {
- mthca_unmap_reg(dev, MTHCA_ECR_BASE,
- MTHCA_ECR_SIZE + MTHCA_ECR_CLR_SIZE,
- dev->eq_regs.tavor.ecr_base);
- mthca_unmap_reg(dev, MTHCA_CLR_INT_BASE, MTHCA_CLR_INT_SIZE,
- dev->clr_base);
+ iounmap(dev->eq_regs.tavor.ecr_base);
+ iounmap(dev->clr_base);
}
}
diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c
index fb9f91b60f3..52f60f4eea0 100644
--- a/drivers/infiniband/hw/mthca/mthca_main.c
+++ b/drivers/infiniband/hw/mthca/mthca_main.c
@@ -921,58 +921,6 @@ err_uar_table_free:
return err;
}
-static int mthca_request_regions(struct pci_dev *pdev, int ddr_hidden)
-{
- int err;
-
- /*
- * We can't just use pci_request_regions() because the MSI-X
- * table is right in the middle of the first BAR. If we did
- * pci_request_region and grab all of the first BAR, then
- * setting up MSI-X would fail, since the PCI core wants to do
- * request_mem_region on the MSI-X vector table.
- *
- * So just request what we need right now, and request any
- * other regions we need when setting up EQs.
- */
- if (!request_mem_region(pci_resource_start(pdev, 0) + MTHCA_HCR_BASE,
- MTHCA_HCR_SIZE, DRV_NAME))
- return -EBUSY;
-
- err = pci_request_region(pdev, 2, DRV_NAME);
- if (err)
- goto err_bar2_failed;
-
- if (!ddr_hidden) {
- err = pci_request_region(pdev, 4, DRV_NAME);
- if (err)
- goto err_bar4_failed;
- }
-
- return 0;
-
-err_bar4_failed:
- pci_release_region(pdev, 2);
-
-err_bar2_failed:
- release_mem_region(pci_resource_start(pdev, 0) + MTHCA_HCR_BASE,
- MTHCA_HCR_SIZE);
-
- return err;
-}
-
-static void mthca_release_regions(struct pci_dev *pdev,
- int ddr_hidden)
-{
- if (!ddr_hidden)
- pci_release_region(pdev, 4);
-
- pci_release_region(pdev, 2);
-
- release_mem_region(pci_resource_start(pdev, 0) + MTHCA_HCR_BASE,
- MTHCA_HCR_SIZE);
-}
-
static int mthca_enable_msi_x(struct mthca_dev *mdev)
{
struct msix_entry entries[3];
@@ -1059,7 +1007,7 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type)
if (!(pci_resource_flags(pdev, 4) & IORESOURCE_MEM))
ddr_hidden = 1;
- err = mthca_request_regions(pdev, ddr_hidden);
+ err = pci_request_regions(pdev, DRV_NAME);
if (err) {
dev_err(&pdev->dev, "Cannot obtain PCI resources, "
"aborting.\n");
@@ -1196,7 +1144,7 @@ err_free_dev:
ib_dealloc_device(&mdev->ib_dev);
err_free_res:
- mthca_release_regions(pdev, ddr_hidden);
+ pci_release_regions(pdev);
err_disable_pdev:
pci_disable_device(pdev);
@@ -1240,8 +1188,7 @@ static void __mthca_remove_one(struct pci_dev *pdev)
pci_disable_msix(pdev);
ib_dealloc_device(&mdev->ib_dev);
- mthca_release_regions(pdev, mdev->mthca_flags &
- MTHCA_FLAG_DDR_HIDDEN);
+ pci_release_regions(pdev);
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
}
diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c
index b0cab64e5e3..a2b04d62b1a 100644
--- a/drivers/infiniband/hw/nes/nes.c
+++ b/drivers/infiniband/hw/nes/nes.c
@@ -70,27 +70,31 @@ int interrupt_mod_interval = 0;
/* Interoperability */
int mpa_version = 1;
-module_param(mpa_version, int, 0);
+module_param(mpa_version, int, 0644);
MODULE_PARM_DESC(mpa_version, "MPA version to be used int MPA Req/Resp (0 or 1)");
/* Interoperability */
int disable_mpa_crc = 0;
-module_param(disable_mpa_crc, int, 0);
+module_param(disable_mpa_crc, int, 0644);
MODULE_PARM_DESC(disable_mpa_crc, "Disable checking of MPA CRC");
unsigned int send_first = 0;
-module_param(send_first, int, 0);
+module_param(send_first, int, 0644);
MODULE_PARM_DESC(send_first, "Send RDMA Message First on Active Connection");
unsigned int nes_drv_opt = 0;
-module_param(nes_drv_opt, int, 0);
+module_param(nes_drv_opt, int, 0644);
MODULE_PARM_DESC(nes_drv_opt, "Driver option parameters");
unsigned int nes_debug_level = 0;
module_param_named(debug_level, nes_debug_level, uint, 0644);
MODULE_PARM_DESC(debug_level, "Enable debug output level");
+unsigned int wqm_quanta = 0x10000;
+module_param(wqm_quanta, int, 0644);
+MODULE_PARM_DESC(wqm_quanta, "WQM quanta");
+
LIST_HEAD(nes_adapter_list);
static LIST_HEAD(nes_dev_list);
@@ -557,12 +561,32 @@ static int __devinit nes_probe(struct pci_dev *pcidev, const struct pci_device_i
goto bail5;
}
nesdev->nesadapter->et_rx_coalesce_usecs_irq = interrupt_mod_interval;
+ nesdev->nesadapter->wqm_quanta = wqm_quanta;
/* nesdev->base_doorbell_index =
nesdev->nesadapter->pd_config_base[PCI_FUNC(nesdev->pcidev->devfn)]; */
nesdev->base_doorbell_index = 1;
nesdev->doorbell_start = nesdev->nesadapter->doorbell_start;
- nesdev->mac_index = PCI_FUNC(nesdev->pcidev->devfn) % nesdev->nesadapter->port_count;
+ if (nesdev->nesadapter->phy_type[0] == NES_PHY_TYPE_PUMA_1G) {
+ switch (PCI_FUNC(nesdev->pcidev->devfn) %
+ nesdev->nesadapter->port_count) {
+ case 1:
+ nesdev->mac_index = 2;
+ break;
+ case 2:
+ nesdev->mac_index = 1;
+ break;
+ case 3:
+ nesdev->mac_index = 3;
+ break;
+ case 0:
+ default:
+ nesdev->mac_index = 0;
+ }
+ } else {
+ nesdev->mac_index = PCI_FUNC(nesdev->pcidev->devfn) %
+ nesdev->nesadapter->port_count;
+ }
tasklet_init(&nesdev->dpc_tasklet, nes_dpc, (unsigned long)nesdev);
@@ -581,7 +605,7 @@ static int __devinit nes_probe(struct pci_dev *pcidev, const struct pci_device_i
nesdev->int_req = (0x101 << PCI_FUNC(nesdev->pcidev->devfn)) |
(1 << (PCI_FUNC(nesdev->pcidev->devfn)+16));
if (PCI_FUNC(nesdev->pcidev->devfn) < 4) {
- nesdev->int_req |= (1 << (PCI_FUNC(nesdev->pcidev->devfn)+24));
+ nesdev->int_req |= (1 << (PCI_FUNC(nesdev->mac_index)+24));
}
/* TODO: This really should be the first driver to load, not function 0 */
@@ -772,14 +796,14 @@ static ssize_t nes_show_adapter(struct device_driver *ddp, char *buf)
list_for_each_entry(nesdev, &nes_dev_list, list) {
if (i == ee_flsh_adapter) {
- devfn = nesdev->nesadapter->devfn;
- bus_number = nesdev->nesadapter->bus_number;
+ devfn = nesdev->pcidev->devfn;
+ bus_number = nesdev->pcidev->bus->number;
break;
}
i++;
}
- return snprintf(buf, PAGE_SIZE, "%x:%x", bus_number, devfn);
+ return snprintf(buf, PAGE_SIZE, "%x:%x\n", bus_number, devfn);
}
static ssize_t nes_store_adapter(struct device_driver *ddp,
@@ -1050,6 +1074,55 @@ static ssize_t nes_store_idx_data(struct device_driver *ddp,
return strnlen(buf, count);
}
+
+/**
+ * nes_show_wqm_quanta
+ */
+static ssize_t nes_show_wqm_quanta(struct device_driver *ddp, char *buf)
+{
+ u32 wqm_quanta_value = 0xdead;
+ u32 i = 0;
+ struct nes_device *nesdev;
+
+ list_for_each_entry(nesdev, &nes_dev_list, list) {
+ if (i == ee_flsh_adapter) {
+ wqm_quanta_value = nesdev->nesadapter->wqm_quanta;
+ break;
+ }
+ i++;
+ }
+
+ return snprintf(buf, PAGE_SIZE, "0x%X\n", wqm_quanta);
+}
+
+
+/**
+ * nes_store_wqm_quanta
+ */
+static ssize_t nes_store_wqm_quanta(struct device_driver *ddp,
+ const char *buf, size_t count)
+{
+ unsigned long wqm_quanta_value;
+ u32 wqm_config1;
+ u32 i = 0;
+ struct nes_device *nesdev;
+
+ strict_strtoul(buf, 0, &wqm_quanta_value);
+ list_for_each_entry(nesdev, &nes_dev_list, list) {
+ if (i == ee_flsh_adapter) {
+ nesdev->nesadapter->wqm_quanta = wqm_quanta_value;
+ wqm_config1 = nes_read_indexed(nesdev,
+ NES_IDX_WQM_CONFIG1);
+ nes_write_indexed(nesdev, NES_IDX_WQM_CONFIG1,
+ ((wqm_quanta_value << 1) |
+ (wqm_config1 & 0x00000001)));
+ break;
+ }
+ i++;
+ }
+ return strnlen(buf, count);
+}
+
static DRIVER_ATTR(adapter, S_IRUSR | S_IWUSR,
nes_show_adapter, nes_store_adapter);
static DRIVER_ATTR(eeprom_cmd, S_IRUSR | S_IWUSR,
@@ -1068,6 +1141,8 @@ static DRIVER_ATTR(idx_addr, S_IRUSR | S_IWUSR,
nes_show_idx_addr, nes_store_idx_addr);
static DRIVER_ATTR(idx_data, S_IRUSR | S_IWUSR,
nes_show_idx_data, nes_store_idx_data);
+static DRIVER_ATTR(wqm_quanta, S_IRUSR | S_IWUSR,
+ nes_show_wqm_quanta, nes_store_wqm_quanta);
static int nes_create_driver_sysfs(struct pci_driver *drv)
{
@@ -1081,6 +1156,7 @@ static int nes_create_driver_sysfs(struct pci_driver *drv)
error |= driver_create_file(&drv->driver, &driver_attr_nonidx_data);
error |= driver_create_file(&drv->driver, &driver_attr_idx_addr);
error |= driver_create_file(&drv->driver, &driver_attr_idx_data);
+ error |= driver_create_file(&drv->driver, &driver_attr_wqm_quanta);
return error;
}
@@ -1095,6 +1171,7 @@ static void nes_remove_driver_sysfs(struct pci_driver *drv)
driver_remove_file(&drv->driver, &driver_attr_nonidx_data);
driver_remove_file(&drv->driver, &driver_attr_idx_addr);
driver_remove_file(&drv->driver, &driver_attr_idx_data);
+ driver_remove_file(&drv->driver, &driver_attr_wqm_quanta);
}
/**
diff --git a/drivers/infiniband/hw/nes/nes.h b/drivers/infiniband/hw/nes/nes.h
index 8eb7ae96974..1595dc7bba9 100644
--- a/drivers/infiniband/hw/nes/nes.h
+++ b/drivers/infiniband/hw/nes/nes.h
@@ -169,7 +169,7 @@ extern int disable_mpa_crc;
extern unsigned int send_first;
extern unsigned int nes_drv_opt;
extern unsigned int nes_debug_level;
-
+extern unsigned int wqm_quanta;
extern struct list_head nes_adapter_list;
extern atomic_t cm_connects;
diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c
index 9f0b964b2c9..2caf9da81ad 100644
--- a/drivers/infiniband/hw/nes/nes_cm.c
+++ b/drivers/infiniband/hw/nes/nes_cm.c
@@ -52,7 +52,7 @@
#include <linux/random.h>
#include <linux/list.h>
#include <linux/threads.h>
-
+#include <net/arp.h>
#include <net/neighbour.h>
#include <net/route.h>
#include <net/ip_fib.h>
@@ -1019,23 +1019,43 @@ static inline int mini_cm_accelerated(struct nes_cm_core *cm_core,
/**
- * nes_addr_send_arp
+ * nes_addr_resolve_neigh
*/
-static void nes_addr_send_arp(u32 dst_ip)
+static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip)
{
struct rtable *rt;
struct flowi fl;
+ struct neighbour *neigh;
+ int rc = -1;
+ DECLARE_MAC_BUF(mac);
memset(&fl, 0, sizeof fl);
fl.nl_u.ip4_u.daddr = htonl(dst_ip);
if (ip_route_output_key(&init_net, &rt, &fl)) {
printk("%s: ip_route_output_key failed for 0x%08X\n",
__func__, dst_ip);
- return;
+ return rc;
+ }
+
+ neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, nesvnic->netdev);
+ if (neigh) {
+ if (neigh->nud_state & NUD_VALID) {
+ nes_debug(NES_DBG_CM, "Neighbor MAC address for 0x%08X"
+ " is %s, Gateway is 0x%08X \n", dst_ip,
+ print_mac(mac, neigh->ha), ntohl(rt->rt_gateway));
+ nes_manage_arp_cache(nesvnic->netdev, neigh->ha,
+ dst_ip, NES_ARP_ADD);
+ rc = nes_arp_table(nesvnic->nesdev, dst_ip, NULL,
+ NES_ARP_RESOLVE);
+ }
+ neigh_release(neigh);
}
- neigh_event_send(rt->u.dst.neighbour, NULL);
+ if ((neigh == NULL) || (!(neigh->nud_state & NUD_VALID)))
+ neigh_event_send(rt->u.dst.neighbour, NULL);
+
ip_rt_put(rt);
+ return rc;
}
@@ -1108,9 +1128,11 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core,
/* get the mac addr for the remote node */
arpindex = nes_arp_table(nesdev, cm_node->rem_addr, NULL, NES_ARP_RESOLVE);
if (arpindex < 0) {
- kfree(cm_node);
- nes_addr_send_arp(cm_info->rem_addr);
- return NULL;
+ arpindex = nes_addr_resolve_neigh(nesvnic, cm_info->rem_addr);
+ if (arpindex < 0) {
+ kfree(cm_node);
+ return NULL;
+ }
}
/* copy the mac addr to node context */
@@ -1826,7 +1848,7 @@ static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *cm_core,
/**
* mini_cm_connect - make a connection node with params
*/
-struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core,
+static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core,
struct nes_vnic *nesvnic, u16 private_data_len,
void *private_data, struct nes_cm_info *cm_info)
{
@@ -1956,13 +1978,6 @@ static int mini_cm_reject(struct nes_cm_core *cm_core,
return ret;
cleanup_retrans_entry(cm_node);
cm_node->state = NES_CM_STATE_CLOSED;
- ret = send_fin(cm_node, NULL);
-
- if (cm_node->accept_pend) {
- BUG_ON(!cm_node->listener);
- atomic_dec(&cm_node->listener->pend_accepts_cnt);
- BUG_ON(atomic_read(&cm_node->listener->pend_accepts_cnt) < 0);
- }
ret = send_reset(cm_node, NULL);
return ret;
@@ -2014,7 +2029,6 @@ static int mini_cm_close(struct nes_cm_core *cm_core, struct nes_cm_node *cm_nod
ret = rem_ref_cm_node(cm_core, cm_node);
break;
}
- cm_node->cm_id = NULL;
return ret;
}
@@ -2383,6 +2397,7 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp)
atomic_inc(&cm_disconnects);
cm_event.event = IW_CM_EVENT_DISCONNECT;
if (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET) {
+ issued_disconnect_reset = 1;
cm_event.status = IW_CM_EVENT_STATUS_RESET;
nes_debug(NES_DBG_CM, "Generating a CM "
"Disconnect Event (status reset) for "
@@ -2508,7 +2523,6 @@ static int nes_disconnect(struct nes_qp *nesqp, int abrupt)
nes_debug(NES_DBG_CM, "Call close API\n");
g_cm_core->api->close(g_cm_core, nesqp->cm_node);
- nesqp->cm_node = NULL;
}
return ret;
@@ -2837,6 +2851,7 @@ int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
cm_node->apbvt_set = 1;
nesqp->cm_node = cm_node;
cm_node->nesqp = nesqp;
+ nes_add_ref(&nesqp->ibqp);
return 0;
}
@@ -3167,7 +3182,6 @@ static void cm_event_connect_error(struct nes_cm_event *event)
if (ret)
printk(KERN_ERR "%s[%u] OFA CM event_handler returned, "
"ret=%d\n", __func__, __LINE__, ret);
- nes_rem_ref(&nesqp->ibqp);
cm_id->rem_ref(cm_id);
rem_ref_cm_node(event->cm_node->cm_core, event->cm_node);
diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c
index 1513d4066f1..7c49cc882d7 100644
--- a/drivers/infiniband/hw/nes/nes_hw.c
+++ b/drivers/infiniband/hw/nes/nes_hw.c
@@ -55,18 +55,19 @@ u32 int_mod_cq_depth_24;
u32 int_mod_cq_depth_16;
u32 int_mod_cq_depth_4;
u32 int_mod_cq_depth_1;
-
+static const u8 nes_max_critical_error_count = 100;
#include "nes_cm.h"
static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq);
static void nes_init_csr_ne020(struct nes_device *nesdev, u8 hw_rev, u8 port_count);
static int nes_init_serdes(struct nes_device *nesdev, u8 hw_rev, u8 port_count,
- u8 OneG_Mode);
+ struct nes_adapter *nesadapter, u8 OneG_Mode);
static void nes_nic_napi_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq);
static void nes_process_aeq(struct nes_device *nesdev, struct nes_hw_aeq *aeq);
static void nes_process_ceq(struct nes_device *nesdev, struct nes_hw_ceq *ceq);
static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
struct nes_hw_aeqe *aeqe);
+static void process_critical_error(struct nes_device *nesdev);
static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number);
static unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_Mode);
@@ -222,11 +223,10 @@ static void nes_nic_tune_timer(struct nes_device *nesdev)
}
/* boundary checking */
- if (shared_timer->timer_in_use > NES_NIC_FAST_TIMER_HIGH)
- shared_timer->timer_in_use = NES_NIC_FAST_TIMER_HIGH;
- else if (shared_timer->timer_in_use < NES_NIC_FAST_TIMER_LOW) {
- shared_timer->timer_in_use = NES_NIC_FAST_TIMER_LOW;
- }
+ if (shared_timer->timer_in_use > shared_timer->threshold_high)
+ shared_timer->timer_in_use = shared_timer->threshold_high;
+ else if (shared_timer->timer_in_use < shared_timer->threshold_low)
+ shared_timer->timer_in_use = shared_timer->threshold_low;
nesdev->currcq_count = 0;
@@ -292,9 +292,6 @@ struct nes_adapter *nes_init_adapter(struct nes_device *nesdev, u8 hw_rev) {
if ((port_count = nes_reset_adapter_ne020(nesdev, &OneG_Mode)) == 0)
return NULL;
- if (nes_init_serdes(nesdev, hw_rev, port_count, OneG_Mode))
- return NULL;
- nes_init_csr_ne020(nesdev, hw_rev, port_count);
max_qp = nes_read_indexed(nesdev, NES_IDX_QP_CTX_SIZE);
nes_debug(NES_DBG_INIT, "QP_CTX_SIZE=%u\n", max_qp);
@@ -353,6 +350,22 @@ struct nes_adapter *nes_init_adapter(struct nes_device *nesdev, u8 hw_rev) {
nes_debug(NES_DBG_INIT, "Allocating new nesadapter @ %p, size = %u (actual size = %u).\n",
nesadapter, (u32)sizeof(struct nes_adapter), adapter_size);
+ if (nes_read_eeprom_values(nesdev, nesadapter)) {
+ printk(KERN_ERR PFX "Unable to read EEPROM data.\n");
+ kfree(nesadapter);
+ return NULL;
+ }
+
+ if (nes_init_serdes(nesdev, hw_rev, port_count, nesadapter,
+ OneG_Mode)) {
+ kfree(nesadapter);
+ return NULL;
+ }
+ nes_init_csr_ne020(nesdev, hw_rev, port_count);
+
+ memset(nesadapter->pft_mcast_map, 255,
+ sizeof nesadapter->pft_mcast_map);
+
/* populate the new nesadapter */
nesadapter->devfn = nesdev->pcidev->devfn;
nesadapter->bus_number = nesdev->pcidev->bus->number;
@@ -468,20 +481,25 @@ struct nes_adapter *nes_init_adapter(struct nes_device *nesdev, u8 hw_rev) {
/* setup port configuration */
if (nesadapter->port_count == 1) {
- u32temp = 0x00000000;
+ nesadapter->log_port = 0x00000000;
if (nes_drv_opt & NES_DRV_OPT_DUAL_LOGICAL_PORT)
nes_write_indexed(nesdev, NES_IDX_TX_POOL_SIZE, 0x00000002);
else
nes_write_indexed(nesdev, NES_IDX_TX_POOL_SIZE, 0x00000003);
} else {
- if (nesadapter->port_count == 2)
- u32temp = 0x00000044;
- else
- u32temp = 0x000000e4;
+ if (nesadapter->phy_type[0] == NES_PHY_TYPE_PUMA_1G) {
+ nesadapter->log_port = 0x000000D8;
+ } else {
+ if (nesadapter->port_count == 2)
+ nesadapter->log_port = 0x00000044;
+ else
+ nesadapter->log_port = 0x000000e4;
+ }
nes_write_indexed(nesdev, NES_IDX_TX_POOL_SIZE, 0x00000003);
}
- nes_write_indexed(nesdev, NES_IDX_NIC_LOGPORT_TO_PHYPORT, u32temp);
+ nes_write_indexed(nesdev, NES_IDX_NIC_LOGPORT_TO_PHYPORT,
+ nesadapter->log_port);
nes_debug(NES_DBG_INIT, "Probe time, LOG2PHY=%u\n",
nes_read_indexed(nesdev, NES_IDX_NIC_LOGPORT_TO_PHYPORT));
@@ -706,23 +724,43 @@ static unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_
* nes_init_serdes
*/
static int nes_init_serdes(struct nes_device *nesdev, u8 hw_rev, u8 port_count,
- u8 OneG_Mode)
+ struct nes_adapter *nesadapter, u8 OneG_Mode)
{
int i;
u32 u32temp;
+ u32 serdes_common_control;
if (hw_rev != NE020_REV) {
/* init serdes 0 */
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000000FF);
- if (!OneG_Mode)
+ if (nesadapter->phy_type[0] == NES_PHY_TYPE_PUMA_1G) {
+ serdes_common_control = nes_read_indexed(nesdev,
+ NES_IDX_ETH_SERDES_COMMON_CONTROL0);
+ serdes_common_control |= 0x000000100;
+ nes_write_indexed(nesdev,
+ NES_IDX_ETH_SERDES_COMMON_CONTROL0,
+ serdes_common_control);
+ } else if (!OneG_Mode) {
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_HIGHZ_LANE_MODE0, 0x11110000);
- if (port_count > 1) {
+ }
+ if (((port_count > 1) &&
+ (nesadapter->phy_type[0] != NES_PHY_TYPE_PUMA_1G)) ||
+ ((port_count > 2) &&
+ (nesadapter->phy_type[0] == NES_PHY_TYPE_PUMA_1G))) {
/* init serdes 1 */
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL1, 0x000000FF);
- if (!OneG_Mode)
+ if (nesadapter->phy_type[0] == NES_PHY_TYPE_PUMA_1G) {
+ serdes_common_control = nes_read_indexed(nesdev,
+ NES_IDX_ETH_SERDES_COMMON_CONTROL1);
+ serdes_common_control |= 0x000000100;
+ nes_write_indexed(nesdev,
+ NES_IDX_ETH_SERDES_COMMON_CONTROL1,
+ serdes_common_control);
+ } else if (!OneG_Mode) {
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_HIGHZ_LANE_MODE1, 0x11110000);
}
+ }
} else {
/* init serdes 0 */
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0, 0x00000008);
@@ -826,7 +864,8 @@ static void nes_init_csr_ne020(struct nes_device *nesdev, u8 hw_rev, u8 port_cou
nes_write_indexed(nesdev, 0x00005000, 0x00018000);
/* nes_write_indexed(nesdev, 0x00005000, 0x00010000); */
- nes_write_indexed(nesdev, 0x00005004, 0x00020001);
+ nes_write_indexed(nesdev, NES_IDX_WQM_CONFIG1, (wqm_quanta << 1) |
+ 0x00000001);
nes_write_indexed(nesdev, 0x00005008, 0x1F1F1F1F);
nes_write_indexed(nesdev, 0x00005010, 0x1F1F1F1F);
nes_write_indexed(nesdev, 0x00005018, 0x1F1F1F1F);
@@ -1226,6 +1265,7 @@ int nes_init_phy(struct nes_device *nesdev)
if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_1G) {
printk(PFX "%s: Programming mdc config for 1G\n", __func__);
tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG);
+ tx_config &= 0xFFFFFFE3;
tx_config |= 0x04;
nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config);
}
@@ -1291,7 +1331,8 @@ int nes_init_phy(struct nes_device *nesdev)
(nesadapter->phy_type[mac_index] == NES_PHY_TYPE_ARGUS)) {
/* setup 10G MDIO operation */
tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG);
- tx_config |= 0x14;
+ tx_config &= 0xFFFFFFE3;
+ tx_config |= 0x15;
nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config);
}
if ((nesadapter->phy_type[mac_index] == NES_PHY_TYPE_ARGUS)) {
@@ -1315,7 +1356,7 @@ int nes_init_phy(struct nes_device *nesdev)
nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc319, 0x0008);
nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc31a, 0x0098);
nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0x0026, 0x0E00);
- nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0x0027, 0x0000);
+ nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0x0027, 0x0001);
nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0x0028, 0xA528);
/*
@@ -1759,9 +1800,14 @@ int nes_init_nic_qp(struct nes_device *nesdev, struct net_device *netdev)
*/
void nes_destroy_nic_qp(struct nes_vnic *nesvnic)
{
+ u64 u64temp;
+ dma_addr_t bus_address;
struct nes_device *nesdev = nesvnic->nesdev;
struct nes_hw_cqp_wqe *cqp_wqe;
+ struct nes_hw_nic_sq_wqe *nic_sqe;
struct nes_hw_nic_rq_wqe *nic_rqe;
+ __le16 *wqe_fragment_length;
+ u16 wqe_fragment_index;
u64 wqe_frag;
u32 cqp_head;
unsigned long flags;
@@ -1770,14 +1816,69 @@ void nes_destroy_nic_qp(struct nes_vnic *nesvnic)
/* Free remaining NIC receive buffers */
while (nesvnic->nic.rq_head != nesvnic->nic.rq_tail) {
nic_rqe = &nesvnic->nic.rq_vbase[nesvnic->nic.rq_tail];
- wqe_frag = (u64)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX]);
- wqe_frag |= ((u64)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX])) << 32;
+ wqe_frag = (u64)le32_to_cpu(
+ nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX]);
+ wqe_frag |= ((u64)le32_to_cpu(
+ nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX]))<<32;
pci_unmap_single(nesdev->pcidev, (dma_addr_t)wqe_frag,
nesvnic->max_frame_size, PCI_DMA_FROMDEVICE);
dev_kfree_skb(nesvnic->nic.rx_skb[nesvnic->nic.rq_tail++]);
nesvnic->nic.rq_tail &= (nesvnic->nic.rq_size - 1);
}
+ /* Free remaining NIC transmit buffers */
+ while (nesvnic->nic.sq_head != nesvnic->nic.sq_tail) {
+ nic_sqe = &nesvnic->nic.sq_vbase[nesvnic->nic.sq_tail];
+ wqe_fragment_index = 1;
+ wqe_fragment_length = (__le16 *)
+ &nic_sqe->wqe_words[NES_NIC_SQ_WQE_LENGTH_0_TAG_IDX];
+ /* bump past the vlan tag */
+ wqe_fragment_length++;
+ if (le16_to_cpu(wqe_fragment_length[wqe_fragment_index]) != 0) {
+ u64temp = (u64)le32_to_cpu(
+ nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX+
+ wqe_fragment_index*2]);
+ u64temp += ((u64)le32_to_cpu(
+ nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX
+ + wqe_fragment_index*2]))<<32;
+ bus_address = (dma_addr_t)u64temp;
+ if (test_and_clear_bit(nesvnic->nic.sq_tail,
+ nesvnic->nic.first_frag_overflow)) {
+ pci_unmap_single(nesdev->pcidev,
+ bus_address,
+ le16_to_cpu(wqe_fragment_length[
+ wqe_fragment_index++]),
+ PCI_DMA_TODEVICE);
+ }
+ for (; wqe_fragment_index < 5; wqe_fragment_index++) {
+ if (wqe_fragment_length[wqe_fragment_index]) {
+ u64temp = le32_to_cpu(
+ nic_sqe->wqe_words[
+ NES_NIC_SQ_WQE_FRAG0_LOW_IDX+
+ wqe_fragment_index*2]);
+ u64temp += ((u64)le32_to_cpu(
+ nic_sqe->wqe_words[
+ NES_NIC_SQ_WQE_FRAG0_HIGH_IDX+
+ wqe_fragment_index*2]))<<32;
+ bus_address = (dma_addr_t)u64temp;
+ pci_unmap_page(nesdev->pcidev,
+ bus_address,
+ le16_to_cpu(
+ wqe_fragment_length[
+ wqe_fragment_index]),
+ PCI_DMA_TODEVICE);
+ } else
+ break;
+ }
+ }
+ if (nesvnic->nic.tx_skb[nesvnic->nic.sq_tail])
+ dev_kfree_skb(
+ nesvnic->nic.tx_skb[nesvnic->nic.sq_tail]);
+
+ nesvnic->nic.sq_tail = (++nesvnic->nic.sq_tail)
+ & (nesvnic->nic.sq_size - 1);
+ }
+
spin_lock_irqsave(&nesdev->cqp.lock, flags);
/* Destroy NIC QP */
@@ -1894,7 +1995,30 @@ int nes_napi_isr(struct nes_device *nesdev)
}
}
-
+static void process_critical_error(struct nes_device *nesdev)
+{
+ u32 debug_error;
+ u32 nes_idx_debug_error_masks0 = 0;
+ u16 error_module = 0;
+
+ debug_error = nes_read_indexed(nesdev, NES_IDX_DEBUG_ERROR_CONTROL_STATUS);
+ printk(KERN_ERR PFX "Critical Error reported by device!!! 0x%02X\n",
+ (u16)debug_error);
+ nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_CONTROL_STATUS,
+ 0x01010000 | (debug_error & 0x0000ffff));
+ if (crit_err_count++ > 10)
+ nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_MASKS1, 1 << 0x17);
+ error_module = (u16) (debug_error & 0x1F00) >> 8;
+ if (++nesdev->nesadapter->crit_error_count[error_module-1] >=
+ nes_max_critical_error_count) {
+ printk(KERN_ERR PFX "Masking off critical error for module "
+ "0x%02X\n", (u16)error_module);
+ nes_idx_debug_error_masks0 = nes_read_indexed(nesdev,
+ NES_IDX_DEBUG_ERROR_MASKS0);
+ nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_MASKS0,
+ nes_idx_debug_error_masks0 | (1 << error_module));
+ }
+}
/**
* nes_dpc
*/
@@ -1909,7 +2033,6 @@ void nes_dpc(unsigned long param)
u32 timer_stat;
u32 temp_int_stat;
u32 intf_int_stat;
- u32 debug_error;
u32 processed_intf_int = 0;
u16 processed_timer_int = 0;
u16 completion_ints = 0;
@@ -1987,14 +2110,7 @@ void nes_dpc(unsigned long param)
intf_int_stat = nes_read32(nesdev->regs+NES_INTF_INT_STAT);
intf_int_stat &= nesdev->intf_int_req;
if (NES_INTF_INT_CRITERR & intf_int_stat) {
- debug_error = nes_read_indexed(nesdev, NES_IDX_DEBUG_ERROR_CONTROL_STATUS);
- printk(KERN_ERR PFX "Critical Error reported by device!!! 0x%02X\n",
- (u16)debug_error);
- nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_CONTROL_STATUS,
- 0x01010000 | (debug_error & 0x0000ffff));
- /* BUG(); */
- if (crit_err_count++ > 10)
- nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_MASKS1, 1 << 0x17);
+ process_critical_error(nesdev);
}
if (NES_INTF_INT_PCIERR & intf_int_stat) {
printk(KERN_ERR PFX "PCI Error reported by device!!!\n");
@@ -2258,7 +2374,8 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number)
spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
}
/* read the PHY interrupt status register */
- if (nesadapter->OneG_Mode) {
+ if ((nesadapter->OneG_Mode) &&
+ (nesadapter->phy_type[mac_index] != NES_PHY_TYPE_PUMA_1G)) {
do {
nes_read_1G_phy_reg(nesdev, 0x1a,
nesadapter->phy_index[mac_index], &phy_data);
@@ -3077,6 +3194,22 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
nes_cm_disconn(nesqp);
break;
/* TODO: additional AEs need to be here */
+ case NES_AEQE_AEID_AMP_BOUNDS_VIOLATION:
+ nesqp = *((struct nes_qp **)&context);
+ spin_lock_irqsave(&nesqp->lock, flags);
+ nesqp->hw_iwarp_state = iwarp_state;
+ nesqp->hw_tcp_state = tcp_state;
+ nesqp->last_aeq = async_event_id;
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ if (nesqp->ibqp.event_handler) {
+ ibevent.device = nesqp->ibqp.device;
+ ibevent.element.qp = &nesqp->ibqp;
+ ibevent.event = IB_EVENT_QP_ACCESS_ERR;
+ nesqp->ibqp.event_handler(&ibevent,
+ nesqp->ibqp.qp_context);
+ }
+ nes_cm_disconn(nesqp);
+ break;
default:
nes_debug(NES_DBG_AEQ, "Processing an iWARP related AE for QP, misc = 0x%04X\n",
async_event_id);
diff --git a/drivers/infiniband/hw/nes/nes_hw.h b/drivers/infiniband/hw/nes/nes_hw.h
index 7b81e0ae007..610b9d85959 100644
--- a/drivers/infiniband/hw/nes/nes_hw.h
+++ b/drivers/infiniband/hw/nes/nes_hw.h
@@ -156,6 +156,7 @@ enum indexed_regs {
NES_IDX_ENDNODE0_NSTAT_TX_OCTETS_HI = 0x7004,
NES_IDX_ENDNODE0_NSTAT_TX_FRAMES_LO = 0x7008,
NES_IDX_ENDNODE0_NSTAT_TX_FRAMES_HI = 0x700c,
+ NES_IDX_WQM_CONFIG1 = 0x5004,
NES_IDX_CM_CONFIG = 0x5100,
NES_IDX_NIC_LOGPORT_TO_PHYPORT = 0x6000,
NES_IDX_NIC_PHYPORT_TO_USW = 0x6008,
@@ -967,6 +968,7 @@ struct nes_arp_entry {
#define DEFAULT_JUMBO_NES_QL_TARGET 40
#define DEFAULT_JUMBO_NES_QL_HIGH 128
#define NES_NIC_CQ_DOWNWARD_TREND 16
+#define NES_PFT_SIZE 48
struct nes_hw_tune_timer {
/* u16 cq_count; */
@@ -1079,6 +1081,7 @@ struct nes_adapter {
u32 et_rx_max_coalesced_frames_high;
u32 et_rate_sample_interval;
u32 timer_int_limit;
+ u32 wqm_quanta;
/* Adapter base MAC address */
u32 mac_addr_low;
@@ -1094,12 +1097,14 @@ struct nes_adapter {
u16 pd_config_base[4];
u16 link_interrupt_count[4];
+ u8 crit_error_count[32];
/* the phy index for each port */
u8 phy_index[4];
u8 mac_sw_state[4];
u8 mac_link_down[4];
u8 phy_type[4];
+ u8 log_port;
/* PCI information */
unsigned int devfn;
@@ -1113,6 +1118,7 @@ struct nes_adapter {
u8 virtwq;
u8 et_use_adaptive_rx_coalesce;
u8 adapter_fcn_count;
+ u8 pft_mcast_map[NES_PFT_SIZE];
};
struct nes_pbl {
diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c
index 1b0938c8777..730358637bb 100644
--- a/drivers/infiniband/hw/nes/nes_nic.c
+++ b/drivers/infiniband/hw/nes/nes_nic.c
@@ -91,6 +91,7 @@ static struct nic_qp_map *nic_qp_mapping_per_function[] = {
static const u32 default_msg = NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK
| NETIF_MSG_IFUP | NETIF_MSG_IFDOWN;
static int debug = -1;
+static int nics_per_function = 1;
/**
* nes_netdev_poll
@@ -201,7 +202,8 @@ static int nes_netdev_open(struct net_device *netdev)
nes_debug(NES_DBG_NETDEV, "i=%d, perfect filter table index= %d, PERF FILTER LOW"
" (Addr:%08X) = %08X, HIGH = %08X.\n",
i, nesvnic->qp_nic_index[i],
- NES_IDX_PERFECT_FILTER_LOW+((nesvnic->perfect_filter_index + i) * 8),
+ NES_IDX_PERFECT_FILTER_LOW+
+ (nesvnic->qp_nic_index[i] * 8),
macaddr_low,
(u32)macaddr_high | NES_MAC_ADDR_VALID |
((((u32)nesvnic->nic_index) << 16)));
@@ -272,14 +274,18 @@ static int nes_netdev_stop(struct net_device *netdev)
break;
}
- if (first_nesvnic->netdev_open == 0)
+ if ((first_nesvnic->netdev_open == 1) && (first_nesvnic != nesvnic) &&
+ (PCI_FUNC(first_nesvnic->nesdev->pcidev->devfn) !=
+ PCI_FUNC(nesvnic->nesdev->pcidev->devfn))) {
+ nes_write_indexed(nesdev, NES_IDX_MAC_INT_MASK+
+ (0x200*nesdev->mac_index), 0xffffffff);
+ nes_write_indexed(first_nesvnic->nesdev,
+ NES_IDX_MAC_INT_MASK+
+ (0x200*first_nesvnic->nesdev->mac_index),
+ ~(NES_MAC_INT_LINK_STAT_CHG | NES_MAC_INT_XGMII_EXT |
+ NES_MAC_INT_TX_UNDERFLOW | NES_MAC_INT_TX_ERROR));
+ } else {
nes_write_indexed(nesdev, NES_IDX_MAC_INT_MASK+(0x200*nesdev->mac_index), 0xffffffff);
- else if ((first_nesvnic != nesvnic) &&
- (PCI_FUNC(first_nesvnic->nesdev->pcidev->devfn) != PCI_FUNC(nesvnic->nesdev->pcidev->devfn))) {
- nes_write_indexed(nesdev, NES_IDX_MAC_INT_MASK + (0x200 * nesdev->mac_index), 0xffffffff);
- nes_write_indexed(first_nesvnic->nesdev, NES_IDX_MAC_INT_MASK + (0x200 * first_nesvnic->nesdev->mac_index),
- ~(NES_MAC_INT_LINK_STAT_CHG | NES_MAC_INT_XGMII_EXT |
- NES_MAC_INT_TX_UNDERFLOW | NES_MAC_INT_TX_ERROR));
}
nic_active_mask = ~((u32)(1 << nesvnic->nic_index));
@@ -437,7 +443,7 @@ static int nes_netdev_start_xmit(struct sk_buff *skb, struct net_device *netdev)
struct nes_hw_nic_sq_wqe *nic_sqe;
struct tcphdr *tcph;
/* struct udphdr *udph; */
-#define NES_MAX_TSO_FRAGS 18
+#define NES_MAX_TSO_FRAGS MAX_SKB_FRAGS
/* 64K segment plus overflow on each side */
dma_addr_t tso_bus_address[NES_MAX_TSO_FRAGS];
dma_addr_t bus_address;
@@ -605,6 +611,8 @@ tso_sq_no_longer_full:
wqe_fragment_length[wqe_fragment_index] = 0;
set_wqe_64bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_FRAG1_LOW_IDX,
bus_address);
+ tso_wqe_length += skb_headlen(skb) -
+ original_first_length;
}
while (wqe_fragment_index < 5) {
wqe_fragment_length[wqe_fragment_index] =
@@ -827,6 +835,7 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev)
{
struct nes_vnic *nesvnic = netdev_priv(netdev);
struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_adapter *nesadapter = nesvnic->nesdev->nesadapter;
struct dev_mc_list *multicast_addr;
u32 nic_active_bit;
u32 nic_active;
@@ -836,7 +845,12 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev)
u8 mc_all_on = 0;
u8 mc_index;
int mc_nic_index = -1;
+ u8 pft_entries_preallocated = max(nesadapter->adapter_fcn_count *
+ nics_per_function, 4);
+ u8 max_pft_entries_avaiable = NES_PFT_SIZE - pft_entries_preallocated;
+ unsigned long flags;
+ spin_lock_irqsave(&nesadapter->resource_lock, flags);
nic_active_bit = 1 << nesvnic->nic_index;
if (netdev->flags & IFF_PROMISC) {
@@ -847,7 +861,7 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev)
nic_active |= nic_active_bit;
nes_write_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL, nic_active);
mc_all_on = 1;
- } else if ((netdev->flags & IFF_ALLMULTI) || (netdev->mc_count > NES_MULTICAST_PF_MAX) ||
+ } else if ((netdev->flags & IFF_ALLMULTI) ||
(nesvnic->nic_index > 3)) {
nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL);
nic_active |= nic_active_bit;
@@ -866,17 +880,34 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev)
}
nes_debug(NES_DBG_NIC_RX, "Number of MC entries = %d, Promiscous = %d, All Multicast = %d.\n",
- netdev->mc_count, (netdev->flags & IFF_PROMISC)?1:0,
- (netdev->flags & IFF_ALLMULTI)?1:0);
+ netdev->mc_count, !!(netdev->flags & IFF_PROMISC),
+ !!(netdev->flags & IFF_ALLMULTI));
if (!mc_all_on) {
multicast_addr = netdev->mc_list;
- perfect_filter_register_address = NES_IDX_PERFECT_FILTER_LOW + 0x80;
- perfect_filter_register_address += nesvnic->nic_index*0x40;
- for (mc_index=0; mc_index < NES_MULTICAST_PF_MAX; mc_index++) {
- while (multicast_addr && nesvnic->mcrq_mcast_filter && ((mc_nic_index = nesvnic->mcrq_mcast_filter(nesvnic, multicast_addr->dmi_addr)) == 0))
+ perfect_filter_register_address = NES_IDX_PERFECT_FILTER_LOW +
+ pft_entries_preallocated * 0x8;
+ for (mc_index = 0; mc_index < max_pft_entries_avaiable;
+ mc_index++) {
+ while (multicast_addr && nesvnic->mcrq_mcast_filter &&
+ ((mc_nic_index = nesvnic->mcrq_mcast_filter(nesvnic,
+ multicast_addr->dmi_addr)) == 0)) {
multicast_addr = multicast_addr->next;
+ }
if (mc_nic_index < 0)
mc_nic_index = nesvnic->nic_index;
+ while (nesadapter->pft_mcast_map[mc_index] < 16 &&
+ nesadapter->pft_mcast_map[mc_index] !=
+ nesvnic->nic_index &&
+ mc_index < max_pft_entries_avaiable) {
+ nes_debug(NES_DBG_NIC_RX,
+ "mc_index=%d skipping nic_index=%d,\
+ used for=%d \n", mc_index,
+ nesvnic->nic_index,
+ nesadapter->pft_mcast_map[mc_index]);
+ mc_index++;
+ }
+ if (mc_index >= max_pft_entries_avaiable)
+ break;
if (multicast_addr) {
DECLARE_MAC_BUF(mac);
nes_debug(NES_DBG_NIC_RX, "Assigning MC Address %s to register 0x%04X nic_idx=%d\n",
@@ -897,15 +928,33 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev)
(u32)macaddr_high | NES_MAC_ADDR_VALID |
((((u32)(1<<mc_nic_index)) << 16)));
multicast_addr = multicast_addr->next;
+ nesadapter->pft_mcast_map[mc_index] =
+ nesvnic->nic_index;
} else {
nes_debug(NES_DBG_NIC_RX, "Clearing MC Address at register 0x%04X\n",
perfect_filter_register_address+(mc_index * 8));
nes_write_indexed(nesdev,
perfect_filter_register_address+4+(mc_index * 8),
0);
+ nesadapter->pft_mcast_map[mc_index] = 255;
}
}
+ /* PFT is not large enough */
+ if (multicast_addr && multicast_addr->next) {
+ nic_active = nes_read_indexed(nesdev,
+ NES_IDX_NIC_MULTICAST_ALL);
+ nic_active |= nic_active_bit;
+ nes_write_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL,
+ nic_active);
+ nic_active = nes_read_indexed(nesdev,
+ NES_IDX_NIC_UNICAST_ALL);
+ nic_active &= ~nic_active_bit;
+ nes_write_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL,
+ nic_active);
+ }
}
+
+ spin_unlock_irqrestore(&nesadapter->resource_lock, flags);
}
@@ -918,6 +967,10 @@ static int nes_netdev_change_mtu(struct net_device *netdev, int new_mtu)
struct nes_device *nesdev = nesvnic->nesdev;
int ret = 0;
u8 jumbomode = 0;
+ u32 nic_active;
+ u32 nic_active_bit;
+ u32 uc_all_active;
+ u32 mc_all_active;
if ((new_mtu < ETH_ZLEN) || (new_mtu > max_mtu))
return -EINVAL;
@@ -931,8 +984,24 @@ static int nes_netdev_change_mtu(struct net_device *netdev, int new_mtu)
nes_nic_init_timer_defaults(nesdev, jumbomode);
if (netif_running(netdev)) {
+ nic_active_bit = 1 << nesvnic->nic_index;
+ mc_all_active = nes_read_indexed(nesdev,
+ NES_IDX_NIC_MULTICAST_ALL) & nic_active_bit;
+ uc_all_active = nes_read_indexed(nesdev,
+ NES_IDX_NIC_UNICAST_ALL) & nic_active_bit;
+
nes_netdev_stop(netdev);
nes_netdev_open(netdev);
+
+ nic_active = nes_read_indexed(nesdev,
+ NES_IDX_NIC_MULTICAST_ALL);
+ nic_active |= mc_all_active;
+ nes_write_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL,
+ nic_active);
+
+ nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL);
+ nic_active |= uc_all_active;
+ nes_write_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL, nic_active);
}
return ret;
@@ -1208,10 +1277,12 @@ static void nes_netdev_get_drvinfo(struct net_device *netdev,
struct ethtool_drvinfo *drvinfo)
{
struct nes_vnic *nesvnic = netdev_priv(netdev);
+ struct nes_adapter *nesadapter = nesvnic->nesdev->nesadapter;
strcpy(drvinfo->driver, DRV_NAME);
strcpy(drvinfo->bus_info, pci_name(nesvnic->nesdev->pcidev));
- strcpy(drvinfo->fw_version, "TBD");
+ sprintf(drvinfo->fw_version, "%u.%u", nesadapter->firmware_version>>16,
+ nesadapter->firmware_version & 0x000000ff);
strcpy(drvinfo->version, DRV_VERSION);
drvinfo->n_stats = nes_netdev_get_stats_count(netdev);
drvinfo->testinfo_len = 0;
@@ -1587,7 +1658,9 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,
nesvnic, (unsigned long)netdev->features, nesvnic->nic.qp_id,
nesvnic->nic_index, nesvnic->logical_port, nesdev->mac_index);
- if (nesvnic->nesdev->nesadapter->port_count == 1) {
+ if (nesvnic->nesdev->nesadapter->port_count == 1 &&
+ nesvnic->nesdev->nesadapter->adapter_fcn_count == 1) {
+
nesvnic->qp_nic_index[0] = nesvnic->nic_index;
nesvnic->qp_nic_index[1] = nesvnic->nic_index + 1;
if (nes_drv_opt & NES_DRV_OPT_DUAL_LOGICAL_PORT) {
@@ -1598,11 +1671,14 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,
nesvnic->qp_nic_index[3] = nesvnic->nic_index + 3;
}
} else {
- if (nesvnic->nesdev->nesadapter->port_count == 2) {
- nesvnic->qp_nic_index[0] = nesvnic->nic_index;
- nesvnic->qp_nic_index[1] = nesvnic->nic_index + 2;
- nesvnic->qp_nic_index[2] = 0xf;
- nesvnic->qp_nic_index[3] = 0xf;
+ if (nesvnic->nesdev->nesadapter->port_count == 2 ||
+ (nesvnic->nesdev->nesadapter->port_count == 1 &&
+ nesvnic->nesdev->nesadapter->adapter_fcn_count == 2)) {
+ nesvnic->qp_nic_index[0] = nesvnic->nic_index;
+ nesvnic->qp_nic_index[1] = nesvnic->nic_index
+ + 2;
+ nesvnic->qp_nic_index[2] = 0xf;
+ nesvnic->qp_nic_index[3] = 0xf;
} else {
nesvnic->qp_nic_index[0] = nesvnic->nic_index;
nesvnic->qp_nic_index[1] = 0xf;
diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c
index d79942e8497..932e56fcf77 100644
--- a/drivers/infiniband/hw/nes/nes_verbs.c
+++ b/drivers/infiniband/hw/nes/nes_verbs.c
@@ -1467,7 +1467,6 @@ static struct ib_qp *nes_create_qp(struct ib_pd *ibpd,
default:
nes_debug(NES_DBG_QP, "Invalid QP type: %d\n", init_attr->qp_type);
return ERR_PTR(-EINVAL);
- break;
}
/* update the QP table */
@@ -2498,7 +2497,6 @@ static struct ib_mr *nes_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
nes_debug(NES_DBG_MR, "Leaving, ibmr=%p", ibmr);
return ibmr;
- break;
case IWNES_MEMREG_TYPE_QP:
case IWNES_MEMREG_TYPE_CQ:
nespbl = kzalloc(sizeof(*nespbl), GFP_KERNEL);
@@ -2572,7 +2570,6 @@ static struct ib_mr *nes_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
nesmr->ibmr.lkey = -1;
nesmr->mode = req.reg_type;
return &nesmr->ibmr;
- break;
}
return ERR_PTR(-ENOSYS);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index b0ffc9abe8c..68ba5c3482e 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -268,10 +268,9 @@ struct ipoib_lro {
};
/*
- * Device private locking: tx_lock protects members used in TX fast
- * path (and we use LLTX so upper layers don't do extra locking).
- * lock protects everything else. lock nests inside of tx_lock (ie
- * tx_lock must be acquired first if needed).
+ * Device private locking: network stack tx_lock protects members used
+ * in TX fast path, lock protects everything else. lock nests inside
+ * of tx_lock (ie tx_lock must be acquired first if needed).
*/
struct ipoib_dev_priv {
spinlock_t lock;
@@ -293,6 +292,7 @@ struct ipoib_dev_priv {
struct delayed_work pkey_poll_task;
struct delayed_work mcast_task;
+ struct work_struct carrier_on_task;
struct work_struct flush_light;
struct work_struct flush_normal;
struct work_struct flush_heavy;
@@ -319,7 +319,6 @@ struct ipoib_dev_priv {
struct ipoib_rx_buf *rx_ring;
- spinlock_t tx_lock;
struct ipoib_tx_buf *tx_ring;
unsigned tx_head;
unsigned tx_tail;
@@ -464,6 +463,7 @@ int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port);
void ipoib_dev_cleanup(struct net_device *dev);
void ipoib_mcast_join_task(struct work_struct *work);
+void ipoib_mcast_carrier_on_task(struct work_struct *work);
void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb);
void ipoib_mcast_restart_task(struct work_struct *work);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
index 341ffedafed..7b14c2c3950 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
@@ -786,7 +786,8 @@ void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ib_wc *wc)
dev_kfree_skb_any(tx_req->skb);
- spin_lock_irqsave(&priv->tx_lock, flags);
+ netif_tx_lock(dev);
+
++tx->tx_tail;
if (unlikely(--priv->tx_outstanding == ipoib_sendq_size >> 1) &&
netif_queue_stopped(dev) &&
@@ -801,7 +802,7 @@ void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ib_wc *wc)
"(status=%d, wrid=%d vend_err %x)\n",
wc->status, wr_id, wc->vendor_err);
- spin_lock(&priv->lock);
+ spin_lock_irqsave(&priv->lock, flags);
neigh = tx->neigh;
if (neigh) {
@@ -821,10 +822,10 @@ void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ib_wc *wc)
clear_bit(IPOIB_FLAG_OPER_UP, &tx->flags);
- spin_unlock(&priv->lock);
+ spin_unlock_irqrestore(&priv->lock, flags);
}
- spin_unlock_irqrestore(&priv->tx_lock, flags);
+ netif_tx_unlock(dev);
}
int ipoib_cm_dev_open(struct net_device *dev)
@@ -1149,7 +1150,6 @@ static void ipoib_cm_tx_destroy(struct ipoib_cm_tx *p)
{
struct ipoib_dev_priv *priv = netdev_priv(p->dev);
struct ipoib_cm_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",
@@ -1180,12 +1180,12 @@ timeout:
DMA_TO_DEVICE);
dev_kfree_skb_any(tx_req->skb);
++p->tx_tail;
- spin_lock_irqsave(&priv->tx_lock, flags);
+ netif_tx_lock_bh(p->dev);
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);
+ netif_tx_unlock_bh(p->dev);
}
if (p->qp)
@@ -1202,6 +1202,7 @@ static int ipoib_cm_tx_handler(struct ib_cm_id *cm_id,
struct ipoib_dev_priv *priv = netdev_priv(tx->dev);
struct net_device *dev = priv->dev;
struct ipoib_neigh *neigh;
+ unsigned long flags;
int ret;
switch (event->event) {
@@ -1220,8 +1221,8 @@ static int ipoib_cm_tx_handler(struct ib_cm_id *cm_id,
case IB_CM_REJ_RECEIVED:
case IB_CM_TIMEWAIT_EXIT:
ipoib_dbg(priv, "CM error %d.\n", event->event);
- spin_lock_irq(&priv->tx_lock);
- spin_lock(&priv->lock);
+ netif_tx_lock_bh(dev);
+ spin_lock_irqsave(&priv->lock, flags);
neigh = tx->neigh;
if (neigh) {
@@ -1239,8 +1240,8 @@ static int ipoib_cm_tx_handler(struct ib_cm_id *cm_id,
queue_work(ipoib_workqueue, &priv->cm.reap_task);
}
- spin_unlock(&priv->lock);
- spin_unlock_irq(&priv->tx_lock);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ netif_tx_unlock_bh(dev);
break;
default:
break;
@@ -1294,19 +1295,24 @@ static void ipoib_cm_tx_start(struct work_struct *work)
struct ib_sa_path_rec pathrec;
u32 qpn;
- spin_lock_irqsave(&priv->tx_lock, flags);
- spin_lock(&priv->lock);
+ netif_tx_lock_bh(dev);
+ spin_lock_irqsave(&priv->lock, flags);
+
while (!list_empty(&priv->cm.start_list)) {
p = list_entry(priv->cm.start_list.next, typeof(*p), list);
list_del_init(&p->list);
neigh = p->neigh;
qpn = IPOIB_QPN(neigh->neighbour->ha);
memcpy(&pathrec, &p->path->pathrec, sizeof pathrec);
- spin_unlock(&priv->lock);
- spin_unlock_irqrestore(&priv->tx_lock, flags);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ netif_tx_unlock_bh(dev);
+
ret = ipoib_cm_tx_init(p, qpn, &pathrec);
- spin_lock_irqsave(&priv->tx_lock, flags);
- spin_lock(&priv->lock);
+
+ netif_tx_lock_bh(dev);
+ spin_lock_irqsave(&priv->lock, flags);
+
if (ret) {
neigh = p->neigh;
if (neigh) {
@@ -1320,44 +1326,52 @@ static void ipoib_cm_tx_start(struct work_struct *work)
kfree(p);
}
}
- spin_unlock(&priv->lock);
- spin_unlock_irqrestore(&priv->tx_lock, flags);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ netif_tx_unlock_bh(dev);
}
static void ipoib_cm_tx_reap(struct work_struct *work)
{
struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv,
cm.reap_task);
+ struct net_device *dev = priv->dev;
struct ipoib_cm_tx *p;
+ unsigned long flags;
+
+ netif_tx_lock_bh(dev);
+ spin_lock_irqsave(&priv->lock, flags);
- spin_lock_irq(&priv->tx_lock);
- spin_lock(&priv->lock);
while (!list_empty(&priv->cm.reap_list)) {
p = list_entry(priv->cm.reap_list.next, typeof(*p), list);
list_del(&p->list);
- spin_unlock(&priv->lock);
- spin_unlock_irq(&priv->tx_lock);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ netif_tx_unlock_bh(dev);
ipoib_cm_tx_destroy(p);
- spin_lock_irq(&priv->tx_lock);
- spin_lock(&priv->lock);
+ netif_tx_lock_bh(dev);
+ spin_lock_irqsave(&priv->lock, flags);
}
- spin_unlock(&priv->lock);
- spin_unlock_irq(&priv->tx_lock);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ netif_tx_unlock_bh(dev);
}
static void ipoib_cm_skb_reap(struct work_struct *work)
{
struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv,
cm.skb_task);
+ struct net_device *dev = priv->dev;
struct sk_buff *skb;
-
+ unsigned long flags;
unsigned mtu = priv->mcast_mtu;
- spin_lock_irq(&priv->tx_lock);
- spin_lock(&priv->lock);
+ netif_tx_lock_bh(dev);
+ spin_lock_irqsave(&priv->lock, flags);
+
while ((skb = skb_dequeue(&priv->cm.skb_queue))) {
- spin_unlock(&priv->lock);
- spin_unlock_irq(&priv->tx_lock);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ netif_tx_unlock_bh(dev);
+
if (skb->protocol == htons(ETH_P_IP))
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
@@ -1365,11 +1379,13 @@ static void ipoib_cm_skb_reap(struct work_struct *work)
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, priv->dev);
#endif
dev_kfree_skb_any(skb);
- spin_lock_irq(&priv->tx_lock);
- spin_lock(&priv->lock);
+
+ netif_tx_lock_bh(dev);
+ spin_lock_irqsave(&priv->lock, flags);
}
- spin_unlock(&priv->lock);
- spin_unlock_irq(&priv->tx_lock);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ netif_tx_unlock_bh(dev);
}
void ipoib_cm_skb_too_long(struct net_device *dev, struct sk_buff *skb,
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
index 66cafa20c24..0e748aeeae9 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -468,21 +468,22 @@ void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr)
static void drain_tx_cq(struct net_device *dev)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
- unsigned long flags;
- spin_lock_irqsave(&priv->tx_lock, flags);
+ netif_tx_lock(dev);
while (poll_tx(priv))
; /* nothing */
if (netif_queue_stopped(dev))
mod_timer(&priv->poll_timer, jiffies + 1);
- spin_unlock_irqrestore(&priv->tx_lock, flags);
+ netif_tx_unlock(dev);
}
void ipoib_send_comp_handler(struct ib_cq *cq, void *dev_ptr)
{
- drain_tx_cq((struct net_device *)dev_ptr);
+ struct ipoib_dev_priv *priv = netdev_priv(dev_ptr);
+
+ mod_timer(&priv->poll_timer, jiffies);
}
static inline int post_send(struct ipoib_dev_priv *priv,
@@ -614,17 +615,20 @@ static void __ipoib_reap_ah(struct net_device *dev)
struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ipoib_ah *ah, *tah;
LIST_HEAD(remove_list);
+ unsigned long flags;
+
+ netif_tx_lock_bh(dev);
+ spin_lock_irqsave(&priv->lock, flags);
- spin_lock_irq(&priv->tx_lock);
- spin_lock(&priv->lock);
list_for_each_entry_safe(ah, tah, &priv->dead_ahs, list)
if ((int) priv->tx_tail - (int) ah->last_send >= 0) {
list_del(&ah->list);
ib_destroy_ah(ah->ah);
kfree(ah);
}
- spin_unlock(&priv->lock);
- spin_unlock_irq(&priv->tx_lock);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ netif_tx_unlock_bh(dev);
}
void ipoib_reap_ah(struct work_struct *work)
@@ -761,6 +765,14 @@ void ipoib_drain_cq(struct net_device *dev)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
int i, n;
+
+ /*
+ * We call completion handling routines that expect to be
+ * called from the BH-disabled NAPI poll context, so disable
+ * BHs here too.
+ */
+ local_bh_disable();
+
do {
n = ib_poll_cq(priv->recv_cq, IPOIB_NUM_WC, priv->ibwc);
for (i = 0; i < n; ++i) {
@@ -784,6 +796,8 @@ void ipoib_drain_cq(struct net_device *dev)
while (poll_tx(priv))
; /* nothing */
+
+ local_bh_enable();
}
int ipoib_ib_dev_stop(struct net_device *dev, int flush)
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index 7e9e218738f..c0ee514396d 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -373,9 +373,10 @@ void ipoib_flush_paths(struct net_device *dev)
struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ipoib_path *path, *tp;
LIST_HEAD(remove_list);
+ unsigned long flags;
- spin_lock_irq(&priv->tx_lock);
- spin_lock(&priv->lock);
+ netif_tx_lock_bh(dev);
+ spin_lock_irqsave(&priv->lock, flags);
list_splice_init(&priv->path_list, &remove_list);
@@ -385,15 +386,16 @@ void ipoib_flush_paths(struct net_device *dev)
list_for_each_entry_safe(path, tp, &remove_list, list) {
if (path->query)
ib_sa_cancel_query(path->query_id, path->query);
- spin_unlock(&priv->lock);
- spin_unlock_irq(&priv->tx_lock);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ netif_tx_unlock_bh(dev);
wait_for_completion(&path->done);
path_free(dev, path);
- spin_lock_irq(&priv->tx_lock);
- spin_lock(&priv->lock);
+ netif_tx_lock_bh(dev);
+ spin_lock_irqsave(&priv->lock, flags);
}
- spin_unlock(&priv->lock);
- spin_unlock_irq(&priv->tx_lock);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ netif_tx_unlock_bh(dev);
}
static void path_rec_completion(int status,
@@ -404,7 +406,7 @@ static void path_rec_completion(int status,
struct net_device *dev = path->dev;
struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ipoib_ah *ah = NULL;
- struct ipoib_ah *old_ah;
+ struct ipoib_ah *old_ah = NULL;
struct ipoib_neigh *neigh, *tn;
struct sk_buff_head skqueue;
struct sk_buff *skb;
@@ -428,12 +430,12 @@ static void path_rec_completion(int status,
spin_lock_irqsave(&priv->lock, flags);
- old_ah = path->ah;
- path->ah = ah;
-
if (ah) {
path->pathrec = *pathrec;
+ old_ah = path->ah;
+ path->ah = ah;
+
ipoib_dbg(priv, "created address handle %p for LID 0x%04x, SL %d\n",
ah, be16_to_cpu(pathrec->dlid), pathrec->sl);
@@ -555,6 +557,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ipoib_path *path;
struct ipoib_neigh *neigh;
+ unsigned long flags;
neigh = ipoib_neigh_alloc(skb->dst->neighbour, skb->dev);
if (!neigh) {
@@ -563,11 +566,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
return;
}
- /*
- * We can only be called from ipoib_start_xmit, so we're
- * inside tx_lock -- no need to save/restore flags.
- */
- spin_lock(&priv->lock);
+ spin_lock_irqsave(&priv->lock, flags);
path = __path_find(dev, skb->dst->neighbour->ha + 4);
if (!path) {
@@ -614,7 +613,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
__skb_queue_tail(&neigh->queue, skb);
}
- spin_unlock(&priv->lock);
+ spin_unlock_irqrestore(&priv->lock, flags);
return;
err_list:
@@ -626,7 +625,7 @@ err_drop:
++dev->stats.tx_dropped;
dev_kfree_skb_any(skb);
- spin_unlock(&priv->lock);
+ spin_unlock_irqrestore(&priv->lock, flags);
}
static void ipoib_path_lookup(struct sk_buff *skb, struct net_device *dev)
@@ -650,12 +649,9 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev,
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ipoib_path *path;
+ unsigned long flags;
- /*
- * We can only be called from ipoib_start_xmit, so we're
- * inside tx_lock -- no need to save/restore flags.
- */
- spin_lock(&priv->lock);
+ spin_lock_irqsave(&priv->lock, flags);
path = __path_find(dev, phdr->hwaddr + 4);
if (!path || !path->valid) {
@@ -667,7 +663,7 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev,
__skb_queue_tail(&path->queue, skb);
if (path_rec_start(dev, path)) {
- spin_unlock(&priv->lock);
+ spin_unlock_irqrestore(&priv->lock, flags);
path_free(dev, path);
return;
} else
@@ -677,7 +673,7 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev,
dev_kfree_skb_any(skb);
}
- spin_unlock(&priv->lock);
+ spin_unlock_irqrestore(&priv->lock, flags);
return;
}
@@ -696,7 +692,7 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev,
dev_kfree_skb_any(skb);
}
- spin_unlock(&priv->lock);
+ spin_unlock_irqrestore(&priv->lock, flags);
}
static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -705,13 +701,10 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct ipoib_neigh *neigh;
unsigned long flags;
- if (unlikely(!spin_trylock_irqsave(&priv->tx_lock, flags)))
- return NETDEV_TX_LOCKED;
-
if (likely(skb->dst && skb->dst->neighbour)) {
if (unlikely(!*to_ipoib_neigh(skb->dst->neighbour))) {
ipoib_path_lookup(skb, dev);
- goto out;
+ return NETDEV_TX_OK;
}
neigh = *to_ipoib_neigh(skb->dst->neighbour);
@@ -721,7 +714,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
skb->dst->neighbour->ha + 4,
sizeof(union ib_gid))) ||
(neigh->dev != dev))) {
- spin_lock(&priv->lock);
+ spin_lock_irqsave(&priv->lock, flags);
/*
* It's safe to call ipoib_put_ah() inside
* priv->lock here, because we know that
@@ -732,25 +725,25 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
ipoib_put_ah(neigh->ah);
list_del(&neigh->list);
ipoib_neigh_free(dev, neigh);
- spin_unlock(&priv->lock);
+ spin_unlock_irqrestore(&priv->lock, flags);
ipoib_path_lookup(skb, dev);
- goto out;
+ return NETDEV_TX_OK;
}
if (ipoib_cm_get(neigh)) {
if (ipoib_cm_up(neigh)) {
ipoib_cm_send(dev, skb, ipoib_cm_get(neigh));
- goto out;
+ return NETDEV_TX_OK;
}
} else if (neigh->ah) {
ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(skb->dst->neighbour->ha));
- goto out;
+ return NETDEV_TX_OK;
}
if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) {
- spin_lock(&priv->lock);
+ spin_lock_irqsave(&priv->lock, flags);
__skb_queue_tail(&neigh->queue, skb);
- spin_unlock(&priv->lock);
+ spin_unlock_irqrestore(&priv->lock, flags);
} else {
++dev->stats.tx_dropped;
dev_kfree_skb_any(skb);
@@ -779,16 +772,13 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
IPOIB_GID_RAW_ARG(phdr->hwaddr + 4));
dev_kfree_skb_any(skb);
++dev->stats.tx_dropped;
- goto out;
+ return NETDEV_TX_OK;
}
unicast_arp_send(skb, dev, phdr);
}
}
-out:
- spin_unlock_irqrestore(&priv->tx_lock, flags);
-
return NETDEV_TX_OK;
}
@@ -1052,7 +1042,6 @@ static void ipoib_setup(struct net_device *dev)
dev->type = ARPHRD_INFINIBAND;
dev->tx_queue_len = ipoib_sendq_size * 2;
dev->features = (NETIF_F_VLAN_CHALLENGED |
- NETIF_F_LLTX |
NETIF_F_HIGHDMA);
memcpy(dev->broadcast, ipv4_bcast_addr, INFINIBAND_ALEN);
@@ -1064,7 +1053,6 @@ static void ipoib_setup(struct net_device *dev)
ipoib_lro_setup(priv);
spin_lock_init(&priv->lock);
- spin_lock_init(&priv->tx_lock);
mutex_init(&priv->vlan_mutex);
@@ -1075,6 +1063,7 @@ static void ipoib_setup(struct net_device *dev)
INIT_DELAYED_WORK(&priv->pkey_poll_task, ipoib_pkey_poll);
INIT_DELAYED_WORK(&priv->mcast_task, ipoib_mcast_join_task);
+ INIT_WORK(&priv->carrier_on_task, ipoib_mcast_carrier_on_task);
INIT_WORK(&priv->flush_light, ipoib_ib_dev_flush_light);
INIT_WORK(&priv->flush_normal, ipoib_ib_dev_flush_normal);
INIT_WORK(&priv->flush_heavy, ipoib_ib_dev_flush_heavy);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
index ac33c8f3ea8..d9d1223c3fd 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
@@ -69,14 +69,13 @@ static void ipoib_mcast_free(struct ipoib_mcast *mcast)
struct net_device *dev = mcast->dev;
struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ipoib_neigh *neigh, *tmp;
- unsigned long flags;
int tx_dropped = 0;
ipoib_dbg_mcast(netdev_priv(dev),
"deleting multicast group " IPOIB_GID_FMT "\n",
IPOIB_GID_ARG(mcast->mcmember.mgid));
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irq(&priv->lock);
list_for_each_entry_safe(neigh, tmp, &mcast->neigh_list, list) {
/*
@@ -90,7 +89,7 @@ static void ipoib_mcast_free(struct ipoib_mcast *mcast)
ipoib_neigh_free(dev, neigh);
}
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock_irq(&priv->lock);
if (mcast->ah)
ipoib_put_ah(mcast->ah);
@@ -100,9 +99,9 @@ static void ipoib_mcast_free(struct ipoib_mcast *mcast)
dev_kfree_skb_any(skb_dequeue(&mcast->pkt_queue));
}
- spin_lock_irqsave(&priv->tx_lock, flags);
+ netif_tx_lock_bh(dev);
dev->stats.tx_dropped += tx_dropped;
- spin_unlock_irqrestore(&priv->tx_lock, flags);
+ netif_tx_unlock_bh(dev);
kfree(mcast);
}
@@ -259,10 +258,10 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast,
}
/* actually send any queued packets */
- spin_lock_irq(&priv->tx_lock);
+ netif_tx_lock_bh(dev);
while (!skb_queue_empty(&mcast->pkt_queue)) {
struct sk_buff *skb = skb_dequeue(&mcast->pkt_queue);
- spin_unlock_irq(&priv->tx_lock);
+ netif_tx_unlock_bh(dev);
skb->dev = dev;
@@ -273,9 +272,9 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast,
if (dev_queue_xmit(skb))
ipoib_warn(priv, "dev_queue_xmit failed to requeue packet\n");
- spin_lock_irq(&priv->tx_lock);
+ netif_tx_lock_bh(dev);
}
- spin_unlock_irq(&priv->tx_lock);
+ netif_tx_unlock_bh(dev);
return 0;
}
@@ -286,7 +285,6 @@ ipoib_mcast_sendonly_join_complete(int status,
{
struct ipoib_mcast *mcast = multicast->context;
struct net_device *dev = mcast->dev;
- struct ipoib_dev_priv *priv = netdev_priv(dev);
/* We trap for port events ourselves. */
if (status == -ENETRESET)
@@ -302,12 +300,12 @@ ipoib_mcast_sendonly_join_complete(int status,
IPOIB_GID_ARG(mcast->mcmember.mgid), status);
/* Flush out any queued packets */
- spin_lock_irq(&priv->tx_lock);
+ netif_tx_lock_bh(dev);
while (!skb_queue_empty(&mcast->pkt_queue)) {
++dev->stats.tx_dropped;
dev_kfree_skb_any(skb_dequeue(&mcast->pkt_queue));
}
- spin_unlock_irq(&priv->tx_lock);
+ netif_tx_unlock_bh(dev);
/* Clear the busy flag so we try again */
status = test_and_clear_bit(IPOIB_MCAST_FLAG_BUSY,
@@ -366,6 +364,21 @@ static int ipoib_mcast_sendonly_join(struct ipoib_mcast *mcast)
return ret;
}
+void ipoib_mcast_carrier_on_task(struct work_struct *work)
+{
+ struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv,
+ carrier_on_task);
+
+ /*
+ * Take rtnl_lock to avoid racing with ipoib_stop() and
+ * turning the carrier back on while a device is being
+ * removed.
+ */
+ rtnl_lock();
+ netif_carrier_on(priv->dev);
+ rtnl_unlock();
+}
+
static int ipoib_mcast_join_complete(int status,
struct ib_sa_multicast *multicast)
{
@@ -392,16 +405,12 @@ static int ipoib_mcast_join_complete(int status,
&priv->mcast_task, 0);
mutex_unlock(&mcast_mutex);
- if (mcast == priv->broadcast) {
- /*
- * Take RTNL lock here to avoid racing with
- * ipoib_stop() and turning the carrier back
- * on while a device is being removed.
- */
- rtnl_lock();
- netif_carrier_on(dev);
- rtnl_unlock();
- }
+ /*
+ * Defer carrier on work to ipoib_workqueue to avoid a
+ * deadlock on rtnl_lock here.
+ */
+ if (mcast == priv->broadcast)
+ queue_work(ipoib_workqueue, &priv->carrier_on_task);
return 0;
}
@@ -651,12 +660,9 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ipoib_mcast *mcast;
+ unsigned long flags;
- /*
- * We can only be called from ipoib_start_xmit, so we're
- * inside tx_lock -- no need to save/restore flags.
- */
- spin_lock(&priv->lock);
+ spin_lock_irqsave(&priv->lock, flags);
if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags) ||
!priv->broadcast ||
@@ -727,7 +733,7 @@ out:
}
unlock:
- spin_unlock(&priv->lock);
+ spin_unlock_irqrestore(&priv->lock, flags);
}
void ipoib_mcast_dev_flush(struct net_device *dev)
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c
index 2ec921bf3c6..2998a6ac9ae 100644
--- a/drivers/input/mouse/bcm5974.c
+++ b/drivers/input/mouse/bcm5974.c
@@ -63,7 +63,7 @@
}
/* table of devices that work with this driver */
-static const struct usb_device_id bcm5974_table [] = {
+static const struct usb_device_id bcm5974_table[] = {
/* MacbookAir1.1 */
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING_ANSI),
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING_ISO),
@@ -105,7 +105,7 @@ struct tp_header {
/* trackpad finger structure */
struct tp_finger {
- __le16 origin; /* left/right origin? */
+ __le16 origin; /* zero when switching track finger */
__le16 abs_x; /* absolute x coodinate */
__le16 abs_y; /* absolute y coodinate */
__le16 rel_x; /* relative x coodinate */
@@ -159,6 +159,7 @@ struct bcm5974 {
struct bt_data *bt_data; /* button transferred data */
struct urb *tp_urb; /* trackpad usb request block */
struct tp_data *tp_data; /* trackpad transferred data */
+ int fingers; /* number of fingers on trackpad */
};
/* logical dimensions */
@@ -172,6 +173,10 @@ struct bcm5974 {
#define SN_WIDTH 100 /* width signal-to-noise ratio */
#define SN_COORD 250 /* coordinate signal-to-noise ratio */
+/* pressure thresholds */
+#define PRESSURE_LOW (2 * DIM_PRESSURE / SN_PRESSURE)
+#define PRESSURE_HIGH (3 * PRESSURE_LOW)
+
/* device constants */
static const struct bcm5974_config bcm5974_config_table[] = {
{
@@ -248,6 +253,7 @@ static void setup_events_to_report(struct input_dev *input_dev,
0, cfg->y.dim, cfg->y.fuzz, 0);
__set_bit(EV_KEY, input_dev->evbit);
+ __set_bit(BTN_TOUCH, input_dev->keybit);
__set_bit(BTN_TOOL_FINGER, input_dev->keybit);
__set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
__set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
@@ -273,32 +279,66 @@ static int report_tp_state(struct bcm5974 *dev, int size)
const struct tp_finger *f = dev->tp_data->finger;
struct input_dev *input = dev->input;
const int fingers = (size - 26) / 28;
- int p = 0, w, x, y, n = 0;
+ int raw_p, raw_w, raw_x, raw_y;
+ int ptest = 0, origin = 0, nmin = 0, nmax = 0;
+ int abs_p = 0, abs_w = 0, abs_x = 0, abs_y = 0;
if (size < 26 || (size - 26) % 28 != 0)
return -EIO;
+ /* always track the first finger; when detached, start over */
if (fingers) {
- p = raw2int(f->force_major);
- w = raw2int(f->size_major);
- x = raw2int(f->abs_x);
- y = raw2int(f->abs_y);
- n = p > 0 ? fingers : 0;
+ raw_p = raw2int(f->force_major);
+ raw_w = raw2int(f->size_major);
+ raw_x = raw2int(f->abs_x);
+ raw_y = raw2int(f->abs_y);
dprintk(9,
- "bcm5974: p: %+05d w: %+05d x: %+05d y: %+05d n: %d\n",
- p, w, x, y, n);
+ "bcm5974: raw: p: %+05d w: %+05d x: %+05d y: %+05d\n",
+ raw_p, raw_w, raw_x, raw_y);
+
+ ptest = int2bound(&c->p, raw_p);
+ origin = raw2int(f->origin);
+ }
- input_report_abs(input, ABS_TOOL_WIDTH, int2bound(&c->w, w));
- input_report_abs(input, ABS_X, int2bound(&c->x, x - c->x.devmin));
- input_report_abs(input, ABS_Y, int2bound(&c->y, c->y.devmax - y));
+ /* while tracking finger still valid, count all fingers */
+ if (ptest > PRESSURE_LOW && origin) {
+ abs_p = ptest;
+ abs_w = int2bound(&c->w, raw_w);
+ abs_x = int2bound(&c->x, raw_x - c->x.devmin);
+ abs_y = int2bound(&c->y, c->y.devmax - raw_y);
+ for (; f != dev->tp_data->finger + fingers; f++) {
+ ptest = int2bound(&c->p, raw2int(f->force_major));
+ if (ptest > PRESSURE_LOW)
+ nmax++;
+ if (ptest > PRESSURE_HIGH)
+ nmin++;
+ }
}
- input_report_abs(input, ABS_PRESSURE, int2bound(&c->p, p));
+ if (dev->fingers < nmin)
+ dev->fingers = nmin;
+ if (dev->fingers > nmax)
+ dev->fingers = nmax;
+
+ input_report_key(input, BTN_TOUCH, dev->fingers > 0);
+ input_report_key(input, BTN_TOOL_FINGER, dev->fingers == 1);
+ input_report_key(input, BTN_TOOL_DOUBLETAP, dev->fingers == 2);
+ input_report_key(input, BTN_TOOL_TRIPLETAP, dev->fingers > 2);
- input_report_key(input, BTN_TOOL_FINGER, n == 1);
- input_report_key(input, BTN_TOOL_DOUBLETAP, n == 2);
- input_report_key(input, BTN_TOOL_TRIPLETAP, n > 2);
+ input_report_abs(input, ABS_PRESSURE, abs_p);
+ input_report_abs(input, ABS_TOOL_WIDTH, abs_w);
+
+ if (abs_p) {
+ input_report_abs(input, ABS_X, abs_x);
+ input_report_abs(input, ABS_Y, abs_y);
+
+ dprintk(8,
+ "bcm5974: abs: p: %+05d w: %+05d x: %+05d y: %+05d "
+ "nmin: %d nmax: %d n: %d\n",
+ abs_p, abs_w, abs_x, abs_y, nmin, nmax, dev->fingers);
+
+ }
input_sync(input);
@@ -311,8 +351,9 @@ static int report_tp_state(struct bcm5974 *dev, int size)
#define BCM5974_WELLSPRING_MODE_REQUEST_VALUE 0x300
#define BCM5974_WELLSPRING_MODE_REQUEST_INDEX 0
#define BCM5974_WELLSPRING_MODE_VENDOR_VALUE 0x01
+#define BCM5974_WELLSPRING_MODE_NORMAL_VALUE 0x08
-static int bcm5974_wellspring_mode(struct bcm5974 *dev)
+static int bcm5974_wellspring_mode(struct bcm5974 *dev, bool on)
{
char *data = kmalloc(8, GFP_KERNEL);
int retval = 0, size;
@@ -337,7 +378,9 @@ static int bcm5974_wellspring_mode(struct bcm5974 *dev)
}
/* apply the mode switch */
- data[0] = BCM5974_WELLSPRING_MODE_VENDOR_VALUE;
+ data[0] = on ?
+ BCM5974_WELLSPRING_MODE_VENDOR_VALUE :
+ BCM5974_WELLSPRING_MODE_NORMAL_VALUE;
/* write configuration */
size = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
@@ -352,7 +395,8 @@ static int bcm5974_wellspring_mode(struct bcm5974 *dev)
goto out;
}
- dprintk(2, "bcm5974: switched to wellspring mode.\n");
+ dprintk(2, "bcm5974: switched to %s mode.\n",
+ on ? "wellspring" : "normal");
out:
kfree(data);
@@ -441,7 +485,7 @@ exit:
*/
static int bcm5974_start_traffic(struct bcm5974 *dev)
{
- if (bcm5974_wellspring_mode(dev)) {
+ if (bcm5974_wellspring_mode(dev, true)) {
dprintk(1, "bcm5974: mode switch failed\n");
goto error;
}
@@ -464,6 +508,7 @@ static void bcm5974_pause_traffic(struct bcm5974 *dev)
{
usb_kill_urb(dev->tp_urb);
usb_kill_urb(dev->bt_urb);
+ bcm5974_wellspring_mode(dev, false);
}
/*
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index 3282b741e24..5aafe24984c 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -305,7 +305,7 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = {
.ident = "Lenovo 3000 n100",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
- DMI_MATCH(DMI_PRODUCT_VERSION, "3000 N100"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "076804U"),
},
},
{
diff --git a/drivers/input/touchscreen/jornada720_ts.c b/drivers/input/touchscreen/jornada720_ts.c
index bf44f9d6834..c8b7e8a45c4 100644
--- a/drivers/input/touchscreen/jornada720_ts.c
+++ b/drivers/input/touchscreen/jornada720_ts.c
@@ -119,8 +119,8 @@ static int __devinit jornada720_ts_probe(struct platform_device *pdev)
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_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, 270, 3900, 0, 0);
input_set_abs_params(input_dev, ABS_Y, 180, 3700, 0, 0);
diff --git a/drivers/leds/leds-fsg.c b/drivers/leds/leds-fsg.c
index be0e12144b8..34935155c1c 100644
--- a/drivers/leds/leds-fsg.c
+++ b/drivers/leds/leds-fsg.c
@@ -161,6 +161,16 @@ static int fsg_led_probe(struct platform_device *pdev)
{
int ret;
+ /* Map the LED chip select address space */
+ latch_address = (unsigned short *) ioremap(IXP4XX_EXP_BUS_BASE(2), 512);
+ if (!latch_address) {
+ ret = -ENOMEM;
+ goto failremap;
+ }
+
+ latch_value = 0xffff;
+ *latch_address = latch_value;
+
ret = led_classdev_register(&pdev->dev, &fsg_wlan_led);
if (ret < 0)
goto failwlan;
@@ -185,20 +195,8 @@ static int fsg_led_probe(struct platform_device *pdev)
if (ret < 0)
goto failring;
- /* Map the LED chip select address space */
- latch_address = (unsigned short *) ioremap(IXP4XX_EXP_BUS_BASE(2), 512);
- if (!latch_address) {
- ret = -ENOMEM;
- goto failremap;
- }
-
- latch_value = 0xffff;
- *latch_address = latch_value;
-
return ret;
- failremap:
- led_classdev_unregister(&fsg_ring_led);
failring:
led_classdev_unregister(&fsg_sync_led);
failsync:
@@ -210,14 +208,14 @@ static int fsg_led_probe(struct platform_device *pdev)
failwan:
led_classdev_unregister(&fsg_wlan_led);
failwlan:
+ iounmap(latch_address);
+ failremap:
return ret;
}
static int fsg_led_remove(struct platform_device *pdev)
{
- iounmap(latch_address);
-
led_classdev_unregister(&fsg_wlan_led);
led_classdev_unregister(&fsg_wan_led);
led_classdev_unregister(&fsg_sata_led);
@@ -225,6 +223,8 @@ static int fsg_led_remove(struct platform_device *pdev)
led_classdev_unregister(&fsg_sync_led);
led_classdev_unregister(&fsg_ring_led);
+ iounmap(latch_address);
+
return 0;
}
diff --git a/drivers/leds/leds-pca955x.c b/drivers/leds/leds-pca955x.c
index 146c0697286..f508729123b 100644
--- a/drivers/leds/leds-pca955x.c
+++ b/drivers/leds/leds-pca955x.c
@@ -248,11 +248,10 @@ static int __devinit pca955x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct pca955x_led *pca955x;
- int i;
- int err = -ENODEV;
struct pca955x_chipdef *chip;
struct i2c_adapter *adapter;
struct led_platform_data *pdata;
+ int i, err;
chip = &pca955x_chipdefs[id->driver_data];
adapter = to_i2c_adapter(client->dev.parent);
@@ -282,43 +281,41 @@ static int __devinit pca955x_probe(struct i2c_client *client,
}
}
+ pca955x = kzalloc(sizeof(*pca955x) * chip->bits, GFP_KERNEL);
+ if (!pca955x)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, pca955x);
+
for (i = 0; i < chip->bits; i++) {
- pca955x = kzalloc(sizeof(struct pca955x_led), GFP_KERNEL);
- if (!pca955x) {
- err = -ENOMEM;
- goto exit;
- }
+ pca955x[i].chipdef = chip;
+ pca955x[i].client = client;
+ pca955x[i].led_num = i;
- pca955x->chipdef = chip;
- pca955x->client = client;
- pca955x->led_num = i;
/* Platform data can specify LED names and default triggers */
if (pdata) {
if (pdata->leds[i].name)
- snprintf(pca955x->name, 32, "pca955x:%s",
- pdata->leds[i].name);
+ snprintf(pca955x[i].name,
+ sizeof(pca955x[i].name), "pca955x:%s",
+ pdata->leds[i].name);
if (pdata->leds[i].default_trigger)
- pca955x->led_cdev.default_trigger =
+ pca955x[i].led_cdev.default_trigger =
pdata->leds[i].default_trigger;
} else {
- snprintf(pca955x->name, 32, "pca955x:%d", i);
+ snprintf(pca955x[i].name, sizeof(pca955x[i].name),
+ "pca955x:%d", i);
}
- spin_lock_init(&pca955x->lock);
- pca955x->led_cdev.name = pca955x->name;
- pca955x->led_cdev.brightness_set =
- pca955x_led_set;
+ spin_lock_init(&pca955x[i].lock);
- /*
- * Client data is a pointer to the _first_ pca955x_led
- * struct
- */
- if (i == 0)
- i2c_set_clientdata(client, pca955x);
+ pca955x[i].led_cdev.name = pca955x[i].name;
+ pca955x[i].led_cdev.brightness_set = pca955x_led_set;
- INIT_WORK(&(pca955x->work), pca955x_led_work);
+ INIT_WORK(&pca955x[i].work, pca955x_led_work);
- led_classdev_register(&client->dev, &(pca955x->led_cdev));
+ err = led_classdev_register(&client->dev, &pca955x[i].led_cdev);
+ if (err < 0)
+ goto exit;
}
/* Turn off LEDs */
@@ -336,23 +333,32 @@ static int __devinit pca955x_probe(struct i2c_client *client,
pca955x_write_psc(client, 1, 0);
return 0;
+
exit:
+ while (i--) {
+ led_classdev_unregister(&pca955x[i].led_cdev);
+ cancel_work_sync(&pca955x[i].work);
+ }
+
+ kfree(pca955x);
+ i2c_set_clientdata(client, NULL);
+
return err;
}
static int __devexit pca955x_remove(struct i2c_client *client)
{
struct pca955x_led *pca955x = i2c_get_clientdata(client);
- int leds = pca955x->chipdef->bits;
int i;
- for (i = 0; i < leds; i++) {
- led_classdev_unregister(&(pca955x->led_cdev));
- cancel_work_sync(&(pca955x->work));
- kfree(pca955x);
- pca955x = pca955x + 1;
+ for (i = 0; i < pca955x->chipdef->bits; i++) {
+ led_classdev_unregister(&pca955x[i].led_cdev);
+ cancel_work_sync(&pca955x[i].work);
}
+ kfree(pca955x);
+ i2c_set_clientdata(client, NULL);
+
return 0;
}
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index 7e65bad522c..ac89a5deaca 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -238,15 +238,47 @@ static struct page *read_sb_page(mddev_t *mddev, long offset, unsigned long inde
}
+static mdk_rdev_t *next_active_rdev(mdk_rdev_t *rdev, mddev_t *mddev)
+{
+ /* Iterate the disks of an mddev, using rcu to protect access to the
+ * linked list, and raising the refcount of devices we return to ensure
+ * they don't disappear while in use.
+ * As devices are only added or removed when raid_disk is < 0 and
+ * nr_pending is 0 and In_sync is clear, the entries we return will
+ * still be in the same position on the list when we re-enter
+ * list_for_each_continue_rcu.
+ */
+ struct list_head *pos;
+ rcu_read_lock();
+ if (rdev == NULL)
+ /* start at the beginning */
+ pos = &mddev->disks;
+ else {
+ /* release the previous rdev and start from there. */
+ rdev_dec_pending(rdev, mddev);
+ pos = &rdev->same_set;
+ }
+ list_for_each_continue_rcu(pos, &mddev->disks) {
+ rdev = list_entry(pos, mdk_rdev_t, same_set);
+ if (rdev->raid_disk >= 0 &&
+ test_bit(In_sync, &rdev->flags) &&
+ !test_bit(Faulty, &rdev->flags)) {
+ /* this is a usable devices */
+ atomic_inc(&rdev->nr_pending);
+ rcu_read_unlock();
+ return rdev;
+ }
+ }
+ rcu_read_unlock();
+ return NULL;
+}
+
static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait)
{
- mdk_rdev_t *rdev;
+ mdk_rdev_t *rdev = NULL;
mddev_t *mddev = bitmap->mddev;
- rcu_read_lock();
- rdev_for_each_rcu(rdev, mddev)
- if (test_bit(In_sync, &rdev->flags)
- && !test_bit(Faulty, &rdev->flags)) {
+ while ((rdev = next_active_rdev(rdev, mddev)) != NULL) {
int size = PAGE_SIZE;
if (page->index == bitmap->file_pages-1)
size = roundup(bitmap->last_page_size,
@@ -281,8 +313,7 @@ static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait)
+ page->index * (PAGE_SIZE/512),
size,
page);
- }
- rcu_read_unlock();
+ }
if (wait)
md_super_wait(mddev);
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 13956437bc8..682ef9e6acd 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -333,7 +333,6 @@ static void crypt_convert_init(struct crypt_config *cc,
ctx->idx_out = bio_out ? bio_out->bi_idx : 0;
ctx->sector = sector + cc->iv_offset;
init_completion(&ctx->restart);
- atomic_set(&ctx->pending, 1);
}
static int crypt_convert_block(struct crypt_config *cc,
@@ -408,6 +407,8 @@ static int crypt_convert(struct crypt_config *cc,
{
int r;
+ atomic_set(&ctx->pending, 1);
+
while(ctx->idx_in < ctx->bio_in->bi_vcnt &&
ctx->idx_out < ctx->bio_out->bi_vcnt) {
@@ -456,9 +457,11 @@ static void dm_crypt_bio_destructor(struct bio *bio)
/*
* Generate a new unfragmented bio with the given size
* This should never violate the device limitations
- * May return a smaller bio when running out of pages
+ * May return a smaller bio when running out of pages, indicated by
+ * *out_of_pages set to 1.
*/
-static struct bio *crypt_alloc_buffer(struct dm_crypt_io *io, unsigned size)
+static struct bio *crypt_alloc_buffer(struct dm_crypt_io *io, unsigned size,
+ unsigned *out_of_pages)
{
struct crypt_config *cc = io->target->private;
struct bio *clone;
@@ -472,11 +475,14 @@ static struct bio *crypt_alloc_buffer(struct dm_crypt_io *io, unsigned size)
return NULL;
clone_init(io, clone);
+ *out_of_pages = 0;
for (i = 0; i < nr_iovecs; i++) {
page = mempool_alloc(cc->page_pool, gfp_mask);
- if (!page)
+ if (!page) {
+ *out_of_pages = 1;
break;
+ }
/*
* if additional pages cannot be allocated without waiting,
@@ -517,6 +523,27 @@ static void crypt_free_buffer_pages(struct crypt_config *cc, struct bio *clone)
}
}
+static struct dm_crypt_io *crypt_io_alloc(struct dm_target *ti,
+ struct bio *bio, sector_t sector)
+{
+ struct crypt_config *cc = ti->private;
+ struct dm_crypt_io *io;
+
+ io = mempool_alloc(cc->io_pool, GFP_NOIO);
+ io->target = ti;
+ io->base_bio = bio;
+ io->sector = sector;
+ io->error = 0;
+ atomic_set(&io->pending, 0);
+
+ return io;
+}
+
+static void crypt_inc_pending(struct dm_crypt_io *io)
+{
+ atomic_inc(&io->pending);
+}
+
/*
* One of the bios was finished. Check for completion of
* the whole request and correctly clean up the buffer.
@@ -591,7 +618,7 @@ static void kcryptd_io_read(struct dm_crypt_io *io)
struct bio *base_bio = io->base_bio;
struct bio *clone;
- atomic_inc(&io->pending);
+ crypt_inc_pending(io);
/*
* The block layer might modify the bvec array, so always
@@ -653,6 +680,7 @@ static void kcryptd_crypt_write_io_submit(struct dm_crypt_io *io,
crypt_free_buffer_pages(cc, clone);
bio_put(clone);
io->error = -EIO;
+ crypt_dec_pending(io);
return;
}
@@ -664,28 +692,34 @@ static void kcryptd_crypt_write_io_submit(struct dm_crypt_io *io,
if (async)
kcryptd_queue_io(io);
- else {
- atomic_inc(&io->pending);
+ else
generic_make_request(clone);
- }
}
-static void kcryptd_crypt_write_convert_loop(struct dm_crypt_io *io)
+static void kcryptd_crypt_write_convert(struct dm_crypt_io *io)
{
struct crypt_config *cc = io->target->private;
struct bio *clone;
+ int crypt_finished;
+ unsigned out_of_pages = 0;
unsigned remaining = io->base_bio->bi_size;
int r;
/*
+ * Prevent io from disappearing until this function completes.
+ */
+ crypt_inc_pending(io);
+ crypt_convert_init(cc, &io->ctx, NULL, io->base_bio, io->sector);
+
+ /*
* The allocated buffers can be smaller than the whole bio,
* so repeat the whole process until all the data can be handled.
*/
while (remaining) {
- clone = crypt_alloc_buffer(io, remaining);
+ clone = crypt_alloc_buffer(io, remaining, &out_of_pages);
if (unlikely(!clone)) {
io->error = -ENOMEM;
- return;
+ break;
}
io->ctx.bio_out = clone;
@@ -693,37 +727,32 @@ static void kcryptd_crypt_write_convert_loop(struct dm_crypt_io *io)
remaining -= clone->bi_size;
+ crypt_inc_pending(io);
r = crypt_convert(cc, &io->ctx);
+ crypt_finished = atomic_dec_and_test(&io->ctx.pending);
- if (atomic_dec_and_test(&io->ctx.pending)) {
- /* processed, no running async crypto */
+ /* Encryption was already finished, submit io now */
+ if (crypt_finished) {
kcryptd_crypt_write_io_submit(io, r, 0);
- if (unlikely(r < 0))
- return;
- } else
- atomic_inc(&io->pending);
- /* out of memory -> run queues */
- if (unlikely(remaining)) {
- /* wait for async crypto then reinitialize pending */
- wait_event(cc->writeq, !atomic_read(&io->ctx.pending));
- atomic_set(&io->ctx.pending, 1);
- congestion_wait(WRITE, HZ/100);
+ /*
+ * If there was an error, do not try next fragments.
+ * For async, error is processed in async handler.
+ */
+ if (unlikely(r < 0))
+ break;
}
- }
-}
-static void kcryptd_crypt_write_convert(struct dm_crypt_io *io)
-{
- struct crypt_config *cc = io->target->private;
-
- /*
- * Prevent io from disappearing until this function completes.
- */
- atomic_inc(&io->pending);
+ /*
+ * Out of memory -> run queues
+ * But don't wait if split was due to the io size restriction
+ */
+ if (unlikely(out_of_pages))
+ congestion_wait(WRITE, HZ/100);
- crypt_convert_init(cc, &io->ctx, NULL, io->base_bio, io->sector);
- kcryptd_crypt_write_convert_loop(io);
+ if (unlikely(remaining))
+ wait_event(cc->writeq, !atomic_read(&io->ctx.pending));
+ }
crypt_dec_pending(io);
}
@@ -741,7 +770,7 @@ static void kcryptd_crypt_read_convert(struct dm_crypt_io *io)
struct crypt_config *cc = io->target->private;
int r = 0;
- atomic_inc(&io->pending);
+ crypt_inc_pending(io);
crypt_convert_init(cc, &io->ctx, io->base_bio, io->base_bio,
io->sector);
@@ -1108,15 +1137,9 @@ static void crypt_dtr(struct dm_target *ti)
static int crypt_map(struct dm_target *ti, struct bio *bio,
union map_info *map_context)
{
- struct crypt_config *cc = ti->private;
struct dm_crypt_io *io;
- io = mempool_alloc(cc->io_pool, GFP_NOIO);
- io->target = ti;
- io->base_bio = bio;
- io->sector = bio->bi_sector - ti->begin;
- io->error = 0;
- atomic_set(&io->pending, 0);
+ io = crypt_io_alloc(ti, bio, bio->bi_sector - ti->begin);
if (bio_data_dir(io->base_bio) == READ)
kcryptd_queue_io(io);
diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c
index 41f408068a7..769ab677f8e 100644
--- a/drivers/md/dm-exception-store.c
+++ b/drivers/md/dm-exception-store.c
@@ -108,12 +108,12 @@ struct pstore {
* Used to keep track of which metadata area the data in
* 'chunk' refers to.
*/
- uint32_t current_area;
+ chunk_t current_area;
/*
* The next free chunk for an exception.
*/
- uint32_t next_free;
+ chunk_t next_free;
/*
* The index of next free exception in the current
@@ -175,7 +175,7 @@ static void do_metadata(struct work_struct *work)
/*
* Read or write a chunk aligned and sized block of data from a device.
*/
-static int chunk_io(struct pstore *ps, uint32_t chunk, int rw, int metadata)
+static int chunk_io(struct pstore *ps, chunk_t chunk, int rw, int metadata)
{
struct dm_io_region where = {
.bdev = ps->snap->cow->bdev,
@@ -209,16 +209,23 @@ static int chunk_io(struct pstore *ps, uint32_t chunk, int rw, int metadata)
}
/*
+ * Convert a metadata area index to a chunk index.
+ */
+static chunk_t area_location(struct pstore *ps, chunk_t area)
+{
+ return 1 + ((ps->exceptions_per_area + 1) * area);
+}
+
+/*
* Read or write a metadata area. Remembering to skip the first
* chunk which holds the header.
*/
-static int area_io(struct pstore *ps, uint32_t area, int rw)
+static int area_io(struct pstore *ps, chunk_t area, int rw)
{
int r;
- uint32_t chunk;
+ chunk_t chunk;
- /* convert a metadata area index to a chunk index */
- chunk = 1 + ((ps->exceptions_per_area + 1) * area);
+ chunk = area_location(ps, area);
r = chunk_io(ps, chunk, rw, 0);
if (r)
@@ -228,7 +235,7 @@ static int area_io(struct pstore *ps, uint32_t area, int rw)
return 0;
}
-static int zero_area(struct pstore *ps, uint32_t area)
+static int zero_area(struct pstore *ps, chunk_t area)
{
memset(ps->area, 0, ps->snap->chunk_size << SECTOR_SHIFT);
return area_io(ps, area, WRITE);
@@ -404,7 +411,7 @@ static int insert_exceptions(struct pstore *ps, int *full)
static int read_exceptions(struct pstore *ps)
{
- uint32_t area;
+ chunk_t area;
int r, full = 1;
/*
@@ -517,6 +524,7 @@ static int persistent_prepare(struct exception_store *store,
{
struct pstore *ps = get_info(store);
uint32_t stride;
+ chunk_t next_free;
sector_t size = get_dev_size(store->snap->cow->bdev);
/* Is there enough room ? */
@@ -530,7 +538,8 @@ static int persistent_prepare(struct exception_store *store,
* into account the location of the metadata chunks.
*/
stride = (ps->exceptions_per_area + 1);
- if ((++ps->next_free % stride) == 1)
+ next_free = ++ps->next_free;
+ if (sector_div(next_free, stride) == 1)
ps->next_free++;
atomic_inc(&ps->pending_count);
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index b262c0042de..dca401dc70a 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -426,7 +426,7 @@ static int list_devices(struct dm_ioctl *param, size_t param_size)
old_nl->next = (uint32_t) ((void *) nl -
(void *) old_nl);
disk = dm_disk(hc->md);
- nl->dev = huge_encode_dev(MKDEV(disk->major, disk->first_minor));
+ nl->dev = huge_encode_dev(disk_devt(disk));
nl->next = 0;
strcpy(nl->name, hc->name);
@@ -539,7 +539,7 @@ static int __dev_status(struct mapped_device *md, struct dm_ioctl *param)
if (dm_suspended(md))
param->flags |= DM_SUSPEND_FLAG;
- param->dev = huge_encode_dev(MKDEV(disk->major, disk->first_minor));
+ param->dev = huge_encode_dev(disk_devt(disk));
/*
* Yes, this will be out of date by the time it gets back
@@ -548,7 +548,7 @@ static int __dev_status(struct mapped_device *md, struct dm_ioctl *param)
*/
param->open_count = dm_open_count(md);
- if (disk->policy)
+ if (get_disk_ro(disk))
param->flags |= DM_READONLY_FLAG;
param->event_nr = dm_get_event_nr(md);
@@ -1131,7 +1131,7 @@ static void retrieve_deps(struct dm_table *table,
unsigned int count = 0;
struct list_head *tmp;
size_t len, needed;
- struct dm_dev *dd;
+ struct dm_dev_internal *dd;
struct dm_target_deps *deps;
deps = get_result_buffer(param, param_size, &len);
@@ -1157,7 +1157,7 @@ static void retrieve_deps(struct dm_table *table,
deps->count = count;
count = 0;
list_for_each_entry (dd, dm_table_get_devices(table), list)
- deps->dev[count++] = huge_encode_dev(dd->bdev->bd_dev);
+ deps->dev[count++] = huge_encode_dev(dd->dm_dev.bdev->bd_dev);
param->data_size = param->data_start + needed;
}
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index 71dd65aa31b..103304c1e3b 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -30,9 +30,11 @@ struct pgpath {
struct list_head list;
struct priority_group *pg; /* Owning PG */
+ unsigned is_active; /* Path status */
unsigned fail_count; /* Cumulative failure count */
struct dm_path path;
+ struct work_struct deactivate_path;
};
#define path_to_pgpath(__pgp) container_of((__pgp), struct pgpath, path)
@@ -63,6 +65,7 @@ struct multipath {
const char *hw_handler_name;
struct work_struct activate_path;
+ struct pgpath *pgpath_to_activate;
unsigned nr_priority_groups;
struct list_head priority_groups;
unsigned pg_init_required; /* pg_init needs calling? */
@@ -111,6 +114,7 @@ static struct workqueue_struct *kmultipathd, *kmpath_handlerd;
static void process_queued_ios(struct work_struct *work);
static void trigger_event(struct work_struct *work);
static void activate_path(struct work_struct *work);
+static void deactivate_path(struct work_struct *work);
/*-----------------------------------------------
@@ -121,8 +125,10 @@ static struct pgpath *alloc_pgpath(void)
{
struct pgpath *pgpath = kzalloc(sizeof(*pgpath), GFP_KERNEL);
- if (pgpath)
- pgpath->path.is_active = 1;
+ if (pgpath) {
+ pgpath->is_active = 1;
+ INIT_WORK(&pgpath->deactivate_path, deactivate_path);
+ }
return pgpath;
}
@@ -132,6 +138,14 @@ static void free_pgpath(struct pgpath *pgpath)
kfree(pgpath);
}
+static void deactivate_path(struct work_struct *work)
+{
+ struct pgpath *pgpath =
+ container_of(work, struct pgpath, deactivate_path);
+
+ blk_abort_queue(pgpath->path.dev->bdev->bd_disk->queue);
+}
+
static struct priority_group *alloc_priority_group(void)
{
struct priority_group *pg;
@@ -146,6 +160,7 @@ static struct priority_group *alloc_priority_group(void)
static void free_pgpaths(struct list_head *pgpaths, struct dm_target *ti)
{
+ unsigned long flags;
struct pgpath *pgpath, *tmp;
struct multipath *m = ti->private;
@@ -154,6 +169,10 @@ static void free_pgpaths(struct list_head *pgpaths, struct dm_target *ti)
if (m->hw_handler_name)
scsi_dh_detach(bdev_get_queue(pgpath->path.dev->bdev));
dm_put_device(ti, pgpath->path.dev);
+ spin_lock_irqsave(&m->lock, flags);
+ if (m->pgpath_to_activate == pgpath)
+ m->pgpath_to_activate = NULL;
+ spin_unlock_irqrestore(&m->lock, flags);
free_pgpath(pgpath);
}
}
@@ -421,6 +440,7 @@ static void process_queued_ios(struct work_struct *work)
__choose_pgpath(m);
pgpath = m->current_pgpath;
+ m->pgpath_to_activate = m->current_pgpath;
if ((pgpath && !m->queue_io) ||
(!pgpath && !m->queue_if_no_path))
@@ -556,12 +576,12 @@ static struct pgpath *parse_path(struct arg_set *as, struct path_selector *ps,
/* we need at least a path arg */
if (as->argc < 1) {
ti->error = "no device given";
- return NULL;
+ return ERR_PTR(-EINVAL);
}
p = alloc_pgpath();
if (!p)
- return NULL;
+ return ERR_PTR(-ENOMEM);
r = dm_get_device(ti, shift(as), ti->begin, ti->len,
dm_table_get_mode(ti->table), &p->path.dev);
@@ -589,7 +609,7 @@ static struct pgpath *parse_path(struct arg_set *as, struct path_selector *ps,
bad:
free_pgpath(p);
- return NULL;
+ return ERR_PTR(r);
}
static struct priority_group *parse_priority_group(struct arg_set *as,
@@ -607,14 +627,14 @@ static struct priority_group *parse_priority_group(struct arg_set *as,
if (as->argc < 2) {
as->argc = 0;
- ti->error = "not enough priority group aruments";
- return NULL;
+ ti->error = "not enough priority group arguments";
+ return ERR_PTR(-EINVAL);
}
pg = alloc_priority_group();
if (!pg) {
ti->error = "couldn't allocate priority group";
- return NULL;
+ return ERR_PTR(-ENOMEM);
}
pg->m = m;
@@ -647,8 +667,10 @@ static struct priority_group *parse_priority_group(struct arg_set *as,
path_args.argv = as->argv;
pgpath = parse_path(&path_args, &pg->ps, ti);
- if (!pgpath)
+ if (IS_ERR(pgpath)) {
+ r = PTR_ERR(pgpath);
goto bad;
+ }
pgpath->pg = pg;
list_add_tail(&pgpath->list, &pg->pgpaths);
@@ -659,7 +681,7 @@ static struct priority_group *parse_priority_group(struct arg_set *as,
bad:
free_priority_group(pg, ti);
- return NULL;
+ return ERR_PTR(r);
}
static int parse_hw_handler(struct arg_set *as, struct multipath *m)
@@ -778,8 +800,8 @@ static int multipath_ctr(struct dm_target *ti, unsigned int argc,
struct priority_group *pg;
pg = parse_priority_group(&as, m);
- if (!pg) {
- r = -EINVAL;
+ if (IS_ERR(pg)) {
+ r = PTR_ERR(pg);
goto bad;
}
@@ -845,13 +867,13 @@ static int fail_path(struct pgpath *pgpath)
spin_lock_irqsave(&m->lock, flags);
- if (!pgpath->path.is_active)
+ if (!pgpath->is_active)
goto out;
DMWARN("Failing path %s.", pgpath->path.dev->name);
pgpath->pg->ps.type->fail_path(&pgpath->pg->ps, &pgpath->path);
- pgpath->path.is_active = 0;
+ pgpath->is_active = 0;
pgpath->fail_count++;
m->nr_valid_paths--;
@@ -863,6 +885,7 @@ static int fail_path(struct pgpath *pgpath)
pgpath->path.dev->name, m->nr_valid_paths);
queue_work(kmultipathd, &m->trigger_event);
+ queue_work(kmultipathd, &pgpath->deactivate_path);
out:
spin_unlock_irqrestore(&m->lock, flags);
@@ -881,7 +904,7 @@ static int reinstate_path(struct pgpath *pgpath)
spin_lock_irqsave(&m->lock, flags);
- if (pgpath->path.is_active)
+ if (pgpath->is_active)
goto out;
if (!pgpath->pg->ps.type->reinstate_path) {
@@ -895,7 +918,7 @@ static int reinstate_path(struct pgpath *pgpath)
if (r)
goto out;
- pgpath->path.is_active = 1;
+ pgpath->is_active = 1;
m->current_pgpath = NULL;
if (!m->nr_valid_paths++ && m->queue_size)
@@ -1093,8 +1116,15 @@ static void activate_path(struct work_struct *work)
int ret;
struct multipath *m =
container_of(work, struct multipath, activate_path);
- struct dm_path *path = &m->current_pgpath->path;
+ struct dm_path *path;
+ unsigned long flags;
+ spin_lock_irqsave(&m->lock, flags);
+ path = &m->pgpath_to_activate->path;
+ m->pgpath_to_activate = NULL;
+ spin_unlock_irqrestore(&m->lock, flags);
+ if (!path)
+ return;
ret = scsi_dh_activate(bdev_get_queue(path->dev->bdev));
pg_init_done(path, ret);
}
@@ -1276,7 +1306,7 @@ static int multipath_status(struct dm_target *ti, status_type_t type,
list_for_each_entry(p, &pg->pgpaths, list) {
DMEMIT("%s %s %u ", p->path.dev->name,
- p->path.is_active ? "A" : "F",
+ p->is_active ? "A" : "F",
p->fail_count);
if (pg->ps.type->status)
sz += pg->ps.type->status(&pg->ps,
diff --git a/drivers/md/dm-mpath.h b/drivers/md/dm-mpath.h
index c198b856a45..e230f719625 100644
--- a/drivers/md/dm-mpath.h
+++ b/drivers/md/dm-mpath.h
@@ -13,8 +13,6 @@ struct dm_dev;
struct dm_path {
struct dm_dev *dev; /* Read-only */
- unsigned is_active; /* Read-only */
-
void *pscontext; /* For path-selector use */
};
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index ff05fe89308..29913e42c4a 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -842,7 +842,9 @@ static int recover(struct mirror_set *ms, struct region *reg)
}
/* hand to kcopyd */
- set_bit(DM_KCOPYD_IGNORE_ERROR, &flags);
+ if (!errors_handled(ms))
+ set_bit(DM_KCOPYD_IGNORE_ERROR, &flags);
+
r = dm_kcopyd_copy(ms->kcopyd_client, &from, ms->nr_mirrors - 1, to,
flags, recovery_complete, reg);
diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c
index 4de90ab3968..b745d8ac625 100644
--- a/drivers/md/dm-stripe.c
+++ b/drivers/md/dm-stripe.c
@@ -284,8 +284,8 @@ static int stripe_end_io(struct dm_target *ti, struct bio *bio,
memset(major_minor, 0, sizeof(major_minor));
sprintf(major_minor, "%d:%d",
- bio->bi_bdev->bd_disk->major,
- bio->bi_bdev->bd_disk->first_minor);
+ MAJOR(disk_devt(bio->bi_bdev->bd_disk)),
+ MINOR(disk_devt(bio->bi_bdev->bd_disk)));
/*
* Test to see which stripe drive triggered the event
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 61f44140923..a740a6950f5 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -250,7 +250,8 @@ static void free_devices(struct list_head *devices)
struct list_head *tmp, *next;
list_for_each_safe(tmp, next, devices) {
- struct dm_dev *dd = list_entry(tmp, struct dm_dev, list);
+ struct dm_dev_internal *dd =
+ list_entry(tmp, struct dm_dev_internal, list);
kfree(dd);
}
}
@@ -327,12 +328,12 @@ static int lookup_device(const char *path, dev_t *dev)
/*
* See if we've already got a device in the list.
*/
-static struct dm_dev *find_device(struct list_head *l, dev_t dev)
+static struct dm_dev_internal *find_device(struct list_head *l, dev_t dev)
{
- struct dm_dev *dd;
+ struct dm_dev_internal *dd;
list_for_each_entry (dd, l, list)
- if (dd->bdev->bd_dev == dev)
+ if (dd->dm_dev.bdev->bd_dev == dev)
return dd;
return NULL;
@@ -341,45 +342,47 @@ static struct dm_dev *find_device(struct list_head *l, dev_t dev)
/*
* Open a device so we can use it as a map destination.
*/
-static int open_dev(struct dm_dev *d, dev_t dev, struct mapped_device *md)
+static int open_dev(struct dm_dev_internal *d, dev_t dev,
+ struct mapped_device *md)
{
static char *_claim_ptr = "I belong to device-mapper";
struct block_device *bdev;
int r;
- BUG_ON(d->bdev);
+ BUG_ON(d->dm_dev.bdev);
- bdev = open_by_devnum(dev, d->mode);
+ bdev = open_by_devnum(dev, d->dm_dev.mode);
if (IS_ERR(bdev))
return PTR_ERR(bdev);
r = bd_claim_by_disk(bdev, _claim_ptr, dm_disk(md));
if (r)
blkdev_put(bdev);
else
- d->bdev = bdev;
+ d->dm_dev.bdev = bdev;
return r;
}
/*
* Close a device that we've been using.
*/
-static void close_dev(struct dm_dev *d, struct mapped_device *md)
+static void close_dev(struct dm_dev_internal *d, struct mapped_device *md)
{
- if (!d->bdev)
+ if (!d->dm_dev.bdev)
return;
- bd_release_from_disk(d->bdev, dm_disk(md));
- blkdev_put(d->bdev);
- d->bdev = NULL;
+ bd_release_from_disk(d->dm_dev.bdev, dm_disk(md));
+ blkdev_put(d->dm_dev.bdev);
+ d->dm_dev.bdev = NULL;
}
/*
* If possible, this checks an area of a destination device is valid.
*/
-static int check_device_area(struct dm_dev *dd, sector_t start, sector_t len)
+static int check_device_area(struct dm_dev_internal *dd, sector_t start,
+ sector_t len)
{
- sector_t dev_size = dd->bdev->bd_inode->i_size >> SECTOR_SHIFT;
+ sector_t dev_size = dd->dm_dev.bdev->bd_inode->i_size >> SECTOR_SHIFT;
if (!dev_size)
return 1;
@@ -392,16 +395,17 @@ static int check_device_area(struct dm_dev *dd, sector_t start, sector_t len)
* careful to leave things as they were if we fail to reopen the
* device.
*/
-static int upgrade_mode(struct dm_dev *dd, int new_mode, struct mapped_device *md)
+static int upgrade_mode(struct dm_dev_internal *dd, int new_mode,
+ struct mapped_device *md)
{
int r;
- struct dm_dev dd_copy;
- dev_t dev = dd->bdev->bd_dev;
+ struct dm_dev_internal dd_copy;
+ dev_t dev = dd->dm_dev.bdev->bd_dev;
dd_copy = *dd;
- dd->mode |= new_mode;
- dd->bdev = NULL;
+ dd->dm_dev.mode |= new_mode;
+ dd->dm_dev.bdev = NULL;
r = open_dev(dd, dev, md);
if (!r)
close_dev(&dd_copy, md);
@@ -421,7 +425,7 @@ static int __table_get_device(struct dm_table *t, struct dm_target *ti,
{
int r;
dev_t uninitialized_var(dev);
- struct dm_dev *dd;
+ struct dm_dev_internal *dd;
unsigned int major, minor;
BUG_ON(!t);
@@ -443,20 +447,20 @@ static int __table_get_device(struct dm_table *t, struct dm_target *ti,
if (!dd)
return -ENOMEM;
- dd->mode = mode;
- dd->bdev = NULL;
+ dd->dm_dev.mode = mode;
+ dd->dm_dev.bdev = NULL;
if ((r = open_dev(dd, dev, t->md))) {
kfree(dd);
return r;
}
- format_dev_t(dd->name, dev);
+ format_dev_t(dd->dm_dev.name, dev);
atomic_set(&dd->count, 0);
list_add(&dd->list, &t->devices);
- } else if (dd->mode != (mode | dd->mode)) {
+ } else if (dd->dm_dev.mode != (mode | dd->dm_dev.mode)) {
r = upgrade_mode(dd, mode, t->md);
if (r)
return r;
@@ -465,11 +469,11 @@ static int __table_get_device(struct dm_table *t, struct dm_target *ti,
if (!check_device_area(dd, start, len)) {
DMWARN("device %s too small for target", path);
- dm_put_device(ti, dd);
+ dm_put_device(ti, &dd->dm_dev);
return -EINVAL;
}
- *result = dd;
+ *result = &dd->dm_dev;
return 0;
}
@@ -478,6 +482,13 @@ void dm_set_device_limits(struct dm_target *ti, struct block_device *bdev)
{
struct request_queue *q = bdev_get_queue(bdev);
struct io_restrictions *rs = &ti->limits;
+ char b[BDEVNAME_SIZE];
+
+ if (unlikely(!q)) {
+ DMWARN("%s: Cannot set limits for nonexistent device %s",
+ dm_device_name(ti->table->md), bdevname(bdev, b));
+ return;
+ }
/*
* Combine the device limits low.
@@ -540,8 +551,11 @@ int dm_get_device(struct dm_target *ti, const char *path, sector_t start,
/*
* Decrement a devices use count and remove it if necessary.
*/
-void dm_put_device(struct dm_target *ti, struct dm_dev *dd)
+void dm_put_device(struct dm_target *ti, struct dm_dev *d)
{
+ struct dm_dev_internal *dd = container_of(d, struct dm_dev_internal,
+ dm_dev);
+
if (atomic_dec_and_test(&dd->count)) {
close_dev(dd, ti->table->md);
list_del(&dd->list);
@@ -937,13 +951,20 @@ int dm_table_resume_targets(struct dm_table *t)
int dm_table_any_congested(struct dm_table *t, int bdi_bits)
{
- struct dm_dev *dd;
+ struct dm_dev_internal *dd;
struct list_head *devices = dm_table_get_devices(t);
int r = 0;
list_for_each_entry(dd, devices, list) {
- struct request_queue *q = bdev_get_queue(dd->bdev);
- r |= bdi_congested(&q->backing_dev_info, bdi_bits);
+ struct request_queue *q = bdev_get_queue(dd->dm_dev.bdev);
+ char b[BDEVNAME_SIZE];
+
+ if (likely(q))
+ r |= bdi_congested(&q->backing_dev_info, bdi_bits);
+ else
+ DMWARN_LIMIT("%s: any_congested: nonexistent device %s",
+ dm_device_name(t->md),
+ bdevname(dd->dm_dev.bdev, b));
}
return r;
@@ -951,13 +972,19 @@ int dm_table_any_congested(struct dm_table *t, int bdi_bits)
void dm_table_unplug_all(struct dm_table *t)
{
- struct dm_dev *dd;
+ struct dm_dev_internal *dd;
struct list_head *devices = dm_table_get_devices(t);
list_for_each_entry(dd, devices, list) {
- struct request_queue *q = bdev_get_queue(dd->bdev);
-
- blk_unplug(q);
+ struct request_queue *q = bdev_get_queue(dd->dm_dev.bdev);
+ char b[BDEVNAME_SIZE];
+
+ if (likely(q))
+ blk_unplug(q);
+ else
+ DMWARN_LIMIT("%s: Cannot unplug nonexistent device %s",
+ dm_device_name(t->md),
+ bdevname(dd->dm_dev.bdev, b));
}
}
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index bca448e1187..327de03a5bd 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -377,13 +377,14 @@ static void free_tio(struct mapped_device *md, struct dm_target_io *tio)
static void start_io_acct(struct dm_io *io)
{
struct mapped_device *md = io->md;
+ int cpu;
io->start_time = jiffies;
- preempt_disable();
- disk_round_stats(dm_disk(md));
- preempt_enable();
- dm_disk(md)->in_flight = atomic_inc_return(&md->pending);
+ cpu = part_stat_lock();
+ part_round_stats(cpu, &dm_disk(md)->part0);
+ part_stat_unlock();
+ dm_disk(md)->part0.in_flight = atomic_inc_return(&md->pending);
}
static int end_io_acct(struct dm_io *io)
@@ -391,15 +392,16 @@ static int end_io_acct(struct dm_io *io)
struct mapped_device *md = io->md;
struct bio *bio = io->bio;
unsigned long duration = jiffies - io->start_time;
- int pending;
+ int pending, cpu;
int rw = bio_data_dir(bio);
- preempt_disable();
- disk_round_stats(dm_disk(md));
- preempt_enable();
- dm_disk(md)->in_flight = pending = atomic_dec_return(&md->pending);
+ cpu = part_stat_lock();
+ part_round_stats(cpu, &dm_disk(md)->part0);
+ part_stat_add(cpu, &dm_disk(md)->part0, ticks[rw], duration);
+ part_stat_unlock();
- disk_stat_add(dm_disk(md), ticks[rw], duration);
+ dm_disk(md)->part0.in_flight = pending =
+ atomic_dec_return(&md->pending);
return !pending;
}
@@ -837,12 +839,14 @@ static int dm_merge_bvec(struct request_queue *q,
struct dm_table *map = dm_get_table(md);
struct dm_target *ti;
sector_t max_sectors;
- int max_size;
+ int max_size = 0;
if (unlikely(!map))
- return 0;
+ goto out;
ti = dm_table_find_target(map, bvm->bi_sector);
+ if (!dm_target_is_valid(ti))
+ goto out_table;
/*
* Find maximum amount of I/O that won't need splitting
@@ -861,14 +865,16 @@ static int dm_merge_bvec(struct request_queue *q,
if (max_size && ti->type->merge)
max_size = ti->type->merge(ti, bvm, biovec, max_size);
+out_table:
+ dm_table_put(map);
+
+out:
/*
* Always allow an entire first page
*/
if (max_size <= biovec->bv_len && !(bvm->bi_size >> SECTOR_SHIFT))
max_size = biovec->bv_len;
- dm_table_put(map);
-
return max_size;
}
@@ -881,6 +887,7 @@ static int dm_request(struct request_queue *q, struct bio *bio)
int r = -EIO;
int rw = bio_data_dir(bio);
struct mapped_device *md = q->queuedata;
+ int cpu;
/*
* There is no use in forwarding any barrier request since we can't
@@ -893,8 +900,10 @@ static int dm_request(struct request_queue *q, struct bio *bio)
down_read(&md->io_lock);
- disk_stat_inc(dm_disk(md), ios[rw]);
- disk_stat_add(dm_disk(md), sectors[rw], bio_sectors(bio));
+ cpu = part_stat_lock();
+ part_stat_inc(cpu, &dm_disk(md)->part0, ios[rw]);
+ part_stat_add(cpu, &dm_disk(md)->part0, sectors[rw], bio_sectors(bio));
+ part_stat_unlock();
/*
* If we're suspended we have to queue
@@ -1142,7 +1151,7 @@ static void unlock_fs(struct mapped_device *md);
static void free_dev(struct mapped_device *md)
{
- int minor = md->disk->first_minor;
+ int minor = MINOR(disk_devt(md->disk));
if (md->suspended_bdev) {
unlock_fs(md);
@@ -1178,7 +1187,7 @@ static void event_callback(void *context)
list_splice_init(&md->uevent_list, &uevents);
spin_unlock_irqrestore(&md->uevent_lock, flags);
- dm_send_uevents(&uevents, &md->disk->dev.kobj);
+ dm_send_uevents(&uevents, &disk_to_dev(md->disk)->kobj);
atomic_inc(&md->event_nr);
wake_up(&md->eventq);
@@ -1263,7 +1272,7 @@ static struct mapped_device *dm_find_md(dev_t dev)
md = idr_find(&_minor_idr, minor);
if (md && (md == MINOR_ALLOCED ||
- (dm_disk(md)->first_minor != minor) ||
+ (MINOR(disk_devt(dm_disk(md))) != minor) ||
test_bit(DMF_FREEING, &md->flags))) {
md = NULL;
goto out;
@@ -1314,7 +1323,8 @@ void dm_put(struct mapped_device *md)
if (atomic_dec_and_lock(&md->holders, &_minor_lock)) {
map = dm_get_table(md);
- idr_replace(&_minor_idr, MINOR_ALLOCED, dm_disk(md)->first_minor);
+ idr_replace(&_minor_idr, MINOR_ALLOCED,
+ MINOR(disk_devt(dm_disk(md))));
set_bit(DMF_FREEING, &md->flags);
spin_unlock(&_minor_lock);
if (!dm_suspended(md)) {
@@ -1634,7 +1644,7 @@ out:
*---------------------------------------------------------------*/
void dm_kobject_uevent(struct mapped_device *md)
{
- kobject_uevent(&md->disk->dev.kobj, KOBJ_CHANGE);
+ kobject_uevent(&disk_to_dev(md->disk)->kobj, KOBJ_CHANGE);
}
uint32_t dm_next_uevent_seq(struct mapped_device *md)
diff --git a/drivers/md/dm.h b/drivers/md/dm.h
index 1e59a0b0a78..cd189da2b2f 100644
--- a/drivers/md/dm.h
+++ b/drivers/md/dm.h
@@ -25,13 +25,10 @@
/*
* List of devices that a metadevice uses and should open/close.
*/
-struct dm_dev {
+struct dm_dev_internal {
struct list_head list;
-
atomic_t count;
- int mode;
- struct block_device *bdev;
- char name[16];
+ struct dm_dev dm_dev;
};
struct dm_table;
@@ -49,7 +46,6 @@ void dm_table_presuspend_targets(struct dm_table *t);
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);
/*
* To check the return value from dm_table_find_target().
@@ -93,8 +89,6 @@ void dm_linear_exit(void);
int dm_stripe_init(void);
void dm_stripe_exit(void);
-void *dm_vcalloc(unsigned long nmemb, unsigned long elem_size);
-union map_info *dm_get_mapinfo(struct bio *bio);
int dm_open_count(struct mapped_device *md);
int dm_lock_for_deletion(struct mapped_device *md);
diff --git a/drivers/md/linear.c b/drivers/md/linear.c
index b1eebf88c20..b9cbee688fa 100644
--- a/drivers/md/linear.c
+++ b/drivers/md/linear.c
@@ -318,14 +318,18 @@ static int linear_make_request (struct request_queue *q, struct bio *bio)
mddev_t *mddev = q->queuedata;
dev_info_t *tmp_dev;
sector_t block;
+ int cpu;
if (unlikely(bio_barrier(bio))) {
bio_endio(bio, -EOPNOTSUPP);
return 0;
}
- disk_stat_inc(mddev->gendisk, ios[rw]);
- disk_stat_add(mddev->gendisk, sectors[rw], bio_sectors(bio));
+ cpu = part_stat_lock();
+ part_stat_inc(cpu, &mddev->gendisk->part0, ios[rw]);
+ part_stat_add(cpu, &mddev->gendisk->part0, sectors[rw],
+ bio_sectors(bio));
+ part_stat_unlock();
tmp_dev = which_dev(mddev, bio->bi_sector);
block = bio->bi_sector >> 1;
@@ -349,7 +353,7 @@ static int linear_make_request (struct request_queue *q, struct bio *bio)
* split it.
*/
struct bio_pair *bp;
- bp = bio_split(bio, bio_split_pool,
+ bp = bio_split(bio,
((tmp_dev->offset + tmp_dev->size)<<1) - bio->bi_sector);
if (linear_make_request(q, &bp->bio1))
generic_make_request(&bp->bio1);
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 8cfadc5bd2b..0a3a4bdcd4a 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -1464,10 +1464,7 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
if ((err = kobject_add(&rdev->kobj, &mddev->kobj, "dev-%s", b)))
goto fail;
- if (rdev->bdev->bd_part)
- ko = &rdev->bdev->bd_part->dev.kobj;
- else
- ko = &rdev->bdev->bd_disk->dev.kobj;
+ ko = &part_to_dev(rdev->bdev->bd_part)->kobj;
if ((err = sysfs_create_link(&rdev->kobj, ko, "block"))) {
kobject_del(&rdev->kobj);
goto fail;
@@ -3470,8 +3467,8 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data)
disk->queue = mddev->queue;
add_disk(disk);
mddev->gendisk = disk;
- error = kobject_init_and_add(&mddev->kobj, &md_ktype, &disk->dev.kobj,
- "%s", "md");
+ error = kobject_init_and_add(&mddev->kobj, &md_ktype,
+ &disk_to_dev(disk)->kobj, "%s", "md");
mutex_unlock(&disks_mutex);
if (error)
printk(KERN_WARNING "md: cannot register %s/md - name in use\n",
@@ -3761,7 +3758,7 @@ static int do_md_run(mddev_t * mddev)
sysfs_notify(&mddev->kobj, NULL, "array_state");
sysfs_notify(&mddev->kobj, NULL, "sync_action");
sysfs_notify(&mddev->kobj, NULL, "degraded");
- kobject_uevent(&mddev->gendisk->dev.kobj, KOBJ_CHANGE);
+ kobject_uevent(&disk_to_dev(mddev->gendisk)->kobj, KOBJ_CHANGE);
return 0;
}
@@ -3841,8 +3838,6 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open)
del_timer_sync(&mddev->safemode_timer);
- invalidate_partition(disk, 0);
-
switch(mode) {
case 1: /* readonly */
err = -ENXIO;
@@ -5551,8 +5546,8 @@ static int is_mddev_idle(mddev_t *mddev)
rcu_read_lock();
rdev_for_each_rcu(rdev, mddev) {
struct gendisk *disk = rdev->bdev->bd_contains->bd_disk;
- curr_events = disk_stat_read(disk, sectors[0]) +
- disk_stat_read(disk, sectors[1]) -
+ curr_events = part_stat_read(&disk->part0, sectors[0]) +
+ part_stat_read(&disk->part0, sectors[1]) -
atomic_read(&disk->sync_io);
/* sync IO will cause sync_io to increase before the disk_stats
* as sync_io is counted when a request starts, and
@@ -5763,7 +5758,11 @@ void md_do_sync(mddev_t *mddev)
* time 'round when curr_resync == 2
*/
continue;
- prepare_to_wait(&resync_wait, &wq, TASK_UNINTERRUPTIBLE);
+ /* We need to wait 'interruptible' so as not to
+ * contribute to the load average, and not to
+ * be caught by 'softlockup'
+ */
+ prepare_to_wait(&resync_wait, &wq, TASK_INTERRUPTIBLE);
if (!kthread_should_stop() &&
mddev2->curr_resync >= mddev->curr_resync) {
printk(KERN_INFO "md: delaying %s of %s"
@@ -5771,6 +5770,8 @@ void md_do_sync(mddev_t *mddev)
" share one or more physical units)\n",
desc, mdname(mddev), mdname(mddev2));
mddev_put(mddev2);
+ if (signal_pending(current))
+ flush_signals(current);
schedule();
finish_wait(&resync_wait, &wq);
goto try_again;
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c
index c4779ccba1c..8bb8794129b 100644
--- a/drivers/md/multipath.c
+++ b/drivers/md/multipath.c
@@ -147,6 +147,7 @@ static int multipath_make_request (struct request_queue *q, struct bio * bio)
struct multipath_bh * mp_bh;
struct multipath_info *multipath;
const int rw = bio_data_dir(bio);
+ int cpu;
if (unlikely(bio_barrier(bio))) {
bio_endio(bio, -EOPNOTSUPP);
@@ -158,8 +159,11 @@ static int multipath_make_request (struct request_queue *q, struct bio * bio)
mp_bh->master_bio = bio;
mp_bh->mddev = mddev;
- disk_stat_inc(mddev->gendisk, ios[rw]);
- disk_stat_add(mddev->gendisk, sectors[rw], bio_sectors(bio));
+ cpu = part_stat_lock();
+ part_stat_inc(cpu, &mddev->gendisk->part0, ios[rw]);
+ part_stat_add(cpu, &mddev->gendisk->part0, sectors[rw],
+ bio_sectors(bio));
+ part_stat_unlock();
mp_bh->path = multipath_map(conf);
if (mp_bh->path < 0) {
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index 18361063566..53508a8a981 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -399,14 +399,18 @@ static int raid0_make_request (struct request_queue *q, struct bio *bio)
sector_t chunk;
sector_t block, rsect;
const int rw = bio_data_dir(bio);
+ int cpu;
if (unlikely(bio_barrier(bio))) {
bio_endio(bio, -EOPNOTSUPP);
return 0;
}
- disk_stat_inc(mddev->gendisk, ios[rw]);
- disk_stat_add(mddev->gendisk, sectors[rw], bio_sectors(bio));
+ cpu = part_stat_lock();
+ part_stat_inc(cpu, &mddev->gendisk->part0, ios[rw]);
+ part_stat_add(cpu, &mddev->gendisk->part0, sectors[rw],
+ bio_sectors(bio));
+ part_stat_unlock();
chunk_size = mddev->chunk_size >> 10;
chunk_sects = mddev->chunk_size >> 9;
@@ -423,7 +427,7 @@ static int raid0_make_request (struct request_queue *q, struct bio *bio)
/* This is a one page bio that upper layers
* refuse to split for us, so we need to split it.
*/
- bp = bio_split(bio, bio_split_pool, chunk_sects - (bio->bi_sector & (chunk_sects - 1)) );
+ bp = bio_split(bio, chunk_sects - (bio->bi_sector & (chunk_sects - 1)));
if (raid0_make_request(q, &bp->bio1))
generic_make_request(&bp->bio1);
if (raid0_make_request(q, &bp->bio2))
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 03a5ab705c2..b9764429d85 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -779,7 +779,7 @@ static int make_request(struct request_queue *q, struct bio * bio)
struct page **behind_pages = NULL;
const int rw = bio_data_dir(bio);
const int do_sync = bio_sync(bio);
- int do_barriers;
+ int cpu, do_barriers;
mdk_rdev_t *blocked_rdev;
/*
@@ -804,8 +804,11 @@ static int make_request(struct request_queue *q, struct bio * bio)
bitmap = mddev->bitmap;
- disk_stat_inc(mddev->gendisk, ios[rw]);
- disk_stat_add(mddev->gendisk, sectors[rw], bio_sectors(bio));
+ cpu = part_stat_lock();
+ part_stat_inc(cpu, &mddev->gendisk->part0, ios[rw]);
+ part_stat_add(cpu, &mddev->gendisk->part0, sectors[rw],
+ bio_sectors(bio));
+ part_stat_unlock();
/*
* make_request() can abort the operation when READA is being
@@ -1302,9 +1305,6 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio)
sbio->bi_size = r1_bio->sectors << 9;
sbio->bi_idx = 0;
sbio->bi_phys_segments = 0;
- sbio->bi_hw_segments = 0;
- sbio->bi_hw_front_size = 0;
- sbio->bi_hw_back_size = 0;
sbio->bi_flags &= ~(BIO_POOL_MASK - 1);
sbio->bi_flags |= 1 << BIO_UPTODATE;
sbio->bi_next = NULL;
@@ -1790,7 +1790,6 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
bio->bi_vcnt = 0;
bio->bi_idx = 0;
bio->bi_phys_segments = 0;
- bio->bi_hw_segments = 0;
bio->bi_size = 0;
bio->bi_end_io = NULL;
bio->bi_private = NULL;
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index e34cd0e6247..8bdc9bfc288 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -789,6 +789,7 @@ static int make_request(struct request_queue *q, struct bio * bio)
mirror_info_t *mirror;
r10bio_t *r10_bio;
struct bio *read_bio;
+ int cpu;
int i;
int chunk_sects = conf->chunk_mask + 1;
const int rw = bio_data_dir(bio);
@@ -816,7 +817,7 @@ static int make_request(struct request_queue *q, struct bio * bio)
/* This is a one page bio that upper layers
* refuse to split for us, so we need to split it.
*/
- bp = bio_split(bio, bio_split_pool,
+ bp = bio_split(bio,
chunk_sects - (bio->bi_sector & (chunk_sects - 1)) );
if (make_request(q, &bp->bio1))
generic_make_request(&bp->bio1);
@@ -843,8 +844,11 @@ static int make_request(struct request_queue *q, struct bio * bio)
*/
wait_barrier(conf);
- disk_stat_inc(mddev->gendisk, ios[rw]);
- disk_stat_add(mddev->gendisk, sectors[rw], bio_sectors(bio));
+ cpu = part_stat_lock();
+ part_stat_inc(cpu, &mddev->gendisk->part0, ios[rw]);
+ part_stat_add(cpu, &mddev->gendisk->part0, sectors[rw],
+ bio_sectors(bio));
+ part_stat_unlock();
r10_bio = mempool_alloc(conf->r10bio_pool, GFP_NOIO);
@@ -1345,9 +1349,6 @@ static void sync_request_write(mddev_t *mddev, r10bio_t *r10_bio)
tbio->bi_size = r10_bio->sectors << 9;
tbio->bi_idx = 0;
tbio->bi_phys_segments = 0;
- tbio->bi_hw_segments = 0;
- tbio->bi_hw_front_size = 0;
- tbio->bi_hw_back_size = 0;
tbio->bi_flags &= ~(BIO_POOL_MASK - 1);
tbio->bi_flags |= 1 << BIO_UPTODATE;
tbio->bi_next = NULL;
@@ -1947,7 +1948,6 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
bio->bi_vcnt = 0;
bio->bi_idx = 0;
bio->bi_phys_segments = 0;
- bio->bi_hw_segments = 0;
bio->bi_size = 0;
}
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 224de022e7c..ae16794bef2 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -101,6 +101,40 @@
const char raid6_empty_zero_page[PAGE_SIZE] __attribute__((aligned(256)));
#endif
+/*
+ * We maintain a biased count of active stripes in the bottom 16 bits of
+ * bi_phys_segments, and a count of processed stripes in the upper 16 bits
+ */
+static inline int raid5_bi_phys_segments(struct bio *bio)
+{
+ return bio->bi_phys_segments & 0xffff;
+}
+
+static inline int raid5_bi_hw_segments(struct bio *bio)
+{
+ return (bio->bi_phys_segments >> 16) & 0xffff;
+}
+
+static inline int raid5_dec_bi_phys_segments(struct bio *bio)
+{
+ --bio->bi_phys_segments;
+ return raid5_bi_phys_segments(bio);
+}
+
+static inline int raid5_dec_bi_hw_segments(struct bio *bio)
+{
+ unsigned short val = raid5_bi_hw_segments(bio);
+
+ --val;
+ bio->bi_phys_segments = (val << 16) | raid5_bi_phys_segments(bio);
+ return val;
+}
+
+static inline void raid5_set_bi_hw_segments(struct bio *bio, unsigned int cnt)
+{
+ bio->bi_phys_segments = raid5_bi_phys_segments(bio) || (cnt << 16);
+}
+
static inline int raid6_next_disk(int disk, int raid_disks)
{
disk++;
@@ -507,7 +541,7 @@ static void ops_complete_biofill(void *stripe_head_ref)
while (rbi && rbi->bi_sector <
dev->sector + STRIPE_SECTORS) {
rbi2 = r5_next_bio(rbi, dev->sector);
- if (--rbi->bi_phys_segments == 0) {
+ if (!raid5_dec_bi_phys_segments(rbi)) {
rbi->bi_next = return_bi;
return_bi = rbi;
}
@@ -1725,7 +1759,7 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in
if (*bip)
bi->bi_next = *bip;
*bip = bi;
- bi->bi_phys_segments ++;
+ bi->bi_phys_segments++;
spin_unlock_irq(&conf->device_lock);
spin_unlock(&sh->lock);
@@ -1819,7 +1853,7 @@ handle_failed_stripe(raid5_conf_t *conf, struct stripe_head *sh,
sh->dev[i].sector + STRIPE_SECTORS) {
struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector);
clear_bit(BIO_UPTODATE, &bi->bi_flags);
- if (--bi->bi_phys_segments == 0) {
+ if (!raid5_dec_bi_phys_segments(bi)) {
md_write_end(conf->mddev);
bi->bi_next = *return_bi;
*return_bi = bi;
@@ -1834,7 +1868,7 @@ handle_failed_stripe(raid5_conf_t *conf, struct stripe_head *sh,
sh->dev[i].sector + STRIPE_SECTORS) {
struct bio *bi2 = r5_next_bio(bi, sh->dev[i].sector);
clear_bit(BIO_UPTODATE, &bi->bi_flags);
- if (--bi->bi_phys_segments == 0) {
+ if (!raid5_dec_bi_phys_segments(bi)) {
md_write_end(conf->mddev);
bi->bi_next = *return_bi;
*return_bi = bi;
@@ -1858,7 +1892,7 @@ handle_failed_stripe(raid5_conf_t *conf, struct stripe_head *sh,
struct bio *nextbi =
r5_next_bio(bi, sh->dev[i].sector);
clear_bit(BIO_UPTODATE, &bi->bi_flags);
- if (--bi->bi_phys_segments == 0) {
+ if (!raid5_dec_bi_phys_segments(bi)) {
bi->bi_next = *return_bi;
*return_bi = bi;
}
@@ -2033,7 +2067,7 @@ static void handle_stripe_clean_event(raid5_conf_t *conf,
while (wbi && wbi->bi_sector <
dev->sector + STRIPE_SECTORS) {
wbi2 = r5_next_bio(wbi, dev->sector);
- if (--wbi->bi_phys_segments == 0) {
+ if (!raid5_dec_bi_phys_segments(wbi)) {
md_write_end(conf->mddev);
wbi->bi_next = *return_bi;
*return_bi = wbi;
@@ -2814,7 +2848,7 @@ static bool handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
copy_data(0, rbi, dev->page, dev->sector);
rbi2 = r5_next_bio(rbi, dev->sector);
spin_lock_irq(&conf->device_lock);
- if (--rbi->bi_phys_segments == 0) {
+ if (!raid5_dec_bi_phys_segments(rbi)) {
rbi->bi_next = return_bi;
return_bi = rbi;
}
@@ -3155,8 +3189,11 @@ static struct bio *remove_bio_from_retry(raid5_conf_t *conf)
if(bi) {
conf->retry_read_aligned_list = bi->bi_next;
bi->bi_next = NULL;
+ /*
+ * this sets the active strip count to 1 and the processed
+ * strip count to zero (upper 8 bits)
+ */
bi->bi_phys_segments = 1; /* biased count of active stripes */
- bi->bi_hw_segments = 0; /* count of processed stripes */
}
return bi;
@@ -3206,8 +3243,7 @@ static int bio_fits_rdev(struct bio *bi)
if ((bi->bi_size>>9) > q->max_sectors)
return 0;
blk_recount_segments(q, bi);
- if (bi->bi_phys_segments > q->max_phys_segments ||
- bi->bi_hw_segments > q->max_hw_segments)
+ if (bi->bi_phys_segments > q->max_phys_segments)
return 0;
if (q->merge_bvec_fn)
@@ -3351,7 +3387,7 @@ static int make_request(struct request_queue *q, struct bio * bi)
sector_t logical_sector, last_sector;
struct stripe_head *sh;
const int rw = bio_data_dir(bi);
- int remaining;
+ int cpu, remaining;
if (unlikely(bio_barrier(bi))) {
bio_endio(bi, -EOPNOTSUPP);
@@ -3360,8 +3396,11 @@ static int make_request(struct request_queue *q, struct bio * bi)
md_write_start(mddev, bi);
- disk_stat_inc(mddev->gendisk, ios[rw]);
- disk_stat_add(mddev->gendisk, sectors[rw], bio_sectors(bi));
+ cpu = part_stat_lock();
+ part_stat_inc(cpu, &mddev->gendisk->part0, ios[rw]);
+ part_stat_add(cpu, &mddev->gendisk->part0, sectors[rw],
+ bio_sectors(bi));
+ part_stat_unlock();
if (rw == READ &&
mddev->reshape_position == MaxSector &&
@@ -3468,7 +3507,7 @@ static int make_request(struct request_queue *q, struct bio * bi)
}
spin_lock_irq(&conf->device_lock);
- remaining = --bi->bi_phys_segments;
+ remaining = raid5_dec_bi_phys_segments(bi);
spin_unlock_irq(&conf->device_lock);
if (remaining == 0) {
@@ -3752,7 +3791,7 @@ static int retry_aligned_read(raid5_conf_t *conf, struct bio *raid_bio)
sector += STRIPE_SECTORS,
scnt++) {
- if (scnt < raid_bio->bi_hw_segments)
+ if (scnt < raid5_bi_hw_segments(raid_bio))
/* already done this stripe */
continue;
@@ -3760,7 +3799,7 @@ static int retry_aligned_read(raid5_conf_t *conf, struct bio *raid_bio)
if (!sh) {
/* failed to get a stripe - must wait */
- raid_bio->bi_hw_segments = scnt;
+ raid5_set_bi_hw_segments(raid_bio, scnt);
conf->retry_read_aligned = raid_bio;
return handled;
}
@@ -3768,7 +3807,7 @@ static int retry_aligned_read(raid5_conf_t *conf, struct bio *raid_bio)
set_bit(R5_ReadError, &sh->dev[dd_idx].flags);
if (!add_stripe_bio(sh, raid_bio, dd_idx, 0)) {
release_stripe(sh);
- raid_bio->bi_hw_segments = scnt;
+ raid5_set_bi_hw_segments(raid_bio, scnt);
conf->retry_read_aligned = raid_bio;
return handled;
}
@@ -3778,7 +3817,7 @@ static int retry_aligned_read(raid5_conf_t *conf, struct bio *raid_bio)
handled++;
}
spin_lock_irq(&conf->device_lock);
- remaining = --raid_bio->bi_phys_segments;
+ remaining = raid5_dec_bi_phys_segments(raid_bio);
spin_unlock_irq(&conf->device_lock);
if (remaining == 0)
bio_endio(raid_bio, 0);
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
index e8bc7abf240..99be9e5c85f 100644
--- a/drivers/media/common/saa7146_video.c
+++ b/drivers/media/common/saa7146_video.c
@@ -1068,7 +1068,7 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
{
v4l2_std_id *id = arg;
int found = 0;
- int i, err;
+ int i;
DEB_EE(("VIDIOC_S_STD\n"));
@@ -1116,7 +1116,6 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
case VIDIOC_OVERLAY:
{
int on = *(int *)arg;
- int err = 0;
DEB_D(("VIDIOC_OVERLAY on:%d\n",on));
if (on != 0) {
@@ -1192,7 +1191,6 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
case VIDIOCGMBUF:
{
struct video_mbuf *mbuf = arg;
- struct videobuf_queue *q;
int i;
/* fixme: number of capture buffers and sizes for v4l apps */
diff --git a/drivers/media/common/tuners/mt2131.c b/drivers/media/common/tuners/mt2131.c
index e254bcfc2ef..e8d3c48f860 100644
--- a/drivers/media/common/tuners/mt2131.c
+++ b/drivers/media/common/tuners/mt2131.c
@@ -1,7 +1,7 @@
/*
* Driver for Microtune MT2131 "QAM/8VSB single chip tuner"
*
- * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ * Copyright (c) 2006 Steven Toth <stoth@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
diff --git a/drivers/media/common/tuners/mt2131.h b/drivers/media/common/tuners/mt2131.h
index cd8376f6f7b..6632de640df 100644
--- a/drivers/media/common/tuners/mt2131.h
+++ b/drivers/media/common/tuners/mt2131.h
@@ -1,7 +1,7 @@
/*
* Driver for Microtune MT2131 "QAM/8VSB single chip tuner"
*
- * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ * Copyright (c) 2006 Steven Toth <stoth@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
diff --git a/drivers/media/common/tuners/mt2131_priv.h b/drivers/media/common/tuners/mt2131_priv.h
index e930759c2c0..4e05a67e88c 100644
--- a/drivers/media/common/tuners/mt2131_priv.h
+++ b/drivers/media/common/tuners/mt2131_priv.h
@@ -1,7 +1,7 @@
/*
* Driver for Microtune MT2131 "QAM/8VSB single chip tuner"
*
- * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ * Copyright (c) 2006 Steven Toth <stoth@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
diff --git a/drivers/media/common/tuners/mxl5005s.c b/drivers/media/common/tuners/mxl5005s.c
index 0dc2bef9f6a..227642b044a 100644
--- a/drivers/media/common/tuners/mxl5005s.c
+++ b/drivers/media/common/tuners/mxl5005s.c
@@ -2,7 +2,7 @@
MaxLinear MXL5005S VSB/QAM/DVBT tuner driver
Copyright (C) 2008 MaxLinear
- Copyright (C) 2006 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2006 Steven Toth <stoth@linuxtv.org>
Functions:
mxl5005s_reset()
mxl5005s_writereg()
@@ -3837,7 +3837,7 @@ static u16 MXL_Hystersis_Test(struct dvb_frontend *fe, int Hystersis)
/* ----------------------------------------------------------------
* Begin: Everything after here is new code to adapt the
* proprietary Realtek driver into a Linux API tuner.
- * Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+ * Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
*/
static int mxl5005s_reset(struct dvb_frontend *fe)
{
diff --git a/drivers/media/common/tuners/mxl5005s.h b/drivers/media/common/tuners/mxl5005s.h
index 396db150bf0..7ac6815b30a 100644
--- a/drivers/media/common/tuners/mxl5005s.h
+++ b/drivers/media/common/tuners/mxl5005s.h
@@ -2,7 +2,7 @@
MaxLinear MXL5005S VSB/QAM/DVBT tuner driver
Copyright (C) 2008 MaxLinear
- Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2008 Steven Toth <stoth@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
diff --git a/drivers/media/common/tuners/tuner-simple.c b/drivers/media/common/tuners/tuner-simple.c
index 597e47f5d69..aa773a658a2 100644
--- a/drivers/media/common/tuners/tuner-simple.c
+++ b/drivers/media/common/tuners/tuner-simple.c
@@ -253,7 +253,7 @@ static struct tuner_params *simple_tuner_params(struct dvb_frontend *fe,
static int simple_config_lookup(struct dvb_frontend *fe,
struct tuner_params *t_params,
- int *frequency, u8 *config, u8 *cb)
+ unsigned *frequency, u8 *config, u8 *cb)
{
struct tuner_simple_priv *priv = fe->tuner_priv;
int i;
@@ -587,45 +587,45 @@ static int simple_set_tv_freq(struct dvb_frontend *fe,
priv->last_div = div;
if (t_params->has_tda9887) {
struct v4l2_priv_tun_config tda9887_cfg;
- int config = 0;
+ int tda_config = 0;
int is_secam_l = (params->std & (V4L2_STD_SECAM_L |
V4L2_STD_SECAM_LC)) &&
!(params->std & ~(V4L2_STD_SECAM_L |
V4L2_STD_SECAM_LC));
tda9887_cfg.tuner = TUNER_TDA9887;
- tda9887_cfg.priv = &config;
+ tda9887_cfg.priv = &tda_config;
if (params->std == V4L2_STD_SECAM_LC) {
if (t_params->port1_active ^ t_params->port1_invert_for_secam_lc)
- config |= TDA9887_PORT1_ACTIVE;
+ tda_config |= TDA9887_PORT1_ACTIVE;
if (t_params->port2_active ^ t_params->port2_invert_for_secam_lc)
- config |= TDA9887_PORT2_ACTIVE;
+ tda_config |= TDA9887_PORT2_ACTIVE;
} else {
if (t_params->port1_active)
- config |= TDA9887_PORT1_ACTIVE;
+ tda_config |= TDA9887_PORT1_ACTIVE;
if (t_params->port2_active)
- config |= TDA9887_PORT2_ACTIVE;
+ tda_config |= TDA9887_PORT2_ACTIVE;
}
if (t_params->intercarrier_mode)
- config |= TDA9887_INTERCARRIER;
+ tda_config |= TDA9887_INTERCARRIER;
if (is_secam_l) {
if (i == 0 && t_params->default_top_secam_low)
- config |= TDA9887_TOP(t_params->default_top_secam_low);
+ tda_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);
+ tda_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);
+ tda_config |= TDA9887_TOP(t_params->default_top_secam_high);
} else {
if (i == 0 && t_params->default_top_low)
- config |= TDA9887_TOP(t_params->default_top_low);
+ tda_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);
+ tda_config |= TDA9887_TOP(t_params->default_top_mid);
else if (t_params->default_top_high)
- config |= TDA9887_TOP(t_params->default_top_high);
+ tda_config |= TDA9887_TOP(t_params->default_top_high);
}
if (t_params->default_pll_gating_18)
- config |= TDA9887_GATING_18;
+ tda_config |= TDA9887_GATING_18;
i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG,
&tda9887_cfg);
}
@@ -813,7 +813,8 @@ static u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf,
static struct tuner_params *t_params;
u8 config, cb;
u32 div;
- int ret, frequency = params->frequency / 62500;
+ int ret;
+ unsigned frequency = params->frequency / 62500;
t_params = simple_tuner_params(fe, TUNER_PARAM_TYPE_DIGITAL);
ret = simple_config_lookup(fe, t_params, &frequency, &config, &cb);
diff --git a/drivers/media/common/tuners/tuner-xc2028.h b/drivers/media/common/tuners/tuner-xc2028.h
index 216025cf5d4..2c5b6282b56 100644
--- a/drivers/media/common/tuners/tuner-xc2028.h
+++ b/drivers/media/common/tuners/tuner-xc2028.h
@@ -10,6 +10,7 @@
#include "dvb_frontend.h"
#define XC2028_DEFAULT_FIRMWARE "xc3028-v27.fw"
+#define XC3028L_DEFAULT_FIRMWARE "xc3028L-v36.fw"
/* Dmoduler IF (kHz) */
#define XC3028_FE_DEFAULT 0 /* Don't load SCODE */
diff --git a/drivers/media/common/tuners/xc5000.c b/drivers/media/common/tuners/xc5000.c
index 5f99de0ad61..dcddfa803a7 100644
--- a/drivers/media/common/tuners/xc5000.c
+++ b/drivers/media/common/tuners/xc5000.c
@@ -2,7 +2,7 @@
* Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
*
* Copyright (c) 2007 Xceive Corporation
- * Copyright (c) 2007 Steven Toth <stoth@hauppauge.com>
+ * Copyright (c) 2007 Steven Toth <stoth@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
diff --git a/drivers/media/common/tuners/xc5000.h b/drivers/media/common/tuners/xc5000.h
index c910715addc..5389f740945 100644
--- a/drivers/media/common/tuners/xc5000.h
+++ b/drivers/media/common/tuners/xc5000.h
@@ -1,7 +1,7 @@
/*
* Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
*
- * Copyright (c) 2007 Steven Toth <stoth@hauppauge.com>
+ * Copyright (c) 2007 Steven Toth <stoth@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
diff --git a/drivers/media/common/tuners/xc5000_priv.h b/drivers/media/common/tuners/xc5000_priv.h
index a72a9887fe7..b2a0074c99c 100644
--- a/drivers/media/common/tuners/xc5000_priv.h
+++ b/drivers/media/common/tuners/xc5000_priv.h
@@ -1,7 +1,7 @@
/*
* Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
*
- * Copyright (c) 2007 Steven Toth <stoth@hauppauge.com>
+ * Copyright (c) 2007 Steven Toth <stoth@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
diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
index f9d087669d5..a127a4175c4 100644
--- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
@@ -137,7 +137,8 @@ static int flexcop_send_diseqc_msg(struct dvb_frontend* fe, int len, u8 *msg, un
flexcop_diseqc_send_byte(fe, 0xff);
else {
flexcop_set_tone(fe, SEC_TONE_ON);
- udelay(12500);
+ mdelay(12);
+ udelay(500);
flexcop_set_tone(fe, SEC_TONE_OFF);
}
msleep(20);
@@ -490,6 +491,7 @@ static struct s5h1420_config skystar2_rev2_7_s5h1420_config = {
.demod_address = 0x53,
.invert = 1,
.repeated_start_workaround = 1,
+ .serial_mpeg = 1,
};
static struct itd1000_config skystar2_rev2_7_itd1000_config = {
diff --git a/drivers/media/dvb/b2c2/flexcop-i2c.c b/drivers/media/dvb/b2c2/flexcop-i2c.c
index 55973eaf371..43a112ec6d4 100644
--- a/drivers/media/dvb/b2c2/flexcop-i2c.c
+++ b/drivers/media/dvb/b2c2/flexcop-i2c.c
@@ -221,12 +221,12 @@ int flexcop_i2c_init(struct flexcop_device *fc)
fc->fc_i2c_adap[1].port = FC_I2C_PORT_EEPROM;
fc->fc_i2c_adap[2].port = FC_I2C_PORT_TUNER;
- strncpy(fc->fc_i2c_adap[0].i2c_adap.name,
- "B2C2 FlexCop I2C to demod", I2C_NAME_SIZE);
- strncpy(fc->fc_i2c_adap[1].i2c_adap.name,
- "B2C2 FlexCop I2C to eeprom", I2C_NAME_SIZE);
- strncpy(fc->fc_i2c_adap[2].i2c_adap.name,
- "B2C2 FlexCop I2C to tuner", I2C_NAME_SIZE);
+ strlcpy(fc->fc_i2c_adap[0].i2c_adap.name, "B2C2 FlexCop I2C to demod",
+ sizeof(fc->fc_i2c_adap[0].i2c_adap.name));
+ strlcpy(fc->fc_i2c_adap[1].i2c_adap.name, "B2C2 FlexCop I2C to eeprom",
+ sizeof(fc->fc_i2c_adap[1].i2c_adap.name));
+ strlcpy(fc->fc_i2c_adap[2].i2c_adap.name, "B2C2 FlexCop I2C to tuner",
+ sizeof(fc->fc_i2c_adap[2].i2c_adap.name));
i2c_set_adapdata(&fc->fc_i2c_adap[0].i2c_adap, &fc->fc_i2c_adap[0]);
i2c_set_adapdata(&fc->fc_i2c_adap[1].i2c_adap, &fc->fc_i2c_adap[1]);
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
index a7637562e74..aa3db57d32d 100644
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/dvb/bt8xx/dst.c
@@ -1244,7 +1244,7 @@ static int dst_command(struct dst_state *state, u8 *data, u8 len)
goto error;
}
if (state->type_flags & DST_TYPE_HAS_FW_1)
- udelay(3000);
+ mdelay(3);
if (read_dst(state, &reply, GET_ACK)) {
dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. ");
if ((dst_error_recovery(state)) < 0) {
@@ -1260,7 +1260,7 @@ static int dst_command(struct dst_state *state, u8 *data, u8 len)
if (len >= 2 && data[0] == 0 && (data[1] == 1 || data[1] == 3))
goto error;
if (state->type_flags & DST_TYPE_HAS_FW_1)
- udelay(3000);
+ mdelay(3);
else
udelay(2000);
if (!dst_wait_dst_ready(state, NO_DELAY))
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 1cf9fcb6f51..0c733c66a44 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -364,15 +364,16 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
enum dmx_success success)
{
struct dmxdev_filter *dmxdevfilter = filter->priv;
+ unsigned long flags;
int ret;
if (dmxdevfilter->buffer.error) {
wake_up(&dmxdevfilter->buffer.queue);
return 0;
}
- spin_lock(&dmxdevfilter->dev->lock);
+ spin_lock_irqsave(&dmxdevfilter->dev->lock, flags);
if (dmxdevfilter->state != DMXDEV_STATE_GO) {
- spin_unlock(&dmxdevfilter->dev->lock);
+ spin_unlock_irqrestore(&dmxdevfilter->dev->lock, flags);
return 0;
}
del_timer(&dmxdevfilter->timer);
@@ -391,7 +392,7 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
}
if (dmxdevfilter->params.sec.flags & DMX_ONESHOT)
dmxdevfilter->state = DMXDEV_STATE_DONE;
- spin_unlock(&dmxdevfilter->dev->lock);
+ spin_unlock_irqrestore(&dmxdevfilter->dev->lock, flags);
wake_up(&dmxdevfilter->buffer.queue);
return 0;
}
@@ -403,11 +404,12 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
{
struct dmxdev_filter *dmxdevfilter = feed->priv;
struct dvb_ringbuffer *buffer;
+ unsigned long flags;
int ret;
- spin_lock(&dmxdevfilter->dev->lock);
+ spin_lock_irqsave(&dmxdevfilter->dev->lock, flags);
if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER) {
- spin_unlock(&dmxdevfilter->dev->lock);
+ spin_unlock_irqrestore(&dmxdevfilter->dev->lock, flags);
return 0;
}
@@ -417,7 +419,7 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
else
buffer = &dmxdevfilter->dev->dvr_buffer;
if (buffer->error) {
- spin_unlock(&dmxdevfilter->dev->lock);
+ spin_unlock_irqrestore(&dmxdevfilter->dev->lock, flags);
wake_up(&buffer->queue);
return 0;
}
@@ -428,7 +430,7 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
dvb_ringbuffer_flush(buffer);
buffer->error = ret;
}
- spin_unlock(&dmxdevfilter->dev->lock);
+ spin_unlock_irqrestore(&dmxdevfilter->dev->lock, flags);
wake_up(&buffer->queue);
return 0;
}
@@ -641,7 +643,6 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
struct timespec timeout = { 0 };
struct dmx_pes_filter_params *para = &filter->params.pes;
dmx_output_t otype;
- int ret;
int ts_type;
enum dmx_ts_pes ts_pes;
struct dmx_ts_feed **tsfeed = &filter->feed.ts;
diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
index 8e5dd7b1f03..98ee16773ff 100644
--- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
@@ -1032,7 +1032,7 @@ static int dvb_ca_en50221_thread(void *data)
/* we need this extra check for annoying interfaces like the budget-av */
if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) &&
(ca->pub->poll_slot_status)) {
- int status = ca->pub->poll_slot_status(ca->pub, slot, 0);
+ status = ca->pub->poll_slot_status(ca->pub, slot, 0);
if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) {
ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
dvb_ca_en50221_thread_update_delay(ca);
@@ -1089,7 +1089,7 @@ static int dvb_ca_en50221_thread(void *data)
/* we need this extra check for annoying interfaces like the budget-av */
if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) &&
(ca->pub->poll_slot_status)) {
- int status = ca->pub->poll_slot_status(ca->pub, slot, 0);
+ status = ca->pub->poll_slot_status(ca->pub, slot, 0);
if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) {
ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
dvb_ca_en50221_thread_update_delay(ca);
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index e2eca0b1fe7..a2c1fd5d2f6 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -399,7 +399,9 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
size_t count)
{
- spin_lock(&demux->lock);
+ unsigned long flags;
+
+ spin_lock_irqsave(&demux->lock, flags);
while (count--) {
if (buf[0] == 0x47)
@@ -407,16 +409,17 @@ void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
buf += 188;
}
- spin_unlock(&demux->lock);
+ spin_unlock_irqrestore(&demux->lock, flags);
}
EXPORT_SYMBOL(dvb_dmx_swfilter_packets);
void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
{
+ unsigned long flags;
int p = 0, i, j;
- spin_lock(&demux->lock);
+ spin_lock_irqsave(&demux->lock, flags);
if (demux->tsbufp) {
i = demux->tsbufp;
@@ -449,17 +452,18 @@ void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
}
bailout:
- spin_unlock(&demux->lock);
+ spin_unlock_irqrestore(&demux->lock, flags);
}
EXPORT_SYMBOL(dvb_dmx_swfilter);
void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
{
+ unsigned long flags;
int p = 0, i, j;
u8 tmppack[188];
- spin_lock(&demux->lock);
+ spin_lock_irqsave(&demux->lock, flags);
if (demux->tsbufp) {
i = demux->tsbufp;
@@ -500,7 +504,7 @@ void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
}
bailout:
- spin_unlock(&demux->lock);
+ spin_unlock_irqrestore(&demux->lock, flags);
}
EXPORT_SYMBOL(dvb_dmx_swfilter_204);
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index 8cbdb218952..3526e3ee948 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -889,13 +889,13 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
* initialization, so parg is 8 bits and does not
* include the initialization or start bit
*/
- unsigned long cmd = ((unsigned long) parg) << 1;
+ unsigned long swcmd = ((unsigned long) parg) << 1;
struct timeval nexttime;
struct timeval tv[10];
int i;
u8 last = 1;
if (dvb_frontend_debug)
- printk("%s switch command: 0x%04lx\n", __func__, cmd);
+ printk("%s switch command: 0x%04lx\n", __func__, swcmd);
do_gettimeofday(&nexttime);
if (dvb_frontend_debug)
memcpy(&tv[0], &nexttime, sizeof(struct timeval));
@@ -908,12 +908,12 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
for (i = 0; i < 9; i++) {
if (dvb_frontend_debug)
do_gettimeofday(&tv[i + 1]);
- if ((cmd & 0x01) != last) {
+ if ((swcmd & 0x01) != last) {
/* set voltage to (last ? 13V : 18V) */
fe->ops.set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18);
last = (last) ? 0 : 1;
}
- cmd = cmd >> 1;
+ swcmd = swcmd >> 1;
if (i != 8)
dvb_frontend_sleep_until(&nexttime, 8000);
}
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
index aaa0b6f0b52..563400277a4 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -210,7 +210,7 @@ static int cxusb_aver_power_ctrl(struct dvb_usb_device *d, int onoff)
if (d->state == DVB_USB_STATE_INIT &&
usb_set_interface(d->udev, 0, 0) < 0)
err("set interface failed");
- do; while (!(ret = cxusb_ctrl_msg(d, CMD_POWER_ON, NULL, 0, NULL, 0)) &&
+ do {} while (!(ret = cxusb_ctrl_msg(d, CMD_POWER_ON, NULL, 0, NULL, 0)) &&
!(ret = cxusb_ctrl_msg(d, 0x15, NULL, 0, NULL, 0)) &&
!(ret = cxusb_ctrl_msg(d, 0x17, NULL, 0, NULL, 0)) && 0);
if (!ret) {
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c
index 3dd20bfbed3..6c0e5c5f436 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c
@@ -1117,7 +1117,8 @@ struct usb_device_id dib0700_usb_id_table[] = {
{ USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_HT_EXPRESS) },
{ USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_XXS) },
{ USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_STK7700P_2) },
- { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009) },
+/* 35 */{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009) },
+ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_3) },
{ 0 } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -1373,7 +1374,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
}
},
- .num_device_descs = 3,
+ .num_device_descs = 4,
.devices = {
{ "DiBcom STK7070PD reference design",
{ &dib0700_usb_id_table[17], NULL },
@@ -1386,6 +1387,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
{ "Hauppauge Nova-TD Stick (52009)",
{ &dib0700_usb_id_table[35], NULL },
{ NULL },
+ },
+ { "Hauppauge Nova-TD-500 (84xxx)",
+ { &dib0700_usb_id_table[36], NULL },
+ { NULL },
}
}
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index 029b437caf9..03dfb9f2fe3 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -129,6 +129,7 @@
#define USB_PID_WINTV_NOVA_T_USB2_WARM 0x9301
#define USB_PID_HAUPPAUGE_NOVA_T_500 0x9941
#define USB_PID_HAUPPAUGE_NOVA_T_500_2 0x9950
+#define USB_PID_HAUPPAUGE_NOVA_T_500_3 0x8400
#define USB_PID_HAUPPAUGE_NOVA_T_STICK 0x7050
#define USB_PID_HAUPPAUGE_NOVA_T_STICK_2 0x7060
#define USB_PID_HAUPPAUGE_NOVA_T_STICK_3 0x7070
diff --git a/drivers/media/dvb/frontends/au8522.c b/drivers/media/dvb/frontends/au8522.c
index f7b71657f0f..0b82cc2a1e1 100644
--- a/drivers/media/dvb/frontends/au8522.c
+++ b/drivers/media/dvb/frontends/au8522.c
@@ -1,7 +1,7 @@
/*
Auvitek AU8522 QAM/8VSB demodulator driver
- Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2008 Steven Toth <stoth@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
@@ -304,6 +304,43 @@ static int au8522_mse2snr_lookup(struct mse2snr_tab *tab, int sz, int mse,
return ret;
}
+static int au8522_set_if(struct dvb_frontend *fe, enum au8522_if_freq if_freq)
+{
+ struct au8522_state *state = fe->demodulator_priv;
+ u8 r0b5, r0b6, r0b7;
+ char *ifmhz;
+
+ switch (if_freq) {
+ case AU8522_IF_3_25MHZ:
+ ifmhz = "3.25";
+ r0b5 = 0x00;
+ r0b6 = 0x3d;
+ r0b7 = 0xa0;
+ break;
+ case AU8522_IF_4MHZ:
+ ifmhz = "4.00";
+ r0b5 = 0x00;
+ r0b6 = 0x4b;
+ r0b7 = 0xd9;
+ break;
+ case AU8522_IF_6MHZ:
+ ifmhz = "6.00";
+ r0b5 = 0xfb;
+ r0b6 = 0x8e;
+ r0b7 = 0x39;
+ break;
+ default:
+ dprintk("%s() IF Frequency not supported\n", __func__);
+ return -EINVAL;
+ }
+ dprintk("%s() %s MHz\n", __func__, ifmhz);
+ au8522_writereg(state, 0x80b5, r0b5);
+ au8522_writereg(state, 0x80b6, r0b6);
+ au8522_writereg(state, 0x80b7, r0b7);
+
+ return 0;
+}
+
/* VSB Modulation table */
static struct {
u16 reg;
@@ -334,9 +371,6 @@ static struct {
{ 0x80af, 0x66 },
{ 0x821b, 0xcc },
{ 0x821d, 0x80 },
- { 0x80b5, 0xfb },
- { 0x80b6, 0x8e },
- { 0x80b7, 0x39 },
{ 0x80a4, 0xe8 },
{ 0x8231, 0x13 },
};
@@ -350,9 +384,6 @@ static struct {
{ 0x80a4, 0x00 },
{ 0x8081, 0xc4 },
{ 0x80a5, 0x40 },
- { 0x80b5, 0xfb },
- { 0x80b6, 0x8e },
- { 0x80b7, 0x39 },
{ 0x80aa, 0x77 },
{ 0x80ad, 0x77 },
{ 0x80a6, 0x67 },
@@ -438,6 +469,7 @@ static int au8522_enable_modulation(struct dvb_frontend *fe,
au8522_writereg(state,
VSB_mod_tab[i].reg,
VSB_mod_tab[i].data);
+ au8522_set_if(fe, state->config->vsb_if);
break;
case QAM_64:
case QAM_256:
@@ -446,6 +478,7 @@ static int au8522_enable_modulation(struct dvb_frontend *fe,
au8522_writereg(state,
QAM_mod_tab[i].reg,
QAM_mod_tab[i].data);
+ au8522_set_if(fe, state->config->qam_if);
break;
default:
dprintk("%s() Invalid modulation\n", __func__);
diff --git a/drivers/media/dvb/frontends/au8522.h b/drivers/media/dvb/frontends/au8522.h
index d7affa3cdb2..595915ade8c 100644
--- a/drivers/media/dvb/frontends/au8522.h
+++ b/drivers/media/dvb/frontends/au8522.h
@@ -1,7 +1,7 @@
/*
Auvitek AU8522 QAM/8VSB demodulator driver
- Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2008 Steven Toth <stoth@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
@@ -24,6 +24,12 @@
#include <linux/dvb/frontend.h>
+enum au8522_if_freq {
+ AU8522_IF_6MHZ = 0,
+ AU8522_IF_4MHZ,
+ AU8522_IF_3_25MHZ,
+};
+
struct au8522_config {
/* the demodulator's i2c address */
u8 demod_address;
@@ -32,6 +38,9 @@ struct au8522_config {
#define AU8522_TUNERLOCKING 0
#define AU8522_DEMODLOCKING 1
u8 status_mode;
+
+ enum au8522_if_freq vsb_if;
+ enum au8522_if_freq qam_if;
};
#if defined(CONFIG_DVB_AU8522) || \
diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c
index cc1db4e371c..9430e03dba6 100644
--- a/drivers/media/dvb/frontends/cx22702.c
+++ b/drivers/media/dvb/frontends/cx22702.c
@@ -7,7 +7,7 @@
Copyright (C) 2001-2002 Convergence Integrated Media GmbH
Holger Waechtler <holger@convergence.de>
- Copyright (C) 2004 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2004 Steven Toth <stoth@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
diff --git a/drivers/media/dvb/frontends/cx22702.h b/drivers/media/dvb/frontends/cx22702.h
index 8af766a3155..b1e465c6c2c 100644
--- a/drivers/media/dvb/frontends/cx22702.h
+++ b/drivers/media/dvb/frontends/cx22702.h
@@ -7,7 +7,7 @@
Copyright (C) 2001-2002 Convergence Integrated Media GmbH
Holger Waechtler <holger@convergence.de>
- Copyright (C) 2004 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2004 Steven Toth <stoth@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
diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c
index 7f68d78c655..7156157cb34 100644
--- a/drivers/media/dvb/frontends/cx24123.c
+++ b/drivers/media/dvb/frontends/cx24123.c
@@ -1,7 +1,7 @@
/*
* Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver
*
- * Copyright (C) 2005 Steven Toth <stoth@hauppauge.com>
+ * Copyright (C) 2005 Steven Toth <stoth@linuxtv.org>
*
* Support for KWorld DVB-S 100 by Vadim Catana <skystar@moldova.cc>
*
@@ -1072,8 +1072,8 @@ struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
if (config->dont_use_pll)
cx24123_repeater_mode(state, 1, 0);
- strncpy(state->tuner_i2c_adapter.name,
- "CX24123 tuner I2C bus", I2C_NAME_SIZE);
+ strlcpy(state->tuner_i2c_adapter.name, "CX24123 tuner I2C bus",
+ sizeof(state->tuner_i2c_adapter.name));
state->tuner_i2c_adapter.class = I2C_CLASS_TV_DIGITAL,
state->tuner_i2c_adapter.algo = &cx24123_tuner_i2c_algo;
state->tuner_i2c_adapter.algo_data = NULL;
diff --git a/drivers/media/dvb/frontends/cx24123.h b/drivers/media/dvb/frontends/cx24123.h
index 81ebc3d2f19..cc6b411d6d2 100644
--- a/drivers/media/dvb/frontends/cx24123.h
+++ b/drivers/media/dvb/frontends/cx24123.h
@@ -1,7 +1,7 @@
/*
Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver
- Copyright (C) 2005 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2005 Steven Toth <stoth@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
diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c
index 5ddb2dca305..7500a1c53e6 100644
--- a/drivers/media/dvb/frontends/s5h1409.c
+++ b/drivers/media/dvb/frontends/s5h1409.c
@@ -1,7 +1,7 @@
/*
Samsung S5H1409 VSB/QAM demodulator driver
- Copyright (C) 2006 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2006 Steven Toth <stoth@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
@@ -404,6 +404,7 @@ static int s5h1409_enable_modulation(struct dvb_frontend* fe,
break;
case QAM_64:
case QAM_256:
+ case QAM_AUTO:
dprintk("%s() QAM_AUTO (64/256)\n", __func__);
if (state->if_freq != S5H1409_QAM_IF_FREQ)
s5h1409_set_if_freq(fe, S5H1409_QAM_IF_FREQ);
diff --git a/drivers/media/dvb/frontends/s5h1409.h b/drivers/media/dvb/frontends/s5h1409.h
index 59f4335964c..d1a1d2eb8e1 100644
--- a/drivers/media/dvb/frontends/s5h1409.h
+++ b/drivers/media/dvb/frontends/s5h1409.h
@@ -1,7 +1,7 @@
/*
Samsung S5H1409 VSB/QAM demodulator driver
- Copyright (C) 2006 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2006 Steven Toth <stoth@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
diff --git a/drivers/media/dvb/frontends/s5h1411.c b/drivers/media/dvb/frontends/s5h1411.c
index cff360ce1ba..2da1a3763de 100644
--- a/drivers/media/dvb/frontends/s5h1411.c
+++ b/drivers/media/dvb/frontends/s5h1411.c
@@ -1,7 +1,7 @@
/*
Samsung S5H1411 VSB/QAM demodulator driver
- Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2008 Steven Toth <stoth@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
@@ -488,6 +488,7 @@ static int s5h1411_enable_modulation(struct dvb_frontend *fe,
break;
case QAM_64:
case QAM_256:
+ case QAM_AUTO:
dprintk("%s() QAM_AUTO (64/256)\n", __func__);
s5h1411_set_if_freq(fe, state->config->qam_if);
s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x00, 0x0171);
diff --git a/drivers/media/dvb/frontends/s5h1411.h b/drivers/media/dvb/frontends/s5h1411.h
index 1855f64ed4d..7d542bc00c4 100644
--- a/drivers/media/dvb/frontends/s5h1411.h
+++ b/drivers/media/dvb/frontends/s5h1411.h
@@ -1,7 +1,7 @@
/*
Samsung S5H1411 VSB/QAM demodulator driver
- Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2008 Steven Toth <stoth@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
diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c
index 720ed9ff7c5..2e9fd2893ed 100644
--- a/drivers/media/dvb/frontends/s5h1420.c
+++ b/drivers/media/dvb/frontends/s5h1420.c
@@ -59,7 +59,7 @@ struct s5h1420_state {
* it does not support repeated-start, workaround: write addr-1
* and then read
*/
- u8 shadow[255];
+ u8 shadow[256];
};
static u32 s5h1420_getsymbolrate(struct s5h1420_state* state);
@@ -94,8 +94,11 @@ static u8 s5h1420_readreg(struct s5h1420_state *state, u8 reg)
if (ret != 3)
return ret;
} else {
- ret = i2c_transfer(state->i2c, &msg[1], 2);
- if (ret != 2)
+ ret = i2c_transfer(state->i2c, &msg[1], 1);
+ if (ret != 1)
+ return ret;
+ ret = i2c_transfer(state->i2c, &msg[2], 1);
+ if (ret != 1)
return ret;
}
@@ -823,7 +826,7 @@ static int s5h1420_init (struct dvb_frontend* fe)
struct s5h1420_state* state = fe->demodulator_priv;
/* disable power down and do reset */
- state->CON_1_val = 0x10;
+ state->CON_1_val = state->config->serial_mpeg << 4;
s5h1420_writereg(state, 0x02, state->CON_1_val);
msleep(10);
s5h1420_reset(state);
@@ -915,7 +918,8 @@ struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config,
state->frontend.demodulator_priv = state;
/* create tuner i2c adapter */
- strncpy(state->tuner_i2c_adapter.name, "S5H1420-PN1010 tuner I2C bus", I2C_NAME_SIZE);
+ strlcpy(state->tuner_i2c_adapter.name, "S5H1420-PN1010 tuner I2C bus",
+ sizeof(state->tuner_i2c_adapter.name));
state->tuner_i2c_adapter.class = I2C_CLASS_TV_DIGITAL,
state->tuner_i2c_adapter.algo = &s5h1420_tuner_i2c_algo;
state->tuner_i2c_adapter.algo_data = NULL;
diff --git a/drivers/media/dvb/frontends/s5h1420.h b/drivers/media/dvb/frontends/s5h1420.h
index 4c913f142bc..ff308136d86 100644
--- a/drivers/media/dvb/frontends/s5h1420.h
+++ b/drivers/media/dvb/frontends/s5h1420.h
@@ -32,10 +32,12 @@ struct s5h1420_config
u8 demod_address;
/* does the inversion require inversion? */
- u8 invert : 1;
+ u8 invert:1;
- u8 repeated_start_workaround : 1;
- u8 cdclk_polarity : 1; /* 1 == falling edge, 0 == raising edge */
+ u8 repeated_start_workaround:1;
+ u8 cdclk_polarity:1; /* 1 == falling edge, 0 == raising edge */
+
+ u8 serial_mpeg:1;
};
#if defined(CONFIG_DVB_S5H1420) || (defined(CONFIG_DVB_S5H1420_MODULE) && defined(MODULE))
diff --git a/drivers/media/dvb/frontends/tda10048.c b/drivers/media/dvb/frontends/tda10048.c
index 0ab8d86b3ae..04e7f1cc140 100644
--- a/drivers/media/dvb/frontends/tda10048.c
+++ b/drivers/media/dvb/frontends/tda10048.c
@@ -1,7 +1,7 @@
/*
NXP TDA10048HN DVB OFDM demodulator driver
- Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2008 Steven Toth <stoth@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
@@ -303,7 +303,7 @@ static int tda10048_firmware_upload(struct dvb_frontend *fe)
if (fw->size != TDA10048_DEFAULT_FIRMWARE_SIZE) {
printk(KERN_ERR "%s: firmware incorrect size\n", __func__);
- return -EIO;
+ ret = -EIO;
} else {
printk(KERN_INFO "%s: firmware uploading\n", __func__);
diff --git a/drivers/media/dvb/frontends/tda10048.h b/drivers/media/dvb/frontends/tda10048.h
index 2b5c78e62c8..0457b24601f 100644
--- a/drivers/media/dvb/frontends/tda10048.h
+++ b/drivers/media/dvb/frontends/tda10048.h
@@ -1,7 +1,7 @@
/*
NXP TDA10048HN DVB OFDM demodulator driver
- Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2008 Steven Toth <stoth@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
diff --git a/drivers/media/dvb/siano/sms-cards.c b/drivers/media/dvb/siano/sms-cards.c
index e7a8ac0c404..9da260fe3fd 100644
--- a/drivers/media/dvb/siano/sms-cards.c
+++ b/drivers/media/dvb/siano/sms-cards.c
@@ -4,7 +4,7 @@
* Copyright (c) 2008 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 version 3 as
+ * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS IS"
@@ -40,6 +40,8 @@ struct usb_device_id smsusb_id_table[] = {
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B },
{ USB_DEVICE(0x2040, 0x5500),
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+ { USB_DEVICE(0x2040, 0x5510),
+ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
{ USB_DEVICE(0x2040, 0x5580),
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
{ USB_DEVICE(0x2040, 0x5590),
@@ -87,7 +89,7 @@ static struct sms_board sms_boards[] = {
.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-b-dvbt-01.fw",
},
[SMS1XXX_BOARD_HAUPPAUGE_WINDHAM] = {
- .name = "Hauppauge WinTV-Nova-T-MiniStick",
+ .name = "Hauppauge WinTV MiniStick",
.type = SMS_NOVA_B0,
.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-01.fw",
},
diff --git a/drivers/media/dvb/siano/sms-cards.h b/drivers/media/dvb/siano/sms-cards.h
index 83b39bc203f..c8f3da6f9bc 100644
--- a/drivers/media/dvb/siano/sms-cards.h
+++ b/drivers/media/dvb/siano/sms-cards.h
@@ -4,7 +4,7 @@
* Copyright (c) 2008 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 version 3 as
+ * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS IS"
diff --git a/drivers/media/dvb/siano/smscoreapi.c b/drivers/media/dvb/siano/smscoreapi.c
index c5f45fed69d..6576fbb40fc 100644
--- a/drivers/media/dvb/siano/smscoreapi.c
+++ b/drivers/media/dvb/siano/smscoreapi.c
@@ -8,7 +8,7 @@
* Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
*
* This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
+ * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS IS"
diff --git a/drivers/media/dvb/siano/smscoreapi.h b/drivers/media/dvb/siano/smscoreapi.h
index c1f8f1dccb1..8d973f726fb 100644
--- a/drivers/media/dvb/siano/smscoreapi.h
+++ b/drivers/media/dvb/siano/smscoreapi.h
@@ -6,7 +6,7 @@
* Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
*
* This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
+ * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS IS"
diff --git a/drivers/media/dvb/siano/smsdvb.c b/drivers/media/dvb/siano/smsdvb.c
index 229274a1411..8d490e133f3 100644
--- a/drivers/media/dvb/siano/smsdvb.c
+++ b/drivers/media/dvb/siano/smsdvb.c
@@ -6,7 +6,7 @@
* Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
*
* This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
+ * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS IS"
diff --git a/drivers/media/dvb/siano/smsusb.c b/drivers/media/dvb/siano/smsusb.c
index c10b1849c6a..87a3c24454b 100644
--- a/drivers/media/dvb/siano/smsusb.c
+++ b/drivers/media/dvb/siano/smsusb.c
@@ -6,7 +6,7 @@
* Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
*
* This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
+ * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS IS"
diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c
index 39bd0a20f53..aa5ed4ef19f 100644
--- a/drivers/media/dvb/ttpci/budget-patch.c
+++ b/drivers/media/dvb/ttpci/budget-patch.c
@@ -116,7 +116,8 @@ static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long
DiseqcSendByte(budget, 0xff);
else {
saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
- udelay(12500);
+ mdelay(12);
+ udelay(500);
saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
}
msleep(20);
diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c
index 2293d80c6e5..f0068996ac0 100644
--- a/drivers/media/dvb/ttpci/budget.c
+++ b/drivers/media/dvb/ttpci/budget.c
@@ -108,7 +108,8 @@ static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long
DiseqcSendByte(budget, 0xff);
else {
saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
- udelay(12500);
+ mdelay(12);
+ udelay(500);
saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
}
msleep(20);
diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile
index a30159f6fa4..7ca71ab96b4 100644
--- a/drivers/media/radio/Makefile
+++ b/drivers/media/radio/Makefile
@@ -2,8 +2,6 @@
# Makefile for the kernel character device drivers.
#
-miropcm20-objs := miropcm20-rds-core.o miropcm20-radio.o
-
obj-$(CONFIG_RADIO_AZTECH) += radio-aztech.o
obj-$(CONFIG_RADIO_RTRACK2) += radio-rtrack2.o
obj-$(CONFIG_RADIO_SF16FMI) += radio-sf16fmi.o
@@ -14,8 +12,6 @@ obj-$(CONFIG_RADIO_TERRATEC) += radio-terratec.o
obj-$(CONFIG_RADIO_MAXIRADIO) += radio-maxiradio.o
obj-$(CONFIG_RADIO_RTRACK) += radio-aimslab.o
obj-$(CONFIG_RADIO_ZOLTRIX) += radio-zoltrix.o
-obj-$(CONFIG_RADIO_MIROPCM20) += miropcm20.o
-obj-$(CONFIG_RADIO_MIROPCM20_RDS) += miropcm20-rds.o
obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o
obj-$(CONFIG_RADIO_GEMTEK_PCI) += radio-gemtek-pci.o
obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c
index 1ed88f3abe6..70c65a74592 100644
--- a/drivers/media/radio/dsbr100.c
+++ b/drivers/media/radio/dsbr100.c
@@ -493,7 +493,7 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
radio->usbdev = interface_to_usbdev(intf);
radio->curfreq = FREQ_MIN*FREQ_MUL;
video_set_drvdata(radio->videodev, radio);
- if (video_register_device(radio->videodev, VFL_TYPE_RADIO,radio_nr)) {
+ if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr) < 0) {
warn("Could not register video device");
video_device_release(radio->videodev);
kfree(radio->transfer_buffer);
diff --git a/drivers/media/radio/miropcm20-radio.c b/drivers/media/radio/miropcm20-radio.c
deleted file mode 100644
index 7fd7ee2d32c..00000000000
--- a/drivers/media/radio/miropcm20-radio.c
+++ /dev/null
@@ -1,266 +0,0 @@
-/* Miro PCM20 radio driver for Linux radio support
- * (c) 1998 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl>
- * Thanks to Norberto Pellici for the ACI device interface specification
- * The API part is based on the radiotrack driver by M. Kirkwood
- * This driver relies on the aci mixer (drivers/sound/aci.c)
- * Look there for further info...
- */
-
-/* Revision history:
- *
- * 1998 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl>
- * 2000-09-05 Robert Siemer <Robert.Siemer@gmx.de>
- * removed unfinished volume control (maybe adding it later again)
- * use OSS-mixer; added stereo control
- */
-
-/* What ever you think about the ACI, version 0x07 is not very well!
- * I can't get frequency, 'tuner status', 'tuner flags' or mute/mono
- * conditions... Robert
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include "oss/aci.h"
-#include "miropcm20-rds-core.h"
-
-static int radio_nr = -1;
-module_param(radio_nr, int, 0);
-
-struct pcm20_device {
- unsigned long freq;
- int muted;
- int stereo;
-};
-
-
-static int pcm20_mute(struct pcm20_device *dev, unsigned char mute)
-{
- dev->muted = mute;
- return aci_write_cmd(ACI_SET_TUNERMUTE, mute);
-}
-
-static int pcm20_stereo(struct pcm20_device *dev, unsigned char stereo)
-{
- dev->stereo = stereo;
- return aci_write_cmd(ACI_SET_TUNERMONO, !stereo);
-}
-
-static int pcm20_setfreq(struct pcm20_device *dev, unsigned long freq)
-{
- unsigned char freql;
- unsigned char freqh;
-
- dev->freq=freq;
-
- freq /= 160;
- if (!(aci_version==0x07 || aci_version>=0xb0))
- freq /= 10; /* I don't know exactly which version
- * needs this hack */
- freql = freq & 0xff;
- freqh = freq >> 8;
-
- aci_rds_cmd(RDS_RESET, NULL, 0);
- pcm20_stereo(dev, 1);
-
- return aci_rw_cmd(ACI_WRITE_TUNE, freql, freqh);
-}
-
-static int pcm20_getflags(struct pcm20_device *dev, __u32 *flags, __u16 *signal)
-{
- /* okay, check for signal, stereo and rds here... */
- int i;
- unsigned char buf;
-
- if ((i=aci_rw_cmd(ACI_READ_TUNERSTATION, -1, -1))<0)
- return i;
- pr_debug("check_sig: 0x%x\n", i);
- if (i & 0x80) {
- /* no signal from tuner */
- *flags=0;
- *signal=0;
- return 0;
- } else
- *signal=0xffff;
-
- if ((i=aci_rw_cmd(ACI_READ_TUNERSTEREO, -1, -1))<0)
- return i;
- if (i & 0x40) {
- *flags=0;
- } else {
- /* stereo */
- *flags=VIDEO_TUNER_STEREO_ON;
- /* I can't see stereo, when forced to mono */
- dev->stereo=1;
- }
-
- if ((i=aci_rds_cmd(RDS_STATUS, &buf, 1))<0)
- return i;
- if (buf & 1)
- /* RDS available */
- *flags|=VIDEO_TUNER_RDS_ON;
- else
- return 0;
-
- if ((i=aci_rds_cmd(RDS_RXVALUE, &buf, 1))<0)
- return i;
- pr_debug("rds-signal: %d\n", buf);
- if (buf > 15) {
- printk("miropcm20-radio: RX strengths unexpected high...\n");
- buf=15;
- }
- /* refine signal */
- if ((*signal=SCALE(15, 0xffff, buf))==0)
- *signal = 1;
-
- return 0;
-}
-
-static int pcm20_do_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg)
-{
- struct video_device *dev = video_devdata(file);
- struct pcm20_device *pcm20 = dev->priv;
- int i;
-
- switch(cmd)
- {
- case VIDIOCGCAP:
- {
- struct video_capability *v = arg;
- memset(v,0,sizeof(*v));
- v->type=VID_TYPE_TUNER;
- strcpy(v->name, "Miro PCM20");
- v->channels=1;
- v->audios=1;
- return 0;
- }
- case VIDIOCGTUNER:
- {
- struct video_tuner *v = arg;
- if(v->tuner) /* Only 1 tuner */
- return -EINVAL;
- v->rangelow=87*16000;
- v->rangehigh=108*16000;
- pcm20_getflags(pcm20, &v->flags, &v->signal);
- v->flags|=VIDEO_TUNER_LOW;
- v->mode=VIDEO_MODE_AUTO;
- strcpy(v->name, "FM");
- return 0;
- }
- case VIDIOCSTUNER:
- {
- struct video_tuner *v = arg;
- if(v->tuner!=0)
- return -EINVAL;
- /* Only 1 tuner so no setting needed ! */
- return 0;
- }
- case VIDIOCGFREQ:
- {
- unsigned long *freq = arg;
- *freq = pcm20->freq;
- return 0;
- }
- case VIDIOCSFREQ:
- {
- unsigned long *freq = arg;
- pcm20->freq = *freq;
- i=pcm20_setfreq(pcm20, pcm20->freq);
- pr_debug("First view (setfreq): 0x%x\n", i);
- return i;
- }
- case VIDIOCGAUDIO:
- {
- struct video_audio *v = arg;
- memset(v,0, sizeof(*v));
- v->flags=VIDEO_AUDIO_MUTABLE;
- if (pcm20->muted)
- v->flags|=VIDEO_AUDIO_MUTE;
- v->mode=VIDEO_SOUND_STEREO;
- if (pcm20->stereo)
- v->mode|=VIDEO_SOUND_MONO;
- /* v->step=2048; */
- strcpy(v->name, "Radio");
- return 0;
- }
- case VIDIOCSAUDIO:
- {
- struct video_audio *v = arg;
- if(v->audio)
- return -EINVAL;
-
- pcm20_mute(pcm20, !!(v->flags&VIDEO_AUDIO_MUTE));
- if(v->flags&VIDEO_SOUND_MONO)
- pcm20_stereo(pcm20, 0);
- if(v->flags&VIDEO_SOUND_STEREO)
- pcm20_stereo(pcm20, 1);
-
- return 0;
- }
- default:
- return -ENOIOCTLCMD;
- }
-}
-
-static int pcm20_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- return video_usercopy(inode, file, cmd, arg, pcm20_do_ioctl);
-}
-
-static struct pcm20_device pcm20_unit = {
- .freq = 87*16000,
- .muted = 1,
-};
-
-static const struct file_operations pcm20_fops = {
- .owner = THIS_MODULE,
- .open = video_exclusive_open,
- .release = video_exclusive_release,
- .ioctl = pcm20_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
- .llseek = no_llseek,
-};
-
-static struct video_device pcm20_radio = {
- .name = "Miro PCM 20 radio",
- .fops = &pcm20_fops,
- .priv = &pcm20_unit
-};
-
-static int __init pcm20_init(void)
-{
- if(video_register_device(&pcm20_radio, VFL_TYPE_RADIO, radio_nr)==-1)
- goto video_register_device;
-
- if(attach_aci_rds()<0)
- goto attach_aci_rds;
-
- printk(KERN_INFO "Miro PCM20 radio card driver.\n");
-
- return 0;
-
- attach_aci_rds:
- video_unregister_device(&pcm20_radio);
- video_register_device:
- return -EINVAL;
-}
-
-MODULE_AUTHOR("Ruurd Reitsma");
-MODULE_DESCRIPTION("A driver for the Miro PCM20 radio card.");
-MODULE_LICENSE("GPL");
-
-static void __exit pcm20_cleanup(void)
-{
- unload_aci_rds();
- video_unregister_device(&pcm20_radio);
-}
-
-module_init(pcm20_init);
-module_exit(pcm20_cleanup);
diff --git a/drivers/media/radio/miropcm20-rds-core.c b/drivers/media/radio/miropcm20-rds-core.c
deleted file mode 100644
index 9428d8b2642..00000000000
--- a/drivers/media/radio/miropcm20-rds-core.c
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Many thanks to Fred Seidel <seidel@metabox.de>, the
- * designer of the RDS decoder hardware. With his help
- * I was able to code this driver.
- * Thanks also to Norberto Pellicci, Dominic Mounteney
- * <DMounteney@pinnaclesys.com> and www.teleauskunft.de
- * for good hints on finding Fred. It was somewhat hard
- * to locate him here in Germany... [:
- *
- * Revision history:
- *
- * 2000-08-09 Robert Siemer <Robert.Siemer@gmx.de>
- * RDS support for MiroSound PCM20 radio
- */
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/mutex.h>
-
-#include <asm/io.h>
-#include "oss/aci.h"
-#include "miropcm20-rds-core.h"
-
-#define DEBUG 0
-
-static struct mutex aci_rds_mutex;
-
-#define RDS_DATASHIFT 2 /* Bit 2 */
-#define RDS_DATAMASK (1 << RDS_DATASHIFT)
-#define RDS_BUSYMASK 0x10 /* Bit 4 */
-#define RDS_CLOCKMASK 0x08 /* Bit 3 */
-
-#define RDS_DATA(x) (((x) >> RDS_DATASHIFT) & 1)
-
-
-#if DEBUG
-static void print_matrix(char array[], unsigned int length)
-{
- int i, j;
-
- for (i=0; i<length; i++) {
- printk(KERN_DEBUG "aci-rds: ");
- for (j=7; j>=0; j--) {
- printk("%d", (array[i] >> j) & 0x1);
- }
- if (i%8 == 0)
- printk(" byte-border\n");
- else
- printk("\n");
- }
-}
-#endif /* DEBUG */
-
-static int byte2trans(unsigned char byte, unsigned char sendbuffer[], int size)
-{
- int i;
-
- if (size != 8)
- return -1;
- for (i = 7; i >= 0; i--)
- sendbuffer[7-i] = (byte & (1 << i)) ? RDS_DATAMASK : 0;
- sendbuffer[0] |= RDS_CLOCKMASK;
-
- return 0;
-}
-
-static int rds_waitread(void)
-{
- unsigned char byte;
- int i=2000;
-
- do {
- byte=inb(RDS_REGISTER);
- i--;
- }
- while ((byte & RDS_BUSYMASK) && i);
-
- if (i) {
- #if DEBUG
- printk(KERN_DEBUG "rds_waitread()");
- print_matrix(&byte, 1);
- #endif
- return (byte);
- } else {
- printk(KERN_WARNING "aci-rds: rds_waitread() timeout...\n");
- return -1;
- }
-}
-
-/* don't use any ..._nowait() function if you are not sure what you do... */
-
-static inline void rds_rawwrite_nowait(unsigned char byte)
-{
- #if DEBUG
- printk(KERN_DEBUG "rds_rawwrite()");
- print_matrix(&byte, 1);
- #endif
- outb(byte, RDS_REGISTER);
-}
-
-static int rds_rawwrite(unsigned char byte)
-{
- if (rds_waitread() >= 0) {
- rds_rawwrite_nowait(byte);
- return 0;
- } else
- return -1;
-}
-
-static int rds_write(unsigned char cmd)
-{
- unsigned char sendbuffer[8];
- int i;
-
- if (byte2trans(cmd, sendbuffer, 8) != 0){
- return -1;
- } else {
- for (i=0; i<8; i++) {
- rds_rawwrite(sendbuffer[i]);
- }
- }
- return 0;
-}
-
-static int rds_readcycle_nowait(void)
-{
- rds_rawwrite_nowait(0);
- return rds_waitread();
-}
-
-static int rds_readcycle(void)
-{
- if (rds_rawwrite(0) < 0)
- return -1;
- return rds_waitread();
-}
-
-static int rds_read(unsigned char databuffer[], int datasize)
-{
- #define READSIZE (8*datasize)
-
- int i,j;
-
- if (datasize < 1) /* nothing to read */
- return 0;
-
- /* to be able to use rds_readcycle_nowait()
- I have to waitread() here */
- if (rds_waitread() < 0)
- return -1;
-
- memset(databuffer, 0, datasize);
-
- for (i=0; i< READSIZE; i++)
- if((j=rds_readcycle_nowait()) < 0) {
- return -1;
- } else {
- databuffer[i/8]|=(RDS_DATA(j) << (7-(i%8)));
- }
-
- return 0;
-}
-
-static int rds_ack(void)
-{
- int i=rds_readcycle();
-
- if (i < 0)
- return -1;
- if (i & RDS_DATAMASK) {
- return 0; /* ACK */
- } else {
- printk(KERN_DEBUG "aci-rds: NACK\n");
- return 1; /* NACK */
- }
-}
-
-int aci_rds_cmd(unsigned char cmd, unsigned char databuffer[], int datasize)
-{
- int ret;
-
- if (mutex_lock_interruptible(&aci_rds_mutex))
- return -EINTR;
-
- rds_write(cmd);
-
- /* RDS_RESET doesn't need further processing */
- if (cmd!=RDS_RESET && (rds_ack() || rds_read(databuffer, datasize)))
- ret = -1;
- else
- ret = 0;
-
- mutex_unlock(&aci_rds_mutex);
-
- return ret;
-}
-EXPORT_SYMBOL(aci_rds_cmd);
-
-int __init attach_aci_rds(void)
-{
- mutex_init(&aci_rds_mutex);
- return 0;
-}
-
-void __exit unload_aci_rds(void)
-{
-}
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/radio/miropcm20-rds-core.h b/drivers/media/radio/miropcm20-rds-core.h
deleted file mode 100644
index aeb5761f046..00000000000
--- a/drivers/media/radio/miropcm20-rds-core.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef _MIROPCM20_RDS_CORE_H_
-#define _MIROPCM20_RDS_CORE_H_
-
-extern int aci_rds_cmd(unsigned char cmd, unsigned char databuffer[], int datasize);
-
-#define RDS_STATUS 0x01
-#define RDS_STATIONNAME 0x02
-#define RDS_TEXT 0x03
-#define RDS_ALTFREQ 0x04
-#define RDS_TIMEDATE 0x05
-#define RDS_PI_CODE 0x06
-#define RDS_PTYTATP 0x07
-#define RDS_RESET 0x08
-#define RDS_RXVALUE 0x09
-
-extern void __exit unload_aci_rds(void);
-extern int __init attach_aci_rds(void);
-
-#endif /* _MIROPCM20_RDS_CORE_H_ */
diff --git a/drivers/media/radio/miropcm20-rds.c b/drivers/media/radio/miropcm20-rds.c
deleted file mode 100644
index 3e840f74d45..00000000000
--- a/drivers/media/radio/miropcm20-rds.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/* MiroSOUND PCM20 radio rds interface driver
- * (c) 2001 Robert Siemer <Robert.Siemer@gmx.de>
- * Thanks to Fred Seidel. See miropcm20-rds-core.c for further information.
- */
-
-/* Revision history:
- *
- * 2001-04-18 Robert Siemer <Robert.Siemer@gmx.de>
- * separate file for user interface driver
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/smp_lock.h>
-#include <linux/fs.h>
-#include <linux/miscdevice.h>
-#include <linux/delay.h>
-#include <asm/uaccess.h>
-#include "miropcm20-rds-core.h"
-
-static char * text_buffer;
-static int rds_users;
-
-
-static int rds_f_open(struct inode *in, struct file *fi)
-{
- if (rds_users)
- return -EBUSY;
-
- lock_kernel();
- rds_users++;
- if ((text_buffer=kmalloc(66, GFP_KERNEL)) == 0) {
- rds_users--;
- printk(KERN_NOTICE "aci-rds: Out of memory by open()...\n");
- unlock_kernel();
- return -ENOMEM;
- }
-
- unlock_kernel();
- return 0;
-}
-
-static int rds_f_release(struct inode *in, struct file *fi)
-{
- kfree(text_buffer);
-
- rds_users--;
- return 0;
-}
-
-static void print_matrix(char *ch, char out[])
-{
- int j;
-
- for (j=7; j>=0; j--) {
- out[7-j] = ((*ch >> j) & 0x1) + '0';
- }
-}
-
-static ssize_t rds_f_read(struct file *file, char __user *buffer, size_t length, loff_t *offset)
-{
-// i = sprintf(text_buffer, "length: %d, offset: %d\n", length, *offset);
-
- char c;
- char bits[8];
-
- msleep(2000);
- aci_rds_cmd(RDS_STATUS, &c, 1);
- print_matrix(&c, bits);
- if (copy_to_user(buffer, bits, 8))
- return -EFAULT;
-
-/* if ((c >> 3) & 1) {
- aci_rds_cmd(RDS_STATIONNAME, text_buffer+1, 8);
- text_buffer[0] = ' ' ;
- text_buffer[9] = '\n';
- return copy_to_user(buffer+8, text_buffer, 10) ? -EFAULT: 18;
- }
-*/
-/* if ((c >> 6) & 1) {
- aci_rds_cmd(RDS_PTYTATP, &c, 1);
- if ( c & 1)
- sprintf(text_buffer, " M");
- else
- sprintf(text_buffer, " S");
- if ((c >> 1) & 1)
- sprintf(text_buffer+2, " TA");
- else
- sprintf(text_buffer+2, " --");
- if ((c >> 7) & 1)
- sprintf(text_buffer+5, " TP");
- else
- sprintf(text_buffer+5, " --");
- sprintf(text_buffer+8, " %2d\n", (c >> 2) & 0x1f);
- return copy_to_user(buffer+8, text_buffer, 12) ? -EFAULT: 20;
- }
-*/
-
- if ((c >> 4) & 1) {
- aci_rds_cmd(RDS_TEXT, text_buffer, 65);
- text_buffer[0] = ' ' ;
- text_buffer[65] = '\n';
- return copy_to_user(buffer+8, text_buffer,66) ? -EFAULT : 66+8;
- } else {
- put_user('\n', buffer+8);
- return 9;
- }
-}
-
-static const struct file_operations rds_fops = {
- .owner = THIS_MODULE,
- .read = rds_f_read,
- .open = rds_f_open,
- .release = rds_f_release
-};
-
-static struct miscdevice rds_miscdev = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = "radiotext",
- .fops = &rds_fops,
-};
-
-static int __init miropcm20_rds_init(void)
-{
- return misc_register(&rds_miscdev);
-}
-
-static void __exit miropcm20_rds_cleanup(void)
-{
- misc_deregister(&rds_miscdev);
-}
-
-module_init(miropcm20_rds_init);
-module_exit(miropcm20_rds_cleanup);
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c
index eba9209b302..1f064f4b32d 100644
--- a/drivers/media/radio/radio-aimslab.c
+++ b/drivers/media/radio/radio-aimslab.c
@@ -426,8 +426,7 @@ static int __init rtrack_init(void)
rtrack_radio.priv=&rtrack_unit;
- if(video_register_device(&rtrack_radio, VFL_TYPE_RADIO, radio_nr)==-1)
- {
+ if (video_register_device(&rtrack_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
release_region(io, 2);
return -EINVAL;
}
diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c
index 3fe5504428c..628c689e3ff 100644
--- a/drivers/media/radio/radio-aztech.c
+++ b/drivers/media/radio/radio-aztech.c
@@ -394,8 +394,7 @@ static int __init aztech_init(void)
mutex_init(&lock);
aztech_radio.priv=&aztech_unit;
- if(video_register_device(&aztech_radio, VFL_TYPE_RADIO, radio_nr)==-1)
- {
+ if (video_register_device(&aztech_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
release_region(io,2);
return -EINVAL;
}
diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c
index 6166e726ed7..04c3698d32e 100644
--- a/drivers/media/radio/radio-cadet.c
+++ b/drivers/media/radio/radio-cadet.c
@@ -682,7 +682,7 @@ static int __init cadet_init(void)
}
if (!request_region(io,2,"cadet"))
goto fail;
- if(video_register_device(&cadet_radio,VFL_TYPE_RADIO,radio_nr)==-1) {
+ if (video_register_device(&cadet_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
release_region(io,2);
goto fail;
}
diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c
index 36e754e3ffb..5cd7f032298 100644
--- a/drivers/media/radio/radio-gemtek-pci.c
+++ b/drivers/media/radio/radio-gemtek-pci.c
@@ -425,7 +425,7 @@ static int __devinit gemtek_pci_probe( struct pci_dev *pci_dev, const struct pci
}
*devradio = vdev_template;
- if ( video_register_device( devradio, VFL_TYPE_RADIO , nr_radio) == -1 ) {
+ if (video_register_device(devradio, VFL_TYPE_RADIO, nr_radio) < 0) {
kfree( devradio );
goto err_video;
}
diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c
index 2b1a6221de6..0a0f956bb30 100644
--- a/drivers/media/radio/radio-gemtek.c
+++ b/drivers/media/radio/radio-gemtek.c
@@ -612,8 +612,7 @@ static int __init gemtek_init(void)
gemtek_radio.priv = &gemtek_unit;
- if (video_register_device(&gemtek_radio, VFL_TYPE_RADIO,
- radio_nr) == -1) {
+ if (video_register_device(&gemtek_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
release_region(io, 1);
return -EBUSY;
}
diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c
index 0ada1c697e8..9ef0a763eeb 100644
--- a/drivers/media/radio/radio-maestro.c
+++ b/drivers/media/radio/radio-maestro.c
@@ -409,8 +409,7 @@ static int __devinit maestro_probe(struct pci_dev *pdev,
video_set_drvdata(maestro_radio_inst, radio_unit);
pci_set_drvdata(pdev, maestro_radio_inst);
- retval = video_register_device(maestro_radio_inst, VFL_TYPE_RADIO,
- radio_nr);
+ retval = video_register_device(maestro_radio_inst, VFL_TYPE_RADIO, radio_nr);
if (retval) {
printk(KERN_ERR "can't register video device!\n");
goto errfr1;
diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c
index 43c75497dc4..0cc6fcb041f 100644
--- a/drivers/media/radio/radio-maxiradio.c
+++ b/drivers/media/radio/radio-maxiradio.c
@@ -156,28 +156,28 @@ static void set_freq(__u16 io, __u32 freq)
{
unsigned long int si;
int bl;
- int data = FREQ2BITS(freq);
+ int val = FREQ2BITS(freq);
/* TEA5757 shift register bits (see pdf) */
- outbit(0,io); // 24 search
- outbit(1,io); // 23 search up/down
+ outbit(0, io); /* 24 search */
+ outbit(1, io); /* 23 search up/down */
- outbit(0,io); // 22 stereo/mono
+ outbit(0, io); /* 22 stereo/mono */
- outbit(0,io); // 21 band
- outbit(0,io); // 20 band (only 00=FM works I think)
+ outbit(0, io); /* 21 band */
+ outbit(0, io); /* 20 band (only 00=FM works I think) */
- outbit(0,io); // 19 port ?
- outbit(0,io); // 18 port ?
+ outbit(0, io); /* 19 port ? */
+ outbit(0, io); /* 18 port ? */
- outbit(0,io); // 17 search level
- outbit(0,io); // 16 search level
+ outbit(0, io); /* 17 search level */
+ outbit(0, io); /* 16 search level */
si = 0x8000;
- for (bl = 1; bl <= 16 ; bl++) {
- outbit(data & si,io);
- si >>=1;
+ for (bl = 1; bl <= 16; bl++) {
+ outbit(val & si, io);
+ si >>= 1;
}
dprintk(1, "Radio freq set to %d.%02d MHz\n",
@@ -410,7 +410,7 @@ static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_d
mutex_init(&radio_unit.lock);
maxiradio_radio.priv = &radio_unit;
- if (video_register_device(&maxiradio_radio, VFL_TYPE_RADIO, radio_nr)==-1) {
+ if (video_register_device(&maxiradio_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
printk("radio-maxiradio: can't register device!");
goto err_out_free_region;
}
diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c
index e2dde080726..6d820e2481e 100644
--- a/drivers/media/radio/radio-rtrack2.c
+++ b/drivers/media/radio/radio-rtrack2.c
@@ -332,8 +332,7 @@ static int __init rtrack2_init(void)
rtrack2_radio.priv=&rtrack2_unit;
spin_lock_init(&lock);
- if(video_register_device(&rtrack2_radio, VFL_TYPE_RADIO, radio_nr)==-1)
- {
+ if (video_register_device(&rtrack2_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
release_region(io, 4);
return -EINVAL;
}
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index bb5d92f104a..0d478f54a90 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -377,7 +377,7 @@ static int __init fmi_init(void)
mutex_init(&lock);
- if (video_register_device(&fmi_radio, VFL_TYPE_RADIO, radio_nr) == -1) {
+ if (video_register_device(&fmi_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
release_region(io, 2);
return -EINVAL;
}
diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c
index a4984ff87c9..16c7ef20265 100644
--- a/drivers/media/radio/radio-si470x.c
+++ b/drivers/media/radio/radio-si470x.c
@@ -1694,8 +1694,8 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
INIT_DELAYED_WORK(&radio->work, si470x_work);
/* register video device */
- if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
- retval = -EIO;
+ retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr);
+ if (retval) {
printk(KERN_WARNING DRIVER_NAME
": Could not register video device\n");
goto err_all;
diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c
index cefa44fc5ae..0876fecc5f2 100644
--- a/drivers/media/radio/radio-terratec.c
+++ b/drivers/media/radio/radio-terratec.c
@@ -405,8 +405,7 @@ static int __init terratec_init(void)
spin_lock_init(&lock);
- if(video_register_device(&terratec_radio, VFL_TYPE_RADIO, radio_nr)==-1)
- {
+ if (video_register_device(&terratec_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
release_region(io,2);
return -EINVAL;
}
diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c
index d70172d23ed..19316195625 100644
--- a/drivers/media/radio/radio-trust.c
+++ b/drivers/media/radio/radio-trust.c
@@ -378,8 +378,7 @@ static int __init trust_init(void)
printk(KERN_ERR "trust: port 0x%x already in use\n", io);
return -EBUSY;
}
- if(video_register_device(&trust_radio, VFL_TYPE_RADIO, radio_nr)==-1)
- {
+ if (video_register_device(&trust_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
release_region(io, 2);
return -EINVAL;
}
diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c
index 9f17a332fa1..51d57ed3b3e 100644
--- a/drivers/media/radio/radio-zoltrix.c
+++ b/drivers/media/radio/radio-zoltrix.c
@@ -446,8 +446,7 @@ static int __init zoltrix_init(void)
return -EBUSY;
}
- if (video_register_device(&zoltrix_radio, VFL_TYPE_RADIO, radio_nr) == -1)
- {
+ if (video_register_device(&zoltrix_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
release_region(io, 2);
return -EINVAL;
}
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index ecbfa1b39b7..3e9e0dcd217 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -968,7 +968,7 @@ config VIDEO_PXA27x
config VIDEO_SH_MOBILE_CEU
tristate "SuperH Mobile CEU Interface driver"
- depends on VIDEO_DEV
+ depends on VIDEO_DEV && HAS_DMA
select SOC_CAMERA
select VIDEOBUF_DMA_CONTIG
---help---
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index bbc6f8b8229..ef7c8d3ffb1 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -20,6 +20,8 @@ ifeq ($(CONFIG_VIDEO_V4L1_COMPAT),y)
obj-$(CONFIG_VIDEO_DEV) += v4l1-compat.o
endif
+obj-$(CONFIG_VIDEO_TUNER) += tuner.o
+
obj-$(CONFIG_VIDEO_BT848) += bt8xx/
obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
@@ -85,8 +87,6 @@ obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o
obj-$(CONFIG_VIDEO_DPC) += dpc7146.o
obj-$(CONFIG_TUNER_3036) += tuner-3036.o
-obj-$(CONFIG_VIDEO_TUNER) += tuner.o
-
obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o
obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o
obj-$(CONFIG_VIDEOBUF_DMA_CONTIG) += videobuf-dma-contig.o
diff --git a/drivers/media/video/au0828/Kconfig b/drivers/media/video/au0828/Kconfig
index ed9a50f189f..018f72b8e3e 100644
--- a/drivers/media/video/au0828/Kconfig
+++ b/drivers/media/video/au0828/Kconfig
@@ -7,6 +7,7 @@ config VIDEO_AU0828
select DVB_AU8522 if !DVB_FE_CUSTOMIZE
select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
select MEDIA_TUNER_MXL5007T if !DVB_FE_CUSTOMIZE
+ select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE
---help---
This is a video4linux driver for Auvitek's USB device.
diff --git a/drivers/media/video/au0828/au0828-cards.c b/drivers/media/video/au0828/au0828-cards.c
index 443e5900976..ed48908a903 100644
--- a/drivers/media/video/au0828/au0828-cards.c
+++ b/drivers/media/video/au0828/au0828-cards.c
@@ -1,7 +1,7 @@
/*
* Driver for the Auvitek USB bridge
*
- * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ * Copyright (c) 2008 Steven Toth <stoth@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
@@ -38,6 +38,9 @@ struct au0828_board au0828_boards[] = {
[AU0828_BOARD_DVICO_FUSIONHDTV7] = {
.name = "DViCO FusionHDTV USB",
},
+ [AU0828_BOARD_HAUPPAUGE_WOODBURY] = {
+ .name = "Hauppauge Woodbury",
+ },
};
/* Tuner callback function for au0828 boards. Currently only needed
@@ -115,6 +118,7 @@ void au0828_card_setup(struct au0828_dev *dev)
case AU0828_BOARD_HAUPPAUGE_HVR850:
case AU0828_BOARD_HAUPPAUGE_HVR950Q:
case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
+ case AU0828_BOARD_HAUPPAUGE_WOODBURY:
if (dev->i2c_rc == 0)
hauppauge_eeprom(dev, eeprom+0xa0);
break;
@@ -134,6 +138,7 @@ void au0828_gpio_setup(struct au0828_dev *dev)
case AU0828_BOARD_HAUPPAUGE_HVR850:
case AU0828_BOARD_HAUPPAUGE_HVR950Q:
case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
+ case AU0828_BOARD_HAUPPAUGE_WOODBURY:
/* GPIO's
* 4 - CS5340
* 5 - AU8522 Demodulator
@@ -205,6 +210,8 @@ struct usb_device_id au0828_usb_id_table [] = {
.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL },
{ USB_DEVICE(0x2040, 0x7281),
.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL },
+ { USB_DEVICE(0x2040, 0x8200),
+ .driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY },
{ },
};
diff --git a/drivers/media/video/au0828/au0828-cards.h b/drivers/media/video/au0828/au0828-cards.h
index c37f5fd0fa8..48a1882c2b6 100644
--- a/drivers/media/video/au0828/au0828-cards.h
+++ b/drivers/media/video/au0828/au0828-cards.h
@@ -1,7 +1,7 @@
/*
* Driver for the Auvitek USB bridge
*
- * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ * Copyright (c) 2008 Steven Toth <stoth@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
@@ -24,3 +24,4 @@
#define AU0828_BOARD_HAUPPAUGE_HVR850 2
#define AU0828_BOARD_DVICO_FUSIONHDTV7 3
#define AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL 4
+#define AU0828_BOARD_HAUPPAUGE_WOODBURY 5
diff --git a/drivers/media/video/au0828/au0828-core.c b/drivers/media/video/au0828/au0828-core.c
index 54bfc0f0529..d856de9f742 100644
--- a/drivers/media/video/au0828/au0828-core.c
+++ b/drivers/media/video/au0828/au0828-core.c
@@ -1,7 +1,7 @@
/*
* Driver for the Auvitek USB bridge
*
- * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ * Copyright (c) 2008 Steven Toth <stoth@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
@@ -252,5 +252,5 @@ module_init(au0828_init);
module_exit(au0828_exit);
MODULE_DESCRIPTION("Driver for Auvitek AU0828 based products");
-MODULE_AUTHOR("Steven Toth <stoth@hauppauge.com>");
+MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/au0828/au0828-dvb.c b/drivers/media/video/au0828/au0828-dvb.c
index 584a83a94a2..ba94be7e0ac 100644
--- a/drivers/media/video/au0828/au0828-dvb.c
+++ b/drivers/media/video/au0828/au0828-dvb.c
@@ -1,7 +1,7 @@
/*
* Driver for the Auvitek USB bridge
*
- * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ * Copyright (c) 2008 Steven Toth <stoth@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
@@ -29,6 +29,7 @@
#include "au8522.h"
#include "xc5000.h"
#include "mxl5007t.h"
+#include "tda18271.h"
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
@@ -38,6 +39,15 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
static struct au8522_config hauppauge_hvr950q_config = {
.demod_address = 0x8e >> 1,
.status_mode = AU8522_DEMODLOCKING,
+ .qam_if = AU8522_IF_6MHZ,
+ .vsb_if = AU8522_IF_6MHZ,
+};
+
+static struct au8522_config hauppauge_woodbury_config = {
+ .demod_address = 0x8e >> 1,
+ .status_mode = AU8522_DEMODLOCKING,
+ .qam_if = AU8522_IF_4MHZ,
+ .vsb_if = AU8522_IF_3_25MHZ,
};
static struct xc5000_config hauppauge_hvr950q_tunerconfig = {
@@ -51,6 +61,10 @@ static struct mxl5007t_config mxl5007t_hvr950q_config = {
.if_freq_hz = MxL_IF_6_MHZ,
};
+static struct tda18271_config hauppauge_woodbury_tunerconfig = {
+ .gate = TDA18271_GATE_DIGITAL,
+};
+
/*-------------------------------------------------------------------*/
static void urb_completion(struct urb *purb)
{
@@ -357,6 +371,15 @@ int au0828_dvb_register(struct au0828_dev *dev)
&dev->i2c_adap, 0x60,
&mxl5007t_hvr950q_config);
break;
+ case AU0828_BOARD_HAUPPAUGE_WOODBURY:
+ dvb->frontend = dvb_attach(au8522_attach,
+ &hauppauge_woodbury_config,
+ &dev->i2c_adap);
+ if (dvb->frontend != NULL)
+ dvb_attach(tda18271_attach, dvb->frontend,
+ 0x60, &dev->i2c_adap,
+ &hauppauge_woodbury_tunerconfig);
+ break;
default:
printk(KERN_WARNING "The frontend of your DVB/ATSC card "
"isn't supported yet\n");
diff --git a/drivers/media/video/au0828/au0828-i2c.c b/drivers/media/video/au0828/au0828-i2c.c
index 741a4937b05..d618fbaade1 100644
--- a/drivers/media/video/au0828/au0828-i2c.c
+++ b/drivers/media/video/au0828/au0828-i2c.c
@@ -1,7 +1,7 @@
/*
* Driver for the Auvitek AU0828 USB bridge
*
- * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ * Copyright (c) 2008 Steven Toth <stoth@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
diff --git a/drivers/media/video/au0828/au0828-reg.h b/drivers/media/video/au0828/au0828-reg.h
index 39827550891..1e87fa0c684 100644
--- a/drivers/media/video/au0828/au0828-reg.h
+++ b/drivers/media/video/au0828/au0828-reg.h
@@ -1,7 +1,7 @@
/*
* Driver for the Auvitek USB bridge
*
- * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ * Copyright (c) 2008 Steven Toth <stoth@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
diff --git a/drivers/media/video/au0828/au0828.h b/drivers/media/video/au0828/au0828.h
index 7beb571798e..4f10ff30013 100644
--- a/drivers/media/video/au0828/au0828.h
+++ b/drivers/media/video/au0828/au0828.h
@@ -1,7 +1,7 @@
/*
* Driver for the Auvitek AU0828 USB bridge
*
- * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ * Copyright (c) 2008 Steven Toth <stoth@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
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
index 1c56ae92ce7..6081edc362d 100644
--- a/drivers/media/video/bt8xx/bttv-cards.c
+++ b/drivers/media/video/bt8xx/bttv-cards.c
@@ -3144,8 +3144,9 @@ static void identify_by_eeprom(struct bttv *btv, unsigned char eeprom_data[256])
static void flyvideo_gpio(struct bttv *btv)
{
- int gpio,has_remote,has_radio,is_capture_only,is_lr90,has_tda9820_tda9821;
- int tuner=UNSET,ttype;
+ int gpio, has_remote, has_radio, is_capture_only;
+ int is_lr90, has_tda9820_tda9821;
+ int tuner_type = UNSET, ttype;
gpio_inout(0xffffff, 0);
udelay(8); /* without this we would see the 0x1800 mask */
@@ -3163,20 +3164,26 @@ static void flyvideo_gpio(struct bttv *btv)
* xxxF00(LR26/LR50), xxxFE0(LR90): Remote control chip (LVA001 or CF45) soldered
* Note: Some bits are Audio_Mask !
*/
- ttype=(gpio&0x0f0000)>>16;
- switch(ttype) {
- case 0x0: tuner=2; /* NTSC, e.g. TPI8NSR11P */
+ ttype = (gpio & 0x0f0000) >> 16;
+ switch (ttype) {
+ case 0x0:
+ tuner_type = 2; /* NTSC, e.g. TPI8NSR11P */
break;
- case 0x2: tuner=39;/* LG NTSC (newer TAPC series) TAPC-H701P */
+ case 0x2:
+ tuner_type = 39; /* LG NTSC (newer TAPC series) TAPC-H701P */
break;
- case 0x4: tuner=5; /* Philips PAL TPI8PSB02P, TPI8PSB12P, TPI8PSB12D or FI1216, FM1216 */
+ case 0x4:
+ tuner_type = 5; /* Philips PAL TPI8PSB02P, TPI8PSB12P, TPI8PSB12D or FI1216, FM1216 */
break;
- case 0x6: tuner=37;/* LG PAL (newer TAPC series) TAPC-G702P */
+ case 0x6:
+ tuner_type = 37; /* LG PAL (newer TAPC series) TAPC-G702P */
break;
- case 0xC: tuner=3; /* Philips SECAM(+PAL) FQ1216ME or FI1216MF */
+ case 0xC:
+ tuner_type = 3; /* Philips SECAM(+PAL) FQ1216ME or FI1216MF */
break;
default:
printk(KERN_INFO "bttv%d: FlyVideo_gpio: unknown tuner type.\n", btv->c.nr);
+ break;
}
has_remote = gpio & 0x800000;
@@ -3189,23 +3196,26 @@ static void flyvideo_gpio(struct bttv *btv)
/*
* gpio & 0x001000 output bit for audio routing */
- if(is_capture_only)
- tuner = TUNER_ABSENT; /* No tuner present */
+ if (is_capture_only)
+ tuner_type = TUNER_ABSENT; /* No tuner present */
printk(KERN_INFO "bttv%d: FlyVideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n",
- btv->c.nr, has_radio? "yes":"no ", has_remote? "yes":"no ", tuner, gpio);
+ btv->c.nr, has_radio ? "yes" : "no ",
+ has_remote ? "yes" : "no ", tuner_type, gpio);
printk(KERN_INFO "bttv%d: FlyVideo LR90=%s tda9821/tda9820=%s capture_only=%s\n",
- btv->c.nr, is_lr90?"yes":"no ", has_tda9820_tda9821?"yes":"no ",
- is_capture_only?"yes":"no ");
+ btv->c.nr, is_lr90 ? "yes" : "no ",
+ has_tda9820_tda9821 ? "yes" : "no ",
+ is_capture_only ? "yes" : "no ");
- if (tuner != UNSET) /* only set if known tuner autodetected, else let insmod option through */
- btv->tuner_type = tuner;
+ if (tuner_type != UNSET) /* only set if known tuner autodetected, else let insmod option through */
+ btv->tuner_type = tuner_type;
btv->has_radio = has_radio;
/* LR90 Audio Routing is done by 2 hef4052, so Audio_Mask has 4 bits: 0x001c80
* LR26/LR50 only has 1 hef4052, Audio_Mask 0x000c00
* Audio options: from tuner, from tda9821/tda9821(mono,stereo,sap), from tda9874, ext., mute */
- if(has_tda9820_tda9821) btv->audio_mode_gpio = lt9415_audio;
+ if (has_tda9820_tda9821)
+ btv->audio_mode_gpio = lt9415_audio;
/* todo: if(has_tda9874) btv->audio_mode_gpio = fv2000s_audio; */
}
@@ -3962,7 +3972,7 @@ static int tuner_1_table[] = {
static void __devinit avermedia_eeprom(struct bttv *btv)
{
- int tuner_make,tuner_tv_fm,tuner_format,tuner=0;
+ int tuner_make, tuner_tv_fm, tuner_format, tuner_type = 0;
tuner_make = (eeprom_data[0x41] & 0x7);
tuner_tv_fm = (eeprom_data[0x41] & 0x18) >> 3;
@@ -3970,24 +3980,24 @@ static void __devinit avermedia_eeprom(struct bttv *btv)
btv->has_remote = (eeprom_data[0x42] & 0x01);
if (tuner_make == 0 || tuner_make == 2)
- if(tuner_format <=0x0a)
- tuner = tuner_0_table[tuner_format];
+ if (tuner_format <= 0x0a)
+ tuner_type = tuner_0_table[tuner_format];
if (tuner_make == 1)
- if(tuner_format <=9)
- tuner = tuner_1_table[tuner_format];
+ if (tuner_format <= 9)
+ tuner_type = tuner_1_table[tuner_format];
if (tuner_make == 4)
- if(tuner_format == 0x09)
- tuner = TUNER_LG_NTSC_NEW_TAPC; /* TAPC-G702P */
+ if (tuner_format == 0x09)
+ tuner_type = TUNER_LG_NTSC_NEW_TAPC; /* TAPC-G702P */
printk(KERN_INFO "bttv%d: Avermedia eeprom[0x%02x%02x]: tuner=",
- btv->c.nr,eeprom_data[0x41],eeprom_data[0x42]);
- if(tuner) {
- btv->tuner_type=tuner;
- printk("%d",tuner);
+ btv->c.nr, eeprom_data[0x41], eeprom_data[0x42]);
+ if (tuner_type) {
+ btv->tuner_type = tuner_type;
+ printk(KERN_CONT "%d", tuner_type);
} else
- printk("Unknown type");
- printk(" radio:%s remote control:%s\n",
+ printk(KERN_CONT "Unknown type");
+ printk(KERN_CONT " radio:%s remote control:%s\n",
tuner_tv_fm ? "yes" : "no",
btv->has_remote ? "yes" : "no");
}
@@ -4029,7 +4039,8 @@ static void __devinit boot_msp34xx(struct bttv *btv, int pin)
gpio_inout(mask,mask);
gpio_bits(mask,0);
- udelay(2500);
+ mdelay(2);
+ udelay(500);
gpio_bits(mask,mask);
if (bttv_gpio)
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index 85bf31ab878..933eaef41ea 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -96,7 +96,6 @@ static unsigned int irq_iswitch;
static unsigned int uv_ratio = 50;
static unsigned int full_luma_range;
static unsigned int coring;
-extern int no_overlay;
/* API features (turn on/off stuff for testing) */
static unsigned int v4l2 = 1;
@@ -3432,7 +3431,7 @@ static int radio_open(struct inode *inode, struct file *file)
dprintk("bttv: open minor=%d\n",minor);
for (i = 0; i < bttv_num; i++) {
- if (bttvs[i].radio_dev->minor == minor) {
+ if (bttvs[i].radio_dev && bttvs[i].radio_dev->minor == minor) {
btv = &bttvs[i];
break;
}
diff --git a/drivers/media/video/bt8xx/bttv-risc.c b/drivers/media/video/bt8xx/bttv-risc.c
index 649682aac1a..5b1b8e4c78b 100644
--- a/drivers/media/video/bt8xx/bttv-risc.c
+++ b/drivers/media/video/bt8xx/bttv-risc.c
@@ -244,7 +244,8 @@ bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc,
const struct bttv_format *fmt, struct bttv_overlay *ov,
int skip_even, int skip_odd)
{
- int dwords,rc,line,maxy,start,end,skip,nskips;
+ int dwords, rc, line, maxy, start, end;
+ unsigned skip, nskips;
struct btcx_skiplist *skips;
__le32 *rp;
u32 ri,ra;
diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h
index 08ef54a22c9..b4d940b2e44 100644
--- a/drivers/media/video/bt8xx/bttvp.h
+++ b/drivers/media/video/bt8xx/bttvp.h
@@ -267,6 +267,11 @@ int bttv_sub_add_device(struct bttv_core *core, char *name);
int bttv_sub_del_devices(struct bttv_core *core);
/* ---------------------------------------------------------- */
+/* bttv-cards.c */
+
+extern int no_overlay;
+
+/* ---------------------------------------------------------- */
/* bttv-driver.c */
/* insmod options */
diff --git a/drivers/media/video/btcx-risc.c b/drivers/media/video/btcx-risc.c
index f42701f82e7..3324ab38f58 100644
--- a/drivers/media/video/btcx-risc.c
+++ b/drivers/media/video/btcx-risc.c
@@ -184,12 +184,12 @@ btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips)
}
void
-btcx_calc_skips(int line, int width, unsigned int *maxy,
+btcx_calc_skips(int line, int width, int *maxy,
struct btcx_skiplist *skips, unsigned int *nskips,
const struct v4l2_clip *clips, unsigned int nclips)
{
unsigned int clip,skip;
- int end,maxline;
+ int end, maxline;
skip=0;
maxline = 9999;
diff --git a/drivers/media/video/btcx-risc.h b/drivers/media/video/btcx-risc.h
index 861bc811282..f8bc6e8e7b5 100644
--- a/drivers/media/video/btcx-risc.h
+++ b/drivers/media/video/btcx-risc.h
@@ -23,7 +23,7 @@ int btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win,
int btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips,
unsigned int n, int mask);
void btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips);
-void btcx_calc_skips(int line, int width, unsigned int *maxy,
+void btcx_calc_skips(int line, int width, int *maxy,
struct btcx_skiplist *skips, unsigned int *nskips,
const struct v4l2_clip *clips, unsigned int nclips);
diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c
index d3b3268bace..6e39e253ce5 100644
--- a/drivers/media/video/bw-qcam.c
+++ b/drivers/media/video/bw-qcam.c
@@ -946,8 +946,7 @@ static int init_bwqcam(struct parport *port)
printk(KERN_INFO "Connectix Quickcam on %s\n", qcam->pport->name);
- if(video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr)==-1)
- {
+ if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
parport_unregister_device(qcam->pdev);
kfree(qcam);
return -ENODEV;
diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c
index fe9379b282d..7f6c6b4bec1 100644
--- a/drivers/media/video/c-qcam.c
+++ b/drivers/media/video/c-qcam.c
@@ -787,8 +787,7 @@ static int init_cqcam(struct parport *port)
parport_release(qcam->pdev);
- if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr)==-1)
- {
+ if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
printk(KERN_ERR "Unable to register Colour QuickCam on %s\n",
qcam->pport->name);
parport_unregister_device(qcam->pdev);
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c
index c149b7d712e..5405c30dbb0 100644
--- a/drivers/media/video/cafe_ccic.c
+++ b/drivers/media/video/cafe_ccic.c
@@ -19,6 +19,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
+#include <linux/mm.h>
#include <linux/pci.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
diff --git a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c
index dc8cc6115e2..a661800b0e6 100644
--- a/drivers/media/video/cpia.c
+++ b/drivers/media/video/cpia.c
@@ -3955,7 +3955,7 @@ struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowleve
camera->lowlevel_data = lowlevel;
/* register v4l device */
- if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
+ if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
kfree(camera);
printk(KERN_DEBUG "video_register_device failed\n");
return NULL;
diff --git a/drivers/media/video/cpia2/cpia2_usb.c b/drivers/media/video/cpia2/cpia2_usb.c
index a4574740350..a8a199047cb 100644
--- a/drivers/media/video/cpia2/cpia2_usb.c
+++ b/drivers/media/video/cpia2/cpia2_usb.c
@@ -632,7 +632,7 @@ int cpia2_usb_transfer_cmd(struct camera_data *cam,
static int submit_urbs(struct camera_data *cam)
{
struct urb *urb;
- int fx, err, i;
+ int fx, err, i, j;
for(i=0; i<NUM_SBUF; ++i) {
if (cam->sbuf[i].data)
@@ -657,6 +657,9 @@ static int submit_urbs(struct camera_data *cam)
}
urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
if (!urb) {
+ ERR("%s: usb_alloc_urb error!\n", __func__);
+ for (j = 0; j < i; j++)
+ usb_free_urb(cam->sbuf[j].urb);
return -ENOMEM;
}
diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c
index 515c8b57a60..eb9f15cd4c4 100644
--- a/drivers/media/video/cpia2/cpia2_v4l.c
+++ b/drivers/media/video/cpia2/cpia2_v4l.c
@@ -1024,7 +1024,6 @@ static int ioctl_queryctrl(void *arg,struct camera_data *cam)
if(cam->params.pnp_id.device_type == DEVICE_STV_672 &&
cam->params.version.sensor_flags==CPIA2_VP_SENSOR_FLAGS_500){
// Maximum 15fps
- int i;
for(i=0; i<c->maximum; ++i) {
if(framerate_controls[i].value ==
CPIA2_VP_FRAMERATE_15) {
@@ -1959,8 +1958,7 @@ int cpia2_register_camera(struct camera_data *cam)
reset_camera_struct_v4l(cam);
/* register v4l device */
- if (video_register_device
- (cam->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
+ if (video_register_device(cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
ERR("video_register_device failed\n");
video_device_release(cam->vdev);
return -ENODEV;
diff --git a/drivers/media/video/cx18/cx18-av-firmware.c b/drivers/media/video/cx18/cx18-av-firmware.c
index 834b9248242..e996a4e3123 100644
--- a/drivers/media/video/cx18/cx18-av-firmware.c
+++ b/drivers/media/video/cx18/cx18-av-firmware.c
@@ -32,7 +32,7 @@ int cx18_av_loadfw(struct cx18 *cx)
u32 v;
const u8 *ptr;
int i;
- int retries = 0;
+ int retries1 = 0;
if (request_firmware(&fw, FWFILE, &cx->dev->dev) != 0) {
CX18_ERR("unable to open firmware %s\n", FWFILE);
@@ -41,7 +41,7 @@ int cx18_av_loadfw(struct cx18 *cx)
/* The firmware load often has byte errors, so allow for several
retries, both at byte level and at the firmware load level. */
- while (retries < 5) {
+ while (retries1 < 5) {
cx18_av_write4(cx, CXADEC_CHIP_CTRL, 0x00010000);
cx18_av_write(cx, CXADEC_STD_DET_CTL, 0xf6);
@@ -57,9 +57,9 @@ int cx18_av_loadfw(struct cx18 *cx)
for (i = 0; i < size; i++) {
u32 dl_control = 0x0F000000 | i | ((u32)ptr[i] << 16);
u32 value = 0;
- int retries;
+ int retries2;
- for (retries = 0; retries < 5; retries++) {
+ for (retries2 = 0; retries2 < 5; retries2++) {
cx18_av_write4(cx, CXADEC_DL_CTL, dl_control);
udelay(10);
value = cx18_av_read4(cx, CXADEC_DL_CTL);
@@ -69,18 +69,18 @@ int cx18_av_loadfw(struct cx18 *cx)
the address. We can only write the lower
address byte of the address. */
if ((value & 0x3F00) != (dl_control & 0x3F00)) {
- retries = 5;
+ retries2 = 5;
break;
}
}
- if (retries >= 5)
+ if (retries2 >= 5)
break;
}
if (i == size)
break;
- retries++;
+ retries1++;
}
- if (retries >= 5) {
+ if (retries1 >= 5) {
CX18_ERR("unable to load firmware %s\n", FWFILE);
release_firmware(fw);
return -EIO;
diff --git a/drivers/media/video/cx18/cx18-cards.c b/drivers/media/video/cx18/cx18-cards.c
index 8fe5f38c4d7..3cb9734ec07 100644
--- a/drivers/media/video/cx18/cx18-cards.c
+++ b/drivers/media/video/cx18/cx18-cards.c
@@ -163,7 +163,7 @@ static const struct cx18_card cx18_card_h900 = {
},
.audio_inputs = {
{ CX18_CARD_INPUT_AUD_TUNER,
- CX18_AV_AUDIO8, 0 },
+ CX18_AV_AUDIO5, 0 },
{ CX18_CARD_INPUT_LINE_IN1,
CX18_AV_AUDIO_SERIAL1, 0 },
},
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
index 22434aadde3..bd18afebbf8 100644
--- a/drivers/media/video/cx18/cx18-driver.c
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -74,9 +74,9 @@ static int radio[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1 };
-static int cardtype_c = 1;
-static int tuner_c = 1;
-static int radio_c = 1;
+static unsigned cardtype_c = 1;
+static unsigned tuner_c = 1;
+static unsigned radio_c = 1;
static char pal[] = "--";
static char secam[] = "--";
static char ntsc[] = "-";
diff --git a/drivers/media/video/cx18/cx18-dvb.c b/drivers/media/video/cx18/cx18-dvb.c
index cae38985b13..1e420a804fc 100644
--- a/drivers/media/video/cx18/cx18-dvb.c
+++ b/drivers/media/video/cx18/cx18-dvb.c
@@ -1,7 +1,7 @@
/*
* cx18 functions for DVB support
*
- * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ * Copyright (c) 2008 Steven Toth <stoth@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
diff --git a/drivers/media/video/cx18/cx18-dvb.h b/drivers/media/video/cx18/cx18-dvb.h
index d6a6ccda79a..bf8d8f6f545 100644
--- a/drivers/media/video/cx18/cx18-dvb.h
+++ b/drivers/media/video/cx18/cx18-dvb.h
@@ -1,7 +1,7 @@
/*
* cx18 functions for DVB support
*
- * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ * Copyright (c) 2008 Steven Toth <stoth@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
diff --git a/drivers/media/video/cx18/cx18-irq.c b/drivers/media/video/cx18/cx18-irq.c
index 25114a5cbd5..ab218315c84 100644
--- a/drivers/media/video/cx18/cx18-irq.c
+++ b/drivers/media/video/cx18/cx18-irq.c
@@ -61,7 +61,7 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb)
CX18_WARN("Ack struct = %d for %s\n",
mb->args[2], s->name);
id = read_enc(off);
- buf = cx18_queue_find_buf(s, id, read_enc(off + 4));
+ buf = cx18_queue_get_buf_irq(s, id, read_enc(off + 4));
CX18_DEBUG_HI_DMA("DMA DONE for %s (buffer %d)\n", s->name, id);
if (buf) {
cx18_buf_sync_for_cpu(s, buf);
diff --git a/drivers/media/video/cx18/cx18-queue.c b/drivers/media/video/cx18/cx18-queue.c
index 6990b77c620..dbe792ac300 100644
--- a/drivers/media/video/cx18/cx18-queue.c
+++ b/drivers/media/video/cx18/cx18-queue.c
@@ -78,12 +78,13 @@ struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q)
return buf;
}
-struct cx18_buffer *cx18_queue_find_buf(struct cx18_stream *s, u32 id,
+struct cx18_buffer *cx18_queue_get_buf_irq(struct cx18_stream *s, u32 id,
u32 bytesused)
{
struct cx18 *cx = s->cx;
struct list_head *p;
+ spin_lock(&s->qlock);
list_for_each(p, &s->q_free.list) {
struct cx18_buffer *buf =
list_entry(p, struct cx18_buffer, list);
@@ -92,114 +93,48 @@ struct cx18_buffer *cx18_queue_find_buf(struct cx18_stream *s, u32 id,
continue;
buf->bytesused = bytesused;
/* the transport buffers are handled differently,
- so there is no need to move them to the full queue */
- if (s->type == CX18_ENC_STREAM_TYPE_TS)
- return buf;
- s->q_free.buffers--;
- s->q_free.length -= s->buf_size;
- s->q_full.buffers++;
- s->q_full.length += s->buf_size;
- s->q_full.bytesused += buf->bytesused;
- list_move_tail(&buf->list, &s->q_full.list);
+ they are not moved to the full queue */
+ if (s->type != CX18_ENC_STREAM_TYPE_TS) {
+ s->q_free.buffers--;
+ s->q_free.length -= s->buf_size;
+ s->q_full.buffers++;
+ s->q_full.length += s->buf_size;
+ s->q_full.bytesused += buf->bytesused;
+ list_move_tail(&buf->list, &s->q_full.list);
+ }
+ spin_unlock(&s->qlock);
return buf;
}
+ spin_unlock(&s->qlock);
CX18_ERR("Cannot find buffer %d for stream %s\n", id, s->name);
return NULL;
}
-static void cx18_queue_move_buf(struct cx18_stream *s, struct cx18_queue *from,
- struct cx18_queue *to, int clear, int full)
-{
- struct cx18_buffer *buf =
- list_entry(from->list.next, struct cx18_buffer, list);
-
- list_move_tail(from->list.next, &to->list);
- from->buffers--;
- from->length -= s->buf_size;
- from->bytesused -= buf->bytesused - buf->readpos;
- /* special handling for q_free */
- if (clear)
- buf->bytesused = buf->readpos = buf->b_flags = 0;
- else if (full) {
- /* special handling for stolen buffers, assume
- all bytes are used. */
- buf->bytesused = s->buf_size;
- buf->readpos = buf->b_flags = 0;
- }
- to->buffers++;
- to->length += s->buf_size;
- to->bytesused += buf->bytesused - buf->readpos;
-}
-
-/* Move 'needed_bytes' worth of buffers from queue 'from' into queue 'to'.
- If 'needed_bytes' == 0, then move all buffers from 'from' into 'to'.
- If 'steal' != NULL, then buffers may also taken from that queue if
- needed.
-
- The buffer is automatically cleared if it goes to the free queue. It is
- also cleared if buffers need to be taken from the 'steal' queue and
- the 'from' queue is the free queue.
-
- When 'from' is q_free, then needed_bytes is compared to the total
- available buffer length, otherwise needed_bytes is compared to the
- bytesused value. For the 'steal' queue the total available buffer
- length is always used.
-
- -ENOMEM is returned if the buffers could not be obtained, 0 if all
- buffers where obtained from the 'from' list and if non-zero then
- the number of stolen buffers is returned. */
-static int cx18_queue_move(struct cx18_stream *s, struct cx18_queue *from,
- struct cx18_queue *steal, struct cx18_queue *to,
- int needed_bytes)
+/* Move all buffers of a queue to q_free, while flushing the buffers */
+static void cx18_queue_flush(struct cx18_stream *s, struct cx18_queue *q)
{
unsigned long flags;
- int rc = 0;
- int from_free = from == &s->q_free;
- int to_free = to == &s->q_free;
- int bytes_available;
-
- spin_lock_irqsave(&s->qlock, flags);
- if (needed_bytes == 0) {
- from_free = 1;
- needed_bytes = from->length;
- }
-
- bytes_available = from_free ? from->length : from->bytesused;
- bytes_available += steal ? steal->length : 0;
+ struct cx18_buffer *buf;
- if (bytes_available < needed_bytes) {
- spin_unlock_irqrestore(&s->qlock, flags);
- return -ENOMEM;
- }
- if (from_free) {
- u32 old_length = to->length;
+ if (q == &s->q_free)
+ return;
- while (to->length - old_length < needed_bytes) {
- if (list_empty(&from->list))
- from = steal;
- if (from == steal)
- rc++; /* keep track of 'stolen' buffers */
- cx18_queue_move_buf(s, from, to, 1, 0);
- }
- } else {
- u32 old_bytesused = to->bytesused;
-
- while (to->bytesused - old_bytesused < needed_bytes) {
- if (list_empty(&from->list))
- from = steal;
- if (from == steal)
- rc++; /* keep track of 'stolen' buffers */
- cx18_queue_move_buf(s, from, to, to_free, rc);
- }
+ spin_lock_irqsave(&s->qlock, flags);
+ while (!list_empty(&q->list)) {
+ buf = list_entry(q->list.next, struct cx18_buffer, list);
+ list_move_tail(q->list.next, &s->q_free.list);
+ buf->bytesused = buf->readpos = buf->b_flags = 0;
+ s->q_free.buffers++;
+ s->q_free.length += s->buf_size;
}
+ cx18_queue_init(q);
spin_unlock_irqrestore(&s->qlock, flags);
- return rc;
}
void cx18_flush_queues(struct cx18_stream *s)
{
- cx18_queue_move(s, &s->q_io, NULL, &s->q_free, 0);
- cx18_queue_move(s, &s->q_full, NULL, &s->q_free, 0);
+ cx18_queue_flush(s, &s->q_io);
+ cx18_queue_flush(s, &s->q_full);
}
int cx18_stream_alloc(struct cx18_stream *s)
@@ -214,10 +149,10 @@ int cx18_stream_alloc(struct cx18_stream *s)
s->name, s->buffers, s->buf_size,
s->buffers * s->buf_size / 1024);
- if (((char *)&cx->scb->cpu_mdl[cx->mdl_offset + s->buffers] -
- (char *)cx->scb) > SCB_RESERVED_SIZE) {
- unsigned bufsz = (((char *)cx->scb) + SCB_RESERVED_SIZE -
- ((char *)cx->scb->cpu_mdl));
+ if (((char __iomem *)&cx->scb->cpu_mdl[cx->mdl_offset + s->buffers] -
+ (char __iomem *)cx->scb) > SCB_RESERVED_SIZE) {
+ unsigned bufsz = (((char __iomem *)cx->scb) + SCB_RESERVED_SIZE -
+ ((char __iomem *)cx->scb->cpu_mdl));
CX18_ERR("Too many buffers, cannot fit in SCB area\n");
CX18_ERR("Max buffers = %zd\n",
diff --git a/drivers/media/video/cx18/cx18-queue.h b/drivers/media/video/cx18/cx18-queue.h
index 91423b9863a..7f93bb13c09 100644
--- a/drivers/media/video/cx18/cx18-queue.h
+++ b/drivers/media/video/cx18/cx18-queue.h
@@ -46,7 +46,7 @@ void cx18_queue_init(struct cx18_queue *q);
void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf,
struct cx18_queue *q);
struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q);
-struct cx18_buffer *cx18_queue_find_buf(struct cx18_stream *s, u32 id,
+struct cx18_buffer *cx18_queue_get_buf_irq(struct cx18_stream *s, u32 id,
u32 bytesused);
void cx18_flush_queues(struct cx18_stream *s);
diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c
index 8118091568f..7b0e8c01692 100644
--- a/drivers/media/video/cx23885/cx23885-417.c
+++ b/drivers/media/video/cx23885/cx23885-417.c
@@ -4,7 +4,7 @@
*
* (c) 2004 Jelle Foks <jelle@foks.8m.com>
* (c) 2004 Gerd Knorr <kraxel@bytesex.org>
- * (c) 2008 Steven Toth <stoth@hauppauge.com>
+ * (c) 2008 Steven Toth <stoth@linuxtv.org>
* - CX23885/7/8 support
*
* Includes parts from the ivtv driver( http://ivtv.sourceforge.net/),
diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c
index a19de850955..c36d3f63210 100644
--- a/drivers/media/video/cx23885/cx23885-cards.c
+++ b/drivers/media/video/cx23885/cx23885-cards.c
@@ -1,7 +1,7 @@
/*
* Driver for the Conexant CX23885 PCIe bridge
*
- * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ * Copyright (c) 2006 Steven Toth <stoth@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
diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c
index 6286a9cf957..25fb0993874 100644
--- a/drivers/media/video/cx23885/cx23885-core.c
+++ b/drivers/media/video/cx23885/cx23885-core.c
@@ -1,7 +1,7 @@
/*
* Driver for the Conexant CX23885 PCIe bridge
*
- * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ * Copyright (c) 2006 Steven Toth <stoth@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
@@ -33,7 +33,7 @@
#include "cx23885.h"
MODULE_DESCRIPTION("Driver for cx23885 based TV cards");
-MODULE_AUTHOR("Steven Toth <stoth@hauppauge.com>");
+MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
MODULE_LICENSE("GPL");
static unsigned int debug;
diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c
index 0a2e6558cd6..291b9d008da 100644
--- a/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/drivers/media/video/cx23885/cx23885-dvb.c
@@ -1,7 +1,7 @@
/*
* Driver for the Conexant CX23885 PCIe bridge
*
- * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ * Copyright (c) 2006 Steven Toth <stoth@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
diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c
index c6bb0a05bc1..f98e476e961 100644
--- a/drivers/media/video/cx23885/cx23885-i2c.c
+++ b/drivers/media/video/cx23885/cx23885-i2c.c
@@ -1,7 +1,7 @@
/*
* Driver for the Conexant CX23885 PCIe bridge
*
- * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ * Copyright (c) 2006 Steven Toth <stoth@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
diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h
index bdd11bc513a..20b68a23626 100644
--- a/drivers/media/video/cx23885/cx23885-reg.h
+++ b/drivers/media/video/cx23885/cx23885-reg.h
@@ -1,7 +1,7 @@
/*
* Driver for the Conexant CX23885 PCIe bridge
*
- * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ * Copyright (c) 2006 Steven Toth <stoth@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
diff --git a/drivers/media/video/cx23885/cx23885-vbi.c b/drivers/media/video/cx23885/cx23885-vbi.c
index e36e3fcae2f..35e61cd112f 100644
--- a/drivers/media/video/cx23885/cx23885-vbi.c
+++ b/drivers/media/video/cx23885/cx23885-vbi.c
@@ -1,7 +1,7 @@
/*
* Driver for the Conexant CX23885 PCIe bridge
*
- * Copyright (c) 2007 Steven Toth <stoth@hauppauge.com>
+ * Copyright (c) 2007 Steven Toth <stoth@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
diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c
index ad2235dab5b..6047c78d84b 100644
--- a/drivers/media/video/cx23885/cx23885-video.c
+++ b/drivers/media/video/cx23885/cx23885-video.c
@@ -1,7 +1,7 @@
/*
* Driver for the Conexant CX23885 PCIe bridge
*
- * Copyright (c) 2007 Steven Toth <stoth@hauppauge.com>
+ * Copyright (c) 2007 Steven Toth <stoth@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
@@ -41,7 +41,7 @@
#endif
MODULE_DESCRIPTION("v4l2 driver module for cx23885 based TV cards");
-MODULE_AUTHOR("Steven Toth <stoth@hauppauge.com>");
+MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
MODULE_LICENSE("GPL");
/* ------------------------------------------------------------------ */
diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h
index 00dfdc89d64..e23d97c071e 100644
--- a/drivers/media/video/cx23885/cx23885.h
+++ b/drivers/media/video/cx23885/cx23885.h
@@ -1,7 +1,7 @@
/*
* Driver for the Conexant CX23885 PCIe bridge
*
- * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ * Copyright (c) 2006 Steven Toth <stoth@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
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index 209d3bcb5db..4da8cd74f00 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -13,7 +13,7 @@
* NTSC sliced VBI support by Christopher Neufeld <television@cneufeld.ca>
* with additional fixes by Hans Verkuil <hverkuil@xs4all.nl>.
*
- * CX23885 support by Steven Toth <stoth@hauppauge.com>.
+ * CX23885 support by Steven Toth <stoth@linuxtv.org>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/drivers/media/video/dabusb.c b/drivers/media/video/dabusb.c
index 48f4b92a8f8..79faedf5852 100644
--- a/drivers/media/video/dabusb.c
+++ b/drivers/media/video/dabusb.c
@@ -403,6 +403,7 @@ static int dabusb_fpga_download (pdabusb_t s, const char *fname)
ret = request_firmware(&fw, "dabusb/bitstream.bin", &s->usbdev->dev);
if (ret) {
err("Failed to load \"dabusb/bitstream.bin\": %d\n", ret);
+ kfree(b);
return ret;
}
diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c
index 3c006103c1e..ac3292d7646 100644
--- a/drivers/media/video/em28xx/em28xx-audio.c
+++ b/drivers/media/video/em28xx/em28xx-audio.c
@@ -117,10 +117,10 @@ static void em28xx_audio_isocirq(struct urb *urb)
if (oldptr + length >= runtime->buffer_size) {
unsigned int cnt =
- runtime->buffer_size - oldptr - 1;
+ runtime->buffer_size - oldptr;
memcpy(runtime->dma_area + oldptr * stride, cp,
cnt * stride);
- memcpy(runtime->dma_area, cp + cnt,
+ memcpy(runtime->dma_area, cp + cnt * stride,
length * stride - cnt * stride);
} else {
memcpy(runtime->dma_area + oldptr * stride, cp,
@@ -161,8 +161,14 @@ static int em28xx_init_audio_isoc(struct em28xx *dev)
memset(dev->adev->transfer_buffer[i], 0x80, sb_size);
urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
- if (!urb)
+ if (!urb) {
+ em28xx_errdev("usb_alloc_urb failed!\n");
+ for (j = 0; j < i; j++) {
+ usb_free_urb(dev->adev->urb[j]);
+ kfree(dev->adev->transfer_buffer[j]);
+ }
return -ENOMEM;
+ }
urb->dev = dev->udev;
urb->context = dev;
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index 452da70e719..de943cf6c16 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -93,28 +93,6 @@ struct em28xx_board em28xx_boards[] = {
.amux = 0,
} },
},
- [EM2800_BOARD_KWORLD_USB2800] = {
- .name = "Kworld USB2800",
- .valid = EM28XX_BOARD_NOT_VALIDATED,
- .is_em2800 = 1,
- .vchannels = 3,
- .tuner_type = TUNER_PHILIPS_FCV1236D,
- .tda9887_conf = TDA9887_PRESENT,
- .decoder = EM28XX_SAA7113,
- .input = { {
- .type = EM28XX_VMUX_TELEVISION,
- .vmux = SAA7115_COMPOSITE2,
- .amux = 0,
- }, {
- .type = EM28XX_VMUX_COMPOSITE1,
- .vmux = SAA7115_COMPOSITE0,
- .amux = 1,
- }, {
- .type = EM28XX_VMUX_SVIDEO,
- .vmux = SAA7115_SVIDEO3,
- .amux = 1,
- } },
- },
[EM2820_BOARD_KWORLD_PVRTV2800RF] = {
.name = "Kworld PVR TV 2800 RF",
.is_em2800 = 0,
@@ -599,7 +577,7 @@ struct em28xx_board em28xx_boards[] = {
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
- .amux = 1,
+ .amux = 3,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
@@ -952,22 +930,23 @@ struct em28xx_board em28xx_boards[] = {
},
[EM2880_BOARD_KWORLD_DVB_310U] = {
.name = "KWorld DVB-T 310U",
- .valid = EM28XX_BOARD_NOT_VALIDATED,
.vchannels = 3,
.tuner_type = TUNER_XC2028,
+ .has_dvb = 1,
+ .mts_firmware = 1,
.decoder = EM28XX_TVP5150,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
- .amux = 0,
+ .amux = EM28XX_AMUX_VIDEO,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
- .amux = 1,
- }, {
+ .amux = EM28XX_AMUX_AC97_LINE_IN,
+ }, { /* S-video has not been tested yet */
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
- .amux = 1,
+ .amux = EM28XX_AMUX_AC97_LINE_IN,
} },
},
[EM2881_BOARD_DNT_DA2_HYBRID] = {
@@ -1282,6 +1261,7 @@ static struct em28xx_reg_seq em2882_terratec_hybrid_xs_digital[] = {
static struct em28xx_hash_table em28xx_eeprom_hash [] = {
/* P/N: SA 60002070465 Tuner: TVF7533-MF */
{0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF},
+ {0x966a0441, EM2880_BOARD_KWORLD_DVB_310U, TUNER_XC2028},
};
/* I2C devicelist hash table for devices with generic USB IDs */
@@ -1552,9 +1532,12 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
/* djh - Not sure which demod we need here */
ctl->demod = XC3028_FE_DEFAULT;
break;
+ case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
+ ctl->demod = XC3028_FE_DEFAULT;
+ ctl->fname = XC3028L_DEFAULT_FIRMWARE;
+ break;
case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
- case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
/* FIXME: Better to specify the needed IF */
ctl->demod = XC3028_FE_DEFAULT;
break;
@@ -1764,6 +1747,20 @@ void em28xx_card_setup(struct em28xx *dev)
break;
case EM2820_BOARD_UNKNOWN:
case EM2800_BOARD_UNKNOWN:
+ /*
+ * The K-WORLD DVB-T 310U is detected as an MSI Digivox AD.
+ *
+ * This occurs because they share identical USB vendor and
+ * product IDs.
+ *
+ * What we do here is look up the EEPROM hash of the K-WORLD
+ * and if it is found then we decide that we do not have
+ * a DIGIVOX and reset the device to the K-WORLD instead.
+ *
+ * This solution is only valid if they do not share eeprom
+ * hash identities which has not been determined as yet.
+ */
+ case EM2880_BOARD_MSI_DIGIVOX_AD:
if (!em28xx_hint_board(dev))
em28xx_set_model(dev);
break;
diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c
index 4b992bc0083..d2b1a1a5268 100644
--- a/drivers/media/video/em28xx/em28xx-dvb.c
+++ b/drivers/media/video/em28xx/em28xx-dvb.c
@@ -452,6 +452,15 @@ static int dvb_init(struct em28xx *dev)
goto out_free;
}
break;
+ case EM2880_BOARD_KWORLD_DVB_310U:
+ dvb->frontend = dvb_attach(zl10353_attach,
+ &em28xx_zl10353_with_xc3028,
+ &dev->i2c_adap);
+ if (attach_xc3028(0x61, dev) < 0) {
+ result = -EINVAL;
+ goto out_free;
+ }
+ break;
default:
printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card"
" isn't supported yet\n",
diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c
index 2d170d101c2..8db2a05bf9c 100644
--- a/drivers/media/video/et61x251/et61x251_core.c
+++ b/drivers/media/video/et61x251/et61x251_core.c
@@ -2588,6 +2588,7 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
cam->v4ldev->fops = &et61x251_fops;
cam->v4ldev->minor = video_nr[dev_nr];
cam->v4ldev->release = video_device_release;
+ cam->v4ldev->parent = &udev->dev;
video_set_drvdata(cam->v4ldev, cam);
init_completion(&cam->probe);
diff --git a/drivers/media/video/gspca/conex.c b/drivers/media/video/gspca/conex.c
index cd3a3f5829b..4d9f4cc255a 100644
--- a/drivers/media/video/gspca/conex.c
+++ b/drivers/media/video/gspca/conex.c
@@ -124,7 +124,7 @@ static void reg_r(struct gspca_dev *gspca_dev,
struct usb_device *dev = gspca_dev->dev;
#ifdef GSPCA_DEBUG
- if (len > sizeof gspca_dev->usb_buf) {
+ if (len > USB_BUF_SZ) {
err("reg_r: buffer overflow");
return;
}
@@ -164,7 +164,7 @@ static void reg_w(struct gspca_dev *gspca_dev,
struct usb_device *dev = gspca_dev->dev;
#ifdef GSPCA_DEBUG
- if (len > sizeof gspca_dev->usb_buf) {
+ if (len > USB_BUF_SZ) {
err("reg_w: buffer overflow");
return;
}
@@ -731,13 +731,13 @@ static void cx11646_jpeg(struct gspca_dev*gspca_dev)
reg_w_val(gspca_dev, 0x0000, 0x00);
/* wait for completion */
retry = 50;
- while (retry--) {
+ do {
reg_r(gspca_dev, 0x0002, 1);
/* 0x07 until 0x00 */
if (gspca_dev->usb_buf[0] == 0x00)
break;
reg_w_val(gspca_dev, 0x0053, 0x00);
- }
+ } while (--retry);
if (retry == 0)
PDEBUG(D_ERR, "Damned Errors sending jpeg Table");
/* send the qtable now */
@@ -826,8 +826,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
return 0;
}
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
{
cx11646_init1(gspca_dev);
cx11646_initsize(gspca_dev);
@@ -845,10 +845,6 @@ static void sd_start(struct gspca_dev *gspca_dev)
cx11646_jpeg(gspca_dev);
}
-static void sd_stopN(struct gspca_dev *gspca_dev)
-{
-}
-
static void sd_stop0(struct gspca_dev *gspca_dev)
{
int retry = 50;
@@ -871,10 +867,6 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
reg_w_val(gspca_dev, 0x00fc, 0xe0);
}
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
-
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
struct gspca_frame *frame, /* target */
__u8 *data, /* isoc packet */
@@ -998,11 +990,9 @@ static struct sd_desc sd_desc = {
.ctrls = sd_ctrls,
.nctrls = ARRAY_SIZE(sd_ctrls),
.config = sd_config,
- .open = sd_open,
+ .init = sd_init,
.start = sd_start,
- .stopN = sd_stopN,
.stop0 = sd_stop0,
- .close = sd_close,
.pkt_scan = sd_pkt_scan,
};
@@ -1026,6 +1016,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
/* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/etoms.c b/drivers/media/video/gspca/etoms.c
index 1dbe92d01e6..4ff0e386914 100644
--- a/drivers/media/video/gspca/etoms.c
+++ b/drivers/media/video/gspca/etoms.c
@@ -81,6 +81,7 @@ static struct ctrl sd_ctrls[] = {
.set = sd_setcontrast,
.get = sd_getcontrast,
},
+#define COLOR_IDX 2
{
{
.id = V4L2_CID_SATURATION,
@@ -234,7 +235,7 @@ static void reg_r(struct gspca_dev *gspca_dev,
struct usb_device *dev = gspca_dev->dev;
#ifdef GSPCA_DEBUG
- if (len > sizeof gspca_dev->usb_buf) {
+ if (len > USB_BUF_SZ) {
err("reg_r: buffer overflow");
return;
}
@@ -272,7 +273,7 @@ static void reg_w(struct gspca_dev *gspca_dev,
struct usb_device *dev = gspca_dev->dev;
#ifdef GSPCA_DEBUG
- if (len > sizeof gspca_dev->usb_buf) {
+ if (len > USB_BUF_SZ) {
err("reg_w: buffer overflow");
return;
}
@@ -665,6 +666,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
} else {
cam->cam_mode = vga_mode;
cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+ gspca_dev->ctrl_dis = (1 << COLOR_IDX);
}
sd->brightness = BRIGHTNESS_DEF;
sd->contrast = CONTRAST_DEF;
@@ -674,8 +676,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
return 0;
}
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -709,14 +711,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
et_video(gspca_dev, 0); /* video off */
}
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
-
static __u8 Et_getgainG(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -893,21 +887,19 @@ static struct sd_desc sd_desc = {
.ctrls = sd_ctrls,
.nctrls = ARRAY_SIZE(sd_ctrls),
.config = sd_config,
- .open = sd_open,
+ .init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
- .stop0 = sd_stop0,
- .close = sd_close,
.pkt_scan = sd_pkt_scan,
.dq_callback = do_autogain,
};
/* -- module initialisation -- */
static __devinitdata struct usb_device_id device_table[] = {
-#ifndef CONFIG_USB_ET61X251
{USB_DEVICE(0x102c, 0x6151), .driver_info = SENSOR_PAS106},
-#endif
+#if !defined CONFIG_USB_ET61X251 && !defined CONFIG_USB_ET61X251_MODULE
{USB_DEVICE(0x102c, 0x6251), .driver_info = SENSOR_TAS5130CXX},
+#endif
{}
};
@@ -926,6 +918,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
/* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c
index 15d302b28b7..ac95c55887d 100644
--- a/drivers/media/video/gspca/gspca.c
+++ b/drivers/media/video/gspca/gspca.c
@@ -114,7 +114,10 @@ static void fill_frame(struct gspca_dev *gspca_dev,
cam_pkt_op pkt_scan;
if (urb->status != 0) {
- PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status);
+#ifdef CONFIG_PM
+ if (!gspca_dev->frozen)
+#endif
+ PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status);
return; /* disconnection ? */
}
pkt_scan = gspca_dev->sd_desc->pkt_scan;
@@ -456,6 +459,7 @@ static int create_urbs(struct gspca_dev *gspca_dev,
urb = usb_alloc_urb(npkt, GFP_KERNEL);
if (!urb) {
err("usb_alloc_urb failed");
+ destroy_urbs(gspca_dev);
return -ENOMEM;
}
urb->transfer_buffer = usb_buffer_alloc(gspca_dev->dev,
@@ -465,8 +469,8 @@ static int create_urbs(struct gspca_dev *gspca_dev,
if (urb->transfer_buffer == NULL) {
usb_free_urb(urb);
- destroy_urbs(gspca_dev);
err("usb_buffer_urb failed");
+ destroy_urbs(gspca_dev);
return -ENOMEM;
}
gspca_dev->urb[n] = urb;
@@ -555,10 +559,12 @@ static void gspca_stream_off(struct gspca_dev *gspca_dev)
gspca_dev->streaming = 0;
atomic_set(&gspca_dev->nevent, 0);
if (gspca_dev->present) {
- gspca_dev->sd_desc->stopN(gspca_dev);
+ if (gspca_dev->sd_desc->stopN)
+ gspca_dev->sd_desc->stopN(gspca_dev);
destroy_urbs(gspca_dev);
gspca_set_alt0(gspca_dev);
- gspca_dev->sd_desc->stop0(gspca_dev);
+ if (gspca_dev->sd_desc->stop0)
+ gspca_dev->sd_desc->stop0(gspca_dev);
PDEBUG(D_STREAM, "stream off OK");
}
}
@@ -767,19 +773,7 @@ static int dev_open(struct inode *inode, struct file *file)
goto out;
}
- /* if not done yet, initialize the sensor */
- if (gspca_dev->users == 0) {
- if (mutex_lock_interruptible(&gspca_dev->usb_lock)) {
- ret = -ERESTARTSYS;
- goto out;
- }
- ret = gspca_dev->sd_desc->open(gspca_dev);
- mutex_unlock(&gspca_dev->usb_lock);
- if (ret != 0) {
- PDEBUG(D_ERR|D_CONF, "init device failed %d", ret);
- goto out;
- }
- } else if (gspca_dev->users > 4) { /* (arbitrary value) */
+ if (gspca_dev->users > 4) { /* (arbitrary value) */
ret = -EBUSY;
goto out;
}
@@ -792,6 +786,7 @@ static int dev_open(struct inode *inode, struct file *file)
else
gspca_dev->vdev.debug &= ~3;
#endif
+ ret = 0;
out:
mutex_unlock(&gspca_dev->queue_lock);
if (ret != 0)
@@ -812,11 +807,11 @@ static int dev_close(struct inode *inode, struct file *file)
/* if the file did the capture, free the streaming resources */
if (gspca_dev->capt_file == file) {
- mutex_lock(&gspca_dev->usb_lock);
- if (gspca_dev->streaming)
+ if (gspca_dev->streaming) {
+ mutex_lock(&gspca_dev->usb_lock);
gspca_stream_off(gspca_dev);
- gspca_dev->sd_desc->close(gspca_dev);
- mutex_unlock(&gspca_dev->usb_lock);
+ mutex_unlock(&gspca_dev->usb_lock);
+ }
frame_free(gspca_dev);
gspca_dev->capt_file = NULL;
gspca_dev->memory = GSPCA_MEMORY_NO;
@@ -853,42 +848,44 @@ static int vidioc_querycap(struct file *file, void *priv,
return 0;
}
-/* the use of V4L2_CTRL_FLAG_NEXT_CTRL asks for the controls to be sorted */
static int vidioc_queryctrl(struct file *file, void *priv,
struct v4l2_queryctrl *q_ctrl)
{
struct gspca_dev *gspca_dev = priv;
- int i;
+ int i, ix;
u32 id;
+ ix = -1;
id = q_ctrl->id;
if (id & V4L2_CTRL_FLAG_NEXT_CTRL) {
id &= V4L2_CTRL_ID_MASK;
id++;
for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) {
- if (id >= gspca_dev->sd_desc->ctrls[i].qctrl.id) {
- memcpy(q_ctrl,
- &gspca_dev->sd_desc->ctrls[i].qctrl,
- sizeof *q_ctrl);
- return 0;
+ if (gspca_dev->sd_desc->ctrls[i].qctrl.id < id)
+ continue;
+ if (ix < 0) {
+ ix = i;
+ continue;
}
+ if (gspca_dev->sd_desc->ctrls[i].qctrl.id
+ > gspca_dev->sd_desc->ctrls[ix].qctrl.id)
+ continue;
+ ix = i;
}
- return -EINVAL;
}
for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) {
if (id == gspca_dev->sd_desc->ctrls[i].qctrl.id) {
- memcpy(q_ctrl,
- &gspca_dev->sd_desc->ctrls[i].qctrl,
- sizeof *q_ctrl);
- return 0;
+ ix = i;
+ break;
}
}
- if (id >= V4L2_CID_BASE
- && id <= V4L2_CID_LASTP1) {
+ if (ix < 0)
+ return -EINVAL;
+ memcpy(q_ctrl, &gspca_dev->sd_desc->ctrls[ix].qctrl,
+ sizeof *q_ctrl);
+ if (gspca_dev->ctrl_dis & (1 << ix))
q_ctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
- return 0;
- }
- return -EINVAL;
+ return 0;
}
static int vidioc_s_ctrl(struct file *file, void *priv,
@@ -903,6 +900,8 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
i++, ctrls++) {
if (ctrl->id != ctrls->qctrl.id)
continue;
+ if (gspca_dev->ctrl_dis & (1 << i))
+ return -EINVAL;
if (ctrl->value < ctrls->qctrl.minimum
|| ctrl->value > ctrls->qctrl.maximum)
return -ERANGE;
@@ -929,6 +928,8 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
i++, ctrls++) {
if (ctrl->id != ctrls->qctrl.id)
continue;
+ if (gspca_dev->ctrl_dis & (1 << i))
+ return -EINVAL;
if (mutex_lock_interruptible(&gspca_dev->usb_lock))
return -ERESTARTSYS;
ret = ctrls->get(gspca_dev, &ctrl->value);
@@ -1403,7 +1404,7 @@ static int vidioc_dqbuf(struct file *file, void *priv,
i = ret; /* frame index */
frame = &gspca_dev->frame[i];
if (gspca_dev->memory == V4L2_MEMORY_USERPTR) {
- if (copy_to_user((__u8 *) frame->v4l2_buf.m.userptr,
+ if (copy_to_user((__u8 __user *) frame->v4l2_buf.m.userptr,
frame->data,
frame->v4l2_buf.bytesused)) {
PDEBUG(D_ERR|D_STREAM,
@@ -1731,6 +1732,12 @@ int gspca_dev_probe(struct usb_interface *intf,
err("couldn't kzalloc gspca struct");
return -EIO;
}
+ gspca_dev->usb_buf = kmalloc(USB_BUF_SZ, GFP_KERNEL);
+ if (!gspca_dev->usb_buf) {
+ err("out of memory");
+ ret = -EIO;
+ goto out;
+ }
gspca_dev->dev = dev;
gspca_dev->iface = interface->bInterfaceNumber;
gspca_dev->nbalt = intf->num_altsetting;
@@ -1738,10 +1745,13 @@ int gspca_dev_probe(struct usb_interface *intf,
/* gspca_dev->users = 0; (done by kzalloc) */
gspca_dev->nbufread = 2;
- /* configure the subdriver */
+ /* configure the subdriver and initialize the USB device */
ret = gspca_dev->sd_desc->config(gspca_dev, id);
if (ret < 0)
goto out;
+ ret = gspca_dev->sd_desc->init(gspca_dev);
+ if (ret < 0)
+ goto out;
ret = gspca_set_alt0(gspca_dev);
if (ret < 0)
goto out;
@@ -1771,6 +1781,7 @@ int gspca_dev_probe(struct usb_interface *intf,
PDEBUG(D_PROBE, "probe ok");
return 0;
out:
+ kfree(gspca_dev->usb_buf);
kfree(gspca_dev);
return ret;
}
@@ -1803,11 +1814,42 @@ void gspca_disconnect(struct usb_interface *intf)
/* We don't want people trying to open up the device */
video_unregister_device(&gspca_dev->vdev);
/* Free the memory */
+ kfree(gspca_dev->usb_buf);
kfree(gspca_dev);
PDEBUG(D_PROBE, "disconnect complete");
}
EXPORT_SYMBOL(gspca_disconnect);
+#ifdef CONFIG_PM
+int gspca_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
+
+ if (!gspca_dev->streaming)
+ return 0;
+ gspca_dev->frozen = 1; /* avoid urb error messages */
+ if (gspca_dev->sd_desc->stopN)
+ gspca_dev->sd_desc->stopN(gspca_dev);
+ destroy_urbs(gspca_dev);
+ gspca_set_alt0(gspca_dev);
+ if (gspca_dev->sd_desc->stop0)
+ gspca_dev->sd_desc->stop0(gspca_dev);
+ return 0;
+}
+EXPORT_SYMBOL(gspca_suspend);
+
+int gspca_resume(struct usb_interface *intf)
+{
+ struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
+
+ gspca_dev->frozen = 0;
+ gspca_dev->sd_desc->init(gspca_dev);
+ if (gspca_dev->streaming)
+ return gspca_init_transfer(gspca_dev);
+ return 0;
+}
+EXPORT_SYMBOL(gspca_resume);
+#endif
/* -- cam driver utility functions -- */
/* auto gain and exposure algorithm based on the knee algorithm described here:
diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h
index 67e448940ea..c17625cff9b 100644
--- a/drivers/media/video/gspca/gspca.h
+++ b/drivers/media/video/gspca/gspca.h
@@ -56,7 +56,6 @@ extern int gspca_debug;
/* device information - set at probe time */
struct cam {
- char *dev_name;
struct v4l2_pix_format *cam_mode; /* size nmodes */
char nmodes;
__u8 epaddr;
@@ -91,15 +90,14 @@ struct sd_desc {
/* controls */
const struct ctrl *ctrls;
int nctrls;
-/* operations */
+/* mandatory operations */
cam_cf_op config; /* called on probe */
- cam_op open; /* called on open */
+ cam_op init; /* called on probe and resume */
cam_v_op start; /* called on stream on */
- cam_v_op stopN; /* called on stream off - main alt */
- cam_v_op stop0; /* called on stream off - alt 0 */
- cam_v_op close; /* called on close */
cam_pkt_op pkt_scan;
/* optional operations */
+ cam_v_op stopN; /* called on stream off - main alt */
+ cam_v_op stop0; /* called on stream off - alt 0 */
cam_v_op dq_callback; /* called when a frame has been dequeued */
cam_jpg_op get_jcomp;
cam_jpg_op set_jcomp;
@@ -127,8 +125,10 @@ struct gspca_dev {
struct cam cam; /* device information */
const struct sd_desc *sd_desc; /* subdriver description */
+ unsigned ctrl_dis; /* disabled controls (bit map) */
- __u8 usb_buf[8]; /* buffer for USB exchanges */
+#define USB_BUF_SZ 64
+ __u8 *usb_buf; /* buffer for USB exchanges */
struct urb *urb[MAX_NURBS];
__u8 *frbuf; /* buffer for nframes */
@@ -155,6 +155,9 @@ struct gspca_dev {
struct mutex queue_lock; /* ISOC queue protection */
__u32 sequence; /* frame sequence number */
char streaming;
+#ifdef CONFIG_PM
+ char frozen; /* suspend - resume */
+#endif
char users; /* number of opens */
char present; /* device connected */
char nbufread; /* number of buffers for read() */
@@ -174,6 +177,10 @@ struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev,
struct gspca_frame *frame,
const __u8 *data,
int len);
+#ifdef CONFIG_PM
+int gspca_suspend(struct usb_interface *intf, pm_message_t message);
+int gspca_resume(struct usb_interface *intf);
+#endif
int gspca_auto_gain_n_exposure(struct gspca_dev *gspca_dev, int avg_lum,
int desired_avg_lum, int deadzone, int gain_knee, int exposure_knee);
#endif /* GSPCAV2_H */
diff --git a/drivers/media/video/gspca/mars.c b/drivers/media/video/gspca/mars.c
index 21c4ee56a10..4d5db47ba8c 100644
--- a/drivers/media/video/gspca/mars.c
+++ b/drivers/media/video/gspca/mars.c
@@ -100,22 +100,6 @@ static int reg_w(struct gspca_dev *gspca_dev,
return rc;
}
-static int reg_w_buf(struct gspca_dev *gspca_dev,
- __u16 index, __u8 *buf, int len)
-{
- int rc;
-
- rc = usb_control_msg(gspca_dev->dev,
- usb_sndbulkpipe(gspca_dev->dev, 4),
- 0x12,
- 0xc8, /* ?? */
- 0, /* value */
- index, buf, len, 500);
- if (rc < 0)
- PDEBUG(D_ERR, "reg write [%02x] error %d", index, rc);
- return rc;
-}
-
static void bulk_w(struct gspca_dev *gspca_dev,
__u16 *pch,
__u16 Address)
@@ -144,8 +128,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
return 0;
}
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
{
return 0;
}
@@ -175,7 +159,6 @@ static void sd_start(struct gspca_dev *gspca_dev)
/*
Initialize the MR97113 chip register
*/
- data = kmalloc(16, GFP_KERNEL);
data[0] = 0x00; /* address */
data[1] = 0x0c | 0x01; /* reg 0 */
data[2] = 0x01; /* reg 1 */
@@ -195,12 +178,10 @@ static void sd_start(struct gspca_dev *gspca_dev)
data[10] = 0x5d; /* reg 9, I2C device address
* [for PAS5101 (0x40)] [for MI (0x5d)] */
- err_code = reg_w_buf(gspca_dev, data[0], data, 11);
- kfree(data);
+ err_code = reg_w(gspca_dev, data[0], 11);
if (err_code < 0)
return;
- data = gspca_dev->usb_buf;
data[0] = 0x23; /* address */
data[1] = 0x09; /* reg 35, append frame header */
@@ -358,14 +339,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
PDEBUG(D_ERR, "Camera Stop failed");
}
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
-
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
struct gspca_frame *frame, /* target */
__u8 *data, /* isoc packet */
@@ -411,11 +384,9 @@ static const struct sd_desc sd_desc = {
.ctrls = sd_ctrls,
.nctrls = ARRAY_SIZE(sd_ctrls),
.config = sd_config,
- .open = sd_open,
+ .init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
- .stop0 = sd_stop0,
- .close = sd_close,
.pkt_scan = sd_pkt_scan,
};
@@ -439,6 +410,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
/* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c
index b4f00ec0885..4df4eec9f7e 100644
--- a/drivers/media/video/gspca/ov519.c
+++ b/drivers/media/video/gspca/ov519.c
@@ -63,11 +63,10 @@ struct sd {
#define SEN_OV6630 2
#define SEN_OV7610 3
#define SEN_OV7620 4
-#define SEN_OV7630 5
-#define SEN_OV7640 6
-#define SEN_OV7670 7
-#define SEN_OV76BE 8
-#define SEN_OV8610 9
+#define SEN_OV7640 5
+#define SEN_OV7670 6
+#define SEN_OV76BE 7
+#define SEN_OV8610 8
};
@@ -127,6 +126,7 @@ static struct ctrl sd_ctrls[] = {
.get = sd_getcolors,
},
/* next controls work with ov7670 only */
+#define HFLIP_IDX 3
{
{
.id = V4L2_CID_HFLIP,
@@ -141,6 +141,7 @@ static struct ctrl sd_ctrls[] = {
.set = sd_sethflip,
.get = sd_gethflip,
},
+#define VFLIP_IDX 4
{
{
.id = V4L2_CID_VFLIP,
@@ -293,6 +294,541 @@ static struct v4l2_pix_format sif_mode[] = {
#define OV7670_REG_HAECC7 0xaa /* Hist AEC/AGC control 7 */
#define OV7670_REG_BD60MAX 0xab /* 60hz banding step limit */
+struct ov_regvals {
+ __u8 reg;
+ __u8 val;
+};
+struct ov_i2c_regvals {
+ __u8 reg;
+ __u8 val;
+};
+
+static const struct ov_i2c_regvals norm_6x20[] = {
+ { 0x12, 0x80 }, /* reset */
+ { 0x11, 0x01 },
+ { 0x03, 0x60 },
+ { 0x05, 0x7f }, /* For when autoadjust is off */
+ { 0x07, 0xa8 },
+ /* The ratio of 0x0c and 0x0d controls the white point */
+ { 0x0c, 0x24 },
+ { 0x0d, 0x24 },
+ { 0x0f, 0x15 }, /* COMS */
+ { 0x10, 0x75 }, /* AEC Exposure time */
+ { 0x12, 0x24 }, /* Enable AGC */
+ { 0x14, 0x04 },
+ /* 0x16: 0x06 helps frame stability with moving objects */
+ { 0x16, 0x06 },
+/* { 0x20, 0x30 }, * Aperture correction enable */
+ { 0x26, 0xb2 }, /* BLC enable */
+ /* 0x28: 0x05 Selects RGB format if RGB on */
+ { 0x28, 0x05 },
+ { 0x2a, 0x04 }, /* Disable framerate adjust */
+/* { 0x2b, 0xac }, * Framerate; Set 2a[7] first */
+ { 0x2d, 0x99 },
+ { 0x33, 0xa0 }, /* Color Processing Parameter */
+ { 0x34, 0xd2 }, /* Max A/D range */
+ { 0x38, 0x8b },
+ { 0x39, 0x40 },
+
+ { 0x3c, 0x39 }, /* Enable AEC mode changing */
+ { 0x3c, 0x3c }, /* Change AEC mode */
+ { 0x3c, 0x24 }, /* Disable AEC mode changing */
+
+ { 0x3d, 0x80 },
+ /* These next two registers (0x4a, 0x4b) are undocumented.
+ * They control the color balance */
+ { 0x4a, 0x80 },
+ { 0x4b, 0x80 },
+ { 0x4d, 0xd2 }, /* This reduces noise a bit */
+ { 0x4e, 0xc1 },
+ { 0x4f, 0x04 },
+/* Do 50-53 have any effect? */
+/* Toggle 0x12[2] off and on here? */
+};
+
+static const struct ov_i2c_regvals norm_6x30[] = {
+ { 0x12, 0x80 }, /* Reset */
+ { 0x00, 0x1f }, /* Gain */
+ { 0x01, 0x99 }, /* Blue gain */
+ { 0x02, 0x7c }, /* Red gain */
+ { 0x03, 0xc0 }, /* Saturation */
+ { 0x05, 0x0a }, /* Contrast */
+ { 0x06, 0x95 }, /* Brightness */
+ { 0x07, 0x2d }, /* Sharpness */
+ { 0x0c, 0x20 },
+ { 0x0d, 0x20 },
+ { 0x0e, 0x20 },
+ { 0x0f, 0x05 },
+ { 0x10, 0x9a },
+ { 0x11, 0x00 }, /* Pixel clock = fastest */
+ { 0x12, 0x24 }, /* Enable AGC and AWB */
+ { 0x13, 0x21 },
+ { 0x14, 0x80 },
+ { 0x15, 0x01 },
+ { 0x16, 0x03 },
+ { 0x17, 0x38 },
+ { 0x18, 0xea },
+ { 0x19, 0x04 },
+ { 0x1a, 0x93 },
+ { 0x1b, 0x00 },
+ { 0x1e, 0xc4 },
+ { 0x1f, 0x04 },
+ { 0x20, 0x20 },
+ { 0x21, 0x10 },
+ { 0x22, 0x88 },
+ { 0x23, 0xc0 }, /* Crystal circuit power level */
+ { 0x25, 0x9a }, /* Increase AEC black ratio */
+ { 0x26, 0xb2 }, /* BLC enable */
+ { 0x27, 0xa2 },
+ { 0x28, 0x00 },
+ { 0x29, 0x00 },
+ { 0x2a, 0x84 }, /* 60 Hz power */
+ { 0x2b, 0xa8 }, /* 60 Hz power */
+ { 0x2c, 0xa0 },
+ { 0x2d, 0x95 }, /* Enable auto-brightness */
+ { 0x2e, 0x88 },
+ { 0x33, 0x26 },
+ { 0x34, 0x03 },
+ { 0x36, 0x8f },
+ { 0x37, 0x80 },
+ { 0x38, 0x83 },
+ { 0x39, 0x80 },
+ { 0x3a, 0x0f },
+ { 0x3b, 0x3c },
+ { 0x3c, 0x1a },
+ { 0x3d, 0x80 },
+ { 0x3e, 0x80 },
+ { 0x3f, 0x0e },
+ { 0x40, 0x00 }, /* White bal */
+ { 0x41, 0x00 }, /* White bal */
+ { 0x42, 0x80 },
+ { 0x43, 0x3f }, /* White bal */
+ { 0x44, 0x80 },
+ { 0x45, 0x20 },
+ { 0x46, 0x20 },
+ { 0x47, 0x80 },
+ { 0x48, 0x7f },
+ { 0x49, 0x00 },
+ { 0x4a, 0x00 },
+ { 0x4b, 0x80 },
+ { 0x4c, 0xd0 },
+ { 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */
+ { 0x4e, 0x40 },
+ { 0x4f, 0x07 }, /* UV avg., col. killer: max */
+ { 0x50, 0xff },
+ { 0x54, 0x23 }, /* Max AGC gain: 18dB */
+ { 0x55, 0xff },
+ { 0x56, 0x12 },
+ { 0x57, 0x81 },
+ { 0x58, 0x75 },
+ { 0x59, 0x01 }, /* AGC dark current comp.: +1 */
+ { 0x5a, 0x2c },
+ { 0x5b, 0x0f }, /* AWB chrominance levels */
+ { 0x5c, 0x10 },
+ { 0x3d, 0x80 },
+ { 0x27, 0xa6 },
+ { 0x12, 0x20 }, /* Toggle AWB */
+ { 0x12, 0x24 },
+};
+
+/* Lawrence Glaister <lg@jfm.bc.ca> reports:
+ *
+ * Register 0x0f in the 7610 has the following effects:
+ *
+ * 0x85 (AEC method 1): Best overall, good contrast range
+ * 0x45 (AEC method 2): Very overexposed
+ * 0xa5 (spec sheet default): Ok, but the black level is
+ * shifted resulting in loss of contrast
+ * 0x05 (old driver setting): very overexposed, too much
+ * contrast
+ */
+static const struct ov_i2c_regvals norm_7610[] = {
+ { 0x10, 0xff },
+ { 0x16, 0x06 },
+ { 0x28, 0x24 },
+ { 0x2b, 0xac },
+ { 0x12, 0x00 },
+ { 0x38, 0x81 },
+ { 0x28, 0x24 }, /* 0c */
+ { 0x0f, 0x85 }, /* lg's setting */
+ { 0x15, 0x01 },
+ { 0x20, 0x1c },
+ { 0x23, 0x2a },
+ { 0x24, 0x10 },
+ { 0x25, 0x8a },
+ { 0x26, 0xa2 },
+ { 0x27, 0xc2 },
+ { 0x2a, 0x04 },
+ { 0x2c, 0xfe },
+ { 0x2d, 0x93 },
+ { 0x30, 0x71 },
+ { 0x31, 0x60 },
+ { 0x32, 0x26 },
+ { 0x33, 0x20 },
+ { 0x34, 0x48 },
+ { 0x12, 0x24 },
+ { 0x11, 0x01 },
+ { 0x0c, 0x24 },
+ { 0x0d, 0x24 },
+};
+
+static const struct ov_i2c_regvals norm_7620[] = {
+ { 0x00, 0x00 }, /* gain */
+ { 0x01, 0x80 }, /* blue gain */
+ { 0x02, 0x80 }, /* red gain */
+ { 0x03, 0xc0 }, /* OV7670_REG_VREF */
+ { 0x06, 0x60 },
+ { 0x07, 0x00 },
+ { 0x0c, 0x24 },
+ { 0x0c, 0x24 },
+ { 0x0d, 0x24 },
+ { 0x11, 0x01 },
+ { 0x12, 0x24 },
+ { 0x13, 0x01 },
+ { 0x14, 0x84 },
+ { 0x15, 0x01 },
+ { 0x16, 0x03 },
+ { 0x17, 0x2f },
+ { 0x18, 0xcf },
+ { 0x19, 0x06 },
+ { 0x1a, 0xf5 },
+ { 0x1b, 0x00 },
+ { 0x20, 0x18 },
+ { 0x21, 0x80 },
+ { 0x22, 0x80 },
+ { 0x23, 0x00 },
+ { 0x26, 0xa2 },
+ { 0x27, 0xea },
+ { 0x28, 0x20 },
+ { 0x29, 0x00 },
+ { 0x2a, 0x10 },
+ { 0x2b, 0x00 },
+ { 0x2c, 0x88 },
+ { 0x2d, 0x91 },
+ { 0x2e, 0x80 },
+ { 0x2f, 0x44 },
+ { 0x60, 0x27 },
+ { 0x61, 0x02 },
+ { 0x62, 0x5f },
+ { 0x63, 0xd5 },
+ { 0x64, 0x57 },
+ { 0x65, 0x83 },
+ { 0x66, 0x55 },
+ { 0x67, 0x92 },
+ { 0x68, 0xcf },
+ { 0x69, 0x76 },
+ { 0x6a, 0x22 },
+ { 0x6b, 0x00 },
+ { 0x6c, 0x02 },
+ { 0x6d, 0x44 },
+ { 0x6e, 0x80 },
+ { 0x6f, 0x1d },
+ { 0x70, 0x8b },
+ { 0x71, 0x00 },
+ { 0x72, 0x14 },
+ { 0x73, 0x54 },
+ { 0x74, 0x00 },
+ { 0x75, 0x8e },
+ { 0x76, 0x00 },
+ { 0x77, 0xff },
+ { 0x78, 0x80 },
+ { 0x79, 0x80 },
+ { 0x7a, 0x80 },
+ { 0x7b, 0xe2 },
+ { 0x7c, 0x00 },
+};
+
+/* 7640 and 7648. The defaults should be OK for most registers. */
+static const struct ov_i2c_regvals norm_7640[] = {
+ { 0x12, 0x80 },
+ { 0x12, 0x14 },
+};
+
+/* 7670. Defaults taken from OmniVision provided data,
+* as provided by Jonathan Corbet of OLPC */
+static const struct ov_i2c_regvals norm_7670[] = {
+ { OV7670_REG_COM7, OV7670_COM7_RESET },
+ { OV7670_REG_TSLB, 0x04 }, /* OV */
+ { OV7670_REG_COM7, OV7670_COM7_FMT_VGA }, /* VGA */
+ { OV7670_REG_CLKRC, 0x01 },
+/*
+ * Set the hardware window. These values from OV don't entirely
+ * make sense - hstop is less than hstart. But they work...
+ */
+ { OV7670_REG_HSTART, 0x13 },
+ { OV7670_REG_HSTOP, 0x01 },
+ { OV7670_REG_HREF, 0xb6 },
+ { OV7670_REG_VSTART, 0x02 },
+ { OV7670_REG_VSTOP, 0x7a },
+ { OV7670_REG_VREF, 0x0a },
+
+ { OV7670_REG_COM3, 0 },
+ { OV7670_REG_COM14, 0 },
+/* Mystery scaling numbers */
+ { 0x70, 0x3a },
+ { 0x71, 0x35 },
+ { 0x72, 0x11 },
+ { 0x73, 0xf0 },
+ { 0xa2, 0x02 },
+/* { OV7670_REG_COM10, 0x0 }, */
+
+/* Gamma curve values */
+ { 0x7a, 0x20 },
+ { 0x7b, 0x10 },
+ { 0x7c, 0x1e },
+ { 0x7d, 0x35 },
+ { 0x7e, 0x5a },
+ { 0x7f, 0x69 },
+ { 0x80, 0x76 },
+ { 0x81, 0x80 },
+ { 0x82, 0x88 },
+ { 0x83, 0x8f },
+ { 0x84, 0x96 },
+ { 0x85, 0xa3 },
+ { 0x86, 0xaf },
+ { 0x87, 0xc4 },
+ { 0x88, 0xd7 },
+ { 0x89, 0xe8 },
+
+/* AGC and AEC parameters. Note we start by disabling those features,
+ then turn them only after tweaking the values. */
+ { OV7670_REG_COM8, OV7670_COM8_FASTAEC
+ | OV7670_COM8_AECSTEP
+ | OV7670_COM8_BFILT },
+ { OV7670_REG_GAIN, 0 },
+ { OV7670_REG_AECH, 0 },
+ { OV7670_REG_COM4, 0x40 }, /* magic reserved bit */
+ { OV7670_REG_COM9, 0x18 }, /* 4x gain + magic rsvd bit */
+ { OV7670_REG_BD50MAX, 0x05 },
+ { OV7670_REG_BD60MAX, 0x07 },
+ { OV7670_REG_AEW, 0x95 },
+ { OV7670_REG_AEB, 0x33 },
+ { OV7670_REG_VPT, 0xe3 },
+ { OV7670_REG_HAECC1, 0x78 },
+ { OV7670_REG_HAECC2, 0x68 },
+ { 0xa1, 0x03 }, /* magic */
+ { OV7670_REG_HAECC3, 0xd8 },
+ { OV7670_REG_HAECC4, 0xd8 },
+ { OV7670_REG_HAECC5, 0xf0 },
+ { OV7670_REG_HAECC6, 0x90 },
+ { OV7670_REG_HAECC7, 0x94 },
+ { OV7670_REG_COM8, OV7670_COM8_FASTAEC
+ | OV7670_COM8_AECSTEP
+ | OV7670_COM8_BFILT
+ | OV7670_COM8_AGC
+ | OV7670_COM8_AEC },
+
+/* Almost all of these are magic "reserved" values. */
+ { OV7670_REG_COM5, 0x61 },
+ { OV7670_REG_COM6, 0x4b },
+ { 0x16, 0x02 },
+ { OV7670_REG_MVFP, 0x07 },
+ { 0x21, 0x02 },
+ { 0x22, 0x91 },
+ { 0x29, 0x07 },
+ { 0x33, 0x0b },
+ { 0x35, 0x0b },
+ { 0x37, 0x1d },
+ { 0x38, 0x71 },
+ { 0x39, 0x2a },
+ { OV7670_REG_COM12, 0x78 },
+ { 0x4d, 0x40 },
+ { 0x4e, 0x20 },
+ { OV7670_REG_GFIX, 0 },
+ { 0x6b, 0x4a },
+ { 0x74, 0x10 },
+ { 0x8d, 0x4f },
+ { 0x8e, 0 },
+ { 0x8f, 0 },
+ { 0x90, 0 },
+ { 0x91, 0 },
+ { 0x96, 0 },
+ { 0x9a, 0 },
+ { 0xb0, 0x84 },
+ { 0xb1, 0x0c },
+ { 0xb2, 0x0e },
+ { 0xb3, 0x82 },
+ { 0xb8, 0x0a },
+
+/* More reserved magic, some of which tweaks white balance */
+ { 0x43, 0x0a },
+ { 0x44, 0xf0 },
+ { 0x45, 0x34 },
+ { 0x46, 0x58 },
+ { 0x47, 0x28 },
+ { 0x48, 0x3a },
+ { 0x59, 0x88 },
+ { 0x5a, 0x88 },
+ { 0x5b, 0x44 },
+ { 0x5c, 0x67 },
+ { 0x5d, 0x49 },
+ { 0x5e, 0x0e },
+ { 0x6c, 0x0a },
+ { 0x6d, 0x55 },
+ { 0x6e, 0x11 },
+ { 0x6f, 0x9f },
+ /* "9e for advance AWB" */
+ { 0x6a, 0x40 },
+ { OV7670_REG_BLUE, 0x40 },
+ { OV7670_REG_RED, 0x60 },
+ { OV7670_REG_COM8, OV7670_COM8_FASTAEC
+ | OV7670_COM8_AECSTEP
+ | OV7670_COM8_BFILT
+ | OV7670_COM8_AGC
+ | OV7670_COM8_AEC
+ | OV7670_COM8_AWB },
+
+/* Matrix coefficients */
+ { 0x4f, 0x80 },
+ { 0x50, 0x80 },
+ { 0x51, 0 },
+ { 0x52, 0x22 },
+ { 0x53, 0x5e },
+ { 0x54, 0x80 },
+ { 0x58, 0x9e },
+
+ { OV7670_REG_COM16, OV7670_COM16_AWBGAIN },
+ { OV7670_REG_EDGE, 0 },
+ { 0x75, 0x05 },
+ { 0x76, 0xe1 },
+ { 0x4c, 0 },
+ { 0x77, 0x01 },
+ { OV7670_REG_COM13, OV7670_COM13_GAMMA
+ | OV7670_COM13_UVSAT
+ | 2}, /* was 3 */
+ { 0x4b, 0x09 },
+ { 0xc9, 0x60 },
+ { OV7670_REG_COM16, 0x38 },
+ { 0x56, 0x40 },
+
+ { 0x34, 0x11 },
+ { OV7670_REG_COM11, OV7670_COM11_EXP|OV7670_COM11_HZAUTO },
+ { 0xa4, 0x88 },
+ { 0x96, 0 },
+ { 0x97, 0x30 },
+ { 0x98, 0x20 },
+ { 0x99, 0x30 },
+ { 0x9a, 0x84 },
+ { 0x9b, 0x29 },
+ { 0x9c, 0x03 },
+ { 0x9d, 0x4c },
+ { 0x9e, 0x3f },
+ { 0x78, 0x04 },
+
+/* Extra-weird stuff. Some sort of multiplexor register */
+ { 0x79, 0x01 },
+ { 0xc8, 0xf0 },
+ { 0x79, 0x0f },
+ { 0xc8, 0x00 },
+ { 0x79, 0x10 },
+ { 0xc8, 0x7e },
+ { 0x79, 0x0a },
+ { 0xc8, 0x80 },
+ { 0x79, 0x0b },
+ { 0xc8, 0x01 },
+ { 0x79, 0x0c },
+ { 0xc8, 0x0f },
+ { 0x79, 0x0d },
+ { 0xc8, 0x20 },
+ { 0x79, 0x09 },
+ { 0xc8, 0x80 },
+ { 0x79, 0x02 },
+ { 0xc8, 0xc0 },
+ { 0x79, 0x03 },
+ { 0xc8, 0x40 },
+ { 0x79, 0x05 },
+ { 0xc8, 0x30 },
+ { 0x79, 0x26 },
+};
+
+static const struct ov_i2c_regvals norm_8610[] = {
+ { 0x12, 0x80 },
+ { 0x00, 0x00 },
+ { 0x01, 0x80 },
+ { 0x02, 0x80 },
+ { 0x03, 0xc0 },
+ { 0x04, 0x30 },
+ { 0x05, 0x30 }, /* was 0x10, new from windrv 090403 */
+ { 0x06, 0x70 }, /* was 0x80, new from windrv 090403 */
+ { 0x0a, 0x86 },
+ { 0x0b, 0xb0 },
+ { 0x0c, 0x20 },
+ { 0x0d, 0x20 },
+ { 0x11, 0x01 },
+ { 0x12, 0x25 },
+ { 0x13, 0x01 },
+ { 0x14, 0x04 },
+ { 0x15, 0x01 }, /* Lin and Win think different about UV order */
+ { 0x16, 0x03 },
+ { 0x17, 0x38 }, /* was 0x2f, new from windrv 090403 */
+ { 0x18, 0xea }, /* was 0xcf, new from windrv 090403 */
+ { 0x19, 0x02 }, /* was 0x06, new from windrv 090403 */
+ { 0x1a, 0xf5 },
+ { 0x1b, 0x00 },
+ { 0x20, 0xd0 }, /* was 0x90, new from windrv 090403 */
+ { 0x23, 0xc0 }, /* was 0x00, new from windrv 090403 */
+ { 0x24, 0x30 }, /* was 0x1d, new from windrv 090403 */
+ { 0x25, 0x50 }, /* was 0x57, new from windrv 090403 */
+ { 0x26, 0xa2 },
+ { 0x27, 0xea },
+ { 0x28, 0x00 },
+ { 0x29, 0x00 },
+ { 0x2a, 0x80 },
+ { 0x2b, 0xc8 }, /* was 0xcc, new from windrv 090403 */
+ { 0x2c, 0xac },
+ { 0x2d, 0x45 }, /* was 0xd5, new from windrv 090403 */
+ { 0x2e, 0x80 },
+ { 0x2f, 0x14 }, /* was 0x01, new from windrv 090403 */
+ { 0x4c, 0x00 },
+ { 0x4d, 0x30 }, /* was 0x10, new from windrv 090403 */
+ { 0x60, 0x02 }, /* was 0x01, new from windrv 090403 */
+ { 0x61, 0x00 }, /* was 0x09, new from windrv 090403 */
+ { 0x62, 0x5f }, /* was 0xd7, new from windrv 090403 */
+ { 0x63, 0xff },
+ { 0x64, 0x53 }, /* new windrv 090403 says 0x57,
+ * maybe thats wrong */
+ { 0x65, 0x00 },
+ { 0x66, 0x55 },
+ { 0x67, 0xb0 },
+ { 0x68, 0xc0 }, /* was 0xaf, new from windrv 090403 */
+ { 0x69, 0x02 },
+ { 0x6a, 0x22 },
+ { 0x6b, 0x00 },
+ { 0x6c, 0x99 }, /* was 0x80, old windrv says 0x00, but
+ * deleting bit7 colors the first images red */
+ { 0x6d, 0x11 }, /* was 0x00, new from windrv 090403 */
+ { 0x6e, 0x11 }, /* was 0x00, new from windrv 090403 */
+ { 0x6f, 0x01 },
+ { 0x70, 0x8b },
+ { 0x71, 0x00 },
+ { 0x72, 0x14 },
+ { 0x73, 0x54 },
+ { 0x74, 0x00 },/* 0x60? - was 0x00, new from windrv 090403 */
+ { 0x75, 0x0e },
+ { 0x76, 0x02 }, /* was 0x02, new from windrv 090403 */
+ { 0x77, 0xff },
+ { 0x78, 0x80 },
+ { 0x79, 0x80 },
+ { 0x7a, 0x80 },
+ { 0x7b, 0x10 }, /* was 0x13, new from windrv 090403 */
+ { 0x7c, 0x00 },
+ { 0x7d, 0x08 }, /* was 0x09, new from windrv 090403 */
+ { 0x7e, 0x08 }, /* was 0xc0, new from windrv 090403 */
+ { 0x7f, 0xfb },
+ { 0x80, 0x28 },
+ { 0x81, 0x00 },
+ { 0x82, 0x23 },
+ { 0x83, 0x0b },
+ { 0x84, 0x00 },
+ { 0x85, 0x62 }, /* was 0x61, new from windrv 090403 */
+ { 0x86, 0xc9 },
+ { 0x87, 0x00 },
+ { 0x88, 0x00 },
+ { 0x89, 0x01 },
+ { 0x12, 0x20 },
+ { 0x12, 0x25 }, /* was 0x24, new from windrv 090403 */
+};
+
static unsigned char ov7670_abs_to_sm(unsigned char v)
{
if (v > 127)
@@ -537,18 +1073,10 @@ static int ov51x_set_slave_ids(struct sd *sd,
rc = reg_w(sd, R51x_I2C_W_SID, slave);
if (rc < 0)
return rc;
+ sd->primary_i2c_slave = slave;
return reg_w(sd, R51x_I2C_R_SID, slave + 1);
}
-struct ov_regvals {
- __u8 reg;
- __u8 val;
-};
-struct ov_i2c_regvals {
- __u8 reg;
- __u8 val;
-};
-
static int write_regvals(struct sd *sd,
const struct ov_regvals *regvals,
int n)
@@ -591,101 +1119,9 @@ static int write_i2c_regvals(struct sd *sd,
static int ov8xx0_configure(struct sd *sd)
{
int rc;
- static const struct ov_i2c_regvals norm_8610[] = {
- { 0x12, 0x80 },
- { 0x00, 0x00 },
- { 0x01, 0x80 },
- { 0x02, 0x80 },
- { 0x03, 0xc0 },
- { 0x04, 0x30 },
- { 0x05, 0x30 }, /* was 0x10, new from windrv 090403 */
- { 0x06, 0x70 }, /* was 0x80, new from windrv 090403 */
- { 0x0a, 0x86 },
- { 0x0b, 0xb0 },
- { 0x0c, 0x20 },
- { 0x0d, 0x20 },
- { 0x11, 0x01 },
- { 0x12, 0x25 },
- { 0x13, 0x01 },
- { 0x14, 0x04 },
- { 0x15, 0x01 }, /* Lin and Win think different about UV order */
- { 0x16, 0x03 },
- { 0x17, 0x38 }, /* was 0x2f, new from windrv 090403 */
- { 0x18, 0xea }, /* was 0xcf, new from windrv 090403 */
- { 0x19, 0x02 }, /* was 0x06, new from windrv 090403 */
- { 0x1a, 0xf5 },
- { 0x1b, 0x00 },
- { 0x20, 0xd0 }, /* was 0x90, new from windrv 090403 */
- { 0x23, 0xc0 }, /* was 0x00, new from windrv 090403 */
- { 0x24, 0x30 }, /* was 0x1d, new from windrv 090403 */
- { 0x25, 0x50 }, /* was 0x57, new from windrv 090403 */
- { 0x26, 0xa2 },
- { 0x27, 0xea },
- { 0x28, 0x00 },
- { 0x29, 0x00 },
- { 0x2a, 0x80 },
- { 0x2b, 0xc8 }, /* was 0xcc, new from windrv 090403 */
- { 0x2c, 0xac },
- { 0x2d, 0x45 }, /* was 0xd5, new from windrv 090403 */
- { 0x2e, 0x80 },
- { 0x2f, 0x14 }, /* was 0x01, new from windrv 090403 */
- { 0x4c, 0x00 },
- { 0x4d, 0x30 }, /* was 0x10, new from windrv 090403 */
- { 0x60, 0x02 }, /* was 0x01, new from windrv 090403 */
- { 0x61, 0x00 }, /* was 0x09, new from windrv 090403 */
- { 0x62, 0x5f }, /* was 0xd7, new from windrv 090403 */
- { 0x63, 0xff },
- { 0x64, 0x53 }, /* new windrv 090403 says 0x57,
- * maybe thats wrong */
- { 0x65, 0x00 },
- { 0x66, 0x55 },
- { 0x67, 0xb0 },
- { 0x68, 0xc0 }, /* was 0xaf, new from windrv 090403 */
- { 0x69, 0x02 },
- { 0x6a, 0x22 },
- { 0x6b, 0x00 },
- { 0x6c, 0x99 }, /* was 0x80, old windrv says 0x00, but
- deleting bit7 colors the first images red */
- { 0x6d, 0x11 }, /* was 0x00, new from windrv 090403 */
- { 0x6e, 0x11 }, /* was 0x00, new from windrv 090403 */
- { 0x6f, 0x01 },
- { 0x70, 0x8b },
- { 0x71, 0x00 },
- { 0x72, 0x14 },
- { 0x73, 0x54 },
- { 0x74, 0x00 },/* 0x60? - was 0x00, new from windrv 090403 */
- { 0x75, 0x0e },
- { 0x76, 0x02 }, /* was 0x02, new from windrv 090403 */
- { 0x77, 0xff },
- { 0x78, 0x80 },
- { 0x79, 0x80 },
- { 0x7a, 0x80 },
- { 0x7b, 0x10 }, /* was 0x13, new from windrv 090403 */
- { 0x7c, 0x00 },
- { 0x7d, 0x08 }, /* was 0x09, new from windrv 090403 */
- { 0x7e, 0x08 }, /* was 0xc0, new from windrv 090403 */
- { 0x7f, 0xfb },
- { 0x80, 0x28 },
- { 0x81, 0x00 },
- { 0x82, 0x23 },
- { 0x83, 0x0b },
- { 0x84, 0x00 },
- { 0x85, 0x62 }, /* was 0x61, new from windrv 090403 */
- { 0x86, 0xc9 },
- { 0x87, 0x00 },
- { 0x88, 0x00 },
- { 0x89, 0x01 },
- { 0x12, 0x20 },
- { 0x12, 0x25 }, /* was 0x24, new from windrv 090403 */
- };
PDEBUG(D_PROBE, "starting ov8xx0 configuration");
- if (init_ov_sensor(sd) < 0)
- PDEBUG(D_ERR|D_PROBE, "Failed to read sensor ID");
- else
- PDEBUG(D_PROBE, "OV86x0 initialized");
-
/* Detect sensor (sub)type */
rc = i2c_r(sd, OV7610_REG_COM_I);
if (rc < 0) {
@@ -698,9 +1134,6 @@ static int ov8xx0_configure(struct sd *sd)
PDEBUG(D_ERR, "Unknown image sensor version: %d", rc & 3);
return -1;
}
- PDEBUG(D_PROBE, "Writing 8610 registers");
- if (write_i2c_regvals(sd, norm_8610, ARRAY_SIZE(norm_8610)))
- return -1;
/* Set sensor-specific vars */
/* sd->sif = 0; already done */
@@ -714,252 +1147,6 @@ static int ov7xx0_configure(struct sd *sd)
{
int rc, high, low;
- /* Lawrence Glaister <lg@jfm.bc.ca> reports:
- *
- * Register 0x0f in the 7610 has the following effects:
- *
- * 0x85 (AEC method 1): Best overall, good contrast range
- * 0x45 (AEC method 2): Very overexposed
- * 0xa5 (spec sheet default): Ok, but the black level is
- * shifted resulting in loss of contrast
- * 0x05 (old driver setting): very overexposed, too much
- * contrast
- */
- static const struct ov_i2c_regvals norm_7610[] = {
- { 0x10, 0xff },
- { 0x16, 0x06 },
- { 0x28, 0x24 },
- { 0x2b, 0xac },
- { 0x12, 0x00 },
- { 0x38, 0x81 },
- { 0x28, 0x24 }, /* 0c */
- { 0x0f, 0x85 }, /* lg's setting */
- { 0x15, 0x01 },
- { 0x20, 0x1c },
- { 0x23, 0x2a },
- { 0x24, 0x10 },
- { 0x25, 0x8a },
- { 0x26, 0xa2 },
- { 0x27, 0xc2 },
- { 0x2a, 0x04 },
- { 0x2c, 0xfe },
- { 0x2d, 0x93 },
- { 0x30, 0x71 },
- { 0x31, 0x60 },
- { 0x32, 0x26 },
- { 0x33, 0x20 },
- { 0x34, 0x48 },
- { 0x12, 0x24 },
- { 0x11, 0x01 },
- { 0x0c, 0x24 },
- { 0x0d, 0x24 },
- };
-
- static const struct ov_i2c_regvals norm_7620[] = {
- { 0x00, 0x00 }, /* gain */
- { 0x01, 0x80 }, /* blue gain */
- { 0x02, 0x80 }, /* red gain */
- { 0x03, 0xc0 }, /* OV7670_REG_VREF */
- { 0x06, 0x60 },
- { 0x07, 0x00 },
- { 0x0c, 0x24 },
- { 0x0c, 0x24 },
- { 0x0d, 0x24 },
- { 0x11, 0x01 },
- { 0x12, 0x24 },
- { 0x13, 0x01 },
- { 0x14, 0x84 },
- { 0x15, 0x01 },
- { 0x16, 0x03 },
- { 0x17, 0x2f },
- { 0x18, 0xcf },
- { 0x19, 0x06 },
- { 0x1a, 0xf5 },
- { 0x1b, 0x00 },
- { 0x20, 0x18 },
- { 0x21, 0x80 },
- { 0x22, 0x80 },
- { 0x23, 0x00 },
- { 0x26, 0xa2 },
- { 0x27, 0xea },
- { 0x28, 0x20 },
- { 0x29, 0x00 },
- { 0x2a, 0x10 },
- { 0x2b, 0x00 },
- { 0x2c, 0x88 },
- { 0x2d, 0x91 },
- { 0x2e, 0x80 },
- { 0x2f, 0x44 },
- { 0x60, 0x27 },
- { 0x61, 0x02 },
- { 0x62, 0x5f },
- { 0x63, 0xd5 },
- { 0x64, 0x57 },
- { 0x65, 0x83 },
- { 0x66, 0x55 },
- { 0x67, 0x92 },
- { 0x68, 0xcf },
- { 0x69, 0x76 },
- { 0x6a, 0x22 },
- { 0x6b, 0x00 },
- { 0x6c, 0x02 },
- { 0x6d, 0x44 },
- { 0x6e, 0x80 },
- { 0x6f, 0x1d },
- { 0x70, 0x8b },
- { 0x71, 0x00 },
- { 0x72, 0x14 },
- { 0x73, 0x54 },
- { 0x74, 0x00 },
- { 0x75, 0x8e },
- { 0x76, 0x00 },
- { 0x77, 0xff },
- { 0x78, 0x80 },
- { 0x79, 0x80 },
- { 0x7a, 0x80 },
- { 0x7b, 0xe2 },
- { 0x7c, 0x00 },
- };
-
- /* 7640 and 7648. The defaults should be OK for most registers. */
- static const struct ov_i2c_regvals norm_7640[] = {
- { 0x12, 0x80 },
- { 0x12, 0x14 },
- };
-
- /* 7670. Defaults taken from OmniVision provided data,
- * as provided by Jonathan Corbet of OLPC */
- static const struct ov_i2c_regvals norm_7670[] = {
- { OV7670_REG_COM7, OV7670_COM7_RESET },
- { OV7670_REG_TSLB, 0x04 }, /* OV */
- { OV7670_REG_COM7, OV7670_COM7_FMT_VGA }, /* VGA */
- { OV7670_REG_CLKRC, 0x01 },
- /*
- * Set the hardware window. These values from OV don't entirely
- * make sense - hstop is less than hstart. But they work...
- */
- { OV7670_REG_HSTART, 0x13 }, { OV7670_REG_HSTOP, 0x01 },
- { OV7670_REG_HREF, 0xb6 }, { OV7670_REG_VSTART, 0x02 },
- { OV7670_REG_VSTOP, 0x7a }, { OV7670_REG_VREF, 0x0a },
-
- { OV7670_REG_COM3, 0 }, { OV7670_REG_COM14, 0 },
- /* Mystery scaling numbers */
- { 0x70, 0x3a }, { 0x71, 0x35 },
- { 0x72, 0x11 }, { 0x73, 0xf0 },
- { 0xa2, 0x02 },
-/* { OV7670_REG_COM10, 0x0 }, */
-
- /* Gamma curve values */
- { 0x7a, 0x20 },
- { 0x7b, 0x10 },
- { 0x7c, 0x1e },
- { 0x7d, 0x35 },
- { 0x7e, 0x5a }, { 0x7f, 0x69 },
- { 0x80, 0x76 }, { 0x81, 0x80 },
- { 0x82, 0x88 }, { 0x83, 0x8f },
- { 0x84, 0x96 }, { 0x85, 0xa3 },
- { 0x86, 0xaf }, { 0x87, 0xc4 },
- { 0x88, 0xd7 }, { 0x89, 0xe8 },
-
- /* AGC and AEC parameters. Note we start by disabling those features,
- then turn them only after tweaking the values. */
- { OV7670_REG_COM8, OV7670_COM8_FASTAEC
- | OV7670_COM8_AECSTEP
- | OV7670_COM8_BFILT },
- { OV7670_REG_GAIN, 0 }, { OV7670_REG_AECH, 0 },
- { OV7670_REG_COM4, 0x40 }, /* magic reserved bit */
- { OV7670_REG_COM9, 0x18 }, /* 4x gain + magic rsvd bit */
- { OV7670_REG_BD50MAX, 0x05 }, { OV7670_REG_BD60MAX, 0x07 },
- { OV7670_REG_AEW, 0x95 }, { OV7670_REG_AEB, 0x33 },
- { OV7670_REG_VPT, 0xe3 }, { OV7670_REG_HAECC1, 0x78 },
- { OV7670_REG_HAECC2, 0x68 },
- { 0xa1, 0x03 }, /* magic */
- { OV7670_REG_HAECC3, 0xd8 }, { OV7670_REG_HAECC4, 0xd8 },
- { OV7670_REG_HAECC5, 0xf0 }, { OV7670_REG_HAECC6, 0x90 },
- { OV7670_REG_HAECC7, 0x94 },
- { OV7670_REG_COM8, OV7670_COM8_FASTAEC
- | OV7670_COM8_AECSTEP
- | OV7670_COM8_BFILT
- | OV7670_COM8_AGC
- | OV7670_COM8_AEC },
-
- /* Almost all of these are magic "reserved" values. */
- { OV7670_REG_COM5, 0x61 }, { OV7670_REG_COM6, 0x4b },
- { 0x16, 0x02 },
- { OV7670_REG_MVFP, 0x07 },
- { 0x21, 0x02 }, { 0x22, 0x91 },
- { 0x29, 0x07 }, { 0x33, 0x0b },
- { 0x35, 0x0b }, { 0x37, 0x1d },
- { 0x38, 0x71 }, { 0x39, 0x2a },
- { OV7670_REG_COM12, 0x78 }, { 0x4d, 0x40 },
- { 0x4e, 0x20 }, { OV7670_REG_GFIX, 0 },
- { 0x6b, 0x4a }, { 0x74, 0x10 },
- { 0x8d, 0x4f }, { 0x8e, 0 },
- { 0x8f, 0 }, { 0x90, 0 },
- { 0x91, 0 }, { 0x96, 0 },
- { 0x9a, 0 }, { 0xb0, 0x84 },
- { 0xb1, 0x0c }, { 0xb2, 0x0e },
- { 0xb3, 0x82 }, { 0xb8, 0x0a },
-
- /* More reserved magic, some of which tweaks white balance */
- { 0x43, 0x0a }, { 0x44, 0xf0 },
- { 0x45, 0x34 }, { 0x46, 0x58 },
- { 0x47, 0x28 }, { 0x48, 0x3a },
- { 0x59, 0x88 }, { 0x5a, 0x88 },
- { 0x5b, 0x44 }, { 0x5c, 0x67 },
- { 0x5d, 0x49 }, { 0x5e, 0x0e },
- { 0x6c, 0x0a }, { 0x6d, 0x55 },
- { 0x6e, 0x11 }, { 0x6f, 0x9f },
- /* "9e for advance AWB" */
- { 0x6a, 0x40 }, { OV7670_REG_BLUE, 0x40 },
- { OV7670_REG_RED, 0x60 },
- { OV7670_REG_COM8, OV7670_COM8_FASTAEC
- | OV7670_COM8_AECSTEP
- | OV7670_COM8_BFILT
- | OV7670_COM8_AGC
- | OV7670_COM8_AEC
- | OV7670_COM8_AWB },
-
- /* Matrix coefficients */
- { 0x4f, 0x80 }, { 0x50, 0x80 },
- { 0x51, 0 }, { 0x52, 0x22 },
- { 0x53, 0x5e }, { 0x54, 0x80 },
- { 0x58, 0x9e },
-
- { OV7670_REG_COM16, OV7670_COM16_AWBGAIN },
- { OV7670_REG_EDGE, 0 },
- { 0x75, 0x05 }, { 0x76, 0xe1 },
- { 0x4c, 0 }, { 0x77, 0x01 },
- { OV7670_REG_COM13, OV7670_COM13_GAMMA
- | OV7670_COM13_UVSAT
- | 2}, /* was 3 */
- { 0x4b, 0x09 },
- { 0xc9, 0x60 }, { OV7670_REG_COM16, 0x38 },
- { 0x56, 0x40 },
-
- { 0x34, 0x11 },
- { OV7670_REG_COM11, OV7670_COM11_EXP|OV7670_COM11_HZAUTO },
- { 0xa4, 0x88 }, { 0x96, 0 },
- { 0x97, 0x30 }, { 0x98, 0x20 },
- { 0x99, 0x30 }, { 0x9a, 0x84 },
- { 0x9b, 0x29 }, { 0x9c, 0x03 },
- { 0x9d, 0x4c }, { 0x9e, 0x3f },
- { 0x78, 0x04 },
-
- /* Extra-weird stuff. Some sort of multiplexor register */
- { 0x79, 0x01 }, { 0xc8, 0xf0 },
- { 0x79, 0x0f }, { 0xc8, 0x00 },
- { 0x79, 0x10 }, { 0xc8, 0x7e },
- { 0x79, 0x0a }, { 0xc8, 0x80 },
- { 0x79, 0x0b }, { 0xc8, 0x01 },
- { 0x79, 0x0c }, { 0xc8, 0x0f },
- { 0x79, 0x0d }, { 0xc8, 0x20 },
- { 0x79, 0x09 }, { 0xc8, 0x80 },
- { 0x79, 0x02 }, { 0xc8, 0xc0 },
- { 0x79, 0x03 }, { 0xc8, 0x40 },
- { 0x79, 0x05 }, { 0xc8, 0x30 },
- { 0x79, 0x26 },
- };
PDEBUG(D_PROBE, "starting OV7xx0 configuration");
@@ -1011,8 +1198,9 @@ static int ov7xx0_configure(struct sd *sd)
switch (low) {
case 0x30:
PDEBUG(D_PROBE, "Sensor is an OV7630/OV7635");
- sd->sensor = SEN_OV7630;
- break;
+ PDEBUG(D_ERR,
+ "7630 is not supported by this driver");
+ return -1;
case 0x40:
PDEBUG(D_PROBE, "Sensor is an OV7645");
sd->sensor = SEN_OV7640; /* FIXME */
@@ -1038,32 +1226,6 @@ static int ov7xx0_configure(struct sd *sd)
return -1;
}
- switch (sd->sensor) {
- case SEN_OV7620:
- PDEBUG(D_PROBE, "Writing 7620 registers");
- if (write_i2c_regvals(sd, norm_7620, ARRAY_SIZE(norm_7620)))
- return -1;
- break;
- case SEN_OV7630:
- PDEBUG(D_ERR, "7630 is not supported by this driver version");
- return -1;
- case SEN_OV7640:
- PDEBUG(D_PROBE, "Writing 7640 registers");
- if (write_i2c_regvals(sd, norm_7640, ARRAY_SIZE(norm_7640)))
- return -1;
- break;
- case SEN_OV7670:
- PDEBUG(D_PROBE, "Writing 7670 registers");
- if (write_i2c_regvals(sd, norm_7670, ARRAY_SIZE(norm_7670)))
- return -1;
- break;
- default:
- PDEBUG(D_PROBE, "Writing 7610 registers");
- if (write_i2c_regvals(sd, norm_7610, ARRAY_SIZE(norm_7610)))
- return -1;
- break;
- }
-
/* Set sensor-specific vars */
/* sd->sif = 0; already done */
return 0;
@@ -1073,141 +1235,7 @@ static int ov7xx0_configure(struct sd *sd)
static int ov6xx0_configure(struct sd *sd)
{
int rc;
- static const struct ov_i2c_regvals norm_6x20[] = {
- { 0x12, 0x80 }, /* reset */
- { 0x11, 0x01 },
- { 0x03, 0x60 },
- { 0x05, 0x7f }, /* For when autoadjust is off */
- { 0x07, 0xa8 },
- /* The ratio of 0x0c and 0x0d controls the white point */
- { 0x0c, 0x24 },
- { 0x0d, 0x24 },
- { 0x0f, 0x15 }, /* COMS */
- { 0x10, 0x75 }, /* AEC Exposure time */
- { 0x12, 0x24 }, /* Enable AGC */
- { 0x14, 0x04 },
- /* 0x16: 0x06 helps frame stability with moving objects */
- { 0x16, 0x06 },
-/* { 0x20, 0x30 }, * Aperture correction enable */
- { 0x26, 0xb2 }, /* BLC enable */
- /* 0x28: 0x05 Selects RGB format if RGB on */
- { 0x28, 0x05 },
- { 0x2a, 0x04 }, /* Disable framerate adjust */
-/* { 0x2b, 0xac }, * Framerate; Set 2a[7] first */
- { 0x2d, 0x99 },
- { 0x33, 0xa0 }, /* Color Processing Parameter */
- { 0x34, 0xd2 }, /* Max A/D range */
- { 0x38, 0x8b },
- { 0x39, 0x40 },
-
- { 0x3c, 0x39 }, /* Enable AEC mode changing */
- { 0x3c, 0x3c }, /* Change AEC mode */
- { 0x3c, 0x24 }, /* Disable AEC mode changing */
-
- { 0x3d, 0x80 },
- /* These next two registers (0x4a, 0x4b) are undocumented.
- * They control the color balance */
- { 0x4a, 0x80 },
- { 0x4b, 0x80 },
- { 0x4d, 0xd2 }, /* This reduces noise a bit */
- { 0x4e, 0xc1 },
- { 0x4f, 0x04 },
-/* Do 50-53 have any effect? */
-/* Toggle 0x12[2] off and on here? */
- };
-
- static const struct ov_i2c_regvals norm_6x30[] = {
- { 0x12, 0x80 }, /* Reset */
- { 0x00, 0x1f }, /* Gain */
- { 0x01, 0x99 }, /* Blue gain */
- { 0x02, 0x7c }, /* Red gain */
- { 0x03, 0xc0 }, /* Saturation */
- { 0x05, 0x0a }, /* Contrast */
- { 0x06, 0x95 }, /* Brightness */
- { 0x07, 0x2d }, /* Sharpness */
- { 0x0c, 0x20 },
- { 0x0d, 0x20 },
- { 0x0e, 0x20 },
- { 0x0f, 0x05 },
- { 0x10, 0x9a },
- { 0x11, 0x00 }, /* Pixel clock = fastest */
- { 0x12, 0x24 }, /* Enable AGC and AWB */
- { 0x13, 0x21 },
- { 0x14, 0x80 },
- { 0x15, 0x01 },
- { 0x16, 0x03 },
- { 0x17, 0x38 },
- { 0x18, 0xea },
- { 0x19, 0x04 },
- { 0x1a, 0x93 },
- { 0x1b, 0x00 },
- { 0x1e, 0xc4 },
- { 0x1f, 0x04 },
- { 0x20, 0x20 },
- { 0x21, 0x10 },
- { 0x22, 0x88 },
- { 0x23, 0xc0 }, /* Crystal circuit power level */
- { 0x25, 0x9a }, /* Increase AEC black ratio */
- { 0x26, 0xb2 }, /* BLC enable */
- { 0x27, 0xa2 },
- { 0x28, 0x00 },
- { 0x29, 0x00 },
- { 0x2a, 0x84 }, /* 60 Hz power */
- { 0x2b, 0xa8 }, /* 60 Hz power */
- { 0x2c, 0xa0 },
- { 0x2d, 0x95 }, /* Enable auto-brightness */
- { 0x2e, 0x88 },
- { 0x33, 0x26 },
- { 0x34, 0x03 },
- { 0x36, 0x8f },
- { 0x37, 0x80 },
- { 0x38, 0x83 },
- { 0x39, 0x80 },
- { 0x3a, 0x0f },
- { 0x3b, 0x3c },
- { 0x3c, 0x1a },
- { 0x3d, 0x80 },
- { 0x3e, 0x80 },
- { 0x3f, 0x0e },
- { 0x40, 0x00 }, /* White bal */
- { 0x41, 0x00 }, /* White bal */
- { 0x42, 0x80 },
- { 0x43, 0x3f }, /* White bal */
- { 0x44, 0x80 },
- { 0x45, 0x20 },
- { 0x46, 0x20 },
- { 0x47, 0x80 },
- { 0x48, 0x7f },
- { 0x49, 0x00 },
- { 0x4a, 0x00 },
- { 0x4b, 0x80 },
- { 0x4c, 0xd0 },
- { 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */
- { 0x4e, 0x40 },
- { 0x4f, 0x07 }, /* UV avg., col. killer: max */
- { 0x50, 0xff },
- { 0x54, 0x23 }, /* Max AGC gain: 18dB */
- { 0x55, 0xff },
- { 0x56, 0x12 },
- { 0x57, 0x81 },
- { 0x58, 0x75 },
- { 0x59, 0x01 }, /* AGC dark current comp.: +1 */
- { 0x5a, 0x2c },
- { 0x5b, 0x0f }, /* AWB chrominance levels */
- { 0x5c, 0x10 },
- { 0x3d, 0x80 },
- { 0x27, 0xa6 },
- { 0x12, 0x20 }, /* Toggle AWB */
- { 0x12, 0x24 },
- };
-
- PDEBUG(D_PROBE, "starting sensor configuration");
-
- if (init_ov_sensor(sd) < 0) {
- PDEBUG(D_ERR, "Failed to read sensor ID.");
- return -1;
- }
- PDEBUG(D_PROBE, "OV6xx0 sensor detected");
+ PDEBUG(D_PROBE, "starting OV6xx0 configuration");
/* Detect sensor (sub)type */
rc = i2c_r(sd, OV7610_REG_COM_I);
@@ -1251,15 +1279,6 @@ static int ov6xx0_configure(struct sd *sd)
/* Set sensor-specific vars */
sd->sif = 1;
- if (sd->sensor == SEN_OV6620) {
- PDEBUG(D_PROBE, "Writing 6x20 registers");
- if (write_i2c_regvals(sd, norm_6x20, ARRAY_SIZE(norm_6x20)))
- return -1;
- } else {
- PDEBUG(D_PROBE, "Writing 6x30 registers");
- if (write_i2c_regvals(sd, norm_6x30, ARRAY_SIZE(norm_6x30)))
- return -1;
- }
return 0;
}
@@ -1298,22 +1317,31 @@ static int sd_config(struct gspca_dev *gspca_dev,
ov51x_led_control(sd, 0); /* turn LED off */
/* Test for 76xx */
- sd->primary_i2c_slave = OV7xx0_SID;
if (ov51x_set_slave_ids(sd, OV7xx0_SID) < 0)
goto error;
/* The OV519 must be more aggressive about sensor detection since
* I2C write will never fail if the sensor is not present. We have
* to try to initialize the sensor to detect its presence */
- if (init_ov_sensor(sd) < 0) {
+ if (init_ov_sensor(sd) >= 0) {
+ if (ov7xx0_configure(sd) < 0) {
+ PDEBUG(D_ERR, "Failed to configure OV7xx0");
+ goto error;
+ }
+ } else {
+
/* Test for 6xx0 */
- sd->primary_i2c_slave = OV6xx0_SID;
if (ov51x_set_slave_ids(sd, OV6xx0_SID) < 0)
goto error;
- if (init_ov_sensor(sd) < 0) {
+ if (init_ov_sensor(sd) >= 0) {
+ if (ov6xx0_configure(sd) < 0) {
+ PDEBUG(D_ERR, "Failed to configure OV6xx0");
+ goto error;
+ }
+ } else {
+
/* Test for 8xx0 */
- sd->primary_i2c_slave = OV8xx0_SID;
if (ov51x_set_slave_ids(sd, OV8xx0_SID) < 0)
goto error;
@@ -1321,24 +1349,13 @@ static int sd_config(struct gspca_dev *gspca_dev,
PDEBUG(D_ERR,
"Can't determine sensor slave IDs");
goto error;
- } else {
- if (ov8xx0_configure(sd) < 0) {
- PDEBUG(D_ERR,
- "Failed to configure OV8xx0 sensor");
- goto error;
- }
}
- } else {
- if (ov6xx0_configure(sd) < 0) {
- PDEBUG(D_ERR, "Failed to configure OV6xx0");
+ if (ov8xx0_configure(sd) < 0) {
+ PDEBUG(D_ERR,
+ "Failed to configure OV8xx0 sensor");
goto error;
}
}
- } else {
- if (ov7xx0_configure(sd) < 0) {
- PDEBUG(D_ERR, "Failed to configure OV7xx0");
- goto error;
- }
}
cam = &gspca_dev->cam;
@@ -1355,15 +1372,53 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->colors = COLOR_DEF;
sd->hflip = HFLIP_DEF;
sd->vflip = VFLIP_DEF;
+ if (sd->sensor != SEN_OV7670)
+ gspca_dev->ctrl_dis = (1 << HFLIP_IDX)
+ | (1 << VFLIP_IDX);
return 0;
error:
PDEBUG(D_ERR, "OV519 Config failed");
return -EBUSY;
}
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ /* initialize the sensor */
+ switch (sd->sensor) {
+ case SEN_OV6620:
+ if (write_i2c_regvals(sd, norm_6x20, ARRAY_SIZE(norm_6x20)))
+ return -EIO;
+ break;
+ case SEN_OV6630:
+ if (write_i2c_regvals(sd, norm_6x30, ARRAY_SIZE(norm_6x30)))
+ return -EIO;
+ break;
+ default:
+/* case SEN_OV7610: */
+/* case SEN_OV76BE: */
+ if (write_i2c_regvals(sd, norm_7610, ARRAY_SIZE(norm_7610)))
+ return -EIO;
+ break;
+ case SEN_OV7620:
+ if (write_i2c_regvals(sd, norm_7620, ARRAY_SIZE(norm_7620)))
+ return -EIO;
+ break;
+ case SEN_OV7640:
+ if (write_i2c_regvals(sd, norm_7640, ARRAY_SIZE(norm_7640)))
+ return -EIO;
+ break;
+ case SEN_OV7670:
+ if (write_i2c_regvals(sd, norm_7670, ARRAY_SIZE(norm_7670)))
+ return -EIO;
+ break;
+ case SEN_OV8610:
+ if (write_i2c_regvals(sd, norm_8610, ARRAY_SIZE(norm_8610)))
+ return -EIO;
+ break;
+ }
return 0;
}
@@ -1827,14 +1882,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
ov51x_led_control((struct sd *) gspca_dev, 0);
}
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
-
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
struct gspca_frame *frame, /* target */
__u8 *data, /* isoc packet */
@@ -2091,11 +2138,9 @@ static const struct sd_desc sd_desc = {
.ctrls = sd_ctrls,
.nctrls = ARRAY_SIZE(sd_ctrls),
.config = sd_config,
- .open = sd_open,
+ .init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
- .stop0 = sd_stop0,
- .close = sd_close,
.pkt_scan = sd_pkt_scan,
};
@@ -2132,6 +2177,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
/* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/pac207.c b/drivers/media/video/gspca/pac207.c
index 7ef18d57881..83b5f740c94 100644
--- a/drivers/media/video/gspca/pac207.c
+++ b/drivers/media/video/gspca/pac207.c
@@ -56,12 +56,6 @@ MODULE_LICENSE("GPL");
#define PAC207_GAIN_KNEE 20
#define PAC207_AUTOGAIN_DEADZONE 30
-/* We calculating the autogain at the end of the transfer of a frame, at this
- moment a frame with the old settings is being transmitted, and a frame is
- being captured with the old settings. So if we adjust the autogain we must
- ignore atleast the 2 next frames for the new settings to come into effect
- before doing any other adjustments */
-#define PAC207_AUTOGAIN_IGNORE_FRAMES 3
/* specific webcam descriptor */
struct sd {
@@ -131,7 +125,8 @@ static struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 1,
.step = 1,
- .default_value = 1,
+#define AUTOGAIN_DEF 1
+ .default_value = AUTOGAIN_DEF,
.flags = 0,
},
.set = sd_setautogain,
@@ -181,9 +176,6 @@ static const __u8 pac207_sensor_init[][8] = {
/* 48 reg_72 Rate Control end BalSize_4a =0x36 */
static const __u8 PacReg72[] = { 0x00, 0x00, 0x36, 0x00 };
-static const unsigned char pac207_sof_marker[5] =
- { 0xff, 0xff, 0x00, 0xff, 0x96 };
-
static int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index,
const u8 *buffer, u16 length)
{
@@ -259,35 +251,32 @@ static int sd_config(struct gspca_dev *gspca_dev,
return -ENODEV;
}
- pac207_write_reg(gspca_dev, 0x41, 0x00);
- /* Bit_0=Image Format,
- * Bit_1=LED,
- * Bit_2=Compression test mode enable */
- pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
- pac207_write_reg(gspca_dev, 0x11, 0x30); /* Analog Bias */
-
PDEBUG(D_PROBE,
"Pixart PAC207BCA Image Processor and Control Chip detected"
" (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
cam = &gspca_dev->cam;
- cam->dev_name = (char *) id->driver_info;
cam->epaddr = 0x05;
cam->cam_mode = sif_mode;
cam->nmodes = ARRAY_SIZE(sif_mode);
sd->brightness = PAC207_BRIGHTNESS_DEFAULT;
sd->exposure = PAC207_EXPOSURE_DEFAULT;
sd->gain = PAC207_GAIN_DEFAULT;
+ sd->autogain = AUTOGAIN_DEF;
return 0;
}
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
{
- struct sd *sd = (struct sd *) gspca_dev;
+ pac207_write_reg(gspca_dev, 0x41, 0x00);
+ /* Bit_0=Image Format,
+ * Bit_1=LED,
+ * Bit_2=Compression test mode enable */
+ pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
+ pac207_write_reg(gspca_dev, 0x11, 0x30); /* Analog Bias */
- sd->autogain = 1;
return 0;
}
@@ -343,14 +332,8 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
}
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-/* this function is called at close time */
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
+/* Include pac common sof detection functions */
+#include "pac_common.h"
static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
{
@@ -365,33 +348,7 @@ static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
100 + sd->brightness / 2, PAC207_AUTOGAIN_DEADZONE,
PAC207_GAIN_KNEE, PAC207_EXPOSURE_KNEE))
- sd->autogain_ignore_frames = PAC207_AUTOGAIN_IGNORE_FRAMES;
-}
-
-static unsigned char *pac207_find_sof(struct gspca_dev *gspca_dev,
- unsigned char *m, int len)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- int i;
-
- /* Search for the SOF marker (fixed part) in the header */
- for (i = 0; i < len; i++) {
- if (m[i] == pac207_sof_marker[sd->sof_read]) {
- sd->sof_read++;
- if (sd->sof_read == sizeof(pac207_sof_marker)) {
- PDEBUG(D_STREAM,
- "SOF found, bytes to analyze: %u."
- " Frame starts at byte #%u",
- len, i + 1);
- sd->sof_read = 0;
- return m + i + 1;
- }
- } else {
- sd->sof_read = 0;
- }
- }
-
- return NULL;
+ sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
}
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
@@ -402,14 +359,14 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
struct sd *sd = (struct sd *) gspca_dev;
unsigned char *sof;
- sof = pac207_find_sof(gspca_dev, data, len);
+ sof = pac_find_sof(gspca_dev, data, len);
if (sof) {
int n;
/* finish decoding current frame */
n = sof - data;
- if (n > sizeof pac207_sof_marker)
- n -= sizeof pac207_sof_marker;
+ if (n > sizeof pac_sof_marker)
+ n -= sizeof pac_sof_marker;
else
n = 0;
frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
@@ -537,7 +494,7 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
sd->gain = PAC207_GAIN_DEFAULT;
if (gspca_dev->streaming) {
sd->autogain_ignore_frames =
- PAC207_AUTOGAIN_IGNORE_FRAMES;
+ PAC_AUTOGAIN_IGNORE_FRAMES;
setexposure(gspca_dev);
setgain(gspca_dev);
}
@@ -560,11 +517,9 @@ static const struct sd_desc sd_desc = {
.ctrls = sd_ctrls,
.nctrls = ARRAY_SIZE(sd_ctrls),
.config = sd_config,
- .open = sd_open,
+ .init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
- .stop0 = sd_stop0,
- .close = sd_close,
.dq_callback = pac207_do_auto_gain,
.pkt_scan = sd_pkt_scan,
};
@@ -597,6 +552,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
/* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c
index 815bea6edc4..ba865b7f1ed 100644
--- a/drivers/media/video/gspca/pac7311.c
+++ b/drivers/media/video/gspca/pac7311.c
@@ -19,6 +19,36 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+/* Some documentation about various registers as determined by trial and error.
+ When the register addresses differ between the 7202 and the 7311 the 2
+ different addresses are written as 7302addr/7311addr, when one of the 2
+ addresses is a - sign that register description is not valid for the
+ matching IC.
+
+ Register page 1:
+
+ Address Description
+ -/0x08 Unknown compressor related, must always be 8 except when not
+ in 640x480 resolution and page 4 reg 2 <= 3 then set it to 9 !
+ -/0x1b Auto white balance related, bit 0 is AWB enable (inverted)
+ bits 345 seem to toggle per color gains on/off (inverted)
+ 0x78 Global control, bit 6 controls the LED (inverted)
+ -/0x80 JPEG compression ratio ? Best not touched
+
+ Register page 3/4:
+
+ Address Description
+ 0x02 Clock divider 2-63, fps =~ 60 / val. Must be a multiple of 3 on
+ the 7302, so one of 3, 6, 9, ..., except when between 6 and 12?
+ -/0x0f Master gain 1-245, low value = high gain
+ 0x10/- Master gain 0-31
+ -/0x10 Another gain 0-15, limited influence (1-2x gain I guess)
+ 0x21 Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused
+ -/0x27 Seems to toggle various gains on / off, Setting bit 7 seems to
+ completely disable the analog amplification block. Set to 0x68
+ for max gain, 0x14 for minimal gain.
+*/
+
#define MODULE_NAME "pac7311"
#include "gspca.h"
@@ -31,18 +61,23 @@ MODULE_LICENSE("GPL");
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
- int lum_sum;
- atomic_t avg_lum;
- atomic_t do_gain;
-
unsigned char brightness;
unsigned char contrast;
unsigned char colors;
+ unsigned char gain;
+ unsigned char exposure;
unsigned char autogain;
+ __u8 hflip;
+ __u8 vflip;
+
+ __u8 sensor;
+#define SENSOR_PAC7302 0
+#define SENSOR_PAC7311 1
- char ffseq;
- signed char ag_cnt;
-#define AG_CNT_START 13
+ u8 sof_read;
+ u8 autogain_ignore_frames;
+
+ atomic_t avg_lum;
};
/* V4L2 controls supported by the driver */
@@ -54,8 +89,18 @@ static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
static struct ctrl sd_ctrls[] = {
+/* This control is pac7302 only */
+#define BRIGHTNESS_IDX 0
{
{
.id = V4L2_CID_BRIGHTNESS,
@@ -71,13 +116,15 @@ static struct ctrl sd_ctrls[] = {
.set = sd_setbrightness,
.get = sd_getbrightness,
},
+/* This control is for both the 7302 and the 7311 */
{
{
.id = V4L2_CID_CONTRAST,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Contrast",
.minimum = 0,
- .maximum = 255,
+#define CONTRAST_MAX 255
+ .maximum = CONTRAST_MAX,
.step = 1,
#define CONTRAST_DEF 127
.default_value = CONTRAST_DEF,
@@ -85,13 +132,16 @@ static struct ctrl sd_ctrls[] = {
.set = sd_setcontrast,
.get = sd_getcontrast,
},
+/* This control is pac7302 only */
+#define SATURATION_IDX 2
{
{
.id = V4L2_CID_SATURATION,
.type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Color",
+ .name = "Saturation",
.minimum = 0,
- .maximum = 255,
+#define COLOR_MAX 255
+ .maximum = COLOR_MAX,
.step = 1,
#define COLOR_DEF 127
.default_value = COLOR_DEF,
@@ -99,6 +149,39 @@ static struct ctrl sd_ctrls[] = {
.set = sd_setcolors,
.get = sd_getcolors,
},
+/* All controls below are for both the 7302 and the 7311 */
+ {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gain",
+ .minimum = 0,
+#define GAIN_MAX 255
+ .maximum = GAIN_MAX,
+ .step = 1,
+#define GAIN_DEF 127
+#define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */
+ .default_value = GAIN_DEF,
+ },
+ .set = sd_setgain,
+ .get = sd_getgain,
+ },
+ {
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Exposure",
+ .minimum = 0,
+#define EXPOSURE_MAX 255
+ .maximum = EXPOSURE_MAX,
+ .step = 1,
+#define EXPOSURE_DEF 16 /* 32 ms / 30 fps */
+#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */
+ .default_value = EXPOSURE_DEF,
+ },
+ .set = sd_setexposure,
+ .get = sd_getexposure,
+ },
{
{
.id = V4L2_CID_AUTOGAIN,
@@ -113,101 +196,207 @@ static struct ctrl sd_ctrls[] = {
.set = sd_setautogain,
.get = sd_getautogain,
},
+ {
+ {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Mirror",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+#define HFLIP_DEF 0
+ .default_value = HFLIP_DEF,
+ },
+ .set = sd_sethflip,
+ .get = sd_gethflip,
+ },
+ {
+ {
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Vflip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+#define VFLIP_DEF 0
+ .default_value = VFLIP_DEF,
+ },
+ .set = sd_setvflip,
+ .get = sd_getvflip,
+ },
};
static struct v4l2_pix_format vga_mode[] = {
- {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ {160, 120, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
.bytesperline = 160,
.sizeimage = 160 * 120 * 3 / 8 + 590,
.colorspace = V4L2_COLORSPACE_JPEG,
.priv = 2},
- {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ {320, 240, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
.bytesperline = 320,
.sizeimage = 320 * 240 * 3 / 8 + 590,
.colorspace = V4L2_COLORSPACE_JPEG,
.priv = 1},
- {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
.bytesperline = 640,
.sizeimage = 640 * 480 * 3 / 8 + 590,
.colorspace = V4L2_COLORSPACE_JPEG,
.priv = 0},
};
-#define PAC7311_JPEG_HEADER_SIZE (sizeof pac7311_jpeg_header) /* (594) */
-
-static const __u8 pac7311_jpeg_header[] = {
- 0xff, 0xd8,
- 0xff, 0xe0, 0x00, 0x03, 0x20,
- 0xff, 0xc0, 0x00, 0x11, 0x08,
- 0x01, 0xe0, /* 12: height */
- 0x02, 0x80, /* 14: width */
- 0x03, /* 16 */
- 0x01, 0x21, 0x00,
- 0x02, 0x11, 0x01,
- 0x03, 0x11, 0x01,
- 0xff, 0xdb, 0x00, 0x84,
- 0x00, 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, 0x0d,
- 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, 0x1a, 0x18, 0x16,
- 0x16, 0x18, 0x31, 0x23, 0x25, 0x1d, 0x28, 0x3a, 0x33, 0x3d,
- 0x3c, 0x39, 0x33, 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40,
- 0x44, 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, 0x5f,
- 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, 0x79, 0x70, 0x64,
- 0x78, 0x5c, 0x65, 0x67, 0x63, 0x01, 0x11, 0x12, 0x12, 0x18,
- 0x15, 0x18, 0x2f, 0x1a, 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42,
- 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
- 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
- 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
- 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
- 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
- 0xff, 0xc4, 0x01, 0xa2, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
- 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02,
- 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d,
- 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31,
- 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32,
- 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52,
- 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
- 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
- 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45,
- 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57,
- 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
- 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83,
- 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
- 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
- 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
- 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
- 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
- 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8,
- 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
- 0xf9, 0xfa, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
- 0x0b, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
- 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01,
- 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41,
- 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14,
- 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
- 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25,
- 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a,
- 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46,
- 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
- 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a,
- 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83,
- 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
- 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
- 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
- 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
- 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
- 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
- 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa,
- 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03,
- 0x11, 0x00, 0x3f, 0x00
+/* pac 7302 */
+static const __u8 init_7302[] = {
+/* index,value */
+ 0xff, 0x01, /* page 1 */
+ 0x78, 0x00, /* deactivate */
+ 0xff, 0x01,
+ 0x78, 0x40, /* led off */
+};
+static const __u8 start_7302[] = {
+/* index, len, [value]* */
+ 0xff, 1, 0x00, /* page 0 */
+ 0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x0d, 24, 0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00,
+ 0x07, 0xc8, 0x00, 0xea, 0x07, 0xcf, 0x07, 0xf7,
+ 0x07, 0x7e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x11,
+ 0x26, 2, 0xaa, 0xaa,
+ 0x2e, 1, 0x31,
+ 0x38, 1, 0x01,
+ 0x3a, 3, 0x14, 0xff, 0x5a,
+ 0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11,
+ 0x00, 0x54, 0x11,
+ 0x55, 1, 0x00,
+ 0x62, 4, 0x10, 0x1e, 0x1e, 0x18,
+ 0x6b, 1, 0x00,
+ 0x6e, 3, 0x08, 0x06, 0x00,
+ 0x72, 3, 0x00, 0xff, 0x00,
+ 0x7d, 23, 0x01, 0x01, 0x58, 0x46, 0x50, 0x3c, 0x50, 0x3c,
+ 0x54, 0x46, 0x54, 0x56, 0x52, 0x50, 0x52, 0x50,
+ 0x56, 0x64, 0xa4, 0x00, 0xda, 0x00, 0x00,
+ 0xa2, 10, 0x22, 0x2c, 0x3c, 0x54, 0x69, 0x7c, 0x9c, 0xb9,
+ 0xd2, 0xeb,
+ 0xaf, 1, 0x02,
+ 0xb5, 2, 0x08, 0x08,
+ 0xb8, 2, 0x08, 0x88,
+ 0xc4, 4, 0xae, 0x01, 0x04, 0x01,
+ 0xcc, 1, 0x00,
+ 0xd1, 11, 0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9,
+ 0xc1, 0xd7, 0xec,
+ 0xdc, 1, 0x01,
+ 0xff, 1, 0x01, /* page 1 */
+ 0x12, 3, 0x02, 0x00, 0x01,
+ 0x3e, 2, 0x00, 0x00,
+ 0x76, 5, 0x01, 0x20, 0x40, 0x00, 0xf2,
+ 0x7c, 1, 0x00,
+ 0x7f, 10, 0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20,
+ 0x02, 0x00,
+ 0x96, 5, 0x01, 0x10, 0x04, 0x01, 0x04,
+ 0xc8, 14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
+ 0x07, 0x00, 0x01, 0x07, 0x04, 0x01,
+ 0xd8, 1, 0x01,
+ 0xdb, 2, 0x00, 0x01,
+ 0xde, 7, 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00,
+ 0xe6, 4, 0x00, 0x00, 0x00, 0x01,
+ 0xeb, 1, 0x00,
+ 0xff, 1, 0x02, /* page 2 */
+ 0x22, 1, 0x00,
+ 0xff, 1, 0x03, /* page 3 */
+ 0x00, 255, /* load the page 3 */
+ 0x11, 1, 0x01,
+ 0xff, 1, 0x02, /* page 2 */
+ 0x13, 1, 0x00,
+ 0x22, 4, 0x1f, 0xa4, 0xf0, 0x96,
+ 0x27, 2, 0x14, 0x0c,
+ 0x2a, 5, 0xc8, 0x00, 0x18, 0x12, 0x22,
+ 0x64, 8, 0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44,
+ 0x6e, 1, 0x08,
+ 0xff, 1, 0x01, /* page 1 */
+ 0x78, 1, 0x00,
+ 0, 0 /* end of sequence */
+};
+
+/* page 3 - the value 0xaa says skip the index - see reg_w_page() */
+static const __u8 page3_7302[] = {
+ 0x90, 0x40, 0x03, 0x50, 0xc2, 0x01, 0x14, 0x16,
+ 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
+ 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00,
+ 0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21,
+ 0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54,
+ 0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00,
+ 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8,
+ 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
+ 0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00,
+ 0x00
+};
+
+/* pac 7311 */
+static const __u8 init_7311[] = {
+ 0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */
+ 0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */
+ 0x78, 0x44, /* Bit_0=start stream, Bit_6=LED */
+ 0xff, 0x04,
+ 0x27, 0x80,
+ 0x28, 0xca,
+ 0x29, 0x53,
+ 0x2a, 0x0e,
+ 0xff, 0x01,
+ 0x3e, 0x20,
+};
+
+static const __u8 start_7311[] = {
+/* index, len, [value]* */
+ 0xff, 1, 0x01, /* page 1 */
+ 0x02, 43, 0x48, 0x0a, 0x40, 0x08, 0x00, 0x00, 0x08, 0x00,
+ 0x06, 0xff, 0x11, 0xff, 0x5a, 0x30, 0x90, 0x4c,
+ 0x00, 0x07, 0x00, 0x0a, 0x10, 0x00, 0xa0, 0x10,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00,
+ 0x3e, 42, 0x00, 0x00, 0x78, 0x52, 0x4a, 0x52, 0x78, 0x6e,
+ 0x48, 0x46, 0x48, 0x6e, 0x5f, 0x49, 0x42, 0x49,
+ 0x5f, 0x5f, 0x49, 0x42, 0x49, 0x5f, 0x6e, 0x48,
+ 0x46, 0x48, 0x6e, 0x78, 0x52, 0x4a, 0x52, 0x78,
+ 0x00, 0x00, 0x09, 0x1b, 0x34, 0x49, 0x5c, 0x9b,
+ 0xd0, 0xff,
+ 0x78, 6, 0x44, 0x00, 0xf2, 0x01, 0x01, 0x80,
+ 0x7f, 18, 0x2a, 0x1c, 0x00, 0xc8, 0x02, 0x58, 0x03, 0x84,
+ 0x12, 0x00, 0x1a, 0x04, 0x08, 0x0c, 0x10, 0x14,
+ 0x18, 0x20,
+ 0x96, 3, 0x01, 0x08, 0x04,
+ 0xa0, 4, 0x44, 0x44, 0x44, 0x04,
+ 0xf0, 13, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x20, 0x00,
+ 0x3f, 0x00, 0x0a, 0x01, 0x00,
+ 0xff, 1, 0x04, /* page 4 */
+ 0x00, 254, /* load the page 4 */
+ 0x11, 1, 0x01,
+ 0, 0 /* end of sequence */
+};
+
+/* page 4 - the value 0xaa says skip the index - see reg_w_page() */
+static const __u8 page4_7311[] = {
+ 0xaa, 0xaa, 0x04, 0x54, 0x07, 0x2b, 0x09, 0x0f,
+ 0x09, 0x00, 0xaa, 0xaa, 0x07, 0x00, 0x00, 0x62,
+ 0x08, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x03, 0xa0, 0x01, 0xf4, 0xaa,
+ 0xaa, 0x00, 0x08, 0xaa, 0x03, 0xaa, 0x00, 0x68,
+ 0xca, 0x10, 0x06, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0x23, 0x28, 0x04, 0x11, 0x00, 0x00
};
static void reg_w_buf(struct gspca_dev *gspca_dev,
- __u16 index,
- const char *buffer, __u16 len)
+ __u8 index,
+ const char *buffer, int len)
{
memcpy(gspca_dev->usb_buf, buffer, len);
usb_control_msg(gspca_dev->dev,
@@ -219,21 +408,9 @@ static void reg_w_buf(struct gspca_dev *gspca_dev,
500);
}
-static __u8 reg_r(struct gspca_dev *gspca_dev,
- __u16 index)
-{
- usb_control_msg(gspca_dev->dev,
- usb_rcvctrlpipe(gspca_dev->dev, 0),
- 0, /* request */
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, /* value */
- index, gspca_dev->usb_buf, 1,
- 500);
- return gspca_dev->usb_buf[0];
-}
static void reg_w(struct gspca_dev *gspca_dev,
- __u16 index,
+ __u8 index,
__u8 value)
{
gspca_dev->usb_buf[0] = value;
@@ -241,10 +418,78 @@ static void reg_w(struct gspca_dev *gspca_dev,
usb_sndctrlpipe(gspca_dev->dev, 0),
0, /* request */
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- value, index, gspca_dev->usb_buf, 1,
+ 0, index, gspca_dev->usb_buf, 1,
500);
}
+static void reg_w_seq(struct gspca_dev *gspca_dev,
+ const __u8 *seq, int len)
+{
+ while (--len >= 0) {
+ reg_w(gspca_dev, seq[0], seq[1]);
+ seq += 2;
+ }
+}
+
+/* load the beginning of a page */
+static void reg_w_page(struct gspca_dev *gspca_dev,
+ const __u8 *page, int len)
+{
+ int index;
+
+ for (index = 0; index < len; index++) {
+ if (page[index] == 0xaa) /* skip this index */
+ continue;
+ gspca_dev->usb_buf[0] = page[index];
+ usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ 0, /* request */
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, index, gspca_dev->usb_buf, 1,
+ 500);
+ }
+}
+
+/* output a variable sequence */
+static void reg_w_var(struct gspca_dev *gspca_dev,
+ const __u8 *seq)
+{
+ int index, len;
+
+ for (;;) {
+ index = *seq++;
+ len = *seq++;
+ switch (len) {
+ case 0:
+ return;
+ case 254:
+ reg_w_page(gspca_dev, page4_7311, sizeof page4_7311);
+ break;
+ case 255:
+ reg_w_page(gspca_dev, page3_7302, sizeof page3_7302);
+ break;
+ default:
+ if (len > 64) {
+ PDEBUG(D_ERR|D_STREAM,
+ "Incorrect variable sequence");
+ return;
+ }
+ while (len > 0) {
+ if (len < 8) {
+ reg_w_buf(gspca_dev, index, seq, len);
+ seq += len;
+ break;
+ }
+ reg_w_buf(gspca_dev, index, seq, 8);
+ seq += 8;
+ index += 8;
+ len -= 8;
+ }
+ }
+ }
+ /* not reached */
+}
+
/* this function is called at probe time */
static int sd_config(struct gspca_dev *gspca_dev,
const struct usb_device_id *id)
@@ -252,203 +497,245 @@ static int sd_config(struct gspca_dev *gspca_dev,
struct sd *sd = (struct sd *) gspca_dev;
struct cam *cam;
- PDEBUG(D_CONF, "Find Sensor PAC7311");
- reg_w(gspca_dev, 0x78, 0x40); /* Bit_0=start stream, Bit_7=LED */
- reg_w(gspca_dev, 0x78, 0x40); /* Bit_0=start stream, Bit_7=LED */
- reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
- reg_w(gspca_dev, 0xff, 0x04);
- reg_w(gspca_dev, 0x27, 0x80);
- reg_w(gspca_dev, 0x28, 0xca);
- reg_w(gspca_dev, 0x29, 0x53);
- reg_w(gspca_dev, 0x2a, 0x0e);
- reg_w(gspca_dev, 0xff, 0x01);
- reg_w(gspca_dev, 0x3e, 0x20);
-
cam = &gspca_dev->cam;
cam->epaddr = 0x05;
- cam->cam_mode = vga_mode;
- cam->nmodes = ARRAY_SIZE(vga_mode);
+
+ sd->sensor = id->driver_info;
+ if (sd->sensor == SENSOR_PAC7302) {
+ PDEBUG(D_CONF, "Find Sensor PAC7302");
+ cam->cam_mode = &vga_mode[2]; /* only 640x480 */
+ cam->nmodes = 1;
+ } else {
+ PDEBUG(D_CONF, "Find Sensor PAC7311");
+ cam->cam_mode = vga_mode;
+ cam->nmodes = ARRAY_SIZE(vga_mode);
+ gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX)
+ | (1 << SATURATION_IDX);
+ }
sd->brightness = BRIGHTNESS_DEF;
sd->contrast = CONTRAST_DEF;
sd->colors = COLOR_DEF;
+ sd->gain = GAIN_DEF;
+ sd->exposure = EXPOSURE_DEF;
sd->autogain = AUTOGAIN_DEF;
- sd->ag_cnt = -1;
+ sd->hflip = HFLIP_DEF;
+ sd->vflip = VFLIP_DEF;
return 0;
}
-static void setbrightness(struct gspca_dev *gspca_dev)
+/* This function is used by pac7302 only */
+static void setbrightcont(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i, v;
+ static const __u8 max[10] =
+ {0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb,
+ 0xd4, 0xec};
+ static const __u8 delta[10] =
+ {0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17,
+ 0x11, 0x0b};
+
+ reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
+ for (i = 0; i < 10; i++) {
+ v = max[i];
+ v += (sd->brightness - BRIGHTNESS_MAX)
+ * 150 / BRIGHTNESS_MAX; /* 200 ? */
+ v -= delta[i] * sd->contrast / CONTRAST_MAX;
+ if (v < 0)
+ v = 0;
+ else if (v > 0xff)
+ v = 0xff;
+ reg_w(gspca_dev, 0xa2 + i, v);
+ }
+ reg_w(gspca_dev, 0xdc, 0x01);
+}
+
+/* This function is used by pac7311 only */
+static void setcontrast(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int brightness;
-/*jfm: inverted?*/
- brightness = BRIGHTNESS_MAX - sd->brightness;
reg_w(gspca_dev, 0xff, 0x04);
-/* reg_w(gspca_dev, 0x0e, 0x00); */
- reg_w(gspca_dev, 0x0f, brightness);
+ reg_w(gspca_dev, 0x10, sd->contrast >> 4);
/* load registers to sensor (Bit 0, auto clear) */
reg_w(gspca_dev, 0x11, 0x01);
- PDEBUG(D_CONF|D_STREAM, "brightness: %i", brightness);
}
-static void setcontrast(struct gspca_dev *gspca_dev)
+/* This function is used by pac7302 only */
+static void setcolors(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
+ int i, v;
+ static const int a[9] =
+ {217, -212, 0, -101, 170, -67, -38, -315, 355};
+ static const int b[9] =
+ {19, 106, 0, 19, 106, 1, 19, 106, 1};
- reg_w(gspca_dev, 0xff, 0x01);
- reg_w(gspca_dev, 0x80, sd->contrast);
- /* load registers to sensor (Bit 0, auto clear) */
+ reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
reg_w(gspca_dev, 0x11, 0x01);
- PDEBUG(D_CONF|D_STREAM, "contrast: %i", sd->contrast);
+ reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
+ reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
+ for (i = 0; i < 9; i++) {
+ v = a[i] * sd->colors / COLOR_MAX + b[i];
+ reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
+ reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
+ }
+ reg_w(gspca_dev, 0xdc, 0x01);
+ PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
}
-static void setcolors(struct gspca_dev *gspca_dev)
+static void setgain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- reg_w(gspca_dev, 0xff, 0x01);
- reg_w(gspca_dev, 0x10, sd->colors);
+ if (sd->sensor == SENSOR_PAC7302) {
+ reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
+ reg_w(gspca_dev, 0x10, sd->gain >> 3);
+ } else {
+ int gain = GAIN_MAX - sd->gain;
+ if (gain < 1)
+ gain = 1;
+ else if (gain > 245)
+ gain = 245;
+ reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
+ reg_w(gspca_dev, 0x0e, 0x00);
+ reg_w(gspca_dev, 0x0f, gain);
+ }
/* load registers to sensor (Bit 0, auto clear) */
reg_w(gspca_dev, 0x11, 0x01);
- PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
}
-static void setautogain(struct gspca_dev *gspca_dev)
+static void setexposure(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
+ __u8 reg;
+
+ /* register 2 of frame 3/4 contains the clock divider configuring the
+ no fps according to the formula: 60 / reg. sd->exposure is the
+ desired exposure time in ms. */
+ reg = 120 * sd->exposure / 1000;
+ if (reg < 2)
+ reg = 2;
+ else if (reg > 63)
+ reg = 63;
+
+ if (sd->sensor == SENSOR_PAC7302) {
+ /* On the pac7302 reg2 MUST be a multiple of 3, so round it to
+ the nearest multiple of 3, except when between 6 and 12? */
+ if (reg < 6 || reg > 12)
+ reg = ((reg + 1) / 3) * 3;
+ reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
+ reg_w(gspca_dev, 0x02, reg);
+ } else {
+ reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
+ reg_w(gspca_dev, 0x02, reg);
+ /* Page 1 register 8 must always be 0x08 except when not in
+ 640x480 mode and Page3/4 reg 2 <= 3 then it must be 9 */
+ reg_w(gspca_dev, 0xff, 0x01);
+ if (gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv &&
+ reg <= 3)
+ reg_w(gspca_dev, 0x08, 0x09);
+ else
+ reg_w(gspca_dev, 0x08, 0x08);
+ }
+ /* load registers to sensor (Bit 0, auto clear) */
+ reg_w(gspca_dev, 0x11, 0x01);
+}
- if (sd->autogain) {
- sd->lum_sum = 0;
- sd->ag_cnt = AG_CNT_START;
+static void sethvflip(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ __u8 data;
+
+ if (sd->sensor == SENSOR_PAC7302) {
+ reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
+ data = (sd->hflip ? 0x08 : 0x00)
+ | (sd->vflip ? 0x04 : 0x00);
} else {
- sd->ag_cnt = -1;
+ reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
+ data = (sd->hflip ? 0x04 : 0x00)
+ | (sd->vflip ? 0x08 : 0x00);
}
+ reg_w(gspca_dev, 0x21, data);
+ /* load registers to sensor (Bit 0, auto clear) */
+ reg_w(gspca_dev, 0x11, 0x01);
}
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
{
- reg_w(gspca_dev, 0x78, 0x00); /* Turn on LED */
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (sd->sensor == SENSOR_PAC7302)
+ reg_w_seq(gspca_dev, init_7302, sizeof init_7302);
+ else
+ reg_w_seq(gspca_dev, init_7311, sizeof init_7311);
+
return 0;
}
static void sd_start(struct gspca_dev *gspca_dev)
{
- reg_w(gspca_dev, 0xff, 0x01);
- reg_w_buf(gspca_dev, 0x0002, "\x48\x0a\x40\x08\x00\x00\x08\x00", 8);
- reg_w_buf(gspca_dev, 0x000a, "\x06\xff\x11\xff\x5a\x30\x90\x4c", 8);
- reg_w_buf(gspca_dev, 0x0012, "\x00\x07\x00\x0a\x10\x00\xa0\x10", 8);
- reg_w_buf(gspca_dev, 0x001a, "\x02\x00\x00\x00\x00\x0b\x01\x00", 8);
- reg_w_buf(gspca_dev, 0x0022, "\x00\x00\x00\x00\x00\x00\x00\x00", 8);
- reg_w_buf(gspca_dev, 0x002a, "\x00\x00\x00", 3);
- reg_w_buf(gspca_dev, 0x003e, "\x00\x00\x78\x52\x4a\x52\x78\x6e", 8);
- reg_w_buf(gspca_dev, 0x0046, "\x48\x46\x48\x6e\x5f\x49\x42\x49", 8);
- reg_w_buf(gspca_dev, 0x004e, "\x5f\x5f\x49\x42\x49\x5f\x6e\x48", 8);
- reg_w_buf(gspca_dev, 0x0056, "\x46\x48\x6e\x78\x52\x4a\x52\x78", 8);
- reg_w_buf(gspca_dev, 0x005e, "\x00\x00\x09\x1b\x34\x49\x5c\x9b", 8);
- reg_w_buf(gspca_dev, 0x0066, "\xd0\xff", 2);
- reg_w_buf(gspca_dev, 0x0078, "\x44\x00\xf2\x01\x01\x80", 6);
- reg_w_buf(gspca_dev, 0x007f, "\x2a\x1c\x00\xc8\x02\x58\x03\x84", 8);
- reg_w_buf(gspca_dev, 0x0087, "\x12\x00\x1a\x04\x08\x0c\x10\x14", 8);
- reg_w_buf(gspca_dev, 0x008f, "\x18\x20", 2);
- reg_w_buf(gspca_dev, 0x0096, "\x01\x08\x04", 3);
- reg_w_buf(gspca_dev, 0x00a0, "\x44\x44\x44\x04", 4);
- reg_w_buf(gspca_dev, 0x00f0, "\x01\x00\x00\x00\x22\x00\x20\x00", 8);
- reg_w_buf(gspca_dev, 0x00f8, "\x3f\x00\x0a\x01\x00", 5);
+ struct sd *sd = (struct sd *) gspca_dev;
- reg_w(gspca_dev, 0xff, 0x04);
- reg_w(gspca_dev, 0x02, 0x04);
- reg_w(gspca_dev, 0x03, 0x54);
- reg_w(gspca_dev, 0x04, 0x07);
- reg_w(gspca_dev, 0x05, 0x2b);
- reg_w(gspca_dev, 0x06, 0x09);
- reg_w(gspca_dev, 0x07, 0x0f);
- reg_w(gspca_dev, 0x08, 0x09);
- reg_w(gspca_dev, 0x09, 0x00);
- reg_w(gspca_dev, 0x0c, 0x07);
- reg_w(gspca_dev, 0x0d, 0x00);
- reg_w(gspca_dev, 0x0e, 0x00);
- reg_w(gspca_dev, 0x0f, 0x62);
- reg_w(gspca_dev, 0x10, 0x08);
- reg_w(gspca_dev, 0x12, 0x07);
- reg_w(gspca_dev, 0x13, 0x00);
- reg_w(gspca_dev, 0x14, 0x00);
- reg_w(gspca_dev, 0x15, 0x00);
- reg_w(gspca_dev, 0x16, 0x00);
- reg_w(gspca_dev, 0x17, 0x00);
- reg_w(gspca_dev, 0x18, 0x00);
- reg_w(gspca_dev, 0x19, 0x00);
- reg_w(gspca_dev, 0x1a, 0x00);
- reg_w(gspca_dev, 0x1b, 0x03);
- reg_w(gspca_dev, 0x1c, 0xa0);
- reg_w(gspca_dev, 0x1d, 0x01);
- reg_w(gspca_dev, 0x1e, 0xf4);
- reg_w(gspca_dev, 0x21, 0x00);
- reg_w(gspca_dev, 0x22, 0x08);
- reg_w(gspca_dev, 0x24, 0x03);
- reg_w(gspca_dev, 0x26, 0x00);
- reg_w(gspca_dev, 0x27, 0x01);
- reg_w(gspca_dev, 0x28, 0xca);
- reg_w(gspca_dev, 0x29, 0x10);
- reg_w(gspca_dev, 0x2a, 0x06);
- reg_w(gspca_dev, 0x2b, 0x78);
- reg_w(gspca_dev, 0x2c, 0x00);
- reg_w(gspca_dev, 0x2d, 0x00);
- reg_w(gspca_dev, 0x2e, 0x00);
- reg_w(gspca_dev, 0x2f, 0x00);
- reg_w(gspca_dev, 0x30, 0x23);
- reg_w(gspca_dev, 0x31, 0x28);
- reg_w(gspca_dev, 0x32, 0x04);
- reg_w(gspca_dev, 0x33, 0x11);
- reg_w(gspca_dev, 0x34, 0x00);
- reg_w(gspca_dev, 0x35, 0x00);
- reg_w(gspca_dev, 0x11, 0x01);
- setcontrast(gspca_dev);
- setbrightness(gspca_dev);
- setcolors(gspca_dev);
- setautogain(gspca_dev);
+ sd->sof_read = 0;
+
+ if (sd->sensor == SENSOR_PAC7302) {
+ reg_w_var(gspca_dev, start_7302);
+ setbrightcont(gspca_dev);
+ setcolors(gspca_dev);
+ } else {
+ reg_w_var(gspca_dev, start_7311);
+ setcontrast(gspca_dev);
+ }
+ setgain(gspca_dev);
+ setexposure(gspca_dev);
+ sethvflip(gspca_dev);
/* set correct resolution */
switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
- case 2: /* 160x120 */
- reg_w(gspca_dev, 0xff, 0x04);
- reg_w(gspca_dev, 0x02, 0x03);
+ case 2: /* 160x120 pac7311 */
reg_w(gspca_dev, 0xff, 0x01);
- reg_w(gspca_dev, 0x08, 0x09);
reg_w(gspca_dev, 0x17, 0x20);
- reg_w(gspca_dev, 0x1b, 0x00);
-/* reg_w(gspca_dev, 0x80, 0x69); */
reg_w(gspca_dev, 0x87, 0x10);
break;
- case 1: /* 320x240 */
- reg_w(gspca_dev, 0xff, 0x04);
- reg_w(gspca_dev, 0x02, 0x03);
+ case 1: /* 320x240 pac7311 */
reg_w(gspca_dev, 0xff, 0x01);
- reg_w(gspca_dev, 0x08, 0x09);
reg_w(gspca_dev, 0x17, 0x30);
-/* reg_w(gspca_dev, 0x80, 0x3f); */
reg_w(gspca_dev, 0x87, 0x11);
break;
case 0: /* 640x480 */
- reg_w(gspca_dev, 0xff, 0x04);
- reg_w(gspca_dev, 0x02, 0x03);
+ if (sd->sensor == SENSOR_PAC7302)
+ break;
reg_w(gspca_dev, 0xff, 0x01);
- reg_w(gspca_dev, 0x08, 0x08);
reg_w(gspca_dev, 0x17, 0x00);
-/* reg_w(gspca_dev, 0x80, 0x1c); */
reg_w(gspca_dev, 0x87, 0x12);
break;
}
+ sd->sof_read = 0;
+ sd->autogain_ignore_frames = 0;
+ atomic_set(&sd->avg_lum, -1);
+
/* start stream */
reg_w(gspca_dev, 0xff, 0x01);
- reg_w(gspca_dev, 0x78, 0x04);
- reg_w(gspca_dev, 0x78, 0x05);
+ if (sd->sensor == SENSOR_PAC7302)
+ reg_w(gspca_dev, 0x78, 0x01);
+ else
+ reg_w(gspca_dev, 0x78, 0x05);
}
static void sd_stopN(struct gspca_dev *gspca_dev)
{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (sd->sensor == SENSOR_PAC7302) {
+ reg_w(gspca_dev, 0xff, 0x01);
+ reg_w(gspca_dev, 0x78, 0x00);
+ reg_w(gspca_dev, 0x78, 0x00);
+ return;
+ }
reg_w(gspca_dev, 0xff, 0x04);
reg_w(gspca_dev, 0x27, 0x80);
reg_w(gspca_dev, 0x28, 0xca);
@@ -456,187 +743,147 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, 0x2a, 0x0e);
reg_w(gspca_dev, 0xff, 0x01);
reg_w(gspca_dev, 0x3e, 0x20);
- reg_w(gspca_dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
- reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
- reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
+ reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
+ reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
+ reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
}
static void sd_stop0(struct gspca_dev *gspca_dev)
{
-}
+ struct sd *sd = (struct sd *) gspca_dev;
-/* this function is called at close time */
-static void sd_close(struct gspca_dev *gspca_dev)
-{
- reg_w(gspca_dev, 0xff, 0x04);
- reg_w(gspca_dev, 0x27, 0x80);
- reg_w(gspca_dev, 0x28, 0xca);
- reg_w(gspca_dev, 0x29, 0x53);
- reg_w(gspca_dev, 0x2a, 0x0e);
- reg_w(gspca_dev, 0xff, 0x01);
- reg_w(gspca_dev, 0x3e, 0x20);
- reg_w(gspca_dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
- reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
- reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
+ if (sd->sensor == SENSOR_PAC7302) {
+ reg_w(gspca_dev, 0xff, 0x01);
+ reg_w(gspca_dev, 0x78, 0x40);
+ }
}
+/* Include pac common sof detection functions */
+#include "pac_common.h"
+
static void do_autogain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int luma;
- int luma_mean = 128;
- int luma_delta = 20;
- __u8 spring = 5;
- int Gbright;
+ int avg_lum = atomic_read(&sd->avg_lum);
+ int desired_lum, deadzone;
- if (!atomic_read(&sd->do_gain))
+ if (avg_lum == -1)
return;
- atomic_set(&sd->do_gain, 0);
-
- luma = atomic_read(&sd->avg_lum);
- Gbright = reg_r(gspca_dev, 0x02);
- PDEBUG(D_FRAM, "luma mean %d", luma);
- if (luma < luma_mean - luma_delta ||
- luma > luma_mean + luma_delta) {
- Gbright += (luma_mean - luma) >> spring;
- if (Gbright > 0x1a)
- Gbright = 0x1a;
- else if (Gbright < 4)
- Gbright = 4;
- PDEBUG(D_FRAM, "gbright %d", Gbright);
- reg_w(gspca_dev, 0xff, 0x04);
- reg_w(gspca_dev, 0x0f, Gbright);
- /* load registers to sensor (Bit 0, auto clear) */
- reg_w(gspca_dev, 0x11, 0x01);
+
+ if (sd->sensor == SENSOR_PAC7302) {
+ desired_lum = 270 + sd->brightness * 4;
+ /* Hack hack, with the 7202 the first exposure step is
+ pretty large, so if we're about to make the first
+ exposure increase make the deadzone large to avoid
+ oscilating */
+ if (desired_lum > avg_lum && sd->gain == GAIN_DEF &&
+ sd->exposure > EXPOSURE_DEF &&
+ sd->exposure < 42)
+ deadzone = 90;
+ else
+ deadzone = 30;
+ } else {
+ desired_lum = 200;
+ deadzone = 20;
}
+
+ if (sd->autogain_ignore_frames > 0)
+ sd->autogain_ignore_frames--;
+ else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
+ deadzone, GAIN_KNEE, EXPOSURE_KNEE))
+ sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
}
+static const unsigned char pac7311_jpeg_header1[] = {
+ 0xff, 0xd8, 0xff, 0xc0, 0x00, 0x11, 0x08
+};
+
+static const unsigned char pac7311_jpeg_header2[] = {
+ 0x03, 0x01, 0x21, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xda,
+ 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00
+};
+
+/* this function is run at interrupt level */
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
struct gspca_frame *frame, /* target */
__u8 *data, /* isoc packet */
int len) /* iso packet length */
{
struct sd *sd = (struct sd *) gspca_dev;
- unsigned char tmpbuf[4];
- int i, p, ffseq;
-
-/* if (len < 5) { */
- if (len < 6) {
-/* gspca_dev->last_packet_type = DISCARD_PACKET; */
- return;
- }
-
- ffseq = sd->ffseq;
-
- for (p = 0; p < len - 6; p++) {
- if ((data[0 + p] == 0xff)
- && (data[1 + p] == 0xff)
- && (data[2 + p] == 0x00)
- && (data[3 + p] == 0xff)
- && (data[4 + p] == 0x96)) {
-
- /* start of frame */
- if (sd->ag_cnt >= 0 && p > 28) {
- sd->lum_sum += data[p - 23];
- if (--sd->ag_cnt < 0) {
- sd->ag_cnt = AG_CNT_START;
- atomic_set(&sd->avg_lum,
- sd->lum_sum / AG_CNT_START);
- sd->lum_sum = 0;
- atomic_set(&sd->do_gain, 1);
- }
- }
+ unsigned char *sof;
+
+ sof = pac_find_sof(gspca_dev, data, len);
+ if (sof) {
+ unsigned char tmpbuf[4];
+ int n, lum_offset, footer_length;
+
+ if (sd->sensor == SENSOR_PAC7302) {
+ /* 6 bytes after the FF D9 EOF marker a number of lumination
+ bytes are send corresponding to different parts of the
+ image, the 14th and 15th byte after the EOF seem to
+ correspond to the center of the image */
+ lum_offset = 61 + sizeof pac_sof_marker;
+ footer_length = 74;
+ } else {
+ lum_offset = 24 + sizeof pac_sof_marker;
+ footer_length = 26;
+ }
- /* copy the end of data to the current frame */
+ /* Finish decoding current frame */
+ n = (sof - data) - (footer_length + sizeof pac_sof_marker);
+ if (n < 0) {
+ frame->data_end += n;
+ n = 0;
+ }
+ frame = gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+ data, n);
+ if (gspca_dev->last_packet_type != DISCARD_PACKET &&
+ frame->data_end[-2] == 0xff &&
+ frame->data_end[-1] == 0xd9)
frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
- data, p);
-
- /* put the JPEG header in the new frame */
- gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
- (unsigned char *) pac7311_jpeg_header,
- 12);
+ NULL, 0);
+
+ n = sof - data;
+ len -= n;
+ data = sof;
+
+ /* Get average lumination */
+ if (gspca_dev->last_packet_type == LAST_PACKET &&
+ n >= lum_offset)
+ atomic_set(&sd->avg_lum, data[-lum_offset] +
+ data[-lum_offset + 1]);
+ else
+ atomic_set(&sd->avg_lum, -1);
+
+ /* Start the new frame with the jpeg header */
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ pac7311_jpeg_header1, sizeof(pac7311_jpeg_header1));
+ if (sd->sensor == SENSOR_PAC7302) {
+ /* The PAC7302 has the image rotated 90 degrees */
+ tmpbuf[0] = gspca_dev->width >> 8;
+ tmpbuf[1] = gspca_dev->width & 0xff;
+ tmpbuf[2] = gspca_dev->height >> 8;
+ tmpbuf[3] = gspca_dev->height & 0xff;
+ } else {
tmpbuf[0] = gspca_dev->height >> 8;
tmpbuf[1] = gspca_dev->height & 0xff;
tmpbuf[2] = gspca_dev->width >> 8;
tmpbuf[3] = gspca_dev->width & 0xff;
- gspca_frame_add(gspca_dev, INTER_PACKET, frame,
- tmpbuf, 4);
- gspca_frame_add(gspca_dev, INTER_PACKET, frame,
- (unsigned char *) &pac7311_jpeg_header[16],
- PAC7311_JPEG_HEADER_SIZE - 16);
-
- data += p + 7;
- len -= p + 7;
- ffseq = 0;
- break;
}
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame, tmpbuf, 4);
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+ pac7311_jpeg_header2, sizeof(pac7311_jpeg_header2));
}
-
- /* remove the 'ff ff ff xx' sequences */
- switch (ffseq) {
- case 3:
- data += 1;
- len -= 1;
- break;
- case 2:
- if (data[0] == 0xff) {
- data += 2;
- len -= 2;
- frame->data_end -= 2;
- }
- break;
- case 1:
- if (data[0] == 0xff
- && data[1] == 0xff) {
- data += 3;
- len -= 3;
- frame->data_end -= 1;
- }
- break;
- }
- for (i = 0; i < len - 4; i++) {
- if (data[i] == 0xff
- && data[i + 1] == 0xff
- && data[i + 2] == 0xff) {
- memmove(&data[i], &data[i + 4], len - i - 4);
- len -= 4;
- }
- }
- ffseq = 0;
- if (data[len - 4] == 0xff) {
- if (data[len - 3] == 0xff
- && data[len - 2] == 0xff) {
- len -= 4;
- }
- } else if (data[len - 3] == 0xff) {
- if (data[len - 2] == 0xff
- && data[len - 1] == 0xff)
- ffseq = 3;
- } else if (data[len - 2] == 0xff) {
- if (data[len - 1] == 0xff)
- ffseq = 2;
- } else if (data[len - 1] == 0xff)
- ffseq = 1;
- sd->ffseq = ffseq;
gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
}
-static void getbrightness(struct gspca_dev *gspca_dev)
-{
-/* sd->brightness = reg_r(gspca_dev, 0x08);
- return sd->brightness; */
-/* PDEBUG(D_CONF, "Called pac7311_getbrightness: Not implemented yet"); */
-}
-
-
-
static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
sd->brightness = val;
if (gspca_dev->streaming)
- setbrightness(gspca_dev);
+ setbrightcont(gspca_dev);
return 0;
}
@@ -644,7 +891,6 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
- getbrightness(gspca_dev);
*val = sd->brightness;
return 0;
}
@@ -654,8 +900,12 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
struct sd *sd = (struct sd *) gspca_dev;
sd->contrast = val;
- if (gspca_dev->streaming)
- setcontrast(gspca_dev);
+ if (gspca_dev->streaming) {
+ if (sd->sensor == SENSOR_PAC7302)
+ setbrightcont(gspca_dev);
+ else
+ setcontrast(gspca_dev);
+ }
return 0;
}
@@ -663,7 +913,6 @@ static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
-/* getcontrast(gspca_dev); */
*val = sd->contrast;
return 0;
}
@@ -682,18 +931,66 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
-/* getcolors(gspca_dev); */
*val = sd->colors;
return 0;
}
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->gain = val;
+ if (gspca_dev->streaming)
+ setgain(gspca_dev);
+ return 0;
+}
+
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->gain;
+ return 0;
+}
+
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->exposure = val;
+ if (gspca_dev->streaming)
+ setexposure(gspca_dev);
+ return 0;
+}
+
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->exposure;
+ return 0;
+}
+
static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
sd->autogain = val;
- if (gspca_dev->streaming)
- setautogain(gspca_dev);
+ /* when switching to autogain set defaults to make sure
+ we are on a valid point of the autogain gain /
+ exposure knee graph, and give this change time to
+ take effect before doing autogain. */
+ if (sd->autogain) {
+ sd->exposure = EXPOSURE_DEF;
+ sd->gain = GAIN_DEF;
+ if (gspca_dev->streaming) {
+ sd->autogain_ignore_frames =
+ PAC_AUTOGAIN_IGNORE_FRAMES;
+ setexposure(gspca_dev);
+ setgain(gspca_dev);
+ }
+ }
+
return 0;
}
@@ -705,30 +1002,68 @@ static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
return 0;
}
+static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->hflip = val;
+ if (gspca_dev->streaming)
+ sethvflip(gspca_dev);
+ return 0;
+}
+
+static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->hflip;
+ return 0;
+}
+
+static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->vflip = val;
+ if (gspca_dev->streaming)
+ sethvflip(gspca_dev);
+ return 0;
+}
+
+static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->vflip;
+ return 0;
+}
+
/* sub-driver description */
static struct sd_desc sd_desc = {
.name = MODULE_NAME,
.ctrls = sd_ctrls,
.nctrls = ARRAY_SIZE(sd_ctrls),
.config = sd_config,
- .open = sd_open,
+ .init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
.stop0 = sd_stop0,
- .close = sd_close,
.pkt_scan = sd_pkt_scan,
.dq_callback = do_autogain,
};
/* -- module initialisation -- */
static __devinitdata struct usb_device_id device_table[] = {
- {USB_DEVICE(0x093a, 0x2600)},
- {USB_DEVICE(0x093a, 0x2601)},
- {USB_DEVICE(0x093a, 0x2603)},
- {USB_DEVICE(0x093a, 0x2608)},
- {USB_DEVICE(0x093a, 0x260e)},
- {USB_DEVICE(0x093a, 0x260f)},
- {USB_DEVICE(0x093a, 0x2621)},
+ {USB_DEVICE(0x093a, 0x2600), .driver_info = SENSOR_PAC7311},
+ {USB_DEVICE(0x093a, 0x2601), .driver_info = SENSOR_PAC7311},
+ {USB_DEVICE(0x093a, 0x2603), .driver_info = SENSOR_PAC7311},
+ {USB_DEVICE(0x093a, 0x2608), .driver_info = SENSOR_PAC7311},
+ {USB_DEVICE(0x093a, 0x260e), .driver_info = SENSOR_PAC7311},
+ {USB_DEVICE(0x093a, 0x260f), .driver_info = SENSOR_PAC7311},
+ {USB_DEVICE(0x093a, 0x2621), .driver_info = SENSOR_PAC7302},
+ {USB_DEVICE(0x093a, 0x2624), .driver_info = SENSOR_PAC7302},
+ {USB_DEVICE(0x093a, 0x2626), .driver_info = SENSOR_PAC7302},
+ {USB_DEVICE(0x093a, 0x262a), .driver_info = SENSOR_PAC7302},
{}
};
MODULE_DEVICE_TABLE(usb, device_table);
@@ -746,6 +1081,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
/* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/pac_common.h b/drivers/media/video/gspca/pac_common.h
new file mode 100644
index 00000000000..34d4b1494cd
--- /dev/null
+++ b/drivers/media/video/gspca/pac_common.h
@@ -0,0 +1,60 @@
+/*
+ * Pixart PAC207BCA / PAC73xx common functions
+ *
+ * Copyright (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+ * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
+ * Copyleft (C) 2005 Michel Xhaard mxhaard@magic.fr
+ *
+ * V4L2 by Jean-Francois Moine <http://moinejf.free.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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You 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
+ *
+ */
+
+/* We calculate the autogain at the end of the transfer of a frame, at this
+ moment a frame with the old settings is being transmitted, and a frame is
+ being captured with the old settings. So if we adjust the autogain we must
+ ignore atleast the 2 next frames for the new settings to come into effect
+ before doing any other adjustments */
+#define PAC_AUTOGAIN_IGNORE_FRAMES 3
+
+static const unsigned char pac_sof_marker[5] =
+ { 0xff, 0xff, 0x00, 0xff, 0x96 };
+
+static unsigned char *pac_find_sof(struct gspca_dev *gspca_dev,
+ unsigned char *m, int len)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i;
+
+ /* Search for the SOF marker (fixed part) in the header */
+ for (i = 0; i < len; i++) {
+ if (m[i] == pac_sof_marker[sd->sof_read]) {
+ sd->sof_read++;
+ if (sd->sof_read == sizeof(pac_sof_marker)) {
+ PDEBUG(D_FRAM,
+ "SOF found, bytes to analyze: %u."
+ " Frame starts at byte #%u",
+ len, i + 1);
+ sd->sof_read = 0;
+ return m + i + 1;
+ }
+ } else {
+ sd->sof_read = 0;
+ }
+ }
+
+ return NULL;
+}
diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c
index 11210c71f66..12b81ae526b 100644
--- a/drivers/media/video/gspca/sonixb.c
+++ b/drivers/media/video/gspca/sonixb.c
@@ -20,6 +20,26 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+/* Some documentation on known sonixb registers:
+
+Reg Use
+0x10 high nibble red gain low nibble blue gain
+0x11 low nibble green gain
+0x12 hstart
+0x13 vstart
+0x15 hsize (hsize = register-value * 16)
+0x16 vsize (vsize = register-value * 16)
+0x17 bit 0 toggle compression quality (according to sn9c102 driver)
+0x18 bit 7 enables compression, bit 4-5 set image down scaling:
+ 00 scale 1, 01 scale 1/2, 10, scale 1/4
+0x19 high-nibble is sensor clock divider, changes exposure on sensors which
+ use a clock generated by the bridge. Some sensors have their own clock.
+0x1c auto_exposure area (for avg_lum) startx (startx = register-value * 32)
+0x1d auto_exposure area (for avg_lum) starty (starty = register-value * 32)
+0x1e auto_exposure area (for avg_lum) stopx (hsize = (0x1e - 0x1c) * 32)
+0x1f auto_exposure area (for avg_lum) stopy (vsize = (0x1f - 0x1d) * 32)
+*/
+
#define MODULE_NAME "sonixb"
#include "gspca.h"
@@ -31,10 +51,8 @@ MODULE_LICENSE("GPL");
/* specific webcam descriptor */
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
-
- struct sd_desc sd_desc; /* our nctrls differ dependend upon the
- sensor, so we use a per cam copy */
atomic_t avg_lum;
+ int prev_avg_lum;
unsigned char gain;
unsigned char exposure;
@@ -44,8 +62,12 @@ struct sd {
unsigned char frames_to_drop;
unsigned char freq; /* light freq filter setting */
- unsigned char fr_h_sz; /* size of frame header */
- char sensor; /* Type of image sensor chip */
+ __u8 bridge; /* Type of bridge */
+#define BRIDGE_101 0
+#define BRIDGE_102 0 /* We make no difference between 101 and 102 */
+#define BRIDGE_103 1
+
+ __u8 sensor; /* Type of image sensor chip */
#define SENSOR_HV7131R 0
#define SENSOR_OV6650 1
#define SENSOR_OV7630 2
@@ -53,16 +75,35 @@ struct sd {
#define SENSOR_PAS202 4
#define SENSOR_TAS5110 5
#define SENSOR_TAS5130CXX 6
- char sensor_has_gain;
- __u8 sensor_addr;
__u8 reg11;
};
-/* flags used in the device id table */
+typedef const __u8 sensor_init_t[8];
+
+struct sensor_data {
+ const __u8 *bridge_init[2];
+ int bridge_init_size[2];
+ sensor_init_t *sensor_init;
+ int sensor_init_size;
+ sensor_init_t *sensor_bridge_init[2];
+ int sensor_bridge_init_size[2];
+ int flags;
+ unsigned ctrl_dis;
+ __u8 sensor_addr;
+};
+
+/* sensor_data flags */
#define F_GAIN 0x01 /* has gain */
-#define F_AUTO 0x02 /* has autogain */
-#define F_SIF 0x04 /* sif or vga */
-#define F_H18 0x08 /* long (18 b) or short (12 b) frame header */
+#define F_SIF 0x02 /* sif or vga */
+
+/* priv field of struct v4l2_pix_format flags (do not use low nibble!) */
+#define MODE_RAW 0x10 /* raw bayer mode */
+#define MODE_REDUCED_SIF 0x20 /* vga mode (320x240 / 160x120) on sif cam */
+
+/* ctrl_dis helper macros */
+#define NO_EXPO ((1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX))
+#define NO_FREQ (1 << FREQ_IDX)
+#define NO_BRIGHTNESS (1 << BRIGHTNESS_IDX)
#define COMP2 0x8f
#define COMP 0xc7 /* 0x87 //0x07 */
@@ -73,6 +114,18 @@ struct sd {
#define SYS_CLK 0x04
+#define SENS(bridge_1, bridge_3, sensor, sensor_1, \
+ sensor_3, _flags, _ctrl_dis, _sensor_addr) \
+{ \
+ .bridge_init = { bridge_1, bridge_3 }, \
+ .bridge_init_size = { sizeof(bridge_1), sizeof(bridge_3) }, \
+ .sensor_init = sensor, \
+ .sensor_init_size = sizeof(sensor), \
+ .sensor_bridge_init = { sensor_1, sensor_3,}, \
+ .sensor_bridge_init_size = { sizeof(sensor_1), sizeof(sensor_3)}, \
+ .flags = _flags, .ctrl_dis = _ctrl_dis, .sensor_addr = _sensor_addr \
+}
+
/* We calculate the autogain at the end of the transfer of a frame, at this
moment a frame with the old settings is being transmitted, and a frame is
being captured with the old settings. So if we adjust the autogain we must
@@ -95,6 +148,7 @@ static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
static struct ctrl sd_ctrls[] = {
+#define BRIGHTNESS_IDX 0
{
{
.id = V4L2_CID_BRIGHTNESS,
@@ -109,6 +163,7 @@ static struct ctrl sd_ctrls[] = {
.set = sd_setbrightness,
.get = sd_getbrightness,
},
+#define GAIN_IDX 1
{
{
.id = V4L2_CID_GAIN,
@@ -124,6 +179,7 @@ static struct ctrl sd_ctrls[] = {
.set = sd_setgain,
.get = sd_getgain,
},
+#define EXPOSURE_IDX 2
{
{
.id = V4L2_CID_EXPOSURE,
@@ -140,6 +196,7 @@ static struct ctrl sd_ctrls[] = {
.set = sd_setexposure,
.get = sd_getexposure,
},
+#define AUTOGAIN_IDX 3
{
{
.id = V4L2_CID_AUTOGAIN,
@@ -155,6 +212,7 @@ static struct ctrl sd_ctrls[] = {
.set = sd_setautogain,
.get = sd_getautogain,
},
+#define FREQ_IDX 4
{
{
.id = V4L2_CID_POWER_LINE_FREQUENCY,
@@ -172,31 +230,56 @@ static struct ctrl sd_ctrls[] = {
};
static struct v4l2_pix_format vga_mode[] = {
- {160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
+ {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
.bytesperline = 160,
.sizeimage = 160 * 120,
.colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 2 | MODE_RAW},
+ {160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
+ .bytesperline = 160,
+ .sizeimage = 160 * 120 * 5 / 4,
+ .colorspace = V4L2_COLORSPACE_SRGB,
.priv = 2},
{320, 240, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
.bytesperline = 320,
- .sizeimage = 320 * 240,
+ .sizeimage = 320 * 240 * 5 / 4,
.colorspace = V4L2_COLORSPACE_SRGB,
.priv = 1},
{640, 480, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
.bytesperline = 640,
- .sizeimage = 640 * 480,
+ .sizeimage = 640 * 480 * 5 / 4,
.colorspace = V4L2_COLORSPACE_SRGB,
.priv = 0},
};
static struct v4l2_pix_format sif_mode[] = {
- {176, 144, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
+ {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+ .bytesperline = 160,
+ .sizeimage = 160 * 120,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1 | MODE_RAW | MODE_REDUCED_SIF},
+ {160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
+ .bytesperline = 160,
+ .sizeimage = 160 * 120 * 5 / 4,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1 | MODE_REDUCED_SIF},
+ {176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
.bytesperline = 176,
.sizeimage = 176 * 144,
.colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1 | MODE_RAW},
+ {176, 144, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
+ .bytesperline = 176,
+ .sizeimage = 176 * 144 * 5 / 4,
+ .colorspace = V4L2_COLORSPACE_SRGB,
.priv = 1},
+ {320, 240, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 5 / 4,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0 | MODE_REDUCED_SIF},
{352, 288, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
.bytesperline = 352,
- .sizeimage = 352 * 288,
+ .sizeimage = 352 * 288 * 5 / 4,
.colorspace = V4L2_COLORSPACE_SRGB,
.priv = 0},
};
@@ -204,7 +287,7 @@ static struct v4l2_pix_format sif_mode[] = {
static const __u8 initHv7131[] = {
0x46, 0x77, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00,
0x00, 0x00,
- 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, /* shift from 0x02 0x01 0x00 */
+ 0x00, 0x00, 0x00, 0x02, 0x01, 0x00,
0x28, 0x1e, 0x60, 0x8a, 0x20,
0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c
};
@@ -218,8 +301,8 @@ static const __u8 hv7131_sensor_init[][8] = {
static const __u8 initOv6650[] = {
0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x02, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x0b,
- 0x10, 0x1d, 0x10, 0x00, 0x06, 0x1f, 0x00
+ 0x00, 0x01, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x8b,
+ 0x10, 0x1d, 0x10, 0x02, 0x02, 0x09, 0x07
};
static const __u8 ov6650_sensor_init[][8] =
{
@@ -257,15 +340,15 @@ static const __u8 ov6650_sensor_init[][8] =
static const __u8 initOv7630[] = {
0x04, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, /* r01 .. r08 */
0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* r09 .. r10 */
- 0x00, 0x02, 0x01, 0x0a, /* r11 .. r14 */
+ 0x00, 0x01, 0x01, 0x0a, /* r11 .. r14 */
0x28, 0x1e, /* H & V sizes r15 .. r16 */
- 0x68, COMP1, MCK_INIT1, /* r17 .. r19 */
+ 0x68, COMP2, MCK_INIT1, /* r17 .. r19 */
0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c /* r1a .. r1f */
};
static const __u8 initOv7630_3[] = {
0x44, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0x80, /* r01 .. r08 */
0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, /* r09 .. r10 */
- 0x00, 0x01, 0x01, 0x0a, /* r11 .. r14 */
+ 0x00, 0x02, 0x01, 0x0a, /* r11 .. r14 */
0x28, 0x1e, /* H & V sizes r15 .. r16 */
0x68, 0x8f, MCK_INIT1, /* r17 .. r19 */
0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c, 0x00, /* r1a .. r20 */
@@ -294,47 +377,65 @@ static const __u8 ov7630_sensor_init[][8] = {
{0xd0, 0x21, 0x17, 0x1c, 0xbd, 0x06, 0xf6, 0x10},
};
+static const __u8 ov7630_sensor_init_3[][8] = {
+ {0xa0, 0x21, 0x13, 0x80, 0x00, 0x00, 0x00, 0x10},
+};
+
static const __u8 initPas106[] = {
0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00,
- 0x00, 0x00, 0x00, 0x05, 0x01, 0x00,
- 0x16, 0x12, 0x28, COMP1, MCK_INIT1,
- 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
+ 0x00, 0x00, 0x00, 0x04, 0x01, 0x00,
+ 0x16, 0x12, 0x24, COMP1, MCK_INIT1,
+ 0x18, 0x10, 0x02, 0x02, 0x09, 0x07
};
/* compression 0x86 mckinit1 0x2b */
-static const __u8 pas106_data[][2] = {
- {0x02, 0x04}, /* Pixel Clock Divider 6 */
- {0x03, 0x13}, /* Frame Time MSB */
-/* {0x03, 0x12}, * Frame Time MSB */
- {0x04, 0x06}, /* Frame Time LSB */
-/* {0x04, 0x05}, * Frame Time LSB */
- {0x05, 0x65}, /* Shutter Time Line Offset */
-/* {0x05, 0x6d}, * Shutter Time Line Offset */
-/* {0x06, 0xb1}, * Shutter Time Pixel Offset */
- {0x06, 0xcd}, /* Shutter Time Pixel Offset */
- {0x07, 0xc1}, /* Black Level Subtract Sign */
-/* {0x07, 0x00}, * Black Level Subtract Sign */
- {0x08, 0x06}, /* Black Level Subtract Level */
- {0x08, 0x06}, /* Black Level Subtract Level */
-/* {0x08, 0x01}, * Black Level Subtract Level */
- {0x09, 0x05}, /* Color Gain B Pixel 5 a */
- {0x0a, 0x04}, /* Color Gain G1 Pixel 1 5 */
- {0x0b, 0x04}, /* Color Gain G2 Pixel 1 0 5 */
- {0x0c, 0x05}, /* Color Gain R Pixel 3 1 */
- {0x0d, 0x00}, /* Color GainH Pixel */
- {0x0e, 0x0e}, /* Global Gain */
- {0x0f, 0x00}, /* Contrast */
- {0x10, 0x06}, /* H&V synchro polarity */
- {0x11, 0x06}, /* ?default */
- {0x12, 0x06}, /* DAC scale */
- {0x14, 0x02}, /* ?default */
- {0x13, 0x01}, /* Validate Settings */
+static const __u8 pas106_sensor_init[][8] = {
+ /* Pixel Clock Divider 6 */
+ { 0xa1, 0x40, 0x02, 0x04, 0x00, 0x00, 0x00, 0x14 },
+ /* Frame Time MSB (also seen as 0x12) */
+ { 0xa1, 0x40, 0x03, 0x13, 0x00, 0x00, 0x00, 0x14 },
+ /* Frame Time LSB (also seen as 0x05) */
+ { 0xa1, 0x40, 0x04, 0x06, 0x00, 0x00, 0x00, 0x14 },
+ /* Shutter Time Line Offset (also seen as 0x6d) */
+ { 0xa1, 0x40, 0x05, 0x65, 0x00, 0x00, 0x00, 0x14 },
+ /* Shutter Time Pixel Offset (also seen as 0xb1) */
+ { 0xa1, 0x40, 0x06, 0xcd, 0x00, 0x00, 0x00, 0x14 },
+ /* Black Level Subtract Sign (also seen 0x00) */
+ { 0xa1, 0x40, 0x07, 0xc1, 0x00, 0x00, 0x00, 0x14 },
+ /* Black Level Subtract Level (also seen 0x01) */
+ { 0xa1, 0x40, 0x08, 0x06, 0x00, 0x00, 0x00, 0x14 },
+ { 0xa1, 0x40, 0x08, 0x06, 0x00, 0x00, 0x00, 0x14 },
+ /* Color Gain B Pixel 5 a */
+ { 0xa1, 0x40, 0x09, 0x05, 0x00, 0x00, 0x00, 0x14 },
+ /* Color Gain G1 Pixel 1 5 */
+ { 0xa1, 0x40, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x14 },
+ /* Color Gain G2 Pixel 1 0 5 */
+ { 0xa1, 0x40, 0x0b, 0x04, 0x00, 0x00, 0x00, 0x14 },
+ /* Color Gain R Pixel 3 1 */
+ { 0xa1, 0x40, 0x0c, 0x05, 0x00, 0x00, 0x00, 0x14 },
+ /* Color GainH Pixel */
+ { 0xa1, 0x40, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x14 },
+ /* Global Gain */
+ { 0xa1, 0x40, 0x0e, 0x0e, 0x00, 0x00, 0x00, 0x14 },
+ /* Contrast */
+ { 0xa1, 0x40, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x14 },
+ /* H&V synchro polarity */
+ { 0xa1, 0x40, 0x10, 0x06, 0x00, 0x00, 0x00, 0x14 },
+ /* ?default */
+ { 0xa1, 0x40, 0x11, 0x06, 0x00, 0x00, 0x00, 0x14 },
+ /* DAC scale */
+ { 0xa1, 0x40, 0x12, 0x06, 0x00, 0x00, 0x00, 0x14 },
+ /* ?default */
+ { 0xa1, 0x40, 0x14, 0x02, 0x00, 0x00, 0x00, 0x14 },
+ /* Validate Settings */
+ { 0xa1, 0x40, 0x13, 0x01, 0x00, 0x00, 0x00, 0x14 },
};
+
static const __u8 initPas202[] = {
0x44, 0x44, 0x21, 0x30, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00,
- 0x00, 0x00, 0x00, 0x07, 0x03, 0x0a, /* 6 */
- 0x28, 0x1e, 0x28, 0x89, 0x30,
+ 0x00, 0x00, 0x00, 0x06, 0x03, 0x0a,
+ 0x28, 0x1e, 0x28, 0x89, 0x20,
0x00, 0x00, 0x02, 0x03, 0x0f, 0x0c
};
static const __u8 pas202_sensor_init[][8] = {
@@ -364,7 +465,7 @@ static const __u8 pas202_sensor_init[][8] = {
static const __u8 initTas5110[] = {
0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
0x00, 0x00,
- 0x00, 0x01, 0x00, 0x46, 0x09, 0x0a, /* shift from 0x45 0x09 0x0a */
+ 0x00, 0x01, 0x00, 0x45, 0x09, 0x0a,
0x16, 0x12, 0x60, 0x86, 0x2b,
0x14, 0x0a, 0x02, 0x02, 0x09, 0x07
};
@@ -377,7 +478,7 @@ static const __u8 tas5110_sensor_init[][8] = {
static const __u8 initTas5130[] = {
0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
0x00, 0x00,
- 0x00, 0x01, 0x00, 0x69, 0x0c, 0x0a,
+ 0x00, 0x01, 0x00, 0x68, 0x0c, 0x0a,
0x28, 0x1e, 0x60, COMP, MCK_INIT,
0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
};
@@ -389,6 +490,21 @@ static const __u8 tas5130_sensor_init[][8] = {
{0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10},
};
+struct sensor_data sensor_data[] = {
+SENS(initHv7131, NULL, hv7131_sensor_init, NULL, NULL, 0, NO_EXPO|NO_FREQ, 0),
+SENS(initOv6650, NULL, ov6650_sensor_init, NULL, NULL, F_GAIN|F_SIF, 0, 0x60),
+SENS(initOv7630, initOv7630_3, ov7630_sensor_init, NULL, ov7630_sensor_init_3,
+ F_GAIN, 0, 0x21),
+SENS(initPas106, NULL, pas106_sensor_init, NULL, NULL, F_SIF, NO_EXPO|NO_FREQ,
+ 0),
+SENS(initPas202, initPas202, pas202_sensor_init, NULL, NULL, 0,
+ NO_EXPO|NO_FREQ, 0),
+SENS(initTas5110, NULL, tas5110_sensor_init, NULL, NULL, F_GAIN|F_SIF,
+ NO_BRIGHTNESS|NO_FREQ, 0),
+SENS(initTas5130, NULL, tas5130_sensor_init, NULL, NULL, 0, NO_EXPO|NO_FREQ,
+ 0),
+};
+
/* get one byte in gspca_dev->usb_buf */
static void reg_r(struct gspca_dev *gspca_dev,
__u16 value)
@@ -409,7 +525,7 @@ static void reg_w(struct gspca_dev *gspca_dev,
int len)
{
#ifdef GSPCA_DEBUG
- if (len > sizeof gspca_dev->usb_buf) {
+ if (len > USB_BUF_SZ) {
PDEBUG(D_ERR|D_PACK, "reg_w: buffer overflow");
return;
}
@@ -425,26 +541,6 @@ static void reg_w(struct gspca_dev *gspca_dev,
500);
}
-static void reg_w_big(struct gspca_dev *gspca_dev,
- __u16 value,
- const __u8 *buffer,
- int len)
-{
- __u8 *tmpbuf;
-
- tmpbuf = kmalloc(len, GFP_KERNEL);
- memcpy(tmpbuf, buffer, len);
- usb_control_msg(gspca_dev->dev,
- usb_sndctrlpipe(gspca_dev->dev, 0),
- 0x08, /* request */
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
- value,
- 0, /* index */
- tmpbuf, len,
- 500);
- kfree(tmpbuf);
-}
-
static int i2c_w(struct gspca_dev *gspca_dev, const __u8 *buffer)
{
int retry = 60;
@@ -487,7 +583,7 @@ static void setbrightness(struct gspca_dev *gspca_dev)
{0xa0, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10};
/* change reg 0x06 */
- i2cOV[1] = sd->sensor_addr;
+ i2cOV[1] = sensor_data[sd->sensor].sensor_addr;
i2cOV[3] = sd->brightness;
if (i2c_w(gspca_dev, i2cOV) < 0)
goto err;
@@ -545,9 +641,6 @@ static void setbrightness(struct gspca_dev *gspca_dev)
goto err;
break;
}
- case SENSOR_TAS5110:
- /* FIXME figure out howto control brightness on TAS5110 */
- break;
}
return;
err:
@@ -577,7 +670,7 @@ static void setsensorgain(struct gspca_dev *gspca_dev)
case SENSOR_OV7630: {
__u8 i2c[] = {0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
- i2c[1] = sd->sensor_addr;
+ i2c[1] = sensor_data[sd->sensor].sensor_addr;
i2c[3] = gain >> 2;
if (i2c_w(gspca_dev, i2c) < 0)
goto err;
@@ -604,7 +697,7 @@ static void setgain(struct gspca_dev *gspca_dev)
rgb_value = gain;
reg_w(gspca_dev, 0x11, &rgb_value, 1);
- if (sd->sensor_has_gain)
+ if (sensor_data[sd->sensor].flags & F_GAIN)
setsensorgain(gspca_dev);
}
@@ -665,6 +758,11 @@ static void setexposure(struct gspca_dev *gspca_dev)
else if (reg11 > 16)
reg11 = 16;
+ /* In 640x480, if the reg11 has less than 3, the image is
+ unstable (not enough bandwidth). */
+ if (gspca_dev->width == 640 && reg11 < 3)
+ reg11 = 3;
+
/* frame exposure time in ms = 1000 * reg11 / 30 ->
reg10 = sd->exposure * 2 * reg10_max / (1000 * reg11 / 30) */
reg10 = (sd->exposure * 60 * reg10_max) / (1000 * reg11);
@@ -678,13 +776,8 @@ static void setexposure(struct gspca_dev *gspca_dev)
else if (reg10 > reg10_max)
reg10 = reg10_max;
- /* In 640x480, if the reg11 has less than 3, the image is
- unstable (not enough bandwidth). */
- if (gspca_dev->width == 640 && reg11 < 3)
- reg11 = 3;
-
/* Write reg 10 and reg11 low nibble */
- i2c[1] = sd->sensor_addr;
+ i2c[1] = sensor_data[sd->sensor].sensor_addr;
i2c[3] = reg10;
i2c[4] |= reg11 - 1;
@@ -724,7 +817,7 @@ static void setfreq(struct gspca_dev *gspca_dev)
? 0x4f : 0x8a;
break;
}
- i2c[1] = sd->sensor_addr;
+ i2c[1] = sensor_data[sd->sensor].sensor_addr;
if (i2c_w(gspca_dev, i2c) < 0)
PDEBUG(D_ERR, "i2c error setfreq");
break;
@@ -757,30 +850,19 @@ static int sd_config(struct gspca_dev *gspca_dev,
{
struct sd *sd = (struct sd *) gspca_dev;
struct cam *cam;
- int sif = 0;
- /* nctrls depends upon the sensor, so we use a per cam copy */
- memcpy(&sd->sd_desc, gspca_dev->sd_desc, sizeof(struct sd_desc));
- gspca_dev->sd_desc = &sd->sd_desc;
+ reg_r(gspca_dev, 0x00);
+ if (gspca_dev->usb_buf[0] != 0x10)
+ return -ENODEV;
/* copy the webcam info from the device id */
- sd->sensor = (id->driver_info >> 24) & 0xff;
- if (id->driver_info & (F_GAIN << 16))
- sd->sensor_has_gain = 1;
- if (id->driver_info & (F_AUTO << 16))
- sd->sd_desc.dq_callback = do_autogain;
- if (id->driver_info & (F_SIF << 16))
- sif = 1;
- if (id->driver_info & (F_H18 << 16))
- sd->fr_h_sz = 18; /* size of frame header */
- else
- sd->fr_h_sz = 12;
- sd->sd_desc.nctrls = (id->driver_info >> 8) & 0xff;
- sd->sensor_addr = id->driver_info & 0xff;
+ sd->sensor = id->driver_info >> 8;
+ sd->bridge = id->driver_info & 0xff;
+ gspca_dev->ctrl_dis = sensor_data[sd->sensor].ctrl_dis;
cam = &gspca_dev->cam;
cam->epaddr = 0x01;
- if (!sif) {
+ if (!(sensor_data[sd->sensor].flags & F_SIF)) {
cam->cam_mode = vga_mode;
cam->nmodes = ARRAY_SIZE(vga_mode);
} else {
@@ -790,157 +872,98 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->brightness = BRIGHTNESS_DEF;
sd->gain = GAIN_DEF;
sd->exposure = EXPOSURE_DEF;
- sd->autogain = AUTOGAIN_DEF;
+ if (gspca_dev->ctrl_dis & (1 << AUTOGAIN_IDX))
+ sd->autogain = 0; /* Disable do_autogain callback */
+ else
+ sd->autogain = AUTOGAIN_DEF;
sd->freq = FREQ_DEF;
return 0;
}
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
{
- reg_r(gspca_dev, 0x00);
- if (gspca_dev->usb_buf[0] != 0x10)
- return -ENODEV;
- return 0;
-}
+ const __u8 stop = 0x09; /* Disable stream turn of LED */
-static void pas106_i2cinit(struct gspca_dev *gspca_dev)
-{
- int i;
- const __u8 *data;
- __u8 i2c1[] = { 0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14 };
-
- i = ARRAY_SIZE(pas106_data);
- data = pas106_data[0];
- while (--i >= 0) {
- memcpy(&i2c1[2], data, 2);
- /* copy 2 bytes from the template */
- if (i2c_w(gspca_dev, i2c1) < 0)
- PDEBUG(D_ERR, "i2c error pas106");
- data += 2;
- }
+ reg_w(gspca_dev, 0x01, &stop, 1);
+
+ return 0;
}
/* -- start the camera -- */
static void sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int mode, l = 0x1f;
+ struct cam *cam = &gspca_dev->cam;
+ int mode, l;
const __u8 *sn9c10x;
- __u8 reg17_19[3];
-
- mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+ __u8 reg12_19[8];
+
+ mode = cam->cam_mode[gspca_dev->curr_mode].priv & 0x07;
+ sn9c10x = sensor_data[sd->sensor].bridge_init[sd->bridge];
+ l = sensor_data[sd->sensor].bridge_init_size[sd->bridge];
+ memcpy(reg12_19, &sn9c10x[0x12 - 1], 8);
+ reg12_19[6] = sn9c10x[0x18 - 1] | (mode << 4);
+ /* Special cases where reg 17 and or 19 value depends on mode */
switch (sd->sensor) {
- case SENSOR_HV7131R:
- sn9c10x = initHv7131;
- reg17_19[0] = 0x60;
- reg17_19[1] = (mode << 4) | 0x8a;
- reg17_19[2] = 0x20;
- break;
- case SENSOR_OV6650:
- sn9c10x = initOv6650;
- reg17_19[0] = 0x68;
- reg17_19[1] = (mode << 4) | 0x8b;
- reg17_19[2] = 0x20;
- break;
- case SENSOR_OV7630:
- if (sd->fr_h_sz == 18) { /* SN9C103 */
- sn9c10x = initOv7630_3;
- l = sizeof initOv7630_3;
- } else
- sn9c10x = initOv7630;
- reg17_19[0] = 0x68;
- reg17_19[1] = (mode << 4) | COMP2;
- reg17_19[2] = MCK_INIT1;
- break;
- case SENSOR_PAS106:
- sn9c10x = initPas106;
- reg17_19[0] = 0x24; /* 0x28 */
- reg17_19[1] = (mode << 4) | COMP1;
- reg17_19[2] = MCK_INIT1;
- break;
case SENSOR_PAS202:
- sn9c10x = initPas202;
- reg17_19[0] = mode ? 0x24 : 0x20;
- reg17_19[1] = (mode << 4) | 0x89;
- reg17_19[2] = 0x20;
+ reg12_19[5] = mode ? 0x24 : 0x20;
break;
- case SENSOR_TAS5110:
- sn9c10x = initTas5110;
- reg17_19[0] = 0x60;
- reg17_19[1] = (mode << 4) | 0x86;
- reg17_19[2] = 0x2b; /* 0xf3; */
- break;
- default:
-/* case SENSOR_TAS5130CXX: */
- sn9c10x = initTas5130;
- reg17_19[0] = 0x60;
- reg17_19[1] = (mode << 4) | COMP;
- reg17_19[2] = mode ? 0x23 : 0x43;
+ case SENSOR_TAS5130CXX:
+ /* probably not mode specific at all most likely the upper
+ nibble of 0x19 is exposure (clock divider) just as with
+ the tas5110, we need someone to test this. */
+ reg12_19[7] = mode ? 0x23 : 0x43;
break;
}
+ /* Disable compression when the raw bayer format has been selected */
+ if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW)
+ reg12_19[6] &= ~0x80;
+
+ /* Vga mode emulation on SIF sensor? */
+ if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_REDUCED_SIF) {
+ reg12_19[0] += 16; /* 0x12: hstart adjust */
+ reg12_19[1] += 24; /* 0x13: vstart adjust */
+ reg12_19[3] = 320 / 16; /* 0x15: hsize */
+ reg12_19[4] = 240 / 16; /* 0x16: vsize */
+ }
/* reg 0x01 bit 2 video transfert on */
reg_w(gspca_dev, 0x01, &sn9c10x[0x01 - 1], 1);
/* reg 0x17 SensorClk enable inv Clk 0x60 */
reg_w(gspca_dev, 0x17, &sn9c10x[0x17 - 1], 1);
/* Set the registers from the template */
- reg_w_big(gspca_dev, 0x01, sn9c10x, l);
- switch (sd->sensor) {
- case SENSOR_HV7131R:
- i2c_w_vector(gspca_dev, hv7131_sensor_init,
- sizeof hv7131_sensor_init);
- break;
- case SENSOR_OV6650:
- i2c_w_vector(gspca_dev, ov6650_sensor_init,
- sizeof ov6650_sensor_init);
- break;
- case SENSOR_OV7630:
- i2c_w_vector(gspca_dev, ov7630_sensor_init,
- sizeof ov7630_sensor_init);
- if (sd->fr_h_sz == 18) { /* SN9C103 */
- const __u8 i2c[] = { 0xa0, 0x21, 0x13, 0x80, 0x00,
- 0x00, 0x00, 0x10 };
- i2c_w(gspca_dev, i2c);
- }
- break;
- case SENSOR_PAS106:
- pas106_i2cinit(gspca_dev);
- break;
- case SENSOR_PAS202:
- i2c_w_vector(gspca_dev, pas202_sensor_init,
- sizeof pas202_sensor_init);
- break;
- case SENSOR_TAS5110:
- i2c_w_vector(gspca_dev, tas5110_sensor_init,
- sizeof tas5110_sensor_init);
- break;
- default:
-/* case SENSOR_TAS5130CXX: */
- i2c_w_vector(gspca_dev, tas5130_sensor_init,
- sizeof tas5130_sensor_init);
- break;
- }
+ reg_w(gspca_dev, 0x01, sn9c10x, l);
+
+ /* Init the sensor */
+ i2c_w_vector(gspca_dev, sensor_data[sd->sensor].sensor_init,
+ sensor_data[sd->sensor].sensor_init_size);
+ if (sensor_data[sd->sensor].sensor_bridge_init[sd->bridge])
+ i2c_w_vector(gspca_dev,
+ sensor_data[sd->sensor].sensor_bridge_init[sd->bridge],
+ sensor_data[sd->sensor].sensor_bridge_init_size[
+ sd->bridge]);
+
/* H_size V_size 0x28, 0x1e -> 640x480. 0x16, 0x12 -> 352x288 */
- reg_w(gspca_dev, 0x15, &sn9c10x[0x15 - 1], 2);
+ reg_w(gspca_dev, 0x15, &reg12_19[3], 2);
/* compression register */
- reg_w(gspca_dev, 0x18, &reg17_19[1], 1);
+ reg_w(gspca_dev, 0x18, &reg12_19[6], 1);
/* H_start */
- reg_w(gspca_dev, 0x12, &sn9c10x[0x12 - 1], 1);
+ reg_w(gspca_dev, 0x12, &reg12_19[0], 1);
/* V_START */
- reg_w(gspca_dev, 0x13, &sn9c10x[0x13 - 1], 1);
+ reg_w(gspca_dev, 0x13, &reg12_19[1], 1);
/* reset 0x17 SensorClk enable inv Clk 0x60 */
/*fixme: ov7630 [17]=68 8f (+20 if 102)*/
- reg_w(gspca_dev, 0x17, &reg17_19[0], 1);
+ reg_w(gspca_dev, 0x17, &reg12_19[5], 1);
/*MCKSIZE ->3 */ /*fixme: not ov7630*/
- reg_w(gspca_dev, 0x19, &reg17_19[2], 1);
+ reg_w(gspca_dev, 0x19, &reg12_19[7], 1);
/* AE_STRX AE_STRY AE_ENDX AE_ENDY */
reg_w(gspca_dev, 0x1c, &sn9c10x[0x1c - 1], 4);
/* Enable video transfert */
reg_w(gspca_dev, 0x01, &sn9c10x[0], 1);
/* Compression */
- reg_w(gspca_dev, 0x18, &reg17_19[1], 2);
+ reg_w(gspca_dev, 0x18, &reg12_19[6], 2);
msleep(20);
sd->reg11 = -1;
@@ -957,18 +980,7 @@ static void sd_start(struct gspca_dev *gspca_dev)
static void sd_stopN(struct gspca_dev *gspca_dev)
{
- __u8 ByteSend;
-
- ByteSend = 0x09; /* 0X00 */
- reg_w(gspca_dev, 0x01, &ByteSend, 1);
-}
-
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-static void sd_close(struct gspca_dev *gspca_dev)
-{
+ sd_init(gspca_dev);
}
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
@@ -978,6 +990,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
{
int i;
struct sd *sd = (struct sd *) gspca_dev;
+ struct cam *cam = &gspca_dev->cam;
/* frames start with:
* ff ff 00 c4 c4 96 synchro
@@ -998,20 +1011,31 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
&& data[5 + i] == 0x96) { /* start of frame */
int lum = -1;
int pkt_type = LAST_PACKET;
+ int fr_h_sz = (sd->bridge == BRIDGE_103) ?
+ 18 : 12;
- if (len - i < sd->fr_h_sz) {
+ if (len - i < fr_h_sz) {
PDEBUG(D_STREAM, "packet too short to"
" get avg brightness");
- } else if (sd->fr_h_sz == 12) {
- lum = data[i + 8] + (data[i + 9] << 8);
- } else {
+ } else if (sd->bridge == BRIDGE_103) {
lum = data[i + 9] +
(data[i + 10] << 8);
+ } else {
+ lum = data[i + 8] + (data[i + 9] << 8);
}
- if (lum == 0) {
+ /* When exposure changes midway a frame we
+ get a lum of 0 in this case drop 2 frames
+ as the frames directly after an exposure
+ change have an unstable image. Sometimes lum
+ *really* is 0 (cam used in low light with
+ low exposure setting), so do not drop frames
+ if the previous lum was 0 too. */
+ if (lum == 0 && sd->prev_avg_lum != 0) {
lum = -1;
sd->frames_to_drop = 2;
- }
+ sd->prev_avg_lum = 0;
+ } else
+ sd->prev_avg_lum = lum;
atomic_set(&sd->avg_lum, lum);
if (sd->frames_to_drop) {
@@ -1021,14 +1045,25 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
frame = gspca_frame_add(gspca_dev, pkt_type,
frame, data, 0);
- data += i + sd->fr_h_sz;
- len -= i + sd->fr_h_sz;
+ data += i + fr_h_sz;
+ len -= i + fr_h_sz;
gspca_frame_add(gspca_dev, FIRST_PACKET,
frame, data, len);
return;
}
}
}
+
+ if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW) {
+ /* In raw mode we sometimes get some garbage after the frame
+ ignore this */
+ int used = frame->data_end - frame->data;
+ int size = cam->cam_mode[gspca_dev->curr_mode].sizeimage;
+
+ if (used + len > size)
+ len = size - used;
+ }
+
gspca_frame_add(gspca_dev, INTER_PACKET,
frame, data, len);
}
@@ -1162,58 +1197,45 @@ static const struct sd_desc sd_desc = {
.ctrls = sd_ctrls,
.nctrls = ARRAY_SIZE(sd_ctrls),
.config = sd_config,
- .open = sd_open,
+ .init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
- .stop0 = sd_stop0,
- .close = sd_close,
.pkt_scan = sd_pkt_scan,
.querymenu = sd_querymenu,
+ .dq_callback = do_autogain,
};
/* -- module initialisation -- */
-#define SFCI(sensor, flags, nctrls, i2c_addr) \
- .driver_info = (SENSOR_ ## sensor << 24) \
- | ((flags) << 16) \
- | ((nctrls) << 8) \
- | (i2c_addr)
+#define SB(sensor, bridge) \
+ .driver_info = (SENSOR_ ## sensor << 8) | BRIDGE_ ## bridge
+
+
static __devinitdata struct usb_device_id device_table[] = {
-#ifndef CONFIG_USB_SN9C102
- {USB_DEVICE(0x0c45, 0x6001), /* SN9C102 */
- SFCI(TAS5110, F_GAIN|F_AUTO|F_SIF, 4, 0)},
- {USB_DEVICE(0x0c45, 0x6005), /* SN9C101 */
- SFCI(TAS5110, F_GAIN|F_AUTO|F_SIF, 4, 0)},
- {USB_DEVICE(0x0c45, 0x6007), /* SN9C101 */
- SFCI(TAS5110, F_GAIN|F_AUTO|F_SIF, 4, 0)},
- {USB_DEVICE(0x0c45, 0x6009), /* SN9C101 */
- SFCI(PAS106, F_SIF, 2, 0)},
- {USB_DEVICE(0x0c45, 0x600d), /* SN9C101 */
- SFCI(PAS106, F_SIF, 2, 0)},
+ {USB_DEVICE(0x0c45, 0x6001), SB(TAS5110, 102)}, /* TAS5110C1B */
+ {USB_DEVICE(0x0c45, 0x6005), SB(TAS5110, 101)}, /* TAS5110C1B */
+#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
+ {USB_DEVICE(0x0c45, 0x6007), SB(TAS5110, 101)}, /* TAS5110D */
+ {USB_DEVICE(0x0c45, 0x6009), SB(PAS106, 101)},
+ {USB_DEVICE(0x0c45, 0x600d), SB(PAS106, 101)},
#endif
- {USB_DEVICE(0x0c45, 0x6011), /* SN9C101 - SN9C101G */
- SFCI(OV6650, F_GAIN|F_AUTO|F_SIF, 5, 0x60)},
-#ifndef CONFIG_USB_SN9C102
- {USB_DEVICE(0x0c45, 0x6019), /* SN9C101 */
- SFCI(OV7630, F_GAIN|F_AUTO, 5, 0x21)},
- {USB_DEVICE(0x0c45, 0x6024), /* SN9C102 */
- SFCI(TAS5130CXX, 0, 2, 0)},
- {USB_DEVICE(0x0c45, 0x6025), /* SN9C102 */
- SFCI(TAS5130CXX, 0, 2, 0)},
- {USB_DEVICE(0x0c45, 0x6028), /* SN9C102 */
- SFCI(PAS202, 0, 2, 0)},
- {USB_DEVICE(0x0c45, 0x6029), /* SN9C101 */
- SFCI(PAS106, F_SIF, 2, 0)},
- {USB_DEVICE(0x0c45, 0x602c), /* SN9C102 */
- SFCI(OV7630, F_GAIN|F_AUTO, 5, 0x21)},
- {USB_DEVICE(0x0c45, 0x602d), /* SN9C102 */
- SFCI(HV7131R, 0, 2, 0)},
- {USB_DEVICE(0x0c45, 0x602e), /* SN9C102 */
- SFCI(OV7630, F_GAIN|F_AUTO, 5, 0x21)},
- {USB_DEVICE(0x0c45, 0x60af), /* SN9C103 */
- SFCI(PAS202, F_H18, 2, 0)},
- {USB_DEVICE(0x0c45, 0x60b0), /* SN9C103 */
- SFCI(OV7630, F_GAIN|F_AUTO|F_H18, 5, 0x21)},
+ {USB_DEVICE(0x0c45, 0x6011), SB(OV6650, 101)},
+#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
+ {USB_DEVICE(0x0c45, 0x6019), SB(OV7630, 101)},
+ {USB_DEVICE(0x0c45, 0x6024), SB(TAS5130CXX, 102)},
+ {USB_DEVICE(0x0c45, 0x6025), SB(TAS5130CXX, 102)},
+ {USB_DEVICE(0x0c45, 0x6028), SB(PAS202, 102)},
+ {USB_DEVICE(0x0c45, 0x6029), SB(PAS106, 102)},
+ {USB_DEVICE(0x0c45, 0x602c), SB(OV7630, 102)},
#endif
+ {USB_DEVICE(0x0c45, 0x602d), SB(HV7131R, 102)},
+#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
+ {USB_DEVICE(0x0c45, 0x602e), SB(OV7630, 102)},
+#endif
+ {USB_DEVICE(0x0c45, 0x608f), SB(OV7630, 103)},
+#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
+ {USB_DEVICE(0x0c45, 0x60af), SB(PAS202, 103)},
+#endif
+ {USB_DEVICE(0x0c45, 0x60b0), SB(OV7630, 103)},
{}
};
MODULE_DEVICE_TABLE(usb, device_table);
@@ -1231,6 +1253,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
/* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c
index 245a30ec5fb..572b0f363b6 100644
--- a/drivers/media/video/gspca/sonixj.c
+++ b/drivers/media/video/gspca/sonixj.c
@@ -54,8 +54,10 @@ struct sd {
#define SENSOR_HV7131R 0
#define SENSOR_MI0360 1
#define SENSOR_MO4000 2
-#define SENSOR_OV7648 3
-#define SENSOR_OV7660 4
+#define SENSOR_OM6802 3
+#define SENSOR_OV7630 4
+#define SENSOR_OV7648 5
+#define SENSOR_OV7660 6
unsigned char i2c_base;
};
@@ -76,7 +78,8 @@ static struct ctrl sd_ctrls[] = {
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Brightness",
.minimum = 0,
- .maximum = 0xffff,
+#define BRIGHTNESS_MAX 0xffff
+ .maximum = BRIGHTNESS_MAX,
.step = 1,
#define BRIGHTNESS_DEF 0x7fff
.default_value = BRIGHTNESS_DEF,
@@ -90,7 +93,8 @@ static struct ctrl sd_ctrls[] = {
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Contrast",
.minimum = 0,
- .maximum = 127,
+#define CONTRAST_MAX 127
+ .maximum = CONTRAST_MAX,
.step = 1,
#define CONTRAST_DEF 63
.default_value = CONTRAST_DEF,
@@ -104,14 +108,15 @@ static struct ctrl sd_ctrls[] = {
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Color",
.minimum = 0,
- .maximum = 255,
+ .maximum = 64,
.step = 1,
-#define COLOR_DEF 127
+#define COLOR_DEF 32
.default_value = COLOR_DEF,
},
.set = sd_setcolors,
.get = sd_getcolors,
},
+#define AUTOGAIN_IDX 3
{
{
.id = V4L2_CID_AUTOGAIN,
@@ -131,7 +136,7 @@ static struct ctrl sd_ctrls[] = {
static struct v4l2_pix_format vga_mode[] = {
{160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 160,
- .sizeimage = 160 * 120 * 3 / 8 + 590,
+ .sizeimage = 160 * 120 * 4 / 8 + 590,
.colorspace = V4L2_COLORSPACE_JPEG,
.priv = 2},
{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
@@ -180,6 +185,31 @@ static const __u8 sn_mo4000[] = {
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
+static const __u8 sn_om6802[] = {
+/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
+ 0x00, 0x23, 0x72, 0x00, 0x1a, 0x34, 0x27, 0x20,
+/* reg8 reg9 rega regb regc regd rege regf */
+ 0x80, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */
+ 0x03, 0x00, 0x51, 0x01, 0x00, 0x28, 0x1e, 0x40,
+/* reg18 reg19 reg1a reg1b reg1c reg1d reg1e reg1f */
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x22, 0x44, 0x63, 0x7d, 0x92, 0xa3, 0xaf,
+ 0xbc, 0xc4, 0xcd, 0xd5, 0xdc, 0xe1, 0xe8, 0xef,
+ 0xf7
+};
+
+static const __u8 sn_ov7630[] = {
+/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
+ 0x00, 0x21, 0x40, 0x00, 0x1a, 0x20, 0x1f, 0x20,
+/* reg8 reg9 rega regb regc regd rege regf */
+ 0xa1, 0x21, 0x76, 0x21, 0x00, 0x00, 0x00, 0x10,
+/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */
+ 0x03, 0x00, 0x04, 0x01, 0x0a, 0x28, 0x1e, 0xc2,
+/* reg18 reg19 reg1a reg1b reg1c reg1d reg1e reg1f */
+ 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
static const __u8 sn_ov7648[] = {
/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
0x00, 0x21, 0x62, 0x00, 0x1a, 0x20, 0x20, 0x20,
@@ -207,31 +237,22 @@ static const __u8 *sn_tb[] = {
sn_hv7131,
sn_mi0360,
sn_mo4000,
+ sn_om6802,
+ sn_ov7630,
sn_ov7648,
sn_ov7660
};
-static const __u8 regsn20[] = {
+static const __u8 gamma_def[] = {
0x00, 0x2d, 0x46, 0x5a, 0x6c, 0x7c, 0x8b, 0x99,
0xa6, 0xb2, 0xbf, 0xca, 0xd5, 0xe0, 0xeb, 0xf5, 0xff
};
-static const __u8 regsn20_sn9c325[] = {
- 0x0a, 0x3a, 0x56, 0x6c, 0x7e, 0x8d, 0x9a, 0xa4,
- 0xaf, 0xbb, 0xc5, 0xcd, 0xd5, 0xde, 0xe8, 0xed, 0xf5
-};
static const __u8 reg84[] = {
0x14, 0x00, 0x27, 0x00, 0x07, 0x00, 0xe5, 0x0f,
0xe4, 0x0f, 0x38, 0x00, 0x3e, 0x00, 0xc3, 0x0f,
-/* 0x00, 0x00, 0x00, 0x00, 0x00 */
- 0xf7, 0x0f, 0x0a, 0x00, 0x00
-};
-static const __u8 reg84_sn9c325[] = {
- 0x14, 0x00, 0x27, 0x00, 0x07, 0x00, 0xe4, 0x0f,
- 0xd3, 0x0f, 0x4b, 0x00, 0x48, 0x00, 0xc0, 0x0f,
- 0xf8, 0x0f, 0x00, 0x00, 0x00
+ 0xf7, 0x0f, 0x00, 0x00, 0x00
};
-
static const __u8 hv7131r_sensor_init[][8] = {
{0xC1, 0x11, 0x01, 0x08, 0x01, 0x00, 0x00, 0x10},
{0xB1, 0x11, 0x34, 0x17, 0x7F, 0x00, 0x00, 0x10},
@@ -340,6 +361,92 @@ static const __u8 mo4000_sensor_init[][8] = {
{0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10},
{}
};
+static __u8 om6802_sensor_init[][8] = {
+ {0xa0, 0x34, 0x90, 0x05, 0x00, 0x00, 0x00, 0x10},
+ {0xa0, 0x34, 0x49, 0x85, 0x00, 0x00, 0x00, 0x10},
+ {0xa0, 0x34, 0x5a, 0xc0, 0x00, 0x00, 0x00, 0x10},
+ {0xa0, 0x34, 0xdd, 0x18, 0x00, 0x00, 0x00, 0x10},
+/* {0xa0, 0x34, 0xfb, 0x11, 0x00, 0x00, 0x00, 0x10}, */
+ {0xa0, 0x34, 0xf0, 0x04, 0x00, 0x00, 0x00, 0x10},
+ /* white balance & auto-exposure */
+/* {0xa0, 0x34, 0xf1, 0x02, 0x00, 0x00, 0x00, 0x10},
+ * set color mode */
+/* {0xa0, 0x34, 0xfe, 0x5b, 0x00, 0x00, 0x00, 0x10},
+ * max AGC value in AE */
+/* {0xa0, 0x34, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x10},
+ * preset AGC */
+/* {0xa0, 0x34, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x10},
+ * preset brightness */
+/* {0xa0, 0x34, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x10},
+ * preset contrast */
+/* {0xa0, 0x34, 0xe8, 0x31, 0x00, 0x00, 0x00, 0x10},
+ * preset gamma */
+ {0xa0, 0x34, 0xe9, 0x0f, 0x00, 0x00, 0x00, 0x10},
+ /* luminance mode (0x4f = AE) */
+ {0xa0, 0x34, 0xe4, 0xff, 0x00, 0x00, 0x00, 0x10},
+ /* preset shutter */
+/* {0xa0, 0x34, 0xef, 0x00, 0x00, 0x00, 0x00, 0x10},
+ * auto frame rate */
+/* {0xa0, 0x34, 0xfb, 0xee, 0x00, 0x00, 0x00, 0x10}, */
+
+/* {0xa0, 0x34, 0x71, 0x84, 0x00, 0x00, 0x00, 0x10}, */
+/* {0xa0, 0x34, 0x72, 0x05, 0x00, 0x00, 0x00, 0x10}, */
+/* {0xa0, 0x34, 0x68, 0x80, 0x00, 0x00, 0x00, 0x10}, */
+/* {0xa0, 0x34, 0x69, 0x01, 0x00, 0x00, 0x00, 0x10}, */
+ {}
+};
+static const __u8 ov7630_sensor_init[][8] = {
+ {0xa1, 0x21, 0x76, 0x01, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x12, 0xc8, 0x00, 0x00, 0x00, 0x10},
+/* win: delay 20ms */
+ {0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x12, 0xc8, 0x00, 0x00, 0x00, 0x10},
+/* win: delay 20ms */
+ {0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10},
+/* win: i2c_r from 00 to 80 */
+ {0xd1, 0x21, 0x03, 0x80, 0x10, 0x20, 0x80, 0x10},
+ {0xb1, 0x21, 0x0c, 0x20, 0x20, 0x00, 0x00, 0x10},
+ {0xd1, 0x21, 0x11, 0x00, 0x48, 0xc0, 0x00, 0x10},
+ {0xb1, 0x21, 0x15, 0x80, 0x03, 0x00, 0x00, 0x10},
+ {0xd1, 0x21, 0x17, 0x1b, 0xbd, 0x05, 0xf6, 0x10},
+ {0xa1, 0x21, 0x1b, 0x04, 0x00, 0x00, 0x00, 0x10},
+ {0xd1, 0x21, 0x1f, 0x00, 0x80, 0x80, 0x80, 0x10},
+ {0xd1, 0x21, 0x23, 0xde, 0x10, 0x8a, 0xa0, 0x10},
+ {0xc1, 0x21, 0x27, 0xca, 0xa2, 0x74, 0x00, 0x10},
+ {0xd1, 0x21, 0x2a, 0x88, 0x00, 0x88, 0x01, 0x10},
+ {0xc1, 0x21, 0x2e, 0x80, 0x00, 0x18, 0x00, 0x10},
+ {0xa1, 0x21, 0x21, 0x08, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xb1, 0x21, 0x32, 0xc2, 0x08, 0x00, 0x00, 0x10},
+ {0xb1, 0x21, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xd1, 0x21, 0x60, 0x05, 0x40, 0x12, 0x57, 0x10},
+ {0xa1, 0x21, 0x64, 0x73, 0x00, 0x00, 0x00, 0x10},
+ {0xd1, 0x21, 0x65, 0x00, 0x55, 0x01, 0xac, 0x10},
+ {0xa1, 0x21, 0x69, 0x38, 0x00, 0x00, 0x00, 0x10},
+ {0xd1, 0x21, 0x6f, 0x1f, 0x01, 0x00, 0x10, 0x10},
+ {0xd1, 0x21, 0x73, 0x50, 0x20, 0x02, 0x01, 0x10},
+ {0xd1, 0x21, 0x77, 0xf3, 0x90, 0x98, 0x98, 0x10},
+ {0xc1, 0x21, 0x7b, 0x00, 0x4c, 0xf7, 0x00, 0x10},
+ {0xd1, 0x21, 0x17, 0x1b, 0xbd, 0x05, 0xf6, 0x10},
+ {0xa1, 0x21, 0x1b, 0x04, 0x00, 0x00, 0x00, 0x10},
+/* */
+ {0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10},
+/*fixme: + 0x12, 0x04*/
+ {0xa1, 0x21, 0x75, 0x82, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x10, 0x32, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xb1, 0x21, 0x01, 0x80, 0x80, 0x00, 0x00, 0x10},
+/* */
+ {0xa1, 0x21, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x2a, 0x88, 0x00, 0x00, 0x00, 0x10},
+ {0xa1, 0x21, 0x2b, 0x34, 0x00, 0x00, 0x00, 0x10},
+/* */
+ {0xa1, 0x21, 0x10, 0x83, 0x00, 0x00, 0x00, 0x10},
+/* {0xb1, 0x21, 0x01, 0x88, 0x70, 0x00, 0x00, 0x10}, */
+ {}
+};
static const __u8 ov7660_sensor_init[][8] = {
{0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset SCCB */
/* (delay 20ms) */
@@ -506,10 +613,16 @@ static const __u8 qtable4[] = {
0x29, 0x29, 0x29, 0x29
};
-/* read <len> bytes (len < sizeof gspca_dev->usb_buf) to gspca_dev->usb_buf */
+/* read <len> bytes to gspca_dev->usb_buf */
static void reg_r(struct gspca_dev *gspca_dev,
__u16 value, int len)
{
+#ifdef GSPCA_DEBUG
+ if (len > USB_BUF_SZ) {
+ err("reg_r: buffer overflow");
+ return;
+ }
+#endif
usb_control_msg(gspca_dev->dev,
usb_rcvctrlpipe(gspca_dev->dev, 0),
0,
@@ -542,29 +655,20 @@ static void reg_w(struct gspca_dev *gspca_dev,
{
PDEBUG(D_USBO, "reg_w [%02x] = %02x %02x ..",
value, buffer[0], buffer[1]);
- if (len <= sizeof gspca_dev->usb_buf) {
- memcpy(gspca_dev->usb_buf, buffer, len);
- usb_control_msg(gspca_dev->dev,
- usb_sndctrlpipe(gspca_dev->dev, 0),
- 0x08,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
- value, 0,
- gspca_dev->usb_buf, len,
- 500);
- } else {
- __u8 *tmpbuf;
-
- tmpbuf = kmalloc(len, GFP_KERNEL);
- memcpy(tmpbuf, buffer, len);
- usb_control_msg(gspca_dev->dev,
- usb_sndctrlpipe(gspca_dev->dev, 0),
- 0x08,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
- value, 0,
- tmpbuf, len,
- 500);
- kfree(tmpbuf);
+#ifdef GSPCA_DEBUG
+ if (len > USB_BUF_SZ) {
+ err("reg_w: buffer overflow");
+ return;
}
+#endif
+ memcpy(gspca_dev->usb_buf, buffer, len);
+ usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ 0x08,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ value, 0,
+ gspca_dev->usb_buf, len,
+ 500);
}
/* I2C write 1 byte */
@@ -603,6 +707,7 @@ static void i2c_w8(struct gspca_dev *gspca_dev,
0x08, 0, /* value, index */
gspca_dev->usb_buf, 8,
500);
+ msleep(2);
}
/* read 5 bytes in gspca_dev->usb_buf */
@@ -665,7 +770,7 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
static const __u8 regd4[] = {0x60, 0x00, 0x00};
reg_w1(gspca_dev, 0xf1, 0x00);
- reg_w1(gspca_dev, 0x01, 0x00); /*jfm was sn9c1xx[1] in v1*/
+ reg_w1(gspca_dev, 0x01, sn9c1xx[1]);
/* configure gpio */
reg_w(gspca_dev, 0x01, &sn9c1xx[1], 2);
@@ -685,21 +790,41 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
reg_w(gspca_dev, 0x03, &sn9c1xx[3], 0x0f);
- switch (sd->bridge) {
- case BRIDGE_SN9C325:
+ switch (sd->sensor) {
+ case SENSOR_OM6802:
+ reg_w1(gspca_dev, 0x02, 0x71);
+ reg_w1(gspca_dev, 0x01, 0x42);
+ reg_w1(gspca_dev, 0x17, 0x64);
+ reg_w1(gspca_dev, 0x01, 0x42);
+ break;
+/*jfm: from win trace */
+ case SENSOR_OV7630:
+ reg_w1(gspca_dev, 0x01, 0x61);
+ reg_w1(gspca_dev, 0x17, 0xe2);
+ reg_w1(gspca_dev, 0x01, 0x60);
+ reg_w1(gspca_dev, 0x01, 0x40);
+ break;
+ case SENSOR_OV7648:
reg_w1(gspca_dev, 0x01, 0x43);
reg_w1(gspca_dev, 0x17, 0xae);
reg_w1(gspca_dev, 0x01, 0x42);
break;
+/*jfm: from win trace */
+ case SENSOR_OV7660:
+ reg_w1(gspca_dev, 0x01, 0x61);
+ reg_w1(gspca_dev, 0x17, 0x20);
+ reg_w1(gspca_dev, 0x01, 0x60);
+ reg_w1(gspca_dev, 0x01, 0x40);
+ break;
default:
reg_w1(gspca_dev, 0x01, 0x43);
reg_w1(gspca_dev, 0x17, 0x61);
reg_w1(gspca_dev, 0x01, 0x42);
- }
-
- if (sd->sensor == SENSOR_HV7131R) {
- if (probesensor(gspca_dev) < 0)
- return -ENODEV;
+ if (sd->sensor == SENSOR_HV7131R) {
+ if (probesensor(gspca_dev) < 0)
+ return -ENODEV;
+ }
+ break;
}
return 0;
}
@@ -737,6 +862,40 @@ static void mo4000_InitSensor(struct gspca_dev *gspca_dev)
}
}
+static void om6802_InitSensor(struct gspca_dev *gspca_dev)
+{
+ int i = 0;
+
+ while (om6802_sensor_init[i][0]) {
+ i2c_w8(gspca_dev, om6802_sensor_init[i]);
+ i++;
+ }
+}
+
+static void ov7630_InitSensor(struct gspca_dev *gspca_dev)
+{
+ int i = 0;
+
+ i2c_w8(gspca_dev, ov7630_sensor_init[i]); /* 76 01 */
+ i++;
+ i2c_w8(gspca_dev, ov7630_sensor_init[i]); /* 12 c8 (RGB+SRST) */
+ i++;
+ msleep(20);
+ i2c_w8(gspca_dev, ov7630_sensor_init[i]); /* 12 48 */
+ i++;
+ i2c_w8(gspca_dev, ov7630_sensor_init[i]); /* 12 c8 */
+ i++;
+ msleep(20);
+ i2c_w8(gspca_dev, ov7630_sensor_init[i]); /* 12 48 */
+ i++;
+/*jfm:win i2c_r from 00 to 80*/
+
+ while (ov7630_sensor_init[i][0]) {
+ i2c_w8(gspca_dev, ov7630_sensor_init[i]);
+ i++;
+ }
+}
+
static void ov7648_InitSensor(struct gspca_dev *gspca_dev)
{
int i = 0;
@@ -783,11 +942,19 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->autogain = AUTOGAIN_DEF;
sd->ag_cnt = -1;
+ switch (sd->sensor) {
+ case SENSOR_OV7630:
+ case SENSOR_OV7648:
+ case SENSOR_OV7660:
+ gspca_dev->ctrl_dis = (1 << AUTOGAIN_IDX);
+ break;
+ }
+
return 0;
}
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
/* const __u8 *sn9c1xx; */
@@ -810,13 +977,13 @@ static int sd_open(struct gspca_dev *gspca_dev)
case BRIDGE_SN9C105:
if (regF1 != 0x11)
return -ENODEV;
- reg_w(gspca_dev, 0x02, regGpio, 2);
+ reg_w(gspca_dev, 0x01, regGpio, 2);
break;
case BRIDGE_SN9C120:
if (regF1 != 0x12)
return -ENODEV;
regGpio[1] = 0x70;
- reg_w(gspca_dev, 0x02, regGpio, 2);
+ reg_w(gspca_dev, 0x01, regGpio, 2);
break;
default:
/* case BRIDGE_SN9C110: */
@@ -891,16 +1058,53 @@ static unsigned int setexposure(struct gspca_dev *gspca_dev,
| ((expoMo10[3] & 0x30) >> 4));
break;
}
+ case SENSOR_OM6802: {
+ __u8 gainOm[] =
+ { 0xa0, 0x34, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x10 };
+
+ if (expo > 0x03ff)
+ expo = 0x03ff;
+ if (expo < 0x0001)
+ expo = 0x0001;
+ gainOm[3] = expo >> 2;
+ i2c_w8(gspca_dev, gainOm);
+ reg_w1(gspca_dev, 0x96, (expo >> 5) & 0x1f);
+ PDEBUG(D_CONF, "set exposure %d", gainOm[3]);
+ break;
+ }
}
return expo;
}
+/* this function is used for sensors o76xx only */
+static void setbrightcont(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ unsigned val;
+ __u8 reg84_full[0x15];
+
+ memset(reg84_full, 0, sizeof reg84_full);
+ val = sd->contrast * 0x20 / CONTRAST_MAX + 0x10; /* 10..30 */
+ reg84_full[2] = val;
+ reg84_full[0] = (val + 1) / 2;
+ reg84_full[4] = (val + 1) / 5;
+ if (val > BRIGHTNESS_DEF)
+ val = (sd->brightness - BRIGHTNESS_DEF) * 0x20
+ / BRIGHTNESS_MAX;
+ else
+ val = 0;
+ reg84_full[0x12] = val; /* 00..1f */
+ reg_w(gspca_dev, 0x84, reg84_full, sizeof reg84_full);
+}
+
+/* sensor != ov76xx */
static void setbrightness(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
unsigned int expo;
__u8 k2;
+ k2 = sd->brightness >> 10;
switch (sd->sensor) {
case SENSOR_HV7131R:
expo = sd->brightness << 4;
@@ -915,12 +1119,17 @@ static void setbrightness(struct gspca_dev *gspca_dev)
expo = sd->brightness >> 4;
sd->exposure = setexposure(gspca_dev, expo);
break;
+ case SENSOR_OM6802:
+ expo = sd->brightness >> 6;
+ sd->exposure = setexposure(gspca_dev, expo);
+ k2 = sd->brightness >> 11;
+ break;
}
- k2 = sd->brightness >> 10;
reg_w1(gspca_dev, 0x96, k2);
}
+/* sensor != ov76xx */
static void setcontrast(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -937,31 +1146,30 @@ static void setcontrast(struct gspca_dev *gspca_dev)
static void setcolors(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- __u8 data;
- int colour;
+ __u8 blue, red;
- colour = sd->colors - 128;
- if (colour > 0)
- data = (colour + 32) & 0x7f; /* blue */
- else
- data = (-colour + 32) & 0x7f; /* red */
- reg_w1(gspca_dev, 0x05, data);
+ if (sd->colors >= 32) {
+ red = 32 + (sd->colors - 32) / 2;
+ blue = 64 - sd->colors;
+ } else {
+ red = sd->colors;
+ blue = 32 + (32 - sd->colors) / 2;
+ }
+ reg_w1(gspca_dev, 0x05, red);
+/* reg_w1(gspca_dev, 0x07, 32); */
+ reg_w1(gspca_dev, 0x06, blue);
}
static void setautogain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- switch (sd->sensor) {
- case SENSOR_HV7131R:
- case SENSOR_MO4000:
- case SENSOR_MI0360:
- if (sd->autogain)
- sd->ag_cnt = AG_CNT_START;
- else
- sd->ag_cnt = -1;
- break;
- }
+ if (gspca_dev->ctrl_dis & (1 << AUTOGAIN_IDX))
+ return;
+ if (sd->autogain)
+ sd->ag_cnt = AG_CNT_START;
+ else
+ sd->ag_cnt = -1;
}
/* -- start the camera -- */
@@ -975,13 +1183,12 @@ static void sd_start(struct gspca_dev *gspca_dev)
static const __u8 C0[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f };
static const __u8 CA[] = { 0x28, 0xd8, 0x14, 0xec };
static const __u8 CE[] = { 0x32, 0xdd, 0x2d, 0xdd }; /* MI0360 */
- static const __u8 CE_sn9c325[] =
- { 0x32, 0xdd, 0x32, 0xdd }; /* OV7648 - SN9C325 */
+ static const __u8 CE_ov76xx[] =
+ { 0x32, 0xdd, 0x32, 0xdd };
sn9c1xx = sn_tb[(int) sd->sensor];
configure_gpio(gspca_dev, sn9c1xx);
-/* reg_w1(gspca_dev, 0x01, 0x44); jfm from win trace*/
reg_w1(gspca_dev, 0x15, sn9c1xx[0x15]);
reg_w1(gspca_dev, 0x16, sn9c1xx[0x16]);
reg_w1(gspca_dev, 0x12, sn9c1xx[0x12]);
@@ -994,10 +1201,17 @@ static void sd_start(struct gspca_dev *gspca_dev)
reg_w1(gspca_dev, 0xc8, 0x50);
reg_w1(gspca_dev, 0xc9, 0x3c);
reg_w1(gspca_dev, 0x18, sn9c1xx[0x18]);
- switch (sd->bridge) {
- case BRIDGE_SN9C325:
+ switch (sd->sensor) {
+ case SENSOR_OV7630:
+ reg17 = 0xe2;
+ break;
+ case SENSOR_OV7648:
reg17 = 0xae;
break;
+/*jfm: from win trace */
+ case SENSOR_OV7660:
+ reg17 = 0xa0;
+ break;
default:
reg17 = 0x60;
break;
@@ -1007,20 +1221,14 @@ static void sd_start(struct gspca_dev *gspca_dev)
reg_w1(gspca_dev, 0x07, sn9c1xx[7]);
reg_w1(gspca_dev, 0x06, sn9c1xx[6]);
reg_w1(gspca_dev, 0x14, sn9c1xx[0x14]);
- switch (sd->bridge) {
- case BRIDGE_SN9C325:
- reg_w(gspca_dev, 0x20, regsn20_sn9c325,
- sizeof regsn20_sn9c325);
- for (i = 0; i < 8; i++)
- reg_w(gspca_dev, 0x84, reg84_sn9c325,
- sizeof reg84_sn9c325);
- reg_w1(gspca_dev, 0x9a, 0x0a);
- reg_w1(gspca_dev, 0x99, 0x60);
+ reg_w(gspca_dev, 0x20, gamma_def, sizeof gamma_def);
+ for (i = 0; i < 8; i++)
+ reg_w(gspca_dev, 0x84, reg84, sizeof reg84);
+ switch (sd->sensor) {
+ case SENSOR_OV7660:
+ reg_w1(gspca_dev, 0x9a, 0x05);
break;
default:
- reg_w(gspca_dev, 0x20, regsn20, sizeof regsn20);
- for (i = 0; i < 8; i++)
- reg_w(gspca_dev, 0x84, reg84, sizeof reg84);
reg_w1(gspca_dev, 0x9a, 0x08);
reg_w1(gspca_dev, 0x99, 0x59);
break;
@@ -1049,6 +1257,15 @@ static void sd_start(struct gspca_dev *gspca_dev)
/* reg1 = 0x06; * 640 clk 24Mz (done) */
}
break;
+ case SENSOR_OM6802:
+ om6802_InitSensor(gspca_dev);
+ reg17 = 0x64; /* 640 MCKSIZE */
+ break;
+ case SENSOR_OV7630:
+ ov7630_InitSensor(gspca_dev);
+ reg17 = 0xe2;
+ reg1 = 0x44;
+ break;
case SENSOR_OV7648:
ov7648_InitSensor(gspca_dev);
reg17 = 0xa2;
@@ -1066,16 +1283,18 @@ static void sd_start(struct gspca_dev *gspca_dev)
/* reg1 = 0x44; */
/* reg1 = 0x46; (done) */
} else {
- reg17 = 0x22; /* 640 MCKSIZE */
- reg1 = 0x06;
+ reg17 = 0xa2; /* 640 */
+ reg1 = 0x44;
}
break;
}
reg_w(gspca_dev, 0xc0, C0, 6);
reg_w(gspca_dev, 0xca, CA, 4);
- switch (sd->bridge) {
- case BRIDGE_SN9C325:
- reg_w(gspca_dev, 0xce, CE_sn9c325, 4);
+ switch (sd->sensor) {
+ case SENSOR_OV7630:
+ case SENSOR_OV7648:
+ case SENSOR_OV7660:
+ reg_w(gspca_dev, 0xce, CE_ov76xx, 4);
break;
default:
reg_w(gspca_dev, 0xce, CE, 4);
@@ -1093,10 +1312,20 @@ static void sd_start(struct gspca_dev *gspca_dev)
reg_w1(gspca_dev, 0x18, reg18);
reg_w1(gspca_dev, 0x17, reg17);
- reg_w1(gspca_dev, 0x01, reg1);
- setbrightness(gspca_dev);
- setcontrast(gspca_dev);
+ switch (sd->sensor) {
+ case SENSOR_HV7131R:
+ case SENSOR_MI0360:
+ case SENSOR_MO4000:
+ case SENSOR_OM6802:
+ setbrightness(gspca_dev);
+ setcontrast(gspca_dev);
+ break;
+ default: /* OV76xx */
+ setbrightcont(gspca_dev);
+ break;
+ }
setautogain(gspca_dev);
+ reg_w1(gspca_dev, 0x01, reg1);
}
static void sd_stopN(struct gspca_dev *gspca_dev)
@@ -1119,6 +1348,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
i2c_w8(gspca_dev, stopmi0360);
data = 0x29;
break;
+ case SENSOR_OV7630:
case SENSOR_OV7648:
data = 0x29;
break;
@@ -1132,15 +1362,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
reg_w1(gspca_dev, 0x17, sn9c1xx[0x17]);
reg_w1(gspca_dev, 0x01, sn9c1xx[1]);
reg_w1(gspca_dev, 0x01, data);
- reg_w1(gspca_dev, 0xf1, 0x01);
-}
-
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-static void sd_close(struct gspca_dev *gspca_dev)
-{
+ reg_w1(gspca_dev, 0xf1, 0x00);
}
static void do_autogain(struct gspca_dev *gspca_dev)
@@ -1174,6 +1396,7 @@ static void do_autogain(struct gspca_dev *gspca_dev)
default:
/* case SENSOR_MO4000: */
/* case SENSOR_MI0360: */
+/* case SENSOR_OM6802: */
expotimes = sd->exposure;
expotimes += (luma_mean - delta) >> 6;
if (expotimes < 0)
@@ -1229,69 +1452,24 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
}
-static unsigned int getexposure(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- __u8 hexpo, mexpo, lexpo;
-
- switch (sd->sensor) {
- case SENSOR_HV7131R:
- /* read sensor exposure */
- i2c_r5(gspca_dev, 0x25);
- return (gspca_dev->usb_buf[0] << 16)
- | (gspca_dev->usb_buf[1] << 8)
- | gspca_dev->usb_buf[2];
- case SENSOR_MI0360:
- /* read sensor exposure */
- i2c_r5(gspca_dev, 0x09);
- return (gspca_dev->usb_buf[0] << 8)
- | gspca_dev->usb_buf[1];
- case SENSOR_MO4000:
- i2c_r5(gspca_dev, 0x0e);
- hexpo = 0; /* gspca_dev->usb_buf[1] & 0x07; */
- mexpo = 0x40; /* gspca_dev->usb_buf[2] & 0xff; */
- lexpo = (gspca_dev->usb_buf[1] & 0x30) >> 4;
- PDEBUG(D_CONF, "exposure %d",
- (hexpo << 10) | (mexpo << 2) | lexpo);
- return (hexpo << 10) | (mexpo << 2) | lexpo;
- default:
-/* case SENSOR_OV7648: * jfm: is it ok for 7648? */
-/* case SENSOR_OV7660: */
- /* read sensor exposure */
- i2c_r5(gspca_dev, 0x04);
- hexpo = gspca_dev->usb_buf[3] & 0x2f;
- lexpo = gspca_dev->usb_buf[0] & 0x02;
- i2c_r5(gspca_dev, 0x08);
- mexpo = gspca_dev->usb_buf[2];
- return (hexpo << 10) | (mexpo << 2) | lexpo;
- }
-}
-
-static void getbrightness(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- /* hardcoded registers seem not readable */
- switch (sd->sensor) {
- case SENSOR_HV7131R:
- sd->brightness = getexposure(gspca_dev) >> 4;
- break;
- case SENSOR_MI0360:
- sd->brightness = getexposure(gspca_dev) << 4;
- break;
- case SENSOR_MO4000:
- sd->brightness = getexposure(gspca_dev) << 4;
- break;
- }
-}
-
static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
sd->brightness = val;
- if (gspca_dev->streaming)
- setbrightness(gspca_dev);
+ if (gspca_dev->streaming) {
+ switch (sd->sensor) {
+ case SENSOR_HV7131R:
+ case SENSOR_MI0360:
+ case SENSOR_MO4000:
+ case SENSOR_OM6802:
+ setbrightness(gspca_dev);
+ break;
+ default: /* OV76xx */
+ setbrightcont(gspca_dev);
+ break;
+ }
+ }
return 0;
}
@@ -1299,7 +1477,6 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
- getbrightness(gspca_dev);
*val = sd->brightness;
return 0;
}
@@ -1309,8 +1486,19 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
struct sd *sd = (struct sd *) gspca_dev;
sd->contrast = val;
- if (gspca_dev->streaming)
- setcontrast(gspca_dev);
+ if (gspca_dev->streaming) {
+ switch (sd->sensor) {
+ case SENSOR_HV7131R:
+ case SENSOR_MI0360:
+ case SENSOR_MO4000:
+ case SENSOR_OM6802:
+ setcontrast(gspca_dev);
+ break;
+ default: /* OV76xx */
+ setbrightcont(gspca_dev);
+ break;
+ }
+ }
return 0;
}
@@ -1364,11 +1552,9 @@ static const struct sd_desc sd_desc = {
.ctrls = sd_ctrls,
.nctrls = ARRAY_SIZE(sd_ctrls),
.config = sd_config,
- .open = sd_open,
+ .init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
- .stop0 = sd_stop0,
- .close = sd_close,
.pkt_scan = sd_pkt_scan,
.dq_callback = do_autogain,
};
@@ -1379,7 +1565,7 @@ static const struct sd_desc sd_desc = {
| (SENSOR_ ## sensor << 8) \
| (i2c_addr)
static const __devinitdata struct usb_device_id device_table[] = {
-#ifndef CONFIG_USB_SN9C102
+#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
{USB_DEVICE(0x0458, 0x7025), BSI(SN9C120, MI0360, 0x5d)},
{USB_DEVICE(0x045e, 0x00f5), BSI(SN9C105, OV7660, 0x21)},
{USB_DEVICE(0x045e, 0x00f7), BSI(SN9C105, OV7660, 0x21)},
@@ -1406,15 +1592,17 @@ static const __devinitdata struct usb_device_id device_table[] = {
/* {USB_DEVICE(0x0c45, 0x6108), BSI(SN9C120, OM6801, 0x??)}, */
/* {USB_DEVICE(0x0c45, 0x6122), BSI(SN9C110, ICM105C, 0x??)}, */
/* {USB_DEVICE(0x0c45, 0x6123), BSI(SN9C110, SanyoCCD, 0x??)}, */
- {USB_DEVICE(0x0c45, 0x612a), BSI(SN9C325, OV7648, 0x21)},
-/* bw600.inf:
- {USB_DEVICE(0x0c45, 0x612a), BSI(SN9C110, OV7648, 0x21)}, */
+ {USB_DEVICE(0x0c45, 0x6128), BSI(SN9C110, OM6802, 0x21)}, /*sn9c325?*/
+/*bw600.inf:*/
+ {USB_DEVICE(0x0c45, 0x612a), BSI(SN9C110, OV7648, 0x21)}, /*sn9c325?*/
{USB_DEVICE(0x0c45, 0x612c), BSI(SN9C110, MO4000, 0x21)},
-/* {USB_DEVICE(0x0c45, 0x612e), BSI(SN9C110, OV7630, 0x??)}, */
+ {USB_DEVICE(0x0c45, 0x612e), BSI(SN9C110, OV7630, 0x21)},
/* {USB_DEVICE(0x0c45, 0x612f), BSI(SN9C110, ICM105C, 0x??)}, */
-#ifndef CONFIG_USB_SN9C102
+#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
{USB_DEVICE(0x0c45, 0x6130), BSI(SN9C120, MI0360, 0x5d)},
+#endif
{USB_DEVICE(0x0c45, 0x6138), BSI(SN9C120, MO4000, 0x21)},
+#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
/* {USB_DEVICE(0x0c45, 0x613a), BSI(SN9C120, OV7648, 0x??)}, */
{USB_DEVICE(0x0c45, 0x613b), BSI(SN9C120, OV7660, 0x21)},
{USB_DEVICE(0x0c45, 0x613c), BSI(SN9C120, HV7131R, 0x11)},
@@ -1438,6 +1626,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
/* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/spca500.c b/drivers/media/video/gspca/spca500.c
index 17fe2c2a440..6e733901fcc 100644
--- a/drivers/media/video/gspca/spca500.c
+++ b/drivers/media/video/gspca/spca500.c
@@ -645,8 +645,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
return 0;
}
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -880,14 +880,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
gspca_dev->usb_buf[0]);
}
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
-
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
struct gspca_frame *frame, /* target */
__u8 *data, /* isoc packet */
@@ -1051,11 +1043,9 @@ static struct sd_desc sd_desc = {
.ctrls = sd_ctrls,
.nctrls = ARRAY_SIZE(sd_ctrls),
.config = sd_config,
- .open = sd_open,
+ .init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
- .stop0 = sd_stop0,
- .close = sd_close,
.pkt_scan = sd_pkt_scan,
};
@@ -1093,6 +1083,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
/* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/spca501.c b/drivers/media/video/gspca/spca501.c
index 51a3c3429ef..e9eb59bae4f 100644
--- a/drivers/media/video/gspca/spca501.c
+++ b/drivers/media/video/gspca/spca501.c
@@ -1953,8 +1953,8 @@ error:
return -EINVAL;
}
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -2023,11 +2023,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
static void sd_stop0(struct gspca_dev *gspca_dev)
{
-}
-
-/* this function is called at close time */
-static void sd_close(struct gspca_dev *gspca_dev)
-{
reg_write(gspca_dev->dev, SPCA501_REG_CTLRL, 0x05, 0x00);
}
@@ -2120,11 +2115,10 @@ static const struct sd_desc sd_desc = {
.ctrls = sd_ctrls,
.nctrls = ARRAY_SIZE(sd_ctrls),
.config = sd_config,
- .open = sd_open,
+ .init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
.stop0 = sd_stop0,
- .close = sd_close,
.pkt_scan = sd_pkt_scan,
};
@@ -2154,6 +2148,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
/* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/spca505.c b/drivers/media/video/gspca/spca505.c
index eda29d60935..f601daf19eb 100644
--- a/drivers/media/video/gspca/spca505.c
+++ b/drivers/media/video/gspca/spca505.c
@@ -655,8 +655,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
return 0;
}
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
int ret;
@@ -743,11 +743,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
static void sd_stop0(struct gspca_dev *gspca_dev)
{
-}
-
-/* this function is called at close time */
-static void sd_close(struct gspca_dev *gspca_dev)
-{
/* This maybe reset or power control */
reg_write(gspca_dev->dev, 0x03, 0x03, 0x20);
reg_write(gspca_dev->dev, 0x03, 0x01, 0x0);
@@ -825,11 +820,10 @@ static const struct sd_desc sd_desc = {
.ctrls = sd_ctrls,
.nctrls = ARRAY_SIZE(sd_ctrls),
.config = sd_config,
- .open = sd_open,
+ .init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
.stop0 = sd_stop0,
- .close = sd_close,
.pkt_scan = sd_pkt_scan,
};
@@ -855,6 +849,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
/* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/spca506.c b/drivers/media/video/gspca/spca506.c
index f622fa75766..195dce96ef0 100644
--- a/drivers/media/video/gspca/spca506.c
+++ b/drivers/media/video/gspca/spca506.c
@@ -313,8 +313,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
return 0;
}
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
{
struct usb_device *dev = gspca_dev->dev;
@@ -560,14 +560,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
reg_w(dev, 0x03, 0x00, 0x0003);
}
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
-
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
struct gspca_frame *frame, /* target */
__u8 *data, /* isoc packet */
@@ -740,11 +732,9 @@ static struct sd_desc sd_desc = {
.ctrls = sd_ctrls,
.nctrls = ARRAY_SIZE(sd_ctrls),
.config = sd_config,
- .open = sd_open,
+ .init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
- .stop0 = sd_stop0,
- .close = sd_close,
.pkt_scan = sd_pkt_scan,
};
@@ -772,6 +762,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
/* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/spca508.c b/drivers/media/video/gspca/spca508.c
index 699340c17de..281ce02103a 100644
--- a/drivers/media/video/gspca/spca508.c
+++ b/drivers/media/video/gspca/spca508.c
@@ -1521,8 +1521,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
return 0; /* success */
}
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
{
/* write_vector(gspca_dev, spca508_open_data); */
return 0;
@@ -1554,15 +1554,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
reg_write(gspca_dev->dev, 0x8112, 0x20);
}
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-/* this function is called at close time */
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
-
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
struct gspca_frame *frame, /* target */
__u8 *data, /* isoc packet */
@@ -1633,11 +1624,9 @@ static const struct sd_desc sd_desc = {
.ctrls = sd_ctrls,
.nctrls = ARRAY_SIZE(sd_ctrls),
.config = sd_config,
- .open = sd_open,
+ .init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
- .stop0 = sd_stop0,
- .close = sd_close,
.pkt_scan = sd_pkt_scan,
};
@@ -1667,6 +1656,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
/* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/spca561.c b/drivers/media/video/gspca/spca561.c
index 1073ac3d2ec..95fcfcb9e31 100644
--- a/drivers/media/video/gspca/spca561.c
+++ b/drivers/media/video/gspca/spca561.c
@@ -32,69 +32,48 @@ MODULE_LICENSE("GPL");
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
- unsigned short contrast;
- __u8 brightness;
+ __u16 contrast; /* rev72a only */
+#define CONTRAST_MIN 0x0000
+#define CONTRAST_DEF 0x2000
+#define CONTRAST_MAX 0x3fff
+
+ __u16 exposure; /* rev12a only */
+#define EXPOSURE_MIN 1
+#define EXPOSURE_DEF 200
+#define EXPOSURE_MAX (4095 - 900) /* see set_exposure */
+
+ __u8 brightness; /* rev72a only */
+#define BRIGHTNESS_MIN 0
+#define BRIGHTNESS_DEF 32
+#define BRIGHTNESS_MAX 63
+
+ __u8 white; /* rev12a only */
+#define WHITE_MIN 1
+#define WHITE_DEF 0x40
+#define WHITE_MAX 0x7f
+
__u8 autogain;
+#define AUTOGAIN_MIN 0
+#define AUTOGAIN_DEF 1
+#define AUTOGAIN_MAX 1
+
+ __u8 gain; /* rev12a only */
+#define GAIN_MIN 0x0
+#define GAIN_DEF 0x24
+#define GAIN_MAX 0x24
+
+#define EXPO12A_DEF 3
+ __u8 expo12a; /* expo/gain? for rev 12a */
__u8 chip_revision;
+#define Rev012A 0
+#define Rev072A 1
+
signed char ag_cnt;
#define AG_CNT_START 13
};
-/* V4L2 controls supported by the driver */
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
-
-static struct ctrl sd_ctrls[] = {
-#define SD_BRIGHTNESS 0
- {
- {
- .id = V4L2_CID_BRIGHTNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Brightness",
- .minimum = 0,
- .maximum = 63,
- .step = 1,
- .default_value = 32,
- },
- .set = sd_setbrightness,
- .get = sd_getbrightness,
- },
-#define SD_CONTRAST 1
- {
- {
- .id = V4L2_CID_CONTRAST,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Contrast",
- .minimum = 0,
- .maximum = 0x3fff,
- .step = 1,
- .default_value = 0x2000,
- },
- .set = sd_setcontrast,
- .get = sd_getcontrast,
- },
-#define SD_AUTOGAIN 2
- {
- {
- .id = V4L2_CID_AUTOGAIN,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Auto Gain",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1,
- },
- .set = sd_setautogain,
- .get = sd_getautogain,
- },
-};
-
-static struct v4l2_pix_format sif_mode[] = {
+static struct v4l2_pix_format sif_012a_mode[] = {
{160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
.bytesperline = 160,
.sizeimage = 160 * 120,
@@ -117,6 +96,29 @@ static struct v4l2_pix_format sif_mode[] = {
.priv = 0},
};
+static struct v4l2_pix_format sif_072a_mode[] = {
+ {160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+ .bytesperline = 160,
+ .sizeimage = 160 * 120,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 3},
+ {176, 144, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+ .bytesperline = 176,
+ .sizeimage = 176 * 144,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 2},
+ {320, 240, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1},
+ {352, 288, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+ .bytesperline = 352,
+ .sizeimage = 352 * 288,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+};
+
/*
* Initialization data
* I'm not very sure how to split initialization from open data
@@ -143,12 +145,8 @@ static struct v4l2_pix_format sif_mode[] = {
#define SPCA561_INDEX_I2C_BASE 0x8800
#define SPCA561_SNAPBIT 0x20
#define SPCA561_SNAPCTRL 0x40
-enum {
- Rev072A = 0,
- Rev012A,
-};
-static void reg_w_val(struct usb_device *dev, __u16 index, __u16 value)
+static void reg_w_val(struct usb_device *dev, __u16 index, __u8 value)
{
int ret;
@@ -198,12 +196,6 @@ static void reg_w_buf(struct gspca_dev *gspca_dev,
index, gspca_dev->usb_buf, len, 500);
}
-static void i2c_init(struct gspca_dev *gspca_dev, __u8 mode)
-{
- reg_w_val(gspca_dev->dev, 0x92, 0x8804);
- reg_w_val(gspca_dev->dev, mode, 0x8802);
-}
-
static void i2c_write(struct gspca_dev *gspca_dev, __u16 valeur, __u16 reg)
{
int retry = 60;
@@ -212,9 +204,9 @@ static void i2c_write(struct gspca_dev *gspca_dev, __u16 valeur, __u16 reg)
DataLow = valeur;
DataHight = valeur >> 8;
- reg_w_val(gspca_dev->dev, reg, 0x8801);
- reg_w_val(gspca_dev->dev, DataLow, 0x8805);
- reg_w_val(gspca_dev->dev, DataHight, 0x8800);
+ reg_w_val(gspca_dev->dev, 0x8801, reg);
+ reg_w_val(gspca_dev->dev, 0x8805, DataLow);
+ reg_w_val(gspca_dev->dev, 0x8800, DataHight);
while (retry--) {
reg_r(gspca_dev, 0x8803, 1);
if (!gspca_dev->usb_buf[0])
@@ -228,14 +220,14 @@ static int i2c_read(struct gspca_dev *gspca_dev, __u16 reg, __u8 mode)
__u8 value;
__u8 vallsb;
- reg_w_val(gspca_dev->dev, 0x92, 0x8804);
- reg_w_val(gspca_dev->dev, reg, 0x8801);
- reg_w_val(gspca_dev->dev, (mode | 0x01), 0x8802);
- while (retry--) {
+ reg_w_val(gspca_dev->dev, 0x8804, 0x92);
+ reg_w_val(gspca_dev->dev, 0x8801, reg);
+ reg_w_val(gspca_dev->dev, 0x8802, (mode | 0x01));
+ do {
reg_r(gspca_dev, 0x8803, 1);
- if (!gspca_dev->usb_buf)
+ if (!gspca_dev->usb_buf[0])
break;
- }
+ } while (--retry);
if (retry == 0)
return -1;
reg_r(gspca_dev, 0x8800, 1);
@@ -438,21 +430,10 @@ static const __u16 spca561_init_data[][2] = {
{0x0035, 0x8801}, /* 0x14 - set gain general */
{0x001f, 0x8805}, /* 0x14 */
{0x0000, 0x8800},
- {0x0030, 0x8112},
+ {0x000e, 0x8112}, /* white balance - was 30 */
{}
};
-static void sensor_reset(struct gspca_dev *gspca_dev)
-{
- reg_w_val(gspca_dev->dev, 0x8631, 0xc8);
- reg_w_val(gspca_dev->dev, 0x8634, 0xc8);
- reg_w_val(gspca_dev->dev, 0x8112, 0x00);
- reg_w_val(gspca_dev->dev, 0x8114, 0x00);
- reg_w_val(gspca_dev->dev, 0x8118, 0x21);
- i2c_init(gspca_dev, 0x14);
- i2c_write(gspca_dev, 1, 0x0d);
- i2c_write(gspca_dev, 0, 0x0d);
-}
/******************** QC Express etch2 stuff ********************/
static const __u16 Pb100_1map8300[][2] = {
@@ -462,9 +443,9 @@ static const __u16 Pb100_1map8300[][2] = {
{0x8303, 0x0125}, /* image area */
{0x8304, 0x0169},
{0x8328, 0x000b},
- {0x833c, 0x0001},
+ {0x833c, 0x0001}, /*fixme: win:07*/
- {0x832f, 0x0419},
+ {0x832f, 0x1904}, /*fixme: was 0419*/
{0x8307, 0x00aa},
{0x8301, 0x0003},
{0x8302, 0x000e},
@@ -478,9 +459,10 @@ static const __u16 Pb100_2map8300[][2] = {
};
static const __u16 spca561_161rev12A_data1[][2] = {
- {0x21, 0x8118},
- {0x01, 0x8114},
- {0x00, 0x8112},
+ {0x29, 0x8118}, /* white balance - was 21 */
+ {0x08, 0x8114}, /* white balance - was 01 */
+ {0x0e, 0x8112}, /* white balance - was 00 */
+ {0x00, 0x8102}, /* white balance - new */
{0x92, 0x8804},
{0x04, 0x8802}, /* windows uses 08 */
{}
@@ -505,14 +487,16 @@ static const __u16 spca561_161rev12A_data2[][2] = {
{0xb0, 0x8603},
/* sensor gains */
+ {0x07, 0x8601}, /* white balance - new */
+ {0x07, 0x8602}, /* white balance - new */
{0x00, 0x8610}, /* *red */
{0x00, 0x8611}, /* 3f *green */
{0x00, 0x8612}, /* green *blue */
{0x00, 0x8613}, /* blue *green */
- {0x35, 0x8614}, /* green *red */
- {0x35, 0x8615}, /* 40 *green */
- {0x35, 0x8616}, /* 7a *blue */
- {0x35, 0x8617}, /* 40 *green */
+ {0x43, 0x8614}, /* green *red - white balance - was 0x35 */
+ {0x40, 0x8615}, /* 40 *green - white balance - was 0x35 */
+ {0x71, 0x8616}, /* 7a *blue - white balance - was 0x35 */
+ {0x40, 0x8617}, /* 40 *green - white balance - was 0x35 */
{0x0c, 0x8620}, /* 0c */
{0xc8, 0x8631}, /* c8 */
@@ -527,6 +511,7 @@ static const __u16 spca561_161rev12A_data2[][2] = {
{0xdf, 0x863c}, /* df */
{0xf0, 0x8505},
{0x32, 0x850a},
+/* {0x99, 0x8700}, * - white balance - new (removed) */
{}
};
@@ -545,9 +530,10 @@ static void sensor_mapwrite(struct gspca_dev *gspca_dev,
}
static void init_161rev12A(struct gspca_dev *gspca_dev)
{
- sensor_reset(gspca_dev);
+/* sensor_reset(gspca_dev); (not in win) */
write_vector(gspca_dev, spca561_161rev12A_data1);
sensor_mapwrite(gspca_dev, Pb100_1map8300);
+/*fixme: should be in sd_start*/
write_vector(gspca_dev, spca561_161rev12A_data2);
sensor_mapwrite(gspca_dev, Pb100_2map8300);
}
@@ -581,35 +567,38 @@ static int sd_config(struct gspca_dev *gspca_dev,
}
cam = &gspca_dev->cam;
- cam->dev_name = (char *) id->driver_info;
cam->epaddr = 0x01;
gspca_dev->nbalt = 7 + 1; /* choose alternate 7 first */
- cam->cam_mode = sif_mode;
- cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
sd->chip_revision = id->driver_info;
- sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
- sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
- sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value;
+ if (sd->chip_revision == Rev012A) {
+ cam->cam_mode = sif_012a_mode;
+ cam->nmodes = ARRAY_SIZE(sif_012a_mode);
+ } else {
+ cam->cam_mode = sif_072a_mode;
+ cam->nmodes = ARRAY_SIZE(sif_072a_mode);
+ }
+ sd->brightness = BRIGHTNESS_DEF;
+ sd->contrast = CONTRAST_DEF;
+ sd->white = WHITE_DEF;
+ sd->exposure = EXPOSURE_DEF;
+ sd->autogain = AUTOGAIN_DEF;
+ sd->gain = GAIN_DEF;
+ sd->expo12a = EXPO12A_DEF;
return 0;
}
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init_12a(struct gspca_dev *gspca_dev)
{
- struct sd *sd = (struct sd *) gspca_dev;
-
- switch (sd->chip_revision) {
- case Rev072A:
- PDEBUG(D_STREAM, "Chip revision id: 072a");
- write_vector(gspca_dev, spca561_init_data);
- break;
- default:
-/* case Rev012A: */
- PDEBUG(D_STREAM, "Chip revision id: 012a");
- init_161rev12A(gspca_dev);
- break;
- }
+ PDEBUG(D_STREAM, "Chip revision: 012a");
+ init_161rev12A(gspca_dev);
+ return 0;
+}
+static int sd_init_72a(struct gspca_dev *gspca_dev)
+{
+ PDEBUG(D_STREAM, "Chip revision: 072a");
+ write_vector(gspca_dev, spca561_init_data);
return 0;
}
@@ -618,25 +607,20 @@ static void setcontrast(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
struct usb_device *dev = gspca_dev->dev;
__u8 lowb;
- int expotimes;
switch (sd->chip_revision) {
case Rev072A:
lowb = sd->contrast >> 8;
- reg_w_val(dev, lowb, 0x8651);
- reg_w_val(dev, lowb, 0x8652);
- reg_w_val(dev, lowb, 0x8653);
- reg_w_val(dev, lowb, 0x8654);
+ reg_w_val(dev, 0x8651, lowb);
+ reg_w_val(dev, 0x8652, lowb);
+ reg_w_val(dev, 0x8653, lowb);
+ reg_w_val(dev, 0x8654, lowb);
break;
- case Rev012A: {
- __u8 Reg8391[] =
- { 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00 };
-
- /* Write camera sensor settings */
- expotimes = (sd->contrast >> 5) & 0x07ff;
- Reg8391[0] = expotimes & 0xff; /* exposure */
- Reg8391[1] = 0x18 | (expotimes >> 8);
- Reg8391[2] = sd->brightness; /* gain */
+ default: {
+/* case Rev012A: { */
+ static const __u8 Reg8391[] =
+ { 0x92, 0x30, 0x20, 0x00, 0x0c, 0x00, 0x00, 0x00 };
+
reg_w_buf(gspca_dev, 0x8391, Reg8391, 8);
reg_w_buf(gspca_dev, 0x8390, Reg8391, 8);
break;
@@ -644,93 +628,151 @@ static void setcontrast(struct gspca_dev *gspca_dev)
}
}
-static void setautogain(struct gspca_dev *gspca_dev)
+/* rev12a only */
+static void setwhite(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
+ __u16 white;
+ __u8 reg8614, reg8616;
+
+ white = sd->white;
+ /* try to emulate MS-win as possible */
+ reg8616 = 0x90 - white * 5 / 8;
+ reg_w_val(gspca_dev->dev, 0x8616, reg8616);
+ reg8614 = 0x20 + white * 3 / 8;
+ reg_w_val(gspca_dev->dev, 0x8614, reg8614);
+}
- if (sd->chip_revision == Rev072A) {
- if (sd->autogain)
- sd->ag_cnt = AG_CNT_START;
- else
- sd->ag_cnt = -1;
+/* rev 12a only */
+static void setexposure(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int expo;
+ int clock_divider;
+ __u8 data[2];
+
+ /* Register 0x8309 controls exposure for the spca561,
+ the basic exposure setting goes from 1-2047, where 1 is completely
+ dark and 2047 is very bright. It not only influences exposure but
+ also the framerate (to allow for longer exposure) from 1 - 300 it
+ only raises the exposure time then from 300 - 600 it halves the
+ framerate to be able to further raise the exposure time and for every
+ 300 more it halves the framerate again. This allows for a maximum
+ exposure time of circa 0.2 - 0.25 seconds (30 / (2000/3000) fps).
+ Sometimes this is not enough, the 1-2047 uses bits 0-10, bits 11-12
+ configure a divider for the base framerate which us used at the
+ exposure setting of 1-300. These bits configure the base framerate
+ according to the following formula: fps = 60 / (value + 2) */
+ if (sd->exposure < 2048) {
+ expo = sd->exposure;
+ clock_divider = 0;
+ } else {
+ /* Add 900 to make the 0 setting of the second part of the
+ exposure equal to the 2047 setting of the first part. */
+ expo = (sd->exposure - 2048) + 900;
+ clock_divider = 3;
}
+ expo |= clock_divider << 11;
+ data[0] = expo;
+ data[1] = expo >> 8;
+ reg_w_buf(gspca_dev, 0x8309, data, 2);
}
-static void sd_start(struct gspca_dev *gspca_dev)
+/* rev 12a only */
+static void setgain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
+ __u8 data[2];
+
+ data[0] = sd->gain;
+ data[1] = 0;
+ reg_w_buf(gspca_dev, 0x8335, data, 2);
+}
+
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (sd->autogain)
+ sd->ag_cnt = AG_CNT_START;
+ else
+ sd->ag_cnt = -1;
+}
+
+static void sd_start_12a(struct gspca_dev *gspca_dev)
+{
struct usb_device *dev = gspca_dev->dev;
- int Clck;
+ int Clck = 0x8a; /* lower 0x8X values lead to fps > 30 */
__u8 Reg8307[] = { 0xaa, 0x00 };
int mode;
mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
- switch (sd->chip_revision) {
- case Rev072A:
- switch (mode) {
- default:
-/* case 0:
- case 1: */
- Clck = 0x25;
- break;
- case 2:
- Clck = 0x22;
- break;
- case 3:
- Clck = 0x21;
- break;
- }
- reg_w_val(dev, 0x8500, mode); /* mode */
- reg_w_val(dev, 0x8700, Clck); /* 0x27 clock */
- reg_w_val(dev, 0x8112, 0x10 | 0x20);
- setautogain(gspca_dev);
- break;
+ if (mode <= 1) {
+ /* Use compression on 320x240 and above */
+ reg_w_val(dev, 0x8500, 0x10 | mode);
+ } else {
+ /* I couldn't get the compression to work below 320x240
+ * Fortunately at these resolutions the bandwidth
+ * is sufficient to push raw frames at ~20fps */
+ reg_w_val(dev, 0x8500, mode);
+ } /* -- qq@kuku.eu.org */
+ reg_w_buf(gspca_dev, 0x8307, Reg8307, 2);
+ reg_w_val(gspca_dev->dev, 0x8700, Clck);
+ /* 0x8f 0x85 0x27 clock */
+ reg_w_val(gspca_dev->dev, 0x8112, 0x1e | 0x20);
+ reg_w_val(gspca_dev->dev, 0x850b, 0x03);
+ setcontrast(gspca_dev);
+ setwhite(gspca_dev);
+ setautogain(gspca_dev);
+ setexposure(gspca_dev);
+}
+static void sd_start_72a(struct gspca_dev *gspca_dev)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int Clck;
+ int mode;
+
+ mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+ switch (mode) {
default:
-/* case Rev012A: */
- switch (mode) {
- case 0:
- case 1:
- Clck = 0x8a;
- break;
- case 2:
- Clck = 0x85;
- break;
- default:
- Clck = 0x83;
- break;
- }
- if (mode <= 1) {
- /* Use compression on 320x240 and above */
- reg_w_val(dev, 0x8500, 0x10 | mode);
- } else {
- /* I couldn't get the compression to work below 320x240
- * Fortunately at these resolutions the bandwidth
- * is sufficient to push raw frames at ~20fps */
- reg_w_val(dev, 0x8500, mode);
- } /* -- qq@kuku.eu.org */
- reg_w_buf(gspca_dev, 0x8307, Reg8307, 2);
- reg_w_val(gspca_dev->dev, 0x8700, Clck);
- /* 0x8f 0x85 0x27 clock */
- reg_w_val(gspca_dev->dev, 0x8112, 0x1e | 0x20);
- reg_w_val(gspca_dev->dev, 0x850b, 0x03);
- setcontrast(gspca_dev);
+/* case 0:
+ case 1: */
+ Clck = 0x25;
+ break;
+ case 2:
+ Clck = 0x22;
+ break;
+ case 3:
+ Clck = 0x21;
break;
}
+ reg_w_val(dev, 0x8500, mode); /* mode */
+ reg_w_val(dev, 0x8700, Clck); /* 0x27 clock */
+ reg_w_val(dev, 0x8112, 0x10 | 0x20);
+ setautogain(gspca_dev);
}
static void sd_stopN(struct gspca_dev *gspca_dev)
{
- reg_w_val(gspca_dev->dev, 0x8112, 0x20);
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (sd->chip_revision == Rev012A) {
+ reg_w_val(gspca_dev->dev, 0x8112, 0x0e);
+ } else {
+ reg_w_val(gspca_dev->dev, 0x8112, 0x20);
+/* reg_w_val(gspca_dev->dev, 0x8102, 0x00); ?? */
+ }
}
static void sd_stop0(struct gspca_dev *gspca_dev)
{
-}
+ struct sd *sd = (struct sd *) gspca_dev;
-/* this function is called at close time */
-static void sd_close(struct gspca_dev *gspca_dev)
-{
- reg_w_val(gspca_dev->dev, 0x8114, 0);
+ if (sd->chip_revision == Rev012A) {
+ reg_w_val(gspca_dev->dev, 0x8118, 0x29);
+ reg_w_val(gspca_dev->dev, 0x8114, 0x08);
+ }
+/* reg_w_val(gspca_dev->dev, 0x8114, 0); */
}
static void do_autogain(struct gspca_dev *gspca_dev)
@@ -744,6 +786,7 @@ static void do_autogain(struct gspca_dev *gspca_dev)
__u8 luma_mean = 110;
__u8 luma_delta = 20;
__u8 spring = 4;
+ __u8 reg8339[2];
if (sd->ag_cnt < 0)
return;
@@ -798,13 +841,16 @@ static void do_autogain(struct gspca_dev *gspca_dev)
}
break;
case Rev012A:
- /* sensor registers is access and memory mapped to 0x8300 */
- /* readind all 0x83xx block the sensor */
- /*
- * The data from the header seem wrong where is the luma
- * and chroma mean value
- * at the moment set exposure in contrast set
- */
+ reg_r(gspca_dev, 0x8330, 2);
+ if (gspca_dev->usb_buf[1] > 0x08) {
+ reg8339[0] = ++sd->expo12a;
+ reg8339[1] = 0;
+ reg_w_buf(gspca_dev, 0x8339, reg8339, 2);
+ } else if (gspca_dev->usb_buf[1] < 0x02) {
+ reg8339[0] = --sd->expo12a;
+ reg8339[1] = 0;
+ reg_w_buf(gspca_dev, 0x8339, reg8339, 2);
+ }
break;
}
}
@@ -814,6 +860,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
__u8 *data, /* isoc packet */
int len) /* iso packet length */
{
+ struct sd *sd = (struct sd *) gspca_dev;
+
switch (data[0]) {
case 0: /* start of frame */
frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
@@ -826,8 +874,13 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
frame, data, len);
} else {
/* raw bayer (with a header, which we skip) */
- data += 20;
- len -= 20;
+ if (sd->chip_revision == Rev012A) {
+ data += 20;
+ len -= 20;
+ } else {
+ data += 16;
+ len -= 16;
+ }
gspca_frame_add(gspca_dev, FIRST_PACKET,
frame, data, len);
}
@@ -841,24 +894,17 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
}
+/* rev 72a only */
static void setbrightness(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
__u8 value;
- switch (sd->chip_revision) {
- case Rev072A:
- value = sd->brightness;
- reg_w_val(gspca_dev->dev, value, 0x8611);
- reg_w_val(gspca_dev->dev, value, 0x8612);
- reg_w_val(gspca_dev->dev, value, 0x8613);
- reg_w_val(gspca_dev->dev, value, 0x8614);
- break;
- default:
-/* case Rev012A: */
- setcontrast(gspca_dev);
- break;
- }
+ value = sd->brightness;
+ reg_w_val(gspca_dev->dev, 0x8611, value);
+ reg_w_val(gspca_dev->dev, 0x8612, value);
+ reg_w_val(gspca_dev->dev, 0x8613, value);
+ reg_w_val(gspca_dev->dev, 0x8614, value);
}
static void getbrightness(struct gspca_dev *gspca_dev)
@@ -866,52 +912,38 @@ static void getbrightness(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
__u16 tot;
- switch (sd->chip_revision) {
- case Rev072A:
- tot = 0;
- reg_r(gspca_dev, 0x8611, 1);
- tot += gspca_dev->usb_buf[0];
- reg_r(gspca_dev, 0x8612, 1);
- tot += gspca_dev->usb_buf[0];
- reg_r(gspca_dev, 0x8613, 1);
- tot += gspca_dev->usb_buf[0];
- reg_r(gspca_dev, 0x8614, 1);
- tot += gspca_dev->usb_buf[0];
- sd->brightness = tot >> 2;
- break;
- default:
-/* case Rev012A: */
- /* no way to read sensor settings */
- break;
- }
+ tot = 0;
+ reg_r(gspca_dev, 0x8611, 1);
+ tot += gspca_dev->usb_buf[0];
+ reg_r(gspca_dev, 0x8612, 1);
+ tot += gspca_dev->usb_buf[0];
+ reg_r(gspca_dev, 0x8613, 1);
+ tot += gspca_dev->usb_buf[0];
+ reg_r(gspca_dev, 0x8614, 1);
+ tot += gspca_dev->usb_buf[0];
+ sd->brightness = tot >> 2;
}
+/* rev72a only */
static void getcontrast(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
__u16 tot;
- switch (sd->chip_revision) {
- case Rev072A:
- tot = 0;
- reg_r(gspca_dev, 0x8651, 1);
- tot += gspca_dev->usb_buf[0];
- reg_r(gspca_dev, 0x8652, 1);
- tot += gspca_dev->usb_buf[0];
- reg_r(gspca_dev, 0x8653, 1);
- tot += gspca_dev->usb_buf[0];
- reg_r(gspca_dev, 0x8654, 1);
- tot += gspca_dev->usb_buf[0];
- sd->contrast = tot << 6;
- break;
- default:
-/* case Rev012A: */
- /* no way to read sensor settings */
- break;
- }
+ tot = 0;
+ reg_r(gspca_dev, 0x8651, 1);
+ tot += gspca_dev->usb_buf[0];
+ reg_r(gspca_dev, 0x8652, 1);
+ tot += gspca_dev->usb_buf[0];
+ reg_r(gspca_dev, 0x8653, 1);
+ tot += gspca_dev->usb_buf[0];
+ reg_r(gspca_dev, 0x8654, 1);
+ tot += gspca_dev->usb_buf[0];
+ sd->contrast = tot << 6;
PDEBUG(D_CONF, "get contrast %d", sd->contrast);
}
+/* rev 72a only */
static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -931,6 +963,7 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
return 0;
}
+/* rev 72a only */
static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -968,20 +1001,190 @@ static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
return 0;
}
+/* rev12a only */
+static int sd_setwhite(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->white = val;
+ if (gspca_dev->streaming)
+ setwhite(gspca_dev);
+ return 0;
+}
+
+static int sd_getwhite(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->white;
+ return 0;
+}
+
+/* rev12a only */
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->exposure = val;
+ if (gspca_dev->streaming)
+ setexposure(gspca_dev);
+ return 0;
+}
+
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->exposure;
+ return 0;
+}
+
+/* rev12a only */
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->gain = val;
+ if (gspca_dev->streaming)
+ setgain(gspca_dev);
+ return 0;
+}
+
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->gain;
+ return 0;
+}
+
+/* control tables */
+static struct ctrl sd_ctrls_12a[] = {
+ {
+ {
+ .id = V4L2_CID_DO_WHITE_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "While Balance",
+ .minimum = WHITE_MIN,
+ .maximum = WHITE_MAX,
+ .step = 1,
+ .default_value = WHITE_DEF,
+ },
+ .set = sd_setwhite,
+ .get = sd_getwhite,
+ },
+ {
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Exposure",
+ .minimum = EXPOSURE_MIN,
+ .maximum = EXPOSURE_MAX,
+ .step = 1,
+ .default_value = EXPOSURE_DEF,
+ },
+ .set = sd_setexposure,
+ .get = sd_getexposure,
+ },
+ {
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto Gain",
+ .minimum = AUTOGAIN_MIN,
+ .maximum = AUTOGAIN_MAX,
+ .step = 1,
+ .default_value = AUTOGAIN_DEF,
+ },
+ .set = sd_setautogain,
+ .get = sd_getautogain,
+ },
+ {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gain",
+ .minimum = GAIN_MIN,
+ .maximum = GAIN_MAX,
+ .step = 1,
+ .default_value = GAIN_DEF,
+ },
+ .set = sd_setgain,
+ .get = sd_getgain,
+ },
+};
+
+static struct ctrl sd_ctrls_72a[] = {
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = BRIGHTNESS_MIN,
+ .maximum = BRIGHTNESS_MAX,
+ .step = 1,
+ .default_value = BRIGHTNESS_DEF,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = CONTRAST_MIN,
+ .maximum = CONTRAST_MAX,
+ .step = 1,
+ .default_value = CONTRAST_DEF,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+ {
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto Gain",
+ .minimum = AUTOGAIN_MIN,
+ .maximum = AUTOGAIN_MAX,
+ .step = 1,
+ .default_value = AUTOGAIN_DEF,
+ },
+ .set = sd_setautogain,
+ .get = sd_getautogain,
+ },
+};
+
/* sub-driver description */
-static const struct sd_desc sd_desc = {
+static const struct sd_desc sd_desc_12a = {
.name = MODULE_NAME,
- .ctrls = sd_ctrls,
- .nctrls = ARRAY_SIZE(sd_ctrls),
+ .ctrls = sd_ctrls_12a,
+ .nctrls = ARRAY_SIZE(sd_ctrls_12a),
.config = sd_config,
- .open = sd_open,
- .start = sd_start,
+ .init = sd_init_12a,
+ .start = sd_start_12a,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .pkt_scan = sd_pkt_scan,
+/* .dq_callback = do_autogain, * fixme */
+};
+static const struct sd_desc sd_desc_72a = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls_72a,
+ .nctrls = ARRAY_SIZE(sd_ctrls_72a),
+ .config = sd_config,
+ .init = sd_init_72a,
+ .start = sd_start_72a,
.stopN = sd_stopN,
.stop0 = sd_stop0,
- .close = sd_close,
.pkt_scan = sd_pkt_scan,
.dq_callback = do_autogain,
};
+static const struct sd_desc *sd_desc[2] = {
+ &sd_desc_12a,
+ &sd_desc_72a
+};
/* -- module initialisation -- */
static const __devinitdata struct usb_device_id device_table[] = {
@@ -1009,7 +1212,9 @@ MODULE_DEVICE_TABLE(usb, device_table);
static int sd_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
- return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+ return gspca_dev_probe(intf, id,
+ sd_desc[id->driver_info],
+ sizeof(struct sd),
THIS_MODULE);
}
@@ -1018,6 +1223,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
/* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/stk014.c b/drivers/media/video/gspca/stk014.c
index 16219cf6a6d..2f2de429e27 100644
--- a/drivers/media/video/gspca/stk014.c
+++ b/drivers/media/video/gspca/stk014.c
@@ -306,8 +306,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
return 0;
}
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
{
int ret;
@@ -398,14 +398,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
PDEBUG(D_STREAM, "camera stopped");
}
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
-
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
struct gspca_frame *frame, /* target */
__u8 *data, /* isoc packet */
@@ -535,11 +527,9 @@ static const struct sd_desc sd_desc = {
.ctrls = sd_ctrls,
.nctrls = ARRAY_SIZE(sd_ctrls),
.config = sd_config,
- .open = sd_open,
+ .init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
- .stop0 = sd_stop0,
- .close = sd_close,
.pkt_scan = sd_pkt_scan,
.querymenu = sd_querymenu,
};
@@ -564,6 +554,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
/* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c
index 54efa48bee0..1cfcc6c4955 100644
--- a/drivers/media/video/gspca/sunplus.c
+++ b/drivers/media/video/gspca/sunplus.c
@@ -449,31 +449,47 @@ static const __u8 qtable_spca504_default[2][64] = {
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
};
-static void reg_r(struct usb_device *dev,
- __u16 req,
- __u16 index,
- __u8 *buffer, __u16 length)
+/* read <len> bytes to gspca_dev->usb_buf */
+static void reg_r(struct gspca_dev *gspca_dev,
+ __u16 req,
+ __u16 index,
+ __u16 len)
{
- usb_control_msg(dev,
- usb_rcvctrlpipe(dev, 0),
+#ifdef GSPCA_DEBUG
+ if (len > USB_BUF_SZ) {
+ err("reg_r: buffer overflow");
+ return;
+ }
+#endif
+ usb_control_msg(gspca_dev->dev,
+ usb_rcvctrlpipe(gspca_dev->dev, 0),
req,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0, /* value */
- index, buffer, length,
+ index,
+ len ? gspca_dev->usb_buf : NULL, len,
500);
}
-static void reg_w(struct usb_device *dev,
- __u16 req,
- __u16 value,
- __u16 index,
- __u8 *buffer, __u16 length)
+/* write <len> bytes from gspca_dev->usb_buf */
+static void reg_w(struct gspca_dev *gspca_dev,
+ __u16 req,
+ __u16 value,
+ __u16 index,
+ __u16 len)
{
- usb_control_msg(dev,
- usb_sndctrlpipe(dev, 0),
+#ifdef GSPCA_DEBUG
+ if (len > USB_BUF_SZ) {
+ err("reg_w: buffer overflow");
+ return;
+ }
+#endif
+ usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
req,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- value, index, buffer, length,
+ value, index,
+ len ? gspca_dev->usb_buf : NULL, len,
500);
}
@@ -634,7 +650,7 @@ static int spca504B_PollingDataReady(struct gspca_dev *gspca_dev)
int count = 10;
while (--count > 0) {
- reg_r(gspca_dev->dev, 0x21, 0, gspca_dev->usb_buf, 1);
+ reg_r(gspca_dev, 0x21, 0, 1);
if ((gspca_dev->usb_buf[0] & 0x01) == 0)
break;
msleep(10);
@@ -644,15 +660,14 @@ static int spca504B_PollingDataReady(struct gspca_dev *gspca_dev)
static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
{
- struct usb_device *dev = gspca_dev->dev;
int count = 50;
while (--count > 0) {
- reg_r(dev, 0x21, 1, gspca_dev->usb_buf, 1);
+ reg_r(gspca_dev, 0x21, 1, 1);
if (gspca_dev->usb_buf[0] != 0) {
gspca_dev->usb_buf[0] = 0;
- reg_w(dev, 0x21, 0, 1, gspca_dev->usb_buf, 1);
- reg_r(dev, 0x21, 1, gspca_dev->usb_buf, 1);
+ reg_w(gspca_dev, 0x21, 0, 1, 1);
+ reg_r(gspca_dev, 0x21, 1, 1);
spca504B_PollingDataReady(gspca_dev);
break;
}
@@ -662,16 +677,14 @@ static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
{
- struct usb_device *dev = gspca_dev->dev;
__u8 *data;
- data = kmalloc(64, GFP_KERNEL);
- reg_r(dev, 0x20, 0, data, 5);
+ data = gspca_dev->usb_buf;
+ reg_r(gspca_dev, 0x20, 0, 5);
PDEBUG(D_STREAM, "FirmWare : %d %d %d %d %d ",
data[0], data[1], data[2], data[3], data[4]);
- reg_r(dev, 0x23, 0, data, 64);
- reg_r(dev, 0x23, 1, data, 64);
- kfree(data);
+ reg_r(gspca_dev, 0x23, 0, 64);
+ reg_r(gspca_dev, 0x23, 1, 64);
}
static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
@@ -686,21 +699,21 @@ static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
Type = 0;
switch (sd->bridge) {
case BRIDGE_SPCA533:
- reg_w(dev, 0x31, 0, 0, NULL, 0);
+ reg_w(gspca_dev, 0x31, 0, 0, 0);
spca504B_WaitCmdStatus(gspca_dev);
rc = spca504B_PollingDataReady(gspca_dev);
spca50x_GetFirmware(gspca_dev);
gspca_dev->usb_buf[0] = 2; /* type */
- reg_w(dev, 0x24, 0, 8, gspca_dev->usb_buf, 1);
- reg_r(dev, 0x24, 8, gspca_dev->usb_buf, 1);
+ reg_w(gspca_dev, 0x24, 0, 8, 1);
+ reg_r(gspca_dev, 0x24, 8, 1);
gspca_dev->usb_buf[0] = Size;
- reg_w(dev, 0x25, 0, 4, gspca_dev->usb_buf, 1);
- reg_r(dev, 0x25, 4, gspca_dev->usb_buf, 1); /* size */
+ reg_w(gspca_dev, 0x25, 0, 4, 1);
+ reg_r(gspca_dev, 0x25, 4, 1); /* size */
rc = spca504B_PollingDataReady(gspca_dev);
/* Init the cam width height with some values get on init ? */
- reg_w(dev, 0x31, 0, 4, NULL, 0);
+ reg_w(gspca_dev, 0x31, 0, 4, 0);
spca504B_WaitCmdStatus(gspca_dev);
rc = spca504B_PollingDataReady(gspca_dev);
break;
@@ -708,12 +721,12 @@ static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
/* case BRIDGE_SPCA504B: */
/* case BRIDGE_SPCA536: */
gspca_dev->usb_buf[0] = Size;
- reg_w(dev, 0x25, 0, 4, gspca_dev->usb_buf, 1);
- reg_r(dev, 0x25, 4, gspca_dev->usb_buf, 1); /* size */
+ reg_w(gspca_dev, 0x25, 0, 4, 1);
+ reg_r(gspca_dev, 0x25, 4, 1); /* size */
Type = 6;
gspca_dev->usb_buf[0] = Type;
- reg_w(dev, 0x27, 0, 0, gspca_dev->usb_buf, 1);
- reg_r(dev, 0x27, 0, gspca_dev->usb_buf, 1); /* type */
+ reg_w(gspca_dev, 0x27, 0, 0, 1);
+ reg_r(gspca_dev, 0x27, 0, 1); /* type */
rc = spca504B_PollingDataReady(gspca_dev);
break;
case BRIDGE_SPCA504:
@@ -752,18 +765,15 @@ static void spca504_wait_status(struct gspca_dev *gspca_dev)
static void spca504B_setQtable(struct gspca_dev *gspca_dev)
{
- struct usb_device *dev = gspca_dev->dev;
-
gspca_dev->usb_buf[0] = 3;
- reg_w(dev, 0x26, 0, 0, gspca_dev->usb_buf, 1);
- reg_r(dev, 0x26, 0, gspca_dev->usb_buf, 1);
+ reg_w(gspca_dev, 0x26, 0, 0, 1);
+ reg_r(gspca_dev, 0x26, 0, 1);
spca504B_PollingDataReady(gspca_dev);
}
static void sp5xx_initContBrigHueRegisters(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- struct usb_device *dev = gspca_dev->dev;
int pollreg = 1;
switch (sd->bridge) {
@@ -774,20 +784,20 @@ static void sp5xx_initContBrigHueRegisters(struct gspca_dev *gspca_dev)
default:
/* case BRIDGE_SPCA533: */
/* case BRIDGE_SPCA504B: */
- reg_w(dev, 0, 0, 0x21a7, NULL, 0); /* brightness */
- reg_w(dev, 0, 0x20, 0x21a8, NULL, 0); /* contrast */
- reg_w(dev, 0, 0, 0x21ad, NULL, 0); /* hue */
- reg_w(dev, 0, 1, 0x21ac, NULL, 0); /* sat/hue */
- reg_w(dev, 0, 0x20, 0x21ae, NULL, 0); /* saturation */
- reg_w(dev, 0, 0, 0x21a3, NULL, 0); /* gamma */
+ reg_w(gspca_dev, 0, 0, 0x21a7, 0); /* brightness */
+ reg_w(gspca_dev, 0, 0x20, 0x21a8, 0); /* contrast */
+ reg_w(gspca_dev, 0, 0, 0x21ad, 0); /* hue */
+ reg_w(gspca_dev, 0, 1, 0x21ac, 0); /* sat/hue */
+ reg_w(gspca_dev, 0, 0x20, 0x21ae, 0); /* saturation */
+ reg_w(gspca_dev, 0, 0, 0x21a3, 0); /* gamma */
break;
case BRIDGE_SPCA536:
- reg_w(dev, 0, 0, 0x20f0, NULL, 0);
- reg_w(dev, 0, 0x21, 0x20f1, NULL, 0);
- reg_w(dev, 0, 0x40, 0x20f5, NULL, 0);
- reg_w(dev, 0, 1, 0x20f4, NULL, 0);
- reg_w(dev, 0, 0x40, 0x20f6, NULL, 0);
- reg_w(dev, 0, 0, 0x2089, NULL, 0);
+ reg_w(gspca_dev, 0, 0, 0x20f0, 0);
+ reg_w(gspca_dev, 0, 0x21, 0x20f1, 0);
+ reg_w(gspca_dev, 0, 0x40, 0x20f5, 0);
+ reg_w(gspca_dev, 0, 1, 0x20f4, 0);
+ reg_w(gspca_dev, 0, 0x40, 0x20f6, 0);
+ reg_w(gspca_dev, 0, 0, 0x2089, 0);
break;
}
if (pollreg)
@@ -799,7 +809,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
const struct usb_device_id *id)
{
struct sd *sd = (struct sd *) gspca_dev;
- struct usb_device *dev = gspca_dev->dev;
struct cam *cam;
cam = &gspca_dev->cam;
@@ -811,7 +820,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
if (sd->subtype == AiptekMiniPenCam13) {
/* try to get the firmware as some cam answer 2.0.1.2.2
* and should be a spca504b then overwrite that setting */
- reg_r(dev, 0x20, 0, gspca_dev->usb_buf, 1);
+ reg_r(gspca_dev, 0x20, 0, 1);
switch (gspca_dev->usb_buf[0]) {
case 1:
break; /* (right bridge/subtype) */
@@ -848,8 +857,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
return 0;
}
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
struct usb_device *dev = gspca_dev->dev;
@@ -860,12 +869,12 @@ static int sd_open(struct gspca_dev *gspca_dev)
switch (sd->bridge) {
case BRIDGE_SPCA504B:
- reg_w(dev, 0x1d, 0, 0, NULL, 0);
- reg_w(dev, 0, 1, 0x2306, NULL, 0);
- reg_w(dev, 0, 0, 0x0d04, NULL, 0);
- reg_w(dev, 0, 0, 0x2000, NULL, 0);
- reg_w(dev, 0, 0x13, 0x2301, NULL, 0);
- reg_w(dev, 0, 0, 0x2306, NULL, 0);
+ reg_w(gspca_dev, 0x1d, 0, 0, 0);
+ reg_w(gspca_dev, 0, 1, 0x2306, 0);
+ reg_w(gspca_dev, 0, 0, 0x0d04, 0);
+ reg_w(gspca_dev, 0, 0, 0x2000, 0);
+ reg_w(gspca_dev, 0, 0x13, 0x2301, 0);
+ reg_w(gspca_dev, 0, 0, 0x2306, 0);
/* fall thru */
case BRIDGE_SPCA533:
rc = spca504B_PollingDataReady(gspca_dev);
@@ -873,12 +882,12 @@ static int sd_open(struct gspca_dev *gspca_dev)
break;
case BRIDGE_SPCA536:
spca50x_GetFirmware(gspca_dev);
- reg_r(dev, 0x00, 0x5002, gspca_dev->usb_buf, 1);
+ reg_r(gspca_dev, 0x00, 0x5002, 1);
gspca_dev->usb_buf[0] = 0;
- reg_w(dev, 0x24, 0, 0, gspca_dev->usb_buf, 1);
- reg_r(dev, 0x24, 0, gspca_dev->usb_buf, 1);
+ reg_w(gspca_dev, 0x24, 0, 0, 1);
+ reg_r(gspca_dev, 0x24, 0, 1);
rc = spca504B_PollingDataReady(gspca_dev);
- reg_w(dev, 0x34, 0, 0, NULL, 0);
+ reg_w(gspca_dev, 0x34, 0, 0, 0);
spca504B_WaitCmdStatus(gspca_dev);
break;
case BRIDGE_SPCA504C: /* pccam600 */
@@ -971,12 +980,12 @@ static void sd_start(struct gspca_dev *gspca_dev)
/* case BRIDGE_SPCA536: */
if (sd->subtype == MegapixV4 ||
sd->subtype == LogitechClickSmart820) {
- reg_w(dev, 0xf0, 0, 0, NULL, 0);
+ reg_w(gspca_dev, 0xf0, 0, 0, 0);
spca504B_WaitCmdStatus(gspca_dev);
- reg_r(dev, 0xf0, 4, NULL, 0);
+ reg_r(gspca_dev, 0xf0, 4, 0);
spca504B_WaitCmdStatus(gspca_dev);
} else {
- reg_w(dev, 0x31, 0, 4, NULL, 0);
+ reg_w(gspca_dev, 0x31, 0, 4, 0);
spca504B_WaitCmdStatus(gspca_dev);
rc = spca504B_PollingDataReady(gspca_dev);
}
@@ -1045,7 +1054,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
/* case BRIDGE_SPCA533: */
/* case BRIDGE_SPCA536: */
/* case BRIDGE_SPCA504B: */
- reg_w(dev, 0x31, 0, 0, NULL, 0);
+ reg_w(gspca_dev, 0x31, 0, 0, 0);
spca504B_WaitCmdStatus(gspca_dev);
spca504B_PollingDataReady(gspca_dev);
break;
@@ -1069,14 +1078,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
}
}
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
-
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
struct gspca_frame *frame, /* target */
__u8 *data, /* isoc packet */
@@ -1369,11 +1370,9 @@ static const struct sd_desc sd_desc = {
.ctrls = sd_ctrls,
.nctrls = ARRAY_SIZE(sd_ctrls),
.config = sd_config,
- .open = sd_open,
+ .init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
- .stop0 = sd_stop0,
- .close = sd_close,
.pkt_scan = sd_pkt_scan,
};
@@ -1456,6 +1455,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
/* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c
index 91b555c34c6..f034c748fc7 100644
--- a/drivers/media/video/gspca/t613.c
+++ b/drivers/media/video/gspca/t613.c
@@ -30,7 +30,7 @@
#define MAX_GAMMA 0x10 /* 0 to 15 */
-#define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 3)
+#define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 0)
MODULE_AUTHOR("Leandro Costantino <le_costantino@pixartargentina.com.ar>");
MODULE_DESCRIPTION("GSPCA/T613 (JPEG Compliance) USB Camera Driver");
@@ -233,7 +233,7 @@ static char *effects_control[] = {
static struct v4l2_pix_format vga_mode_t16[] = {
{160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 160,
- .sizeimage = 160 * 120 * 3 / 8 + 590,
+ .sizeimage = 160 * 120 * 4 / 8 + 590,
.colorspace = V4L2_COLORSPACE_JPEG,
.priv = 4},
{176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
@@ -391,7 +391,7 @@ static void reg_w(struct gspca_dev *gspca_dev,
NULL, 0, 500);
return;
}
- if (len <= sizeof gspca_dev->usb_buf) {
+ if (len <= USB_BUF_SZ) {
memcpy(gspca_dev->usb_buf, buffer, len);
usb_control_msg(gspca_dev->dev,
usb_sndctrlpipe(gspca_dev->dev, 0),
@@ -552,6 +552,13 @@ static int init_default_parameters(struct gspca_dev *gspca_dev)
return 0;
}
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+ init_default_parameters(gspca_dev);
+ return 0;
+}
+
static void setbrightness(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -893,18 +900,6 @@ static void sd_start(struct gspca_dev *gspca_dev)
setcolors(gspca_dev);
}
-static void sd_stopN(struct gspca_dev *gspca_dev)
-{
-}
-
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
-
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
struct gspca_frame *frame, /* target */
__u8 *data, /* isoc packet */
@@ -972,24 +967,14 @@ static int sd_querymenu(struct gspca_dev *gspca_dev,
return -EINVAL;
}
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
-{
- init_default_parameters(gspca_dev);
- return 0;
-}
-
/* sub-driver description */
static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
.ctrls = sd_ctrls,
.nctrls = ARRAY_SIZE(sd_ctrls),
.config = sd_config,
- .open = sd_open,
+ .init = sd_init,
.start = sd_start,
- .stopN = sd_stopN,
- .stop0 = sd_stop0,
- .close = sd_close,
.pkt_scan = sd_pkt_scan,
.querymenu = sd_querymenu,
};
@@ -1014,6 +999,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
/* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/tv8532.c b/drivers/media/video/gspca/tv8532.c
index 1ff8ba2f7fe..084af05302a 100644
--- a/drivers/media/video/gspca/tv8532.c
+++ b/drivers/media/video/gspca/tv8532.c
@@ -331,8 +331,8 @@ static void tv_8532_PollReg(struct gspca_dev *gspca_dev)
}
}
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
{
reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x32);
reg_w_1(gspca_dev, TV8532_AD_BITCTRL, 0x00);
@@ -450,14 +450,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b);
}
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
-
static void tv8532_preprocess(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -611,11 +603,9 @@ static const struct sd_desc sd_desc = {
.ctrls = sd_ctrls,
.nctrls = ARRAY_SIZE(sd_ctrls),
.config = sd_config,
- .open = sd_open,
+ .init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
- .stop0 = sd_stop0,
- .close = sd_close,
.pkt_scan = sd_pkt_scan,
};
@@ -644,6 +634,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
/* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c
index f4a52956e0d..bd4c226c9a0 100644
--- a/drivers/media/video/gspca/vc032x.c
+++ b/drivers/media/video/gspca/vc032x.c
@@ -69,6 +69,7 @@ static struct ctrl sd_ctrls[] = {
.set = sd_setautogain,
.get = sd_getautogain,
},
+#define LIGHTFREQ_IDX 1
{
{
.id = V4L2_CID_POWER_LINE_FREQUENCY,
@@ -87,12 +88,12 @@ static struct ctrl sd_ctrls[] = {
};
static struct v4l2_pix_format vc0321_mode[] = {
- {320, 240, V4L2_PIX_FMT_YUV420, V4L2_FIELD_NONE,
+ {320, 240, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE,
.bytesperline = 320,
.sizeimage = 320 * 240 * 2,
.colorspace = V4L2_COLORSPACE_SRGB,
.priv = 1},
- {640, 480, V4L2_PIX_FMT_YUV420, V4L2_FIELD_NONE,
+ {640, 480, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE,
.bytesperline = 640,
.sizeimage = 640 * 480 * 2,
.colorspace = V4L2_COLORSPACE_SRGB,
@@ -1463,6 +1464,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->qindex = 7;
sd->autogain = AUTOGAIN_DEF;
sd->lightfreq = FREQ_DEF;
+ if (sd->sensor != SENSOR_OV7670)
+ gspca_dev->ctrl_dis = (1 << LIGHTFREQ_IDX);
if (sd->bridge == BRIDGE_VC0321) {
reg_r(gspca_dev, 0x8a, 0, 3);
@@ -1474,8 +1477,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
return 0;
}
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and time */
+static int sd_init(struct gspca_dev *gspca_dev)
{
return 0;
}
@@ -1637,19 +1640,6 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
reg_w(dev, 0x89, 0xffff, 0xffff);
}
-/* this function is called at close time */
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-/* struct usb_device *dev = gspca_dev->dev;
- __u8 buffread;
-
- reg_w(dev, 0x89, 0xffff, 0xffff);
- reg_w(dev, 0xa0, 0x01, 0xb301);
- reg_w(dev, 0xa0, 0x09, 0xb303);
- reg_w(dev, 0x89, 0xffff, 0xffff);
-*/
-}
-
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
struct gspca_frame *frame, /* target */
__u8 *data, /* isoc packet */
@@ -1738,11 +1728,10 @@ static const struct sd_desc sd_desc = {
.ctrls = sd_ctrls,
.nctrls = ARRAY_SIZE(sd_ctrls),
.config = sd_config,
- .open = sd_open,
+ .init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
.stop0 = sd_stop0,
- .close = sd_close,
.pkt_scan = sd_pkt_scan,
.querymenu = sd_querymenu,
};
@@ -1774,6 +1763,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
/* -- module insert / remove -- */
diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c
index bc7d0eedcd8..d61ef727e0c 100644
--- a/drivers/media/video/gspca/zc3xx.c
+++ b/drivers/media/video/gspca/zc3xx.c
@@ -85,6 +85,7 @@ static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
static struct ctrl sd_ctrls[] = {
+#define BRIGHTNESS_IDX 0
#define SD_BRIGHTNESS 0
{
{
@@ -141,6 +142,7 @@ static struct ctrl sd_ctrls[] = {
.set = sd_setautogain,
.get = sd_getautogain,
},
+#define LIGHTFREQ_IDX 4
#define SD_FREQ 4
{
{
@@ -6574,8 +6576,8 @@ static int setlightfreq(struct gspca_dev *gspca_dev)
cs2102_60HZ, cs2102_60HZScale},
/* SENSOR_CS2102K 1 */
{cs2102_NoFliker, cs2102_NoFlikerScale,
- cs2102_50HZ, cs2102_50HZScale,
- cs2102_60HZ, cs2102_60HZScale},
+ NULL, NULL, /* currently disabled */
+ NULL, NULL},
/* SENSOR_GC0305 2 */
{gc0305_NoFliker, gc0305_NoFliker,
gc0305_50HZ, gc0305_50HZ,
@@ -6964,8 +6966,13 @@ static int zcxx_probeSensor(struct gspca_dev *gspca_dev)
case SENSOR_MC501CB:
return -1; /* don't probe */
case SENSOR_TAS5130C_VF0250:
- /* may probe but with write in reg 0x0010 */
+ /* may probe but with no write in reg 0x0010 */
return -1; /* don't probe */
+ case SENSOR_PAS106:
+ sensor = sif_probe(gspca_dev);
+ if (sensor >= 0)
+ return sensor;
+ break;
}
sensor = vga_2wr_probe(gspca_dev);
if (sensor >= 0) {
@@ -6974,12 +6981,10 @@ static int zcxx_probeSensor(struct gspca_dev *gspca_dev)
/* next probe is needed for OmniVision ? */
}
sensor2 = vga_3wr_probe(gspca_dev);
- if (sensor2 >= 0) {
- if (sensor >= 0)
- return sensor;
- return sensor2;
- }
- return sif_probe(gspca_dev);
+ if (sensor2 >= 0
+ && sensor >= 0)
+ return sensor;
+ return sensor2;
}
/* this function is called at probe time */
@@ -7147,13 +7152,27 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->lightfreq = sd_ctrls[SD_FREQ].qctrl.default_value;
sd->sharpness = sd_ctrls[SD_SHARPNESS].qctrl.default_value;
+ switch (sd->sensor) {
+ case SENSOR_GC0305:
+ case SENSOR_OV7620:
+ case SENSOR_PO2030:
+ gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX);
+ break;
+ case SENSOR_HDCS2020:
+ case SENSOR_HV7131B:
+ case SENSOR_HV7131C:
+ case SENSOR_OV7630C:
+ gspca_dev->ctrl_dis = (1 << LIGHTFREQ_IDX);
+ break;
+ }
+
/* switch the led off */
reg_w(gspca_dev->dev, 0x01, 0x0000);
return 0;
}
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
{
reg_w(gspca_dev->dev, 0x01, 0x0000);
return 0;
@@ -7314,10 +7333,6 @@ static void sd_start(struct gspca_dev *gspca_dev)
}
}
-static void sd_stopN(struct gspca_dev *gspca_dev)
-{
-}
-
static void sd_stop0(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -7325,11 +7340,6 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
send_unknown(gspca_dev->dev, sd->sensor);
}
-/* this function is called at close time */
-static void sd_close(struct gspca_dev *gspca_dev)
-{
-}
-
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
struct gspca_frame *frame,
__u8 *data,
@@ -7489,37 +7499,30 @@ static const struct sd_desc sd_desc = {
.ctrls = sd_ctrls,
.nctrls = sizeof sd_ctrls / sizeof sd_ctrls[0],
.config = sd_config,
- .open = sd_open,
+ .init = sd_init,
.start = sd_start,
- .stopN = sd_stopN,
.stop0 = sd_stop0,
- .close = sd_close,
.pkt_scan = sd_pkt_scan,
.querymenu = sd_querymenu,
};
static const __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x041e, 0x041e)},
-#ifndef CONFIG_USB_ZC0301
{USB_DEVICE(0x041e, 0x4017)},
- {USB_DEVICE(0x041e, 0x401c)},
+ {USB_DEVICE(0x041e, 0x401c), .driver_info = SENSOR_PAS106},
{USB_DEVICE(0x041e, 0x401e)},
{USB_DEVICE(0x041e, 0x401f)},
-#endif
+ {USB_DEVICE(0x041e, 0x4022)},
{USB_DEVICE(0x041e, 0x4029)},
-#ifndef CONFIG_USB_ZC0301
- {USB_DEVICE(0x041e, 0x4034)},
- {USB_DEVICE(0x041e, 0x4035)},
+ {USB_DEVICE(0x041e, 0x4034), .driver_info = SENSOR_PAS106},
+ {USB_DEVICE(0x041e, 0x4035), .driver_info = SENSOR_PAS106},
{USB_DEVICE(0x041e, 0x4036)},
{USB_DEVICE(0x041e, 0x403a)},
-#endif
{USB_DEVICE(0x041e, 0x4051), .driver_info = SENSOR_TAS5130C_VF0250},
{USB_DEVICE(0x041e, 0x4053), .driver_info = SENSOR_TAS5130C_VF0250},
-#ifndef CONFIG_USB_ZC0301
{USB_DEVICE(0x0458, 0x7007)},
{USB_DEVICE(0x0458, 0x700c)},
{USB_DEVICE(0x0458, 0x700f)},
-#endif
{USB_DEVICE(0x0461, 0x0a00)},
{USB_DEVICE(0x046d, 0x08a0)},
{USB_DEVICE(0x046d, 0x08a1)},
@@ -7531,7 +7534,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x046d, 0x08aa)},
{USB_DEVICE(0x046d, 0x08ac)},
{USB_DEVICE(0x046d, 0x08ad)},
-#ifndef CONFIG_USB_ZC0301
+#if !defined CONFIG_USB_ZC0301 && !defined CONFIG_USB_ZC0301_MODULE
{USB_DEVICE(0x046d, 0x08ae)},
#endif
{USB_DEVICE(0x046d, 0x08af)},
@@ -7541,27 +7544,25 @@ static const __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x046d, 0x08d8)},
{USB_DEVICE(0x046d, 0x08da)},
{USB_DEVICE(0x046d, 0x08dd), .driver_info = SENSOR_MC501CB},
- {USB_DEVICE(0x0471, 0x0325)},
- {USB_DEVICE(0x0471, 0x0326)},
- {USB_DEVICE(0x0471, 0x032d)},
- {USB_DEVICE(0x0471, 0x032e)},
+ {USB_DEVICE(0x0471, 0x0325), .driver_info = SENSOR_PAS106},
+ {USB_DEVICE(0x0471, 0x0326), .driver_info = SENSOR_PAS106},
+ {USB_DEVICE(0x0471, 0x032d), .driver_info = SENSOR_PAS106},
+ {USB_DEVICE(0x0471, 0x032e), .driver_info = SENSOR_PAS106},
{USB_DEVICE(0x055f, 0xc005)},
-#ifndef CONFIG_USB_ZC0301
{USB_DEVICE(0x055f, 0xd003)},
{USB_DEVICE(0x055f, 0xd004)},
-#endif
{USB_DEVICE(0x0698, 0x2003)},
+ {USB_DEVICE(0x0ac8, 0x0301), .driver_info = SENSOR_PAS106},
{USB_DEVICE(0x0ac8, 0x0302)},
-#ifndef CONFIG_USB_ZC0301
{USB_DEVICE(0x0ac8, 0x301b)},
+#if !defined CONFIG_USB_ZC0301 && !defined CONFIG_USB_ZC0301_MODULE
{USB_DEVICE(0x0ac8, 0x303b)},
#endif
{USB_DEVICE(0x0ac8, 0x305b), .driver_info = SENSOR_TAS5130C_VF0250},
-#ifndef CONFIG_USB_ZC0301
{USB_DEVICE(0x0ac8, 0x307b)},
{USB_DEVICE(0x10fd, 0x0128)},
+ {USB_DEVICE(0x10fd, 0x804d)},
{USB_DEVICE(0x10fd, 0x8050)},
-#endif
{} /* end of entry */
};
#undef DVNAME
@@ -7581,6 +7582,10 @@ static struct usb_driver sd_driver = {
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
};
static int __init sd_mod_init(void)
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index aea1664948c..4afc7ea07e8 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -688,7 +688,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv)
spin_lock_init(&itv->lock);
spin_lock_init(&itv->dma_reg_lock);
- itv->irq_work_queues = create_workqueue(itv->name);
+ itv->irq_work_queues = create_singlethread_workqueue(itv->name);
if (itv->irq_work_queues == NULL) {
IVTV_ERR("Could not create ivtv workqueue\n");
return -1;
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
index ab287b48fc2..2ceb5227637 100644
--- a/drivers/media/video/ivtv/ivtv-driver.h
+++ b/drivers/media/video/ivtv/ivtv-driver.h
@@ -251,6 +251,7 @@ struct ivtv_mailbox_data {
#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 */
+#define IVTV_F_I_WORK_INITED 23 /* worker thread was initialized */
/* Event notifications */
#define IVTV_F_I_EV_DEC_STOPPED 28 /* decoder stopped event */
diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c
index fba150a6cd2..34f3ab82785 100644
--- a/drivers/media/video/ivtv/ivtv-irq.c
+++ b/drivers/media/video/ivtv/ivtv-irq.c
@@ -76,6 +76,13 @@ void ivtv_irq_work_handler(struct work_struct *work)
DEFINE_WAIT(wait);
+ if (test_and_clear_bit(IVTV_F_I_WORK_INITED, &itv->i_flags)) {
+ struct sched_param param = { .sched_priority = 99 };
+
+ /* This thread must use the FIFO scheduler as it
+ is realtime sensitive. */
+ sched_setscheduler(current, SCHED_FIFO, &param);
+ }
if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_PIO, &itv->i_flags))
ivtv_pio_work_handler(itv);
@@ -678,34 +685,14 @@ static void ivtv_irq_enc_start_cap(struct ivtv *itv)
static void ivtv_irq_enc_vbi_cap(struct ivtv *itv)
{
- struct ivtv_stream *s_mpg = &itv->streams[IVTV_ENC_STREAM_TYPE_MPG];
u32 data[CX2341X_MBOX_MAX_DATA];
struct ivtv_stream *s;
IVTV_DEBUG_HI_IRQ("ENC START VBI CAP\n");
s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
- /* If more than two VBI buffers are pending, then
- clear the old ones and start with this new one.
- This can happen during transition stages when MPEG capturing is
- started, but the first interrupts haven't arrived yet. During
- that period VBI requests can accumulate without being able to
- 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_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_pending_size = 0;
- }
- /* if we can append the data, and the MPEG stream isn't capturing,
- then start a DMA request for just the VBI data. */
- if (!stream_enc_dma_append(s, data) &&
- !test_bit(IVTV_F_S_STREAMING, &s_mpg->s_flags)) {
+ if (!stream_enc_dma_append(s, data))
set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags);
- }
}
static void ivtv_irq_dec_vbi_reinsert(struct ivtv *itv)
diff --git a/drivers/media/video/ivtv/ivtv-queue.h b/drivers/media/video/ivtv/ivtv-queue.h
index 7cfc0c9ab05..476556afd39 100644
--- a/drivers/media/video/ivtv/ivtv-queue.h
+++ b/drivers/media/video/ivtv/ivtv-queue.h
@@ -23,7 +23,7 @@
#define IVTV_QUEUE_H
#define IVTV_DMA_UNMAPPED ((u32) -1)
-#define SLICED_VBI_PIO 1
+#define SLICED_VBI_PIO 0
/* ivtv_buffer utility functions */
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
index 54d2023b26c..730e85d86fc 100644
--- a/drivers/media/video/ivtv/ivtv-streams.c
+++ b/drivers/media/video/ivtv/ivtv-streams.c
@@ -363,7 +363,7 @@ static void ivtv_vbi_setup(struct ivtv *itv)
/* Every X number of frames a VBI interrupt arrives (frames as in 25 or 30 fps) */
data[1] = 1;
/* The VBI frames are stored in a ringbuffer with this size (with a VBI frame as unit) */
- data[2] = raw ? 4 : 8;
+ data[2] = raw ? 4 : 4 * (itv->vbi.raw_size / itv->vbi.enc_size);
/* The start/stop codes determine which VBI lines end up in the raw VBI data area.
The codes are from table 24 in the saa7115 datasheet. Each raw/sliced/video line
is framed with codes FF0000XX where XX is the SAV/EAV (Start/End of Active Video)
diff --git a/drivers/media/video/ivtv/ivtv-vbi.c b/drivers/media/video/ivtv/ivtv-vbi.c
index 71798f0da27..1ce9deb1104 100644
--- a/drivers/media/video/ivtv/ivtv-vbi.c
+++ b/drivers/media/video/ivtv/ivtv-vbi.c
@@ -293,6 +293,7 @@ static u32 compress_sliced_buf(struct ivtv *itv, u32 line, u8 *buf, u32 size, u8
u32 line_size = itv->vbi.sliced_decoder_line_size;
struct v4l2_decode_vbi_line vbi;
int i;
+ unsigned lines = 0;
/* find the first valid line */
for (i = 0; i < size; i++, buf++) {
@@ -313,7 +314,8 @@ static u32 compress_sliced_buf(struct ivtv *itv, u32 line, u8 *buf, u32 size, u8
}
vbi.p = p + 4;
itv->video_dec_func(itv, VIDIOC_INT_DECODE_VBI_LINE, &vbi);
- if (vbi.type) {
+ if (vbi.type && !(lines & (1 << vbi.line))) {
+ lines |= 1 << vbi.line;
itv->vbi.sliced_data[line].id = vbi.type;
itv->vbi.sliced_data[line].field = vbi.is_second_field;
itv->vbi.sliced_data[line].line = vbi.line;
diff --git a/drivers/media/video/ivtv/ivtv-version.h b/drivers/media/video/ivtv/ivtv-version.h
index 442f43f11b7..8cd753d30bf 100644
--- a/drivers/media/video/ivtv/ivtv-version.h
+++ b/drivers/media/video/ivtv/ivtv-version.h
@@ -22,7 +22,7 @@
#define IVTV_DRIVER_NAME "ivtv"
#define IVTV_DRIVER_VERSION_MAJOR 1
-#define IVTV_DRIVER_VERSION_MINOR 3
+#define IVTV_DRIVER_VERSION_MINOR 4
#define IVTV_DRIVER_VERSION_PATCHLEVEL 0
#define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL)
diff --git a/drivers/media/video/ks0127.c b/drivers/media/video/ks0127.c
index 4895540be19..2fd4b4a44aa 100644
--- a/drivers/media/video/ks0127.c
+++ b/drivers/media/video/ks0127.c
@@ -679,26 +679,27 @@ static int ks0127_command(struct i2c_client *client,
case DECODER_ENABLE_OUTPUT:
{
+ int enable;
- int *iarg = arg;
- int enable = (*iarg != 0);
- if (enable) {
- dprintk("ks0127: command "
+ iarg = arg;
+ enable = (*iarg != 0);
+ if (enable) {
+ dprintk("ks0127: command "
"DECODER_ENABLE_OUTPUT on "
"(%d)\n", enable);
- /* All output pins on */
- ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x30);
- /* Obey the OEN pin */
- ks0127_and_or(ks, KS_CDEM, 0x7f, 0x00);
- } else {
- dprintk("ks0127: command "
+ /* All output pins on */
+ ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x30);
+ /* Obey the OEN pin */
+ ks0127_and_or(ks, KS_CDEM, 0x7f, 0x00);
+ } else {
+ dprintk("ks0127: command "
"DECODER_ENABLE_OUTPUT off "
"(%d)\n", enable);
- /* Video output pins off */
- ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x00);
- /* Ignore the OEN pin */
- ks0127_and_or(ks, KS_CDEM, 0x7f, 0x80);
- }
+ /* Video output pins off */
+ ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x00);
+ /* Ignore the OEN pin */
+ ks0127_and_or(ks, KS_CDEM, 0x7f, 0x80);
+ }
}
break;
diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
index 7c8ef6ac6c3..a9ef7802eb5 100644
--- a/drivers/media/video/meye.c
+++ b/drivers/media/video/meye.c
@@ -1806,6 +1806,7 @@ static int __devinit meye_probe(struct pci_dev *pcidev,
memcpy(meye.video_dev, &meye_template, sizeof(meye_template));
meye.video_dev->parent = &meye.mchip_dev->dev;
+ ret = -EIO;
if ((ret = sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 1))) {
printk(KERN_ERR "meye: unable to power on the camera\n");
printk(KERN_ERR "meye: did you enable the camera in "
@@ -1813,7 +1814,6 @@ static int __devinit meye_probe(struct pci_dev *pcidev,
goto outsonypienable;
}
- ret = -EIO;
if ((ret = pci_enable_device(meye.mchip_dev))) {
printk(KERN_ERR "meye: pci_enable_device failed\n");
goto outenabledev;
diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c
index f68e91fbe7f..8ef578caba3 100644
--- a/drivers/media/video/mxb.c
+++ b/drivers/media/video/mxb.c
@@ -931,27 +931,29 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
return 0;
}
-static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std)
+static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standard)
{
- struct mxb* mxb = (struct mxb*)dev->ext_priv;
+ struct mxb *mxb = (struct mxb *)dev->ext_priv;
int zero = 0;
int one = 1;
- if(V4L2_STD_PAL_I == std->id ) {
+ if (V4L2_STD_PAL_I == standard->id) {
v4l2_std_id std = V4L2_STD_PAL_I;
+
DEB_D(("VIDIOC_S_STD: setting mxb for PAL_I.\n"));
/* set the 7146 gpio register -- I don't know what this does exactly */
saa7146_write(dev, GPIO_CTRL, 0x00404050);
/* unset the 7111 gpio register -- I don't know what this does exactly */
- mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_GPIO, &zero);
+ mxb->saa7111a->driver->command(mxb->saa7111a, DECODER_SET_GPIO, &zero);
mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
} else {
v4l2_std_id std = V4L2_STD_PAL_BG;
+
DEB_D(("VIDIOC_S_STD: setting mxb for PAL/NTSC/SECAM.\n"));
/* set the 7146 gpio register -- I don't know what this does exactly */
saa7146_write(dev, GPIO_CTRL, 0x00404050);
/* set the 7111 gpio register -- I don't know what this does exactly */
- mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_GPIO, &one);
+ mxb->saa7111a->driver->command(mxb->saa7111a, DECODER_SET_GPIO, &one);
mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
}
return 0;
diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c
index 9edaca4371d..c6852402c5e 100644
--- a/drivers/media/video/ov511.c
+++ b/drivers/media/video/ov511.c
@@ -626,9 +626,9 @@ ov511_i2c_write_internal(struct usb_ov511 *ov,
break;
/* Retry until idle */
- do
+ do {
rc = reg_r(ov, R511_I2C_CTL);
- while (rc > 0 && ((rc&1) == 0));
+ } while (rc > 0 && ((rc&1) == 0));
if (rc < 0)
break;
@@ -703,9 +703,9 @@ ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
return rc;
/* Retry until idle */
- do
- rc = reg_r(ov, R511_I2C_CTL);
- while (rc > 0 && ((rc&1) == 0));
+ do {
+ rc = reg_r(ov, R511_I2C_CTL);
+ } while (rc > 0 && ((rc & 1) == 0));
if (rc < 0)
return rc;
@@ -729,9 +729,9 @@ ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
return rc;
/* Retry until idle */
- do
+ do {
rc = reg_r(ov, R511_I2C_CTL);
- while (rc > 0 && ((rc&1) == 0));
+ } while (rc > 0 && ((rc&1) == 0));
if (rc < 0)
return rc;
@@ -3591,7 +3591,7 @@ static int
ov51x_init_isoc(struct usb_ov511 *ov)
{
struct urb *urb;
- int fx, err, n, size;
+ int fx, err, n, i, size;
PDEBUG(3, "*** Initializing capture ***");
@@ -3662,6 +3662,8 @@ ov51x_init_isoc(struct usb_ov511 *ov)
urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
if (!urb) {
err("init isoc: usb_alloc_urb ret. NULL");
+ for (i = 0; i < n; i++)
+ usb_free_urb(ov->sbuf[i].urb);
return -ENOMEM;
}
ov->sbuf[n].urb = urb;
@@ -5651,7 +5653,7 @@ static ssize_t show_exposure(struct device *cd,
if (!ov->dev)
return -ENODEV;
sensor_get_exposure(ov, &exp);
- return sprintf(buf, "%d\n", exp >> 8);
+ return sprintf(buf, "%d\n", exp);
}
static DEVICE_ATTR(exposure, S_IRUGO, show_exposure, NULL);
diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c
index 00425d74365..7c84f795db5 100644
--- a/drivers/media/video/pms.c
+++ b/drivers/media/video/pms.c
@@ -1019,10 +1019,23 @@ static int init_mediavision(void)
* Initialization and module stuff
*/
+#ifndef MODULE
+static int enable;
+module_param(enable, int, 0);
+#endif
+
static int __init init_pms_cards(void)
{
printk(KERN_INFO "Mediavision Pro Movie Studio driver 0.02\n");
+#ifndef MODULE
+ if (!enable) {
+ printk(KERN_INFO "PMS: not enabled, use pms.enable=1 to "
+ "probe\n");
+ return -ENODEV;
+ }
+#endif
+
data_port = io_port +1;
if(init_mediavision())
diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
index 88e17516843..cbe2a341785 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
@@ -489,6 +489,8 @@ static const struct pvr2_device_desc pvr2_device_751xx = {
struct usb_device_id pvr2_device_table[] = {
{ USB_DEVICE(0x2040, 0x2900),
.driver_info = (kernel_ulong_t)&pvr2_device_29xxx},
+ { USB_DEVICE(0x2040, 0x2950), /* Logically identical to 2900 */
+ .driver_info = (kernel_ulong_t)&pvr2_device_29xxx},
{ USB_DEVICE(0x2040, 0x2400),
.driver_info = (kernel_ulong_t)&pvr2_device_24xxx},
{ USB_DEVICE(0x1164, 0x0622),
diff --git a/drivers/media/video/pwc/pwc-ctrl.c b/drivers/media/video/pwc/pwc-ctrl.c
index 1cccd5c7704..dbc56074255 100644
--- a/drivers/media/video/pwc/pwc-ctrl.c
+++ b/drivers/media/video/pwc/pwc-ctrl.c
@@ -1635,15 +1635,15 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
case VIDIOCPWCGVIDCMD:
{
- ARG_DEF(struct pwc_video_command, cmd);
-
- ARGR(cmd).type = pdev->type;
- ARGR(cmd).release = pdev->release;
- ARGR(cmd).command_len = pdev->cmd_len;
- memcpy(&ARGR(cmd).command_buf, pdev->cmd_buf, pdev->cmd_len);
- ARGR(cmd).bandlength = pdev->vbandlength;
- ARGR(cmd).frame_size = pdev->frame_size;
- ARG_OUT(cmd)
+ ARG_DEF(struct pwc_video_command, vcmd);
+
+ ARGR(vcmd).type = pdev->type;
+ ARGR(vcmd).release = pdev->release;
+ ARGR(vcmd).command_len = pdev->cmd_len;
+ memcpy(&ARGR(vcmd).command_buf, pdev->cmd_buf, pdev->cmd_len);
+ ARGR(vcmd).bandlength = pdev->vbandlength;
+ ARGR(vcmd).frame_size = pdev->frame_size;
+ ARG_OUT(vcmd)
break;
}
/*
diff --git a/drivers/media/video/s2255drv.c b/drivers/media/video/s2255drv.c
index b1d09d8e2b8..92b83feae36 100644
--- a/drivers/media/video/s2255drv.c
+++ b/drivers/media/video/s2255drv.c
@@ -669,7 +669,7 @@ static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf,
(unsigned long)vbuf, pos);
/* tell v4l buffer was filled */
- buf->vb.field_count++;
+ buf->vb.field_count = dev->frame_count[chn] * 2;
do_gettimeofday(&ts);
buf->vb.ts = ts;
buf->vb.state = VIDEOBUF_DONE;
@@ -1268,6 +1268,7 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
dev->last_frame[chn] = -1;
dev->bad_payload[chn] = 0;
dev->cur_frame[chn] = 0;
+ dev->frame_count[chn] = 0;
for (j = 0; j < SYS_FRAMES; j++) {
dev->buffer[chn].frame[j].ulState = 0;
dev->buffer[chn].frame[j].cur_size = 0;
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c
index bcd1c8f6cf6..ad733caec72 100644
--- a/drivers/media/video/saa7115.c
+++ b/drivers/media/video/saa7115.c
@@ -1489,10 +1489,9 @@ static int saa7115_probe(struct i2c_client *client,
client->addr << 1, client->adapter->name);
state = kzalloc(sizeof(struct saa711x_state), GFP_KERNEL);
- i2c_set_clientdata(client, state);
- if (state == NULL) {
+ if (state == NULL)
return -ENOMEM;
- }
+ i2c_set_clientdata(client, state);
state->input = -1;
state->output = SAA7115_IPORT_ON;
state->enable = 1;
diff --git a/drivers/media/video/se401.c b/drivers/media/video/se401.c
index f481277892d..acceed5d04a 100644
--- a/drivers/media/video/se401.c
+++ b/drivers/media/video/se401.c
@@ -1397,7 +1397,7 @@ static int se401_probe(struct usb_interface *intf,
mutex_init(&se401->lock);
wmb();
- if (video_register_device(&se401->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
+ if (video_register_device(&se401->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
kfree(se401);
err("video_register_device failed");
return -EIO;
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c
index 23408764d0e..2da6938718f 100644
--- a/drivers/media/video/sn9c102/sn9c102_core.c
+++ b/drivers/media/video/sn9c102/sn9c102_core.c
@@ -3312,6 +3312,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
cam->v4ldev->fops = &sn9c102_fops;
cam->v4ldev->minor = video_nr[dev_nr];
cam->v4ldev->release = video_device_release;
+ cam->v4ldev->parent = &udev->dev;
init_completion(&cam->probe);
diff --git a/drivers/media/video/sn9c102/sn9c102_devtable.h b/drivers/media/video/sn9c102/sn9c102_devtable.h
index 6ff489baacf..90a401dc388 100644
--- a/drivers/media/video/sn9c102/sn9c102_devtable.h
+++ b/drivers/media/video/sn9c102/sn9c102_devtable.h
@@ -40,11 +40,14 @@ struct sn9c102_device;
static const struct usb_device_id sn9c102_id_table[] = {
/* SN9C101 and SN9C102 */
+#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE
{ SN9C102_USB_DEVICE(0x0c45, 0x6001, BRIDGE_SN9C102), },
{ SN9C102_USB_DEVICE(0x0c45, 0x6005, BRIDGE_SN9C102), },
+#endif
{ SN9C102_USB_DEVICE(0x0c45, 0x6007, BRIDGE_SN9C102), },
{ SN9C102_USB_DEVICE(0x0c45, 0x6009, BRIDGE_SN9C102), },
{ SN9C102_USB_DEVICE(0x0c45, 0x600d, BRIDGE_SN9C102), },
+/* { SN9C102_USB_DEVICE(0x0c45, 0x6011, BRIDGE_SN9C102), }, OV6650 */
{ SN9C102_USB_DEVICE(0x0c45, 0x6019, BRIDGE_SN9C102), },
{ SN9C102_USB_DEVICE(0x0c45, 0x6024, BRIDGE_SN9C102), },
{ SN9C102_USB_DEVICE(0x0c45, 0x6025, BRIDGE_SN9C102), },
@@ -53,29 +56,33 @@ static const struct usb_device_id sn9c102_id_table[] = {
{ SN9C102_USB_DEVICE(0x0c45, 0x602a, BRIDGE_SN9C102), },
{ SN9C102_USB_DEVICE(0x0c45, 0x602b, BRIDGE_SN9C102), },
{ SN9C102_USB_DEVICE(0x0c45, 0x602c, BRIDGE_SN9C102), },
- { SN9C102_USB_DEVICE(0x0c45, 0x602d, BRIDGE_SN9C102), },
+/* { SN9C102_USB_DEVICE(0x0c45, 0x602d, BRIDGE_SN9C102), }, HV7131R */
{ SN9C102_USB_DEVICE(0x0c45, 0x602e, BRIDGE_SN9C102), },
{ SN9C102_USB_DEVICE(0x0c45, 0x6030, BRIDGE_SN9C102), },
/* SN9C103 */
{ SN9C102_USB_DEVICE(0x0c45, 0x6080, BRIDGE_SN9C103), },
{ SN9C102_USB_DEVICE(0x0c45, 0x6082, BRIDGE_SN9C103), },
- { SN9C102_USB_DEVICE(0x0c45, 0x6083, BRIDGE_SN9C103), },
+/* { SN9C102_USB_DEVICE(0x0c45, 0x6083, BRIDGE_SN9C103), }, HY7131D/E */
{ SN9C102_USB_DEVICE(0x0c45, 0x6088, BRIDGE_SN9C103), },
{ SN9C102_USB_DEVICE(0x0c45, 0x608a, BRIDGE_SN9C103), },
{ SN9C102_USB_DEVICE(0x0c45, 0x608b, BRIDGE_SN9C103), },
{ SN9C102_USB_DEVICE(0x0c45, 0x608c, BRIDGE_SN9C103), },
- { SN9C102_USB_DEVICE(0x0c45, 0x608e, BRIDGE_SN9C103), },
+/* { SN9C102_USB_DEVICE(0x0c45, 0x608e, BRIDGE_SN9C103), }, CISVF10 */
+#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE
{ SN9C102_USB_DEVICE(0x0c45, 0x608f, BRIDGE_SN9C103), },
+#endif
{ SN9C102_USB_DEVICE(0x0c45, 0x60a0, BRIDGE_SN9C103), },
{ SN9C102_USB_DEVICE(0x0c45, 0x60a2, BRIDGE_SN9C103), },
{ SN9C102_USB_DEVICE(0x0c45, 0x60a3, BRIDGE_SN9C103), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60a8, BRIDGE_SN9C103), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60aa, BRIDGE_SN9C103), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60ab, BRIDGE_SN9C103), },
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60a8, BRIDGE_SN9C103), }, PAS106 */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60aa, BRIDGE_SN9C103), }, TAS5130 */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60ab, BRIDGE_SN9C103), }, TAS5130 */
{ SN9C102_USB_DEVICE(0x0c45, 0x60ac, BRIDGE_SN9C103), },
{ SN9C102_USB_DEVICE(0x0c45, 0x60ae, BRIDGE_SN9C103), },
{ SN9C102_USB_DEVICE(0x0c45, 0x60af, BRIDGE_SN9C103), },
+#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE
{ SN9C102_USB_DEVICE(0x0c45, 0x60b0, BRIDGE_SN9C103), },
+#endif
{ SN9C102_USB_DEVICE(0x0c45, 0x60b2, BRIDGE_SN9C103), },
{ SN9C102_USB_DEVICE(0x0c45, 0x60b3, BRIDGE_SN9C103), },
{ SN9C102_USB_DEVICE(0x0c45, 0x60b8, BRIDGE_SN9C103), },
@@ -105,7 +112,7 @@ static const struct usb_device_id sn9c102_id_table[] = {
{ SN9C102_USB_DEVICE(0x0c45, 0x6108, BRIDGE_SN9C120), },
{ SN9C102_USB_DEVICE(0x0c45, 0x610f, BRIDGE_SN9C120), },
{ SN9C102_USB_DEVICE(0x0c45, 0x6130, BRIDGE_SN9C120), },
- { SN9C102_USB_DEVICE(0x0c45, 0x6138, BRIDGE_SN9C120), },
+/* { SN9C102_USB_DEVICE(0x0c45, 0x6138, BRIDGE_SN9C120), }, MO8000 */
{ SN9C102_USB_DEVICE(0x0c45, 0x613a, BRIDGE_SN9C120), },
{ SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), },
{ SN9C102_USB_DEVICE(0x0c45, 0x613c, BRIDGE_SN9C120), },
diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c
index 56dc3d6b5b2..dce94743945 100644
--- a/drivers/media/video/stv680.c
+++ b/drivers/media/video/stv680.c
@@ -1462,7 +1462,7 @@ static int stv680_probe (struct usb_interface *intf, const struct usb_device_id
mutex_init (&stv680->lock);
wmb ();
- if (video_register_device (stv680->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
+ if (video_register_device(stv680->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
PDEBUG (0, "STV(e): video_register_device failed");
retval = -EIO;
goto error_vdev;
diff --git a/drivers/media/video/usbvideo/ibmcam.c b/drivers/media/video/usbvideo/ibmcam.c
index 59166b76010..cc27efe121d 100644
--- a/drivers/media/video/usbvideo/ibmcam.c
+++ b/drivers/media/video/usbvideo/ibmcam.c
@@ -736,12 +736,12 @@ static enum ParseState ibmcam_model2_320x240_parse_lines(
* make black color and quit the horizontal scanning loop.
*/
if (((frame->curline + 2) >= scanHeight) || (i >= scanLength)) {
- const int j = i * V4L_BYTES_PER_PIXEL;
+ const int offset = i * V4L_BYTES_PER_PIXEL;
#if USES_IBMCAM_PUTPIXEL
/* Refresh 'f' because we don't use it much with PUTPIXEL */
- f = frame->data + (v4l_linesize * frame->curline) + j;
+ f = frame->data + (v4l_linesize * frame->curline) + offset;
#endif
- memset(f, 0, v4l_linesize - j);
+ memset(f, 0, v4l_linesize - offset);
break;
}
diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c
index b7792451a29..2eb45829791 100644
--- a/drivers/media/video/usbvideo/vicam.c
+++ b/drivers/media/video/usbvideo/vicam.c
@@ -866,7 +866,7 @@ vicam_probe( struct usb_interface *intf, const struct usb_device_id *id)
cam->udev = dev;
cam->bulkEndpoint = bulkEndpoint;
- if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) == -1) {
+ if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) < 0) {
kfree(cam);
printk(KERN_WARNING "video_register_device failed\n");
return -EIO;
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
index 6ef3e5297de..feab12aa2c7 100644
--- a/drivers/media/video/uvc/uvc_ctrl.c
+++ b/drivers/media/video/uvc/uvc_ctrl.c
@@ -592,7 +592,7 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
if (ctrl == NULL)
return -EINVAL;
- data = kmalloc(8, GFP_KERNEL);
+ data = kmalloc(ctrl->info->size, GFP_KERNEL);
if (data == NULL)
return -ENOMEM;
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
index 6f36006aecd..155fdec9ac7 100644
--- a/drivers/media/video/v4l2-dev.c
+++ b/drivers/media/video/v4l2-dev.c
@@ -257,6 +257,9 @@ int video_register_device_index(struct video_device *vfd, int type, int nr,
int ret;
char *name_base;
+ if (vfd == NULL)
+ return -EINVAL;
+
switch (type) {
case VFL_TYPE_GRABBER:
base = MINOR_VFL_TYPE_GRABBER_MIN;
@@ -281,7 +284,7 @@ int video_register_device_index(struct video_device *vfd, int type, int nr,
default:
printk(KERN_ERR "%s called with unknown type: %d\n",
__func__, type);
- return -1;
+ return -EINVAL;
}
/* pick a minor number */
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index fdfe7739c96..140ef92c19c 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -499,7 +499,7 @@ static void dbgbuf(unsigned int cmd, struct video_device *vfd,
p->timestamp.tv_sec / 3600,
(int)(p->timestamp.tv_sec / 60) % 60,
(int)(p->timestamp.tv_sec % 60),
- p->timestamp.tv_usec,
+ (long)p->timestamp.tv_usec,
p->index,
prt_names(p->type, v4l2_type_names),
p->bytesused, p->flags,
@@ -674,7 +674,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
__video_do_ioctl will be called again, with one or more
V4L2 ioctls.
********************************************************/
- if (_IOC_TYPE(cmd) == 'v')
+ if (_IOC_TYPE(cmd) == 'v' && _IOC_NR(cmd) < BASE_VIDIOCPRIVATE)
return v4l_compat_translate_ioctl(inode, file, cmd, arg,
__video_do_ioctl);
#endif
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index 3518af071a2..8ba8daafd7e 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -1021,13 +1021,13 @@ static int vivi_release(void)
dev = list_entry(list, struct vivi_dev, vivi_devlist);
if (-1 != dev->vfd->minor) {
- video_unregister_device(dev->vfd);
- printk(KERN_INFO "%s: /dev/video%d unregistered.\n",
+ printk(KERN_INFO "%s: unregistering /dev/video%d\n",
VIVI_MODULE_NAME, dev->vfd->minor);
+ video_unregister_device(dev->vfd);
} else {
- video_device_release(dev->vfd);
- printk(KERN_INFO "%s: /dev/video%d released.\n",
+ printk(KERN_INFO "%s: releasing /dev/video%d\n",
VIVI_MODULE_NAME, dev->vfd->minor);
+ video_device_release(dev->vfd);
}
kfree(dev);
@@ -1104,19 +1104,29 @@ static struct video_device vivi_template = {
Initialization and module stuff
------------------------------------------------------------------*/
+/* This routine allocates from 1 to n_devs virtual drivers.
+
+ The real maximum number of virtual drivers will depend on how many drivers
+ will succeed. This is limited to the maximum number of devices that
+ videodev supports. Since there are 64 minors for video grabbers, this is
+ currently the theoretical maximum limit. However, a further limit does
+ exist at videodev that forbids any driver to register more than 32 video
+ grabbers.
+ */
static int __init vivi_init(void)
{
int ret = -ENOMEM, i;
struct vivi_dev *dev;
struct video_device *vfd;
+ if (n_devs <= 0)
+ n_devs = 1;
+
for (i = 0; i < n_devs; i++) {
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (NULL == dev)
+ if (!dev)
break;
- list_add_tail(&dev->vivi_devlist, &vivi_devlist);
-
/* init video dma queues */
INIT_LIST_HEAD(&dev->vidq.active);
init_waitqueue_head(&dev->vidq.wq);
@@ -1126,14 +1136,27 @@ static int __init vivi_init(void)
mutex_init(&dev->mutex);
vfd = video_device_alloc();
- if (NULL == vfd)
+ if (!vfd) {
+ kfree(dev);
break;
+ }
*vfd = vivi_template;
ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
- if (ret < 0)
+ if (ret < 0) {
+ video_device_release(vfd);
+ kfree(dev);
+
+ /* If some registers succeeded, keep driver */
+ if (i)
+ ret = 0;
+
break;
+ }
+
+ /* Now that everything is fine, let's add it to device list */
+ list_add_tail(&dev->vivi_devlist, &vivi_devlist);
snprintf(vfd->name, sizeof(vfd->name), "%s (%i)",
vivi_template.name, vfd->minor);
@@ -1149,11 +1172,16 @@ static int __init vivi_init(void)
if (ret < 0) {
vivi_release();
printk(KERN_INFO "Error %d while loading vivi driver\n", ret);
- } else
+ } else {
printk(KERN_INFO "Video Technology Magazine Virtual Video "
"Capture Board ver %u.%u.%u successfully loaded.\n",
(VIVI_VERSION >> 16) & 0xFF, (VIVI_VERSION >> 8) & 0xFF,
VIVI_VERSION & 0xFF);
+
+ /* n_devs will reflect the actual number of allocated devices */
+ n_devs = i;
+ }
+
return ret;
}
@@ -1169,10 +1197,10 @@ MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");
MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
MODULE_LICENSE("Dual BSD/GPL");
-module_param(video_nr, int, 0);
+module_param(video_nr, uint, 0444);
MODULE_PARM_DESC(video_nr, "video iminor start number");
-module_param(n_devs, int, 0);
+module_param(n_devs, uint, 0444);
MODULE_PARM_DESC(n_devs, "number of video devices to create");
module_param_named(debug, vivi_template.debug, int, 0444);
diff --git a/drivers/media/video/w9966.c b/drivers/media/video/w9966.c
index 9402f40095b..2ff00bc5ad6 100644
--- a/drivers/media/video/w9966.c
+++ b/drivers/media/video/w9966.c
@@ -334,7 +334,7 @@ static int w9966_init(struct w9966_dev* cam, struct parport* port)
memcpy(&cam->vdev, &w9966_template, sizeof(struct video_device));
cam->vdev.priv = cam;
- if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) == -1)
+ if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0)
return -1;
w9966_setState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV);
diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c
index 168baabe465..11edf79f57b 100644
--- a/drivers/media/video/w9968cf.c
+++ b/drivers/media/video/w9968cf.c
@@ -911,7 +911,6 @@ static int w9968cf_start_transfer(struct w9968cf_device* cam)
for (i = 0; i < W9968CF_URBS; i++) {
urb = usb_alloc_urb(W9968CF_ISO_PACKETS, GFP_KERNEL);
- cam->urb[i] = urb;
if (!urb) {
for (j = 0; j < i; j++)
usb_free_urb(cam->urb[j]);
@@ -919,6 +918,7 @@ static int w9968cf_start_transfer(struct w9968cf_device* cam)
return -ENOMEM;
}
+ cam->urb[i] = urb;
urb->dev = udev;
urb->context = (void*)cam;
urb->pipe = usb_rcvisocpipe(udev, 1);
diff --git a/drivers/media/video/wm8739.c b/drivers/media/video/wm8739.c
index 95c79ad8048..54ac3fe26ec 100644
--- a/drivers/media/video/wm8739.c
+++ b/drivers/media/video/wm8739.c
@@ -274,10 +274,8 @@ static int wm8739_probe(struct i2c_client *client,
client->addr << 1, client->adapter->name);
state = kmalloc(sizeof(struct wm8739_state), GFP_KERNEL);
- if (state == NULL) {
- kfree(client);
+ if (state == NULL)
return -ENOMEM;
- }
state->vol_l = 0x17; /* 0dB */
state->vol_r = 0x17; /* 0dB */
state->muted = 0;
diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c
index 550ce7bd5c8..0c3287734c9 100644
--- a/drivers/media/video/zc0301/zc0301_core.c
+++ b/drivers/media/video/zc0301/zc0301_core.c
@@ -1988,6 +1988,7 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
cam->v4ldev->fops = &zc0301_fops;
cam->v4ldev->minor = video_nr[dev_nr];
cam->v4ldev->release = video_device_release;
+ cam->v4ldev->parent = &udev->dev;
video_set_drvdata(cam->v4ldev, cam);
init_completion(&cam->probe);
diff --git a/drivers/media/video/zc0301/zc0301_sensor.h b/drivers/media/video/zc0301/zc0301_sensor.h
index 70fe6fc6cdd..b0cd49c438a 100644
--- a/drivers/media/video/zc0301/zc0301_sensor.h
+++ b/drivers/media/video/zc0301/zc0301_sensor.h
@@ -60,27 +60,8 @@ zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor);
#define ZC0301_ID_TABLE \
static const struct usb_device_id zc0301_id_table[] = { \
- { ZC0301_USB_DEVICE(0x041e, 0x4017, 0xff), }, /* ICM105 */ \
- { ZC0301_USB_DEVICE(0x041e, 0x401c, 0xff), }, /* PAS106 */ \
- { ZC0301_USB_DEVICE(0x041e, 0x401e, 0xff), }, /* HV7131 */ \
- { ZC0301_USB_DEVICE(0x041e, 0x401f, 0xff), }, /* TAS5130 */ \
- { ZC0301_USB_DEVICE(0x041e, 0x4022, 0xff), }, \
- { ZC0301_USB_DEVICE(0x041e, 0x4034, 0xff), }, /* PAS106 */ \
- { ZC0301_USB_DEVICE(0x041e, 0x4035, 0xff), }, /* PAS106 */ \
- { ZC0301_USB_DEVICE(0x041e, 0x4036, 0xff), }, /* HV7131 */ \
- { ZC0301_USB_DEVICE(0x041e, 0x403a, 0xff), }, /* HV7131 */ \
- { ZC0301_USB_DEVICE(0x0458, 0x7007, 0xff), }, /* TAS5130 */ \
- { ZC0301_USB_DEVICE(0x0458, 0x700c, 0xff), }, /* TAS5130 */ \
- { ZC0301_USB_DEVICE(0x0458, 0x700f, 0xff), }, /* TAS5130 */ \
{ ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */ \
- { ZC0301_USB_DEVICE(0x055f, 0xd003, 0xff), }, /* TAS5130 */ \
- { ZC0301_USB_DEVICE(0x055f, 0xd004, 0xff), }, /* TAS5130 */ \
- { ZC0301_USB_DEVICE(0x0ac8, 0x0301, 0xff), }, \
- { ZC0301_USB_DEVICE(0x0ac8, 0x301b, 0xff), }, /* PB-0330/HV7131 */ \
{ ZC0301_USB_DEVICE(0x0ac8, 0x303b, 0xff), }, /* PB-0330 */ \
- { ZC0301_USB_DEVICE(0x10fd, 0x0128, 0xff), }, /* TAS5130 */ \
- { ZC0301_USB_DEVICE(0x10fd, 0x8050, 0xff), }, /* TAS5130 */ \
- { ZC0301_USB_DEVICE(0x10fd, 0x804e, 0xff), }, /* TAS5130 */ \
{ } \
};
diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c
index d842a7cb99d..3282be73029 100644
--- a/drivers/media/video/zoran_card.c
+++ b/drivers/media/video/zoran_card.c
@@ -988,7 +988,7 @@ zoran_open_init_params (struct zoran *zr)
zr->v4l_grab_seq = 0;
zr->v4l_settings.width = 192;
zr->v4l_settings.height = 144;
- zr->v4l_settings.format = &zoran_formats[4]; /* YUY2 - YUV-4:2:2 packed */
+ zr->v4l_settings.format = &zoran_formats[7]; /* YUY2 - YUV-4:2:2 packed */
zr->v4l_settings.bytesperline =
zr->v4l_settings.width *
((zr->v4l_settings.format->depth + 7) / 8);
diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c
index ec6f59674b1..2dab9eea4de 100644
--- a/drivers/media/video/zoran_driver.c
+++ b/drivers/media/video/zoran_driver.c
@@ -134,7 +134,7 @@ const struct zoran_format zoran_formats[] = {
}, {
.name = "16-bit RGB BE",
ZFMT(-1,
- V4L2_PIX_FMT_RGB565, V4L2_COLORSPACE_SRGB),
+ V4L2_PIX_FMT_RGB565X, V4L2_COLORSPACE_SRGB),
.depth = 16,
.flags = ZORAN_FORMAT_CAPTURE |
ZORAN_FORMAT_OVERLAY,
@@ -2737,7 +2737,8 @@ zoran_do_ioctl (struct inode *inode,
fh->v4l_settings.format->fourcc;
fmt->fmt.pix.colorspace =
fh->v4l_settings.format->colorspace;
- fmt->fmt.pix.bytesperline = 0;
+ fmt->fmt.pix.bytesperline =
+ fh->v4l_settings.bytesperline;
if (BUZ_MAX_HEIGHT <
(fh->v4l_settings.height * 2))
fmt->fmt.pix.field =
@@ -2833,13 +2834,6 @@ zoran_do_ioctl (struct inode *inode,
fmt->fmt.pix.pixelformat,
(char *) &printformat);
- if (fmt->fmt.pix.bytesperline > 0) {
- dprintk(5,
- KERN_ERR "%s: bpl not supported\n",
- ZR_DEVNAME(zr));
- return -EINVAL;
- }
-
/* we can be requested to do JPEG/raw playback/capture */
if (!
(fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
@@ -2923,6 +2917,7 @@ zoran_do_ioctl (struct inode *inode,
fh->jpg_buffers.buffer_size =
zoran_v4l2_calc_bufsize(&fh->
jpg_settings);
+ fmt->fmt.pix.bytesperline = 0;
fmt->fmt.pix.sizeimage =
fh->jpg_buffers.buffer_size;
@@ -2979,6 +2974,8 @@ zoran_do_ioctl (struct inode *inode,
/* tell the user the
* results/missing stuff */
+ fmt->fmt.pix.bytesperline =
+ fh->v4l_settings.bytesperline;
fmt->fmt.pix.sizeimage =
fh->v4l_settings.height *
fh->v4l_settings.bytesperline;
diff --git a/drivers/memstick/core/memstick.c b/drivers/memstick/core/memstick.c
index a38005008a2..cea46906408 100644
--- a/drivers/memstick/core/memstick.c
+++ b/drivers/memstick/core/memstick.c
@@ -185,7 +185,7 @@ static void memstick_free(struct device *dev)
}
static struct class memstick_host_class = {
- .name = "memstick_host",
+ .name = "memstick_host",
.dev_release = memstick_free
};
@@ -264,7 +264,7 @@ EXPORT_SYMBOL(memstick_new_req);
* @sg - TPC argument
*/
void memstick_init_req_sg(struct memstick_request *mrq, unsigned char tpc,
- struct scatterlist *sg)
+ const struct scatterlist *sg)
{
mrq->tpc = tpc;
if (tpc & 8)
@@ -294,7 +294,7 @@ EXPORT_SYMBOL(memstick_init_req_sg);
* user supplied buffer.
*/
void memstick_init_req(struct memstick_request *mrq, unsigned char tpc,
- void *buf, size_t length)
+ const void *buf, size_t length)
{
mrq->tpc = tpc;
if (tpc & 8)
@@ -439,7 +439,7 @@ static void memstick_check(struct work_struct *work)
if (!host->card) {
if (memstick_power_on(host))
goto out_power_off;
- } else
+ } else if (host->card->stop)
host->card->stop(host->card);
card = memstick_alloc_card(host);
@@ -458,7 +458,7 @@ static void memstick_check(struct work_struct *work)
|| !(host->card->check(host->card))) {
device_unregister(&host->card->dev);
host->card = NULL;
- } else
+ } else if (host->card->start)
host->card->start(host->card);
}
diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c
index 44b1817f2f2..6e291bf8237 100644
--- a/drivers/memstick/core/mspro_block.c
+++ b/drivers/memstick/core/mspro_block.c
@@ -30,6 +30,8 @@ module_param(major, int, 0644);
#define MSPRO_BLOCK_SIGNATURE 0xa5c3
#define MSPRO_BLOCK_MAX_ATTRIBUTES 41
+#define MSPRO_BLOCK_PART_SHIFT 3
+
enum {
MSPRO_BLOCK_ID_SYSINFO = 0x10,
MSPRO_BLOCK_ID_MODELNAME = 0x15,
@@ -195,7 +197,7 @@ static int mspro_block_bd_open(struct inode *inode, struct file *filp)
static int mspro_block_disk_release(struct gendisk *disk)
{
struct mspro_block_data *msb = disk->private_data;
- int disk_id = disk->first_minor >> MEMSTICK_PART_SHIFT;
+ int disk_id = MINOR(disk_devt(disk)) >> MSPRO_BLOCK_PART_SHIFT;
mutex_lock(&mspro_block_disk_lock);
@@ -826,7 +828,7 @@ static void mspro_block_submit_req(struct request_queue *q)
if (msb->eject) {
while ((req = elv_next_request(q)) != NULL)
- end_queued_request(req, -ENODEV);
+ __blk_end_request(req, -ENODEV, blk_rq_bytes(req));
return;
}
@@ -877,6 +879,7 @@ static int mspro_block_switch_interface(struct memstick_dev *card)
struct mspro_block_data *msb = memstick_get_drvdata(card);
int rc = 0;
+try_again:
if (msb->caps & MEMSTICK_CAP_PAR4)
rc = mspro_block_set_interface(card, MEMSTICK_SYS_PAR4);
else
@@ -930,6 +933,18 @@ static int mspro_block_switch_interface(struct memstick_dev *card)
rc = memstick_set_rw_addr(card);
if (!rc)
rc = mspro_block_set_interface(card, msb->system);
+
+ if (!rc) {
+ msleep(150);
+ rc = mspro_block_wait_for_ced(card);
+ if (rc)
+ return rc;
+
+ if (msb->caps & MEMSTICK_CAP_PAR8) {
+ msb->caps &= ~MEMSTICK_CAP_PAR8;
+ goto try_again;
+ }
+ }
}
return rc;
}
@@ -1117,14 +1132,16 @@ static int mspro_block_init_card(struct memstick_dev *card)
return -EIO;
msb->caps = host->caps;
- rc = mspro_block_switch_interface(card);
+
+ msleep(150);
+ rc = mspro_block_wait_for_ced(card);
if (rc)
return rc;
- msleep(200);
- rc = mspro_block_wait_for_ced(card);
+ rc = mspro_block_switch_interface(card);
if (rc)
return rc;
+
dev_dbg(&card->dev, "card activated\n");
if (msb->system != MEMSTICK_SYS_SERIAL)
msb->caps |= MEMSTICK_CAP_AUTO_GET_INT;
@@ -1192,12 +1209,12 @@ static int mspro_block_init_disk(struct memstick_dev *card)
if (rc)
return rc;
- if ((disk_id << MEMSTICK_PART_SHIFT) > 255) {
+ if ((disk_id << MSPRO_BLOCK_PART_SHIFT) > 255) {
rc = -ENOSPC;
goto out_release_id;
}
- msb->disk = alloc_disk(1 << MEMSTICK_PART_SHIFT);
+ msb->disk = alloc_disk(1 << MSPRO_BLOCK_PART_SHIFT);
if (!msb->disk) {
rc = -ENOMEM;
goto out_release_id;
@@ -1220,7 +1237,7 @@ static int mspro_block_init_disk(struct memstick_dev *card)
MSPRO_BLOCK_MAX_PAGES * msb->page_size);
msb->disk->major = major;
- msb->disk->first_minor = disk_id << MEMSTICK_PART_SHIFT;
+ msb->disk->first_minor = disk_id << MSPRO_BLOCK_PART_SHIFT;
msb->disk->fops = &ms_block_bdops;
msb->usage_count = 1;
msb->disk->private_data = msb;
@@ -1416,7 +1433,7 @@ out_unlock:
static struct memstick_device_id mspro_block_id_tbl[] = {
{MEMSTICK_MATCH_ALL, MEMSTICK_TYPE_PRO, MEMSTICK_CATEGORY_STORAGE_DUO,
- MEMSTICK_CLASS_GENERIC_DUO},
+ MEMSTICK_CLASS_DUO},
{}
};
diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c
index 3485c63d20b..2fb95a5b72e 100644
--- a/drivers/memstick/host/jmb38x_ms.c
+++ b/drivers/memstick/host/jmb38x_ms.c
@@ -81,6 +81,8 @@ struct jmb38x_ms {
#define TPC_CODE_SZ_MASK 0x00000700
#define TPC_DATA_SZ_MASK 0x00000007
+#define HOST_CONTROL_TDELAY_EN 0x00040000
+#define HOST_CONTROL_HW_OC_P 0x00010000
#define HOST_CONTROL_RESET_REQ 0x00008000
#define HOST_CONTROL_REI 0x00004000
#define HOST_CONTROL_LED 0x00000400
@@ -88,6 +90,7 @@ struct jmb38x_ms {
#define HOST_CONTROL_RESET 0x00000100
#define HOST_CONTROL_POWER_EN 0x00000080
#define HOST_CONTROL_CLOCK_EN 0x00000040
+#define HOST_CONTROL_REO 0x00000008
#define HOST_CONTROL_IF_SHIFT 4
#define HOST_CONTROL_IF_SERIAL 0x0
@@ -133,11 +136,15 @@ struct jmb38x_ms {
#define PAD_PU_PD_ON_MS_SOCK1 0x0f0f0000
#define CLOCK_CONTROL_40MHZ 0x00000001
-#define CLOCK_CONTROL_50MHZ 0x00000002
+#define CLOCK_CONTROL_50MHZ 0x0000000a
#define CLOCK_CONTROL_60MHZ 0x00000008
#define CLOCK_CONTROL_62_5MHZ 0x0000000c
#define CLOCK_CONTROL_OFF 0x00000000
+#define PCI_CTL_CLOCK_DLY_ADDR 0x000000b0
+#define PCI_CTL_CLOCK_DLY_MASK_A 0x00000f00
+#define PCI_CTL_CLOCK_DLY_MASK_B 0x0000f000
+
enum {
CMD_READY = 0x01,
FIFO_READY = 0x02,
@@ -367,8 +374,7 @@ static int jmb38x_ms_issue_cmd(struct memstick_host *msh)
return host->req->error;
}
- dev_dbg(&msh->dev, "control %08x\n",
- readl(host->addr + HOST_CONTROL));
+ dev_dbg(&msh->dev, "control %08x\n", readl(host->addr + HOST_CONTROL));
dev_dbg(&msh->dev, "status %08x\n", readl(host->addr + INT_STATUS));
dev_dbg(&msh->dev, "hstatus %08x\n", readl(host->addr + STATUS));
@@ -637,7 +643,7 @@ static int jmb38x_ms_reset(struct jmb38x_ms_host *host)
ndelay(20);
}
dev_dbg(&host->chip->pdev->dev, "reset_req timeout\n");
- return -EIO;
+ /* return -EIO; */
reset_next:
writel(HOST_CONTROL_RESET | HOST_CONTROL_CLOCK_EN
@@ -680,7 +686,9 @@ static int jmb38x_ms_set_param(struct memstick_host *msh,
host_ctl = 7;
host_ctl |= HOST_CONTROL_POWER_EN
- | HOST_CONTROL_CLOCK_EN;
+ | HOST_CONTROL_CLOCK_EN
+ | HOST_CONTROL_HW_OC_P
+ | HOST_CONTROL_TDELAY_EN;
writel(host_ctl, host->addr + HOST_CONTROL);
writel(host->id ? PAD_PU_PD_ON_MS_SOCK1
@@ -704,33 +712,40 @@ static int jmb38x_ms_set_param(struct memstick_host *msh,
break;
case MEMSTICK_INTERFACE:
host_ctl &= ~(3 << HOST_CONTROL_IF_SHIFT);
+ pci_read_config_dword(host->chip->pdev,
+ PCI_CTL_CLOCK_DLY_ADDR,
+ &clock_delay);
+ clock_delay &= host->id ? ~PCI_CTL_CLOCK_DLY_MASK_B
+ : ~PCI_CTL_CLOCK_DLY_MASK_A;
if (value == MEMSTICK_SERIAL) {
host_ctl &= ~HOST_CONTROL_FAST_CLK;
+ host_ctl &= ~HOST_CONTROL_REO;
host_ctl |= HOST_CONTROL_IF_SERIAL
<< HOST_CONTROL_IF_SHIFT;
host_ctl |= HOST_CONTROL_REI;
clock_ctl = CLOCK_CONTROL_40MHZ;
- clock_delay = 0;
} else if (value == MEMSTICK_PAR4) {
- host_ctl |= HOST_CONTROL_FAST_CLK;
+ host_ctl |= HOST_CONTROL_FAST_CLK | HOST_CONTROL_REO;
host_ctl |= HOST_CONTROL_IF_PAR4
<< HOST_CONTROL_IF_SHIFT;
host_ctl &= ~HOST_CONTROL_REI;
clock_ctl = CLOCK_CONTROL_40MHZ;
- clock_delay = 4;
+ clock_delay |= host->id ? (4 << 12) : (4 << 8);
} else if (value == MEMSTICK_PAR8) {
host_ctl |= HOST_CONTROL_FAST_CLK;
host_ctl |= HOST_CONTROL_IF_PAR8
<< HOST_CONTROL_IF_SHIFT;
- host_ctl &= ~HOST_CONTROL_REI;
- clock_ctl = CLOCK_CONTROL_60MHZ;
- clock_delay = 0;
+ host_ctl &= ~(HOST_CONTROL_REI | HOST_CONTROL_REO);
+ clock_ctl = CLOCK_CONTROL_50MHZ;
} else
return -EINVAL;
+
writel(host_ctl, host->addr + HOST_CONTROL);
writel(clock_ctl, host->addr + CLOCK_CONTROL);
- writel(clock_delay, host->addr + CLOCK_DELAY);
+ pci_write_config_dword(host->chip->pdev,
+ PCI_CTL_CLOCK_DLY_ADDR,
+ clock_delay);
break;
};
return 0;
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 10c44d3fe01..68dc8d9eb24 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -21,7 +21,7 @@ config MFD_SM501
config MFD_SM501_GPIO
bool "Export GPIO via GPIO layer"
- depends on MFD_SM501 && HAVE_GPIO_LIB
+ depends on MFD_SM501 && GPIOLIB
---help---
This option uses the gpio library layer to export the 64 GPIO
lines on the SM501. The platform data is used to supply the
@@ -29,7 +29,7 @@ config MFD_SM501_GPIO
config MFD_ASIC3
bool "Support for Compaq ASIC3"
- depends on GENERIC_HARDIRQS && HAVE_GPIO_LIB && ARM
+ depends on GENERIC_HARDIRQS && GPIOLIB && ARM
---help---
This driver supports the ASIC3 multifunction chip found on many
PDAs (mainly iPAQ and HTC based ones)
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c
index bc2a807f210..ba5aa200827 100644
--- a/drivers/mfd/asic3.c
+++ b/drivers/mfd/asic3.c
@@ -312,7 +312,6 @@ static int __init asic3_irq_probe(struct platform_device *pdev)
struct asic3 *asic = platform_get_drvdata(pdev);
unsigned long clksel = 0;
unsigned int irq, irq_base;
- int map_size;
int ret;
ret = platform_get_irq(pdev, 0);
@@ -534,6 +533,7 @@ static int __init asic3_probe(struct platform_device *pdev)
struct asic3 *asic;
struct resource *mem;
unsigned long clksel;
+ int map_size;
int ret = 0;
asic = kzalloc(sizeof(struct asic3), GFP_KERNEL);
diff --git a/drivers/misc/acer-wmi.c b/drivers/misc/acer-wmi.c
index c6c77a505ec..d8b0d326e45 100644
--- a/drivers/misc/acer-wmi.c
+++ b/drivers/misc/acer-wmi.c
@@ -1189,7 +1189,7 @@ static int create_debugfs(void)
return 0;
error_debugfs:
- remove_debugfs();
+ remove_debugfs();
return -ENOMEM;
}
@@ -1272,6 +1272,7 @@ error_platform_register:
static void __exit acer_wmi_exit(void)
{
remove_sysfs(acer_platform_device);
+ remove_debugfs();
platform_device_del(acer_platform_device);
platform_driver_unregister(&acer_platform_driver);
diff --git a/drivers/misc/eeepc-laptop.c b/drivers/misc/eeepc-laptop.c
index facdb9893c8..1ee8501e90f 100644
--- a/drivers/misc/eeepc-laptop.c
+++ b/drivers/misc/eeepc-laptop.c
@@ -450,12 +450,14 @@ static int eeepc_get_fan_pwm(void)
int value = 0;
read_acpi_int(NULL, EEEPC_EC_FAN_PWM, &value);
+ value = value * 255 / 100;
return (value);
}
static void eeepc_set_fan_pwm(int value)
{
- value = SENSORS_LIMIT(value, 0, 100);
+ value = SENSORS_LIMIT(value, 0, 255);
+ value = value * 100 / 255;
ec_write(EEEPC_EC_SC02, value);
}
@@ -520,15 +522,23 @@ static ssize_t show_sys_hwmon(int (*get)(void), char *buf)
static SENSOR_DEVICE_ATTR(_name, _mode, show_##_name, store_##_name, 0);
EEEPC_CREATE_SENSOR_ATTR(fan1_input, S_IRUGO, eeepc_get_fan_rpm, NULL);
-EEEPC_CREATE_SENSOR_ATTR(fan1_pwm, S_IRUGO | S_IWUSR,
+EEEPC_CREATE_SENSOR_ATTR(pwm1, S_IRUGO | S_IWUSR,
eeepc_get_fan_pwm, eeepc_set_fan_pwm);
EEEPC_CREATE_SENSOR_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
eeepc_get_fan_ctrl, eeepc_set_fan_ctrl);
+static ssize_t
+show_name(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "eeepc\n");
+}
+static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
+
static struct attribute *hwmon_attributes[] = {
- &sensor_dev_attr_fan1_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm1.dev_attr.attr,
&sensor_dev_attr_fan1_input.dev_attr.attr,
&sensor_dev_attr_pwm1_enable.dev_attr.attr,
+ &sensor_dev_attr_name.dev_attr.attr,
NULL
};
diff --git a/drivers/misc/fujitsu-laptop.c b/drivers/misc/fujitsu-laptop.c
index 7a1ef6c262d..3e56203e494 100644
--- a/drivers/misc/fujitsu-laptop.c
+++ b/drivers/misc/fujitsu-laptop.c
@@ -463,6 +463,13 @@ static struct dmi_system_id __initdata fujitsu_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6410"),
},
.callback = dmi_check_cb_s6410},
+ {
+ .ident = "FUJITSU LifeBook P8010",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P8010"),
+ },
+ .callback = dmi_check_cb_s6410},
{}
};
diff --git a/drivers/misc/hp-wmi.c b/drivers/misc/hp-wmi.c
index 1dbcbcb323a..6d407c2a4f9 100644
--- a/drivers/misc/hp-wmi.c
+++ b/drivers/misc/hp-wmi.c
@@ -49,6 +49,7 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4");
#define HPWMI_ALS_QUERY 0x3
#define HPWMI_DOCK_QUERY 0x4
#define HPWMI_WIRELESS_QUERY 0x5
+#define HPWMI_HOTKEY_QUERY 0xc
static int __init hp_wmi_bios_setup(struct platform_device *device);
static int __exit hp_wmi_bios_remove(struct platform_device *device);
@@ -69,7 +70,7 @@ struct bios_return {
struct key_entry {
char type; /* See KE_* below */
- u8 code;
+ u16 code;
u16 keycode;
};
@@ -79,7 +80,9 @@ static struct key_entry hp_wmi_keymap[] = {
{KE_SW, 0x01, SW_DOCK},
{KE_KEY, 0x02, KEY_BRIGHTNESSUP},
{KE_KEY, 0x03, KEY_BRIGHTNESSDOWN},
- {KE_KEY, 0x04, KEY_HELP},
+ {KE_KEY, 0x20e6, KEY_PROG1},
+ {KE_KEY, 0x2142, KEY_MEDIA},
+ {KE_KEY, 0x231b, KEY_HELP},
{KE_END, 0}
};
@@ -177,9 +180,9 @@ static int hp_wmi_wifi_state(void)
int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
if (wireless & 0x100)
- return 1;
+ return RFKILL_STATE_UNBLOCKED;
else
- return 0;
+ return RFKILL_STATE_SOFT_BLOCKED;
}
static int hp_wmi_bluetooth_state(void)
@@ -187,9 +190,9 @@ static int hp_wmi_bluetooth_state(void)
int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
if (wireless & 0x10000)
- return 1;
+ return RFKILL_STATE_UNBLOCKED;
else
- return 0;
+ return RFKILL_STATE_SOFT_BLOCKED;
}
static int hp_wmi_wwan_state(void)
@@ -197,9 +200,9 @@ static int hp_wmi_wwan_state(void)
int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
if (wireless & 0x1000000)
- return 1;
+ return RFKILL_STATE_UNBLOCKED;
else
- return 0;
+ return RFKILL_STATE_SOFT_BLOCKED;
}
static ssize_t show_display(struct device *dev, struct device_attribute *attr,
@@ -318,6 +321,9 @@ void hp_wmi_notify(u32 value, void *context)
if (obj && obj->type == ACPI_TYPE_BUFFER && obj->buffer.length == 8) {
int eventcode = *((u8 *) obj->buffer.pointer);
+ if (eventcode == 0x4)
+ eventcode = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0,
+ 0);
key = hp_wmi_get_entry_by_scancode(eventcode);
if (key) {
switch (key->type) {
@@ -338,12 +344,14 @@ void hp_wmi_notify(u32 value, void *context)
}
} else if (eventcode == 0x5) {
if (wifi_rfkill)
- wifi_rfkill->state = hp_wmi_wifi_state();
+ rfkill_force_state(wifi_rfkill,
+ hp_wmi_wifi_state());
if (bluetooth_rfkill)
- bluetooth_rfkill->state =
- hp_wmi_bluetooth_state();
+ rfkill_force_state(bluetooth_rfkill,
+ hp_wmi_bluetooth_state());
if (wwan_rfkill)
- wwan_rfkill->state = hp_wmi_wwan_state();
+ rfkill_force_state(wwan_rfkill,
+ hp_wmi_wwan_state());
} else
printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n",
eventcode);
@@ -398,6 +406,7 @@ static void cleanup_sysfs(struct platform_device *device)
static int __init hp_wmi_bios_setup(struct platform_device *device)
{
int err;
+ int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
err = device_create_file(&device->dev, &dev_attr_display);
if (err)
@@ -412,28 +421,33 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
if (err)
goto add_sysfs_error;
- wifi_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WLAN);
- wifi_rfkill->name = "hp-wifi";
- wifi_rfkill->state = hp_wmi_wifi_state();
- wifi_rfkill->toggle_radio = hp_wmi_wifi_set;
- wifi_rfkill->user_claim_unsupported = 1;
-
- bluetooth_rfkill = rfkill_allocate(&device->dev,
- RFKILL_TYPE_BLUETOOTH);
- bluetooth_rfkill->name = "hp-bluetooth";
- bluetooth_rfkill->state = hp_wmi_bluetooth_state();
- bluetooth_rfkill->toggle_radio = hp_wmi_bluetooth_set;
- bluetooth_rfkill->user_claim_unsupported = 1;
-
- wwan_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WIMAX);
- wwan_rfkill->name = "hp-wwan";
- wwan_rfkill->state = hp_wmi_wwan_state();
- wwan_rfkill->toggle_radio = hp_wmi_wwan_set;
- wwan_rfkill->user_claim_unsupported = 1;
-
- rfkill_register(wifi_rfkill);
- rfkill_register(bluetooth_rfkill);
- rfkill_register(wwan_rfkill);
+ if (wireless & 0x1) {
+ wifi_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WLAN);
+ wifi_rfkill->name = "hp-wifi";
+ wifi_rfkill->state = hp_wmi_wifi_state();
+ wifi_rfkill->toggle_radio = hp_wmi_wifi_set;
+ wifi_rfkill->user_claim_unsupported = 1;
+ rfkill_register(wifi_rfkill);
+ }
+
+ if (wireless & 0x2) {
+ bluetooth_rfkill = rfkill_allocate(&device->dev,
+ RFKILL_TYPE_BLUETOOTH);
+ bluetooth_rfkill->name = "hp-bluetooth";
+ bluetooth_rfkill->state = hp_wmi_bluetooth_state();
+ bluetooth_rfkill->toggle_radio = hp_wmi_bluetooth_set;
+ bluetooth_rfkill->user_claim_unsupported = 1;
+ rfkill_register(bluetooth_rfkill);
+ }
+
+ if (wireless & 0x4) {
+ wwan_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WWAN);
+ wwan_rfkill->name = "hp-wwan";
+ wwan_rfkill->state = hp_wmi_wwan_state();
+ wwan_rfkill->toggle_radio = hp_wmi_wwan_set;
+ wwan_rfkill->user_claim_unsupported = 1;
+ rfkill_register(wwan_rfkill);
+ }
return 0;
add_sysfs_error:
@@ -445,9 +459,12 @@ static int __exit hp_wmi_bios_remove(struct platform_device *device)
{
cleanup_sysfs(device);
- rfkill_unregister(wifi_rfkill);
- rfkill_unregister(bluetooth_rfkill);
- rfkill_unregister(wwan_rfkill);
+ if (wifi_rfkill)
+ rfkill_unregister(wifi_rfkill);
+ if (bluetooth_rfkill)
+ rfkill_unregister(bluetooth_rfkill);
+ if (wwan_rfkill)
+ rfkill_unregister(wwan_rfkill);
return 0;
}
diff --git a/drivers/misc/sgi-gru/grufile.c b/drivers/misc/sgi-gru/grufile.c
index 23c91f5f6b6..d61cee796ef 100644
--- a/drivers/misc/sgi-gru/grufile.c
+++ b/drivers/misc/sgi-gru/grufile.c
@@ -445,6 +445,9 @@ static void __exit gru_exit(void)
int order = get_order(sizeof(struct gru_state) *
GRU_CHIPLETS_PER_BLADE);
+ if (!IS_UV())
+ return;
+
for (i = 0; i < GRU_CHIPLETS_PER_BLADE; i++)
free_irq(IRQ_GRU + i, NULL);
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index d3eb7903c34..6b9300779a4 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -3086,7 +3086,6 @@ static struct ibm_struct wan_driver_data = {
.read = wan_read,
.write = wan_write,
.exit = wan_exit,
- .flags.experimental = 1,
};
/*************************************************************************
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 86dbb366415..efacee0404a 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -29,6 +29,7 @@
#include <linux/blkdev.h>
#include <linux/mutex.h>
#include <linux/scatterlist.h>
+#include <linux/string_helpers.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
@@ -83,7 +84,7 @@ static void mmc_blk_put(struct mmc_blk_data *md)
mutex_lock(&open_lock);
md->usage--;
if (md->usage == 0) {
- int devidx = md->disk->first_minor >> MMC_SHIFT;
+ int devidx = MINOR(disk_devt(md->disk)) >> MMC_SHIFT;
__clear_bit(devidx, dev_use);
put_disk(md->disk);
@@ -103,8 +104,10 @@ static int mmc_blk_open(struct inode *inode, struct file *filp)
check_disk_change(inode->i_bdev);
ret = 0;
- if ((filp->f_mode & FMODE_WRITE) && md->read_only)
+ if ((filp->f_mode & FMODE_WRITE) && md->read_only) {
+ mmc_blk_put(md);
ret = -EROFS;
+ }
}
return ret;
@@ -530,6 +533,8 @@ static int mmc_blk_probe(struct mmc_card *card)
struct mmc_blk_data *md;
int err;
+ char cap_str[10];
+
/*
* Check that the card supports the command class(es) we need.
*/
@@ -544,10 +549,11 @@ static int mmc_blk_probe(struct mmc_card *card)
if (err)
goto out;
- printk(KERN_INFO "%s: %s %s %lluKiB %s\n",
+ string_get_size(get_capacity(md->disk) << 9, STRING_UNITS_2,
+ cap_str, sizeof(cap_str));
+ printk(KERN_INFO "%s: %s %s %s %s\n",
md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
- (unsigned long long)(get_capacity(md->disk) >> 1),
- md->read_only ? "(ro)" : "");
+ cap_str, md->read_only ? "(ro)" : "");
mmc_set_drvdata(card, md);
add_disk(md->disk);
@@ -613,14 +619,19 @@ static struct mmc_driver mmc_driver = {
static int __init mmc_blk_init(void)
{
- int res = -ENOMEM;
+ int res;
res = register_blkdev(MMC_BLOCK_MAJOR, "mmc");
if (res)
goto out;
- return mmc_register_driver(&mmc_driver);
+ res = mmc_register_driver(&mmc_driver);
+ if (res)
+ goto out2;
+ return 0;
+ out2:
+ unregister_blkdev(MMC_BLOCK_MAJOR, "mmc");
out:
return res;
}
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c
index f26b01d811a..b92b172074e 100644
--- a/drivers/mmc/card/mmc_test.c
+++ b/drivers/mmc/card/mmc_test.c
@@ -1040,7 +1040,7 @@ static const struct mmc_test_case mmc_test_cases[] = {
};
-static struct mutex mmc_test_lock;
+static DEFINE_MUTEX(mmc_test_lock);
static void mmc_test_run(struct mmc_test_card *test, int testcase)
{
@@ -1171,8 +1171,6 @@ static int mmc_test_probe(struct mmc_card *card)
if ((card->type != MMC_TYPE_MMC) && (card->type != MMC_TYPE_SD))
return -ENODEV;
- mutex_init(&mmc_test_lock);
-
ret = device_create_file(&card->dev, &dev_attr_test);
if (ret)
return ret;
diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c
index 6915f40ac8a..1f8b5b36222 100644
--- a/drivers/mmc/host/at91_mci.c
+++ b/drivers/mmc/host/at91_mci.c
@@ -621,12 +621,21 @@ static void at91_mci_send_command(struct at91mci_host *host, struct mmc_command
if (cpu_is_at91sam9260 () || cpu_is_at91sam9263())
if (host->total_length < 12)
host->total_length = 12;
- host->buffer = dma_alloc_coherent(NULL,
- host->total_length,
- &host->physical_address, GFP_KERNEL);
+
+ host->buffer = kmalloc(host->total_length, GFP_KERNEL);
+ if (!host->buffer) {
+ pr_debug("Can't alloc tx buffer\n");
+ cmd->error = -ENOMEM;
+ mmc_request_done(host->mmc, host->request);
+ return;
+ }
at91_mci_sg_to_dma(host, data);
+ host->physical_address = dma_map_single(NULL,
+ host->buffer, host->total_length,
+ DMA_TO_DEVICE);
+
pr_debug("Transmitting %d bytes\n", host->total_length);
at91_mci_write(host, ATMEL_PDC_TPR, host->physical_address);
@@ -694,7 +703,10 @@ static void at91_mci_completed_command(struct at91mci_host *host, unsigned int s
cmd->resp[3] = at91_mci_read(host, AT91_MCI_RSPR(3));
if (host->buffer) {
- dma_free_coherent(NULL, host->total_length, host->buffer, host->physical_address);
+ dma_unmap_single(NULL,
+ host->physical_address, host->total_length,
+ DMA_TO_DEVICE);
+ kfree(host->buffer);
host->buffer = NULL;
}
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index 0bd06f5bd62..00008967ef7 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -195,7 +195,9 @@ static int atmci_regs_show(struct seq_file *s, void *v)
/* Grab a more or less consistent snapshot */
spin_lock_irq(&host->mmc->lock);
+ clk_enable(host->mck);
memcpy_fromio(buf, host->regs, MCI_REGS_SIZE);
+ clk_disable(host->mck);
spin_unlock_irq(&host->mmc->lock);
seq_printf(s, "MR:\t0x%08x%s%s CLKDIV=%u\n",
@@ -216,6 +218,8 @@ static int atmci_regs_show(struct seq_file *s, void *v)
atmci_show_status_reg(s, "SR", buf[MCI_SR / 4]);
atmci_show_status_reg(s, "IMR", buf[MCI_IMR / 4]);
+ kfree(buf);
+
return 0;
}
@@ -237,7 +241,6 @@ static void atmci_init_debugfs(struct atmel_mci *host)
struct mmc_host *mmc;
struct dentry *root;
struct dentry *node;
- struct resource *res;
mmc = host->mmc;
root = mmc->debugfs_root;
@@ -251,9 +254,6 @@ static void atmci_init_debugfs(struct atmel_mci *host)
if (!node)
goto err;
- res = platform_get_resource(host->pdev, IORESOURCE_MEM, 0);
- node->d_inode->i_size = res->end - res->start + 1;
-
node = debugfs_create_file("req", S_IRUSR, root, host, &atmci_req_fops);
if (!node)
goto err;
@@ -426,8 +426,6 @@ static u32 atmci_submit_data(struct mmc_host *mmc, struct mmc_data *data)
host->sg = NULL;
host->data = data;
- mci_writel(host, BLKR, MCI_BCNT(data->blocks)
- | MCI_BLKLEN(data->blksz));
dev_vdbg(&mmc->class_dev, "BLKR=0x%08x\n",
MCI_BCNT(data->blocks) | MCI_BLKLEN(data->blksz));
@@ -483,6 +481,10 @@ static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
if (data->blocks > 1 && data->blksz & 3)
goto fail;
atmci_set_timeout(host, data);
+
+ /* Must set block count/size before sending command */
+ mci_writel(host, BLKR, MCI_BCNT(data->blocks)
+ | MCI_BLKLEN(data->blksz));
}
iflags = MCI_CMDRDY;
@@ -1059,6 +1061,10 @@ static int __init atmci_probe(struct platform_device *pdev)
host->present = !gpio_get_value(host->detect_pin);
}
}
+
+ if (!gpio_is_valid(host->detect_pin))
+ mmc->caps |= MMC_CAP_NEEDS_POLL;
+
if (gpio_is_valid(host->wp_pin)) {
if (gpio_request(host->wp_pin, "mmc_wp")) {
dev_dbg(&mmc->class_dev, "no WP pin available\n");
diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
index 9e647a06054..ba2b4240a86 100644
--- a/drivers/mmc/host/tmio_mmc.h
+++ b/drivers/mmc/host/tmio_mmc.h
@@ -159,10 +159,10 @@ static inline void tmio_mmc_kunmap_atomic(struct tmio_mmc_host *host,
#define STATUS_TO_TEXT(a) \
do { \
if (status & TMIO_STAT_##a) \
- printf(#a); \
+ printk(#a); \
} while (0)
-void debug_status(u32 status)
+void pr_debug_status(u32 status)
{
printk(KERN_DEBUG "status: %08x = ", status);
STATUS_TO_TEXT(CARD_REMOVE);
diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c
index f34f20c7891..9bf581c4f74 100644
--- a/drivers/mtd/ftl.c
+++ b/drivers/mtd/ftl.c
@@ -1005,6 +1005,29 @@ static int ftl_writesect(struct mtd_blktrans_dev *dev,
return ftl_write((void *)dev, buf, block, 1);
}
+static int ftl_discardsect(struct mtd_blktrans_dev *dev,
+ unsigned long sector, unsigned nr_sects)
+{
+ partition_t *part = (void *)dev;
+ uint32_t bsize = 1 << part->header.EraseUnitSize;
+
+ DEBUG(1, "FTL erase sector %ld for %d sectors\n",
+ sector, nr_sects);
+
+ while (nr_sects) {
+ uint32_t old_addr = part->VirtualBlockMap[sector];
+ if (old_addr != 0xffffffff) {
+ part->VirtualBlockMap[sector] = 0xffffffff;
+ part->EUNInfo[old_addr/bsize].Deleted++;
+ if (set_bam_entry(part, old_addr, 0))
+ return -EIO;
+ }
+ nr_sects--;
+ sector++;
+ }
+
+ return 0;
+}
/*====================================================================*/
static void ftl_freepart(partition_t *part)
@@ -1069,6 +1092,7 @@ static struct mtd_blktrans_ops ftl_tr = {
.blksize = SECTOR_SIZE,
.readsect = ftl_readsect,
.writesect = ftl_writesect,
+ .discard = ftl_discardsect,
.getgeo = ftl_getgeo,
.add_mtd = ftl_add_mtd,
.remove_dev = ftl_remove_dev,
diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c
index 9ff007c4962..681d5aca2af 100644
--- a/drivers/mtd/mtd_blkdevs.c
+++ b/drivers/mtd/mtd_blkdevs.c
@@ -32,6 +32,14 @@ struct mtd_blkcore_priv {
spinlock_t queue_lock;
};
+static int blktrans_discard_request(struct request_queue *q,
+ struct request *req)
+{
+ req->cmd_type = REQ_TYPE_LINUX_BLOCK;
+ req->cmd[0] = REQ_LB_OP_DISCARD;
+ return 0;
+}
+
static int do_blktrans_request(struct mtd_blktrans_ops *tr,
struct mtd_blktrans_dev *dev,
struct request *req)
@@ -44,6 +52,10 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr,
buf = req->buffer;
+ if (req->cmd_type == REQ_TYPE_LINUX_BLOCK &&
+ req->cmd[0] == REQ_LB_OP_DISCARD)
+ return !tr->discard(dev, block, nsect);
+
if (!blk_fs_request(req))
return 0;
@@ -367,6 +379,10 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr)
tr->blkcore_priv->rq->queuedata = tr;
blk_queue_hardsect_size(tr->blkcore_priv->rq, tr->blksize);
+ if (tr->discard)
+ blk_queue_set_discard(tr->blkcore_priv->rq,
+ blktrans_discard_request);
+
tr->blkshift = ffs(tr->blksize) - 1;
tr->blkcore_priv->thread = kthread_run(mtd_blktrans_thread, tr,
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index d2f331876e4..e00d424e657 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -410,16 +410,20 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
case MEMGETREGIONINFO:
{
- struct region_info_user ur;
+ uint32_t ur_idx;
+ struct mtd_erase_region_info *kr;
+ struct region_info_user *ur = (struct region_info_user *) argp;
- if (copy_from_user(&ur, argp, sizeof(struct region_info_user)))
+ if (get_user(ur_idx, &(ur->regionindex)))
return -EFAULT;
- if (ur.regionindex >= mtd->numeraseregions)
- return -EINVAL;
- if (copy_to_user(argp, &(mtd->eraseregions[ur.regionindex]),
- sizeof(struct mtd_erase_region_info)))
+ kr = &(mtd->eraseregions[ur_idx]);
+
+ if (put_user(kr->offset, &(ur->offset))
+ || put_user(kr->erasesize, &(ur->erasesize))
+ || put_user(kr->numblocks, &(ur->numblocks)))
return -EFAULT;
+
break;
}
diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/tmio_nand.c
index cbab654b03c..edb1e322113 100644
--- a/drivers/mtd/nand/tmio_nand.c
+++ b/drivers/mtd/nand/tmio_nand.c
@@ -109,7 +109,7 @@ struct tmio_nand {
void __iomem *ccr;
void __iomem *fcr;
- unsigned long fcr_phys;
+ unsigned long fcr_base;
unsigned int irq;
@@ -316,8 +316,8 @@ static int tmio_hw_init(struct platform_device *dev, struct tmio_nand *tmio)
tmio_iowrite8(0x81, tmio->ccr + CCR_ICC);
/* (10h)BaseAddress 0x1000 spba.spba2 */
- tmio_iowrite16(tmio->fcr_phys, tmio->ccr + CCR_BASE);
- tmio_iowrite16(tmio->fcr_phys >> 16, tmio->ccr + CCR_BASE + 16);
+ tmio_iowrite16(tmio->fcr_base, tmio->ccr + CCR_BASE);
+ tmio_iowrite16(tmio->fcr_base >> 16, tmio->ccr + CCR_BASE + 2);
/* (04h)Command Register I/O spcmd */
tmio_iowrite8(0x02, tmio->ccr + CCR_COMMAND);
@@ -395,7 +395,7 @@ static int tmio_probe(struct platform_device *dev)
goto err_iomap_ccr;
}
- tmio->fcr_phys = (unsigned long)fcr->start;
+ tmio->fcr_base = fcr->start & 0xfffff;
tmio->fcr = ioremap(fcr->start, fcr->end - fcr->start + 1);
if (!tmio->fcr) {
retval = -EIO;
diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h
index c3c579f98ed..dfacd31f7ed 100644
--- a/drivers/net/bnx2.h
+++ b/drivers/net/bnx2.h
@@ -6597,7 +6597,7 @@ struct flash_spec {
struct bnx2_irq {
irq_handler_t handler;
- u16 vector;
+ unsigned int vector;
u8 requested;
char name[16];
};
diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h
index a14dba1afcc..fd705d1295a 100644
--- a/drivers/net/bnx2x.h
+++ b/drivers/net/bnx2x.h
@@ -151,6 +151,8 @@ struct sw_rx_page {
#define PAGES_PER_SGE_SHIFT 0
#define PAGES_PER_SGE (1 << PAGES_PER_SGE_SHIFT)
+#define BCM_RX_ETH_PAYLOAD_ALIGN 64
+
/* SGE ring related macros */
#define NUM_RX_SGE_PAGES 2
#define RX_SGE_CNT (BCM_PAGE_SIZE / sizeof(struct eth_rx_sge))
@@ -750,8 +752,7 @@ struct bnx2x {
u32 rx_csum;
u32 rx_offset;
- u32 rx_buf_use_size; /* useable size */
- u32 rx_buf_size; /* with alignment */
+ u32 rx_buf_size;
#define ETH_OVREHEAD (ETH_HLEN + 8) /* 8 for CRC + VLAN */
#define ETH_MIN_PACKET_SIZE 60
#define ETH_MAX_PACKET_SIZE 1500
diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c
index 82deea0a63f..a8eb3c4a47c 100644
--- a/drivers/net/bnx2x_main.c
+++ b/drivers/net/bnx2x_main.c
@@ -59,8 +59,8 @@
#include "bnx2x.h"
#include "bnx2x_init.h"
-#define DRV_MODULE_VERSION "1.45.20"
-#define DRV_MODULE_RELDATE "2008/08/25"
+#define DRV_MODULE_VERSION "1.45.21"
+#define DRV_MODULE_RELDATE "2008/09/03"
#define BNX2X_BC_VER 0x040200
/* Time in jiffies before concluding the transmitter is hung */
@@ -1027,7 +1027,7 @@ static inline int bnx2x_alloc_rx_skb(struct bnx2x *bp,
if (unlikely(skb == NULL))
return -ENOMEM;
- mapping = pci_map_single(bp->pdev, skb->data, bp->rx_buf_use_size,
+ mapping = pci_map_single(bp->pdev, skb->data, bp->rx_buf_size,
PCI_DMA_FROMDEVICE);
if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) {
dev_kfree_skb(skb);
@@ -1169,7 +1169,7 @@ static void bnx2x_tpa_start(struct bnx2x_fastpath *fp, u16 queue,
/* move empty skb from pool to prod and map it */
prod_rx_buf->skb = fp->tpa_pool[queue].skb;
mapping = pci_map_single(bp->pdev, fp->tpa_pool[queue].skb->data,
- bp->rx_buf_use_size, PCI_DMA_FROMDEVICE);
+ bp->rx_buf_size, PCI_DMA_FROMDEVICE);
pci_unmap_addr_set(prod_rx_buf, mapping, mapping);
/* move partial skb from cons to pool (don't unmap yet) */
@@ -1276,7 +1276,7 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
pool entry status to BNX2X_TPA_STOP even if new skb allocation
fails. */
pci_unmap_single(bp->pdev, pci_unmap_addr(rx_buf, mapping),
- bp->rx_buf_use_size, PCI_DMA_FROMDEVICE);
+ bp->rx_buf_size, PCI_DMA_FROMDEVICE);
if (likely(new_skb)) {
/* fix ip xsum and give it to the stack */
@@ -1520,7 +1520,7 @@ static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
} else if (bnx2x_alloc_rx_skb(bp, fp, bd_prod) == 0) {
pci_unmap_single(bp->pdev,
pci_unmap_addr(rx_buf, mapping),
- bp->rx_buf_use_size,
+ bp->rx_buf_size,
PCI_DMA_FROMDEVICE);
skb_reserve(skb, pad);
skb_put(skb, len);
@@ -4229,7 +4229,7 @@ static inline void bnx2x_free_tpa_pool(struct bnx2x *bp,
if (fp->tpa_state[i] == BNX2X_TPA_START)
pci_unmap_single(bp->pdev,
pci_unmap_addr(rx_buf, mapping),
- bp->rx_buf_use_size,
+ bp->rx_buf_size,
PCI_DMA_FROMDEVICE);
dev_kfree_skb(skb);
@@ -4245,15 +4245,14 @@ static void bnx2x_init_rx_rings(struct bnx2x *bp)
u16 ring_prod, cqe_ring_prod;
int i, j;
- bp->rx_buf_use_size = bp->dev->mtu;
- bp->rx_buf_use_size += bp->rx_offset + ETH_OVREHEAD;
- bp->rx_buf_size = bp->rx_buf_use_size + 64;
+ bp->rx_buf_size = bp->dev->mtu;
+ bp->rx_buf_size += bp->rx_offset + ETH_OVREHEAD +
+ BCM_RX_ETH_PAYLOAD_ALIGN;
if (bp->flags & TPA_ENABLE_FLAG) {
DP(NETIF_MSG_IFUP,
- "rx_buf_use_size %d rx_buf_size %d effective_mtu %d\n",
- bp->rx_buf_use_size, bp->rx_buf_size,
- bp->dev->mtu + ETH_OVREHEAD);
+ "rx_buf_size %d effective_mtu %d\n",
+ bp->rx_buf_size, bp->dev->mtu + ETH_OVREHEAD);
for_each_queue(bp, j) {
struct bnx2x_fastpath *fp = &bp->fp[j];
@@ -4462,9 +4461,10 @@ static void bnx2x_init_context(struct bnx2x *bp)
context->ustorm_st_context.common.status_block_id = sb_id;
context->ustorm_st_context.common.flags =
USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_MC_ALIGNMENT;
- context->ustorm_st_context.common.mc_alignment_size = 64;
+ context->ustorm_st_context.common.mc_alignment_size =
+ BCM_RX_ETH_PAYLOAD_ALIGN;
context->ustorm_st_context.common.bd_buff_size =
- bp->rx_buf_use_size;
+ bp->rx_buf_size;
context->ustorm_st_context.common.bd_page_base_hi =
U64_HI(fp->rx_desc_mapping);
context->ustorm_st_context.common.bd_page_base_lo =
@@ -4717,7 +4717,7 @@ static void bnx2x_init_internal_func(struct bnx2x *bp)
}
/* Init CQ ring mapping and aggregation size */
- max_agg_size = min((u32)(bp->rx_buf_use_size +
+ max_agg_size = min((u32)(bp->rx_buf_size +
8*BCM_PAGE_SIZE*PAGES_PER_SGE),
(u32)0xffff);
for_each_queue(bp, i) {
@@ -5940,7 +5940,7 @@ static void bnx2x_free_rx_skbs(struct bnx2x *bp)
pci_unmap_single(bp->pdev,
pci_unmap_addr(rx_buf, mapping),
- bp->rx_buf_use_size,
+ bp->rx_buf_size,
PCI_DMA_FROMDEVICE);
rx_buf->skb = NULL;
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index 453115acaad..5cf78d612c4 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -2738,9 +2738,7 @@ static int __devinit e100_probe(struct pci_dev *pdev,
nic->flags |= wol_magic;
/* ack any pending wake events, disable PME */
- err = pci_enable_wake(pdev, 0, 0);
- if (err)
- DPRINTK(PROBE, ERR, "Error clearing wake event\n");
+ pci_pme_active(pdev, false);
strcpy(netdev->name, "eth%d");
if((err = register_netdev(netdev))) {
diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
index 9d6edf3e73f..d04eef53571 100644
--- a/drivers/net/e1000/e1000_hw.c
+++ b/drivers/net/e1000/e1000_hw.c
@@ -144,6 +144,8 @@ static s32 e1000_host_if_read_cookie(struct e1000_hw *hw, u8 *buffer);
static u8 e1000_calculate_mng_checksum(char *buffer, u32 length);
static s32 e1000_configure_kmrn_for_10_100(struct e1000_hw *hw, u16 duplex);
static s32 e1000_configure_kmrn_for_1000(struct e1000_hw *hw);
+static s32 e1000_do_read_eeprom(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
+static s32 e1000_do_write_eeprom(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
/* IGP cable length table */
static const
@@ -168,6 +170,8 @@ u16 e1000_igp_2_cable_length_table[IGP02E1000_AGC_LENGTH_TABLE_SIZE] =
83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124,
104, 109, 114, 118, 121, 124};
+static DEFINE_SPINLOCK(e1000_eeprom_lock);
+
/******************************************************************************
* Set the phy type member in the hw struct.
*
@@ -4904,6 +4908,15 @@ static s32 e1000_spi_eeprom_ready(struct e1000_hw *hw)
*****************************************************************************/
s32 e1000_read_eeprom(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
{
+ s32 ret;
+ spin_lock(&e1000_eeprom_lock);
+ ret = e1000_do_read_eeprom(hw, offset, words, data);
+ spin_unlock(&e1000_eeprom_lock);
+ return ret;
+}
+
+static s32 e1000_do_read_eeprom(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
struct e1000_eeprom_info *eeprom = &hw->eeprom;
u32 i = 0;
@@ -5236,6 +5249,16 @@ s32 e1000_update_eeprom_checksum(struct e1000_hw *hw)
*****************************************************************************/
s32 e1000_write_eeprom(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
{
+ s32 ret;
+ spin_lock(&e1000_eeprom_lock);
+ ret = e1000_do_write_eeprom(hw, offset, words, data);
+ spin_unlock(&e1000_eeprom_lock);
+ return ret;
+}
+
+
+static s32 e1000_do_write_eeprom(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
struct e1000_eeprom_info *eeprom = &hw->eeprom;
s32 status = 0;
diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h
index ac4e506b4f8..5ea6b60fa37 100644
--- a/drivers/net/e1000e/e1000.h
+++ b/drivers/net/e1000e/e1000.h
@@ -257,7 +257,6 @@ struct e1000_adapter {
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;
@@ -284,6 +283,8 @@ struct e1000_adapter {
unsigned long led_status;
unsigned int flags;
+ struct work_struct downshift_task;
+ struct work_struct update_phy_task;
};
struct e1000_info {
@@ -305,6 +306,7 @@ struct e1000_info {
#define FLAG_HAS_CTRLEXT_ON_LOAD (1 << 5)
#define FLAG_HAS_SWSM_ON_LOAD (1 << 6)
#define FLAG_HAS_JUMBO_FRAMES (1 << 7)
+#define FLAG_READ_ONLY_NVM (1 << 8)
#define FLAG_IS_ICH (1 << 9)
#define FLAG_HAS_SMART_POWER_DOWN (1 << 11)
#define FLAG_IS_QUAD_PORT_A (1 << 12)
@@ -385,6 +387,7 @@ 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_write_protect_nvm_ich8lan(struct e1000_hw *hw);
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);
diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c
index e21c9e0f373..33a3ff17b5d 100644
--- a/drivers/net/e1000e/ethtool.c
+++ b/drivers/net/e1000e/ethtool.c
@@ -432,6 +432,10 @@ static void e1000_get_regs(struct net_device *netdev,
regs_buff[11] = er32(TIDV);
regs_buff[12] = adapter->hw.phy.type; /* PHY type (IGP=1, M88=0) */
+
+ /* ethtool doesn't use anything past this point, so all this
+ * code is likely legacy junk for apps that may or may not
+ * exist */
if (hw->phy.type == e1000_phy_m88) {
e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
regs_buff[13] = (u32)phy_data; /* cable length */
@@ -447,7 +451,7 @@ static void e1000_get_regs(struct net_device *netdev,
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 */
+ regs_buff[21] = 0; /* was 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 */
@@ -529,6 +533,9 @@ static int e1000_set_eeprom(struct net_device *netdev,
if (eeprom->magic != (adapter->pdev->vendor | (adapter->pdev->device << 16)))
return -EFAULT;
+ if (adapter->flags & FLAG_READ_ONLY_NVM)
+ return -EINVAL;
+
max_len = hw->nvm.word_size * 2;
first_word = eeprom->offset >> 1;
diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c
index 9e38452a738..bcd2bc477af 100644
--- a/drivers/net/e1000e/ich8lan.c
+++ b/drivers/net/e1000e/ich8lan.c
@@ -58,6 +58,7 @@
#define ICH_FLASH_HSFCTL 0x0006
#define ICH_FLASH_FADDR 0x0008
#define ICH_FLASH_FDATA0 0x0010
+#define ICH_FLASH_PR0 0x0074
#define ICH_FLASH_READ_COMMAND_TIMEOUT 500
#define ICH_FLASH_WRITE_COMMAND_TIMEOUT 500
@@ -150,6 +151,19 @@ union ich8_hws_flash_regacc {
u16 regval;
};
+/* ICH Flash Protected Region */
+union ich8_flash_protected_range {
+ struct ich8_pr {
+ u32 base:13; /* 0:12 Protected Range Base */
+ u32 reserved1:2; /* 13:14 Reserved */
+ u32 rpe:1; /* 15 Read Protection Enable */
+ u32 limit:13; /* 16:28 Protected Range Limit */
+ u32 reserved2:2; /* 29:30 Reserved */
+ u32 wpe:1; /* 31 Write Protection Enable */
+ } range;
+ u32 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);
@@ -366,6 +380,9 @@ static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter)
return 0;
}
+static DEFINE_MUTEX(nvm_mutex);
+static pid_t nvm_owner = -1;
+
/**
* e1000_acquire_swflag_ich8lan - Acquire software control flag
* @hw: pointer to the HW structure
@@ -379,6 +396,15 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
u32 extcnf_ctrl;
u32 timeout = PHY_CFG_TIMEOUT;
+ might_sleep();
+
+ if (!mutex_trylock(&nvm_mutex)) {
+ WARN(1, KERN_ERR "e1000e mutex contention. Owned by pid %d\n",
+ nvm_owner);
+ mutex_lock(&nvm_mutex);
+ }
+ nvm_owner = current->pid;
+
while (timeout) {
extcnf_ctrl = er32(EXTCNF_CTRL);
extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG;
@@ -393,6 +419,8 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
if (!timeout) {
hw_dbg(hw, "FW or HW has locked the resource for too long.\n");
+ nvm_owner = -1;
+ mutex_unlock(&nvm_mutex);
return -E1000_ERR_CONFIG;
}
@@ -414,6 +442,9 @@ static void e1000_release_swflag_ich8lan(struct e1000_hw *hw)
extcnf_ctrl = er32(EXTCNF_CTRL);
extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
ew32(EXTCNF_CTRL, extcnf_ctrl);
+
+ nvm_owner = -1;
+ mutex_unlock(&nvm_mutex);
}
/**
@@ -1284,6 +1315,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
* programming failed.
*/
if (ret_val) {
+ /* Possibly read-only, see e1000e_write_protect_nvm_ich8lan() */
hw_dbg(hw, "Flash commit failed.\n");
e1000_release_swflag_ich8lan(hw);
return ret_val;
@@ -1374,6 +1406,49 @@ static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw)
}
/**
+ * e1000e_write_protect_nvm_ich8lan - Make the NVM read-only
+ * @hw: pointer to the HW structure
+ *
+ * To prevent malicious write/erase of the NVM, set it to be read-only
+ * so that the hardware ignores all write/erase cycles of the NVM via
+ * the flash control registers. The shadow-ram copy of the NVM will
+ * still be updated, however any updates to this copy will not stick
+ * across driver reloads.
+ **/
+void e1000e_write_protect_nvm_ich8lan(struct e1000_hw *hw)
+{
+ union ich8_flash_protected_range pr0;
+ union ich8_hws_flash_status hsfsts;
+ u32 gfpreg;
+ s32 ret_val;
+
+ ret_val = e1000_acquire_swflag_ich8lan(hw);
+ if (ret_val)
+ return;
+
+ gfpreg = er32flash(ICH_FLASH_GFPREG);
+
+ /* Write-protect GbE Sector of NVM */
+ pr0.regval = er32flash(ICH_FLASH_PR0);
+ pr0.range.base = gfpreg & FLASH_GFPREG_BASE_MASK;
+ pr0.range.limit = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK);
+ pr0.range.wpe = true;
+ ew32flash(ICH_FLASH_PR0, pr0.regval);
+
+ /*
+ * Lock down a subset of GbE Flash Control Registers, e.g.
+ * PR0 to prevent the write-protection from being lifted.
+ * Once FLOCKDN is set, the registers protected by it cannot
+ * be written until FLOCKDN is cleared by a hardware reset.
+ */
+ hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
+ hsfsts.hsf_status.flockdn = true;
+ ew32flash(ICH_FLASH_HSFSTS, hsfsts.regval);
+
+ e1000_release_swflag_ich8lan(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.
@@ -1720,6 +1795,9 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
ew32(CTRL, (ctrl | E1000_CTRL_RST));
msleep(20);
+ /* release the swflag because it is not reset by hardware reset */
+ e1000_release_swflag_ich8lan(hw);
+
ret_val = e1000e_get_auto_rd_done(hw);
if (ret_val) {
/*
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index d266510c8a9..b81c4237b5d 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -47,7 +47,7 @@
#include "e1000.h"
-#define DRV_VERSION "0.3.3.3-k2"
+#define DRV_VERSION "0.3.3.3-k6"
char e1000e_driver_name[] = "e1000e";
const char e1000e_driver_version[] = DRV_VERSION;
@@ -1115,6 +1115,14 @@ static void e1000_clean_rx_ring(struct e1000_adapter *adapter)
writel(0, adapter->hw.hw_addr + rx_ring->tail);
}
+static void e1000e_downshift_workaround(struct work_struct *work)
+{
+ struct e1000_adapter *adapter = container_of(work,
+ struct e1000_adapter, downshift_task);
+
+ e1000e_gig_downshift_workaround_ich8lan(&adapter->hw);
+}
+
/**
* e1000_intr_msi - Interrupt Handler
* @irq: interrupt number
@@ -1139,7 +1147,7 @@ static irqreturn_t e1000_intr_msi(int irq, void *data)
*/
if ((adapter->flags & FLAG_LSC_GIG_SPEED_DROP) &&
(!(er32(STATUS) & E1000_STATUS_LU)))
- e1000e_gig_downshift_workaround_ich8lan(hw);
+ schedule_work(&adapter->downshift_task);
/*
* 80003ES2LAN workaround-- For packet buffer work-around on
@@ -1205,7 +1213,7 @@ static irqreturn_t e1000_intr(int irq, void *data)
*/
if ((adapter->flags & FLAG_LSC_GIG_SPEED_DROP) &&
(!(er32(STATUS) & E1000_STATUS_LU)))
- e1000e_gig_downshift_workaround_ich8lan(hw);
+ schedule_work(&adapter->downshift_task);
/*
* 80003ES2LAN workaround--
@@ -2592,8 +2600,6 @@ static int __devinit e1000_sw_init(struct e1000_adapter *adapter)
/* Explicitly disable IRQ since the NIC can be in any state. */
e1000_irq_disable(adapter);
- spin_lock_init(&adapter->stats_lock);
-
set_bit(__E1000_DOWN, &adapter->state);
return 0;
@@ -2912,6 +2918,21 @@ static int e1000_set_mac(struct net_device *netdev, void *p)
return 0;
}
+/**
+ * e1000e_update_phy_task - work thread to update phy
+ * @work: pointer to our work struct
+ *
+ * this worker thread exists because we must acquire a
+ * semaphore to read the phy, which we could msleep while
+ * waiting for it, and we can't msleep in a timer.
+ **/
+static void e1000e_update_phy_task(struct work_struct *work)
+{
+ struct e1000_adapter *adapter = container_of(work,
+ struct e1000_adapter, update_phy_task);
+ e1000_get_phy_info(&adapter->hw);
+}
+
/*
* Need to wait a few seconds after link up to get diagnostic information from
* the phy
@@ -2919,7 +2940,7 @@ static int e1000_set_mac(struct net_device *netdev, void *p)
static void e1000_update_phy_info(unsigned long data)
{
struct e1000_adapter *adapter = (struct e1000_adapter *) data;
- e1000_get_phy_info(&adapter->hw);
+ schedule_work(&adapter->update_phy_task);
}
/**
@@ -2930,10 +2951,6 @@ 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
@@ -2944,14 +2961,6 @@ void e1000e_update_stats(struct e1000_adapter *adapter)
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.gorc += er32(GORCL);
@@ -3022,21 +3031,10 @@ void e1000e_update_stats(struct e1000_adapter *adapter)
/* Tx Dropped needs to be maintained elsewhere */
- /* Phy Stats */
- if (hw->phy.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);
}
/**
@@ -3048,10 +3046,6 @@ static void e1000_phy_read_status(struct e1000_adapter *adapter)
struct e1000_hw *hw = &adapter->hw;
struct e1000_phy_regs *phy = &adapter->phy_regs;
int ret_val;
- unsigned long irq_flags;
-
-
- spin_lock_irqsave(&adapter->stats_lock, irq_flags);
if ((er32(STATUS) & E1000_STATUS_LU) &&
(adapter->hw.phy.media_type == e1000_media_type_copper)) {
@@ -3082,8 +3076,6 @@ static void e1000_phy_read_status(struct e1000_adapter *adapter)
phy->stat1000 = 0;
phy->estatus = (ESTATUS_1000_TFULL | ESTATUS_1000_THALF);
}
-
- spin_unlock_irqrestore(&adapter->stats_lock, irq_flags);
}
static void e1000_print_link_info(struct e1000_adapter *adapter)
@@ -4467,6 +4459,8 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
adapter->bd_number = cards_found++;
+ e1000e_check_options(adapter);
+
/* setup adapter struct */
err = e1000_sw_init(adapter);
if (err)
@@ -4482,6 +4476,10 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
if (err)
goto err_hw_init;
+ if ((adapter->flags & FLAG_IS_ICH) &&
+ (adapter->flags & FLAG_READ_ONLY_NVM))
+ e1000e_write_protect_nvm_ich8lan(&adapter->hw);
+
hw->mac.ops.get_bus_info(&adapter->hw);
adapter->hw.phy.autoneg_wait_to_complete = 0;
@@ -4572,8 +4570,8 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
INIT_WORK(&adapter->reset_task, e1000_reset_task);
INIT_WORK(&adapter->watchdog_task, e1000_watchdog_task);
-
- e1000e_check_options(adapter);
+ INIT_WORK(&adapter->downshift_task, e1000e_downshift_workaround);
+ INIT_WORK(&adapter->update_phy_task, e1000e_update_phy_task);
/* Initialize link parameters. User can change them with ethtool */
adapter->hw.mac.autoneg = 1;
diff --git a/drivers/net/e1000e/param.c b/drivers/net/e1000e/param.c
index ed912e023a7..d91dbf7ba43 100644
--- a/drivers/net/e1000e/param.c
+++ b/drivers/net/e1000e/param.c
@@ -133,6 +133,15 @@ E1000_PARAM(SmartPowerDownEnable, "Enable PHY smart power down");
*/
E1000_PARAM(KumeranLockLoss, "Enable Kumeran lock loss workaround");
+/*
+ * Write Protect NVM
+ *
+ * Valid Range: 0, 1
+ *
+ * Default Value: 1 (enabled)
+ */
+E1000_PARAM(WriteProtectNVM, "Write-protect NVM [WARNING: disabling this can lead to corrupted NVM]");
+
struct e1000_option {
enum { enable_option, range_option, list_option } type;
const char *name;
@@ -388,4 +397,25 @@ void __devinit e1000e_check_options(struct e1000_adapter *adapter)
opt.def);
}
}
+ { /* Write-protect NVM */
+ const struct e1000_option opt = {
+ .type = enable_option,
+ .name = "Write-protect NVM",
+ .err = "defaulting to Enabled",
+ .def = OPTION_ENABLED
+ };
+
+ if (adapter->flags & FLAG_IS_ICH) {
+ if (num_WriteProtectNVM > bd) {
+ unsigned int write_protect_nvm = WriteProtectNVM[bd];
+ e1000_validate_option(&write_protect_nvm, &opt,
+ adapter);
+ if (write_protect_nvm)
+ adapter->flags |= FLAG_READ_ONLY_NVM;
+ } else {
+ if (opt.def)
+ adapter->flags |= FLAG_READ_ONLY_NVM;
+ }
+ }
+ }
}
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 331b86b01fa..eeb55ed2152 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -5643,6 +5643,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
dev->dev_addr[4] = (np->orig_mac[0] >> 8) & 0xff;
dev->dev_addr[5] = (np->orig_mac[0] >> 0) & 0xff;
writel(txreg|NVREG_TRANSMITPOLL_MAC_ADDR_REV, base + NvRegTransmitPoll);
+ printk(KERN_DEBUG "nv_probe: set workaround bit for reversed mac addr\n");
}
memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
@@ -5890,14 +5891,12 @@ static void nv_restore_phy(struct net_device *dev)
}
}
-static void __devexit nv_remove(struct pci_dev *pci_dev)
+static void nv_restore_mac_addr(struct pci_dev *pci_dev)
{
struct net_device *dev = pci_get_drvdata(pci_dev);
struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
- unregister_netdev(dev);
-
/* special op: write back the misordered MAC address - otherwise
* the next nv_probe would see a wrong address.
*/
@@ -5905,6 +5904,15 @@ static void __devexit nv_remove(struct pci_dev *pci_dev)
writel(np->orig_mac[1], base + NvRegMacAddrB);
writel(readl(base + NvRegTransmitPoll) & ~NVREG_TRANSMITPOLL_MAC_ADDR_REV,
base + NvRegTransmitPoll);
+}
+
+static void __devexit nv_remove(struct pci_dev *pci_dev)
+{
+ struct net_device *dev = pci_get_drvdata(pci_dev);
+
+ unregister_netdev(dev);
+
+ nv_restore_mac_addr(pci_dev);
/* restore any phy related changes */
nv_restore_phy(dev);
@@ -5975,10 +5983,14 @@ static void nv_shutdown(struct pci_dev *pdev)
if (netif_running(dev))
nv_close(dev);
- pci_enable_wake(pdev, PCI_D3hot, np->wolenabled);
- pci_enable_wake(pdev, PCI_D3cold, np->wolenabled);
+ nv_restore_mac_addr(pdev);
+
pci_disable_device(pdev);
- pci_set_power_state(pdev, PCI_D3hot);
+ if (system_state == SYSTEM_POWER_OFF) {
+ if (pci_enable_wake(pdev, PCI_D3cold, np->wolenabled))
+ pci_enable_wake(pdev, PCI_D3hot, np->wolenabled);
+ pci_set_power_state(pdev, PCI_D3hot);
+ }
}
#else
#define nv_suspend NULL
diff --git a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c
index 8239939554b..fbbd3e660c2 100644
--- a/drivers/net/hp-plus.c
+++ b/drivers/net/hp-plus.c
@@ -139,7 +139,7 @@ static int __init do_hpp_probe(struct net_device *dev)
#ifndef MODULE
struct net_device * __init hp_plus_probe(int unit)
{
- struct net_device *dev = alloc_ei_netdev();
+ struct net_device *dev = alloc_eip_netdev();
int err;
if (!dev)
@@ -284,7 +284,7 @@ hpp_open(struct net_device *dev)
int option_reg;
int retval;
- if ((retval = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev))) {
+ if ((retval = request_irq(dev->irq, eip_interrupt, 0, dev->name, dev))) {
return retval;
}
@@ -302,7 +302,7 @@ hpp_open(struct net_device *dev)
/* Select the operational page. */
outw(Perf_Page, ioaddr + HP_PAGING);
- ei_open(dev);
+ eip_open(dev);
return 0;
}
@@ -313,7 +313,7 @@ hpp_close(struct net_device *dev)
int option_reg = inw(ioaddr + HPP_OPTION);
free_irq(dev->irq, dev);
- ei_close(dev);
+ eip_close(dev);
outw((option_reg & ~EnableIRQ) | MemDisable | NICReset | ChipReset,
ioaddr + HPP_OPTION);
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index 53f41b649f0..a417be7f8be 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -2304,6 +2304,12 @@ static int __devinit ixgbe_set_interrupt_capability(struct ixgbe_adapter
int vector, v_budget;
/*
+ * Set the default interrupt throttle rate.
+ */
+ adapter->rx_eitr = (1000000 / IXGBE_DEFAULT_ITR_RX_USECS);
+ adapter->tx_eitr = (1000000 / IXGBE_DEFAULT_ITR_TX_USECS);
+
+ /*
* It's easy to be greedy for MSI-X vectors, but it really
* doesn't do us much good if we have a lot more vectors
* than CPU's. So let's be conservative and only ask for
diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c
index 62071d9c4a5..d1dd5b48dbd 100644
--- a/drivers/net/mlx4/mr.c
+++ b/drivers/net/mlx4/mr.c
@@ -67,11 +67,10 @@ struct mlx4_mpt_entry {
#define MLX4_MPT_FLAG_PHYSICAL (1 << 9)
#define MLX4_MPT_FLAG_REGION (1 << 8)
-#define MLX4_MPT_PD_FLAG_FAST_REG (1 << 26)
+#define MLX4_MPT_PD_FLAG_FAST_REG (1 << 27)
+#define MLX4_MPT_PD_FLAG_RAE (1 << 28)
#define MLX4_MPT_PD_FLAG_EN_INV (3 << 24)
-#define MLX4_MTT_FLAG_PRESENT 1
-
#define MLX4_MPT_STATUS_SW 0xF0
#define MLX4_MPT_STATUS_HW 0x00
@@ -348,7 +347,10 @@ int mlx4_mr_enable(struct mlx4_dev *dev, struct mlx4_mr *mr)
if (mr->mtt.order >= 0 && mr->mtt.page_shift == 0) {
/* fast register MR in free state */
mpt_entry->flags |= cpu_to_be32(MLX4_MPT_FLAG_FREE);
- mpt_entry->pd_flags |= cpu_to_be32(MLX4_MPT_PD_FLAG_FAST_REG);
+ mpt_entry->pd_flags |= cpu_to_be32(MLX4_MPT_PD_FLAG_FAST_REG |
+ MLX4_MPT_PD_FLAG_RAE);
+ mpt_entry->mtt_sz = cpu_to_be32((1 << mr->mtt.order) *
+ MLX4_MTT_ENTRY_PER_SEG);
} else {
mpt_entry->flags |= cpu_to_be32(MLX4_MPT_FLAG_SW_OWNS);
}
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c
index 32bb47adbe3..008fd6618a5 100644
--- a/drivers/net/netxen/netxen_nic_main.c
+++ b/drivers/net/netxen/netxen_nic_main.c
@@ -359,16 +359,6 @@ static void netxen_pcie_strap_init(struct netxen_adapter *adapter)
int i, pos;
struct pci_dev *pdev;
- pdev = pci_get_device(0x1166, 0x0140, NULL);
- if (pdev) {
- pci_dev_put(pdev);
- adapter->hw_read_wx(adapter,
- NETXEN_PCIE_REG(PCIE_TGT_SPLIT_CHICKEN), &chicken, 4);
- chicken |= 0x4000;
- adapter->hw_write_wx(adapter,
- NETXEN_PCIE_REG(PCIE_TGT_SPLIT_CHICKEN), &chicken, 4);
- }
-
pdev = adapter->pdev;
adapter->hw_read_wx(adapter,
diff --git a/drivers/net/niu.c b/drivers/net/niu.c
index e4765b713ab..e3be81eba8a 100644
--- a/drivers/net/niu.c
+++ b/drivers/net/niu.c
@@ -5984,6 +5984,56 @@ static void niu_netif_start(struct niu *np)
niu_enable_interrupts(np, 1);
}
+static void niu_reset_buffers(struct niu *np)
+{
+ int i, j, k, err;
+
+ if (np->rx_rings) {
+ for (i = 0; i < np->num_rx_rings; i++) {
+ struct rx_ring_info *rp = &np->rx_rings[i];
+
+ for (j = 0, k = 0; j < MAX_RBR_RING_SIZE; j++) {
+ struct page *page;
+
+ page = rp->rxhash[j];
+ while (page) {
+ struct page *next =
+ (struct page *) page->mapping;
+ u64 base = page->index;
+ base = base >> RBR_DESCR_ADDR_SHIFT;
+ rp->rbr[k++] = cpu_to_le32(base);
+ page = next;
+ }
+ }
+ for (; k < MAX_RBR_RING_SIZE; k++) {
+ err = niu_rbr_add_page(np, rp, GFP_ATOMIC, k);
+ if (unlikely(err))
+ break;
+ }
+
+ rp->rbr_index = rp->rbr_table_size - 1;
+ rp->rcr_index = 0;
+ rp->rbr_pending = 0;
+ rp->rbr_refill_pending = 0;
+ }
+ }
+ if (np->tx_rings) {
+ for (i = 0; i < np->num_tx_rings; i++) {
+ struct tx_ring_info *rp = &np->tx_rings[i];
+
+ for (j = 0; j < MAX_TX_RING_SIZE; j++) {
+ if (rp->tx_buffs[j].skb)
+ (void) release_tx_packet(np, rp, j);
+ }
+
+ rp->pending = MAX_TX_RING_SIZE;
+ rp->prod = 0;
+ rp->cons = 0;
+ rp->wrap_bit = 0;
+ }
+ }
+}
+
static void niu_reset_task(struct work_struct *work)
{
struct niu *np = container_of(work, struct niu, reset_task);
@@ -6006,6 +6056,12 @@ static void niu_reset_task(struct work_struct *work)
niu_stop_hw(np);
+ spin_unlock_irqrestore(&np->lock, flags);
+
+ niu_reset_buffers(np);
+
+ spin_lock_irqsave(&np->lock, flags);
+
err = niu_init_hw(np);
if (!err) {
np->timer.expires = jiffies + HZ;
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
index 3f682d49a4e..52bf11b73c6 100644
--- a/drivers/net/pcmcia/axnet_cs.c
+++ b/drivers/net/pcmcia/axnet_cs.c
@@ -784,6 +784,7 @@ static struct pcmcia_device_id axnet_ids[] = {
PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FEther PCC-TXD", 0x5261440f, 0x436768c5),
PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FEtherII PCC-TXD", 0x5261440f, 0x730df72e),
PCMCIA_DEVICE_PROD_ID12("Dynalink", "L100C16", 0x55632fd5, 0x66bc2a90),
+ PCMCIA_DEVICE_PROD_ID12("IO DATA", "ETXPCM", 0x547e66dc, 0x233adac2),
PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 PC Card (PCMPC100 V3)", 0x0733cc81, 0x232019a8),
PCMCIA_DEVICE_PROD_ID12("MELCO", "LPC3-TX", 0x481e0094, 0xf91af609),
PCMCIA_DEVICE_PROD_ID12("PCMCIA", "100BASE", 0x281f1c5d, 0x7c2add04),
diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
index 2d4c4ad89b8..ebc1ae6bcbe 100644
--- a/drivers/net/pcmcia/pcnet_cs.c
+++ b/drivers/net/pcmcia/pcnet_cs.c
@@ -1626,6 +1626,7 @@ static struct pcmcia_device_id pcnet_ids[] = {
PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega EtherII PCC-TD", 0x5261440f, 0xc49bd73d),
PCMCIA_DEVICE_PROD_ID12("Corega K.K.", "corega EtherII PCC-TD", 0xd4fdcbd8, 0xc49bd73d),
PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega Ether PCC-T", 0x5261440f, 0x6705fcaa),
+ PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega Ether PCC-TD", 0x5261440f, 0x47d5ca83),
PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FastEther PCC-TX", 0x5261440f, 0x485e85d9),
PCMCIA_DEVICE_PROD_ID12("Corega,K.K.", "Ethernet LAN Card", 0x110d26d9, 0x9fd2f0a2),
PCMCIA_DEVICE_PROD_ID12("corega,K.K.", "Ethernet LAN Card", 0x9791a90e, 0x9fd2f0a2),
@@ -1737,7 +1738,6 @@ static struct pcmcia_device_id pcnet_ids[] = {
PCMCIA_DEVICE_PROD_ID1("CyQ've 10 Base-T LAN CARD", 0x94faf360),
PCMCIA_DEVICE_PROD_ID1("EP-210 PCMCIA LAN CARD.", 0x8850b4de),
PCMCIA_DEVICE_PROD_ID1("ETHER-C16", 0x06a8514f),
- PCMCIA_DEVICE_PROD_ID1("IC-CARD", 0x60cb09a6),
PCMCIA_DEVICE_PROD_ID1("NE2000 Compatible", 0x75b8ad5a),
PCMCIA_DEVICE_PROD_ID2("EN-6200P2", 0xa996d078),
/* too generic! */
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c
index a84ba487c71..8c19307e504 100644
--- a/drivers/net/usb/pegasus.c
+++ b/drivers/net/usb/pegasus.c
@@ -117,7 +117,7 @@ static void ctrl_callback(struct urb *urb)
case -ENOENT:
break;
default:
- if (netif_msg_drv(pegasus))
+ if (netif_msg_drv(pegasus) && printk_ratelimit())
dev_dbg(&pegasus->intf->dev, "%s, status %d\n",
__FUNCTION__, urb->status);
}
@@ -166,7 +166,7 @@ static int get_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
set_current_state(TASK_RUNNING);
if (ret == -ENODEV)
netif_device_detach(pegasus->net);
- if (netif_msg_drv(pegasus))
+ if (netif_msg_drv(pegasus) && printk_ratelimit())
dev_err(&pegasus->intf->dev, "%s, status %d\n",
__FUNCTION__, ret);
goto out;
@@ -275,7 +275,7 @@ static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data)
if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) {
if (ret == -ENODEV)
netif_device_detach(pegasus->net);
- if (netif_msg_drv(pegasus))
+ if (netif_msg_drv(pegasus) && printk_ratelimit())
dev_err(&pegasus->intf->dev, "%s, status %d\n",
__FUNCTION__, ret);
goto out;
@@ -1209,8 +1209,7 @@ static void pegasus_set_multicast(struct net_device *net)
pegasus->eth_regs[EthCtrl2] |= RX_PROMISCUOUS;
if (netif_msg_link(pegasus))
pr_info("%s: Promiscuous mode enabled.\n", net->name);
- } else if (net->mc_count ||
- (net->flags & IFF_ALLMULTI)) {
+ } else if (net->mc_count || (net->flags & IFF_ALLMULTI)) {
pegasus->eth_regs[EthCtrl0] |= RX_MULTICAST;
pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS;
if (netif_msg_link(pegasus))
@@ -1220,6 +1219,8 @@ static void pegasus_set_multicast(struct net_device *net)
pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS;
}
+ pegasus->ctrl_urb->status = 0;
+
pegasus->flags |= ETH_REGS_CHANGE;
ctrl_callback(pegasus->ctrl_urb);
}
diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c
index caf569401a3..00a0eaa0886 100644
--- a/drivers/net/wireless/ath9k/beacon.c
+++ b/drivers/net/wireless/ath9k/beacon.c
@@ -209,6 +209,7 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
unsigned int curlen;
struct ath_txq *cabq;
struct ath_txq *mcastq;
+ struct ieee80211_tx_info *info;
avp = sc->sc_vaps[if_id];
mcastq = &avp->av_mcastq;
@@ -232,6 +233,18 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
*/
curlen = skb->len;
+ info = IEEE80211_SKB_CB(skb);
+ if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
+ /*
+ * TODO: make sure the seq# gets assigned properly (vs. other
+ * TX frames)
+ */
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ sc->seq_no += 0x10;
+ hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
+ hdr->seq_ctrl |= cpu_to_le16(sc->seq_no);
+ }
+
/* XXX: spin_lock_bh should not be used here, but sparse bitches
* otherwise. We should fix sparse :) */
spin_lock_bh(&mcastq->axq_lock);
diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c
index f6c45288d0e..87e37bc3914 100644
--- a/drivers/net/wireless/ath9k/core.c
+++ b/drivers/net/wireless/ath9k/core.c
@@ -294,8 +294,6 @@ static int ath_stop(struct ath_softc *sc)
* hardware is gone (invalid).
*/
- if (!sc->sc_invalid)
- ath9k_hw_set_interrupts(ah, 0);
ath_draintxq(sc, false);
if (!sc->sc_invalid) {
ath_stoprecv(sc);
@@ -797,6 +795,12 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan)
if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT)
sc->sc_imask |= ATH9K_INT_CST;
+ /* Note: We disable MIB interrupts for now as we don't yet
+ * handle processing ANI, otherwise you will get an interrupt
+ * storm after about 7 hours of usage making the system unusable
+ * with huge latency. Once we do have ANI processing included
+ * we can re-enable this interrupt. */
+#if 0
/*
* Enable MIB interrupts when there are hardware phy counters.
* Note we only do this (at the moment) for station mode.
@@ -804,6 +808,7 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan)
if (ath9k_hw_phycounters(ah) &&
((sc->sc_opmode == ATH9K_M_STA) || (sc->sc_opmode == ATH9K_M_IBSS)))
sc->sc_imask |= ATH9K_INT_MIB;
+#endif
/*
* Some hardware processes the TIM IE and fires an
* interrupt when the TIM bit is set. For hardware
@@ -1336,6 +1341,8 @@ void ath_deinit(struct ath_softc *sc)
DPRINTF(sc, ATH_DBG_CONFIG, "%s\n", __func__);
+ tasklet_kill(&sc->intr_tq);
+ tasklet_kill(&sc->bcon_tasklet);
ath_stop(sc);
if (!sc->sc_invalid)
ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h
index 673b3d81133..2f84093331e 100644
--- a/drivers/net/wireless/ath9k/core.h
+++ b/drivers/net/wireless/ath9k/core.h
@@ -974,7 +974,6 @@ struct ath_softc {
u32 sc_keymax; /* size of key cache */
DECLARE_BITMAP(sc_keymap, ATH_KEYMAX); /* key use bit map */
u8 sc_splitmic; /* split TKIP MIC keys */
- int sc_keytype;
/* RX */
struct list_head sc_rxbuf;
@@ -992,6 +991,7 @@ struct ath_softc {
u32 sc_txintrperiod; /* tx interrupt batching */
int sc_haltype2q[ATH9K_WME_AC_VO+1]; /* HAL WME AC -> h/w qnum */
u32 sc_ant_tx[8]; /* recent tx frames/antenna */
+ u16 seq_no; /* TX sequence number */
/* Beacon */
struct ath9k_tx_queue_info sc_beacon_qi;
diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c
index a17eb130f57..6dbfed0b414 100644
--- a/drivers/net/wireless/ath9k/hw.c
+++ b/drivers/net/wireless/ath9k/hw.c
@@ -7285,15 +7285,15 @@ ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry,
}
break;
case ATH9K_CIPHER_WEP:
- if (k->kv_len < 40 / NBBY) {
+ if (k->kv_len < LEN_WEP40) {
DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
"%s: WEP key length %u too small\n",
__func__, k->kv_len);
return false;
}
- if (k->kv_len <= 40 / NBBY)
+ if (k->kv_len <= LEN_WEP40)
keyType = AR_KEYTABLE_TYPE_40;
- else if (k->kv_len <= 104 / NBBY)
+ else if (k->kv_len <= LEN_WEP104)
keyType = AR_KEYTABLE_TYPE_104;
else
keyType = AR_KEYTABLE_TYPE_128;
@@ -7313,7 +7313,7 @@ ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry,
key2 = get_unaligned_le32(k->kv_val + 6) ^ xorMask;
key3 = (get_unaligned_le16(k->kv_val + 10) ^ xorMask) & 0xffff;
key4 = get_unaligned_le32(k->kv_val + 12) ^ xorMask;
- if (k->kv_len <= 104 / NBBY)
+ if (k->kv_len <= LEN_WEP104)
key4 &= 0xff;
if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) {
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c
index 2888778040e..acebdf1d20a 100644
--- a/drivers/net/wireless/ath9k/main.c
+++ b/drivers/net/wireless/ath9k/main.c
@@ -206,7 +206,6 @@ static int ath_key_config(struct ath_softc *sc,
if (!ret)
return -EIO;
- sc->sc_keytype = hk.kv_type;
return 0;
}
@@ -368,6 +367,20 @@ static int ath9k_tx(struct ieee80211_hw *hw,
{
struct ath_softc *sc = hw->priv;
int hdrlen, padsize;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+ /*
+ * As a temporary workaround, assign seq# here; this will likely need
+ * to be cleaned up to work better with Beacon transmission and virtual
+ * BSSes.
+ */
+ if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
+ sc->seq_no += 0x10;
+ hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
+ hdr->seq_ctrl |= cpu_to_le16(sc->seq_no);
+ }
/* Add the padding after the header if this is not already done */
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
@@ -756,13 +769,13 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
key->hw_key_idx = key->keyidx;
/* push IV and Michael MIC generation to stack */
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
- key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
+ if (key->alg == ALG_TKIP)
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
}
break;
case DISABLE_KEY:
ath_key_delete(sc, key);
clear_bit(key->keyidx, sc->sc_keymap);
- sc->sc_keytype = ATH9K_CIPHER_CLR;
break;
default:
ret = -EINVAL;
@@ -1065,8 +1078,16 @@ void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
tx_status->flags &= ~ATH_TX_BAR;
}
- if (tx_status->flags)
- tx_info->status.excessive_retries = 1;
+
+ if (tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY)) {
+ if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) {
+ /* Frame was not ACKed, but an ACK was expected */
+ tx_info->status.excessive_retries = 1;
+ }
+ } else {
+ /* Frame was ACKed */
+ tx_info->flags |= IEEE80211_TX_STAT_ACK;
+ }
tx_info->status.retry_count = tx_status->retries;
@@ -1390,10 +1411,17 @@ static void ath_pci_remove(struct pci_dev *pdev)
{
struct ieee80211_hw *hw = pci_get_drvdata(pdev);
struct ath_softc *sc = hw->priv;
+ enum ath9k_int status;
- if (pdev->irq)
+ if (pdev->irq) {
+ ath9k_hw_set_interrupts(sc->sc_ah, 0);
+ /* clear the ISR */
+ ath9k_hw_getisr(sc->sc_ah, &status);
+ sc->sc_invalid = 1;
free_irq(pdev->irq, sc);
+ }
ath_detach(sc);
+
pci_iounmap(pdev, sc->mem);
pci_release_region(pdev, 0);
pci_disable_device(pdev);
diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c
index 2fe806175c0..20ddb7acdb9 100644
--- a/drivers/net/wireless/ath9k/recv.c
+++ b/drivers/net/wireless/ath9k/recv.c
@@ -360,8 +360,9 @@ static void ath_rx_flush_tid(struct ath_softc *sc,
struct ath_arx_tid *rxtid, int drop)
{
struct ath_rxbuf *rxbuf;
+ unsigned long flag;
- spin_lock_bh(&rxtid->tidlock);
+ spin_lock_irqsave(&rxtid->tidlock, flag);
while (rxtid->baw_head != rxtid->baw_tail) {
rxbuf = rxtid->rxbuf + rxtid->baw_head;
if (!rxbuf->rx_wbuf) {
@@ -382,7 +383,7 @@ static void ath_rx_flush_tid(struct ath_softc *sc,
INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
}
- spin_unlock_bh(&rxtid->tidlock);
+ spin_unlock_irqrestore(&rxtid->tidlock, flag);
}
static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc,
diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c
index 157f830ee6b..8b332e11a65 100644
--- a/drivers/net/wireless/ath9k/xmit.c
+++ b/drivers/net/wireless/ath9k/xmit.c
@@ -315,11 +315,11 @@ static int ath_tx_prepare(struct ath_softc *sc,
txctl->keyix = tx_info->control.hw_key->hw_key_idx;
txctl->frmlen += tx_info->control.icv_len;
- if (sc->sc_keytype == ATH9K_CIPHER_WEP)
+ if (tx_info->control.hw_key->alg == ALG_WEP)
txctl->keytype = ATH9K_KEY_TYPE_WEP;
- else if (sc->sc_keytype == ATH9K_CIPHER_TKIP)
+ else if (tx_info->control.hw_key->alg == ALG_TKIP)
txctl->keytype = ATH9K_KEY_TYPE_TKIP;
- else if (sc->sc_keytype == ATH9K_CIPHER_AES_CCM)
+ else if (tx_info->control.hw_key->alg == ALG_CCMP)
txctl->keytype = ATH9K_KEY_TYPE_AES;
}
@@ -357,9 +357,9 @@ static int ath_tx_prepare(struct ath_softc *sc,
txctl->flags = ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */
if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
- tx_info->flags |= ATH9K_TXDESC_NOACK;
+ txctl->flags |= ATH9K_TXDESC_NOACK;
if (tx_info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
- tx_info->flags |= ATH9K_TXDESC_RTSENA;
+ txctl->flags |= ATH9K_TXDESC_RTSENA;
/*
* Setup for rate calculations.
diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c
index fec5645944a..34ae125d538 100644
--- a/drivers/net/wireless/b43/rfkill.c
+++ b/drivers/net/wireless/b43/rfkill.c
@@ -43,23 +43,6 @@ static bool b43_is_hw_radio_enabled(struct b43_wldev *dev)
return 0;
}
-/* Update the rfkill state */
-static void b43_rfkill_update_state(struct b43_wldev *dev)
-{
- struct b43_rfkill *rfk = &(dev->wl->rfkill);
-
- if (!dev->radio_hw_enable) {
- rfk->rfkill->state = RFKILL_STATE_HARD_BLOCKED;
- return;
- }
-
- if (!dev->phy.radio_on)
- rfk->rfkill->state = RFKILL_STATE_SOFT_BLOCKED;
- else
- rfk->rfkill->state = RFKILL_STATE_UNBLOCKED;
-
-}
-
/* The poll callback for the hardware button. */
static void b43_rfkill_poll(struct input_polled_dev *poll_dev)
{
@@ -77,7 +60,6 @@ static void b43_rfkill_poll(struct input_polled_dev *poll_dev)
if (unlikely(enabled != dev->radio_hw_enable)) {
dev->radio_hw_enable = enabled;
report_change = 1;
- b43_rfkill_update_state(dev);
b43info(wl, "Radio hardware status changed to %s\n",
enabled ? "ENABLED" : "DISABLED");
}
diff --git a/drivers/net/wireless/b43legacy/rfkill.c b/drivers/net/wireless/b43legacy/rfkill.c
index 476add97e97..b32bf6a94f1 100644
--- a/drivers/net/wireless/b43legacy/rfkill.c
+++ b/drivers/net/wireless/b43legacy/rfkill.c
@@ -44,23 +44,6 @@ static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev)
return 0;
}
-/* Update the rfkill state */
-static void b43legacy_rfkill_update_state(struct b43legacy_wldev *dev)
-{
- struct b43legacy_rfkill *rfk = &(dev->wl->rfkill);
-
- if (!dev->radio_hw_enable) {
- rfk->rfkill->state = RFKILL_STATE_HARD_BLOCKED;
- return;
- }
-
- if (!dev->phy.radio_on)
- rfk->rfkill->state = RFKILL_STATE_SOFT_BLOCKED;
- else
- rfk->rfkill->state = RFKILL_STATE_UNBLOCKED;
-
-}
-
/* The poll callback for the hardware button. */
static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev)
{
@@ -78,7 +61,6 @@ static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev)
if (unlikely(enabled != dev->radio_hw_enable)) {
dev->radio_hw_enable = enabled;
report_change = 1;
- b43legacy_rfkill_update_state(dev);
b43legacyinfo(wl, "Radio hardware status changed to %s\n",
enabled ? "ENABLED" : "DISABLED");
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index e2581229d8b..23fed329896 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -474,8 +474,8 @@ static void iwl4965_apm_stop(struct iwl_priv *priv)
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);
+ /* clear "init complete" move adapter D0A* --> D0U state */
+ iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
spin_unlock_irqrestore(&priv->lock, flags);
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index cbc01a00eaf..b08036a9d89 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -145,7 +145,8 @@ static void iwl5000_apm_stop(struct iwl_priv *priv)
udelay(10);
- iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+ /* clear "init complete" move adapter D0A* --> D0U state */
+ iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
spin_unlock_irqrestore(&priv->lock, flags);
}
@@ -577,14 +578,11 @@ static int iwl5000_load_section(struct iwl_priv *priv,
FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL),
phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK);
- /* FIME: write the MSB of the phy_addr in CTRL1
- * iwl_write_direct32(priv,
- IWL_FH_TFDIB_CTRL1_REG(IWL_FH_SRVC_CHNL),
- ((phy_addr & MSB_MSK)
- << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_count);
- */
iwl_write_direct32(priv,
- FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL), byte_cnt);
+ FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL),
+ (iwl_get_dma_hi_address(phy_addr)
+ << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt);
+
iwl_write_direct32(priv,
FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL),
1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
index 754fef5b592..90a2b6dee7c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
@@ -1153,7 +1153,8 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv,
!sta->ht_info.ht_supported)
return -1;
- if (priv->current_ht_config.tx_mimo_ps_mode == IWL_MIMO_PS_STATIC)
+ if (((sta->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS) >> 2)
+ == IWL_MIMO_PS_STATIC)
return -1;
/* Need both Tx chains/antennas to support MIMO */
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 061ffba9c88..e01f048a02d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -181,14 +181,14 @@ static int iwl4965_check_rxon_cmd(struct iwl_rxon_cmd *rxon)
}
/**
- * iwl4965_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed
+ * iwl_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed
* @priv: staging_rxon is compared to active_rxon
*
* If the RXON structure is changing enough to require a new tune,
* or is clearing the RXON_FILTER_ASSOC_MSK, then return 1 to indicate that
* a new tune (full RXON command, rather than RXON_ASSOC cmd) is required.
*/
-static int iwl4965_full_rxon_required(struct iwl_priv *priv)
+static int iwl_full_rxon_required(struct iwl_priv *priv)
{
/* These items are only settable from the full RXON command */
@@ -207,7 +207,6 @@ static int iwl4965_full_rxon_required(struct iwl_priv *priv)
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;
@@ -263,7 +262,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
/* If we don't need to send a full RXON, we can use
* iwl4965_rxon_assoc_cmd which is used to reconfigure filter
* and other flags for the current radio configuration. */
- if (!iwl4965_full_rxon_required(priv)) {
+ if (!iwl_full_rxon_required(priv)) {
ret = iwl_send_rxon_assoc(priv);
if (ret) {
IWL_ERROR("Error setting RXON_ASSOC (%d)\n", ret);
@@ -587,8 +586,6 @@ static void iwl4965_ht_conf(struct iwl_priv *priv,
iwl_conf->supported_chan_width = 0;
}
- iwl_conf->tx_mimo_ps_mode =
- (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2);
memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16);
iwl_conf->control_channel = ht_bss_conf->primary_channel;
@@ -2190,7 +2187,10 @@ static void __iwl4965_down(struct iwl_priv *priv)
udelay(5);
/* FIXME: apm_ops.suspend(priv) */
- priv->cfg->ops->lib->apm_ops.reset(priv);
+ if (exit_pending || test_bit(STATUS_IN_SUSPEND, &priv->status))
+ priv->cfg->ops->lib->apm_ops.stop(priv);
+ else
+ priv->cfg->ops->lib->apm_ops.reset(priv);
priv->cfg->ops->lib->free_shared_mem(priv);
exit:
@@ -2602,6 +2602,7 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw)
{
struct iwl_priv *priv = hw->priv;
int ret;
+ u16 pci_cmd;
IWL_DEBUG_MAC80211("enter\n");
@@ -2612,6 +2613,13 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw)
pci_restore_state(priv->pci_dev);
pci_enable_msi(priv->pci_dev);
+ /* enable interrupts if needed: hw bug w/a */
+ pci_read_config_word(priv->pci_dev, PCI_COMMAND, &pci_cmd);
+ if (pci_cmd & PCI_COMMAND_INTX_DISABLE) {
+ pci_cmd &= ~PCI_COMMAND_INTX_DISABLE;
+ pci_write_config_word(priv->pci_dev, PCI_COMMAND, pci_cmd);
+ }
+
ret = request_irq(priv->pci_dev->irq, iwl4965_isr, IRQF_SHARED,
DRV_NAME, priv);
if (ret) {
@@ -3580,7 +3588,7 @@ static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk
priv->assoc_id = 0;
timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
- priv->timestamp = le64_to_cpu(timestamp) + (priv->beacon_int * 1000);
+ priv->timestamp = le64_to_cpu(timestamp);
IWL_DEBUG_MAC80211("leave\n");
spin_unlock_irqrestore(&priv->lock, flags);
@@ -4364,15 +4372,18 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev)
iwl_dbgfs_unregister(priv);
sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group);
+ /* ieee80211_unregister_hw call wil cause iwl4965_mac_stop to
+ * to be called and iwl4965_down since we are removing the device
+ * we need to set STATUS_EXIT_PENDING bit.
+ */
+ set_bit(STATUS_EXIT_PENDING, &priv->status);
if (priv->mac80211_registered) {
ieee80211_unregister_hw(priv->hw);
priv->mac80211_registered = 0;
+ } else {
+ iwl4965_down(priv);
}
- set_bit(STATUS_EXIT_PENDING, &priv->status);
-
- iwl4965_down(priv);
-
/* make sure we flush any pending irq or
* tasklet for the driver
*/
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index c72f72579be..80f2f84defa 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -592,12 +592,11 @@ static void iwlcore_free_geos(struct iwl_priv *priv)
clear_bit(STATUS_GEO_CONFIGURED, &priv->status);
}
-static u8 is_single_rx_stream(struct iwl_priv *priv)
+static bool is_single_rx_stream(struct iwl_priv *priv)
{
return !priv->current_ht_config.is_ht ||
((priv->current_ht_config.supp_mcs_set[1] == 0) &&
- (priv->current_ht_config.supp_mcs_set[2] == 0)) ||
- priv->ps_mode == IWL_MIMO_PS_STATIC;
+ (priv->current_ht_config.supp_mcs_set[2] == 0));
}
static u8 iwl_is_channel_extension(struct iwl_priv *priv,
@@ -704,33 +703,39 @@ EXPORT_SYMBOL(iwl_set_rxon_ht);
* 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 iwlcore_get_rx_chain_counter(struct iwl_priv *priv,
- u8 *idle_state, u8 *rx_state)
+static int iwl_get_active_rx_chain_count(struct iwl_priv *priv)
{
- u8 is_single = is_single_rx_stream(priv);
- u8 is_cam = test_bit(STATUS_POWER_PMI, &priv->status) ? 0 : 1;
+ bool is_single = is_single_rx_stream(priv);
+ bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
/* # of Rx chains to use when expecting MIMO. */
if (is_single || (!is_cam && (priv->ps_mode == IWL_MIMO_PS_STATIC)))
- *rx_state = 2;
+ return 2;
else
- *rx_state = 3;
+ return 3;
+}
+static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt)
+{
+ int idle_cnt;
+ bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
/* # 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;
+ idle_cnt = (is_cam) ? 2 : 1;
break;
case IWL_MIMO_PS_NONE:
- *idle_state = (is_cam) ? *rx_state : 1;
+ idle_cnt = (is_cam) ? active_cnt : 1;
break;
+ case IWL_MIMO_PS_INVALID:
default:
- *idle_state = 1;
+ IWL_ERROR("invalide mimo ps mode %d\n", priv->ps_mode);
+ WARN_ON(1);
+ idle_cnt = -1;
break;
}
-
- return 0;
+ return idle_cnt;
}
/**
@@ -741,34 +746,44 @@ static int iwlcore_get_rx_chain_counter(struct iwl_priv *priv,
*/
void iwl_set_rxon_chain(struct iwl_priv *priv)
{
- u8 is_single = is_single_rx_stream(priv);
- u8 idle_state, rx_state;
-
- priv->staging_rxon.rx_chain = 0;
- rx_state = idle_state = 3;
+ bool is_single = is_single_rx_stream(priv);
+ bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
+ u8 idle_rx_cnt, active_rx_cnt;
+ u16 rx_chain;
/* Tell uCode which antennas are actually connected.
* Before first association, we assume all antennas are connected.
* Just after first association, iwl_chain_noise_calibration()
* checks which antennas actually *are* connected. */
- priv->staging_rxon.rx_chain |=
- cpu_to_le16(priv->hw_params.valid_rx_ant <<
- RXON_RX_CHAIN_VALID_POS);
+ rx_chain = priv->hw_params.valid_rx_ant << RXON_RX_CHAIN_VALID_POS;
/* How many receivers should we use? */
- iwlcore_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))
+ active_rx_cnt = iwl_get_active_rx_chain_count(priv);
+ idle_rx_cnt = iwl_get_idle_rx_chain_count(priv, active_rx_cnt);
+
+ /* correct rx chain count accoridng hw settings */
+ if (priv->hw_params.rx_chains_num < active_rx_cnt)
+ active_rx_cnt = priv->hw_params.rx_chains_num;
+
+ if (priv->hw_params.rx_chains_num < idle_rx_cnt)
+ idle_rx_cnt = priv->hw_params.rx_chains_num;
+
+ rx_chain |= active_rx_cnt << RXON_RX_CHAIN_MIMO_CNT_POS;
+ rx_chain |= idle_rx_cnt << RXON_RX_CHAIN_CNT_POS;
+
+ priv->staging_rxon.rx_chain = cpu_to_le16(rx_chain);
+
+ if (!is_single && (active_rx_cnt >= 2) && is_cam)
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);
+ IWL_DEBUG_ASSOC("rx_chain=0x%Xi active=%d idle=%d\n",
+ priv->staging_rxon.rx_chain,
+ active_rx_cnt, idle_rx_cnt);
+
+ WARN_ON(active_rx_cnt == 0 || idle_rx_cnt == 0 ||
+ active_rx_cnt < idle_rx_cnt);
}
EXPORT_SYMBOL(iwl_set_rxon_chain);
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index c19db438306..cdfb343c7ec 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -412,7 +412,6 @@ struct iwl_ht_info {
/* self configuration data */
u8 is_ht;
u8 supported_chan_width;
- u16 tx_mimo_ps_mode;
u8 is_green_field;
u8 sgf; /* HT_SHORT_GI_* short guard interval */
u8 max_amsdu_size;
diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h
index 944642450d3..cd11c0ca299 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fh.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fh.h
@@ -287,6 +287,7 @@
#define FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE (0x01000000)
+#define FH_MEM_TFDIB_REG1_ADDR_BITSHIFT 28
/**
* Transmit DMA Channel Control/Status Registers (TCSR)
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index f3f6ea49fdd..e81bfc42a7c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -1173,7 +1173,10 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
rx_status.antenna = 0;
rx_status.flag = 0;
- rx_status.flag |= RX_FLAG_TSFT;
+
+ /* TSF isn't reliable. In order to allow smooth user experience,
+ * this W/A doesn't propagate it to the mac80211 */
+ /*rx_status.flag |= RX_FLAG_TSFT;*/
if ((unlikely(rx_start->cfg_phy_cnt > 20))) {
IWL_DEBUG_DROP("dsp size out of range [0,20]: %d/n",
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index 9bb6adb28b7..6c8ac3a87d5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -421,7 +421,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
else
scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE;
- if ((scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) && n_probes)
+ if (n_probes)
scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes);
scan_ch->active_dwell = cpu_to_le16(active_dwell);
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index d82823b5c8a..78b1a7a4ca4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -402,12 +402,11 @@ static int iwl_hw_tx_queue_init(struct iwl_priv *priv,
/**
* iwl_tx_queue_init - Allocate and initialize one tx/cmd queue
*/
-static int iwl_tx_queue_init(struct iwl_priv *priv,
- struct iwl_tx_queue *txq,
+static int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
int slots_num, u32 txq_id)
{
int i, len;
- int rc = 0;
+ int ret;
/*
* Alloc buffer array for commands (Tx or other types of commands).
@@ -426,19 +425,16 @@ static int iwl_tx_queue_init(struct iwl_priv *priv,
continue;
}
- txq->cmd[i] = kmalloc(len, GFP_KERNEL | GFP_DMA);
+ txq->cmd[i] = kmalloc(len, GFP_KERNEL);
if (!txq->cmd[i])
- return -ENOMEM;
+ goto err;
}
/* Alloc driver data array and TFD circular buffer */
- rc = iwl_tx_queue_alloc(priv, txq, txq_id);
- if (rc) {
- for (i = 0; i < slots_num; i++)
- kfree(txq->cmd[i]);
+ ret = iwl_tx_queue_alloc(priv, txq, txq_id);
+ if (ret)
+ goto err;
- return -ENOMEM;
- }
txq->need_update = 0;
/* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
@@ -452,6 +448,17 @@ static int iwl_tx_queue_init(struct iwl_priv *priv,
iwl_hw_tx_queue_init(priv, txq);
return 0;
+err:
+ for (i = 0; i < slots_num; i++) {
+ kfree(txq->cmd[i]);
+ txq->cmd[i] = NULL;
+ }
+
+ if (txq_id == IWL_CMD_QUEUE_NUM) {
+ kfree(txq->cmd[slots_num]);
+ txq->cmd[slots_num] = NULL;
+ }
+ return -ENOMEM;
}
/**
* iwl_hw_txq_ctx_free - Free TXQ Context
diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
index 04d7a251e3f..8941919001b 100644
--- a/drivers/net/wireless/libertas/if_cs.c
+++ b/drivers/net/wireless/libertas/if_cs.c
@@ -595,7 +595,7 @@ static int if_cs_prog_helper(struct if_cs_card *card)
if (ret < 0) {
lbs_pr_err("can't download helper at 0x%x, ret %d\n",
sent, ret);
- goto done;
+ goto err_release;
}
if (count == 0)
@@ -604,9 +604,8 @@ static int if_cs_prog_helper(struct if_cs_card *card)
sent += count;
}
+err_release:
release_firmware(fw);
- ret = 0;
-
done:
lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
return ret;
@@ -676,14 +675,8 @@ static int if_cs_prog_real(struct if_cs_card *card)
}
ret = if_cs_poll_while_fw_download(card, IF_CS_SCRATCH, 0x5a);
- if (ret < 0) {
+ if (ret < 0)
lbs_pr_err("firmware download failed\n");
- goto err_release;
- }
-
- ret = 0;
- goto done;
-
err_release:
release_firmware(fw);
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
index 1ebcafe7ca5..36c004e1560 100644
--- a/drivers/net/wireless/orinoco.c
+++ b/drivers/net/wireless/orinoco.c
@@ -1970,6 +1970,9 @@ __orinoco_set_multicast_list(struct net_device *dev)
priv->promiscuous = promisc;
}
+ /* If we're not in promiscuous mode, then we need to set the
+ * group address if either we want to multicast, or if we were
+ * multicasting and want to stop */
if (! promisc && (mc_count || priv->mc_count) ) {
struct dev_mc_list *p = dev->mc_list;
struct hermes_multicast mclist;
@@ -1989,9 +1992,10 @@ __orinoco_set_multicast_list(struct net_device *dev)
printk(KERN_WARNING "%s: Multicast list is "
"longer than mc_count\n", dev->name);
- err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFGROUPADDRESSES,
- HERMES_BYTES_TO_RECLEN(priv->mc_count * ETH_ALEN),
- &mclist);
+ err = hermes_write_ltv(hw, USER_BAP,
+ HERMES_RID_CNFGROUPADDRESSES,
+ HERMES_BYTES_TO_RECLEN(mc_count * ETH_ALEN),
+ &mclist);
if (err)
printk(KERN_ERR "%s: Error %d setting multicast list.\n",
dev->name, err);
diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h
index 7e88ce5651b..2ea7866abd5 100644
--- a/drivers/net/wireless/rt2x00/rt2x00reg.h
+++ b/drivers/net/wireless/rt2x00/rt2x00reg.h
@@ -136,7 +136,7 @@ struct rt2x00_field32 {
*/
#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 is_valid_mask(x) is_power_of_two(1LU + (x) + low_bit_mask(x))
/*
* Macro's to find first set bit in a variable.
@@ -173,8 +173,7 @@ struct rt2x00_field32 {
* does not exceed the given typelimit.
*/
#define FIELD_CHECK(__mask, __type) \
- BUILD_BUG_ON(!__builtin_constant_p(__mask) || \
- !(__mask) || \
+ BUILD_BUG_ON(!(__mask) || \
!is_valid_mask(__mask) || \
(__mask) != (__type)(__mask)) \
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index da8b7433e3a..a60ae86bd5c 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -58,6 +58,7 @@ static struct usb_device_id usb_ids[] = {
{ USB_DEVICE(0x0586, 0x3407), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x129b, 0x1666), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x157e, 0x300a), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x0105, 0x145f), .driver_info = DEVICE_ZD1211 },
/* ZD1211B */
{ USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c
index 40337a06c18..146ca9cd156 100644
--- a/drivers/pci/hotplug/fakephp.c
+++ b/drivers/pci/hotplug/fakephp.c
@@ -320,15 +320,15 @@ static int disable_slot(struct hotplug_slot *slot)
return -ENODEV;
}
+ /* remove the device from the pci core */
+ pci_remove_bus_device(dev);
+
/* queue work item to blow away this sysfs entry and other
* parts.
*/
INIT_WORK(&dslot->remove_work, remove_slot_worker);
queue_work(dummyphp_wq, &dslot->remove_work);
- /* blow away this sysfs entry and other parts. */
- remove_slot(dslot);
-
pci_dev_put(dev);
}
return 0;
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index ab31f5ba665..9d934ddee95 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -258,7 +258,7 @@ static int pcie_poll_cmd(struct controller *ctrl)
return 1;
}
}
- while (timeout > 1000) {
+ while (timeout > 0) {
msleep(10);
timeout -= 10;
if (!pciehp_readw(ctrl, SLOTSTATUS, &slot_status)) {
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c
index 8d0e60ac849..c3edcdc08e7 100644
--- a/drivers/pci/intel-iommu.c
+++ b/drivers/pci/intel-iommu.c
@@ -2348,11 +2348,34 @@ static void __init iommu_exit_mempool(void)
}
+static int blacklist_iommu(const struct dmi_system_id *id)
+{
+ printk(KERN_INFO "%s detected; disabling IOMMU\n",
+ id->ident);
+ dmar_disabled = 1;
+ return 0;
+}
+
+static struct dmi_system_id __initdata intel_iommu_dmi_table[] = {
+ { /* Some DG33BU BIOS revisions advertised non-existent VT-d */
+ .callback = blacklist_iommu,
+ .ident = "Intel DG33BU",
+ { DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
+ DMI_MATCH(DMI_BOARD_NAME, "DG33BU"),
+ }
+ },
+ { }
+};
+
+
void __init detect_intel_iommu(void)
{
if (swiotlb || no_iommu || iommu_detected || dmar_disabled)
return;
if (early_dmar_detect()) {
+ dmi_check_system(intel_iommu_dmi_table);
+ if (dmar_disabled)
+ return;
iommu_detected = 1;
}
}
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 9c718583a23..77baff022f7 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -16,6 +16,7 @@
#include <linux/kernel.h>
+#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/stat.h>
#include <linux/topology.h>
@@ -484,6 +485,21 @@ pci_mmap_legacy_mem(struct kobject *kobj, struct bin_attribute *attr,
#endif /* HAVE_PCI_LEGACY */
#ifdef HAVE_PCI_MMAP
+
+static int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vma)
+{
+ unsigned long nr, start, size;
+
+ nr = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+ start = vma->vm_pgoff;
+ size = pci_resource_len(pdev, resno) >> PAGE_SHIFT;
+ if (start < size && size - start >= nr)
+ return 1;
+ WARN(1, "process \"%s\" tried to map 0x%08lx-0x%08lx on %s BAR %d (size 0x%08lx)\n",
+ current->comm, start, start+nr, pci_name(pdev), resno, size);
+ return 0;
+}
+
/**
* pci_mmap_resource - map a PCI resource into user memory space
* @kobj: kobject for mapping
@@ -510,6 +526,9 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
if (i >= PCI_ROM_RESOURCE)
return -ENODEV;
+ if (!pci_mmap_fits(pdev, i, vma))
+ return -EINVAL;
+
/* pci_mmap_page_range() expects the same kind of entry as coming
* from /proc/bus/pci/ which is a "user visible" value. If this is
* different from the resource itself, arch will do necessary fixup.
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 9a7c9e1408a..851f5b83cdb 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -527,7 +527,7 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev)
*/
pci_read_config_dword(child_dev, child_pos + PCI_EXP_DEVCAP,
&reg32);
- if (!(reg32 & PCI_EXP_DEVCAP_RBER && !aspm_force)) {
+ if (!(reg32 & PCI_EXP_DEVCAP_RBER) && !aspm_force) {
printk("Pre-1.1 PCIe device detected, "
"disable ASPM for %s. It can be enabled forcedly"
" with 'pcie_aspm=force'\n", pci_name(pdev));
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index cce2f4cb1fb..36698e57b97 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -304,6 +304,9 @@ static int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
} else {
res->start = l64;
res->end = l64 + sz64;
+ printk(KERN_DEBUG "PCI: %s reg %x 64bit mmio: [%llx, %llx]\n",
+ pci_name(dev), pos, (unsigned long long)res->start,
+ (unsigned long long)res->end);
}
} else {
sz = pci_size(l, sz, mask);
@@ -313,6 +316,9 @@ static int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
res->start = l;
res->end = l + sz;
+ printk(KERN_DEBUG "PCI: %s reg %x %s: [%llx, %llx]\n", pci_name(dev),
+ pos, (res->flags & IORESOURCE_IO) ? "io port":"32bit mmio",
+ (unsigned long long)res->start, (unsigned long long)res->end);
}
out:
@@ -383,7 +389,9 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
res->start = base;
if (!res->end)
res->end = limit + 0xfff;
- printk(KERN_INFO "PCI: bridge %s io port: [%llx, %llx]\n", pci_name(dev), res->start, res->end);
+ printk(KERN_DEBUG "PCI: bridge %s io port: [%llx, %llx]\n",
+ pci_name(dev), (unsigned long long) res->start,
+ (unsigned long long) res->end);
}
res = child->resource[1];
@@ -395,7 +403,9 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM;
res->start = base;
res->end = limit + 0xfffff;
- printk(KERN_INFO "PCI: bridge %s 32bit mmio: [%llx, %llx]\n", pci_name(dev), res->start, res->end);
+ printk(KERN_DEBUG "PCI: bridge %s 32bit mmio: [%llx, %llx]\n",
+ pci_name(dev), (unsigned long long) res->start,
+ (unsigned long long) res->end);
}
res = child->resource[2];
@@ -431,7 +441,9 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM | IORESOURCE_PREFETCH;
res->start = base;
res->end = limit + 0xfffff;
- printk(KERN_INFO "PCI: bridge %s %sbit mmio pref: [%llx, %llx]\n", pci_name(dev), (res->flags & PCI_PREF_RANGE_TYPE_64)?"64":"32",res->start, res->end);
+ printk(KERN_DEBUG "PCI: bridge %s %sbit mmio pref: [%llx, %llx]\n",
+ pci_name(dev), (res->flags & PCI_PREF_RANGE_TYPE_64) ? "64" : "32",
+ (unsigned long long) res->start, (unsigned long long) res->end);
}
}
diff --git a/drivers/pci/search.c b/drivers/pci/search.c
index 3b3b5f17879..4edfc4731bd 100644
--- a/drivers/pci/search.c
+++ b/drivers/pci/search.c
@@ -162,7 +162,7 @@ EXPORT_SYMBOL(pci_find_slot);
* time.
*/
struct pci_dev *pci_find_device(unsigned int vendor, unsigned int device,
- const struct pci_dev *from)
+ struct pci_dev *from)
{
struct pci_dev *pdev;
@@ -263,7 +263,7 @@ static int match_pci_dev_by_id(struct device *dev, void *data)
* this file.
*/
static struct pci_dev *pci_get_dev_by_id(const struct pci_device_id *id,
- const struct pci_dev *from)
+ struct pci_dev *from)
{
struct device *dev;
struct device *dev_start = NULL;
@@ -303,7 +303,7 @@ static struct pci_dev *pci_get_dev_by_id(const struct pci_device_id *id,
*/
struct pci_dev *pci_get_subsys(unsigned int vendor, unsigned int device,
unsigned int ss_vendor, unsigned int ss_device,
- const struct pci_dev *from)
+ struct pci_dev *from)
{
struct pci_dev *pdev;
struct pci_device_id *id;
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 82634a2f1b1..3abbfad9dda 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -352,11 +352,12 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long
continue;
r_size = r->end - r->start + 1;
/* For bridges size != alignment */
- align = (i < PCI_BRIDGE_RESOURCES) ? r_size : r->start;
+ align = resource_alignment(r);
order = __ffs(align) - 20;
if (order > 11) {
- dev_warn(&dev->dev, "BAR %d too large: "
+ dev_warn(&dev->dev, "BAR %d bad alignment %llx: "
"%#016llx-%#016llx\n", i,
+ (unsigned long long)align,
(unsigned long long)r->start,
(unsigned long long)r->end);
r->flags = 0;
@@ -539,7 +540,11 @@ static void pci_bus_dump_res(struct pci_bus *bus)
if (!res)
continue;
- printk(KERN_INFO "bus: %02x index %x %s: [%llx, %llx]\n", bus->number, i, (res->flags & IORESOURCE_IO)? "io port":"mmio", res->start, res->end);
+ printk(KERN_INFO "bus: %02x index %x %s: [%llx, %llx]\n",
+ bus->number, i,
+ (res->flags & IORESOURCE_IO) ? "io port" : "mmio",
+ (unsigned long long) res->start,
+ (unsigned long long) res->end);
}
}
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 4174d9656e3..34c83d3ca0f 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -427,6 +427,18 @@ static int pcmcia_device_probe(struct device * dev)
p_drv = to_pcmcia_drv(dev->driver);
s = p_dev->socket;
+ /* The PCMCIA code passes the match data in via dev->driver_data
+ * which is an ugly hack. Once the driver probe is called it may
+ * and often will overwrite the match data so we must save it first
+ *
+ * handle pseudo multifunction devices:
+ * there are at most two pseudo multifunction devices.
+ * if we're matching against the first, schedule a
+ * call which will then check whether there are two
+ * pseudo devices, and if not, add the second one.
+ */
+ did = p_dev->dev.driver_data;
+
ds_dbg(1, "trying to bind %s to %s\n", p_dev->dev.bus_id,
p_drv->drv.name);
@@ -455,21 +467,14 @@ static int pcmcia_device_probe(struct device * dev)
goto put_module;
}
- /* handle pseudo multifunction devices:
- * there are at most two pseudo multifunction devices.
- * if we're matching against the first, schedule a
- * call which will then check whether there are two
- * pseudo devices, and if not, add the second one.
- */
- did = p_dev->dev.driver_data;
if (did && (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) &&
(p_dev->socket->device_count == 1) && (p_dev->device_no == 0))
pcmcia_add_device_later(p_dev->socket, 0);
- put_module:
+put_module:
if (ret)
module_put(p_drv->owner);
- put_dev:
+put_dev:
if (ret)
put_device(dev);
return (ret);
diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c
index c48f3f69bda..da397215322 100644
--- a/drivers/pcmcia/soc_common.c
+++ b/drivers/pcmcia/soc_common.c
@@ -748,7 +748,9 @@ int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops
add_timer(&skt->poll_timer);
- device_create_file(&skt->socket.dev, &dev_attr_status);
+ ret = device_create_file(&skt->socket.dev, &dev_attr_status);
+ if (ret)
+ goto out_err_8;
}
dev_set_drvdata(dev, sinfo);
@@ -758,6 +760,8 @@ int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops
do {
skt = &sinfo->skt[i];
+ device_remove_file(&skt->socket.dev, &dev_attr_status);
+ out_err_8:
del_timer_sync(&skt->poll_timer);
pcmcia_unregister_socket(&skt->socket);
diff --git a/drivers/pnp/Makefile b/drivers/pnp/Makefile
index 26f5abc9c3f..e83f34f1b5b 100644
--- a/drivers/pnp/Makefile
+++ b/drivers/pnp/Makefile
@@ -2,12 +2,15 @@
# Makefile for the Linux Plug-and-Play Support.
#
-obj-y := core.o card.o driver.o resource.o manager.o support.o interface.o quirks.o system.o
+obj-y := core.o card.o driver.o resource.o manager.o support.o interface.o quirks.o
obj-$(CONFIG_PNPACPI) += pnpacpi/
obj-$(CONFIG_PNPBIOS) += pnpbios/
obj-$(CONFIG_ISAPNP) += isapnp/
+# pnp_system_init goes after pnpacpi/pnpbios init
+obj-y += system.o
+
ifeq ($(CONFIG_PNP_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
endif
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index c1b9ea34977..53561d72b4e 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -268,7 +268,7 @@ static int __init pnpacpi_init(void)
return 0;
}
-subsys_initcall(pnpacpi_init);
+fs_initcall(pnpacpi_init);
static int __init pnpacpi_setup(char *str)
{
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c
index d7e9f2152df..95015cbfd33 100644
--- a/drivers/pnp/pnpacpi/rsparser.c
+++ b/drivers/pnp/pnpacpi/rsparser.c
@@ -405,8 +405,6 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
extended_irq = &res->data.extended_irq;
- if (extended_irq->producer_consumer == ACPI_PRODUCER)
- return AE_OK;
if (extended_irq->interrupt_count == 0)
pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED);
diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c
index 19a4be1a9a3..662dfcddedc 100644
--- a/drivers/pnp/pnpbios/core.c
+++ b/drivers/pnp/pnpbios/core.c
@@ -571,7 +571,7 @@ static int __init pnpbios_init(void)
return 0;
}
-subsys_initcall(pnpbios_init);
+fs_initcall(pnpbios_init);
static int __init pnpbios_thread_init(void)
{
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index 6ea349aba3b..b184367637d 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -800,7 +800,6 @@ static void __exit cmos_do_remove(struct device *dev)
static int cmos_suspend(struct device *dev, pm_message_t mesg)
{
struct cmos_rtc *cmos = dev_get_drvdata(dev);
- int do_wake = device_may_wakeup(dev);
unsigned char tmp;
/* only the alarm might be a wakeup event source */
@@ -809,7 +808,7 @@ static int cmos_suspend(struct device *dev, pm_message_t mesg)
if (tmp & (RTC_PIE|RTC_AIE|RTC_UIE)) {
unsigned char mask;
- if (do_wake)
+ if (device_may_wakeup(dev))
mask = RTC_IRQMASK & ~RTC_AIE;
else
mask = RTC_IRQMASK;
@@ -837,6 +836,17 @@ static int cmos_suspend(struct device *dev, pm_message_t mesg)
return 0;
}
+/* We want RTC alarms to wake us from e.g. ACPI G2/S5 "soft off", even
+ * after a detour through G3 "mechanical off", although the ACPI spec
+ * says wakeup should only work from G1/S4 "hibernate". To most users,
+ * distinctions between S4 and S5 are pointless. So when the hardware
+ * allows, don't draw that distinction.
+ */
+static inline int cmos_poweroff(struct device *dev)
+{
+ return cmos_suspend(dev, PMSG_HIBERNATE);
+}
+
static int cmos_resume(struct device *dev)
{
struct cmos_rtc *cmos = dev_get_drvdata(dev);
@@ -884,6 +894,12 @@ static int cmos_resume(struct device *dev)
#else
#define cmos_suspend NULL
#define cmos_resume NULL
+
+static inline int cmos_poweroff(struct device *dev)
+{
+ return -ENOSYS;
+}
+
#endif
/*----------------------------------------------------------------*/
@@ -903,10 +919,6 @@ static int cmos_resume(struct device *dev)
static int __devinit
cmos_pnp_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
{
- /* REVISIT paranoia argues for a shutdown notifier, since PNP
- * drivers can't provide shutdown() methods to disable IRQs.
- * Or better yet, fix PNP to allow those methods...
- */
if (pnp_port_start(pnp,0) == 0x70 && !pnp_irq_valid(pnp,0))
/* Some machines contain a PNP entry for the RTC, but
* don't define the IRQ. It should always be safe to
@@ -942,6 +954,13 @@ static int cmos_pnp_resume(struct pnp_dev *pnp)
#define cmos_pnp_resume NULL
#endif
+static void cmos_pnp_shutdown(struct device *pdev)
+{
+ if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(pdev))
+ return;
+
+ cmos_do_shutdown();
+}
static const struct pnp_device_id rtc_ids[] = {
{ .id = "PNP0b00", },
@@ -961,6 +980,10 @@ static struct pnp_driver cmos_pnp_driver = {
.flags = PNP_DRIVER_RES_DO_NOT_CHANGE,
.suspend = cmos_pnp_suspend,
.resume = cmos_pnp_resume,
+ .driver = {
+ .name = (char *)driver_name,
+ .shutdown = cmos_pnp_shutdown,
+ }
};
#endif /* CONFIG_PNP */
@@ -986,6 +1009,9 @@ static int __exit cmos_platform_remove(struct platform_device *pdev)
static void cmos_platform_shutdown(struct platform_device *pdev)
{
+ if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(&pdev->dev))
+ return;
+
cmos_do_shutdown();
}
diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c
index f118252f3a9..52e2743b04e 100644
--- a/drivers/rtc/rtc-dev.c
+++ b/drivers/rtc/rtc-dev.c
@@ -422,6 +422,12 @@ done:
return err;
}
+static int rtc_dev_fasync(int fd, struct file *file, int on)
+{
+ struct rtc_device *rtc = file->private_data;
+ return fasync_helper(fd, file, on, &rtc->async_queue);
+}
+
static int rtc_dev_release(struct inode *inode, struct file *file)
{
struct rtc_device *rtc = file->private_data;
@@ -434,16 +440,13 @@ static int rtc_dev_release(struct inode *inode, struct file *file)
if (rtc->ops->release)
rtc->ops->release(rtc->dev.parent);
+ if (file->f_flags & FASYNC)
+ rtc_dev_fasync(-1, file, 0);
+
clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags);
return 0;
}
-static int rtc_dev_fasync(int fd, struct file *file, int on)
-{
- struct rtc_device *rtc = file->private_data;
- return fasync_helper(fd, file, on, &rtc->async_queue);
-}
-
static const struct file_operations rtc_dev_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c
index 9f996ec881c..dd70bf73ce9 100644
--- a/drivers/rtc/rtc-lib.c
+++ b/drivers/rtc/rtc-lib.c
@@ -51,10 +51,11 @@ EXPORT_SYMBOL(rtc_year_days);
*/
void rtc_time_to_tm(unsigned long time, struct rtc_time *tm)
{
- unsigned int days, month, year;
+ unsigned int month, year;
+ int days;
days = time / 86400;
- time -= days * 86400;
+ time -= (unsigned int) days * 86400;
/* day of the week, 1970-01-01 was a Thursday */
tm->tm_wday = (days + 4) % 7;
diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c
index 03c0e40a92f..e3b5c4d3036 100644
--- a/drivers/s390/block/dasd_proc.c
+++ b/drivers/s390/block/dasd_proc.c
@@ -76,7 +76,8 @@ dasd_devices_show(struct seq_file *m, void *v)
/* Print kdev. */
if (block->gdp)
seq_printf(m, " at (%3d:%6d)",
- block->gdp->major, block->gdp->first_minor);
+ MAJOR(disk_devt(block->gdp)),
+ MINOR(disk_devt(block->gdp)));
else
seq_printf(m, " at (???:??????)");
/* Print device name. */
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index 711b3004b3e..9481e4a3f76 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -114,7 +114,7 @@ dcssblk_assign_free_minor(struct dcssblk_dev_info *dev_info)
found = 0;
// test if minor available
list_for_each_entry(entry, &dcssblk_devices, lh)
- if (minor == entry->gd->first_minor)
+ if (minor == MINOR(disk_devt(entry->gd)))
found++;
if (!found) break; // got unused minor
}
@@ -397,7 +397,7 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
goto unload_seg;
}
sprintf(dev_info->gd->disk_name, "dcssblk%d",
- dev_info->gd->first_minor);
+ MINOR(disk_devt(dev_info->gd)));
list_add_tail(&dev_info->lh, &dcssblk_devices);
if (!try_module_get(THIS_MODULE)) {
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index e0ce65fca4e..9a50f245774 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -113,7 +113,8 @@ ccwgroup_release (struct device *dev)
for (i = 0; i < gdev->count; i++) {
if (gdev->cdev[i]) {
- dev_set_drvdata(&gdev->cdev[i]->dev, NULL);
+ if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev)
+ dev_set_drvdata(&gdev->cdev[i]->dev, NULL);
put_device(&gdev->cdev[i]->dev);
}
}
@@ -296,6 +297,7 @@ error:
if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev)
dev_set_drvdata(&gdev->cdev[i]->dev, NULL);
put_device(&gdev->cdev[i]->dev);
+ gdev->cdev[i] = NULL;
}
mutex_unlock(&gdev->reg_mutex);
put_device(&gdev->dev);
diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c
index db00b059173..f1216cf6fa8 100644
--- a/drivers/s390/cio/chp.c
+++ b/drivers/s390/cio/chp.c
@@ -423,7 +423,7 @@ int chp_new(struct chp_id chpid)
ret = sysfs_create_group(&chp->dev.kobj, &chp_attr_group);
if (ret) {
device_unregister(&chp->dev);
- goto out_free;
+ goto out;
}
mutex_lock(&channel_subsystems[chpid.cssid]->mutex);
if (channel_subsystems[chpid.cssid]->cm_enabled) {
@@ -432,14 +432,15 @@ int chp_new(struct chp_id chpid)
sysfs_remove_group(&chp->dev.kobj, &chp_attr_group);
device_unregister(&chp->dev);
mutex_unlock(&channel_subsystems[chpid.cssid]->mutex);
- goto out_free;
+ goto out;
}
}
channel_subsystems[chpid.cssid]->chps[chpid.id] = chp;
mutex_unlock(&channel_subsystems[chpid.cssid]->mutex);
- return ret;
+ goto out;
out_free:
kfree(chp);
+out:
return ret;
}
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 33bff8fec7d..326f4cc7f92 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -174,6 +174,7 @@ cio_start_key (struct subchannel *sch, /* subchannel structure */
CIO_TRACE_EVENT(4, sch->dev.bus_id);
orb = &to_io_private(sch)->orb;
+ memset(orb, 0, sizeof(union orb));
/* sch is always under 2G. */
orb->cmd.intparm = (u32)(addr_t)sch;
orb->cmd.fmt = 1;
@@ -208,8 +209,10 @@ cio_start_key (struct subchannel *sch, /* subchannel structure */
case 1: /* status pending */
case 2: /* busy */
return -EBUSY;
- default: /* device/path not operational */
+ case 3: /* device/path not operational */
return cio_start_handle_notoper(sch, lpm);
+ default:
+ return ccode;
}
}
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 51489eff6b0..1261e1a9e8c 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -633,6 +633,11 @@ channel_subsystem_release(struct device *dev)
css = to_css(dev);
mutex_destroy(&css->mutex);
+ if (css->pseudo_subchannel) {
+ /* Implies that it has been generated but never registered. */
+ css_subchannel_release(&css->pseudo_subchannel->dev);
+ css->pseudo_subchannel = NULL;
+ }
kfree(css);
}
@@ -785,11 +790,15 @@ init_channel_subsystem (void)
}
channel_subsystems[i] = css;
ret = setup_css(i);
- if (ret)
- goto out_free;
+ if (ret) {
+ kfree(channel_subsystems[i]);
+ goto out_unregister;
+ }
ret = device_register(&css->device);
- if (ret)
- goto out_free_all;
+ if (ret) {
+ put_device(&css->device);
+ goto out_unregister;
+ }
if (css_chsc_characteristics.secm) {
ret = device_create_file(&css->device,
&dev_attr_cm_enable);
@@ -802,7 +811,7 @@ init_channel_subsystem (void)
}
ret = register_reboot_notifier(&css_reboot_notifier);
if (ret)
- goto out_pseudo;
+ goto out_unregister;
css_init_done = 1;
/* Enable default isc for I/O subchannels. */
@@ -810,18 +819,12 @@ init_channel_subsystem (void)
for_each_subchannel(__init_channel_subsystem, NULL);
return 0;
-out_pseudo:
- device_unregister(&channel_subsystems[i]->pseudo_subchannel->dev);
out_file:
- device_remove_file(&channel_subsystems[i]->device,
- &dev_attr_cm_enable);
+ if (css_chsc_characteristics.secm)
+ device_remove_file(&channel_subsystems[i]->device,
+ &dev_attr_cm_enable);
out_device:
device_unregister(&channel_subsystems[i]->device);
-out_free_all:
- kfree(channel_subsystems[i]->pseudo_subchannel->lock);
- kfree(channel_subsystems[i]->pseudo_subchannel);
-out_free:
- kfree(channel_subsystems[i]);
out_unregister:
while (i > 0) {
struct channel_subsystem *css;
@@ -829,6 +832,7 @@ out_unregister:
i--;
css = channel_subsystems[i];
device_unregister(&css->pseudo_subchannel->dev);
+ css->pseudo_subchannel = NULL;
if (css_chsc_characteristics.secm)
device_remove_file(&css->device,
&dev_attr_cm_enable);
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 550508df952..84cc9ea346d 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -658,6 +658,13 @@ ccw_device_offline(struct ccw_device *cdev)
{
struct subchannel *sch;
+ /* Allow ccw_device_offline while disconnected. */
+ if (cdev->private->state == DEV_STATE_DISCONNECTED ||
+ cdev->private->state == DEV_STATE_NOT_OPER) {
+ cdev->private->flags.donotify = 0;
+ ccw_device_done(cdev, DEV_STATE_NOT_OPER);
+ return 0;
+ }
if (ccw_device_is_orphan(cdev)) {
ccw_device_done(cdev, DEV_STATE_OFFLINE);
return 0;
diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c
index 1679e2f91c9..a0b6b46e746 100644
--- a/drivers/s390/cio/qdio_setup.c
+++ b/drivers/s390/cio/qdio_setup.c
@@ -447,51 +447,36 @@ void qdio_print_subchannel_info(struct qdio_irq *irq_ptr,
{
char s[80];
- sprintf(s, "%s sc:%x ", cdev->dev.bus_id, irq_ptr->schid.sch_no);
-
+ sprintf(s, "qdio: %s ", dev_name(&cdev->dev));
switch (irq_ptr->qib.qfmt) {
case QDIO_QETH_QFMT:
- sprintf(s + strlen(s), "OSADE ");
+ sprintf(s + strlen(s), "OSA ");
break;
case QDIO_ZFCP_QFMT:
sprintf(s + strlen(s), "ZFCP ");
break;
case QDIO_IQDIO_QFMT:
- sprintf(s + strlen(s), "HiperSockets ");
+ sprintf(s + strlen(s), "HS ");
break;
}
- sprintf(s + strlen(s), "using: ");
-
- if (!is_thinint_irq(irq_ptr))
- sprintf(s + strlen(s), "no");
- sprintf(s + strlen(s), "AdapterInterrupts ");
- if (!(irq_ptr->sch_token != 0))
- sprintf(s + strlen(s), "no");
- sprintf(s + strlen(s), "QEBSM ");
- if (!(irq_ptr->qib.ac & QIB_AC_OUTBOUND_PCI_SUPPORTED))
- sprintf(s + strlen(s), "no");
- sprintf(s + strlen(s), "OutboundPCI ");
- if (!css_general_characteristics.aif_tdd)
- sprintf(s + strlen(s), "no");
- sprintf(s + strlen(s), "TDD\n");
- printk(KERN_INFO "qdio: %s", s);
-
- memset(s, 0, sizeof(s));
- sprintf(s, "%s SIGA required: ", cdev->dev.bus_id);
- if (irq_ptr->siga_flag.input)
- sprintf(s + strlen(s), "Read ");
- if (irq_ptr->siga_flag.output)
- sprintf(s + strlen(s), "Write ");
- if (irq_ptr->siga_flag.sync)
- sprintf(s + strlen(s), "Sync ");
- if (!irq_ptr->siga_flag.no_sync_ti)
- sprintf(s + strlen(s), "SyncAI ");
- if (!irq_ptr->siga_flag.no_sync_out_ti)
- sprintf(s + strlen(s), "SyncOutAI ");
- if (!irq_ptr->siga_flag.no_sync_out_pci)
- sprintf(s + strlen(s), "SyncOutPCI");
+ sprintf(s + strlen(s), "on SC %x using ", irq_ptr->schid.sch_no);
+ sprintf(s + strlen(s), "AI:%d ", is_thinint_irq(irq_ptr));
+ sprintf(s + strlen(s), "QEBSM:%d ", (irq_ptr->sch_token) ? 1 : 0);
+ sprintf(s + strlen(s), "PCI:%d ",
+ (irq_ptr->qib.ac & QIB_AC_OUTBOUND_PCI_SUPPORTED) ? 1 : 0);
+ sprintf(s + strlen(s), "TDD:%d ", css_general_characteristics.aif_tdd);
+ sprintf(s + strlen(s), "SIGA:");
+ sprintf(s + strlen(s), "%s", (irq_ptr->siga_flag.input) ? "R" : " ");
+ sprintf(s + strlen(s), "%s", (irq_ptr->siga_flag.output) ? "W" : " ");
+ sprintf(s + strlen(s), "%s", (irq_ptr->siga_flag.sync) ? "S" : " ");
+ sprintf(s + strlen(s), "%s",
+ (!irq_ptr->siga_flag.no_sync_ti) ? "A" : " ");
+ sprintf(s + strlen(s), "%s",
+ (!irq_ptr->siga_flag.no_sync_out_ti) ? "O" : " ");
+ sprintf(s + strlen(s), "%s",
+ (!irq_ptr->siga_flag.no_sync_out_pci) ? "P" : " ");
sprintf(s + strlen(s), "\n");
- printk(KERN_INFO "qdio: %s", s);
+ printk(KERN_INFO "%s", s);
}
int __init qdio_setup_init(void)
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index 90abfd06ed5..24255e42dc3 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -88,11 +88,13 @@ static int __init zfcp_device_setup(char *devstr)
strncpy(zfcp_data.init_busid, token, BUS_ID_SIZE);
token = strsep(&str, ",");
- if (!token || strict_strtoull(token, 0, &zfcp_data.init_wwpn))
+ if (!token || strict_strtoull(token, 0,
+ (unsigned long long *) &zfcp_data.init_wwpn))
goto err_out;
token = strsep(&str, ",");
- if (!token || strict_strtoull(token, 0, &zfcp_data.init_fcp_lun))
+ if (!token || strict_strtoull(token, 0,
+ (unsigned long long *) &zfcp_data.init_fcp_lun))
goto err_out;
kfree(str);
@@ -100,24 +102,10 @@ static int __init zfcp_device_setup(char *devstr)
err_out:
kfree(str);
- pr_err("zfcp: Parse error for device parameter string %s, "
- "device not attached.\n", devstr);
+ pr_err("zfcp: %s is not a valid SCSI device\n", devstr);
return 0;
}
-static struct zfcp_adapter *zfcp_get_adapter_by_busid(char *bus_id)
-{
- struct zfcp_adapter *adapter;
-
- list_for_each_entry(adapter, &zfcp_data.adapter_list_head, list)
- if ((strncmp(bus_id, adapter->ccw_device->dev.bus_id,
- BUS_ID_SIZE) == 0) &&
- !(atomic_read(&adapter->status) &
- ZFCP_STATUS_COMMON_REMOVE))
- return adapter;
- return NULL;
-}
-
static void __init zfcp_init_device_configure(void)
{
struct zfcp_adapter *adapter;
@@ -141,7 +129,12 @@ static void __init zfcp_init_device_configure(void)
goto out_unit;
up(&zfcp_data.config_sema);
ccw_device_set_online(adapter->ccw_device);
+
zfcp_erp_wait(adapter);
+ wait_event(adapter->erp_done_wqh,
+ !(atomic_read(&unit->status) &
+ ZFCP_STATUS_UNIT_SCSI_WORK_PENDING));
+
down(&zfcp_data.config_sema);
zfcp_unit_put(unit);
out_unit:
@@ -180,9 +173,9 @@ static int __init zfcp_module_init(void)
if (!zfcp_data.gid_pn_cache)
goto out_gid_cache;
- INIT_LIST_HEAD(&zfcp_data.adapter_list_head);
- INIT_LIST_HEAD(&zfcp_data.adapter_remove_lh);
+ zfcp_data.work_queue = create_singlethread_workqueue("zfcp_wq");
+ INIT_LIST_HEAD(&zfcp_data.adapter_list_head);
sema_init(&zfcp_data.config_sema, 1);
rwlock_init(&zfcp_data.config_lock);
@@ -193,13 +186,14 @@ static int __init zfcp_module_init(void)
retval = misc_register(&zfcp_cfdc_misc);
if (retval) {
- pr_err("zfcp: registration of misc device zfcp_cfdc failed\n");
+ pr_err("zfcp: Registering the misc device zfcp_cfdc failed\n");
goto out_misc;
}
retval = zfcp_ccw_register();
if (retval) {
- pr_err("zfcp: Registration with common I/O layer failed.\n");
+ pr_err("zfcp: The zfcp device driver could not register with "
+ "the common I/O layer\n");
goto out_ccw_register;
}
@@ -231,8 +225,7 @@ module_init(zfcp_module_init);
*
* Returns: pointer to zfcp_unit or NULL
*/
-struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *port,
- fcp_lun_t fcp_lun)
+struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *port, u64 fcp_lun)
{
struct zfcp_unit *unit;
@@ -251,7 +244,7 @@ struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *port,
* Returns: pointer to zfcp_port or NULL
*/
struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *adapter,
- wwn_t wwpn)
+ u64 wwpn)
{
struct zfcp_port *port;
@@ -276,7 +269,7 @@ static void zfcp_sysfs_unit_release(struct device *dev)
*
* Sets up some unit internal structures and creates sysfs entry.
*/
-struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun)
+struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun)
{
struct zfcp_unit *unit;
@@ -290,7 +283,8 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun)
unit->port = port;
unit->fcp_lun = fcp_lun;
- snprintf(unit->sysfs_device.bus_id, BUS_ID_SIZE, "0x%016llx", fcp_lun);
+ snprintf(unit->sysfs_device.bus_id, BUS_ID_SIZE, "0x%016llx",
+ (unsigned long long) fcp_lun);
unit->sysfs_device.parent = &port->sysfs_device;
unit->sysfs_device.release = zfcp_sysfs_unit_release;
dev_set_drvdata(&unit->sysfs_device, unit);
@@ -323,7 +317,6 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun)
}
zfcp_unit_get(unit);
- unit->scsi_lun = scsilun_to_int((struct scsi_lun *)&unit->fcp_lun);
write_lock_irq(&zfcp_data.config_lock);
list_add_tail(&unit->list, &port->unit_list_head);
@@ -332,7 +325,6 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun)
write_unlock_irq(&zfcp_data.config_lock);
- port->units++;
zfcp_port_get(port);
return unit;
@@ -351,11 +343,10 @@ err_out_free:
*/
void zfcp_unit_dequeue(struct zfcp_unit *unit)
{
- zfcp_unit_wait(unit);
+ wait_event(unit->remove_wq, atomic_read(&unit->refcount) == 0);
write_lock_irq(&zfcp_data.config_lock);
list_del(&unit->list);
write_unlock_irq(&zfcp_data.config_lock);
- unit->port->units--;
zfcp_port_put(unit->port);
sysfs_remove_group(&unit->sysfs_device.kobj, &zfcp_sysfs_unit_attrs);
device_unregister(&unit->sysfs_device);
@@ -416,11 +407,6 @@ static void zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter)
mempool_destroy(adapter->pool.data_gid_pn);
}
-static void zfcp_dummy_release(struct device *dev)
-{
- return;
-}
-
/**
* zfcp_status_read_refill - refill the long running status_read_requests
* @adapter: ptr to struct zfcp_adapter for which the buffers should be refilled
@@ -450,19 +436,6 @@ static void _zfcp_status_read_scheduler(struct work_struct *work)
stat_work));
}
-static int zfcp_nameserver_enqueue(struct zfcp_adapter *adapter)
-{
- struct zfcp_port *port;
-
- port = zfcp_port_enqueue(adapter, 0, ZFCP_STATUS_PORT_WKA,
- ZFCP_DID_DIRECTORY_SERVICE);
- if (IS_ERR(port))
- return PTR_ERR(port);
- zfcp_port_put(port);
-
- return 0;
-}
-
/**
* zfcp_adapter_enqueue - enqueue a new adapter to the list
* @ccw_device: pointer to the struct cc_device
@@ -508,7 +481,6 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device)
init_waitqueue_head(&adapter->erp_done_wqh);
INIT_LIST_HEAD(&adapter->port_list_head);
- INIT_LIST_HEAD(&adapter->port_remove_lh);
INIT_LIST_HEAD(&adapter->erp_ready_head);
INIT_LIST_HEAD(&adapter->erp_running_head);
@@ -518,7 +490,7 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device)
spin_lock_init(&adapter->san_dbf_lock);
spin_lock_init(&adapter->scsi_dbf_lock);
spin_lock_init(&adapter->rec_dbf_lock);
- spin_lock_init(&adapter->req_q.lock);
+ spin_lock_init(&adapter->req_q_lock);
rwlock_init(&adapter->erp_lock);
rwlock_init(&adapter->abort_lock);
@@ -537,28 +509,15 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device)
&zfcp_sysfs_adapter_attrs))
goto sysfs_failed;
- adapter->generic_services.parent = &adapter->ccw_device->dev;
- adapter->generic_services.release = zfcp_dummy_release;
- snprintf(adapter->generic_services.bus_id, BUS_ID_SIZE,
- "generic_services");
-
- if (device_register(&adapter->generic_services))
- goto generic_services_failed;
-
write_lock_irq(&zfcp_data.config_lock);
atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status);
list_add_tail(&adapter->list, &zfcp_data.adapter_list_head);
write_unlock_irq(&zfcp_data.config_lock);
- zfcp_data.adapters++;
-
- zfcp_nameserver_enqueue(adapter);
+ zfcp_fc_nameserver_init(adapter);
return 0;
-generic_services_failed:
- sysfs_remove_group(&ccw_device->dev.kobj,
- &zfcp_sysfs_adapter_attrs);
sysfs_failed:
zfcp_adapter_debug_unregister(adapter);
debug_register_failed:
@@ -585,7 +544,6 @@ void zfcp_adapter_dequeue(struct zfcp_adapter *adapter)
cancel_work_sync(&adapter->scan_work);
cancel_work_sync(&adapter->stat_work);
zfcp_adapter_scsi_unregister(adapter);
- device_unregister(&adapter->generic_services);
sysfs_remove_group(&adapter->ccw_device->dev.kobj,
&zfcp_sysfs_adapter_attrs);
dev_set_drvdata(&adapter->ccw_device->dev, NULL);
@@ -603,9 +561,6 @@ void zfcp_adapter_dequeue(struct zfcp_adapter *adapter)
list_del(&adapter->list);
write_unlock_irq(&zfcp_data.config_lock);
- /* decrease number of adapters in list */
- zfcp_data.adapters--;
-
zfcp_qdio_free(adapter);
zfcp_free_low_mem_buffers(adapter);
@@ -633,21 +588,19 @@ static void zfcp_sysfs_port_release(struct device *dev)
* d_id is used to enqueue ports with a well known address like the Directory
* Service for nameserver lookup.
*/
-struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn,
+struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,
u32 status, u32 d_id)
{
struct zfcp_port *port;
int retval;
- char *bus_id;
port = kzalloc(sizeof(struct zfcp_port), GFP_KERNEL);
if (!port)
return ERR_PTR(-ENOMEM);
init_waitqueue_head(&port->remove_wq);
-
INIT_LIST_HEAD(&port->unit_list_head);
- INIT_LIST_HEAD(&port->unit_remove_lh);
+ INIT_WORK(&port->gid_pn_work, zfcp_erp_port_strategy_open_lookup);
port->adapter = adapter;
port->d_id = d_id;
@@ -657,34 +610,9 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn,
atomic_set_mask(status | ZFCP_STATUS_COMMON_REMOVE, &port->status);
atomic_set(&port->refcount, 0);
- if (status & ZFCP_STATUS_PORT_WKA) {
- switch (d_id) {
- case ZFCP_DID_DIRECTORY_SERVICE:
- bus_id = "directory";
- break;
- case ZFCP_DID_MANAGEMENT_SERVICE:
- bus_id = "management";
- break;
- case ZFCP_DID_KEY_DISTRIBUTION_SERVICE:
- bus_id = "key_distribution";
- break;
- case ZFCP_DID_ALIAS_SERVICE:
- bus_id = "alias";
- break;
- case ZFCP_DID_TIME_SERVICE:
- bus_id = "time";
- break;
- default:
- kfree(port);
- return ERR_PTR(-EINVAL);
- }
- snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, "%s", bus_id);
- port->sysfs_device.parent = &adapter->generic_services;
- } else {
- snprintf(port->sysfs_device.bus_id,
- BUS_ID_SIZE, "0x%016llx", wwpn);
- port->sysfs_device.parent = &adapter->ccw_device->dev;
- }
+ snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, "0x%016llx",
+ (unsigned long long) wwpn);
+ port->sysfs_device.parent = &adapter->ccw_device->dev;
port->sysfs_device.release = zfcp_sysfs_port_release;
dev_set_drvdata(&port->sysfs_device, port);
@@ -700,12 +628,8 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn,
if (device_register(&port->sysfs_device))
goto err_out_free;
- if (status & ZFCP_STATUS_PORT_WKA)
- retval = sysfs_create_group(&port->sysfs_device.kobj,
- &zfcp_sysfs_ns_port_attrs);
- else
- retval = sysfs_create_group(&port->sysfs_device.kobj,
- &zfcp_sysfs_port_attrs);
+ retval = sysfs_create_group(&port->sysfs_device.kobj,
+ &zfcp_sysfs_port_attrs);
if (retval) {
device_unregister(&port->sysfs_device);
@@ -718,10 +642,6 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn,
list_add_tail(&port->list, &adapter->port_list_head);
atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status);
atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &port->status);
- if (d_id == ZFCP_DID_DIRECTORY_SERVICE)
- if (!adapter->nameserver_port)
- adapter->nameserver_port = port;
- adapter->ports++;
write_unlock_irq(&zfcp_data.config_lock);
@@ -740,21 +660,15 @@ err_out:
*/
void zfcp_port_dequeue(struct zfcp_port *port)
{
- zfcp_port_wait(port);
+ wait_event(port->remove_wq, atomic_read(&port->refcount) == 0);
write_lock_irq(&zfcp_data.config_lock);
list_del(&port->list);
- port->adapter->ports--;
write_unlock_irq(&zfcp_data.config_lock);
if (port->rport)
fc_remote_port_delete(port->rport);
port->rport = NULL;
zfcp_adapter_put(port->adapter);
- if (atomic_read(&port->status) & ZFCP_STATUS_PORT_WKA)
- sysfs_remove_group(&port->sysfs_device.kobj,
- &zfcp_sysfs_ns_port_attrs);
- else
- sysfs_remove_group(&port->sysfs_device.kobj,
- &zfcp_sysfs_port_attrs);
+ sysfs_remove_group(&port->sysfs_device.kobj, &zfcp_sysfs_port_attrs);
device_unregister(&port->sysfs_device);
}
diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c
index 391dd29749f..b04038c7478 100644
--- a/drivers/s390/scsi/zfcp_ccw.c
+++ b/drivers/s390/scsi/zfcp_ccw.c
@@ -25,7 +25,8 @@ static int zfcp_ccw_probe(struct ccw_device *ccw_device)
down(&zfcp_data.config_sema);
if (zfcp_adapter_enqueue(ccw_device)) {
dev_err(&ccw_device->dev,
- "Setup of data structures failed.\n");
+ "Setting up data structures for the "
+ "FCP adapter failed\n");
retval = -EINVAL;
}
up(&zfcp_data.config_sema);
@@ -46,6 +47,8 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device)
struct zfcp_adapter *adapter;
struct zfcp_port *port, *p;
struct zfcp_unit *unit, *u;
+ LIST_HEAD(unit_remove_lh);
+ LIST_HEAD(port_remove_lh);
ccw_device_set_offline(ccw_device);
down(&zfcp_data.config_sema);
@@ -54,26 +57,26 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device)
write_lock_irq(&zfcp_data.config_lock);
list_for_each_entry_safe(port, p, &adapter->port_list_head, list) {
list_for_each_entry_safe(unit, u, &port->unit_list_head, list) {
- list_move(&unit->list, &port->unit_remove_lh);
+ list_move(&unit->list, &unit_remove_lh);
atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE,
&unit->status);
}
- list_move(&port->list, &adapter->port_remove_lh);
+ list_move(&port->list, &port_remove_lh);
atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status);
}
atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status);
write_unlock_irq(&zfcp_data.config_lock);
- list_for_each_entry_safe(port, p, &adapter->port_remove_lh, list) {
- list_for_each_entry_safe(unit, u, &port->unit_remove_lh, list) {
- if (atomic_test_mask(ZFCP_STATUS_UNIT_REGISTERED,
- &unit->status))
+ list_for_each_entry_safe(port, p, &port_remove_lh, list) {
+ list_for_each_entry_safe(unit, u, &unit_remove_lh, list) {
+ if (atomic_read(&unit->status) &
+ ZFCP_STATUS_UNIT_REGISTERED)
scsi_remove_device(unit->device);
zfcp_unit_dequeue(unit);
}
zfcp_port_dequeue(port);
}
- zfcp_adapter_wait(adapter);
+ wait_event(adapter->remove_wq, atomic_read(&adapter->refcount) == 0);
zfcp_adapter_dequeue(adapter);
up(&zfcp_data.config_sema);
@@ -152,21 +155,22 @@ static int zfcp_ccw_set_offline(struct ccw_device *ccw_device)
*/
static int zfcp_ccw_notify(struct ccw_device *ccw_device, int event)
{
- struct zfcp_adapter *adapter;
+ struct zfcp_adapter *adapter = dev_get_drvdata(&ccw_device->dev);
- down(&zfcp_data.config_sema);
- adapter = dev_get_drvdata(&ccw_device->dev);
switch (event) {
case CIO_GONE:
- dev_warn(&adapter->ccw_device->dev, "device gone\n");
+ dev_warn(&adapter->ccw_device->dev,
+ "The FCP device has been detached\n");
zfcp_erp_adapter_shutdown(adapter, 0, 87, NULL);
break;
case CIO_NO_PATH:
- dev_warn(&adapter->ccw_device->dev, "no path\n");
+ dev_warn(&adapter->ccw_device->dev,
+ "The CHPID for the FCP device is offline\n");
zfcp_erp_adapter_shutdown(adapter, 0, 88, NULL);
break;
case CIO_OPER:
- dev_info(&adapter->ccw_device->dev, "operational again\n");
+ dev_info(&adapter->ccw_device->dev,
+ "The FCP device is operational again\n");
zfcp_erp_modify_adapter_status(adapter, 11, NULL,
ZFCP_STATUS_COMMON_RUNNING,
ZFCP_SET);
@@ -174,8 +178,6 @@ static int zfcp_ccw_notify(struct ccw_device *ccw_device, int event)
89, NULL);
break;
}
- zfcp_erp_wait(adapter);
- up(&zfcp_data.config_sema);
return 1;
}
@@ -224,3 +226,20 @@ int __init zfcp_ccw_register(void)
{
return ccw_driver_register(&zfcp_ccw_driver);
}
+
+/**
+ * zfcp_get_adapter_by_busid - find zfcp_adapter struct
+ * @busid: bus id string of zfcp adapter to find
+ */
+struct zfcp_adapter *zfcp_get_adapter_by_busid(char *busid)
+{
+ struct ccw_device *ccw_device;
+ struct zfcp_adapter *adapter = NULL;
+
+ ccw_device = get_ccwdev_by_busid(&zfcp_ccw_driver, busid);
+ if (ccw_device) {
+ adapter = dev_get_drvdata(&ccw_device->dev);
+ put_device(&ccw_device->dev);
+ }
+ return adapter;
+}
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c
index fca48b88fc5..060f5f2352e 100644
--- a/drivers/s390/scsi/zfcp_dbf.c
+++ b/drivers/s390/scsi/zfcp_dbf.c
@@ -318,6 +318,26 @@ void zfcp_hba_dbf_event_qdio(struct zfcp_adapter *adapter,
spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags);
}
+/**
+ * zfcp_hba_dbf_event_berr - trace event for bit error threshold
+ * @adapter: adapter affected by this QDIO related event
+ * @req: fsf request
+ */
+void zfcp_hba_dbf_event_berr(struct zfcp_adapter *adapter,
+ struct zfcp_fsf_req *req)
+{
+ struct zfcp_hba_dbf_record *r = &adapter->hba_dbf_buf;
+ struct fsf_status_read_buffer *sr_buf = req->data;
+ struct fsf_bit_error_payload *err = &sr_buf->payload.bit_error;
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->hba_dbf_lock, flags);
+ memset(r, 0, sizeof(*r));
+ strncpy(r->tag, "berr", ZFCP_DBF_TAG_SIZE);
+ memcpy(&r->u.berr, err, sizeof(struct fsf_bit_error_payload));
+ debug_event(adapter->hba_dbf, 0, r, sizeof(*r));
+ spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags);
+}
static void zfcp_hba_dbf_view_response(char **p,
struct zfcp_hba_dbf_record_response *r)
{
@@ -399,6 +419,30 @@ static void zfcp_hba_dbf_view_qdio(char **p, struct zfcp_hba_dbf_record_qdio *r)
zfcp_dbf_out(p, "sbal_count", "0x%02x", r->sbal_count);
}
+static void zfcp_hba_dbf_view_berr(char **p, struct fsf_bit_error_payload *r)
+{
+ zfcp_dbf_out(p, "link_failures", "%d", r->link_failure_error_count);
+ zfcp_dbf_out(p, "loss_of_sync_err", "%d", r->loss_of_sync_error_count);
+ zfcp_dbf_out(p, "loss_of_sig_err", "%d", r->loss_of_signal_error_count);
+ zfcp_dbf_out(p, "prim_seq_err", "%d",
+ r->primitive_sequence_error_count);
+ zfcp_dbf_out(p, "inval_trans_word_err", "%d",
+ r->invalid_transmission_word_error_count);
+ zfcp_dbf_out(p, "CRC_errors", "%d", r->crc_error_count);
+ zfcp_dbf_out(p, "prim_seq_event_to", "%d",
+ r->primitive_sequence_event_timeout_count);
+ zfcp_dbf_out(p, "elast_buf_overrun_err", "%d",
+ r->elastic_buffer_overrun_error_count);
+ zfcp_dbf_out(p, "adv_rec_buf2buf_cred", "%d",
+ r->advertised_receive_b2b_credit);
+ zfcp_dbf_out(p, "curr_rec_buf2buf_cred", "%d",
+ r->current_receive_b2b_credit);
+ zfcp_dbf_out(p, "adv_trans_buf2buf_cred", "%d",
+ r->advertised_transmit_b2b_credit);
+ zfcp_dbf_out(p, "curr_trans_buf2buf_cred", "%d",
+ r->current_transmit_b2b_credit);
+}
+
static int zfcp_hba_dbf_view_format(debug_info_t *id, struct debug_view *view,
char *out_buf, const char *in_buf)
{
@@ -418,6 +462,8 @@ static int zfcp_hba_dbf_view_format(debug_info_t *id, struct debug_view *view,
zfcp_hba_dbf_view_status(&p, &r->u.status);
else if (strncmp(r->tag, "qdio", ZFCP_DBF_TAG_SIZE) == 0)
zfcp_hba_dbf_view_qdio(&p, &r->u.qdio);
+ else if (strncmp(r->tag, "berr", ZFCP_DBF_TAG_SIZE) == 0)
+ zfcp_hba_dbf_view_berr(&p, &r->u.berr);
p += sprintf(p, "\n");
return p - out_buf;
@@ -519,14 +565,14 @@ static const char *zfcp_rec_dbf_ids[] = {
[75] = "physical port recovery escalation after failed port "
"recovery",
[76] = "port recovery escalation after failed unit recovery",
- [77] = "recovery opening nameserver port",
+ [77] = "",
[78] = "duplicate request id",
[79] = "link down",
[80] = "exclusive read-only unit access unsupported",
[81] = "shared read-write unit access unsupported",
[82] = "incoming rscn",
[83] = "incoming wwpn",
- [84] = "",
+ [84] = "wka port handle not valid close port",
[85] = "online",
[86] = "offline",
[87] = "ccw device gone",
@@ -570,7 +616,7 @@ static const char *zfcp_rec_dbf_ids[] = {
[125] = "need newer zfcp",
[126] = "need newer microcode",
[127] = "arbitrated loop not supported",
- [128] = "unknown topology",
+ [128] = "",
[129] = "qtcb size mismatch",
[130] = "unknown fsf status ecd",
[131] = "fcp request too big",
@@ -829,9 +875,9 @@ void zfcp_rec_dbf_event_action(u8 id2, struct zfcp_erp_action *erp_action)
void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req)
{
struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data;
- struct zfcp_port *port = ct->port;
- struct zfcp_adapter *adapter = port->adapter;
- struct ct_hdr *hdr = zfcp_sg_to_address(ct->req);
+ struct zfcp_wka_port *wka_port = ct->wka_port;
+ struct zfcp_adapter *adapter = wka_port->adapter;
+ struct ct_hdr *hdr = sg_virt(ct->req);
struct zfcp_san_dbf_record *r = &adapter->san_dbf_buf;
struct zfcp_san_dbf_record_ct_request *oct = &r->u.ct_req;
unsigned long flags;
@@ -842,7 +888,7 @@ void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req)
r->fsf_reqid = (unsigned long)fsf_req;
r->fsf_seqno = fsf_req->seq_no;
r->s_id = fc_host_port_id(adapter->scsi_host);
- r->d_id = port->d_id;
+ r->d_id = wka_port->d_id;
oct->cmd_req_code = hdr->cmd_rsp_code;
oct->revision = hdr->revision;
oct->gs_type = hdr->gs_type;
@@ -863,9 +909,9 @@ void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req)
void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req)
{
struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data;
- struct zfcp_port *port = ct->port;
- struct zfcp_adapter *adapter = port->adapter;
- struct ct_hdr *hdr = zfcp_sg_to_address(ct->resp);
+ struct zfcp_wka_port *wka_port = ct->wka_port;
+ struct zfcp_adapter *adapter = wka_port->adapter;
+ struct ct_hdr *hdr = sg_virt(ct->resp);
struct zfcp_san_dbf_record *r = &adapter->san_dbf_buf;
struct zfcp_san_dbf_record_ct_response *rct = &r->u.ct_resp;
unsigned long flags;
@@ -875,7 +921,7 @@ void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req)
strncpy(r->tag, "rctc", ZFCP_DBF_TAG_SIZE);
r->fsf_reqid = (unsigned long)fsf_req;
r->fsf_seqno = fsf_req->seq_no;
- r->s_id = port->d_id;
+ r->s_id = wka_port->d_id;
r->d_id = fc_host_port_id(adapter->scsi_host);
rct->cmd_rsp_code = hdr->cmd_rsp_code;
rct->revision = hdr->revision;
@@ -922,8 +968,8 @@ void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *fsf_req)
zfcp_san_dbf_event_els("oels", 2, fsf_req,
fc_host_port_id(els->adapter->scsi_host),
- els->d_id, *(u8 *) zfcp_sg_to_address(els->req),
- zfcp_sg_to_address(els->req), els->req->length);
+ els->d_id, *(u8 *) sg_virt(els->req),
+ sg_virt(els->req), els->req->length);
}
/**
@@ -936,8 +982,7 @@ void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *fsf_req)
zfcp_san_dbf_event_els("rels", 2, fsf_req, els->d_id,
fc_host_port_id(els->adapter->scsi_host),
- *(u8 *)zfcp_sg_to_address(els->req),
- zfcp_sg_to_address(els->resp),
+ *(u8 *)sg_virt(els->req), sg_virt(els->resp),
els->resp->length);
}
diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h
index 0ddb18449d1..e8f450801fe 100644
--- a/drivers/s390/scsi/zfcp_dbf.h
+++ b/drivers/s390/scsi/zfcp_dbf.h
@@ -151,6 +151,7 @@ struct zfcp_hba_dbf_record {
struct zfcp_hba_dbf_record_response response;
struct zfcp_hba_dbf_record_status status;
struct zfcp_hba_dbf_record_qdio qdio;
+ struct fsf_bit_error_payload berr;
} u;
} __attribute__ ((packed));
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h
index 67f45fc62f5..73eb41580f2 100644
--- a/drivers/s390/scsi/zfcp_def.h
+++ b/drivers/s390/scsi/zfcp_def.h
@@ -39,29 +39,6 @@
/********************* GENERAL DEFINES *********************************/
-/**
- * zfcp_sg_to_address - determine kernel address from struct scatterlist
- * @list: struct scatterlist
- * Return: kernel address
- */
-static inline void *
-zfcp_sg_to_address(struct scatterlist *list)
-{
- 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, unsigned int size)
-{
- sg_set_buf(list, address, size);
-}
-
#define REQUEST_LIST_SIZE 128
/********************* SCSI SPECIFIC DEFINES *********************************/
@@ -101,11 +78,6 @@ zfcp_address_to_sg(void *address, struct scatterlist *list, unsigned int size)
/*************** FIBRE CHANNEL PROTOCOL SPECIFIC DEFINES ********************/
-typedef unsigned long long wwn_t;
-typedef unsigned long long fcp_lun_t;
-/* data length field may be at variable position in FCP-2 FCP_CMND IU */
-typedef unsigned int fcp_dl_t;
-
/* timeout for name-server lookup (in seconds) */
#define ZFCP_NS_GID_PN_TIMEOUT 10
@@ -129,7 +101,7 @@ typedef unsigned int fcp_dl_t;
/* FCP(-2) FCP_CMND IU */
struct fcp_cmnd_iu {
- fcp_lun_t fcp_lun; /* FCP logical unit number */
+ u64 fcp_lun; /* FCP logical unit number */
u8 crn; /* command reference number */
u8 reserved0:5; /* reserved */
u8 task_attribute:3; /* task attribute */
@@ -204,7 +176,7 @@ struct fcp_rscn_element {
struct fcp_logo {
u32 command;
u32 nport_did;
- wwn_t nport_wwpn;
+ u64 nport_wwpn;
} __attribute__((packed));
/*
@@ -218,13 +190,6 @@ struct fcp_logo {
#define ZFCP_LS_RSCN 0x61
#define ZFCP_LS_RNID 0x78
-struct zfcp_ls_rjt_par {
- u8 action;
- u8 reason_code;
- u8 reason_expl;
- u8 vendor_unique;
-} __attribute__ ((packed));
-
struct zfcp_ls_adisc {
u8 code;
u8 field[3];
@@ -234,20 +199,6 @@ struct zfcp_ls_adisc {
u32 nport_id;
} __attribute__ ((packed));
-struct zfcp_ls_adisc_acc {
- u8 code;
- u8 field[3];
- u32 hard_nport_id;
- u64 wwpn;
- u64 wwnn;
- u32 nport_id;
-} __attribute__ ((packed));
-
-struct zfcp_rc_entry {
- u8 code;
- const char *description;
-};
-
/*
* FC-GS-2 stuff
*/
@@ -281,9 +232,7 @@ struct zfcp_rc_entry {
#define ZFCP_STATUS_COMMON_RUNNING 0x40000000
#define ZFCP_STATUS_COMMON_ERP_FAILED 0x20000000
#define ZFCP_STATUS_COMMON_UNBLOCKED 0x10000000
-#define ZFCP_STATUS_COMMON_OPENING 0x08000000
#define ZFCP_STATUS_COMMON_OPEN 0x04000000
-#define ZFCP_STATUS_COMMON_CLOSING 0x02000000
#define ZFCP_STATUS_COMMON_ERP_INUSE 0x01000000
#define ZFCP_STATUS_COMMON_ACCESS_DENIED 0x00800000
#define ZFCP_STATUS_COMMON_ACCESS_BOXED 0x00400000
@@ -291,16 +240,15 @@ struct zfcp_rc_entry {
/* adapter status */
#define ZFCP_STATUS_ADAPTER_QDIOUP 0x00000002
-#define ZFCP_STATUS_ADAPTER_REGISTERED 0x00000004
#define ZFCP_STATUS_ADAPTER_XCONFIG_OK 0x00000008
#define ZFCP_STATUS_ADAPTER_HOST_CON_INIT 0x00000010
#define ZFCP_STATUS_ADAPTER_ERP_THREAD_UP 0x00000020
#define ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL 0x00000080
#define ZFCP_STATUS_ADAPTER_ERP_PENDING 0x00000100
#define ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED 0x00000200
-#define ZFCP_STATUS_ADAPTER_XPORT_OK 0x00000800
/* FC-PH/FC-GS well-known address identifiers for generic services */
+#define ZFCP_DID_WKA 0xFFFFF0
#define ZFCP_DID_MANAGEMENT_SERVICE 0xFFFFFA
#define ZFCP_DID_TIME_SERVICE 0xFFFFFB
#define ZFCP_DID_DIRECTORY_SERVICE 0xFFFFFC
@@ -312,29 +260,27 @@ struct zfcp_rc_entry {
#define ZFCP_STATUS_PORT_DID_DID 0x00000002
#define ZFCP_STATUS_PORT_PHYS_CLOSING 0x00000004
#define ZFCP_STATUS_PORT_NO_WWPN 0x00000008
-#define ZFCP_STATUS_PORT_NO_SCSI_ID 0x00000010
#define ZFCP_STATUS_PORT_INVALID_WWPN 0x00000020
-/* for ports with well known addresses */
-#define ZFCP_STATUS_PORT_WKA \
- (ZFCP_STATUS_PORT_NO_WWPN | \
- ZFCP_STATUS_PORT_NO_SCSI_ID)
+/* well known address (WKA) port status*/
+enum zfcp_wka_status {
+ ZFCP_WKA_PORT_OFFLINE,
+ ZFCP_WKA_PORT_CLOSING,
+ ZFCP_WKA_PORT_OPENING,
+ ZFCP_WKA_PORT_ONLINE,
+};
/* logical unit status */
-#define ZFCP_STATUS_UNIT_TEMPORARY 0x00000002
#define ZFCP_STATUS_UNIT_SHARED 0x00000004
#define ZFCP_STATUS_UNIT_READONLY 0x00000008
#define ZFCP_STATUS_UNIT_REGISTERED 0x00000010
#define ZFCP_STATUS_UNIT_SCSI_WORK_PENDING 0x00000020
/* FSF request status (this does not have a common part) */
-#define ZFCP_STATUS_FSFREQ_NOT_INIT 0x00000000
-#define ZFCP_STATUS_FSFREQ_POOL 0x00000001
#define ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT 0x00000002
#define ZFCP_STATUS_FSFREQ_COMPLETED 0x00000004
#define ZFCP_STATUS_FSFREQ_ERROR 0x00000008
#define ZFCP_STATUS_FSFREQ_CLEANUP 0x00000010
-#define ZFCP_STATUS_FSFREQ_ABORTING 0x00000020
#define ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED 0x00000040
#define ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED 0x00000080
#define ZFCP_STATUS_FSFREQ_ABORTED 0x00000100
@@ -379,7 +325,7 @@ struct ct_hdr {
* a port name is required */
struct ct_iu_gid_pn_req {
struct ct_hdr header;
- wwn_t wwpn;
+ u64 wwpn;
} __attribute__ ((packed));
/* FS_ACC IU and data unit for GID_PN nameserver request */
@@ -388,11 +334,9 @@ struct ct_iu_gid_pn_resp {
u32 d_id;
} __attribute__ ((packed));
-typedef void (*zfcp_send_ct_handler_t)(unsigned long);
-
/**
* struct zfcp_send_ct - used to pass parameters to function zfcp_fsf_send_ct
- * @port: port where the request is sent to
+ * @wka_port: port where the request is sent to
* @req: scatter-gather list for request
* @resp: scatter-gather list for response
* @req_count: number of elements in request scatter-gather list
@@ -404,12 +348,12 @@ typedef void (*zfcp_send_ct_handler_t)(unsigned long);
* @status: used to pass error status to calling function
*/
struct zfcp_send_ct {
- struct zfcp_port *port;
+ struct zfcp_wka_port *wka_port;
struct scatterlist *req;
struct scatterlist *resp;
unsigned int req_count;
unsigned int resp_count;
- zfcp_send_ct_handler_t handler;
+ void (*handler)(unsigned long);
unsigned long handler_data;
int timeout;
struct completion *completion;
@@ -426,8 +370,6 @@ struct zfcp_gid_pn_data {
struct zfcp_port *port;
};
-typedef void (*zfcp_send_els_handler_t)(unsigned long);
-
/**
* struct zfcp_send_els - used to pass parameters to function zfcp_fsf_send_els
* @adapter: adapter where request is sent from
@@ -451,22 +393,28 @@ struct zfcp_send_els {
struct scatterlist *resp;
unsigned int req_count;
unsigned int resp_count;
- zfcp_send_els_handler_t handler;
+ void (*handler)(unsigned long);
unsigned long handler_data;
struct completion *completion;
int ls_code;
int status;
};
+struct zfcp_wka_port {
+ struct zfcp_adapter *adapter;
+ wait_queue_head_t completion_wq;
+ enum zfcp_wka_status status;
+ atomic_t refcount;
+ u32 d_id;
+ u32 handle;
+ struct mutex mutex;
+ struct delayed_work work;
+};
+
struct zfcp_qdio_queue {
- struct qdio_buffer *sbal[QDIO_MAX_BUFFERS_PER_Q]; /* SBALs */
- u8 first; /* index of next free bfr
- in queue (free_count>0) */
- atomic_t count; /* number of free buffers
- in queue */
- spinlock_t lock; /* lock for operations on queue */
- int pci_batch; /* SBALs since PCI indication
- was last set */
+ struct qdio_buffer *sbal[QDIO_MAX_BUFFERS_PER_Q];
+ u8 first; /* index of next free bfr in queue */
+ atomic_t count; /* number of free buffers in queue */
};
struct zfcp_erp_action {
@@ -475,7 +423,7 @@ struct zfcp_erp_action {
struct zfcp_adapter *adapter; /* device which should be recovered */
struct zfcp_port *port;
struct zfcp_unit *unit;
- volatile u32 status; /* recovery status */
+ u32 status; /* recovery status */
u32 step; /* active step of this erp action */
struct zfcp_fsf_req *fsf_req; /* fsf request currently pending
for this action */
@@ -506,8 +454,8 @@ struct zfcp_adapter {
atomic_t refcount; /* reference count */
wait_queue_head_t remove_wq; /* can be used to wait for
refcount drop to zero */
- wwn_t peer_wwnn; /* P2P peer WWNN */
- wwn_t peer_wwpn; /* P2P peer WWPN */
+ u64 peer_wwnn; /* P2P peer WWNN */
+ u64 peer_wwpn; /* P2P peer WWPN */
u32 peer_d_id; /* P2P peer D_ID */
struct ccw_device *ccw_device; /* S/390 ccw device */
u32 hydra_version; /* Hydra version */
@@ -518,13 +466,13 @@ struct zfcp_adapter {
u16 timer_ticks; /* time int for a tick */
struct Scsi_Host *scsi_host; /* Pointer to mid-layer */
struct list_head port_list_head; /* remote port list */
- struct list_head port_remove_lh; /* head of ports to be
- removed */
- u32 ports; /* number of remote ports */
unsigned long req_no; /* unique FSF req number */
struct list_head *req_list; /* list of pending reqs */
spinlock_t req_list_lock; /* request list lock */
struct zfcp_qdio_queue req_q; /* request queue */
+ spinlock_t req_q_lock; /* for operations on queue */
+ int req_q_pci_batch; /* SBALs since PCI indication
+ was last set */
u32 fsf_req_seq_no; /* FSF cmnd seq number */
wait_queue_head_t request_wq; /* can be used to wait for
more avaliable SBALs */
@@ -548,7 +496,7 @@ struct zfcp_adapter {
actions */
u32 erp_low_mem_count; /* nr of erp actions waiting
for memory */
- struct zfcp_port *nameserver_port; /* adapter's nameserver */
+ struct zfcp_wka_port nsp; /* adapter's nameserver */
debug_info_t *rec_dbf;
debug_info_t *hba_dbf;
debug_info_t *san_dbf; /* debug feature areas */
@@ -563,11 +511,11 @@ struct zfcp_adapter {
struct zfcp_scsi_dbf_record scsi_dbf_buf;
struct zfcp_adapter_mempool pool; /* Adapter memory pools */
struct qdio_initialize qdio_init_data; /* for qdio_establish */
- struct device generic_services; /* directory for WKA ports */
struct fc_host_statistics *fc_stats;
struct fsf_qtcb_bottom_port *stats_reset_data;
unsigned long stats_reset;
struct work_struct scan_work;
+ atomic_t qdio_outb_full; /* queue full incidents */
};
struct zfcp_port {
@@ -579,18 +527,16 @@ struct zfcp_port {
refcount drop to zero */
struct zfcp_adapter *adapter; /* adapter used to access port */
struct list_head unit_list_head; /* head of logical unit list */
- struct list_head unit_remove_lh; /* head of luns to be removed
- list */
- u32 units; /* # of logical units in list */
atomic_t status; /* status of this remote port */
- wwn_t wwnn; /* WWNN if known */
- wwn_t wwpn; /* WWPN */
+ u64 wwnn; /* WWNN if known */
+ u64 wwpn; /* WWPN */
u32 d_id; /* D_ID */
u32 handle; /* handle assigned by FSF */
struct zfcp_erp_action erp_action; /* pending error recovery */
atomic_t erp_counter;
u32 maxframe_size;
u32 supported_classes;
+ struct work_struct gid_pn_work;
};
struct zfcp_unit {
@@ -601,8 +547,7 @@ struct zfcp_unit {
refcount drop to zero */
struct zfcp_port *port; /* remote port of unit */
atomic_t status; /* status of this logical unit */
- unsigned int scsi_lun; /* own SCSI LUN */
- fcp_lun_t fcp_lun; /* own FCP_LUN */
+ u64 fcp_lun; /* own FCP_LUN */
u32 handle; /* handle assigned by FSF */
struct scsi_device *device; /* scsi device struct pointer */
struct zfcp_erp_action erp_action; /* pending error recovery */
@@ -625,7 +570,7 @@ struct zfcp_fsf_req {
u8 sbal_response; /* SBAL used in interrupt */
wait_queue_head_t completion_wq; /* can be used by a routine
to wait for completion */
- volatile u32 status; /* status of this request */
+ u32 status; /* status of this request */
u32 fsf_command; /* FSF Command copy */
struct fsf_qtcb *qtcb; /* address of associated QTCB */
u32 seq_no; /* Sequence number of request */
@@ -644,11 +589,7 @@ struct zfcp_fsf_req {
struct zfcp_data {
struct scsi_host_template scsi_host_template;
struct scsi_transport_template *scsi_transport_template;
- atomic_t status; /* Module status flags */
struct list_head adapter_list_head; /* head of adapter list */
- struct list_head adapter_remove_lh; /* head of adapters to be
- removed */
- u32 adapters; /* # of adapters in list */
rwlock_t config_lock; /* serialises changes
to adapter/port/unit
lists */
@@ -656,11 +597,12 @@ struct zfcp_data {
changes */
atomic_t loglevel; /* current loglevel */
char init_busid[BUS_ID_SIZE];
- wwn_t init_wwpn;
- fcp_lun_t init_fcp_lun;
- struct kmem_cache *fsf_req_qtcb_cache;
- struct kmem_cache *sr_buffer_cache;
- struct kmem_cache *gid_pn_cache;
+ u64 init_wwpn;
+ u64 init_fcp_lun;
+ struct kmem_cache *fsf_req_qtcb_cache;
+ struct kmem_cache *sr_buffer_cache;
+ struct kmem_cache *gid_pn_cache;
+ struct workqueue_struct *work_queue;
};
/* struct used by memory pools for fsf_requests */
@@ -677,14 +619,7 @@ struct zfcp_fsf_req_qtcb {
#define ZFCP_SET 0x00000100
#define ZFCP_CLEAR 0x00000200
-#ifndef atomic_test_mask
-#define atomic_test_mask(mask, target) \
- ((atomic_read(target) & mask) == mask)
-#endif
-
#define zfcp_get_busid_by_adapter(adapter) (adapter->ccw_device->dev.bus_id)
-#define zfcp_get_busid_by_port(port) (zfcp_get_busid_by_adapter(port->adapter))
-#define zfcp_get_busid_by_unit(unit) (zfcp_get_busid_by_port(unit->port))
/*
* Helper functions for request ID management.
@@ -745,12 +680,6 @@ zfcp_unit_put(struct zfcp_unit *unit)
}
static inline void
-zfcp_unit_wait(struct zfcp_unit *unit)
-{
- wait_event(unit->remove_wq, atomic_read(&unit->refcount) == 0);
-}
-
-static inline void
zfcp_port_get(struct zfcp_port *port)
{
atomic_inc(&port->refcount);
@@ -764,12 +693,6 @@ zfcp_port_put(struct zfcp_port *port)
}
static inline void
-zfcp_port_wait(struct zfcp_port *port)
-{
- wait_event(port->remove_wq, atomic_read(&port->refcount) == 0);
-}
-
-static inline void
zfcp_adapter_get(struct zfcp_adapter *adapter)
{
atomic_inc(&adapter->refcount);
@@ -782,10 +705,4 @@ zfcp_adapter_put(struct zfcp_adapter *adapter)
wake_up(&adapter->remove_wq);
}
-static inline void
-zfcp_adapter_wait(struct zfcp_adapter *adapter)
-{
- wait_event(adapter->remove_wq, atomic_read(&adapter->refcount) == 0);
-}
-
#endif /* ZFCP_DEF_H */
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index 643ac4bba5b..78231313187 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -23,7 +23,6 @@ enum zfcp_erp_steps {
ZFCP_ERP_STEP_FSF_XCONFIG = 0x0001,
ZFCP_ERP_STEP_PHYS_PORT_CLOSING = 0x0010,
ZFCP_ERP_STEP_PORT_CLOSING = 0x0100,
- ZFCP_ERP_STEP_NAMESERVER_OPEN = 0x0200,
ZFCP_ERP_STEP_NAMESERVER_LOOKUP = 0x0400,
ZFCP_ERP_STEP_PORT_OPENING = 0x0800,
ZFCP_ERP_STEP_UNIT_CLOSING = 0x1000,
@@ -532,8 +531,7 @@ static void _zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter,
struct zfcp_port *port;
list_for_each_entry(port, &adapter->port_list_head, list)
- if (!(atomic_read(&port->status) & ZFCP_STATUS_PORT_WKA))
- _zfcp_erp_port_reopen(port, clear, id, ref);
+ _zfcp_erp_port_reopen(port, clear, id, ref);
}
static void _zfcp_erp_unit_reopen_all(struct zfcp_port *port, int clear, u8 id,
@@ -669,8 +667,6 @@ static int zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *act)
int ret;
struct zfcp_adapter *adapter = act->adapter;
- atomic_clear_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status);
-
write_lock_irq(&adapter->erp_lock);
zfcp_erp_action_to_running(act);
write_unlock_irq(&adapter->erp_lock);
@@ -741,8 +737,7 @@ static int zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *act,
ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR);
failed_qdio:
atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK |
- ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
- ZFCP_STATUS_ADAPTER_XPORT_OK,
+ ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
&act->adapter->status);
return retval;
}
@@ -751,15 +746,11 @@ static int zfcp_erp_adapter_strategy(struct zfcp_erp_action *act)
{
int retval;
- atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &act->adapter->status);
zfcp_erp_adapter_strategy_generic(act, 1); /* close */
- atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, &act->adapter->status);
if (act->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
return ZFCP_ERP_EXIT;
- atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &act->adapter->status);
retval = zfcp_erp_adapter_strategy_generic(act, 0); /* open */
- atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, &act->adapter->status);
if (retval == ZFCP_ERP_FAILED)
ssleep(8);
@@ -783,10 +774,7 @@ static int zfcp_erp_port_forced_strategy_close(struct zfcp_erp_action *act)
static void zfcp_erp_port_strategy_clearstati(struct zfcp_port *port)
{
- atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING |
- ZFCP_STATUS_COMMON_CLOSING |
- ZFCP_STATUS_COMMON_ACCESS_DENIED |
- ZFCP_STATUS_PORT_DID_DID |
+ atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
ZFCP_STATUS_PORT_PHYS_CLOSING |
ZFCP_STATUS_PORT_INVALID_WWPN,
&port->status);
@@ -839,73 +827,12 @@ static int zfcp_erp_port_strategy_open_port(struct zfcp_erp_action *erp_action)
return ZFCP_ERP_CONTINUES;
}
-static void zfcp_erp_port_strategy_open_ns_wake(struct zfcp_erp_action *ns_act)
-{
- unsigned long flags;
- struct zfcp_adapter *adapter = ns_act->adapter;
- struct zfcp_erp_action *act, *tmp;
- int status;
-
- read_lock_irqsave(&adapter->erp_lock, flags);
- list_for_each_entry_safe(act, tmp, &adapter->erp_running_head, list) {
- if (act->step == ZFCP_ERP_STEP_NAMESERVER_OPEN) {
- status = atomic_read(&adapter->nameserver_port->status);
- if (status & ZFCP_STATUS_COMMON_ERP_FAILED)
- zfcp_erp_port_failed(act->port, 27, NULL);
- zfcp_erp_action_ready(act);
- }
- }
- read_unlock_irqrestore(&adapter->erp_lock, flags);
-}
-
-static int zfcp_erp_port_strategy_open_nameserver(struct zfcp_erp_action *act)
-{
- int retval;
-
- switch (act->step) {
- case ZFCP_ERP_STEP_UNINITIALIZED:
- case ZFCP_ERP_STEP_PHYS_PORT_CLOSING:
- case ZFCP_ERP_STEP_PORT_CLOSING:
- return zfcp_erp_port_strategy_open_port(act);
-
- case ZFCP_ERP_STEP_PORT_OPENING:
- if (atomic_read(&act->port->status) & ZFCP_STATUS_COMMON_OPEN)
- retval = ZFCP_ERP_SUCCEEDED;
- else
- retval = ZFCP_ERP_FAILED;
- /* this is needed anyway */
- zfcp_erp_port_strategy_open_ns_wake(act);
- return retval;
-
- default:
- return ZFCP_ERP_FAILED;
- }
-}
-
-static int zfcp_erp_port_strategy_open_lookup(struct zfcp_erp_action *act)
-{
- int retval;
-
- retval = zfcp_fc_ns_gid_pn_request(act);
- if (retval == -ENOMEM)
- return ZFCP_ERP_NOMEM;
- act->step = ZFCP_ERP_STEP_NAMESERVER_LOOKUP;
- if (retval)
- return ZFCP_ERP_FAILED;
- return ZFCP_ERP_CONTINUES;
-}
-
static int zfcp_erp_open_ptp_port(struct zfcp_erp_action *act)
{
struct zfcp_adapter *adapter = act->adapter;
struct zfcp_port *port = act->port;
if (port->wwpn != adapter->peer_wwpn) {
- dev_err(&adapter->ccw_device->dev,
- "Failed to open port 0x%016Lx, "
- "Peer WWPN 0x%016Lx does not "
- "match.\n", port->wwpn,
- adapter->peer_wwpn);
zfcp_erp_port_failed(port, 25, NULL);
return ZFCP_ERP_FAILED;
}
@@ -914,11 +841,25 @@ static int zfcp_erp_open_ptp_port(struct zfcp_erp_action *act)
return zfcp_erp_port_strategy_open_port(act);
}
+void zfcp_erp_port_strategy_open_lookup(struct work_struct *work)
+{
+ int retval;
+ struct zfcp_port *port = container_of(work, struct zfcp_port,
+ gid_pn_work);
+
+ retval = zfcp_fc_ns_gid_pn(&port->erp_action);
+ if (retval == -ENOMEM)
+ zfcp_erp_notify(&port->erp_action, ZFCP_ERP_NOMEM);
+ port->erp_action.step = ZFCP_ERP_STEP_NAMESERVER_LOOKUP;
+ if (retval)
+ zfcp_erp_notify(&port->erp_action, ZFCP_ERP_FAILED);
+
+}
+
static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act)
{
struct zfcp_adapter *adapter = act->adapter;
struct zfcp_port *port = act->port;
- struct zfcp_port *ns_port = adapter->nameserver_port;
int p_status = atomic_read(&port->status);
switch (act->step) {
@@ -927,28 +868,10 @@ static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act)
case ZFCP_ERP_STEP_PORT_CLOSING:
if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP)
return zfcp_erp_open_ptp_port(act);
- if (!ns_port) {
- dev_err(&adapter->ccw_device->dev,
- "Nameserver port unavailable.\n");
- return ZFCP_ERP_FAILED;
- }
- if (!(atomic_read(&ns_port->status) &
- ZFCP_STATUS_COMMON_UNBLOCKED)) {
- /* nameserver port may live again */
- atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING,
- &ns_port->status);
- if (zfcp_erp_port_reopen(ns_port, 0, 77, act) >= 0) {
- act->step = ZFCP_ERP_STEP_NAMESERVER_OPEN;
- return ZFCP_ERP_CONTINUES;
- }
- return ZFCP_ERP_FAILED;
+ if (!(p_status & ZFCP_STATUS_PORT_DID_DID)) {
+ queue_work(zfcp_data.work_queue, &port->gid_pn_work);
+ return ZFCP_ERP_CONTINUES;
}
- /* else nameserver port is already open, fall through */
- case ZFCP_ERP_STEP_NAMESERVER_OPEN:
- if (!(atomic_read(&ns_port->status) & ZFCP_STATUS_COMMON_OPEN))
- return ZFCP_ERP_FAILED;
- return zfcp_erp_port_strategy_open_lookup(act);
-
case ZFCP_ERP_STEP_NAMESERVER_LOOKUP:
if (!(p_status & ZFCP_STATUS_PORT_DID_DID)) {
if (p_status & (ZFCP_STATUS_PORT_INVALID_WWPN)) {
@@ -961,25 +884,26 @@ static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act)
case ZFCP_ERP_STEP_PORT_OPENING:
/* D_ID might have changed during open */
- if ((p_status & ZFCP_STATUS_COMMON_OPEN) &&
- (p_status & ZFCP_STATUS_PORT_DID_DID))
- return ZFCP_ERP_SUCCEEDED;
+ if (p_status & ZFCP_STATUS_COMMON_OPEN) {
+ if (p_status & ZFCP_STATUS_PORT_DID_DID)
+ return ZFCP_ERP_SUCCEEDED;
+ else {
+ act->step = ZFCP_ERP_STEP_PORT_CLOSING;
+ return ZFCP_ERP_CONTINUES;
+ }
/* fall through otherwise */
+ }
}
return ZFCP_ERP_FAILED;
}
-static int zfcp_erp_port_strategy_open(struct zfcp_erp_action *act)
-{
- if (atomic_read(&act->port->status) & (ZFCP_STATUS_PORT_WKA))
- return zfcp_erp_port_strategy_open_nameserver(act);
- return zfcp_erp_port_strategy_open_common(act);
-}
-
static int zfcp_erp_port_strategy(struct zfcp_erp_action *erp_action)
{
struct zfcp_port *port = erp_action->port;
+ if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC)
+ goto close_init_done;
+
switch (erp_action->step) {
case ZFCP_ERP_STEP_UNINITIALIZED:
zfcp_erp_port_strategy_clearstati(port);
@@ -992,19 +916,17 @@ static int zfcp_erp_port_strategy(struct zfcp_erp_action *erp_action)
return ZFCP_ERP_FAILED;
break;
}
+
+close_init_done:
if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
return ZFCP_ERP_EXIT;
- else
- return zfcp_erp_port_strategy_open(erp_action);
- return ZFCP_ERP_FAILED;
+ return zfcp_erp_port_strategy_open_common(erp_action);
}
static void zfcp_erp_unit_strategy_clearstati(struct zfcp_unit *unit)
{
- atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING |
- ZFCP_STATUS_COMMON_CLOSING |
- ZFCP_STATUS_COMMON_ACCESS_DENIED |
+ atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
ZFCP_STATUS_UNIT_SHARED |
ZFCP_STATUS_UNIT_READONLY,
&unit->status);
@@ -1065,8 +987,14 @@ static int zfcp_erp_strategy_check_unit(struct zfcp_unit *unit, int result)
break;
case ZFCP_ERP_FAILED :
atomic_inc(&unit->erp_counter);
- if (atomic_read(&unit->erp_counter) > ZFCP_MAX_ERPS)
+ if (atomic_read(&unit->erp_counter) > ZFCP_MAX_ERPS) {
+ dev_err(&unit->port->adapter->ccw_device->dev,
+ "ERP failed for unit 0x%016Lx on "
+ "port 0x%016Lx\n",
+ (unsigned long long)unit->fcp_lun,
+ (unsigned long long)unit->port->wwpn);
zfcp_erp_unit_failed(unit, 21, NULL);
+ }
break;
}
@@ -1091,8 +1019,12 @@ static int zfcp_erp_strategy_check_port(struct zfcp_port *port, int result)
result = ZFCP_ERP_EXIT;
}
atomic_inc(&port->erp_counter);
- if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS)
+ if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS) {
+ dev_err(&port->adapter->ccw_device->dev,
+ "ERP failed for remote port 0x%016Lx\n",
+ (unsigned long long)port->wwpn);
zfcp_erp_port_failed(port, 22, NULL);
+ }
break;
}
@@ -1114,8 +1046,12 @@ static int zfcp_erp_strategy_check_adapter(struct zfcp_adapter *adapter,
case ZFCP_ERP_FAILED :
atomic_inc(&adapter->erp_counter);
- if (atomic_read(&adapter->erp_counter) > ZFCP_MAX_ERPS)
+ if (atomic_read(&adapter->erp_counter) > ZFCP_MAX_ERPS) {
+ dev_err(&adapter->ccw_device->dev,
+ "ERP cannot recover an error "
+ "on the FCP device\n");
zfcp_erp_adapter_failed(adapter, 23, NULL);
+ }
break;
}
@@ -1250,9 +1186,10 @@ static void zfcp_erp_scsi_scan(struct work_struct *work)
struct zfcp_unit *unit = p->unit;
struct fc_rport *rport = unit->port->rport;
scsi_scan_target(&rport->dev, 0, rport->scsi_target_id,
- unit->scsi_lun, 0);
+ scsilun_to_int((struct scsi_lun *)&unit->fcp_lun), 0);
atomic_clear_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status);
zfcp_unit_put(unit);
+ wake_up(&unit->port->adapter->erp_done_wqh);
kfree(p);
}
@@ -1263,9 +1200,9 @@ static void zfcp_erp_schedule_work(struct zfcp_unit *unit)
p = kzalloc(sizeof(*p), GFP_KERNEL);
if (!p) {
dev_err(&unit->port->adapter->ccw_device->dev,
- "Out of resources. Could not register unit "
- "0x%016Lx on port 0x%016Lx with SCSI stack.\n",
- unit->fcp_lun, unit->port->wwpn);
+ "Registering unit 0x%016Lx on port 0x%016Lx failed\n",
+ (unsigned long long)unit->fcp_lun,
+ (unsigned long long)unit->port->wwpn);
return;
}
@@ -1273,7 +1210,7 @@ static void zfcp_erp_schedule_work(struct zfcp_unit *unit)
atomic_set_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status);
INIT_WORK(&p->work, zfcp_erp_scsi_scan);
p->unit = unit;
- schedule_work(&p->work);
+ queue_work(zfcp_data.work_queue, &p->work);
}
static void zfcp_erp_rport_register(struct zfcp_port *port)
@@ -1286,8 +1223,8 @@ static void zfcp_erp_rport_register(struct zfcp_port *port)
port->rport = fc_remote_port_add(port->adapter->scsi_host, 0, &ids);
if (!port->rport) {
dev_err(&port->adapter->ccw_device->dev,
- "Failed registration of rport "
- "0x%016Lx.\n", port->wwpn);
+ "Registering port 0x%016Lx failed\n",
+ (unsigned long long)port->wwpn);
return;
}
@@ -1299,12 +1236,12 @@ static void zfcp_erp_rport_register(struct zfcp_port *port)
static void zfcp_erp_rports_del(struct zfcp_adapter *adapter)
{
struct zfcp_port *port;
- list_for_each_entry(port, &adapter->port_list_head, list)
- if (port->rport && !(atomic_read(&port->status) &
- ZFCP_STATUS_PORT_WKA)) {
- fc_remote_port_delete(port->rport);
- port->rport = NULL;
- }
+ list_for_each_entry(port, &adapter->port_list_head, list) {
+ if (!port->rport)
+ continue;
+ fc_remote_port_delete(port->rport);
+ port->rport = NULL;
+ }
}
static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
@@ -1459,9 +1396,9 @@ static int zfcp_erp_thread(void *data)
zfcp_erp_wakeup(adapter);
}
- zfcp_rec_dbf_event_thread(4, adapter);
+ zfcp_rec_dbf_event_thread_lock(4, adapter);
down_interruptible(&adapter->erp_ready_sem);
- zfcp_rec_dbf_event_thread(5, adapter);
+ zfcp_rec_dbf_event_thread_lock(5, adapter);
}
atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status);
@@ -1484,7 +1421,7 @@ int zfcp_erp_thread_setup(struct zfcp_adapter *adapter)
retval = kernel_thread(zfcp_erp_thread, adapter, SIGCHLD);
if (retval < 0) {
dev_err(&adapter->ccw_device->dev,
- "Creation of ERP thread failed.\n");
+ "Creating an ERP thread for the FCP device failed.\n");
return retval;
}
wait_event(adapter->erp_thread_wqh,
@@ -1506,7 +1443,7 @@ void zfcp_erp_thread_kill(struct zfcp_adapter *adapter)
{
atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, &adapter->status);
up(&adapter->erp_ready_sem);
- zfcp_rec_dbf_event_thread_lock(2, adapter);
+ zfcp_rec_dbf_event_thread_lock(3, adapter);
wait_event(adapter->erp_thread_wqh,
!(atomic_read(&adapter->status) &
@@ -1526,7 +1463,6 @@ void zfcp_erp_adapter_failed(struct zfcp_adapter *adapter, u8 id, void *ref)
{
zfcp_erp_modify_adapter_status(adapter, id, ref,
ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET);
- dev_err(&adapter->ccw_device->dev, "Adapter ERP failed.\n");
}
/**
@@ -1539,15 +1475,6 @@ void zfcp_erp_port_failed(struct zfcp_port *port, u8 id, void *ref)
{
zfcp_erp_modify_port_status(port, id, ref,
ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET);
-
- if (atomic_read(&port->status) & ZFCP_STATUS_PORT_WKA)
- dev_err(&port->adapter->ccw_device->dev,
- "Port ERP failed for WKA port d_id=0x%06x.\n",
- port->d_id);
- else
- dev_err(&port->adapter->ccw_device->dev,
- "Port ERP failed for port wwpn=0x%016Lx.\n",
- port->wwpn);
}
/**
@@ -1560,10 +1487,6 @@ void zfcp_erp_unit_failed(struct zfcp_unit *unit, u8 id, void *ref)
{
zfcp_erp_modify_unit_status(unit, id, ref,
ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET);
-
- dev_err(&unit->port->adapter->ccw_device->dev,
- "Unit ERP failed for unit 0x%016Lx on port 0x%016Lx.\n",
- unit->fcp_lun, unit->port->wwpn);
}
/**
@@ -1754,9 +1677,8 @@ static void zfcp_erp_port_access_changed(struct zfcp_port *port, u8 id,
if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED |
ZFCP_STATUS_COMMON_ACCESS_BOXED))) {
- if (!(status & ZFCP_STATUS_PORT_WKA))
- list_for_each_entry(unit, &port->unit_list_head, list)
- zfcp_erp_unit_access_changed(unit, id, ref);
+ list_for_each_entry(unit, &port->unit_list_head, list)
+ zfcp_erp_unit_access_changed(unit, id, ref);
return;
}
@@ -1779,10 +1701,7 @@ void zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter, u8 id,
return;
read_lock_irqsave(&zfcp_data.config_lock, flags);
- if (adapter->nameserver_port)
- zfcp_erp_port_access_changed(adapter->nameserver_port, id, ref);
list_for_each_entry(port, &adapter->port_list_head, list)
- if (port != adapter->nameserver_port)
- zfcp_erp_port_access_changed(port, id, ref);
+ zfcp_erp_port_access_changed(port, id, ref);
read_unlock_irqrestore(&zfcp_data.config_lock, flags);
}
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
index edfdb21591f..b5adeda93e1 100644
--- a/drivers/s390/scsi/zfcp_ext.h
+++ b/drivers/s390/scsi/zfcp_ext.h
@@ -12,16 +12,14 @@
#include "zfcp_def.h"
/* zfcp_aux.c */
-extern struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *,
- fcp_lun_t);
-extern struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *,
- wwn_t);
+extern struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *, u64);
+extern struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *, u64);
extern int zfcp_adapter_enqueue(struct ccw_device *);
extern void zfcp_adapter_dequeue(struct zfcp_adapter *);
-extern struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *, wwn_t, u32,
+extern struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *, u64, u32,
u32);
extern void zfcp_port_dequeue(struct zfcp_port *);
-extern struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *, fcp_lun_t);
+extern struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *, u64);
extern void zfcp_unit_dequeue(struct zfcp_unit *);
extern int zfcp_reqlist_isempty(struct zfcp_adapter *);
extern void zfcp_sg_free_table(struct scatterlist *, int);
@@ -29,6 +27,7 @@ extern int zfcp_sg_setup_table(struct scatterlist *, int);
/* zfcp_ccw.c */
extern int zfcp_ccw_register(void);
+extern struct zfcp_adapter *zfcp_get_adapter_by_busid(char *);
/* zfcp_cfdc.c */
extern struct miscdevice zfcp_cfdc_misc;
@@ -50,6 +49,8 @@ extern void zfcp_hba_dbf_event_fsf_unsol(const char *, struct zfcp_adapter *,
struct fsf_status_read_buffer *);
extern void zfcp_hba_dbf_event_qdio(struct zfcp_adapter *, unsigned int, int,
int);
+extern void zfcp_hba_dbf_event_berr(struct zfcp_adapter *,
+ struct zfcp_fsf_req *);
extern void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *);
extern void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *);
extern void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *);
@@ -91,17 +92,21 @@ extern void zfcp_erp_port_access_denied(struct zfcp_port *, u8, void *);
extern void zfcp_erp_unit_access_denied(struct zfcp_unit *, u8, void *);
extern void zfcp_erp_adapter_access_changed(struct zfcp_adapter *, u8, void *);
extern void zfcp_erp_timeout_handler(unsigned long);
+extern void zfcp_erp_port_strategy_open_lookup(struct work_struct *);
/* zfcp_fc.c */
extern int zfcp_scan_ports(struct zfcp_adapter *);
extern void _zfcp_scan_ports_later(struct work_struct *);
extern void zfcp_fc_incoming_els(struct zfcp_fsf_req *);
-extern int zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *);
+extern int zfcp_fc_ns_gid_pn(struct zfcp_erp_action *);
extern void zfcp_fc_plogi_evaluate(struct zfcp_port *, struct fsf_plogi *);
extern void zfcp_test_link(struct zfcp_port *);
+extern void zfcp_fc_nameserver_init(struct zfcp_adapter *);
/* zfcp_fsf.c */
extern int zfcp_fsf_open_port(struct zfcp_erp_action *);
+extern int zfcp_fsf_open_wka_port(struct zfcp_wka_port *);
+extern int zfcp_fsf_close_wka_port(struct zfcp_wka_port *);
extern int zfcp_fsf_close_port(struct zfcp_erp_action *);
extern int zfcp_fsf_close_physical_port(struct zfcp_erp_action *);
extern int zfcp_fsf_open_unit(struct zfcp_erp_action *);
@@ -135,10 +140,8 @@ extern struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long,
extern int zfcp_qdio_allocate(struct zfcp_adapter *);
extern void zfcp_qdio_free(struct zfcp_adapter *);
extern int zfcp_qdio_send(struct zfcp_fsf_req *);
-extern volatile struct qdio_buffer_element *zfcp_qdio_sbale_req(
- struct zfcp_fsf_req *);
-extern volatile struct qdio_buffer_element *zfcp_qdio_sbale_curr(
- struct zfcp_fsf_req *);
+extern struct qdio_buffer_element *zfcp_qdio_sbale_req(struct zfcp_fsf_req *);
+extern struct qdio_buffer_element *zfcp_qdio_sbale_curr(struct zfcp_fsf_req *);
extern int zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *, unsigned long,
struct scatterlist *, int);
extern int zfcp_qdio_open(struct zfcp_adapter *);
@@ -148,14 +151,12 @@ extern void zfcp_qdio_close(struct zfcp_adapter *);
extern struct zfcp_data zfcp_data;
extern int zfcp_adapter_scsi_register(struct zfcp_adapter *);
extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *);
-extern void zfcp_set_fcp_dl(struct fcp_cmnd_iu *, fcp_dl_t);
extern char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *);
extern struct fc_function_template zfcp_transport_functions;
/* zfcp_sysfs.c */
extern struct attribute_group zfcp_sysfs_unit_attrs;
extern struct attribute_group zfcp_sysfs_adapter_attrs;
-extern struct attribute_group zfcp_sysfs_ns_port_attrs;
extern struct attribute_group zfcp_sysfs_port_attrs;
extern struct device_attribute *zfcp_sysfs_sdev_attrs[];
extern struct device_attribute *zfcp_sysfs_shost_attrs[];
diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c
index e984469bb98..1a7c80a77ff 100644
--- a/drivers/s390/scsi/zfcp_fc.c
+++ b/drivers/s390/scsi/zfcp_fc.c
@@ -39,16 +39,82 @@ struct zfcp_gpn_ft {
struct scatterlist sg_resp[ZFCP_GPN_FT_BUFFERS];
};
-static struct zfcp_port *zfcp_get_port_by_did(struct zfcp_adapter *adapter,
- u32 d_id)
+struct zfcp_fc_ns_handler_data {
+ struct completion done;
+ void (*handler)(unsigned long);
+ unsigned long handler_data;
+};
+
+static int zfcp_wka_port_get(struct zfcp_wka_port *wka_port)
{
- struct zfcp_port *port;
+ if (mutex_lock_interruptible(&wka_port->mutex))
+ return -ERESTARTSYS;
- list_for_each_entry(port, &adapter->port_list_head, list)
- if ((port->d_id == d_id) &&
- !atomic_test_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status))
- return port;
- return NULL;
+ if (wka_port->status != ZFCP_WKA_PORT_ONLINE) {
+ wka_port->status = ZFCP_WKA_PORT_OPENING;
+ if (zfcp_fsf_open_wka_port(wka_port))
+ wka_port->status = ZFCP_WKA_PORT_OFFLINE;
+ }
+
+ mutex_unlock(&wka_port->mutex);
+
+ wait_event_timeout(
+ wka_port->completion_wq,
+ wka_port->status == ZFCP_WKA_PORT_ONLINE ||
+ wka_port->status == ZFCP_WKA_PORT_OFFLINE,
+ HZ >> 1);
+
+ if (wka_port->status == ZFCP_WKA_PORT_ONLINE) {
+ atomic_inc(&wka_port->refcount);
+ return 0;
+ }
+ return -EIO;
+}
+
+static void zfcp_wka_port_offline(struct work_struct *work)
+{
+ struct delayed_work *dw = container_of(work, struct delayed_work, work);
+ struct zfcp_wka_port *wka_port =
+ container_of(dw, struct zfcp_wka_port, work);
+
+ wait_event(wka_port->completion_wq,
+ atomic_read(&wka_port->refcount) == 0);
+
+ mutex_lock(&wka_port->mutex);
+ if ((atomic_read(&wka_port->refcount) != 0) ||
+ (wka_port->status != ZFCP_WKA_PORT_ONLINE))
+ goto out;
+
+ wka_port->status = ZFCP_WKA_PORT_CLOSING;
+ if (zfcp_fsf_close_wka_port(wka_port)) {
+ wka_port->status = ZFCP_WKA_PORT_OFFLINE;
+ wake_up(&wka_port->completion_wq);
+ }
+out:
+ mutex_unlock(&wka_port->mutex);
+}
+
+static void zfcp_wka_port_put(struct zfcp_wka_port *wka_port)
+{
+ if (atomic_dec_return(&wka_port->refcount) != 0)
+ return;
+ /* wait 10 miliseconds, other reqs might pop in */
+ schedule_delayed_work(&wka_port->work, HZ / 100);
+}
+
+void zfcp_fc_nameserver_init(struct zfcp_adapter *adapter)
+{
+ struct zfcp_wka_port *wka_port = &adapter->nsp;
+
+ init_waitqueue_head(&wka_port->completion_wq);
+
+ wka_port->adapter = adapter;
+ wka_port->d_id = ZFCP_DID_DIRECTORY_SERVICE;
+
+ wka_port->status = ZFCP_WKA_PORT_OFFLINE;
+ atomic_set(&wka_port->refcount, 0);
+ mutex_init(&wka_port->mutex);
+ INIT_DELAYED_WORK(&wka_port->work, zfcp_wka_port_offline);
}
static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range,
@@ -59,10 +125,8 @@ static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range,
read_lock_irqsave(&zfcp_data.config_lock, flags);
list_for_each_entry(port, &fsf_req->adapter->port_list_head, list) {
- if (atomic_test_mask(ZFCP_STATUS_PORT_WKA, &port->status))
- continue;
/* FIXME: ZFCP_STATUS_PORT_DID_DID check is racy */
- if (!atomic_test_mask(ZFCP_STATUS_PORT_DID_DID, &port->status))
+ if (!(atomic_read(&port->status) & ZFCP_STATUS_PORT_DID_DID))
/* Try to connect to unused ports anyway. */
zfcp_erp_port_reopen(port,
ZFCP_STATUS_COMMON_ERP_FAILED,
@@ -114,7 +178,7 @@ static void zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req)
schedule_work(&fsf_req->adapter->scan_work);
}
-static void zfcp_fc_incoming_wwpn(struct zfcp_fsf_req *req, wwn_t wwpn)
+static void zfcp_fc_incoming_wwpn(struct zfcp_fsf_req *req, u64 wwpn)
{
struct zfcp_adapter *adapter = req->adapter;
struct zfcp_port *port;
@@ -169,7 +233,18 @@ void zfcp_fc_incoming_els(struct zfcp_fsf_req *fsf_req)
zfcp_fc_incoming_rscn(fsf_req);
}
-static void zfcp_ns_gid_pn_handler(unsigned long data)
+static void zfcp_fc_ns_handler(unsigned long data)
+{
+ struct zfcp_fc_ns_handler_data *compl_rec =
+ (struct zfcp_fc_ns_handler_data *) data;
+
+ if (compl_rec->handler)
+ compl_rec->handler(compl_rec->handler_data);
+
+ complete(&compl_rec->done);
+}
+
+static void zfcp_fc_ns_gid_pn_eval(unsigned long data)
{
struct zfcp_gid_pn_data *gid_pn = (struct zfcp_gid_pn_data *) data;
struct zfcp_send_ct *ct = &gid_pn->ct;
@@ -178,43 +253,31 @@ static void zfcp_ns_gid_pn_handler(unsigned long data)
struct zfcp_port *port = gid_pn->port;
if (ct->status)
- goto out;
+ return;
if (ct_iu_resp->header.cmd_rsp_code != ZFCP_CT_ACCEPT) {
atomic_set_mask(ZFCP_STATUS_PORT_INVALID_WWPN, &port->status);
- goto out;
+ return;
}
/* paranoia */
if (ct_iu_req->wwpn != port->wwpn)
- goto out;
+ return;
/* looks like a valid d_id */
port->d_id = ct_iu_resp->d_id & ZFCP_DID_MASK;
atomic_set_mask(ZFCP_STATUS_PORT_DID_DID, &port->status);
-out:
- mempool_free(gid_pn, port->adapter->pool.data_gid_pn);
}
-/**
- * zfcp_fc_ns_gid_pn_request - initiate GID_PN nameserver request
- * @erp_action: pointer to zfcp_erp_action where GID_PN request is needed
- * return: -ENOMEM on error, 0 otherwise
- */
-int zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action)
+int static zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action,
+ struct zfcp_gid_pn_data *gid_pn)
{
- int ret;
- struct zfcp_gid_pn_data *gid_pn;
struct zfcp_adapter *adapter = erp_action->adapter;
-
- gid_pn = mempool_alloc(adapter->pool.data_gid_pn, GFP_ATOMIC);
- if (!gid_pn)
- return -ENOMEM;
-
- memset(gid_pn, 0, sizeof(*gid_pn));
+ struct zfcp_fc_ns_handler_data compl_rec;
+ int ret;
/* setup parameters for send generic command */
gid_pn->port = erp_action->port;
- gid_pn->ct.port = adapter->nameserver_port;
- gid_pn->ct.handler = zfcp_ns_gid_pn_handler;
- gid_pn->ct.handler_data = (unsigned long) gid_pn;
+ gid_pn->ct.wka_port = &adapter->nsp;
+ gid_pn->ct.handler = zfcp_fc_ns_handler;
+ gid_pn->ct.handler_data = (unsigned long) &compl_rec;
gid_pn->ct.timeout = ZFCP_NS_GID_PN_TIMEOUT;
gid_pn->ct.req = &gid_pn->req;
gid_pn->ct.resp = &gid_pn->resp;
@@ -234,10 +297,42 @@ int zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action)
gid_pn->ct_iu_req.header.max_res_size = ZFCP_CT_MAX_SIZE;
gid_pn->ct_iu_req.wwpn = erp_action->port->wwpn;
+ init_completion(&compl_rec.done);
+ compl_rec.handler = zfcp_fc_ns_gid_pn_eval;
+ compl_rec.handler_data = (unsigned long) gid_pn;
ret = zfcp_fsf_send_ct(&gid_pn->ct, adapter->pool.fsf_req_erp,
erp_action);
+ if (!ret)
+ wait_for_completion(&compl_rec.done);
+ return ret;
+}
+
+/**
+ * zfcp_fc_ns_gid_pn_request - initiate GID_PN nameserver request
+ * @erp_action: pointer to zfcp_erp_action where GID_PN request is needed
+ * return: -ENOMEM on error, 0 otherwise
+ */
+int zfcp_fc_ns_gid_pn(struct zfcp_erp_action *erp_action)
+{
+ int ret;
+ struct zfcp_gid_pn_data *gid_pn;
+ struct zfcp_adapter *adapter = erp_action->adapter;
+
+ gid_pn = mempool_alloc(adapter->pool.data_gid_pn, GFP_ATOMIC);
+ if (!gid_pn)
+ return -ENOMEM;
+
+ memset(gid_pn, 0, sizeof(*gid_pn));
+
+ ret = zfcp_wka_port_get(&adapter->nsp);
if (ret)
- mempool_free(gid_pn, adapter->pool.data_gid_pn);
+ goto out;
+
+ ret = zfcp_fc_ns_gid_pn_request(erp_action, gid_pn);
+
+ zfcp_wka_port_put(&adapter->nsp);
+out:
+ mempool_free(gid_pn, adapter->pool.data_gid_pn);
return ret;
}
@@ -267,14 +362,14 @@ struct zfcp_els_adisc {
struct scatterlist req;
struct scatterlist resp;
struct zfcp_ls_adisc ls_adisc;
- struct zfcp_ls_adisc_acc ls_adisc_acc;
+ struct zfcp_ls_adisc ls_adisc_acc;
};
static void zfcp_fc_adisc_handler(unsigned long data)
{
struct zfcp_els_adisc *adisc = (struct zfcp_els_adisc *) data;
struct zfcp_port *port = adisc->els.port;
- struct zfcp_ls_adisc_acc *ls_adisc = &adisc->ls_adisc_acc;
+ struct zfcp_ls_adisc *ls_adisc = &adisc->ls_adisc_acc;
if (adisc->els.status) {
/* request rejected or timed out */
@@ -307,7 +402,7 @@ static int zfcp_fc_adisc(struct zfcp_port *port)
sg_init_one(adisc->els.req, &adisc->ls_adisc,
sizeof(struct zfcp_ls_adisc));
sg_init_one(adisc->els.resp, &adisc->ls_adisc_acc,
- sizeof(struct zfcp_ls_adisc_acc));
+ sizeof(struct zfcp_ls_adisc));
adisc->els.req_count = 1;
adisc->els.resp_count = 1;
@@ -341,37 +436,13 @@ void zfcp_test_link(struct zfcp_port *port)
zfcp_port_get(port);
retval = zfcp_fc_adisc(port);
- if (retval == 0 || retval == -EBUSY)
+ if (retval == 0)
return;
/* send of ADISC was not possible */
zfcp_port_put(port);
- zfcp_erp_port_forced_reopen(port, 0, 65, NULL);
-}
-
-static int zfcp_scan_get_nameserver(struct zfcp_adapter *adapter)
-{
- int ret;
-
- if (!adapter->nameserver_port)
- return -EINTR;
-
- if (!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED,
- &adapter->nameserver_port->status)) {
- ret = zfcp_erp_port_reopen(adapter->nameserver_port, 0, 148,
- NULL);
- if (ret)
- return ret;
- zfcp_erp_wait(adapter);
- zfcp_port_put(adapter->nameserver_port);
- }
- return !atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED,
- &adapter->nameserver_port->status);
-}
-
-static void zfcp_gpn_ft_handler(unsigned long _done)
-{
- complete((struct completion *)_done);
+ if (retval != -EBUSY)
+ zfcp_erp_port_forced_reopen(port, 0, 65, NULL);
}
static void zfcp_free_sg_env(struct zfcp_gpn_ft *gpn_ft)
@@ -415,7 +486,7 @@ static int zfcp_scan_issue_gpn_ft(struct zfcp_gpn_ft *gpn_ft,
{
struct zfcp_send_ct *ct = &gpn_ft->ct;
struct ct_iu_gpn_ft_req *req = sg_virt(&gpn_ft->sg_req);
- struct completion done;
+ struct zfcp_fc_ns_handler_data compl_rec;
int ret;
/* prepare CT IU for GPN_FT */
@@ -432,19 +503,20 @@ static int zfcp_scan_issue_gpn_ft(struct zfcp_gpn_ft *gpn_ft,
req->fc4_type = ZFCP_CT_SCSI_FCP;
/* prepare zfcp_send_ct */
- ct->port = adapter->nameserver_port;
- ct->handler = zfcp_gpn_ft_handler;
- ct->handler_data = (unsigned long)&done;
+ ct->wka_port = &adapter->nsp;
+ ct->handler = zfcp_fc_ns_handler;
+ ct->handler_data = (unsigned long)&compl_rec;
ct->timeout = 10;
ct->req = &gpn_ft->sg_req;
ct->resp = gpn_ft->sg_resp;
ct->req_count = 1;
ct->resp_count = ZFCP_GPN_FT_BUFFERS;
- init_completion(&done);
+ init_completion(&compl_rec.done);
+ compl_rec.handler = NULL;
ret = zfcp_fsf_send_ct(ct, NULL, NULL);
if (!ret)
- wait_for_completion(&done);
+ wait_for_completion(&compl_rec.done);
return ret;
}
@@ -454,9 +526,8 @@ static void zfcp_validate_port(struct zfcp_port *port)
atomic_clear_mask(ZFCP_STATUS_COMMON_NOESC, &port->status);
- if (port == adapter->nameserver_port)
- return;
- if ((port->supported_classes != 0) || (port->units != 0)) {
+ if ((port->supported_classes != 0) ||
+ !list_empty(&port->unit_list_head)) {
zfcp_port_put(port);
return;
}
@@ -472,10 +543,10 @@ static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft)
struct scatterlist *sg = gpn_ft->sg_resp;
struct ct_hdr *hdr = sg_virt(sg);
struct gpn_ft_resp_acc *acc = sg_virt(sg);
- struct zfcp_adapter *adapter = ct->port->adapter;
+ struct zfcp_adapter *adapter = ct->wka_port->adapter;
struct zfcp_port *port, *tmp;
u32 d_id;
- int ret = 0, x;
+ int ret = 0, x, last = 0;
if (ct->status)
return -EIO;
@@ -492,19 +563,27 @@ static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft)
down(&zfcp_data.config_sema);
/* first entry is the header */
- for (x = 1; x < ZFCP_GPN_FT_MAX_ENTRIES; x++) {
+ for (x = 1; x < ZFCP_GPN_FT_MAX_ENTRIES && !last; x++) {
if (x % (ZFCP_GPN_FT_ENTRIES + 1))
acc++;
else
acc = sg_virt(++sg);
+ last = acc->control & 0x80;
d_id = acc->port_id[0] << 16 | acc->port_id[1] << 8 |
acc->port_id[2];
+ /* don't attach ports with a well known address */
+ if ((d_id & ZFCP_DID_WKA) == ZFCP_DID_WKA)
+ continue;
/* skip the adapter's port and known remote ports */
- if (acc->wwpn == fc_host_port_name(adapter->scsi_host) ||
- zfcp_get_port_by_did(adapter, d_id))
+ if (acc->wwpn == fc_host_port_name(adapter->scsi_host))
continue;
+ port = zfcp_get_port_by_wwpn(adapter, acc->wwpn);
+ if (port) {
+ zfcp_port_get(port);
+ continue;
+ }
port = zfcp_port_enqueue(adapter, acc->wwpn,
ZFCP_STATUS_PORT_DID_DID |
@@ -513,8 +592,6 @@ static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft)
ret = PTR_ERR(port);
else
zfcp_erp_port_reopen(port, 0, 149, NULL);
- if (acc->control & 0x80) /* last entry */
- break;
}
zfcp_erp_wait(adapter);
@@ -537,13 +614,15 @@ int zfcp_scan_ports(struct zfcp_adapter *adapter)
if (fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPORT)
return 0;
- ret = zfcp_scan_get_nameserver(adapter);
+ ret = zfcp_wka_port_get(&adapter->nsp);
if (ret)
return ret;
gpn_ft = zfcp_alloc_sg_env();
- if (!gpn_ft)
- return -ENOMEM;
+ if (!gpn_ft) {
+ ret = -ENOMEM;
+ goto out;
+ }
for (i = 0; i < 3; i++) {
ret = zfcp_scan_issue_gpn_ft(gpn_ft, adapter);
@@ -556,7 +635,8 @@ int zfcp_scan_ports(struct zfcp_adapter *adapter)
}
}
zfcp_free_sg_env(gpn_ft);
-
+out:
+ zfcp_wka_port_put(&adapter->nsp);
return ret;
}
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 19c1ca91387..739356a5c12 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -50,19 +50,16 @@ static u32 fsf_qtcb_type[] = {
[FSF_QTCB_UPLOAD_CONTROL_FILE] = FSF_SUPPORT_COMMAND
};
-static const char *zfcp_act_subtable_type[] = {
- "unknown", "OS", "WWPN", "DID", "LUN"
-};
-
static void zfcp_act_eval_err(struct zfcp_adapter *adapter, u32 table)
{
u16 subtable = table >> 16;
u16 rule = table & 0xffff;
+ const char *act_type[] = { "unknown", "OS", "WWPN", "DID", "LUN" };
- if (subtable && subtable < ARRAY_SIZE(zfcp_act_subtable_type))
+ if (subtable && subtable < ARRAY_SIZE(act_type))
dev_warn(&adapter->ccw_device->dev,
- "Access denied in subtable %s, rule %d.\n",
- zfcp_act_subtable_type[subtable], rule);
+ "Access denied according to ACT rule type %s, "
+ "rule %d\n", act_type[subtable], rule);
}
static void zfcp_fsf_access_denied_port(struct zfcp_fsf_req *req,
@@ -70,8 +67,8 @@ static void zfcp_fsf_access_denied_port(struct zfcp_fsf_req *req,
{
struct fsf_qtcb_header *header = &req->qtcb->header;
dev_warn(&req->adapter->ccw_device->dev,
- "Access denied, cannot send command to port 0x%016Lx.\n",
- port->wwpn);
+ "Access denied to port 0x%016Lx\n",
+ (unsigned long long)port->wwpn);
zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[0]);
zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[1]);
zfcp_erp_port_access_denied(port, 55, req);
@@ -83,8 +80,9 @@ static void zfcp_fsf_access_denied_unit(struct zfcp_fsf_req *req,
{
struct fsf_qtcb_header *header = &req->qtcb->header;
dev_warn(&req->adapter->ccw_device->dev,
- "Access denied for unit 0x%016Lx on port 0x%016Lx.\n",
- unit->fcp_lun, unit->port->wwpn);
+ "Access denied to unit 0x%016Lx on port 0x%016Lx\n",
+ (unsigned long long)unit->fcp_lun,
+ (unsigned long long)unit->port->wwpn);
zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[0]);
zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[1]);
zfcp_erp_unit_access_denied(unit, 59, req);
@@ -93,9 +91,8 @@ static void zfcp_fsf_access_denied_unit(struct zfcp_fsf_req *req,
static void zfcp_fsf_class_not_supp(struct zfcp_fsf_req *req)
{
- dev_err(&req->adapter->ccw_device->dev,
- "Required FC class not supported by adapter, "
- "shutting down adapter.\n");
+ dev_err(&req->adapter->ccw_device->dev, "FCP device not "
+ "operational because of an unsupported FC class\n");
zfcp_erp_adapter_shutdown(req->adapter, 0, 123, req);
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
}
@@ -171,42 +168,6 @@ static void zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *req)
read_unlock_irqrestore(&zfcp_data.config_lock, flags);
}
-static void zfcp_fsf_bit_error_threshold(struct zfcp_fsf_req *req)
-{
- struct zfcp_adapter *adapter = req->adapter;
- struct fsf_status_read_buffer *sr_buf = req->data;
- struct fsf_bit_error_payload *err = &sr_buf->payload.bit_error;
-
- dev_warn(&adapter->ccw_device->dev,
- "Warning: bit error threshold data "
- "received for the adapter: "
- "link failures = %i, loss of sync errors = %i, "
- "loss of signal errors = %i, "
- "primitive sequence errors = %i, "
- "invalid transmission word errors = %i, "
- "CRC errors = %i).\n",
- err->link_failure_error_count,
- err->loss_of_sync_error_count,
- err->loss_of_signal_error_count,
- err->primitive_sequence_error_count,
- err->invalid_transmission_word_error_count,
- err->crc_error_count);
- dev_warn(&adapter->ccw_device->dev,
- "Additional bit error threshold data of the adapter: "
- "primitive sequence event time-outs = %i, "
- "elastic buffer overrun errors = %i, "
- "advertised receive buffer-to-buffer credit = %i, "
- "current receice buffer-to-buffer credit = %i, "
- "advertised transmit buffer-to-buffer credit = %i, "
- "current transmit buffer-to-buffer credit = %i).\n",
- err->primitive_sequence_event_timeout_count,
- err->elastic_buffer_overrun_error_count,
- err->advertised_receive_b2b_credit,
- err->current_receive_b2b_credit,
- err->advertised_transmit_b2b_credit,
- err->current_transmit_b2b_credit);
-}
-
static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req, u8 id,
struct fsf_link_down_info *link_down)
{
@@ -223,62 +184,66 @@ static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req, u8 id,
switch (link_down->error_code) {
case FSF_PSQ_LINK_NO_LIGHT:
dev_warn(&req->adapter->ccw_device->dev,
- "The local link is down: no light detected.\n");
+ "There is no light signal from the local "
+ "fibre channel cable\n");
break;
case FSF_PSQ_LINK_WRAP_PLUG:
dev_warn(&req->adapter->ccw_device->dev,
- "The local link is down: wrap plug detected.\n");
+ "There is a wrap plug instead of a fibre "
+ "channel cable\n");
break;
case FSF_PSQ_LINK_NO_FCP:
dev_warn(&req->adapter->ccw_device->dev,
- "The local link is down: "
- "adjacent node on link does not support FCP.\n");
+ "The adjacent fibre channel node does not "
+ "support FCP\n");
break;
case FSF_PSQ_LINK_FIRMWARE_UPDATE:
dev_warn(&req->adapter->ccw_device->dev,
- "The local link is down: "
- "firmware update in progress.\n");
+ "The FCP device is suspended because of a "
+ "firmware update\n");
break;
case FSF_PSQ_LINK_INVALID_WWPN:
dev_warn(&req->adapter->ccw_device->dev,
- "The local link is down: "
- "duplicate or invalid WWPN detected.\n");
+ "The FCP device detected a WWPN that is "
+ "duplicate or not valid\n");
break;
case FSF_PSQ_LINK_NO_NPIV_SUPPORT:
dev_warn(&req->adapter->ccw_device->dev,
- "The local link is down: "
- "no support for NPIV by Fabric.\n");
+ "The fibre channel fabric does not support NPIV\n");
break;
case FSF_PSQ_LINK_NO_FCP_RESOURCES:
dev_warn(&req->adapter->ccw_device->dev,
- "The local link is down: "
- "out of resource in FCP daughtercard.\n");
+ "The FCP adapter cannot support more NPIV ports\n");
break;
case FSF_PSQ_LINK_NO_FABRIC_RESOURCES:
dev_warn(&req->adapter->ccw_device->dev,
- "The local link is down: "
- "out of resource in Fabric.\n");
+ "The adjacent switch cannot support "
+ "more NPIV ports\n");
break;
case FSF_PSQ_LINK_FABRIC_LOGIN_UNABLE:
dev_warn(&req->adapter->ccw_device->dev,
- "The local link is down: "
- "unable to login to Fabric.\n");
+ "The FCP adapter could not log in to the "
+ "fibre channel fabric\n");
break;
case FSF_PSQ_LINK_WWPN_ASSIGNMENT_CORRUPTED:
dev_warn(&req->adapter->ccw_device->dev,
- "WWPN assignment file corrupted on adapter.\n");
+ "The WWPN assignment file on the FCP adapter "
+ "has been damaged\n");
break;
case FSF_PSQ_LINK_MODE_TABLE_CURRUPTED:
dev_warn(&req->adapter->ccw_device->dev,
- "Mode table corrupted on adapter.\n");
+ "The mode table on the FCP adapter "
+ "has been damaged\n");
break;
case FSF_PSQ_LINK_NO_WWPN_ASSIGNMENT:
dev_warn(&req->adapter->ccw_device->dev,
- "No WWPN for assignment table on adapter.\n");
+ "All NPIV ports on the FCP adapter have "
+ "been assigned\n");
break;
default:
dev_warn(&req->adapter->ccw_device->dev,
- "The local link to adapter is down.\n");
+ "The link between the FCP adapter and "
+ "the FC fabric is down\n");
}
out:
zfcp_erp_adapter_failed(adapter, id, req);
@@ -286,27 +251,18 @@ out:
static void zfcp_fsf_status_read_link_down(struct zfcp_fsf_req *req)
{
- struct zfcp_adapter *adapter = req->adapter;
struct fsf_status_read_buffer *sr_buf = req->data;
struct fsf_link_down_info *ldi =
(struct fsf_link_down_info *) &sr_buf->payload;
switch (sr_buf->status_subtype) {
case FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK:
- dev_warn(&adapter->ccw_device->dev,
- "Physical link is down.\n");
zfcp_fsf_link_down_info_eval(req, 38, ldi);
break;
case FSF_STATUS_READ_SUB_FDISC_FAILED:
- dev_warn(&adapter->ccw_device->dev,
- "Local link is down "
- "due to failed FDISC login.\n");
zfcp_fsf_link_down_info_eval(req, 39, ldi);
break;
case FSF_STATUS_READ_SUB_FIRMWARE_UPDATE:
- dev_warn(&adapter->ccw_device->dev,
- "Local link is down "
- "due to firmware update on adapter.\n");
zfcp_fsf_link_down_info_eval(req, 40, NULL);
};
}
@@ -335,14 +291,17 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req)
case FSF_STATUS_READ_SENSE_DATA_AVAIL:
break;
case FSF_STATUS_READ_BIT_ERROR_THRESHOLD:
- zfcp_fsf_bit_error_threshold(req);
+ dev_warn(&adapter->ccw_device->dev,
+ "The error threshold for checksum statistics "
+ "has been exceeded\n");
+ zfcp_hba_dbf_event_berr(adapter, req);
break;
case FSF_STATUS_READ_LINK_DOWN:
zfcp_fsf_status_read_link_down(req);
break;
case FSF_STATUS_READ_LINK_UP:
dev_info(&adapter->ccw_device->dev,
- "Local link was replugged.\n");
+ "The local link has been restored\n");
/* All ports should be marked as ready to run again */
zfcp_erp_modify_adapter_status(adapter, 30, NULL,
ZFCP_STATUS_COMMON_RUNNING,
@@ -370,7 +329,7 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req)
zfcp_fsf_req_free(req);
atomic_inc(&adapter->stat_miss);
- schedule_work(&adapter->stat_work);
+ queue_work(zfcp_data.work_queue, &adapter->stat_work);
}
static void zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *req)
@@ -386,8 +345,8 @@ static void zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *req)
break;
case FSF_SQ_NO_RECOM:
dev_err(&req->adapter->ccw_device->dev,
- "No recommendation could be given for a "
- "problem on the adapter.\n");
+ "The FCP adapter reported a problem "
+ "that cannot be recovered\n");
zfcp_erp_adapter_shutdown(req->adapter, 0, 121, req);
break;
}
@@ -403,8 +362,7 @@ static void zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *req)
switch (req->qtcb->header.fsf_status) {
case FSF_UNKNOWN_COMMAND:
dev_err(&req->adapter->ccw_device->dev,
- "Command issued by the device driver (0x%x) is "
- "not known by the adapter.\n",
+ "The FCP adapter does not recognize the command 0x%x\n",
req->qtcb->header.fsf_command);
zfcp_erp_adapter_shutdown(req->adapter, 0, 120, req);
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
@@ -435,11 +393,9 @@ static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req)
return;
case FSF_PROT_QTCB_VERSION_ERROR:
dev_err(&adapter->ccw_device->dev,
- "The QTCB version requested by zfcp (0x%x) is not "
- "supported by the FCP adapter (lowest supported "
- "0x%x, highest supported 0x%x).\n",
- FSF_QTCB_CURRENT_VERSION, psq->word[0],
- psq->word[1]);
+ "QTCB version 0x%x not supported by FCP adapter "
+ "(0x%x to 0x%x)\n", FSF_QTCB_CURRENT_VERSION,
+ psq->word[0], psq->word[1]);
zfcp_erp_adapter_shutdown(adapter, 0, 117, req);
break;
case FSF_PROT_ERROR_STATE:
@@ -449,8 +405,7 @@ static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req)
break;
case FSF_PROT_UNSUPP_QTCB_TYPE:
dev_err(&adapter->ccw_device->dev,
- "Packet header type used by the device driver is "
- "incompatible with that used on the adapter.\n");
+ "The QTCB type is not supported by the FCP adapter\n");
zfcp_erp_adapter_shutdown(adapter, 0, 118, req);
break;
case FSF_PROT_HOST_CONNECTION_INITIALIZING:
@@ -459,7 +414,7 @@ static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req)
break;
case FSF_PROT_DUPLICATE_REQUEST_ID:
dev_err(&adapter->ccw_device->dev,
- "The request identifier 0x%Lx is ambiguous.\n",
+ "0x%Lx is an ambiguous request identifier\n",
(unsigned long long)qtcb->bottom.support.req_handle);
zfcp_erp_adapter_shutdown(adapter, 0, 78, req);
break;
@@ -479,9 +434,7 @@ static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req)
break;
default:
dev_err(&adapter->ccw_device->dev,
- "Transfer protocol status information"
- "provided by the adapter (0x%x) "
- "is not compatible with the device driver.\n",
+ "0x%x is not a valid transfer protocol status\n",
qtcb->prefix.prot_status);
zfcp_erp_adapter_shutdown(adapter, 0, 119, req);
}
@@ -559,33 +512,17 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req)
adapter->peer_wwpn = bottom->plogi_payload.wwpn;
adapter->peer_wwnn = bottom->plogi_payload.wwnn;
fc_host_port_type(shost) = FC_PORTTYPE_PTP;
- if (req->erp_action)
- dev_info(&adapter->ccw_device->dev,
- "Point-to-Point fibrechannel "
- "configuration detected.\n");
break;
case FSF_TOPO_FABRIC:
fc_host_port_type(shost) = FC_PORTTYPE_NPORT;
- if (req->erp_action)
- dev_info(&adapter->ccw_device->dev,
- "Switched fabric fibrechannel "
- "network detected.\n");
break;
case FSF_TOPO_AL:
fc_host_port_type(shost) = FC_PORTTYPE_NLPORT;
- dev_err(&adapter->ccw_device->dev,
- "Unsupported arbitrated loop fibrechannel "
- "topology detected, shutting down "
- "adapter.\n");
- zfcp_erp_adapter_shutdown(adapter, 0, 127, req);
- return -EIO;
default:
- fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN;
dev_err(&adapter->ccw_device->dev,
- "The fibrechannel topology reported by the"
- " adapter is not known by the zfcp driver,"
- " shutting down adapter.\n");
- zfcp_erp_adapter_shutdown(adapter, 0, 128, req);
+ "Unknown or unsupported arbitrated loop "
+ "fibre channel topology detected\n");
+ zfcp_erp_adapter_shutdown(adapter, 0, 127, req);
return -EIO;
}
@@ -616,11 +553,9 @@ static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req)
if (bottom->max_qtcb_size < sizeof(struct fsf_qtcb)) {
dev_err(&adapter->ccw_device->dev,
- "Maximum QTCB size (%d bytes) allowed by "
- "the adapter is lower than the minimum "
- "required by the driver (%ld bytes).\n",
- bottom->max_qtcb_size,
- sizeof(struct fsf_qtcb));
+ "FCP adapter maximum QTCB size (%d bytes) "
+ "is too small\n",
+ bottom->max_qtcb_size);
zfcp_erp_adapter_shutdown(adapter, 0, 129, req);
return;
}
@@ -656,15 +591,15 @@ static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req)
if (FSF_QTCB_CURRENT_VERSION < bottom->low_qtcb_version) {
dev_err(&adapter->ccw_device->dev,
- "The adapter only supports newer control block "
- "versions, try updated device driver.\n");
+ "The FCP adapter only supports newer "
+ "control block versions\n");
zfcp_erp_adapter_shutdown(adapter, 0, 125, req);
return;
}
if (FSF_QTCB_CURRENT_VERSION > bottom->high_qtcb_version) {
dev_err(&adapter->ccw_device->dev,
- "The adapter only supports older control block "
- "versions, consider a microcode upgrade.\n");
+ "The FCP adapter only supports older "
+ "control block versions\n");
zfcp_erp_adapter_shutdown(adapter, 0, 126, req);
}
}
@@ -688,7 +623,6 @@ static void zfcp_fsf_exchange_port_evaluate(struct zfcp_fsf_req *req)
static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *req)
{
- struct zfcp_adapter *adapter = req->adapter;
struct fsf_qtcb *qtcb = req->qtcb;
if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
@@ -697,38 +631,47 @@ static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *req)
switch (qtcb->header.fsf_status) {
case FSF_GOOD:
zfcp_fsf_exchange_port_evaluate(req);
- atomic_set_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status);
break;
case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE:
zfcp_fsf_exchange_port_evaluate(req);
- atomic_set_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status);
zfcp_fsf_link_down_info_eval(req, 43,
&qtcb->header.fsf_status_qual.link_down_info);
break;
}
}
-static int zfcp_fsf_sbal_check(struct zfcp_qdio_queue *queue)
+static int zfcp_fsf_sbal_check(struct zfcp_adapter *adapter)
{
- spin_lock(&queue->lock);
- if (atomic_read(&queue->count))
+ struct zfcp_qdio_queue *req_q = &adapter->req_q;
+
+ spin_lock_bh(&adapter->req_q_lock);
+ if (atomic_read(&req_q->count))
return 1;
- spin_unlock(&queue->lock);
+ spin_unlock_bh(&adapter->req_q_lock);
return 0;
}
+static int zfcp_fsf_sbal_available(struct zfcp_adapter *adapter)
+{
+ unsigned int count = atomic_read(&adapter->req_q.count);
+ if (!count)
+ atomic_inc(&adapter->qdio_outb_full);
+ return count > 0;
+}
+
static int zfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter)
{
long ret;
- struct zfcp_qdio_queue *req_q = &adapter->req_q;
- spin_unlock(&req_q->lock);
+ spin_unlock_bh(&adapter->req_q_lock);
ret = wait_event_interruptible_timeout(adapter->request_wq,
- zfcp_fsf_sbal_check(req_q), 5 * HZ);
+ zfcp_fsf_sbal_check(adapter), 5 * HZ);
if (ret > 0)
return 0;
+ if (!ret)
+ atomic_inc(&adapter->qdio_outb_full);
- spin_lock(&req_q->lock);
+ spin_lock_bh(&adapter->req_q_lock);
return -EIO;
}
@@ -765,7 +708,7 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_adapter *adapter,
u32 fsf_cmd, int req_flags,
mempool_t *pool)
{
- volatile struct qdio_buffer_element *sbale;
+ struct qdio_buffer_element *sbale;
struct zfcp_fsf_req *req;
struct zfcp_qdio_queue *req_q = &adapter->req_q;
@@ -867,17 +810,17 @@ int zfcp_fsf_status_read(struct zfcp_adapter *adapter)
{
struct zfcp_fsf_req *req;
struct fsf_status_read_buffer *sr_buf;
- volatile struct qdio_buffer_element *sbale;
+ struct qdio_buffer_element *sbale;
int retval = -EIO;
- spin_lock(&adapter->req_q.lock);
+ spin_lock_bh(&adapter->req_q_lock);
if (zfcp_fsf_req_sbal_get(adapter))
goto out;
req = zfcp_fsf_req_create(adapter, FSF_QTCB_UNSOLICITED_STATUS,
ZFCP_REQ_NO_QTCB,
adapter->pool.fsf_req_status_read);
- if (unlikely(IS_ERR(req))) {
+ if (IS_ERR(req)) {
retval = PTR_ERR(req);
goto out;
}
@@ -910,7 +853,7 @@ failed_buf:
zfcp_fsf_req_free(req);
zfcp_hba_dbf_event_fsf_unsol("fail", adapter, NULL);
out:
- spin_unlock(&adapter->req_q.lock);
+ spin_unlock_bh(&adapter->req_q_lock);
return retval;
}
@@ -980,15 +923,15 @@ struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long old_req_id,
struct zfcp_unit *unit,
int req_flags)
{
- volatile struct qdio_buffer_element *sbale;
+ struct qdio_buffer_element *sbale;
struct zfcp_fsf_req *req = NULL;
- spin_lock(&adapter->req_q.lock);
- if (!atomic_read(&adapter->req_q.count))
+ spin_lock(&adapter->req_q_lock);
+ if (!zfcp_fsf_sbal_available(adapter))
goto out;
req = zfcp_fsf_req_create(adapter, FSF_QTCB_ABORT_FCP_CMND,
req_flags, adapter->pool.fsf_req_abort);
- if (unlikely(IS_ERR(req)))
+ if (IS_ERR(req))
goto out;
if (unlikely(!(atomic_read(&unit->status) &
@@ -1013,7 +956,7 @@ out_error_free:
zfcp_fsf_req_free(req);
req = NULL;
out:
- spin_unlock(&adapter->req_q.lock);
+ spin_unlock(&adapter->req_q_lock);
return req;
}
@@ -1021,7 +964,6 @@ static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req)
{
struct zfcp_adapter *adapter = req->adapter;
struct zfcp_send_ct *send_ct = req->data;
- struct zfcp_port *port = send_ct->port;
struct fsf_qtcb_header *header = &req->qtcb->header;
send_ct->status = -EINVAL;
@@ -1040,17 +982,14 @@ static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req)
case FSF_ADAPTER_STATUS_AVAILABLE:
switch (header->fsf_status_qual.word[0]){
case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
- zfcp_test_link(port);
case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
}
break;
case FSF_ACCESS_DENIED:
- zfcp_fsf_access_denied_port(req, port);
break;
case FSF_PORT_BOXED:
- zfcp_erp_port_boxed(port, 49, req);
req->status |= ZFCP_STATUS_FSFREQ_ERROR |
ZFCP_STATUS_FSFREQ_RETRY;
break;
@@ -1101,18 +1040,18 @@ static int zfcp_fsf_setup_sbals(struct zfcp_fsf_req *req,
int zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool,
struct zfcp_erp_action *erp_action)
{
- struct zfcp_port *port = ct->port;
- struct zfcp_adapter *adapter = port->adapter;
+ struct zfcp_wka_port *wka_port = ct->wka_port;
+ struct zfcp_adapter *adapter = wka_port->adapter;
struct zfcp_fsf_req *req;
int ret = -EIO;
- spin_lock(&adapter->req_q.lock);
+ spin_lock_bh(&adapter->req_q_lock);
if (zfcp_fsf_req_sbal_get(adapter))
goto out;
req = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_GENERIC,
ZFCP_REQ_AUTO_CLEANUP, pool);
- if (unlikely(IS_ERR(req))) {
+ if (IS_ERR(req)) {
ret = PTR_ERR(req);
goto out;
}
@@ -1123,7 +1062,7 @@ int zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool,
goto failed_send;
req->handler = zfcp_fsf_send_ct_handler;
- req->qtcb->header.port_handle = port->handle;
+ req->qtcb->header.port_handle = wka_port->handle;
req->qtcb->bottom.support.service_class = FSF_CLASS_3;
req->qtcb->bottom.support.timeout = ct->timeout;
req->data = ct;
@@ -1148,7 +1087,7 @@ failed_send:
if (erp_action)
erp_action->fsf_req = NULL;
out:
- spin_unlock(&adapter->req_q.lock);
+ spin_unlock_bh(&adapter->req_q_lock);
return ret;
}
@@ -1218,18 +1157,18 @@ int zfcp_fsf_send_els(struct zfcp_send_els *els)
ZFCP_STATUS_COMMON_UNBLOCKED)))
return -EBUSY;
- spin_lock(&adapter->req_q.lock);
- if (!atomic_read(&adapter->req_q.count))
+ spin_lock(&adapter->req_q_lock);
+ if (!zfcp_fsf_sbal_available(adapter))
goto out;
req = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_ELS,
ZFCP_REQ_AUTO_CLEANUP, NULL);
- if (unlikely(IS_ERR(req))) {
+ if (IS_ERR(req)) {
ret = PTR_ERR(req);
goto out;
}
- ret = zfcp_fsf_setup_sbals(req, els->req, els->resp,
- FSF_MAX_SBALS_PER_ELS_REQ);
+ ret = zfcp_fsf_setup_sbals(req, els->req, els->resp, 2);
+
if (ret)
goto failed_send;
@@ -1252,25 +1191,25 @@ int zfcp_fsf_send_els(struct zfcp_send_els *els)
failed_send:
zfcp_fsf_req_free(req);
out:
- spin_unlock(&adapter->req_q.lock);
+ spin_unlock(&adapter->req_q_lock);
return ret;
}
int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
{
- volatile struct qdio_buffer_element *sbale;
+ struct qdio_buffer_element *sbale;
struct zfcp_fsf_req *req;
struct zfcp_adapter *adapter = erp_action->adapter;
int retval = -EIO;
- spin_lock(&adapter->req_q.lock);
- if (!atomic_read(&adapter->req_q.count))
+ spin_lock_bh(&adapter->req_q_lock);
+ if (!zfcp_fsf_sbal_available(adapter))
goto out;
req = zfcp_fsf_req_create(adapter,
FSF_QTCB_EXCHANGE_CONFIG_DATA,
ZFCP_REQ_AUTO_CLEANUP,
adapter->pool.fsf_req_erp);
- if (unlikely(IS_ERR(req))) {
+ if (IS_ERR(req)) {
retval = PTR_ERR(req);
goto out;
}
@@ -1295,24 +1234,24 @@ int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
erp_action->fsf_req = NULL;
}
out:
- spin_unlock(&adapter->req_q.lock);
+ spin_unlock_bh(&adapter->req_q_lock);
return retval;
}
int zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *adapter,
struct fsf_qtcb_bottom_config *data)
{
- volatile struct qdio_buffer_element *sbale;
+ struct qdio_buffer_element *sbale;
struct zfcp_fsf_req *req = NULL;
int retval = -EIO;
- spin_lock(&adapter->req_q.lock);
+ spin_lock_bh(&adapter->req_q_lock);
if (zfcp_fsf_req_sbal_get(adapter))
goto out;
req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_CONFIG_DATA,
0, NULL);
- if (unlikely(IS_ERR(req))) {
+ if (IS_ERR(req)) {
retval = PTR_ERR(req);
goto out;
}
@@ -1334,7 +1273,7 @@ int zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *adapter,
zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
retval = zfcp_fsf_req_send(req);
out:
- spin_unlock(&adapter->req_q.lock);
+ spin_unlock_bh(&adapter->req_q_lock);
if (!retval)
wait_event(req->completion_wq,
req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
@@ -1351,7 +1290,7 @@ out:
*/
int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action)
{
- volatile struct qdio_buffer_element *sbale;
+ struct qdio_buffer_element *sbale;
struct zfcp_fsf_req *req;
struct zfcp_adapter *adapter = erp_action->adapter;
int retval = -EIO;
@@ -1359,13 +1298,13 @@ int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action)
if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT))
return -EOPNOTSUPP;
- spin_lock(&adapter->req_q.lock);
- if (!atomic_read(&adapter->req_q.count))
+ spin_lock_bh(&adapter->req_q_lock);
+ if (!zfcp_fsf_sbal_available(adapter))
goto out;
req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA,
ZFCP_REQ_AUTO_CLEANUP,
adapter->pool.fsf_req_erp);
- if (unlikely(IS_ERR(req))) {
+ if (IS_ERR(req)) {
retval = PTR_ERR(req);
goto out;
}
@@ -1385,7 +1324,7 @@ int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action)
erp_action->fsf_req = NULL;
}
out:
- spin_unlock(&adapter->req_q.lock);
+ spin_unlock_bh(&adapter->req_q_lock);
return retval;
}
@@ -1398,20 +1337,20 @@ out:
int zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *adapter,
struct fsf_qtcb_bottom_port *data)
{
- volatile struct qdio_buffer_element *sbale;
+ struct qdio_buffer_element *sbale;
struct zfcp_fsf_req *req = NULL;
int retval = -EIO;
if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT))
return -EOPNOTSUPP;
- spin_lock(&adapter->req_q.lock);
- if (!atomic_read(&adapter->req_q.count))
+ spin_lock_bh(&adapter->req_q_lock);
+ if (!zfcp_fsf_sbal_available(adapter))
goto out;
req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, 0,
NULL);
- if (unlikely(IS_ERR(req))) {
+ if (IS_ERR(req)) {
retval = PTR_ERR(req);
goto out;
}
@@ -1427,7 +1366,7 @@ int zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *adapter,
zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
retval = zfcp_fsf_req_send(req);
out:
- spin_unlock(&adapter->req_q.lock);
+ spin_unlock_bh(&adapter->req_q_lock);
if (!retval)
wait_event(req->completion_wq,
req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
@@ -1443,7 +1382,7 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req)
struct fsf_plogi *plogi;
if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
- goto skip_fsfstatus;
+ return;
switch (header->fsf_status) {
case FSF_PORT_ALREADY_OPEN:
@@ -1453,9 +1392,9 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req)
break;
case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED:
dev_warn(&req->adapter->ccw_device->dev,
- "The adapter is out of resources. The remote port "
- "0x%016Lx could not be opened, disabling it.\n",
- port->wwpn);
+ "Not enough FCP adapter resources to open "
+ "remote port 0x%016Lx\n",
+ (unsigned long long)port->wwpn);
zfcp_erp_port_failed(port, 31, req);
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
@@ -1467,8 +1406,8 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req)
break;
case FSF_SQ_NO_RETRY_POSSIBLE:
dev_warn(&req->adapter->ccw_device->dev,
- "The remote port 0x%016Lx could not be "
- "opened. Disabling it.\n", port->wwpn);
+ "Remote port 0x%016Lx could not be opened\n",
+ (unsigned long long)port->wwpn);
zfcp_erp_port_failed(port, 32, req);
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
@@ -1496,9 +1435,6 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req)
* another GID_PN straight after a port has been opened.
* Alternately, an ADISC/PDISC ELS should suffice, as well.
*/
- if (atomic_read(&port->status) & ZFCP_STATUS_PORT_NO_WWPN)
- break;
-
plogi = (struct fsf_plogi *) req->qtcb->bottom.support.els;
if (req->qtcb->bottom.support.els1_length >= sizeof(*plogi)) {
if (plogi->serv_param.wwpn != port->wwpn)
@@ -1514,9 +1450,6 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req)
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
}
-
-skip_fsfstatus:
- atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, &port->status);
}
/**
@@ -1526,12 +1459,12 @@ skip_fsfstatus:
*/
int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
{
- volatile struct qdio_buffer_element *sbale;
+ struct qdio_buffer_element *sbale;
struct zfcp_adapter *adapter = erp_action->adapter;
struct zfcp_fsf_req *req;
int retval = -EIO;
- spin_lock(&adapter->req_q.lock);
+ spin_lock_bh(&adapter->req_q_lock);
if (zfcp_fsf_req_sbal_get(adapter))
goto out;
@@ -1539,7 +1472,7 @@ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
FSF_QTCB_OPEN_PORT_WITH_DID,
ZFCP_REQ_AUTO_CLEANUP,
adapter->pool.fsf_req_erp);
- if (unlikely(IS_ERR(req))) {
+ if (IS_ERR(req)) {
retval = PTR_ERR(req);
goto out;
}
@@ -1553,7 +1486,6 @@ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
req->data = erp_action->port;
req->erp_action = erp_action;
erp_action->fsf_req = req;
- atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->port->status);
zfcp_fsf_start_erp_timer(req);
retval = zfcp_fsf_req_send(req);
@@ -1562,7 +1494,7 @@ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
erp_action->fsf_req = NULL;
}
out:
- spin_unlock(&adapter->req_q.lock);
+ spin_unlock_bh(&adapter->req_q_lock);
return retval;
}
@@ -1571,7 +1503,7 @@ static void zfcp_fsf_close_port_handler(struct zfcp_fsf_req *req)
struct zfcp_port *port = req->data;
if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
- goto skip_fsfstatus;
+ return;
switch (req->qtcb->header.fsf_status) {
case FSF_PORT_HANDLE_NOT_VALID:
@@ -1586,9 +1518,6 @@ static void zfcp_fsf_close_port_handler(struct zfcp_fsf_req *req)
ZFCP_CLEAR);
break;
}
-
-skip_fsfstatus:
- atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, &port->status);
}
/**
@@ -1598,19 +1527,19 @@ skip_fsfstatus:
*/
int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action)
{
- volatile struct qdio_buffer_element *sbale;
+ struct qdio_buffer_element *sbale;
struct zfcp_adapter *adapter = erp_action->adapter;
struct zfcp_fsf_req *req;
int retval = -EIO;
- spin_lock(&adapter->req_q.lock);
+ spin_lock_bh(&adapter->req_q_lock);
if (zfcp_fsf_req_sbal_get(adapter))
goto out;
req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_PORT,
ZFCP_REQ_AUTO_CLEANUP,
adapter->pool.fsf_req_erp);
- if (unlikely(IS_ERR(req))) {
+ if (IS_ERR(req)) {
retval = PTR_ERR(req);
goto out;
}
@@ -1624,7 +1553,6 @@ int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action)
req->erp_action = erp_action;
req->qtcb->header.port_handle = erp_action->port->handle;
erp_action->fsf_req = req;
- atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->port->status);
zfcp_fsf_start_erp_timer(req);
retval = zfcp_fsf_req_send(req);
@@ -1633,7 +1561,131 @@ int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action)
erp_action->fsf_req = NULL;
}
out:
- spin_unlock(&adapter->req_q.lock);
+ spin_unlock_bh(&adapter->req_q_lock);
+ return retval;
+}
+
+static void zfcp_fsf_open_wka_port_handler(struct zfcp_fsf_req *req)
+{
+ struct zfcp_wka_port *wka_port = req->data;
+ struct fsf_qtcb_header *header = &req->qtcb->header;
+
+ if (req->status & ZFCP_STATUS_FSFREQ_ERROR) {
+ wka_port->status = ZFCP_WKA_PORT_OFFLINE;
+ goto out;
+ }
+
+ switch (header->fsf_status) {
+ case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED:
+ dev_warn(&req->adapter->ccw_device->dev,
+ "Opening WKA port 0x%x failed\n", wka_port->d_id);
+ case FSF_ADAPTER_STATUS_AVAILABLE:
+ req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+ case FSF_ACCESS_DENIED:
+ wka_port->status = ZFCP_WKA_PORT_OFFLINE;
+ break;
+ case FSF_PORT_ALREADY_OPEN:
+ case FSF_GOOD:
+ wka_port->handle = header->port_handle;
+ wka_port->status = ZFCP_WKA_PORT_ONLINE;
+ }
+out:
+ wake_up(&wka_port->completion_wq);
+}
+
+/**
+ * zfcp_fsf_open_wka_port - create and send open wka-port request
+ * @wka_port: pointer to struct zfcp_wka_port
+ * Returns: 0 on success, error otherwise
+ */
+int zfcp_fsf_open_wka_port(struct zfcp_wka_port *wka_port)
+{
+ struct qdio_buffer_element *sbale;
+ struct zfcp_adapter *adapter = wka_port->adapter;
+ struct zfcp_fsf_req *req;
+ int retval = -EIO;
+
+ spin_lock_bh(&adapter->req_q_lock);
+ if (zfcp_fsf_req_sbal_get(adapter))
+ goto out;
+
+ req = zfcp_fsf_req_create(adapter,
+ FSF_QTCB_OPEN_PORT_WITH_DID,
+ ZFCP_REQ_AUTO_CLEANUP,
+ adapter->pool.fsf_req_erp);
+ if (unlikely(IS_ERR(req))) {
+ retval = PTR_ERR(req);
+ goto out;
+ }
+
+ sbale = zfcp_qdio_sbale_req(req);
+ sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
+ sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+
+ req->handler = zfcp_fsf_open_wka_port_handler;
+ req->qtcb->bottom.support.d_id = wka_port->d_id;
+ req->data = wka_port;
+
+ zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
+ retval = zfcp_fsf_req_send(req);
+ if (retval)
+ zfcp_fsf_req_free(req);
+out:
+ spin_unlock_bh(&adapter->req_q_lock);
+ return retval;
+}
+
+static void zfcp_fsf_close_wka_port_handler(struct zfcp_fsf_req *req)
+{
+ struct zfcp_wka_port *wka_port = req->data;
+
+ if (req->qtcb->header.fsf_status == FSF_PORT_HANDLE_NOT_VALID) {
+ req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+ zfcp_erp_adapter_reopen(wka_port->adapter, 0, 84, req);
+ }
+
+ wka_port->status = ZFCP_WKA_PORT_OFFLINE;
+ wake_up(&wka_port->completion_wq);
+}
+
+/**
+ * zfcp_fsf_close_wka_port - create and send close wka port request
+ * @erp_action: pointer to struct zfcp_erp_action
+ * Returns: 0 on success, error otherwise
+ */
+int zfcp_fsf_close_wka_port(struct zfcp_wka_port *wka_port)
+{
+ struct qdio_buffer_element *sbale;
+ struct zfcp_adapter *adapter = wka_port->adapter;
+ struct zfcp_fsf_req *req;
+ int retval = -EIO;
+
+ spin_lock_bh(&adapter->req_q_lock);
+ if (zfcp_fsf_req_sbal_get(adapter))
+ goto out;
+
+ req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_PORT,
+ ZFCP_REQ_AUTO_CLEANUP,
+ adapter->pool.fsf_req_erp);
+ if (unlikely(IS_ERR(req))) {
+ retval = PTR_ERR(req);
+ goto out;
+ }
+
+ sbale = zfcp_qdio_sbale_req(req);
+ sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
+ sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+
+ req->handler = zfcp_fsf_close_wka_port_handler;
+ req->data = wka_port;
+ req->qtcb->header.port_handle = wka_port->handle;
+
+ zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
+ retval = zfcp_fsf_req_send(req);
+ if (retval)
+ zfcp_fsf_req_free(req);
+out:
+ spin_unlock_bh(&adapter->req_q_lock);
return retval;
}
@@ -1695,19 +1747,19 @@ skip_fsfstatus:
*/
int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action)
{
- volatile struct qdio_buffer_element *sbale;
+ struct qdio_buffer_element *sbale;
struct zfcp_adapter *adapter = erp_action->adapter;
struct zfcp_fsf_req *req;
int retval = -EIO;
- spin_lock(&adapter->req_q.lock);
+ spin_lock_bh(&adapter->req_q_lock);
if (zfcp_fsf_req_sbal_get(adapter))
goto out;
req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_PHYSICAL_PORT,
ZFCP_REQ_AUTO_CLEANUP,
adapter->pool.fsf_req_erp);
- if (unlikely(IS_ERR(req))) {
+ if (IS_ERR(req)) {
retval = PTR_ERR(req);
goto out;
}
@@ -1731,7 +1783,7 @@ int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action)
erp_action->fsf_req = NULL;
}
out:
- spin_unlock(&adapter->req_q.lock);
+ spin_unlock_bh(&adapter->req_q_lock);
return retval;
}
@@ -1746,7 +1798,7 @@ static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req)
int exclusive, readwrite;
if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
- goto skip_fsfstatus;
+ return;
atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
ZFCP_STATUS_COMMON_ACCESS_BOXED |
@@ -1774,14 +1826,12 @@ static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req)
case FSF_LUN_SHARING_VIOLATION:
if (header->fsf_status_qual.word[0])
dev_warn(&adapter->ccw_device->dev,
- "FCP-LUN 0x%Lx at the remote port "
- "with WWPN 0x%Lx "
- "connected to the adapter "
- "is already in use in LPAR%d, CSS%d.\n",
- unit->fcp_lun,
- unit->port->wwpn,
- queue_designator->hla,
- queue_designator->cssid);
+ "LUN 0x%Lx on port 0x%Lx is already in "
+ "use by CSS%d, MIF Image ID %x\n",
+ (unsigned long long)unit->fcp_lun,
+ (unsigned long long)unit->port->wwpn,
+ queue_designator->cssid,
+ queue_designator->hla);
else
zfcp_act_eval_err(adapter,
header->fsf_status_qual.word[2]);
@@ -1792,9 +1842,10 @@ static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req)
break;
case FSF_MAXIMUM_NUMBER_OF_LUNS_EXCEEDED:
dev_warn(&adapter->ccw_device->dev,
- "The adapter ran out of resources. There is no "
- "handle available for unit 0x%016Lx on port 0x%016Lx.",
- unit->fcp_lun, unit->port->wwpn);
+ "No handle is available for LUN "
+ "0x%016Lx on port 0x%016Lx\n",
+ (unsigned long long)unit->fcp_lun,
+ (unsigned long long)unit->port->wwpn);
zfcp_erp_unit_failed(unit, 34, req);
/* fall through */
case FSF_INVALID_COMMAND_OPTION:
@@ -1831,26 +1882,29 @@ static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req)
atomic_set_mask(ZFCP_STATUS_UNIT_READONLY,
&unit->status);
dev_info(&adapter->ccw_device->dev,
- "Read-only access for unit 0x%016Lx "
- "on port 0x%016Lx.\n",
- unit->fcp_lun, unit->port->wwpn);
+ "SCSI device at LUN 0x%016Lx on port "
+ "0x%016Lx opened read-only\n",
+ (unsigned long long)unit->fcp_lun,
+ (unsigned long long)unit->port->wwpn);
}
if (exclusive && !readwrite) {
dev_err(&adapter->ccw_device->dev,
- "Exclusive access of read-only unit "
- "0x%016Lx on port 0x%016Lx not "
- "supported, disabling unit.\n",
- unit->fcp_lun, unit->port->wwpn);
+ "Exclusive read-only access not "
+ "supported (unit 0x%016Lx, "
+ "port 0x%016Lx)\n",
+ (unsigned long long)unit->fcp_lun,
+ (unsigned long long)unit->port->wwpn);
zfcp_erp_unit_failed(unit, 35, req);
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
zfcp_erp_unit_shutdown(unit, 0, 80, req);
} else if (!exclusive && readwrite) {
dev_err(&adapter->ccw_device->dev,
- "Shared access of read-write unit "
- "0x%016Lx on port 0x%016Lx not "
- "supported, disabling unit.\n",
- unit->fcp_lun, unit->port->wwpn);
+ "Shared read-write access not "
+ "supported (unit 0x%016Lx, port "
+ "0x%016Lx\n)",
+ (unsigned long long)unit->fcp_lun,
+ (unsigned long long)unit->port->wwpn);
zfcp_erp_unit_failed(unit, 36, req);
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
zfcp_erp_unit_shutdown(unit, 0, 81, req);
@@ -1858,9 +1912,6 @@ static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req)
}
break;
}
-
-skip_fsfstatus:
- atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, &unit->status);
}
/**
@@ -1870,19 +1921,19 @@ skip_fsfstatus:
*/
int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
{
- volatile struct qdio_buffer_element *sbale;
+ struct qdio_buffer_element *sbale;
struct zfcp_adapter *adapter = erp_action->adapter;
struct zfcp_fsf_req *req;
int retval = -EIO;
- spin_lock(&adapter->req_q.lock);
+ spin_lock_bh(&adapter->req_q_lock);
if (zfcp_fsf_req_sbal_get(adapter))
goto out;
req = zfcp_fsf_req_create(adapter, FSF_QTCB_OPEN_LUN,
ZFCP_REQ_AUTO_CLEANUP,
adapter->pool.fsf_req_erp);
- if (unlikely(IS_ERR(req))) {
+ if (IS_ERR(req)) {
retval = PTR_ERR(req);
goto out;
}
@@ -1901,8 +1952,6 @@ int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE))
req->qtcb->bottom.support.option = FSF_OPEN_LUN_SUPPRESS_BOXING;
- atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->unit->status);
-
zfcp_fsf_start_erp_timer(req);
retval = zfcp_fsf_req_send(req);
if (retval) {
@@ -1910,7 +1959,7 @@ int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
erp_action->fsf_req = NULL;
}
out:
- spin_unlock(&adapter->req_q.lock);
+ spin_unlock_bh(&adapter->req_q_lock);
return retval;
}
@@ -1919,7 +1968,7 @@ static void zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *req)
struct zfcp_unit *unit = req->data;
if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
- goto skip_fsfstatus;
+ return;
switch (req->qtcb->header.fsf_status) {
case FSF_PORT_HANDLE_NOT_VALID:
@@ -1949,8 +1998,6 @@ static void zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *req)
atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status);
break;
}
-skip_fsfstatus:
- atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, &unit->status);
}
/**
@@ -1960,18 +2007,18 @@ skip_fsfstatus:
*/
int zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action)
{
- volatile struct qdio_buffer_element *sbale;
+ struct qdio_buffer_element *sbale;
struct zfcp_adapter *adapter = erp_action->adapter;
struct zfcp_fsf_req *req;
int retval = -EIO;
- spin_lock(&adapter->req_q.lock);
+ spin_lock_bh(&adapter->req_q_lock);
if (zfcp_fsf_req_sbal_get(adapter))
goto out;
req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_LUN,
ZFCP_REQ_AUTO_CLEANUP,
adapter->pool.fsf_req_erp);
- if (unlikely(IS_ERR(req))) {
+ if (IS_ERR(req)) {
retval = PTR_ERR(req);
goto out;
}
@@ -1986,7 +2033,6 @@ int zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action)
req->data = erp_action->unit;
req->erp_action = erp_action;
erp_action->fsf_req = req;
- atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->unit->status);
zfcp_fsf_start_erp_timer(req);
retval = zfcp_fsf_req_send(req);
@@ -1995,7 +2041,7 @@ int zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action)
erp_action->fsf_req = NULL;
}
out:
- spin_unlock(&adapter->req_q.lock);
+ spin_unlock_bh(&adapter->req_q_lock);
return retval;
}
@@ -2156,21 +2202,21 @@ static void zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *req)
break;
case FSF_DIRECTION_INDICATOR_NOT_VALID:
dev_err(&req->adapter->ccw_device->dev,
- "Invalid data direction (%d) given for unit "
- "0x%016Lx on port 0x%016Lx, shutting down "
- "adapter.\n",
+ "Incorrect direction %d, unit 0x%016Lx on port "
+ "0x%016Lx closed\n",
req->qtcb->bottom.io.data_direction,
- unit->fcp_lun, unit->port->wwpn);
+ (unsigned long long)unit->fcp_lun,
+ (unsigned long long)unit->port->wwpn);
zfcp_erp_adapter_shutdown(unit->port->adapter, 0, 133, req);
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
case FSF_CMND_LENGTH_NOT_VALID:
dev_err(&req->adapter->ccw_device->dev,
- "An invalid control-data-block length field (%d) "
- "was found in a command for unit 0x%016Lx on port "
- "0x%016Lx. Shutting down adapter.\n",
+ "Incorrect CDB length %d, unit 0x%016Lx on "
+ "port 0x%016Lx closed\n",
req->qtcb->bottom.io.fcp_cmnd_length,
- unit->fcp_lun, unit->port->wwpn);
+ (unsigned long long)unit->fcp_lun,
+ (unsigned long long)unit->port->wwpn);
zfcp_erp_adapter_shutdown(unit->port->adapter, 0, 134, req);
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
break;
@@ -2201,6 +2247,20 @@ skip_fsfstatus:
}
}
+static void zfcp_set_fcp_dl(struct fcp_cmnd_iu *fcp_cmd, u32 fcp_dl)
+{
+ u32 *fcp_dl_ptr;
+
+ /*
+ * 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
+ */
+ fcp_dl_ptr = (u32 *) ((unsigned char *) &fcp_cmd[1] +
+ (fcp_cmd->add_fcp_cdb_length << 2));
+ *fcp_dl_ptr = fcp_dl;
+}
+
/**
* zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command)
* @adapter: adapter where scsi command is issued
@@ -2223,12 +2283,12 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
ZFCP_STATUS_COMMON_UNBLOCKED)))
return -EBUSY;
- spin_lock(&adapter->req_q.lock);
- if (!atomic_read(&adapter->req_q.count))
+ spin_lock(&adapter->req_q_lock);
+ if (!zfcp_fsf_sbal_available(adapter))
goto out;
req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags,
adapter->pool.fsf_req_scsi);
- if (unlikely(IS_ERR(req))) {
+ if (IS_ERR(req)) {
retval = PTR_ERR(req);
goto out;
}
@@ -2286,7 +2346,7 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
memcpy(fcp_cmnd_iu->fcp_cdb, scsi_cmnd->cmnd, scsi_cmnd->cmd_len);
req->qtcb->bottom.io.fcp_cmnd_length = sizeof(struct fcp_cmnd_iu) +
- fcp_cmnd_iu->add_fcp_cdb_length + sizeof(fcp_dl_t);
+ fcp_cmnd_iu->add_fcp_cdb_length + sizeof(u32);
real_bytes = zfcp_qdio_sbals_from_sg(req, sbtype,
scsi_sglist(scsi_cmnd),
@@ -2296,10 +2356,10 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
retval = -EIO;
else {
dev_err(&adapter->ccw_device->dev,
- "SCSI request too large. "
- "Shutting down unit 0x%016Lx on port "
- "0x%016Lx.\n", unit->fcp_lun,
- unit->port->wwpn);
+ "Oversize data package, unit 0x%016Lx "
+ "on port 0x%016Lx closed\n",
+ (unsigned long long)unit->fcp_lun,
+ (unsigned long long)unit->port->wwpn);
zfcp_erp_unit_shutdown(unit, 0, 131, req);
retval = -EINVAL;
}
@@ -2322,7 +2382,7 @@ failed_scsi_cmnd:
zfcp_fsf_req_free(req);
scsi_cmnd->host_scribble = NULL;
out:
- spin_unlock(&adapter->req_q.lock);
+ spin_unlock(&adapter->req_q_lock);
return retval;
}
@@ -2338,7 +2398,7 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_adapter *adapter,
struct zfcp_unit *unit,
u8 tm_flags, int req_flags)
{
- volatile struct qdio_buffer_element *sbale;
+ struct qdio_buffer_element *sbale;
struct zfcp_fsf_req *req = NULL;
struct fcp_cmnd_iu *fcp_cmnd_iu;
@@ -2346,12 +2406,12 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_adapter *adapter,
ZFCP_STATUS_COMMON_UNBLOCKED)))
return NULL;
- spin_lock(&adapter->req_q.lock);
- if (!atomic_read(&adapter->req_q.count))
+ spin_lock(&adapter->req_q_lock);
+ if (!zfcp_fsf_sbal_available(adapter))
goto out;
req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags,
adapter->pool.fsf_req_scsi);
- if (unlikely(IS_ERR(req)))
+ if (IS_ERR(req))
goto out;
req->status |= ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT;
@@ -2362,7 +2422,7 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_adapter *adapter,
req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND;
req->qtcb->bottom.io.service_class = FSF_CLASS_3;
req->qtcb->bottom.io.fcp_cmnd_length = sizeof(struct fcp_cmnd_iu) +
- sizeof(fcp_dl_t);
+ sizeof(u32);
sbale = zfcp_qdio_sbale_req(req);
sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE;
@@ -2379,7 +2439,7 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_adapter *adapter,
zfcp_fsf_req_free(req);
req = NULL;
out:
- spin_unlock(&adapter->req_q.lock);
+ spin_unlock(&adapter->req_q_lock);
return req;
}
@@ -2398,7 +2458,7 @@ static void zfcp_fsf_control_file_handler(struct zfcp_fsf_req *req)
struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter,
struct zfcp_fsf_cfdc *fsf_cfdc)
{
- volatile struct qdio_buffer_element *sbale;
+ struct qdio_buffer_element *sbale;
struct zfcp_fsf_req *req = NULL;
struct fsf_qtcb_bottom_support *bottom;
int direction, retval = -EIO, bytes;
@@ -2417,12 +2477,12 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter,
return ERR_PTR(-EINVAL);
}
- spin_lock(&adapter->req_q.lock);
+ spin_lock_bh(&adapter->req_q_lock);
if (zfcp_fsf_req_sbal_get(adapter))
goto out;
req = zfcp_fsf_req_create(adapter, fsf_cfdc->command, 0, NULL);
- if (unlikely(IS_ERR(req))) {
+ if (IS_ERR(req)) {
retval = -EPERM;
goto out;
}
@@ -2447,7 +2507,7 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter,
zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
retval = zfcp_fsf_req_send(req);
out:
- spin_unlock(&adapter->req_q.lock);
+ spin_unlock_bh(&adapter->req_q_lock);
if (!retval) {
wait_event(req->completion_wq,
diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h
index bf94b4da076..fd3a88777ac 100644
--- a/drivers/s390/scsi/zfcp_fsf.h
+++ b/drivers/s390/scsi/zfcp_fsf.h
@@ -71,13 +71,6 @@
#define FSF_MAXIMUM_NUMBER_OF_LUNS_EXCEEDED 0x00000041
#define FSF_ELS_COMMAND_REJECTED 0x00000050
#define FSF_GENERIC_COMMAND_REJECTED 0x00000051
-#define FSF_OPERATION_PARTIALLY_SUCCESSFUL 0x00000052
-#define FSF_AUTHORIZATION_FAILURE 0x00000053
-#define FSF_CFDC_ERROR_DETECTED 0x00000054
-#define FSF_CONTROL_FILE_UPDATE_ERROR 0x00000055
-#define FSF_CONTROL_FILE_TOO_LARGE 0x00000056
-#define FSF_ACCESS_CONFLICT_DETECTED 0x00000057
-#define FSF_CONFLICTS_OVERRULED 0x00000058
#define FSF_PORT_BOXED 0x00000059
#define FSF_LUN_BOXED 0x0000005A
#define FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE 0x0000005B
@@ -85,9 +78,7 @@
#define FSF_REQUEST_SIZE_TOO_LARGE 0x00000061
#define FSF_RESPONSE_SIZE_TOO_LARGE 0x00000062
#define FSF_SBAL_MISMATCH 0x00000063
-#define FSF_OPEN_PORT_WITHOUT_PRLI 0x00000064
#define FSF_ADAPTER_STATUS_AVAILABLE 0x000000AD
-#define FSF_FCP_RSP_AVAILABLE 0x000000AF
#define FSF_UNKNOWN_COMMAND 0x000000E2
#define FSF_UNKNOWN_OP_SUBTYPE 0x000000E3
#define FSF_INVALID_COMMAND_OPTION 0x000000E5
@@ -102,20 +93,9 @@
#define FSF_SQ_RETRY_IF_POSSIBLE 0x02
#define FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED 0x03
#define FSF_SQ_INVOKE_LINK_TEST_PROCEDURE 0x04
-#define FSF_SQ_ULP_PROGRAMMING_ERROR 0x05
#define FSF_SQ_COMMAND_ABORTED 0x06
#define FSF_SQ_NO_RETRY_POSSIBLE 0x07
-/* FSF status qualifier for CFDC commands */
-#define FSF_SQ_CFDC_HARDENED_ON_SE 0x00000000
-#define FSF_SQ_CFDC_COULD_NOT_HARDEN_ON_SE 0x00000001
-#define FSF_SQ_CFDC_COULD_NOT_HARDEN_ON_SE2 0x00000002
-/* CFDC subtable codes */
-#define FSF_SQ_CFDC_SUBTABLE_OS 0x0001
-#define FSF_SQ_CFDC_SUBTABLE_PORT_WWPN 0x0002
-#define FSF_SQ_CFDC_SUBTABLE_PORT_DID 0x0003
-#define FSF_SQ_CFDC_SUBTABLE_LUN 0x0004
-
/* FSF status qualifier (most significant 4 bytes), local link down */
#define FSF_PSQ_LINK_NO_LIGHT 0x00000004
#define FSF_PSQ_LINK_WRAP_PLUG 0x00000008
@@ -145,7 +125,6 @@
#define FSF_STATUS_READ_LINK_UP 0x00000006
#define FSF_STATUS_READ_NOTIFICATION_LOST 0x00000009
#define FSF_STATUS_READ_CFDC_UPDATED 0x0000000A
-#define FSF_STATUS_READ_CFDC_HARDENED 0x0000000B
#define FSF_STATUS_READ_FEATURE_UPDATE_ALERT 0x0000000C
/* status subtypes in status read buffer */
@@ -159,20 +138,9 @@
/* status subtypes for unsolicited status notification lost */
#define FSF_STATUS_READ_SUB_INCOMING_ELS 0x00000001
-#define FSF_STATUS_READ_SUB_SENSE_DATA 0x00000002
-#define FSF_STATUS_READ_SUB_LINK_STATUS 0x00000004
-#define FSF_STATUS_READ_SUB_PORT_CLOSED 0x00000008
-#define FSF_STATUS_READ_SUB_BIT_ERROR_THRESHOLD 0x00000010
#define FSF_STATUS_READ_SUB_ACT_UPDATED 0x00000020
-#define FSF_STATUS_READ_SUB_ACT_HARDENED 0x00000040
-#define FSF_STATUS_READ_SUB_FEATURE_UPDATE_ALERT 0x00000080
-
-/* status subtypes for CFDC */
-#define FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE 0x00000002
-#define FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE2 0x0000000F
/* topologie that is detected by the adapter */
-#define FSF_TOPO_ERROR 0x00000000
#define FSF_TOPO_P2P 0x00000001
#define FSF_TOPO_FABRIC 0x00000002
#define FSF_TOPO_AL 0x00000003
@@ -180,17 +148,13 @@
/* data direction for FCP commands */
#define FSF_DATADIR_WRITE 0x00000001
#define FSF_DATADIR_READ 0x00000002
-#define FSF_DATADIR_READ_WRITE 0x00000003
#define FSF_DATADIR_CMND 0x00000004
/* fc service class */
-#define FSF_CLASS_1 0x00000001
-#define FSF_CLASS_2 0x00000002
#define FSF_CLASS_3 0x00000003
/* SBAL chaining */
#define FSF_MAX_SBALS_PER_REQ 36
-#define FSF_MAX_SBALS_PER_ELS_REQ 2
/* logging space behind QTCB */
#define FSF_QTCB_LOG_SIZE 1024
@@ -200,50 +164,16 @@
#define FSF_FEATURE_LUN_SHARING 0x00000004
#define FSF_FEATURE_NOTIFICATION_LOST 0x00000008
#define FSF_FEATURE_HBAAPI_MANAGEMENT 0x00000010
-#define FSF_FEATURE_ELS_CT_CHAINED_SBALS 0x00000020
#define FSF_FEATURE_UPDATE_ALERT 0x00000100
#define FSF_FEATURE_MEASUREMENT_DATA 0x00000200
/* host connection features */
#define FSF_FEATURE_NPIV_MODE 0x00000001
-#define FSF_FEATURE_VM_ASSIGNED_WWPN 0x00000002
/* option */
#define FSF_OPEN_LUN_SUPPRESS_BOXING 0x00000001
-#define FSF_OPEN_LUN_REPLICATE_SENSE 0x00000002
-
-/* adapter types */
-#define FSF_ADAPTER_TYPE_FICON 0x00000001
-#define FSF_ADAPTER_TYPE_FICON_EXPRESS 0x00000002
-
-/* port types */
-#define FSF_HBA_PORTTYPE_UNKNOWN 0x00000001
-#define FSF_HBA_PORTTYPE_NOTPRESENT 0x00000003
-#define FSF_HBA_PORTTYPE_NPORT 0x00000005
-#define FSF_HBA_PORTTYPE_PTP 0x00000021
-/* following are not defined and used by FSF Spec
- but are additionally defined by FC-HBA */
-#define FSF_HBA_PORTTYPE_OTHER 0x00000002
-#define FSF_HBA_PORTTYPE_NOTPRESENT 0x00000003
-#define FSF_HBA_PORTTYPE_NLPORT 0x00000006
-#define FSF_HBA_PORTTYPE_FLPORT 0x00000007
-#define FSF_HBA_PORTTYPE_FPORT 0x00000008
-#define FSF_HBA_PORTTYPE_LPORT 0x00000020
-
-/* port states */
-#define FSF_HBA_PORTSTATE_UNKNOWN 0x00000001
-#define FSF_HBA_PORTSTATE_ONLINE 0x00000002
-#define FSF_HBA_PORTSTATE_OFFLINE 0x00000003
-#define FSF_HBA_PORTSTATE_LINKDOWN 0x00000006
-#define FSF_HBA_PORTSTATE_ERROR 0x00000007
-
-/* IO states of adapter */
-#define FSF_IOSTAT_NPORT_RJT 0x00000004
-#define FSF_IOSTAT_FABRIC_RJT 0x00000005
-#define FSF_IOSTAT_LS_RJT 0x00000009
/* open LUN access flags*/
-#define FSF_UNIT_ACCESS_OPEN_LUN_ALLOWED 0x01000000
#define FSF_UNIT_ACCESS_EXCLUSIVE 0x02000000
#define FSF_UNIT_ACCESS_OUTBOUND_TRANSFER 0x10000000
@@ -265,11 +195,6 @@ struct fsf_queue_designator {
u32 res1;
} __attribute__ ((packed));
-struct fsf_port_closed_payload {
- struct fsf_queue_designator queue_designator;
- u32 port_handle;
-} __attribute__ ((packed));
-
struct fsf_bit_error_payload {
u32 res1;
u32 link_failure_error_count;
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c
index d6dbd653fde..3e05080e62d 100644
--- a/drivers/s390/scsi/zfcp_qdio.c
+++ b/drivers/s390/scsi/zfcp_qdio.c
@@ -28,7 +28,7 @@ static int zfcp_qdio_buffers_enqueue(struct qdio_buffer **sbal)
return 0;
}
-static volatile struct qdio_buffer_element *
+static struct qdio_buffer_element *
zfcp_qdio_sbale(struct zfcp_qdio_queue *q, int sbal_idx, int sbale_idx)
{
return &q->sbal[sbal_idx]->element[sbale_idx];
@@ -57,7 +57,7 @@ void zfcp_qdio_free(struct zfcp_adapter *adapter)
static void zfcp_qdio_handler_error(struct zfcp_adapter *adapter, u8 id)
{
- dev_warn(&adapter->ccw_device->dev, "QDIO problem occurred.\n");
+ dev_warn(&adapter->ccw_device->dev, "A QDIO problem occurred\n");
zfcp_erp_adapter_reopen(adapter,
ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
@@ -145,7 +145,7 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err,
{
struct zfcp_adapter *adapter = (struct zfcp_adapter *) parm;
struct zfcp_qdio_queue *queue = &adapter->resp_q;
- volatile struct qdio_buffer_element *sbale;
+ struct qdio_buffer_element *sbale;
int sbal_idx, sbale_idx, sbal_no;
if (unlikely(qdio_err)) {
@@ -174,8 +174,8 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err,
if (unlikely(!(sbale->flags & SBAL_FLAGS_LAST_ENTRY)))
dev_warn(&adapter->ccw_device->dev,
- "Protocol violation by adapter. "
- "Continuing operations.\n");
+ "A QDIO protocol error occurred, "
+ "operations continue\n");
}
/*
@@ -190,8 +190,7 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err,
* @fsf_req: pointer to struct fsf_req
* Returns: pointer to qdio_buffer_element (SBALE) structure
*/
-volatile struct qdio_buffer_element *
-zfcp_qdio_sbale_req(struct zfcp_fsf_req *req)
+struct qdio_buffer_element *zfcp_qdio_sbale_req(struct zfcp_fsf_req *req)
{
return zfcp_qdio_sbale(&req->adapter->req_q, req->sbal_last, 0);
}
@@ -201,8 +200,7 @@ zfcp_qdio_sbale_req(struct zfcp_fsf_req *req)
* @fsf_req: pointer to struct fsf_req
* Returns: pointer to qdio_buffer_element (SBALE) structure
*/
-volatile struct qdio_buffer_element *
-zfcp_qdio_sbale_curr(struct zfcp_fsf_req *req)
+struct qdio_buffer_element *zfcp_qdio_sbale_curr(struct zfcp_fsf_req *req)
{
return zfcp_qdio_sbale(&req->adapter->req_q, req->sbal_last,
req->sbale_curr);
@@ -216,10 +214,10 @@ static void zfcp_qdio_sbal_limit(struct zfcp_fsf_req *fsf_req, int max_sbals)
% QDIO_MAX_BUFFERS_PER_Q;
}
-static volatile struct qdio_buffer_element *
+static struct qdio_buffer_element *
zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype)
{
- volatile struct qdio_buffer_element *sbale;
+ struct qdio_buffer_element *sbale;
/* set last entry flag in current SBALE of current SBAL */
sbale = zfcp_qdio_sbale_curr(fsf_req);
@@ -250,7 +248,7 @@ zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype)
return sbale;
}
-static volatile struct qdio_buffer_element *
+static struct qdio_buffer_element *
zfcp_qdio_sbale_next(struct zfcp_fsf_req *fsf_req, unsigned long sbtype)
{
if (fsf_req->sbale_curr == ZFCP_LAST_SBALE_PER_SBAL)
@@ -273,7 +271,7 @@ static int zfcp_qdio_fill_sbals(struct zfcp_fsf_req *fsf_req,
unsigned int sbtype, void *start_addr,
unsigned int total_length)
{
- volatile struct qdio_buffer_element *sbale;
+ struct qdio_buffer_element *sbale;
unsigned long remaining, length;
void *addr;
@@ -282,6 +280,7 @@ static int zfcp_qdio_fill_sbals(struct zfcp_fsf_req *fsf_req,
addr += length, remaining -= length) {
sbale = zfcp_qdio_sbale_next(fsf_req, sbtype);
if (!sbale) {
+ atomic_inc(&fsf_req->adapter->qdio_outb_full);
zfcp_qdio_undo_sbals(fsf_req);
return -EINVAL;
}
@@ -307,7 +306,7 @@ static int zfcp_qdio_fill_sbals(struct zfcp_fsf_req *fsf_req,
int zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
struct scatterlist *sg, int max_sbals)
{
- volatile struct qdio_buffer_element *sbale;
+ struct qdio_buffer_element *sbale;
int retval, bytes = 0;
/* figure out last allowed SBAL */
@@ -344,10 +343,10 @@ int zfcp_qdio_send(struct zfcp_fsf_req *fsf_req)
int first = fsf_req->sbal_first;
int count = fsf_req->sbal_number;
int retval, pci, pci_batch;
- volatile struct qdio_buffer_element *sbale;
+ struct qdio_buffer_element *sbale;
/* acknowledgements for transferred buffers */
- pci_batch = req_q->pci_batch + count;
+ pci_batch = adapter->req_q_pci_batch + count;
if (unlikely(pci_batch >= ZFCP_QDIO_PCI_INTERVAL)) {
pci_batch %= ZFCP_QDIO_PCI_INTERVAL;
pci = first + count - (pci_batch + 1);
@@ -367,7 +366,7 @@ int zfcp_qdio_send(struct zfcp_fsf_req *fsf_req)
atomic_sub(count, &req_q->count);
req_q->first += count;
req_q->first %= QDIO_MAX_BUFFERS_PER_Q;
- req_q->pci_batch = pci_batch;
+ adapter->req_q_pci_batch = pci_batch;
return 0;
}
@@ -418,14 +417,14 @@ void zfcp_qdio_close(struct zfcp_adapter *adapter)
struct zfcp_qdio_queue *req_q;
int first, count;
- if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status))
+ if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP))
return;
/* clear QDIOUP flag, thus do_QDIO is not called during qdio_shutdown */
req_q = &adapter->req_q;
- spin_lock(&req_q->lock);
+ spin_lock_bh(&adapter->req_q_lock);
atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status);
- spin_unlock(&req_q->lock);
+ spin_unlock_bh(&adapter->req_q_lock);
qdio_shutdown(adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR);
@@ -438,7 +437,7 @@ void zfcp_qdio_close(struct zfcp_adapter *adapter)
}
req_q->first = 0;
atomic_set(&req_q->count, 0);
- req_q->pci_batch = 0;
+ adapter->req_q_pci_batch = 0;
adapter->resp_q.first = 0;
atomic_set(&adapter->resp_q.count, 0);
}
@@ -450,23 +449,17 @@ void zfcp_qdio_close(struct zfcp_adapter *adapter)
*/
int zfcp_qdio_open(struct zfcp_adapter *adapter)
{
- volatile struct qdio_buffer_element *sbale;
+ struct qdio_buffer_element *sbale;
int cc;
- if (atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status))
+ if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)
return -EIO;
- if (qdio_establish(&adapter->qdio_init_data)) {
- dev_err(&adapter->ccw_device->dev,
- "Establish of QDIO queues failed.\n");
- return -EIO;
- }
+ if (qdio_establish(&adapter->qdio_init_data))
+ goto failed_establish;
- if (qdio_activate(adapter->ccw_device)) {
- dev_err(&adapter->ccw_device->dev,
- "Activate of QDIO queues failed.\n");
+ if (qdio_activate(adapter->ccw_device))
goto failed_qdio;
- }
for (cc = 0; cc < QDIO_MAX_BUFFERS_PER_Q; cc++) {
sbale = &(adapter->resp_q.sbal[cc]->element[0]);
@@ -476,20 +469,20 @@ int zfcp_qdio_open(struct zfcp_adapter *adapter)
}
if (do_QDIO(adapter->ccw_device, QDIO_FLAG_SYNC_INPUT, 0, 0,
- QDIO_MAX_BUFFERS_PER_Q)) {
- dev_err(&adapter->ccw_device->dev,
- "Init of QDIO response queue failed.\n");
+ QDIO_MAX_BUFFERS_PER_Q))
goto failed_qdio;
- }
/* set index of first avalable SBALS / number of available SBALS */
adapter->req_q.first = 0;
atomic_set(&adapter->req_q.count, QDIO_MAX_BUFFERS_PER_Q);
- adapter->req_q.pci_batch = 0;
+ adapter->req_q_pci_batch = 0;
return 0;
failed_qdio:
qdio_shutdown(adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR);
+failed_establish:
+ dev_err(&adapter->ccw_device->dev,
+ "Setting up the QDIO connection to the FCP adapter failed\n");
return -EIO;
}
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index aeae56b00b4..ca8f85f3dad 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -21,20 +21,6 @@ char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *fcp_rsp_iu)
return fcp_sns_info_ptr;
}
-void zfcp_set_fcp_dl(struct fcp_cmnd_iu *fcp_cmd, fcp_dl_t fcp_dl)
-{
- fcp_dl_t *fcp_dl_ptr;
-
- /*
- * 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
- */
- fcp_dl_ptr = (fcp_dl_t *) ((unsigned char *) &fcp_cmd[1] +
- (fcp_cmd->add_fcp_cdb_length << 2));
- *fcp_dl_ptr = fcp_dl;
-}
-
static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt)
{
struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata;
@@ -119,13 +105,17 @@ static struct zfcp_unit *zfcp_unit_lookup(struct zfcp_adapter *adapter,
{
struct zfcp_port *port;
struct zfcp_unit *unit;
+ int scsi_lun;
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)
- if (lun == unit->scsi_lun)
+ list_for_each_entry(unit, &port->unit_list_head, list) {
+ scsi_lun = scsilun_to_int(
+ (struct scsi_lun *)&unit->fcp_lun);
+ if (lun == scsi_lun)
return unit;
+ }
}
return NULL;
@@ -183,7 +173,6 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
return retval;
}
fsf_req->data = NULL;
- fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTING;
/* don't access old fsf_req after releasing the abort_lock */
write_unlock_irqrestore(&adapter->abort_lock, flags);
@@ -294,7 +283,8 @@ int zfcp_adapter_scsi_register(struct zfcp_adapter *adapter)
sizeof (struct zfcp_adapter *));
if (!adapter->scsi_host) {
dev_err(&adapter->ccw_device->dev,
- "registration with SCSI stack failed.");
+ "Registering the FCP device with the "
+ "SCSI stack failed\n");
return -EIO;
}
@@ -312,7 +302,6 @@ int zfcp_adapter_scsi_register(struct zfcp_adapter *adapter)
scsi_host_put(adapter->scsi_host);
return -EIO;
}
- atomic_set_mask(ZFCP_STATUS_ADAPTER_REGISTERED, &adapter->status);
return 0;
}
@@ -336,7 +325,6 @@ void zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter)
scsi_remove_host(shost);
scsi_host_put(shost);
adapter->scsi_host = NULL;
- atomic_clear_mask(ZFCP_STATUS_ADAPTER_REGISTERED, &adapter->status);
return;
}
diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c
index 2e85c6c49e7..2809d789b55 100644
--- a/drivers/s390/scsi/zfcp_sysfs.c
+++ b/drivers/s390/scsi/zfcp_sysfs.c
@@ -26,9 +26,9 @@ static ZFCP_DEV_ATTR(_feat, _name, S_IRUGO, \
ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, status, "0x%08x\n",
atomic_read(&adapter->status));
ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, peer_wwnn, "0x%016llx\n",
- adapter->peer_wwnn);
+ (unsigned long long) adapter->peer_wwnn);
ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, peer_wwpn, "0x%016llx\n",
- adapter->peer_wwpn);
+ (unsigned long long) adapter->peer_wwpn);
ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, peer_d_id, "0x%06x\n",
adapter->peer_d_id);
ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, card_version, "0x%04x\n",
@@ -135,8 +135,9 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev,
{
struct zfcp_adapter *adapter = dev_get_drvdata(dev);
struct zfcp_port *port;
- wwn_t wwpn;
+ u64 wwpn;
int retval = 0;
+ LIST_HEAD(port_remove_lh);
down(&zfcp_data.config_sema);
if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_REMOVE) {
@@ -144,7 +145,7 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev,
goto out;
}
- if (strict_strtoull(buf, 0, &wwpn)) {
+ if (strict_strtoull(buf, 0, (unsigned long long *) &wwpn)) {
retval = -EINVAL;
goto out;
}
@@ -154,7 +155,7 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev,
if (port && (atomic_read(&port->refcount) == 0)) {
zfcp_port_get(port);
atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status);
- list_move(&port->list, &adapter->port_remove_lh);
+ list_move(&port->list, &port_remove_lh);
} else
port = NULL;
write_unlock_irq(&zfcp_data.config_lock);
@@ -200,7 +201,7 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev,
{
struct zfcp_port *port = dev_get_drvdata(dev);
struct zfcp_unit *unit;
- fcp_lun_t fcp_lun;
+ u64 fcp_lun;
int retval = -EINVAL;
down(&zfcp_data.config_sema);
@@ -209,7 +210,7 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev,
goto out;
}
- if (strict_strtoull(buf, 0, &fcp_lun))
+ if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun))
goto out;
unit = zfcp_unit_enqueue(port, fcp_lun);
@@ -233,8 +234,9 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev,
{
struct zfcp_port *port = dev_get_drvdata(dev);
struct zfcp_unit *unit;
- fcp_lun_t fcp_lun;
+ u64 fcp_lun;
int retval = 0;
+ LIST_HEAD(unit_remove_lh);
down(&zfcp_data.config_sema);
if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE) {
@@ -242,7 +244,7 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev,
goto out;
}
- if (strict_strtoull(buf, 0, &fcp_lun)) {
+ if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun)) {
retval = -EINVAL;
goto out;
}
@@ -252,7 +254,7 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev,
if (unit && (atomic_read(&unit->refcount) == 0)) {
zfcp_unit_get(unit);
atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status);
- list_move(&unit->list, &port->unit_remove_lh);
+ list_move(&unit->list, &unit_remove_lh);
} else
unit = NULL;
@@ -273,22 +275,7 @@ out:
}
static DEVICE_ATTR(unit_remove, S_IWUSR, NULL, zfcp_sysfs_unit_remove_store);
-static struct attribute *zfcp_port_ns_attrs[] = {
- &dev_attr_port_failed.attr,
- &dev_attr_port_in_recovery.attr,
- &dev_attr_port_status.attr,
- &dev_attr_port_access_denied.attr,
- NULL
-};
-
-/**
- * zfcp_sysfs_ns_port_attrs - sysfs attributes for nameserver
- */
-struct attribute_group zfcp_sysfs_ns_port_attrs = {
- .attrs = zfcp_port_ns_attrs,
-};
-
-static struct attribute *zfcp_port_no_ns_attrs[] = {
+static struct attribute *zfcp_port_attrs[] = {
&dev_attr_unit_add.attr,
&dev_attr_unit_remove.attr,
&dev_attr_port_failed.attr,
@@ -302,7 +289,7 @@ static struct attribute *zfcp_port_no_ns_attrs[] = {
* zfcp_sysfs_port_attrs - sysfs attributes for all other ports
*/
struct attribute_group zfcp_sysfs_port_attrs = {
- .attrs = zfcp_port_no_ns_attrs,
+ .attrs = zfcp_port_attrs,
};
static struct attribute *zfcp_unit_attrs[] = {
@@ -395,8 +382,10 @@ static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_scsi_##_name##_show, NULL);
ZFCP_DEFINE_SCSI_ATTR(hba_id, "%s\n",
unit->port->adapter->ccw_device->dev.bus_id);
-ZFCP_DEFINE_SCSI_ATTR(wwpn, "0x%016llx\n", unit->port->wwpn);
-ZFCP_DEFINE_SCSI_ATTR(fcp_lun, "0x%016llx\n", unit->fcp_lun);
+ZFCP_DEFINE_SCSI_ATTR(wwpn, "0x%016llx\n",
+ (unsigned long long) unit->port->wwpn);
+ZFCP_DEFINE_SCSI_ATTR(fcp_lun, "0x%016llx\n",
+ (unsigned long long) unit->fcp_lun);
struct device_attribute *zfcp_sysfs_sdev_attrs[] = {
&dev_attr_fcp_lun,
@@ -487,10 +476,23 @@ ZFCP_SHOST_ATTR(megabytes, "%llu %llu\n",
ZFCP_SHOST_ATTR(seconds_active, "%llu\n",
(unsigned long long) stat_info.seconds_act);
+static ssize_t zfcp_sysfs_adapter_q_full_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *scsi_host = class_to_shost(dev);
+ struct zfcp_adapter *adapter =
+ (struct zfcp_adapter *) scsi_host->hostdata[0];
+
+ return sprintf(buf, "%d\n", atomic_read(&adapter->qdio_outb_full));
+}
+static DEVICE_ATTR(queue_full, S_IRUGO, zfcp_sysfs_adapter_q_full_show, NULL);
+
struct device_attribute *zfcp_sysfs_shost_attrs[] = {
&dev_attr_utilization,
&dev_attr_requests,
&dev_attr_megabytes,
&dev_attr_seconds_active,
+ &dev_attr_queue_full,
NULL
};
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index c7f06298bd3..d3b211af4e1 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -63,7 +63,7 @@ comment "SCSI support type (disk, tape, CD-ROM)"
config BLK_DEV_SD
tristate "SCSI disk support"
depends on SCSI
- select CRC_T10DIF
+ select CRC_T10DIF if BLK_DEV_INTEGRITY
---help---
If you want to use SCSI hard disks, Fibre Channel disks,
Serial ATA (SATA) or Parallel ATA (PATA) hard disks,
@@ -1325,14 +1325,6 @@ config SCSI_QLOGIC_FAS
To compile this driver as a module, choose M here: the
module will be called qlogicfas.
-config SCSI_QLOGIC_FC_FIRMWARE
- bool "Include loadable firmware in driver"
- depends on SCSI_QLOGIC_FC
- help
- Say Y to include ISP2X00 Fabric Initiator/Target Firmware, with
- expanded LUN addressing and FcTape (FCP-2) support, in the
- qlogicfc driver. This is required on some platforms.
-
config SCSI_QLOGIC_1280
tristate "Qlogic QLA 1240/1x80/1x160 SCSI support"
depends on PCI && SCSI
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index aa4e77c2527..8abfd06b5a7 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -1139,7 +1139,7 @@ static struct aac_srb * aac_scsi_common(struct fib * fib, struct scsi_cmnd * cmd
srbcmd->id = cpu_to_le32(scmd_id(cmd));
srbcmd->lun = cpu_to_le32(cmd->device->lun);
srbcmd->flags = cpu_to_le32(flag);
- timeout = cmd->timeout_per_command/HZ;
+ timeout = cmd->request->timeout/HZ;
if (timeout == 0)
timeout = 1;
srbcmd->timeout = cpu_to_le32(timeout); // timeout in seconds
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 994da56fffe..708e475896b 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -425,7 +425,7 @@ static int alua_check_sense(struct scsi_device *sdev,
/*
* LUN Not Accessible - ALUA state transition
*/
- return NEEDS_RETRY;
+ return ADD_TO_MLQUEUE;
if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0b)
/*
* LUN Not Accessible -- Target port in standby state
@@ -447,18 +447,18 @@ static int alua_check_sense(struct scsi_device *sdev,
/*
* Power On, Reset, or Bus Device Reset, just retry.
*/
- return NEEDS_RETRY;
+ return ADD_TO_MLQUEUE;
if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x06) {
/*
* ALUA state changed
*/
- return NEEDS_RETRY;
+ return ADD_TO_MLQUEUE;
}
if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x07) {
/*
* Implicit ALUA state transition failed
*/
- return NEEDS_RETRY;
+ return ADD_TO_MLQUEUE;
}
break;
}
@@ -490,7 +490,7 @@ static int alua_stpg(struct scsi_device *sdev, int state,
if (!err)
return SCSI_DH_IO;
err = alua_check_sense(sdev, &sense_hdr);
- if (retry > 0 && err == NEEDS_RETRY) {
+ if (retry > 0 && err == ADD_TO_MLQUEUE) {
retry--;
goto retry;
}
@@ -535,7 +535,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h)
return SCSI_DH_IO;
err = alua_check_sense(sdev, &sense_hdr);
- if (err == NEEDS_RETRY)
+ if (err == ADD_TO_MLQUEUE)
goto retry;
sdev_printk(KERN_INFO, sdev,
"%s: rtpg sense code %02x/%02x/%02x\n",
diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c
index b9d23e9e9a4..8f45570a8a0 100644
--- a/drivers/scsi/device_handler/scsi_dh_emc.c
+++ b/drivers/scsi/device_handler/scsi_dh_emc.c
@@ -84,7 +84,7 @@ struct clariion_dh_data {
/*
* I/O buffer for both MODE_SELECT and INQUIRY commands.
*/
- char buffer[CLARIION_BUFFER_SIZE];
+ unsigned char buffer[CLARIION_BUFFER_SIZE];
/*
* SCSI sense buffer for commands -- assumes serial issuance
* and completion sequence of all commands for same multipath.
@@ -176,7 +176,7 @@ static int parse_sp_info_reply(struct scsi_device *sdev,
err = SCSI_DH_DEV_TEMP_BUSY;
goto out;
}
- if (csdev->buffer[4] < 0 || csdev->buffer[4] > 2) {
+ if (csdev->buffer[4] > 2) {
/* Invalid buffer format */
sdev_printk(KERN_NOTICE, sdev,
"%s: invalid VPD page 0xC0 format\n",
@@ -278,7 +278,6 @@ static struct request *get_req(struct scsi_device *sdev, int cmd,
return NULL;
}
- memset(rq->cmd, 0, BLK_MAX_CDB);
rq->cmd_len = COMMAND_SIZE(cmd);
rq->cmd[0] = cmd;
@@ -439,7 +438,7 @@ static int clariion_check_sense(struct scsi_device *sdev,
* Unit Attention Code. This is the first IO
* to the new path, so just retry.
*/
- return NEEDS_RETRY;
+ return ADD_TO_MLQUEUE;
break;
}
@@ -514,7 +513,7 @@ retry:
return SCSI_DH_IO;
err = clariion_check_sense(sdev, &sshdr);
- if (retry > 0 && err == NEEDS_RETRY) {
+ if (retry > 0 && err == ADD_TO_MLQUEUE) {
retry--;
goto retry;
}
diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
index a6a4ef3ad51..5e93c88ad66 100644
--- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c
+++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
@@ -114,7 +114,6 @@ static int hp_sw_tur(struct scsi_device *sdev, struct hp_sw_dh_data *h)
req->cmd_type = REQ_TYPE_BLOCK_PC;
req->cmd_flags |= REQ_FAILFAST;
req->cmd_len = COMMAND_SIZE(TEST_UNIT_READY);
- memset(req->cmd, 0, MAX_COMMAND_SIZE);
req->cmd[0] = TEST_UNIT_READY;
req->timeout = HP_SW_TIMEOUT;
req->sense = h->sense;
@@ -207,7 +206,6 @@ static int hp_sw_start_stop(struct scsi_device *sdev, struct hp_sw_dh_data *h)
req->cmd_type = REQ_TYPE_BLOCK_PC;
req->cmd_flags |= REQ_FAILFAST;
req->cmd_len = COMMAND_SIZE(START_STOP);
- memset(req->cmd, 0, MAX_COMMAND_SIZE);
req->cmd[0] = START_STOP;
req->cmd[4] = 1; /* Start spin cycle */
req->timeout = HP_SW_TIMEOUT;
diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c
index 2dee69da35c..50bf95f3b5c 100644
--- a/drivers/scsi/device_handler/scsi_dh_rdac.c
+++ b/drivers/scsi/device_handler/scsi_dh_rdac.c
@@ -225,8 +225,6 @@ static struct request *get_rdac_req(struct scsi_device *sdev,
return NULL;
}
- memset(rq->cmd, 0, BLK_MAX_CDB);
-
rq->cmd_type = REQ_TYPE_BLOCK_PC;
rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE;
rq->retries = RDAC_RETRIES;
@@ -551,7 +549,7 @@ static int rdac_check_sense(struct scsi_device *sdev,
*
* Just retry and wait.
*/
- return NEEDS_RETRY;
+ return ADD_TO_MLQUEUE;
break;
case ILLEGAL_REQUEST:
if (sense_hdr->asc == 0x94 && sense_hdr->ascq == 0x01) {
@@ -568,7 +566,7 @@ static int rdac_check_sense(struct scsi_device *sdev,
/*
* Power On, Reset, or Bus Device Reset, just retry.
*/
- return NEEDS_RETRY;
+ return ADD_TO_MLQUEUE;
break;
}
/* success just means we do not care what scsi-ml does */
@@ -590,6 +588,8 @@ static const struct scsi_dh_devlist rdac_dev_list[] = {
{"STK", "OPENstorage D280"},
{"SUN", "CSM200_R"},
{"SUN", "LCSM100_F"},
+ {"DELL", "MD3000"},
+ {"DELL", "MD3000i"},
{NULL, NULL},
};
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index 822d5214692..c387c15a212 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -464,7 +464,6 @@ int __gdth_execute(struct scsi_device *sdev, gdth_cmd_str *gdtcmd, char *cmnd,
/* use request field to save the ptr. to completion struct. */
scp->request = (struct request *)&wait;
- scp->timeout_per_command = timeout*HZ;
scp->cmd_len = 12;
scp->cmnd = cmnd;
cmndinfo.priority = IOCTL_PRI;
@@ -1995,23 +1994,12 @@ static void gdth_putq(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar priority)
register Scsi_Cmnd *pscp;
register Scsi_Cmnd *nscp;
ulong flags;
- unchar b, t;
TRACE(("gdth_putq() priority %d\n",priority));
spin_lock_irqsave(&ha->smp_lock, flags);
- if (!cmndinfo->internal_command) {
+ 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"));
- cmndinfo->timeout = gdth_update_timeout(scp, 0);
- }
- }
- }
if (ha->req_first==NULL) {
ha->req_first = scp; /* queue was empty */
@@ -3899,6 +3887,39 @@ static const char *gdth_info(struct Scsi_Host *shp)
return ((const char *)ha->binfo.type_string);
}
+static enum blk_eh_timer_return gdth_timed_out(struct scsi_cmnd *scp)
+{
+ gdth_ha_str *ha = shost_priv(scp->device->host);
+ struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp);
+ unchar b, t;
+ ulong flags;
+ enum blk_eh_timer_return retval = BLK_EH_NOT_HANDLED;
+
+ TRACE(("%s() cmd 0x%x\n", scp->cmnd[0], __func__));
+ b = scp->device->channel;
+ t = scp->device->id;
+
+ /*
+ * We don't really honor the command timeout, but we try to
+ * honor 6 times of the actual command timeout! So reset the
+ * timer if this is less than 6th timeout on this command!
+ */
+ if (++cmndinfo->timeout_count < 6)
+ retval = BLK_EH_RESET_TIMER;
+
+ /* Reset the timeout if it is locked IO */
+ spin_lock_irqsave(&ha->smp_lock, flags);
+ if ((b != ha->virt_bus && ha->raw[BUS_L2P(ha, b)].lock) ||
+ (b == ha->virt_bus && t < MAX_HDRIVES && ha->hdr[t].lock)) {
+ TRACE2(("%s(): locked IO, reset timeout\n", __func__));
+ retval = BLK_EH_RESET_TIMER;
+ }
+ spin_unlock_irqrestore(&ha->smp_lock, flags);
+
+ return retval;
+}
+
+
static int gdth_eh_bus_reset(Scsi_Cmnd *scp)
{
gdth_ha_str *ha = shost_priv(scp->device->host);
@@ -3992,7 +4013,7 @@ static int gdth_queuecommand(struct scsi_cmnd *scp,
BUG_ON(!cmndinfo);
scp->scsi_done = done;
- gdth_update_timeout(scp, scp->timeout_per_command * 6);
+ cmndinfo->timeout_count = 0;
cmndinfo->priority = DEFAULT_PRI;
return __gdth_queuecommand(ha, scp, cmndinfo);
@@ -4096,12 +4117,10 @@ static int ioc_lockdrv(void __user *arg)
ha->hdr[j].lock = 1;
spin_unlock_irqrestore(&ha->smp_lock, flags);
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(ha, ha->bus_cnt, j);
gdth_next(ha);
}
}
@@ -4539,18 +4558,14 @@ static int gdth_ioctl(struct inode *inode, struct file *filep,
spin_lock_irqsave(&ha->smp_lock, flags);
ha->raw[i].lock = 1;
spin_unlock_irqrestore(&ha->smp_lock, flags);
- for (j = 0; j < ha->tid_cnt; ++j) {
+ for (j = 0; j < ha->tid_cnt; ++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(ha, i, j);
+ for (j = 0; j < ha->tid_cnt; ++j)
gdth_next(ha);
- }
}
}
break;
@@ -4644,6 +4659,7 @@ static struct scsi_host_template gdth_template = {
.slave_configure = gdth_slave_configure,
.bios_param = gdth_bios_param,
.proc_info = gdth_proc_info,
+ .eh_timed_out = gdth_timed_out,
.proc_name = "gdth",
.can_queue = GDTH_MAXCMDS,
.this_id = -1,
diff --git a/drivers/scsi/gdth.h b/drivers/scsi/gdth.h
index ca92476727c..1646444e9bd 100644
--- a/drivers/scsi/gdth.h
+++ b/drivers/scsi/gdth.h
@@ -916,7 +916,7 @@ typedef struct {
gdth_cmd_str *internal_cmd_str; /* crier for internal messages*/
dma_addr_t sense_paddr; /* sense dma-addr */
unchar priority;
- int timeout;
+ int timeout_count; /* # of timeout calls */
volatile int wait_for_completion;
ushort status;
ulong32 info;
diff --git a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c
index ce0228e26ae..59349a316e1 100644
--- a/drivers/scsi/gdth_proc.c
+++ b/drivers/scsi/gdth_proc.c
@@ -748,69 +748,3 @@ static void gdth_wait_completion(gdth_ha_str *ha, int busnum, int id)
}
spin_unlock_irqrestore(&ha->smp_lock, flags);
}
-
-static void gdth_stop_timeout(gdth_ha_str *ha, int busnum, int id)
-{
- ulong flags;
- Scsi_Cmnd *scp;
- unchar b, t;
-
- spin_lock_irqsave(&ha->smp_lock, flags);
-
- for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) {
- 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"));
- cmndinfo->timeout = gdth_update_timeout(scp, 0);
- }
- }
- }
- spin_unlock_irqrestore(&ha->smp_lock, flags);
-}
-
-static void gdth_start_timeout(gdth_ha_str *ha, int busnum, int id)
-{
- ulong flags;
- Scsi_Cmnd *scp;
- unchar b, t;
-
- spin_lock_irqsave(&ha->smp_lock, flags);
-
- for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) {
- 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(scp, cmndinfo->timeout);
- }
- }
- }
- spin_unlock_irqrestore(&ha->smp_lock, flags);
-}
-
-static int gdth_update_timeout(Scsi_Cmnd *scp, int timeout)
-{
- int oldto;
-
- oldto = scp->timeout_per_command;
- scp->timeout_per_command = timeout;
-
- if (timeout == 0) {
- del_timer(&scp->eh_timeout);
- scp->eh_timeout.data = (unsigned long) NULL;
- scp->eh_timeout.expires = 0;
- } else {
- if (scp->eh_timeout.data != (unsigned long) NULL)
- del_timer(&scp->eh_timeout);
- scp->eh_timeout.data = (unsigned long) scp;
- scp->eh_timeout.expires = jiffies + timeout;
- add_timer(&scp->eh_timeout);
- }
-
- return oldto;
-}
diff --git a/drivers/scsi/gdth_proc.h b/drivers/scsi/gdth_proc.h
index 45e6fdacf36..9b900cc9ebe 100644
--- a/drivers/scsi/gdth_proc.h
+++ b/drivers/scsi/gdth_proc.h
@@ -20,9 +20,6 @@ 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 fed0b02ebc1..3fdbb13e80a 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -464,7 +464,7 @@ static int __scsi_host_match(struct device *dev, void *data)
struct Scsi_Host *scsi_host_lookup(unsigned short hostnum)
{
struct device *cdev;
- struct Scsi_Host *shost = ERR_PTR(-ENXIO);
+ struct Scsi_Host *shost = NULL;
cdev = class_find_device(&shost_class, NULL, &hostnum,
__scsi_host_match);
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index 7b1502c0ab6..87e09f35d3d 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -756,7 +756,7 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd,
init_event_struct(evt_struct,
handle_cmd_rsp,
VIOSRP_SRP_FORMAT,
- cmnd->timeout_per_command/HZ);
+ cmnd->request->timeout/HZ);
evt_struct->cmnd = cmnd;
evt_struct->cmnd_done = done;
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
index 461331d3dc4..81c16cba541 100644
--- a/drivers/scsi/ide-scsi.c
+++ b/drivers/scsi/ide-scsi.c
@@ -612,7 +612,7 @@ static int idescsi_queue (struct scsi_cmnd *cmd,
pc->req_xfer = pc->buf_size = scsi_bufflen(cmd);
pc->scsi_cmd = cmd;
pc->done = done;
- pc->timeout = jiffies + cmd->timeout_per_command;
+ pc->timeout = jiffies + cmd->request->timeout;
if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) {
printk ("ide-scsi: %s: que %lu, cmd = ", drive->name, cmd->serial_number);
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index e7a3a655442..d30eb7ba018 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -3670,7 +3670,8 @@ static int ipr_slave_configure(struct scsi_device *sdev)
sdev->no_uld_attach = 1;
}
if (ipr_is_vset_device(res)) {
- sdev->timeout = IPR_VSET_RW_TIMEOUT;
+ blk_queue_rq_timeout(sdev->request_queue,
+ IPR_VSET_RW_TIMEOUT);
blk_queue_max_sectors(sdev->request_queue, IPR_VSET_MAX_SECTORS);
}
if (ipr_is_vset_device(res) || ipr_is_scsi_disk(res))
diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
index bc9e6ddf41d..ef683f0d2b5 100644
--- a/drivers/scsi/ips.c
+++ b/drivers/scsi/ips.c
@@ -3818,7 +3818,7 @@ ips_send_cmd(ips_ha_t * ha, ips_scb_t * scb)
scb->cmd.dcdb.segment_4G = 0;
scb->cmd.dcdb.enhanced_sg = 0;
- TimeOut = scb->scsi_cmd->timeout_per_command;
+ TimeOut = scb->scsi_cmd->request->timeout;
if (ha->subsys->param[4] & 0x00100000) { /* If NEW Tape DCDB is Supported */
if (!scb->sg_len) {
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 299e075a7b3..da7b67d30d9 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -1456,7 +1456,7 @@ static void fail_all_commands(struct iscsi_conn *conn, unsigned lun,
if (lun == task->sc->device->lun || lun == -1) {
debug_scsi("failing in progress sc %p itt 0x%x\n",
task->sc, task->itt);
- fail_command(conn, task, DID_BUS_BUSY << 16);
+ fail_command(conn, task, error << 16);
}
}
}
@@ -1476,12 +1476,12 @@ static void iscsi_start_tx(struct iscsi_conn *conn)
scsi_queue_work(conn->session->host, &conn->xmitwork);
}
-static enum scsi_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd)
+static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd)
{
struct iscsi_cls_session *cls_session;
struct iscsi_session *session;
struct iscsi_conn *conn;
- enum scsi_eh_timer_return rc = EH_NOT_HANDLED;
+ enum blk_eh_timer_return rc = BLK_EH_NOT_HANDLED;
cls_session = starget_to_session(scsi_target(scmd->device));
session = cls_session->dd_data;
@@ -1494,14 +1494,14 @@ static enum scsi_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd)
* We are probably in the middle of iscsi recovery so let
* that complete and handle the error.
*/
- rc = EH_RESET_TIMER;
+ rc = BLK_EH_RESET_TIMER;
goto done;
}
conn = session->leadconn;
if (!conn) {
/* In the middle of shuting down */
- rc = EH_RESET_TIMER;
+ rc = BLK_EH_RESET_TIMER;
goto done;
}
@@ -1513,20 +1513,21 @@ static enum scsi_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd)
*/
if (time_before_eq(conn->last_recv + (conn->recv_timeout * HZ) +
(conn->ping_timeout * HZ), jiffies))
- rc = EH_RESET_TIMER;
+ rc = BLK_EH_RESET_TIMER;
/*
* if we are about to check the transport then give the command
* more time
*/
if (time_before_eq(conn->last_recv + (conn->recv_timeout * HZ),
jiffies))
- rc = EH_RESET_TIMER;
+ rc = BLK_EH_RESET_TIMER;
/* if in the middle of checking the transport then give us more time */
if (conn->ping_task)
- rc = EH_RESET_TIMER;
+ rc = BLK_EH_RESET_TIMER;
done:
spin_unlock(&session->lock);
- debug_scsi("return %s\n", rc == EH_RESET_TIMER ? "timer reset" : "nh");
+ debug_scsi("return %s\n", rc == BLK_EH_RESET_TIMER ?
+ "timer reset" : "nh");
return rc;
}
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index 48ee8c7f5bd..e1550117069 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -294,10 +294,10 @@ static void sas_ata_post_internal(struct ata_queued_cmd *qc)
}
}
-static int sas_ata_scr_write(struct ata_port *ap, unsigned int sc_reg_in,
+static int sas_ata_scr_write(struct ata_link *link, unsigned int sc_reg_in,
u32 val)
{
- struct domain_device *dev = ap->private_data;
+ struct domain_device *dev = link->ap->private_data;
SAS_DPRINTK("STUB %s\n", __func__);
switch (sc_reg_in) {
@@ -319,10 +319,10 @@ static int sas_ata_scr_write(struct ata_port *ap, unsigned int sc_reg_in,
return 0;
}
-static int sas_ata_scr_read(struct ata_port *ap, unsigned int sc_reg_in,
+static int sas_ata_scr_read(struct ata_link *link, unsigned int sc_reg_in,
u32 *val)
{
- struct domain_device *dev = ap->private_data;
+ struct domain_device *dev = link->ap->private_data;
SAS_DPRINTK("STUB %s\n", __func__);
switch (sc_reg_in) {
@@ -398,7 +398,7 @@ void sas_ata_task_abort(struct sas_task *task)
/* Bounce SCSI-initiated commands to the SCSI EH */
if (qc->scsicmd) {
- scsi_req_abort_cmd(qc->scsicmd);
+ blk_abort_request(qc->scsicmd->request);
scsi_schedule_eh(qc->scsicmd->device->host);
return;
}
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
index b4f9368f116..0001374bd6b 100644
--- a/drivers/scsi/libsas/sas_internal.h
+++ b/drivers/scsi/libsas/sas_internal.h
@@ -55,7 +55,7 @@ void sas_unregister_phys(struct sas_ha_struct *sas_ha);
int sas_register_ports(struct sas_ha_struct *sas_ha);
void sas_unregister_ports(struct sas_ha_struct *sas_ha);
-enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *);
+enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *);
int sas_init_queue(struct sas_ha_struct *sas_ha);
int sas_init_events(struct sas_ha_struct *sas_ha);
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index a8e3ef30907..744838780ad 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -673,43 +673,43 @@ out:
return;
}
-enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
+enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
{
struct sas_task *task = TO_SAS_TASK(cmd);
unsigned long flags;
if (!task) {
- cmd->timeout_per_command /= 2;
+ cmd->request->timeout /= 2;
SAS_DPRINTK("command 0x%p, task 0x%p, gone: %s\n",
- cmd, task, (cmd->timeout_per_command ?
- "EH_RESET_TIMER" : "EH_NOT_HANDLED"));
- if (!cmd->timeout_per_command)
- return EH_NOT_HANDLED;
- return EH_RESET_TIMER;
+ cmd, task, (cmd->request->timeout ?
+ "BLK_EH_RESET_TIMER" : "BLK_EH_NOT_HANDLED"));
+ if (!cmd->request->timeout)
+ return BLK_EH_NOT_HANDLED;
+ return BLK_EH_RESET_TIMER;
}
spin_lock_irqsave(&task->task_state_lock, flags);
BUG_ON(task->task_state_flags & SAS_TASK_STATE_ABORTED);
if (task->task_state_flags & SAS_TASK_STATE_DONE) {
spin_unlock_irqrestore(&task->task_state_lock, flags);
- SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n",
- cmd, task);
- return EH_HANDLED;
+ SAS_DPRINTK("command 0x%p, task 0x%p, timed out: "
+ "BLK_EH_HANDLED\n", cmd, task);
+ return BLK_EH_HANDLED;
}
if (!(task->task_state_flags & SAS_TASK_AT_INITIATOR)) {
spin_unlock_irqrestore(&task->task_state_lock, flags);
SAS_DPRINTK("command 0x%p, task 0x%p, not at initiator: "
- "EH_RESET_TIMER\n",
+ "BLK_EH_RESET_TIMER\n",
cmd, task);
- return EH_RESET_TIMER;
+ return BLK_EH_RESET_TIMER;
}
task->task_state_flags |= SAS_TASK_STATE_ABORTED;
spin_unlock_irqrestore(&task->task_state_lock, flags);
- SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_NOT_HANDLED\n",
+ SAS_DPRINTK("command 0x%p, task 0x%p, timed out: BLK_EH_NOT_HANDLED\n",
cmd, task);
- return EH_NOT_HANDLED;
+ return BLK_EH_NOT_HANDLED;
}
int sas_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
@@ -1039,7 +1039,7 @@ void sas_task_abort(struct sas_task *task)
return;
}
- scsi_req_abort_cmd(sc);
+ blk_abort_request(sc->request);
scsi_schedule_eh(sc->device->host);
}
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
index 97b763378e7..afe1de99876 100644
--- a/drivers/scsi/megaraid/megaraid_sas.c
+++ b/drivers/scsi/megaraid/megaraid_sas.c
@@ -1167,7 +1167,7 @@ static int megasas_generic_reset(struct scsi_cmnd *scmd)
* cmd has not been completed within the timeout period.
*/
static enum
-scsi_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
+blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
{
struct megasas_cmd *cmd = (struct megasas_cmd *)scmd->SCp.ptr;
struct megasas_instance *instance;
@@ -1175,7 +1175,7 @@ scsi_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
if (time_after(jiffies, scmd->jiffies_at_alloc +
(MEGASAS_DEFAULT_CMD_TIMEOUT * 2) * HZ)) {
- return EH_NOT_HANDLED;
+ return BLK_EH_NOT_HANDLED;
}
instance = cmd->instance;
@@ -1189,7 +1189,7 @@ scsi_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
spin_unlock_irqrestore(instance->host->host_lock, flags);
}
- return EH_RESET_TIMER;
+ return BLK_EH_RESET_TIMER;
}
/**
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
index c57c94c0ffd..3b7240e4081 100644
--- a/drivers/scsi/ncr53c8xx.c
+++ b/drivers/scsi/ncr53c8xx.c
@@ -4170,8 +4170,8 @@ static int ncr_queue_command (struct ncb *np, struct scsi_cmnd *cmd)
**
**----------------------------------------------------
*/
- if (np->settle_time && cmd->timeout_per_command >= HZ) {
- u_long tlimit = jiffies + cmd->timeout_per_command - HZ;
+ if (np->settle_time && cmd->request->timeout >= HZ) {
+ u_long tlimit = jiffies + cmd->request->timeout - HZ;
if (time_after(np->settle_time, tlimit))
np->settle_time = tlimit;
}
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index 37f9ba0cd79..b6cd12b2e99 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -2845,7 +2845,7 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8));
/* Set ISP command timeout. */
- pkt->timeout = cpu_to_le16(cmd->timeout_per_command/HZ);
+ pkt->timeout = cpu_to_le16(cmd->request->timeout/HZ);
/* Set device target ID and LUN */
pkt->lun = SCSI_LUN_32(cmd);
@@ -3114,7 +3114,7 @@ qla1280_32bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8));
/* Set ISP command timeout. */
- pkt->timeout = cpu_to_le16(cmd->timeout_per_command/HZ);
+ pkt->timeout = cpu_to_le16(cmd->request->timeout/HZ);
/* Set device target ID and LUN */
pkt->lun = SCSI_LUN_32(cmd);
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 45e7dcb4b34..0ddfe7106b3 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -292,10 +292,11 @@ qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj,
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))
+ else if (start == (ha->flt_region_boot * 4) ||
+ start == (ha->flt_region_fw * 4))
valid = 1;
- else if (IS_QLA25XX(ha) && start == (FA_VPD_NVRAM_ADDR*4))
+ else if (IS_QLA25XX(ha) &&
+ start == (ha->flt_region_vpd_nvram * 4))
valid = 1;
if (!valid) {
qla_printk(KERN_WARNING, ha,
@@ -1065,6 +1066,8 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
pfc_host_stat->dumped_frames = stats->dumped_frames;
pfc_host_stat->nos_count = stats->nos_rcvd;
}
+ pfc_host_stat->fcp_input_megabytes = ha->qla_stats.input_bytes >> 20;
+ pfc_host_stat->fcp_output_megabytes = ha->qla_stats.output_bytes >> 20;
done_free:
dma_pool_free(ha->s_dma_pool, stats, stats_dma);
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 94a720eabfd..83c81921677 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -25,7 +25,6 @@
#include <linux/firmware.h>
#include <linux/aer.h>
#include <linux/mutex.h>
-#include <linux/semaphore.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
@@ -2157,6 +2156,8 @@ struct qla_chip_state_84xx {
struct qla_statistics {
uint32_t total_isp_aborts;
+ uint64_t input_bytes;
+ uint64_t output_bytes;
};
/*
@@ -2238,6 +2239,7 @@ typedef struct scsi_qla_host {
#define FCPORT_UPDATE_NEEDED 27
#define VP_DPC_NEEDED 28 /* wake up for VP dpc handling */
#define UNLOADING 29
+#define NPIV_CONFIG_NEEDED 30
uint32_t device_flags;
#define DFLG_LOCAL_DEVICES BIT_0
@@ -2507,7 +2509,6 @@ typedef struct scsi_qla_host {
uint64_t fce_wr, fce_rd;
struct mutex fce_mutex;
- uint32_t hw_event_start;
uint32_t hw_event_ptr;
uint32_t hw_event_pause_errors;
@@ -2553,6 +2554,14 @@ typedef struct scsi_qla_host {
uint32_t fdt_unprotect_sec_cmd;
uint32_t fdt_protect_sec_cmd;
+ uint32_t flt_region_flt;
+ uint32_t flt_region_fdt;
+ uint32_t flt_region_boot;
+ uint32_t flt_region_fw;
+ uint32_t flt_region_vpd_nvram;
+ uint32_t flt_region_hw_event;
+ uint32_t flt_region_npiv_conf;
+
/* Needed for BEACON */
uint16_t beacon_blink_led;
uint8_t beacon_color_state;
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
index cf194517400..d1d14202575 100644
--- a/drivers/scsi/qla2xxx/qla_fw.h
+++ b/drivers/scsi/qla2xxx/qla_fw.h
@@ -789,14 +789,23 @@ struct device_reg_24xx {
#define FA_RISC_CODE_ADDR 0x20000
#define FA_RISC_CODE_SEGMENTS 2
+#define FA_FLASH_DESCR_ADDR_24 0x11000
+#define FA_FLASH_LAYOUT_ADDR_24 0x11400
+#define FA_NPIV_CONF0_ADDR_24 0x16000
+#define FA_NPIV_CONF1_ADDR_24 0x17000
+
#define FA_FW_AREA_ADDR 0x40000
#define FA_VPD_NVRAM_ADDR 0x48000
#define FA_FEATURE_ADDR 0x4C000
#define FA_FLASH_DESCR_ADDR 0x50000
+#define FA_FLASH_LAYOUT_ADDR 0x50400
#define FA_HW_EVENT0_ADDR 0x54000
-#define FA_HW_EVENT1_ADDR 0x54200
+#define FA_HW_EVENT1_ADDR 0x54400
#define FA_HW_EVENT_SIZE 0x200
#define FA_HW_EVENT_ENTRY_SIZE 4
+#define FA_NPIV_CONF0_ADDR 0x5C000
+#define FA_NPIV_CONF1_ADDR 0x5D000
+
/*
* Flash Error Log Event Codes.
*/
@@ -806,10 +815,6 @@ struct device_reg_24xx {
#define HW_EVENT_NVRAM_CHKSUM_ERR 0xF023
#define HW_EVENT_FLASH_FW_ERR 0xF024
-#define FA_BOOT_LOG_ADDR 0x58000
-#define FA_FW_DUMP0_ADDR 0x60000
-#define FA_FW_DUMP1_ADDR 0x70000
-
uint32_t flash_data; /* Flash/NVRAM BIOS data. */
uint32_t ctrl_status; /* Control/Status. */
@@ -1203,6 +1208,62 @@ struct qla_fdt_layout {
uint8_t unused2[65];
};
+/* Flash Layout Table ********************************************************/
+
+struct qla_flt_location {
+ uint8_t sig[4];
+ uint32_t start_lo;
+ uint32_t start_hi;
+ uint16_t unused;
+ uint16_t checksum;
+};
+
+struct qla_flt_header {
+ uint16_t version;
+ uint16_t length;
+ uint16_t checksum;
+ uint16_t unused;
+};
+
+#define FLT_REG_FW 0x01
+#define FLT_REG_BOOT_CODE 0x07
+#define FLT_REG_VPD_0 0x14
+#define FLT_REG_NVRAM_0 0x15
+#define FLT_REG_VPD_1 0x16
+#define FLT_REG_NVRAM_1 0x17
+#define FLT_REG_FDT 0x1a
+#define FLT_REG_FLT 0x1c
+#define FLT_REG_HW_EVENT_0 0x1d
+#define FLT_REG_HW_EVENT_1 0x1f
+#define FLT_REG_NPIV_CONF_0 0x29
+#define FLT_REG_NPIV_CONF_1 0x2a
+
+struct qla_flt_region {
+ uint32_t code;
+ uint32_t size;
+ uint32_t start;
+ uint32_t end;
+};
+
+/* Flash NPIV Configuration Table ********************************************/
+
+struct qla_npiv_header {
+ uint8_t sig[2];
+ uint16_t version;
+ uint16_t entries;
+ uint16_t unused[4];
+ uint16_t checksum;
+};
+
+struct qla_npiv_entry {
+ uint16_t flags;
+ uint16_t vf_id;
+ uint16_t qos;
+ uint16_t unused1;
+ uint8_t port_name[WWN_SIZE];
+ uint8_t node_name[WWN_SIZE];
+};
+
/* 84XX Support **************************************************************/
#define MBA_ISP84XX_ALERT 0x800f /* Alert Notification. */
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 0b156735e9a..753dbe6cce6 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -313,9 +313,11 @@ extern int qla24xx_get_flash_version(scsi_qla_host_t *, void *);
extern int qla2xxx_hw_event_log(scsi_qla_host_t *, uint16_t , uint16_t,
uint16_t, uint16_t);
-extern void qla2xxx_get_flash_info(scsi_qla_host_t *);
+extern int qla2xxx_get_flash_info(scsi_qla_host_t *);
extern int qla2xxx_get_vpd_field(scsi_qla_host_t *, char *, char *, size_t);
+extern void qla2xxx_flash_npiv_conf(scsi_qla_host_t *);
+
/*
* Global Function Prototypes in qla_dbg.c source file.
*/
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index ee89ddd64aa..a470f2d3270 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -83,6 +83,13 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha)
ha->isp_ops->reset_chip(ha);
+ rval = qla2xxx_get_flash_info(ha);
+ if (rval) {
+ DEBUG2(printk("scsi(%ld): Unable to validate FLASH data.\n",
+ ha->host_no));
+ return (rval);
+ }
+
ha->isp_ops->get_flash_version(ha, ha->request_ring);
qla_printk(KERN_INFO, ha, "Configure NVRAM parameters...\n");
@@ -109,7 +116,6 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha)
rval = qla2x00_setup_chip(ha);
if (rval)
return (rval);
- qla2xxx_get_flash_info(ha);
}
if (IS_QLA84XX(ha)) {
ha->cs84xx = qla84xx_get_chip(ha);
@@ -2016,7 +2022,7 @@ qla2x00_configure_loop(scsi_qla_host_t *ha)
DEBUG3(printk("%s: exiting normally\n", __func__));
}
- /* Restore state if a resync event occured during processing */
+ /* Restore state if a resync event occurred during processing */
if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) {
if (test_bit(LOCAL_LOOP_UPDATE, &save_flags))
set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
@@ -2561,7 +2567,7 @@ 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 = kcalloc(MAX_FIBRE_DEVICES, sizeof(sw_info_t), GFP_ATOMIC);
+ swl = kcalloc(MAX_FIBRE_DEVICES, sizeof(sw_info_t), GFP_KERNEL);
if (!swl) {
/*EMPTY*/
DEBUG2(printk("scsi(%ld): GID_PT allocations failed, fallback "
@@ -3751,7 +3757,7 @@ qla24xx_load_risc_flash(scsi_qla_host_t *ha, uint32_t *srisc_addr)
rval = QLA_SUCCESS;
segments = FA_RISC_CODE_SEGMENTS;
- faddr = FA_RISC_CODE_ADDR;
+ faddr = ha->flt_region_fw;
dcode = (uint32_t *)ha->request_ring;
*srisc_addr = 0;
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
index 92fafbdbbaa..e90afad120e 100644
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -52,7 +52,7 @@ to_qla_parent(scsi_qla_host_t *ha)
* @ha: HA context
* @ha_locked: is function called with the hardware lock
*
- * Returns non-zero if a failure occured, else zero.
+ * Returns non-zero if a failure occurred, else zero.
*/
static inline int
qla2x00_issue_marker(scsi_qla_host_t *ha, int ha_locked)
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index d57669aa461..85bc0a48598 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -21,17 +21,22 @@ static void qla2x00_isp_cmd(scsi_qla_host_t *ha);
* Returns the proper CF_* direction based on CDB.
*/
static inline uint16_t
-qla2x00_get_cmd_direction(struct scsi_cmnd *cmd)
+qla2x00_get_cmd_direction(srb_t *sp)
{
uint16_t cflags;
cflags = 0;
/* Set transfer direction */
- if (cmd->sc_data_direction == DMA_TO_DEVICE)
+ if (sp->cmd->sc_data_direction == DMA_TO_DEVICE) {
cflags = CF_WRITE;
- else if (cmd->sc_data_direction == DMA_FROM_DEVICE)
+ sp->fcport->ha->qla_stats.output_bytes +=
+ scsi_bufflen(sp->cmd);
+ } else if (sp->cmd->sc_data_direction == DMA_FROM_DEVICE) {
cflags = CF_READ;
+ sp->fcport->ha->qla_stats.input_bytes +=
+ scsi_bufflen(sp->cmd);
+ }
return (cflags);
}
@@ -169,7 +174,7 @@ void qla2x00_build_scsi_iocbs_32(srb_t *sp, cmd_entry_t *cmd_pkt,
ha = sp->ha;
- cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(cmd));
+ cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(sp));
/* Three DSDs are available in the Command Type 2 IOCB */
avail_dsds = 3;
@@ -228,7 +233,7 @@ void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt,
ha = sp->ha;
- cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(cmd));
+ cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(sp));
/* Two DSDs are available in the Command Type 3 IOCB */
avail_dsds = 2;
@@ -262,7 +267,7 @@ void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt,
* qla2x00_start_scsi() - Send a SCSI command to the ISP
* @sp: command to send to the ISP
*
- * Returns non-zero if a failure occured, else zero.
+ * Returns non-zero if a failure occurred, else zero.
*/
int
qla2x00_start_scsi(srb_t *sp)
@@ -407,7 +412,7 @@ queuing_error:
*
* Can be called from both normal and interrupt context.
*
- * Returns non-zero if a failure occured, else zero.
+ * Returns non-zero if a failure occurred, else zero.
*/
int
__qla2x00_marker(scsi_qla_host_t *ha, uint16_t loop_id, uint16_t lun,
@@ -625,12 +630,17 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt,
ha = sp->ha;
/* Set transfer direction */
- if (cmd->sc_data_direction == DMA_TO_DEVICE)
+ if (cmd->sc_data_direction == DMA_TO_DEVICE) {
cmd_pkt->task_mgmt_flags =
__constant_cpu_to_le16(TMF_WRITE_DATA);
- else if (cmd->sc_data_direction == DMA_FROM_DEVICE)
+ sp->fcport->ha->qla_stats.output_bytes +=
+ scsi_bufflen(sp->cmd);
+ } else if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
cmd_pkt->task_mgmt_flags =
__constant_cpu_to_le16(TMF_READ_DATA);
+ sp->fcport->ha->qla_stats.input_bytes +=
+ scsi_bufflen(sp->cmd);
+ }
/* One DSD is available in the Command Type 3 IOCB */
avail_dsds = 1;
@@ -666,7 +676,7 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt,
* qla24xx_start_scsi() - Send a SCSI command to the ISP
* @sp: command to send to the ISP
*
- * Returns non-zero if a failure occured, else zero.
+ * Returns non-zero if a failure occurred, else zero.
*/
int
qla24xx_start_scsi(srb_t *sp)
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 45a3b93eed5..fc4bfa7f839 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -391,9 +391,9 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
break;
case MBA_LIP_OCCURRED: /* Loop Initialization Procedure */
- DEBUG2(printk("scsi(%ld): LIP occured (%x).\n", ha->host_no,
+ DEBUG2(printk("scsi(%ld): LIP occurred (%x).\n", ha->host_no,
mb[1]));
- qla_printk(KERN_INFO, ha, "LIP occured (%x).\n", mb[1]);
+ qla_printk(KERN_INFO, ha, "LIP occurred (%x).\n", mb[1]);
if (atomic_read(&ha->loop_state) != LOOP_DOWN) {
atomic_set(&ha->loop_state, LOOP_DOWN);
@@ -460,7 +460,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
DEBUG2(printk("scsi(%ld): Asynchronous LIP RESET (%x).\n",
ha->host_no, mb[1]));
qla_printk(KERN_INFO, ha,
- "LIP reset occured (%x).\n", mb[1]);
+ "LIP reset occurred (%x).\n", mb[1]);
if (atomic_read(&ha->loop_state) != LOOP_DOWN) {
atomic_set(&ha->loop_state, LOOP_DOWN);
@@ -543,7 +543,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
case MBA_PORT_UPDATE: /* Port database update */
/*
- * If PORT UPDATE is global (recieved LIP_OCCURED/LIP_RESET
+ * If PORT UPDATE is global (received LIP_OCCURRED/LIP_RESET
* event etc. earlier indicating loop is down) then process
* it. Otherwise ignore it and Wait for RSCN to come in.
*/
@@ -589,7 +589,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
"scsi(%ld): RSCN database changed -- %04x %04x %04x.\n",
ha->host_no, mb[1], mb[2], mb[3]));
- rscn_entry = (mb[1] << 16) | mb[2];
+ rscn_entry = ((mb[1] & 0xff) << 16) | mb[2];
host_pid = (ha->d_id.b.domain << 16) | (ha->d_id.b.area << 8) |
ha->d_id.b.al_pa;
if (rscn_entry == host_pid) {
@@ -600,6 +600,8 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
break;
}
+ /* Ignore reserved bits from RSCN-payload. */
+ rscn_entry = ((mb[1] & 0x3ff) << 16) | mb[2];
rscn_queue_index = ha->rscn_in_ptr + 1;
if (rscn_queue_index == MAX_RSCN_COUNT)
rscn_queue_index = 0;
@@ -1060,8 +1062,9 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
resid = resid_len;
/* Use F/W calculated residual length. */
if (IS_FWI2_CAPABLE(ha)) {
- if (scsi_status & SS_RESIDUAL_UNDER &&
- resid != fw_resid_len) {
+ if (!(scsi_status & SS_RESIDUAL_UNDER)) {
+ lscsi_status = 0;
+ } else if (resid != fw_resid_len) {
scsi_status &= ~SS_RESIDUAL_UNDER;
lscsi_status = 0;
}
@@ -1834,7 +1837,6 @@ clear_risc_ints:
WRT_REG_WORD(&reg->isp.hccr, HCCR_CLR_HOST_INT);
}
spin_unlock_irq(&ha->hardware_lock);
- ha->isp_ops->enable_intrs(ha);
fail:
return ret;
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 813bc7784c0..36bc6851e23 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -233,7 +233,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
DEBUG2_3_11(printk("%s(%ld): timeout schedule "
"isp_abort_needed.\n", __func__, ha->host_no));
qla_printk(KERN_WARNING, ha,
- "Mailbox command timeout occured. Scheduling ISP "
+ "Mailbox command timeout occurred. Scheduling ISP "
"abort.\n");
set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
qla2xxx_wake_dpc(ha);
@@ -244,7 +244,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
DEBUG2_3_11(printk("%s(%ld): timeout calling "
"abort_isp\n", __func__, ha->host_no));
qla_printk(KERN_WARNING, ha,
- "Mailbox command timeout occured. Issuing ISP "
+ "Mailbox command timeout occurred. Issuing ISP "
"abort.\n");
set_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
@@ -1995,7 +1995,7 @@ qla2x00_get_fcal_position_map(scsi_qla_host_t *ha, char *pos_map)
char *pmap;
dma_addr_t pmap_dma;
- pmap = dma_pool_alloc(ha->s_dma_pool, GFP_ATOMIC, &pmap_dma);
+ pmap = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &pmap_dma);
if (pmap == NULL) {
DEBUG2_3_11(printk("%s(%ld): **** Mem Alloc Failed ****",
__func__, ha->host_no));
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 26afe44265c..3433441b956 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -1517,6 +1517,7 @@ qla2xxx_scan_start(struct Scsi_Host *shost)
set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
set_bit(RSCN_UPDATE, &ha->dpc_flags);
+ set_bit(NPIV_CONFIG_NEEDED, &ha->dpc_flags);
}
static int
@@ -1663,8 +1664,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->gid_list_info_size = 8;
ha->optrom_size = OPTROM_SIZE_25XX;
ha->isp_ops = &qla25xx_isp_ops;
- ha->hw_event_start = PCI_FUNC(pdev->devfn) ?
- FA_HW_EVENT1_ADDR: FA_HW_EVENT0_ADDR;
}
host->can_queue = ha->request_q_length + 128;
@@ -1740,6 +1739,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
if (ret)
goto probe_failed;
+ ha->isp_ops->enable_intrs(ha);
+
scsi_scan_host(host);
qla2x00_alloc_sysfs_attr(ha);
@@ -2431,6 +2432,12 @@ qla2x00_do_dpc(void *data)
ha->host_no));
}
+ if (test_bit(NPIV_CONFIG_NEEDED, &ha->dpc_flags) &&
+ atomic_read(&ha->loop_state) == LOOP_READY) {
+ clear_bit(NPIV_CONFIG_NEEDED, &ha->dpc_flags);
+ qla2xxx_flash_npiv_conf(ha);
+ }
+
if (!ha->interrupts_on)
ha->isp_ops->enable_intrs(ha);
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index 1bca7447493..90a13211717 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -543,23 +543,198 @@ qla24xx_get_flash_manufacturer(scsi_qla_host_t *ha, uint8_t *man_id,
}
}
-void
-qla2xxx_get_flash_info(scsi_qla_host_t *ha)
+static int
+qla2xxx_find_flt_start(scsi_qla_host_t *ha, uint32_t *start)
+{
+ const char *loc, *locations[] = { "DEF", "PCI" };
+ uint32_t pcihdr, pcids;
+ uint32_t *dcode;
+ uint8_t *buf, *bcode, last_image;
+ uint16_t cnt, chksum, *wptr;
+ struct qla_flt_location *fltl;
+
+ /*
+ * FLT-location structure resides after the last PCI region.
+ */
+
+ /* Begin with sane defaults. */
+ loc = locations[0];
+ *start = IS_QLA24XX_TYPE(ha) ? FA_FLASH_LAYOUT_ADDR_24:
+ FA_FLASH_LAYOUT_ADDR;
+
+ /* Begin with first PCI expansion ROM header. */
+ buf = (uint8_t *)ha->request_ring;
+ dcode = (uint32_t *)ha->request_ring;
+ pcihdr = 0;
+ last_image = 1;
+ do {
+ /* Verify PCI expansion ROM header. */
+ qla24xx_read_flash_data(ha, dcode, pcihdr >> 2, 0x20);
+ bcode = buf + (pcihdr % 4);
+ if (bcode[0x0] != 0x55 || bcode[0x1] != 0xaa)
+ goto end;
+
+ /* Locate PCI data structure. */
+ pcids = pcihdr + ((bcode[0x19] << 8) | bcode[0x18]);
+ qla24xx_read_flash_data(ha, dcode, pcids >> 2, 0x20);
+ bcode = buf + (pcihdr % 4);
+
+ /* Validate signature of PCI data structure. */
+ if (bcode[0x0] != 'P' || bcode[0x1] != 'C' ||
+ bcode[0x2] != 'I' || bcode[0x3] != 'R')
+ goto end;
+
+ last_image = bcode[0x15] & BIT_7;
+
+ /* Locate next PCI expansion ROM. */
+ pcihdr += ((bcode[0x11] << 8) | bcode[0x10]) * 512;
+ } while (!last_image);
+
+ /* Now verify FLT-location structure. */
+ fltl = (struct qla_flt_location *)ha->request_ring;
+ qla24xx_read_flash_data(ha, dcode, pcihdr >> 2,
+ sizeof(struct qla_flt_location) >> 2);
+ if (fltl->sig[0] != 'Q' || fltl->sig[1] != 'F' ||
+ fltl->sig[2] != 'L' || fltl->sig[3] != 'T')
+ goto end;
+
+ wptr = (uint16_t *)ha->request_ring;
+ cnt = sizeof(struct qla_flt_location) >> 1;
+ for (chksum = 0; cnt; cnt--)
+ chksum += le16_to_cpu(*wptr++);
+ if (chksum) {
+ qla_printk(KERN_ERR, ha,
+ "Inconsistent FLTL detected: checksum=0x%x.\n", chksum);
+ qla2x00_dump_buffer(buf, sizeof(struct qla_flt_location));
+ return QLA_FUNCTION_FAILED;
+ }
+
+ /* Good data. Use specified location. */
+ loc = locations[1];
+ *start = le16_to_cpu(fltl->start_hi) << 16 |
+ le16_to_cpu(fltl->start_lo);
+end:
+ DEBUG2(qla_printk(KERN_DEBUG, ha, "FLTL[%s] = 0x%x.\n", loc, *start));
+ return QLA_SUCCESS;
+}
+
+static void
+qla2xxx_get_flt_info(scsi_qla_host_t *ha, uint32_t flt_addr)
+{
+ const char *loc, *locations[] = { "DEF", "FLT" };
+ uint16_t *wptr;
+ uint16_t cnt, chksum;
+ uint32_t start;
+ struct qla_flt_header *flt;
+ struct qla_flt_region *region;
+
+ ha->flt_region_flt = flt_addr;
+ wptr = (uint16_t *)ha->request_ring;
+ flt = (struct qla_flt_header *)ha->request_ring;
+ region = (struct qla_flt_region *)&flt[1];
+ ha->isp_ops->read_optrom(ha, (uint8_t *)ha->request_ring,
+ flt_addr << 2, OPTROM_BURST_SIZE);
+ if (*wptr == __constant_cpu_to_le16(0xffff))
+ goto no_flash_data;
+ if (flt->version != __constant_cpu_to_le16(1)) {
+ DEBUG2(qla_printk(KERN_INFO, ha, "Unsupported FLT detected: "
+ "version=0x%x length=0x%x checksum=0x%x.\n",
+ le16_to_cpu(flt->version), le16_to_cpu(flt->length),
+ le16_to_cpu(flt->checksum)));
+ goto no_flash_data;
+ }
+
+ cnt = (sizeof(struct qla_flt_header) + le16_to_cpu(flt->length)) >> 1;
+ for (chksum = 0; cnt; cnt--)
+ chksum += le16_to_cpu(*wptr++);
+ if (chksum) {
+ DEBUG2(qla_printk(KERN_INFO, ha, "Inconsistent FLT detected: "
+ "version=0x%x length=0x%x checksum=0x%x.\n",
+ le16_to_cpu(flt->version), le16_to_cpu(flt->length),
+ chksum));
+ goto no_flash_data;
+ }
+
+ loc = locations[1];
+ cnt = le16_to_cpu(flt->length) / sizeof(struct qla_flt_region);
+ for ( ; cnt; cnt--, region++) {
+ /* Store addresses as DWORD offsets. */
+ start = le32_to_cpu(region->start) >> 2;
+
+ DEBUG3(qla_printk(KERN_DEBUG, ha, "FLT[%02x]: start=0x%x "
+ "end=0x%x size=0x%x.\n", le32_to_cpu(region->code), start,
+ le32_to_cpu(region->end) >> 2, le32_to_cpu(region->size)));
+
+ switch (le32_to_cpu(region->code)) {
+ case FLT_REG_FW:
+ ha->flt_region_fw = start;
+ break;
+ case FLT_REG_BOOT_CODE:
+ ha->flt_region_boot = start;
+ break;
+ case FLT_REG_VPD_0:
+ ha->flt_region_vpd_nvram = start;
+ break;
+ case FLT_REG_FDT:
+ ha->flt_region_fdt = start;
+ break;
+ case FLT_REG_HW_EVENT_0:
+ if (!PCI_FUNC(ha->pdev->devfn))
+ ha->flt_region_hw_event = start;
+ break;
+ case FLT_REG_HW_EVENT_1:
+ if (PCI_FUNC(ha->pdev->devfn))
+ ha->flt_region_hw_event = start;
+ break;
+ case FLT_REG_NPIV_CONF_0:
+ if (!PCI_FUNC(ha->pdev->devfn))
+ ha->flt_region_npiv_conf = start;
+ break;
+ case FLT_REG_NPIV_CONF_1:
+ if (PCI_FUNC(ha->pdev->devfn))
+ ha->flt_region_npiv_conf = start;
+ break;
+ }
+ }
+ goto done;
+
+no_flash_data:
+ /* Use hardcoded defaults. */
+ loc = locations[0];
+ ha->flt_region_fw = FA_RISC_CODE_ADDR;
+ ha->flt_region_boot = FA_BOOT_CODE_ADDR;
+ ha->flt_region_vpd_nvram = FA_VPD_NVRAM_ADDR;
+ ha->flt_region_fdt = IS_QLA24XX_TYPE(ha) ? FA_FLASH_DESCR_ADDR_24:
+ FA_FLASH_DESCR_ADDR;
+ ha->flt_region_hw_event = !PCI_FUNC(ha->pdev->devfn) ?
+ FA_HW_EVENT0_ADDR: FA_HW_EVENT1_ADDR;
+ ha->flt_region_npiv_conf = !PCI_FUNC(ha->pdev->devfn) ?
+ (IS_QLA24XX_TYPE(ha) ? FA_NPIV_CONF0_ADDR_24: FA_NPIV_CONF0_ADDR):
+ (IS_QLA24XX_TYPE(ha) ? FA_NPIV_CONF1_ADDR_24: FA_NPIV_CONF1_ADDR);
+done:
+ DEBUG2(qla_printk(KERN_DEBUG, ha, "FLT[%s]: boot=0x%x fw=0x%x "
+ "vpd_nvram=0x%x fdt=0x%x flt=0x%x hwe=0x%x npiv=0x%x.\n", loc,
+ ha->flt_region_boot, ha->flt_region_fw, ha->flt_region_vpd_nvram,
+ ha->flt_region_fdt, ha->flt_region_flt, ha->flt_region_hw_event,
+ ha->flt_region_npiv_conf));
+}
+
+static void
+qla2xxx_get_fdt_info(scsi_qla_host_t *ha)
{
#define FLASH_BLK_SIZE_32K 0x8000
#define FLASH_BLK_SIZE_64K 0x10000
+ const char *loc, *locations[] = { "MID", "FDT" };
uint16_t cnt, chksum;
uint16_t *wptr;
struct qla_fdt_layout *fdt;
uint8_t man_id, flash_id;
-
- if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha))
- return;
+ uint16_t mid, fid;
wptr = (uint16_t *)ha->request_ring;
fdt = (struct qla_fdt_layout *)ha->request_ring;
ha->isp_ops->read_optrom(ha, (uint8_t *)ha->request_ring,
- FA_FLASH_DESCR_ADDR << 2, OPTROM_BURST_SIZE);
+ ha->flt_region_fdt << 2, OPTROM_BURST_SIZE);
if (*wptr == __constant_cpu_to_le16(0xffff))
goto no_flash_data;
if (fdt->sig[0] != 'Q' || fdt->sig[1] != 'L' || fdt->sig[2] != 'I' ||
@@ -577,7 +752,10 @@ qla2xxx_get_flash_info(scsi_qla_host_t *ha)
goto no_flash_data;
}
- ha->fdt_odd_index = le16_to_cpu(fdt->man_id) == 0x1f;
+ loc = locations[1];
+ mid = le16_to_cpu(fdt->man_id);
+ fid = le16_to_cpu(fdt->id);
+ ha->fdt_odd_index = mid == 0x1f;
ha->fdt_wrt_disable = fdt->wrt_disable_bits;
ha->fdt_erase_cmd = flash_conf_to_access_addr(0x0300 | fdt->erase_cmd);
ha->fdt_block_size = le32_to_cpu(fdt->block_size);
@@ -588,16 +766,12 @@ qla2xxx_get_flash_info(scsi_qla_host_t *ha)
flash_conf_to_access_addr(0x0300 | fdt->protect_sec_cmd):
flash_conf_to_access_addr(0x0336);
}
-
- DEBUG2(qla_printk(KERN_DEBUG, ha, "Flash[FDT]: (0x%x/0x%x) erase=0x%x "
- "pro=%x upro=%x idx=%d wrtd=0x%x blk=0x%x.\n",
- le16_to_cpu(fdt->man_id), le16_to_cpu(fdt->id), ha->fdt_erase_cmd,
- ha->fdt_protect_sec_cmd, ha->fdt_unprotect_sec_cmd,
- ha->fdt_odd_index, ha->fdt_wrt_disable, ha->fdt_block_size));
- return;
-
+ goto done;
no_flash_data:
+ loc = locations[0];
qla24xx_get_flash_manufacturer(ha, &man_id, &flash_id);
+ mid = man_id;
+ fid = flash_id;
ha->fdt_wrt_disable = 0x9c;
ha->fdt_erase_cmd = flash_conf_to_access_addr(0x03d8);
switch (man_id) {
@@ -625,14 +799,117 @@ no_flash_data:
ha->fdt_block_size = FLASH_BLK_SIZE_64K;
break;
}
-
- DEBUG2(qla_printk(KERN_DEBUG, ha, "Flash[MID]: (0x%x/0x%x) erase=0x%x "
- "pro=%x upro=%x idx=%d wrtd=0x%x blk=0x%x.\n", man_id, flash_id,
+done:
+ DEBUG2(qla_printk(KERN_DEBUG, ha, "FDT[%s]: (0x%x/0x%x) erase=0x%x "
+ "pro=%x upro=%x idx=%d wrtd=0x%x blk=0x%x.\n", loc, mid, fid,
ha->fdt_erase_cmd, ha->fdt_protect_sec_cmd,
ha->fdt_unprotect_sec_cmd, ha->fdt_odd_index, ha->fdt_wrt_disable,
ha->fdt_block_size));
}
+int
+qla2xxx_get_flash_info(scsi_qla_host_t *ha)
+{
+ int ret;
+ uint32_t flt_addr;
+
+ if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha))
+ return QLA_SUCCESS;
+
+ ret = qla2xxx_find_flt_start(ha, &flt_addr);
+ if (ret != QLA_SUCCESS)
+ return ret;
+
+ qla2xxx_get_flt_info(ha, flt_addr);
+ qla2xxx_get_fdt_info(ha);
+
+ return QLA_SUCCESS;
+}
+
+void
+qla2xxx_flash_npiv_conf(scsi_qla_host_t *ha)
+{
+#define NPIV_CONFIG_SIZE (16*1024)
+ void *data;
+ uint16_t *wptr;
+ uint16_t cnt, chksum;
+ struct qla_npiv_header hdr;
+ struct qla_npiv_entry *entry;
+
+ if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha))
+ return;
+
+ ha->isp_ops->read_optrom(ha, (uint8_t *)&hdr,
+ ha->flt_region_npiv_conf << 2, sizeof(struct qla_npiv_header));
+ if (hdr.version == __constant_cpu_to_le16(0xffff))
+ return;
+ if (hdr.version != __constant_cpu_to_le16(1)) {
+ DEBUG2(qla_printk(KERN_INFO, ha, "Unsupported NPIV-Config "
+ "detected: version=0x%x entries=0x%x checksum=0x%x.\n",
+ le16_to_cpu(hdr.version), le16_to_cpu(hdr.entries),
+ le16_to_cpu(hdr.checksum)));
+ return;
+ }
+
+ data = kmalloc(NPIV_CONFIG_SIZE, GFP_KERNEL);
+ if (!data) {
+ DEBUG2(qla_printk(KERN_INFO, ha, "NPIV-Config: Unable to "
+ "allocate memory.\n"));
+ return;
+ }
+
+ ha->isp_ops->read_optrom(ha, (uint8_t *)data,
+ ha->flt_region_npiv_conf << 2, NPIV_CONFIG_SIZE);
+
+ cnt = (sizeof(struct qla_npiv_header) + le16_to_cpu(hdr.entries) *
+ sizeof(struct qla_npiv_entry)) >> 1;
+ for (wptr = data, chksum = 0; cnt; cnt--)
+ chksum += le16_to_cpu(*wptr++);
+ if (chksum) {
+ DEBUG2(qla_printk(KERN_INFO, ha, "Inconsistent NPIV-Config "
+ "detected: version=0x%x entries=0x%x checksum=0x%x.\n",
+ le16_to_cpu(hdr.version), le16_to_cpu(hdr.entries),
+ chksum));
+ goto done;
+ }
+
+ entry = data + sizeof(struct qla_npiv_header);
+ cnt = le16_to_cpu(hdr.entries);
+ for ( ; cnt; cnt--, entry++) {
+ uint16_t flags;
+ struct fc_vport_identifiers vid;
+ struct fc_vport *vport;
+
+ flags = le16_to_cpu(entry->flags);
+ if (flags == 0xffff)
+ continue;
+ if ((flags & BIT_0) == 0)
+ continue;
+
+ memset(&vid, 0, sizeof(vid));
+ vid.roles = FC_PORT_ROLE_FCP_INITIATOR;
+ vid.vport_type = FC_PORTTYPE_NPIV;
+ vid.disable = false;
+ vid.port_name = wwn_to_u64(entry->port_name);
+ vid.node_name = wwn_to_u64(entry->node_name);
+
+ DEBUG2(qla_printk(KERN_DEBUG, ha, "NPIV[%02x]: wwpn=%llx "
+ "wwnn=%llx vf_id=0x%x qos=0x%x.\n", cnt,
+ (unsigned long long)vid.port_name,
+ (unsigned long long)vid.node_name,
+ le16_to_cpu(entry->vf_id), le16_to_cpu(entry->qos)));
+
+ vport = fc_vport_create(ha->host, 0, &vid);
+ if (!vport)
+ qla_printk(KERN_INFO, ha, "NPIV-Config: Failed to "
+ "create vport [%02x]: wwpn=%llx wwnn=%llx.\n", cnt,
+ (unsigned long long)vid.port_name,
+ (unsigned long long)vid.node_name);
+ }
+done:
+ kfree(data);
+}
+
static void
qla24xx_unprotect_flash(scsi_qla_host_t *ha)
{
@@ -920,7 +1197,8 @@ qla25xx_read_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,
dwptr = (uint32_t *)buf;
for (i = 0; i < bytes >> 2; i++, naddr++)
dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha,
- flash_data_to_access_addr(FA_VPD_NVRAM_ADDR | naddr)));
+ flash_data_to_access_addr(ha->flt_region_vpd_nvram |
+ naddr)));
return buf;
}
@@ -935,10 +1213,10 @@ qla25xx_write_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,
dbuf = vmalloc(RMW_BUFFER_SIZE);
if (!dbuf)
return QLA_MEMORY_ALLOC_FAILED;
- ha->isp_ops->read_optrom(ha, dbuf, FA_VPD_NVRAM_ADDR << 2,
+ ha->isp_ops->read_optrom(ha, dbuf, ha->flt_region_vpd_nvram << 2,
RMW_BUFFER_SIZE);
memcpy(dbuf + (naddr << 2), buf, bytes);
- ha->isp_ops->write_optrom(ha, dbuf, FA_VPD_NVRAM_ADDR << 2,
+ ha->isp_ops->write_optrom(ha, dbuf, ha->flt_region_vpd_nvram << 2,
RMW_BUFFER_SIZE);
vfree(dbuf);
@@ -2166,7 +2444,7 @@ qla2x00_get_flash_version(scsi_qla_host_t *ha, void *mbuf)
memset(dbyte, 0, 8);
dcode = (uint16_t *)dbyte;
- qla2x00_read_flash_data(ha, dbyte, FA_RISC_CODE_ADDR * 4 + 10,
+ qla2x00_read_flash_data(ha, dbyte, ha->flt_region_fw * 4 + 10,
8);
DEBUG3(printk("%s(%ld): dumping fw ver from flash:\n",
__func__, ha->host_no));
@@ -2177,7 +2455,7 @@ qla2x00_get_flash_version(scsi_qla_host_t *ha, void *mbuf)
(dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 &&
dcode[3] == 0)) {
DEBUG2(printk("%s(): Unrecognized fw revision at "
- "%x.\n", __func__, FA_RISC_CODE_ADDR * 4));
+ "%x.\n", __func__, ha->flt_region_fw * 4));
} else {
/* values are in big endian */
ha->fw_revision[0] = dbyte[0] << 16 | dbyte[1];
@@ -2212,7 +2490,7 @@ qla24xx_get_flash_version(scsi_qla_host_t *ha, void *mbuf)
dcode = mbuf;
/* Begin with first PCI expansion ROM header. */
- pcihdr = 0;
+ pcihdr = ha->flt_region_boot;
last_image = 1;
do {
/* Verify PCI expansion ROM header. */
@@ -2282,7 +2560,7 @@ qla24xx_get_flash_version(scsi_qla_host_t *ha, void *mbuf)
memset(ha->fw_revision, 0, sizeof(ha->fw_revision));
dcode = mbuf;
- qla24xx_read_flash_data(ha, dcode, FA_RISC_CODE_ADDR + 4, 4);
+ qla24xx_read_flash_data(ha, dcode, ha->flt_region_fw + 4, 4);
for (i = 0; i < 4; i++)
dcode[i] = be32_to_cpu(dcode[i]);
@@ -2291,7 +2569,7 @@ qla24xx_get_flash_version(scsi_qla_host_t *ha, void *mbuf)
(dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 &&
dcode[3] == 0)) {
DEBUG2(printk("%s(): Unrecognized fw version at %x.\n",
- __func__, FA_RISC_CODE_ADDR));
+ __func__, ha->flt_region_fw));
} else {
ha->fw_revision[0] = dcode[0];
ha->fw_revision[1] = dcode[1];
@@ -2355,7 +2633,7 @@ qla2xxx_hw_event_store(scsi_qla_host_t *ha, uint32_t *fdata)
/* Locate first empty entry. */
for (;;) {
if (ha->hw_event_ptr >=
- ha->hw_event_start + FA_HW_EVENT_SIZE) {
+ ha->flt_region_hw_event + FA_HW_EVENT_SIZE) {
DEBUG2(qla_printk(KERN_WARNING, ha,
"HW event -- Log Full!\n"));
return QLA_MEMORY_ALLOC_FAILED;
@@ -2391,7 +2669,7 @@ qla2xxx_hw_event_log(scsi_qla_host_t *ha, uint16_t code, uint16_t d1,
int rval;
uint32_t marker[2], fdata[4];
- if (ha->hw_event_start == 0)
+ if (ha->flt_region_hw_event == 0)
return QLA_FUNCTION_FAILED;
DEBUG2(qla_printk(KERN_WARNING, ha,
@@ -2406,7 +2684,7 @@ qla2xxx_hw_event_log(scsi_qla_host_t *ha, uint16_t code, uint16_t d1,
QLA_DRIVER_PATCH_VER, QLA_DRIVER_BETA_VER);
/* Locate marker. */
- ha->hw_event_ptr = ha->hw_event_start;
+ ha->hw_event_ptr = ha->flt_region_hw_event;
for (;;) {
qla24xx_read_flash_data(ha, fdata, ha->hw_event_ptr,
4);
@@ -2415,7 +2693,7 @@ qla2xxx_hw_event_log(scsi_qla_host_t *ha, uint16_t code, uint16_t d1,
break;
ha->hw_event_ptr += FA_HW_EVENT_ENTRY_SIZE;
if (ha->hw_event_ptr >=
- ha->hw_event_start + FA_HW_EVENT_SIZE) {
+ ha->flt_region_hw_event + FA_HW_EVENT_SIZE) {
DEBUG2(qla_printk(KERN_WARNING, ha,
"HW event -- Log Full!\n"));
return QLA_MEMORY_ALLOC_FAILED;
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index 4160e4caa7b..be5e299df52 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.01-k7"
+#define QLA2XXX_VERSION "8.02.01-k8"
#define QLA_DRIVER_MAJOR_VER 8
#define QLA_DRIVER_MINOR_VER 2
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index 88bebb13bc5..de8279ad7d8 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -1542,7 +1542,7 @@ static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd)
DEBUG2(printk(KERN_INFO
"scsi%ld: DEVICE_RESET cmd=%p jiffies = 0x%lx, to=%x,"
"dpc_flags=%lx, status=%x allowed=%d\n", ha->host_no,
- cmd, jiffies, cmd->timeout_per_command / HZ,
+ cmd, jiffies, cmd->request->timeout / HZ,
ha->dpc_flags, cmd->result, cmd->allowed));
/* FIXME: wait for hba to go online */
@@ -1598,7 +1598,7 @@ static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd)
DEBUG2(printk(KERN_INFO
"scsi%ld: TARGET_DEVICE_RESET cmd=%p jiffies = 0x%lx, "
"to=%x,dpc_flags=%lx, status=%x allowed=%d\n",
- ha->host_no, cmd, jiffies, cmd->timeout_per_command / HZ,
+ ha->host_no, cmd, jiffies, cmd->request->timeout / HZ,
ha->dpc_flags, cmd->result, cmd->allowed));
stat = qla4xxx_reset_target(ha, ddb_entry);
diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
index 4a1cf6377f6..90535089672 100644
--- a/drivers/scsi/qlogicpti.c
+++ b/drivers/scsi/qlogicpti.c
@@ -914,6 +914,7 @@ static inline int load_cmd(struct scsi_cmnd *Cmnd, struct Command_Entry *cmd,
ds[i].d_count = sg_dma_len(s);
}
sg_count -= n;
+ sg = s;
}
} else {
cmd->dataseg[0].d_base = 0;
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index ee6be596503..2ac3cb2b908 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -291,7 +291,6 @@ struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, gfp_t gfp_mask)
unsigned long flags;
cmd->device = dev;
- init_timer(&cmd->eh_timeout);
INIT_LIST_HEAD(&cmd->list);
spin_lock_irqsave(&dev->list_lock, flags);
list_add_tail(&cmd->list, &dev->cmd_list);
@@ -652,26 +651,33 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
unsigned long timeout;
int rtn = 0;
+ /*
+ * We will use a queued command if possible, otherwise we will
+ * emulate the queuing and calling of completion function ourselves.
+ */
+ atomic_inc(&cmd->device->iorequest_cnt);
+
/* check if the device is still usable */
if (unlikely(cmd->device->sdev_state == SDEV_DEL)) {
/* in SDEV_DEL we error all commands. DID_NO_CONNECT
* returns an immediate error upwards, and signals
* that the device is no longer present */
cmd->result = DID_NO_CONNECT << 16;
- atomic_inc(&cmd->device->iorequest_cnt);
- __scsi_done(cmd);
+ scsi_done(cmd);
/* return 0 (because the command has been processed) */
goto out;
}
- /* Check to see if the scsi lld put this device into state SDEV_BLOCK. */
- if (unlikely(cmd->device->sdev_state == SDEV_BLOCK)) {
+ /* Check to see if the scsi lld made this device blocked. */
+ if (unlikely(scsi_device_blocked(cmd->device))) {
/*
- * in SDEV_BLOCK, the command is just put back on the device
- * queue. The suspend state has already blocked the queue so
- * future requests should not occur until the device
- * transitions out of the suspend state.
+ * in blocked state, the command is just put back on
+ * the device queue. The suspend state has already
+ * blocked the queue so future requests should not
+ * occur until the device transitions out of the
+ * suspend state.
*/
+
scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
SCSI_LOG_MLQUEUE(3, printk("queuecommand : device blocked \n"));
@@ -714,21 +720,9 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
host->resetting = 0;
}
- /*
- * AK: unlikely race here: for some reason the timer could
- * expire before the serial number is set up below.
- */
- scsi_add_timer(cmd, cmd->timeout_per_command, scsi_times_out);
-
scsi_log_send(cmd);
/*
- * We will use a queued command if possible, otherwise we will
- * emulate the queuing and calling of completion function ourselves.
- */
- atomic_inc(&cmd->device->iorequest_cnt);
-
- /*
* Before we queue this command, check if the command
* length exceeds what the host adapter can handle.
*/
@@ -744,6 +738,12 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
}
spin_lock_irqsave(host->host_lock, flags);
+ /*
+ * AK: unlikely race here: for some reason the timer could
+ * expire before the serial number is set up below.
+ *
+ * TODO: kill serial or move to blk layer
+ */
scsi_cmd_get_serial(host, cmd);
if (unlikely(host->shost_state == SHOST_DEL)) {
@@ -754,12 +754,8 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
}
spin_unlock_irqrestore(host->host_lock, flags);
if (rtn) {
- if (scsi_delete_timer(cmd)) {
- atomic_inc(&cmd->device->iodone_cnt);
- scsi_queue_insert(cmd,
- (rtn == SCSI_MLQUEUE_DEVICE_BUSY) ?
- rtn : SCSI_MLQUEUE_HOST_BUSY);
- }
+ scsi_queue_insert(cmd, (rtn == SCSI_MLQUEUE_DEVICE_BUSY) ?
+ rtn : SCSI_MLQUEUE_HOST_BUSY);
SCSI_LOG_MLQUEUE(3,
printk("queuecommand : request rejected\n"));
}
@@ -770,24 +766,6 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
}
/**
- * scsi_req_abort_cmd -- Request command recovery for the specified command
- * @cmd: pointer to the SCSI command of interest
- *
- * This function requests that SCSI Core start recovery for the
- * command by deleting the timer and adding the command to the eh
- * queue. It can be called by either LLDDs or SCSI Core. LLDDs who
- * implement their own error recovery MAY ignore the timeout event if
- * they generated scsi_req_abort_cmd.
- */
-void scsi_req_abort_cmd(struct scsi_cmnd *cmd)
-{
- if (!scsi_delete_timer(cmd))
- return;
- scsi_times_out(cmd);
-}
-EXPORT_SYMBOL(scsi_req_abort_cmd);
-
-/**
* scsi_done - Enqueue the finished SCSI command into the done queue.
* @cmd: The SCSI Command for which a low-level device driver (LLDD) gives
* ownership back to SCSI Core -- i.e. the LLDD has finished with it.
@@ -802,42 +780,7 @@ EXPORT_SYMBOL(scsi_req_abort_cmd);
*/
static void scsi_done(struct scsi_cmnd *cmd)
{
- /*
- * We don't have to worry about this one timing out anymore.
- * If we are unable to remove the timer, then the command
- * has already timed out. In which case, we have no choice but to
- * let the timeout function run, as we have no idea where in fact
- * that function could really be. It might be on another processor,
- * etc, etc.
- */
- if (!scsi_delete_timer(cmd))
- return;
- __scsi_done(cmd);
-}
-
-/* Private entry to scsi_done() to complete a command when the timer
- * isn't running --- used by scsi_times_out */
-void __scsi_done(struct scsi_cmnd *cmd)
-{
- struct request *rq = cmd->request;
-
- /*
- * Set the serial numbers back to zero
- */
- cmd->serial_number = 0;
-
- atomic_inc(&cmd->device->iodone_cnt);
- if (cmd->result)
- atomic_inc(&cmd->device->ioerr_cnt);
-
- BUG_ON(!rq);
-
- /*
- * The uptodate/nbytes values don't matter, as we allow partial
- * completes and thus will check this in the softirq callback
- */
- rq->completion_data = cmd;
- blk_complete_request(rq);
+ blk_complete_request(cmd->request);
}
/* Move this to a header if it becomes more generally useful */
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 880051c89bd..fecefa05cb6 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -112,69 +112,8 @@ int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag)
}
/**
- * scsi_add_timer - Start timeout timer for a single scsi command.
- * @scmd: scsi command that is about to start running.
- * @timeout: amount of time to allow this command to run.
- * @complete: timeout function to call if timer isn't canceled.
- *
- * Notes:
- * This should be turned into an inline function. Each scsi command
- * has its own timer, and as it is added to the queue, we set up the
- * timer. When the command completes, we cancel the timer.
- */
-void scsi_add_timer(struct scsi_cmnd *scmd, int timeout,
- void (*complete)(struct scsi_cmnd *))
-{
-
- /*
- * If the clock was already running for this command, then
- * first delete the timer. The timer handling code gets rather
- * confused if we don't do this.
- */
- if (scmd->eh_timeout.function)
- del_timer(&scmd->eh_timeout);
-
- scmd->eh_timeout.data = (unsigned long)scmd;
- scmd->eh_timeout.expires = jiffies + timeout;
- scmd->eh_timeout.function = (void (*)(unsigned long)) complete;
-
- SCSI_LOG_ERROR_RECOVERY(5, printk("%s: scmd: %p, time:"
- " %d, (%p)\n", __func__,
- scmd, timeout, complete));
-
- add_timer(&scmd->eh_timeout);
-}
-
-/**
- * scsi_delete_timer - Delete/cancel timer for a given function.
- * @scmd: Cmd that we are canceling timer for
- *
- * Notes:
- * This should be turned into an inline function.
- *
- * Return value:
- * 1 if we were able to detach the timer. 0 if we blew it, and the
- * timer function has already started to run.
- */
-int scsi_delete_timer(struct scsi_cmnd *scmd)
-{
- int rtn;
-
- rtn = del_timer(&scmd->eh_timeout);
-
- SCSI_LOG_ERROR_RECOVERY(5, printk("%s: scmd: %p,"
- " rtn: %d\n", __func__,
- scmd, rtn));
-
- scmd->eh_timeout.data = (unsigned long)NULL;
- scmd->eh_timeout.function = NULL;
-
- return rtn;
-}
-
-/**
* scsi_times_out - Timeout function for normal scsi commands.
- * @scmd: Cmd that is timing out.
+ * @req: request that is timing out.
*
* Notes:
* We do not need to lock this. There is the potential for a race
@@ -182,9 +121,11 @@ int scsi_delete_timer(struct scsi_cmnd *scmd)
* normal completion function determines that the timer has already
* fired, then it mustn't do anything.
*/
-void scsi_times_out(struct scsi_cmnd *scmd)
+enum blk_eh_timer_return scsi_times_out(struct request *req)
{
- enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
+ struct scsi_cmnd *scmd = req->special;
+ enum blk_eh_timer_return (*eh_timed_out)(struct scsi_cmnd *);
+ enum blk_eh_timer_return rtn = BLK_EH_NOT_HANDLED;
scsi_log_completion(scmd, TIMEOUT_ERROR);
@@ -196,22 +137,20 @@ void scsi_times_out(struct scsi_cmnd *scmd)
eh_timed_out = NULL;
if (eh_timed_out)
- switch (eh_timed_out(scmd)) {
- case EH_HANDLED:
- __scsi_done(scmd);
- return;
- case EH_RESET_TIMER:
- scsi_add_timer(scmd, scmd->timeout_per_command,
- scsi_times_out);
- return;
- case EH_NOT_HANDLED:
+ rtn = eh_timed_out(scmd);
+ switch (rtn) {
+ case BLK_EH_NOT_HANDLED:
break;
+ default:
+ return rtn;
}
if (unlikely(!scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD))) {
scmd->result |= DID_TIME_OUT << 16;
- __scsi_done(scmd);
+ return BLK_EH_HANDLED;
}
+
+ return BLK_EH_NOT_HANDLED;
}
/**
@@ -391,7 +330,7 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
case HARDWARE_ERROR:
if (scmd->device->retry_hwerror)
- return NEEDS_RETRY;
+ return ADD_TO_MLQUEUE;
else
return SUCCESS;
@@ -1793,7 +1732,6 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
blk_rq_init(NULL, &req);
scmd->request = &req;
- memset(&scmd->eh_timeout, 0, sizeof(scmd->eh_timeout));
scmd->cmnd = req.cmd;
@@ -1804,8 +1742,6 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
scmd->sc_data_direction = DMA_BIDIRECTIONAL;
- init_timer(&scmd->eh_timeout);
-
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 ff5d56b3ee4..98ee55ced59 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -852,7 +852,7 @@ static void scsi_end_bidi_request(struct scsi_cmnd *cmd)
void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
{
int result = cmd->result;
- int this_count = scsi_bufflen(cmd);
+ int this_count;
struct request_queue *q = cmd->device->request_queue;
struct request *req = cmd->request;
int error = 0;
@@ -908,6 +908,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
*/
if (scsi_end_request(cmd, error, good_bytes, result == 0) == NULL)
return;
+ this_count = blk_rq_bytes(req);
/* good_bytes = 0, or (inclusive) there were leftovers and
* result = 0, so scsi_end_request couldn't retry.
@@ -1180,7 +1181,6 @@ 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;
return BLKPREP_OK;
}
EXPORT_SYMBOL(scsi_setup_blk_pc_cmnd);
@@ -1250,6 +1250,7 @@ int scsi_prep_state_check(struct scsi_device *sdev, struct request *req)
break;
case SDEV_QUIESCE:
case SDEV_BLOCK:
+ case SDEV_CREATED_BLOCK:
/*
* If the devices is blocked we defer normal commands.
*/
@@ -1415,17 +1416,26 @@ static void scsi_kill_request(struct request *req, struct request_queue *q)
spin_unlock(shost->host_lock);
spin_lock(sdev->request_queue->queue_lock);
- __scsi_done(cmd);
+ blk_complete_request(req);
}
static void scsi_softirq_done(struct request *rq)
{
- struct scsi_cmnd *cmd = rq->completion_data;
- unsigned long wait_for = (cmd->allowed + 1) * cmd->timeout_per_command;
+ struct scsi_cmnd *cmd = rq->special;
+ unsigned long wait_for = (cmd->allowed + 1) * rq->timeout;
int disposition;
INIT_LIST_HEAD(&cmd->eh_entry);
+ /*
+ * Set the serial numbers back to zero
+ */
+ cmd->serial_number = 0;
+
+ atomic_inc(&cmd->device->iodone_cnt);
+ if (cmd->result)
+ atomic_inc(&cmd->device->ioerr_cnt);
+
disposition = scsi_decide_disposition(cmd);
if (disposition != SUCCESS &&
time_before(cmd->jiffies_at_alloc + wait_for, jiffies)) {
@@ -1674,6 +1684,7 @@ struct request_queue *scsi_alloc_queue(struct scsi_device *sdev)
blk_queue_prep_rq(q, scsi_prep_fn);
blk_queue_softirq_done(q, scsi_softirq_done);
+ blk_queue_rq_timed_out(q, scsi_times_out);
return q;
}
@@ -2063,10 +2074,13 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state)
switch (state) {
case SDEV_CREATED:
- /* There are no legal states that come back to
- * created. This is the manually initialised start
- * state */
- goto illegal;
+ switch (oldstate) {
+ case SDEV_CREATED_BLOCK:
+ break;
+ default:
+ goto illegal;
+ }
+ break;
case SDEV_RUNNING:
switch (oldstate) {
@@ -2104,8 +2118,17 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state)
case SDEV_BLOCK:
switch (oldstate) {
- case SDEV_CREATED:
case SDEV_RUNNING:
+ case SDEV_CREATED_BLOCK:
+ break;
+ default:
+ goto illegal;
+ }
+ break;
+
+ case SDEV_CREATED_BLOCK:
+ switch (oldstate) {
+ case SDEV_CREATED:
break;
default:
goto illegal;
@@ -2393,8 +2416,12 @@ scsi_internal_device_block(struct scsi_device *sdev)
int err = 0;
err = scsi_device_set_state(sdev, SDEV_BLOCK);
- if (err)
- return err;
+ if (err) {
+ err = scsi_device_set_state(sdev, SDEV_CREATED_BLOCK);
+
+ if (err)
+ return err;
+ }
/*
* The device has transitioned to SDEV_BLOCK. Stop the
@@ -2437,8 +2464,12 @@ scsi_internal_device_unblock(struct scsi_device *sdev)
* and goose the device queue if successful.
*/
err = scsi_device_set_state(sdev, SDEV_RUNNING);
- if (err)
- return err;
+ if (err) {
+ err = scsi_device_set_state(sdev, SDEV_CREATED);
+
+ if (err)
+ return err;
+ }
spin_lock_irqsave(q->queue_lock, flags);
blk_start_queue(q);
diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c
index ae7ed9a2266..b37e133de80 100644
--- a/drivers/scsi/scsi_netlink.c
+++ b/drivers/scsi/scsi_netlink.c
@@ -21,6 +21,7 @@
#include <linux/time.h>
#include <linux/jiffies.h>
#include <linux/security.h>
+#include <linux/delay.h>
#include <net/sock.h>
#include <net/netlink.h>
@@ -30,6 +31,39 @@
struct sock *scsi_nl_sock = NULL;
EXPORT_SYMBOL_GPL(scsi_nl_sock);
+static DEFINE_SPINLOCK(scsi_nl_lock);
+static struct list_head scsi_nl_drivers;
+
+static u32 scsi_nl_state;
+#define STATE_EHANDLER_BSY 0x00000001
+
+struct scsi_nl_transport {
+ int (*msg_handler)(struct sk_buff *);
+ void (*event_handler)(struct notifier_block *, unsigned long, void *);
+ unsigned int refcnt;
+ int flags;
+};
+
+/* flags values (bit flags) */
+#define HANDLER_DELETING 0x1
+
+static struct scsi_nl_transport transports[SCSI_NL_MAX_TRANSPORTS] =
+ { {NULL, }, };
+
+
+struct scsi_nl_drvr {
+ struct list_head next;
+ int (*dmsg_handler)(struct Scsi_Host *shost, void *payload,
+ u32 len, u32 pid);
+ void (*devt_handler)(struct notifier_block *nb,
+ unsigned long event, void *notify_ptr);
+ struct scsi_host_template *hostt;
+ u64 vendor_id;
+ unsigned int refcnt;
+ int flags;
+};
+
+
/**
* scsi_nl_rcv_msg - Receive message handler.
@@ -45,8 +79,9 @@ scsi_nl_rcv_msg(struct sk_buff *skb)
{
struct nlmsghdr *nlh;
struct scsi_nl_hdr *hdr;
- uint32_t rlen;
- int err;
+ unsigned long flags;
+ u32 rlen;
+ int err, tport;
while (skb->len >= NLMSG_SPACE(0)) {
err = 0;
@@ -65,7 +100,7 @@ scsi_nl_rcv_msg(struct sk_buff *skb)
if (nlh->nlmsg_type != SCSI_TRANSPORT_MSG) {
err = -EBADMSG;
- return;
+ goto next_msg;
}
hdr = NLMSG_DATA(nlh);
@@ -83,12 +118,27 @@ scsi_nl_rcv_msg(struct sk_buff *skb)
if (nlh->nlmsg_len < (sizeof(*nlh) + hdr->msglen)) {
printk(KERN_WARNING "%s: discarding partial message\n",
__func__);
- return;
+ goto next_msg;
}
/*
- * We currently don't support anyone sending us a message
+ * Deliver message to the appropriate transport
*/
+ spin_lock_irqsave(&scsi_nl_lock, flags);
+
+ tport = hdr->transport;
+ if ((tport < SCSI_NL_MAX_TRANSPORTS) &&
+ !(transports[tport].flags & HANDLER_DELETING) &&
+ (transports[tport].msg_handler)) {
+ transports[tport].refcnt++;
+ spin_unlock_irqrestore(&scsi_nl_lock, flags);
+ err = transports[tport].msg_handler(skb);
+ spin_lock_irqsave(&scsi_nl_lock, flags);
+ transports[tport].refcnt--;
+ } else
+ err = -ENOENT;
+
+ spin_unlock_irqrestore(&scsi_nl_lock, flags);
next_msg:
if ((err) || (nlh->nlmsg_flags & NLM_F_ACK))
@@ -110,14 +160,42 @@ static int
scsi_nl_rcv_event(struct notifier_block *this, unsigned long event, void *ptr)
{
struct netlink_notify *n = ptr;
+ struct scsi_nl_drvr *driver;
+ unsigned long flags;
+ int tport;
if (n->protocol != NETLINK_SCSITRANSPORT)
return NOTIFY_DONE;
+ spin_lock_irqsave(&scsi_nl_lock, flags);
+ scsi_nl_state |= STATE_EHANDLER_BSY;
+
/*
- * Currently, we are not tracking PID's, etc. There is nothing
- * to handle.
+ * Pass event on to any transports that may be listening
*/
+ for (tport = 0; tport < SCSI_NL_MAX_TRANSPORTS; tport++) {
+ if (!(transports[tport].flags & HANDLER_DELETING) &&
+ (transports[tport].event_handler)) {
+ spin_unlock_irqrestore(&scsi_nl_lock, flags);
+ transports[tport].event_handler(this, event, ptr);
+ spin_lock_irqsave(&scsi_nl_lock, flags);
+ }
+ }
+
+ /*
+ * Pass event on to any drivers that may be listening
+ */
+ list_for_each_entry(driver, &scsi_nl_drivers, next) {
+ if (!(driver->flags & HANDLER_DELETING) &&
+ (driver->devt_handler)) {
+ spin_unlock_irqrestore(&scsi_nl_lock, flags);
+ driver->devt_handler(this, event, ptr);
+ spin_lock_irqsave(&scsi_nl_lock, flags);
+ }
+ }
+
+ scsi_nl_state &= ~STATE_EHANDLER_BSY;
+ spin_unlock_irqrestore(&scsi_nl_lock, flags);
return NOTIFY_DONE;
}
@@ -128,7 +206,281 @@ static struct notifier_block scsi_netlink_notifier = {
/**
- * scsi_netlink_init - Called by SCSI subsystem to intialize the SCSI transport netlink interface
+ * GENERIC SCSI transport receive and event handlers
+ **/
+
+/**
+ * scsi_generic_msg_handler - receive message handler for GENERIC transport
+ * messages
+ *
+ * @skb: socket receive buffer
+ *
+ **/
+static int
+scsi_generic_msg_handler(struct sk_buff *skb)
+{
+ struct nlmsghdr *nlh = nlmsg_hdr(skb);
+ struct scsi_nl_hdr *snlh = NLMSG_DATA(nlh);
+ struct scsi_nl_drvr *driver;
+ struct Scsi_Host *shost;
+ unsigned long flags;
+ int err = 0, match, pid;
+
+ pid = NETLINK_CREDS(skb)->pid;
+
+ switch (snlh->msgtype) {
+ case SCSI_NL_SHOST_VENDOR:
+ {
+ struct scsi_nl_host_vendor_msg *msg = NLMSG_DATA(nlh);
+
+ /* Locate the driver that corresponds to the message */
+ spin_lock_irqsave(&scsi_nl_lock, flags);
+ match = 0;
+ list_for_each_entry(driver, &scsi_nl_drivers, next) {
+ if (driver->vendor_id == msg->vendor_id) {
+ match = 1;
+ break;
+ }
+ }
+
+ if ((!match) || (!driver->dmsg_handler)) {
+ spin_unlock_irqrestore(&scsi_nl_lock, flags);
+ err = -ESRCH;
+ goto rcv_exit;
+ }
+
+ if (driver->flags & HANDLER_DELETING) {
+ spin_unlock_irqrestore(&scsi_nl_lock, flags);
+ err = -ESHUTDOWN;
+ goto rcv_exit;
+ }
+
+ driver->refcnt++;
+ spin_unlock_irqrestore(&scsi_nl_lock, flags);
+
+
+ /* if successful, scsi_host_lookup takes a shost reference */
+ shost = scsi_host_lookup(msg->host_no);
+ if (!shost) {
+ err = -ENODEV;
+ goto driver_exit;
+ }
+
+ /* is this host owned by the vendor ? */
+ if (shost->hostt != driver->hostt) {
+ err = -EINVAL;
+ goto vendormsg_put;
+ }
+
+ /* pass message on to the driver */
+ err = driver->dmsg_handler(shost, (void *)&msg[1],
+ msg->vmsg_datalen, pid);
+
+vendormsg_put:
+ /* release reference by scsi_host_lookup */
+ scsi_host_put(shost);
+
+driver_exit:
+ /* release our own reference on the registration object */
+ spin_lock_irqsave(&scsi_nl_lock, flags);
+ driver->refcnt--;
+ spin_unlock_irqrestore(&scsi_nl_lock, flags);
+ break;
+ }
+
+ default:
+ err = -EBADR;
+ break;
+ }
+
+rcv_exit:
+ if (err)
+ printk(KERN_WARNING "%s: Msgtype %d failed - err %d\n",
+ __func__, snlh->msgtype, err);
+ return err;
+}
+
+
+/**
+ * scsi_nl_add_transport -
+ * Registers message and event handlers for a transport. Enables
+ * receipt of netlink messages and events to a transport.
+ *
+ * @tport: transport registering handlers
+ * @msg_handler: receive message handler callback
+ * @event_handler: receive event handler callback
+ **/
+int
+scsi_nl_add_transport(u8 tport,
+ int (*msg_handler)(struct sk_buff *),
+ void (*event_handler)(struct notifier_block *, unsigned long, void *))
+{
+ unsigned long flags;
+ int err = 0;
+
+ if (tport >= SCSI_NL_MAX_TRANSPORTS)
+ return -EINVAL;
+
+ spin_lock_irqsave(&scsi_nl_lock, flags);
+
+ if (scsi_nl_state & STATE_EHANDLER_BSY) {
+ spin_unlock_irqrestore(&scsi_nl_lock, flags);
+ msleep(1);
+ spin_lock_irqsave(&scsi_nl_lock, flags);
+ }
+
+ if (transports[tport].msg_handler || transports[tport].event_handler) {
+ err = -EALREADY;
+ goto register_out;
+ }
+
+ transports[tport].msg_handler = msg_handler;
+ transports[tport].event_handler = event_handler;
+ transports[tport].flags = 0;
+ transports[tport].refcnt = 0;
+
+register_out:
+ spin_unlock_irqrestore(&scsi_nl_lock, flags);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(scsi_nl_add_transport);
+
+
+/**
+ * scsi_nl_remove_transport -
+ * Disable transport receiption of messages and events
+ *
+ * @tport: transport deregistering handlers
+ *
+ **/
+void
+scsi_nl_remove_transport(u8 tport)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&scsi_nl_lock, flags);
+ if (scsi_nl_state & STATE_EHANDLER_BSY) {
+ spin_unlock_irqrestore(&scsi_nl_lock, flags);
+ msleep(1);
+ spin_lock_irqsave(&scsi_nl_lock, flags);
+ }
+
+ if (tport < SCSI_NL_MAX_TRANSPORTS) {
+ transports[tport].flags |= HANDLER_DELETING;
+
+ while (transports[tport].refcnt != 0) {
+ spin_unlock_irqrestore(&scsi_nl_lock, flags);
+ schedule_timeout_uninterruptible(HZ/4);
+ spin_lock_irqsave(&scsi_nl_lock, flags);
+ }
+ transports[tport].msg_handler = NULL;
+ transports[tport].event_handler = NULL;
+ transports[tport].flags = 0;
+ }
+
+ spin_unlock_irqrestore(&scsi_nl_lock, flags);
+
+ return;
+}
+EXPORT_SYMBOL_GPL(scsi_nl_remove_transport);
+
+
+/**
+ * scsi_nl_add_driver -
+ * A driver is registering its interfaces for SCSI netlink messages
+ *
+ * @vendor_id: A unique identification value for the driver.
+ * @hostt: address of the driver's host template. Used
+ * to verify an shost is bound to the driver
+ * @nlmsg_handler: receive message handler callback
+ * @nlevt_handler: receive event handler callback
+ *
+ * Returns:
+ * 0 on Success
+ * error result otherwise
+ **/
+int
+scsi_nl_add_driver(u64 vendor_id, struct scsi_host_template *hostt,
+ int (*nlmsg_handler)(struct Scsi_Host *shost, void *payload,
+ u32 len, u32 pid),
+ void (*nlevt_handler)(struct notifier_block *nb,
+ unsigned long event, void *notify_ptr))
+{
+ struct scsi_nl_drvr *driver;
+ unsigned long flags;
+
+ driver = kzalloc(sizeof(*driver), GFP_KERNEL);
+ if (unlikely(!driver)) {
+ printk(KERN_ERR "%s: allocation failure\n", __func__);
+ return -ENOMEM;
+ }
+
+ driver->dmsg_handler = nlmsg_handler;
+ driver->devt_handler = nlevt_handler;
+ driver->hostt = hostt;
+ driver->vendor_id = vendor_id;
+
+ spin_lock_irqsave(&scsi_nl_lock, flags);
+ if (scsi_nl_state & STATE_EHANDLER_BSY) {
+ spin_unlock_irqrestore(&scsi_nl_lock, flags);
+ msleep(1);
+ spin_lock_irqsave(&scsi_nl_lock, flags);
+ }
+ list_add_tail(&driver->next, &scsi_nl_drivers);
+ spin_unlock_irqrestore(&scsi_nl_lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(scsi_nl_add_driver);
+
+
+/**
+ * scsi_nl_remove_driver -
+ * An driver is unregistering with the SCSI netlink messages
+ *
+ * @vendor_id: The unique identification value for the driver.
+ **/
+void
+scsi_nl_remove_driver(u64 vendor_id)
+{
+ struct scsi_nl_drvr *driver;
+ unsigned long flags;
+
+ spin_lock_irqsave(&scsi_nl_lock, flags);
+ if (scsi_nl_state & STATE_EHANDLER_BSY) {
+ spin_unlock_irqrestore(&scsi_nl_lock, flags);
+ msleep(1);
+ spin_lock_irqsave(&scsi_nl_lock, flags);
+ }
+
+ list_for_each_entry(driver, &scsi_nl_drivers, next) {
+ if (driver->vendor_id == vendor_id) {
+ driver->flags |= HANDLER_DELETING;
+ while (driver->refcnt != 0) {
+ spin_unlock_irqrestore(&scsi_nl_lock, flags);
+ schedule_timeout_uninterruptible(HZ/4);
+ spin_lock_irqsave(&scsi_nl_lock, flags);
+ }
+ list_del(&driver->next);
+ kfree(driver);
+ spin_unlock_irqrestore(&scsi_nl_lock, flags);
+ return;
+ }
+ }
+
+ spin_unlock_irqrestore(&scsi_nl_lock, flags);
+
+ printk(KERN_ERR "%s: removal of driver failed - vendor_id 0x%llx\n",
+ __func__, (unsigned long long)vendor_id);
+ return;
+}
+EXPORT_SYMBOL_GPL(scsi_nl_remove_driver);
+
+
+/**
+ * scsi_netlink_init - Called by SCSI subsystem to intialize
+ * the SCSI transport netlink interface
*
**/
void
@@ -136,6 +488,8 @@ scsi_netlink_init(void)
{
int error;
+ INIT_LIST_HEAD(&scsi_nl_drivers);
+
error = netlink_register_notifier(&scsi_netlink_notifier);
if (error) {
printk(KERN_ERR "%s: register of event handler failed - %d\n",
@@ -150,8 +504,15 @@ scsi_netlink_init(void)
printk(KERN_ERR "%s: register of recieve handler failed\n",
__func__);
netlink_unregister_notifier(&scsi_netlink_notifier);
+ return;
}
+ /* Register the entry points for the generic SCSI transport */
+ error = scsi_nl_add_transport(SCSI_NL_TRANSPORT,
+ scsi_generic_msg_handler, NULL);
+ if (error)
+ printk(KERN_ERR "%s: register of GENERIC transport handler"
+ " failed - %d\n", __func__, error);
return;
}
@@ -163,6 +524,8 @@ scsi_netlink_init(void)
void
scsi_netlink_exit(void)
{
+ scsi_nl_remove_transport(SCSI_NL_TRANSPORT);
+
if (scsi_nl_sock) {
netlink_kernel_release(scsi_nl_sock);
netlink_unregister_notifier(&scsi_netlink_notifier);
@@ -172,3 +535,147 @@ scsi_netlink_exit(void)
}
+/*
+ * Exported Interfaces
+ */
+
+/**
+ * scsi_nl_send_transport_msg -
+ * Generic function to send a single message from a SCSI transport to
+ * a single process
+ *
+ * @pid: receiving pid
+ * @hdr: message payload
+ *
+ **/
+void
+scsi_nl_send_transport_msg(u32 pid, struct scsi_nl_hdr *hdr)
+{
+ struct sk_buff *skb;
+ struct nlmsghdr *nlh;
+ const char *fn;
+ char *datab;
+ u32 len, skblen;
+ int err;
+
+ if (!scsi_nl_sock) {
+ err = -ENOENT;
+ fn = "netlink socket";
+ goto msg_fail;
+ }
+
+ len = NLMSG_SPACE(hdr->msglen);
+ skblen = NLMSG_SPACE(len);
+
+ skb = alloc_skb(skblen, GFP_KERNEL);
+ if (!skb) {
+ err = -ENOBUFS;
+ fn = "alloc_skb";
+ goto msg_fail;
+ }
+
+ nlh = nlmsg_put(skb, pid, 0, SCSI_TRANSPORT_MSG, len - sizeof(*nlh), 0);
+ if (!nlh) {
+ err = -ENOBUFS;
+ fn = "nlmsg_put";
+ goto msg_fail_skb;
+ }
+ datab = NLMSG_DATA(nlh);
+ memcpy(datab, hdr, hdr->msglen);
+
+ err = nlmsg_unicast(scsi_nl_sock, skb, pid);
+ if (err < 0) {
+ fn = "nlmsg_unicast";
+ /* nlmsg_unicast already kfree_skb'd */
+ goto msg_fail;
+ }
+
+ return;
+
+msg_fail_skb:
+ kfree_skb(skb);
+msg_fail:
+ printk(KERN_WARNING
+ "%s: Dropped Message : pid %d Transport %d, msgtype x%x, "
+ "msglen %d: %s : err %d\n",
+ __func__, pid, hdr->transport, hdr->msgtype, hdr->msglen,
+ fn, err);
+ return;
+}
+EXPORT_SYMBOL_GPL(scsi_nl_send_transport_msg);
+
+
+/**
+ * scsi_nl_send_vendor_msg - called to send a shost vendor unique message
+ * to a specific process id.
+ *
+ * @pid: process id of the receiver
+ * @host_no: host # sending the message
+ * @vendor_id: unique identifier for the driver's vendor
+ * @data_len: amount, in bytes, of vendor unique payload data
+ * @data_buf: pointer to vendor unique data buffer
+ *
+ * Returns:
+ * 0 on succesful return
+ * otherwise, failing error code
+ *
+ * Notes:
+ * This routine assumes no locks are held on entry.
+ */
+int
+scsi_nl_send_vendor_msg(u32 pid, unsigned short host_no, u64 vendor_id,
+ char *data_buf, u32 data_len)
+{
+ struct sk_buff *skb;
+ struct nlmsghdr *nlh;
+ struct scsi_nl_host_vendor_msg *msg;
+ u32 len, skblen;
+ int err;
+
+ if (!scsi_nl_sock) {
+ err = -ENOENT;
+ goto send_vendor_fail;
+ }
+
+ len = SCSI_NL_MSGALIGN(sizeof(*msg) + data_len);
+ skblen = NLMSG_SPACE(len);
+
+ skb = alloc_skb(skblen, GFP_KERNEL);
+ if (!skb) {
+ err = -ENOBUFS;
+ goto send_vendor_fail;
+ }
+
+ nlh = nlmsg_put(skb, 0, 0, SCSI_TRANSPORT_MSG,
+ skblen - sizeof(*nlh), 0);
+ if (!nlh) {
+ err = -ENOBUFS;
+ goto send_vendor_fail_skb;
+ }
+ msg = NLMSG_DATA(nlh);
+
+ INIT_SCSI_NL_HDR(&msg->snlh, SCSI_NL_TRANSPORT,
+ SCSI_NL_SHOST_VENDOR, len);
+ msg->vendor_id = vendor_id;
+ msg->host_no = host_no;
+ msg->vmsg_datalen = data_len; /* bytes */
+ memcpy(&msg[1], data_buf, data_len);
+
+ err = nlmsg_unicast(scsi_nl_sock, skb, pid);
+ if (err)
+ /* nlmsg_multicast already kfree_skb'd */
+ goto send_vendor_fail;
+
+ return 0;
+
+send_vendor_fail_skb:
+ kfree_skb(skb);
+send_vendor_fail:
+ printk(KERN_WARNING
+ "%s: Dropped SCSI Msg : host %d vendor_unique - err %d\n",
+ __func__, host_no, err);
+ return err;
+}
+EXPORT_SYMBOL(scsi_nl_send_vendor_msg);
+
+
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index 79f0f751120..6cddd5dd323 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -4,6 +4,7 @@
#include <linux/device.h>
struct request_queue;
+struct request;
struct scsi_cmnd;
struct scsi_device;
struct scsi_host_template;
@@ -27,7 +28,6 @@ extern void scsi_exit_hosts(void);
extern int scsi_dispatch_cmd(struct scsi_cmnd *cmd);
extern int scsi_setup_command_freelist(struct Scsi_Host *shost);
extern void scsi_destroy_command_freelist(struct Scsi_Host *shost);
-extern void __scsi_done(struct scsi_cmnd *cmd);
#ifdef CONFIG_SCSI_LOGGING
void scsi_log_send(struct scsi_cmnd *cmd);
void scsi_log_completion(struct scsi_cmnd *cmd, int disposition);
@@ -49,10 +49,7 @@ extern int __init scsi_init_devinfo(void);
extern void scsi_exit_devinfo(void);
/* scsi_error.c */
-extern void scsi_add_timer(struct scsi_cmnd *, int,
- void (*)(struct scsi_cmnd *));
-extern int scsi_delete_timer(struct scsi_cmnd *);
-extern void scsi_times_out(struct scsi_cmnd *cmd);
+extern enum blk_eh_timer_return scsi_times_out(struct request *req);
extern int scsi_error_handler(void *host);
extern int scsi_decide_disposition(struct scsi_cmnd *cmd);
extern void scsi_eh_wakeup(struct Scsi_Host *shost);
diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c
index c6a904a45bf..82f7b2dd08a 100644
--- a/drivers/scsi/scsi_proc.c
+++ b/drivers/scsi/scsi_proc.c
@@ -259,8 +259,8 @@ static int scsi_add_single_device(uint host, uint channel, uint id, uint lun)
int error = -ENXIO;
shost = scsi_host_lookup(host);
- if (IS_ERR(shost))
- return PTR_ERR(shost);
+ if (!shost)
+ return error;
if (shost->transportt->user_scan)
error = shost->transportt->user_scan(shost, channel, id, lun);
@@ -287,8 +287,8 @@ static int scsi_remove_single_device(uint host, uint channel, uint id, uint lun)
int error = -ENXIO;
shost = scsi_host_lookup(host);
- if (IS_ERR(shost))
- return PTR_ERR(shost);
+ if (!shost)
+ return error;
sdev = scsi_device_lookup(shost, channel, id, lun);
if (sdev) {
scsi_remove_device(sdev);
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 84b4879cff1..334862e26a1 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -730,6 +730,8 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result,
static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
int *bflags, int async)
{
+ int ret;
+
/*
* XXX do not save the inquiry, since it can change underneath us,
* save just vendor/model/rev.
@@ -885,7 +887,17 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
/* set the device running here so that slave configure
* may do I/O */
- scsi_device_set_state(sdev, SDEV_RUNNING);
+ ret = scsi_device_set_state(sdev, SDEV_RUNNING);
+ if (ret) {
+ ret = scsi_device_set_state(sdev, SDEV_BLOCK);
+
+ if (ret) {
+ sdev_printk(KERN_ERR, sdev,
+ "in wrong state %s to complete scan\n",
+ scsi_device_state_name(sdev->sdev_state));
+ return SCSI_SCAN_NO_RESPONSE;
+ }
+ }
if (*bflags & BLIST_MS_192_BYTES_FOR_3F)
sdev->use_192_bytes_for_3f = 1;
@@ -899,7 +911,7 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
transport_configure_device(&sdev->sdev_gendev);
if (sdev->host->hostt->slave_configure) {
- int ret = sdev->host->hostt->slave_configure(sdev);
+ ret = sdev->host->hostt->slave_configure(sdev);
if (ret) {
/*
* if LLDD reports slave not present, don't clutter
@@ -994,7 +1006,7 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget,
*/
sdev = scsi_device_lookup_by_target(starget, lun);
if (sdev) {
- if (rescan || sdev->sdev_state != SDEV_CREATED) {
+ if (rescan || !scsi_device_created(sdev)) {
SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO
"scsi scan: device exists on %s\n",
sdev->sdev_gendev.bus_id));
@@ -1080,7 +1092,8 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget,
* PDT=1Fh none (no FDD connected to the requested logical unit)
*/
if (((result[0] >> 5) == 1 || starget->pdt_1f_for_no_lun) &&
- (result[0] & 0x1f) == 0x1f) {
+ (result[0] & 0x1f) == 0x1f &&
+ !scsi_is_wlun(lun)) {
SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO
"scsi scan: peripheral device type"
" of 31, no device added\n"));
@@ -1466,7 +1479,7 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags,
kfree(lun_data);
out:
scsi_device_put(sdev);
- if (sdev->sdev_state == SDEV_CREATED)
+ if (scsi_device_created(sdev))
/*
* the sdev we used didn't appear in the report luns scan
*/
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index ab3c71869be..93c28f30bbd 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -34,6 +34,7 @@ static const struct {
{ SDEV_QUIESCE, "quiesce" },
{ SDEV_OFFLINE, "offline" },
{ SDEV_BLOCK, "blocked" },
+ { SDEV_CREATED_BLOCK, "created-blocked" },
};
const char *scsi_device_state_name(enum scsi_device_state state)
@@ -560,12 +561,15 @@ sdev_rd_attr (vendor, "%.8s\n");
sdev_rd_attr (model, "%.16s\n");
sdev_rd_attr (rev, "%.4s\n");
+/*
+ * TODO: can we make these symlinks to the block layer ones?
+ */
static ssize_t
sdev_show_timeout (struct device *dev, struct device_attribute *attr, char *buf)
{
struct scsi_device *sdev;
sdev = to_scsi_device(dev);
- return snprintf (buf, 20, "%d\n", sdev->timeout / HZ);
+ return snprintf(buf, 20, "%d\n", sdev->request_queue->rq_timeout / HZ);
}
static ssize_t
@@ -576,7 +580,7 @@ sdev_store_timeout (struct device *dev, struct device_attribute *attr,
int timeout;
sdev = to_scsi_device(dev);
sscanf (buf, "%d\n", &timeout);
- sdev->timeout = timeout * HZ;
+ blk_queue_rq_timeout(sdev->request_queue, timeout * HZ);
return count;
}
static DEVICE_ATTR(timeout, S_IRUGO | S_IWUSR, sdev_show_timeout, sdev_store_timeout);
diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c
index 257e097c39a..48ba413f7f6 100644
--- a/drivers/scsi/scsi_tgt_lib.c
+++ b/drivers/scsi/scsi_tgt_lib.c
@@ -362,7 +362,7 @@ static int scsi_map_user_pages(struct scsi_tgt_cmd *tcmd, struct scsi_cmnd *cmd,
int err;
dprintk("%lx %u\n", uaddr, len);
- err = blk_rq_map_user(q, rq, (void *)uaddr, len);
+ err = blk_rq_map_user(q, rq, NULL, (void *)uaddr, len, GFP_KERNEL);
if (err) {
/*
* TODO: need to fixup sg_tablesize, max_segment_size,
@@ -460,7 +460,7 @@ int scsi_tgt_kspace_exec(int host_no, u64 itn_id, int result, u64 tag,
/* TODO: replace with a O(1) alg */
shost = scsi_host_lookup(host_no);
- if (IS_ERR(shost)) {
+ if (!shost) {
printk(KERN_ERR "Could not find host no %d\n", host_no);
return -EINVAL;
}
@@ -550,7 +550,7 @@ int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 itn_id, u64 mid, int result)
dprintk("%d %d %llx\n", host_no, result, (unsigned long long) mid);
shost = scsi_host_lookup(host_no);
- if (IS_ERR(shost)) {
+ if (!shost) {
printk(KERN_ERR "Could not find host no %d\n", host_no);
return err;
}
@@ -603,7 +603,7 @@ int scsi_tgt_kspace_it_nexus_rsp(int host_no, u64 itn_id, int result)
dprintk("%d %d%llx\n", host_no, result, (unsigned long long)itn_id);
shost = scsi_host_lookup(host_no);
- if (IS_ERR(shost)) {
+ if (!shost) {
printk(KERN_ERR "Could not find host no %d\n", host_no);
return err;
}
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index 56823fd1fb8..d5f7653bb94 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -40,31 +40,7 @@
static int fc_queue_work(struct Scsi_Host *, struct work_struct *);
static void fc_vport_sched_delete(struct work_struct *work);
-
-/*
- * This is a temporary carrier for creating a vport. It will eventually
- * be replaced by a real message definition for sgio or netlink.
- *
- * fc_vport_identifiers: This set of data contains all elements
- * to uniquely identify and instantiate a FC virtual port.
- *
- * Notes:
- * symbolic_name: The driver is to append the symbolic_name string data
- * to the symbolic_node_name data that it generates by default.
- * the resulting combination should then be registered with the switch.
- * It is expected that things like Xen may stuff a VM title into
- * this field.
- */
-struct fc_vport_identifiers {
- u64 node_name;
- u64 port_name;
- u32 roles;
- bool disable;
- enum fc_port_type vport_type; /* only FC_PORTTYPE_NPIV allowed */
- char symbolic_name[FC_VPORT_SYMBOLIC_NAMELEN];
-};
-
-static int fc_vport_create(struct Scsi_Host *shost, int channel,
+static int fc_vport_setup(struct Scsi_Host *shost, int channel,
struct device *pdev, struct fc_vport_identifiers *ids,
struct fc_vport **vport);
@@ -1760,7 +1736,7 @@ store_fc_host_vport_create(struct device *dev, struct device_attribute *attr,
vid.disable = false; /* always enabled */
/* we only allow support on Channel 0 !!! */
- stat = fc_vport_create(shost, 0, &shost->shost_gendev, &vid, &vport);
+ stat = fc_vport_setup(shost, 0, &shost->shost_gendev, &vid, &vport);
return stat ? stat : count;
}
static FC_DEVICE_ATTR(host, vport_create, S_IWUSR, NULL,
@@ -1950,15 +1926,15 @@ static int fc_vport_match(struct attribute_container *cont,
* Notes:
* This routine assumes no locks are held on entry.
*/
-static enum scsi_eh_timer_return
+static enum blk_eh_timer_return
fc_timed_out(struct scsi_cmnd *scmd)
{
struct fc_rport *rport = starget_to_rport(scsi_target(scmd->device));
if (rport->port_state == FC_PORTSTATE_BLOCKED)
- return EH_RESET_TIMER;
+ return BLK_EH_RESET_TIMER;
- return EH_NOT_HANDLED;
+ return BLK_EH_NOT_HANDLED;
}
/*
@@ -3103,7 +3079,7 @@ fc_scsi_scan_rport(struct work_struct *work)
/**
- * fc_vport_create - allocates and creates a FC virtual port.
+ * fc_vport_setup - allocates and creates a FC virtual port.
* @shost: scsi host the virtual port is connected to.
* @channel: Channel on shost port connected to.
* @pdev: parent device for vport
@@ -3118,7 +3094,7 @@ fc_scsi_scan_rport(struct work_struct *work)
* This routine assumes no locks are held on entry.
*/
static int
-fc_vport_create(struct Scsi_Host *shost, int channel, struct device *pdev,
+fc_vport_setup(struct Scsi_Host *shost, int channel, struct device *pdev,
struct fc_vport_identifiers *ids, struct fc_vport **ret_vport)
{
struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
@@ -3231,6 +3207,28 @@ delete_vport:
return error;
}
+/**
+ * fc_vport_create - Admin App or LLDD requests creation of a vport
+ * @shost: scsi host the virtual port is connected to.
+ * @channel: channel on shost port connected to.
+ * @ids: The world wide names, FC4 port roles, etc for
+ * the virtual port.
+ *
+ * Notes:
+ * This routine assumes no locks are held on entry.
+ */
+struct fc_vport *
+fc_vport_create(struct Scsi_Host *shost, int channel,
+ struct fc_vport_identifiers *ids)
+{
+ int stat;
+ struct fc_vport *vport;
+
+ stat = fc_vport_setup(shost, channel, &shost->shost_gendev,
+ ids, &vport);
+ return stat ? NULL : vport;
+}
+EXPORT_SYMBOL(fc_vport_create);
/**
* fc_vport_terminate - Admin App or LLDD requests termination of a vport
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 043c3921164..0ce5f7cdfe2 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -1361,7 +1361,7 @@ iscsi_tgt_dscvr(struct iscsi_transport *transport,
return -EINVAL;
shost = scsi_host_lookup(ev->u.tgt_dscvr.host_no);
- if (IS_ERR(shost)) {
+ if (!shost) {
printk(KERN_ERR "target discovery could not find host no %u\n",
ev->u.tgt_dscvr.host_no);
return -ENODEV;
@@ -1387,7 +1387,7 @@ iscsi_set_host_param(struct iscsi_transport *transport,
return -ENOSYS;
shost = scsi_host_lookup(ev->u.set_host_param.host_no);
- if (IS_ERR(shost)) {
+ if (!shost) {
printk(KERN_ERR "set_host_param could not find host no %u\n",
ev->u.set_host_param.host_no);
return -ENODEV;
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index e5e7d785645..a7b53be6336 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -47,6 +47,7 @@
#include <linux/blkpg.h>
#include <linux/delay.h>
#include <linux/mutex.h>
+#include <linux/string_helpers.h>
#include <asm/uaccess.h>
#include <scsi/scsi.h>
@@ -86,6 +87,12 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_DISK);
MODULE_ALIAS_SCSI_DEVICE(TYPE_MOD);
MODULE_ALIAS_SCSI_DEVICE(TYPE_RBC);
+#if !defined(CONFIG_DEBUG_BLOCK_EXT_DEVT)
+#define SD_MINORS 16
+#else
+#define SD_MINORS 0
+#endif
+
static int sd_revalidate_disk(struct gendisk *);
static int sd_probe(struct device *);
static int sd_remove(struct device *);
@@ -159,7 +166,7 @@ sd_store_cache_type(struct device *dev, struct device_attribute *attr,
sd_print_sense_hdr(sdkp, &sshdr);
return -EINVAL;
}
- sd_revalidate_disk(sdkp->disk);
+ revalidate_disk(sdkp->disk);
return count;
}
@@ -377,7 +384,6 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
sector_t block = rq->sector;
sector_t threshold;
unsigned int this_count = rq->nr_sectors;
- unsigned int timeout = sdp->timeout;
int ret;
if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {
@@ -578,7 +584,6 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
SCpnt->transfersize = sdp->sector_size;
SCpnt->underflow = this_count << 9;
SCpnt->allowed = SD_MAX_RETRIES;
- SCpnt->timeout_per_command = timeout;
/*
* This indicates that the command is ready from our end to be
@@ -910,7 +915,7 @@ static void sd_rescan(struct device *dev)
struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev);
if (sdkp) {
- sd_revalidate_disk(sdkp->disk);
+ revalidate_disk(sdkp->disk);
scsi_disk_put(sdkp);
}
}
@@ -1429,27 +1434,21 @@ got_data:
*/
sector_size = 512;
}
+ blk_queue_hardsect_size(sdp->request_queue, sector_size);
+
{
- /*
- * The msdos fs needs to know the hardware sector size
- * So I have created this table. See ll_rw_blk.c
- * Jacques Gelinas (Jacques@solucorp.qc.ca)
- */
- int hard_sector = sector_size;
- sector_t sz = (sdkp->capacity/2) * (hard_sector/256);
- struct request_queue *queue = sdp->request_queue;
- sector_t mb = sz;
+ char cap_str_2[10], cap_str_10[10];
+ u64 sz = sdkp->capacity << ffz(~sector_size);
- blk_queue_hardsect_size(queue, hard_sector);
- /* avoid 64-bit division on 32-bit platforms */
- sector_div(sz, 625);
- mb -= sz - 974;
- sector_div(mb, 1950);
+ string_get_size(sz, STRING_UNITS_2, cap_str_2,
+ sizeof(cap_str_2));
+ string_get_size(sz, STRING_UNITS_10, cap_str_10,
+ sizeof(cap_str_10));
sd_printk(KERN_NOTICE, sdkp,
- "%llu %d-byte hardware sectors (%llu MB)\n",
+ "%llu %d-byte hardware sectors: (%s/%s)\n",
(unsigned long long)sdkp->capacity,
- hard_sector, (unsigned long long)mb);
+ sector_size, cap_str_10, cap_str_2);
}
/* Rescale capacity to 512-byte units */
@@ -1764,6 +1763,52 @@ static int sd_revalidate_disk(struct gendisk *disk)
}
/**
+ * sd_format_disk_name - format disk name
+ * @prefix: name prefix - ie. "sd" for SCSI disks
+ * @index: index of the disk to format name for
+ * @buf: output buffer
+ * @buflen: length of the output buffer
+ *
+ * SCSI disk names starts at sda. The 26th device is sdz and the
+ * 27th is sdaa. The last one for two lettered suffix is sdzz
+ * which is followed by sdaaa.
+ *
+ * This is basically 26 base counting with one extra 'nil' entry
+ * at the beggining from the second digit on and can be
+ * determined using similar method as 26 base conversion with the
+ * index shifted -1 after each digit is computed.
+ *
+ * CONTEXT:
+ * Don't care.
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+static int sd_format_disk_name(char *prefix, int index, char *buf, int buflen)
+{
+ const int base = 'z' - 'a' + 1;
+ char *begin = buf + strlen(prefix);
+ char *end = buf + buflen;
+ char *p;
+ int unit;
+
+ p = end - 1;
+ *p = '\0';
+ unit = base;
+ do {
+ if (p == begin)
+ return -EINVAL;
+ *--p = 'a' + (index % unit);
+ index = (index / unit) - 1;
+ } while (index >= 0);
+
+ memmove(begin, p, end - p);
+ memcpy(buf, prefix, strlen(prefix));
+
+ return 0;
+}
+
+/**
* sd_probe - called during driver initialization and whenever a
* new scsi device is attached to the system. It is called once
* for each scsi device (not just disks) present.
@@ -1801,7 +1846,7 @@ static int sd_probe(struct device *dev)
if (!sdkp)
goto out;
- gd = alloc_disk(16);
+ gd = alloc_disk(SD_MINORS);
if (!gd)
goto out_free;
@@ -1815,8 +1860,8 @@ static int sd_probe(struct device *dev)
if (error)
goto out_put;
- error = -EBUSY;
- if (index >= SD_MAX_DISKS)
+ error = sd_format_disk_name("sd", index, gd->disk_name, DISK_NAME_LEN);
+ if (error)
goto out_free_index;
sdkp->device = sdp;
@@ -1826,11 +1871,12 @@ static int sd_probe(struct device *dev)
sdkp->openers = 0;
sdkp->previous_state = 1;
- if (!sdp->timeout) {
+ if (!sdp->request_queue->rq_timeout) {
if (sdp->type != TYPE_MOD)
- sdp->timeout = SD_TIMEOUT;
+ blk_queue_rq_timeout(sdp->request_queue, SD_TIMEOUT);
else
- sdp->timeout = SD_MOD_TIMEOUT;
+ blk_queue_rq_timeout(sdp->request_queue,
+ SD_MOD_TIMEOUT);
}
device_initialize(&sdkp->dev);
@@ -1843,24 +1889,12 @@ static int sd_probe(struct device *dev)
get_device(&sdp->sdev_gendev);
- gd->major = sd_major((index & 0xf0) >> 4);
- gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00);
- gd->minors = 16;
- gd->fops = &sd_fops;
-
- if (index < 26) {
- sprintf(gd->disk_name, "sd%c", 'a' + index % 26);
- } else if (index < (26 + 1) * 26) {
- sprintf(gd->disk_name, "sd%c%c",
- 'a' + index / 26 - 1,'a' + index % 26);
- } else {
- const unsigned int m1 = (index / 26 - 1) / 26 - 1;
- const unsigned int m2 = (index / 26 - 1) % 26;
- const unsigned int m3 = index % 26;
- sprintf(gd->disk_name, "sd%c%c%c",
- 'a' + m1, 'a' + m2, 'a' + m3);
+ if (index < SD_MAX_DISKS) {
+ gd->major = sd_major((index & 0xf0) >> 4);
+ gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00);
+ gd->minors = SD_MINORS;
}
-
+ gd->fops = &sd_fops;
gd->private_data = &sdkp->driver;
gd->queue = sdkp->device->request_queue;
@@ -1869,7 +1903,7 @@ static int sd_probe(struct device *dev)
blk_queue_prep_rq(sdp->request_queue, sd_prep_fn);
gd->driverfs_dev = &sdp->sdev_gendev;
- gd->flags = GENHD_FL_DRIVERFS;
+ gd->flags = GENHD_FL_EXT_DEVT | GENHD_FL_DRIVERFS;
if (sdp->removable)
gd->flags |= GENHD_FL_REMOVABLE;
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 661f9f21650..ba9b9bbd4e7 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -47,7 +47,6 @@ static int sg_version_num = 30534; /* 2 digits for each component */
#include <linux/seq_file.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
-#include <linux/scatterlist.h>
#include <linux/blktrace_api.h>
#include <linux/smp_lock.h>
@@ -69,7 +68,6 @@ static void sg_proc_cleanup(void);
#endif
#define SG_ALLOW_DIO_DEF 0
-#define SG_ALLOW_DIO_CODE /* compile out by commenting this define */
#define SG_MAX_DEVS 32768
@@ -118,8 +116,8 @@ typedef struct sg_scatter_hold { /* holding area for scsi scatter gather info */
unsigned short k_use_sg; /* Count of kernel scatter-gather pieces */
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 */
+ struct page **pages;
+ int page_order;
char dio_in_use; /* 0->indirect IO (or mmap), 1->dio */
unsigned char cmd_opcode; /* first byte of command */
} Sg_scatter_hold;
@@ -137,6 +135,8 @@ typedef struct sg_request { /* SG_MAX_QUEUE requests outstanding per file */
char orphan; /* 1 -> drop on sight, 0 -> normal */
char sg_io_owned; /* 1 -> packet belongs to SG_IO */
volatile char done; /* 0->before bh, 1->before read, 2->read */
+ struct request *rq;
+ struct bio *bio;
} Sg_request;
typedef struct sg_fd { /* holds the state of a file descriptor */
@@ -175,8 +175,8 @@ typedef struct sg_device { /* holds the state of each scsi generic device */
static int sg_fasync(int fd, struct file *filp, int mode);
/* tasklet or soft irq callback */
-static void sg_cmd_done(void *data, char *sense, int result, int resid);
-static int sg_start_req(Sg_request * srp);
+static void sg_rq_end_io(struct request *rq, int uptodate);
+static int sg_start_req(Sg_request *srp, unsigned char *cmd);
static void sg_finish_rem_req(Sg_request * srp);
static int sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size);
static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp,
@@ -188,17 +188,11 @@ static ssize_t sg_new_write(Sg_fd *sfp, struct file *file,
int read_only, Sg_request **o_srp);
static int sg_common_write(Sg_fd * sfp, Sg_request * srp,
unsigned char *cmnd, int timeout, int blocking);
-static int sg_u_iovec(sg_io_hdr_t * hp, int sg_num, int ind,
- int wr_xf, int *countp, unsigned char __user **up);
-static int sg_write_xfer(Sg_request * srp);
-static int sg_read_xfer(Sg_request * srp);
static int sg_read_oxfer(Sg_request * srp, char __user *outp, int num_read_xfer);
static void sg_remove_scat(Sg_scatter_hold * schp);
static void sg_build_reserve(Sg_fd * sfp, int req_size);
static void sg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size);
static void sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp);
-static struct page *sg_page_malloc(int rqSz, int lowDma, int *retSzp);
-static void sg_page_free(struct page *page, int size);
static Sg_fd *sg_add_sfp(Sg_device * sdp, int dev);
static int sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp);
static void __sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp);
@@ -206,7 +200,6 @@ static Sg_request *sg_get_rq_mark(Sg_fd * sfp, int pack_id);
static Sg_request *sg_add_request(Sg_fd * sfp);
static int sg_remove_request(Sg_fd * sfp, Sg_request * srp);
static int sg_res_in_use(Sg_fd * sfp);
-static int sg_build_direct(Sg_request * srp, Sg_fd * sfp, int dxfer_len);
static Sg_device *sg_get_dev(int dev);
#ifdef CONFIG_SCSI_PROC_FS
static int sg_last_dev(void);
@@ -529,8 +522,7 @@ sg_new_read(Sg_fd * sfp, char __user *buf, size_t count, Sg_request * srp)
err = -EFAULT;
goto err_out;
}
- err = sg_read_xfer(srp);
- err_out:
+err_out:
sg_finish_rem_req(srp);
return (0 == err) ? count : err;
}
@@ -612,7 +604,10 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
else
hp->dxfer_direction = (mxsize > 0) ? SG_DXFER_FROM_DEV : SG_DXFER_NONE;
hp->dxfer_len = mxsize;
- hp->dxferp = (char __user *)buf + cmd_size;
+ if (hp->dxfer_direction == SG_DXFER_TO_DEV)
+ hp->dxferp = (char __user *)buf + cmd_size;
+ else
+ hp->dxferp = NULL;
hp->sbp = NULL;
hp->timeout = old_hdr.reply_len; /* structure abuse ... */
hp->flags = input_size; /* structure abuse ... */
@@ -732,16 +727,12 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp,
SCSI_LOG_TIMEOUT(4, printk("sg_common_write: scsi opcode=0x%02x, cmd_size=%d\n",
(int) cmnd[0], (int) hp->cmd_len));
- if ((k = sg_start_req(srp))) {
+ k = sg_start_req(srp, cmnd);
+ if (k) {
SCSI_LOG_TIMEOUT(1, printk("sg_common_write: start_req err=%d\n", k));
sg_finish_rem_req(srp);
return k; /* probably out of space --> ENOMEM */
}
- if ((k = sg_write_xfer(srp))) {
- SCSI_LOG_TIMEOUT(1, printk("sg_common_write: write_xfer, bad address\n"));
- sg_finish_rem_req(srp);
- return k;
- }
if (sdp->detached) {
sg_finish_rem_req(srp);
return -ENODEV;
@@ -763,20 +754,11 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp,
break;
}
hp->duration = jiffies_to_msecs(jiffies);
-/* Now send everything of to mid-level. The next time we hear about this
- packet is when sg_cmd_done() is called (i.e. a callback). */
- if (scsi_execute_async(sdp->device, cmnd, hp->cmd_len, data_dir, srp->data.buffer,
- hp->dxfer_len, srp->data.k_use_sg, timeout,
- SG_DEFAULT_RETRIES, srp, sg_cmd_done,
- GFP_ATOMIC)) {
- SCSI_LOG_TIMEOUT(1, printk("sg_common_write: scsi_execute_async failed\n"));
- /*
- * most likely out of mem, but could also be a bad map
- */
- sg_finish_rem_req(srp);
- return -ENOMEM;
- } else
- return 0;
+
+ srp->rq->timeout = timeout;
+ blk_execute_rq_nowait(sdp->device->request_queue, sdp->disk,
+ srp->rq, 1, sg_rq_end_io);
+ return 0;
}
static int
@@ -1192,8 +1174,7 @@ sg_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
Sg_fd *sfp;
unsigned long offset, len, sa;
Sg_scatter_hold *rsv_schp;
- struct scatterlist *sg;
- int k;
+ int k, length;
if ((NULL == vma) || (!(sfp = (Sg_fd *) vma->vm_private_data)))
return VM_FAULT_SIGBUS;
@@ -1203,15 +1184,14 @@ sg_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
return VM_FAULT_SIGBUS;
SCSI_LOG_TIMEOUT(3, printk("sg_vma_fault: offset=%lu, scatg=%d\n",
offset, rsv_schp->k_use_sg));
- sg = rsv_schp->buffer;
sa = vma->vm_start;
- for (k = 0; (k < rsv_schp->k_use_sg) && (sa < vma->vm_end);
- ++k, sg = sg_next(sg)) {
+ length = 1 << (PAGE_SHIFT + rsv_schp->page_order);
+ for (k = 0; k < rsv_schp->k_use_sg && sa < vma->vm_end; k++) {
len = vma->vm_end - sa;
- len = (len < sg->length) ? len : sg->length;
+ len = (len < length) ? len : length;
if (offset < len) {
- struct page *page;
- page = virt_to_page(page_address(sg_page(sg)) + offset);
+ struct page *page = nth_page(rsv_schp->pages[k],
+ offset >> PAGE_SHIFT);
get_page(page); /* increment page count */
vmf->page = page;
return 0; /* success */
@@ -1233,8 +1213,7 @@ sg_mmap(struct file *filp, struct vm_area_struct *vma)
Sg_fd *sfp;
unsigned long req_sz, len, sa;
Sg_scatter_hold *rsv_schp;
- int k;
- struct scatterlist *sg;
+ int k, length;
if ((!filp) || (!vma) || (!(sfp = (Sg_fd *) filp->private_data)))
return -ENXIO;
@@ -1248,11 +1227,10 @@ sg_mmap(struct file *filp, struct vm_area_struct *vma)
return -ENOMEM; /* cannot map more than reserved buffer */
sa = vma->vm_start;
- sg = rsv_schp->buffer;
- for (k = 0; (k < rsv_schp->k_use_sg) && (sa < vma->vm_end);
- ++k, sg = sg_next(sg)) {
+ length = 1 << (PAGE_SHIFT + rsv_schp->page_order);
+ for (k = 0; k < rsv_schp->k_use_sg && sa < vma->vm_end; k++) {
len = vma->vm_end - sa;
- len = (len < sg->length) ? len : sg->length;
+ len = (len < length) ? len : length;
sa += len;
}
@@ -1263,16 +1241,19 @@ sg_mmap(struct file *filp, struct vm_area_struct *vma)
return 0;
}
-/* This function is a "bottom half" handler that is called by the
- * mid level when a command is completed (or has failed). */
-static void
-sg_cmd_done(void *data, char *sense, int result, int resid)
+/*
+ * This function is a "bottom half" handler that is called by the mid
+ * level when a command is completed (or has failed).
+ */
+static void sg_rq_end_io(struct request *rq, int uptodate)
{
- Sg_request *srp = data;
+ struct sg_request *srp = rq->end_io_data;
Sg_device *sdp = NULL;
Sg_fd *sfp;
unsigned long iflags;
unsigned int ms;
+ char *sense;
+ int result, resid;
if (NULL == srp) {
printk(KERN_ERR "sg_cmd_done: NULL request\n");
@@ -1286,6 +1267,9 @@ sg_cmd_done(void *data, char *sense, int result, int resid)
return;
}
+ sense = rq->sense;
+ result = rq->errors;
+ resid = rq->data_len;
SCSI_LOG_TIMEOUT(4, printk("sg_cmd_done: %s, pack_id=%d, res=0x%x\n",
sdp->disk->disk_name, srp->header.pack_id, result));
@@ -1296,7 +1280,6 @@ sg_cmd_done(void *data, char *sense, int result, int resid)
if (0 != result) {
struct scsi_sense_hdr sshdr;
- memcpy(srp->sense_b, sense, sizeof (srp->sense_b));
srp->header.status = 0xff & result;
srp->header.masked_status = status_byte(result);
srp->header.msg_status = msg_byte(result);
@@ -1634,37 +1617,79 @@ exit_sg(void)
idr_destroy(&sg_index_idr);
}
-static int
-sg_start_req(Sg_request * srp)
+static int sg_start_req(Sg_request *srp, unsigned char *cmd)
{
int res;
+ struct request *rq;
Sg_fd *sfp = srp->parentfp;
sg_io_hdr_t *hp = &srp->header;
int dxfer_len = (int) hp->dxfer_len;
int dxfer_dir = hp->dxfer_direction;
+ unsigned int iov_count = hp->iovec_count;
Sg_scatter_hold *req_schp = &srp->data;
Sg_scatter_hold *rsv_schp = &sfp->reserve;
+ struct request_queue *q = sfp->parentdp->device->request_queue;
+ struct rq_map_data *md, map_data;
+ int rw = hp->dxfer_direction == SG_DXFER_TO_DEV ? WRITE : READ;
+
+ SCSI_LOG_TIMEOUT(4, printk(KERN_INFO "sg_start_req: dxfer_len=%d\n",
+ dxfer_len));
+
+ rq = blk_get_request(q, rw, GFP_ATOMIC);
+ if (!rq)
+ return -ENOMEM;
+
+ memcpy(rq->cmd, cmd, hp->cmd_len);
+
+ rq->cmd_len = hp->cmd_len;
+ rq->cmd_type = REQ_TYPE_BLOCK_PC;
+
+ srp->rq = rq;
+ rq->end_io_data = srp;
+ rq->sense = srp->sense_b;
+ rq->retries = SG_DEFAULT_RETRIES;
- SCSI_LOG_TIMEOUT(4, printk("sg_start_req: dxfer_len=%d\n", dxfer_len));
if ((dxfer_len <= 0) || (dxfer_dir == SG_DXFER_NONE))
return 0;
- if (sg_allow_dio && (hp->flags & SG_FLAG_DIRECT_IO) &&
- (dxfer_dir != SG_DXFER_UNKNOWN) && (0 == hp->iovec_count) &&
- (!sfp->parentdp->device->host->unchecked_isa_dma)) {
- res = sg_build_direct(srp, sfp, dxfer_len);
- if (res <= 0) /* -ve -> error, 0 -> done, 1 -> try indirect */
- return res;
- }
- if ((!sg_res_in_use(sfp)) && (dxfer_len <= rsv_schp->bufflen))
- sg_link_reserve(sfp, srp, dxfer_len);
- else {
- res = sg_build_indirect(req_schp, sfp, dxfer_len);
- if (res) {
- sg_remove_scat(req_schp);
- return res;
+
+ if (sg_allow_dio && hp->flags & SG_FLAG_DIRECT_IO &&
+ dxfer_dir != SG_DXFER_UNKNOWN && !iov_count &&
+ !sfp->parentdp->device->host->unchecked_isa_dma &&
+ blk_rq_aligned(q, hp->dxferp, dxfer_len))
+ md = NULL;
+ else
+ md = &map_data;
+
+ if (md) {
+ if (!sg_res_in_use(sfp) && dxfer_len <= rsv_schp->bufflen)
+ sg_link_reserve(sfp, srp, dxfer_len);
+ else {
+ res = sg_build_indirect(req_schp, sfp, dxfer_len);
+ if (res)
+ return res;
}
+
+ md->pages = req_schp->pages;
+ md->page_order = req_schp->page_order;
+ md->nr_entries = req_schp->k_use_sg;
}
- return 0;
+
+ if (iov_count)
+ res = blk_rq_map_user_iov(q, rq, md, hp->dxferp, iov_count,
+ hp->dxfer_len, GFP_ATOMIC);
+ else
+ res = blk_rq_map_user(q, rq, md, hp->dxferp,
+ hp->dxfer_len, GFP_ATOMIC);
+
+ if (!res) {
+ srp->bio = rq->bio;
+
+ if (!md) {
+ req_schp->dio_in_use = 1;
+ hp->info |= SG_INFO_DIRECT_IO;
+ }
+ }
+ return res;
}
static void
@@ -1678,186 +1703,37 @@ sg_finish_rem_req(Sg_request * srp)
sg_unlink_reserve(sfp, srp);
else
sg_remove_scat(req_schp);
+
+ if (srp->rq) {
+ if (srp->bio)
+ blk_rq_unmap_user(srp->bio);
+
+ blk_put_request(srp->rq);
+ }
+
sg_remove_request(sfp, srp);
}
static int
sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp, int tablesize)
{
- int sg_bufflen = tablesize * sizeof(struct scatterlist);
+ int sg_bufflen = tablesize * sizeof(struct page *);
gfp_t gfp_flags = GFP_ATOMIC | __GFP_NOWARN;
- /*
- * TODO: test without low_dma, we should not need it since
- * the block layer will bounce the buffer for us
- *
- * XXX(hch): we shouldn't need GFP_DMA for the actual S/G list.
- */
- if (sfp->low_dma)
- gfp_flags |= GFP_DMA;
- schp->buffer = kzalloc(sg_bufflen, gfp_flags);
- if (!schp->buffer)
+ schp->pages = kzalloc(sg_bufflen, gfp_flags);
+ if (!schp->pages)
return -ENOMEM;
- sg_init_table(schp->buffer, tablesize);
schp->sglist_len = sg_bufflen;
return tablesize; /* number of scat_gath elements allocated */
}
-#ifdef SG_ALLOW_DIO_CODE
-/* vvvvvvvv following code borrowed from st driver's direct IO vvvvvvvvv */
- /* TODO: hopefully we can use the generic block layer code */
-
-/* Pin down user pages and put them into a scatter gather list. Returns <= 0 if
- - mapping of all pages not successful
- (i.e., either completely successful or fails)
-*/
-static int
-st_map_user_pages(struct scatterlist *sgl, const unsigned int max_pages,
- unsigned long uaddr, size_t count, int rw)
-{
- unsigned long end = (uaddr + count + PAGE_SIZE - 1) >> PAGE_SHIFT;
- unsigned long start = uaddr >> PAGE_SHIFT;
- const int nr_pages = end - start;
- int res, i, j;
- struct page **pages;
-
- /* User attempted Overflow! */
- if ((uaddr + count) < uaddr)
- return -EINVAL;
-
- /* Too big */
- if (nr_pages > max_pages)
- return -ENOMEM;
-
- /* Hmm? */
- if (count == 0)
- return 0;
-
- if ((pages = kmalloc(max_pages * sizeof(*pages), GFP_ATOMIC)) == NULL)
- return -ENOMEM;
-
- /* Try to fault in all of the necessary pages */
- down_read(&current->mm->mmap_sem);
- /* rw==READ means read from drive, write into memory area */
- res = get_user_pages(
- current,
- current->mm,
- uaddr,
- nr_pages,
- rw == READ,
- 0, /* don't force */
- pages,
- NULL);
- up_read(&current->mm->mmap_sem);
-
- /* Errors and no page mapped should return here */
- if (res < nr_pages)
- goto out_unmap;
-
- for (i=0; i < nr_pages; i++) {
- /* FIXME: flush superflous for rw==READ,
- * probably wrong function for rw==WRITE
- */
- flush_dcache_page(pages[i]);
- /* ?? Is locking needed? I don't think so */
- /* if (!trylock_page(pages[i]))
- goto out_unlock; */
- }
-
- 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++)
- sg_set_page(&sgl[i], pages[i], count < PAGE_SIZE ? count : PAGE_SIZE, 0);
- }
- else {
- sgl[0].length = count;
- }
-
- kfree(pages);
- return nr_pages;
-
- out_unmap:
- if (res > 0) {
- for (j=0; j < res; j++)
- page_cache_release(pages[j]);
- res = 0;
- }
- kfree(pages);
- return res;
-}
-
-
-/* And unmap them... */
-static int
-st_unmap_user_pages(struct scatterlist *sgl, const unsigned int nr_pages,
- int dirtied)
-{
- int i;
-
- for (i=0; i < nr_pages; i++) {
- struct page *page = sg_page(&sgl[i]);
-
- if (dirtied)
- SetPageDirty(page);
- /* unlock_page(page); */
- /* FIXME: cache flush missing for rw==READ
- * FIXME: call the correct reference counting function
- */
- page_cache_release(page);
- }
-
- return 0;
-}
-
-/* ^^^^^^^^ above code borrowed from st driver's direct IO ^^^^^^^^^ */
-#endif
-
-
-/* Returns: -ve -> error, 0 -> done, 1 -> try indirect */
-static int
-sg_build_direct(Sg_request * srp, Sg_fd * sfp, int dxfer_len)
-{
-#ifdef SG_ALLOW_DIO_CODE
- sg_io_hdr_t *hp = &srp->header;
- Sg_scatter_hold *schp = &srp->data;
- int sg_tablesize = sfp->parentdp->sg_tablesize;
- int mx_sc_elems, res;
- struct scsi_device *sdev = sfp->parentdp->device;
-
- if (((unsigned long)hp->dxferp &
- queue_dma_alignment(sdev->request_queue)) != 0)
- return 1;
-
- mx_sc_elems = sg_build_sgat(schp, sfp, sg_tablesize);
- if (mx_sc_elems <= 0) {
- return 1;
- }
- res = st_map_user_pages(schp->buffer, mx_sc_elems,
- (unsigned long)hp->dxferp, dxfer_len,
- (SG_DXFER_TO_DEV == hp->dxfer_direction) ? 1 : 0);
- if (res <= 0) {
- sg_remove_scat(schp);
- return 1;
- }
- schp->k_use_sg = res;
- schp->dio_in_use = 1;
- hp->info |= SG_INFO_DIRECT_IO;
- return 0;
-#else
- return 1;
-#endif
-}
-
static int
sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size)
{
- struct scatterlist *sg;
- int ret_sz = 0, k, rem_sz, num, mx_sc_elems;
+ int ret_sz = 0, i, k, rem_sz, num, mx_sc_elems;
int sg_tablesize = sfp->parentdp->sg_tablesize;
- int blk_size = buff_size;
- struct page *p = NULL;
+ int blk_size = buff_size, order;
+ gfp_t gfp_mask = GFP_ATOMIC | __GFP_COMP | __GFP_NOWARN;
if (blk_size < 0)
return -EFAULT;
@@ -1881,15 +1757,26 @@ sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size)
} else
scatter_elem_sz_prev = num;
}
- for (k = 0, sg = schp->buffer, rem_sz = blk_size;
- (rem_sz > 0) && (k < mx_sc_elems);
- ++k, rem_sz -= ret_sz, sg = sg_next(sg)) {
-
+
+ if (sfp->low_dma)
+ gfp_mask |= GFP_DMA;
+
+ if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+ gfp_mask |= __GFP_ZERO;
+
+ order = get_order(num);
+retry:
+ ret_sz = 1 << (PAGE_SHIFT + order);
+
+ for (k = 0, rem_sz = blk_size; rem_sz > 0 && k < mx_sc_elems;
+ k++, rem_sz -= ret_sz) {
+
num = (rem_sz > scatter_elem_sz_prev) ?
- scatter_elem_sz_prev : rem_sz;
- p = sg_page_malloc(num, sfp->low_dma, &ret_sz);
- if (!p)
- return -ENOMEM;
+ scatter_elem_sz_prev : rem_sz;
+
+ schp->pages[k] = alloc_pages(gfp_mask, order);
+ if (!schp->pages[k])
+ goto out;
if (num == scatter_elem_sz_prev) {
if (unlikely(ret_sz > scatter_elem_sz_prev)) {
@@ -1897,12 +1784,12 @@ sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size)
scatter_elem_sz_prev = 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));
} /* end of for loop */
+ schp->page_order = order;
schp->k_use_sg = k;
SCSI_LOG_TIMEOUT(5, printk("sg_build_indirect: k_use_sg=%d, "
"rem_sz=%d\n", k, rem_sz));
@@ -1910,223 +1797,42 @@ sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size)
schp->bufflen = blk_size;
if (rem_sz > 0) /* must have failed */
return -ENOMEM;
-
return 0;
-}
-
-static int
-sg_write_xfer(Sg_request * srp)
-{
- sg_io_hdr_t *hp = &srp->header;
- Sg_scatter_hold *schp = &srp->data;
- struct scatterlist *sg = schp->buffer;
- int num_xfer = 0;
- int j, k, onum, usglen, ksglen, res;
- int iovec_count = (int) hp->iovec_count;
- int dxfer_dir = hp->dxfer_direction;
- unsigned char *p;
- unsigned char __user *up;
- int new_interface = ('\0' == hp->interface_id) ? 0 : 1;
-
- if ((SG_DXFER_UNKNOWN == dxfer_dir) || (SG_DXFER_TO_DEV == dxfer_dir) ||
- (SG_DXFER_TO_FROM_DEV == dxfer_dir)) {
- num_xfer = (int) (new_interface ? hp->dxfer_len : hp->flags);
- if (schp->bufflen < num_xfer)
- num_xfer = schp->bufflen;
- }
- if ((num_xfer <= 0) || (schp->dio_in_use) ||
- (new_interface
- && ((SG_FLAG_NO_DXFER | SG_FLAG_MMAP_IO) & hp->flags)))
- return 0;
-
- SCSI_LOG_TIMEOUT(4, printk("sg_write_xfer: num_xfer=%d, iovec_count=%d, k_use_sg=%d\n",
- num_xfer, iovec_count, schp->k_use_sg));
- if (iovec_count) {
- onum = iovec_count;
- if (!access_ok(VERIFY_READ, hp->dxferp, SZ_SG_IOVEC * onum))
- return -EFAULT;
- } else
- onum = 1;
-
- ksglen = sg->length;
- 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 = sg_next(sg), ksglen = sg->length,
- p = page_address(sg_page(sg))) {
- if (usglen <= 0)
- break;
- if (ksglen > usglen) {
- if (usglen >= num_xfer) {
- if (__copy_from_user(p, up, num_xfer))
- return -EFAULT;
- return 0;
- }
- if (__copy_from_user(p, up, usglen))
- return -EFAULT;
- p += usglen;
- ksglen -= usglen;
- break;
- } else {
- if (ksglen >= num_xfer) {
- if (__copy_from_user(p, up, num_xfer))
- return -EFAULT;
- return 0;
- }
- if (__copy_from_user(p, up, ksglen))
- return -EFAULT;
- up += ksglen;
- usglen -= ksglen;
- }
- ++k;
- if (k >= schp->k_use_sg)
- return 0;
- }
- }
-
- return 0;
-}
+out:
+ for (i = 0; i < k; i++)
+ __free_pages(schp->pages[k], order);
-static int
-sg_u_iovec(sg_io_hdr_t * hp, int sg_num, int ind,
- int wr_xf, int *countp, unsigned char __user **up)
-{
- int num_xfer = (int) hp->dxfer_len;
- unsigned char __user *p = hp->dxferp;
- int count;
+ if (--order >= 0)
+ goto retry;
- if (0 == sg_num) {
- if (wr_xf && ('\0' == hp->interface_id))
- count = (int) hp->flags; /* holds "old" input_size */
- else
- count = num_xfer;
- } else {
- sg_iovec_t iovec;
- if (__copy_from_user(&iovec, p + ind*SZ_SG_IOVEC, SZ_SG_IOVEC))
- return -EFAULT;
- p = iovec.iov_base;
- count = (int) iovec.iov_len;
- }
- if (!access_ok(wr_xf ? VERIFY_READ : VERIFY_WRITE, p, count))
- return -EFAULT;
- if (up)
- *up = p;
- if (countp)
- *countp = count;
- return 0;
+ return -ENOMEM;
}
static void
sg_remove_scat(Sg_scatter_hold * schp)
{
SCSI_LOG_TIMEOUT(4, printk("sg_remove_scat: k_use_sg=%d\n", schp->k_use_sg));
- if (schp->buffer && (schp->sglist_len > 0)) {
- struct scatterlist *sg = schp->buffer;
-
- if (schp->dio_in_use) {
-#ifdef SG_ALLOW_DIO_CODE
- st_unmap_user_pages(sg, schp->k_use_sg, TRUE);
-#endif
- } else {
+ if (schp->pages && schp->sglist_len > 0) {
+ if (!schp->dio_in_use) {
int k;
- for (k = 0; (k < schp->k_use_sg) && sg_page(sg);
- ++k, sg = sg_next(sg)) {
+ for (k = 0; k < schp->k_use_sg && schp->pages[k]; k++) {
SCSI_LOG_TIMEOUT(5, printk(
- "sg_remove_scat: k=%d, pg=0x%p, len=%d\n",
- k, sg_page(sg), sg->length));
- sg_page_free(sg_page(sg), sg->length);
+ "sg_remove_scat: k=%d, pg=0x%p\n",
+ k, schp->pages[k]));
+ __free_pages(schp->pages[k], schp->page_order);
}
- }
- kfree(schp->buffer);
- }
- memset(schp, 0, sizeof (*schp));
-}
-static int
-sg_read_xfer(Sg_request * srp)
-{
- sg_io_hdr_t *hp = &srp->header;
- Sg_scatter_hold *schp = &srp->data;
- struct scatterlist *sg = schp->buffer;
- int num_xfer = 0;
- int j, k, onum, usglen, ksglen, res;
- int iovec_count = (int) hp->iovec_count;
- int dxfer_dir = hp->dxfer_direction;
- unsigned char *p;
- unsigned char __user *up;
- int new_interface = ('\0' == hp->interface_id) ? 0 : 1;
-
- if ((SG_DXFER_UNKNOWN == dxfer_dir) || (SG_DXFER_FROM_DEV == dxfer_dir)
- || (SG_DXFER_TO_FROM_DEV == dxfer_dir)) {
- num_xfer = hp->dxfer_len;
- if (schp->bufflen < num_xfer)
- num_xfer = schp->bufflen;
- }
- if ((num_xfer <= 0) || (schp->dio_in_use) ||
- (new_interface
- && ((SG_FLAG_NO_DXFER | SG_FLAG_MMAP_IO) & hp->flags)))
- return 0;
-
- SCSI_LOG_TIMEOUT(4, printk("sg_read_xfer: num_xfer=%d, iovec_count=%d, k_use_sg=%d\n",
- num_xfer, iovec_count, schp->k_use_sg));
- if (iovec_count) {
- onum = iovec_count;
- if (!access_ok(VERIFY_READ, hp->dxferp, SZ_SG_IOVEC * onum))
- return -EFAULT;
- } else
- onum = 1;
-
- 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 = sg_next(sg), ksglen = sg->length,
- p = page_address(sg_page(sg))) {
- if (usglen <= 0)
- break;
- if (ksglen > usglen) {
- if (usglen >= num_xfer) {
- if (__copy_to_user(up, p, num_xfer))
- return -EFAULT;
- return 0;
- }
- if (__copy_to_user(up, p, usglen))
- return -EFAULT;
- p += usglen;
- ksglen -= usglen;
- break;
- } else {
- if (ksglen >= num_xfer) {
- if (__copy_to_user(up, p, num_xfer))
- return -EFAULT;
- return 0;
- }
- if (__copy_to_user(up, p, ksglen))
- return -EFAULT;
- up += ksglen;
- usglen -= ksglen;
- }
- ++k;
- if (k >= schp->k_use_sg)
- return 0;
+ kfree(schp->pages);
}
}
-
- return 0;
+ memset(schp, 0, sizeof (*schp));
}
static int
sg_read_oxfer(Sg_request * srp, char __user *outp, int num_read_xfer)
{
Sg_scatter_hold *schp = &srp->data;
- struct scatterlist *sg = schp->buffer;
int k, num;
SCSI_LOG_TIMEOUT(4, printk("sg_read_oxfer: num_read_xfer=%d\n",
@@ -2134,15 +1840,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(sg); ++k, sg = sg_next(sg)) {
- num = sg->length;
+ num = 1 << (PAGE_SHIFT + schp->page_order);
+ for (k = 0; k < schp->k_use_sg && schp->pages[k]; k++) {
if (num > num_read_xfer) {
- if (__copy_to_user(outp, page_address(sg_page(sg)),
+ if (__copy_to_user(outp, page_address(schp->pages[k]),
num_read_xfer))
return -EFAULT;
break;
} else {
- if (__copy_to_user(outp, page_address(sg_page(sg)),
+ if (__copy_to_user(outp, page_address(schp->pages[k]),
num))
return -EFAULT;
num_read_xfer -= num;
@@ -2177,24 +1883,21 @@ sg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size)
{
Sg_scatter_hold *req_schp = &srp->data;
Sg_scatter_hold *rsv_schp = &sfp->reserve;
- struct scatterlist *sg = rsv_schp->buffer;
int k, num, rem;
srp->res_used = 1;
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 = sg_next(sg)) {
- num = sg->length;
+ num = 1 << (PAGE_SHIFT + rsv_schp->page_order);
+ for (k = 0; k < rsv_schp->k_use_sg; k++) {
if (rem <= num) {
- sfp->save_scat_len = num;
- sg->length = rem;
req_schp->k_use_sg = k + 1;
req_schp->sglist_len = rsv_schp->sglist_len;
- req_schp->buffer = rsv_schp->buffer;
+ req_schp->pages = rsv_schp->pages;
req_schp->bufflen = size;
- req_schp->b_malloc_len = rsv_schp->b_malloc_len;
+ req_schp->page_order = rsv_schp->page_order;
break;
} else
rem -= num;
@@ -2208,22 +1911,13 @@ static void
sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp)
{
Sg_scatter_hold *req_schp = &srp->data;
- Sg_scatter_hold *rsv_schp = &sfp->reserve;
SCSI_LOG_TIMEOUT(4, printk("sg_unlink_reserve: req->k_use_sg=%d\n",
(int) req_schp->k_use_sg));
- if ((rsv_schp->k_use_sg > 0) && (req_schp->k_use_sg > 0)) {
- struct scatterlist *sg = rsv_schp->buffer;
-
- if (sfp->save_scat_len > 0)
- (sg + (req_schp->k_use_sg - 1))->length =
- (unsigned) sfp->save_scat_len;
- else
- SCSI_LOG_TIMEOUT(1, printk ("sg_unlink_reserve: BAD save_scat_len\n"));
- }
req_schp->k_use_sg = 0;
req_schp->bufflen = 0;
- req_schp->buffer = NULL;
+ req_schp->pages = NULL;
+ req_schp->page_order = 0;
req_schp->sglist_len = 0;
sfp->save_scat_len = 0;
srp->res_used = 0;
@@ -2481,53 +2175,6 @@ sg_res_in_use(Sg_fd * sfp)
return srp ? 1 : 0;
}
-/* The size fetched (value output via retSzp) set when non-NULL return */
-static struct page *
-sg_page_malloc(int rqSz, int lowDma, int *retSzp)
-{
- struct page *resp = NULL;
- gfp_t page_mask;
- int order, a_size;
- int resSz;
-
- if ((rqSz <= 0) || (NULL == retSzp))
- return resp;
-
- if (lowDma)
- page_mask = GFP_ATOMIC | GFP_DMA | __GFP_COMP | __GFP_NOWARN;
- else
- page_mask = GFP_ATOMIC | __GFP_COMP | __GFP_NOWARN;
-
- for (order = 0, a_size = PAGE_SIZE; a_size < rqSz;
- order++, a_size <<= 1) ;
- resSz = a_size; /* rounded up if necessary */
- resp = alloc_pages(page_mask, order);
- while ((!resp) && order) {
- --order;
- a_size >>= 1; /* divide by 2, until PAGE_SIZE */
- resp = alloc_pages(page_mask, order); /* try half */
- resSz = a_size;
- }
- if (resp) {
- if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
- memset(page_address(resp), 0, resSz);
- *retSzp = resSz;
- }
- return resp;
-}
-
-static void
-sg_page_free(struct page *page, int size)
-{
- int order, a_size;
-
- if (!page)
- return;
- for (order = 0, a_size = PAGE_SIZE; a_size < size;
- order++, a_size <<= 1) ;
- __free_pages(page, order);
-}
-
#ifdef CONFIG_SCSI_PROC_FS
static int
sg_idr_max_id(int id, void *p, void *data)
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 27f5bfd1def..0f17009c99d 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -331,7 +331,7 @@ static int sr_done(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;
+ int block = 0, this_count, s_size;
struct scsi_cd *cd;
struct scsi_cmnd *SCpnt;
struct scsi_device *sdp = q->queuedata;
@@ -461,7 +461,6 @@ static int sr_prep_fn(struct request_queue *q, struct request *rq)
SCpnt->transfersize = cd->device->sector_size;
SCpnt->underflow = this_count << 9;
SCpnt->allowed = MAX_RETRIES;
- SCpnt->timeout_per_command = timeout;
/*
* This indicates that the command is ready from our end to be
@@ -620,6 +619,8 @@ static int sr_probe(struct device *dev)
disk->fops = &sr_bdops;
disk->flags = GENHD_FL_CD;
+ blk_queue_rq_timeout(sdev->request_queue, SR_TIMEOUT);
+
cd->device = sdev;
cd->disk = disk;
cd->driver = &sr_template;
@@ -878,7 +879,7 @@ static void sr_kref_release(struct kref *kref)
struct gendisk *disk = cd->disk;
spin_lock(&sr_index_lock);
- clear_bit(disk->first_minor, sr_index_bits);
+ clear_bit(MINOR(disk_devt(disk)), sr_index_bits);
spin_unlock(&sr_index_lock);
unregister_cdrom(&cd->cdi);
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
index d39107b7669..f4e6cde1fd0 100644
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
@@ -519,8 +519,8 @@ static int sym53c8xx_queue_command(struct scsi_cmnd *cmd,
* Shorten our settle_time if needed for
* this command not to time out.
*/
- if (np->s.settle_time_valid && cmd->timeout_per_command) {
- unsigned long tlimit = jiffies + cmd->timeout_per_command;
+ if (np->s.settle_time_valid && cmd->request->timeout) {
+ unsigned long tlimit = jiffies + cmd->request->timeout;
tlimit -= SYM_CONF_TIMER_INTERVAL*2;
if (time_after(np->s.settle_time, tlimit)) {
np->s.settle_time = tlimit;
diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c
index 1723d71cbf3..69ac6e590f1 100644
--- a/drivers/scsi/tmscsim.c
+++ b/drivers/scsi/tmscsim.c
@@ -2573,8 +2573,8 @@ static struct pci_driver dc390_driver = {
static int __init dc390_module_init(void)
{
if (!disable_clustering)
- printk(KERN_INFO "DC390: clustering now enabled by default. If you get problems load\n"
- "\twith \"disable_clustering=1\" and report to maintainers\n");
+ printk(KERN_INFO "DC390: clustering now enabled by default. If you get problems load\n");
+ printk(KERN_INFO " with \"disable_clustering=1\" and report to maintainers\n");
if (tmscsim[0] == -1 || tmscsim[0] > 15) {
tmscsim[0] = 7;
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 342e12fb1c2..9ccc563d873 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -1908,15 +1908,23 @@ static int serial8250_startup(struct uart_port *port)
* kick the UART on a regular basis.
*/
if (!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) {
+ up->bugs |= UART_BUG_THRE;
pr_debug("ttyS%d - using backup timer\n", port->line);
- up->timer.function = serial8250_backup_timeout;
- up->timer.data = (unsigned long)up;
- mod_timer(&up->timer, jiffies +
- poll_timeout(up->port.timeout) + HZ / 5);
}
}
/*
+ * The above check will only give an accurate result the first time
+ * the port is opened so this value needs to be preserved.
+ */
+ if (up->bugs & UART_BUG_THRE) {
+ up->timer.function = serial8250_backup_timeout;
+ up->timer.data = (unsigned long)up;
+ mod_timer(&up->timer, jiffies +
+ poll_timeout(up->port.timeout) + HZ / 5);
+ }
+
+ /*
* If the "interrupt" for this port doesn't correspond with any
* hardware interrupt, we use a timer-based system. The original
* driver used to do this with IRQ0.
diff --git a/drivers/serial/8250.h b/drivers/serial/8250.h
index 78c00162b04..520260326f3 100644
--- a/drivers/serial/8250.h
+++ b/drivers/serial/8250.h
@@ -47,6 +47,7 @@ struct serial8250_config {
#define UART_BUG_QUOT (1 << 0) /* UART has buggy quot LSB */
#define UART_BUG_TXEN (1 << 1) /* UART has buggy TX IIR status */
#define UART_BUG_NOMSR (1 << 2) /* UART has buggy MSR status bits (Au1x00) */
+#define UART_BUG_THRE (1 << 3) /* UART has buggy THRE reassertion */
#define PROBE_RSA (1 << 0)
#define PROBE_ANY (~0)
diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c
index 3a6da80b081..61fb8b6d19a 100644
--- a/drivers/serial/atmel_serial.c
+++ b/drivers/serial/atmel_serial.c
@@ -131,7 +131,8 @@ struct atmel_uart_char {
struct atmel_uart_port {
struct uart_port uart; /* uart */
struct clk *clk; /* uart clock */
- unsigned short suspended; /* is port suspended? */
+ int may_wakeup; /* cached value of device_may_wakeup for times we need to disable it */
+ u32 backup_imr; /* IMR saved during suspend */
int break_active; /* break being received */
short use_dma_rx; /* enable PDC receiver */
@@ -984,8 +985,15 @@ static void atmel_serial_pm(struct uart_port *port, unsigned int state,
* This is called on uart_open() or a resume event.
*/
clk_enable(atmel_port->clk);
+
+ /* re-enable interrupts if we disabled some on suspend */
+ UART_PUT_IER(port, atmel_port->backup_imr);
break;
case 3:
+ /* Back up the interrupt mask and disable all interrupts */
+ atmel_port->backup_imr = UART_GET_IMR(port);
+ UART_PUT_IDR(port, -1);
+
/*
* Disable the peripheral clock for this serial port.
* This is called on uart_close() or a suspend event.
@@ -1475,13 +1483,12 @@ static int atmel_serial_suspend(struct platform_device *pdev,
cpu_relax();
}
- if (device_may_wakeup(&pdev->dev)
- && !atmel_serial_clk_will_stop())
- enable_irq_wake(port->irq);
- else {
- uart_suspend_port(&atmel_uart, port);
- atmel_port->suspended = 1;
- }
+ /* we can not wake up if we're running on slow clock */
+ atmel_port->may_wakeup = device_may_wakeup(&pdev->dev);
+ if (atmel_serial_clk_will_stop())
+ device_set_wakeup_enable(&pdev->dev, 0);
+
+ uart_suspend_port(&atmel_uart, port);
return 0;
}
@@ -1491,11 +1498,8 @@ static int atmel_serial_resume(struct platform_device *pdev)
struct uart_port *port = platform_get_drvdata(pdev);
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
- if (atmel_port->suspended) {
- uart_resume_port(&atmel_uart, port);
- atmel_port->suspended = 0;
- } else
- disable_irq_wake(port->irq);
+ uart_resume_port(&atmel_uart, port);
+ device_set_wakeup_enable(&pdev->dev, atmel_port->may_wakeup);
return 0;
}
@@ -1513,6 +1517,8 @@ static int __devinit atmel_serial_probe(struct platform_device *pdev)
BUILD_BUG_ON(!is_power_of_2(ATMEL_SERIAL_RINGSIZE));
port = &atmel_ports[pdev->id];
+ port->backup_imr = 0;
+
atmel_init_port(port, pdev);
if (!atmel_use_dma_rx(&port->uart)) {
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c
index 6a29f9330a7..3f90f1bbbbc 100644
--- a/drivers/serial/imx.c
+++ b/drivers/serial/imx.c
@@ -127,8 +127,13 @@
#define UCR3_RXDSEN (1<<6) /* Receive status interrupt enable */
#define UCR3_AIRINTEN (1<<5) /* Async IR wake interrupt enable */
#define UCR3_AWAKEN (1<<4) /* Async wake interrupt enable */
-#define UCR3_REF25 (1<<3) /* Ref freq 25 MHz */
-#define UCR3_REF30 (1<<2) /* Ref Freq 30 MHz */
+#ifdef CONFIG_ARCH_IMX
+#define UCR3_REF25 (1<<3) /* Ref freq 25 MHz, only on mx1 */
+#define UCR3_REF30 (1<<2) /* Ref Freq 30 MHz, only on mx1 */
+#endif
+#if defined CONFIG_ARCH_MX2 || defined CONFIG_ARCH_MX3
+#define UCR3_RXDMUXSEL (1<<2) /* RXD Muxed Input Select, on mx2/mx3 */
+#endif
#define UCR3_INVT (1<<1) /* Inverted Infrared transmission */
#define UCR3_BPEN (1<<0) /* Preset registers enable */
#define UCR4_CTSTL_32 (32<<10) /* CTS trigger level (32 chars) */
@@ -445,7 +450,7 @@ static irqreturn_t imx_int(int irq, void *dev_id)
readl(sport->port.membase + UCR1) & UCR1_TXMPTYEN)
imx_txint(irq, dev_id);
- if (sts & USR1_RTSS)
+ if (sts & USR1_RTSD)
imx_rtsint(irq, dev_id);
return IRQ_HANDLED;
@@ -598,6 +603,12 @@ static int imx_startup(struct uart_port *port)
temp |= (UCR2_RXEN | UCR2_TXEN);
writel(temp, sport->port.membase + UCR2);
+#if defined CONFIG_ARCH_MX2 || defined CONFIG_ARCH_MX3
+ temp = readl(sport->port.membase + UCR3);
+ temp |= UCR3_RXDMUXSEL;
+ writel(temp, sport->port.membase + UCR3);
+#endif
+
/*
* Enable modem status interrupts
*/
@@ -1133,13 +1144,19 @@ static int serial_imx_probe(struct platform_device *pdev)
if(pdata && (pdata->flags & IMXUART_HAVE_RTSCTS))
sport->have_rtscts = 1;
- if (pdata->init)
- pdata->init(pdev);
+ if (pdata->init) {
+ ret = pdata->init(pdev);
+ if (ret)
+ goto clkput;
+ }
uart_add_one_port(&imx_reg, &sport->port);
platform_set_drvdata(pdev, &sport->port);
return 0;
+clkput:
+ clk_put(sport->clk);
+ clk_disable(sport->clk);
unmap:
iounmap(sport->port.membase);
free:
diff --git a/drivers/spi/orion_spi.c b/drivers/spi/orion_spi.c
index c4eaacd6e55..b872bfaf4bd 100644
--- a/drivers/spi/orion_spi.c
+++ b/drivers/spi/orion_spi.c
@@ -427,7 +427,7 @@ static int orion_spi_transfer(struct spi_device *spi, struct spi_message *m)
goto msg_rejected;
}
- if (t->speed_hz < orion_spi->min_speed) {
+ if (t->speed_hz && t->speed_hz < orion_spi->min_speed) {
dev_err(&spi->dev,
"message rejected : "
"device min speed (%d Hz) exceeds "
diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c
index 34c7c987568..d47d3636227 100644
--- a/drivers/spi/pxa2xx_spi.c
+++ b/drivers/spi/pxa2xx_spi.c
@@ -47,9 +47,10 @@ MODULE_ALIAS("platform:pxa2xx-spi");
#define MAX_BUSES 3
-#define DMA_INT_MASK (DCSR_ENDINTR | DCSR_STARTINTR | DCSR_BUSERR)
-#define RESET_DMA_CHANNEL (DCSR_NODESC | DMA_INT_MASK)
-#define IS_DMA_ALIGNED(x) (((u32)(x)&0x07)==0)
+#define DMA_INT_MASK (DCSR_ENDINTR | DCSR_STARTINTR | DCSR_BUSERR)
+#define RESET_DMA_CHANNEL (DCSR_NODESC | DMA_INT_MASK)
+#define IS_DMA_ALIGNED(x) ((((u32)(x)) & 0x07) == 0)
+#define MAX_DMA_LEN 8191
/*
* for testing SSCR1 changes that require SSP restart, basically
@@ -144,7 +145,6 @@ struct driver_data {
size_t tx_map_len;
u8 n_bytes;
u32 dma_width;
- int cs_change;
int (*write)(struct driver_data *drv_data);
int (*read)(struct driver_data *drv_data);
irqreturn_t (*transfer_handler)(struct driver_data *drv_data);
@@ -406,8 +406,45 @@ static void giveback(struct driver_data *drv_data)
struct spi_transfer,
transfer_list);
+ /* Delay if requested before any change in chip select */
+ if (last_transfer->delay_usecs)
+ udelay(last_transfer->delay_usecs);
+
+ /* Drop chip select UNLESS cs_change is true or we are returning
+ * a message with an error, or next message is for another chip
+ */
if (!last_transfer->cs_change)
drv_data->cs_control(PXA2XX_CS_DEASSERT);
+ else {
+ struct spi_message *next_msg;
+
+ /* Holding of cs was hinted, but we need to make sure
+ * the next message is for the same chip. Don't waste
+ * time with the following tests unless this was hinted.
+ *
+ * We cannot postpone this until pump_messages, because
+ * after calling msg->complete (below) the driver that
+ * sent the current message could be unloaded, which
+ * could invalidate the cs_control() callback...
+ */
+
+ /* get a pointer to the next message, if any */
+ spin_lock_irqsave(&drv_data->lock, flags);
+ if (list_empty(&drv_data->queue))
+ next_msg = NULL;
+ else
+ next_msg = list_entry(drv_data->queue.next,
+ struct spi_message, queue);
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+
+ /* see if the next and current messages point
+ * to the same chip
+ */
+ if (next_msg && next_msg->spi != msg->spi)
+ next_msg = NULL;
+ if (!next_msg || msg->state == ERROR_STATE)
+ drv_data->cs_control(PXA2XX_CS_DEASSERT);
+ }
msg->state = NULL;
if (msg->complete)
@@ -490,10 +527,9 @@ static void dma_transfer_complete(struct driver_data *drv_data)
msg->actual_length += drv_data->len -
(drv_data->rx_end - drv_data->rx);
- /* Release chip select if requested, transfer delays are
- * handled in pump_transfers */
- if (drv_data->cs_change)
- drv_data->cs_control(PXA2XX_CS_DEASSERT);
+ /* Transfer delays and chip select release are
+ * handled in pump_transfers or giveback
+ */
/* Move to next transfer */
msg->state = next_transfer(drv_data);
@@ -602,10 +638,9 @@ static void int_transfer_complete(struct driver_data *drv_data)
drv_data->cur_msg->actual_length += drv_data->len -
(drv_data->rx_end - drv_data->rx);
- /* Release chip select if requested, transfer delays are
- * handled in pump_transfers */
- if (drv_data->cs_change)
- drv_data->cs_control(PXA2XX_CS_DEASSERT);
+ /* Transfer delays and chip select release are
+ * handled in pump_transfers or giveback
+ */
/* Move to next transfer */
drv_data->cur_msg->state = next_transfer(drv_data);
@@ -840,23 +875,40 @@ static void pump_transfers(unsigned long data)
return;
}
- /* Delay if requested at end of transfer*/
+ /* Delay if requested at end of transfer before CS change */
if (message->state == RUNNING_STATE) {
previous = list_entry(transfer->transfer_list.prev,
struct spi_transfer,
transfer_list);
if (previous->delay_usecs)
udelay(previous->delay_usecs);
+
+ /* Drop chip select only if cs_change is requested */
+ if (previous->cs_change)
+ drv_data->cs_control(PXA2XX_CS_DEASSERT);
}
- /* Check transfer length */
- if (transfer->len > 8191)
- {
- dev_warn(&drv_data->pdev->dev, "pump_transfers: transfer "
- "length greater than 8191\n");
- message->status = -EINVAL;
- giveback(drv_data);
- return;
+ /* Check for transfers that need multiple DMA segments */
+ if (transfer->len > MAX_DMA_LEN && chip->enable_dma) {
+
+ /* reject already-mapped transfers; PIO won't always work */
+ if (message->is_dma_mapped
+ || transfer->rx_dma || transfer->tx_dma) {
+ dev_err(&drv_data->pdev->dev,
+ "pump_transfers: mapped transfer length "
+ "of %u is greater than %d\n",
+ transfer->len, MAX_DMA_LEN);
+ message->status = -EINVAL;
+ giveback(drv_data);
+ return;
+ }
+
+ /* warn ... we force this to PIO mode */
+ if (printk_ratelimit())
+ dev_warn(&message->spi->dev, "pump_transfers: "
+ "DMA disabled for transfer length %ld "
+ "greater than %d\n",
+ (long)drv_data->len, MAX_DMA_LEN);
}
/* Setup the transfer state based on the type of transfer */
@@ -878,7 +930,6 @@ static void pump_transfers(unsigned long data)
drv_data->len = transfer->len & DCMD_LENGTH;
drv_data->write = drv_data->tx ? chip->write : null_writer;
drv_data->read = drv_data->rx ? chip->read : null_reader;
- drv_data->cs_change = transfer->cs_change;
/* Change speed and bit per word on a per transfer */
cr0 = chip->cr0;
@@ -925,7 +976,7 @@ static void pump_transfers(unsigned long data)
&dma_thresh))
if (printk_ratelimit())
dev_warn(&message->spi->dev,
- "pump_transfer: "
+ "pump_transfers: "
"DMA burst size reduced to "
"match bits_per_word\n");
}
@@ -939,8 +990,23 @@ static void pump_transfers(unsigned long data)
message->state = RUNNING_STATE;
- /* Try to map dma buffer and do a dma transfer if successful */
- if ((drv_data->dma_mapped = map_dma_buffers(drv_data))) {
+ /* Try to map dma buffer and do a dma transfer if successful, but
+ * only if the length is non-zero and less than MAX_DMA_LEN.
+ *
+ * Zero-length non-descriptor DMA is illegal on PXA2xx; force use
+ * of PIO instead. Care is needed above because the transfer may
+ * have have been passed with buffers that are already dma mapped.
+ * A zero-length transfer in PIO mode will not try to write/read
+ * to/from the buffers
+ *
+ * REVISIT large transfers are exactly where we most want to be
+ * using DMA. If this happens much, split those transfers into
+ * multiple DMA segments rather than forcing PIO.
+ */
+ drv_data->dma_mapped = 0;
+ if (drv_data->len > 0 && drv_data->len <= MAX_DMA_LEN)
+ drv_data->dma_mapped = map_dma_buffers(drv_data);
+ if (drv_data->dma_mapped) {
/* Ensure we have the correct interrupt handler */
drv_data->transfer_handler = dma_transfer;
diff --git a/drivers/spi/spi_mpc83xx.c b/drivers/spi/spi_mpc83xx.c
index 070c6219e2d..ac0e3e4b3c5 100644
--- a/drivers/spi/spi_mpc83xx.c
+++ b/drivers/spi/spi_mpc83xx.c
@@ -267,16 +267,13 @@ int mpc83xx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
cs->hw_mode |= SPMODE_LEN(bits_per_word);
if ((mpc83xx_spi->spibrg / hz) > 64) {
+ cs->hw_mode |= SPMODE_DIV16;
pm = mpc83xx_spi->spibrg / (hz * 64);
if (pm > 16) {
- cs->hw_mode |= SPMODE_DIV16;
- pm /= 16;
- if (pm > 16) {
- dev_err(&spi->dev, "Requested speed is too "
- "low: %d Hz. Will use %d Hz instead.\n",
- hz, mpc83xx_spi->spibrg / 1024);
- pm = 16;
- }
+ dev_err(&spi->dev, "Requested speed is too "
+ "low: %d Hz. Will use %d Hz instead.\n",
+ hz, mpc83xx_spi->spibrg / 1024);
+ pm = 16;
}
} else
pm = mpc83xx_spi->spibrg / (hz * 4);
@@ -315,11 +312,20 @@ static int mpc83xx_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
if (t->bits_per_word)
bits_per_word = t->bits_per_word;
len = t->len;
- if (bits_per_word > 8)
+ if (bits_per_word > 8) {
+ /* invalid length? */
+ if (len & 1)
+ return -EINVAL;
len /= 2;
- if (bits_per_word > 16)
+ }
+ if (bits_per_word > 16) {
+ /* invalid length? */
+ if (len & 1)
+ return -EINVAL;
len /= 2;
+ }
mpc83xx_spi->count = len;
+
INIT_COMPLETION(mpc83xx_spi->done);
/* enable rx ints */
diff --git a/drivers/spi/spi_s3c24xx.c b/drivers/spi/spi_s3c24xx.c
index 98abc73c1a1..3eb414b84a9 100644
--- a/drivers/spi/spi_s3c24xx.c
+++ b/drivers/spi/spi_s3c24xx.c
@@ -430,7 +430,7 @@ static int s3c24xx_spi_resume(struct platform_device *pdev)
#endif
MODULE_ALIAS("platform:s3c2410-spi");
-static struct platform_driver s3c24xx_spidrv = {
+static struct platform_driver s3c24xx_spi_driver = {
.remove = __exit_p(s3c24xx_spi_remove),
.suspend = s3c24xx_spi_suspend,
.resume = s3c24xx_spi_resume,
@@ -442,12 +442,12 @@ static struct platform_driver s3c24xx_spidrv = {
static int __init s3c24xx_spi_init(void)
{
- return platform_driver_probe(&s3c24xx_spidrv, s3c24xx_spi_probe);
+ return platform_driver_probe(&s3c24xx_spi_driver, s3c24xx_spi_probe);
}
static void __exit s3c24xx_spi_exit(void)
{
- platform_driver_unregister(&s3c24xx_spidrv);
+ platform_driver_unregister(&s3c24xx_spi_driver);
}
module_init(s3c24xx_spi_init);
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
index 87ab2443e66..0ffabf5c0b6 100644
--- a/drivers/ssb/main.c
+++ b/drivers/ssb/main.c
@@ -471,6 +471,7 @@ static int ssb_devices_register(struct ssb_bus *bus)
#endif
break;
case SSB_BUSTYPE_SSB:
+ dev->dma_mask = &dev->coherent_dma_mask;
break;
}
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 8abd4e59bf4..8ab389dca2b 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1876,7 +1876,8 @@ int usb_add_hcd(struct usb_hcd *hcd,
* with IRQF_SHARED. As usb_hcd_irq() will always disable
* interrupts we can remove it here.
*/
- irqflags &= ~IRQF_DISABLED;
+ if (irqflags & IRQF_SHARED)
+ irqflags &= ~IRQF_DISABLED;
snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d",
hcd->driver->description, hcd->self.busnum);
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 6a5cb018383..d99963873e3 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -2683,35 +2683,17 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
USB_PORT_STAT_C_ENABLE);
#endif
- /* Try to use the debounce delay for protection against
- * port-enable changes caused, for example, by EMI.
- */
- if (portchange & (USB_PORT_STAT_C_CONNECTION |
- USB_PORT_STAT_C_ENABLE)) {
- status = hub_port_debounce(hub, port1);
- if (status < 0) {
- if (printk_ratelimit())
- dev_err (hub_dev, "connect-debounce failed, "
- "port %d disabled\n", port1);
- portstatus &= ~USB_PORT_STAT_CONNECTION;
- } else {
- portstatus = status;
- }
- }
-
/* Try to resuscitate an existing device */
udev = hdev->children[port1-1];
if ((portstatus & USB_PORT_STAT_CONNECTION) && udev &&
udev->state != USB_STATE_NOTATTACHED) {
-
usb_lock_device(udev);
if (portstatus & USB_PORT_STAT_ENABLE) {
status = 0; /* Nothing to do */
- } else if (!udev->persist_enabled) {
- status = -ENODEV; /* Mustn't resuscitate */
#ifdef CONFIG_USB_SUSPEND
- } else if (udev->state == USB_STATE_SUSPENDED) {
+ } else if (udev->state == USB_STATE_SUSPENDED &&
+ udev->persist_enabled) {
/* For a suspended device, treat this as a
* remote wakeup event.
*/
@@ -2726,7 +2708,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
#endif
} else {
- status = usb_reset_device(udev);
+ status = -ENODEV; /* Don't resuscitate */
}
usb_unlock_device(udev);
@@ -2741,6 +2723,19 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
usb_disconnect(&hdev->children[port1-1]);
clear_bit(port1, hub->change_bits);
+ if (portchange & (USB_PORT_STAT_C_CONNECTION |
+ USB_PORT_STAT_C_ENABLE)) {
+ status = hub_port_debounce(hub, port1);
+ if (status < 0) {
+ if (printk_ratelimit())
+ dev_err(hub_dev, "connect-debounce failed, "
+ "port %d disabled\n", port1);
+ portstatus &= ~USB_PORT_STAT_CONNECTION;
+ } else {
+ portstatus = status;
+ }
+ }
+
/* Return now if debouncing failed or nothing is connected */
if (!(portstatus & USB_PORT_STAT_CONNECTION)) {
@@ -2748,7 +2743,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2
&& !(portstatus & (1 << USB_PORT_FEAT_POWER)))
set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
-
+
if (portstatus & USB_PORT_STAT_ENABLE)
goto done;
return;
diff --git a/drivers/usb/gadget/fsl_usb2_udc.c b/drivers/usb/gadget/fsl_usb2_udc.c
index 1cfccf102a2..45ad556169f 100644
--- a/drivers/usb/gadget/fsl_usb2_udc.c
+++ b/drivers/usb/gadget/fsl_usb2_udc.c
@@ -223,7 +223,7 @@ static int dr_controller_setup(struct fsl_udc *udc)
fsl_writel(tmp, &dr_regs->endpointlistaddr);
VDBG("vir[qh_base] is %p phy[qh_base] is 0x%8x reg is 0x%8x",
- (int)udc->ep_qh, (int)tmp,
+ udc->ep_qh, (int)tmp,
fsl_readl(&dr_regs->endpointlistaddr));
/* Config PHY interface */
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index 574c53831a0..bb54cca4c54 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -787,7 +787,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
omap_set_dma_dest_params(ep->lch,
OMAP_DMA_PORT_TIPB,
OMAP_DMA_AMODE_CONSTANT,
- (unsigned long) io_v2p(UDC_DATA_DMA),
+ UDC_DATA_DMA,
0, 0);
}
} else {
@@ -804,7 +804,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
omap_set_dma_src_params(ep->lch,
OMAP_DMA_PORT_TIPB,
OMAP_DMA_AMODE_CONSTANT,
- (unsigned long) io_v2p(UDC_DATA_DMA),
+ UDC_DATA_DMA,
0, 0);
/* EMIFF or SDRC */
omap_set_dma_dest_burst_mode(ep->lch,
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index d9d53f289ca..8409e0705d6 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -145,16 +145,6 @@ static int handshake (struct ehci_hcd *ehci, void __iomem *ptr,
return -ETIMEDOUT;
}
-static int handshake_on_error_set_halt(struct ehci_hcd *ehci, void __iomem *ptr,
- u32 mask, u32 done, int usec)
-{
- int error = handshake(ehci, ptr, mask, done, usec);
- if (error)
- ehci_to_hcd(ehci)->state = HC_STATE_HALT;
-
- return error;
-}
-
/* force HC to halt state from unknown (EHCI spec section 2.3) */
static int ehci_halt (struct ehci_hcd *ehci)
{
@@ -173,6 +163,22 @@ static int ehci_halt (struct ehci_hcd *ehci)
STS_HALT, STS_HALT, 16 * 125);
}
+static int handshake_on_error_set_halt(struct ehci_hcd *ehci, void __iomem *ptr,
+ u32 mask, u32 done, int usec)
+{
+ int error;
+
+ error = handshake(ehci, ptr, mask, done, usec);
+ if (error) {
+ ehci_halt(ehci);
+ ehci_to_hcd(ehci)->state = HC_STATE_HALT;
+ ehci_err(ehci, "force halt; handhake %p %08x %08x -> %d\n",
+ ptr, mask, done, error);
+ }
+
+ return error;
+}
+
/* put TDI/ARC silicon into EHCI mode */
static void tdi_reset (struct ehci_hcd *ehci)
{
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index b7853c8bac0..4a0c5a78b2e 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -437,6 +437,9 @@ static int enable_periodic (struct ehci_hcd *ehci)
u32 cmd;
int status;
+ if (ehci->periodic_sched++)
+ return 0;
+
/* did clearing PSE did take effect yet?
* takes effect only at frame boundaries...
*/
@@ -461,6 +464,9 @@ static int disable_periodic (struct ehci_hcd *ehci)
u32 cmd;
int status;
+ if (--ehci->periodic_sched)
+ return 0;
+
/* did setting PSE not take effect yet?
* takes effect only at frame boundaries...
*/
@@ -544,13 +550,10 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
: (qh->usecs * 8);
/* maybe enable periodic schedule processing */
- if (!ehci->periodic_sched++)
- return enable_periodic (ehci);
-
- return 0;
+ return enable_periodic(ehci);
}
-static void qh_unlink_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
+static int qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
{
unsigned i;
unsigned period;
@@ -586,9 +589,7 @@ static void qh_unlink_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
qh_put (qh);
/* maybe turn off periodic schedule */
- ehci->periodic_sched--;
- if (!ehci->periodic_sched)
- (void) disable_periodic (ehci);
+ return disable_periodic(ehci);
}
static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
@@ -1562,9 +1563,7 @@ itd_link_urb (
urb->hcpriv = NULL;
timer_action (ehci, TIMER_IO_WATCHDOG);
- if (unlikely (!ehci->periodic_sched++))
- return enable_periodic (ehci);
- return 0;
+ return enable_periodic(ehci);
}
#define ISO_ERRS (EHCI_ISOC_BUF_ERR | EHCI_ISOC_BABBLE | EHCI_ISOC_XACTERR)
@@ -1642,7 +1641,7 @@ itd_complete (
ehci_urb_done(ehci, urb, 0);
retval = true;
urb = NULL;
- ehci->periodic_sched--;
+ (void) disable_periodic(ehci);
ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
if (unlikely (list_empty (&stream->td_list))) {
@@ -1951,9 +1950,7 @@ sitd_link_urb (
urb->hcpriv = NULL;
timer_action (ehci, TIMER_IO_WATCHDOG);
- if (!ehci->periodic_sched++)
- return enable_periodic (ehci);
- return 0;
+ return enable_periodic(ehci);
}
/*-------------------------------------------------------------------------*/
@@ -2019,7 +2016,7 @@ sitd_complete (
ehci_urb_done(ehci, urb, 0);
retval = true;
urb = NULL;
- ehci->periodic_sched--;
+ (void) disable_periodic(ehci);
ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
if (list_empty (&stream->td_list)) {
@@ -2243,8 +2240,7 @@ restart:
if (unlikely (modified)) {
if (likely(ehci->periodic_sched > 0))
goto restart;
- /* maybe we can short-circuit this scan! */
- disable_periodic(ehci);
+ /* short-circuit this scan */
now_uframe = clock;
break;
}
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index 1eb64d08b60..95b3ec89c12 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -208,7 +208,7 @@ static int ohci_omap_init(struct usb_hcd *hcd)
if (cpu_is_omap16xx())
ocpi_enable();
-#ifdef CONFIG_ARCH_OMAP_OTG
+#ifdef CONFIG_USB_OTG
if (need_transceiver) {
ohci->transceiver = otg_get_transceiver();
if (ohci->transceiver) {
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index a0017486ad4..58b2b8fc943 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -9,6 +9,7 @@ comment "Enable Host or Gadget support to see Inventra options"
# (M)HDRC = (Multipoint) Highspeed Dual-Role Controller
config USB_MUSB_HDRC
depends on (USB || USB_GADGET) && HAVE_CLK
+ depends on !SUPERH
select TWL4030_USB if MACH_OMAP_3430SDP
tristate 'Inventra Highspeed Dual Role Controller (TI, ...)'
help
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index c5b8f0296fc..128e949db47 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -100,8 +100,8 @@
#include <linux/io.h>
#ifdef CONFIG_ARM
-#include <asm/arch/hardware.h>
-#include <asm/arch/memory.h>
+#include <mach/hardware.h>
+#include <mach/memory.h>
#include <asm/mach-types.h>
#endif
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index 298b22e6ad0..9d2dcb121c5 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -35,8 +35,8 @@
#include <linux/io.h>
#include <asm/mach-types.h>
-#include <asm/arch/hardware.h>
-#include <asm/arch/mux.h>
+#include <mach/hardware.h>
+#include <mach/mux.h>
#include "musb_core.h"
#include "omap2430.h"
diff --git a/drivers/usb/musb/omap2430.h b/drivers/usb/musb/omap2430.h
index 786a62071f7..dc7670718cd 100644
--- a/drivers/usb/musb/omap2430.h
+++ b/drivers/usb/musb/omap2430.h
@@ -11,8 +11,8 @@
#define __MUSB_OMAP243X_H__
#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430)
-#include <asm/arch/hardware.h>
-#include <asm/arch/usb.h>
+#include <mach/hardware.h>
+#include <mach/usb.h>
/*
* OMAP2430-specific definitions
diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c
index 7b74238ad1c..e980766bb84 100644
--- a/drivers/usb/serial/console.c
+++ b/drivers/usb/serial/console.c
@@ -161,7 +161,7 @@ static int usb_console_setup(struct console *co, char *options)
if (serial->type->set_termios) {
termios->c_cflag = cflag;
tty_termios_encode_baud_rate(termios, baud, baud);
- serial->type->set_termios(NULL, port, &dummy);
+ serial->type->set_termios(tty, port, &dummy);
port->port.tty = NULL;
kfree(termios);
diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c
index 442cba69cce..1279553381e 100644
--- a/drivers/usb/serial/cp2101.c
+++ b/drivers/usb/serial/cp2101.c
@@ -72,6 +72,7 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x10C4, 0x80CA) }, /* Degree Controls Inc */
{ USB_DEVICE(0x10C4, 0x80DD) }, /* Tracient RFID */
{ USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */
+ { USB_DEVICE(0x10C4, 0x8115) }, /* Arygon NFC/Mifare Reader */
{ USB_DEVICE(0x10C4, 0x813D) }, /* Burnside Telecom Deskmobile */
{ USB_DEVICE(0x10C4, 0x814A) }, /* West Mountain Radio RIGblaster P&P */
{ USB_DEVICE(0x10C4, 0x814B) }, /* West Mountain Radio RIGtalk */
@@ -83,6 +84,7 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x10C4, 0x81E7) }, /* Aerocomm Radio */
{ USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */
{ USB_DEVICE(0x10c4, 0x8293) }, /* Telegesys ETRX2USB */
+ { USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */
{ USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
{ USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */
{ USB_DEVICE(0x10C4, 0xF001) }, /* Elan Digital Systems USBscope50 */
@@ -93,6 +95,7 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */
{ USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */
{ USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */
+ { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */
{ } /* Terminating Entry */
};
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 984f6eff4c4..3dc93b542b3 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -654,6 +654,9 @@ static struct usb_device_id id_table_combined [] = {
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) },
{ USB_DEVICE(FTDI_VID, FTDI_REU_TINY_PID) },
+ { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO4x4_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_DOMINTELL_DGQG_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_DOMINTELL_DUSB_PID) },
{ }, /* Optional parameter entry */
{ } /* Terminating entry */
};
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index 382265bba96..8a5b6df3a97 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -750,6 +750,7 @@
#define PAPOUCH_VID 0x5050 /* Vendor ID */
#define PAPOUCH_TMU_PID 0x0400 /* TMU USB Thermometer */
+#define PAPOUCH_QUIDO4x4_PID 0x0900 /* Quido 4/4 Module */
/*
* ACG Identification Technologies GmbH products (http://www.acg.de/).
@@ -838,6 +839,10 @@
/* Rig Expert Ukraine devices */
#define FTDI_REU_TINY_PID 0xED22 /* RigExpert Tiny */
+/* Domintell products http://www.domintell.com */
+#define FTDI_DOMINTELL_DGQG_PID 0xEF50 /* Master */
+#define FTDI_DOMINTELL_DUSB_PID 0xEF51 /* DUSB01 module */
+
/* Commands */
#define FTDI_SIO_RESET 0 /* Reset the port */
#define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 9f9cd36455f..73f8277f88f 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -218,6 +218,7 @@ static int option_send_setup(struct tty_struct *tty, struct usb_serial_port *po
/* ZTE PRODUCTS */
#define ZTE_VENDOR_ID 0x19d2
#define ZTE_PRODUCT_MF628 0x0015
+#define ZTE_PRODUCT_CDMA_TECH 0xfffe
static struct usb_device_id option_ids[] = {
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
@@ -347,6 +348,7 @@ static struct usb_device_id option_ids[] = {
{ USB_DEVICE(MAXON_VENDOR_ID, 0x6280) }, /* BP3-USB & BP3-EXT HSDPA */
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864E) },
{ USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_MF628) },
+ { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, option_ids);
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index 706033753ad..ea1a103c99b 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -14,7 +14,7 @@
Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org>
*/
-#define DRIVER_VERSION "v.1.2.13a"
+#define DRIVER_VERSION "v.1.3.2"
#define DRIVER_AUTHOR "Kevin Lloyd <klloyd@sierrawireless.com>"
#define DRIVER_DESC "USB Driver for Sierra Wireless USB modems"
@@ -30,9 +30,6 @@
#define SWIMS_USB_REQUEST_SetPower 0x00
#define SWIMS_USB_REQUEST_SetNmea 0x07
-#define SWIMS_USB_REQUEST_SetMode 0x0B
-#define SWIMS_USB_REQUEST_GetSwocInfo 0x0A
-#define SWIMS_SET_MODE_Modem 0x0001
/* per port private data */
#define N_IN_URB 4
@@ -163,7 +160,7 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
{ USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
{ USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
- { USB_DEVICE(0x0f30, 0x1b1d) }, /* Sierra Wireless MC5720 */
+ { USB_DEVICE(0x03f0, 0x1b1d) }, /* HP ev2200 a.k.a MC5720 */
{ USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
{ USB_DEVICE(0x1199, 0x0024) }, /* Sierra Wireless MC5727 */
{ USB_DEVICE(0x1199, 0x0220) }, /* Sierra Wireless MC5725 */
@@ -175,6 +172,8 @@ static struct usb_device_id id_table [] = {
/* Sierra Wireless Device */
{ USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x0025, 0xFF, 0xFF, 0xFF) },
{ USB_DEVICE(0x1199, 0x0026) }, /* Sierra Wireless Device */
+ { USB_DEVICE(0x1199, 0x0027) }, /* Sierra Wireless Device */
+ { USB_DEVICE(0x1199, 0x0028) }, /* Sierra Wireless Device */
{ USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
{ USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */
@@ -187,6 +186,7 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x1199, 0x6821) }, /* Sierra Wireless AirCard 875U */
{ USB_DEVICE(0x1199, 0x6832) }, /* Sierra Wireless MC8780 */
{ USB_DEVICE(0x1199, 0x6833) }, /* Sierra Wireless MC8781 */
+ { USB_DEVICE(0x1199, 0x683A) }, /* Sierra Wireless MC8785 */
{ USB_DEVICE(0x1199, 0x683B) }, /* Sierra Wireless MC8785 Composite */
{ USB_DEVICE(0x1199, 0x683C) }, /* Sierra Wireless MC8790 */
{ USB_DEVICE(0x1199, 0x683D) }, /* Sierra Wireless MC8790 */
@@ -204,6 +204,8 @@ static struct usb_device_id id_table [] = {
/* Sierra Wireless Device */
{ USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6890, 0xFF, 0xFF, 0xFF)},
/* Sierra Wireless Device */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6891, 0xFF, 0xFF, 0xFF)},
+ /* Sierra Wireless Device */
{ USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6892, 0xFF, 0xFF, 0xFF)},
{ USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index e39c779e416..9a3e495c769 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -1744,7 +1744,7 @@ static int ti_download_firmware(struct ti_device *tdev, int type)
if (buffer) {
memcpy(buffer, fw_p->data, fw_p->size);
memset(buffer + fw_p->size, 0xff, buffer_size - fw_p->size);
- ti_do_download(dev, pipe, buffer, fw_p->size);
+ status = ti_do_download(dev, pipe, buffer, fw_p->size);
kfree(buffer);
}
release_firmware(fw_p);
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index b157c48e8b7..4f7f9e3ae0a 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -733,7 +733,9 @@ int usb_serial_probe(struct usb_interface *interface,
((le16_to_cpu(dev->descriptor.idVendor) == ATEN_VENDOR_ID) &&
(le16_to_cpu(dev->descriptor.idProduct) == ATEN_PRODUCT_ID)) ||
((le16_to_cpu(dev->descriptor.idVendor) == ALCOR_VENDOR_ID) &&
- (le16_to_cpu(dev->descriptor.idProduct) == ALCOR_PRODUCT_ID))) {
+ (le16_to_cpu(dev->descriptor.idProduct) == ALCOR_PRODUCT_ID)) ||
+ ((le16_to_cpu(dev->descriptor.idVendor) == SIEMENS_VENDOR_ID) &&
+ (le16_to_cpu(dev->descriptor.idProduct) == SIEMENS_PRODUCT_ID_EF81))) {
if (interface != dev->actconfig->interface[0]) {
/* check out the endpoints of the other interface*/
iface_desc = dev->actconfig->interface[0]->cur_altsetting;
diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig
index c76034672c1..3d9249632ae 100644
--- a/drivers/usb/storage/Kconfig
+++ b/drivers/usb/storage/Kconfig
@@ -146,18 +146,6 @@ config USB_STORAGE_KARMA
on the resulting scsi device node returns the Karma to normal
operation.
-config USB_STORAGE_SIERRA
- bool "Sierra Wireless TRU-Install Feature Support"
- depends on USB_STORAGE
- help
- Say Y here to include additional code to support Sierra Wireless
- products with the TRU-Install feature (e.g., AC597E, AC881U).
-
- This code switches the Sierra Wireless device from being in
- Mass Storage mode to Modem mode. It also has the ability to
- support host software upgrades should full Linux support be added
- to TRU-Install.
-
config USB_STORAGE_CYPRESS_ATACB
bool "SAT emulation on Cypress USB/ATA Bridge with ATACB"
depends on USB_STORAGE
diff --git a/drivers/usb/storage/Makefile b/drivers/usb/storage/Makefile
index bc3415b475c..7f8beb5366a 100644
--- a/drivers/usb/storage/Makefile
+++ b/drivers/usb/storage/Makefile
@@ -21,11 +21,10 @@ usb-storage-obj-$(CONFIG_USB_STORAGE_JUMPSHOT) += jumpshot.o
usb-storage-obj-$(CONFIG_USB_STORAGE_ALAUDA) += alauda.o
usb-storage-obj-$(CONFIG_USB_STORAGE_ONETOUCH) += onetouch.o
usb-storage-obj-$(CONFIG_USB_STORAGE_KARMA) += karma.o
-usb-storage-obj-$(CONFIG_USB_STORAGE_SIERRA) += sierra_ms.o
usb-storage-obj-$(CONFIG_USB_STORAGE_CYPRESS_ATACB) += cypress_atacb.o
usb-storage-objs := scsiglue.o protocol.o transport.o usb.o \
- initializers.o $(usb-storage-obj-y)
+ initializers.o sierra_ms.o $(usb-storage-obj-y)
ifneq ($(CONFIG_USB_LIBUSUAL),)
obj-$(CONFIG_USB) += libusual.o
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index ba412e68d47..cd155475cb6 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -160,6 +160,13 @@ UNUSUAL_DEV( 0x0421, 0x0019, 0x0592, 0x0592,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_MAX_SECTORS_64 ),
+/* Reported by Filip Joelsson <filip@blueturtle.nu> */
+UNUSUAL_DEV( 0x0421, 0x005d, 0x0001, 0x0600,
+ "Nokia",
+ "Nokia 3110c",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY ),
+
/* Reported by Mario Rettig <mariorettig@web.de> */
UNUSUAL_DEV( 0x0421, 0x042e, 0x0100, 0x0100,
"Nokia",
@@ -232,6 +239,20 @@ UNUSUAL_DEV( 0x0421, 0x04b9, 0x0551, 0x0551,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_CAPACITY ),
+/* Reported by Richard Nauber <RichardNauber@web.de> */
+UNUSUAL_DEV( 0x0421, 0x04fa, 0x0601, 0x0601,
+ "Nokia",
+ "6300",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY ),
+
+/* Patch for Nokia 5310 capacity */
+UNUSUAL_DEV( 0x0421, 0x006a, 0x0000, 0x0591,
+ "Nokia",
+ "5310",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY ),
+
/* Reported by Olaf Hering <olh@suse.de> from novell bug #105878 */
UNUSUAL_DEV( 0x0424, 0x0fdc, 0x0210, 0x0210,
"SMSC",
@@ -987,6 +1008,13 @@ UNUSUAL_DEV( 0x069b, 0x3004, 0x0001, 0x0001,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_CAPACITY ),
+/* Reported by Adrian Pilchowiec <adi1981@epf.pl> */
+UNUSUAL_DEV( 0x071b, 0x3203, 0x0000, 0x0000,
+ "RockChip",
+ "MP3",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_NO_WP_DETECT | US_FL_MAX_SECTORS_64),
+
/* Reported by Massimiliano Ghilardi <massimiliano.ghilardi@gmail.com>
* This USB MP3/AVI player device fails and disconnects if more than 128
* sectors (64kB) are read/written in a single command, and may be present
@@ -1576,7 +1604,6 @@ UNUSUAL_DEV( 0x10d6, 0x2200, 0x0100, 0x0100,
US_SC_DEVICE, US_PR_DEVICE, NULL,
0),
-#ifdef CONFIG_USB_STORAGE_SIERRA
/* Reported by Kevin Lloyd <linux@sierrawireless.com>
* Entry is needed for the initializer function override,
* which instructs the device to load as a modem
@@ -1587,7 +1614,6 @@ UNUSUAL_DEV( 0x1199, 0x0fff, 0x0000, 0x9999,
"USB MMC Storage",
US_SC_DEVICE, US_PR_DEVICE, sierra_ms_init,
0),
-#endif
/* Reported by Jaco Kroon <jaco@kroon.co.za>
* The usb-storage module found on the Digitech GNX4 (and supposedly other
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 73679aa506d..27016fd2cad 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -102,9 +102,7 @@
#ifdef CONFIG_USB_STORAGE_CYPRESS_ATACB
#include "cypress_atacb.h"
#endif
-#ifdef CONFIG_USB_STORAGE_SIERRA
#include "sierra_ms.h"
-#endif
/* Some informational data */
MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>");
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index 9c5925927ec..75dac578104 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -208,6 +208,36 @@ static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2)
return value;
}
+static void atmel_lcdfb_stop_nowait(struct atmel_lcdfb_info *sinfo)
+{
+ /* Turn off the LCD controller and the DMA controller */
+ lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
+ sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
+
+ /* Wait for the LCDC core to become idle */
+ while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY)
+ msleep(10);
+
+ lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
+}
+
+static void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo)
+{
+ atmel_lcdfb_stop_nowait(sinfo);
+
+ /* Wait for DMA engine to become idle... */
+ while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
+ msleep(10);
+}
+
+static void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo)
+{
+ lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
+ lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
+ (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET)
+ | ATMEL_LCDC_PWR);
+}
+
static void atmel_lcdfb_update_dma(struct fb_info *info,
struct fb_var_screeninfo *var)
{
@@ -420,26 +450,8 @@ static void atmel_lcdfb_reset(struct atmel_lcdfb_info *sinfo)
{
might_sleep();
- /* LCD power off */
- lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
-
- /* wait for the LCDC core to become idle */
- while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY)
- msleep(10);
-
- /* DMA disable */
- lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
-
- /* wait for DMA engine to become idle */
- while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
- msleep(10);
-
- /* LCD power on */
- lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
- (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET) | ATMEL_LCDC_PWR);
-
- /* DMA enable */
- lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
+ atmel_lcdfb_stop(sinfo);
+ atmel_lcdfb_start(sinfo);
}
/**
@@ -471,14 +483,7 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
info->var.xres, info->var.yres,
info->var.xres_virtual, info->var.yres_virtual);
- /* Turn off the LCD controller and the DMA controller */
- lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
-
- /* Wait for the LCDC core to become idle */
- while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY)
- msleep(10);
-
- lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
+ atmel_lcdfb_stop_nowait(sinfo);
if (info->var.bits_per_pixel == 1)
info->fix.visual = FB_VISUAL_MONO01;
@@ -583,13 +588,7 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
msleep(10);
- dev_dbg(info->device, " * re-enable DMA engine\n");
- /* ...and enable it with updated configuration */
- lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
-
- dev_dbg(info->device, " * re-enable LCDC core\n");
- lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
- (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET) | ATMEL_LCDC_PWR);
+ atmel_lcdfb_start(sinfo);
dev_dbg(info->device, " * DONE\n");
@@ -939,7 +938,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
ret = register_framebuffer(info);
if (ret < 0) {
dev_err(dev, "failed to register framebuffer device: %d\n", ret);
- goto free_cmap;
+ goto reset_drvdata;
}
/* add selected videomode to modelist */
@@ -955,7 +954,8 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
return 0;
-
+reset_drvdata:
+ dev_set_drvdata(dev, NULL);
free_cmap:
fb_dealloc_cmap(&info->cmap);
unregister_irqs:
@@ -992,10 +992,11 @@ static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct fb_info *info = dev_get_drvdata(dev);
- struct atmel_lcdfb_info *sinfo = info->par;
+ struct atmel_lcdfb_info *sinfo;
- if (!sinfo)
+ if (!info || !info->par)
return 0;
+ sinfo = info->par;
cancel_work_sync(&sinfo->task);
exit_backlight(sinfo);
@@ -1030,11 +1031,20 @@ static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg)
struct fb_info *info = platform_get_drvdata(pdev);
struct atmel_lcdfb_info *sinfo = info->par;
+ /*
+ * We don't want to handle interrupts while the clock is
+ * stopped. It may take forever.
+ */
+ lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
+
sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, 0);
if (sinfo->atmel_lcdfb_power_control)
sinfo->atmel_lcdfb_power_control(0);
+
+ atmel_lcdfb_stop(sinfo);
atmel_lcdfb_stop_clock(sinfo);
+
return 0;
}
@@ -1044,9 +1054,15 @@ static int atmel_lcdfb_resume(struct platform_device *pdev)
struct atmel_lcdfb_info *sinfo = info->par;
atmel_lcdfb_start_clock(sinfo);
+ atmel_lcdfb_start(sinfo);
if (sinfo->atmel_lcdfb_power_control)
sinfo->atmel_lcdfb_power_control(1);
lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, sinfo->saved_lcdcon);
+
+ /* Enable FIFO & DMA errors */
+ lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI
+ | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
+
return 0;
}
diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c
index c14b2435d23..e729fb27964 100644
--- a/drivers/video/cirrusfb.c
+++ b/drivers/video/cirrusfb.c
@@ -628,27 +628,18 @@ 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)
{
- int nom, den; /* translyting from pixels->bytes */
- int yres, i;
- static struct { int xres, yres; } modes[] =
- { { 1600, 1280 },
- { 1280, 1024 },
- { 1024, 768 },
- { 800, 600 },
- { 640, 480 },
- { -1, -1 } };
+ int yres;
+ /* memory size in pixels */
+ unsigned pixels = info->screen_size * 8 / var->bits_per_pixel;
switch (var->bits_per_pixel) {
case 1:
- nom = 4;
- den = 8;
+ pixels /= 4;
break; /* 8 pixel per byte, only 1/4th of mem usable */
case 8:
case 16:
case 24:
case 32:
- nom = var->bits_per_pixel / 8;
- den = 1;
break; /* 1 pixel == 1 byte */
default:
printk(KERN_ERR "cirrusfb: mode %dx%dx%d rejected..."
@@ -658,43 +649,29 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var,
return -EINVAL;
}
- 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");
- return -EINVAL;
- }
-
+ if (var->xres_virtual < var->xres)
+ var->xres_virtual = var->xres;
/* use highest possible virtual resolution */
- if (var->xres_virtual == -1 &&
- var->yres_virtual == -1) {
- printk(KERN_INFO
- "cirrusfb: using maximum available virtual resolution\n");
- for (i = 0; modes[i].xres != -1; i++) {
- int size = modes[i].xres * nom / den * modes[i].yres;
- if (size < info->screen_size / 2)
- break;
- }
- if (modes[i].xres == -1) {
- 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;
+ if (var->yres_virtual == -1) {
+ var->yres_virtual = pixels / var->xres_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)
- var->xres_virtual = var->xres;
if (var->yres_virtual < var->yres)
var->yres_virtual = var->yres;
+ if (var->xres_virtual * var->yres_virtual > pixels) {
+ printk(KERN_ERR "cirrusfb: mode %dx%dx%d rejected... "
+ "virtual resolution too high to fit into video memory!\n",
+ var->xres_virtual, var->yres_virtual,
+ var->bits_per_pixel);
+ DPRINTK("EXIT - EINVAL error\n");
+ return -EINVAL;
+ }
+
+
if (var->xoffset < 0)
var->xoffset = 0;
if (var->yoffset < 0)
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index c6299e8a041..9cbff84b787 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -2400,11 +2400,15 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
if (!fbcon_is_inactive(vc, info)) {
if (ops->blank_state != blank) {
+ int ret = 1;
+
ops->blank_state = blank;
fbcon_cursor(vc, blank ? CM_ERASE : CM_DRAW);
ops->cursor_flash = (!blank);
- if (fb_blank(info, blank))
+ if (info->fbops->fb_blank)
+ ret = info->fbops->fb_blank(blank, info);
+ if (ret)
fbcon_generic_blank(vc, info, blank);
}
diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h
index a6e38e9ea73..89a346880ec 100644
--- a/drivers/video/console/fbcon.h
+++ b/drivers/video/console/fbcon.h
@@ -110,7 +110,7 @@ static inline int mono_col(const struct fb_info *info)
__u32 max_len;
max_len = max(info->var.green.length, info->var.red.length);
max_len = max(info->var.blue.length, max_len);
- return ~(0xfff << (max_len & 0xff));
+ return (~(0xfff << max_len)) & 0xff;
}
static inline int attr_col_ec(int shift, struct vc_data *vc,
diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c
index 77aafcfae03..4599a4385bc 100644
--- a/drivers/video/tdfxfb.c
+++ b/drivers/video/tdfxfb.c
@@ -95,7 +95,6 @@ static inline int mtrr_del(int reg, unsigned long base,
#define VOODOO5_MAX_PIXCLOCK 350000
static struct fb_fix_screeninfo tdfx_fix __devinitdata = {
- .id = "3Dfx",
.type = FB_TYPE_PACKED_PIXELS,
.visual = FB_VISUAL_PSEUDOCOLOR,
.ypanstep = 1,
@@ -426,7 +425,7 @@ static unsigned long do_lfb_size(struct tdfx_par *par, unsigned short dev_id)
if (dev_id < PCI_DEVICE_ID_3DFX_VOODOO5) {
/* Banshee/Voodoo3 */
chip_size = 2;
- if (has_sgram && (draminit0 & DRAMINIT0_SGRAM_TYPE))
+ if (has_sgram && !(draminit0 & DRAMINIT0_SGRAM_TYPE))
chip_size = 1;
} else {
/* Voodoo4/5 */
@@ -1200,15 +1199,15 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev,
/* Configure the default fb_fix_screeninfo first */
switch (pdev->device) {
case PCI_DEVICE_ID_3DFX_BANSHEE:
- strcat(tdfx_fix.id, " Banshee");
+ strcpy(tdfx_fix.id, "3Dfx Banshee");
default_par->max_pixclock = BANSHEE_MAX_PIXCLOCK;
break;
case PCI_DEVICE_ID_3DFX_VOODOO3:
- strcat(tdfx_fix.id, " Voodoo3");
+ strcpy(tdfx_fix.id, "3Dfx Voodoo3");
default_par->max_pixclock = VOODOO3_MAX_PIXCLOCK;
break;
case PCI_DEVICE_ID_3DFX_VOODOO5:
- strcat(tdfx_fix.id, " Voodoo5");
+ strcpy(tdfx_fix.id, "3Dfx Voodoo5");
default_par->max_pixclock = VOODOO5_MAX_PIXCLOCK;
break;
}
diff --git a/drivers/watchdog/geodewdt.c b/drivers/watchdog/geodewdt.c
index 614a5c7017b..6799a6de66f 100644
--- a/drivers/watchdog/geodewdt.c
+++ b/drivers/watchdog/geodewdt.c
@@ -130,8 +130,8 @@ static ssize_t geodewdt_write(struct file *file, const char __user *data,
return len;
}
-static int geodewdt_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static long geodewdt_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
{
void __user *argp = (void __user *)arg;
int __user *p = argp;
@@ -198,7 +198,7 @@ static const struct file_operations geodewdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = geodewdt_write,
- .ioctl = geodewdt_ioctl,
+ .unlocked_ioctl = geodewdt_ioctl,
.open = geodewdt_open,
.release = geodewdt_release,
};
diff --git a/drivers/watchdog/ibmasr.c b/drivers/watchdog/ibmasr.c
index b82405cfb4c..89fcefcc851 100644
--- a/drivers/watchdog/ibmasr.c
+++ b/drivers/watchdog/ibmasr.c
@@ -85,7 +85,6 @@ static void __asr_toggle(void)
outb(reg & ~asr_toggle_mask, asr_write_addr);
reg = inb(asr_read_addr);
- spin_unlock(&asr_lock);
}
static void asr_toggle(void)
diff --git a/drivers/watchdog/pnx4008_wdt.c b/drivers/watchdog/pnx4008_wdt.c
index 0ed84162437..6d9f3d4a998 100644
--- a/drivers/watchdog/pnx4008_wdt.c
+++ b/drivers/watchdog/pnx4008_wdt.c
@@ -173,8 +173,8 @@ static const struct watchdog_info ident = {
.identity = "PNX4008 Watchdog",
};
-static long pnx4008_wdt_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static long pnx4008_wdt_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
{
int ret = -ENOTTY;
int time;
diff --git a/drivers/watchdog/rc32434_wdt.c b/drivers/watchdog/rc32434_wdt.c
index 6756bcb009e..c9c73b69c5e 100644
--- a/drivers/watchdog/rc32434_wdt.c
+++ b/drivers/watchdog/rc32434_wdt.c
@@ -182,8 +182,8 @@ static ssize_t rc32434_wdt_write(struct file *file, const char *data,
return 0;
}
-static int rc32434_wdt_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static long rc32434_wdt_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
{
void __user *argp = (void __user *)arg;
int new_timeout;
@@ -242,7 +242,7 @@ static struct file_operations rc32434_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = rc32434_wdt_write,
- .ioctl = rc32434_wdt_ioctl,
+ .unlocked_ioctl = rc32434_wdt_ioctl,
.open = rc32434_wdt_open,
.release = rc32434_wdt_release,
};
diff --git a/drivers/watchdog/rdc321x_wdt.c b/drivers/watchdog/rdc321x_wdt.c
index 9108efa73e7..bf92802f2bb 100644
--- a/drivers/watchdog/rdc321x_wdt.c
+++ b/drivers/watchdog/rdc321x_wdt.c
@@ -144,8 +144,8 @@ static int rdc321x_wdt_release(struct inode *inode, struct file *file)
return 0;
}
-static int rdc321x_wdt_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static long rdc321x_wdt_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
{
void __user *argp = (void __user *)arg;
unsigned int value;
@@ -204,7 +204,7 @@ static ssize_t rdc321x_wdt_write(struct file *file, const char __user *buf,
static const struct file_operations rdc321x_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
- .ioctl = rdc321x_wdt_ioctl,
+ .unlocked_ioctl = rdc321x_wdt_ioctl,
.open = rdc321x_wdt_open,
.write = rdc321x_wdt_write,
.release = rdc321x_wdt_release,
diff --git a/drivers/watchdog/wdt285.c b/drivers/watchdog/wdt285.c
index db362c34958..191ea630210 100644
--- a/drivers/watchdog/wdt285.c
+++ b/drivers/watchdog/wdt285.c
@@ -115,8 +115,8 @@ static int watchdog_release(struct inode *inode, struct file *file)
return 0;
}
-static ssize_t watchdog_write(struct file *file, const char *data,
- size_t len, loff_t *ppos)
+static ssize_t watchdog_write(struct file *file, const char __user *data,
+ size_t len, loff_t *ppos)
{
/*
* Refresh the timer.
@@ -133,21 +133,22 @@ static const struct watchdog_info ident = {
};
static long watchdog_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
+ unsigned long arg)
{
unsigned int new_margin;
+ int __user *int_arg = (int __user *)arg;
int ret = -ENOTTY;
switch (cmd) {
case WDIOC_GETSUPPORT:
ret = 0;
- if (copy_to_user((void *)arg, &ident, sizeof(ident)))
+ if (copy_to_user((void __user *)arg, &ident, sizeof(ident)))
ret = -EFAULT;
break;
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
- ret = put_user(0, (int *)arg);
+ ret = put_user(0, int_arg);
break;
case WDIOC_KEEPALIVE:
@@ -156,7 +157,7 @@ static long watchdog_ioctl(struct file *file, unsigned int cmd,
break;
case WDIOC_SETTIMEOUT:
- ret = get_user(new_margin, (int *)arg);
+ ret = get_user(new_margin, int_arg);
if (ret)
break;
@@ -171,7 +172,7 @@ static long watchdog_ioctl(struct file *file, unsigned int cmd,
watchdog_ping();
/* Fall */
case WDIOC_GETTIMEOUT:
- ret = put_user(soft_margin, (int *)arg);
+ ret = put_user(soft_margin, int_arg);
break;
}
return ret;
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c
index d4427cb8697..2e15da5459c 100644
--- a/drivers/xen/balloon.c
+++ b/drivers/xen/balloon.c
@@ -60,7 +60,7 @@
#define PAGES2KB(_p) ((_p)<<(PAGE_SHIFT-10))
-#define BALLOON_CLASS_NAME "memory"
+#define BALLOON_CLASS_NAME "xen_memory"
struct balloon_stats {
/* We aim for 'current allocation' == 'target allocation'. */