aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/ec.c6
-rw-r--r--drivers/acpi/executer/exregion.c5
-rw-r--r--drivers/acpi/fan.c30
-rw-r--r--drivers/acpi/processor_core.c39
-rw-r--r--drivers/acpi/processor_idle.c10
-rw-r--r--drivers/acpi/utils.c18
-rw-r--r--drivers/acpi/video.c3
-rw-r--r--drivers/ata/ahci.c30
-rw-r--r--drivers/ata/ata_piix.c4
-rw-r--r--drivers/ata/libata-core.c646
-rw-r--r--drivers/ata/libata-eh.c8
-rw-r--r--drivers/ata/libata-pmp.c4
-rw-r--r--drivers/ata/libata-scsi.c87
-rw-r--r--drivers/ata/libata.h2
-rw-r--r--drivers/ata/pata_acpi.c4
-rw-r--r--drivers/ata/pata_amd.c7
-rw-r--r--drivers/ata/pata_atiixp.c4
-rw-r--r--drivers/ata/pata_cs5536.c10
-rw-r--r--drivers/ata/pata_icside.c8
-rw-r--r--drivers/ata/pata_jmicron.c3
-rw-r--r--drivers/ata/pata_legacy.c46
-rw-r--r--drivers/ata/pata_marvell.c4
-rw-r--r--drivers/ata/pata_scc.c2
-rw-r--r--drivers/ata/sata_fsl.c21
-rw-r--r--drivers/ata/sata_mv.c19
-rw-r--r--drivers/ata/sata_promise.c2
-rw-r--r--drivers/ata/sata_sil24.c5
-rw-r--r--drivers/ata/sata_svw.c77
-rw-r--r--drivers/ata/sata_via.c4
-rw-r--r--drivers/base/bus.c9
-rw-r--r--drivers/base/driver.c3
-rw-r--r--drivers/base/power/main.c4
-rw-r--r--drivers/block/nbd.c6
-rw-r--r--drivers/block/xen-blkfront.c18
-rw-r--r--drivers/char/agp/amd-k7-agp.c9
-rw-r--r--drivers/char/agp/ati-agp.c16
-rw-r--r--drivers/char/agp/generic.c9
-rw-r--r--drivers/char/agp/sis-agp.c47
-rw-r--r--drivers/char/agp/sworks-agp.c18
-rw-r--r--drivers/char/drm/drmP.h2
-rw-r--r--drivers/char/drm/drm_pciids.h3
-rw-r--r--drivers/char/drm/drm_sysfs.c2
-rw-r--r--drivers/char/drm/drm_vm.c125
-rw-r--r--drivers/char/drm/i915_dma.c5
-rw-r--r--drivers/char/drm/i915_drv.c52
-rw-r--r--drivers/char/drm/i915_drv.h17
-rw-r--r--drivers/char/drm/radeon_cp.c81
-rw-r--r--drivers/char/drm/radeon_drv.h38
-rw-r--r--drivers/char/rtc.c4
-rw-r--r--drivers/connector/connector.c2
-rw-r--r--drivers/cpufreq/cpufreq.c8
-rw-r--r--drivers/crypto/hifn_795x.c6
-rw-r--r--drivers/firewire/fw-cdev.c17
-rw-r--r--drivers/firewire/fw-device.c48
-rw-r--r--drivers/firewire/fw-device.h2
-rw-r--r--drivers/firewire/fw-sbp2.c358
-rw-r--r--drivers/firmware/dmi_scan.c82
-rw-r--r--drivers/hwmon/Kconfig10
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/ad7418.c2
-rw-r--r--drivers/hwmon/adm1021.c6
-rw-r--r--drivers/hwmon/adm1025.c2
-rw-r--r--drivers/hwmon/adm1026.c4
-rw-r--r--drivers/hwmon/adm1029.c6
-rw-r--r--drivers/hwmon/adm1031.c2
-rw-r--r--drivers/hwmon/adm9240.c2
-rw-r--r--drivers/hwmon/ads7828.c2
-rw-r--r--drivers/hwmon/adt7470.c2
-rw-r--r--drivers/hwmon/adt7473.c1157
-rw-r--r--drivers/hwmon/applesmc.c29
-rw-r--r--drivers/hwmon/asb100.c2
-rw-r--r--drivers/hwmon/atxp1.c2
-rw-r--r--drivers/hwmon/coretemp.c119
-rw-r--r--drivers/hwmon/dme1737.c2
-rw-r--r--drivers/hwmon/ds1621.c2
-rw-r--r--drivers/hwmon/f75375s.c2
-rw-r--r--drivers/hwmon/fscher.c2
-rw-r--r--drivers/hwmon/fschmd.c2
-rw-r--r--drivers/hwmon/fscpos.c2
-rw-r--r--drivers/hwmon/gl518sm.c2
-rw-r--r--drivers/hwmon/gl520sm.c2
-rw-r--r--drivers/hwmon/lm63.c2
-rw-r--r--drivers/hwmon/lm75.c2
-rw-r--r--drivers/hwmon/lm77.c3
-rw-r--r--drivers/hwmon/lm78.c4
-rw-r--r--drivers/hwmon/lm80.c4
-rw-r--r--drivers/hwmon/lm83.c6
-rw-r--r--drivers/hwmon/lm85.c2
-rw-r--r--drivers/hwmon/lm87.c2
-rw-r--r--drivers/hwmon/lm90.c6
-rw-r--r--drivers/hwmon/lm92.c20
-rw-r--r--drivers/hwmon/lm93.c2
-rw-r--r--drivers/hwmon/max1619.c23
-rw-r--r--drivers/hwmon/max6650.c3
-rw-r--r--drivers/hwmon/smsc47m1.c25
-rw-r--r--drivers/hwmon/smsc47m192.c2
-rw-r--r--drivers/hwmon/thmc50.c8
-rw-r--r--drivers/hwmon/via686a.c28
-rw-r--r--drivers/hwmon/vt8231.c44
-rw-r--r--drivers/hwmon/w83781d.c4
-rw-r--r--drivers/hwmon/w83791d.c3
-rw-r--r--drivers/hwmon/w83792d.c3
-rw-r--r--drivers/hwmon/w83793.c3
-rw-r--r--drivers/hwmon/w83l785ts.c2
-rw-r--r--drivers/hwmon/w83l786ng.c2
-rw-r--r--drivers/i2c/busses/Kconfig2
-rw-r--r--drivers/i2c/busses/i2c-i801.c10
-rw-r--r--drivers/i2c/busses/i2c-pca-isa.c7
-rw-r--r--drivers/i2c/busses/i2c-pmcmsp.c4
-rw-r--r--drivers/i2c/busses/i2c-pxa.c29
-rw-r--r--drivers/ide/ide-cd.c36
-rw-r--r--drivers/ide/ide-disk.c6
-rw-r--r--drivers/ide/ide-dma.c52
-rw-r--r--drivers/ide/ide-generic.c6
-rw-r--r--drivers/ide/ide-probe.c3
-rw-r--r--drivers/ide/ide-tape.c5
-rw-r--r--drivers/ide/ide.c22
-rw-r--r--drivers/ide/legacy/falconide.c4
-rw-r--r--drivers/ide/legacy/ht6560b.c25
-rw-r--r--drivers/ide/legacy/macide.c2
-rw-r--r--drivers/ide/legacy/qd65xx.c43
-rw-r--r--drivers/ide/pci/cmd640.c3
-rw-r--r--drivers/ide/pci/hpt366.c12
-rw-r--r--drivers/ide/pci/via82cxxx.c1
-rw-r--r--drivers/ide/ppc/pmac.c4
-rw-r--r--drivers/ieee1394/sbp2.c15
-rw-r--r--drivers/ieee1394/sbp2.h2
-rw-r--r--drivers/infiniband/core/sysfs.c4
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_mem.c10
-rw-r--r--drivers/infiniband/hw/mthca/mthca_mr.c2
-rw-r--r--drivers/infiniband/hw/nes/nes.c2
-rw-r--r--drivers/infiniband/hw/nes/nes.h15
-rw-r--r--drivers/infiniband/hw/nes/nes_cm.c15
-rw-r--r--drivers/infiniband/hw/nes/nes_hw.c13
-rw-r--r--drivers/infiniband/hw/nes/nes_hw.h2
-rw-r--r--drivers/infiniband/hw/nes/nes_nic.c62
-rw-r--r--drivers/infiniband/hw/nes/nes_verbs.c12
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_cm.c10
-rw-r--r--drivers/macintosh/mediabay.c3
-rw-r--r--drivers/md/dm-raid1.c7
-rw-r--r--drivers/media/Kconfig18
-rw-r--r--drivers/media/common/Kconfig2
-rw-r--r--drivers/media/common/ir-keymaps.c46
-rw-r--r--drivers/media/common/saa7146_vbi.c1
-rw-r--r--drivers/media/common/saa7146_video.c2
-rw-r--r--drivers/media/dvb/bt8xx/bt878.c23
-rw-r--r--drivers/media/dvb/dvb-usb/ttusb2.c1
-rw-r--r--drivers/media/dvb/frontends/tda10086.c28
-rw-r--r--drivers/media/dvb/frontends/tda10086.h3
-rw-r--r--drivers/media/dvb/frontends/tda18271-common.c2
-rw-r--r--drivers/media/dvb/frontends/xc5000.h3
-rw-r--r--drivers/media/dvb/ttpci/av7110_av.c15
-rw-r--r--drivers/media/dvb/ttpci/budget-av.c8
-rw-r--r--drivers/media/dvb/ttpci/budget.c1
-rw-r--r--drivers/media/radio/Kconfig4
-rw-r--r--drivers/media/radio/radio-sf16fmi.c1
-rw-r--r--drivers/media/radio/radio-sf16fmr2.c5
-rw-r--r--drivers/media/radio/radio-si470x.c597
-rw-r--r--drivers/media/video/Kconfig4
-rw-r--r--drivers/media/video/Makefile5
-rw-r--r--drivers/media/video/bt8xx/bttv-driver.c51
-rw-r--r--drivers/media/video/bt8xx/bttv-vbi.c4
-rw-r--r--drivers/media/video/cx88/cx88-mpeg.c16
-rw-r--r--drivers/media/video/cx88/cx88.h1
-rw-r--r--drivers/media/video/em28xx/em28xx-audio.c6
-rw-r--r--drivers/media/video/em28xx/em28xx-cards.c8
-rw-r--r--drivers/media/video/em28xx/em28xx-core.c111
-rw-r--r--drivers/media/video/em28xx/em28xx-video.c79
-rw-r--r--drivers/media/video/em28xx/em28xx.h5
-rw-r--r--drivers/media/video/saa7134/saa7134-cards.c123
-rw-r--r--drivers/media/video/saa7134/saa7134-dvb.c28
-rw-r--r--drivers/media/video/saa7134/saa7134-empress.c6
-rw-r--r--drivers/media/video/saa7134/saa7134-input.c6
-rw-r--r--drivers/media/video/saa7134/saa7134-video.c20
-rw-r--r--drivers/media/video/saa7134/saa7134.h2
-rw-r--r--drivers/media/video/stk-sensor.c23
-rw-r--r--drivers/media/video/stk-webcam.c104
-rw-r--r--drivers/media/video/stk-webcam.h3
-rw-r--r--drivers/media/video/tcm825x.c2
-rw-r--r--drivers/media/video/tuner-core.c2
-rw-r--r--drivers/media/video/tuner-xc2028.c3
-rw-r--r--drivers/media/video/tvaudio.c10
-rw-r--r--drivers/media/video/tveeprom.c2
-rw-r--r--drivers/media/video/v4l2-common.c393
-rw-r--r--drivers/media/video/videobuf-core.c78
-rw-r--r--drivers/media/video/videobuf-dma-sg.c4
-rw-r--r--drivers/media/video/videobuf-vmalloc.c20
-rw-r--r--drivers/media/video/videodev.c444
-rw-r--r--drivers/media/video/zoran.h22
-rw-r--r--drivers/media/video/zoran_device.c12
-rw-r--r--drivers/media/video/zr364xx.c2
-rw-r--r--drivers/message/fusion/mptbase.c4
-rw-r--r--drivers/message/fusion/mptbase.h2
-rw-r--r--drivers/misc/Kconfig17
-rw-r--r--drivers/misc/acer-wmi.c9
-rw-r--r--drivers/misc/intel_menlow.c11
-rw-r--r--drivers/misc/thinkpad_acpi.c123
-rw-r--r--drivers/net/Kconfig6
-rw-r--r--drivers/net/bnx2.c50
-rw-r--r--drivers/net/bnx2.h1
-rw-r--r--drivers/net/bnx2x.c2663
-rw-r--r--drivers/net/bnx2x.h56
-rw-r--r--drivers/net/bnx2x_fw_defs.h2
-rw-r--r--drivers/net/bnx2x_hsi.h428
-rw-r--r--drivers/net/bnx2x_init.h12
-rw-r--r--drivers/net/bnx2x_reg.h212
-rw-r--r--drivers/net/cs89x0.c12
-rw-r--r--drivers/net/e1000/e1000_ethtool.c2
-rw-r--r--drivers/net/e1000/e1000_main.c8
-rw-r--r--drivers/net/e1000e/82571.c22
-rw-r--r--drivers/net/e1000e/defines.h10
-rw-r--r--drivers/net/e1000e/e1000.h3
-rw-r--r--drivers/net/e1000e/hw.h4
-rw-r--r--drivers/net/e1000e/ich8lan.c24
-rw-r--r--drivers/net/e1000e/lib.c50
-rw-r--r--drivers/net/e1000e/netdev.c52
-rw-r--r--drivers/net/e1000e/phy.c10
-rw-r--r--drivers/net/ehea/ehea.h34
-rw-r--r--drivers/net/ehea/ehea_main.c281
-rw-r--r--drivers/net/fs_enet/fs_enet-main.c7
-rw-r--r--drivers/net/gianfar.c18
-rw-r--r--drivers/net/gianfar_mii.c4
-rw-r--r--drivers/net/hamradio/mkiss.c5
-rw-r--r--drivers/net/ibm_newemac/rgmii.c1
-rw-r--r--drivers/net/igb/igb_ethtool.c2
-rw-r--r--drivers/net/igb/igb_main.c43
-rw-r--r--drivers/net/ixgb/ixgb_ethtool.c3
-rw-r--r--drivers/net/ixgbe/ixgbe_main.c41
-rw-r--r--drivers/net/macb.c2
-rw-r--r--drivers/net/niu.c20
-rw-r--r--drivers/net/niu.h2
-rw-r--r--drivers/net/pcmcia/pcnet_cs.c10
-rw-r--r--drivers/net/pcmcia/smc91c92_cs.c12
-rw-r--r--drivers/net/phy/mdio_bus.c4
-rw-r--r--drivers/net/ps3_gelic_wireless.c1
-rw-r--r--drivers/net/sis190.c15
-rw-r--r--drivers/net/sky2.c123
-rw-r--r--drivers/net/sky2.h27
-rw-r--r--drivers/net/tg3.c2
-rw-r--r--drivers/net/tlan.c64
-rw-r--r--drivers/net/tsi108_eth.c72
-rw-r--r--drivers/net/tulip/uli526x.c12
-rw-r--r--drivers/net/veth.c53
-rw-r--r--drivers/net/via-rhine.c2
-rw-r--r--drivers/net/virtio_net.c2
-rw-r--r--drivers/net/wireless/ath5k/ath5k.h2
-rw-r--r--drivers/net/wireless/ath5k/base.c24
-rw-r--r--drivers/net/wireless/ath5k/hw.c42
-rw-r--r--drivers/net/wireless/b43/Kconfig1
-rw-r--r--drivers/net/wireless/b43/b43.h6
-rw-r--r--drivers/net/wireless/b43/main.c40
-rw-r--r--drivers/net/wireless/b43legacy/Kconfig1
-rw-r--r--drivers/net/wireless/b43legacy/b43legacy.h4
-rw-r--r--drivers/net/wireless/b43legacy/dma.c167
-rw-r--r--drivers/net/wireless/b43legacy/dma.h33
-rw-r--r--drivers/net/wireless/b43legacy/main.c41
-rw-r--r--drivers/net/wireless/bcm43xx/Kconfig2
-rw-r--r--drivers/net/wireless/ipw2200.c45
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c19
-rw-r--r--drivers/net/wireless/iwlwifi/iwl4965-base.c17
-rw-r--r--drivers/net/wireless/libertas/cmd.c2
-rw-r--r--drivers/net/wireless/libertas/decl.h1
-rw-r--r--drivers/net/wireless/libertas/main.c17
-rw-r--r--drivers/net/wireless/p54usb.c2
-rw-r--r--drivers/net/wireless/rndis_wlan.c28
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c6
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c6
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c8
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00config.c8
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c73
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00reg.h2
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c6
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c6
-rw-r--r--drivers/net/wireless/rtl8180_dev.c4
-rw-r--r--drivers/net/wireless/rtl8187_dev.c4
-rw-r--r--drivers/net/wireless/wavelan.h6
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c12
-rw-r--r--drivers/pci/dmar.c9
-rw-r--r--drivers/pci/hotplug/acpiphp_core.c6
-rw-r--r--drivers/pci/hotplug/acpiphp_ibm.c33
-rw-r--r--drivers/pci/intel-iommu.c7
-rw-r--r--drivers/pci/intel-iommu.h5
-rw-r--r--drivers/pci/iova.c3
-rw-r--r--drivers/pci/iova.h3
-rw-r--r--drivers/pci/pci-acpi.c3
-rw-r--r--drivers/pci/pci.c1
-rw-r--r--drivers/pci/proc.c2
-rw-r--r--drivers/pci/quirks.c79
-rw-r--r--drivers/pci/setup-bus.c6
-rw-r--r--drivers/pcmcia/i82092.c7
-rw-r--r--drivers/rtc/rtc-cmos.c2
-rw-r--r--drivers/s390/block/dasd.c12
-rw-r--r--drivers/s390/block/dcssblk.c2
-rw-r--r--drivers/s390/char/sclp.c12
-rw-r--r--drivers/s390/char/sclp.h6
-rw-r--r--drivers/s390/char/sclp_config.c2
-rw-r--r--drivers/s390/char/sclp_cpi_sys.c2
-rw-r--r--drivers/s390/char/sclp_rw.c4
-rw-r--r--drivers/s390/char/sclp_vt220.c2
-rw-r--r--drivers/s390/cio/device.c15
-rw-r--r--drivers/s390/cio/qdio.c13
-rw-r--r--drivers/s390/cio/qdio.h2
-rw-r--r--drivers/s390/net/claw.c39
-rw-r--r--drivers/scsi/Kconfig10
-rw-r--r--drivers/scsi/Makefile1
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm_pci.c2
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_core.c11
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm_pci.c2
-rw-r--r--drivers/scsi/aic94xx/aic94xx_scb.c14
-rw-r--r--drivers/scsi/aic94xx/aic94xx_tmf.c4
-rw-r--r--drivers/scsi/arcmsr/arcmsr_hba.c26
-rw-r--r--drivers/scsi/arm/fas216.h2
-rw-r--r--drivers/scsi/gdth_proc.c6
-rw-r--r--drivers/scsi/ipr.c4
-rw-r--r--drivers/scsi/ips.c2
-rw-r--r--drivers/scsi/libsas/sas_ata.c4
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c68
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h1
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c2
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c18
-rw-r--r--drivers/scsi/megaraid.c10
-rw-r--r--drivers/scsi/mesh.c1
-rw-r--r--drivers/scsi/mvsas.c2970
-rw-r--r--drivers/scsi/qla2xxx/qla_dfs.c2
-rw-r--r--drivers/scsi/qla4xxx/ql4_isr.c3
-rw-r--r--drivers/scsi/qlogicpti.c12
-rw-r--r--drivers/scsi/scsi_debug.c2
-rw-r--r--drivers/scsi/scsi_lib.c8
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c4
-rw-r--r--drivers/scsi/sd.c3
-rw-r--r--drivers/scsi/ses.c126
-rw-r--r--drivers/scsi/st.c11
-rw-r--r--drivers/scsi/st.h1
-rw-r--r--drivers/scsi/stex.c44
-rw-r--r--drivers/serial/Kconfig6
-rw-r--r--drivers/serial/atmel_serial.c2
-rw-r--r--drivers/serial/bfin_5xx.c281
-rw-r--r--drivers/serial/sh-sci.c2
-rw-r--r--drivers/sh/maple/maple.c66
-rw-r--r--drivers/spi/atmel_spi.c10
-rw-r--r--drivers/spi/pxa2xx_spi.c41
-rw-r--r--drivers/ssb/Kconfig11
-rw-r--r--drivers/ssb/Makefile3
-rw-r--r--drivers/ssb/driver_chipcommon.c65
-rw-r--r--drivers/ssb/driver_extif.c25
-rw-r--r--drivers/ssb/driver_pcicore.c47
-rw-r--r--drivers/ssb/embedded.c132
-rw-r--r--drivers/ssb/main.c4
-rw-r--r--drivers/ssb/ssb_private.h4
-rw-r--r--drivers/thermal/thermal.c39
-rw-r--r--drivers/uio/uio.c54
-rw-r--r--drivers/usb/class/cdc-acm.c10
-rw-r--r--drivers/usb/class/usblp.c1
-rw-r--r--drivers/usb/core/quirks.c12
-rw-r--r--drivers/usb/gadget/ether.c1
-rw-r--r--drivers/usb/gadget/printer.c2
-rw-r--r--drivers/usb/host/Kconfig5
-rw-r--r--drivers/usb/host/ehci-hcd.c26
-rw-r--r--drivers/usb/host/sl811-hcd.c1
-rw-r--r--drivers/usb/host/u132-hcd.c15
-rw-r--r--drivers/usb/misc/ldusb.c2
-rw-r--r--drivers/usb/misc/trancevibrator.c4
-rw-r--r--drivers/usb/serial/ftdi_sio.c4
-rw-r--r--drivers/usb/serial/option.c43
-rw-r--r--drivers/usb/serial/sierra.c1
-rw-r--r--drivers/usb/storage/protocol.c27
-rw-r--r--drivers/usb/storage/transport.c11
-rw-r--r--drivers/usb/storage/unusual_devs.h34
-rw-r--r--drivers/video/aty/atyfb_base.c64
-rw-r--r--drivers/video/cg14.c1
-rw-r--r--drivers/video/chipsfb.c2
-rw-r--r--drivers/video/nvidia/nvidia.c2
-rw-r--r--drivers/video/pxafb.c8
-rw-r--r--drivers/video/sbuslib.c1
-rw-r--r--drivers/video/uvesafb.c2
-rw-r--r--drivers/watchdog/Kconfig25
-rw-r--r--drivers/watchdog/Makefile2
-rw-r--r--drivers/watchdog/bfin_wdt.c7
-rw-r--r--drivers/watchdog/hpwdt.c926
-rw-r--r--drivers/watchdog/mtx-1_wdt.c35
-rw-r--r--drivers/watchdog/sb_wdog.c353
381 files changed, 13488 insertions, 4347 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 7222a18a031..caf873c14bf 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -943,7 +943,11 @@ int __init acpi_ec_ecdt_probe(void)
boot_ec->command_addr = ecdt_ptr->control.address;
boot_ec->data_addr = ecdt_ptr->data.address;
boot_ec->gpe = ecdt_ptr->gpe;
- boot_ec->handle = ACPI_ROOT_OBJECT;
+ if (ACPI_FAILURE(acpi_get_handle(NULL, ecdt_ptr->id,
+ &boot_ec->handle))) {
+ pr_info("Failed to locate handle for boot EC\n");
+ boot_ec->handle = ACPI_ROOT_OBJECT;
+ }
} else {
/* This workaround is needed only on some broken machines,
* which require early EC, but fail to provide ECDT */
diff --git a/drivers/acpi/executer/exregion.c b/drivers/acpi/executer/exregion.c
index 2e9ce94798c..3f51b7e84a1 100644
--- a/drivers/acpi/executer/exregion.c
+++ b/drivers/acpi/executer/exregion.c
@@ -338,6 +338,7 @@ acpi_ex_pci_config_space_handler(u32 function,
acpi_status status = AE_OK;
struct acpi_pci_id *pci_id;
u16 pci_register;
+ u32 value32;
ACPI_FUNCTION_TRACE(ex_pci_config_space_handler);
@@ -364,9 +365,9 @@ acpi_ex_pci_config_space_handler(u32 function,
switch (function) {
case ACPI_READ:
- *value = 0;
status = acpi_os_read_pci_configuration(pci_id, pci_register,
- value, bit_width);
+ &value32, bit_width);
+ *value = value32;
break;
case ACPI_WRITE:
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index 48cb705b274..c8e3cba423e 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -256,22 +256,28 @@ static int acpi_fan_add(struct acpi_device *device)
cdev = thermal_cooling_device_register("Fan", device,
&fan_cooling_ops);
- if (cdev)
+ if (IS_ERR(cdev)) {
+ result = PTR_ERR(cdev);
+ goto end;
+ }
+ if (cdev) {
printk(KERN_INFO PREFIX
"%s is registered as cooling_device%d\n",
device->dev.bus_id, cdev->id);
- else
- goto end;
- acpi_driver_data(device) = cdev;
- result = sysfs_create_link(&device->dev.kobj, &cdev->device.kobj,
- "thermal_cooling");
- if (result)
- return result;
- result = sysfs_create_link(&cdev->device.kobj, &device->dev.kobj,
- "device");
- if (result)
- return result;
+ acpi_driver_data(device) = cdev;
+ result = sysfs_create_link(&device->dev.kobj,
+ &cdev->device.kobj,
+ "thermal_cooling");
+ if (result)
+ return result;
+
+ result = sysfs_create_link(&cdev->device.kobj,
+ &device->dev.kobj,
+ "device");
+ if (result)
+ return result;
+ }
result = acpi_fan_add_fs(device);
if (result)
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index 75ccf5d18bf..a3cc8a98255 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -670,21 +670,26 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device)
pr->cdev = thermal_cooling_device_register("Processor", device,
&processor_cooling_ops);
- if (pr->cdev)
+ if (IS_ERR(pr->cdev)) {
+ result = PTR_ERR(pr->cdev);
+ goto end;
+ }
+ if (pr->cdev) {
printk(KERN_INFO PREFIX
"%s is registered as cooling_device%d\n",
device->dev.bus_id, pr->cdev->id);
- else
- goto end;
- result = sysfs_create_link(&device->dev.kobj, &pr->cdev->device.kobj,
- "thermal_cooling");
- if (result)
- return result;
- result = sysfs_create_link(&pr->cdev->device.kobj, &device->dev.kobj,
- "device");
- if (result)
- return result;
+ result = sysfs_create_link(&device->dev.kobj,
+ &pr->cdev->device.kobj,
+ "thermal_cooling");
+ if (result)
+ return result;
+ result = sysfs_create_link(&pr->cdev->device.kobj,
+ &device->dev.kobj,
+ "device");
+ if (result)
+ return result;
+ }
if (pr->flags.throttling) {
printk(KERN_INFO PREFIX "%s [%s] (supports",
@@ -809,10 +814,12 @@ static int acpi_processor_remove(struct acpi_device *device, int type)
acpi_processor_remove_fs(device);
- sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
- sysfs_remove_link(&pr->cdev->device.kobj, "device");
- thermal_cooling_device_unregister(pr->cdev);
- pr->cdev = NULL;
+ if (pr->cdev) {
+ sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
+ sysfs_remove_link(&pr->cdev->device.kobj, "device");
+ thermal_cooling_device_unregister(pr->cdev);
+ pr->cdev = NULL;
+ }
processors[pr->id] = NULL;
@@ -826,8 +833,6 @@ static int acpi_processor_remove(struct acpi_device *device, int type)
* Acpi processor hotplug support *
****************************************************************************/
-static int is_processor_present(acpi_handle handle);
-
static int is_processor_present(acpi_handle handle)
{
acpi_status status;
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 980e1c33e6c..6f3b217699e 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -364,7 +364,7 @@ int acpi_processor_resume(struct acpi_device * device)
return 0;
}
-#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
+#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86)
static int tsc_halts_in_c(int state)
{
switch (boot_cpu_data.x86_vendor) {
@@ -544,7 +544,7 @@ static void acpi_processor_idle(void)
/* Get end time (ticks) */
t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
-#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
+#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86)
/* TSC halts in C2, so notify users */
if (tsc_halts_in_c(ACPI_STATE_C2))
mark_tsc_unstable("possible TSC halt in C2");
@@ -609,7 +609,7 @@ static void acpi_processor_idle(void)
acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0);
}
-#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
+#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86)
/* TSC halts in C3, so notify users */
if (tsc_halts_in_c(ACPI_STATE_C3))
mark_tsc_unstable("TSC halts in C3");
@@ -1500,7 +1500,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
acpi_idle_do_entry(cx);
t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
-#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
+#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86)
/* TSC could halt in idle, so notify users */
if (tsc_halts_in_c(cx->type))
mark_tsc_unstable("TSC halts in idle");;
@@ -1614,7 +1614,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
spin_unlock(&c3_lock);
}
-#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
+#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86)
/* TSC could halt in idle, so notify users */
if (tsc_halts_in_c(ACPI_STATE_C3))
mark_tsc_unstable("TSC halts in idle");
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
index 34f15757108..eba55b7d6c9 100644
--- a/drivers/acpi/utils.c
+++ b/drivers/acpi/utils.c
@@ -36,16 +36,20 @@ ACPI_MODULE_NAME("utils");
/* --------------------------------------------------------------------------
Object Evaluation Helpers
-------------------------------------------------------------------------- */
+static void
+acpi_util_eval_error(acpi_handle h, acpi_string p, acpi_status s)
+{
#ifdef ACPI_DEBUG_OUTPUT
-#define acpi_util_eval_error(h,p,s) {\
- char prefix[80] = {'\0'};\
- struct acpi_buffer buffer = {sizeof(prefix), prefix};\
- acpi_get_name(h, ACPI_FULL_PATHNAME, &buffer);\
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluate [%s.%s]: %s\n",\
- (char *) prefix, p, acpi_format_exception(s))); }
+ char prefix[80] = {'\0'};
+ struct acpi_buffer buffer = {sizeof(prefix), prefix};
+ acpi_get_name(h, ACPI_FULL_PATHNAME, &buffer);
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluate [%s.%s]: %s\n",
+ (char *) prefix, p, acpi_format_exception(s)));
#else
-#define acpi_util_eval_error(h,p,s)
+ return;
#endif
+}
+
acpi_status
acpi_extract_package(union acpi_object *package,
struct acpi_buffer *format, struct acpi_buffer *buffer)
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index 7f714fa2a45..12cce69b544 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -731,6 +731,9 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
device->cdev = thermal_cooling_device_register("LCD",
device->dev, &video_cooling_ops);
+ if (IS_ERR(device->cdev))
+ return;
+
if (device->cdev) {
printk(KERN_INFO PREFIX
"%s is registered as cooling_device%d\n",
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 29e71bddd6f..1db93b61907 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -85,6 +85,7 @@ enum {
board_ahci_ign_iferr = 2,
board_ahci_sb600 = 3,
board_ahci_mv = 4,
+ board_ahci_sb700 = 5,
/* global controller registers */
HOST_CAP = 0x00, /* host capabilities */
@@ -442,6 +443,16 @@ static const struct ata_port_info ahci_port_info[] = {
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops,
},
+ /* board_ahci_sb700 */
+ {
+ AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL |
+ AHCI_HFLAG_NO_PMP),
+ .flags = AHCI_FLAG_COMMON,
+ .link_flags = AHCI_LFLAG_COMMON,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &ahci_ops,
+ },
};
static const struct pci_device_id ahci_pci_tbl[] = {
@@ -484,12 +495,12 @@ static const struct pci_device_id ahci_pci_tbl[] = {
/* ATI */
{ PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */
- { PCI_VDEVICE(ATI, 0x4390), board_ahci_sb600 }, /* ATI SB700/800 */
- { PCI_VDEVICE(ATI, 0x4391), board_ahci_sb600 }, /* ATI SB700/800 */
- { PCI_VDEVICE(ATI, 0x4392), board_ahci_sb600 }, /* ATI SB700/800 */
- { PCI_VDEVICE(ATI, 0x4393), board_ahci_sb600 }, /* ATI SB700/800 */
- { PCI_VDEVICE(ATI, 0x4394), board_ahci_sb600 }, /* ATI SB700/800 */
- { PCI_VDEVICE(ATI, 0x4395), board_ahci_sb600 }, /* ATI SB700/800 */
+ { PCI_VDEVICE(ATI, 0x4390), board_ahci_sb700 }, /* ATI SB700/800 */
+ { PCI_VDEVICE(ATI, 0x4391), board_ahci_sb700 }, /* ATI SB700/800 */
+ { PCI_VDEVICE(ATI, 0x4392), board_ahci_sb700 }, /* ATI SB700/800 */
+ { PCI_VDEVICE(ATI, 0x4393), board_ahci_sb700 }, /* ATI SB700/800 */
+ { PCI_VDEVICE(ATI, 0x4394), board_ahci_sb700 }, /* ATI SB700/800 */
+ { PCI_VDEVICE(ATI, 0x4395), board_ahci_sb700 }, /* ATI SB700/800 */
/* VIA */
{ PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
@@ -1932,7 +1943,7 @@ static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
u32 ctl;
- if (mesg.event == PM_EVENT_SUSPEND) {
+ if (mesg.event & PM_EVENT_SLEEP) {
/* AHCI spec rev1.1 section 8.3.3:
* Software must disable interrupts prior to requesting a
* transition of the HBA to D3 state.
@@ -1975,16 +1986,11 @@ static int ahci_port_start(struct ata_port *ap)
struct ahci_port_priv *pp;
void *mem;
dma_addr_t mem_dma;
- int rc;
pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
if (!pp)
return -ENOMEM;
- rc = ata_pad_alloc(ap, dev);
- if (rc)
- return rc;
-
mem = dmam_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma,
GFP_KERNEL);
if (!mem)
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index 9c2515f67de..fae8404254c 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -1339,7 +1339,7 @@ static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
* cycles and power trying to do something to the sleeping
* beauty.
*/
- if (piix_broken_suspend() && mesg.event == PM_EVENT_SUSPEND) {
+ if (piix_broken_suspend() && (mesg.event & PM_EVENT_SLEEP)) {
pci_save_state(pdev);
/* mark its power state as "unknown", since we don't
@@ -1652,7 +1652,7 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
u8 tmp;
pci_read_config_byte(pdev, PIIX_SCC, &tmp);
if (tmp == PIIX_AHCI_DEVICE) {
- int rc = piix_disable_ahci(pdev);
+ rc = piix_disable_ahci(pdev);
if (rc)
return rc;
}
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 004dae4ea5b..4fbcce758b0 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -87,11 +87,33 @@ static struct workqueue_struct *ata_wq;
struct workqueue_struct *ata_aux_wq;
+struct ata_force_param {
+ const char *name;
+ unsigned int cbl;
+ int spd_limit;
+ unsigned long xfer_mask;
+ unsigned int horkage_on;
+ unsigned int horkage_off;
+};
+
+struct ata_force_ent {
+ int port;
+ int device;
+ struct ata_force_param param;
+};
+
+static struct ata_force_ent *ata_force_tbl;
+static int ata_force_tbl_size;
+
+static char ata_force_param_buf[PAGE_SIZE] __initdata;
+module_param_string(force, ata_force_param_buf, sizeof(ata_force_param_buf), 0444);
+MODULE_PARM_DESC(force, "Force ATA configurations including cable type, link speed and transfer mode (see Documentation/kernel-parameters.txt for details)");
+
int atapi_enabled = 1;
module_param(atapi_enabled, int, 0444);
MODULE_PARM_DESC(atapi_enabled, "Enable discovery of ATAPI devices (0=off, 1=on)");
-int atapi_dmadir = 0;
+static int atapi_dmadir = 0;
module_param(atapi_dmadir, int, 0444);
MODULE_PARM_DESC(atapi_dmadir, "Enable ATAPI DMADIR bridge support (0=off, 1=on)");
@@ -130,6 +152,179 @@ MODULE_VERSION(DRV_VERSION);
/**
+ * ata_force_cbl - force cable type according to libata.force
+ * @ap: ATA port of interest
+ *
+ * Force cable type according to libata.force and whine about it.
+ * The last entry which has matching port number is used, so it
+ * can be specified as part of device force parameters. For
+ * example, both "a:40c,1.00:udma4" and "1.00:40c,udma4" have the
+ * same effect.
+ *
+ * LOCKING:
+ * EH context.
+ */
+void ata_force_cbl(struct ata_port *ap)
+{
+ int i;
+
+ for (i = ata_force_tbl_size - 1; i >= 0; i--) {
+ const struct ata_force_ent *fe = &ata_force_tbl[i];
+
+ if (fe->port != -1 && fe->port != ap->print_id)
+ continue;
+
+ if (fe->param.cbl == ATA_CBL_NONE)
+ continue;
+
+ ap->cbl = fe->param.cbl;
+ ata_port_printk(ap, KERN_NOTICE,
+ "FORCE: cable set to %s\n", fe->param.name);
+ return;
+ }
+}
+
+/**
+ * ata_force_spd_limit - force SATA spd limit according to libata.force
+ * @link: ATA link of interest
+ *
+ * Force SATA spd limit according to libata.force and whine about
+ * it. When only the port part is specified (e.g. 1:), the limit
+ * applies to all links connected to both 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.
+ *
+ * LOCKING:
+ * EH context.
+ */
+static void ata_force_spd_limit(struct ata_link *link)
+{
+ int linkno, i;
+
+ if (ata_is_host_link(link))
+ linkno = 15;
+ else
+ linkno = link->pmp;
+
+ for (i = ata_force_tbl_size - 1; i >= 0; i--) {
+ const struct ata_force_ent *fe = &ata_force_tbl[i];
+
+ if (fe->port != -1 && fe->port != link->ap->print_id)
+ continue;
+
+ if (fe->device != -1 && fe->device != linkno)
+ continue;
+
+ if (!fe->param.spd_limit)
+ continue;
+
+ link->hw_sata_spd_limit = (1 << fe->param.spd_limit) - 1;
+ ata_link_printk(link, KERN_NOTICE,
+ "FORCE: PHY spd limit set to %s\n", fe->param.name);
+ return;
+ }
+}
+
+/**
+ * ata_force_xfermask - force xfermask according to libata.force
+ * @dev: ATA device of interest
+ *
+ * Force xfer_mask according to libata.force and whine about it.
+ * For consistency with link selection, device number 15 selects
+ * the first device connected to the host link.
+ *
+ * LOCKING:
+ * EH context.
+ */
+static void ata_force_xfermask(struct ata_device *dev)
+{
+ int devno = dev->link->pmp + dev->devno;
+ 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;
+
+ for (i = ata_force_tbl_size - 1; i >= 0; i--) {
+ const struct ata_force_ent *fe = &ata_force_tbl[i];
+ unsigned long pio_mask, mwdma_mask, udma_mask;
+
+ if (fe->port != -1 && fe->port != dev->link->ap->print_id)
+ continue;
+
+ if (fe->device != -1 && fe->device != devno &&
+ fe->device != alt_devno)
+ continue;
+
+ if (!fe->param.xfer_mask)
+ continue;
+
+ ata_unpack_xfermask(fe->param.xfer_mask,
+ &pio_mask, &mwdma_mask, &udma_mask);
+ if (udma_mask)
+ dev->udma_mask = udma_mask;
+ else if (mwdma_mask) {
+ dev->udma_mask = 0;
+ dev->mwdma_mask = mwdma_mask;
+ } else {
+ dev->udma_mask = 0;
+ dev->mwdma_mask = 0;
+ dev->pio_mask = pio_mask;
+ }
+
+ ata_dev_printk(dev, KERN_NOTICE,
+ "FORCE: xfer_mask set to %s\n", fe->param.name);
+ return;
+ }
+}
+
+/**
+ * ata_force_horkage - force horkage according to libata.force
+ * @dev: ATA device of interest
+ *
+ * Force horkage according to libata.force and whine about it.
+ * For consistency with link selection, device number 15 selects
+ * the first device connected to the host link.
+ *
+ * LOCKING:
+ * EH context.
+ */
+static void ata_force_horkage(struct ata_device *dev)
+{
+ int devno = dev->link->pmp + dev->devno;
+ 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;
+
+ for (i = 0; i < ata_force_tbl_size; i++) {
+ const struct ata_force_ent *fe = &ata_force_tbl[i];
+
+ if (fe->port != -1 && fe->port != dev->link->ap->print_id)
+ continue;
+
+ if (fe->device != -1 && fe->device != devno &&
+ fe->device != alt_devno)
+ continue;
+
+ if (!(~dev->horkage & fe->param.horkage_on) &&
+ !(dev->horkage & fe->param.horkage_off))
+ continue;
+
+ dev->horkage |= fe->param.horkage_on;
+ dev->horkage &= ~fe->param.horkage_off;
+
+ ata_dev_printk(dev, KERN_NOTICE,
+ "FORCE: horkage modified (%s)\n", fe->param.name);
+ }
+}
+
+/**
* ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure
* @tf: Taskfile to convert
* @pmp: Port multiplier port
@@ -2067,6 +2262,7 @@ int ata_dev_configure(struct ata_device *dev)
/* set horkage */
dev->horkage |= ata_dev_blacklisted(dev);
+ ata_force_horkage(dev);
/* let ACPI work its magic */
rc = ata_acpi_on_devcfg(dev);
@@ -2200,6 +2396,7 @@ int ata_dev_configure(struct ata_device *dev)
else if (dev->class == ATA_DEV_ATAPI) {
const char *cdb_intr_string = "";
const char *atapi_an_string = "";
+ const char *dma_dir_string = "";
u32 sntf;
rc = atapi_cdb_len(id);
@@ -2240,13 +2437,19 @@ int ata_dev_configure(struct ata_device *dev)
cdb_intr_string = ", CDB intr";
}
+ if (atapi_dmadir || atapi_id_dmadir(dev->id)) {
+ dev->flags |= ATA_DFLAG_DMADIR;
+ dma_dir_string = ", DMADIR";
+ }
+
/* print device info to dmesg */
if (ata_msg_drv(ap) && print_info)
ata_dev_printk(dev, KERN_INFO,
- "ATAPI: %s, %s, max %s%s%s\n",
+ "ATAPI: %s, %s, max %s%s%s%s\n",
modelbuf, fwrevbuf,
ata_mode_string(xfer_mask),
- cdb_intr_string, atapi_an_string);
+ cdb_intr_string, atapi_an_string,
+ dma_dir_string);
}
/* determine max_sectors */
@@ -3150,6 +3353,7 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
mode_mask = ATA_DMA_MASK_CFA;
ata_dev_xfermask(dev);
+ ata_force_xfermask(dev);
pio_mask = ata_pack_xfermask(dev->pio_mask, 0, 0);
dma_mask = ata_pack_xfermask(0, dev->mwdma_mask, dev->udma_mask);
@@ -4190,6 +4394,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
/* Devices which report 1 sector over size HPA */
{ "ST340823A", NULL, ATA_HORKAGE_HPA_SIZE, },
{ "ST320413A", NULL, ATA_HORKAGE_HPA_SIZE, },
+ { "ST310211A", NULL, ATA_HORKAGE_HPA_SIZE, },
/* Devices which get the IVB wrong */
{ "QUANTUM FIREBALLlct10 05", "A03.0900", ATA_HORKAGE_IVB, },
@@ -4492,30 +4697,13 @@ void ata_sg_clean(struct ata_queued_cmd *qc)
struct ata_port *ap = qc->ap;
struct scatterlist *sg = qc->sg;
int dir = qc->dma_dir;
- void *pad_buf = NULL;
WARN_ON(sg == NULL);
- VPRINTK("unmapping %u sg elements\n", qc->mapped_n_elem);
-
- /* if we padded the buffer out to 32-bit bound, and data
- * xfer direction is from-device, we must copy from the
- * pad buffer back into the supplied buffer
- */
- if (qc->pad_len && !(qc->tf.flags & ATA_TFLAG_WRITE))
- pad_buf = ap->pad + (qc->tag * ATA_DMA_PAD_SZ);
+ VPRINTK("unmapping %u sg elements\n", qc->n_elem);
- if (qc->mapped_n_elem)
- dma_unmap_sg(ap->dev, sg, qc->mapped_n_elem, dir);
- /* restore last sg */
- if (qc->last_sg)
- *qc->last_sg = qc->saved_last_sg;
- if (pad_buf) {
- struct scatterlist *psg = &qc->extra_sg[1];
- void *addr = kmap_atomic(sg_page(psg), KM_IRQ0);
- memcpy(addr + psg->offset, pad_buf, qc->pad_len);
- kunmap_atomic(addr, KM_IRQ0);
- }
+ if (qc->n_elem)
+ dma_unmap_sg(ap->dev, sg, qc->n_elem, dir);
qc->flags &= ~ATA_QCFLAG_DMAMAP;
qc->sg = NULL;
@@ -4658,43 +4846,6 @@ int ata_check_atapi_dma(struct ata_queued_cmd *qc)
}
/**
- * atapi_qc_may_overflow - Check whether data transfer may overflow
- * @qc: ATA command in question
- *
- * ATAPI commands which transfer variable length data to host
- * might overflow due to application error or hardare bug. This
- * function checks whether overflow should be drained and ignored
- * for @qc.
- *
- * LOCKING:
- * None.
- *
- * RETURNS:
- * 1 if @qc may overflow; otherwise, 0.
- */
-static int atapi_qc_may_overflow(struct ata_queued_cmd *qc)
-{
- if (qc->tf.protocol != ATAPI_PROT_PIO &&
- qc->tf.protocol != ATAPI_PROT_DMA)
- return 0;
-
- if (qc->tf.flags & ATA_TFLAG_WRITE)
- return 0;
-
- switch (qc->cdb[0]) {
- case READ_10:
- case READ_12:
- case WRITE_10:
- case WRITE_12:
- case GPCMD_READ_CD:
- case GPCMD_READ_CD_MSF:
- return 0;
- }
-
- return 1;
-}
-
-/**
* ata_std_qc_defer - Check whether a qc needs to be deferred
* @qc: ATA command in question
*
@@ -4781,97 +4932,6 @@ void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg,
qc->cursg = qc->sg;
}
-static unsigned int ata_sg_setup_extra(struct ata_queued_cmd *qc,
- unsigned int *n_elem_extra,
- unsigned int *nbytes_extra)
-{
- struct ata_port *ap = qc->ap;
- unsigned int n_elem = qc->n_elem;
- struct scatterlist *lsg, *copy_lsg = NULL, *tsg = NULL, *esg = NULL;
-
- *n_elem_extra = 0;
- *nbytes_extra = 0;
-
- /* needs padding? */
- qc->pad_len = qc->nbytes & 3;
-
- if (likely(!qc->pad_len))
- return n_elem;
-
- /* locate last sg and save it */
- lsg = sg_last(qc->sg, n_elem);
- qc->last_sg = lsg;
- qc->saved_last_sg = *lsg;
-
- sg_init_table(qc->extra_sg, ARRAY_SIZE(qc->extra_sg));
-
- if (qc->pad_len) {
- struct scatterlist *psg = &qc->extra_sg[1];
- void *pad_buf = ap->pad + (qc->tag * ATA_DMA_PAD_SZ);
- unsigned int offset;
-
- WARN_ON(qc->dev->class != ATA_DEV_ATAPI);
-
- memset(pad_buf, 0, ATA_DMA_PAD_SZ);
-
- /* psg->page/offset are used to copy to-be-written
- * data in this function or read data in ata_sg_clean.
- */
- offset = lsg->offset + lsg->length - qc->pad_len;
- sg_set_page(psg, nth_page(sg_page(lsg), offset >> PAGE_SHIFT),
- qc->pad_len, offset_in_page(offset));
-
- if (qc->tf.flags & ATA_TFLAG_WRITE) {
- void *addr = kmap_atomic(sg_page(psg), KM_IRQ0);
- memcpy(pad_buf, addr + psg->offset, qc->pad_len);
- kunmap_atomic(addr, KM_IRQ0);
- }
-
- sg_dma_address(psg) = ap->pad_dma + (qc->tag * ATA_DMA_PAD_SZ);
- sg_dma_len(psg) = ATA_DMA_PAD_SZ;
-
- /* Trim the last sg entry and chain the original and
- * padding sg lists.
- *
- * Because chaining consumes one sg entry, one extra
- * sg entry is allocated and the last sg entry is
- * copied to it if the length isn't zero after padded
- * amount is removed.
- *
- * If the last sg entry is completely replaced by
- * padding sg entry, the first sg entry is skipped
- * while chaining.
- */
- lsg->length -= qc->pad_len;
- if (lsg->length) {
- copy_lsg = &qc->extra_sg[0];
- tsg = &qc->extra_sg[0];
- } else {
- n_elem--;
- tsg = &qc->extra_sg[1];
- }
-
- esg = &qc->extra_sg[1];
-
- (*n_elem_extra)++;
- (*nbytes_extra) += 4 - qc->pad_len;
- }
-
- if (copy_lsg)
- sg_set_page(copy_lsg, sg_page(lsg), lsg->length, lsg->offset);
-
- sg_chain(lsg, 1, tsg);
- sg_mark_end(esg);
-
- /* sglist can't start with chaining sg entry, fast forward */
- if (qc->sg == lsg) {
- qc->sg = tsg;
- qc->cursg = tsg;
- }
-
- return n_elem;
-}
-
/**
* ata_sg_setup - DMA-map the scatter-gather table associated with a command.
* @qc: Command with scatter-gather table to be mapped.
@@ -4888,26 +4948,17 @@ static unsigned int ata_sg_setup_extra(struct ata_queued_cmd *qc,
static int ata_sg_setup(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
- unsigned int n_elem, n_elem_extra, nbytes_extra;
+ unsigned int n_elem;
VPRINTK("ENTER, ata%u\n", ap->print_id);
- n_elem = ata_sg_setup_extra(qc, &n_elem_extra, &nbytes_extra);
+ n_elem = dma_map_sg(ap->dev, qc->sg, qc->n_elem, qc->dma_dir);
+ if (n_elem < 1)
+ return -1;
- if (n_elem) {
- n_elem = dma_map_sg(ap->dev, qc->sg, n_elem, qc->dma_dir);
- if (n_elem < 1) {
- /* restore last sg */
- if (qc->last_sg)
- *qc->last_sg = qc->saved_last_sg;
- return -1;
- }
- DPRINTK("%d sg elements mapped\n", n_elem);
- }
+ DPRINTK("%d sg elements mapped\n", n_elem);
- qc->n_elem = qc->mapped_n_elem = n_elem;
- qc->n_elem += n_elem_extra;
- qc->nbytes += nbytes_extra;
+ qc->n_elem = n_elem;
qc->flags |= ATA_QCFLAG_DMAMAP;
return 0;
@@ -5145,46 +5196,22 @@ static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc)
*/
static int __atapi_pio_bytes(struct ata_queued_cmd *qc, unsigned int bytes)
{
- int do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
+ int rw = (qc->tf.flags & ATA_TFLAG_WRITE) ? WRITE : READ;
struct ata_port *ap = qc->ap;
- struct ata_eh_info *ehi = &qc->dev->link->eh_info;
+ struct ata_device *dev = qc->dev;
+ struct ata_eh_info *ehi = &dev->link->eh_info;
struct scatterlist *sg;
struct page *page;
unsigned char *buf;
- unsigned int offset, count;
+ unsigned int offset, count, consumed;
next_sg:
sg = qc->cursg;
if (unlikely(!sg)) {
- /*
- * The end of qc->sg is reached and the device expects
- * more data to transfer. In order not to overrun qc->sg
- * and fulfill length specified in the byte count register,
- * - for read case, discard trailing data from the device
- * - for write case, padding zero data to the device
- */
- u16 pad_buf[1] = { 0 };
- unsigned int i;
-
- if (bytes > qc->curbytes - qc->nbytes + ATAPI_MAX_DRAIN) {
- ata_ehi_push_desc(ehi, "too much trailing data "
- "buf=%u cur=%u bytes=%u",
- qc->nbytes, qc->curbytes, bytes);
- return -1;
- }
-
- /* overflow is exptected for misc ATAPI commands */
- if (bytes && !atapi_qc_may_overflow(qc))
- ata_dev_printk(qc->dev, KERN_WARNING, "ATAPI %u bytes "
- "trailing data (cdb=%02x nbytes=%u)\n",
- bytes, qc->cdb[0], qc->nbytes);
-
- for (i = 0; i < (bytes + 1) / 2; i++)
- ap->ops->data_xfer(qc->dev, (unsigned char *)pad_buf, 2, do_write);
-
- qc->curbytes += bytes;
-
- return 0;
+ ata_ehi_push_desc(ehi, "unexpected or too much trailing data "
+ "buf=%u cur=%u bytes=%u",
+ qc->nbytes, qc->curbytes, bytes);
+ return -1;
}
page = sg_page(sg);
@@ -5210,18 +5237,16 @@ next_sg:
buf = kmap_atomic(page, KM_IRQ0);
/* do the actual data transfer */
- ap->ops->data_xfer(qc->dev, buf + offset, count, do_write);
+ consumed = ap->ops->data_xfer(dev, buf + offset, count, rw);
kunmap_atomic(buf, KM_IRQ0);
local_irq_restore(flags);
} else {
buf = page_address(page);
- ap->ops->data_xfer(qc->dev, buf + offset, count, do_write);
+ consumed = ap->ops->data_xfer(dev, buf + offset, count, rw);
}
- bytes -= count;
- if ((count & 1) && bytes)
- bytes--;
+ bytes -= min(bytes, consumed);
qc->curbytes += count;
qc->cursg_ofs += count;
@@ -5230,9 +5255,11 @@ next_sg:
qc->cursg_ofs = 0;
}
+ /* consumed can be larger than count only for the last transfer */
+ WARN_ON(qc->cursg && count != consumed);
+
if (bytes)
goto next_sg;
-
return 0;
}
@@ -5250,6 +5277,7 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
struct ata_device *dev = qc->dev;
+ struct ata_eh_info *ehi = &dev->link->eh_info;
unsigned int ireason, bc_lo, bc_hi, bytes;
int i_write, do_write = (qc->tf.flags & ATA_TFLAG_WRITE) ? 1 : 0;
@@ -5267,26 +5295,28 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc)
/* shall be cleared to zero, indicating xfer of data */
if (unlikely(ireason & (1 << 0)))
- goto err_out;
+ goto atapi_check;
/* make sure transfer direction matches expected */
i_write = ((ireason & (1 << 1)) == 0) ? 1 : 0;
if (unlikely(do_write != i_write))
- goto err_out;
+ goto atapi_check;
if (unlikely(!bytes))
- goto err_out;
+ goto atapi_check;
VPRINTK("ata%u: xfering %d bytes\n", ap->print_id, bytes);
- if (__atapi_pio_bytes(qc, bytes))
+ if (unlikely(__atapi_pio_bytes(qc, bytes)))
goto err_out;
ata_altstatus(ap); /* flush */
return;
-err_out:
- ata_dev_printk(dev, KERN_INFO, "ATAPI check failed\n");
+ atapi_check:
+ ata_ehi_push_desc(ehi, "ATAPI check failed (ireason=0x%x bytes=%u)",
+ ireason, bytes);
+ err_out:
qc->err_mask |= AC_ERR_HSM;
ap->hsm_task_state = HSM_ST_ERR;
}
@@ -5971,9 +6001,6 @@ void ata_qc_issue(struct ata_queued_cmd *qc)
*/
BUG_ON(ata_is_data(prot) && (!qc->sg || !qc->n_elem || !qc->nbytes));
- /* ata_sg_setup() may update nbytes */
- qc->raw_nbytes = qc->nbytes;
-
if (ata_is_dma(prot) || (ata_is_pio(prot) &&
(ap->flags & ATA_FLAG_PIO_DMA)))
if (ata_sg_setup(qc))
@@ -6582,19 +6609,12 @@ void ata_host_resume(struct ata_host *host)
int ata_port_start(struct ata_port *ap)
{
struct device *dev = ap->dev;
- int rc;
ap->prd = dmam_alloc_coherent(dev, ATA_PRD_TBL_SZ, &ap->prd_dma,
GFP_KERNEL);
if (!ap->prd)
return -ENOMEM;
- rc = ata_pad_alloc(ap, dev);
- if (rc)
- return rc;
-
- DPRINTK("prd alloc, virt %p, dma %llx\n", ap->prd,
- (unsigned long long)ap->prd_dma);
return 0;
}
@@ -6681,7 +6701,8 @@ void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp)
*/
int sata_link_init_spd(struct ata_link *link)
{
- u32 scontrol, spd;
+ u32 scontrol;
+ u8 spd;
int rc;
rc = sata_scr_read(link, SCR_CONTROL, &scontrol);
@@ -6692,6 +6713,8 @@ int sata_link_init_spd(struct ata_link *link)
if (spd)
link->hw_sata_spd_limit &= (1 << spd) - 1;
+ ata_force_spd_limit(link);
+
link->sata_spd_limit = link->hw_sata_spd_limit;
return 0;
@@ -7086,7 +7109,6 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
DPRINTK("probe begin\n");
for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap = host->ports[i];
- int rc;
/* probe */
if (ap->ops->error_handler) {
@@ -7353,7 +7375,7 @@ void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t mesg)
pci_save_state(pdev);
pci_disable_device(pdev);
- if (mesg.event == PM_EVENT_SUSPEND)
+ if (mesg.event & PM_EVENT_SLEEP)
pci_set_power_state(pdev, PCI_D3hot);
}
@@ -7403,10 +7425,187 @@ int ata_pci_device_resume(struct pci_dev *pdev)
#endif /* CONFIG_PCI */
+static int __init ata_parse_force_one(char **cur,
+ struct ata_force_ent *force_ent,
+ const char **reason)
+{
+ /* FIXME: Currently, there's no way to tag init const data and
+ * using __initdata causes build failure on some versions of
+ * gcc. Once __initdataconst is implemented, add const to the
+ * following structure.
+ */
+ static struct ata_force_param force_tbl[] __initdata = {
+ { "40c", .cbl = ATA_CBL_PATA40 },
+ { "80c", .cbl = ATA_CBL_PATA80 },
+ { "short40c", .cbl = ATA_CBL_PATA40_SHORT },
+ { "unk", .cbl = ATA_CBL_PATA_UNK },
+ { "ign", .cbl = ATA_CBL_PATA_IGN },
+ { "sata", .cbl = ATA_CBL_SATA },
+ { "1.5Gbps", .spd_limit = 1 },
+ { "3.0Gbps", .spd_limit = 2 },
+ { "noncq", .horkage_on = ATA_HORKAGE_NONCQ },
+ { "ncq", .horkage_off = ATA_HORKAGE_NONCQ },
+ { "pio0", .xfer_mask = 1 << (ATA_SHIFT_PIO + 0) },
+ { "pio1", .xfer_mask = 1 << (ATA_SHIFT_PIO + 1) },
+ { "pio2", .xfer_mask = 1 << (ATA_SHIFT_PIO + 2) },
+ { "pio3", .xfer_mask = 1 << (ATA_SHIFT_PIO + 3) },
+ { "pio4", .xfer_mask = 1 << (ATA_SHIFT_PIO + 4) },
+ { "pio5", .xfer_mask = 1 << (ATA_SHIFT_PIO + 5) },
+ { "pio6", .xfer_mask = 1 << (ATA_SHIFT_PIO + 6) },
+ { "mwdma0", .xfer_mask = 1 << (ATA_SHIFT_MWDMA + 0) },
+ { "mwdma1", .xfer_mask = 1 << (ATA_SHIFT_MWDMA + 1) },
+ { "mwdma2", .xfer_mask = 1 << (ATA_SHIFT_MWDMA + 2) },
+ { "mwdma3", .xfer_mask = 1 << (ATA_SHIFT_MWDMA + 3) },
+ { "mwdma4", .xfer_mask = 1 << (ATA_SHIFT_MWDMA + 4) },
+ { "udma0", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 0) },
+ { "udma16", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 0) },
+ { "udma/16", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 0) },
+ { "udma1", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 1) },
+ { "udma25", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 1) },
+ { "udma/25", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 1) },
+ { "udma2", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 2) },
+ { "udma33", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 2) },
+ { "udma/33", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 2) },
+ { "udma3", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 3) },
+ { "udma44", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 3) },
+ { "udma/44", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 3) },
+ { "udma4", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 4) },
+ { "udma66", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 4) },
+ { "udma/66", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 4) },
+ { "udma5", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 5) },
+ { "udma100", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 5) },
+ { "udma/100", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 5) },
+ { "udma6", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 6) },
+ { "udma133", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 6) },
+ { "udma/133", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 6) },
+ { "udma7", .xfer_mask = 1 << (ATA_SHIFT_UDMA + 7) },
+ };
+ char *start = *cur, *p = *cur;
+ char *id, *val, *endp;
+ const struct ata_force_param *match_fp = NULL;
+ int nr_matches = 0, i;
+
+ /* find where this param ends and update *cur */
+ while (*p != '\0' && *p != ',')
+ p++;
+
+ if (*p == '\0')
+ *cur = p;
+ else
+ *cur = p + 1;
+
+ *p = '\0';
+
+ /* parse */
+ p = strchr(start, ':');
+ if (!p) {
+ val = strstrip(start);
+ goto parse_val;
+ }
+ *p = '\0';
+
+ id = strstrip(start);
+ val = strstrip(p + 1);
+
+ /* parse id */
+ p = strchr(id, '.');
+ if (p) {
+ *p++ = '\0';
+ force_ent->device = simple_strtoul(p, &endp, 10);
+ if (p == endp || *endp != '\0') {
+ *reason = "invalid device";
+ return -EINVAL;
+ }
+ }
+
+ force_ent->port = simple_strtoul(id, &endp, 10);
+ if (p == endp || *endp != '\0') {
+ *reason = "invalid port/link";
+ return -EINVAL;
+ }
+
+ parse_val:
+ /* parse val, allow shortcuts so that both 1.5 and 1.5Gbps work */
+ for (i = 0; i < ARRAY_SIZE(force_tbl); i++) {
+ const struct ata_force_param *fp = &force_tbl[i];
+
+ if (strncasecmp(val, fp->name, strlen(val)))
+ continue;
+
+ nr_matches++;
+ match_fp = fp;
+
+ if (strcasecmp(val, fp->name) == 0) {
+ nr_matches = 1;
+ break;
+ }
+ }
+
+ if (!nr_matches) {
+ *reason = "unknown value";
+ return -EINVAL;
+ }
+ if (nr_matches > 1) {
+ *reason = "ambigious value";
+ return -EINVAL;
+ }
+
+ force_ent->param = *match_fp;
+
+ return 0;
+}
+
+static void __init ata_parse_force_param(void)
+{
+ int idx = 0, size = 1;
+ int last_port = -1, last_device = -1;
+ char *p, *cur, *next;
+
+ /* calculate maximum number of params and allocate force_tbl */
+ for (p = ata_force_param_buf; *p; p++)
+ if (*p == ',')
+ size++;
+
+ ata_force_tbl = kzalloc(sizeof(ata_force_tbl[0]) * size, GFP_KERNEL);
+ if (!ata_force_tbl) {
+ printk(KERN_WARNING "ata: failed to extend force table, "
+ "libata.force ignored\n");
+ return;
+ }
+
+ /* parse and populate the table */
+ for (cur = ata_force_param_buf; *cur != '\0'; cur = next) {
+ const char *reason = "";
+ struct ata_force_ent te = { .port = -1, .device = -1 };
+
+ next = cur;
+ if (ata_parse_force_one(&next, &te, &reason)) {
+ printk(KERN_WARNING "ata: failed to parse force "
+ "parameter \"%s\" (%s)\n",
+ cur, reason);
+ continue;
+ }
+
+ if (te.port == -1) {
+ te.port = last_port;
+ te.device = last_device;
+ }
+
+ ata_force_tbl[idx++] = te;
+
+ last_port = te.port;
+ last_device = te.device;
+ }
+
+ ata_force_tbl_size = idx;
+}
static int __init ata_init(void)
{
ata_probe_timeout *= HZ;
+
+ ata_parse_force_param();
+
ata_wq = create_workqueue("ata");
if (!ata_wq)
return -ENOMEM;
@@ -7423,6 +7622,7 @@ static int __init ata_init(void)
static void __exit ata_exit(void)
{
+ kfree(ata_force_tbl);
destroy_workqueue(ata_wq);
destroy_workqueue(ata_aux_wq);
}
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 4e31071acc0..698ce2cea52 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -2393,9 +2393,11 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link,
}
/* PDIAG- should have been released, ask cable type if post-reset */
- if (ata_is_host_link(link) && ap->ops->cable_detect &&
- (ehc->i.flags & ATA_EHI_DID_RESET))
- ap->cbl = ap->ops->cable_detect(ap);
+ if ((ehc->i.flags & ATA_EHI_DID_RESET) && ata_is_host_link(link)) {
+ if (ap->ops->cable_detect)
+ ap->cbl = ap->ops->cable_detect(ap);
+ ata_force_cbl(ap);
+ }
/* Configure new devices forward such that user doesn't see
* device detection messages backwards.
diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c
index caef2bbd4a8..d91f5090ba9 100644
--- a/drivers/ata/libata-pmp.c
+++ b/drivers/ata/libata-pmp.c
@@ -35,7 +35,7 @@ static unsigned int sata_pmp_read(struct ata_link *link, int reg, u32 *r_val)
ata_tf_init(pmp_dev, &tf);
tf.command = ATA_CMD_PMP_READ;
tf.protocol = ATA_PROT_NODATA;
- tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+ tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48;
tf.feature = reg;
tf.device = link->pmp;
@@ -71,7 +71,7 @@ static unsigned int sata_pmp_write(struct ata_link *link, int reg, u32 val)
ata_tf_init(pmp_dev, &tf);
tf.command = ATA_CMD_PMP_WRITE;
tf.protocol = ATA_PROT_NODATA;
- tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+ tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48;
tf.feature = reg;
tf.device = link->pmp;
tf.nsect = val & 0xff;
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index c02c490122d..7b1f1ee8131 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -826,30 +826,61 @@ static void ata_scsi_sdev_config(struct scsi_device *sdev)
sdev->max_device_blocked = 1;
}
-static void ata_scsi_dev_config(struct scsi_device *sdev,
- struct ata_device *dev)
+/**
+ * atapi_drain_needed - Check whether data transfer may overflow
+ * @rq: request to be checked
+ *
+ * ATAPI commands which transfer variable length data to host
+ * might overflow due to application error or hardare bug. This
+ * function checks whether overflow should be drained and ignored
+ * for @request.
+ *
+ * LOCKING:
+ * None.
+ *
+ * RETURNS:
+ * 1 if ; otherwise, 0.
+ */
+static int atapi_drain_needed(struct request *rq)
+{
+ if (likely(!blk_pc_request(rq)))
+ return 0;
+
+ if (!rq->data_len || (rq->cmd_flags & REQ_RW))
+ return 0;
+
+ return atapi_cmd_type(rq->cmd[0]) == ATAPI_MISC;
+}
+
+static int ata_scsi_dev_config(struct scsi_device *sdev,
+ struct ata_device *dev)
{
/* configure max sectors */
blk_queue_max_sectors(sdev->request_queue, dev->max_sectors);
- /* SATA DMA transfers must be multiples of 4 byte, so
- * we need to pad ATAPI transfers using an extra sg.
- * Decrement max hw segments accordingly.
- */
if (dev->class == ATA_DEV_ATAPI) {
struct request_queue *q = sdev->request_queue;
- blk_queue_max_hw_segments(q, q->max_hw_segments - 1);
+ void *buf;
/* set the min alignment */
blk_queue_update_dma_alignment(sdev->request_queue,
ATA_DMA_PAD_SZ - 1);
- } else
+
+ /* configure draining */
+ buf = kmalloc(ATAPI_MAX_DRAIN, q->bounce_gfp | GFP_KERNEL);
+ if (!buf) {
+ ata_dev_printk(dev, KERN_ERR,
+ "drain buffer allocation failed\n");
+ return -ENOMEM;
+ }
+
+ blk_queue_dma_drain(q, atapi_drain_needed, buf, ATAPI_MAX_DRAIN);
+ } else {
/* ATA devices must be sector aligned */
blk_queue_update_dma_alignment(sdev->request_queue,
ATA_SECT_SIZE - 1);
-
- if (dev->class == ATA_DEV_ATA)
sdev->manage_start_stop = 1;
+ }
if (dev->flags & ATA_DFLAG_AN)
set_bit(SDEV_EVT_MEDIA_CHANGE, sdev->supported_events);
@@ -861,6 +892,8 @@ static void ata_scsi_dev_config(struct scsi_device *sdev,
depth = min(ATA_MAX_QUEUE - 1, depth);
scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, depth);
}
+
+ return 0;
}
/**
@@ -879,13 +912,14 @@ int ata_scsi_slave_config(struct scsi_device *sdev)
{
struct ata_port *ap = ata_shost_to_port(sdev->host);
struct ata_device *dev = __ata_scsi_find_dev(ap, sdev);
+ int rc = 0;
ata_scsi_sdev_config(sdev);
if (dev)
- ata_scsi_dev_config(sdev, dev);
+ rc = ata_scsi_dev_config(sdev, dev);
- return 0;
+ return rc;
}
/**
@@ -905,6 +939,7 @@ int ata_scsi_slave_config(struct scsi_device *sdev)
void ata_scsi_slave_destroy(struct scsi_device *sdev)
{
struct ata_port *ap = ata_shost_to_port(sdev->host);
+ struct request_queue *q = sdev->request_queue;
unsigned long flags;
struct ata_device *dev;
@@ -920,6 +955,10 @@ void ata_scsi_slave_destroy(struct scsi_device *sdev)
ata_port_schedule_eh(ap);
}
spin_unlock_irqrestore(ap->lock, flags);
+
+ kfree(q->dma_drain_buffer);
+ q->dma_drain_buffer = NULL;
+ q->dma_drain_size = 0;
}
/**
@@ -1655,12 +1694,17 @@ void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
u8 *rbuf;
unsigned int buflen, rc;
struct scsi_cmnd *cmd = args->cmd;
+ unsigned long flags;
+
+ local_irq_save(flags);
buflen = ata_scsi_rbuf_get(cmd, &rbuf);
memset(rbuf, 0, buflen);
rc = actor(args, rbuf, buflen);
ata_scsi_rbuf_put(cmd, rbuf);
+ local_irq_restore(flags);
+
if (rc == 0)
cmd->result = SAM_STAT_GOOD;
args->done(cmd);
@@ -1862,7 +1906,7 @@ unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf,
* spin_lock_irqsave(host lock)
*/
-unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf,
+static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf,
unsigned int buflen)
{
u8 pbuf[60];
@@ -2434,6 +2478,9 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc)
if ((scsicmd[0] == INQUIRY) && ((scsicmd[1] & 0x03) == 0)) {
u8 *buf = NULL;
unsigned int buflen;
+ unsigned long flags;
+
+ local_irq_save(flags);
buflen = ata_scsi_rbuf_get(cmd, &buf);
@@ -2451,6 +2498,8 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc)
}
ata_scsi_rbuf_put(cmd, buf);
+
+ local_irq_restore(flags);
}
cmd->result = SAM_STAT_GOOD;
@@ -2500,7 +2549,7 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc)
* want to set it properly, and for DMA where it is
* effectively meaningless.
*/
- nbytes = min(qc->nbytes, (unsigned int)63 * 1024);
+ nbytes = min(scmd->request->raw_data_len, (unsigned int)63 * 1024);
/* Most ATAPI devices which honor transfer chunk size don't
* behave according to the spec when odd chunk size which
@@ -2543,7 +2592,8 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc)
qc->tf.protocol = ATAPI_PROT_DMA;
qc->tf.feature |= ATAPI_PKT_DMA;
- if (atapi_dmadir && (scmd->sc_data_direction != DMA_TO_DEVICE))
+ if ((dev->flags & ATA_DFLAG_DMADIR) &&
+ (scmd->sc_data_direction != DMA_TO_DEVICE))
/* some SATA bridges need us to indicate data xfer direction */
qc->tf.feature |= ATAPI_DMADIR;
}
@@ -3555,7 +3605,7 @@ EXPORT_SYMBOL_GPL(ata_sas_port_alloc);
* @ap: Port to initialize
*
* Called just after data structures for each port are
- * initialized. Allocates DMA pad.
+ * initialized.
*
* May be used as the port_start() entry in ata_port_operations.
*
@@ -3564,7 +3614,7 @@ EXPORT_SYMBOL_GPL(ata_sas_port_alloc);
*/
int ata_sas_port_start(struct ata_port *ap)
{
- return ata_pad_alloc(ap, ap->dev);
+ return 0;
}
EXPORT_SYMBOL_GPL(ata_sas_port_start);
@@ -3572,8 +3622,6 @@ EXPORT_SYMBOL_GPL(ata_sas_port_start);
* ata_port_stop - Undo ata_sas_port_start()
* @ap: Port to shut down
*
- * Frees the DMA pad.
- *
* May be used as the port_stop() entry in ata_port_operations.
*
* LOCKING:
@@ -3582,7 +3630,6 @@ EXPORT_SYMBOL_GPL(ata_sas_port_start);
void ata_sas_port_stop(struct ata_port *ap)
{
- ata_pad_free(ap, ap->dev);
}
EXPORT_SYMBOL_GPL(ata_sas_port_stop);
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 409ffb9af16..aa884f71a12 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -56,11 +56,11 @@ enum {
extern unsigned int ata_print_id;
extern struct workqueue_struct *ata_aux_wq;
extern int atapi_enabled;
-extern int atapi_dmadir;
extern int atapi_passthru16;
extern int libata_fua;
extern int libata_noacpi;
extern int libata_allow_tpm;
+extern void ata_force_cbl(struct ata_port *ap);
extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev);
extern int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev,
u64 block, u32 n_block, unsigned int tf_flags,
diff --git a/drivers/ata/pata_acpi.c b/drivers/ata/pata_acpi.c
index 244098a80ce..bdc3b9d7395 100644
--- a/drivers/ata/pata_acpi.c
+++ b/drivers/ata/pata_acpi.c
@@ -77,8 +77,8 @@ static int pacpi_cable_detect(struct ata_port *ap)
static void pacpi_error_handler(struct ata_port *ap)
{
- return ata_bmdma_drive_eh(ap, pacpi_pre_reset, ata_std_softreset,
- NULL, ata_std_postreset);
+ ata_bmdma_drive_eh(ap, pacpi_pre_reset, ata_std_softreset, NULL,
+ ata_std_postreset);
}
/**
diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c
index ea567e2b170..4b8d9b592ca 100644
--- a/drivers/ata/pata_amd.c
+++ b/drivers/ata/pata_amd.c
@@ -146,9 +146,8 @@ static int amd_pre_reset(struct ata_link *link, unsigned long deadline)
static void amd_error_handler(struct ata_port *ap)
{
- return ata_bmdma_drive_eh(ap, amd_pre_reset,
- ata_std_softreset, NULL,
- ata_std_postreset);
+ ata_bmdma_drive_eh(ap, amd_pre_reset, ata_std_softreset, NULL,
+ ata_std_postreset);
}
static int amd_cable_detect(struct ata_port *ap)
@@ -506,7 +505,6 @@ static struct ata_port_operations amd133_port_ops = {
static struct ata_port_operations nv100_port_ops = {
.set_piomode = nv100_set_piomode,
.set_dmamode = nv100_set_dmamode,
- .mode_filter = ata_pci_default_filter,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -541,7 +539,6 @@ static struct ata_port_operations nv100_port_ops = {
static struct ata_port_operations nv133_port_ops = {
.set_piomode = nv133_set_piomode,
.set_dmamode = nv133_set_dmamode,
- .mode_filter = ata_pci_default_filter,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c
index 9623f529553..408bdc1a977 100644
--- a/drivers/ata/pata_atiixp.c
+++ b/drivers/ata/pata_atiixp.c
@@ -227,7 +227,7 @@ static struct scsi_host_template atiixp_sht = {
.queuecommand = ata_scsi_queuecmd,
.can_queue = ATA_DEF_QUEUE,
.this_id = ATA_SHT_THIS_ID,
- .sg_tablesize = LIBATA_MAX_PRD,
+ .sg_tablesize = LIBATA_DUMB_MAX_PRD,
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
.emulated = ATA_SHT_EMULATED,
.use_clustering = ATA_SHT_USE_CLUSTERING,
@@ -259,7 +259,7 @@ static struct ata_port_operations atiixp_port_ops = {
.bmdma_stop = atiixp_bmdma_stop,
.bmdma_status = ata_bmdma_status,
- .qc_prep = ata_qc_prep,
+ .qc_prep = ata_dumb_qc_prep,
.qc_issue = ata_qc_issue_prot,
.data_xfer = ata_data_xfer,
diff --git a/drivers/ata/pata_cs5536.c b/drivers/ata/pata_cs5536.c
index d753e568588..1c4ff9b52b5 100644
--- a/drivers/ata/pata_cs5536.c
+++ b/drivers/ata/pata_cs5536.c
@@ -40,7 +40,7 @@
#include <asm/msr.h>
#define DRV_NAME "pata_cs5536"
-#define DRV_VERSION "0.0.6"
+#define DRV_VERSION "0.0.7"
enum {
CFG = 0,
@@ -85,7 +85,7 @@ static const u8 pci_reg[4] = {
PCI_IDE_CFG, PCI_IDE_DTC, PCI_IDE_CAST, PCI_IDE_ETC,
};
-static inline int cs5536_read(struct pci_dev *pdev, int reg, int *val)
+static inline int cs5536_read(struct pci_dev *pdev, int reg, u32 *val)
{
if (unlikely(use_msr)) {
u32 dummy;
@@ -153,8 +153,8 @@ static void cs5536_set_piomode(struct ata_port *ap, struct ata_device *adev)
struct ata_device *pair = ata_dev_pair(adev);
int mode = adev->pio_mode - XFER_PIO_0;
int cmdmode = mode;
- int dshift = ap->port_no ? IDE_D1_SHIFT : IDE_D0_SHIFT;
- int cshift = ap->port_no ? IDE_CAST_D1_SHIFT : IDE_CAST_D0_SHIFT;
+ int dshift = adev->devno ? IDE_D1_SHIFT : IDE_D0_SHIFT;
+ int cshift = adev->devno ? IDE_CAST_D1_SHIFT : IDE_CAST_D0_SHIFT;
u32 dtc, cast, etc;
if (pair)
@@ -201,7 +201,7 @@ static void cs5536_set_dmamode(struct ata_port *ap, struct ata_device *adev)
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u32 dtc, etc;
int mode = adev->dma_mode;
- int dshift = ap->port_no ? IDE_D1_SHIFT : IDE_D0_SHIFT;
+ int dshift = adev->devno ? IDE_D1_SHIFT : IDE_D0_SHIFT;
if (mode >= XFER_UDMA_0) {
cs5536_read(pdev, ETC, &etc);
diff --git a/drivers/ata/pata_icside.c b/drivers/ata/pata_icside.c
index 5b8586dac63..f97068be2d7 100644
--- a/drivers/ata/pata_icside.c
+++ b/drivers/ata/pata_icside.c
@@ -304,12 +304,6 @@ static int icside_dma_init(struct pata_icside_info *info)
}
-static int pata_icside_port_start(struct ata_port *ap)
-{
- /* No PRD to alloc */
- return ata_pad_alloc(ap, ap->dev);
-}
-
static struct scsi_host_template pata_icside_sht = {
.module = THIS_MODULE,
.name = DRV_NAME,
@@ -389,8 +383,6 @@ static struct ata_port_operations pata_icside_port_ops = {
.irq_clear = ata_dummy_noret,
.irq_on = ata_irq_on,
- .port_start = pata_icside_port_start,
-
.bmdma_stop = pata_icside_bmdma_stop,
.bmdma_status = pata_icside_bmdma_status,
};
diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c
index 5b8174d9406..00bbbbd50e9 100644
--- a/drivers/ata/pata_jmicron.c
+++ b/drivers/ata/pata_jmicron.c
@@ -115,7 +115,8 @@ static int jmicron_pre_reset(struct ata_link *link, unsigned long deadline)
static void jmicron_error_handler(struct ata_port *ap)
{
- return ata_bmdma_drive_eh(ap, jmicron_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+ ata_bmdma_drive_eh(ap, jmicron_pre_reset, ata_std_softreset, NULL,
+ ata_std_postreset);
}
/* No PIO or DMA methods needed for this device */
diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c
index 6c59969fd50..50fe08ebe23 100644
--- a/drivers/ata/pata_legacy.c
+++ b/drivers/ata/pata_legacy.c
@@ -774,14 +774,14 @@ static struct ata_port_operations opti82c46x_port_ops = {
static void qdi6500_set_piomode(struct ata_port *ap, struct ata_device *adev)
{
struct ata_timing t;
- struct legacy_data *qdi = ap->host->private_data;
+ struct legacy_data *ld_qdi = ap->host->private_data;
int active, recovery;
u8 timing;
/* Get the timing data in cycles */
ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
- if (qdi->fast) {
+ if (ld_qdi->fast) {
active = 8 - FIT(t.active, 1, 8);
recovery = 18 - FIT(t.recover, 3, 18);
} else {
@@ -790,9 +790,9 @@ static void qdi6500_set_piomode(struct ata_port *ap, struct ata_device *adev)
}
timing = (recovery << 4) | active | 0x08;
- qdi->clock[adev->devno] = timing;
+ ld_qdi->clock[adev->devno] = timing;
- outb(timing, qdi->timing);
+ outb(timing, ld_qdi->timing);
}
/**
@@ -808,14 +808,14 @@ static void qdi6500_set_piomode(struct ata_port *ap, struct ata_device *adev)
static void qdi6580dp_set_piomode(struct ata_port *ap, struct ata_device *adev)
{
struct ata_timing t;
- struct legacy_data *qdi = ap->host->private_data;
+ struct legacy_data *ld_qdi = ap->host->private_data;
int active, recovery;
u8 timing;
/* Get the timing data in cycles */
ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
- if (qdi->fast) {
+ if (ld_qdi->fast) {
active = 8 - FIT(t.active, 1, 8);
recovery = 18 - FIT(t.recover, 3, 18);
} else {
@@ -824,12 +824,12 @@ static void qdi6580dp_set_piomode(struct ata_port *ap, struct ata_device *adev)
}
timing = (recovery << 4) | active | 0x08;
- qdi->clock[adev->devno] = timing;
+ ld_qdi->clock[adev->devno] = timing;
- outb(timing, qdi->timing + 2 * ap->port_no);
+ outb(timing, ld_qdi->timing + 2 * ap->port_no);
/* Clear the FIFO */
if (adev->class != ATA_DEV_ATA)
- outb(0x5F, qdi->timing + 3);
+ outb(0x5F, ld_qdi->timing + 3);
}
/**
@@ -845,14 +845,14 @@ static void qdi6580dp_set_piomode(struct ata_port *ap, struct ata_device *adev)
static void qdi6580_set_piomode(struct ata_port *ap, struct ata_device *adev)
{
struct ata_timing t;
- struct legacy_data *qdi = ap->host->private_data;
+ struct legacy_data *ld_qdi = ap->host->private_data;
int active, recovery;
u8 timing;
/* Get the timing data in cycles */
ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
- if (qdi->fast) {
+ if (ld_qdi->fast) {
active = 8 - FIT(t.active, 1, 8);
recovery = 18 - FIT(t.recover, 3, 18);
} else {
@@ -860,11 +860,11 @@ static void qdi6580_set_piomode(struct ata_port *ap, struct ata_device *adev)
recovery = 15 - FIT(t.recover, 0, 15);
}
timing = (recovery << 4) | active | 0x08;
- qdi->clock[adev->devno] = timing;
- outb(timing, qdi->timing + 2 * adev->devno);
+ ld_qdi->clock[adev->devno] = timing;
+ outb(timing, ld_qdi->timing + 2 * adev->devno);
/* Clear the FIFO */
if (adev->class != ATA_DEV_ATA)
- outb(0x5F, qdi->timing + 3);
+ outb(0x5F, ld_qdi->timing + 3);
}
/**
@@ -879,12 +879,12 @@ static unsigned int qdi_qc_issue_prot(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
struct ata_device *adev = qc->dev;
- struct legacy_data *qdi = ap->host->private_data;
+ struct legacy_data *ld_qdi = ap->host->private_data;
- if (qdi->clock[adev->devno] != qdi->last) {
+ if (ld_qdi->clock[adev->devno] != ld_qdi->last) {
if (adev->pio_mode) {
- qdi->last = qdi->clock[adev->devno];
- outb(qdi->clock[adev->devno], qdi->timing +
+ ld_qdi->last = ld_qdi->clock[adev->devno];
+ outb(ld_qdi->clock[adev->devno], ld_qdi->timing +
2 * ap->port_no);
}
}
@@ -1037,12 +1037,12 @@ static u8 winbond_readcfg(unsigned long port, u8 reg)
static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev)
{
struct ata_timing t;
- struct legacy_data *winbond = ap->host->private_data;
+ struct legacy_data *ld_winbond = ap->host->private_data;
int active, recovery;
u8 reg;
int timing = 0x88 + (ap->port_no * 4) + (adev->devno * 2);
- reg = winbond_readcfg(winbond->timing, 0x81);
+ reg = winbond_readcfg(ld_winbond->timing, 0x81);
/* Get the timing data in cycles */
if (reg & 0x40) /* Fast VLB bus, assume 50MHz */
@@ -1053,7 +1053,7 @@ static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev)
active = (FIT(t.active, 3, 17) - 1) & 0x0F;
recovery = (FIT(t.recover, 1, 15) + 1) & 0x0F;
timing = (active << 4) | recovery;
- winbond_writecfg(winbond->timing, timing, reg);
+ winbond_writecfg(ld_winbond->timing, timing, reg);
/* Load the setup timing */
@@ -1063,7 +1063,7 @@ static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev)
if (!ata_pio_need_iordy(adev))
reg |= 0x02; /* IORDY off */
reg |= (FIT(t.setup, 0, 3) << 6);
- winbond_writecfg(winbond->timing, timing + 1, reg);
+ winbond_writecfg(ld_winbond->timing, timing + 1, reg);
}
static int winbond_port(struct platform_device *dev,
@@ -1278,8 +1278,6 @@ static __init int legacy_init_one(struct legacy_probe *probe)
}
}
fail:
- if (host)
- ata_host_detach(host);
platform_device_unregister(pdev);
return ret;
}
diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c
index 9afc8a32b22..a81f25d8723 100644
--- a/drivers/ata/pata_marvell.c
+++ b/drivers/ata/pata_marvell.c
@@ -85,8 +85,8 @@ static int marvell_cable_detect(struct ata_port *ap)
static void marvell_error_handler(struct ata_port *ap)
{
- return ata_bmdma_drive_eh(ap, marvell_pre_reset, ata_std_softreset,
- NULL, ata_std_postreset);
+ ata_bmdma_drive_eh(ap, marvell_pre_reset, ata_std_softreset, NULL,
+ ata_std_postreset);
}
/* No PIO or DMA methods needed for this device */
diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c
index 55055b27524..6c016deeaed 100644
--- a/drivers/ata/pata_scc.c
+++ b/drivers/ata/pata_scc.c
@@ -1007,6 +1007,8 @@ static const struct ata_port_operations scc_pata_ops = {
.qc_issue = ata_qc_issue_prot,
.freeze = scc_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+
.error_handler = scc_error_handler,
.post_internal_cmd = scc_bmdma_stop,
diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c
index efcb66b6cce..07791a7a48a 100644
--- a/drivers/ata/sata_fsl.c
+++ b/drivers/ata/sata_fsl.c
@@ -335,7 +335,7 @@ static unsigned int sata_fsl_fill_sg(struct ata_queued_cmd *qc, void *cmd_desc,
dma_addr_t indirect_ext_segment_paddr;
unsigned int si;
- VPRINTK("SATA FSL : cd = 0x%x, prd = 0x%x\n", cmd_desc, prd);
+ VPRINTK("SATA FSL : cd = 0x%p, prd = 0x%p\n", cmd_desc, prd);
indirect_ext_segment_paddr = cmd_desc_paddr +
SATA_FSL_CMD_DESC_OFFSET_TO_PRDT + SATA_FSL_MAX_PRD_DIRECT * 16;
@@ -459,7 +459,8 @@ static unsigned int sata_fsl_qc_issue(struct ata_queued_cmd *qc)
VPRINTK("CE=0x%x, DE=0x%x, CC=0x%x, CmdStat = 0x%x\n",
ioread32(CE + hcr_base),
ioread32(DE + hcr_base),
- ioread32(CC + hcr_base), ioread32(COMMANDSTAT + csr_base));
+ ioread32(CC + hcr_base),
+ ioread32(COMMANDSTAT + host_priv->csr_base));
return 0;
}
@@ -522,7 +523,8 @@ static void sata_fsl_freeze(struct ata_port *ap)
ioread32(CQ + hcr_base),
ioread32(CA + hcr_base),
ioread32(CE + hcr_base), ioread32(DE + hcr_base));
- VPRINTK("CmdStat = 0x%x\n", ioread32(csr_base + COMMANDSTAT));
+ VPRINTK("CmdStat = 0x%x\n",
+ ioread32(host_priv->csr_base + COMMANDSTAT));
/* disable interrupts on the controller/port */
temp = ioread32(hcr_base + HCONTROL);
@@ -601,21 +603,9 @@ static int sata_fsl_port_start(struct ata_port *ap)
if (!pp)
return -ENOMEM;
- /*
- * allocate per command dma alignment pad buffer, which is used
- * internally by libATA to ensure that all transfers ending on
- * unaligned boundaries are padded, to align on Dword boundaries
- */
- retval = ata_pad_alloc(ap, dev);
- if (retval) {
- kfree(pp);
- return retval;
- }
-
mem = dma_alloc_coherent(dev, SATA_FSL_PORT_PRIV_DMA_SZ, &mem_dma,
GFP_KERNEL);
if (!mem) {
- ata_pad_free(ap, dev);
kfree(pp);
return -ENOMEM;
}
@@ -694,7 +684,6 @@ static void sata_fsl_port_stop(struct ata_port *ap)
dma_free_coherent(dev, SATA_FSL_PORT_PRIV_DMA_SZ,
pp->cmdslot, pp->cmdslot_paddr);
- ata_pad_free(ap, dev);
kfree(pp);
}
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index 04b571764af..6ebebde8454 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -870,7 +870,7 @@ static void mv_start_dma(struct ata_port *ap, void __iomem *port_mmio,
struct mv_host_priv *hpriv = ap->host->private_data;
int hard_port = mv_hardport_from_port(ap->port_no);
void __iomem *hc_mmio = mv_hc_base_from_port(
- ap->host->iomap[MV_PRIMARY_BAR], hard_port);
+ mv_host_base(ap->host), hard_port);
u32 hc_irq_cause, ipending;
/* clear EDMA event indicators, if any */
@@ -1158,17 +1158,13 @@ static int mv_port_start(struct ata_port *ap)
struct mv_port_priv *pp;
void __iomem *port_mmio = mv_ap_base(ap);
unsigned long flags;
- int tag, rc;
+ int tag;
pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
if (!pp)
return -ENOMEM;
ap->private_data = pp;
- rc = ata_pad_alloc(ap, dev);
- if (rc)
- return rc;
-
pp->crqb = dma_pool_alloc(hpriv->crqb_pool, GFP_KERNEL, &pp->crqb_dma);
if (!pp->crqb)
return -ENOMEM;
@@ -1542,7 +1538,7 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
eh_freeze_mask = EDMA_EH_FREEZE_5;
if (edma_err_cause & EDMA_ERR_SELF_DIS_5) {
- struct mv_port_priv *pp = ap->private_data;
+ pp = ap->private_data;
pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
ata_ehi_push_desc(ehi, "EDMA self-disable");
}
@@ -1550,7 +1546,7 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
eh_freeze_mask = EDMA_EH_FREEZE;
if (edma_err_cause & EDMA_ERR_SELF_DIS) {
- struct mv_port_priv *pp = ap->private_data;
+ pp = ap->private_data;
pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
ata_ehi_push_desc(ehi, "EDMA self-disable");
}
@@ -2951,7 +2947,8 @@ static int mv_platform_probe(struct platform_device *pdev)
hpriv->n_ports = n_ports;
host->iomap = NULL;
- hpriv->base = ioremap(res->start, res->end - res->start + 1);
+ hpriv->base = devm_ioremap(&pdev->dev, res->start,
+ res->end - res->start + 1);
hpriv->base -= MV_SATAHC0_REG_BASE;
rc = mv_create_dma_pools(hpriv, &pdev->dev);
@@ -2983,11 +2980,8 @@ static int __devexit mv_platform_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct ata_host *host = dev_get_drvdata(dev);
- struct mv_host_priv *hpriv = host->private_data;
- void __iomem *base = hpriv->base;
ata_host_detach(host);
- iounmap(base);
return 0;
}
@@ -3198,6 +3192,7 @@ MODULE_DESCRIPTION("SCSI low-level driver for Marvell SATA controllers");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, mv_pci_tbl);
MODULE_VERSION(DRV_VERSION);
+MODULE_ALIAS("platform:sata_mv");
#ifdef CONFIG_PCI
module_param(msi, int, 0444);
diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c
index a07d319f6e8..f251a5f569d 100644
--- a/drivers/ata/sata_promise.c
+++ b/drivers/ata/sata_promise.c
@@ -543,7 +543,7 @@ static void pdc_fill_sg(struct ata_queued_cmd *qc)
idx = 0;
for_each_sg(qc->sg, sg, qc->n_elem, si) {
u32 addr, offset;
- u32 sg_len, len;
+ u32 sg_len;
/* determine if physical DMA addr spans 64K boundary.
* Note h/w doesn't support 64-bit, so we unconditionally
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index b4b1f91ea69..df7988df790 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -1234,7 +1234,6 @@ static int sil24_port_start(struct ata_port *ap)
union sil24_cmd_block *cb;
size_t cb_size = sizeof(*cb) * SIL24_MAX_CMDS;
dma_addr_t cb_dma;
- int rc;
pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
if (!pp)
@@ -1247,10 +1246,6 @@ static int sil24_port_start(struct ata_port *ap)
return -ENOMEM;
memset(cb, 0, cb_size);
- rc = ata_pad_alloc(ap, dev);
- if (rc)
- return rc;
-
pp->cmd_block = cb;
pp->cmd_block_dma = cb_dma;
diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c
index 69f651e0bc9..840d1c4a785 100644
--- a/drivers/ata/sata_svw.c
+++ b/drivers/ata/sata_svw.c
@@ -45,6 +45,8 @@
#include <linux/interrupt.h>
#include <linux/device.h>
#include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi.h>
#include <linux/libata.h>
#ifdef CONFIG_PPC_OF
@@ -59,6 +61,7 @@ enum {
/* ap->flags bits */
K2_FLAG_SATA_8_PORTS = (1 << 24),
K2_FLAG_NO_ATAPI_DMA = (1 << 25),
+ K2_FLAG_BAR_POS_3 = (1 << 26),
/* Taskfile registers offsets */
K2_SATA_TF_CMD_OFFSET = 0x00,
@@ -88,8 +91,10 @@ enum {
/* Port stride */
K2_SATA_PORT_OFFSET = 0x100,
- board_svw4 = 0,
- board_svw8 = 1,
+ chip_svw4 = 0,
+ chip_svw8 = 1,
+ chip_svw42 = 2, /* bar 3 */
+ chip_svw43 = 3, /* bar 5 */
};
static u8 k2_stat_check_status(struct ata_port *ap);
@@ -97,10 +102,25 @@ static u8 k2_stat_check_status(struct ata_port *ap);
static int k2_sata_check_atapi_dma(struct ata_queued_cmd *qc)
{
+ u8 cmnd = qc->scsicmd->cmnd[0];
+
if (qc->ap->flags & K2_FLAG_NO_ATAPI_DMA)
return -1; /* ATAPI DMA not supported */
+ else {
+ switch (cmnd) {
+ case READ_10:
+ case READ_12:
+ case READ_16:
+ case WRITE_10:
+ case WRITE_12:
+ case WRITE_16:
+ return 0;
+
+ default:
+ return -1;
+ }
- return 0;
+ }
}
static int k2_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
@@ -354,7 +374,7 @@ static const struct ata_port_operations k2_sata_ops = {
};
static const struct ata_port_info k2_port_info[] = {
- /* board_svw4 */
+ /* chip_svw4 */
{
.flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_MMIO | K2_FLAG_NO_ATAPI_DMA,
@@ -363,7 +383,7 @@ static const struct ata_port_info k2_port_info[] = {
.udma_mask = ATA_UDMA6,
.port_ops = &k2_sata_ops,
},
- /* board_svw8 */
+ /* chip_svw8 */
{
.flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_MMIO | K2_FLAG_NO_ATAPI_DMA |
@@ -373,6 +393,24 @@ static const struct ata_port_info k2_port_info[] = {
.udma_mask = ATA_UDMA6,
.port_ops = &k2_sata_ops,
},
+ /* chip_svw42 */
+ {
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_MMIO | K2_FLAG_BAR_POS_3,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &k2_sata_ops,
+ },
+ /* chip_svw43 */
+ {
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_MMIO,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &k2_sata_ops,
+ },
};
static void k2_sata_setup_port(struct ata_ioports *port, void __iomem *base)
@@ -402,7 +440,7 @@ static int k2_sata_init_one(struct pci_dev *pdev, const struct pci_device_id *en
{ &k2_port_info[ent->driver_data], NULL };
struct ata_host *host;
void __iomem *mmio_base;
- int n_ports, i, rc;
+ int n_ports, i, rc, bar_pos;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
@@ -416,6 +454,9 @@ static int k2_sata_init_one(struct pci_dev *pdev, const struct pci_device_id *en
if (!host)
return -ENOMEM;
+ bar_pos = 5;
+ if (ppi[0]->flags & K2_FLAG_BAR_POS_3)
+ bar_pos = 3;
/*
* If this driver happens to only be useful on Apple's K2, then
* we should check that here as it has a normal Serverworks ID
@@ -428,17 +469,23 @@ static int k2_sata_init_one(struct pci_dev *pdev, const struct pci_device_id *en
* Check if we have resources mapped at all (second function may
* have been disabled by firmware)
*/
- if (pci_resource_len(pdev, 5) == 0)
+ if (pci_resource_len(pdev, bar_pos) == 0) {
+ /* In IDE mode we need to pin the device to ensure that
+ pcim_release does not clear the busmaster bit in config
+ space, clearing causes busmaster DMA to fail on
+ ports 3 & 4 */
+ pcim_pin_device(pdev);
return -ENODEV;
+ }
/* Request and iomap PCI regions */
- rc = pcim_iomap_regions(pdev, 1 << 5, DRV_NAME);
+ rc = pcim_iomap_regions(pdev, 1 << bar_pos, DRV_NAME);
if (rc == -EBUSY)
pcim_pin_device(pdev);
if (rc)
return rc;
host->iomap = pcim_iomap_table(pdev);
- mmio_base = host->iomap[5];
+ mmio_base = host->iomap[bar_pos];
/* different controllers have different number of ports - currently 4 or 8 */
/* All ports are on the same function. Multi-function device is no
@@ -483,11 +530,13 @@ static int k2_sata_init_one(struct pci_dev *pdev, const struct pci_device_id *en
* controller
* */
static const struct pci_device_id k2_sata_pci_tbl[] = {
- { PCI_VDEVICE(SERVERWORKS, 0x0240), board_svw4 },
- { PCI_VDEVICE(SERVERWORKS, 0x0241), board_svw4 },
- { PCI_VDEVICE(SERVERWORKS, 0x0242), board_svw8 },
- { PCI_VDEVICE(SERVERWORKS, 0x024a), board_svw4 },
- { PCI_VDEVICE(SERVERWORKS, 0x024b), board_svw4 },
+ { PCI_VDEVICE(SERVERWORKS, 0x0240), chip_svw4 },
+ { PCI_VDEVICE(SERVERWORKS, 0x0241), chip_svw4 },
+ { PCI_VDEVICE(SERVERWORKS, 0x0242), chip_svw8 },
+ { PCI_VDEVICE(SERVERWORKS, 0x024a), chip_svw4 },
+ { PCI_VDEVICE(SERVERWORKS, 0x024b), chip_svw4 },
+ { PCI_VDEVICE(SERVERWORKS, 0x0410), chip_svw42 },
+ { PCI_VDEVICE(SERVERWORKS, 0x0411), chip_svw43 },
{ }
};
diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c
index 30caa033719..0d03f44824f 100644
--- a/drivers/ata/sata_via.c
+++ b/drivers/ata/sata_via.c
@@ -333,8 +333,8 @@ static int vt6420_prereset(struct ata_link *link, unsigned long deadline)
static void vt6420_error_handler(struct ata_port *ap)
{
- return ata_bmdma_drive_eh(ap, vt6420_prereset, ata_std_softreset,
- NULL, ata_std_postreset);
+ ata_bmdma_drive_eh(ap, vt6420_prereset, ata_std_softreset, NULL,
+ ata_std_postreset);
}
static int vt6421_pata_cable_detect(struct ata_port *ap)
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 055989e9479..2d207ad3033 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -658,9 +658,10 @@ int bus_add_driver(struct device_driver *drv)
pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
+ if (!priv) {
+ error = -ENOMEM;
+ goto out_put_bus;
+ }
klist_init(&priv->klist_devices, NULL, NULL);
priv->driver = drv;
drv->p = priv;
@@ -668,7 +669,7 @@ int bus_add_driver(struct device_driver *drv)
error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
"%s", drv->name);
if (error)
- goto out_put_bus;
+ goto out_unregister;
if (drv->bus->p->drivers_autoprobe) {
error = driver_attach(drv);
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index ba75184c653..bf31a0170a4 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -120,6 +120,9 @@ EXPORT_SYMBOL_GPL(driver_remove_file);
/**
* driver_add_kobj - add a kobject below the specified driver
+ * @drv: requesting device driver
+ * @kobj: kobject to add below this driver
+ * @fmt: format string that names the kobject
*
* You really don't want to do this, this is only here due to one looney
* iseries driver, go poke those developers if you are annoyed about
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index bdc03f7e842..ee9d1c8db0d 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -415,7 +415,7 @@ EXPORT_SYMBOL_GPL(device_power_down);
* @dev: Device.
* @state: Power state device is entering.
*/
-int suspend_device(struct device *dev, pm_message_t state)
+static int suspend_device(struct device *dev, pm_message_t state)
{
int error = 0;
@@ -479,7 +479,6 @@ static int dpm_suspend(pm_message_t state)
mutex_lock(&dpm_list_mtx);
if (list_empty(&dev->power.entry))
list_add(&dev->power.entry, &dpm_locked);
- mutex_unlock(&dpm_list_mtx);
break;
}
mutex_lock(&dpm_list_mtx);
@@ -523,6 +522,7 @@ static void lock_all_devices(void)
/**
* device_suspend - Save state and stop all devices in system.
+ * @state: new power management state
*
* Prevent new devices from being registered, then lock all devices
* and suspend them.
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 018753c59b8..b53fdb0a282 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -655,6 +655,7 @@ static int __init nbd_init(void)
for (i = 0; i < nbds_max; i++) {
struct gendisk *disk = alloc_disk(1);
+ elevator_t *old_e;
if (!disk)
goto out;
nbd_dev[i].disk = disk;
@@ -668,6 +669,11 @@ static int __init nbd_init(void)
put_disk(disk);
goto out;
}
+ old_e = disk->queue->elevator;
+ if (elevator_init(disk->queue, "deadline") == 0 ||
+ elevator_init(disk->queue, "noop") == 0) {
+ elevator_exit(old_e);
+ }
}
if (register_blkdev(NBD_MAJOR, "nbd")) {
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index 8afce67c0aa..9c6f3f99208 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -37,6 +37,7 @@
#include <linux/interrupt.h>
#include <linux/blkdev.h>
+#include <linux/hdreg.h>
#include <linux/module.h>
#include <xen/xenbus.h>
@@ -135,6 +136,22 @@ static void blkif_restart_queue_callback(void *arg)
schedule_work(&info->work);
}
+int blkif_getgeo(struct block_device *bd, struct hd_geometry *hg)
+{
+ /* We don't have real geometry info, but let's at least return
+ values consistent with the size of the device */
+ sector_t nsect = get_capacity(bd->bd_disk);
+ sector_t cylinders = nsect;
+
+ hg->heads = 0xff;
+ hg->sectors = 0x3f;
+ sector_div(cylinders, hg->heads * hg->sectors);
+ hg->cylinders = cylinders;
+ if ((sector_t)(hg->cylinders + 1) * hg->heads * hg->sectors < nsect)
+ hg->cylinders = 0xffff;
+ return 0;
+}
+
/*
* blkif_queue_request
*
@@ -937,6 +954,7 @@ static struct block_device_operations xlvbd_block_fops =
.owner = THIS_MODULE,
.open = blkif_open,
.release = blkif_release,
+ .getgeo = blkif_getgeo,
};
diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c
index 87be46406da..d2866999214 100644
--- a/drivers/char/agp/amd-k7-agp.c
+++ b/drivers/char/agp/amd-k7-agp.c
@@ -41,6 +41,7 @@ static int amd_create_page_map(struct amd_page_map *page_map)
if (page_map->real == NULL)
return -ENOMEM;
+#ifndef CONFIG_X86
SetPageReserved(virt_to_page(page_map->real));
global_cache_flush();
page_map->remapped = ioremap_nocache(virt_to_gart(page_map->real),
@@ -52,6 +53,10 @@ static int amd_create_page_map(struct amd_page_map *page_map)
return -ENOMEM;
}
global_cache_flush();
+#else
+ set_memory_uc((unsigned long)page_map->real, 1);
+ page_map->remapped = page_map->real;
+#endif
for (i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) {
writel(agp_bridge->scratch_page, page_map->remapped+i);
@@ -63,8 +68,12 @@ static int amd_create_page_map(struct amd_page_map *page_map)
static void amd_free_page_map(struct amd_page_map *page_map)
{
+#ifndef CONFIG_X86
iounmap(page_map->remapped);
ClearPageReserved(virt_to_page(page_map->real));
+#else
+ set_memory_wb((unsigned long)page_map->real, 1);
+#endif
free_page((unsigned long) page_map->real);
}
diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c
index 2d46b713c8f..55c97f62324 100644
--- a/drivers/char/agp/ati-agp.c
+++ b/drivers/char/agp/ati-agp.c
@@ -60,18 +60,9 @@ static int ati_create_page_map(struct ati_page_map *page_map)
if (page_map->real == NULL)
return -ENOMEM;
- SetPageReserved(virt_to_page(page_map->real));
+ set_memory_uc((unsigned long)page_map->real, 1);
err = map_page_into_agp(virt_to_page(page_map->real));
- page_map->remapped = ioremap_nocache(virt_to_gart(page_map->real),
- PAGE_SIZE);
- if (page_map->remapped == NULL || err) {
- ClearPageReserved(virt_to_page(page_map->real));
- free_page((unsigned long) page_map->real);
- page_map->real = NULL;
- return -ENOMEM;
- }
- /*CACHE_FLUSH();*/
- global_cache_flush();
+ page_map->remapped = page_map->real;
for (i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) {
writel(agp_bridge->scratch_page, page_map->remapped+i);
@@ -85,8 +76,7 @@ static int ati_create_page_map(struct ati_page_map *page_map)
static void ati_free_page_map(struct ati_page_map *page_map)
{
unmap_page_from_agp(virt_to_page(page_map->real));
- iounmap(page_map->remapped);
- ClearPageReserved(virt_to_page(page_map->real));
+ set_memory_wb((unsigned long)page_map->real, 1);
free_page((unsigned long) page_map->real);
}
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index 7484bc759c4..7fc0c99a3a5 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -932,9 +932,14 @@ int agp_generic_create_gatt_table(struct agp_bridge_data *bridge)
agp_gatt_table = (void *)table;
bridge->driver->cache_flush();
+#ifdef CONFIG_X86
+ set_memory_uc((unsigned long)table, 1 << page_order);
+ bridge->gatt_table = (void *)table;
+#else
bridge->gatt_table = ioremap_nocache(virt_to_gart(table),
(PAGE_SIZE * (1 << page_order)));
bridge->driver->cache_flush();
+#endif
if (bridge->gatt_table == NULL) {
for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
@@ -991,7 +996,11 @@ int agp_generic_free_gatt_table(struct agp_bridge_data *bridge)
* called, then all agp memory is deallocated and removed
* from the table. */
+#ifdef CONFIG_X86
+ set_memory_wb((unsigned long)bridge->gatt_table, 1 << page_order);
+#else
iounmap(bridge->gatt_table);
+#endif
table = (char *) bridge->gatt_table_real;
table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1);
diff --git a/drivers/char/agp/sis-agp.c b/drivers/char/agp/sis-agp.c
index eb1a1c73819..b6791846809 100644
--- a/drivers/char/agp/sis-agp.c
+++ b/drivers/char/agp/sis-agp.c
@@ -14,6 +14,9 @@
#define SIS_TLBCNTRL 0x97
#define SIS_TLBFLUSH 0x98
+#define PCI_DEVICE_ID_SI_662 0x0662
+#define PCI_DEVICE_ID_SI_671 0x0671
+
static int __devinitdata agp_sis_force_delay = 0;
static int __devinitdata agp_sis_agp_spec = -1;
@@ -27,8 +30,8 @@ static int sis_fetch_size(void)
values = A_SIZE_8(agp_bridge->driver->aperture_sizes);
for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {
if ((temp_size == values[i].size_value) ||
- ((temp_size & ~(0x03)) ==
- (values[i].size_value & ~(0x03)))) {
+ ((temp_size & ~(0x07)) ==
+ (values[i].size_value & ~(0x07)))) {
agp_bridge->previous_size =
agp_bridge->current_size = (void *) (values + i);
@@ -214,6 +217,26 @@ static void __devexit agp_sis_remove(struct pci_dev *pdev)
agp_put_bridge(bridge);
}
+#ifdef CONFIG_PM
+
+static int agp_sis_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ pci_save_state(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+ return 0;
+}
+
+static int agp_sis_resume(struct pci_dev *pdev)
+{
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+
+ return sis_driver.configure();
+}
+
+#endif /* CONFIG_PM */
+
static struct pci_device_id agp_sis_pci_table[] = {
{
.class = (PCI_CLASS_BRIDGE_HOST << 8),
@@ -331,6 +354,22 @@ static struct pci_device_id agp_sis_pci_table[] = {
.class = (PCI_CLASS_BRIDGE_HOST << 8),
.class_mask = ~0,
.vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_662,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_671,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
.device = PCI_DEVICE_ID_SI_730,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
@@ -393,6 +432,10 @@ static struct pci_driver agp_sis_pci_driver = {
.id_table = agp_sis_pci_table,
.probe = agp_sis_probe,
.remove = agp_sis_remove,
+#ifdef CONFIG_PM
+ .suspend = agp_sis_suspend,
+ .resume = agp_sis_resume,
+#endif
};
static int __init agp_sis_init(void)
diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c
index 551ef25063e..e08934e58f3 100644
--- a/drivers/char/agp/sworks-agp.c
+++ b/drivers/char/agp/sworks-agp.c
@@ -52,28 +52,20 @@ static int serverworks_create_page_map(struct serverworks_page_map *page_map)
if (page_map->real == NULL) {
return -ENOMEM;
}
- SetPageReserved(virt_to_page(page_map->real));
- global_cache_flush();
- page_map->remapped = ioremap_nocache(virt_to_gart(page_map->real),
- PAGE_SIZE);
- if (page_map->remapped == NULL) {
- ClearPageReserved(virt_to_page(page_map->real));
- free_page((unsigned long) page_map->real);
- page_map->real = NULL;
- return -ENOMEM;
- }
- global_cache_flush();
+
+ set_memory_uc((unsigned long)page_map->real, 1);
+ page_map->remapped = page_map->real;
for (i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++)
writel(agp_bridge->scratch_page, page_map->remapped+i);
+ /* Red Pen: Everyone else does pci posting flush here */
return 0;
}
static void serverworks_free_page_map(struct serverworks_page_map *page_map)
{
- iounmap(page_map->remapped);
- ClearPageReserved(virt_to_page(page_map->real));
+ set_memory_wb((unsigned long)page_map->real, 1);
free_page((unsigned long) page_map->real);
}
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
index 19d3be5c4b2..a6789f25009 100644
--- a/drivers/char/drm/drmP.h
+++ b/drivers/char/drm/drmP.h
@@ -568,7 +568,7 @@ struct drm_driver {
void (*postclose) (struct drm_device *, struct drm_file *);
void (*lastclose) (struct drm_device *);
int (*unload) (struct drm_device *);
- int (*suspend) (struct drm_device *);
+ int (*suspend) (struct drm_device *, pm_message_t state);
int (*resume) (struct drm_device *);
int (*dma_ioctl) (struct drm_device *dev, void *data, struct drm_file *file_priv);
void (*dma_ready) (struct drm_device *);
diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h
index f5246884367..715b361f0c2 100644
--- a/drivers/char/drm/drm_pciids.h
+++ b/drivers/char/drm/drm_pciids.h
@@ -83,6 +83,7 @@
{0x1002, 0x5460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
{0x1002, 0x5462, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
{0x1002, 0x5464, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
+ {0x1002, 0x5657, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
{0x1002, 0x5548, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
{0x1002, 0x5549, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
{0x1002, 0x554A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
@@ -236,6 +237,7 @@
{0x1002, 0x7297, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV560|RADEON_NEW_MEMMAP}, \
{0x1002, 0x7834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_NEW_MEMMAP}, \
{0x1002, 0x7835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x791e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS690|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART}, \
{0, 0, 0}
#define r128_PCI_IDS \
@@ -313,6 +315,7 @@
{0x1039, 0x5300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1039, 0x6300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1039, 0x6330, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_CHIP_315}, \
+ {0x1039, 0x6351, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1039, 0x7300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x18CA, 0x0040, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_CHIP_315}, \
{0x18CA, 0x0042, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_CHIP_315}, \
diff --git a/drivers/char/drm/drm_sysfs.c b/drivers/char/drm/drm_sysfs.c
index fa36153619e..05ed5043254 100644
--- a/drivers/char/drm/drm_sysfs.c
+++ b/drivers/char/drm/drm_sysfs.c
@@ -36,7 +36,7 @@ static int drm_sysfs_suspend(struct device *dev, pm_message_t state)
printk(KERN_ERR "%s\n", __FUNCTION__);
if (drm_dev->driver->suspend)
- return drm_dev->driver->suspend(drm_dev);
+ return drm_dev->driver->suspend(drm_dev, state);
return 0;
}
diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c
index cea4105374b..3d65c4dcd0c 100644
--- a/drivers/char/drm/drm_vm.c
+++ b/drivers/char/drm/drm_vm.c
@@ -66,7 +66,7 @@ static pgprot_t drm_io_prot(uint32_t map_type, struct vm_area_struct *vma)
}
/**
- * \c nopage method for AGP virtual memory.
+ * \c fault method for AGP virtual memory.
*
* \param vma virtual memory area.
* \param address access address.
@@ -76,8 +76,7 @@ static pgprot_t drm_io_prot(uint32_t map_type, struct vm_area_struct *vma)
* map, get the page, increment the use count and return it.
*/
#if __OS_HAS_AGP
-static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma,
- unsigned long address)
+static int drm_do_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
struct drm_file *priv = vma->vm_file->private_data;
struct drm_device *dev = priv->head->dev;
@@ -89,19 +88,24 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma,
* Find the right map
*/
if (!drm_core_has_AGP(dev))
- goto vm_nopage_error;
+ goto vm_fault_error;
if (!dev->agp || !dev->agp->cant_use_aperture)
- goto vm_nopage_error;
+ goto vm_fault_error;
if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff, &hash))
- goto vm_nopage_error;
+ goto vm_fault_error;
r_list = drm_hash_entry(hash, struct drm_map_list, hash);
map = r_list->map;
if (map && map->type == _DRM_AGP) {
- unsigned long offset = address - vma->vm_start;
+ /*
+ * Using vm_pgoff as a selector forces us to use this unusual
+ * addressing scheme.
+ */
+ unsigned long offset = (unsigned long)vmf->virtual_address -
+ vma->vm_start;
unsigned long baddr = map->offset + offset;
struct drm_agp_mem *agpmem;
struct page *page;
@@ -123,7 +127,7 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma,
}
if (!agpmem)
- goto vm_nopage_error;
+ goto vm_fault_error;
/*
* Get the page, inc the use count, and return it
@@ -131,22 +135,21 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma,
offset = (baddr - agpmem->bound) >> PAGE_SHIFT;
page = virt_to_page(__va(agpmem->memory->memory[offset]));
get_page(page);
+ vmf->page = page;
DRM_DEBUG
("baddr = 0x%lx page = 0x%p, offset = 0x%lx, count=%d\n",
baddr, __va(agpmem->memory->memory[offset]), offset,
page_count(page));
-
- return page;
+ return 0;
}
- vm_nopage_error:
- return NOPAGE_SIGBUS; /* Disallow mremap */
+vm_fault_error:
+ return VM_FAULT_SIGBUS; /* Disallow mremap */
}
#else /* __OS_HAS_AGP */
-static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma,
- unsigned long address)
+static int drm_do_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
- return NOPAGE_SIGBUS;
+ return VM_FAULT_SIGBUS;
}
#endif /* __OS_HAS_AGP */
@@ -160,28 +163,26 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma,
* Get the mapping, find the real physical page to map, get the page, and
* return it.
*/
-static __inline__ struct page *drm_do_vm_shm_nopage(struct vm_area_struct *vma,
- unsigned long address)
+static int drm_do_vm_shm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
struct drm_map *map = (struct drm_map *) vma->vm_private_data;
unsigned long offset;
unsigned long i;
struct page *page;
- if (address > vma->vm_end)
- return NOPAGE_SIGBUS; /* Disallow mremap */
if (!map)
- return NOPAGE_SIGBUS; /* Nothing allocated */
+ return VM_FAULT_SIGBUS; /* Nothing allocated */
- offset = address - vma->vm_start;
+ offset = (unsigned long)vmf->virtual_address - vma->vm_start;
i = (unsigned long)map->handle + offset;
page = vmalloc_to_page((void *)i);
if (!page)
- return NOPAGE_SIGBUS;
+ return VM_FAULT_SIGBUS;
get_page(page);
+ vmf->page = page;
- DRM_DEBUG("0x%lx\n", address);
- return page;
+ DRM_DEBUG("shm_fault 0x%lx\n", offset);
+ return 0;
}
/**
@@ -263,7 +264,7 @@ static void drm_vm_shm_close(struct vm_area_struct *vma)
}
/**
- * \c nopage method for DMA virtual memory.
+ * \c fault method for DMA virtual memory.
*
* \param vma virtual memory area.
* \param address access address.
@@ -271,8 +272,7 @@ static void drm_vm_shm_close(struct vm_area_struct *vma)
*
* Determine the page number from the page offset and get it from drm_device_dma::pagelist.
*/
-static __inline__ struct page *drm_do_vm_dma_nopage(struct vm_area_struct *vma,
- unsigned long address)
+static int drm_do_vm_dma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
struct drm_file *priv = vma->vm_file->private_data;
struct drm_device *dev = priv->head->dev;
@@ -282,24 +282,23 @@ static __inline__ struct page *drm_do_vm_dma_nopage(struct vm_area_struct *vma,
struct page *page;
if (!dma)
- return NOPAGE_SIGBUS; /* Error */
- if (address > vma->vm_end)
- return NOPAGE_SIGBUS; /* Disallow mremap */
+ return VM_FAULT_SIGBUS; /* Error */
if (!dma->pagelist)
- return NOPAGE_SIGBUS; /* Nothing allocated */
+ return VM_FAULT_SIGBUS; /* Nothing allocated */
- offset = address - vma->vm_start; /* vm_[pg]off[set] should be 0 */
- page_nr = offset >> PAGE_SHIFT;
+ offset = (unsigned long)vmf->virtual_address - vma->vm_start; /* vm_[pg]off[set] should be 0 */
+ page_nr = offset >> PAGE_SHIFT; /* page_nr could just be vmf->pgoff */
page = virt_to_page((dma->pagelist[page_nr] + (offset & (~PAGE_MASK))));
get_page(page);
+ vmf->page = page;
- DRM_DEBUG("0x%lx (page %lu)\n", address, page_nr);
- return page;
+ DRM_DEBUG("dma_fault 0x%lx (page %lu)\n", offset, page_nr);
+ return 0;
}
/**
- * \c nopage method for scatter-gather virtual memory.
+ * \c fault method for scatter-gather virtual memory.
*
* \param vma virtual memory area.
* \param address access address.
@@ -307,8 +306,7 @@ static __inline__ struct page *drm_do_vm_dma_nopage(struct vm_area_struct *vma,
*
* Determine the map offset from the page offset and get it from drm_sg_mem::pagelist.
*/
-static __inline__ struct page *drm_do_vm_sg_nopage(struct vm_area_struct *vma,
- unsigned long address)
+static int drm_do_vm_sg_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
struct drm_map *map = (struct drm_map *) vma->vm_private_data;
struct drm_file *priv = vma->vm_file->private_data;
@@ -320,77 +318,64 @@ static __inline__ struct page *drm_do_vm_sg_nopage(struct vm_area_struct *vma,
struct page *page;
if (!entry)
- return NOPAGE_SIGBUS; /* Error */
- if (address > vma->vm_end)
- return NOPAGE_SIGBUS; /* Disallow mremap */
+ return VM_FAULT_SIGBUS; /* Error */
if (!entry->pagelist)
- return NOPAGE_SIGBUS; /* Nothing allocated */
+ return VM_FAULT_SIGBUS; /* Nothing allocated */
- offset = address - vma->vm_start;
+ offset = (unsigned long)vmf->virtual_address - vma->vm_start;
map_offset = map->offset - (unsigned long)dev->sg->virtual;
page_offset = (offset >> PAGE_SHIFT) + (map_offset >> PAGE_SHIFT);
page = entry->pagelist[page_offset];
get_page(page);
+ vmf->page = page;
- return page;
+ return 0;
}
-static struct page *drm_vm_nopage(struct vm_area_struct *vma,
- unsigned long address, int *type)
+static int drm_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
- if (type)
- *type = VM_FAULT_MINOR;
- return drm_do_vm_nopage(vma, address);
+ return drm_do_vm_fault(vma, vmf);
}
-static struct page *drm_vm_shm_nopage(struct vm_area_struct *vma,
- unsigned long address, int *type)
+static int drm_vm_shm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
- if (type)
- *type = VM_FAULT_MINOR;
- return drm_do_vm_shm_nopage(vma, address);
+ return drm_do_vm_shm_fault(vma, vmf);
}
-static struct page *drm_vm_dma_nopage(struct vm_area_struct *vma,
- unsigned long address, int *type)
+static int drm_vm_dma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
- if (type)
- *type = VM_FAULT_MINOR;
- return drm_do_vm_dma_nopage(vma, address);
+ return drm_do_vm_dma_fault(vma, vmf);
}
-static struct page *drm_vm_sg_nopage(struct vm_area_struct *vma,
- unsigned long address, int *type)
+static int drm_vm_sg_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
- if (type)
- *type = VM_FAULT_MINOR;
- return drm_do_vm_sg_nopage(vma, address);
+ return drm_do_vm_sg_fault(vma, vmf);
}
/** AGP virtual memory operations */
static struct vm_operations_struct drm_vm_ops = {
- .nopage = drm_vm_nopage,
+ .fault = drm_vm_fault,
.open = drm_vm_open,
.close = drm_vm_close,
};
/** Shared virtual memory operations */
static struct vm_operations_struct drm_vm_shm_ops = {
- .nopage = drm_vm_shm_nopage,
+ .fault = drm_vm_shm_fault,
.open = drm_vm_open,
.close = drm_vm_shm_close,
};
/** DMA virtual memory operations */
static struct vm_operations_struct drm_vm_dma_ops = {
- .nopage = drm_vm_dma_nopage,
+ .fault = drm_vm_dma_fault,
.open = drm_vm_open,
.close = drm_vm_close,
};
/** Scatter-gather virtual memory operations */
static struct vm_operations_struct drm_vm_sg_ops = {
- .nopage = drm_vm_sg_nopage,
+ .fault = drm_vm_sg_fault,
.open = drm_vm_open,
.close = drm_vm_close,
};
@@ -604,7 +589,7 @@ static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
/*
* On some platforms we can't talk to bus dma address from the CPU, so for
* memory of type DRM_AGP, we'll deal with sorting out the real physical
- * pages and mappings in nopage()
+ * pages and mappings in fault()
*/
#if defined(__powerpc__)
pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
@@ -634,7 +619,7 @@ static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
break;
case _DRM_CONSISTENT:
/* Consistent memory is really like shared memory. But
- * it's allocated in a different way, so avoid nopage */
+ * it's allocated in a different way, so avoid fault */
if (remap_pfn_range(vma, vma->vm_start,
page_to_pfn(virt_to_page(map->handle)),
vma->vm_end - vma->vm_start, vma->vm_page_prot))
diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c
index 43986d81ae3..e9d6663bec7 100644
--- a/drivers/char/drm/i915_dma.c
+++ b/drivers/char/drm/i915_dma.c
@@ -171,7 +171,7 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
dev_priv->allow_batchbuffer = 1;
/* Program Hardware Status Page */
- if (!IS_G33(dev)) {
+ if (!I915_NEED_GFX_HWS(dev)) {
dev_priv->status_page_dmah =
drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 0xffffffff);
@@ -720,6 +720,9 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
drm_i915_private_t *dev_priv = dev->dev_private;
drm_i915_hws_addr_t *hws = data;
+ if (!I915_NEED_GFX_HWS(dev))
+ return -EINVAL;
+
if (!dev_priv) {
DRM_ERROR("called with no initialization\n");
return -EINVAL;
diff --git a/drivers/char/drm/i915_drv.c b/drivers/char/drm/i915_drv.c
index 52e51033d32..b2b451dc446 100644
--- a/drivers/char/drm/i915_drv.c
+++ b/drivers/char/drm/i915_drv.c
@@ -160,6 +160,7 @@ static void i915_save_vga(struct drm_device *dev)
dev_priv->saveAR[i] = i915_read_ar(st01, i, 0);
inb(st01);
outb(dev_priv->saveAR_INDEX, VGA_AR_INDEX);
+ inb(st01);
/* Graphics controller registers */
for (i = 0; i < 9; i++)
@@ -221,10 +222,12 @@ static void i915_restore_vga(struct drm_device *dev)
dev_priv->saveGR[0x18]);
/* Attribute controller registers */
+ inb(st01);
for (i = 0; i < 20; i++)
i915_write_ar(st01, i, dev_priv->saveAR[i], 0);
inb(st01); /* switch back to index mode */
outb(dev_priv->saveAR_INDEX | 0x20, VGA_AR_INDEX);
+ inb(st01);
/* VGA color palette registers */
outb(dev_priv->saveDACMASK, VGA_DACMASK);
@@ -236,7 +239,7 @@ static void i915_restore_vga(struct drm_device *dev)
}
-static int i915_suspend(struct drm_device *dev)
+static int i915_suspend(struct drm_device *dev, pm_message_t state)
{
struct drm_i915_private *dev_priv = dev->dev_private;
int i;
@@ -247,6 +250,9 @@ static int i915_suspend(struct drm_device *dev)
return -ENODEV;
}
+ if (state.event == PM_EVENT_PRETHAW)
+ return 0;
+
pci_save_state(dev->pdev);
pci_read_config_byte(dev->pdev, LBB, &dev_priv->saveLBB);
@@ -276,6 +282,7 @@ static int i915_suspend(struct drm_device *dev)
dev_priv->saveDSPATILEOFF = I915_READ(DSPATILEOFF);
}
i915_save_palette(dev, PIPE_A);
+ dev_priv->savePIPEASTAT = I915_READ(I915REG_PIPEASTAT);
/* Pipe & plane B info */
dev_priv->savePIPEBCONF = I915_READ(PIPEBCONF);
@@ -303,6 +310,7 @@ static int i915_suspend(struct drm_device *dev)
dev_priv->saveDSPBTILEOFF = I915_READ(DSPBTILEOFF);
}
i915_save_palette(dev, PIPE_B);
+ dev_priv->savePIPEBSTAT = I915_READ(I915REG_PIPEBSTAT);
/* CRT state */
dev_priv->saveADPA = I915_READ(ADPA);
@@ -329,12 +337,26 @@ static int i915_suspend(struct drm_device *dev)
dev_priv->saveFBC_CONTROL2 = I915_READ(FBC_CONTROL2);
dev_priv->saveFBC_CONTROL = I915_READ(FBC_CONTROL);
+ /* Interrupt state */
+ dev_priv->saveIIR = I915_READ(I915REG_INT_IDENTITY_R);
+ dev_priv->saveIER = I915_READ(I915REG_INT_ENABLE_R);
+ dev_priv->saveIMR = I915_READ(I915REG_INT_MASK_R);
+
/* VGA state */
dev_priv->saveVCLK_DIVISOR_VGA0 = I915_READ(VCLK_DIVISOR_VGA0);
dev_priv->saveVCLK_DIVISOR_VGA1 = I915_READ(VCLK_DIVISOR_VGA1);
dev_priv->saveVCLK_POST_DIV = I915_READ(VCLK_POST_DIV);
dev_priv->saveVGACNTRL = I915_READ(VGACNTRL);
+ /* Clock gating state */
+ dev_priv->saveDSPCLK_GATE_D = I915_READ(DSPCLK_GATE_D);
+
+ /* Cache mode state */
+ dev_priv->saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0);
+
+ /* Memory Arbitration state */
+ dev_priv->saveMI_ARB_STATE = I915_READ(MI_ARB_STATE);
+
/* Scratch space */
for (i = 0; i < 16; i++) {
dev_priv->saveSWF0[i] = I915_READ(SWF0 + (i << 2));
@@ -345,9 +367,11 @@ static int i915_suspend(struct drm_device *dev)
i915_save_vga(dev);
- /* Shut down the device */
- pci_disable_device(dev->pdev);
- pci_set_power_state(dev->pdev, PCI_D3hot);
+ if (state.event == PM_EVENT_SUSPEND) {
+ /* Shut down the device */
+ pci_disable_device(dev->pdev);
+ pci_set_power_state(dev->pdev, PCI_D3hot);
+ }
return 0;
}
@@ -400,9 +424,7 @@ static int i915_resume(struct drm_device *dev)
I915_WRITE(DSPATILEOFF, dev_priv->saveDSPATILEOFF);
}
- if ((dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) &&
- (dev_priv->saveDPLL_A & DPLL_VGA_MODE_DIS))
- I915_WRITE(PIPEACONF, dev_priv->savePIPEACONF);
+ I915_WRITE(PIPEACONF, dev_priv->savePIPEACONF);
i915_restore_palette(dev, PIPE_A);
/* Enable the plane */
@@ -444,10 +466,9 @@ static int i915_resume(struct drm_device *dev)
I915_WRITE(DSPBTILEOFF, dev_priv->saveDSPBTILEOFF);
}
- if ((dev_priv->saveDPLL_B & DPLL_VCO_ENABLE) &&
- (dev_priv->saveDPLL_B & DPLL_VGA_MODE_DIS))
- I915_WRITE(PIPEBCONF, dev_priv->savePIPEBCONF);
- i915_restore_palette(dev, PIPE_A);
+ I915_WRITE(PIPEBCONF, dev_priv->savePIPEBCONF);
+
+ i915_restore_palette(dev, PIPE_B);
/* Enable the plane */
I915_WRITE(DSPBCNTR, dev_priv->saveDSPBCNTR);
I915_WRITE(DSPBBASE, I915_READ(DSPBBASE));
@@ -485,6 +506,15 @@ static int i915_resume(struct drm_device *dev)
I915_WRITE(VCLK_POST_DIV, dev_priv->saveVCLK_POST_DIV);
udelay(150);
+ /* Clock gating state */
+ I915_WRITE (DSPCLK_GATE_D, dev_priv->saveDSPCLK_GATE_D);
+
+ /* Cache mode state */
+ I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000);
+
+ /* Memory arbitration state */
+ I915_WRITE (MI_ARB_STATE, dev_priv->saveMI_ARB_STATE | 0xffff0000);
+
for (i = 0; i < 16; i++) {
I915_WRITE(SWF0 + (i << 2), dev_priv->saveSWF0[i]);
I915_WRITE(SWF10 + (i << 2), dev_priv->saveSWF1[i+7]);
diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h
index f8308bfb261..c10d128e34d 100644
--- a/drivers/char/drm/i915_drv.h
+++ b/drivers/char/drm/i915_drv.h
@@ -134,6 +134,7 @@ typedef struct drm_i915_private {
u32 saveVBLANK_A;
u32 saveVSYNC_A;
u32 saveBCLRPAT_A;
+ u32 savePIPEASTAT;
u32 saveDSPASTRIDE;
u32 saveDSPASIZE;
u32 saveDSPAPOS;
@@ -154,6 +155,7 @@ typedef struct drm_i915_private {
u32 saveVBLANK_B;
u32 saveVSYNC_B;
u32 saveBCLRPAT_B;
+ u32 savePIPEBSTAT;
u32 saveDSPBSTRIDE;
u32 saveDSPBSIZE;
u32 saveDSPBPOS;
@@ -182,6 +184,12 @@ typedef struct drm_i915_private {
u32 saveFBC_LL_BASE;
u32 saveFBC_CONTROL;
u32 saveFBC_CONTROL2;
+ u32 saveIER;
+ u32 saveIIR;
+ u32 saveIMR;
+ u32 saveCACHE_MODE_0;
+ u32 saveDSPCLK_GATE_D;
+ u32 saveMI_ARB_STATE;
u32 saveSWF0[16];
u32 saveSWF1[16];
u32 saveSWF2[3];
@@ -450,6 +458,10 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
*/
#define DMA_FADD_S 0x20d4
+/* Memory Interface Arbitration State
+ */
+#define MI_ARB_STATE 0x20e4
+
/* Cache mode 0 reg.
* - Manipulating render cache behaviour is central
* to the concept of zone rendering, tuning this reg can help avoid
@@ -460,6 +472,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
* bit of interest either set or cleared. EG: (BIT<<16) | BIT to set.
*/
#define Cache_Mode_0 0x2120
+#define CACHE_MODE_0 0x2120
#define CM0_MASK_SHIFT 16
#define CM0_IZ_OPT_DISABLE (1<<6)
#define CM0_ZR_OPT_DISABLE (1<<5)
@@ -655,6 +668,8 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
/** P1 value is 2 greater than this field */
# define VGA0_PD_P1_MASK (0x1f << 0)
+#define DSPCLK_GATE_D 0x6200
+
/* I830 CRTC registers */
#define HTOTAL_A 0x60000
#define HBLANK_A 0x60004
@@ -1101,6 +1116,8 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
#define IS_MOBILE(dev) (IS_I830(dev) || IS_I85X(dev) || IS_I915GM(dev) || \
IS_I945GM(dev) || IS_I965GM(dev) || IS_IGD_GM(dev))
+#define I915_NEED_GFX_HWS(dev) (IS_G33(dev) || IS_IGD_GM(dev))
+
#define PRIMARY_RINGBUFFER_SIZE (128*1024)
#endif
diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c
index 5dc799ab86b..833abc7e55f 100644
--- a/drivers/char/drm/radeon_cp.c
+++ b/drivers/char/drm/radeon_cp.c
@@ -825,11 +825,19 @@ static u32 RADEON_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
return ret;
}
+static u32 RS690_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
+{
+ RADEON_WRITE(RS690_MC_INDEX, (addr & RS690_MC_INDEX_MASK));
+ return RADEON_READ(RS690_MC_DATA);
+}
+
u32 radeon_read_fb_location(drm_radeon_private_t *dev_priv)
{
if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
return RADEON_READ_MCIND(dev_priv, RV515_MC_FB_LOCATION);
+ else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690)
+ return RS690_READ_MCIND(dev_priv, RS690_MC_FB_LOCATION);
else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
return RADEON_READ_MCIND(dev_priv, R520_MC_FB_LOCATION);
else
@@ -840,6 +848,8 @@ static void radeon_write_fb_location(drm_radeon_private_t *dev_priv, u32 fb_loc)
{
if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
RADEON_WRITE_MCIND(RV515_MC_FB_LOCATION, fb_loc);
+ else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690)
+ RS690_WRITE_MCIND(RS690_MC_FB_LOCATION, fb_loc);
else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
RADEON_WRITE_MCIND(R520_MC_FB_LOCATION, fb_loc);
else
@@ -850,6 +860,8 @@ static void radeon_write_agp_location(drm_radeon_private_t *dev_priv, u32 agp_lo
{
if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
RADEON_WRITE_MCIND(RV515_MC_AGP_LOCATION, agp_loc);
+ else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690)
+ RS690_WRITE_MCIND(RS690_MC_AGP_LOCATION, agp_loc);
else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
RADEON_WRITE_MCIND(R520_MC_AGP_LOCATION, agp_loc);
else
@@ -1362,6 +1374,70 @@ static void radeon_set_igpgart(drm_radeon_private_t * dev_priv, int on)
}
}
+/* Enable or disable RS690 GART on the chip */
+static void radeon_set_rs690gart(drm_radeon_private_t *dev_priv, int on)
+{
+ u32 temp;
+
+ if (on) {
+ DRM_DEBUG("programming rs690 gart %08X %08lX %08X\n",
+ dev_priv->gart_vm_start,
+ (long)dev_priv->gart_info.bus_addr,
+ dev_priv->gart_size);
+
+ temp = RS690_READ_MCIND(dev_priv, RS690_MC_MISC_CNTL);
+ RS690_WRITE_MCIND(RS690_MC_MISC_CNTL, 0x5000);
+
+ RS690_WRITE_MCIND(RS690_MC_AGP_SIZE,
+ RS690_MC_GART_EN | RS690_MC_AGP_SIZE_32MB);
+
+ temp = RS690_READ_MCIND(dev_priv, RS690_MC_GART_FEATURE_ID);
+ RS690_WRITE_MCIND(RS690_MC_GART_FEATURE_ID, 0x42040800);
+
+ RS690_WRITE_MCIND(RS690_MC_GART_BASE,
+ dev_priv->gart_info.bus_addr);
+
+ temp = RS690_READ_MCIND(dev_priv, RS690_MC_AGP_MODE_CONTROL);
+ RS690_WRITE_MCIND(RS690_MC_AGP_MODE_CONTROL, 0x01400000);
+
+ RS690_WRITE_MCIND(RS690_MC_AGP_BASE,
+ (unsigned int)dev_priv->gart_vm_start);
+
+ dev_priv->gart_size = 32*1024*1024;
+ temp = (((dev_priv->gart_vm_start - 1 + dev_priv->gart_size) &
+ 0xffff0000) | (dev_priv->gart_vm_start >> 16));
+
+ RS690_WRITE_MCIND(RS690_MC_AGP_LOCATION, temp);
+
+ temp = RS690_READ_MCIND(dev_priv, RS690_MC_AGP_SIZE);
+ RS690_WRITE_MCIND(RS690_MC_AGP_SIZE,
+ RS690_MC_GART_EN | RS690_MC_AGP_SIZE_32MB);
+
+ do {
+ temp = RS690_READ_MCIND(dev_priv, RS690_MC_GART_CACHE_CNTL);
+ if ((temp & RS690_MC_GART_CLEAR_STATUS) ==
+ RS690_MC_GART_CLEAR_DONE)
+ break;
+ DRM_UDELAY(1);
+ } while (1);
+
+ RS690_WRITE_MCIND(RS690_MC_GART_CACHE_CNTL,
+ RS690_MC_GART_CC_CLEAR);
+ do {
+ temp = RS690_READ_MCIND(dev_priv, RS690_MC_GART_CACHE_CNTL);
+ if ((temp & RS690_MC_GART_CLEAR_STATUS) ==
+ RS690_MC_GART_CLEAR_DONE)
+ break;
+ DRM_UDELAY(1);
+ } while (1);
+
+ RS690_WRITE_MCIND(RS690_MC_GART_CACHE_CNTL,
+ RS690_MC_GART_CC_NO_CHANGE);
+ } else {
+ RS690_WRITE_MCIND(RS690_MC_AGP_SIZE, RS690_MC_GART_DIS);
+ }
+}
+
static void radeon_set_pciegart(drm_radeon_private_t * dev_priv, int on)
{
u32 tmp = RADEON_READ_PCIE(dev_priv, RADEON_PCIE_TX_GART_CNTL);
@@ -1396,6 +1472,11 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on)
{
u32 tmp;
+ if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) {
+ radeon_set_rs690gart(dev_priv, on);
+ return;
+ }
+
if (dev_priv->flags & RADEON_IS_IGPGART) {
radeon_set_igpgart(dev_priv, on);
return;
diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h
index 4434332c79b..173ae620223 100644
--- a/drivers/char/drm/radeon_drv.h
+++ b/drivers/char/drm/radeon_drv.h
@@ -123,6 +123,7 @@ enum radeon_family {
CHIP_R420,
CHIP_RV410,
CHIP_RS400,
+ CHIP_RS690,
CHIP_RV515,
CHIP_R520,
CHIP_RV530,
@@ -467,6 +468,36 @@ extern int r300_do_cp_cmdbuf(struct drm_device * dev,
#define RADEON_IGPGART_ENABLE 0x38
#define RADEON_IGPGART_UNK_39 0x39
+#define RS690_MC_INDEX 0x78
+# define RS690_MC_INDEX_MASK 0x1ff
+# define RS690_MC_INDEX_WR_EN (1 << 9)
+# define RS690_MC_INDEX_WR_ACK 0x7f
+#define RS690_MC_DATA 0x7c
+
+#define RS690_MC_MISC_CNTL 0x18
+#define RS690_MC_GART_FEATURE_ID 0x2b
+#define RS690_MC_GART_BASE 0x2c
+#define RS690_MC_GART_CACHE_CNTL 0x2e
+# define RS690_MC_GART_CC_NO_CHANGE 0x0
+# define RS690_MC_GART_CC_CLEAR 0x1
+# define RS690_MC_GART_CLEAR_STATUS (1 << 1)
+# define RS690_MC_GART_CLEAR_DONE (0 << 1)
+# define RS690_MC_GART_CLEAR_PENDING (1 << 1)
+#define RS690_MC_AGP_SIZE 0x38
+# define RS690_MC_GART_DIS 0x0
+# define RS690_MC_GART_EN 0x1
+# define RS690_MC_AGP_SIZE_32MB (0 << 1)
+# define RS690_MC_AGP_SIZE_64MB (1 << 1)
+# define RS690_MC_AGP_SIZE_128MB (2 << 1)
+# define RS690_MC_AGP_SIZE_256MB (3 << 1)
+# define RS690_MC_AGP_SIZE_512MB (4 << 1)
+# define RS690_MC_AGP_SIZE_1GB (5 << 1)
+# define RS690_MC_AGP_SIZE_2GB (6 << 1)
+#define RS690_MC_AGP_MODE_CONTROL 0x39
+#define RS690_MC_FB_LOCATION 0x100
+#define RS690_MC_AGP_LOCATION 0x101
+#define RS690_MC_AGP_BASE 0x102
+
#define R520_MC_IND_INDEX 0x70
#define R520_MC_IND_WR_EN (1<<24)
#define R520_MC_IND_DATA 0x74
@@ -1076,6 +1107,13 @@ do { \
RADEON_WRITE(R520_MC_IND_INDEX, 0); \
} while (0)
+#define RS690_WRITE_MCIND( addr, val ) \
+do { \
+ RADEON_WRITE(RS690_MC_INDEX, RS690_MC_INDEX_WR_EN | ((addr) & RS690_MC_INDEX_MASK)); \
+ RADEON_WRITE(RS690_MC_DATA, val); \
+ RADEON_WRITE(RS690_MC_INDEX, RS690_MC_INDEX_WR_ACK); \
+} while (0)
+
#define CP_PACKET0( reg, n ) \
(RADEON_CP_PACKET0 | ((n) << 16) | ((reg) >> 2))
#define CP_PACKET0_TABLE( reg, n ) \
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index 78b151c4d20..5c3142b6f1f 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -110,8 +110,8 @@ static int rtc_has_irq = 1;
#define hpet_set_rtc_irq_bit(arg) 0
#define hpet_rtc_timer_init() do { } while (0)
#define hpet_rtc_dropped_irq() 0
-#define hpet_register_irq_handler(h) 0
-#define hpet_unregister_irq_handler(h) 0
+#define hpet_register_irq_handler(h) ({ 0; })
+#define hpet_unregister_irq_handler(h) ({ 0; })
#ifdef RTC_IRQ
static irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id)
{
diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c
index fea2d3ed9cb..85e2ba7fcfb 100644
--- a/drivers/connector/connector.c
+++ b/drivers/connector/connector.c
@@ -47,7 +47,7 @@ static LIST_HEAD(notify_list);
static struct cn_dev cdev;
-int cn_already_initialized = 0;
+static int cn_already_initialized;
/*
* msg->seq and msg->ack are used to determine message genealogy.
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 64926aa990d..89a29cd9378 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -1006,14 +1006,6 @@ static int __cpufreq_remove_dev (struct sys_device * sys_dev)
}
#endif
-
- if (!kobject_get(&data->kobj)) {
- spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
- cpufreq_debug_enable_ratelimit();
- unlock_policy_rwsem_write(cpu);
- return -EFAULT;
- }
-
#ifdef CONFIG_SMP
#ifdef CONFIG_HOTPLUG_CPU
diff --git a/drivers/crypto/hifn_795x.c b/drivers/crypto/hifn_795x.c
index dfbf24c4033..3110bf7014f 100644
--- a/drivers/crypto/hifn_795x.c
+++ b/drivers/crypto/hifn_795x.c
@@ -463,7 +463,7 @@ struct hifn_device
unsigned int pk_clk_freq;
-#ifdef CRYPTO_DEV_HIFN_795X_RNG
+#ifdef CONFIG_CRYPTO_DEV_HIFN_795X_RNG
unsigned int rng_wait_time;
ktime_t rngtime;
struct hwrng rng;
@@ -795,7 +795,7 @@ static struct pci2id {
}
};
-#ifdef CRYPTO_DEV_HIFN_795X_RNG
+#ifdef CONFIG_CRYPTO_DEV_HIFN_795X_RNG
static int hifn_rng_data_present(struct hwrng *rng, int wait)
{
struct hifn_device *dev = (struct hifn_device *)rng->priv;
@@ -880,7 +880,7 @@ static int hifn_init_pubrng(struct hifn_device *dev)
dprintk("Chip %s: RNG engine has been successfully initialised.\n",
dev->name);
-#ifdef CRYPTO_DEV_HIFN_795X_RNG
+#ifdef CONFIG_CRYPTO_DEV_HIFN_795X_RNG
/* First value must be discarded */
hifn_read_1(dev, HIFN_1_RNG_DATA);
dev->rngtime = ktime_get();
diff --git a/drivers/firewire/fw-cdev.c b/drivers/firewire/fw-cdev.c
index 7e73cbaa412..46bc197a047 100644
--- a/drivers/firewire/fw-cdev.c
+++ b/drivers/firewire/fw-cdev.c
@@ -109,15 +109,17 @@ static int fw_device_op_open(struct inode *inode, struct file *file)
struct client *client;
unsigned long flags;
- device = fw_device_from_devt(inode->i_rdev);
+ device = fw_device_get_by_devt(inode->i_rdev);
if (device == NULL)
return -ENODEV;
client = kzalloc(sizeof(*client), GFP_KERNEL);
- if (client == NULL)
+ if (client == NULL) {
+ fw_device_put(device);
return -ENOMEM;
+ }
- client->device = fw_device_get(device);
+ client->device = device;
INIT_LIST_HEAD(&client->event_list);
INIT_LIST_HEAD(&client->resource_list);
spin_lock_init(&client->lock);
@@ -644,6 +646,10 @@ static int ioctl_create_iso_context(struct client *client, void *buffer)
struct fw_cdev_create_iso_context *request = buffer;
struct fw_iso_context *context;
+ /* We only support one context at this time. */
+ if (client->iso_context != NULL)
+ return -EBUSY;
+
if (request->channel > 63)
return -EINVAL;
@@ -790,8 +796,9 @@ static int ioctl_start_iso(struct client *client, void *buffer)
{
struct fw_cdev_start_iso *request = buffer;
- if (request->handle != 0)
+ if (client->iso_context == NULL || request->handle != 0)
return -EINVAL;
+
if (client->iso_context->type == FW_ISO_CONTEXT_RECEIVE) {
if (request->tags == 0 || request->tags > 15)
return -EINVAL;
@@ -808,7 +815,7 @@ static int ioctl_stop_iso(struct client *client, void *buffer)
{
struct fw_cdev_stop_iso *request = buffer;
- if (request->handle != 0)
+ if (client->iso_context == NULL || request->handle != 0)
return -EINVAL;
return fw_iso_context_stop(client->iso_context);
diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c
index de9066e69ad..2ab13e0f346 100644
--- a/drivers/firewire/fw-device.c
+++ b/drivers/firewire/fw-device.c
@@ -358,12 +358,9 @@ static ssize_t
guid_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct fw_device *device = fw_device(dev);
- u64 guid;
- guid = ((u64)device->config_rom[3] << 32) | device->config_rom[4];
-
- return snprintf(buf, PAGE_SIZE, "0x%016llx\n",
- (unsigned long long)guid);
+ return snprintf(buf, PAGE_SIZE, "0x%08x%08x\n",
+ device->config_rom[3], device->config_rom[4]);
}
static struct device_attribute fw_device_attributes[] = {
@@ -610,12 +607,14 @@ static DECLARE_RWSEM(idr_rwsem);
static DEFINE_IDR(fw_device_idr);
int fw_cdev_major;
-struct fw_device *fw_device_from_devt(dev_t devt)
+struct fw_device *fw_device_get_by_devt(dev_t devt)
{
struct fw_device *device;
down_read(&idr_rwsem);
device = idr_find(&fw_device_idr, MINOR(devt));
+ if (device)
+ fw_device_get(device);
up_read(&idr_rwsem);
return device;
@@ -627,13 +626,14 @@ static void fw_device_shutdown(struct work_struct *work)
container_of(work, struct fw_device, work.work);
int minor = MINOR(device->device.devt);
- down_write(&idr_rwsem);
- idr_remove(&fw_device_idr, minor);
- up_write(&idr_rwsem);
-
fw_device_cdev_remove(device);
device_for_each_child(&device->device, NULL, shutdown_unit);
device_unregister(&device->device);
+
+ down_write(&idr_rwsem);
+ idr_remove(&fw_device_idr, minor);
+ up_write(&idr_rwsem);
+ fw_device_put(device);
}
static struct device_type fw_device_type = {
@@ -682,10 +682,13 @@ static void fw_device_init(struct work_struct *work)
}
err = -ENOMEM;
+
+ fw_device_get(device);
down_write(&idr_rwsem);
if (idr_pre_get(&fw_device_idr, GFP_KERNEL))
err = idr_get_new(&fw_device_idr, device, &minor);
up_write(&idr_rwsem);
+
if (err < 0)
goto error;
@@ -717,13 +720,22 @@ static void fw_device_init(struct work_struct *work)
*/
if (atomic_cmpxchg(&device->state,
FW_DEVICE_INITIALIZING,
- FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN)
+ FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN) {
fw_device_shutdown(&device->work.work);
- else
- fw_notify("created new fw device %s "
- "(%d config rom retries, S%d00)\n",
- device->device.bus_id, device->config_rom_retries,
- 1 << device->max_speed);
+ } else {
+ if (device->config_rom_retries)
+ fw_notify("created device %s: GUID %08x%08x, S%d00, "
+ "%d config ROM retries\n",
+ device->device.bus_id,
+ device->config_rom[3], device->config_rom[4],
+ 1 << device->max_speed,
+ device->config_rom_retries);
+ else
+ fw_notify("created device %s: GUID %08x%08x, S%d00\n",
+ device->device.bus_id,
+ device->config_rom[3], device->config_rom[4],
+ 1 << device->max_speed);
+ }
/*
* Reschedule the IRM work if we just finished reading the
@@ -741,7 +753,9 @@ static void fw_device_init(struct work_struct *work)
idr_remove(&fw_device_idr, minor);
up_write(&idr_rwsem);
error:
- put_device(&device->device);
+ fw_device_put(device); /* fw_device_idr's reference */
+
+ put_device(&device->device); /* our reference */
}
static int update_unit(struct device *dev, void *data)
diff --git a/drivers/firewire/fw-device.h b/drivers/firewire/fw-device.h
index 0854fe2bc11..43808c02793 100644
--- a/drivers/firewire/fw-device.h
+++ b/drivers/firewire/fw-device.h
@@ -77,13 +77,13 @@ fw_device_is_shutdown(struct fw_device *device)
}
struct fw_device *fw_device_get(struct fw_device *device);
+struct fw_device *fw_device_get_by_devt(dev_t devt);
void fw_device_put(struct fw_device *device);
int fw_device_enable_phys_dma(struct fw_device *device);
void fw_device_cdev_update(struct fw_device *device);
void fw_device_cdev_remove(struct fw_device *device);
-struct fw_device *fw_device_from_devt(dev_t devt);
extern int fw_cdev_major;
struct fw_unit {
diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c
index 19ece9b6d74..5259491580f 100644
--- a/drivers/firewire/fw-sbp2.c
+++ b/drivers/firewire/fw-sbp2.c
@@ -28,14 +28,15 @@
* and many others.
*/
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/mod_devicetable.h>
-#include <linux/device.h>
#include <linux/scatterlist.h>
-#include <linux/dma-mapping.h>
-#include <linux/blkdev.h>
#include <linux/string.h>
#include <linux/stringify.h>
#include <linux/timer.h>
@@ -47,9 +48,9 @@
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
-#include "fw-transaction.h"
-#include "fw-topology.h"
#include "fw-device.h"
+#include "fw-topology.h"
+#include "fw-transaction.h"
/*
* So far only bridges from Oxford Semiconductor are known to support
@@ -82,6 +83,9 @@ MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device "
* Avoids access beyond actual disk limits on devices with an off-by-one bug.
* Don't use this with devices which don't have this bug.
*
+ * - delay inquiry
+ * Wait extra SBP2_INQUIRY_DELAY seconds after login before SCSI inquiry.
+ *
* - override internal blacklist
* Instead of adding to the built-in blacklist, use only the workarounds
* specified in the module load parameter.
@@ -91,6 +95,8 @@ MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device "
#define SBP2_WORKAROUND_INQUIRY_36 0x2
#define SBP2_WORKAROUND_MODE_SENSE_8 0x4
#define SBP2_WORKAROUND_FIX_CAPACITY 0x8
+#define SBP2_WORKAROUND_DELAY_INQUIRY 0x10
+#define SBP2_INQUIRY_DELAY 12
#define SBP2_WORKAROUND_OVERRIDE 0x100
static int sbp2_param_workarounds;
@@ -100,6 +106,7 @@ MODULE_PARM_DESC(workarounds, "Work around device bugs (default = 0"
", 36 byte inquiry = " __stringify(SBP2_WORKAROUND_INQUIRY_36)
", skip mode page 8 = " __stringify(SBP2_WORKAROUND_MODE_SENSE_8)
", fix capacity = " __stringify(SBP2_WORKAROUND_FIX_CAPACITY)
+ ", delay inquiry = " __stringify(SBP2_WORKAROUND_DELAY_INQUIRY)
", override internal blacklist = " __stringify(SBP2_WORKAROUND_OVERRIDE)
", or a combination)");
@@ -132,6 +139,7 @@ struct sbp2_logical_unit {
int generation;
int retries;
struct delayed_work work;
+ bool blocked;
};
/*
@@ -141,16 +149,18 @@ struct sbp2_logical_unit {
struct sbp2_target {
struct kref kref;
struct fw_unit *unit;
+ const char *bus_id;
+ struct list_head lu_list;
u64 management_agent_address;
int directory_id;
int node_id;
int address_high;
-
- unsigned workarounds;
- struct list_head lu_list;
-
+ unsigned int workarounds;
unsigned int mgt_orb_timeout;
+
+ int dont_block; /* counter for each logical unit */
+ int blocked; /* ditto */
};
/*
@@ -160,7 +170,7 @@ struct sbp2_target {
*/
#define SBP2_MIN_LOGIN_ORB_TIMEOUT 5000U /* Timeout in ms */
#define SBP2_MAX_LOGIN_ORB_TIMEOUT 40000U /* Timeout in ms */
-#define SBP2_ORB_TIMEOUT 2000 /* Timeout in ms */
+#define SBP2_ORB_TIMEOUT 2000U /* Timeout in ms */
#define SBP2_ORB_NULL 0x80000000
#define SBP2_MAX_SG_ELEMENT_LENGTH 0xf000
@@ -297,7 +307,7 @@ struct sbp2_command_orb {
static const struct {
u32 firmware_revision;
u32 model;
- unsigned workarounds;
+ unsigned int workarounds;
} sbp2_workarounds_table[] = {
/* DViCO Momobay CX-1 with TSB42AA9 bridge */ {
.firmware_revision = 0x002800,
@@ -305,6 +315,11 @@ static const struct {
.workarounds = SBP2_WORKAROUND_INQUIRY_36 |
SBP2_WORKAROUND_MODE_SENSE_8,
},
+ /* DViCO Momobay FX-3A with TSB42AA9A bridge */ {
+ .firmware_revision = 0x002800,
+ .model = 0x000000,
+ .workarounds = SBP2_WORKAROUND_DELAY_INQUIRY,
+ },
/* Initio bridges, actually only needed for some older ones */ {
.firmware_revision = 0x000200,
.model = ~0,
@@ -501,6 +516,9 @@ sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id,
unsigned int timeout;
int retval = -ENOMEM;
+ if (function == SBP2_LOGOUT_REQUEST && fw_device_is_shutdown(device))
+ return 0;
+
orb = kzalloc(sizeof(*orb), GFP_ATOMIC);
if (orb == NULL)
return -ENOMEM;
@@ -553,20 +571,20 @@ sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id,
retval = -EIO;
if (sbp2_cancel_orbs(lu) == 0) {
- fw_error("orb reply timed out, rcode=0x%02x\n",
- orb->base.rcode);
+ fw_error("%s: orb reply timed out, rcode=0x%02x\n",
+ lu->tgt->bus_id, orb->base.rcode);
goto out;
}
if (orb->base.rcode != RCODE_COMPLETE) {
- fw_error("management write failed, rcode 0x%02x\n",
- orb->base.rcode);
+ fw_error("%s: management write failed, rcode 0x%02x\n",
+ lu->tgt->bus_id, orb->base.rcode);
goto out;
}
if (STATUS_GET_RESPONSE(orb->status) != 0 ||
STATUS_GET_SBP_STATUS(orb->status) != 0) {
- fw_error("error status: %d:%d\n",
+ fw_error("%s: error status: %d:%d\n", lu->tgt->bus_id,
STATUS_GET_RESPONSE(orb->status),
STATUS_GET_SBP_STATUS(orb->status));
goto out;
@@ -590,29 +608,147 @@ sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id,
static void
complete_agent_reset_write(struct fw_card *card, int rcode,
- void *payload, size_t length, void *data)
+ void *payload, size_t length, void *done)
+{
+ complete(done);
+}
+
+static void sbp2_agent_reset(struct sbp2_logical_unit *lu)
{
- struct fw_transaction *t = data;
+ struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
+ DECLARE_COMPLETION_ONSTACK(done);
+ struct fw_transaction t;
+ static u32 z;
+
+ fw_send_request(device->card, &t, TCODE_WRITE_QUADLET_REQUEST,
+ lu->tgt->node_id, lu->generation, device->max_speed,
+ lu->command_block_agent_address + SBP2_AGENT_RESET,
+ &z, sizeof(z), complete_agent_reset_write, &done);
+ wait_for_completion(&done);
+}
- kfree(t);
+static void
+complete_agent_reset_write_no_wait(struct fw_card *card, int rcode,
+ void *payload, size_t length, void *data)
+{
+ kfree(data);
}
-static int sbp2_agent_reset(struct sbp2_logical_unit *lu)
+static void sbp2_agent_reset_no_wait(struct sbp2_logical_unit *lu)
{
struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
struct fw_transaction *t;
- static u32 zero;
+ static u32 z;
- t = kzalloc(sizeof(*t), GFP_ATOMIC);
+ t = kmalloc(sizeof(*t), GFP_ATOMIC);
if (t == NULL)
- return -ENOMEM;
+ return;
fw_send_request(device->card, t, TCODE_WRITE_QUADLET_REQUEST,
lu->tgt->node_id, lu->generation, device->max_speed,
lu->command_block_agent_address + SBP2_AGENT_RESET,
- &zero, sizeof(zero), complete_agent_reset_write, t);
+ &z, sizeof(z), complete_agent_reset_write_no_wait, t);
+}
- return 0;
+static void sbp2_set_generation(struct sbp2_logical_unit *lu, int generation)
+{
+ struct fw_card *card = fw_device(lu->tgt->unit->device.parent)->card;
+ unsigned long flags;
+
+ /* serialize with comparisons of lu->generation and card->generation */
+ spin_lock_irqsave(&card->lock, flags);
+ lu->generation = generation;
+ spin_unlock_irqrestore(&card->lock, flags);
+}
+
+static inline void sbp2_allow_block(struct sbp2_logical_unit *lu)
+{
+ /*
+ * We may access dont_block without taking card->lock here:
+ * All callers of sbp2_allow_block() and all callers of sbp2_unblock()
+ * are currently serialized against each other.
+ * And a wrong result in sbp2_conditionally_block()'s access of
+ * dont_block is rather harmless, it simply misses its first chance.
+ */
+ --lu->tgt->dont_block;
+}
+
+/*
+ * Blocks lu->tgt if all of the following conditions are met:
+ * - Login, INQUIRY, and high-level SCSI setup of all of the target's
+ * logical units have been finished (indicated by dont_block == 0).
+ * - lu->generation is stale.
+ *
+ * Note, scsi_block_requests() must be called while holding card->lock,
+ * otherwise it might foil sbp2_[conditionally_]unblock()'s attempt to
+ * unblock the target.
+ */
+static void sbp2_conditionally_block(struct sbp2_logical_unit *lu)
+{
+ struct sbp2_target *tgt = lu->tgt;
+ struct fw_card *card = fw_device(tgt->unit->device.parent)->card;
+ struct Scsi_Host *shost =
+ container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
+ unsigned long flags;
+
+ spin_lock_irqsave(&card->lock, flags);
+ if (!tgt->dont_block && !lu->blocked &&
+ lu->generation != card->generation) {
+ lu->blocked = true;
+ if (++tgt->blocked == 1) {
+ scsi_block_requests(shost);
+ fw_notify("blocked %s\n", lu->tgt->bus_id);
+ }
+ }
+ spin_unlock_irqrestore(&card->lock, flags);
+}
+
+/*
+ * Unblocks lu->tgt as soon as all its logical units can be unblocked.
+ * Note, it is harmless to run scsi_unblock_requests() outside the
+ * card->lock protected section. On the other hand, running it inside
+ * the section might clash with shost->host_lock.
+ */
+static void sbp2_conditionally_unblock(struct sbp2_logical_unit *lu)
+{
+ struct sbp2_target *tgt = lu->tgt;
+ struct fw_card *card = fw_device(tgt->unit->device.parent)->card;
+ struct Scsi_Host *shost =
+ container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
+ unsigned long flags;
+ bool unblock = false;
+
+ spin_lock_irqsave(&card->lock, flags);
+ if (lu->blocked && lu->generation == card->generation) {
+ lu->blocked = false;
+ unblock = --tgt->blocked == 0;
+ }
+ spin_unlock_irqrestore(&card->lock, flags);
+
+ if (unblock) {
+ scsi_unblock_requests(shost);
+ fw_notify("unblocked %s\n", lu->tgt->bus_id);
+ }
+}
+
+/*
+ * Prevents future blocking of tgt and unblocks it.
+ * Note, it is harmless to run scsi_unblock_requests() outside the
+ * card->lock protected section. On the other hand, running it inside
+ * the section might clash with shost->host_lock.
+ */
+static void sbp2_unblock(struct sbp2_target *tgt)
+{
+ struct fw_card *card = fw_device(tgt->unit->device.parent)->card;
+ struct Scsi_Host *shost =
+ container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
+ unsigned long flags;
+
+ spin_lock_irqsave(&card->lock, flags);
+ ++tgt->dont_block;
+ spin_unlock_irqrestore(&card->lock, flags);
+
+ scsi_unblock_requests(shost);
}
static void sbp2_release_target(struct kref *kref)
@@ -621,23 +757,24 @@ static void sbp2_release_target(struct kref *kref)
struct sbp2_logical_unit *lu, *next;
struct Scsi_Host *shost =
container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
- struct fw_device *device = fw_device(tgt->unit->device.parent);
+
+ /* prevent deadlocks */
+ sbp2_unblock(tgt);
list_for_each_entry_safe(lu, next, &tgt->lu_list, link) {
- if (lu->sdev)
+ if (lu->sdev) {
scsi_remove_device(lu->sdev);
-
- if (!fw_device_is_shutdown(device))
- sbp2_send_management_orb(lu, tgt->node_id,
- lu->generation, SBP2_LOGOUT_REQUEST,
- lu->login_id, NULL);
+ scsi_device_put(lu->sdev);
+ }
+ sbp2_send_management_orb(lu, tgt->node_id, lu->generation,
+ SBP2_LOGOUT_REQUEST, lu->login_id, NULL);
fw_core_remove_address_handler(&lu->address_handler);
list_del(&lu->link);
kfree(lu);
}
scsi_remove_host(shost);
- fw_notify("released %s\n", tgt->unit->device.bus_id);
+ fw_notify("released %s\n", tgt->bus_id);
put_device(&tgt->unit->device);
scsi_host_put(shost);
@@ -666,33 +803,43 @@ static void sbp2_login(struct work_struct *work)
{
struct sbp2_logical_unit *lu =
container_of(work, struct sbp2_logical_unit, work.work);
- struct Scsi_Host *shost =
- container_of((void *)lu->tgt, struct Scsi_Host, hostdata[0]);
+ struct sbp2_target *tgt = lu->tgt;
+ struct fw_device *device = fw_device(tgt->unit->device.parent);
+ struct Scsi_Host *shost;
struct scsi_device *sdev;
struct scsi_lun eight_bytes_lun;
- struct fw_unit *unit = lu->tgt->unit;
- struct fw_device *device = fw_device(unit->device.parent);
struct sbp2_login_response response;
int generation, node_id, local_node_id;
+ if (fw_device_is_shutdown(device))
+ goto out;
+
generation = device->generation;
smp_rmb(); /* node_id must not be older than generation */
node_id = device->node_id;
local_node_id = device->card->node_id;
+ /* If this is a re-login attempt, log out, or we might be rejected. */
+ if (lu->sdev)
+ sbp2_send_management_orb(lu, device->node_id, generation,
+ SBP2_LOGOUT_REQUEST, lu->login_id, NULL);
+
if (sbp2_send_management_orb(lu, node_id, generation,
SBP2_LOGIN_REQUEST, lu->lun, &response) < 0) {
- if (lu->retries++ < 5)
+ if (lu->retries++ < 5) {
sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5));
- else
- fw_error("failed to login to %s LUN %04x\n",
- unit->device.bus_id, lu->lun);
+ } else {
+ fw_error("%s: failed to login to LUN %04x\n",
+ tgt->bus_id, lu->lun);
+ /* Let any waiting I/O fail from now on. */
+ sbp2_unblock(lu->tgt);
+ }
goto out;
}
- lu->generation = generation;
- lu->tgt->node_id = node_id;
- lu->tgt->address_high = local_node_id << 16;
+ tgt->node_id = node_id;
+ tgt->address_high = local_node_id << 16;
+ sbp2_set_generation(lu, generation);
/* Get command block agent offset and login id. */
lu->command_block_agent_address =
@@ -700,8 +847,8 @@ static void sbp2_login(struct work_struct *work)
response.command_block_agent.low;
lu->login_id = LOGIN_RESPONSE_GET_LOGIN_ID(response);
- fw_notify("logged in to %s LUN %04x (%d retries)\n",
- unit->device.bus_id, lu->lun, lu->retries);
+ fw_notify("%s: logged in to LUN %04x (%d retries)\n",
+ tgt->bus_id, lu->lun, lu->retries);
#if 0
/* FIXME: The linux1394 sbp2 does this last step. */
@@ -711,26 +858,62 @@ static void sbp2_login(struct work_struct *work)
PREPARE_DELAYED_WORK(&lu->work, sbp2_reconnect);
sbp2_agent_reset(lu);
+ /* This was a re-login. */
+ if (lu->sdev) {
+ sbp2_cancel_orbs(lu);
+ sbp2_conditionally_unblock(lu);
+ goto out;
+ }
+
+ if (lu->tgt->workarounds & SBP2_WORKAROUND_DELAY_INQUIRY)
+ ssleep(SBP2_INQUIRY_DELAY);
+
memset(&eight_bytes_lun, 0, sizeof(eight_bytes_lun));
eight_bytes_lun.scsi_lun[0] = (lu->lun >> 8) & 0xff;
eight_bytes_lun.scsi_lun[1] = lu->lun & 0xff;
+ shost = container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
sdev = __scsi_add_device(shost, 0, 0,
scsilun_to_int(&eight_bytes_lun), lu);
- if (IS_ERR(sdev)) {
- sbp2_send_management_orb(lu, node_id, generation,
- SBP2_LOGOUT_REQUEST, lu->login_id, NULL);
- /*
- * Set this back to sbp2_login so we fall back and
- * retry login on bus reset.
- */
- PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
- } else {
- lu->sdev = sdev;
+ /*
+ * FIXME: We are unable to perform reconnects while in sbp2_login().
+ * Therefore __scsi_add_device() will get into trouble if a bus reset
+ * happens in parallel. It will either fail or leave us with an
+ * unusable sdev. As a workaround we check for this and retry the
+ * whole login and SCSI probing.
+ */
+
+ /* Reported error during __scsi_add_device() */
+ if (IS_ERR(sdev))
+ goto out_logout_login;
+
+ /* Unreported error during __scsi_add_device() */
+ smp_rmb(); /* get current card generation */
+ if (generation != device->card->generation) {
+ scsi_remove_device(sdev);
scsi_device_put(sdev);
+ goto out_logout_login;
}
+
+ /* No error during __scsi_add_device() */
+ lu->sdev = sdev;
+ sbp2_allow_block(lu);
+ goto out;
+
+ out_logout_login:
+ smp_rmb(); /* generation may have changed */
+ generation = device->generation;
+ smp_rmb(); /* node_id must not be older than generation */
+
+ sbp2_send_management_orb(lu, device->node_id, generation,
+ SBP2_LOGOUT_REQUEST, lu->login_id, NULL);
+ /*
+ * If a bus reset happened, sbp2_update will have requeued
+ * lu->work already. Reset the work from reconnect to login.
+ */
+ PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
out:
- sbp2_target_put(lu->tgt);
+ sbp2_target_put(tgt);
}
static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry)
@@ -755,6 +938,8 @@ static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry)
lu->sdev = NULL;
lu->lun = lun_entry & 0xffff;
lu->retries = 0;
+ lu->blocked = false;
+ ++tgt->dont_block;
INIT_LIST_HEAD(&lu->orb_list);
INIT_DELAYED_WORK(&lu->work, sbp2_login);
@@ -813,7 +998,7 @@ static int sbp2_scan_unit_dir(struct sbp2_target *tgt, u32 *directory,
if (timeout > tgt->mgt_orb_timeout)
fw_notify("%s: config rom contains %ds "
"management ORB timeout, limiting "
- "to %ds\n", tgt->unit->device.bus_id,
+ "to %ds\n", tgt->bus_id,
timeout / 1000,
tgt->mgt_orb_timeout / 1000);
break;
@@ -836,12 +1021,12 @@ static void sbp2_init_workarounds(struct sbp2_target *tgt, u32 model,
u32 firmware_revision)
{
int i;
- unsigned w = sbp2_param_workarounds;
+ unsigned int w = sbp2_param_workarounds;
if (w)
fw_notify("Please notify linux1394-devel@lists.sourceforge.net "
"if you need the workarounds parameter for %s\n",
- tgt->unit->device.bus_id);
+ tgt->bus_id);
if (w & SBP2_WORKAROUND_OVERRIDE)
goto out;
@@ -863,8 +1048,7 @@ static void sbp2_init_workarounds(struct sbp2_target *tgt, u32 model,
if (w)
fw_notify("Workarounds for %s: 0x%x "
"(firmware_revision 0x%06x, model_id 0x%06x)\n",
- tgt->unit->device.bus_id,
- w, firmware_revision, model);
+ tgt->bus_id, w, firmware_revision, model);
tgt->workarounds = w;
}
@@ -888,6 +1072,7 @@ static int sbp2_probe(struct device *dev)
tgt->unit = unit;
kref_init(&tgt->kref);
INIT_LIST_HEAD(&tgt->lu_list);
+ tgt->bus_id = unit->device.bus_id;
if (fw_device_enable_phys_dma(device) < 0)
goto fail_shost_put;
@@ -938,10 +1123,13 @@ static void sbp2_reconnect(struct work_struct *work)
{
struct sbp2_logical_unit *lu =
container_of(work, struct sbp2_logical_unit, work.work);
- struct fw_unit *unit = lu->tgt->unit;
- struct fw_device *device = fw_device(unit->device.parent);
+ struct sbp2_target *tgt = lu->tgt;
+ struct fw_device *device = fw_device(tgt->unit->device.parent);
int generation, node_id, local_node_id;
+ if (fw_device_is_shutdown(device))
+ goto out;
+
generation = device->generation;
smp_rmb(); /* node_id must not be older than generation */
node_id = device->node_id;
@@ -950,10 +1138,17 @@ static void sbp2_reconnect(struct work_struct *work)
if (sbp2_send_management_orb(lu, node_id, generation,
SBP2_RECONNECT_REQUEST,
lu->login_id, NULL) < 0) {
- if (lu->retries++ >= 5) {
- fw_error("failed to reconnect to %s\n",
- unit->device.bus_id);
- /* Fall back and try to log in again. */
+ /*
+ * If reconnect was impossible even though we are in the
+ * current generation, fall back and try to log in again.
+ *
+ * We could check for "Function rejected" status, but
+ * looking at the bus generation as simpler and more general.
+ */
+ smp_rmb(); /* get current card generation */
+ if (generation == device->card->generation ||
+ lu->retries++ >= 5) {
+ fw_error("%s: failed to reconnect\n", tgt->bus_id);
lu->retries = 0;
PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
}
@@ -961,17 +1156,18 @@ static void sbp2_reconnect(struct work_struct *work)
goto out;
}
- lu->generation = generation;
- lu->tgt->node_id = node_id;
- lu->tgt->address_high = local_node_id << 16;
+ tgt->node_id = node_id;
+ tgt->address_high = local_node_id << 16;
+ sbp2_set_generation(lu, generation);
- fw_notify("reconnected to %s LUN %04x (%d retries)\n",
- unit->device.bus_id, lu->lun, lu->retries);
+ fw_notify("%s: reconnected to LUN %04x (%d retries)\n",
+ tgt->bus_id, lu->lun, lu->retries);
sbp2_agent_reset(lu);
sbp2_cancel_orbs(lu);
+ sbp2_conditionally_unblock(lu);
out:
- sbp2_target_put(lu->tgt);
+ sbp2_target_put(tgt);
}
static void sbp2_update(struct fw_unit *unit)
@@ -986,6 +1182,7 @@ static void sbp2_update(struct fw_unit *unit)
* Iteration over tgt->lu_list is therefore safe here.
*/
list_for_each_entry(lu, &tgt->lu_list, link) {
+ sbp2_conditionally_block(lu);
lu->retries = 0;
sbp2_queue_work(lu, 0);
}
@@ -1063,7 +1260,7 @@ complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status)
if (status != NULL) {
if (STATUS_GET_DEAD(*status))
- sbp2_agent_reset(orb->lu);
+ sbp2_agent_reset_no_wait(orb->lu);
switch (STATUS_GET_RESPONSE(*status)) {
case SBP2_STATUS_REQUEST_COMPLETE:
@@ -1089,6 +1286,7 @@ complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status)
* or when sending the write (less likely).
*/
result = DID_BUS_BUSY << 16;
+ sbp2_conditionally_block(orb->lu);
}
dma_unmap_single(device->card->device, orb->base.request_bus,
@@ -1197,7 +1395,7 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
struct sbp2_logical_unit *lu = cmd->device->hostdata;
struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
struct sbp2_command_orb *orb;
- unsigned max_payload;
+ unsigned int max_payload;
int retval = SCSI_MLQUEUE_HOST_BUSY;
/*
@@ -1275,6 +1473,10 @@ static int sbp2_scsi_slave_alloc(struct scsi_device *sdev)
{
struct sbp2_logical_unit *lu = sdev->hostdata;
+ /* (Re-)Adding logical units via the SCSI stack is not supported. */
+ if (!lu)
+ return -ENOSYS;
+
sdev->allow_restart = 1;
/*
@@ -1319,7 +1521,7 @@ static int sbp2_scsi_abort(struct scsi_cmnd *cmd)
{
struct sbp2_logical_unit *lu = cmd->device->hostdata;
- fw_notify("sbp2_scsi_abort\n");
+ fw_notify("%s: sbp2_scsi_abort\n", lu->tgt->bus_id);
sbp2_agent_reset(lu);
sbp2_cancel_orbs(lu);
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index 653265a40b7..4072449ad1c 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -10,10 +10,9 @@
static char dmi_empty_string[] = " ";
-static char * __init dmi_string(const struct dmi_header *dm, u8 s)
+static const char * __init dmi_string_nosave(const struct dmi_header *dm, u8 s)
{
const u8 *bp = ((u8 *) dm) + dm->length;
- char *str = "";
if (s) {
s--;
@@ -28,14 +27,29 @@ static char * __init dmi_string(const struct dmi_header *dm, u8 s)
if (!memcmp(bp, dmi_empty_string, cmp_len))
return dmi_empty_string;
- str = dmi_alloc(len);
- if (str != NULL)
- strcpy(str, bp);
- else
- printk(KERN_ERR "dmi_string: cannot allocate %Zu bytes.\n", len);
+ return bp;
}
}
+ return "";
+}
+
+static char * __init dmi_string(const struct dmi_header *dm, u8 s)
+{
+ const char *bp = dmi_string_nosave(dm, s);
+ char *str;
+ size_t len;
+
+ if (bp == dmi_empty_string)
+ return dmi_empty_string;
+
+ len = strlen(bp) + 1;
+ str = dmi_alloc(len);
+ if (str != NULL)
+ strcpy(str, bp);
+ else
+ printk(KERN_ERR "dmi_string: cannot allocate %Zu bytes.\n", len);
+
return str;
}
@@ -167,10 +181,30 @@ static void __init dmi_save_type(const struct dmi_header *dm, int slot, int inde
dmi_ident[slot] = s;
}
+static void __init dmi_save_one_device(int type, const char *name)
+{
+ struct dmi_device *dev;
+
+ /* No duplicate device */
+ if (dmi_find_device(type, name, NULL))
+ return;
+
+ dev = dmi_alloc(sizeof(*dev) + strlen(name) + 1);
+ if (!dev) {
+ printk(KERN_ERR "dmi_save_one_device: out of memory.\n");
+ return;
+ }
+
+ dev->type = type;
+ strcpy((char *)(dev + 1), name);
+ dev->name = (char *)(dev + 1);
+ dev->device_data = NULL;
+ list_add(&dev->list, &dmi_devices);
+}
+
static void __init dmi_save_devices(const struct dmi_header *dm)
{
int i, count = (dm->length - sizeof(struct dmi_header)) / 2;
- struct dmi_device *dev;
for (i = 0; i < count; i++) {
const char *d = (char *)(dm + 1) + (i * 2);
@@ -179,23 +213,10 @@ static void __init dmi_save_devices(const struct dmi_header *dm)
if ((*d & 0x80) == 0)
continue;
- dev = dmi_alloc(sizeof(*dev));
- if (!dev) {
- printk(KERN_ERR "dmi_save_devices: out of memory.\n");
- break;
- }
-
- dev->type = *d++ & 0x7f;
- dev->name = dmi_string(dm, *d);
- dev->device_data = NULL;
- list_add(&dev->list, &dmi_devices);
+ dmi_save_one_device(*d & 0x7f, dmi_string_nosave(dm, *(d + 1)));
}
}
-static struct dmi_device empty_oem_string_dev = {
- .name = dmi_empty_string,
-};
-
static void __init dmi_save_oem_strings_devices(const struct dmi_header *dm)
{
int i, count = *(u8 *)(dm + 1);
@@ -204,10 +225,8 @@ static void __init dmi_save_oem_strings_devices(const struct dmi_header *dm)
for (i = 1; i <= count; i++) {
char *devname = dmi_string(dm, i);
- if (!strcmp(devname, dmi_empty_string)) {
- list_add(&empty_oem_string_dev.list, &dmi_devices);
+ if (devname == dmi_empty_string)
continue;
- }
dev = dmi_alloc(sizeof(*dev));
if (!dev) {
@@ -253,23 +272,12 @@ static void __init dmi_save_ipmi_device(const struct dmi_header *dm)
static void __init dmi_save_extended_devices(const struct dmi_header *dm)
{
const u8 *d = (u8*) dm + 5;
- struct dmi_device *dev;
/* Skip disabled device */
if ((*d & 0x80) == 0)
return;
- dev = dmi_alloc(sizeof(*dev));
- if (!dev) {
- printk(KERN_ERR "dmi_save_extended_devices: out of memory.\n");
- return;
- }
-
- dev->type = *d-- & 0x7f;
- dev->name = dmi_string(dm, *d);
- dev->device_data = NULL;
-
- list_add(&dev->list, &dmi_devices);
+ dmi_save_one_device(*d & 0x7f, dmi_string_nosave(dm, *(d - 1)));
}
/*
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 410ffe4e9d8..368879ff5d8 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -143,6 +143,16 @@ config SENSORS_ADT7470
This driver can also be built as a module. If so, the module
will be called adt7470.
+config SENSORS_ADT7473
+ tristate "Analog Devices ADT7473"
+ depends on I2C && EXPERIMENTAL
+ help
+ If you say yes here you get support for the Analog Devices
+ ADT7473 temperature monitoring chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called adt7473.
+
config SENSORS_K8TEMP
tristate "AMD Athlon64/FX or Opteron temperature sensor"
depends on X86 && PCI && EXPERIMENTAL
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 824161337f1..3bdb05a5cbd 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o
obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o
obj-$(CONFIG_SENSORS_ADS7828) += ads7828.o
obj-$(CONFIG_SENSORS_ADT7470) += adt7470.o
+obj-$(CONFIG_SENSORS_ADT7473) += adt7473.o
obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o
obj-$(CONFIG_SENSORS_AMS) += ams/
obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
diff --git a/drivers/hwmon/ad7418.c b/drivers/hwmon/ad7418.c
index fcd7fe78f3f..466b9ee9279 100644
--- a/drivers/hwmon/ad7418.c
+++ b/drivers/hwmon/ad7418.c
@@ -26,7 +26,7 @@
#define DRV_VERSION "0.3"
/* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x28, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x28, I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD_3(ad7416, ad7417, ad7418);
diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c
index b96be772e49..ecbf69484bf 100644
--- a/drivers/hwmon/adm1021.c
+++ b/drivers/hwmon/adm1021.c
@@ -31,10 +31,8 @@
/* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a,
- 0x29, 0x2a, 0x2b,
- 0x4c, 0x4d, 0x4e,
- I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = {
+ 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x4c, 0x4d, 0x4e, I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD_8(adm1021, adm1023, max1617, max1617a, thmc10, lm84, gl523sm,
diff --git a/drivers/hwmon/adm1025.c b/drivers/hwmon/adm1025.c
index e96c3725203..1d76de7d75c 100644
--- a/drivers/hwmon/adm1025.c
+++ b/drivers/hwmon/adm1025.c
@@ -62,7 +62,7 @@
* NE1619 has two possible addresses: 0x2c and 0x2d.
*/
-static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
/*
* Insmod parameters
diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c
index 8002f68240c..904c6ce9d83 100644
--- a/drivers/hwmon/adm1026.c
+++ b/drivers/hwmon/adm1026.c
@@ -35,7 +35,7 @@
#include <linux/mutex.h>
/* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD_1(adm1026);
@@ -1624,6 +1624,7 @@ static struct attribute *adm1026_attributes_temp3[] = {
&dev_attr_temp3_crit_enable.attr,
&dev_attr_temp3_auto_point1_pwm.attr,
&dev_attr_temp3_auto_point2_pwm.attr,
+ NULL
};
static const struct attribute_group adm1026_group_temp3 = {
@@ -1639,6 +1640,7 @@ static struct attribute *adm1026_attributes_in8_9[] = {
&sensor_dev_attr_in9_max.dev_attr.attr,
&sensor_dev_attr_in9_min.dev_attr.attr,
&sensor_dev_attr_in9_alarm.dev_attr.attr,
+ NULL
};
static const struct attribute_group adm1026_group_in8_9 = {
diff --git a/drivers/hwmon/adm1029.c b/drivers/hwmon/adm1029.c
index 0bc897dffa2..2c6608d453c 100644
--- a/drivers/hwmon/adm1029.c
+++ b/drivers/hwmon/adm1029.c
@@ -39,10 +39,8 @@
* Addresses to scan
*/
-static unsigned short normal_i2c[] = {
- 0x28, 0x29, 0x2a,
- 0x2b, 0x2c, 0x2d,
- 0x2e, 0x2f, I2C_CLIENT_END
+static const unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
+ 0x2e, 0x2f, I2C_CLIENT_END
};
/*
diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c
index 5aaad3636c9..2bffcab7dc9 100644
--- a/drivers/hwmon/adm1031.c
+++ b/drivers/hwmon/adm1031.c
@@ -61,7 +61,7 @@
#define ADM1031_CONF2_TEMP_ENABLE(chan) (0x10 << (chan))
/* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD_2(adm1030, adm1031);
diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c
index 7671d2bf780..149ef25252e 100644
--- a/drivers/hwmon/adm9240.c
+++ b/drivers/hwmon/adm9240.c
@@ -52,7 +52,7 @@
#include <linux/mutex.h>
/* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
+static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
I2C_CLIENT_END };
/* Insmod parameters */
diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c
index 6b8a73ef404..ed71a8bc70d 100644
--- a/drivers/hwmon/ads7828.c
+++ b/drivers/hwmon/ads7828.c
@@ -44,7 +44,7 @@
#define ADS7828_INT_VREF_MV 2500 /* Internal vref is 2.5V, 2500mV */
/* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
+static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
I2C_CLIENT_END };
/* Insmod parameters */
diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c
index 747693ab2ff..6b5325f33a2 100644
--- a/drivers/hwmon/adt7470.c
+++ b/drivers/hwmon/adt7470.c
@@ -30,7 +30,7 @@
#include <linux/log2.h>
/* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x2C, 0x2E, 0x2F, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x2C, 0x2E, 0x2F, I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD_1(adt7470);
diff --git a/drivers/hwmon/adt7473.c b/drivers/hwmon/adt7473.c
new file mode 100644
index 00000000000..9587869bdba
--- /dev/null
+++ b/drivers/hwmon/adt7473.c
@@ -0,0 +1,1157 @@
+/*
+ * A hwmon driver for the Analog Devices ADT7473
+ * Copyright (C) 2007 IBM
+ *
+ * Author: Darrick J. Wong <djwong@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/log2.h>
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = { 0x2C, 0x2D, 0x2E, I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_1(adt7473);
+
+/* ADT7473 registers */
+#define ADT7473_REG_BASE_ADDR 0x20
+
+#define ADT7473_REG_VOLT_BASE_ADDR 0x21
+#define ADT7473_REG_VOLT_MAX_ADDR 0x22
+#define ADT7473_REG_VOLT_MIN_BASE_ADDR 0x46
+#define ADT7473_REG_VOLT_MIN_MAX_ADDR 0x49
+
+#define ADT7473_REG_TEMP_BASE_ADDR 0x25
+#define ADT7473_REG_TEMP_MAX_ADDR 0x27
+#define ADT7473_REG_TEMP_LIMITS_BASE_ADDR 0x4E
+#define ADT7473_REG_TEMP_LIMITS_MAX_ADDR 0x53
+#define ADT7473_REG_TEMP_TMIN_BASE_ADDR 0x67
+#define ADT7473_REG_TEMP_TMIN_MAX_ADDR 0x69
+#define ADT7473_REG_TEMP_TMAX_BASE_ADDR 0x6A
+#define ADT7473_REG_TEMP_TMAX_MAX_ADDR 0x6C
+
+#define ADT7473_REG_FAN_BASE_ADDR 0x28
+#define ADT7473_REG_FAN_MAX_ADDR 0x2F
+#define ADT7473_REG_FAN_MIN_BASE_ADDR 0x54
+#define ADT7473_REG_FAN_MIN_MAX_ADDR 0x5B
+
+#define ADT7473_REG_PWM_BASE_ADDR 0x30
+#define ADT7473_REG_PWM_MAX_ADDR 0x32
+#define ADT7473_REG_PWM_MIN_BASE_ADDR 0x64
+#define ADT7473_REG_PWM_MIN_MAX_ADDR 0x66
+#define ADT7473_REG_PWM_MAX_BASE_ADDR 0x38
+#define ADT7473_REG_PWM_MAX_MAX_ADDR 0x3A
+#define ADT7473_REG_PWM_BHVR_BASE_ADDR 0x5C
+#define ADT7473_REG_PWM_BHVR_MAX_ADDR 0x5E
+#define ADT7473_PWM_BHVR_MASK 0xE0
+#define ADT7473_PWM_BHVR_SHIFT 5
+
+#define ADT7473_REG_CFG1 0x40
+#define ADT7473_CFG1_START 0x01
+#define ADT7473_CFG1_READY 0x04
+#define ADT7473_REG_CFG2 0x73
+#define ADT7473_REG_CFG3 0x78
+#define ADT7473_REG_CFG4 0x7D
+#define ADT7473_CFG4_MAX_DUTY_AT_OVT 0x08
+#define ADT7473_REG_CFG5 0x7C
+#define ADT7473_CFG5_TEMP_TWOS 0x01
+#define ADT7473_CFG5_TEMP_OFFSET 0x02
+
+#define ADT7473_REG_DEVICE 0x3D
+#define ADT7473_VENDOR 0x41
+#define ADT7473_REG_VENDOR 0x3E
+#define ADT7473_DEVICE 0x73
+#define ADT7473_REG_REVISION 0x3F
+#define ADT7473_REV_68 0x68
+#define ADT7473_REV_69 0x69
+
+#define ADT7473_REG_ALARM1 0x41
+#define ADT7473_VCCP_ALARM 0x02
+#define ADT7473_VCC_ALARM 0x04
+#define ADT7473_R1T_ALARM 0x10
+#define ADT7473_LT_ALARM 0x20
+#define ADT7473_R2T_ALARM 0x40
+#define ADT7473_OOL 0x80
+#define ADT7473_REG_ALARM2 0x42
+#define ADT7473_OVT_ALARM 0x02
+#define ADT7473_FAN1_ALARM 0x04
+#define ADT7473_FAN2_ALARM 0x08
+#define ADT7473_FAN3_ALARM 0x10
+#define ADT7473_FAN4_ALARM 0x20
+#define ADT7473_R1T_SHORT 0x40
+#define ADT7473_R2T_SHORT 0x80
+#define ADT7473_REG_MAX_ADDR 0x80
+
+#define ALARM2(x) ((x) << 8)
+
+#define ADT7473_VOLT_COUNT 2
+#define ADT7473_REG_VOLT(x) (ADT7473_REG_VOLT_BASE_ADDR + (x))
+#define ADT7473_REG_VOLT_MIN(x) (ADT7473_REG_VOLT_MIN_BASE_ADDR + ((x) * 2))
+#define ADT7473_REG_VOLT_MAX(x) (ADT7473_REG_VOLT_MIN_BASE_ADDR + \
+ ((x) * 2) + 1)
+
+#define ADT7473_TEMP_COUNT 3
+#define ADT7473_REG_TEMP(x) (ADT7473_REG_TEMP_BASE_ADDR + (x))
+#define ADT7473_REG_TEMP_MIN(x) (ADT7473_REG_TEMP_LIMITS_BASE_ADDR + ((x) * 2))
+#define ADT7473_REG_TEMP_MAX(x) (ADT7473_REG_TEMP_LIMITS_BASE_ADDR + \
+ ((x) * 2) + 1)
+#define ADT7473_REG_TEMP_TMIN(x) (ADT7473_REG_TEMP_TMIN_BASE_ADDR + (x))
+#define ADT7473_REG_TEMP_TMAX(x) (ADT7473_REG_TEMP_TMAX_BASE_ADDR + (x))
+
+#define ADT7473_FAN_COUNT 4
+#define ADT7473_REG_FAN(x) (ADT7473_REG_FAN_BASE_ADDR + ((x) * 2))
+#define ADT7473_REG_FAN_MIN(x) (ADT7473_REG_FAN_MIN_BASE_ADDR + ((x) * 2))
+
+#define ADT7473_PWM_COUNT 3
+#define ADT7473_REG_PWM(x) (ADT7473_REG_PWM_BASE_ADDR + (x))
+#define ADT7473_REG_PWM_MAX(x) (ADT7473_REG_PWM_MAX_BASE_ADDR + (x))
+#define ADT7473_REG_PWM_MIN(x) (ADT7473_REG_PWM_MIN_BASE_ADDR + (x))
+#define ADT7473_REG_PWM_BHVR(x) (ADT7473_REG_PWM_BHVR_BASE_ADDR + (x))
+
+/* How often do we reread sensors values? (In jiffies) */
+#define SENSOR_REFRESH_INTERVAL (2 * HZ)
+
+/* How often do we reread sensor limit values? (In jiffies) */
+#define LIMIT_REFRESH_INTERVAL (60 * HZ)
+
+/* datasheet says to divide this number by the fan reading to get fan rpm */
+#define FAN_PERIOD_TO_RPM(x) ((90000 * 60) / (x))
+#define FAN_RPM_TO_PERIOD FAN_PERIOD_TO_RPM
+#define FAN_PERIOD_INVALID 65535
+#define FAN_DATA_VALID(x) ((x) && (x) != FAN_PERIOD_INVALID)
+
+struct adt7473_data {
+ struct i2c_client client;
+ struct device *hwmon_dev;
+ struct attribute_group attrs;
+ struct mutex lock;
+ char sensors_valid;
+ char limits_valid;
+ unsigned long sensors_last_updated; /* In jiffies */
+ unsigned long limits_last_updated; /* In jiffies */
+
+ u8 volt[ADT7473_VOLT_COUNT];
+ s8 volt_min[ADT7473_VOLT_COUNT];
+ s8 volt_max[ADT7473_VOLT_COUNT];
+
+ s8 temp[ADT7473_TEMP_COUNT];
+ s8 temp_min[ADT7473_TEMP_COUNT];
+ s8 temp_max[ADT7473_TEMP_COUNT];
+ s8 temp_tmin[ADT7473_TEMP_COUNT];
+ /* This is called the !THERM limit in the datasheet */
+ s8 temp_tmax[ADT7473_TEMP_COUNT];
+
+ u16 fan[ADT7473_FAN_COUNT];
+ u16 fan_min[ADT7473_FAN_COUNT];
+
+ u8 pwm[ADT7473_PWM_COUNT];
+ u8 pwm_max[ADT7473_PWM_COUNT];
+ u8 pwm_min[ADT7473_PWM_COUNT];
+ u8 pwm_behavior[ADT7473_PWM_COUNT];
+
+ u8 temp_twos_complement;
+ u8 temp_offset;
+
+ u16 alarm;
+ u8 max_duty_at_overheat;
+};
+
+static int adt7473_attach_adapter(struct i2c_adapter *adapter);
+static int adt7473_detect(struct i2c_adapter *adapter, int address, int kind);
+static int adt7473_detach_client(struct i2c_client *client);
+
+static struct i2c_driver adt7473_driver = {
+ .driver = {
+ .name = "adt7473",
+ },
+ .attach_adapter = adt7473_attach_adapter,
+ .detach_client = adt7473_detach_client,
+};
+
+/*
+ * 16-bit registers on the ADT7473 are low-byte first. The data sheet says
+ * that the low byte must be read before the high byte.
+ */
+static inline int adt7473_read_word_data(struct i2c_client *client, u8 reg)
+{
+ u16 foo;
+ foo = i2c_smbus_read_byte_data(client, reg);
+ foo |= ((u16)i2c_smbus_read_byte_data(client, reg + 1) << 8);
+ return foo;
+}
+
+static inline int adt7473_write_word_data(struct i2c_client *client, u8 reg,
+ u16 value)
+{
+ return i2c_smbus_write_byte_data(client, reg, value & 0xFF)
+ && i2c_smbus_write_byte_data(client, reg + 1, value >> 8);
+}
+
+static void adt7473_init_client(struct i2c_client *client)
+{
+ int reg = i2c_smbus_read_byte_data(client, ADT7473_REG_CFG1);
+
+ if (!(reg & ADT7473_CFG1_READY)) {
+ dev_err(&client->dev, "Chip not ready.\n");
+ } else {
+ /* start monitoring */
+ i2c_smbus_write_byte_data(client, ADT7473_REG_CFG1,
+ reg | ADT7473_CFG1_START);
+ }
+}
+
+static struct adt7473_data *adt7473_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7473_data *data = i2c_get_clientdata(client);
+ unsigned long local_jiffies = jiffies;
+ u8 cfg;
+ int i;
+
+ mutex_lock(&data->lock);
+ if (time_before(local_jiffies, data->sensors_last_updated +
+ SENSOR_REFRESH_INTERVAL)
+ && data->sensors_valid)
+ goto no_sensor_update;
+
+ for (i = 0; i < ADT7473_VOLT_COUNT; i++)
+ data->volt[i] = i2c_smbus_read_byte_data(client,
+ ADT7473_REG_VOLT(i));
+
+ /* Determine temperature encoding */
+ cfg = i2c_smbus_read_byte_data(client, ADT7473_REG_CFG5);
+ data->temp_twos_complement = (cfg & ADT7473_CFG5_TEMP_TWOS);
+
+ /*
+ * What does this do? it implies a variable temperature sensor
+ * offset, but the datasheet doesn't say anything about this bit
+ * and other parts of the datasheet imply that "offset64" mode
+ * means that you shift temp values by -64 if the above bit was set.
+ */
+ data->temp_offset = (cfg & ADT7473_CFG5_TEMP_OFFSET);
+
+ for (i = 0; i < ADT7473_TEMP_COUNT; i++)
+ data->temp[i] = i2c_smbus_read_byte_data(client,
+ ADT7473_REG_TEMP(i));
+
+ for (i = 0; i < ADT7473_FAN_COUNT; i++)
+ data->fan[i] = adt7473_read_word_data(client,
+ ADT7473_REG_FAN(i));
+
+ for (i = 0; i < ADT7473_PWM_COUNT; i++)
+ data->pwm[i] = i2c_smbus_read_byte_data(client,
+ ADT7473_REG_PWM(i));
+
+ data->alarm = i2c_smbus_read_byte_data(client, ADT7473_REG_ALARM1);
+ if (data->alarm & ADT7473_OOL)
+ data->alarm |= ALARM2(i2c_smbus_read_byte_data(client,
+ ADT7473_REG_ALARM2));
+
+ data->sensors_last_updated = local_jiffies;
+ data->sensors_valid = 1;
+
+no_sensor_update:
+ if (time_before(local_jiffies, data->limits_last_updated +
+ LIMIT_REFRESH_INTERVAL)
+ && data->limits_valid)
+ goto out;
+
+ for (i = 0; i < ADT7473_VOLT_COUNT; i++) {
+ data->volt_min[i] = i2c_smbus_read_byte_data(client,
+ ADT7473_REG_VOLT_MIN(i));
+ data->volt_max[i] = i2c_smbus_read_byte_data(client,
+ ADT7473_REG_VOLT_MAX(i));
+ }
+
+ for (i = 0; i < ADT7473_TEMP_COUNT; i++) {
+ data->temp_min[i] = i2c_smbus_read_byte_data(client,
+ ADT7473_REG_TEMP_MIN(i));
+ data->temp_max[i] = i2c_smbus_read_byte_data(client,
+ ADT7473_REG_TEMP_MAX(i));
+ data->temp_tmin[i] = i2c_smbus_read_byte_data(client,
+ ADT7473_REG_TEMP_TMIN(i));
+ data->temp_tmax[i] = i2c_smbus_read_byte_data(client,
+ ADT7473_REG_TEMP_TMAX(i));
+ }
+
+ for (i = 0; i < ADT7473_FAN_COUNT; i++)
+ data->fan_min[i] = adt7473_read_word_data(client,
+ ADT7473_REG_FAN_MIN(i));
+
+ for (i = 0; i < ADT7473_PWM_COUNT; i++) {
+ data->pwm_max[i] = i2c_smbus_read_byte_data(client,
+ ADT7473_REG_PWM_MAX(i));
+ data->pwm_min[i] = i2c_smbus_read_byte_data(client,
+ ADT7473_REG_PWM_MIN(i));
+ data->pwm_behavior[i] = i2c_smbus_read_byte_data(client,
+ ADT7473_REG_PWM_BHVR(i));
+ }
+
+ data->limits_last_updated = local_jiffies;
+ data->limits_valid = 1;
+
+out:
+ mutex_unlock(&data->lock);
+ return data;
+}
+
+/*
+ * On this chip, voltages are given as a count of steps between a minimum
+ * and maximum voltage, not a direct voltage.
+ */
+static const int volt_convert_table[][2] = {
+ {2997, 3},
+ {4395, 4},
+};
+
+static int decode_volt(int volt_index, u8 raw)
+{
+ int cmax = volt_convert_table[volt_index][0];
+ int cmin = volt_convert_table[volt_index][1];
+ return ((raw * (cmax - cmin)) / 255) + cmin;
+}
+
+static u8 encode_volt(int volt_index, int cooked)
+{
+ int cmax = volt_convert_table[volt_index][0];
+ int cmin = volt_convert_table[volt_index][1];
+ u8 x;
+
+ if (cooked > cmax)
+ cooked = cmax;
+ else if (cooked < cmin)
+ cooked = cmin;
+
+ x = ((cooked - cmin) * 255) / (cmax - cmin);
+
+ return x;
+}
+
+static ssize_t show_volt_min(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7473_data *data = adt7473_update_device(dev);
+ return sprintf(buf, "%d\n",
+ decode_volt(attr->index, data->volt_min[attr->index]));
+}
+
+static ssize_t set_volt_min(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7473_data *data = i2c_get_clientdata(client);
+ int volt = encode_volt(attr->index, simple_strtol(buf, NULL, 10));
+
+ mutex_lock(&data->lock);
+ data->volt_min[attr->index] = volt;
+ i2c_smbus_write_byte_data(client, ADT7473_REG_VOLT_MIN(attr->index),
+ volt);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t show_volt_max(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7473_data *data = adt7473_update_device(dev);
+ return sprintf(buf, "%d\n",
+ decode_volt(attr->index, data->volt_max[attr->index]));
+}
+
+static ssize_t set_volt_max(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7473_data *data = i2c_get_clientdata(client);
+ int volt = encode_volt(attr->index, simple_strtol(buf, NULL, 10));
+
+ mutex_lock(&data->lock);
+ data->volt_max[attr->index] = volt;
+ i2c_smbus_write_byte_data(client, ADT7473_REG_VOLT_MAX(attr->index),
+ volt);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t show_volt(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7473_data *data = adt7473_update_device(dev);
+
+ return sprintf(buf, "%d\n",
+ decode_volt(attr->index, data->volt[attr->index]));
+}
+
+/*
+ * This chip can report temperature data either as a two's complement
+ * number in the range -128 to 127, or as an unsigned number that must
+ * be offset by 64.
+ */
+static int decode_temp(struct adt7473_data *data, u8 raw)
+{
+ if (data->temp_twos_complement)
+ return (s8)raw;
+ return raw - 64;
+}
+
+static u8 encode_temp(struct adt7473_data *data, int cooked)
+{
+ if (data->temp_twos_complement)
+ return (cooked & 0xFF);
+ return cooked + 64;
+}
+
+static ssize_t show_temp_min(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7473_data *data = adt7473_update_device(dev);
+ return sprintf(buf, "%d\n",
+ 1000 * decode_temp(data, data->temp_min[attr->index]));
+}
+
+static ssize_t set_temp_min(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7473_data *data = i2c_get_clientdata(client);
+ int temp = simple_strtol(buf, NULL, 10) / 1000;
+ temp = encode_temp(data, temp);
+
+ mutex_lock(&data->lock);
+ data->temp_min[attr->index] = temp;
+ i2c_smbus_write_byte_data(client, ADT7473_REG_TEMP_MIN(attr->index),
+ temp);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t show_temp_max(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7473_data *data = adt7473_update_device(dev);
+ return sprintf(buf, "%d\n",
+ 1000 * decode_temp(data, data->temp_max[attr->index]));
+}
+
+static ssize_t set_temp_max(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7473_data *data = i2c_get_clientdata(client);
+ int temp = simple_strtol(buf, NULL, 10) / 1000;
+ temp = encode_temp(data, temp);
+
+ mutex_lock(&data->lock);
+ data->temp_max[attr->index] = temp;
+ i2c_smbus_write_byte_data(client, ADT7473_REG_TEMP_MAX(attr->index),
+ temp);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7473_data *data = adt7473_update_device(dev);
+ return sprintf(buf, "%d\n",
+ 1000 * decode_temp(data, data->temp[attr->index]));
+}
+
+static ssize_t show_fan_min(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7473_data *data = adt7473_update_device(dev);
+
+ if (FAN_DATA_VALID(data->fan_min[attr->index]))
+ return sprintf(buf, "%d\n",
+ FAN_PERIOD_TO_RPM(data->fan_min[attr->index]));
+ else
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t set_fan_min(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7473_data *data = i2c_get_clientdata(client);
+ int temp = simple_strtol(buf, NULL, 10);
+
+ if (!temp)
+ return -EINVAL;
+ temp = FAN_RPM_TO_PERIOD(temp);
+
+ mutex_lock(&data->lock);
+ data->fan_min[attr->index] = temp;
+ adt7473_write_word_data(client, ADT7473_REG_FAN_MIN(attr->index), temp);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7473_data *data = adt7473_update_device(dev);
+
+ if (FAN_DATA_VALID(data->fan[attr->index]))
+ return sprintf(buf, "%d\n",
+ FAN_PERIOD_TO_RPM(data->fan[attr->index]));
+ else
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t show_max_duty_at_crit(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct adt7473_data *data = adt7473_update_device(dev);
+ return sprintf(buf, "%d\n", data->max_duty_at_overheat);
+}
+
+static ssize_t set_max_duty_at_crit(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf,
+ size_t count)
+{
+ u8 reg;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7473_data *data = i2c_get_clientdata(client);
+ int temp = simple_strtol(buf, NULL, 10);
+ temp = temp && 0xFF;
+
+ mutex_lock(&data->lock);
+ data->max_duty_at_overheat = temp;
+ reg = i2c_smbus_read_byte_data(client, ADT7473_REG_CFG4);
+ if (temp)
+ reg |= ADT7473_CFG4_MAX_DUTY_AT_OVT;
+ else
+ reg &= ~ADT7473_CFG4_MAX_DUTY_AT_OVT;
+ i2c_smbus_write_byte_data(client, ADT7473_REG_CFG4, reg);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7473_data *data = adt7473_update_device(dev);
+ return sprintf(buf, "%d\n", data->pwm[attr->index]);
+}
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7473_data *data = i2c_get_clientdata(client);
+ int temp = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->lock);
+ data->pwm[attr->index] = temp;
+ i2c_smbus_write_byte_data(client, ADT7473_REG_PWM(attr->index), temp);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t show_pwm_max(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7473_data *data = adt7473_update_device(dev);
+ return sprintf(buf, "%d\n", data->pwm_max[attr->index]);
+}
+
+static ssize_t set_pwm_max(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7473_data *data = i2c_get_clientdata(client);
+ int temp = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->lock);
+ data->pwm_max[attr->index] = temp;
+ i2c_smbus_write_byte_data(client, ADT7473_REG_PWM_MAX(attr->index),
+ temp);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t show_pwm_min(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7473_data *data = adt7473_update_device(dev);
+ return sprintf(buf, "%d\n", data->pwm_min[attr->index]);
+}
+
+static ssize_t set_pwm_min(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7473_data *data = i2c_get_clientdata(client);
+ int temp = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->lock);
+ data->pwm_min[attr->index] = temp;
+ i2c_smbus_write_byte_data(client, ADT7473_REG_PWM_MIN(attr->index),
+ temp);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t show_temp_tmax(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7473_data *data = adt7473_update_device(dev);
+ return sprintf(buf, "%d\n",
+ 1000 * decode_temp(data, data->temp_tmax[attr->index]));
+}
+
+static ssize_t set_temp_tmax(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7473_data *data = i2c_get_clientdata(client);
+ int temp = simple_strtol(buf, NULL, 10) / 1000;
+ temp = encode_temp(data, temp);
+
+ mutex_lock(&data->lock);
+ data->temp_tmax[attr->index] = temp;
+ i2c_smbus_write_byte_data(client, ADT7473_REG_TEMP_TMAX(attr->index),
+ temp);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t show_temp_tmin(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7473_data *data = adt7473_update_device(dev);
+ return sprintf(buf, "%d\n",
+ 1000 * decode_temp(data, data->temp_tmin[attr->index]));
+}
+
+static ssize_t set_temp_tmin(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7473_data *data = i2c_get_clientdata(client);
+ int temp = simple_strtol(buf, NULL, 10) / 1000;
+ temp = encode_temp(data, temp);
+
+ mutex_lock(&data->lock);
+ data->temp_tmin[attr->index] = temp;
+ i2c_smbus_write_byte_data(client, ADT7473_REG_TEMP_TMIN(attr->index),
+ temp);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t show_pwm_enable(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7473_data *data = adt7473_update_device(dev);
+
+ switch (data->pwm_behavior[attr->index] >> ADT7473_PWM_BHVR_SHIFT) {
+ case 3:
+ return sprintf(buf, "0\n");
+ case 7:
+ return sprintf(buf, "1\n");
+ default:
+ return sprintf(buf, "2\n");
+ }
+}
+
+static ssize_t set_pwm_enable(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf,
+ size_t count)
+{
+ u8 reg;
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7473_data *data = i2c_get_clientdata(client);
+ int temp = simple_strtol(buf, NULL, 10);
+
+ switch (temp) {
+ case 0:
+ temp = 3;
+ break;
+ case 1:
+ temp = 7;
+ break;
+ case 2:
+ /* Enter automatic mode with fans off */
+ temp = 4;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ mutex_lock(&data->lock);
+ reg = i2c_smbus_read_byte_data(client,
+ ADT7473_REG_PWM_BHVR(attr->index));
+ reg = (temp << ADT7473_PWM_BHVR_SHIFT) |
+ (reg & ~ADT7473_PWM_BHVR_MASK);
+ i2c_smbus_write_byte_data(client, ADT7473_REG_PWM_BHVR(attr->index),
+ reg);
+ data->pwm_behavior[attr->index] = reg;
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t show_pwm_auto_temp(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7473_data *data = adt7473_update_device(dev);
+ int bhvr = data->pwm_behavior[attr->index] >> ADT7473_PWM_BHVR_SHIFT;
+
+ switch (bhvr) {
+ case 3:
+ case 4:
+ case 7:
+ return sprintf(buf, "0\n");
+ case 0:
+ case 1:
+ case 5:
+ case 6:
+ return sprintf(buf, "%d\n", bhvr + 1);
+ case 2:
+ return sprintf(buf, "4\n");
+ }
+ /* shouldn't ever get here */
+ BUG();
+}
+
+static ssize_t set_pwm_auto_temp(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf,
+ size_t count)
+{
+ u8 reg;
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7473_data *data = i2c_get_clientdata(client);
+ int temp = simple_strtol(buf, NULL, 10);
+
+ switch (temp) {
+ case 1:
+ case 2:
+ case 6:
+ case 7:
+ temp--;
+ break;
+ case 0:
+ temp = 4;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ mutex_lock(&data->lock);
+ reg = i2c_smbus_read_byte_data(client,
+ ADT7473_REG_PWM_BHVR(attr->index));
+ reg = (temp << ADT7473_PWM_BHVR_SHIFT) |
+ (reg & ~ADT7473_PWM_BHVR_MASK);
+ i2c_smbus_write_byte_data(client, ADT7473_REG_PWM_BHVR(attr->index),
+ reg);
+ data->pwm_behavior[attr->index] = reg;
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t show_alarm(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7473_data *data = adt7473_update_device(dev);
+
+ if (data->alarm & attr->index)
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+
+
+static SENSOR_DEVICE_ATTR(in1_max, S_IWUSR | S_IRUGO, show_volt_max,
+ set_volt_max, 0);
+static SENSOR_DEVICE_ATTR(in2_max, S_IWUSR | S_IRUGO, show_volt_max,
+ set_volt_max, 1);
+
+static SENSOR_DEVICE_ATTR(in1_min, S_IWUSR | S_IRUGO, show_volt_min,
+ set_volt_min, 0);
+static SENSOR_DEVICE_ATTR(in2_min, S_IWUSR | S_IRUGO, show_volt_min,
+ set_volt_min, 1);
+
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_volt, NULL, 0);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_volt, NULL, 1);
+
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL,
+ ADT7473_VCCP_ALARM);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL,
+ ADT7473_VCC_ALARM);
+
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max,
+ set_temp_max, 0);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_max,
+ set_temp_max, 1);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_temp_max,
+ set_temp_max, 2);
+
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_min,
+ set_temp_min, 0);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_min,
+ set_temp_min, 1);
+static SENSOR_DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO, show_temp_min,
+ set_temp_min, 2);
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
+
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL,
+ ADT7473_R1T_ALARM | ALARM2(ADT7473_R1T_SHORT));
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL,
+ ADT7473_LT_ALARM);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL,
+ ADT7473_R2T_ALARM | ALARM2(ADT7473_R2T_SHORT));
+
+static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min,
+ set_fan_min, 0);
+static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min,
+ set_fan_min, 1);
+static SENSOR_DEVICE_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min,
+ set_fan_min, 2);
+static SENSOR_DEVICE_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min,
+ set_fan_min, 3);
+
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3);
+
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL,
+ ALARM2(ADT7473_FAN1_ALARM));
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL,
+ ALARM2(ADT7473_FAN2_ALARM));
+static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL,
+ ALARM2(ADT7473_FAN3_ALARM));
+static SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL,
+ ALARM2(ADT7473_FAN4_ALARM));
+
+static SENSOR_DEVICE_ATTR(pwm_use_point2_pwm_at_crit, S_IWUSR | S_IRUGO,
+ show_max_duty_at_crit, set_max_duty_at_crit, 0);
+
+static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 0);
+static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 1);
+static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 2);
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IWUSR | S_IRUGO,
+ show_pwm_min, set_pwm_min, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_point1_pwm, S_IWUSR | S_IRUGO,
+ show_pwm_min, set_pwm_min, 1);
+static SENSOR_DEVICE_ATTR(pwm3_auto_point1_pwm, S_IWUSR | S_IRUGO,
+ show_pwm_min, set_pwm_min, 2);
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, S_IWUSR | S_IRUGO,
+ show_pwm_max, set_pwm_max, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_point2_pwm, S_IWUSR | S_IRUGO,
+ show_pwm_max, set_pwm_max, 1);
+static SENSOR_DEVICE_ATTR(pwm3_auto_point2_pwm, S_IWUSR | S_IRUGO,
+ show_pwm_max, set_pwm_max, 2);
+
+static SENSOR_DEVICE_ATTR(temp1_auto_point1_temp, S_IWUSR | S_IRUGO,
+ show_temp_tmin, set_temp_tmin, 0);
+static SENSOR_DEVICE_ATTR(temp2_auto_point1_temp, S_IWUSR | S_IRUGO,
+ show_temp_tmin, set_temp_tmin, 1);
+static SENSOR_DEVICE_ATTR(temp3_auto_point1_temp, S_IWUSR | S_IRUGO,
+ show_temp_tmin, set_temp_tmin, 2);
+
+static SENSOR_DEVICE_ATTR(temp1_auto_point2_temp, S_IWUSR | S_IRUGO,
+ show_temp_tmax, set_temp_tmax, 0);
+static SENSOR_DEVICE_ATTR(temp2_auto_point2_temp, S_IWUSR | S_IRUGO,
+ show_temp_tmax, set_temp_tmax, 1);
+static SENSOR_DEVICE_ATTR(temp3_auto_point2_temp, S_IWUSR | S_IRUGO,
+ show_temp_tmax, set_temp_tmax, 2);
+
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
+ set_pwm_enable, 0);
+static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
+ set_pwm_enable, 1);
+static SENSOR_DEVICE_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
+ set_pwm_enable, 2);
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_channels_temp, S_IWUSR | S_IRUGO,
+ show_pwm_auto_temp, set_pwm_auto_temp, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_channels_temp, S_IWUSR | S_IRUGO,
+ show_pwm_auto_temp, set_pwm_auto_temp, 1);
+static SENSOR_DEVICE_ATTR(pwm3_auto_channels_temp, S_IWUSR | S_IRUGO,
+ show_pwm_auto_temp, set_pwm_auto_temp, 2);
+
+static struct attribute *adt7473_attr[] =
+{
+ &sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in1_alarm.dev_attr.attr,
+ &sensor_dev_attr_in2_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_temp2_min.dev_attr.attr,
+ &sensor_dev_attr_temp3_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_point1_temp.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_point1_temp.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_point1_temp.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_point2_temp.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_point2_temp.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_point2_temp.dev_attr.attr,
+
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_min.dev_attr.attr,
+ &sensor_dev_attr_fan3_min.dev_attr.attr,
+ &sensor_dev_attr_fan4_min.dev_attr.attr,
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan3_input.dev_attr.attr,
+ &sensor_dev_attr_fan4_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan2_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan3_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan4_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_pwm_use_point2_pwm_at_crit.dev_attr.attr,
+
+ &sensor_dev_attr_pwm1.dev_attr.attr,
+ &sensor_dev_attr_pwm2.dev_attr.attr,
+ &sensor_dev_attr_pwm3.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr,
+
+ &sensor_dev_attr_pwm1_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm2_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm3_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_channels_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_channels_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_channels_temp.dev_attr.attr,
+
+ NULL
+};
+
+static int adt7473_attach_adapter(struct i2c_adapter *adapter)
+{
+ if (!(adapter->class & I2C_CLASS_HWMON))
+ return 0;
+ return i2c_probe(adapter, &addr_data, adt7473_detect);
+}
+
+static int adt7473_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct i2c_client *client;
+ struct adt7473_data *data;
+ int err = 0;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ goto exit;
+
+ data = kzalloc(sizeof(struct adt7473_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ client = &data->client;
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &adt7473_driver;
+
+ i2c_set_clientdata(client, data);
+
+ mutex_init(&data->lock);
+
+ if (kind <= 0) {
+ int vendor, device, revision;
+
+ vendor = i2c_smbus_read_byte_data(client, ADT7473_REG_VENDOR);
+ if (vendor != ADT7473_VENDOR) {
+ err = -ENODEV;
+ goto exit_free;
+ }
+
+ device = i2c_smbus_read_byte_data(client, ADT7473_REG_DEVICE);
+ if (device != ADT7473_DEVICE) {
+ err = -ENODEV;
+ goto exit_free;
+ }
+
+ revision = i2c_smbus_read_byte_data(client,
+ ADT7473_REG_REVISION);
+ if (revision != ADT7473_REV_68 && revision != ADT7473_REV_69) {
+ err = -ENODEV;
+ goto exit_free;
+ }
+ } else
+ dev_dbg(&adapter->dev, "detection forced\n");
+
+ strlcpy(client->name, "adt7473", I2C_NAME_SIZE);
+
+ err = i2c_attach_client(client);
+ if (err)
+ goto exit_free;
+
+ dev_info(&client->dev, "%s chip found\n", client->name);
+
+ /* Initialize the ADT7473 chip */
+ adt7473_init_client(client);
+
+ /* Register sysfs hooks */
+ data->attrs.attrs = adt7473_attr;
+ err = sysfs_create_group(&client->dev.kobj, &data->attrs);
+ if (err)
+ goto exit_detach;
+
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
+ goto exit_remove;
+ }
+
+ return 0;
+
+exit_remove:
+ sysfs_remove_group(&client->dev.kobj, &data->attrs);
+exit_detach:
+ i2c_detach_client(client);
+exit_free:
+ kfree(data);
+exit:
+ return err;
+}
+
+static int adt7473_detach_client(struct i2c_client *client)
+{
+ struct adt7473_data *data = i2c_get_clientdata(client);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&client->dev.kobj, &data->attrs);
+ i2c_detach_client(client);
+ kfree(data);
+ return 0;
+}
+
+static int __init adt7473_init(void)
+{
+ return i2c_add_driver(&adt7473_driver);
+}
+
+static void __exit adt7473_exit(void)
+{
+ i2c_del_driver(&adt7473_driver);
+}
+
+MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>");
+MODULE_DESCRIPTION("ADT7473 driver");
+MODULE_LICENSE("GPL");
+
+module_init(adt7473_init);
+module_exit(adt7473_exit);
diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
index 0c94770b7f8..aacc0c4b809 100644
--- a/drivers/hwmon/applesmc.c
+++ b/drivers/hwmon/applesmc.c
@@ -84,12 +84,15 @@ static const char* temperature_sensors_sets[][36] = {
/* Set 0: Macbook Pro */
{ "TA0P", "TB0T", "TC0D", "TC0P", "TG0H", "TG0P", "TG0T", "Th0H",
"Th1H", "Tm0P", "Ts0P", "Ts1P", NULL },
-/* Set 1: Macbook set */
+/* Set 1: Macbook2 set */
+ { "TB0T", "TC0D", "TC0P", "TM0P", "TN0P", "TN1P", "TTF0", "Th0H",
+ "Th0S", "Th1H", NULL },
+/* Set 2: Macbook set */
{ "TB0T", "TC0D", "TC0P", "TM0P", "TN0P", "TN1P", "Th0H", "Th0S",
"Th1H", "Ts0P", NULL },
-/* Set 2: Macmini set */
+/* Set 3: Macmini set */
{ "TC0D", "TC0P", NULL },
-/* Set 3: Mac Pro (2 x Quad-Core) */
+/* Set 4: Mac Pro (2 x Quad-Core) */
{ "TA0P", "TCAG", "TCAH", "TCBG", "TCBH", "TC0C", "TC0D", "TC0P",
"TC1C", "TC1D", "TC2C", "TC2D", "TC3C", "TC3D", "THTG", "TH0P",
"TH1P", "TH2P", "TH3P", "TMAP", "TMAS", "TMBS", "TM0P", "TM0S",
@@ -1212,12 +1215,14 @@ static void applesmc_release_accelerometer(void)
static __initdata struct dmi_match_data applesmc_dmi_data[] = {
/* MacBook Pro: accelerometer, backlight and temperature set 0 */
{ .accelerometer = 1, .light = 1, .temperature_set = 0 },
-/* MacBook: accelerometer and temperature set 1 */
+/* MacBook2: accelerometer and temperature set 1 */
{ .accelerometer = 1, .light = 0, .temperature_set = 1 },
-/* MacMini: temperature set 2 */
- { .accelerometer = 0, .light = 0, .temperature_set = 2 },
-/* MacPro: temperature set 3 */
+/* MacBook: accelerometer and temperature set 2 */
+ { .accelerometer = 1, .light = 0, .temperature_set = 2 },
+/* MacMini: temperature set 3 */
{ .accelerometer = 0, .light = 0, .temperature_set = 3 },
+/* MacPro: temperature set 4 */
+ { .accelerometer = 0, .light = 0, .temperature_set = 4 },
};
/* Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1".
@@ -1229,16 +1234,20 @@ static __initdata struct dmi_system_id applesmc_whitelist[] = {
(void*)&applesmc_dmi_data[0]},
{ applesmc_dmi_match, "Apple MacBook", {
DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
- DMI_MATCH(DMI_PRODUCT_NAME,"MacBook") },
+ DMI_MATCH(DMI_PRODUCT_NAME,"MacBook2") },
(void*)&applesmc_dmi_data[1]},
+ { applesmc_dmi_match, "Apple MacBook", {
+ DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
+ DMI_MATCH(DMI_PRODUCT_NAME,"MacBook") },
+ (void*)&applesmc_dmi_data[2]},
{ applesmc_dmi_match, "Apple Macmini", {
DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
DMI_MATCH(DMI_PRODUCT_NAME,"Macmini") },
- (void*)&applesmc_dmi_data[2]},
+ (void*)&applesmc_dmi_data[3]},
{ applesmc_dmi_match, "Apple MacPro2", {
DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
DMI_MATCH(DMI_PRODUCT_NAME,"MacPro2") },
- (void*)&applesmc_dmi_data[3]},
+ (void*)&applesmc_dmi_data[4]},
{ .ident = NULL }
};
diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c
index 950cea8d1d6..84712a22ace 100644
--- a/drivers/hwmon/asb100.c
+++ b/drivers/hwmon/asb100.c
@@ -49,7 +49,7 @@
#include "lm75.h"
/* I2C addresses to scan */
-static unsigned short normal_i2c[] = { 0x2d, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x2d, I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD_1(asb100);
diff --git a/drivers/hwmon/atxp1.c b/drivers/hwmon/atxp1.c
index cce3350e539..01c17e387f0 100644
--- a/drivers/hwmon/atxp1.c
+++ b/drivers/hwmon/atxp1.c
@@ -42,7 +42,7 @@ MODULE_AUTHOR("Sebastian Witt <se.witt@gmx.net>");
#define ATXP1_VIDMASK 0x1f
#define ATXP1_GPIO1MASK 0x0f
-static unsigned short normal_i2c[] = { 0x37, 0x4e, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x37, 0x4e, I2C_CLIENT_END };
I2C_CLIENT_INSMOD_1(atxp1);
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index 3ee60d26e3a..70239acecc8 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -38,7 +38,8 @@
#define DRVNAME "coretemp"
-typedef enum { SHOW_TEMP, SHOW_TJMAX, SHOW_LABEL, SHOW_NAME } SHOW;
+typedef enum { SHOW_TEMP, SHOW_TJMAX, SHOW_TTARGET, SHOW_LABEL,
+ SHOW_NAME } SHOW;
/*
* Functions declaration
@@ -55,6 +56,7 @@ struct coretemp_data {
unsigned long last_updated; /* in jiffies */
int temp;
int tjmax;
+ int ttarget;
u8 alarm;
};
@@ -93,9 +95,10 @@ static ssize_t show_temp(struct device *dev,
if (attr->index == SHOW_TEMP)
err = data->valid ? sprintf(buf, "%d\n", data->temp) : -EAGAIN;
- else
+ else if (attr->index == SHOW_TJMAX)
err = sprintf(buf, "%d\n", data->tjmax);
-
+ else
+ err = sprintf(buf, "%d\n", data->ttarget);
return err;
}
@@ -103,6 +106,8 @@ static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL,
SHOW_TEMP);
static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp, NULL,
SHOW_TJMAX);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp, NULL,
+ SHOW_TTARGET);
static DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL);
static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_name, NULL, SHOW_LABEL);
static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, SHOW_NAME);
@@ -147,6 +152,56 @@ static struct coretemp_data *coretemp_update_device(struct device *dev)
return data;
}
+static int __devinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
+{
+ /* The 100C is default for both mobile and non mobile CPUs */
+
+ int tjmax = 100000;
+ int ismobile = 1;
+ int err;
+ u32 eax, edx;
+
+ /* Early chips have no MSR for TjMax */
+
+ if ((c->x86_model == 0xf) && (c->x86_mask < 4)) {
+ ismobile = 0;
+ }
+
+ if ((c->x86_model > 0xe) && (ismobile)) {
+
+ /* Now we can detect the mobile CPU using Intel provided table
+ http://softwarecommunity.intel.com/Wiki/Mobility/720.htm
+ For Core2 cores, check MSR 0x17, bit 28 1 = Mobile CPU
+ */
+
+ err = rdmsr_safe_on_cpu(id, 0x17, &eax, &edx);
+ if (err) {
+ dev_warn(dev,
+ "Unable to access MSR 0x17, assuming desktop"
+ " CPU\n");
+ ismobile = 0;
+ } else if (!(eax & 0x10000000)) {
+ ismobile = 0;
+ }
+ }
+
+ if (ismobile) {
+
+ err = rdmsr_safe_on_cpu(id, 0xee, &eax, &edx);
+ if (err) {
+ dev_warn(dev,
+ "Unable to access MSR 0xEE, for Tjmax, left"
+ " at default");
+ } else if (eax & 0x40000000) {
+ tjmax = 85000;
+ }
+ } else {
+ dev_warn(dev, "Using relative temperature scale!\n");
+ }
+
+ return tjmax;
+}
+
static int __devinit coretemp_probe(struct platform_device *pdev)
{
struct coretemp_data *data;
@@ -163,8 +218,6 @@ static int __devinit coretemp_probe(struct platform_device *pdev)
data->id = pdev->id;
data->name = "coretemp";
mutex_init(&data->update_lock);
- /* Tjmax default is 100 degrees C */
- data->tjmax = 100000;
/* test if we can access the THERM_STATUS MSR */
err = rdmsr_safe_on_cpu(data->id, MSR_IA32_THERM_STATUS, &eax, &edx);
@@ -191,40 +244,29 @@ static int __devinit coretemp_probe(struct platform_device *pdev)
}
}
- /* Some processors have Tjmax 85 following magic should detect it
- Intel won't disclose the information without signed NDA, but
- individuals cannot sign it. Catch(ed) 22.
- */
+ data->tjmax = adjust_tjmax(c, data->id, &pdev->dev);
+ platform_set_drvdata(pdev, data);
- if (((c->x86_model == 0xf) && (c->x86_mask > 3)) ||
- (c->x86_model == 0xe)) {
- err = rdmsr_safe_on_cpu(data->id, 0xee, &eax, &edx);
+ /* read the still undocumented IA32_TEMPERATURE_TARGET it exists
+ on older CPUs but not in this register */
+
+ if (c->x86_model > 0xe) {
+ err = rdmsr_safe_on_cpu(data->id, 0x1a2, &eax, &edx);
if (err) {
- dev_warn(&pdev->dev,
- "Unable to access MSR 0xEE, Tjmax left at %d "
- "degrees C\n", data->tjmax/1000);
- } else if (eax & 0x40000000) {
- data->tjmax = 85000;
+ dev_warn(&pdev->dev, "Unable to read"
+ " IA32_TEMPERATURE_TARGET MSR\n");
+ } else {
+ data->ttarget = data->tjmax -
+ (((eax >> 8) & 0xff) * 1000);
+ err = device_create_file(&pdev->dev,
+ &sensor_dev_attr_temp1_max.dev_attr);
+ if (err)
+ goto exit_free;
}
}
- /* Intel says that above should not work for desktop Core2 processors,
- but it seems to work. There is no other way how get the absolute
- readings. Warn the user about this. First check if are desktop,
- bit 50 of MSR_IA32_PLATFORM_ID should be 0.
- */
-
- rdmsr_safe_on_cpu(data->id, MSR_IA32_PLATFORM_ID, &eax, &edx);
-
- if ((c->x86_model == 0xf) && (!(edx & 0x00040000))) {
- dev_warn(&pdev->dev, "Using undocumented features, absolute "
- "temperature might be wrong!\n");
- }
-
- platform_set_drvdata(pdev, data);
-
if ((err = sysfs_create_group(&pdev->dev.kobj, &coretemp_group)))
- goto exit_free;
+ goto exit_dev;
data->hwmon_dev = hwmon_device_register(&pdev->dev);
if (IS_ERR(data->hwmon_dev)) {
@@ -238,6 +280,8 @@ static int __devinit coretemp_probe(struct platform_device *pdev)
exit_class:
sysfs_remove_group(&pdev->dev.kobj, &coretemp_group);
+exit_dev:
+ device_remove_file(&pdev->dev, &sensor_dev_attr_temp1_max.dev_attr);
exit_free:
kfree(data);
exit:
@@ -250,6 +294,7 @@ static int __devexit coretemp_remove(struct platform_device *pdev)
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&pdev->dev.kobj, &coretemp_group);
+ device_remove_file(&pdev->dev, &sensor_dev_attr_temp1_max.dev_attr);
platform_set_drvdata(pdev, NULL);
kfree(data);
return 0;
@@ -330,7 +375,7 @@ static void coretemp_device_remove(unsigned int cpu)
mutex_unlock(&pdev_list_mutex);
}
-static int coretemp_cpu_callback(struct notifier_block *nfb,
+static int __cpuinit coretemp_cpu_callback(struct notifier_block *nfb,
unsigned long action, void *hcpu)
{
unsigned int cpu = (unsigned long) hcpu;
@@ -347,7 +392,7 @@ static int coretemp_cpu_callback(struct notifier_block *nfb,
return NOTIFY_OK;
}
-static struct notifier_block coretemp_cpu_notifier = {
+static struct notifier_block coretemp_cpu_notifier __refdata = {
.notifier_call = coretemp_cpu_callback,
};
#endif /* !CONFIG_HOTPLUG_CPU */
@@ -368,10 +413,10 @@ static int __init coretemp_init(void)
for_each_online_cpu(i) {
struct cpuinfo_x86 *c = &cpu_data(i);
- /* check if family 6, models e, f, 16 */
+ /* check if family 6, models 0xe, 0xf, 0x16, 0x17 */
if ((c->cpuid_level < 0) || (c->x86 != 0x6) ||
!((c->x86_model == 0xe) || (c->x86_model == 0xf) ||
- (c->x86_model == 0x16))) {
+ (c->x86_model == 0x16) || (c->x86_model == 0x17))) {
/* supported CPU not found, but report the unknown
family 6 CPU */
diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c
index ddddd9f34c1..7673f65877e 100644
--- a/drivers/hwmon/dme1737.c
+++ b/drivers/hwmon/dme1737.c
@@ -49,7 +49,7 @@ module_param(force_id, ushort, 0);
MODULE_PARM_DESC(force_id, "Override the detected device ID");
/* Addresses to scan */
-static unsigned short normal_i2c[] = {0x2c, 0x2d, 0x2e, I2C_CLIENT_END};
+static const unsigned short normal_i2c[] = {0x2c, 0x2d, 0x2e, I2C_CLIENT_END};
/* Insmod parameters */
I2C_CLIENT_INSMOD_1(dme1737);
diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c
index 3f5163de13c..5f300ffed65 100644
--- a/drivers/hwmon/ds1621.c
+++ b/drivers/hwmon/ds1621.c
@@ -34,7 +34,7 @@
#include "lm75.h"
/* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
+static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
/* Insmod parameters */
diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c
index 6892f76fc18..1464338e4e1 100644
--- a/drivers/hwmon/f75375s.c
+++ b/drivers/hwmon/f75375s.c
@@ -37,7 +37,7 @@
#include <linux/f75375s.h>
/* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x2d, 0x2e, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x2d, 0x2e, I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD_2(f75373, f75375);
diff --git a/drivers/hwmon/fscher.c b/drivers/hwmon/fscher.c
index 721c70177b1..ed26b66e083 100644
--- a/drivers/hwmon/fscher.c
+++ b/drivers/hwmon/fscher.c
@@ -40,7 +40,7 @@
* Addresses to scan
*/
-static unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
/*
* Insmod parameters
diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c
index b7c9eef0f92..bd89d270a5e 100644
--- a/drivers/hwmon/fschmd.c
+++ b/drivers/hwmon/fschmd.c
@@ -44,7 +44,7 @@
#include <linux/dmi.h>
/* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd);
diff --git a/drivers/hwmon/fscpos.c b/drivers/hwmon/fscpos.c
index 2f1075323a1..00f48484e54 100644
--- a/drivers/hwmon/fscpos.c
+++ b/drivers/hwmon/fscpos.c
@@ -43,7 +43,7 @@
/*
* Addresses to scan
*/
-static unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
/*
* Insmod parameters
diff --git a/drivers/hwmon/gl518sm.c b/drivers/hwmon/gl518sm.c
index 3b1ac48fce2..33e9e8a8d1c 100644
--- a/drivers/hwmon/gl518sm.c
+++ b/drivers/hwmon/gl518sm.c
@@ -44,7 +44,7 @@
#include <linux/sysfs.h>
/* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD_2(gl518sm_r00, gl518sm_r80);
diff --git a/drivers/hwmon/gl520sm.c b/drivers/hwmon/gl520sm.c
index 03ecdc33476..8984ef14162 100644
--- a/drivers/hwmon/gl520sm.c
+++ b/drivers/hwmon/gl520sm.c
@@ -39,7 +39,7 @@ module_param(extra_sensor_type, ushort, 0);
MODULE_PARM_DESC(extra_sensor_type, "Type of extra sensor (0=autodetect, 1=temperature, 2=voltage)");
/* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD_1(gl520sm);
diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c
index 650b07d5b90..11628700808 100644
--- a/drivers/hwmon/lm63.c
+++ b/drivers/hwmon/lm63.c
@@ -53,7 +53,7 @@
* Address is fully defined internally and cannot be changed.
*/
-static unsigned short normal_i2c[] = { 0x4c, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x4c, I2C_CLIENT_END };
/*
* Insmod parameters
diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c
index e5c35a355a5..115f4090b98 100644
--- a/drivers/hwmon/lm75.c
+++ b/drivers/hwmon/lm75.c
@@ -31,7 +31,7 @@
/* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
+static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
/* Insmod parameters */
diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c
index 459b70ad6be..36d5a8c3ad8 100644
--- a/drivers/hwmon/lm77.c
+++ b/drivers/hwmon/lm77.c
@@ -36,7 +36,8 @@
#include <linux/mutex.h>
/* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
+ I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD_1(lm77);
diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c
index 0a9eb1f6f4e..ed7859f0e16 100644
--- a/drivers/hwmon/lm78.c
+++ b/drivers/hwmon/lm78.c
@@ -37,8 +37,8 @@
static struct platform_device *pdev;
/* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
- 0x2e, 0x2f, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
+ 0x2e, 0x2f, I2C_CLIENT_END };
static unsigned short isa_address = 0x290;
/* Insmod parameters */
diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c
index a2ca055f392..26c91c9d476 100644
--- a/drivers/hwmon/lm80.c
+++ b/drivers/hwmon/lm80.c
@@ -32,8 +32,8 @@
#include <linux/mutex.h>
/* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c,
- 0x2d, 0x2e, 0x2f, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
+ 0x2e, 0x2f, I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD_1(lm80);
diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c
index 6e8903a6e90..6a8642fa25f 100644
--- a/drivers/hwmon/lm83.c
+++ b/drivers/hwmon/lm83.c
@@ -48,10 +48,8 @@
* addresses.
*/
-static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a,
- 0x29, 0x2a, 0x2b,
- 0x4c, 0x4d, 0x4e,
- I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = {
+ 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x4c, 0x4d, 0x4e, I2C_CLIENT_END };
/*
* Insmod parameters
diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c
index 4bb0f291a6b..182fe6a5605 100644
--- a/drivers/hwmon/lm85.c
+++ b/drivers/hwmon/lm85.c
@@ -35,7 +35,7 @@
#include <linux/mutex.h>
/* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD_6(lm85b, lm85c, adm1027, adt7463, emc6d100, emc6d102);
diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c
index 8ee07c5c97a..e1c183f0aae 100644
--- a/drivers/hwmon/lm87.c
+++ b/drivers/hwmon/lm87.c
@@ -73,7 +73,7 @@
* LM87 has three possible addresses: 0x2c, 0x2d and 0x2e.
*/
-static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
/*
* Insmod parameters
diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
index f7ec95bedbf..d1a3da3dd8e 100644
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -101,10 +101,8 @@
* 0x4c, 0x4d or 0x4e.
*/
-static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a,
- 0x29, 0x2a, 0x2b,
- 0x4c, 0x4d, 0x4e,
- I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = {
+ 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x4c, 0x4d, 0x4e, I2C_CLIENT_END };
/*
* Insmod parameters
diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c
index af5c77d568f..c31942e0824 100644
--- a/drivers/hwmon/lm92.c
+++ b/drivers/hwmon/lm92.c
@@ -45,13 +45,14 @@
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
/* The LM92 and MAX6635 have 2 two-state pins for address selection,
resulting in 4 possible addresses. */
-static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
- I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
+ I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD_1(lm92);
@@ -209,6 +210,14 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ch
return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->temp1_input));
}
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int bitnr = to_sensor_dev_attr(attr)->index;
+ struct lm92_data *data = lm92_update_device(dev);
+ return sprintf(buf, "%d\n", (data->temp1_input >> bitnr) & 1);
+}
+
static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1_input, NULL);
static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp1_crit,
set_temp1_crit);
@@ -221,6 +230,9 @@ static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp1_max,
set_temp1_max);
static DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_temp1_max_hyst, NULL);
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 1);
/*
@@ -297,7 +309,9 @@ static struct attribute *lm92_attributes[] = {
&dev_attr_temp1_max.attr,
&dev_attr_temp1_max_hyst.attr,
&dev_attr_alarms.attr,
-
+ &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
NULL
};
diff --git a/drivers/hwmon/lm93.c b/drivers/hwmon/lm93.c
index ea61946a4bf..5e678f5c883 100644
--- a/drivers/hwmon/lm93.c
+++ b/drivers/hwmon/lm93.c
@@ -142,7 +142,7 @@
I2C_FUNC_SMBUS_WORD_DATA)
/* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD_1(lm93);
diff --git a/drivers/hwmon/max1619.c b/drivers/hwmon/max1619.c
index 38a44c3d6ce..7e7267a0454 100644
--- a/drivers/hwmon/max1619.c
+++ b/drivers/hwmon/max1619.c
@@ -32,14 +32,13 @@
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
-static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a,
- 0x29, 0x2a, 0x2b,
- 0x4c, 0x4d, 0x4e,
- I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = {
+ 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x4c, 0x4d, 0x4e, I2C_CLIENT_END };
/*
* Insmod parameters
@@ -161,6 +160,14 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ch
return sprintf(buf, "%d\n", data->alarms);
}
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int bitnr = to_sensor_dev_attr(attr)->index;
+ struct max1619_data *data = max1619_update_device(dev);
+ return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1);
+}
+
static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL);
static DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input2, NULL);
static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_low2,
@@ -172,6 +179,10 @@ static DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp_crit2,
static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp_hyst2,
set_temp_hyst2);
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4);
static struct attribute *max1619_attributes[] = {
&dev_attr_temp1_input.attr,
@@ -182,6 +193,10 @@ static struct attribute *max1619_attributes[] = {
&dev_attr_temp2_crit_hyst.attr,
&dev_attr_alarms.attr,
+ &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_fault.dev_attr.attr,
+ &sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
NULL
};
diff --git a/drivers/hwmon/max6650.c b/drivers/hwmon/max6650.c
index 755570c1f4e..52d528b76cc 100644
--- a/drivers/hwmon/max6650.c
+++ b/drivers/hwmon/max6650.c
@@ -44,7 +44,8 @@
* Addresses to scan. There are four disjoint possibilities, by pin config.
*/
-static unsigned short normal_i2c[] = {0x1b, 0x1f, 0x48, 0x4b, I2C_CLIENT_END};
+static const unsigned short normal_i2c[] = {0x1b, 0x1f, 0x48, 0x4b,
+ I2C_CLIENT_END};
/*
* Insmod parameters
diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c
index 0d7f0c4d06b..d1b49854873 100644
--- a/drivers/hwmon/smsc47m1.c
+++ b/drivers/hwmon/smsc47m1.c
@@ -198,6 +198,14 @@ static ssize_t get_fan_div(struct device *dev, struct device_attribute
return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[attr->index]));
}
+static ssize_t get_fan_alarm(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ int bitnr = to_sensor_dev_attr(devattr)->index;
+ struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
+ return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
+}
+
static ssize_t get_pwm(struct device *dev, struct device_attribute
*devattr, char *buf)
{
@@ -347,6 +355,8 @@ static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
get_fan_min, set_fan_min, offset - 1); \
static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
get_fan_div, set_fan_div, offset - 1); \
+static SENSOR_DEVICE_ATTR(fan##offset##_alarm, S_IRUGO, get_fan_alarm, \
+ NULL, offset - 1); \
static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
get_pwm, set_pwm, offset - 1); \
static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \
@@ -374,12 +384,15 @@ static struct attribute *smsc47m1_attributes[] = {
&sensor_dev_attr_fan1_input.dev_attr.attr,
&sensor_dev_attr_fan1_min.dev_attr.attr,
&sensor_dev_attr_fan1_div.dev_attr.attr,
+ &sensor_dev_attr_fan1_alarm.dev_attr.attr,
&sensor_dev_attr_fan2_input.dev_attr.attr,
&sensor_dev_attr_fan2_min.dev_attr.attr,
&sensor_dev_attr_fan2_div.dev_attr.attr,
+ &sensor_dev_attr_fan2_alarm.dev_attr.attr,
&sensor_dev_attr_fan3_input.dev_attr.attr,
&sensor_dev_attr_fan3_min.dev_attr.attr,
&sensor_dev_attr_fan3_div.dev_attr.attr,
+ &sensor_dev_attr_fan3_alarm.dev_attr.attr,
&sensor_dev_attr_pwm1.dev_attr.attr,
&sensor_dev_attr_pwm1_enable.dev_attr.attr,
@@ -533,7 +546,9 @@ static int __devinit smsc47m1_probe(struct platform_device *pdev)
|| (err = device_create_file(dev,
&sensor_dev_attr_fan1_min.dev_attr))
|| (err = device_create_file(dev,
- &sensor_dev_attr_fan1_div.dev_attr)))
+ &sensor_dev_attr_fan1_div.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_fan1_alarm.dev_attr)))
goto error_remove_files;
} else
dev_dbg(dev, "Fan 1 not enabled by hardware, skipping\n");
@@ -544,7 +559,9 @@ static int __devinit smsc47m1_probe(struct platform_device *pdev)
|| (err = device_create_file(dev,
&sensor_dev_attr_fan2_min.dev_attr))
|| (err = device_create_file(dev,
- &sensor_dev_attr_fan2_div.dev_attr)))
+ &sensor_dev_attr_fan2_div.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_fan2_alarm.dev_attr)))
goto error_remove_files;
} else
dev_dbg(dev, "Fan 2 not enabled by hardware, skipping\n");
@@ -555,7 +572,9 @@ static int __devinit smsc47m1_probe(struct platform_device *pdev)
|| (err = device_create_file(dev,
&sensor_dev_attr_fan3_min.dev_attr))
|| (err = device_create_file(dev,
- &sensor_dev_attr_fan3_div.dev_attr)))
+ &sensor_dev_attr_fan3_div.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_fan3_alarm.dev_attr)))
goto error_remove_files;
} else if (data->type == smsc47m2)
dev_dbg(dev, "Fan 3 not enabled by hardware, skipping\n");
diff --git a/drivers/hwmon/smsc47m192.c b/drivers/hwmon/smsc47m192.c
index 8b0c188e60f..3c9db6598ba 100644
--- a/drivers/hwmon/smsc47m192.c
+++ b/drivers/hwmon/smsc47m192.c
@@ -34,7 +34,7 @@
#include <linux/mutex.h>
/* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD_1(smsc47m192);
diff --git a/drivers/hwmon/thmc50.c b/drivers/hwmon/thmc50.c
index 04dd7699b3a..76a3859c3fb 100644
--- a/drivers/hwmon/thmc50.c
+++ b/drivers/hwmon/thmc50.c
@@ -32,7 +32,7 @@
MODULE_LICENSE("GPL");
/* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD_2(thmc50, adm1022);
@@ -52,9 +52,9 @@ I2C_CLIENT_MODULE_PARM(adm1022_temp3, "List of adapter,address pairs "
*/
#define THMC50_REG_INTR 0x41
-const static u8 THMC50_REG_TEMP[] = { 0x27, 0x26, 0x20 };
-const static u8 THMC50_REG_TEMP_MIN[] = { 0x3A, 0x38, 0x2C };
-const static u8 THMC50_REG_TEMP_MAX[] = { 0x39, 0x37, 0x2B };
+static const u8 THMC50_REG_TEMP[] = { 0x27, 0x26, 0x20 };
+static const u8 THMC50_REG_TEMP_MIN[] = { 0x3A, 0x38, 0x2C };
+static const u8 THMC50_REG_TEMP_MAX[] = { 0x39, 0x37, 0x2B };
#define THMC50_REG_CONF_nFANOFF 0x20
diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c
index 2635bba1e3f..f1ee5e73196 100644
--- a/drivers/hwmon/via686a.c
+++ b/drivers/hwmon/via686a.c
@@ -533,6 +533,24 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ch
}
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int bitnr = to_sensor_dev_attr(attr)->index;
+ struct via686a_data *data = via686a_update_device(dev);
+ return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
+}
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 15);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
+
static ssize_t show_name(struct device *dev, struct device_attribute
*devattr, char *buf)
{
@@ -557,6 +575,11 @@ static struct attribute *via686a_attributes[] = {
&sensor_dev_attr_in2_max.dev_attr.attr,
&sensor_dev_attr_in3_max.dev_attr.attr,
&sensor_dev_attr_in4_max.dev_attr.attr,
+ &sensor_dev_attr_in0_alarm.dev_attr.attr,
+ &sensor_dev_attr_in1_alarm.dev_attr.attr,
+ &sensor_dev_attr_in2_alarm.dev_attr.attr,
+ &sensor_dev_attr_in3_alarm.dev_attr.attr,
+ &sensor_dev_attr_in4_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_temp2_input.dev_attr.attr,
@@ -567,6 +590,9 @@ static struct attribute *via686a_attributes[] = {
&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp1_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_alarm.dev_attr.attr,
&sensor_dev_attr_fan1_input.dev_attr.attr,
&sensor_dev_attr_fan2_input.dev_attr.attr,
@@ -574,6 +600,8 @@ static struct attribute *via686a_attributes[] = {
&sensor_dev_attr_fan2_min.dev_attr.attr,
&sensor_dev_attr_fan1_div.dev_attr.attr,
&sensor_dev_attr_fan2_div.dev_attr.attr,
+ &sensor_dev_attr_fan1_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan2_alarm.dev_attr.attr,
&dev_attr_alarms.attr,
&dev_attr_name.attr,
diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c
index f87661775fe..5bc57275cae 100644
--- a/drivers/hwmon/vt8231.c
+++ b/drivers/hwmon/vt8231.c
@@ -2,7 +2,7 @@
vt8231.c - Part of lm_sensors, Linux kernel modules
for hardware monitoring
- Copyright (c) 2005 Roger Lucas <roger@planbit.co.uk>
+ Copyright (c) 2005 Roger Lucas <vt8231@hiddenengine.co.uk>
Copyright (c) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
Aaron M. Marsh <amarsh@sdf.lonestar.org>
@@ -541,6 +541,28 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int bitnr = to_sensor_dev_attr(attr)->index;
+ struct vt8231_data *data = vt8231_update_device(dev);
+ return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
+}
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp4_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp5_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp6_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
+
static ssize_t show_name(struct device *dev, struct device_attribute
*devattr, char *buf)
{
@@ -549,36 +571,42 @@ static ssize_t show_name(struct device *dev, struct device_attribute
}
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
-static struct attribute *vt8231_attributes_temps[6][4] = {
+static struct attribute *vt8231_attributes_temps[6][5] = {
{
&dev_attr_temp1_input.attr,
&dev_attr_temp1_max_hyst.attr,
&dev_attr_temp1_max.attr,
+ &sensor_dev_attr_temp1_alarm.dev_attr.attr,
NULL
}, {
&sensor_dev_attr_temp2_input.dev_attr.attr,
&sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_alarm.dev_attr.attr,
NULL
}, {
&sensor_dev_attr_temp3_input.dev_attr.attr,
&sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp3_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_alarm.dev_attr.attr,
NULL
}, {
&sensor_dev_attr_temp4_input.dev_attr.attr,
&sensor_dev_attr_temp4_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp4_max.dev_attr.attr,
+ &sensor_dev_attr_temp4_alarm.dev_attr.attr,
NULL
}, {
&sensor_dev_attr_temp5_input.dev_attr.attr,
&sensor_dev_attr_temp5_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp5_max.dev_attr.attr,
+ &sensor_dev_attr_temp5_alarm.dev_attr.attr,
NULL
}, {
&sensor_dev_attr_temp6_input.dev_attr.attr,
&sensor_dev_attr_temp6_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp6_max.dev_attr.attr,
+ &sensor_dev_attr_temp6_alarm.dev_attr.attr,
NULL
}
};
@@ -592,36 +620,42 @@ static const struct attribute_group vt8231_group_temps[6] = {
{ .attrs = vt8231_attributes_temps[5] },
};
-static struct attribute *vt8231_attributes_volts[6][4] = {
+static struct attribute *vt8231_attributes_volts[6][5] = {
{
&sensor_dev_attr_in0_input.dev_attr.attr,
&sensor_dev_attr_in0_min.dev_attr.attr,
&sensor_dev_attr_in0_max.dev_attr.attr,
+ &sensor_dev_attr_in0_alarm.dev_attr.attr,
NULL
}, {
&sensor_dev_attr_in1_input.dev_attr.attr,
&sensor_dev_attr_in1_min.dev_attr.attr,
&sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in1_alarm.dev_attr.attr,
NULL
}, {
&sensor_dev_attr_in2_input.dev_attr.attr,
&sensor_dev_attr_in2_min.dev_attr.attr,
&sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in2_alarm.dev_attr.attr,
NULL
}, {
&sensor_dev_attr_in3_input.dev_attr.attr,
&sensor_dev_attr_in3_min.dev_attr.attr,
&sensor_dev_attr_in3_max.dev_attr.attr,
+ &sensor_dev_attr_in3_alarm.dev_attr.attr,
NULL
}, {
&sensor_dev_attr_in4_input.dev_attr.attr,
&sensor_dev_attr_in4_min.dev_attr.attr,
&sensor_dev_attr_in4_max.dev_attr.attr,
+ &sensor_dev_attr_in4_alarm.dev_attr.attr,
NULL
}, {
&dev_attr_in5_input.attr,
&dev_attr_in5_min.attr,
&dev_attr_in5_max.attr,
+ &sensor_dev_attr_in5_alarm.dev_attr.attr,
NULL
}
};
@@ -642,6 +676,8 @@ static struct attribute *vt8231_attributes[] = {
&sensor_dev_attr_fan2_min.dev_attr.attr,
&sensor_dev_attr_fan1_div.dev_attr.attr,
&sensor_dev_attr_fan2_div.dev_attr.attr,
+ &sensor_dev_attr_fan1_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan2_alarm.dev_attr.attr,
&dev_attr_alarms.attr,
&dev_attr_name.attr,
NULL
@@ -963,7 +999,7 @@ static void __exit sm_vt8231_exit(void)
}
}
-MODULE_AUTHOR("Roger Lucas <roger@planbit.co.uk>");
+MODULE_AUTHOR("Roger Lucas <vt8231@hiddenengine.co.uk>");
MODULE_DESCRIPTION("VT8231 sensors");
MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c
index 7421f6ea53e..5c85670e2d1 100644
--- a/drivers/hwmon/w83781d.c
+++ b/drivers/hwmon/w83781d.c
@@ -53,8 +53,8 @@
static struct platform_device *pdev;
/* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
- 0x2e, 0x2f, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
+ 0x2e, 0x2f, I2C_CLIENT_END };
static unsigned short isa_address = 0x290;
/* Insmod parameters */
diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c
index 85bd21ee329..85077c4c803 100644
--- a/drivers/hwmon/w83791d.c
+++ b/drivers/hwmon/w83791d.c
@@ -47,7 +47,8 @@
#define NUMBER_OF_TEMPIN 3
/* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
+ I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD_1(w83791d);
diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c
index 007449d3e16..299629d47ed 100644
--- a/drivers/hwmon/w83792d.c
+++ b/drivers/hwmon/w83792d.c
@@ -46,7 +46,8 @@
#include <linux/sysfs.h>
/* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
+ I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD_1(w83792d);
diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c
index 3ba1d6b3347..ee35af93b57 100644
--- a/drivers/hwmon/w83793.c
+++ b/drivers/hwmon/w83793.c
@@ -37,7 +37,8 @@
#include <linux/mutex.h>
/* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
+ I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD_1(w83793);
diff --git a/drivers/hwmon/w83l785ts.c b/drivers/hwmon/w83l785ts.c
index 1d6259d29e7..77f2d482888 100644
--- a/drivers/hwmon/w83l785ts.c
+++ b/drivers/hwmon/w83l785ts.c
@@ -49,7 +49,7 @@
* Address is fully defined internally and cannot be changed.
*/
-static unsigned short normal_i2c[] = { 0x2e, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x2e, I2C_CLIENT_END };
/*
* Insmod parameters
diff --git a/drivers/hwmon/w83l786ng.c b/drivers/hwmon/w83l786ng.c
index 1dbee4fa23a..41e22ddb568 100644
--- a/drivers/hwmon/w83l786ng.c
+++ b/drivers/hwmon/w83l786ng.c
@@ -35,7 +35,7 @@
#include <linux/mutex.h>
/* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x2e, 0x2f, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x2e, 0x2f, I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD_1(w83l786ng);
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index b61f56b6f31..476b0bb72d6 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -177,6 +177,8 @@ config I2C_I801
ESB2
ICH8
ICH9
+ Tolapai
+ ICH10
This driver can also be built as a module. If so, the module
will be called i2c-i801.
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index aa9157913b9..b0f771fe432 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -40,7 +40,9 @@
82801G (ICH7) 0x27da 32 hard yes yes yes
82801H (ICH8) 0x283e 32 hard yes yes yes
82801I (ICH9) 0x2930 32 hard yes yes yes
- Tolapai 0x5032 32 hard yes ? ?
+ Tolapai 0x5032 32 hard yes yes yes
+ ICH10 0x3a30 32 hard yes yes yes
+ ICH10 0x3a60 32 hard yes yes yes
Features supported by this driver:
Software PEC no
@@ -588,6 +590,8 @@ static struct pci_device_id i801_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_5) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_6) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TOLAPAI_1) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_4) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_5) },
{ 0, }
};
@@ -608,10 +612,12 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
case PCI_DEVICE_ID_INTEL_ESB2_17:
case PCI_DEVICE_ID_INTEL_ICH8_5:
case PCI_DEVICE_ID_INTEL_ICH9_6:
+ case PCI_DEVICE_ID_INTEL_TOLAPAI_1:
+ case PCI_DEVICE_ID_INTEL_ICH10_4:
+ case PCI_DEVICE_ID_INTEL_ICH10_5:
i801_features |= FEATURE_I2C_BLOCK_READ;
/* fall through */
case PCI_DEVICE_ID_INTEL_82801DB_3:
- case PCI_DEVICE_ID_INTEL_TOLAPAI_1:
i801_features |= FEATURE_SMBUS_PEC;
i801_features |= FEATURE_BLOCK_BUFFER;
break;
diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c
index 5161aaf9341..496ee875eb4 100644
--- a/drivers/i2c/busses/i2c-pca-isa.c
+++ b/drivers/i2c/busses/i2c-pca-isa.c
@@ -125,6 +125,13 @@ static int __devinit pca_isa_probe(struct device *dev, unsigned int id)
dev_info(dev, "i/o base %#08lx. irq %d\n", base, irq);
+#ifdef CONFIG_PPC_MERGE
+ if (check_legacy_ioport(base)) {
+ dev_err(dev, "I/O address %#08lx is not available\n", base);
+ goto out;
+ }
+#endif
+
if (!request_region(base, IO_SIZE, "i2c-pca-isa")) {
dev_err(dev, "I/O address %#08lx is in use\n", base);
goto out;
diff --git a/drivers/i2c/busses/i2c-pmcmsp.c b/drivers/i2c/busses/i2c-pmcmsp.c
index be99c02ecac..b03af5653c6 100644
--- a/drivers/i2c/busses/i2c-pmcmsp.c
+++ b/drivers/i2c/busses/i2c-pmcmsp.c
@@ -122,7 +122,7 @@ struct pmcmsptwi_data {
};
/* The default settings */
-const static struct pmcmsptwi_clockcfg pmcmsptwi_defclockcfg = {
+static const struct pmcmsptwi_clockcfg pmcmsptwi_defclockcfg = {
.standard = {
.filter = 0x3,
.clock = 0x1f,
@@ -133,7 +133,7 @@ const static struct pmcmsptwi_clockcfg pmcmsptwi_defclockcfg = {
},
};
-const static struct pmcmsptwi_cfg pmcmsptwi_defcfg = {
+static const struct pmcmsptwi_cfg pmcmsptwi_defcfg = {
.arbf = 0x03,
.nak = 0x03,
.add10 = 0x00,
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index 2598d29fd7a..2d2087ad708 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -138,11 +138,13 @@ static const struct bits icr_bits[] = {
PXA_BIT(ICR_UR, "UR", "ur"),
};
+#ifdef CONFIG_I2C_PXA_SLAVE
static void decode_ICR(unsigned int val)
{
decode_bits(KERN_DEBUG "ICR", icr_bits, ARRAY_SIZE(icr_bits), val);
printk("\n");
}
+#endif
static unsigned int i2c_debug = DEBUG;
@@ -997,7 +999,14 @@ static int i2c_pxa_probe(struct platform_device *dev)
spin_lock_init(&i2c->lock);
init_waitqueue_head(&i2c->wait);
- sprintf(i2c->adap.name, "pxa_i2c-i2c.%u", dev->id);
+ /*
+ * If "dev->id" is negative we consider it as zero.
+ * The reason to do so is to avoid sysfs names that only make
+ * sense when there are multiple adapters.
+ */
+ i2c->adap.nr = dev->id != -1 ? dev->id : 0;
+ snprintf(i2c->adap.name, sizeof(i2c->adap.name), "pxa_i2c-i2c.%u",
+ i2c->adap.nr);
i2c->clk = clk_get(&dev->dev, "I2CCLK");
if (IS_ERR(i2c->clk)) {
@@ -1048,13 +1057,6 @@ static int i2c_pxa_probe(struct platform_device *dev)
i2c->adap.algo_data = i2c;
i2c->adap.dev.parent = &dev->dev;
- /*
- * If "dev->id" is negative we consider it as zero.
- * The reason to do so is to avoid sysfs names that only make
- * sense when there are multiple adapters.
- */
- i2c->adap.nr = dev->id != -1 ? dev->id : 0;
-
ret = i2c_add_numbered_adapter(&i2c->adap);
if (ret < 0) {
printk(KERN_INFO "I2C: Failed to add bus\n");
@@ -1078,6 +1080,7 @@ eadapt:
ereqirq:
clk_disable(i2c->clk);
i2c_pxa_disable(dev);
+ iounmap(i2c->reg_base);
eremap:
clk_put(i2c->clk);
eclk:
@@ -1087,7 +1090,7 @@ emalloc:
return ret;
}
-static int i2c_pxa_remove(struct platform_device *dev)
+static int __exit i2c_pxa_remove(struct platform_device *dev)
{
struct pxa_i2c *i2c = platform_get_drvdata(dev);
@@ -1101,6 +1104,7 @@ static int i2c_pxa_remove(struct platform_device *dev)
clk_put(i2c->clk);
i2c_pxa_disable(dev);
+ iounmap(i2c->reg_base);
release_mem_region(i2c->iobase, i2c->iosize);
kfree(i2c);
@@ -1109,9 +1113,10 @@ static int i2c_pxa_remove(struct platform_device *dev)
static struct platform_driver i2c_pxa_driver = {
.probe = i2c_pxa_probe,
- .remove = i2c_pxa_remove,
+ .remove = __exit_p(i2c_pxa_remove),
.driver = {
.name = "pxa2xx-i2c",
+ .owner = THIS_MODULE,
},
};
@@ -1120,9 +1125,9 @@ static int __init i2c_adap_pxa_init(void)
return platform_driver_register(&i2c_pxa_driver);
}
-static void i2c_adap_pxa_exit(void)
+static void __exit i2c_adap_pxa_exit(void)
{
- return platform_driver_unregister(&i2c_pxa_driver);
+ platform_driver_unregister(&i2c_pxa_driver);
}
MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index 354c91d06a6..c8d0e871599 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -670,8 +670,8 @@ static void cdrom_buffer_sectors (ide_drive_t *drive, unsigned long sector,
* and attempt to recover if there are problems. Returns 0 if everything's
* ok; nonzero if the request has been terminated.
*/
-static
-int ide_cd_check_ireason(ide_drive_t *drive, int len, int ireason, int rw)
+static int ide_cd_check_ireason(ide_drive_t *drive, struct request *rq,
+ int len, int ireason, int rw)
{
/*
* ireason == 0: the drive wants to receive data from us
@@ -701,6 +701,9 @@ int ide_cd_check_ireason(ide_drive_t *drive, int len, int ireason, int rw)
drive->name, __FUNCTION__, ireason);
}
+ if (rq->cmd_type == REQ_TYPE_ATA_PC)
+ rq->cmd_flags |= REQ_FAILED;
+
cdrom_end_request(drive, 0);
return -1;
}
@@ -1071,11 +1074,11 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
/*
* check which way to transfer data
*/
- if (blk_fs_request(rq) || blk_pc_request(rq)) {
- if (ide_cd_check_ireason(drive, len, ireason, write))
- return ide_stopped;
+ if (ide_cd_check_ireason(drive, rq, len, ireason, write))
+ return ide_stopped;
- if (blk_fs_request(rq) && write == 0) {
+ if (blk_fs_request(rq)) {
+ if (write == 0) {
int nskip;
if (ide_cd_check_transfer_size(drive, len)) {
@@ -1101,16 +1104,9 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
if (ireason == 0) {
write = 1;
xferfunc = HWIF(drive)->atapi_output_bytes;
- } else if (ireason == 2 || (ireason == 1 &&
- (blk_fs_request(rq) || blk_pc_request(rq)))) {
+ } else {
write = 0;
xferfunc = HWIF(drive)->atapi_input_bytes;
- } else {
- printk(KERN_ERR "%s: %s: The drive "
- "appears confused (ireason = 0x%02x). "
- "Trying to recover by ending request.\n",
- drive->name, __FUNCTION__, ireason);
- goto end_request;
}
/*
@@ -1182,11 +1178,10 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
else
rq->data += blen;
}
+ if (!write && blk_sense_request(rq))
+ rq->sense_len += blen;
}
- if (write && blk_sense_request(rq))
- rq->sense_len += thislen;
-
/*
* pad, if necessary
*/
@@ -1207,9 +1202,13 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
end_request:
if (blk_pc_request(rq)) {
unsigned long flags;
+ unsigned int dlen = rq->data_len;
+
+ if (dma)
+ rq->data_len = 0;
spin_lock_irqsave(&ide_lock, flags);
- if (__blk_end_request(rq, 0, rq->data_len))
+ if (__blk_end_request(rq, 0, dlen))
BUG();
HWGROUP(drive)->rq = NULL;
spin_unlock_irqrestore(&ide_lock, flags);
@@ -1927,6 +1926,7 @@ static const struct cd_list_entry ide_cd_quirks_list[] = {
{ "MATSHITADVD-ROM SR-8186", NULL, IDE_CD_FLAG_PLAY_AUDIO_OK },
{ "MATSHITADVD-ROM SR-8176", NULL, IDE_CD_FLAG_PLAY_AUDIO_OK },
{ "MATSHITADVD-ROM SR-8174", NULL, IDE_CD_FLAG_PLAY_AUDIO_OK },
+ { "Optiarc DVD RW AD-5200A", NULL, IDE_CD_FLAG_PLAY_AUDIO_OK },
{ NULL, NULL, 0 }
};
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index aed8b31ca56..39501d13025 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -397,6 +397,7 @@ static inline int idedisk_supports_lba48(const struct hd_driveid *id)
static const struct drive_list_entry hpa_list[] = {
{ "ST340823A", NULL },
{ "ST320413A", NULL },
+ { "ST310211A", NULL },
{ NULL, NULL }
};
@@ -866,7 +867,7 @@ static void idedisk_setup (ide_drive_t *drive)
/* Only print cache size when it was specified */
if (id->buf_size)
- printk (" w/%dKiB Cache", id->buf_size/2);
+ printk(KERN_CONT " w/%dKiB Cache", id->buf_size / 2);
printk(KERN_CONT ", CHS=%d/%d/%d\n",
drive->bios_cyl, drive->bios_head, drive->bios_sect);
@@ -948,7 +949,8 @@ static void ide_device_shutdown(ide_drive_t *drive)
return;
}
- printk("Shutdown: %s\n", drive->name);
+ printk(KERN_INFO "Shutdown: %s\n", drive->name);
+
drive->gendev.bus->suspend(&drive->gendev, PMSG_SUSPEND);
}
diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
index d0e7b537353..2de99e4be5c 100644
--- a/drivers/ide/ide-dma.c
+++ b/drivers/ide/ide-dma.c
@@ -1,9 +1,13 @@
/*
+ * IDE DMA support (including IDE PCI BM-DMA).
+ *
* Copyright (C) 1995-1998 Mark Lord
* Copyright (C) 1999-2000 Andre Hedrick <andre@linux-ide.org>
* Copyright (C) 2004, 2007 Bartlomiej Zolnierkiewicz
*
* May be copied or modified under the terms of the GNU General Public License
+ *
+ * DMA is supported for all IDE devices (disk drives, cdroms, tapes, floppies).
*/
/*
@@ -11,49 +15,6 @@
*/
/*
- * This module provides support for the bus-master IDE DMA functions
- * of various PCI chipsets, including the Intel PIIX (i82371FB for
- * the 430 FX chipset), the PIIX3 (i82371SB for the 430 HX/VX and
- * 440 chipsets), and the PIIX4 (i82371AB for the 430 TX chipset)
- * ("PIIX" stands for "PCI ISA IDE Xcellerator").
- *
- * Pretty much the same code works for other IDE PCI bus-mastering chipsets.
- *
- * DMA is supported for all IDE devices (disk drives, cdroms, tapes, floppies).
- *
- * By default, DMA support is prepared for use, but is currently enabled only
- * for drives which already have DMA enabled (UltraDMA or mode 2 multi/single),
- * or which are recognized as "good" (see table below). Drives with only mode0
- * or mode1 (multi/single) DMA should also work with this chipset/driver
- * (eg. MC2112A) but are not enabled by default.
- *
- * Use "hdparm -i" to view modes supported by a given drive.
- *
- * The hdparm-3.5 (or later) utility can be used for manually enabling/disabling
- * DMA support, but must be (re-)compiled against this kernel version or later.
- *
- * To enable DMA, use "hdparm -d1 /dev/hd?" on a per-drive basis after booting.
- * If problems arise, ide.c will disable DMA operation after a few retries.
- * This error recovery mechanism works and has been extremely well exercised.
- *
- * IDE drives, depending on their vintage, may support several different modes
- * of DMA operation. The boot-time modes are indicated with a "*" in
- * the "hdparm -i" listing, and can be changed with *knowledgeable* use of
- * the "hdparm -X" feature. There is seldom a need to do this, as drives
- * normally power-up with their "best" PIO/DMA modes enabled.
- *
- * Testing has been done with a rather extensive number of drives,
- * with Quantum & Western Digital models generally outperforming the pack,
- * and Fujitsu & Conner (and some Seagate which are really Conner) drives
- * showing more lackluster throughput.
- *
- * Keep an eye on /var/adm/messages for "DMA disabled" messages.
- *
- * Some people have reported trouble with Intel Zappa motherboards.
- * This can be fixed by upgrading the AMI BIOS to version 1.00.04.BS0,
- * available from ftp://ftp.intel.com/pub/bios/10004bs0.exe
- * (thanks to Glen Morrell <glen@spin.Stanford.edu> for researching this).
- *
* Thanks to "Christopher J. Reimer" <reimer@doe.carleton.ca> for
* fixing the problem with the BIOS on some Acer motherboards.
*
@@ -65,11 +26,6 @@
*
* Most importantly, thanks to Robert Bringman <rob@mars.trion.com>
* for supplying a Promise UDMA board & WD UDMA drive for this work!
- *
- * And, yes, Intel Zappa boards really *do* use both PIIX IDE ports.
- *
- * ATA-66/100 and recovery functions, I forgot the rest......
- *
*/
#include <linux/module.h>
diff --git a/drivers/ide/ide-generic.c b/drivers/ide/ide-generic.c
index 709b9e4d287..9ebec08eefd 100644
--- a/drivers/ide/ide-generic.c
+++ b/drivers/ide/ide-generic.c
@@ -17,9 +17,6 @@ static int __init ide_generic_init(void)
u8 idx[MAX_HWIFS];
int i;
- if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET])
- ide_get_lock(NULL, NULL); /* for atari only */
-
for (i = 0; i < MAX_HWIFS; i++) {
ide_hwif_t *hwif = &ide_hwifs[i];
@@ -31,9 +28,6 @@ static int __init ide_generic_init(void)
ide_device_add_all(idx, NULL);
- if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET])
- ide_release_lock(); /* for atari only */
-
return 0;
}
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 4a2cb286822..194ecb0049e 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -756,7 +756,8 @@ static int ide_probe_port(ide_hwif_t *hwif)
BUG_ON(hwif->present);
- if (hwif->noprobe)
+ if (hwif->noprobe ||
+ (hwif->drives[0].noprobe && hwif->drives[1].noprobe))
return -EACCES;
/*
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index 0598ecfd5f3..43e0e055777 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -3765,6 +3765,11 @@ static int ide_tape_probe(ide_drive_t *drive)
g->fops = &idetape_block_ops;
ide_register_region(g);
+ printk(KERN_WARNING "It is possible that this driver does not have any"
+ " users anymore and, as a result, it will be REMOVED soon."
+ " Please notify Bart <bzolnier@gmail.com> or Boris"
+ " <petkovbb@gmail.com> in case you still need it.\n");
+
return 0;
out_free_tape:
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index 4a8952a6c3d..fa16bc30bbc 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -590,11 +590,6 @@ void ide_unregister(unsigned int index, int init_default, int restore)
hwif->extra_ports = 0;
}
- /*
- * Note that we only release the standard ports,
- * and do not even try to handle any extra ports
- * allocated for weird IDE interface chipsets.
- */
ide_hwif_release_regions(hwif);
/* copy original settings */
@@ -1036,10 +1031,9 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device
drive->nice1 = (arg >> IDE_NICE_1) & 1;
return 0;
case HDIO_DRIVE_RESET:
- {
- unsigned long flags;
- if (!capable(CAP_SYS_ADMIN)) return -EACCES;
-
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
/*
* Abort the current command on the
* group if there is one, taking
@@ -1058,17 +1052,15 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device
ide_abort(drive, "drive reset");
BUG_ON(HWGROUP(drive)->handler);
-
+
/* Ensure nothing gets queued after we
drop the lock. Reset will clear the busy */
-
+
HWGROUP(drive)->busy = 1;
spin_unlock_irqrestore(&ide_lock, flags);
(void) ide_do_reset(drive);
return 0;
- }
-
case HDIO_GET_BUSSTATE:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
@@ -1229,7 +1221,7 @@ static int __init ide_setup(char *s)
if (!strcmp(s, "ide=reverse")) {
ide_scan_direction = 1;
printk(" : Enabled support for IDE inverse scan order.\n");
- return 1;
+ goto obsolete_option;
}
#endif
@@ -1449,7 +1441,7 @@ static int __init ide_setup(char *s)
case -1: /* "noprobe" */
hwif->noprobe = 1;
- goto done;
+ goto obsolete_option;
case 1: /* base */
vals[1] = vals[0] + 0x206; /* default ctl */
diff --git a/drivers/ide/legacy/falconide.c b/drivers/ide/legacy/falconide.c
index f044048903b..8949ce71bdd 100644
--- a/drivers/ide/legacy/falconide.c
+++ b/drivers/ide/legacy/falconide.c
@@ -54,7 +54,7 @@ static void __init falconide_setup_ports(hw_regs_t *hw)
for (i = 1; i < 8; i++)
hw->io_ports[i] = ATA_HD_BASE + 1 + i * 4;
- hw->io_ports[IDE_CONTROL_OFFSET] = ATA_HD_CONTROL;
+ hw->io_ports[IDE_CONTROL_OFFSET] = ATA_HD_BASE + ATA_HD_CONTROL;
hw->irq = IRQ_MFP_IDE;
hw->ack_intr = NULL;
@@ -84,7 +84,9 @@ static int __init falconide_init(void)
ide_init_port_data(hwif, index);
ide_init_port_hw(hwif, &hw);
+ ide_get_lock(NULL, NULL);
ide_device_add(idx, NULL);
+ ide_release_lock();
}
return 0;
diff --git a/drivers/ide/legacy/ht6560b.c b/drivers/ide/legacy/ht6560b.c
index 02d12c74764..78ca68e60f9 100644
--- a/drivers/ide/legacy/ht6560b.c
+++ b/drivers/ide/legacy/ht6560b.c
@@ -21,18 +21,21 @@
* "Prefetch" mode bit OFF for ide disks and
* ON for anything else.
*
+ * Version 0.08 Need to force prefetch for CDs and other non-disk
+ * devices. (not sure which devices exactly need
+ * prefetch)
*
* HT-6560B EIDE-controller support
* To activate controller support use kernel parameter "ide0=ht6560b".
* Use hdparm utility to enable PIO mode support.
*
* Author: Mikko Ala-Fossi <maf@iki.fi>
- * Jan Evert van Grootheest <janevert@iae.nl>
+ * Jan Evert van Grootheest <janevert@caiway.nl>
*
* Try: http://www.maf.iki.fi/~maf/ht6560b/
*/
-#define HT6560B_VERSION "v0.07"
+#define HT6560B_VERSION "v0.08"
#include <linux/module.h>
#include <linux/types.h>
@@ -130,15 +133,20 @@ static void ht6560b_selectproc (ide_drive_t *drive)
u8 select, timing;
local_irq_save(flags);
-
+
select = HT_CONFIG(drive);
timing = HT_TIMING(drive);
-
+
+ /*
+ * Need to enforce prefetch sometimes because otherwise
+ * it'll hang (hard).
+ */
+ if (drive->media != ide_disk || !drive->present)
+ select |= HT_PREFETCH_MODE;
+
if (select != current_select || timing != current_timing) {
current_select = select;
current_timing = timing;
- if (drive->media != ide_disk || !drive->present)
- select |= HT_PREFETCH_MODE;
(void)inb(HT_CONFIG_PORT);
(void)inb(HT_CONFIG_PORT);
(void)inb(HT_CONFIG_PORT);
@@ -188,11 +196,12 @@ static int __init try_to_init_ht6560b(void)
outb(HT_TIMING_DEFAULT, 0x1f6); /* IDE_SELECT_REG */
(void) inb(0x1f7); /* IDE_STATUS_REG */
- printk("\nht6560b " HT6560B_VERSION
+ printk("ht6560b " HT6560B_VERSION
": chipset detected and initialized"
#ifdef DEBUG
" with debug enabled"
#endif
+ "\n"
);
return 1;
}
@@ -323,7 +332,7 @@ static const struct ide_port_info ht6560b_port_info __initdata = {
IDE_HFLAG_NO_DMA |
IDE_HFLAG_NO_AUTOTUNE |
IDE_HFLAG_ABUSE_PREFETCH,
- .pio_mask = ATA_PIO5,
+ .pio_mask = ATA_PIO4,
};
static int __init ht6560b_init(void)
diff --git a/drivers/ide/legacy/macide.c b/drivers/ide/legacy/macide.c
index a61e60737dc..9a79098d9eb 100644
--- a/drivers/ide/legacy/macide.c
+++ b/drivers/ide/legacy/macide.c
@@ -74,7 +74,7 @@ static void __init macide_setup_ports(hw_regs_t *hw, unsigned long base,
for (i = 0; i < 8; i++)
hw->io_ports[i] = base + i * 4;
- hw->io_ports[IDE_CONTROL_OFFSET] = IDE_CONTROL;
+ hw->io_ports[IDE_CONTROL_OFFSET] = base + IDE_CONTROL;
hw->irq = irq;
hw->ack_intr = ack_intr;
diff --git a/drivers/ide/legacy/qd65xx.c b/drivers/ide/legacy/qd65xx.c
index bba29df5f21..2f4f47ad602 100644
--- a/drivers/ide/legacy/qd65xx.c
+++ b/drivers/ide/legacy/qd65xx.c
@@ -334,43 +334,6 @@ static void __init qd6580_port_init_devs(ide_hwif_t *hwif)
hwif->drives[1].drive_data = t2;
}
-/*
- * qd_unsetup:
- *
- * called to unsetup an ata channel : back to default values, unlinks tuning
- */
-/*
-static void __exit qd_unsetup(ide_hwif_t *hwif)
-{
- u8 config = hwif->config_data;
- int base = hwif->select_data;
- void *set_pio_mode = (void *)hwif->set_pio_mode;
-
- if (hwif->chipset != ide_qd65xx)
- return;
-
- printk(KERN_NOTICE "%s: back to defaults\n", hwif->name);
-
- hwif->selectproc = NULL;
- hwif->set_pio_mode = NULL;
-
- if (set_pio_mode == (void *)qd6500_set_pio_mode) {
- // will do it for both
- outb(QD6500_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
- } else if (set_pio_mode == (void *)qd6580_set_pio_mode) {
- if (QD_CONTROL(hwif) & QD_CONTR_SEC_DISABLED) {
- outb(QD6580_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
- outb(QD6580_DEF_DATA2, QD_TIMREG(&hwif->drives[1]));
- } else {
- outb(hwif->channel ? QD6580_DEF_DATA2 : QD6580_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
- }
- } else {
- printk(KERN_WARNING "Unknown qd65xx tuning fonction !\n");
- printk(KERN_WARNING "keeping settings !\n");
- }
-}
-*/
-
static const struct ide_port_info qd65xx_port_info __initdata = {
.chipset = ide_qd65xx,
.host_flags = IDE_HFLAG_IO_32BIT |
@@ -444,6 +407,8 @@ static int __init qd_probe(int base)
printk(KERN_DEBUG "qd6580: config=%#x, control=%#x, ID3=%u\n",
config, control, QD_ID3);
+ outb(QD_DEF_CONTR, QD_CONTROL_PORT);
+
if (control & QD_CONTR_SEC_DISABLED) {
/* secondary disabled */
@@ -460,8 +425,6 @@ static int __init qd_probe(int base)
ide_device_add(idx, &qd65xx_port_info);
- outb(QD_DEF_CONTR, QD_CONTROL_PORT);
-
return 1;
} else {
ide_hwif_t *mate;
@@ -487,8 +450,6 @@ static int __init qd_probe(int base)
ide_device_add(idx, &qd65xx_port_info);
- outb(QD_DEF_CONTR, QD_CONTROL_PORT);
-
return 0; /* no other qd65xx possible */
}
}
diff --git a/drivers/ide/pci/cmd640.c b/drivers/ide/pci/cmd640.c
index bd24dad3cfc..ec667982809 100644
--- a/drivers/ide/pci/cmd640.c
+++ b/drivers/ide/pci/cmd640.c
@@ -787,7 +787,8 @@ static int __init cmd640x_init(void)
/*
* Try to enable the secondary interface, if not already enabled
*/
- if (cmd_hwif1->noprobe) {
+ if (cmd_hwif1->noprobe ||
+ (cmd_hwif1->drives[0].noprobe && cmd_hwif1->drives[1].noprobe)) {
port2 = "not probed";
} else {
b = get_cmd640_reg(CNTRL);
diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c
index d0f7bb8b8ad..6357bb6269a 100644
--- a/drivers/ide/pci/hpt366.c
+++ b/drivers/ide/pci/hpt366.c
@@ -1570,10 +1570,12 @@ static int __devinit hpt366_init_one(struct pci_dev *dev, const struct pci_devic
if (rev < 3)
info = &hpt36x;
else {
- static const struct hpt_info *hpt37x_info[] =
- { &hpt370, &hpt370a, &hpt372, &hpt372n };
-
- info = hpt37x_info[min_t(u8, rev, 6) - 3];
+ switch (min_t(u8, rev, 6)) {
+ case 3: info = &hpt370; break;
+ case 4: info = &hpt370a; break;
+ case 5: info = &hpt372; break;
+ case 6: info = &hpt372n; break;
+ }
idx++;
}
break;
@@ -1626,7 +1628,7 @@ static int __devinit hpt366_init_one(struct pci_dev *dev, const struct pci_devic
return ide_setup_pci_device(dev, &d);
}
-static const struct pci_device_id hpt366_pci_tbl[] = {
+static const struct pci_device_id hpt366_pci_tbl[] __devinitconst = {
{ PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT366), 0 },
{ PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372), 1 },
{ PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT302), 2 },
diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c
index f3f79f80581..9004e752188 100644
--- a/drivers/ide/pci/via82cxxx.c
+++ b/drivers/ide/pci/via82cxxx.c
@@ -479,6 +479,7 @@ static int __devinit via_init_one(struct pci_dev *dev, const struct pci_device_i
static const struct pci_device_id via_pci_tbl[] = {
{ PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C576_1), 0 },
{ PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C586_1), 0 },
+ { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_CX700_IDE), 0 },
{ PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_6410), 1 },
{ PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_SATA_EIDE), 1 },
{ 0, },
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
index 12ac3bfb4f9..78c9eeb8563 100644
--- a/drivers/ide/ppc/pmac.c
+++ b/drivers/ide/ppc/pmac.c
@@ -1254,7 +1254,7 @@ pmac_ide_macio_suspend(struct macio_dev *mdev, pm_message_t mesg)
int rc = 0;
if (mesg.event != mdev->ofdev.dev.power.power_state.event
- && mesg.event == PM_EVENT_SUSPEND) {
+ && (mesg.event & PM_EVENT_SLEEP)) {
rc = pmac_ide_do_suspend(hwif);
if (rc == 0)
mdev->ofdev.dev.power.power_state = mesg;
@@ -1364,7 +1364,7 @@ pmac_ide_pci_suspend(struct pci_dev *pdev, pm_message_t mesg)
int rc = 0;
if (mesg.event != pdev->dev.power.power_state.event
- && mesg.event == PM_EVENT_SUSPEND) {
+ && (mesg.event & PM_EVENT_SLEEP)) {
rc = pmac_ide_do_suspend(hwif);
if (rc == 0)
pdev->dev.power.power_state = mesg;
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
index 28e155a9e2a..9e2b1964d71 100644
--- a/drivers/ieee1394/sbp2.c
+++ b/drivers/ieee1394/sbp2.c
@@ -183,6 +183,9 @@ MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device "
* Avoids access beyond actual disk limits on devices with an off-by-one bug.
* Don't use this with devices which don't have this bug.
*
+ * - delay inquiry
+ * Wait extra SBP2_INQUIRY_DELAY seconds after login before SCSI inquiry.
+ *
* - override internal blacklist
* Instead of adding to the built-in blacklist, use only the workarounds
* specified in the module load parameter.
@@ -195,6 +198,7 @@ MODULE_PARM_DESC(workarounds, "Work around device bugs (default = 0"
", 36 byte inquiry = " __stringify(SBP2_WORKAROUND_INQUIRY_36)
", skip mode page 8 = " __stringify(SBP2_WORKAROUND_MODE_SENSE_8)
", fix capacity = " __stringify(SBP2_WORKAROUND_FIX_CAPACITY)
+ ", delay inquiry = " __stringify(SBP2_WORKAROUND_DELAY_INQUIRY)
", override internal blacklist = " __stringify(SBP2_WORKAROUND_OVERRIDE)
", or a combination)");
@@ -357,6 +361,11 @@ static const struct {
.workarounds = SBP2_WORKAROUND_INQUIRY_36 |
SBP2_WORKAROUND_MODE_SENSE_8,
},
+ /* DViCO Momobay FX-3A with TSB42AA9A bridge */ {
+ .firmware_revision = 0x002800,
+ .model_id = 0x000000,
+ .workarounds = SBP2_WORKAROUND_DELAY_INQUIRY,
+ },
/* Initio bridges, actually only needed for some older ones */ {
.firmware_revision = 0x000200,
.model_id = SBP2_ROM_VALUE_WILDCARD,
@@ -914,6 +923,9 @@ static int sbp2_start_device(struct sbp2_lu *lu)
sbp2_agent_reset(lu, 1);
sbp2_max_speed_and_size(lu);
+ if (lu->workarounds & SBP2_WORKAROUND_DELAY_INQUIRY)
+ ssleep(SBP2_INQUIRY_DELAY);
+
error = scsi_add_device(lu->shost, 0, lu->ud->id, 0);
if (error) {
SBP2_ERR("scsi_add_device failed");
@@ -1962,6 +1974,9 @@ static int sbp2scsi_slave_alloc(struct scsi_device *sdev)
{
struct sbp2_lu *lu = (struct sbp2_lu *)sdev->host->hostdata[0];
+ if (sdev->lun != 0 || sdev->id != lu->ud->id || sdev->channel != 0)
+ return -ENODEV;
+
lu->sdev = sdev;
sdev->allow_restart = 1;
diff --git a/drivers/ieee1394/sbp2.h b/drivers/ieee1394/sbp2.h
index d2ecb0d8a1b..80d8e097b06 100644
--- a/drivers/ieee1394/sbp2.h
+++ b/drivers/ieee1394/sbp2.h
@@ -343,6 +343,8 @@ enum sbp2lu_state_types {
#define SBP2_WORKAROUND_INQUIRY_36 0x2
#define SBP2_WORKAROUND_MODE_SENSE_8 0x4
#define SBP2_WORKAROUND_FIX_CAPACITY 0x8
+#define SBP2_WORKAROUND_DELAY_INQUIRY 0x10
+#define SBP2_INQUIRY_DELAY 12
#define SBP2_WORKAROUND_OVERRIDE 0x100
#endif /* SBP2_H */
diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c
index c864ef70fdf..5a4b2e65534 100644
--- a/drivers/infiniband/core/sysfs.c
+++ b/drivers/infiniband/core/sysfs.c
@@ -686,8 +686,10 @@ int ib_device_register_sysfs(struct ib_device *device)
device->ports_parent = kobject_create_and_add("ports",
kobject_get(&class_dev->kobj));
- if (!device->ports_parent)
+ if (!device->ports_parent) {
+ ret = -ENOMEM;
goto err_put;
+ }
if (device->node_type == RDMA_NODE_IB_SWITCH) {
ret = add_port(device, 0);
diff --git a/drivers/infiniband/hw/cxgb3/iwch_mem.c b/drivers/infiniband/hw/cxgb3/iwch_mem.c
index 73bfd1656f8..b8797c66676 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_mem.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_mem.c
@@ -136,14 +136,8 @@ int build_phys_page_list(struct ib_phys_buf *buffer_list,
/* Find largest page shift we can use to cover buffers */
for (*shift = PAGE_SHIFT; *shift < 27; ++(*shift))
- if (num_phys_buf > 1) {
- if ((1ULL << *shift) & mask)
- break;
- } else
- if (1ULL << *shift >=
- buffer_list[0].size +
- (buffer_list[0].addr & ((1ULL << *shift) - 1)))
- break;
+ if ((1ULL << *shift) & mask)
+ break;
buffer_list[0].size += buffer_list[0].addr & ((1ULL << *shift) - 1);
buffer_list[0].addr &= ~0ull << *shift;
diff --git a/drivers/infiniband/hw/mthca/mthca_mr.c b/drivers/infiniband/hw/mthca/mthca_mr.c
index 3b6985557cb..3538da16e3f 100644
--- a/drivers/infiniband/hw/mthca/mthca_mr.c
+++ b/drivers/infiniband/hw/mthca/mthca_mr.c
@@ -686,7 +686,7 @@ err_out_table:
mthca_table_put(dev, dev->mr_table.mpt_table, key);
err_out_mpt_free:
- mthca_free(&dev->mr_table.mpt_alloc, mr->ibmr.lkey);
+ mthca_free(&dev->mr_table.mpt_alloc, key);
return err;
}
diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c
index 7f8853b44ee..b2112f5a422 100644
--- a/drivers/infiniband/hw/nes/nes.c
+++ b/drivers/infiniband/hw/nes/nes.c
@@ -567,12 +567,12 @@ static int __devinit nes_probe(struct pci_dev *pcidev, const struct pci_device_i
/* Init the adapter */
nesdev->nesadapter = nes_init_adapter(nesdev, hw_rev);
- nesdev->nesadapter->et_rx_coalesce_usecs_irq = interrupt_mod_interval;
if (!nesdev->nesadapter) {
printk(KERN_ERR PFX "Unable to initialize adapter.\n");
ret = -ENOMEM;
goto bail5;
}
+ nesdev->nesadapter->et_rx_coalesce_usecs_irq = interrupt_mod_interval;
/* nesdev->base_doorbell_index =
nesdev->nesadapter->pd_config_base[PCI_FUNC(nesdev->pcidev->devfn)]; */
diff --git a/drivers/infiniband/hw/nes/nes.h b/drivers/infiniband/hw/nes/nes.h
index fd57e8a1582..a48b288618e 100644
--- a/drivers/infiniband/hw/nes/nes.h
+++ b/drivers/infiniband/hw/nes/nes.h
@@ -285,6 +285,21 @@ struct nes_device {
};
+static inline __le32 get_crc_value(struct nes_v4_quad *nes_quad)
+{
+ u32 crc_value;
+ crc_value = crc32c(~0, (void *)nes_quad, sizeof (struct nes_v4_quad));
+
+ /*
+ * With commit ef19454b ("[LIB] crc32c: Keep intermediate crc
+ * state in cpu order"), behavior of crc32c changes on
+ * big-endian platforms. Our algorithm expects the previous
+ * behavior; otherwise we have RDMA connection establishment
+ * issue on big-endian.
+ */
+ return cpu_to_le32(crc_value);
+}
+
static inline void
set_wqe_64bit_value(__le32 *wqe_words, u32 index, u64 value)
{
diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c
index bd5cfeaac20..39adb267fb1 100644
--- a/drivers/infiniband/hw/nes/nes_cm.c
+++ b/drivers/infiniband/hw/nes/nes_cm.c
@@ -370,11 +370,11 @@ int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb,
int ret = 0;
u32 was_timer_set;
+ if (!cm_node)
+ return -EINVAL;
new_send = kzalloc(sizeof(*new_send), GFP_ATOMIC);
if (!new_send)
return -1;
- if (!cm_node)
- return -EINVAL;
/* new_send->timetosend = currenttime */
new_send->retrycount = NES_DEFAULT_RETRYS;
@@ -947,6 +947,7 @@ static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core,
nes_debug(NES_DBG_CM, "destroying listener (%p)\n", listener);
kfree(listener);
+ listener = NULL;
ret = 0;
cm_listens_destroyed++;
} else {
@@ -2319,6 +2320,7 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
struct iw_cm_event cm_event;
struct nes_hw_qp_wqe *wqe;
struct nes_v4_quad nes_quad;
+ u32 crc_value;
int ret;
ibqp = nes_get_qp(cm_id->device, conn_param->qpn);
@@ -2435,8 +2437,8 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
nes_quad.TcpPorts[1] = cm_id->local_addr.sin_port;
/* Produce hash key */
- nesqp->hte_index = cpu_to_be32(
- crc32c(~0, (void *)&nes_quad, sizeof(nes_quad)) ^ 0xffffffff);
+ crc_value = get_crc_value(&nes_quad);
+ nesqp->hte_index = cpu_to_be32(crc_value ^ 0xffffffff);
nes_debug(NES_DBG_CM, "HTE Index = 0x%08X, CRC = 0x%08X\n",
nesqp->hte_index, nesqp->hte_index & adapter->hte_index_mask);
@@ -2750,6 +2752,7 @@ void cm_event_connected(struct nes_cm_event *event)
struct iw_cm_event cm_event;
struct nes_hw_qp_wqe *wqe;
struct nes_v4_quad nes_quad;
+ u32 crc_value;
int ret;
/* get all our handles */
@@ -2827,8 +2830,8 @@ void cm_event_connected(struct nes_cm_event *event)
nes_quad.TcpPorts[1] = cm_id->local_addr.sin_port;
/* Produce hash key */
- nesqp->hte_index = cpu_to_be32(
- crc32c(~0, (void *)&nes_quad, sizeof(nes_quad)) ^ 0xffffffff);
+ crc_value = get_crc_value(&nes_quad);
+ nesqp->hte_index = cpu_to_be32(crc_value ^ 0xffffffff);
nes_debug(NES_DBG_CM, "HTE Index = 0x%08X, After CRC = 0x%08X\n",
nesqp->hte_index, nesqp->hte_index & nesadapter->hte_index_mask);
diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c
index 7c4c0fbf0ab..49e53e4c1eb 100644
--- a/drivers/infiniband/hw/nes/nes_hw.c
+++ b/drivers/infiniband/hw/nes/nes_hw.c
@@ -156,15 +156,14 @@ static void nes_nic_tune_timer(struct nes_device *nesdev)
spin_lock_irqsave(&nesadapter->periodic_timer_lock, flags);
- if (shared_timer->cq_count_old < cq_count) {
- if (cq_count > shared_timer->threshold_low)
- shared_timer->cq_direction_downward=0;
- }
- if (shared_timer->cq_count_old >= cq_count)
+ if (shared_timer->cq_count_old <= cq_count)
+ shared_timer->cq_direction_downward = 0;
+ else
shared_timer->cq_direction_downward++;
shared_timer->cq_count_old = cq_count;
if (shared_timer->cq_direction_downward > NES_NIC_CQ_DOWNWARD_TREND) {
- if (cq_count <= shared_timer->threshold_low) {
+ if (cq_count <= shared_timer->threshold_low &&
+ shared_timer->threshold_low > 4) {
shared_timer->threshold_low = shared_timer->threshold_low/2;
shared_timer->cq_direction_downward=0;
nesdev->currcq_count = 0;
@@ -1728,7 +1727,6 @@ int nes_napi_isr(struct nes_device *nesdev)
nesdev->int_req &= ~NES_INT_TIMER;
nes_write32(nesdev->regs+NES_INTF_INT_MASK, ~(nesdev->intf_int_req));
nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req);
- nesadapter->tune_timer.timer_in_use_old = 0;
}
nesdev->deepcq_count = 0;
return 1;
@@ -1867,7 +1865,6 @@ void nes_dpc(unsigned long param)
nesdev->int_req &= ~NES_INT_TIMER;
nes_write32(nesdev->regs + NES_INTF_INT_MASK, ~(nesdev->intf_int_req));
nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req);
- nesdev->nesadapter->tune_timer.timer_in_use_old = 0;
} else {
nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff|(~nesdev->int_req));
}
diff --git a/drivers/infiniband/hw/nes/nes_hw.h b/drivers/infiniband/hw/nes/nes_hw.h
index 1e10df550c9..b7e2844f096 100644
--- a/drivers/infiniband/hw/nes/nes_hw.h
+++ b/drivers/infiniband/hw/nes/nes_hw.h
@@ -962,7 +962,7 @@ struct nes_arp_entry {
#define DEFAULT_JUMBO_NES_QL_LOW 12
#define DEFAULT_JUMBO_NES_QL_TARGET 40
#define DEFAULT_JUMBO_NES_QL_HIGH 128
-#define NES_NIC_CQ_DOWNWARD_TREND 8
+#define NES_NIC_CQ_DOWNWARD_TREND 16
struct nes_hw_tune_timer {
//u16 cq_count;
diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c
index b6cc265aa9a..eee77da6193 100644
--- a/drivers/infiniband/hw/nes/nes_nic.c
+++ b/drivers/infiniband/hw/nes/nes_nic.c
@@ -148,14 +148,15 @@ static int nes_netdev_open(struct net_device *netdev)
struct nes_device *nesdev = nesvnic->nesdev;
int ret;
int i;
- struct nes_vnic *first_nesvnic;
+ struct nes_vnic *first_nesvnic = NULL;
u32 nic_active_bit;
u32 nic_active;
+ struct list_head *list_pos, *list_temp;
assert(nesdev != NULL);
- first_nesvnic = list_entry(nesdev->nesadapter->nesvnic_list[nesdev->mac_index].next,
- struct nes_vnic, list);
+ if (nesvnic->netdev_open == 1)
+ return 0;
if (netif_msg_ifup(nesvnic))
printk(KERN_INFO PFX "%s: enabling interface\n", netdev->name);
@@ -225,7 +226,18 @@ static int nes_netdev_open(struct net_device *netdev)
nes_write32(nesdev->regs+NES_CQE_ALLOC, NES_CQE_ALLOC_NOTIFY_NEXT |
nesvnic->nic_cq.cq_number);
nes_read32(nesdev->regs+NES_CQE_ALLOC);
-
+ list_for_each_safe(list_pos, list_temp, &nesdev->nesadapter->nesvnic_list[nesdev->mac_index]) {
+ first_nesvnic = container_of(list_pos, struct nes_vnic, list);
+ if (first_nesvnic->netdev_open == 1)
+ break;
+ }
+ if (first_nesvnic->netdev_open == 0) {
+ nes_debug(NES_DBG_INIT, "Setting up MAC interrupt mask.\n");
+ nes_write_indexed(nesdev, NES_IDX_MAC_INT_MASK + (0x200 * nesdev->mac_index),
+ ~(NES_MAC_INT_LINK_STAT_CHG | NES_MAC_INT_XGMII_EXT |
+ NES_MAC_INT_TX_UNDERFLOW | NES_MAC_INT_TX_ERROR));
+ first_nesvnic = nesvnic;
+ }
if (first_nesvnic->linkup) {
/* Enable network packets */
nesvnic->linkup = 1;
@@ -248,6 +260,8 @@ static int nes_netdev_stop(struct net_device *netdev)
struct nes_device *nesdev = nesvnic->nesdev;
u32 nic_active_mask;
u32 nic_active;
+ struct nes_vnic *first_nesvnic = NULL;
+ struct list_head *list_pos, *list_temp;
nes_debug(NES_DBG_SHUTDOWN, "nesvnic=%p, nesdev=%p, netdev=%p %s\n",
nesvnic, nesdev, netdev, netdev->name);
@@ -260,9 +274,20 @@ static int nes_netdev_stop(struct net_device *netdev)
/* Disable network packets */
napi_disable(&nesvnic->napi);
netif_stop_queue(netdev);
- if ((nesdev->netdev[0] == netdev) & (nesvnic->logical_port == nesdev->mac_index)) {
- nes_write_indexed(nesdev,
- NES_IDX_MAC_INT_MASK+(0x200*nesdev->mac_index), 0xffffffff);
+ list_for_each_safe(list_pos, list_temp, &nesdev->nesadapter->nesvnic_list[nesdev->mac_index]) {
+ first_nesvnic = container_of(list_pos, struct nes_vnic, list);
+ if ((first_nesvnic->netdev_open == 1) && (first_nesvnic != nesvnic))
+ break;
+ }
+
+ if (first_nesvnic->netdev_open == 0)
+ 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));
@@ -859,7 +884,6 @@ void nes_netdev_set_multicast_list(struct net_device *netdev)
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))
multicast_addr = multicast_addr->next;
-
if (mc_nic_index < 0)
mc_nic_index = nesvnic->nic_index;
if (multicast_addr) {
@@ -908,7 +932,7 @@ static int nes_netdev_change_mtu(struct net_device *netdev, int new_mtu)
return -EINVAL;
netdev->mtu = new_mtu;
- nesvnic->max_frame_size = new_mtu+ETH_HLEN;
+ nesvnic->max_frame_size = new_mtu + VLAN_ETH_HLEN;
if (netdev->mtu > 1500) {
jumbomode=1;
@@ -1470,10 +1494,15 @@ static void nes_netdev_vlan_rx_register(struct net_device *netdev, struct vlan_g
{
struct nes_vnic *nesvnic = netdev_priv(netdev);
struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
u32 u32temp;
+ unsigned long flags;
+ spin_lock_irqsave(&nesadapter->phy_lock, flags);
nesvnic->vlan_grp = grp;
+ nes_debug(NES_DBG_NETDEV, "%s: %s\n", __func__, netdev->name);
+
/* Enable/Disable VLAN Stripping */
u32temp = nes_read_indexed(nesdev, NES_IDX_PCIX_DIAG);
if (grp)
@@ -1482,6 +1511,7 @@ static void nes_netdev_vlan_rx_register(struct net_device *netdev, struct vlan_g
u32temp |= 0x02000000;
nes_write_indexed(nesdev, NES_IDX_PCIX_DIAG, u32temp);
+ spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
}
@@ -1540,7 +1570,7 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,
nesvnic->msg_enable = netif_msg_init(debug, default_msg);
nesvnic->netdev_index = nesdev->netdev_count;
nesvnic->perfect_filter_index = nesdev->nesadapter->netdev_count;
- nesvnic->max_frame_size = netdev->mtu+netdev->hard_header_len;
+ nesvnic->max_frame_size = netdev->mtu + netdev->hard_header_len + VLAN_HLEN;
curr_qp_map = nic_qp_mapping_per_function[PCI_FUNC(nesdev->pcidev->devfn)];
nesvnic->nic.qp_id = curr_qp_map[nesdev->netdev_count].qpid;
@@ -1610,7 +1640,7 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,
list_add_tail(&nesvnic->list, &nesdev->nesadapter->nesvnic_list[nesdev->mac_index]);
if ((nesdev->netdev_count == 0) &&
- (PCI_FUNC(nesdev->pcidev->devfn) == nesdev->mac_index)) {
+ (PCI_FUNC(nesdev->pcidev->devfn) == nesdev->mac_index)) {
nes_debug(NES_DBG_INIT, "Setting up PHY interrupt mask. Using register index 0x%04X\n",
NES_IDX_PHY_PCS_CONTROL_STATUS0+(0x200*(nesvnic->logical_port&1)));
u32temp = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 +
@@ -1648,18 +1678,14 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,
nesvnic->linkup = 1;
}
}
- nes_debug(NES_DBG_INIT, "Setting up MAC interrupt mask.\n");
/* clear the MAC interrupt status, assumes direct logical to physical mapping */
- u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS+(0x200*nesvnic->logical_port));
+ u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS + (0x200 * nesdev->mac_index));
nes_debug(NES_DBG_INIT, "Phy interrupt status = 0x%X.\n", u32temp);
- nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS+(0x200*nesvnic->logical_port), u32temp);
+ nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS + (0x200 * nesdev->mac_index), u32temp);
- if (nesdev->nesadapter->phy_type[nesvnic->logical_port] != NES_PHY_TYPE_IRIS)
+ if (nesdev->nesadapter->phy_type[nesdev->mac_index] != NES_PHY_TYPE_IRIS)
nes_init_phy(nesdev);
- nes_write_indexed(nesdev, NES_IDX_MAC_INT_MASK+(0x200*nesvnic->logical_port),
- ~(NES_MAC_INT_LINK_STAT_CHG | NES_MAC_INT_XGMII_EXT |
- NES_MAC_INT_TX_UNDERFLOW | NES_MAC_INT_TX_ERROR));
}
return netdev;
diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c
index ffd4b425567..a651e9d9f0e 100644
--- a/drivers/infiniband/hw/nes/nes_verbs.c
+++ b/drivers/infiniband/hw/nes/nes_verbs.c
@@ -929,7 +929,7 @@ static struct ib_pd *nes_alloc_pd(struct ib_device *ibdev,
NES_MAX_USER_DB_REGIONS, nesucontext->first_free_db);
nes_debug(NES_DBG_PD, "find_first_zero_biton doorbells returned %u, mapping pd_id %u.\n",
nespd->mmap_db_index, nespd->pd_id);
- if (nespd->mmap_db_index > NES_MAX_USER_DB_REGIONS) {
+ if (nespd->mmap_db_index >= NES_MAX_USER_DB_REGIONS) {
nes_debug(NES_DBG_PD, "mmap_db_index > MAX\n");
nes_free_resource(nesadapter, nesadapter->allocated_pds, pd_num);
kfree(nespd);
@@ -1327,7 +1327,7 @@ static struct ib_qp *nes_create_qp(struct ib_pd *ibpd,
(long long unsigned int)req.user_wqe_buffers);
nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);
kfree(nesqp->allocated_buffer);
- return ERR_PTR(-ENOMEM);
+ return ERR_PTR(-EFAULT);
}
}
@@ -1337,7 +1337,7 @@ static struct ib_qp *nes_create_qp(struct ib_pd *ibpd,
NES_MAX_USER_WQ_REGIONS, nes_ucontext->first_free_wq);
/* nes_debug(NES_DBG_QP, "find_first_zero_biton wqs returned %u\n",
nespd->mmap_db_index); */
- if (nesqp->mmap_sq_db_index > NES_MAX_USER_WQ_REGIONS) {
+ if (nesqp->mmap_sq_db_index >= NES_MAX_USER_WQ_REGIONS) {
nes_debug(NES_DBG_QP,
"db index > max user regions, failing create QP\n");
nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);
@@ -1674,6 +1674,7 @@ static struct ib_cq *nes_create_cq(struct ib_device *ibdev, int entries,
}
nes_debug(NES_DBG_CQ, "CQ Virtual Address = %08lX, size = %u.\n",
(unsigned long)req.user_cq_buffer, entries);
+ err = 1;
list_for_each_entry(nespbl, &nes_ucontext->cq_reg_mem_list, list) {
if (nespbl->user_base == (unsigned long )req.user_cq_buffer) {
list_del(&nespbl->list);
@@ -1686,7 +1687,7 @@ static struct ib_cq *nes_create_cq(struct ib_device *ibdev, int entries,
if (err) {
nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
kfree(nescq);
- return ERR_PTR(err);
+ return ERR_PTR(-EFAULT);
}
pbl_entries = nespbl->pbl_size >> 3;
@@ -1831,9 +1832,6 @@ static struct ib_cq *nes_create_cq(struct ib_device *ibdev, int entries,
spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
}
}
- nes_debug(NES_DBG_CQ, "iWARP CQ%u create timeout expired, major code = 0x%04X,"
- " minor code = 0x%04X\n",
- nescq->hw_cq.cq_number, cqp_request->major_code, cqp_request->minor_code);
if (!context)
pci_free_consistent(nesdev->pcidev, nescq->cq_mem_size, mem,
nescq->hw_cq.cq_pbase);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
index 7dd2ec473d2..52b1bebfa74 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
@@ -824,7 +824,6 @@ void ipoib_cm_dev_stop(struct net_device *dev)
struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ipoib_cm_rx *p;
unsigned long begin;
- LIST_HEAD(list);
int ret;
if (!IPOIB_CM_SUPPORTED(dev->dev_addr) || !priv->cm.id)
@@ -857,9 +856,12 @@ void ipoib_cm_dev_stop(struct net_device *dev)
/*
* assume the HW is wedged and just free up everything.
*/
- list_splice_init(&priv->cm.rx_flush_list, &list);
- list_splice_init(&priv->cm.rx_error_list, &list);
- list_splice_init(&priv->cm.rx_drain_list, &list);
+ list_splice_init(&priv->cm.rx_flush_list,
+ &priv->cm.rx_reap_list);
+ list_splice_init(&priv->cm.rx_error_list,
+ &priv->cm.rx_reap_list);
+ list_splice_init(&priv->cm.rx_drain_list,
+ &priv->cm.rx_reap_list);
break;
}
spin_unlock_irq(&priv->lock);
diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c
index 51a112815f4..bd8a1d14b45 100644
--- a/drivers/macintosh/mediabay.c
+++ b/drivers/macintosh/mediabay.c
@@ -698,7 +698,8 @@ static int media_bay_suspend(struct macio_dev *mdev, pm_message_t state)
{
struct media_bay_info *bay = macio_get_drvdata(mdev);
- if (state.event != mdev->ofdev.dev.power.power_state.event && state.event == PM_EVENT_SUSPEND) {
+ if (state.event != mdev->ofdev.dev.power.power_state.event
+ && (state.event & PM_EVENT_SLEEP)) {
down(&bay->lock);
bay->sleeping = 1;
set_mb_power(bay, 0);
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index 2928ef22810..51605870f89 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -1695,14 +1695,15 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio,
* information for a retry or there was no other
* mirror in-sync.
*/
- DMERR_LIMIT("Mirror read failed from %s.",
- m->dev->name);
+ DMERR_LIMIT("Mirror read failed.");
return -EIO;
}
+
+ m = read_record->m;
+
DMERR("Mirror read failed from %s. Trying alternative device.",
m->dev->name);
- m = read_record->m;
fail_mirror(m, DM_RAID1_READ_ERROR);
/*
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index 8f4a45346de..11950698a2e 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -25,11 +25,16 @@ config VIDEO_DEV
To compile this driver as a module, choose M here: the
module will be called videodev.
+config VIDEO_V4L2_COMMON
+ tristate
+ depends on (I2C || I2C=n) && VIDEO_DEV
+ default (I2C || I2C=n) && VIDEO_DEV
+
config VIDEO_V4L1
bool "Enable Video For Linux API 1 (DEPRECATED)"
- depends on VIDEO_DEV
+ depends on VIDEO_DEV && VIDEO_V4L2_COMMON
+ default VIDEO_DEV && VIDEO_V4L2_COMMON
select VIDEO_V4L1_COMPAT
- default y
---help---
Enables a compatibility API used by most V4L2 devices to allow
its usage with legacy applications that supports only V4L1 api.
@@ -39,7 +44,7 @@ config VIDEO_V4L1
config VIDEO_V4L1_COMPAT
bool "Enable Video For Linux API 1 compatible Layer"
depends on VIDEO_DEV
- default y
+ default VIDEO_DEV
---help---
This api were developed to be used at Kernel 2.2 and 2.4, but
lacks support for several video standards. There are several
@@ -55,8 +60,8 @@ config VIDEO_V4L1_COMPAT
config VIDEO_V4L2
bool
- depends on VIDEO_DEV
- default y
+ depends on VIDEO_DEV && VIDEO_V4L2_COMMON
+ default VIDEO_DEV && VIDEO_V4L2_COMMON
source "drivers/media/video/Kconfig"
@@ -93,7 +98,7 @@ if VIDEO_TUNER_CUSTOMIZE
config TUNER_XC2028
tristate "XCeive xc2028/xc3028 tuners"
- depends on I2C
+ depends on I2C && FW_LOADER
default m if VIDEO_TUNER_CUSTOMIZE
help
Say Y here to include support for the xc2028/xc3028 tuners.
@@ -180,7 +185,6 @@ config VIDEO_TVEEPROM
config DAB
boolean "DAB adapters"
- default y
---help---
Allow selecting support for for Digital Audio Broadcasting (DAB)
Receiver adapters.
diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig
index 06ca75911b7..769c6f8142d 100644
--- a/drivers/media/common/Kconfig
+++ b/drivers/media/common/Kconfig
@@ -4,6 +4,6 @@ config VIDEO_SAA7146
config VIDEO_SAA7146_VV
tristate
- depends on VIDEO_DEV
+ depends on VIDEO_V4L2
select VIDEOBUF_DMA_SG
select VIDEO_SAA7146
diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c
index a4a937c9053..2ab5a120470 100644
--- a/drivers/media/common/ir-keymaps.c
+++ b/drivers/media/common/ir-keymaps.c
@@ -1987,3 +1987,49 @@ IR_KEYTAB_TYPE ir_codes_behold[IR_KEYTAB_SIZE] = {
};
EXPORT_SYMBOL_GPL(ir_codes_behold);
+
+/*
+ * Remote control for the Genius TVGO A11MCE
+ * Adrian Pardini <pardo.bsso@gmail.com>
+ */
+IR_KEYTAB_TYPE ir_codes_genius_tvgo_a11mce[IR_KEYTAB_SIZE] = {
+ /* Keys 0 to 9 */
+ [0x48] = KEY_0,
+ [0x09] = KEY_1,
+ [0x1d] = KEY_2,
+ [0x1f] = KEY_3,
+ [0x19] = KEY_4,
+ [0x1b] = KEY_5,
+ [0x11] = KEY_6,
+ [0x17] = KEY_7,
+ [0x12] = KEY_8,
+ [0x16] = KEY_9,
+
+ [0x54] = KEY_RECORD, /* recording */
+ [0x06] = KEY_MUTE, /* mute */
+ [0x10] = KEY_POWER,
+ [0x40] = KEY_LAST, /* recall */
+ [0x4c] = KEY_CHANNELUP, /* channel / program + */
+ [0x00] = KEY_CHANNELDOWN, /* channel / program - */
+ [0x0d] = KEY_VOLUMEUP,
+ [0x15] = KEY_VOLUMEDOWN,
+ [0x4d] = KEY_OK, /* also labeled as Pause */
+ [0x1c] = KEY_ZOOM, /* full screen and Stop*/
+ [0x02] = KEY_MODE, /* AV Source or Rewind*/
+ [0x04] = KEY_LIST, /* -/-- */
+ /* small arrows above numbers */
+ [0x1a] = KEY_NEXT, /* also Fast Forward */
+ [0x0e] = KEY_PREVIOUS, /* also Rewind */
+ /* these are in a rather non standard layout and have
+ an alternate name written */
+ [0x1e] = KEY_UP, /* Video Setting */
+ [0x0a] = KEY_DOWN, /* Video Default */
+ [0x05] = KEY_LEFT, /* Snapshot */
+ [0x0c] = KEY_RIGHT, /* Hide Panel */
+ /* Four buttons without label */
+ [0x49] = KEY_RED,
+ [0x0b] = KEY_GREEN,
+ [0x13] = KEY_YELLOW,
+ [0x50] = KEY_BLUE,
+};
+EXPORT_SYMBOL_GPL(ir_codes_genius_tvgo_a11mce);
diff --git a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146_vbi.c
index c32dda973e9..bfbd5a841eb 100644
--- a/drivers/media/common/saa7146_vbi.c
+++ b/drivers/media/common/saa7146_vbi.c
@@ -413,7 +413,6 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file)
V4L2_FIELD_SEQ_TB, // FIXME: does this really work?
sizeof(struct saa7146_buf),
file);
- mutex_init(&fh->vbi_q.lock);
init_timer(&fh->vbi_read_timeout);
fh->vbi_read_timeout.function = vbi_read_timeout;
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
index c31ab480d8e..66fdbd0e6a6 100644
--- a/drivers/media/common/saa7146_video.c
+++ b/drivers/media/common/saa7146_video.c
@@ -1417,8 +1417,6 @@ static int video_open(struct saa7146_dev *dev, struct file *file)
sizeof(struct saa7146_buf),
file);
- mutex_init(&fh->video_q.lock);
-
return 0;
}
diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c
index c7bbb40223f..56d8fab688b 100644
--- a/drivers/media/dvb/bt8xx/bt878.c
+++ b/drivers/media/dvb/bt8xx/bt878.c
@@ -75,7 +75,11 @@ EXPORT_SYMBOL(bt878);
#if defined(dprintk)
#undef dprintk
#endif
-#define dprintk if(bt878_debug) printk
+#define dprintk(fmt, arg...) \
+ do { \
+ if (bt878_debug) \
+ printk(KERN_DEBUG fmt, ##arg); \
+ } while (0)
static void bt878_mem_free(struct bt878 *bt)
{
@@ -154,7 +158,7 @@ static int bt878_make_risc(struct bt878 *bt)
}
if (bt->line_count > 255) {
- printk("bt878: buffer size error!\n");
+ printk(KERN_ERR "bt878: buffer size error!\n");
return -EINVAL;
}
return 0;
@@ -285,7 +289,8 @@ static irqreturn_t bt878_irq(int irq, void *dev_id)
if (astat & (BT878_ASCERR | BT878_AOCERR)) {
if (bt878_verbose) {
- printk("bt878(%d): irq%s%s risc_pc=%08x\n",
+ printk(KERN_INFO
+ "bt878(%d): irq%s%s risc_pc=%08x\n",
bt->nr,
(astat & BT878_ASCERR) ? " SCERR" :
"",
@@ -295,8 +300,8 @@ static irqreturn_t bt878_irq(int irq, void *dev_id)
}
if (astat & (BT878_APABORT | BT878_ARIPERR | BT878_APPERR)) {
if (bt878_verbose) {
- printk
- ("bt878(%d): irq%s%s%s risc_pc=%08x\n",
+ printk(KERN_INFO
+ "bt878(%d): irq%s%s%s risc_pc=%08x\n",
bt->nr,
(astat & BT878_APABORT) ? " PABORT" :
"",
@@ -308,8 +313,8 @@ static irqreturn_t bt878_irq(int irq, void *dev_id)
}
if (astat & (BT878_AFDSR | BT878_AFTRGT | BT878_AFBUS)) {
if (bt878_verbose) {
- printk
- ("bt878(%d): irq%s%s%s risc_pc=%08x\n",
+ printk(KERN_INFO
+ "bt878(%d): irq%s%s%s risc_pc=%08x\n",
bt->nr,
(astat & BT878_AFDSR) ? " FDSR" : "",
(astat & BT878_AFTRGT) ? " FTRGT" :
@@ -510,7 +515,7 @@ static int __devinit bt878_probe(struct pci_dev *dev,
*/
if ((result = bt878_mem_alloc(bt))) {
- printk("bt878: failed to allocate memory!\n");
+ printk(KERN_ERR "bt878: failed to allocate memory!\n");
goto fail2;
}
@@ -536,7 +541,7 @@ static void __devexit bt878_remove(struct pci_dev *pci_dev)
struct bt878 *bt = pci_get_drvdata(pci_dev);
if (bt878_verbose)
- printk("bt878(%d): unloading\n", bt->nr);
+ printk(KERN_INFO "bt878(%d): unloading\n", bt->nr);
/* turn off all capturing, DMA and IRQs */
btand(~0x13, BT878_AGPIO_DMA_CTL);
diff --git a/drivers/media/dvb/dvb-usb/ttusb2.c b/drivers/media/dvb/dvb-usb/ttusb2.c
index 88dc4367a2e..3b9da9c25c6 100644
--- a/drivers/media/dvb/dvb-usb/ttusb2.c
+++ b/drivers/media/dvb/dvb-usb/ttusb2.c
@@ -144,6 +144,7 @@ static int ttusb2_power_ctrl(struct dvb_usb_device *d, int onoff)
static struct tda10086_config tda10086_config = {
.demod_address = 0x0e,
.invert = 0,
+ .diseqc_tone = 1,
};
static int ttusb2_frontend_attach(struct dvb_usb_adapter *adap)
diff --git a/drivers/media/dvb/frontends/tda10086.c b/drivers/media/dvb/frontends/tda10086.c
index 9d26ace6515..0d2b69a99ad 100644
--- a/drivers/media/dvb/frontends/tda10086.c
+++ b/drivers/media/dvb/frontends/tda10086.c
@@ -106,9 +106,12 @@ static int tda10086_write_mask(struct tda10086_state *state, int reg, int mask,
static int tda10086_init(struct dvb_frontend* fe)
{
struct tda10086_state* state = fe->demodulator_priv;
+ u8 t22k_off = 0x80;
dprintk ("%s\n", __FUNCTION__);
+ if (state->config->diseqc_tone)
+ t22k_off = 0;
// reset
tda10086_write_byte(state, 0x00, 0x00);
msleep(10);
@@ -158,7 +161,7 @@ static int tda10086_init(struct dvb_frontend* fe)
tda10086_write_byte(state, 0x3d, 0x80);
// setup SEC
- tda10086_write_byte(state, 0x36, 0x80); // all SEC off, no 22k tone
+ tda10086_write_byte(state, 0x36, t22k_off); // all SEC off, 22k tone
tda10086_write_byte(state, 0x34, (((1<<19) * (22000/1000)) / (SACLK/1000))); // } tone frequency
tda10086_write_byte(state, 0x35, (((1<<19) * (22000/1000)) / (SACLK/1000)) >> 8); // }
@@ -180,16 +183,20 @@ static void tda10086_diseqc_wait(struct tda10086_state *state)
static int tda10086_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
{
struct tda10086_state* state = fe->demodulator_priv;
+ u8 t22k_off = 0x80;
dprintk ("%s\n", __FUNCTION__);
+ if (state->config->diseqc_tone)
+ t22k_off = 0;
+
switch (tone) {
case SEC_TONE_OFF:
- tda10086_write_byte(state, 0x36, 0x80);
+ tda10086_write_byte(state, 0x36, t22k_off);
break;
case SEC_TONE_ON:
- tda10086_write_byte(state, 0x36, 0x81);
+ tda10086_write_byte(state, 0x36, 0x01 + t22k_off);
break;
}
@@ -202,9 +209,13 @@ static int tda10086_send_master_cmd (struct dvb_frontend* fe,
struct tda10086_state* state = fe->demodulator_priv;
int i;
u8 oldval;
+ u8 t22k_off = 0x80;
dprintk ("%s\n", __FUNCTION__);
+ if (state->config->diseqc_tone)
+ t22k_off = 0;
+
if (cmd->msg_len > 6)
return -EINVAL;
oldval = tda10086_read_byte(state, 0x36);
@@ -212,7 +223,8 @@ static int tda10086_send_master_cmd (struct dvb_frontend* fe,
for(i=0; i< cmd->msg_len; i++) {
tda10086_write_byte(state, 0x48+i, cmd->msg[i]);
}
- tda10086_write_byte(state, 0x36, 0x88 | ((cmd->msg_len - 1) << 4));
+ tda10086_write_byte(state, 0x36, (0x08 + t22k_off)
+ | ((cmd->msg_len - 1) << 4));
tda10086_diseqc_wait(state);
@@ -225,16 +237,20 @@ static int tda10086_send_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t minic
{
struct tda10086_state* state = fe->demodulator_priv;
u8 oldval = tda10086_read_byte(state, 0x36);
+ u8 t22k_off = 0x80;
dprintk ("%s\n", __FUNCTION__);
+ if (state->config->diseqc_tone)
+ t22k_off = 0;
+
switch(minicmd) {
case SEC_MINI_A:
- tda10086_write_byte(state, 0x36, 0x84);
+ tda10086_write_byte(state, 0x36, 0x04 + t22k_off);
break;
case SEC_MINI_B:
- tda10086_write_byte(state, 0x36, 0x86);
+ tda10086_write_byte(state, 0x36, 0x06 + t22k_off);
break;
}
diff --git a/drivers/media/dvb/frontends/tda10086.h b/drivers/media/dvb/frontends/tda10086.h
index ed584a8f4a8..eeceaeee78f 100644
--- a/drivers/media/dvb/frontends/tda10086.h
+++ b/drivers/media/dvb/frontends/tda10086.h
@@ -33,6 +33,9 @@ struct tda10086_config
/* does the "inversion" need inverted? */
u8 invert;
+
+ /* do we need the diseqc signal with carrier? */
+ u8 diseqc_tone;
};
#if defined(CONFIG_DVB_TDA10086) || (defined(CONFIG_DVB_TDA10086_MODULE) && defined(MODULE))
diff --git a/drivers/media/dvb/frontends/tda18271-common.c b/drivers/media/dvb/frontends/tda18271-common.c
index cebb6b90b7e..bca57099061 100644
--- a/drivers/media/dvb/frontends/tda18271-common.c
+++ b/drivers/media/dvb/frontends/tda18271-common.c
@@ -171,7 +171,7 @@ int tda18271_read_extended(struct dvb_frontend *fe)
if (ret != 2)
tda_err("ERROR: i2c_transfer returned: %d\n", ret);
- for (i = 0; i <= TDA18271_NUM_REGS; i++) {
+ for (i = 0; i < TDA18271_NUM_REGS; i++) {
/* don't update write-only registers */
if ((i != R_EB9) &&
(i != R_EB16) &&
diff --git a/drivers/media/dvb/frontends/xc5000.h b/drivers/media/dvb/frontends/xc5000.h
index e0e84562aed..32a5f1c86a1 100644
--- a/drivers/media/dvb/frontends/xc5000.h
+++ b/drivers/media/dvb/frontends/xc5000.h
@@ -45,7 +45,8 @@ struct xc5000_config {
/* xc5000 callback command */
#define XC5000_TUNER_RESET 0
-#if defined(CONFIG_DVB_TUNER_XC5000) || defined(CONFIG_DVB_TUNER_XC5000_MODULE)
+#if defined(CONFIG_DVB_TUNER_XC5000) || \
+ (defined(CONFIG_DVB_TUNER_XC5000_MODULE) && defined(MODULE))
extern struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
struct xc5000_config *cfg);
diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c
index aef6e36d7c5..3e6b650fbb8 100644
--- a/drivers/media/dvb/ttpci/av7110_av.c
+++ b/drivers/media/dvb/ttpci/av7110_av.c
@@ -966,6 +966,7 @@ static u8 iframe_header[] = { 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x00, 0x
static int play_iframe(struct av7110 *av7110, char __user *buf, unsigned int len, int nonblock)
{
int i, n;
+ int progressive = 0;
dprintk(2, "av7110:%p, \n", av7110);
@@ -974,6 +975,14 @@ static int play_iframe(struct av7110 *av7110, char __user *buf, unsigned int len
return -EBUSY;
}
+ for (i = 0; i < len - 5; i++) {
+ /* get progressive flag from picture extension */
+ if (buf[i] == 0x00 && buf[i+1] == 0x00 &&
+ buf[i+2] == 0x01 && (unsigned char)buf[i+3] == 0xb5 &&
+ (buf[i+4] & 0xf0) == 0x10)
+ progressive = buf[i+5] & 0x08;
+ }
+
/* setting n always > 1, fixes problems when playing stillframes
consisting of I- and P-Frames */
n = MIN_IFRAME / len + 1;
@@ -985,7 +994,11 @@ static int play_iframe(struct av7110 *av7110, char __user *buf, unsigned int len
dvb_play(av7110, buf, len, 0, 1);
av7110_ipack_flush(&av7110->ipack[1]);
- return 0;
+
+ if (progressive)
+ return vidcom(av7110, AV_VIDEO_CMD_FREEZE, 1);
+ else
+ return 0;
}
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
index 3439c9864f6..2d64d557b97 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -896,6 +896,7 @@ static u8 read_pwm(struct budget_av *budget_av)
#define SUBID_DVBS_CINERGY1200 0x1154
#define SUBID_DVBS_CYNERGY1200N 0x1155
#define SUBID_DVBS_TV_STAR 0x0014
+#define SUBID_DVBS_TV_STAR_PLUS_X4 0x0015
#define SUBID_DVBS_TV_STAR_CI 0x0016
#define SUBID_DVBS_EASYWATCH_1 0x001a
#define SUBID_DVBS_EASYWATCH_2 0x001b
@@ -910,6 +911,7 @@ static u8 read_pwm(struct budget_av *budget_av)
#define SUBID_DVBC_CINERGY1200 0x1156
#define SUBID_DVBC_CINERGY1200_MK3 0x1176
+#define SUBID_DVBT_EASYWATCH 0x003a
#define SUBID_DVBT_KNC1_PLUS 0x0031
#define SUBID_DVBT_KNC1 0x0030
#define SUBID_DVBT_CINERGY1200 0x1157
@@ -957,6 +959,7 @@ static void frontend_init(struct budget_av *budget_av)
break;
case SUBID_DVBS_TV_STAR:
+ case SUBID_DVBS_TV_STAR_PLUS_X4:
case SUBID_DVBS_TV_STAR_CI:
case SUBID_DVBS_CYNERGY1200N:
case SUBID_DVBS_EASYWATCH:
@@ -1018,6 +1021,7 @@ static void frontend_init(struct budget_av *budget_av)
}
break;
+ case SUBID_DVBT_EASYWATCH:
case SUBID_DVBT_KNC1:
case SUBID_DVBT_KNC1_PLUS:
case SUBID_DVBT_CINERGY1200:
@@ -1248,7 +1252,9 @@ MAKE_BUDGET_INFO(satewpls1, "Satelco EasyWatch DVB-S light", BUDGET_KNC1S);
MAKE_BUDGET_INFO(satewps, "Satelco EasyWatch DVB-S", BUDGET_KNC1S);
MAKE_BUDGET_INFO(satewplc, "Satelco EasyWatch DVB-C", BUDGET_KNC1CP);
MAKE_BUDGET_INFO(satewcmk3, "Satelco EasyWatch DVB-C MK3", BUDGET_KNC1C_MK3);
+MAKE_BUDGET_INFO(satewt, "Satelco EasyWatch DVB-T", BUDGET_KNC1T);
MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP);
+MAKE_BUDGET_INFO(knc1spx4, "KNC1 DVB-S Plus X4", BUDGET_KNC1SP);
MAKE_BUDGET_INFO(knc1cp, "KNC1 DVB-C Plus", BUDGET_KNC1CP);
MAKE_BUDGET_INFO(knc1cmk3, "KNC1 DVB-C MK3", BUDGET_KNC1C_MK3);
MAKE_BUDGET_INFO(knc1cpmk3, "KNC1 DVB-C Plus MK3", BUDGET_KNC1CP_MK3);
@@ -1266,12 +1272,14 @@ static struct pci_device_id pci_tbl[] = {
MAKE_EXTENSION_PCI(knc1sp, 0x1131, 0x0011),
MAKE_EXTENSION_PCI(knc1sp, 0x1894, 0x0011),
MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0014),
+ MAKE_EXTENSION_PCI(knc1spx4, 0x1894, 0x0015),
MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016),
MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e),
MAKE_EXTENSION_PCI(satewpls1, 0x1894, 0x001a),
MAKE_EXTENSION_PCI(satewps, 0x1894, 0x001b),
MAKE_EXTENSION_PCI(satewplc, 0x1894, 0x002a),
MAKE_EXTENSION_PCI(satewcmk3, 0x1894, 0x002c),
+ MAKE_EXTENSION_PCI(satewt, 0x1894, 0x003a),
MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020),
MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021),
MAKE_EXTENSION_PCI(knc1cmk3, 0x1894, 0x0022),
diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c
index 9268a82bada..14b00f57b5d 100644
--- a/drivers/media/dvb/ttpci/budget.c
+++ b/drivers/media/dvb/ttpci/budget.c
@@ -351,6 +351,7 @@ static struct s5h1420_config s5h1420_config = {
static struct tda10086_config tda10086_config = {
.demod_address = 0x0e,
.invert = 0,
+ .diseqc_tone = 1,
};
static u8 read_pwm(struct budget* budget)
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
index 8d5214f18cf..1b41b3f77cf 100644
--- a/drivers/media/radio/Kconfig
+++ b/drivers/media/radio/Kconfig
@@ -4,12 +4,12 @@
menuconfig RADIO_ADAPTERS
bool "Radio Adapters"
- depends on VIDEO_DEV
+ depends on VIDEO_V4L2
default y
---help---
Say Y here to enable selecting AM/FM radio adapters.
-if RADIO_ADAPTERS && VIDEO_DEV
+if RADIO_ADAPTERS && VIDEO_V4L2
config RADIO_CADET
tristate "ADS Cadet AM/FM Tuner"
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index 3118bdab318..53e11485737 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -361,6 +361,7 @@ static int __init fmi_init(void)
}
if (!request_region(io, 2, "radio-sf16fmi")) {
printk(KERN_ERR "radio-sf16fmi: port 0x%x already in use\n", io);
+ pnp_device_detach(dev);
return -EBUSY;
}
diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c
index f7c8b000404..ebc5fbbc38b 100644
--- a/drivers/media/radio/radio-sf16fmr2.c
+++ b/drivers/media/radio/radio-sf16fmr2.c
@@ -470,9 +470,8 @@ static int __init fmr2_init(void)
mutex_init(&lock);
- if (request_region(io, 2, "sf16fmr2"))
- {
- printk(KERN_ERR "fmr2: port 0x%x already in use\n", io);
+ if (!request_region(io, 2, "sf16fmr2")) {
+ printk(KERN_ERR "radio-sf16fmr2: request_region failed!\n");
return -EBUSY;
}
diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c
index 8e4bd476904..649f14d2c01 100644
--- a/drivers/media/radio/radio-si470x.c
+++ b/drivers/media/radio/radio-si470x.c
@@ -62,6 +62,29 @@
* - code cleaned of unnecessary rds_commands
* - USB Vendor/Product ID for ADS/Tech FM Radio Receiver verified
* (thanks to Guillaume RAMOUSSE)
+ * 2008-01-27 Tobias Lorenz <tobias.lorenz@gmx.net>
+ * Version 1.0.5
+ * - number of seek_retries changed to tune_timeout
+ * - fixed problem with incomplete tune operations by own buffers
+ * - optimization of variables and printf types
+ * - improved error logging
+ * 2008-01-31 Tobias Lorenz <tobias.lorenz@gmx.net>
+ * Oliver Neukum <oliver@neukum.org>
+ * Version 1.0.6
+ * - fixed coverity checker warnings in *_usb_driver_disconnect
+ * - probe()/open() race by correct ordering in probe()
+ * - DMA coherency rules by separate allocation of all buffers
+ * - use of endianness macros
+ * - abuse of spinlock, replaced by mutex
+ * - racy handling of timer in disconnect,
+ * replaced by delayed_work
+ * - racy interruptible_sleep_on(),
+ * replaced with wait_event_interruptible()
+ * - handle signals in read()
+ * 2008-02-08 Tobias Lorenz <tobias.lorenz@gmx.net>
+ * Oliver Neukum <oliver@neukum.org>
+ * Version 1.0.7
+ * - usb autosuspend support
*
* ToDo:
* - add seeking support
@@ -74,9 +97,10 @@
/* driver definitions */
#define DRIVER_AUTHOR "Tobias Lorenz <tobias.lorenz@gmx.net>"
#define DRIVER_NAME "radio-si470x"
-#define DRIVER_VERSION KERNEL_VERSION(1, 0, 4)
+#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 6)
#define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver"
#define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers"
+#define DRIVER_VERSION "1.0.6"
/* kernel includes */
@@ -89,8 +113,10 @@
#include <linux/hid.h>
#include <linux/version.h>
#include <linux/videodev2.h>
+#include <linux/mutex.h>
#include <media/v4l2-common.h>
#include <media/rds.h>
+#include <asm/unaligned.h>
/* USB Device ID List */
@@ -119,56 +145,56 @@ MODULE_PARM_DESC(radio_nr, "Radio Nr");
/* 0: 200 kHz (USA, Australia) */
/* 1: 100 kHz (Europe, Japan) */
/* 2: 50 kHz */
-static int space = 2;
-module_param(space, int, 0);
+static unsigned short space = 2;
+module_param(space, ushort, 0);
MODULE_PARM_DESC(radio_nr, "Spacing: 0=200kHz 1=100kHz *2=50kHz*");
/* Bottom of Band (MHz) */
/* 0: 87.5 - 108 MHz (USA, Europe)*/
/* 1: 76 - 108 MHz (Japan wide band) */
/* 2: 76 - 90 MHz (Japan) */
-static int band = 1;
-module_param(band, int, 0);
+static unsigned short band = 1;
+module_param(band, ushort, 0);
MODULE_PARM_DESC(radio_nr, "Band: 0=87.5..108MHz *1=76..108MHz* 2=76..90MHz");
/* De-emphasis */
/* 0: 75 us (USA) */
/* 1: 50 us (Europe, Australia, Japan) */
-static int de = 1;
-module_param(de, int, 0);
+static unsigned short de = 1;
+module_param(de, ushort, 0);
MODULE_PARM_DESC(radio_nr, "De-emphasis: 0=75us *1=50us*");
/* USB timeout */
-static int usb_timeout = 500;
-module_param(usb_timeout, int, 0);
+static unsigned int usb_timeout = 500;
+module_param(usb_timeout, uint, 0);
MODULE_PARM_DESC(usb_timeout, "USB timeout (ms): *500*");
-/* Seek retries */
-static int seek_retries = 100;
-module_param(seek_retries, int, 0);
-MODULE_PARM_DESC(seek_retries, "Seek retries: *100*");
+/* Tune timeout */
+static unsigned int tune_timeout = 3000;
+module_param(tune_timeout, uint, 0);
+MODULE_PARM_DESC(tune_timeout, "Tune timeout: *3000*");
/* RDS buffer blocks */
-static int rds_buf = 100;
-module_param(rds_buf, int, 0);
+static unsigned int rds_buf = 100;
+module_param(rds_buf, uint, 0);
MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*");
/* RDS maximum block errors */
-static int max_rds_errors = 1;
+static unsigned short max_rds_errors = 1;
/* 0 means 0 errors requiring correction */
/* 1 means 1-2 errors requiring correction (used by original USBRadio.exe) */
/* 2 means 3-5 errors requiring correction */
/* 3 means 6+ errors or errors in checkword, correction not possible */
-module_param(max_rds_errors, int, 0);
+module_param(max_rds_errors, ushort, 0);
MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*");
/* RDS poll frequency */
-static int rds_poll_time = 40;
+static unsigned int rds_poll_time = 40;
/* 40 is used by the original USBRadio.exe */
/* 50 is used by radio-cadet */
/* 75 should be okay */
/* 80 is the usual RDS receive interval */
-module_param(rds_poll_time, int, 0);
+module_param(rds_poll_time, uint, 0);
MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*");
@@ -393,22 +419,19 @@ MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*");
struct si470x_device {
/* reference to USB and video device */
struct usb_device *usbdev;
+ struct usb_interface *intf;
struct video_device *videodev;
- /* are these really necessary ? */
- int users;
-
- /* report buffer (maximum 64 bytes) */
- unsigned char buf[64];
+ /* driver management */
+ unsigned int users;
/* Silabs internal registers (0..15) */
unsigned short registers[RADIO_REGISTER_NUM];
/* RDS receive buffer */
- struct work_struct work;
+ struct delayed_work work;
wait_queue_head_t read_queue;
- struct timer_list timer;
- spinlock_t lock; /* buffer locking */
+ struct mutex lock; /* buffer locking */
unsigned char *buffer; /* size is always multiple of three */
unsigned int buf_size;
unsigned int rd_index;
@@ -434,28 +457,46 @@ struct si470x_device {
/*
* si470x_get_report - receive a HID report
*/
-static int si470x_get_report(struct si470x_device *radio, int size)
+static int si470x_get_report(struct si470x_device *radio, void *buf, int size)
{
- return usb_control_msg(radio->usbdev,
+ unsigned char *report = (unsigned char *) buf;
+ int retval;
+
+ retval = usb_control_msg(radio->usbdev,
usb_rcvctrlpipe(radio->usbdev, 0),
HID_REQ_GET_REPORT,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- radio->buf[0], 2,
- radio->buf, size, usb_timeout);
+ report[0], 2,
+ buf, size, usb_timeout);
+ if (retval < 0)
+ printk(KERN_WARNING DRIVER_NAME
+ ": si470x_get_report: usb_control_msg returned %d\n",
+ retval);
+
+ return retval;
}
/*
* si470x_set_report - send a HID report
*/
-static int si470x_set_report(struct si470x_device *radio, int size)
+static int si470x_set_report(struct si470x_device *radio, void *buf, int size)
{
- return usb_control_msg(radio->usbdev,
+ unsigned char *report = (unsigned char *) buf;
+ int retval;
+
+ retval = usb_control_msg(radio->usbdev,
usb_sndctrlpipe(radio->usbdev, 0),
HID_REQ_SET_REPORT,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
- radio->buf[0], 2,
- radio->buf, size, usb_timeout);
+ report[0], 2,
+ buf, size, usb_timeout);
+ if (retval < 0)
+ printk(KERN_WARNING DRIVER_NAME
+ ": si470x_set_report: usb_control_msg returned %d\n",
+ retval);
+
+ return retval;
}
@@ -464,13 +505,16 @@ static int si470x_set_report(struct si470x_device *radio, int size)
*/
static int si470x_get_register(struct si470x_device *radio, int regnr)
{
+ unsigned char buf[REGISTER_REPORT_SIZE];
int retval;
- radio->buf[0] = REGISTER_REPORT(regnr);
+ buf[0] = REGISTER_REPORT(regnr);
+
+ retval = si470x_get_report(radio, (void *) &buf, sizeof(buf));
- retval = si470x_get_report(radio, REGISTER_REPORT_SIZE);
if (retval >= 0)
- radio->registers[regnr] = (radio->buf[1] << 8) | radio->buf[2];
+ radio->registers[regnr] = be16_to_cpu(get_unaligned(
+ (unsigned short *) &buf[1]));
return (retval < 0) ? -EINVAL : 0;
}
@@ -481,13 +525,14 @@ static int si470x_get_register(struct si470x_device *radio, int regnr)
*/
static int si470x_set_register(struct si470x_device *radio, int regnr)
{
+ unsigned char buf[REGISTER_REPORT_SIZE];
int retval;
- radio->buf[0] = REGISTER_REPORT(regnr);
- radio->buf[1] = (radio->registers[regnr] & 0xff00) >> 8;
- radio->buf[2] = (radio->registers[regnr] & 0x00ff);
+ buf[0] = REGISTER_REPORT(regnr);
+ put_unaligned(cpu_to_be16(radio->registers[regnr]),
+ (unsigned short *) &buf[1]);
- retval = si470x_set_report(radio, REGISTER_REPORT_SIZE);
+ retval = si470x_set_report(radio, (void *) &buf, sizeof(buf));
return (retval < 0) ? -EINVAL : 0;
}
@@ -498,18 +543,19 @@ static int si470x_set_register(struct si470x_device *radio, int regnr)
*/
static int si470x_get_all_registers(struct si470x_device *radio)
{
+ unsigned char buf[ENTIRE_REPORT_SIZE];
int retval;
- int regnr;
+ unsigned char regnr;
- radio->buf[0] = ENTIRE_REPORT;
+ buf[0] = ENTIRE_REPORT;
- retval = si470x_get_report(radio, ENTIRE_REPORT_SIZE);
+ retval = si470x_get_report(radio, (void *) &buf, sizeof(buf));
if (retval >= 0)
for (regnr = 0; regnr < RADIO_REGISTER_NUM; regnr++)
- radio->registers[regnr] =
- (radio->buf[regnr * RADIO_REGISTER_SIZE + 1] << 8) |
- radio->buf[regnr * RADIO_REGISTER_SIZE + 2];
+ radio->registers[regnr] = be16_to_cpu(get_unaligned(
+ (unsigned short *)
+ &buf[regnr * RADIO_REGISTER_SIZE + 1]));
return (retval < 0) ? -EINVAL : 0;
}
@@ -520,21 +566,28 @@ static int si470x_get_all_registers(struct si470x_device *radio)
*/
static int si470x_get_rds_registers(struct si470x_device *radio)
{
+ unsigned char buf[RDS_REPORT_SIZE];
int retval;
- int regnr;
int size;
+ unsigned char regnr;
- radio->buf[0] = RDS_REPORT;
+ buf[0] = RDS_REPORT;
retval = usb_interrupt_msg(radio->usbdev,
- usb_rcvctrlpipe(radio->usbdev, 1),
- radio->buf, RDS_REPORT_SIZE, &size, usb_timeout);
+ usb_rcvintpipe(radio->usbdev, 1),
+ (void *) &buf, sizeof(buf), &size, usb_timeout);
+ if (size != sizeof(buf))
+ printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_register: "
+ "return size differs: %d != %zu\n", size, sizeof(buf));
+ if (retval < 0)
+ printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: "
+ "usb_interrupt_msg returned %d\n", retval);
if (retval >= 0)
for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++)
radio->registers[STATUSRSSI + regnr] =
- (radio->buf[regnr * RADIO_REGISTER_SIZE + 1] << 8) |
- radio->buf[regnr * RADIO_REGISTER_SIZE + 2];
+ be16_to_cpu(get_unaligned((unsigned short *)
+ &buf[regnr * RADIO_REGISTER_SIZE + 1]));
return (retval < 0) ? -EINVAL : 0;
}
@@ -543,9 +596,11 @@ static int si470x_get_rds_registers(struct si470x_device *radio)
/*
* si470x_set_chan - set the channel
*/
-static int si470x_set_chan(struct si470x_device *radio, int chan)
+static int si470x_set_chan(struct si470x_device *radio, unsigned short chan)
{
- int retval, i;
+ int retval;
+ unsigned long timeout;
+ bool timed_out = 0;
/* start tuning */
radio->registers[CHANNEL] &= ~CHANNEL_CHAN;
@@ -555,16 +610,17 @@ static int si470x_set_chan(struct si470x_device *radio, int chan)
return retval;
/* wait till seek operation has completed */
- i = 0;
+ timeout = jiffies + msecs_to_jiffies(tune_timeout);
do {
retval = si470x_get_register(radio, STATUSRSSI);
if (retval < 0)
return retval;
- } while ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) &&
- (++i < seek_retries));
- if (i >= seek_retries)
+ timed_out = time_after(jiffies, timeout);
+ } while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) &&
+ (!timed_out));
+ if (timed_out)
printk(KERN_WARNING DRIVER_NAME
- ": seek does not finish after %d tries\n", i);
+ ": seek does not finish after %u ms\n", tune_timeout);
/* stop tuning */
radio->registers[CHANNEL] &= ~CHANNEL_TUNE;
@@ -575,9 +631,10 @@ static int si470x_set_chan(struct si470x_device *radio, int chan)
/*
* si470x_get_freq - get the frequency
*/
-static int si470x_get_freq(struct si470x_device *radio)
+static unsigned int si470x_get_freq(struct si470x_device *radio)
{
- int spacing, band_bottom, chan, freq;
+ unsigned int spacing, band_bottom, freq;
+ unsigned short chan;
int retval;
/* Spacing (kHz) */
@@ -616,9 +673,10 @@ static int si470x_get_freq(struct si470x_device *radio)
/*
* si470x_set_freq - set the frequency
*/
-static int si470x_set_freq(struct si470x_device *radio, int freq)
+static int si470x_set_freq(struct si470x_device *radio, unsigned int freq)
{
- int spacing, band_bottom, chan;
+ unsigned int spacing, band_bottom;
+ unsigned short chan;
/* Spacing (kHz) */
switch (space) {
@@ -709,9 +767,17 @@ static int si470x_stop(struct si470x_device *radio)
*/
static int si470x_rds_on(struct si470x_device *radio)
{
+ int retval;
+
/* sysconfig 1 */
+ mutex_lock(&radio->lock);
radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDS;
- return si470x_set_register(radio, SYSCONFIG1);
+ retval = si470x_set_register(radio, SYSCONFIG1);
+ if (retval < 0)
+ radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS;
+ mutex_unlock(&radio->lock);
+
+ return retval;
}
@@ -725,11 +791,10 @@ static int si470x_rds_on(struct si470x_device *radio)
*/
static void si470x_rds(struct si470x_device *radio)
{
- unsigned char tmpbuf[3];
unsigned char blocknum;
- unsigned char bler; /* rds block errors */
+ unsigned short bler; /* rds block errors */
unsigned short rds;
- unsigned int i;
+ unsigned char tmpbuf[3];
/* get rds blocks */
if (si470x_get_rds_registers(radio) < 0)
@@ -743,63 +808,58 @@ static void si470x_rds(struct si470x_device *radio)
return;
}
- /* copy four RDS blocks to internal buffer */
- if (spin_trylock(&radio->lock)) {
- /* process each rds block */
- for (blocknum = 0; blocknum < 4; blocknum++) {
- switch (blocknum) {
- default:
- bler = (radio->registers[STATUSRSSI] &
- STATUSRSSI_BLERA) >> 9;
- rds = radio->registers[RDSA];
- break;
- case 1:
- bler = (radio->registers[READCHAN] &
- READCHAN_BLERB) >> 14;
- rds = radio->registers[RDSB];
- break;
- case 2:
- bler = (radio->registers[READCHAN] &
- READCHAN_BLERC) >> 12;
- rds = radio->registers[RDSC];
- break;
- case 3:
- bler = (radio->registers[READCHAN] &
- READCHAN_BLERD) >> 10;
- rds = radio->registers[RDSD];
- break;
- };
-
- /* Fill the V4L2 RDS buffer */
- tmpbuf[0] = rds & 0x00ff; /* LSB */
- tmpbuf[1] = (rds & 0xff00) >> 8;/* MSB */
- tmpbuf[2] = blocknum; /* offset name */
- tmpbuf[2] |= blocknum << 3; /* received offset */
- if (bler > max_rds_errors)
- tmpbuf[2] |= 0x80; /* uncorrectable errors */
- else if (bler > 0)
- tmpbuf[2] |= 0x40; /* corrected error(s) */
-
- /* copy RDS block to internal buffer */
- for (i = 0; i < 3; i++) {
- radio->buffer[radio->wr_index] = tmpbuf[i];
- radio->wr_index++;
- }
-
- /* wrap write pointer */
- if (radio->wr_index >= radio->buf_size)
- radio->wr_index = 0;
-
- /* check for overflow */
- if (radio->wr_index == radio->rd_index) {
- /* increment and wrap read pointer */
- radio->rd_index += 3;
- if (radio->rd_index >= radio->buf_size)
- radio->rd_index = 0;
- }
+ /* copy all four RDS blocks to internal buffer */
+ mutex_lock(&radio->lock);
+ for (blocknum = 0; blocknum < 4; blocknum++) {
+ switch (blocknum) {
+ default:
+ bler = (radio->registers[STATUSRSSI] &
+ STATUSRSSI_BLERA) >> 9;
+ rds = radio->registers[RDSA];
+ break;
+ case 1:
+ bler = (radio->registers[READCHAN] &
+ READCHAN_BLERB) >> 14;
+ rds = radio->registers[RDSB];
+ break;
+ case 2:
+ bler = (radio->registers[READCHAN] &
+ READCHAN_BLERC) >> 12;
+ rds = radio->registers[RDSC];
+ break;
+ case 3:
+ bler = (radio->registers[READCHAN] &
+ READCHAN_BLERD) >> 10;
+ rds = radio->registers[RDSD];
+ break;
+ };
+
+ /* Fill the V4L2 RDS buffer */
+ put_unaligned(cpu_to_le16(rds), (unsigned short *) &tmpbuf);
+ tmpbuf[2] = blocknum; /* offset name */
+ tmpbuf[2] |= blocknum << 3; /* received offset */
+ if (bler > max_rds_errors)
+ tmpbuf[2] |= 0x80; /* uncorrectable errors */
+ else if (bler > 0)
+ tmpbuf[2] |= 0x40; /* corrected error(s) */
+
+ /* copy RDS block to internal buffer */
+ memcpy(&radio->buffer[radio->wr_index], &tmpbuf, 3);
+ radio->wr_index += 3;
+
+ /* wrap write pointer */
+ if (radio->wr_index >= radio->buf_size)
+ radio->wr_index = 0;
+
+ /* check for overflow */
+ if (radio->wr_index == radio->rd_index) {
+ /* increment and wrap read pointer */
+ radio->rd_index += 3;
+ if (radio->rd_index >= radio->buf_size)
+ radio->rd_index = 0;
}
- spin_unlock(&radio->lock);
}
+ mutex_unlock(&radio->lock);
/* wake up read queue */
if (radio->wr_index != radio->rd_index)
@@ -808,29 +868,18 @@ static void si470x_rds(struct si470x_device *radio)
/*
- * si470x_timer - rds timer function
- */
-static void si470x_timer(unsigned long data)
-{
- struct si470x_device *radio = (struct si470x_device *) data;
-
- schedule_work(&radio->work);
-}
-
-
-/*
* si470x_work - rds work function
*/
static void si470x_work(struct work_struct *work)
{
struct si470x_device *radio = container_of(work, struct si470x_device,
- work);
+ work.work);
if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
return;
si470x_rds(radio);
- mod_timer(&radio->timer, jiffies + msecs_to_jiffies(rds_poll_time));
+ schedule_delayed_work(&radio->work, msecs_to_jiffies(rds_poll_time));
}
@@ -852,44 +901,44 @@ static ssize_t si470x_fops_read(struct file *file, char __user *buf,
/* switch on rds reception */
if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) {
si470x_rds_on(radio);
- schedule_work(&radio->work);
+ schedule_delayed_work(&radio->work,
+ msecs_to_jiffies(rds_poll_time));
}
/* block if no new data available */
while (radio->wr_index == radio->rd_index) {
if (file->f_flags & O_NONBLOCK)
return -EWOULDBLOCK;
- interruptible_sleep_on(&radio->read_queue);
+ if (wait_event_interruptible(radio->read_queue,
+ radio->wr_index != radio->rd_index) < 0)
+ return -EINTR;
}
/* calculate block count from byte count */
count /= 3;
/* copy RDS block out of internal buffer and to user buffer */
- if (spin_trylock(&radio->lock)) {
- while (block_count < count) {
- if (radio->rd_index == radio->wr_index)
- break;
-
- /* always transfer rds complete blocks */
- if (copy_to_user(buf,
- &radio->buffer[radio->rd_index], 3))
- /* retval = -EFAULT; */
- break;
-
- /* increment and wrap read pointer */
- radio->rd_index += 3;
- if (radio->rd_index >= radio->buf_size)
- radio->rd_index = 0;
-
- /* increment counters */
- block_count++;
- buf += 3;
- retval += 3;
- }
-
- spin_unlock(&radio->lock);
+ mutex_lock(&radio->lock);
+ while (block_count < count) {
+ if (radio->rd_index == radio->wr_index)
+ break;
+
+ /* always transfer rds complete blocks */
+ if (copy_to_user(buf, &radio->buffer[radio->rd_index], 3))
+ /* retval = -EFAULT; */
+ break;
+
+ /* increment and wrap read pointer */
+ radio->rd_index += 3;
+ if (radio->rd_index >= radio->buf_size)
+ radio->rd_index = 0;
+
+ /* increment counters */
+ block_count++;
+ buf += 3;
+ retval += 3;
}
+ mutex_unlock(&radio->lock);
return retval;
}
@@ -906,7 +955,8 @@ static unsigned int si470x_fops_poll(struct file *file,
/* switch on rds reception */
if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) {
si470x_rds_on(radio);
- schedule_work(&radio->work);
+ schedule_delayed_work(&radio->work,
+ msecs_to_jiffies(rds_poll_time));
}
poll_wait(file, &radio->read_queue, pts);
@@ -924,10 +974,22 @@ static unsigned int si470x_fops_poll(struct file *file,
static int si470x_fops_open(struct inode *inode, struct file *file)
{
struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+ int retval;
radio->users++;
- if (radio->users == 1)
- return si470x_start(radio);
+
+ retval = usb_autopm_get_interface(radio->intf);
+ if (retval < 0) {
+ radio->users--;
+ return -EIO;
+ }
+
+ if (radio->users == 1) {
+ retval = si470x_start(radio);
+ if (retval < 0)
+ usb_autopm_put_interface(radio->intf);
+ return retval;
+ }
return 0;
}
@@ -939,6 +1001,7 @@ static int si470x_fops_open(struct inode *inode, struct file *file)
static int si470x_fops_release(struct inode *inode, struct file *file)
{
struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+ int retval;
if (!radio)
return -ENODEV;
@@ -946,13 +1009,14 @@ static int si470x_fops_release(struct inode *inode, struct file *file)
radio->users--;
if (radio->users == 0) {
/* stop rds reception */
- del_timer_sync(&radio->timer);
- flush_scheduled_work();
+ cancel_delayed_work_sync(&radio->work);
/* cancel read processes */
wake_up_interruptible(&radio->read_queue);
- return si470x_stop(radio);
+ retval = si470x_stop(radio);
+ usb_autopm_put_interface(radio->intf);
+ return retval;
}
return 0;
@@ -1030,7 +1094,7 @@ static int si470x_vidioc_querycap(struct file *file, void *priv,
strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
sprintf(capability->bus_info, "USB");
- capability->version = DRIVER_VERSION;
+ capability->version = DRIVER_KERNEL_VERSION;
capability->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
return 0;
@@ -1067,16 +1131,21 @@ static int si470x_vidioc_s_input(struct file *filp, void *priv, unsigned int i)
static int si470x_vidioc_queryctrl(struct file *file, void *priv,
struct v4l2_queryctrl *qc)
{
- int i;
+ unsigned char i;
+ int retval = -EINVAL;
for (i = 0; i < ARRAY_SIZE(si470x_v4l2_queryctrl); i++) {
if (qc->id && qc->id == si470x_v4l2_queryctrl[i].id) {
memcpy(qc, &(si470x_v4l2_queryctrl[i]), sizeof(*qc));
- return 0;
+ retval = 0;
+ break;
}
}
+ if (retval < 0)
+ printk(KERN_WARNING DRIVER_NAME
+ ": query control failed with %d\n", retval);
- return -EINVAL;
+ return retval;
}
@@ -1110,21 +1179,29 @@ static int si470x_vidioc_s_ctrl(struct file *file, void *priv,
struct v4l2_control *ctrl)
{
struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+ int retval;
switch (ctrl->id) {
case V4L2_CID_AUDIO_VOLUME:
radio->registers[SYSCONFIG2] &= ~SYSCONFIG2_VOLUME;
radio->registers[SYSCONFIG2] |= ctrl->value;
- return si470x_set_register(radio, SYSCONFIG2);
+ retval = si470x_set_register(radio, SYSCONFIG2);
+ break;
case V4L2_CID_AUDIO_MUTE:
if (ctrl->value == 1)
radio->registers[POWERCFG] &= ~POWERCFG_DMUTE;
else
radio->registers[POWERCFG] |= POWERCFG_DMUTE;
- return si470x_set_register(radio, POWERCFG);
+ retval = si470x_set_register(radio, POWERCFG);
+ break;
+ default:
+ retval = -EINVAL;
}
+ if (retval < 0)
+ printk(KERN_WARNING DRIVER_NAME
+ ": set control failed with %d\n", retval);
- return -EINVAL;
+ return retval;
}
@@ -1163,8 +1240,8 @@ static int si470x_vidioc_s_audio(struct file *file, void *priv,
static int si470x_vidioc_g_tuner(struct file *file, void *priv,
struct v4l2_tuner *tuner)
{
- int retval;
struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+ int retval;
if (tuner->index > 0)
return -EINVAL;
@@ -1220,6 +1297,7 @@ static int si470x_vidioc_s_tuner(struct file *file, void *priv,
struct v4l2_tuner *tuner)
{
struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+ int retval;
if (tuner->index > 0)
return -EINVAL;
@@ -1229,7 +1307,12 @@ static int si470x_vidioc_s_tuner(struct file *file, void *priv,
else
radio->registers[POWERCFG] &= ~POWERCFG_MONO; /* try stereo */
- return si470x_set_register(radio, POWERCFG);
+ retval = si470x_set_register(radio, POWERCFG);
+ if (retval < 0)
+ printk(KERN_WARNING DRIVER_NAME
+ ": set tuner failed with %d\n", retval);
+
+ return retval;
}
@@ -1255,11 +1338,17 @@ static int si470x_vidioc_s_frequency(struct file *file, void *priv,
struct v4l2_frequency *freq)
{
struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+ int retval;
if (freq->type != V4L2_TUNER_RADIO)
return -EINVAL;
- return si470x_set_freq(radio, freq->frequency);
+ retval = si470x_set_freq(radio, freq->frequency);
+ if (retval < 0)
+ printk(KERN_WARNING DRIVER_NAME
+ ": set frequency failed with %d\n", retval);
+
+ return 0;
}
@@ -1299,71 +1388,116 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct si470x_device *radio;
+ int retval = -ENOMEM;
- /* memory and interface allocations */
- radio = kmalloc(sizeof(struct si470x_device), GFP_KERNEL);
+ /* private data allocation */
+ radio = kzalloc(sizeof(struct si470x_device), GFP_KERNEL);
if (!radio)
- return -ENOMEM;
+ goto err_initial;
+
+ /* video device allocation */
radio->videodev = video_device_alloc();
- if (!radio->videodev) {
- kfree(radio);
- return -ENOMEM;
- }
+ if (!radio->videodev)
+ goto err_radio;
+
+ /* initial configuration */
memcpy(radio->videodev, &si470x_viddev_template,
sizeof(si470x_viddev_template));
radio->users = 0;
radio->usbdev = interface_to_usbdev(intf);
+ radio->intf = intf;
+ mutex_init(&radio->lock);
video_set_drvdata(radio->videodev, radio);
- if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
- printk(KERN_WARNING DRIVER_NAME
- ": Could not register video device\n");
- video_device_release(radio->videodev);
- kfree(radio);
- return -EIO;
- }
- usb_set_intfdata(intf, radio);
/* show some infos about the specific device */
- if (si470x_get_all_registers(radio) < 0) {
- video_device_release(radio->videodev);
- kfree(radio);
- return -EIO;
- }
- printk(KERN_INFO DRIVER_NAME ": DeviceID=0x%4.4x ChipID=0x%4.4x\n",
+ retval = -EIO;
+ if (si470x_get_all_registers(radio) < 0)
+ goto err_all;
+ printk(KERN_INFO DRIVER_NAME ": DeviceID=0x%4.4hx ChipID=0x%4.4hx\n",
radio->registers[DEVICEID], radio->registers[CHIPID]);
/* check if firmware is current */
if ((radio->registers[CHIPID] & CHIPID_FIRMWARE)
- < RADIO_SW_VERSION_CURRENT)
+ < RADIO_SW_VERSION_CURRENT) {
+ printk(KERN_WARNING DRIVER_NAME
+ ": This driver is known to work with "
+ "firmware version %hu,\n", RADIO_SW_VERSION_CURRENT);
+ printk(KERN_WARNING DRIVER_NAME
+ ": but the device has firmware version %hu.\n",
+ radio->registers[CHIPID] & CHIPID_FIRMWARE);
+ printk(KERN_WARNING DRIVER_NAME
+ ": If you have some trouble using this driver,\n");
printk(KERN_WARNING DRIVER_NAME
- ": This driver is known to work with chip version %d, "
- "but the device has firmware %d.\n"
- DRIVER_NAME
- "If you have some trouble using this driver, please "
- "report to V4L ML at video4linux-list@redhat.com\n",
- radio->registers[CHIPID] & CHIPID_FIRMWARE,
- RADIO_SW_VERSION_CURRENT);
+ ": please report to V4L ML at "
+ "video4linux-list@redhat.com\n");
+ }
/* set initial frequency */
si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */
- /* rds initialization */
+ /* rds buffer allocation */
radio->buf_size = rds_buf * 3;
radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL);
- if (!radio->buffer) {
- video_device_release(radio->videodev);
- kfree(radio);
- return -ENOMEM;
- }
+ if (!radio->buffer)
+ goto err_all;
+
+ /* rds buffer configuration */
radio->wr_index = 0;
radio->rd_index = 0;
init_waitqueue_head(&radio->read_queue);
- /* prepare polling via eventd */
- INIT_WORK(&radio->work, si470x_work);
- init_timer(&radio->timer);
- radio->timer.function = si470x_timer;
- radio->timer.data = (unsigned long) radio;
+ /* prepare rds work function */
+ INIT_DELAYED_WORK(&radio->work, si470x_work);
+
+ /* register video device */
+ if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
+ printk(KERN_WARNING DRIVER_NAME
+ ": Could not register video device\n");
+ goto err_all;
+ }
+ usb_set_intfdata(intf, radio);
+
+ return 0;
+err_all:
+ video_device_release(radio->videodev);
+ kfree(radio->buffer);
+err_radio:
+ kfree(radio);
+err_initial:
+ return retval;
+}
+
+
+/*
+ * si470x_usb_driver_suspend - suspend the device
+ */
+static int si470x_usb_driver_suspend(struct usb_interface *intf,
+ pm_message_t message)
+{
+ struct si470x_device *radio = usb_get_intfdata(intf);
+
+ printk(KERN_INFO DRIVER_NAME ": suspending now...\n");
+
+ cancel_delayed_work_sync(&radio->work);
+
+ return 0;
+}
+
+
+/*
+ * si470x_usb_driver_resume - resume the device
+ */
+static int si470x_usb_driver_resume(struct usb_interface *intf)
+{
+ struct si470x_device *radio = usb_get_intfdata(intf);
+
+ printk(KERN_INFO DRIVER_NAME ": resuming now...\n");
+
+ mutex_lock(&radio->lock);
+ if (radio->users && radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS)
+ schedule_delayed_work(&radio->work,
+ msecs_to_jiffies(rds_poll_time));
+ mutex_unlock(&radio->lock);
return 0;
}
@@ -1376,15 +1510,11 @@ static void si470x_usb_driver_disconnect(struct usb_interface *intf)
{
struct si470x_device *radio = usb_get_intfdata(intf);
- del_timer_sync(&radio->timer);
- flush_scheduled_work();
-
+ cancel_delayed_work_sync(&radio->work);
usb_set_intfdata(intf, NULL);
- if (radio) {
- video_unregister_device(radio->videodev);
- kfree(radio->buffer);
- kfree(radio);
- }
+ video_unregister_device(radio->videodev);
+ kfree(radio->buffer);
+ kfree(radio);
}
@@ -1392,10 +1522,13 @@ static void si470x_usb_driver_disconnect(struct usb_interface *intf)
* si470x_usb_driver - usb driver interface
*/
static struct usb_driver si470x_usb_driver = {
- .name = DRIVER_NAME,
- .probe = si470x_usb_driver_probe,
- .disconnect = si470x_usb_driver_disconnect,
- .id_table = si470x_usb_driver_id_table,
+ .name = DRIVER_NAME,
+ .probe = si470x_usb_driver_probe,
+ .disconnect = si470x_usb_driver_disconnect,
+ .suspend = si470x_usb_driver_suspend,
+ .resume = si470x_usb_driver_resume,
+ .id_table = si470x_usb_driver_id_table,
+ .supports_autosuspend = 1,
};
@@ -1409,7 +1542,7 @@ static struct usb_driver si470x_usb_driver = {
*/
static int __init si470x_module_init(void)
{
- printk(KERN_INFO DRIVER_DESC "\n");
+ printk(KERN_INFO DRIVER_DESC ", Version " DRIVER_VERSION "\n");
return usb_register(&si470x_usb_driver);
}
@@ -1429,4 +1562,4 @@ module_exit(si470x_module_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_VERSION("1.0.4");
+MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index a2e8987a619..37072a21d8c 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -4,14 +4,14 @@
menuconfig VIDEO_CAPTURE_DRIVERS
bool "Video capture adapters"
- depends on VIDEO_DEV
+ depends on VIDEO_V4L2
default y
---help---
Say Y here to enable selecting the video adapters for
webcams, analog TV, and hybrid analog/digital TV.
Some of those devices also supports FM radio.
-if VIDEO_CAPTURE_DRIVERS && VIDEO_DEV
+if VIDEO_CAPTURE_DRIVERS && VIDEO_V4L2
config VIDEO_ADV_DEBUG
bool "Enable advanced debug functionality"
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 850b8c6f457..3f209b32eea 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -10,8 +10,9 @@ msp3400-objs := msp3400-driver.o msp3400-kthreads.o
stkwebcam-objs := stk-webcam.o stk-sensor.o
-obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o \
- v4l2-int-device.o
+obj-$(CONFIG_VIDEO_DEV) += videodev.o compat_ioctl32.o v4l2-int-device.o
+
+obj-$(CONFIG_VIDEO_V4L2_COMMON) += v4l2-common.o
ifeq ($(CONFIG_VIDEO_V4L1_COMPAT),y)
obj-$(CONFIG_VIDEO_DEV) += v4l1-compat.o
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index 907dc62c178..5404fcc5276 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -2354,8 +2354,8 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv,
BUG();
}
- mutex_lock(&fh->cap.lock);
- kfree(fh->ov.clips);
+ mutex_lock(&fh->cap.vb_lock);
+ kfree(fh->ov.clips);
fh->ov.clips = clips;
fh->ov.nclips = n;
@@ -2376,7 +2376,7 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv,
bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
retval = bttv_switch_overlay(btv,fh,new);
}
- mutex_unlock(&fh->cap.lock);
+ mutex_unlock(&fh->cap.vb_lock);
return retval;
}
@@ -2576,7 +2576,7 @@ static int bttv_s_fmt_cap(struct file *file, void *priv,
fmt = format_by_fourcc(f->fmt.pix.pixelformat);
/* update our state informations */
- mutex_lock(&fh->cap.lock);
+ mutex_lock(&fh->cap.vb_lock);
fh->fmt = fmt;
fh->cap.field = f->fmt.pix.field;
fh->cap.last = V4L2_FIELD_NONE;
@@ -2585,7 +2585,7 @@ static int bttv_s_fmt_cap(struct file *file, void *priv,
btv->init.fmt = fmt;
btv->init.width = f->fmt.pix.width;
btv->init.height = f->fmt.pix.height;
- mutex_unlock(&fh->cap.lock);
+ mutex_unlock(&fh->cap.vb_lock);
return 0;
}
@@ -2611,11 +2611,11 @@ static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
unsigned int i;
struct bttv_fh *fh = priv;
- mutex_lock(&fh->cap.lock);
+ mutex_lock(&fh->cap.vb_lock);
retval = videobuf_mmap_setup(&fh->cap, gbuffers, gbufsize,
V4L2_MEMORY_MMAP);
if (retval < 0) {
- mutex_unlock(&fh->cap.lock);
+ mutex_unlock(&fh->cap.vb_lock);
return retval;
}
@@ -2627,7 +2627,7 @@ static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
for (i = 0; i < gbuffers; i++)
mbuf->offsets[i] = i * gbufsize;
- mutex_unlock(&fh->cap.lock);
+ mutex_unlock(&fh->cap.vb_lock);
return 0;
}
#endif
@@ -2756,10 +2756,11 @@ static int bttv_overlay(struct file *file, void *f, unsigned int on)
if (!check_alloc_btres(btv, fh, RESOURCE_OVERLAY))
return -EBUSY;
- mutex_lock(&fh->cap.lock);
+ mutex_lock(&fh->cap.vb_lock);
if (on) {
fh->ov.tvnorm = btv->tvnorm;
new = videobuf_pci_alloc(sizeof(*new));
+ new->crop = btv->crop[!!fh->do_crop].rect;
bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
} else {
new = NULL;
@@ -2767,7 +2768,7 @@ static int bttv_overlay(struct file *file, void *f, unsigned int on)
/* switch over */
retval = bttv_switch_overlay(btv, fh, new);
- mutex_unlock(&fh->cap.lock);
+ mutex_unlock(&fh->cap.vb_lock);
return retval;
}
@@ -2806,7 +2807,7 @@ static int bttv_s_fbuf(struct file *file, void *f,
}
/* ok, accept it */
- mutex_lock(&fh->cap.lock);
+ mutex_lock(&fh->cap.vb_lock);
btv->fbuf.base = fb->base;
btv->fbuf.fmt.width = fb->fmt.width;
btv->fbuf.fmt.height = fb->fmt.height;
@@ -2838,7 +2839,7 @@ static int bttv_s_fbuf(struct file *file, void *f,
retval = bttv_switch_overlay(btv, fh, new);
}
}
- mutex_unlock(&fh->cap.lock);
+ mutex_unlock(&fh->cap.vb_lock);
return retval;
}
@@ -3090,7 +3091,7 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop)
fh->do_crop = 1;
- mutex_lock(&fh->cap.lock);
+ mutex_lock(&fh->cap.vb_lock);
if (fh->width < c.min_scaled_width) {
fh->width = c.min_scaled_width;
@@ -3108,7 +3109,7 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop)
btv->init.height = c.max_scaled_height;
}
- mutex_unlock(&fh->cap.lock);
+ mutex_unlock(&fh->cap.vb_lock);
return 0;
}
@@ -3177,30 +3178,25 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream);
} else {
/* read() capture */
- mutex_lock(&fh->cap.lock);
+ mutex_lock(&fh->cap.vb_lock);
if (NULL == fh->cap.read_buf) {
/* need to capture a new frame */
- if (locked_btres(fh->btv,RESOURCE_VIDEO_STREAM)) {
- mutex_unlock(&fh->cap.lock);
- return POLLERR;
- }
+ if (locked_btres(fh->btv,RESOURCE_VIDEO_STREAM))
+ goto err;
fh->cap.read_buf = videobuf_pci_alloc(fh->cap.msize);
- if (NULL == fh->cap.read_buf) {
- mutex_unlock(&fh->cap.lock);
- return POLLERR;
- }
+ if (NULL == fh->cap.read_buf)
+ goto err;
fh->cap.read_buf->memory = V4L2_MEMORY_USERPTR;
field = videobuf_next_field(&fh->cap);
if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,field)) {
kfree (fh->cap.read_buf);
fh->cap.read_buf = NULL;
- mutex_unlock(&fh->cap.lock);
- return POLLERR;
+ goto err;
}
fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
fh->cap.read_off = 0;
}
- mutex_unlock(&fh->cap.lock);
+ mutex_unlock(&fh->cap.vb_lock);
buf = (struct bttv_buffer*)fh->cap.read_buf;
}
@@ -3209,6 +3205,9 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
buf->vb.state == VIDEOBUF_ERROR)
return POLLIN|POLLRDNORM;
return 0;
+err:
+ mutex_unlock(&fh->cap.vb_lock);
+ return POLLERR;
}
static int bttv_open(struct inode *inode, struct file *file)
diff --git a/drivers/media/video/bt8xx/bttv-vbi.c b/drivers/media/video/bt8xx/bttv-vbi.c
index 1f0cc79e2a3..75fa82c7c73 100644
--- a/drivers/media/video/bt8xx/bttv-vbi.c
+++ b/drivers/media/video/bt8xx/bttv-vbi.c
@@ -352,13 +352,13 @@ int bttv_s_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt)
because vbi_fmt.end counts field lines times two. */
end = max(frt->fmt.vbi.start[0], start1) * 2 + 2;
- mutex_lock(&fh->vbi.lock);
+ mutex_lock(&fh->vbi.vb_lock);
fh->vbi_fmt.fmt = frt->fmt.vbi;
fh->vbi_fmt.tvnorm = tvnorm;
fh->vbi_fmt.end = end;
- mutex_unlock(&fh->vbi.lock);
+ mutex_unlock(&fh->vbi.vb_lock);
rc = 0;
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
index 0aedbeaf94c..e357f415db0 100644
--- a/drivers/media/video/cx88/cx88-mpeg.c
+++ b/drivers/media/video/cx88/cx88-mpeg.c
@@ -609,13 +609,19 @@ static int cx8802_request_acquire(struct cx8802_driver *drv)
struct cx88_core *core = drv->core;
/* Fail a request for hardware if the device is busy. */
- if (core->active_type_id != CX88_BOARD_NONE)
+ if (core->active_type_id != CX88_BOARD_NONE &&
+ core->active_type_id != drv->type_id)
return -EBUSY;
if (drv->advise_acquire)
{
- core->active_type_id = drv->type_id;
- drv->advise_acquire(drv);
+ mutex_lock(&drv->core->lock);
+ core->active_ref++;
+ if (core->active_type_id == CX88_BOARD_NONE) {
+ core->active_type_id = drv->type_id;
+ drv->advise_acquire(drv);
+ }
+ mutex_unlock(&drv->core->lock);
mpeg_dbg(1,"%s() Post acquire GPIO=%x\n", __FUNCTION__, cx_read(MO_GP0_IO));
}
@@ -628,12 +634,14 @@ static int cx8802_request_release(struct cx8802_driver *drv)
{
struct cx88_core *core = drv->core;
- if (drv->advise_release)
+ mutex_lock(&drv->core->lock);
+ if (drv->advise_release && --core->active_ref == 0)
{
drv->advise_release(drv);
core->active_type_id = CX88_BOARD_NONE;
mpeg_dbg(1,"%s() Post release GPIO=%x\n", __FUNCTION__, cx_read(MO_GP0_IO));
}
+ mutex_unlock(&drv->core->lock);
return 0;
}
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index 4e823f2a539..37e6d2e4002 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -336,6 +336,7 @@ struct cx88_core {
/* cx88-video needs to access cx8802 for hybrid tuner pll access. */
struct cx8802_dev *dvbdev;
enum cx88_board_type active_type_id;
+ int active_ref;
};
struct cx8800_dev;
diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c
index 941357c4f3f..8c67f678266 100644
--- a/drivers/media/video/em28xx/em28xx-audio.c
+++ b/drivers/media/video/em28xx/em28xx-audio.c
@@ -35,7 +35,6 @@
#include <linux/vmalloc.h>
#include <linux/proc_fs.h>
#include <linux/module.h>
-#include <sound/driver.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -270,8 +269,11 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
dprintk("opening device and trying to acquire exclusive lock\n");
/* Sets volume, mute, etc */
+
dev->mute = 0;
+ mutex_lock(&dev->lock);
ret = em28xx_audio_analog_set(dev);
+ mutex_unlock(&dev->lock);
if (ret < 0)
goto err;
@@ -303,7 +305,9 @@ static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream)
dprintk("closing device\n");
dev->mute = 1;
+ mutex_lock(&dev->lock);
em28xx_audio_analog_set(dev);
+ mutex_unlock(&dev->lock);
if (dev->adev->users == 0 && dev->adev->shutdown == 1) {
dprintk("audio users: %d\n", dev->adev->users);
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index 2159d0160df..aae7753fef1 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -393,15 +393,15 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE2,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
};
@@ -441,6 +441,8 @@ struct usb_device_id em28xx_id_table [] = {
.driver_info = EM2820_BOARD_PINNACLE_DVC_90 },
{ USB_DEVICE(0x2040, 0x6500),
.driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 },
+ { USB_DEVICE(0x2040, 0x6502),
+ .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 },
{ USB_DEVICE(0x2040, 0x6513),
.driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 },
{ USB_DEVICE(0x0ccd, 0x0042),
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
index f6b78357f0e..7d1537cab86 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -72,7 +72,8 @@ u32 em28xx_request_buffers(struct em28xx *dev, u32 count)
const size_t imagesize = PAGE_ALIGN(dev->frame_size); /*needs to be page aligned cause the buffers can be mapped individually! */
void *buff = NULL;
u32 i;
- em28xx_coredbg("requested %i buffers with size %zi", count, imagesize);
+ em28xx_coredbg("requested %i buffers with size %zi\n",
+ count, imagesize);
if (count > EM28XX_NUM_FRAMES)
count = EM28XX_NUM_FRAMES;
@@ -150,7 +151,7 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
if (reg_debug){
printk(ret < 0 ? " failed!\n" : "%02x values: ", ret);
for (byte = 0; byte < len; byte++) {
- printk(" %02x", buf[byte]);
+ printk(" %02x", (unsigned char)buf[byte]);
}
printk("\n");
}
@@ -177,7 +178,8 @@ int em28xx_read_reg_req(struct em28xx *dev, u8 req, u16 reg)
0x0000, reg, &val, 1, HZ);
if (reg_debug)
- printk(ret < 0 ? " failed!\n" : "%02x\n", val);
+ printk(ret < 0 ? " failed!\n" :
+ "%02x\n", (unsigned char) val);
if (ret < 0)
return ret;
@@ -237,7 +239,7 @@ int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len)
* sets only some bits (specified by bitmask) of a register, by first reading
* the actual value
*/
-int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
+static int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
u8 bitmask)
{
int oldval;
@@ -254,26 +256,31 @@ int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
*/
static int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 *val)
{
- int ret;
+ int ret, i;
u8 addr = reg & 0x7f;
if ((ret = em28xx_write_regs(dev, AC97LSB_REG, val, 2)) < 0)
return ret;
if ((ret = em28xx_write_regs(dev, AC97ADDR_REG, &addr, 1)) < 0)
return ret;
- if ((ret = em28xx_read_reg(dev, AC97BUSY_REG)) < 0)
- return ret;
- else if (((u8) ret) & 0x01) {
- em28xx_warn ("AC97 command still being executed: not handled properly!\n");
+
+ /* Wait up to 50 ms for AC97 command to complete */
+ for (i = 0; i < 10; i++) {
+ if ((ret = em28xx_read_reg(dev, AC97BUSY_REG)) < 0)
+ return ret;
+ if (!((u8) ret) & 0x01)
+ return 0;
+ msleep(5);
}
+ em28xx_warn ("AC97 command still being executed: not handled properly!\n");
return 0;
}
-int em28xx_set_audio_source(struct em28xx *dev)
+static int em28xx_set_audio_source(struct em28xx *dev)
{
static char *enable = "\x08\x08";
static char *disable = "\x08\x88";
char *video = enable, *line = disable;
- int ret, no_ac97;
+ int ret;
u8 input;
if (dev->is_em2800) {
@@ -293,11 +300,9 @@ int em28xx_set_audio_source(struct em28xx *dev)
switch (dev->ctl_ainput) {
case EM28XX_AMUX_VIDEO:
input = EM28XX_AUDIO_SRC_TUNER;
- no_ac97 = 1;
break;
case EM28XX_AMUX_LINE_IN:
input = EM28XX_AUDIO_SRC_LINE;
- no_ac97 = 1;
break;
case EM28XX_AMUX_AC97_VIDEO:
input = EM28XX_AUDIO_SRC_LINE;
@@ -313,12 +318,11 @@ int em28xx_set_audio_source(struct em28xx *dev)
ret = em28xx_write_reg_bits(dev, AUDIOSRC_REG, input, 0xc0);
if (ret < 0)
return ret;
+ msleep(5);
- if (no_ac97)
- return 0;
-
- /* Sets AC97 mixer registers */
-
+ /* Sets AC97 mixer registers
+ This is seems to be needed, even for non-ac97 configs
+ */
ret = em28xx_write_ac97(dev, VIDEO_AC97, video);
if (ret < 0)
return ret;
@@ -337,9 +341,10 @@ int em28xx_audio_analog_set(struct em28xx *dev)
s[0] |= 0x1f - dev->volume;
s[1] |= 0x1f - dev->volume;
- if (dev->mute)
- s[1] |= 0x80;
+ /* Mute */
+ s[1] |= 0x80;
ret = em28xx_write_ac97(dev, MASTER_AC97, s);
+
if (ret < 0)
return ret;
@@ -357,6 +362,11 @@ int em28xx_audio_analog_set(struct em28xx *dev)
/* Selects the proper audio input */
ret = em28xx_set_audio_source(dev);
+ /* Unmute device */
+ if (!dev->mute)
+ s[1] &= ~0x80;
+ ret = em28xx_write_ac97(dev, MASTER_AC97, s);
+
return ret;
}
EXPORT_SYMBOL_GPL(em28xx_audio_analog_set);
@@ -667,7 +677,7 @@ static void em28xx_isocIrq(struct urb *urb)
continue;
}
if (urb->iso_frame_desc[i].actual_length >
- dev->max_pkt_size) {
+ urb->iso_frame_desc[i].length) {
em28xx_isocdbg("packet bigger than packet size");
continue;
}
@@ -713,8 +723,11 @@ void em28xx_uninit_isoc(struct em28xx *dev)
for (i = 0; i < EM28XX_NUM_BUFS; i++) {
if (dev->urb[i]) {
usb_kill_urb(dev->urb[i]);
- if (dev->transfer_buffer[i]){
- usb_buffer_free(dev->udev,(EM28XX_NUM_PACKETS*dev->max_pkt_size),dev->transfer_buffer[i],dev->urb[i]->transfer_dma);
+ if (dev->transfer_buffer[i]) {
+ usb_buffer_free(dev->udev,
+ dev->urb[i]->transfer_buffer_length,
+ dev->transfer_buffer[i],
+ dev->urb[i]->transfer_dma);
}
usb_free_urb(dev->urb[i]);
}
@@ -732,7 +745,10 @@ int em28xx_init_isoc(struct em28xx *dev)
{
/* change interface to 3 which allows the biggest packet sizes */
int i, errCode;
- const int sb_size = EM28XX_NUM_PACKETS * dev->max_pkt_size;
+ int sb_size;
+
+ em28xx_set_alternate(dev);
+ sb_size = EM28XX_NUM_PACKETS * dev->max_pkt_size;
/* reset streaming vars */
dev->frame_current = NULL;
@@ -741,7 +757,7 @@ int em28xx_init_isoc(struct em28xx *dev)
/* allocate urbs */
for (i = 0; i < EM28XX_NUM_BUFS; i++) {
struct urb *urb;
- int j, k;
+ int j;
/* allocate transfer buffer */
urb = usb_alloc_urb(EM28XX_NUM_PACKETS, GFP_KERNEL);
if (!urb){
@@ -749,7 +765,9 @@ int em28xx_init_isoc(struct em28xx *dev)
em28xx_uninit_isoc(dev);
return -ENOMEM;
}
- dev->transfer_buffer[i] = usb_buffer_alloc(dev->udev, sb_size, GFP_KERNEL,&urb->transfer_dma);
+ dev->transfer_buffer[i] = usb_buffer_alloc(dev->udev, sb_size,
+ GFP_KERNEL,
+ &urb->transfer_dma);
if (!dev->transfer_buffer[i]) {
em28xx_errdev
("unable to allocate %i bytes for transfer buffer %i\n",
@@ -762,22 +780,22 @@ int em28xx_init_isoc(struct em28xx *dev)
urb->dev = dev->udev;
urb->context = dev;
urb->pipe = usb_rcvisocpipe(dev->udev, 0x82);
- urb->transfer_flags = URB_ISO_ASAP;
+ urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
urb->interval = 1;
urb->transfer_buffer = dev->transfer_buffer[i];
urb->complete = em28xx_isocIrq;
urb->number_of_packets = EM28XX_NUM_PACKETS;
urb->transfer_buffer_length = sb_size;
- for (j = k = 0; j < EM28XX_NUM_PACKETS;
- j++, k += dev->max_pkt_size) {
- urb->iso_frame_desc[j].offset = k;
- urb->iso_frame_desc[j].length =
- dev->max_pkt_size;
+ for (j = 0; j < EM28XX_NUM_PACKETS; j++) {
+ urb->iso_frame_desc[j].offset = j * dev->max_pkt_size;
+ urb->iso_frame_desc[j].length = dev->max_pkt_size;
}
dev->urb[i] = urb;
}
/* submit urbs */
+ em28xx_coredbg("Submitting %d urbs of %d packets (%d each)\n",
+ EM28XX_NUM_BUFS, EM28XX_NUM_PACKETS, dev->max_pkt_size);
for (i = 0; i < EM28XX_NUM_BUFS; i++) {
errCode = usb_submit_urb(dev->urb[i], GFP_KERNEL);
if (errCode) {
@@ -794,22 +812,31 @@ int em28xx_init_isoc(struct em28xx *dev)
int em28xx_set_alternate(struct em28xx *dev)
{
int errCode, prev_alt = dev->alt;
- dev->alt = alt;
- if (dev->alt == 0) {
- int i;
- for(i=0;i< dev->num_alt; i++)
- if(dev->alt_max_pkt_size[i]>dev->alt_max_pkt_size[dev->alt])
- dev->alt=i;
- }
+ int i;
+ unsigned int min_pkt_size = dev->bytesperline+4;
+
+ /* When image size is bigger than a ceirtain value,
+ the frame size should be increased, otherwise, only
+ green screen will be received.
+ */
+ if (dev->frame_size > 720*240*2)
+ min_pkt_size *= 2;
+
+ for (i = 0; i < dev->num_alt; i++)
+ if (dev->alt_max_pkt_size[i] >= min_pkt_size)
+ break;
+ dev->alt = i;
if (dev->alt != prev_alt) {
+ em28xx_coredbg("minimum isoc packet size: %u (alt=%d)\n",
+ min_pkt_size, dev->alt);
dev->max_pkt_size = dev->alt_max_pkt_size[dev->alt];
- em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n", dev->alt,
- dev->max_pkt_size);
+ em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n",
+ dev->alt, dev->max_pkt_size);
errCode = usb_set_interface(dev->udev, 0, dev->alt);
if (errCode < 0) {
em28xx_errdev ("cannot change alternate number to %d (error=%i)\n",
- dev->alt, errCode);
+ dev->alt, errCode);
return errCode;
}
}
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index a0c33467248..4abe6701a77 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -189,7 +189,7 @@ static void video_mux(struct em28xx *dev, int index)
em28xx_i2c_call_clients(dev, VIDIOC_INT_S_AUDIO_ROUTING, &route);
}
- em28xx_set_audio_source(dev);
+ em28xx_audio_analog_set(dev);
}
/* Usage lock check functions */
@@ -830,6 +830,63 @@ static int vidioc_s_frequency(struct file *file, void *priv,
return 0;
}
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int em28xx_reg_len(int reg)
+{
+ switch (reg) {
+ case AC97LSB_REG:
+ case HSCALELOW_REG:
+ case VSCALELOW_REG:
+ return 2;
+ default:
+ return 1;
+ }
+}
+
+static int vidioc_g_register(struct file *file, void *priv,
+ struct v4l2_register *reg)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ int ret;
+
+ if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ return -EINVAL;
+
+ if (em28xx_reg_len(reg->reg) == 1) {
+ ret = em28xx_read_reg(dev, reg->reg);
+ if (ret < 0)
+ return ret;
+
+ reg->val = ret;
+ } else {
+ u64 val = 0;
+ ret = em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
+ reg->reg, (char *)&val, 2);
+ if (ret < 0)
+ return ret;
+
+ reg->val = cpu_to_le64((__u64)val);
+ }
+
+ return 0;
+}
+
+static int vidioc_s_register(struct file *file, void *priv,
+ struct v4l2_register *reg)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ u64 buf;
+
+ buf = le64_to_cpu((__u64)reg->val);
+
+ return em28xx_write_regs(dev, reg->reg, (char *)&buf,
+ em28xx_reg_len(reg->reg));
+}
+#endif
+
+
static int vidioc_cropcap(struct file *file, void *priv,
struct v4l2_cropcap *cc)
{
@@ -1295,8 +1352,6 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
filp->private_data = fh;
if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
- em28xx_set_alternate(dev);
-
dev->width = norm_maxw(dev);
dev->height = norm_maxh(dev);
dev->frame_size = dev->width * dev->height * 2;
@@ -1305,6 +1360,7 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
dev->hscale = 0;
dev->vscale = 0;
+ em28xx_set_alternate(dev);
em28xx_capture_start(dev, 1);
em28xx_resolution_set(dev);
@@ -1730,6 +1786,10 @@ static const struct video_device em28xx_video_template = {
.vidioc_s_tuner = vidioc_s_tuner,
.vidioc_g_frequency = vidioc_g_frequency,
.vidioc_s_frequency = vidioc_s_frequency,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = vidioc_g_register,
+ .vidioc_s_register = vidioc_s_register,
+#endif
.tvnorms = V4L2_STD_ALL,
.current_norm = V4L2_STD_PAL,
@@ -1752,6 +1812,10 @@ static struct video_device em28xx_radio_template = {
.vidioc_s_ctrl = vidioc_s_ctrl,
.vidioc_g_frequency = vidioc_g_frequency,
.vidioc_s_frequency = vidioc_s_frequency,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = vidioc_g_register,
+ .vidioc_s_register = vidioc_s_register,
+#endif
};
/******************************** usb interface *****************************************/
@@ -1796,10 +1860,10 @@ void em28xx_unregister_extension(struct em28xx_ops *ops)
}
EXPORT_SYMBOL(em28xx_unregister_extension);
-struct video_device *em28xx_vdev_init(struct em28xx *dev,
- const struct video_device *template,
- const int type,
- const char *type_name)
+static struct video_device *em28xx_vdev_init(struct em28xx *dev,
+ const struct video_device *template,
+ const int type,
+ const char *type_name)
{
struct video_device *vfd;
@@ -2064,6 +2128,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
snprintf(dev->name, 29, "em28xx #%d", nr);
dev->devno = nr;
dev->model = id->driver_info;
+ dev->alt = -1;
/* Checks if audio is provided by some interface */
for (i = 0; i < udev->config->desc.bNumInterfaces; i++) {
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
index f3bad0c1c51..04e0e48ecab 100644
--- a/drivers/media/video/em28xx/em28xx.h
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -33,7 +33,7 @@
#define UNSET -1
/* maximum number of em28xx boards */
-#define EM28XX_MAXBOARDS 1 /*FIXME: should be bigger */
+#define EM28XX_MAXBOARDS 4 /*FIXME: should be bigger */
/* maximum number of frames that can be queued */
#define EM28XX_NUM_FRAMES 5
@@ -345,9 +345,6 @@ int em28xx_read_reg(struct em28xx *dev, u16 reg);
int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
int len);
int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len);
-int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
- u8 bitmask);
-int em28xx_set_audio_source(struct em28xx *dev);
int em28xx_audio_analog_set(struct em28xx *dev);
int em28xx_colorlevels_set_default(struct em28xx *dev);
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 7d7f383b404..262830da08c 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -928,27 +928,38 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x03,
.inputs = {{
.name = name_tv,
.vmux = 1,
.amux = TV,
.tv = 1,
- },{
+ .gpio = 0x00,
+ }, {
.name = name_comp1,
- .vmux = 0,
- .amux = LINE2,
- },{
- .name = name_comp2,
.vmux = 3,
- .amux = LINE2,
- },{
+ .amux = LINE1,
+ .gpio = 0x02,
+ }, {
+ .name = name_comp2,
+ .vmux = 0,
+ .amux = LINE1,
+ .gpio = 0x02,
+ }, {
.name = name_svideo,
.vmux = 8,
- .amux = LINE2,
- }},
+ .amux = LINE1,
+ .gpio = 0x02,
+ } },
.radio = {
.name = name_radio,
- .amux = LINE2,
+ .amux = LINE1,
+ .gpio = 0x01,
+ },
+ .mute = {
+ .name = name_mute,
+ .amux = TV,
+ .gpio = 0x00,
},
},
[SAA7134_BOARD_BMK_MPEX_TUNER] = {
@@ -3912,6 +3923,74 @@ struct saa7134_board saa7134_boards[] = {
},
.mpeg = SAA7134_MPEG_EMPRESS,
},
+ [SAA7134_BOARD_TWINHAN_DTV_DVB_3056] = {
+ .name = "Twinhan Hybrid DTV-DVB 3056 PCI",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tuner_config = 2,
+ .mpeg = SAA7134_MPEG_DVB,
+ .gpiomask = 0x0200000,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ }, {
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ }, {
+ .name = name_svideo,
+ .vmux = 8, /* untested */
+ .amux = LINE1,
+ } },
+ .radio = {
+ .name = name_radio,
+ .amux = TV,
+ .gpio = 0x0200000,
+ },
+ },
+ [SAA7134_BOARD_GENIUS_TVGO_A11MCE] = {
+ /* Adrian Pardini <pardo.bsso@gmail.com> */
+ .name = "Genius TVGO AM11MCE",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_TNF_5335MF,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0xf000,
+ .inputs = {{
+ .name = name_tv_mono,
+ .vmux = 1,
+ .amux = LINE2,
+ .gpio = 0x0000,
+ .tv = 1,
+ }, {
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x2000,
+ .tv = 1
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ .gpio = 0x2000,
+ } },
+ .radio = {
+ .name = name_radio,
+ .amux = LINE2,
+ .gpio = 0x1000,
+ },
+ .mute = {
+ .name = name_mute,
+ .amux = LINE2,
+ .gpio = 0x6000,
+ },
+ },
};
const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -4511,6 +4590,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5168,
+ .subdevice = 0x3307, /* FlyDVB-T Hybrid Mini PCI */
+ .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
.subvendor = 0x16be,
.subdevice = 0x0007,
.driver_data = SAA7134_BOARD_MEDION_MD8800_QUADRO,
@@ -4523,6 +4608,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x16be,
+ .subdevice = 0x000d, /* triple CTX948_V1.1.1 */
+ .driver_data = SAA7134_BOARD_MEDION_MD8800_QUADRO,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
.subvendor = 0x1461,
.subdevice = 0x2c05,
.driver_data = SAA7134_BOARD_AVERMEDIA_777,
@@ -4843,7 +4934,13 @@ struct pci_device_id saa7134_pci_tbl[] = {
.device = PCI_DEVICE_ID_PHILIPS_SAA7133,
.subvendor = 0x4e42,
.subdevice = 0x3502,
- .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS
+ .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1822, /*Twinhan Technology Co. Ltd*/
+ .subdevice = 0x0022,
+ .driver_data = SAA7134_BOARD_TWINHAN_DTV_DVB_3056,
},{
/* --- boards without eeprom + subsystem ID --- */
.vendor = PCI_VENDOR_ID_PHILIPS,
@@ -4995,6 +5092,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_BEHOLD_409:
case SAA7134_BOARD_BEHOLD_505FM:
case SAA7134_BOARD_BEHOLD_507_9FM:
+ case SAA7134_BOARD_GENIUS_TVGO_A11MCE:
dev->has_remote = SAA7134_REMOTE_GPIO;
break;
case SAA7134_BOARD_FLYDVBS_LR300:
@@ -5232,7 +5330,8 @@ int saa7134_board_init2(struct saa7134_dev *dev)
case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
case SAA7134_BOARD_MEDION_MD8800_QUADRO:
- case SAA7134_BOARD_AVERMEDIA_SUPER_007:
+ case SAA7134_BOARD_AVERMEDIA_SUPER_007:
+ case SAA7134_BOARD_TWINHAN_DTV_DVB_3056:
/* this is a hybrid board, initialize to analog mode
* and configure firmware eeprom address
*/
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index a9ca5730826..ea2be9eceeb 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -779,6 +779,21 @@ static struct tda1004x_config avermedia_super_007_config = {
.request_firmware = philips_tda1004x_request_firmware
};
+static struct tda1004x_config twinhan_dtv_dvb_3056_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP01_I,
+ .if_freq = TDA10046_FREQ_045,
+ .i2c_gate = 0x42,
+ .tuner_address = 0x61,
+ .tuner_config = 2,
+ .antenna_switch = 1,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
/* ------------------------------------------------------------------
* special case: this card uses saa713x GPIO22 for the mode switch
*/
@@ -826,6 +841,7 @@ static struct tda1004x_config ads_tech_duo_config = {
static struct tda10086_config flydvbs = {
.demod_address = 0x0e,
.invert = 0,
+ .diseqc_tone = 0,
};
/* ==================================================================
@@ -940,9 +956,9 @@ static int dvb_init(struct saa7134_dev *dev)
configure_tda827x_fe(dev, &tda827x_lifeview_config);
break;
case SAA7134_BOARD_FLYDVB_TRIO:
- if(! use_frontend) { //terrestrial
+ if(! use_frontend) { /* terrestrial */
configure_tda827x_fe(dev, &lifeview_trio_config);
- } else { //satellite
+ } else { /* satellite */
dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap);
if (dev->dvb.frontend) {
if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x63,
@@ -1007,8 +1023,9 @@ static int dvb_init(struct saa7134_dev *dev)
}
break;
case SAA7134_BOARD_ASUS_EUROPA2_HYBRID:
- dev->dvb.frontend = tda10046_attach(&medion_cardbus,
- &dev->i2c_adap);
+ dev->dvb.frontend = dvb_attach(tda10046_attach,
+ &medion_cardbus,
+ &dev->i2c_adap);
if (dev->dvb.frontend) {
dev->original_demod_sleep = dev->dvb.frontend->ops.sleep;
dev->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
@@ -1044,6 +1061,9 @@ static int dvb_init(struct saa7134_dev *dev)
case SAA7134_BOARD_AVERMEDIA_SUPER_007:
configure_tda827x_fe(dev, &avermedia_super_007_config);
break;
+ case SAA7134_BOARD_TWINHAN_DTV_DVB_3056:
+ configure_tda827x_fe(dev, &twinhan_dtv_dvb_3056_config);
+ break;
default:
wprintk("Huh? unknown DVB card?\n");
break;
diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c
index b1b01fa8672..3d2ec30de22 100644
--- a/drivers/media/video/saa7134/saa7134-empress.c
+++ b/drivers/media/video/saa7134/saa7134-empress.c
@@ -87,7 +87,7 @@ static int ts_open(struct inode *inode, struct file *file)
dprintk("open minor=%d\n",minor);
err = -EBUSY;
- if (!mutex_trylock(&dev->empress_tsq.lock))
+ if (!mutex_trylock(&dev->empress_tsq.vb_lock))
goto done;
if (dev->empress_users)
goto done_up;
@@ -101,7 +101,7 @@ static int ts_open(struct inode *inode, struct file *file)
err = 0;
done_up:
- mutex_unlock(&dev->empress_tsq.lock);
+ mutex_unlock(&dev->empress_tsq.vb_lock);
done:
return err;
}
@@ -110,7 +110,6 @@ static int ts_release(struct inode *inode, struct file *file)
{
struct saa7134_dev *dev = file->private_data;
- mutex_lock(&dev->empress_tsq.lock);
videobuf_stop(&dev->empress_tsq);
videobuf_mmap_free(&dev->empress_tsq);
dev->empress_users--;
@@ -122,7 +121,6 @@ static int ts_release(struct inode *inode, struct file *file)
saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
saa_readb(SAA7134_AUDIO_MUTE_CTRL) | (1 << 6));
- mutex_unlock(&dev->empress_tsq.lock);
return 0;
}
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index 0db955c2d9b..b4188819782 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -406,6 +406,12 @@ int saa7134_input_init1(struct saa7134_dev *dev)
mask_keyup = 0x8000000;
polling = 50; //ms
break;
+ case SAA7134_BOARD_GENIUS_TVGO_A11MCE:
+ ir_codes = ir_codes_genius_tvgo_a11mce;
+ mask_keycode = 0xff;
+ mask_keydown = 0xf00000;
+ polling = 50; /* ms */
+ break;
}
if (NULL == ir_codes) {
printk("%s: Oops: IR config error [card=%d]\n",
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
index 1184d359e84..39c41ad97d0 100644
--- a/drivers/media/video/saa7134/saa7134-video.c
+++ b/drivers/media/video/saa7134/saa7134-video.c
@@ -1414,21 +1414,17 @@ video_poll(struct file *file, struct poll_table_struct *wait)
if (!list_empty(&fh->cap.stream))
buf = list_entry(fh->cap.stream.next, struct videobuf_buffer, stream);
} else {
- mutex_lock(&fh->cap.lock);
+ mutex_lock(&fh->cap.vb_lock);
if (UNSET == fh->cap.read_off) {
/* need to capture a new frame */
- if (res_locked(fh->dev,RESOURCE_VIDEO)) {
- mutex_unlock(&fh->cap.lock);
- return POLLERR;
- }
- if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,fh->cap.field)) {
- mutex_unlock(&fh->cap.lock);
- return POLLERR;
- }
+ if (res_locked(fh->dev,RESOURCE_VIDEO))
+ goto err;
+ if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,fh->cap.field))
+ goto err;
fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
fh->cap.read_off = 0;
}
- mutex_unlock(&fh->cap.lock);
+ mutex_unlock(&fh->cap.vb_lock);
buf = fh->cap.read_buf;
}
@@ -1440,6 +1436,10 @@ video_poll(struct file *file, struct poll_table_struct *wait)
buf->state == VIDEOBUF_ERROR)
return POLLIN|POLLRDNORM;
return 0;
+
+err:
+ mutex_unlock(&fh->cap.vb_lock);
+ return POLLERR;
}
static int video_release(struct inode *inode, struct file *file)
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index b88ca995faf..f940d025479 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -252,6 +252,8 @@ struct saa7134_format {
#define SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM 128
#define SAA7134_BOARD_BEHOLD_607_9FM 129
#define SAA7134_BOARD_BEHOLD_M6 130
+#define SAA7134_BOARD_TWINHAN_DTV_DVB_3056 131
+#define SAA7134_BOARD_GENIUS_TVGO_A11MCE 132
#define SAA7134_MAXBOARDS 8
#define SAA7134_INPUT_MAX 8
diff --git a/drivers/media/video/stk-sensor.c b/drivers/media/video/stk-sensor.c
index 4a9a0b62efa..e546b014d7a 100644
--- a/drivers/media/video/stk-sensor.c
+++ b/drivers/media/video/stk-sensor.c
@@ -225,7 +225,7 @@
/* Returns 0 if OK */
-int stk_sensor_outb(struct stk_camera *dev, u8 reg, u8 val)
+static int stk_sensor_outb(struct stk_camera *dev, u8 reg, u8 val)
{
int i = 0;
int tmpval = 0;
@@ -250,7 +250,7 @@ int stk_sensor_outb(struct stk_camera *dev, u8 reg, u8 val)
return 0;
}
-int stk_sensor_inb(struct stk_camera *dev, u8 reg, u8 *val)
+static int stk_sensor_inb(struct stk_camera *dev, u8 reg, u8 *val)
{
int i = 0;
int tmpval = 0;
@@ -380,7 +380,7 @@ int stk_sensor_init(struct stk_camera *dev)
STK_ERROR("Strange error reading sensor ID\n");
return -ENODEV;
}
- if (idh != 0x7F || idl != 0xA2) {
+ if (idh != 0x7f || idl != 0xa2) {
STK_ERROR("Huh? you don't have a sensor from ovt\n");
return -ENODEV;
}
@@ -409,6 +409,19 @@ static struct regval ov_fmt_uyvy[] = {
{REG_COM15, COM15_R00FF },
{0xff, 0xff}, /* END MARKER */
};
+/* V4L2_PIX_FMT_YUYV */
+static struct regval ov_fmt_yuyv[] = {
+ {REG_TSLB, 0 },
+ { 0x4f, 0x80 }, /* "matrix coefficient 1" */
+ { 0x50, 0x80 }, /* "matrix coefficient 2" */
+ { 0x51, 0 }, /* vb */
+ { 0x52, 0x22 }, /* "matrix coefficient 4" */
+ { 0x53, 0x5e }, /* "matrix coefficient 5" */
+ { 0x54, 0x80 }, /* "matrix coefficient 6" */
+ {REG_COM13, COM13_UVSAT|COM13_CMATRIX},
+ {REG_COM15, COM15_R00FF },
+ {0xff, 0xff}, /* END MARKER */
+};
/* V4L2_PIX_FMT_RGB565X rrrrrggg gggbbbbb */
static struct regval ov_fmt_rgbr[] = {
@@ -519,6 +532,10 @@ int stk_sensor_configure(struct stk_camera *dev)
com7 |= COM7_YUV;
rv = ov_fmt_uyvy;
break;
+ case V4L2_PIX_FMT_YUYV:
+ com7 |= COM7_YUV;
+ rv = ov_fmt_yuyv;
+ break;
case V4L2_PIX_FMT_RGB565:
com7 |= COM7_RGB;
rv = ov_fmt_rgbp;
diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c
index d37e5e2594b..ceba45ad029 100644
--- a/drivers/media/video/stk-webcam.c
+++ b/drivers/media/video/stk-webcam.c
@@ -63,7 +63,7 @@ static struct usb_device_id stkwebcam_table[] = {
};
MODULE_DEVICE_TABLE(usb, stkwebcam_table);
-void stk_camera_cleanup(struct kref *kref)
+static void stk_camera_cleanup(struct kref *kref)
{
struct stk_camera *dev = to_stk_camera(kref);
@@ -682,6 +682,7 @@ static int v4l_stk_open(struct inode *inode, struct file *fp)
return -ENXIO;
fp->private_data = vdev;
kref_get(&dev->kref);
+ usb_autopm_get_interface(dev->interface);
return 0;
}
@@ -703,6 +704,7 @@ static int v4l_stk_release(struct inode *inode, struct file *fp)
}
if (dev->owner != fp) {
+ usb_autopm_put_interface(dev->interface);
kref_put(&dev->kref, stk_camera_cleanup);
return 0;
}
@@ -713,6 +715,7 @@ static int v4l_stk_release(struct inode *inode, struct file *fp)
dev->owner = NULL;
+ usb_autopm_put_interface(dev->interface);
kref_put(&dev->kref, stk_camera_cleanup);
return 0;
@@ -993,6 +996,10 @@ static int stk_vidioc_enum_fmt_cap(struct file *filp,
fmtd->pixelformat = V4L2_PIX_FMT_SBGGR8;
strcpy(fmtd->description, "Raw bayer");
break;
+ case 4:
+ fmtd->pixelformat = V4L2_PIX_FMT_YUYV;
+ strcpy(fmtd->description, "yuv4:2:2");
+ break;
default:
return -EINVAL;
}
@@ -1048,6 +1055,7 @@ static int stk_vidioc_try_fmt_cap(struct file *filp,
case V4L2_PIX_FMT_RGB565:
case V4L2_PIX_FMT_RGB565X:
case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_SBGGR8:
break;
default:
@@ -1080,6 +1088,42 @@ static int stk_vidioc_try_fmt_cap(struct file *filp,
return 0;
}
+static int stk_setup_format(struct stk_camera *dev)
+{
+ int i = 0;
+ int depth;
+ if (dev->vsettings.palette == V4L2_PIX_FMT_SBGGR8)
+ depth = 1;
+ else
+ depth = 2;
+ while (stk_sizes[i].m != dev->vsettings.mode
+ && i < ARRAY_SIZE(stk_sizes))
+ i++;
+ if (i == ARRAY_SIZE(stk_sizes)) {
+ STK_ERROR("Something is broken in %s\n", __FUNCTION__);
+ return -EFAULT;
+ }
+ /* This registers controls some timings, not sure of what. */
+ stk_camera_write_reg(dev, 0x001b, 0x0e);
+ if (dev->vsettings.mode == MODE_SXGA)
+ stk_camera_write_reg(dev, 0x001c, 0x0e);
+ else
+ stk_camera_write_reg(dev, 0x001c, 0x46);
+ /*
+ * Registers 0x0115 0x0114 are the size of each line (bytes),
+ * regs 0x0117 0x0116 are the heigth of the image.
+ */
+ stk_camera_write_reg(dev, 0x0115,
+ ((stk_sizes[i].w * depth) >> 8) & 0xff);
+ stk_camera_write_reg(dev, 0x0114,
+ (stk_sizes[i].w * depth) & 0xff);
+ stk_camera_write_reg(dev, 0x0117,
+ (stk_sizes[i].h >> 8) & 0xff);
+ stk_camera_write_reg(dev, 0x0116,
+ stk_sizes[i].h & 0xff);
+ return stk_sensor_configure(dev);
+}
+
static int stk_vidioc_s_fmt_cap(struct file *filp,
void *priv, struct v4l2_format *fmtd)
{
@@ -1094,10 +1138,10 @@ static int stk_vidioc_s_fmt_cap(struct file *filp,
return -EBUSY;
if (dev->owner && dev->owner != filp)
return -EBUSY;
- dev->owner = filp;
ret = stk_vidioc_try_fmt_cap(filp, priv, fmtd);
if (ret)
return ret;
+ dev->owner = filp;
dev->vsettings.palette = fmtd->fmt.pix.pixelformat;
stk_free_buffers(dev);
@@ -1105,25 +1149,7 @@ static int stk_vidioc_s_fmt_cap(struct file *filp,
dev->vsettings.mode = stk_sizes[fmtd->fmt.pix.priv].m;
stk_initialise(dev);
- /* This registers controls some timings, not sure of what. */
- stk_camera_write_reg(dev, 0x001b, 0x0e);
- if (dev->vsettings.mode == MODE_SXGA)
- stk_camera_write_reg(dev, 0x001c, 0x0e);
- else
- stk_camera_write_reg(dev, 0x001c, 0x46);
- /*
- * Registers 0x0115 0x0114 are the size of each line (bytes),
- * regs 0x0117 0x0116 are the heigth of the image.
- */
- stk_camera_write_reg(dev, 0x0115,
- (fmtd->fmt.pix.bytesperline >> 8) & 0xff);
- stk_camera_write_reg(dev, 0x0114,
- fmtd->fmt.pix.bytesperline & 0xff);
- stk_camera_write_reg(dev, 0x0117,
- (fmtd->fmt.pix.height >> 8) & 0xff);
- stk_camera_write_reg(dev, 0x0116,
- fmtd->fmt.pix.height & 0xff);
- return stk_sensor_configure(dev);
+ return stk_setup_format(dev);
}
static int stk_vidioc_reqbufs(struct file *filp,
@@ -1288,6 +1314,9 @@ static struct file_operations v4l_stk_fops = {
.poll = v4l_stk_poll,
.mmap = v4l_stk_mmap,
.ioctl = video_ioctl2,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = v4l_compat_ioctl32,
+#endif
.llseek = no_llseek
};
@@ -1403,7 +1432,7 @@ static int stk_camera_probe(struct usb_interface *interface,
dev->vsettings.brightness = 0x7fff;
dev->vsettings.palette = V4L2_PIX_FMT_RGB565;
dev->vsettings.mode = MODE_VGA;
- dev->frame_size = 640*480*2;
+ dev->frame_size = 640 * 480 * 2;
INIT_LIST_HEAD(&dev->sio_avail);
INIT_LIST_HEAD(&dev->sio_full);
@@ -1417,6 +1446,7 @@ static int stk_camera_probe(struct usb_interface *interface,
}
stk_create_sysfs_files(&dev->vdev);
+ usb_autopm_enable(dev->interface);
return 0;
}
@@ -1434,11 +1464,41 @@ static void stk_camera_disconnect(struct usb_interface *interface)
kref_put(&dev->kref, stk_camera_cleanup);
}
+#ifdef CONFIG_PM
+int stk_camera_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct stk_camera *dev = usb_get_intfdata(intf);
+ if (is_streaming(dev)) {
+ stk_stop_stream(dev);
+ /* yes, this is ugly */
+ set_streaming(dev);
+ }
+ return 0;
+}
+
+int stk_camera_resume(struct usb_interface *intf)
+{
+ struct stk_camera *dev = usb_get_intfdata(intf);
+ if (!is_initialised(dev))
+ return 0;
+ unset_initialised(dev);
+ stk_initialise(dev);
+ stk_setup_format(dev);
+ if (is_streaming(dev))
+ stk_start_stream(dev);
+ return 0;
+}
+#endif
+
static struct usb_driver stk_camera_driver = {
.name = "stkwebcam",
.probe = stk_camera_probe,
.disconnect = stk_camera_disconnect,
.id_table = stkwebcam_table,
+#ifdef CONFIG_PM
+ .suspend = stk_camera_suspend,
+ .resume = stk_camera_resume,
+#endif
};
diff --git a/drivers/media/video/stk-webcam.h b/drivers/media/video/stk-webcam.h
index 7e989d1ac1e..df4dfefc532 100644
--- a/drivers/media/video/stk-webcam.h
+++ b/drivers/media/video/stk-webcam.h
@@ -79,6 +79,7 @@ enum stk_status {
#define unset_present(dev) ((dev)->status &= \
~(S_PRESENT|S_INITIALISED|S_STREAMING))
#define set_initialised(dev) ((dev)->status |= S_INITIALISED)
+#define unset_initialised(dev) ((dev)->status &= ~S_INITIALISED)
#define set_memallocd(dev) ((dev)->status |= S_MEMALLOCD)
#define unset_memallocd(dev) ((dev)->status &= ~S_MEMALLOCD)
#define set_streaming(dev) ((dev)->status |= S_STREAMING)
@@ -127,8 +128,6 @@ void stk_camera_delete(struct kref *);
int stk_camera_write_reg(struct stk_camera *, u16, u8);
int stk_camera_read_reg(struct stk_camera *, u16, int *);
-int stk_sensor_outb(struct stk_camera *dev, u8 reg, u8 val);
-int stk_sensor_inb(struct stk_camera *dev, u8 reg, u8 *val);
int stk_sensor_init(struct stk_camera *);
int stk_sensor_configure(struct stk_camera *);
int stk_sensor_sleep(struct stk_camera *dev);
diff --git a/drivers/media/video/tcm825x.c b/drivers/media/video/tcm825x.c
index 41cd6a0b048..fb895f6684a 100644
--- a/drivers/media/video/tcm825x.c
+++ b/drivers/media/video/tcm825x.c
@@ -851,7 +851,7 @@ static int tcm825x_probe(struct i2c_client *client)
sensor->platform_data = client->dev.platform_data;
if (sensor->platform_data == NULL
- && !sensor->platform_data->is_okay())
+ || !sensor->platform_data->is_okay())
return -ENODEV;
sensor->v4l2_int_device = &tcm825x_int_device;
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index ba538f6fbcc..78a09a2a485 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -1038,7 +1038,7 @@ static int tuner_resume(struct i2c_client *c)
/* ---------------------------------------------------------------------- */
-LIST_HEAD(tuner_list);
+static LIST_HEAD(tuner_list);
/* Search for existing radio and/or TV tuners on the given I2C adapter.
Note that when this function is called from tuner_probe you can be
diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c
index f191f6a4807..50cf876f020 100644
--- a/drivers/media/video/tuner-xc2028.c
+++ b/drivers/media/video/tuner-xc2028.c
@@ -754,6 +754,9 @@ skip_std_specific:
goto check_device;
}
+ if (new_fw.type & FM)
+ goto check_device;
+
/* Load SCODE firmware, if exists */
tuner_dbg("Trying to load scode %d\n", new_fw.scode_nr);
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
index a75560540e7..01ebcec040c 100644
--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/video/tvaudio.c
@@ -1571,14 +1571,14 @@ static int tvaudio_get_ctrl(struct CHIPSTATE *chip,
ctrl->value=chip->muted;
return 0;
case V4L2_CID_AUDIO_VOLUME:
- if (!desc->flags & CHIP_HAS_VOLUME)
+ if (!(desc->flags & CHIP_HAS_VOLUME))
break;
ctrl->value = max(chip->left,chip->right);
return 0;
case V4L2_CID_AUDIO_BALANCE:
{
int volume;
- if (!desc->flags & CHIP_HAS_VOLUME)
+ if (!(desc->flags & CHIP_HAS_VOLUME))
break;
volume = max(chip->left,chip->right);
if (volume)
@@ -1621,7 +1621,7 @@ static int tvaudio_set_ctrl(struct CHIPSTATE *chip,
{
int volume,balance;
- if (!desc->flags & CHIP_HAS_VOLUME)
+ if (!(desc->flags & CHIP_HAS_VOLUME))
break;
volume = max(chip->left,chip->right);
@@ -1642,7 +1642,7 @@ static int tvaudio_set_ctrl(struct CHIPSTATE *chip,
case V4L2_CID_AUDIO_BALANCE:
{
int volume, balance;
- if (!desc->flags & CHIP_HAS_VOLUME)
+ if (!(desc->flags & CHIP_HAS_VOLUME))
break;
volume = max(chip->left,chip->right);
@@ -1702,7 +1702,7 @@ static int chip_command(struct i2c_client *client,
break;
case V4L2_CID_AUDIO_VOLUME:
case V4L2_CID_AUDIO_BALANCE:
- if (!desc->flags & CHIP_HAS_VOLUME)
+ if (!(desc->flags & CHIP_HAS_VOLUME))
return -EINVAL;
break;
case V4L2_CID_AUDIO_BASS:
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
index 0b8fbad3c72..dc0da44a5af 100644
--- a/drivers/media/video/tveeprom.c
+++ b/drivers/media/video/tveeprom.c
@@ -242,7 +242,7 @@ hauppauge_tuner[] =
{ TUNER_ABSENT, "TCL M2523_3DBH_E"},
{ TUNER_ABSENT, "TCL M2523_3DIH_E"},
{ TUNER_ABSENT, "TCL MFPE05_2_U"},
- { TUNER_ABSENT, "Philips FMD1216MEX"},
+ { TUNER_PHILIPS_FMD1216ME_MK3, "Philips FMD1216MEX"},
{ TUNER_ABSENT, "Philips FRH2036B"},
{ TUNER_ABSENT, "Panasonic ENGF75_01GF"},
{ TUNER_ABSENT, "MaxLinear MXL5005"},
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index c056ff6d810..34deb68ae56 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -56,7 +56,6 @@
#include <asm/pgtable.h>
#include <asm/io.h>
#include <asm/div64.h>
-#include <linux/video_decoder.h>
#define __OLD_VIDIOC_ /* To allow fixing old calls*/
#include <media/v4l2-common.h>
#include <media/v4l2-chip-ident.h>
@@ -82,108 +81,6 @@ MODULE_LICENSE("GPL");
*/
-char *v4l2_norm_to_name(v4l2_std_id id)
-{
- char *name;
- u32 myid = id;
-
- /* HACK: ppc32 architecture doesn't have __ucmpdi2 function to handle
- 64 bit comparations. So, on that architecture, with some gcc variants,
- compilation fails. Currently, the max value is 30bit wide.
- */
- BUG_ON(myid != id);
-
- switch (myid) {
- case V4L2_STD_PAL:
- name="PAL"; break;
- case V4L2_STD_PAL_BG:
- name="PAL-BG"; break;
- case V4L2_STD_PAL_DK:
- name="PAL-DK"; break;
- case V4L2_STD_PAL_B:
- name="PAL-B"; break;
- case V4L2_STD_PAL_B1:
- name="PAL-B1"; break;
- case V4L2_STD_PAL_G:
- name="PAL-G"; break;
- case V4L2_STD_PAL_H:
- name="PAL-H"; break;
- case V4L2_STD_PAL_I:
- name="PAL-I"; break;
- case V4L2_STD_PAL_D:
- name="PAL-D"; break;
- case V4L2_STD_PAL_D1:
- name="PAL-D1"; break;
- case V4L2_STD_PAL_K:
- name="PAL-K"; break;
- case V4L2_STD_PAL_M:
- name="PAL-M"; break;
- case V4L2_STD_PAL_N:
- name="PAL-N"; break;
- case V4L2_STD_PAL_Nc:
- name="PAL-Nc"; break;
- case V4L2_STD_PAL_60:
- name="PAL-60"; break;
- case V4L2_STD_NTSC:
- name="NTSC"; break;
- case V4L2_STD_NTSC_M:
- name="NTSC-M"; break;
- case V4L2_STD_NTSC_M_JP:
- name="NTSC-M-JP"; break;
- case V4L2_STD_NTSC_443:
- name="NTSC-443"; break;
- case V4L2_STD_NTSC_M_KR:
- name="NTSC-M-KR"; break;
- case V4L2_STD_SECAM:
- name="SECAM"; break;
- case V4L2_STD_SECAM_DK:
- name="SECAM-DK"; break;
- case V4L2_STD_SECAM_B:
- name="SECAM-B"; break;
- case V4L2_STD_SECAM_D:
- name="SECAM-D"; break;
- case V4L2_STD_SECAM_G:
- name="SECAM-G"; break;
- case V4L2_STD_SECAM_H:
- name="SECAM-H"; break;
- case V4L2_STD_SECAM_K:
- name="SECAM-K"; break;
- case V4L2_STD_SECAM_K1:
- name="SECAM-K1"; break;
- case V4L2_STD_SECAM_L:
- name="SECAM-L"; break;
- case V4L2_STD_SECAM_LC:
- name="SECAM-LC"; break;
- default:
- name="Unknown"; break;
- }
-
- return name;
-}
-
-/* Fill in the fields of a v4l2_standard structure according to the
- 'id' and 'transmission' parameters. Returns negative on error. */
-int v4l2_video_std_construct(struct v4l2_standard *vs,
- int id, char *name)
-{
- u32 index = vs->index;
-
- memset(vs, 0, sizeof(struct v4l2_standard));
- vs->index = index;
- vs->id = id;
- if (id & V4L2_STD_525_60) {
- vs->frameperiod.numerator = 1001;
- vs->frameperiod.denominator = 30000;
- vs->framelines = 525;
- } else {
- vs->frameperiod.numerator = 1;
- vs->frameperiod.denominator = 25;
- vs->framelines = 625;
- }
- strlcpy(vs->name,name,sizeof(vs->name));
- return 0;
-}
-
/* ----------------------------------------------------------------- */
/* priority handling */
@@ -196,6 +93,7 @@ int v4l2_prio_init(struct v4l2_prio_state *global)
memset(global,0,sizeof(*global));
return 0;
}
+EXPORT_SYMBOL(v4l2_prio_init);
int v4l2_prio_change(struct v4l2_prio_state *global, enum v4l2_priority *local,
enum v4l2_priority new)
@@ -211,11 +109,13 @@ int v4l2_prio_change(struct v4l2_prio_state *global, enum v4l2_priority *local,
*local = new;
return 0;
}
+EXPORT_SYMBOL(v4l2_prio_change);
int v4l2_prio_open(struct v4l2_prio_state *global, enum v4l2_priority *local)
{
return v4l2_prio_change(global,local,V4L2_PRIORITY_DEFAULT);
}
+EXPORT_SYMBOL(v4l2_prio_open);
int v4l2_prio_close(struct v4l2_prio_state *global, enum v4l2_priority *local)
{
@@ -223,6 +123,7 @@ int v4l2_prio_close(struct v4l2_prio_state *global, enum v4l2_priority *local)
atomic_dec(&global->prios[*local]);
return 0;
}
+EXPORT_SYMBOL(v4l2_prio_close);
enum v4l2_priority v4l2_prio_max(struct v4l2_prio_state *global)
{
@@ -234,6 +135,7 @@ enum v4l2_priority v4l2_prio_max(struct v4l2_prio_state *global)
return V4L2_PRIORITY_BACKGROUND;
return V4L2_PRIORITY_UNSET;
}
+EXPORT_SYMBOL(v4l2_prio_max);
int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority *local)
{
@@ -241,225 +143,7 @@ int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority *local)
return -EBUSY;
return 0;
}
-
-
-/* ----------------------------------------------------------------- */
-/* some arrays for pretty-printing debug messages of enum types */
-
-char *v4l2_field_names[] = {
- [V4L2_FIELD_ANY] = "any",
- [V4L2_FIELD_NONE] = "none",
- [V4L2_FIELD_TOP] = "top",
- [V4L2_FIELD_BOTTOM] = "bottom",
- [V4L2_FIELD_INTERLACED] = "interlaced",
- [V4L2_FIELD_SEQ_TB] = "seq-tb",
- [V4L2_FIELD_SEQ_BT] = "seq-bt",
- [V4L2_FIELD_ALTERNATE] = "alternate",
- [V4L2_FIELD_INTERLACED_TB] = "interlaced-tb",
- [V4L2_FIELD_INTERLACED_BT] = "interlaced-bt",
-};
-
-char *v4l2_type_names[] = {
- [V4L2_BUF_TYPE_VIDEO_CAPTURE] = "video-cap",
- [V4L2_BUF_TYPE_VIDEO_OVERLAY] = "video-over",
- [V4L2_BUF_TYPE_VIDEO_OUTPUT] = "video-out",
- [V4L2_BUF_TYPE_VBI_CAPTURE] = "vbi-cap",
- [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out",
- [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-cap",
- [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "sliced-vbi-out",
- [V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "video-out-over",
-};
-
-
-#define prt_names(a,arr) (((a)>=0)&&((a)<ARRAY_SIZE(arr)))?arr[a]:"unknown"
-
-/* ------------------------------------------------------------------ */
-/* debug help functions */
-
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-static const char *v4l1_ioctls[] = {
- [_IOC_NR(VIDIOCGCAP)] = "VIDIOCGCAP",
- [_IOC_NR(VIDIOCGCHAN)] = "VIDIOCGCHAN",
- [_IOC_NR(VIDIOCSCHAN)] = "VIDIOCSCHAN",
- [_IOC_NR(VIDIOCGTUNER)] = "VIDIOCGTUNER",
- [_IOC_NR(VIDIOCSTUNER)] = "VIDIOCSTUNER",
- [_IOC_NR(VIDIOCGPICT)] = "VIDIOCGPICT",
- [_IOC_NR(VIDIOCSPICT)] = "VIDIOCSPICT",
- [_IOC_NR(VIDIOCCAPTURE)] = "VIDIOCCAPTURE",
- [_IOC_NR(VIDIOCGWIN)] = "VIDIOCGWIN",
- [_IOC_NR(VIDIOCSWIN)] = "VIDIOCSWIN",
- [_IOC_NR(VIDIOCGFBUF)] = "VIDIOCGFBUF",
- [_IOC_NR(VIDIOCSFBUF)] = "VIDIOCSFBUF",
- [_IOC_NR(VIDIOCKEY)] = "VIDIOCKEY",
- [_IOC_NR(VIDIOCGFREQ)] = "VIDIOCGFREQ",
- [_IOC_NR(VIDIOCSFREQ)] = "VIDIOCSFREQ",
- [_IOC_NR(VIDIOCGAUDIO)] = "VIDIOCGAUDIO",
- [_IOC_NR(VIDIOCSAUDIO)] = "VIDIOCSAUDIO",
- [_IOC_NR(VIDIOCSYNC)] = "VIDIOCSYNC",
- [_IOC_NR(VIDIOCMCAPTURE)] = "VIDIOCMCAPTURE",
- [_IOC_NR(VIDIOCGMBUF)] = "VIDIOCGMBUF",
- [_IOC_NR(VIDIOCGUNIT)] = "VIDIOCGUNIT",
- [_IOC_NR(VIDIOCGCAPTURE)] = "VIDIOCGCAPTURE",
- [_IOC_NR(VIDIOCSCAPTURE)] = "VIDIOCSCAPTURE",
- [_IOC_NR(VIDIOCSPLAYMODE)] = "VIDIOCSPLAYMODE",
- [_IOC_NR(VIDIOCSWRITEMODE)] = "VIDIOCSWRITEMODE",
- [_IOC_NR(VIDIOCGPLAYINFO)] = "VIDIOCGPLAYINFO",
- [_IOC_NR(VIDIOCSMICROCODE)] = "VIDIOCSMICROCODE",
- [_IOC_NR(VIDIOCGVBIFMT)] = "VIDIOCGVBIFMT",
- [_IOC_NR(VIDIOCSVBIFMT)] = "VIDIOCSVBIFMT"
-};
-#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls)
-#endif
-
-static const char *v4l2_ioctls[] = {
- [_IOC_NR(VIDIOC_QUERYCAP)] = "VIDIOC_QUERYCAP",
- [_IOC_NR(VIDIOC_RESERVED)] = "VIDIOC_RESERVED",
- [_IOC_NR(VIDIOC_ENUM_FMT)] = "VIDIOC_ENUM_FMT",
- [_IOC_NR(VIDIOC_G_FMT)] = "VIDIOC_G_FMT",
- [_IOC_NR(VIDIOC_S_FMT)] = "VIDIOC_S_FMT",
- [_IOC_NR(VIDIOC_REQBUFS)] = "VIDIOC_REQBUFS",
- [_IOC_NR(VIDIOC_QUERYBUF)] = "VIDIOC_QUERYBUF",
- [_IOC_NR(VIDIOC_G_FBUF)] = "VIDIOC_G_FBUF",
- [_IOC_NR(VIDIOC_S_FBUF)] = "VIDIOC_S_FBUF",
- [_IOC_NR(VIDIOC_OVERLAY)] = "VIDIOC_OVERLAY",
- [_IOC_NR(VIDIOC_QBUF)] = "VIDIOC_QBUF",
- [_IOC_NR(VIDIOC_DQBUF)] = "VIDIOC_DQBUF",
- [_IOC_NR(VIDIOC_STREAMON)] = "VIDIOC_STREAMON",
- [_IOC_NR(VIDIOC_STREAMOFF)] = "VIDIOC_STREAMOFF",
- [_IOC_NR(VIDIOC_G_PARM)] = "VIDIOC_G_PARM",
- [_IOC_NR(VIDIOC_S_PARM)] = "VIDIOC_S_PARM",
- [_IOC_NR(VIDIOC_G_STD)] = "VIDIOC_G_STD",
- [_IOC_NR(VIDIOC_S_STD)] = "VIDIOC_S_STD",
- [_IOC_NR(VIDIOC_ENUMSTD)] = "VIDIOC_ENUMSTD",
- [_IOC_NR(VIDIOC_ENUMINPUT)] = "VIDIOC_ENUMINPUT",
- [_IOC_NR(VIDIOC_G_CTRL)] = "VIDIOC_G_CTRL",
- [_IOC_NR(VIDIOC_S_CTRL)] = "VIDIOC_S_CTRL",
- [_IOC_NR(VIDIOC_G_TUNER)] = "VIDIOC_G_TUNER",
- [_IOC_NR(VIDIOC_S_TUNER)] = "VIDIOC_S_TUNER",
- [_IOC_NR(VIDIOC_G_AUDIO)] = "VIDIOC_G_AUDIO",
- [_IOC_NR(VIDIOC_S_AUDIO)] = "VIDIOC_S_AUDIO",
- [_IOC_NR(VIDIOC_QUERYCTRL)] = "VIDIOC_QUERYCTRL",
- [_IOC_NR(VIDIOC_QUERYMENU)] = "VIDIOC_QUERYMENU",
- [_IOC_NR(VIDIOC_G_INPUT)] = "VIDIOC_G_INPUT",
- [_IOC_NR(VIDIOC_S_INPUT)] = "VIDIOC_S_INPUT",
- [_IOC_NR(VIDIOC_G_OUTPUT)] = "VIDIOC_G_OUTPUT",
- [_IOC_NR(VIDIOC_S_OUTPUT)] = "VIDIOC_S_OUTPUT",
- [_IOC_NR(VIDIOC_ENUMOUTPUT)] = "VIDIOC_ENUMOUTPUT",
- [_IOC_NR(VIDIOC_G_AUDOUT)] = "VIDIOC_G_AUDOUT",
- [_IOC_NR(VIDIOC_S_AUDOUT)] = "VIDIOC_S_AUDOUT",
- [_IOC_NR(VIDIOC_G_MODULATOR)] = "VIDIOC_G_MODULATOR",
- [_IOC_NR(VIDIOC_S_MODULATOR)] = "VIDIOC_S_MODULATOR",
- [_IOC_NR(VIDIOC_G_FREQUENCY)] = "VIDIOC_G_FREQUENCY",
- [_IOC_NR(VIDIOC_S_FREQUENCY)] = "VIDIOC_S_FREQUENCY",
- [_IOC_NR(VIDIOC_CROPCAP)] = "VIDIOC_CROPCAP",
- [_IOC_NR(VIDIOC_G_CROP)] = "VIDIOC_G_CROP",
- [_IOC_NR(VIDIOC_S_CROP)] = "VIDIOC_S_CROP",
- [_IOC_NR(VIDIOC_G_JPEGCOMP)] = "VIDIOC_G_JPEGCOMP",
- [_IOC_NR(VIDIOC_S_JPEGCOMP)] = "VIDIOC_S_JPEGCOMP",
- [_IOC_NR(VIDIOC_QUERYSTD)] = "VIDIOC_QUERYSTD",
- [_IOC_NR(VIDIOC_TRY_FMT)] = "VIDIOC_TRY_FMT",
- [_IOC_NR(VIDIOC_ENUMAUDIO)] = "VIDIOC_ENUMAUDIO",
- [_IOC_NR(VIDIOC_ENUMAUDOUT)] = "VIDIOC_ENUMAUDOUT",
- [_IOC_NR(VIDIOC_G_PRIORITY)] = "VIDIOC_G_PRIORITY",
- [_IOC_NR(VIDIOC_S_PRIORITY)] = "VIDIOC_S_PRIORITY",
- [_IOC_NR(VIDIOC_G_SLICED_VBI_CAP)] = "VIDIOC_G_SLICED_VBI_CAP",
- [_IOC_NR(VIDIOC_LOG_STATUS)] = "VIDIOC_LOG_STATUS",
- [_IOC_NR(VIDIOC_G_EXT_CTRLS)] = "VIDIOC_G_EXT_CTRLS",
- [_IOC_NR(VIDIOC_S_EXT_CTRLS)] = "VIDIOC_S_EXT_CTRLS",
- [_IOC_NR(VIDIOC_TRY_EXT_CTRLS)] = "VIDIOC_TRY_EXT_CTRLS",
-#if 1
- [_IOC_NR(VIDIOC_ENUM_FRAMESIZES)] = "VIDIOC_ENUM_FRAMESIZES",
- [_IOC_NR(VIDIOC_ENUM_FRAMEINTERVALS)] = "VIDIOC_ENUM_FRAMEINTERVALS",
- [_IOC_NR(VIDIOC_G_ENC_INDEX)] = "VIDIOC_G_ENC_INDEX",
- [_IOC_NR(VIDIOC_ENCODER_CMD)] = "VIDIOC_ENCODER_CMD",
- [_IOC_NR(VIDIOC_TRY_ENCODER_CMD)] = "VIDIOC_TRY_ENCODER_CMD",
-
- [_IOC_NR(VIDIOC_DBG_S_REGISTER)] = "VIDIOC_DBG_S_REGISTER",
- [_IOC_NR(VIDIOC_DBG_G_REGISTER)] = "VIDIOC_DBG_G_REGISTER",
-
- [_IOC_NR(VIDIOC_G_CHIP_IDENT)] = "VIDIOC_G_CHIP_IDENT",
-#endif
-};
-#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
-
-static const char *v4l2_int_ioctls[] = {
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- [_IOC_NR(DECODER_GET_CAPABILITIES)] = "DECODER_GET_CAPABILITIES",
- [_IOC_NR(DECODER_GET_STATUS)] = "DECODER_GET_STATUS",
- [_IOC_NR(DECODER_SET_NORM)] = "DECODER_SET_NORM",
- [_IOC_NR(DECODER_SET_INPUT)] = "DECODER_SET_INPUT",
- [_IOC_NR(DECODER_SET_OUTPUT)] = "DECODER_SET_OUTPUT",
- [_IOC_NR(DECODER_ENABLE_OUTPUT)] = "DECODER_ENABLE_OUTPUT",
- [_IOC_NR(DECODER_SET_PICTURE)] = "DECODER_SET_PICTURE",
- [_IOC_NR(DECODER_SET_GPIO)] = "DECODER_SET_GPIO",
- [_IOC_NR(DECODER_INIT)] = "DECODER_INIT",
- [_IOC_NR(DECODER_SET_VBI_BYPASS)] = "DECODER_SET_VBI_BYPASS",
- [_IOC_NR(DECODER_DUMP)] = "DECODER_DUMP",
-#endif
- [_IOC_NR(AUDC_SET_RADIO)] = "AUDC_SET_RADIO",
-
- [_IOC_NR(TUNER_SET_TYPE_ADDR)] = "TUNER_SET_TYPE_ADDR",
- [_IOC_NR(TUNER_SET_STANDBY)] = "TUNER_SET_STANDBY",
- [_IOC_NR(TUNER_SET_CONFIG)] = "TUNER_SET_CONFIG",
-
- [_IOC_NR(VIDIOC_INT_S_TUNER_MODE)] = "VIDIOC_INT_S_TUNER_MODE",
- [_IOC_NR(VIDIOC_INT_RESET)] = "VIDIOC_INT_RESET",
- [_IOC_NR(VIDIOC_INT_AUDIO_CLOCK_FREQ)] = "VIDIOC_INT_AUDIO_CLOCK_FREQ",
- [_IOC_NR(VIDIOC_INT_DECODE_VBI_LINE)] = "VIDIOC_INT_DECODE_VBI_LINE",
- [_IOC_NR(VIDIOC_INT_S_VBI_DATA)] = "VIDIOC_INT_S_VBI_DATA",
- [_IOC_NR(VIDIOC_INT_G_VBI_DATA)] = "VIDIOC_INT_G_VBI_DATA",
- [_IOC_NR(VIDIOC_INT_I2S_CLOCK_FREQ)] = "VIDIOC_INT_I2S_CLOCK_FREQ",
- [_IOC_NR(VIDIOC_INT_S_STANDBY)] = "VIDIOC_INT_S_STANDBY",
- [_IOC_NR(VIDIOC_INT_S_AUDIO_ROUTING)] = "VIDIOC_INT_S_AUDIO_ROUTING",
- [_IOC_NR(VIDIOC_INT_G_AUDIO_ROUTING)] = "VIDIOC_INT_G_AUDIO_ROUTING",
- [_IOC_NR(VIDIOC_INT_S_VIDEO_ROUTING)] = "VIDIOC_INT_S_VIDEO_ROUTING",
- [_IOC_NR(VIDIOC_INT_G_VIDEO_ROUTING)] = "VIDIOC_INT_G_VIDEO_ROUTING",
- [_IOC_NR(VIDIOC_INT_S_CRYSTAL_FREQ)] = "VIDIOC_INT_S_CRYSTAL_FREQ",
- [_IOC_NR(VIDIOC_INT_INIT)] = "VIDIOC_INT_INIT",
- [_IOC_NR(VIDIOC_INT_G_STD_OUTPUT)] = "VIDIOC_INT_G_STD_OUTPUT",
- [_IOC_NR(VIDIOC_INT_S_STD_OUTPUT)] = "VIDIOC_INT_S_STD_OUTPUT",
-};
-#define V4L2_INT_IOCTLS ARRAY_SIZE(v4l2_int_ioctls)
-
-
-/* Common ioctl debug function. This function can be used by
- external ioctl messages as well as internal V4L ioctl */
-void v4l_printk_ioctl(unsigned int cmd)
-{
- char *dir;
-
- switch (_IOC_DIR(cmd)) {
- case _IOC_NONE: dir = "--"; break;
- case _IOC_READ: dir = "r-"; break;
- case _IOC_WRITE: dir = "-w"; break;
- case _IOC_READ | _IOC_WRITE: dir = "rw"; break;
- default: dir = "*ERR*"; break;
- }
- switch (_IOC_TYPE(cmd)) {
- case 'd':
- printk("v4l2_int ioctl %s, dir=%s (0x%08x)\n",
- (_IOC_NR(cmd) < V4L2_INT_IOCTLS) ?
- v4l2_int_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd);
- break;
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- case 'v':
- printk("v4l1 ioctl %s, dir=%s (0x%08x)\n",
- (_IOC_NR(cmd) < V4L1_IOCTLS) ?
- v4l1_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd);
- break;
-#endif
- case 'V':
- printk("v4l2 ioctl %s, dir=%s (0x%08x)\n",
- (_IOC_NR(cmd) < V4L2_IOCTLS) ?
- v4l2_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd);
- break;
-
- default:
- printk("unknown ioctl '%c', dir=%s, #%d (0x%08x)\n",
- _IOC_TYPE(cmd), dir, _IOC_NR(cmd), cmd);
- }
-}
-
+EXPORT_SYMBOL(v4l2_prio_check);
/* ----------------------------------------------------------------- */
@@ -488,6 +172,7 @@ int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl,
}
return 0;
}
+EXPORT_SYMBOL(v4l2_ctrl_check);
/* Returns NULL or a character pointer array containing the menu for
the given control ID. The pointer array ends with a NULL pointer.
@@ -648,6 +333,7 @@ const char **v4l2_ctrl_get_menu(u32 id)
return NULL;
}
}
+EXPORT_SYMBOL(v4l2_ctrl_get_menu);
/* Fill in a struct v4l2_queryctrl */
int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def)
@@ -770,6 +456,7 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste
snprintf(qctrl->name, sizeof(qctrl->name), name);
return 0;
}
+EXPORT_SYMBOL(v4l2_ctrl_query_fill);
/* Fill in a struct v4l2_queryctrl with standard values based on
the control ID. */
@@ -904,6 +591,7 @@ int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl)
return -EINVAL;
}
}
+EXPORT_SYMBOL(v4l2_ctrl_query_fill_std);
/* Fill in a struct v4l2_querymenu based on the struct v4l2_queryctrl and
the menu. The qctrl pointer may be NULL, in which case it is ignored. */
@@ -922,6 +610,7 @@ int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu, struct v4l2_queryctrl *qc
qmenu->reserved = 0;
return 0;
}
+EXPORT_SYMBOL(v4l2_ctrl_query_menu);
/* ctrl_classes points to an array of u32 pointers, the last element is
a NULL pointer. Each u32 array is a 0-terminated array of control IDs.
@@ -972,7 +661,20 @@ u32 v4l2_ctrl_next(const u32 * const * ctrl_classes, u32 id)
return 0;
return **ctrl_classes;
}
+EXPORT_SYMBOL(v4l2_ctrl_next);
+int v4l2_chip_match_host(u32 match_type, u32 match_chip)
+{
+ switch (match_type) {
+ case V4L2_CHIP_MATCH_HOST:
+ return match_chip == 0;
+ default:
+ return 0;
+ }
+}
+EXPORT_SYMBOL(v4l2_chip_match_host);
+
+#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
int v4l2_chip_match_i2c_client(struct i2c_client *c, u32 match_type, u32 match_chip)
{
switch (match_type) {
@@ -984,6 +686,7 @@ int v4l2_chip_match_i2c_client(struct i2c_client *c, u32 match_type, u32 match_c
return 0;
}
}
+EXPORT_SYMBOL(v4l2_chip_match_i2c_client);
int v4l2_chip_ident_i2c_client(struct i2c_client *c, struct v4l2_chip_ident *chip,
u32 ident, u32 revision)
@@ -1000,16 +703,7 @@ int v4l2_chip_ident_i2c_client(struct i2c_client *c, struct v4l2_chip_ident *chi
}
return 0;
}
-
-int v4l2_chip_match_host(u32 match_type, u32 match_chip)
-{
- switch (match_type) {
- case V4L2_CHIP_MATCH_HOST:
- return match_chip == 0;
- default:
- return 0;
- }
-}
+EXPORT_SYMBOL(v4l2_chip_ident_i2c_client);
/* ----------------------------------------------------------------- */
@@ -1038,38 +732,5 @@ int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver
}
return err != -ENOMEM ? 0 : err;
}
-
-/* ----------------------------------------------------------------- */
-
-EXPORT_SYMBOL(v4l2_norm_to_name);
-EXPORT_SYMBOL(v4l2_video_std_construct);
-
-EXPORT_SYMBOL(v4l2_prio_init);
-EXPORT_SYMBOL(v4l2_prio_change);
-EXPORT_SYMBOL(v4l2_prio_open);
-EXPORT_SYMBOL(v4l2_prio_close);
-EXPORT_SYMBOL(v4l2_prio_max);
-EXPORT_SYMBOL(v4l2_prio_check);
-
-EXPORT_SYMBOL(v4l2_field_names);
-EXPORT_SYMBOL(v4l2_type_names);
-EXPORT_SYMBOL(v4l_printk_ioctl);
-
-EXPORT_SYMBOL(v4l2_ctrl_next);
-EXPORT_SYMBOL(v4l2_ctrl_check);
-EXPORT_SYMBOL(v4l2_ctrl_get_menu);
-EXPORT_SYMBOL(v4l2_ctrl_query_menu);
-EXPORT_SYMBOL(v4l2_ctrl_query_fill);
-EXPORT_SYMBOL(v4l2_ctrl_query_fill_std);
-
-EXPORT_SYMBOL(v4l2_chip_match_i2c_client);
-EXPORT_SYMBOL(v4l2_chip_ident_i2c_client);
-EXPORT_SYMBOL(v4l2_chip_match_host);
-
EXPORT_SYMBOL(v4l2_i2c_attach);
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
+#endif
diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c
index 80a14da9ace..eab79ffdf56 100644
--- a/drivers/media/video/videobuf-core.c
+++ b/drivers/media/video/videobuf-core.c
@@ -147,7 +147,7 @@ void videobuf_queue_core_init(struct videobuf_queue *q,
/* Having implementations for abstract methods are mandatory */
BUG_ON(!q->int_ops);
- mutex_init(&q->lock);
+ mutex_init(&q->vb_lock);
INIT_LIST_HEAD(&q->stream);
}
@@ -189,7 +189,7 @@ int videobuf_queue_is_busy(struct videobuf_queue *q)
return 0;
}
-/* Locking: Caller holds q->lock */
+/* Locking: Caller holds q->vb_lock */
void videobuf_queue_cancel(struct videobuf_queue *q)
{
unsigned long flags = 0;
@@ -220,7 +220,7 @@ void videobuf_queue_cancel(struct videobuf_queue *q)
/* --------------------------------------------------------------------- */
-/* Locking: Caller holds q->lock */
+/* Locking: Caller holds q->vb_lock */
enum v4l2_field videobuf_next_field(struct videobuf_queue *q)
{
enum v4l2_field field = q->field;
@@ -239,7 +239,7 @@ enum v4l2_field videobuf_next_field(struct videobuf_queue *q)
return field;
}
-/* Locking: Caller holds q->lock */
+/* Locking: Caller holds q->vb_lock */
static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b,
struct videobuf_buffer *vb, enum v4l2_buf_type type)
{
@@ -295,7 +295,7 @@ static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b,
b->sequence = vb->field_count >> 1;
}
-/* Locking: Caller holds q->lock */
+/* Locking: Caller holds q->vb_lock */
static int __videobuf_mmap_free(struct videobuf_queue *q)
{
int i;
@@ -328,13 +328,13 @@ static int __videobuf_mmap_free(struct videobuf_queue *q)
int videobuf_mmap_free(struct videobuf_queue *q)
{
int ret;
- mutex_lock(&q->lock);
+ mutex_lock(&q->vb_lock);
ret = __videobuf_mmap_free(q);
- mutex_unlock(&q->lock);
+ mutex_unlock(&q->vb_lock);
return ret;
}
-/* Locking: Caller holds q->lock */
+/* Locking: Caller holds q->vb_lock */
static int __videobuf_mmap_setup(struct videobuf_queue *q,
unsigned int bcount, unsigned int bsize,
enum v4l2_memory memory)
@@ -384,9 +384,9 @@ int videobuf_mmap_setup(struct videobuf_queue *q,
enum v4l2_memory memory)
{
int ret;
- mutex_lock(&q->lock);
+ mutex_lock(&q->vb_lock);
ret = __videobuf_mmap_setup(q, bcount, bsize, memory);
- mutex_unlock(&q->lock);
+ mutex_unlock(&q->vb_lock);
return ret;
}
@@ -408,7 +408,7 @@ int videobuf_reqbufs(struct videobuf_queue *q,
return -EINVAL;
}
- mutex_lock(&q->lock);
+ mutex_lock(&q->vb_lock);
if (req->type != q->type) {
dprintk(1, "reqbufs: queue type invalid\n");
retval = -EINVAL;
@@ -444,7 +444,7 @@ int videobuf_reqbufs(struct videobuf_queue *q,
req->count = retval;
done:
- mutex_unlock(&q->lock);
+ mutex_unlock(&q->vb_lock);
return retval;
}
@@ -452,7 +452,7 @@ int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b)
{
int ret = -EINVAL;
- mutex_lock(&q->lock);
+ mutex_lock(&q->vb_lock);
if (unlikely(b->type != q->type)) {
dprintk(1, "querybuf: Wrong type.\n");
goto done;
@@ -470,7 +470,7 @@ int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b)
ret = 0;
done:
- mutex_unlock(&q->lock);
+ mutex_unlock(&q->vb_lock);
return ret;
}
@@ -487,7 +487,7 @@ int videobuf_qbuf(struct videobuf_queue *q,
if (b->memory == V4L2_MEMORY_MMAP)
down_read(&current->mm->mmap_sem);
- mutex_lock(&q->lock);
+ mutex_lock(&q->vb_lock);
retval = -EBUSY;
if (q->reading) {
dprintk(1, "qbuf: Reading running...\n");
@@ -573,7 +573,7 @@ int videobuf_qbuf(struct videobuf_queue *q,
retval = 0;
done:
- mutex_unlock(&q->lock);
+ mutex_unlock(&q->vb_lock);
if (b->memory == V4L2_MEMORY_MMAP)
up_read(&current->mm->mmap_sem);
@@ -589,7 +589,7 @@ int videobuf_dqbuf(struct videobuf_queue *q,
MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
- mutex_lock(&q->lock);
+ mutex_lock(&q->vb_lock);
retval = -EBUSY;
if (q->reading) {
dprintk(1, "dqbuf: Reading running...\n");
@@ -632,7 +632,7 @@ int videobuf_dqbuf(struct videobuf_queue *q,
videobuf_status(q, b, buf, q->type);
done:
- mutex_unlock(&q->lock);
+ mutex_unlock(&q->vb_lock);
return retval;
}
@@ -642,7 +642,7 @@ int videobuf_streamon(struct videobuf_queue *q)
unsigned long flags = 0;
int retval;
- mutex_lock(&q->lock);
+ mutex_lock(&q->vb_lock);
retval = -EBUSY;
if (q->reading)
goto done;
@@ -659,11 +659,11 @@ int videobuf_streamon(struct videobuf_queue *q)
spin_unlock_irqrestore(q->irqlock, flags);
done:
- mutex_unlock(&q->lock);
+ mutex_unlock(&q->vb_lock);
return retval;
}
-/* Locking: Caller holds q->lock */
+/* Locking: Caller holds q->vb_lock */
static int __videobuf_streamoff(struct videobuf_queue *q)
{
if (!q->streaming)
@@ -679,14 +679,14 @@ int videobuf_streamoff(struct videobuf_queue *q)
{
int retval;
- mutex_lock(&q->lock);
+ mutex_lock(&q->vb_lock);
retval = __videobuf_streamoff(q);
- mutex_unlock(&q->lock);
+ mutex_unlock(&q->vb_lock);
return retval;
}
-/* Locking: Caller holds q->lock */
+/* Locking: Caller holds q->vb_lock */
static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q,
char __user *data,
size_t count, loff_t *ppos)
@@ -745,7 +745,7 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
- mutex_lock(&q->lock);
+ mutex_lock(&q->vb_lock);
nbufs = 1; size = 0;
q->ops->buf_setup(q, &nbufs, &size);
@@ -817,11 +817,11 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
}
done:
- mutex_unlock(&q->lock);
+ mutex_unlock(&q->vb_lock);
return retval;
}
-/* Locking: Caller holds q->lock */
+/* Locking: Caller holds q->vb_lock */
static int __videobuf_read_start(struct videobuf_queue *q)
{
enum v4l2_field field;
@@ -882,23 +882,23 @@ int videobuf_read_start(struct videobuf_queue *q)
{
int rc;
- mutex_lock(&q->lock);
+ mutex_lock(&q->vb_lock);
rc = __videobuf_read_start(q);
- mutex_unlock(&q->lock);
+ mutex_unlock(&q->vb_lock);
return rc;
}
void videobuf_read_stop(struct videobuf_queue *q)
{
- mutex_lock(&q->lock);
+ mutex_lock(&q->vb_lock);
__videobuf_read_stop(q);
- mutex_unlock(&q->lock);
+ mutex_unlock(&q->vb_lock);
}
void videobuf_stop(struct videobuf_queue *q)
{
- mutex_lock(&q->lock);
+ mutex_lock(&q->vb_lock);
if (q->streaming)
__videobuf_streamoff(q);
@@ -906,7 +906,7 @@ void videobuf_stop(struct videobuf_queue *q)
if (q->reading)
__videobuf_read_stop(q);
- mutex_unlock(&q->lock);
+ mutex_unlock(&q->vb_lock);
}
@@ -920,7 +920,7 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
dprintk(2, "%s\n", __FUNCTION__);
- mutex_lock(&q->lock);
+ mutex_lock(&q->vb_lock);
retval = -EBUSY;
if (q->streaming)
goto done;
@@ -980,7 +980,7 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
}
done:
- mutex_unlock(&q->lock);
+ mutex_unlock(&q->vb_lock);
return retval;
}
@@ -991,7 +991,7 @@ unsigned int videobuf_poll_stream(struct file *file,
struct videobuf_buffer *buf = NULL;
unsigned int rc = 0;
- mutex_lock(&q->lock);
+ mutex_lock(&q->vb_lock);
if (q->streaming) {
if (!list_empty(&q->stream))
buf = list_entry(q->stream.next,
@@ -1019,7 +1019,7 @@ unsigned int videobuf_poll_stream(struct file *file,
buf->state == VIDEOBUF_ERROR)
rc = POLLIN|POLLRDNORM;
}
- mutex_unlock(&q->lock);
+ mutex_unlock(&q->vb_lock);
return rc;
}
@@ -1030,10 +1030,10 @@ int videobuf_mmap_mapper(struct videobuf_queue *q,
MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
- mutex_lock(&q->lock);
+ mutex_lock(&q->vb_lock);
retval = CALL(q, mmap_mapper, q, vma);
q->is_mmapped = 1;
- mutex_unlock(&q->lock);
+ mutex_unlock(&q->vb_lock);
return retval;
}
diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c
index 98efd7ab1f5..53fed4b74ce 100644
--- a/drivers/media/video/videobuf-dma-sg.c
+++ b/drivers/media/video/videobuf-dma-sg.c
@@ -356,7 +356,7 @@ videobuf_vm_close(struct vm_area_struct *vma)
map->count--;
if (0 == map->count) {
dprintk(1,"munmap %p q=%p\n",map,q);
- mutex_lock(&q->lock);
+ mutex_lock(&q->vb_lock);
for (i = 0; i < VIDEO_MAX_FRAME; i++) {
if (NULL == q->bufs[i])
continue;
@@ -373,7 +373,7 @@ videobuf_vm_close(struct vm_area_struct *vma)
q->bufs[i]->baddr = 0;
q->ops->buf_release(q,q->bufs[i]);
}
- mutex_unlock(&q->lock);
+ mutex_unlock(&q->vb_lock);
kfree(map);
}
return;
diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c
index 9b3898347ca..5266ecc91da 100644
--- a/drivers/media/video/videobuf-vmalloc.c
+++ b/drivers/media/video/videobuf-vmalloc.c
@@ -70,7 +70,7 @@ videobuf_vm_close(struct vm_area_struct *vma)
map->count--;
if (0 == map->count) {
dprintk(1,"munmap %p q=%p\n",map,q);
- mutex_lock(&q->lock);
+ mutex_lock(&q->vb_lock);
for (i = 0; i < VIDEO_MAX_FRAME; i++) {
if (NULL == q->bufs[i])
continue;
@@ -83,7 +83,7 @@ videobuf_vm_close(struct vm_area_struct *vma)
q->bufs[i]->map = NULL;
q->bufs[i]->baddr = 0;
}
- mutex_unlock(&q->lock);
+ mutex_unlock(&q->vb_lock);
kfree(map);
}
return;
@@ -107,7 +107,7 @@ static struct vm_operations_struct videobuf_vm_ops =
static void *__videobuf_alloc(size_t size)
{
- struct videbuf_vmalloc_memory *mem;
+ struct videobuf_vmalloc_memory *mem;
struct videobuf_buffer *vb;
vb = kzalloc(size+sizeof(*mem),GFP_KERNEL);
@@ -127,9 +127,7 @@ static int __videobuf_iolock (struct videobuf_queue* q,
struct v4l2_framebuffer *fbuf)
{
int pages;
-
- struct videbuf_vmalloc_memory *mem=vb->priv;
-
+ struct videobuf_vmalloc_memory *mem=vb->priv;
BUG_ON(!mem);
@@ -195,7 +193,7 @@ static int __videobuf_mmap_free(struct videobuf_queue *q)
static int __videobuf_mmap_mapper(struct videobuf_queue *q,
struct vm_area_struct *vma)
{
- struct videbuf_vmalloc_memory *mem;
+ struct videobuf_vmalloc_memory *mem;
struct videobuf_mapping *map;
unsigned int first;
int retval;
@@ -267,7 +265,7 @@ static int __videobuf_copy_to_user ( struct videobuf_queue *q,
char __user *data, size_t count,
int nonblocking )
{
- struct videbuf_vmalloc_memory *mem=q->read_buf->priv;
+ struct videobuf_vmalloc_memory *mem=q->read_buf->priv;
BUG_ON (!mem);
MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
@@ -288,7 +286,7 @@ static int __videobuf_copy_stream ( struct videobuf_queue *q,
int vbihack, int nonblocking )
{
unsigned int *fc;
- struct videbuf_vmalloc_memory *mem=q->read_buf->priv;
+ struct videobuf_vmalloc_memory *mem=q->read_buf->priv;
BUG_ON (!mem);
MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
@@ -341,7 +339,7 @@ EXPORT_SYMBOL_GPL(videobuf_queue_vmalloc_init);
void *videobuf_to_vmalloc (struct videobuf_buffer *buf)
{
- struct videbuf_vmalloc_memory *mem=buf->priv;
+ struct videobuf_vmalloc_memory *mem=buf->priv;
BUG_ON (!mem);
MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
@@ -351,7 +349,7 @@ EXPORT_SYMBOL_GPL(videobuf_to_vmalloc);
void videobuf_vmalloc_free (struct videobuf_buffer *buf)
{
- struct videbuf_vmalloc_memory *mem=buf->priv;
+ struct videobuf_vmalloc_memory *mem=buf->priv;
BUG_ON (!mem);
MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c
index 28655f8983c..0d9b63762a4 100644
--- a/drivers/media/video/videodev.c
+++ b/drivers/media/video/videodev.c
@@ -46,10 +46,373 @@
#include <linux/videodev.h>
#endif
#include <media/v4l2-common.h>
+#include <linux/video_decoder.h>
#define VIDEO_NUM_DEVICES 256
#define VIDEO_NAME "video4linux"
+/* video4linux standard ID conversion to standard name
+ */
+char *v4l2_norm_to_name(v4l2_std_id id)
+{
+ char *name;
+ u32 myid = id;
+
+ /* HACK: ppc32 architecture doesn't have __ucmpdi2 function to handle
+ 64 bit comparations. So, on that architecture, with some gcc
+ variants, compilation fails. Currently, the max value is 30bit wide.
+ */
+ BUG_ON(myid != id);
+
+ switch (myid) {
+ case V4L2_STD_PAL:
+ name = "PAL";
+ break;
+ case V4L2_STD_PAL_BG:
+ name = "PAL-BG";
+ break;
+ case V4L2_STD_PAL_DK:
+ name = "PAL-DK";
+ break;
+ case V4L2_STD_PAL_B:
+ name = "PAL-B";
+ break;
+ case V4L2_STD_PAL_B1:
+ name = "PAL-B1";
+ break;
+ case V4L2_STD_PAL_G:
+ name = "PAL-G";
+ break;
+ case V4L2_STD_PAL_H:
+ name = "PAL-H";
+ break;
+ case V4L2_STD_PAL_I:
+ name = "PAL-I";
+ break;
+ case V4L2_STD_PAL_D:
+ name = "PAL-D";
+ break;
+ case V4L2_STD_PAL_D1:
+ name = "PAL-D1";
+ break;
+ case V4L2_STD_PAL_K:
+ name = "PAL-K";
+ break;
+ case V4L2_STD_PAL_M:
+ name = "PAL-M";
+ break;
+ case V4L2_STD_PAL_N:
+ name = "PAL-N";
+ break;
+ case V4L2_STD_PAL_Nc:
+ name = "PAL-Nc";
+ break;
+ case V4L2_STD_PAL_60:
+ name = "PAL-60";
+ break;
+ case V4L2_STD_NTSC:
+ name = "NTSC";
+ break;
+ case V4L2_STD_NTSC_M:
+ name = "NTSC-M";
+ break;
+ case V4L2_STD_NTSC_M_JP:
+ name = "NTSC-M-JP";
+ break;
+ case V4L2_STD_NTSC_443:
+ name = "NTSC-443";
+ break;
+ case V4L2_STD_NTSC_M_KR:
+ name = "NTSC-M-KR";
+ break;
+ case V4L2_STD_SECAM:
+ name = "SECAM";
+ break;
+ case V4L2_STD_SECAM_DK:
+ name = "SECAM-DK";
+ break;
+ case V4L2_STD_SECAM_B:
+ name = "SECAM-B";
+ break;
+ case V4L2_STD_SECAM_D:
+ name = "SECAM-D";
+ break;
+ case V4L2_STD_SECAM_G:
+ name = "SECAM-G";
+ break;
+ case V4L2_STD_SECAM_H:
+ name = "SECAM-H";
+ break;
+ case V4L2_STD_SECAM_K:
+ name = "SECAM-K";
+ break;
+ case V4L2_STD_SECAM_K1:
+ name = "SECAM-K1";
+ break;
+ case V4L2_STD_SECAM_L:
+ name = "SECAM-L";
+ break;
+ case V4L2_STD_SECAM_LC:
+ name = "SECAM-LC";
+ break;
+ default:
+ name = "Unknown";
+ break;
+ }
+
+ return name;
+}
+EXPORT_SYMBOL(v4l2_norm_to_name);
+
+/* Fill in the fields of a v4l2_standard structure according to the
+ 'id' and 'transmission' parameters. Returns negative on error. */
+int v4l2_video_std_construct(struct v4l2_standard *vs,
+ int id, char *name)
+{
+ u32 index = vs->index;
+
+ memset(vs, 0, sizeof(struct v4l2_standard));
+ vs->index = index;
+ vs->id = id;
+ if (id & V4L2_STD_525_60) {
+ vs->frameperiod.numerator = 1001;
+ vs->frameperiod.denominator = 30000;
+ vs->framelines = 525;
+ } else {
+ vs->frameperiod.numerator = 1;
+ vs->frameperiod.denominator = 25;
+ vs->framelines = 625;
+ }
+ strlcpy(vs->name, name, sizeof(vs->name));
+ return 0;
+}
+EXPORT_SYMBOL(v4l2_video_std_construct);
+
+/* ----------------------------------------------------------------- */
+/* some arrays for pretty-printing debug messages of enum types */
+
+char *v4l2_field_names[] = {
+ [V4L2_FIELD_ANY] = "any",
+ [V4L2_FIELD_NONE] = "none",
+ [V4L2_FIELD_TOP] = "top",
+ [V4L2_FIELD_BOTTOM] = "bottom",
+ [V4L2_FIELD_INTERLACED] = "interlaced",
+ [V4L2_FIELD_SEQ_TB] = "seq-tb",
+ [V4L2_FIELD_SEQ_BT] = "seq-bt",
+ [V4L2_FIELD_ALTERNATE] = "alternate",
+ [V4L2_FIELD_INTERLACED_TB] = "interlaced-tb",
+ [V4L2_FIELD_INTERLACED_BT] = "interlaced-bt",
+};
+EXPORT_SYMBOL(v4l2_field_names);
+
+char *v4l2_type_names[] = {
+ [V4L2_BUF_TYPE_VIDEO_CAPTURE] = "video-cap",
+ [V4L2_BUF_TYPE_VIDEO_OVERLAY] = "video-over",
+ [V4L2_BUF_TYPE_VIDEO_OUTPUT] = "video-out",
+ [V4L2_BUF_TYPE_VBI_CAPTURE] = "vbi-cap",
+ [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out",
+ [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-cap",
+ [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "sliced-vbi-out",
+ [V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "video-out-over",
+};
+EXPORT_SYMBOL(v4l2_type_names);
+
+static char *v4l2_memory_names[] = {
+ [V4L2_MEMORY_MMAP] = "mmap",
+ [V4L2_MEMORY_USERPTR] = "userptr",
+ [V4L2_MEMORY_OVERLAY] = "overlay",
+};
+
+#define prt_names(a, arr) ((((a) >= 0) && ((a) < ARRAY_SIZE(arr))) ? \
+ arr[a] : "unknown")
+
+/* ------------------------------------------------------------------ */
+/* debug help functions */
+
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+static const char *v4l1_ioctls[] = {
+ [_IOC_NR(VIDIOCGCAP)] = "VIDIOCGCAP",
+ [_IOC_NR(VIDIOCGCHAN)] = "VIDIOCGCHAN",
+ [_IOC_NR(VIDIOCSCHAN)] = "VIDIOCSCHAN",
+ [_IOC_NR(VIDIOCGTUNER)] = "VIDIOCGTUNER",
+ [_IOC_NR(VIDIOCSTUNER)] = "VIDIOCSTUNER",
+ [_IOC_NR(VIDIOCGPICT)] = "VIDIOCGPICT",
+ [_IOC_NR(VIDIOCSPICT)] = "VIDIOCSPICT",
+ [_IOC_NR(VIDIOCCAPTURE)] = "VIDIOCCAPTURE",
+ [_IOC_NR(VIDIOCGWIN)] = "VIDIOCGWIN",
+ [_IOC_NR(VIDIOCSWIN)] = "VIDIOCSWIN",
+ [_IOC_NR(VIDIOCGFBUF)] = "VIDIOCGFBUF",
+ [_IOC_NR(VIDIOCSFBUF)] = "VIDIOCSFBUF",
+ [_IOC_NR(VIDIOCKEY)] = "VIDIOCKEY",
+ [_IOC_NR(VIDIOCGFREQ)] = "VIDIOCGFREQ",
+ [_IOC_NR(VIDIOCSFREQ)] = "VIDIOCSFREQ",
+ [_IOC_NR(VIDIOCGAUDIO)] = "VIDIOCGAUDIO",
+ [_IOC_NR(VIDIOCSAUDIO)] = "VIDIOCSAUDIO",
+ [_IOC_NR(VIDIOCSYNC)] = "VIDIOCSYNC",
+ [_IOC_NR(VIDIOCMCAPTURE)] = "VIDIOCMCAPTURE",
+ [_IOC_NR(VIDIOCGMBUF)] = "VIDIOCGMBUF",
+ [_IOC_NR(VIDIOCGUNIT)] = "VIDIOCGUNIT",
+ [_IOC_NR(VIDIOCGCAPTURE)] = "VIDIOCGCAPTURE",
+ [_IOC_NR(VIDIOCSCAPTURE)] = "VIDIOCSCAPTURE",
+ [_IOC_NR(VIDIOCSPLAYMODE)] = "VIDIOCSPLAYMODE",
+ [_IOC_NR(VIDIOCSWRITEMODE)] = "VIDIOCSWRITEMODE",
+ [_IOC_NR(VIDIOCGPLAYINFO)] = "VIDIOCGPLAYINFO",
+ [_IOC_NR(VIDIOCSMICROCODE)] = "VIDIOCSMICROCODE",
+ [_IOC_NR(VIDIOCGVBIFMT)] = "VIDIOCGVBIFMT",
+ [_IOC_NR(VIDIOCSVBIFMT)] = "VIDIOCSVBIFMT"
+};
+#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls)
+#endif
+
+static const char *v4l2_ioctls[] = {
+ [_IOC_NR(VIDIOC_QUERYCAP)] = "VIDIOC_QUERYCAP",
+ [_IOC_NR(VIDIOC_RESERVED)] = "VIDIOC_RESERVED",
+ [_IOC_NR(VIDIOC_ENUM_FMT)] = "VIDIOC_ENUM_FMT",
+ [_IOC_NR(VIDIOC_G_FMT)] = "VIDIOC_G_FMT",
+ [_IOC_NR(VIDIOC_S_FMT)] = "VIDIOC_S_FMT",
+ [_IOC_NR(VIDIOC_REQBUFS)] = "VIDIOC_REQBUFS",
+ [_IOC_NR(VIDIOC_QUERYBUF)] = "VIDIOC_QUERYBUF",
+ [_IOC_NR(VIDIOC_G_FBUF)] = "VIDIOC_G_FBUF",
+ [_IOC_NR(VIDIOC_S_FBUF)] = "VIDIOC_S_FBUF",
+ [_IOC_NR(VIDIOC_OVERLAY)] = "VIDIOC_OVERLAY",
+ [_IOC_NR(VIDIOC_QBUF)] = "VIDIOC_QBUF",
+ [_IOC_NR(VIDIOC_DQBUF)] = "VIDIOC_DQBUF",
+ [_IOC_NR(VIDIOC_STREAMON)] = "VIDIOC_STREAMON",
+ [_IOC_NR(VIDIOC_STREAMOFF)] = "VIDIOC_STREAMOFF",
+ [_IOC_NR(VIDIOC_G_PARM)] = "VIDIOC_G_PARM",
+ [_IOC_NR(VIDIOC_S_PARM)] = "VIDIOC_S_PARM",
+ [_IOC_NR(VIDIOC_G_STD)] = "VIDIOC_G_STD",
+ [_IOC_NR(VIDIOC_S_STD)] = "VIDIOC_S_STD",
+ [_IOC_NR(VIDIOC_ENUMSTD)] = "VIDIOC_ENUMSTD",
+ [_IOC_NR(VIDIOC_ENUMINPUT)] = "VIDIOC_ENUMINPUT",
+ [_IOC_NR(VIDIOC_G_CTRL)] = "VIDIOC_G_CTRL",
+ [_IOC_NR(VIDIOC_S_CTRL)] = "VIDIOC_S_CTRL",
+ [_IOC_NR(VIDIOC_G_TUNER)] = "VIDIOC_G_TUNER",
+ [_IOC_NR(VIDIOC_S_TUNER)] = "VIDIOC_S_TUNER",
+ [_IOC_NR(VIDIOC_G_AUDIO)] = "VIDIOC_G_AUDIO",
+ [_IOC_NR(VIDIOC_S_AUDIO)] = "VIDIOC_S_AUDIO",
+ [_IOC_NR(VIDIOC_QUERYCTRL)] = "VIDIOC_QUERYCTRL",
+ [_IOC_NR(VIDIOC_QUERYMENU)] = "VIDIOC_QUERYMENU",
+ [_IOC_NR(VIDIOC_G_INPUT)] = "VIDIOC_G_INPUT",
+ [_IOC_NR(VIDIOC_S_INPUT)] = "VIDIOC_S_INPUT",
+ [_IOC_NR(VIDIOC_G_OUTPUT)] = "VIDIOC_G_OUTPUT",
+ [_IOC_NR(VIDIOC_S_OUTPUT)] = "VIDIOC_S_OUTPUT",
+ [_IOC_NR(VIDIOC_ENUMOUTPUT)] = "VIDIOC_ENUMOUTPUT",
+ [_IOC_NR(VIDIOC_G_AUDOUT)] = "VIDIOC_G_AUDOUT",
+ [_IOC_NR(VIDIOC_S_AUDOUT)] = "VIDIOC_S_AUDOUT",
+ [_IOC_NR(VIDIOC_G_MODULATOR)] = "VIDIOC_G_MODULATOR",
+ [_IOC_NR(VIDIOC_S_MODULATOR)] = "VIDIOC_S_MODULATOR",
+ [_IOC_NR(VIDIOC_G_FREQUENCY)] = "VIDIOC_G_FREQUENCY",
+ [_IOC_NR(VIDIOC_S_FREQUENCY)] = "VIDIOC_S_FREQUENCY",
+ [_IOC_NR(VIDIOC_CROPCAP)] = "VIDIOC_CROPCAP",
+ [_IOC_NR(VIDIOC_G_CROP)] = "VIDIOC_G_CROP",
+ [_IOC_NR(VIDIOC_S_CROP)] = "VIDIOC_S_CROP",
+ [_IOC_NR(VIDIOC_G_JPEGCOMP)] = "VIDIOC_G_JPEGCOMP",
+ [_IOC_NR(VIDIOC_S_JPEGCOMP)] = "VIDIOC_S_JPEGCOMP",
+ [_IOC_NR(VIDIOC_QUERYSTD)] = "VIDIOC_QUERYSTD",
+ [_IOC_NR(VIDIOC_TRY_FMT)] = "VIDIOC_TRY_FMT",
+ [_IOC_NR(VIDIOC_ENUMAUDIO)] = "VIDIOC_ENUMAUDIO",
+ [_IOC_NR(VIDIOC_ENUMAUDOUT)] = "VIDIOC_ENUMAUDOUT",
+ [_IOC_NR(VIDIOC_G_PRIORITY)] = "VIDIOC_G_PRIORITY",
+ [_IOC_NR(VIDIOC_S_PRIORITY)] = "VIDIOC_S_PRIORITY",
+ [_IOC_NR(VIDIOC_G_SLICED_VBI_CAP)] = "VIDIOC_G_SLICED_VBI_CAP",
+ [_IOC_NR(VIDIOC_LOG_STATUS)] = "VIDIOC_LOG_STATUS",
+ [_IOC_NR(VIDIOC_G_EXT_CTRLS)] = "VIDIOC_G_EXT_CTRLS",
+ [_IOC_NR(VIDIOC_S_EXT_CTRLS)] = "VIDIOC_S_EXT_CTRLS",
+ [_IOC_NR(VIDIOC_TRY_EXT_CTRLS)] = "VIDIOC_TRY_EXT_CTRLS",
+#if 1
+ [_IOC_NR(VIDIOC_ENUM_FRAMESIZES)] = "VIDIOC_ENUM_FRAMESIZES",
+ [_IOC_NR(VIDIOC_ENUM_FRAMEINTERVALS)] = "VIDIOC_ENUM_FRAMEINTERVALS",
+ [_IOC_NR(VIDIOC_G_ENC_INDEX)] = "VIDIOC_G_ENC_INDEX",
+ [_IOC_NR(VIDIOC_ENCODER_CMD)] = "VIDIOC_ENCODER_CMD",
+ [_IOC_NR(VIDIOC_TRY_ENCODER_CMD)] = "VIDIOC_TRY_ENCODER_CMD",
+
+ [_IOC_NR(VIDIOC_DBG_S_REGISTER)] = "VIDIOC_DBG_S_REGISTER",
+ [_IOC_NR(VIDIOC_DBG_G_REGISTER)] = "VIDIOC_DBG_G_REGISTER",
+
+ [_IOC_NR(VIDIOC_G_CHIP_IDENT)] = "VIDIOC_G_CHIP_IDENT",
+#endif
+};
+#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
+
+static const char *v4l2_int_ioctls[] = {
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+ [_IOC_NR(DECODER_GET_CAPABILITIES)] = "DECODER_GET_CAPABILITIES",
+ [_IOC_NR(DECODER_GET_STATUS)] = "DECODER_GET_STATUS",
+ [_IOC_NR(DECODER_SET_NORM)] = "DECODER_SET_NORM",
+ [_IOC_NR(DECODER_SET_INPUT)] = "DECODER_SET_INPUT",
+ [_IOC_NR(DECODER_SET_OUTPUT)] = "DECODER_SET_OUTPUT",
+ [_IOC_NR(DECODER_ENABLE_OUTPUT)] = "DECODER_ENABLE_OUTPUT",
+ [_IOC_NR(DECODER_SET_PICTURE)] = "DECODER_SET_PICTURE",
+ [_IOC_NR(DECODER_SET_GPIO)] = "DECODER_SET_GPIO",
+ [_IOC_NR(DECODER_INIT)] = "DECODER_INIT",
+ [_IOC_NR(DECODER_SET_VBI_BYPASS)] = "DECODER_SET_VBI_BYPASS",
+ [_IOC_NR(DECODER_DUMP)] = "DECODER_DUMP",
+#endif
+ [_IOC_NR(AUDC_SET_RADIO)] = "AUDC_SET_RADIO",
+
+ [_IOC_NR(TUNER_SET_TYPE_ADDR)] = "TUNER_SET_TYPE_ADDR",
+ [_IOC_NR(TUNER_SET_STANDBY)] = "TUNER_SET_STANDBY",
+ [_IOC_NR(TUNER_SET_CONFIG)] = "TUNER_SET_CONFIG",
+
+ [_IOC_NR(VIDIOC_INT_S_TUNER_MODE)] = "VIDIOC_INT_S_TUNER_MODE",
+ [_IOC_NR(VIDIOC_INT_RESET)] = "VIDIOC_INT_RESET",
+ [_IOC_NR(VIDIOC_INT_AUDIO_CLOCK_FREQ)] = "VIDIOC_INT_AUDIO_CLOCK_FREQ",
+ [_IOC_NR(VIDIOC_INT_DECODE_VBI_LINE)] = "VIDIOC_INT_DECODE_VBI_LINE",
+ [_IOC_NR(VIDIOC_INT_S_VBI_DATA)] = "VIDIOC_INT_S_VBI_DATA",
+ [_IOC_NR(VIDIOC_INT_G_VBI_DATA)] = "VIDIOC_INT_G_VBI_DATA",
+ [_IOC_NR(VIDIOC_INT_I2S_CLOCK_FREQ)] = "VIDIOC_INT_I2S_CLOCK_FREQ",
+ [_IOC_NR(VIDIOC_INT_S_STANDBY)] = "VIDIOC_INT_S_STANDBY",
+ [_IOC_NR(VIDIOC_INT_S_AUDIO_ROUTING)] = "VIDIOC_INT_S_AUDIO_ROUTING",
+ [_IOC_NR(VIDIOC_INT_G_AUDIO_ROUTING)] = "VIDIOC_INT_G_AUDIO_ROUTING",
+ [_IOC_NR(VIDIOC_INT_S_VIDEO_ROUTING)] = "VIDIOC_INT_S_VIDEO_ROUTING",
+ [_IOC_NR(VIDIOC_INT_G_VIDEO_ROUTING)] = "VIDIOC_INT_G_VIDEO_ROUTING",
+ [_IOC_NR(VIDIOC_INT_S_CRYSTAL_FREQ)] = "VIDIOC_INT_S_CRYSTAL_FREQ",
+ [_IOC_NR(VIDIOC_INT_INIT)] = "VIDIOC_INT_INIT",
+ [_IOC_NR(VIDIOC_INT_G_STD_OUTPUT)] = "VIDIOC_INT_G_STD_OUTPUT",
+ [_IOC_NR(VIDIOC_INT_S_STD_OUTPUT)] = "VIDIOC_INT_S_STD_OUTPUT",
+};
+#define V4L2_INT_IOCTLS ARRAY_SIZE(v4l2_int_ioctls)
+
+/* Common ioctl debug function. This function can be used by
+ external ioctl messages as well as internal V4L ioctl */
+void v4l_printk_ioctl(unsigned int cmd)
+{
+ char *dir;
+
+ switch (_IOC_DIR(cmd)) {
+ case _IOC_NONE: dir = "--"; break;
+ case _IOC_READ: dir = "r-"; break;
+ case _IOC_WRITE: dir = "-w"; break;
+ case _IOC_READ | _IOC_WRITE: dir = "rw"; break;
+ default: dir = "*ERR*"; break;
+ }
+ switch (_IOC_TYPE(cmd)) {
+ case 'd':
+ printk("v4l2_int ioctl %s, dir=%s (0x%08x)\n",
+ (_IOC_NR(cmd) < V4L2_INT_IOCTLS) ?
+ v4l2_int_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd);
+ break;
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+ case 'v':
+ printk("v4l1 ioctl %s, dir=%s (0x%08x)\n",
+ (_IOC_NR(cmd) < V4L1_IOCTLS) ?
+ v4l1_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd);
+ break;
+#endif
+ case 'V':
+ printk("v4l2 ioctl %s, dir=%s (0x%08x)\n",
+ (_IOC_NR(cmd) < V4L2_IOCTLS) ?
+ v4l2_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd);
+ break;
+
+ default:
+ printk("unknown ioctl '%c', dir=%s, #%d (0x%08x)\n",
+ _IOC_TYPE(cmd), dir, _IOC_NR(cmd), cmd);
+ }
+}
+EXPORT_SYMBOL(v4l_printk_ioctl);
+
/*
* sysfs stuff
*/
@@ -69,11 +432,13 @@ struct video_device *video_device_alloc(void)
vfd = kzalloc(sizeof(*vfd),GFP_KERNEL);
return vfd;
}
+EXPORT_SYMBOL(video_device_alloc);
void video_device_release(struct video_device *vfd)
{
kfree(vfd);
}
+EXPORT_SYMBOL(video_device_release);
static void video_release(struct device *cd)
{
@@ -110,6 +475,7 @@ struct video_device* video_devdata(struct file *file)
{
return video_device[iminor(file->f_path.dentry->d_inode)];
}
+EXPORT_SYMBOL(video_devdata);
/*
* Open a video device - FIXME: Obsoleted
@@ -278,6 +644,7 @@ out:
kfree(mbuf);
return err;
}
+EXPORT_SYMBOL(video_usercopy);
/*
* open/release helper functions -- handle exclusive opens
@@ -297,6 +664,7 @@ int video_exclusive_open(struct inode *inode, struct file *file)
mutex_unlock(&vfl->lock);
return retval;
}
+EXPORT_SYMBOL(video_exclusive_open);
int video_exclusive_release(struct inode *inode, struct file *file)
{
@@ -305,41 +673,7 @@ int video_exclusive_release(struct inode *inode, struct file *file)
vfl->users--;
return 0;
}
-
-static char *v4l2_memory_names[] = {
- [V4L2_MEMORY_MMAP] = "mmap",
- [V4L2_MEMORY_USERPTR] = "userptr",
- [V4L2_MEMORY_OVERLAY] = "overlay",
-};
-
-
-/* FIXME: Those stuff are replicated also on v4l2-common.c */
-static char *v4l2_type_names_FIXME[] = {
- [V4L2_BUF_TYPE_VIDEO_CAPTURE] = "video-cap",
- [V4L2_BUF_TYPE_VIDEO_OVERLAY] = "video-over",
- [V4L2_BUF_TYPE_VIDEO_OUTPUT] = "video-out",
- [V4L2_BUF_TYPE_VBI_CAPTURE] = "vbi-cap",
- [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out",
- [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "sliced-vbi-out",
- [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-capture",
- [V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "video-out-over",
- [V4L2_BUF_TYPE_PRIVATE] = "private",
-};
-
-static char *v4l2_field_names_FIXME[] = {
- [V4L2_FIELD_ANY] = "any",
- [V4L2_FIELD_NONE] = "none",
- [V4L2_FIELD_TOP] = "top",
- [V4L2_FIELD_BOTTOM] = "bottom",
- [V4L2_FIELD_INTERLACED] = "interlaced",
- [V4L2_FIELD_SEQ_TB] = "seq-tb",
- [V4L2_FIELD_SEQ_BT] = "seq-bt",
- [V4L2_FIELD_ALTERNATE] = "alternate",
- [V4L2_FIELD_INTERLACED_TB] = "interlaced-tb",
- [V4L2_FIELD_INTERLACED_BT] = "interlaced-bt",
-};
-
-#define prt_names(a,arr) (((a)>=0)&&((a)<ARRAY_SIZE(arr)))?arr[a]:"unknown"
+EXPORT_SYMBOL(video_exclusive_release);
static void dbgbuf(unsigned int cmd, struct video_device *vfd,
struct v4l2_buffer *p)
@@ -354,10 +688,10 @@ static void dbgbuf(unsigned int cmd, struct video_device *vfd,
(int)(p->timestamp.tv_sec%60),
p->timestamp.tv_usec,
p->index,
- prt_names(p->type,v4l2_type_names_FIXME),
- p->bytesused,p->flags,
- p->field,p->sequence,
- prt_names(p->memory,v4l2_memory_names),
+ prt_names(p->type, v4l2_type_names),
+ p->bytesused, p->flags,
+ p->field, p->sequence,
+ prt_names(p->memory, v4l2_memory_names),
p->m.userptr, p->length);
dbgarg2 ("timecode= %02d:%02d:%02d type=%d, "
"flags=0x%08d, frames=%d, userbits=0x%08x\n",
@@ -382,8 +716,8 @@ static inline void v4l_print_pix_fmt (struct video_device *vfd,
(fmt->pixelformat >> 8) & 0xff,
(fmt->pixelformat >> 16) & 0xff,
(fmt->pixelformat >> 24) & 0xff,
- prt_names(fmt->field,v4l2_field_names_FIXME),
- fmt->bytesperline,fmt->sizeimage,fmt->colorspace);
+ prt_names(fmt->field, v4l2_field_names),
+ fmt->bytesperline, fmt->sizeimage, fmt->colorspace);
};
@@ -597,7 +931,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
/* FIXME: Should be one dump per type */
dbgarg (cmd, "type=%s\n", prt_names(type,
- v4l2_type_names_FIXME));
+ v4l2_type_names));
switch (type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
@@ -650,7 +984,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
/* FIXME: Should be one dump per type */
dbgarg (cmd, "type=%s\n", prt_names(f->type,
- v4l2_type_names_FIXME));
+ v4l2_type_names));
switch (f->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
@@ -702,7 +1036,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
/* FIXME: Should be one dump per type */
dbgarg (cmd, "type=%s\n", prt_names(f->type,
- v4l2_type_names_FIXME));
+ v4l2_type_names));
switch (f->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
if (vfd->vidioc_try_fmt_cap)
@@ -768,8 +1102,8 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
ret=vfd->vidioc_reqbufs(file, fh, p);
dbgarg (cmd, "count=%d, type=%s, memory=%s\n",
p->count,
- prt_names(p->type,v4l2_type_names_FIXME),
- prt_names(p->memory,v4l2_memory_names));
+ prt_names(p->type, v4l2_type_names),
+ prt_names(p->memory, v4l2_memory_names));
break;
}
case VIDIOC_QUERYBUF:
@@ -858,7 +1192,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
enum v4l2_buf_type i = *(int *)arg;
if (!vfd->vidioc_streamon)
break;
- dbgarg (cmd, "type=%s\n", prt_names(i,v4l2_type_names_FIXME));
+ dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names));
ret=vfd->vidioc_streamon(file, fh,i);
break;
}
@@ -868,7 +1202,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
if (!vfd->vidioc_streamoff)
break;
- dbgarg (cmd, "type=%s\n", prt_names(i,v4l2_type_names_FIXME));
+ dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names));
ret=vfd->vidioc_streamoff(file, fh, i);
break;
}
@@ -1624,7 +1958,7 @@ out:
kfree(mbuf);
return err;
}
-
+EXPORT_SYMBOL(video_ioctl2);
static const struct file_operations video_fops;
@@ -1743,6 +2077,7 @@ fail_minor:
mutex_unlock(&videodev_lock);
return ret;
}
+EXPORT_SYMBOL(video_register_device);
/**
* video_unregister_device - unregister a video4linux device
@@ -1762,6 +2097,7 @@ void video_unregister_device(struct video_device *vfd)
device_unregister(&vfd->class_dev);
mutex_unlock(&videodev_lock);
}
+EXPORT_SYMBOL(video_unregister_device);
/*
* Video fs operations
@@ -1806,16 +2142,6 @@ static void __exit videodev_exit(void)
module_init(videodev_init)
module_exit(videodev_exit)
-EXPORT_SYMBOL(video_register_device);
-EXPORT_SYMBOL(video_unregister_device);
-EXPORT_SYMBOL(video_devdata);
-EXPORT_SYMBOL(video_usercopy);
-EXPORT_SYMBOL(video_exclusive_open);
-EXPORT_SYMBOL(video_exclusive_release);
-EXPORT_SYMBOL(video_ioctl2);
-EXPORT_SYMBOL(video_device_alloc);
-EXPORT_SYMBOL(video_device_release);
-
MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab <mchehab@infradead.org>");
MODULE_DESCRIPTION("Device registrar for Video4Linux drivers v2");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/zoran.h b/drivers/media/video/zoran.h
index 937c4a616c0..498a43c1f2b 100644
--- a/drivers/media/video/zoran.h
+++ b/drivers/media/video/zoran.h
@@ -221,15 +221,15 @@ enum zoran_map_mode {
};
enum gpio_type {
- GPIO_JPEG_SLEEP = 0,
- GPIO_JPEG_RESET,
- GPIO_JPEG_FRAME,
- GPIO_VID_DIR,
- GPIO_VID_EN,
- GPIO_VID_RESET,
- GPIO_CLK_SEL1,
- GPIO_CLK_SEL2,
- GPIO_MAX,
+ ZR_GPIO_JPEG_SLEEP = 0,
+ ZR_GPIO_JPEG_RESET,
+ ZR_GPIO_JPEG_FRAME,
+ ZR_GPIO_VID_DIR,
+ ZR_GPIO_VID_EN,
+ ZR_GPIO_VID_RESET,
+ ZR_GPIO_CLK_SEL1,
+ ZR_GPIO_CLK_SEL2,
+ ZR_GPIO_MAX,
};
enum gpcs_type {
@@ -378,11 +378,11 @@ struct card_info {
u32 jpeg_int; /* JPEG interrupt */
u32 vsync_int; /* VSYNC interrupt */
- s8 gpio[GPIO_MAX];
+ s8 gpio[ZR_GPIO_MAX];
u8 gpcs[GPCS_MAX];
struct vfe_polarity vfe_pol;
- u8 gpio_pol[GPIO_MAX];
+ u8 gpio_pol[ZR_GPIO_MAX];
/* is the /GWS line conected? */
u8 gws_not_connected;
diff --git a/drivers/media/video/zoran_device.c b/drivers/media/video/zoran_device.c
index 68c7c505587..f97c2069205 100644
--- a/drivers/media/video/zoran_device.c
+++ b/drivers/media/video/zoran_device.c
@@ -250,7 +250,7 @@ void
jpeg_codec_sleep (struct zoran *zr,
int sleep)
{
- GPIO(zr, zr->card.gpio[GPIO_JPEG_SLEEP], !sleep);
+ GPIO(zr, zr->card.gpio[ZR_GPIO_JPEG_SLEEP], !sleep);
if (!sleep) {
dprintk(3,
KERN_DEBUG
@@ -277,9 +277,9 @@ jpeg_codec_reset (struct zoran *zr)
0);
udelay(2);
} else {
- GPIO(zr, zr->card.gpio[GPIO_JPEG_RESET], 0);
+ GPIO(zr, zr->card.gpio[ZR_GPIO_JPEG_RESET], 0);
udelay(2);
- GPIO(zr, zr->card.gpio[GPIO_JPEG_RESET], 1);
+ GPIO(zr, zr->card.gpio[ZR_GPIO_JPEG_RESET], 1);
udelay(2);
}
@@ -688,7 +688,7 @@ static inline void
set_frame (struct zoran *zr,
int val)
{
- GPIO(zr, zr->card.gpio[GPIO_JPEG_FRAME], val);
+ GPIO(zr, zr->card.gpio[ZR_GPIO_JPEG_FRAME], val);
}
static void
@@ -704,8 +704,8 @@ set_videobus_dir (struct zoran *zr,
GPIO(zr, 5, 1);
break;
default:
- GPIO(zr, zr->card.gpio[GPIO_VID_DIR],
- zr->card.gpio_pol[GPIO_VID_DIR] ? !val : val);
+ GPIO(zr, zr->card.gpio[ZR_GPIO_VID_DIR],
+ zr->card.gpio_pol[ZR_GPIO_VID_DIR] ? !val : val);
break;
}
}
diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c
index 1fdbb46de7f..1b44784d0ef 100644
--- a/drivers/media/video/zr364xx.c
+++ b/drivers/media/video/zr364xx.c
@@ -93,6 +93,8 @@ static struct usb_device_id device_table[] = {
{USB_DEVICE(0x06d6, 0x0034), .driver_info = METHOD0 },
{USB_DEVICE(0x0a17, 0x0062), .driver_info = METHOD2 },
{USB_DEVICE(0x06d6, 0x003b), .driver_info = METHOD0 },
+ {USB_DEVICE(0x0a17, 0x004e), .driver_info = METHOD2 },
+ {USB_DEVICE(0x041e, 0x405d), .driver_info = METHOD2 },
{} /* Terminating entry */
};
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index bfda731696f..0c303c84b37 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -1481,15 +1481,15 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
if (pci_enable_device_mem(pdev)) {
- kfree(ioc);
printk(MYIOC_s_ERR_FMT "pci_enable_device_mem() "
"failed\n", ioc->name);
+ kfree(ioc);
return r;
}
if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) {
- kfree(ioc);
printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with "
"MEM failed\n", ioc->name);
+ kfree(ioc);
return r;
}
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
index d83ea96fe13..caadc68c300 100644
--- a/drivers/message/fusion/mptbase.h
+++ b/drivers/message/fusion/mptbase.h
@@ -923,7 +923,7 @@ extern struct proc_dir_entry *mpt_proc_root_dir;
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
#endif /* } __KERNEL__ */
-#if defined(__alpha__) || defined(__sparc_v9__) || defined(__ia64__) || defined(__x86_64__) || defined(__powerpc__)
+#ifdef CONFIG_64BIT
#define CAST_U32_TO_PTR(x) ((void *)(u64)x)
#define CAST_PTR_TO_U32(x) ((u32)(u64)x)
#else
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 1abc95ca9df..982e27b86d1 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -258,6 +258,23 @@ config THINKPAD_ACPI_BAY
If you are not sure, say Y here.
+config THINKPAD_ACPI_VIDEO
+ bool "Video output control support"
+ depends on THINKPAD_ACPI
+ default y
+ ---help---
+ Allows the thinkpad_acpi driver to provide an interface to control
+ the various video output ports.
+
+ This feature often won't work well, depending on ThinkPad model,
+ display state, video output devices in use, whether there is a X
+ server running, phase of the moon, and the current mood of
+ Schroedinger's cat. If you can use X.org's RandR to control
+ your ThinkPad's video output ports instead of this feature,
+ don't think twice: do it and say N here to save some memory.
+
+ If you are not sure, say Y here.
+
config THINKPAD_ACPI_HOTKEY_POLL
bool "Suport NVRAM polling for hot keys"
depends on THINKPAD_ACPI
diff --git a/drivers/misc/acer-wmi.c b/drivers/misc/acer-wmi.c
index d7aea93081f..74d12b4a3ab 100644
--- a/drivers/misc/acer-wmi.c
+++ b/drivers/misc/acer-wmi.c
@@ -273,6 +273,15 @@ static struct dmi_system_id acer_quirks[] = {
},
{
.callback = dmi_matched,
+ .ident = "Acer TravelMate 4200",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4200"),
+ },
+ .driver_data = &quirk_acer_travelmate_2490,
+ },
+ {
+ .callback = dmi_matched,
.ident = "Medion MD 98300",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
diff --git a/drivers/misc/intel_menlow.c b/drivers/misc/intel_menlow.c
index f70984ab1e1..de16e88eb8d 100644
--- a/drivers/misc/intel_menlow.c
+++ b/drivers/misc/intel_menlow.c
@@ -170,10 +170,13 @@ static int intel_menlow_memory_add(struct acpi_device *device)
cdev = thermal_cooling_device_register("Memory controller", device,
&memory_cooling_ops);
- acpi_driver_data(device) = cdev;
- if (!cdev)
- result = -ENODEV;
- else {
+ if (IS_ERR(cdev)) {
+ result = PTR_ERR(cdev);
+ goto end;
+ }
+
+ if (cdev) {
+ acpi_driver_data(device) = cdev;
result = sysfs_create_link(&device->dev.kobj,
&cdev->device.kobj, "thermal_cooling");
if (result)
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index e2c7edd206a..bb269d0c677 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -221,6 +221,7 @@ static struct {
u32 hotkey:1;
u32 hotkey_mask:1;
u32 hotkey_wlsw:1;
+ u32 hotkey_tablet:1;
u32 light:1;
u32 light_status:1;
u32 bright_16levels:1;
@@ -301,6 +302,13 @@ TPACPI_HANDLE(hkey, ec, "\\_SB.HKEY", /* 600e/x, 770e, 770x */
"HKEY", /* all others */
); /* 570 */
+TPACPI_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA", /* 570 */
+ "\\_SB.PCI0.AGP0.VID0", /* 600e/x, 770x */
+ "\\_SB.PCI0.VID0", /* 770e */
+ "\\_SB.PCI0.VID", /* A21e, G4x, R50e, X30, X40 */
+ "\\_SB.PCI0.AGP.VID", /* all others */
+ ); /* R30, R31 */
+
/*************************************************************************
* ACPI helpers
@@ -1053,6 +1061,9 @@ static struct attribute_set *hotkey_dev_attributes;
#define HOTKEY_CONFIG_CRITICAL_END
#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
+/* HKEY.MHKG() return bits */
+#define TP_HOTKEY_TABLET_MASK (1 << 3)
+
static int hotkey_get_wlsw(int *status)
{
if (!acpi_evalf(hkey_handle, status, "WLSW", "d"))
@@ -1060,6 +1071,16 @@ static int hotkey_get_wlsw(int *status)
return 0;
}
+static int hotkey_get_tablet_mode(int *status)
+{
+ int s;
+
+ if (!acpi_evalf(hkey_handle, &s, "MHKG", "d"))
+ return -EIO;
+
+ return ((s & TP_HOTKEY_TABLET_MASK) != 0);
+}
+
/*
* Call with hotkey_mutex held
*/
@@ -1154,15 +1175,31 @@ static void tpacpi_input_send_radiosw(void)
{
int wlsw;
- mutex_lock(&tpacpi_inputdev_send_mutex);
-
if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) {
+ mutex_lock(&tpacpi_inputdev_send_mutex);
+
input_report_switch(tpacpi_inputdev,
SW_RADIO, !!wlsw);
input_sync(tpacpi_inputdev);
+
+ mutex_unlock(&tpacpi_inputdev_send_mutex);
}
+}
+
+static void tpacpi_input_send_tabletsw(void)
+{
+ int state;
+
+ if (tp_features.hotkey_tablet &&
+ !hotkey_get_tablet_mode(&state)) {
+ mutex_lock(&tpacpi_inputdev_send_mutex);
- mutex_unlock(&tpacpi_inputdev_send_mutex);
+ input_report_switch(tpacpi_inputdev,
+ SW_TABLET_MODE, !!state);
+ input_sync(tpacpi_inputdev);
+
+ mutex_unlock(&tpacpi_inputdev_send_mutex);
+ }
}
static void tpacpi_input_send_key(unsigned int scancode)
@@ -1417,6 +1454,14 @@ static void hotkey_poll_setup_safe(int may_warn)
mutex_unlock(&hotkey_mutex);
}
+#else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
+
+static void hotkey_poll_setup_safe(int __unused)
+{
+}
+
+#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
+
static int hotkey_inputdev_open(struct input_dev *dev)
{
switch (tpacpi_lifecycle) {
@@ -1444,7 +1489,6 @@ static void hotkey_inputdev_close(struct input_dev *dev)
if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING)
hotkey_poll_setup_safe(0);
}
-#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
/* sysfs hotkey enable ------------------------------------------------- */
static ssize_t hotkey_enable_show(struct device *dev,
@@ -1666,6 +1710,29 @@ static void hotkey_radio_sw_notify_change(void)
"hotkey_radio_sw");
}
+/* sysfs hotkey tablet mode (pollable) --------------------------------- */
+static ssize_t hotkey_tablet_mode_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int res, s;
+ res = hotkey_get_tablet_mode(&s);
+ if (res < 0)
+ return res;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", !!s);
+}
+
+static struct device_attribute dev_attr_hotkey_tablet_mode =
+ __ATTR(hotkey_tablet_mode, S_IRUGO, hotkey_tablet_mode_show, NULL);
+
+static void hotkey_tablet_mode_notify_change(void)
+{
+ if (tp_features.hotkey_tablet)
+ sysfs_notify(&tpacpi_pdev->dev.kobj, NULL,
+ "hotkey_tablet_mode");
+}
+
/* sysfs hotkey report_mode -------------------------------------------- */
static ssize_t hotkey_report_mode_show(struct device *dev,
struct device_attribute *attr,
@@ -1878,7 +1945,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
str_supported(tp_features.hotkey));
if (tp_features.hotkey) {
- hotkey_dev_attributes = create_attr_set(12, NULL);
+ hotkey_dev_attributes = create_attr_set(13, NULL);
if (!hotkey_dev_attributes)
return -ENOMEM;
res = add_many_to_attr_set(hotkey_dev_attributes,
@@ -1957,6 +2024,18 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
&dev_attr_hotkey_radio_sw.attr);
}
+ /* For X41t, X60t, X61t Tablets... */
+ if (!res && acpi_evalf(hkey_handle, &status, "MHKG", "qd")) {
+ tp_features.hotkey_tablet = 1;
+ printk(TPACPI_INFO
+ "possible tablet mode switch found; "
+ "ThinkPad in %s mode\n",
+ (status & TP_HOTKEY_TABLET_MASK)?
+ "tablet" : "laptop");
+ res = add_to_attr_set(hotkey_dev_attributes,
+ &dev_attr_hotkey_tablet_mode.attr);
+ }
+
if (!res)
res = register_attr_set_with_sysfs(
hotkey_dev_attributes,
@@ -2006,6 +2085,10 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
set_bit(EV_SW, tpacpi_inputdev->evbit);
set_bit(SW_RADIO, tpacpi_inputdev->swbit);
}
+ if (tp_features.hotkey_tablet) {
+ set_bit(EV_SW, tpacpi_inputdev->evbit);
+ set_bit(SW_TABLET_MODE, tpacpi_inputdev->swbit);
+ }
dbg_printk(TPACPI_DBG_INIT,
"enabling hot key handling\n");
@@ -2023,12 +2106,12 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
(hotkey_report_mode < 2) ?
"enabled" : "disabled");
-#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
tpacpi_inputdev->open = &hotkey_inputdev_open;
tpacpi_inputdev->close = &hotkey_inputdev_close;
hotkey_poll_setup_safe(1);
-#endif
+ tpacpi_input_send_radiosw();
+ tpacpi_input_send_tabletsw();
}
return (tp_features.hotkey)? 0 : 1;
@@ -2156,11 +2239,15 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
/* 0x5000-0x5FFF: human interface helpers */
switch (hkey) {
case 0x5010: /* Lenovo new BIOS: brightness changed */
- case 0x5009: /* X61t: swivel up (tablet mode) */
- case 0x500a: /* X61t: swivel down (normal mode) */
case 0x500b: /* X61t: tablet pen inserted into bay */
case 0x500c: /* X61t: tablet pen removed from bay */
break;
+ case 0x5009: /* X41t-X61t: swivel up (tablet mode) */
+ case 0x500a: /* X41t-X61t: swivel down (normal mode) */
+ tpacpi_input_send_tabletsw();
+ hotkey_tablet_mode_notify_change();
+ send_acpi_ev = 0;
+ break;
case 0x5001:
case 0x5002:
/* LID switch events. Do not propagate */
@@ -2219,11 +2306,10 @@ static void hotkey_resume(void)
"from firmware\n");
tpacpi_input_send_radiosw();
hotkey_radio_sw_notify_change();
+ hotkey_tablet_mode_notify_change();
hotkey_wakeup_reason_notify_change();
hotkey_wakeup_hotunplug_complete_notify_change();
-#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
hotkey_poll_setup_safe(0);
-#endif
}
/* procfs -------------------------------------------------------------- */
@@ -2676,6 +2762,8 @@ static struct ibm_struct wan_driver_data = {
* Video subdriver
*/
+#ifdef CONFIG_THINKPAD_ACPI_VIDEO
+
enum video_access_mode {
TPACPI_VIDEO_NONE = 0,
TPACPI_VIDEO_570, /* 570 */
@@ -2703,13 +2791,6 @@ static int video_orig_autosw;
static int video_autosw_get(void);
static int video_autosw_set(int enable);
-TPACPI_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA", /* 570 */
- "\\_SB.PCI0.AGP0.VID0", /* 600e/x, 770x */
- "\\_SB.PCI0.VID0", /* 770e */
- "\\_SB.PCI0.VID", /* A21e, G4x, R50e, X30, X40 */
- "\\_SB.PCI0.AGP.VID", /* all others */
- ); /* R30, R31 */
-
TPACPI_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID"); /* G41 */
static int __init video_init(struct ibm_init_struct *iibm)
@@ -3019,6 +3100,8 @@ static struct ibm_struct video_driver_data = {
.exit = video_exit,
};
+#endif /* CONFIG_THINKPAD_ACPI_VIDEO */
+
/*************************************************************************
* Light (thinklight) subdriver
*/
@@ -5803,10 +5886,12 @@ static struct ibm_init_struct ibms_init[] __initdata = {
.init = wan_init,
.data = &wan_driver_data,
},
+#ifdef CONFIG_THINKPAD_ACPI_VIDEO
{
.init = video_init,
.data = &video_driver_data,
},
+#endif
{
.init = light_init,
.data = &light_driver_data,
@@ -5918,7 +6003,7 @@ MODULE_PARM_DESC(hotkey_report_mode,
#define TPACPI_PARAM(feature) \
module_param_call(feature, set_ibm_param, NULL, NULL, 0); \
- MODULE_PARM_DESC(feature, "Simulates thinkpad-aci procfs command " \
+ MODULE_PARM_DESC(feature, "Simulates thinkpad-acpi procfs command " \
"at module load, see documentation")
TPACPI_PARAM(hotkey);
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index f337800076c..a0f0e605d63 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -90,6 +90,11 @@ config MACVLAN
This allows one to create virtual interfaces that map packets to
or from specific MAC addresses to a particular interface.
+ Macvlan devices can be added using the "ip" command from the
+ iproute2 package starting with the iproute2-2.6.23 release:
+
+ "ip link add link <real dev> [ address MAC ] [ NAME ] type macvlan"
+
To compile this driver as a module, choose M here: the module
will be called macvlan.
@@ -2363,6 +2368,7 @@ config GELIC_NET
config GELIC_WIRELESS
bool "PS3 Wireless support"
depends on GELIC_NET
+ select WIRELESS_EXT
help
This option adds the support for the wireless feature of PS3.
If you have the wireless-less model of PS3 or have no plan to
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 471c7f3e8a4..15853be4680 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -56,8 +56,8 @@
#define DRV_MODULE_NAME "bnx2"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "1.7.3"
-#define DRV_MODULE_RELDATE "January 29, 2008"
+#define DRV_MODULE_VERSION "1.7.4"
+#define DRV_MODULE_RELDATE "February 18, 2008"
#define RUN_AT(x) (jiffies + (x))
@@ -1273,14 +1273,20 @@ bnx2_set_link(struct bnx2 *bp)
if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
(CHIP_NUM(bp) == CHIP_NUM_5706)) {
- u32 val;
+ u32 val, an_dbg;
if (bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN) {
bnx2_5706s_force_link_dn(bp, 0);
bp->phy_flags &= ~BNX2_PHY_FLAG_FORCED_DOWN;
}
val = REG_RD(bp, BNX2_EMAC_STATUS);
- if (val & BNX2_EMAC_STATUS_LINK)
+
+ bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
+ bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
+ bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
+
+ if ((val & BNX2_EMAC_STATUS_LINK) &&
+ !(an_dbg & MISC_SHDW_AN_DBG_NOSYNC))
bmsr |= BMSR_LSTATUS;
else
bmsr &= ~BMSR_LSTATUS;
@@ -5356,11 +5362,15 @@ bnx2_test_intr(struct bnx2 *bp)
return -ENODEV;
}
+/* Determining link for parallel detection. */
static int
bnx2_5706_serdes_has_link(struct bnx2 *bp)
{
u32 mode_ctl, an_dbg, exp;
+ if (bp->phy_flags & BNX2_PHY_FLAG_NO_PARALLEL)
+ return 0;
+
bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_MODE_CTL);
bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &mode_ctl);
@@ -5390,13 +5400,6 @@ bnx2_5706_serdes_timer(struct bnx2 *bp)
int check_link = 1;
spin_lock(&bp->phy_lock);
- if (bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN) {
- bnx2_5706s_force_link_dn(bp, 0);
- bp->phy_flags &= ~BNX2_PHY_FLAG_FORCED_DOWN;
- spin_unlock(&bp->phy_lock);
- return;
- }
-
if (bp->serdes_an_pending) {
bp->serdes_an_pending--;
check_link = 0;
@@ -5420,7 +5423,6 @@ bnx2_5706_serdes_timer(struct bnx2 *bp)
(bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT)) {
u32 phy2;
- check_link = 0;
bnx2_write_phy(bp, 0x17, 0x0f01);
bnx2_read_phy(bp, 0x15, &phy2);
if (phy2 & 0x20) {
@@ -5435,17 +5437,21 @@ bnx2_5706_serdes_timer(struct bnx2 *bp)
} else
bp->current_interval = bp->timer_interval;
- if (bp->link_up && (bp->autoneg & AUTONEG_SPEED) && check_link) {
+ if (check_link) {
u32 val;
bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &val);
bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &val);
- if (val & MISC_SHDW_AN_DBG_NOSYNC) {
- bnx2_5706s_force_link_dn(bp, 1);
- bp->phy_flags |= BNX2_PHY_FLAG_FORCED_DOWN;
- }
+ if (bp->link_up && (val & MISC_SHDW_AN_DBG_NOSYNC)) {
+ if (!(bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN)) {
+ bnx2_5706s_force_link_dn(bp, 1);
+ bp->phy_flags |= BNX2_PHY_FLAG_FORCED_DOWN;
+ } else
+ bnx2_set_link(bp);
+ } else if (!bp->link_up && !(val & MISC_SHDW_AN_DBG_NOSYNC))
+ bnx2_set_link(bp);
}
spin_unlock(&bp->phy_lock);
}
@@ -7326,7 +7332,15 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
bp->flags |= BNX2_FLAG_NO_WOL;
bp->wol = 0;
}
- if (CHIP_NUM(bp) != CHIP_NUM_5706) {
+ if (CHIP_NUM(bp) == CHIP_NUM_5706) {
+ /* Don't do parallel detect on this board because of
+ * some board problems. The link will not go down
+ * if we do parallel detect.
+ */
+ if (pdev->subsystem_vendor == PCI_VENDOR_ID_HP &&
+ pdev->subsystem_device == 0x310c)
+ bp->phy_flags |= BNX2_PHY_FLAG_NO_PARALLEL;
+ } else {
bp->phy_addr = 2;
if (reg & BNX2_SHARED_HW_CFG_PHY_2_5G)
bp->phy_flags |= BNX2_PHY_FLAG_2_5G_CAPABLE;
diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h
index 3aa0364942e..1eaf5bb3d9c 100644
--- a/drivers/net/bnx2.h
+++ b/drivers/net/bnx2.h
@@ -6673,6 +6673,7 @@ struct bnx2 {
#define BNX2_PHY_FLAG_DIS_EARLY_DAC 0x00000400
#define BNX2_PHY_FLAG_REMOTE_PHY_CAP 0x00000800
#define BNX2_PHY_FLAG_FORCED_DOWN 0x00001000
+#define BNX2_PHY_FLAG_NO_PARALLEL 0x00002000
u32 mii_bmcr;
u32 mii_bmsr;
diff --git a/drivers/net/bnx2x.c b/drivers/net/bnx2x.c
index afc7f34b1dc..8af142ccf37 100644
--- a/drivers/net/bnx2x.c
+++ b/drivers/net/bnx2x.c
@@ -1,6 +1,6 @@
/* bnx2x.c: Broadcom Everest network driver.
*
- * Copyright (c) 2007 Broadcom Corporation
+ * Copyright (c) 2007-2008 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -10,13 +10,13 @@
* Based on code from Michael Chan's bnx2 driver
* UDP CSUM errata workaround by Arik Gendelman
* Slowpath rework by Vladislav Zolotarov
- * Statistics and Link managment by Yitchak Gertner
+ * Statistics and Link management by Yitchak Gertner
*
*/
/* define this to make the driver freeze on error
* to allow getting debug info
- * (you will need to reboot afterwords)
+ * (you will need to reboot afterwards)
*/
/*#define BNX2X_STOP_ON_ERROR*/
@@ -63,22 +63,21 @@
#include "bnx2x.h"
#include "bnx2x_init.h"
-#define DRV_MODULE_VERSION "0.40.15"
-#define DRV_MODULE_RELDATE "$DateTime: 2007/11/15 07:28:37 $"
-#define BNX2X_BC_VER 0x040009
+#define DRV_MODULE_VERSION "1.40.22"
+#define DRV_MODULE_RELDATE "2007/11/27"
+#define BNX2X_BC_VER 0x040200
/* Time in jiffies before concluding the transmitter is hung. */
#define TX_TIMEOUT (5*HZ)
static char version[] __devinitdata =
- "Broadcom NetXtreme II 577xx 10Gigabit Ethernet Driver "
+ "Broadcom NetXtreme II 5771X 10Gigabit Ethernet Driver "
DRV_MODULE_NAME " " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
MODULE_AUTHOR("Eliezer Tamir <eliezert@broadcom.com>");
MODULE_DESCRIPTION("Broadcom NetXtreme II BCM57710 Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_MODULE_VERSION);
-MODULE_INFO(cvs_version, "$Revision: #356 $");
static int use_inta;
static int poll;
@@ -94,8 +93,8 @@ module_param(debug, int, 0);
MODULE_PARM_DESC(use_inta, "use INT#A instead of MSI-X");
MODULE_PARM_DESC(poll, "use polling (for debug)");
MODULE_PARM_DESC(onefunc, "enable only first function");
-MODULE_PARM_DESC(nomcp, "ignore managment CPU (Implies onefunc)");
-MODULE_PARM_DESC(debug, "defualt debug msglevel");
+MODULE_PARM_DESC(nomcp, "ignore management CPU (Implies onefunc)");
+MODULE_PARM_DESC(debug, "default debug msglevel");
#ifdef BNX2X_MULTI
module_param(use_multi, int, 0);
@@ -298,8 +297,7 @@ static void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32)
static int bnx2x_mc_assert(struct bnx2x *bp)
{
- int i, j;
- int rc = 0;
+ int i, j, rc = 0;
char last_idx;
const char storm[] = {"XTCU"};
const u32 intmem_base[] = {
@@ -313,8 +311,9 @@ static int bnx2x_mc_assert(struct bnx2x *bp)
for (i = 0; i < 4; i++) {
last_idx = REG_RD8(bp, XSTORM_ASSERT_LIST_INDEX_OFFSET +
intmem_base[i]);
- BNX2X_ERR("DATA %cSTORM_ASSERT_LIST_INDEX 0x%x\n",
- storm[i], last_idx);
+ if (last_idx)
+ BNX2X_LOG("DATA %cSTORM_ASSERT_LIST_INDEX 0x%x\n",
+ storm[i], last_idx);
/* print the asserts */
for (j = 0; j < STROM_ASSERT_ARRAY_SIZE; j++) {
@@ -330,7 +329,7 @@ static int bnx2x_mc_assert(struct bnx2x *bp)
intmem_base[i]);
if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) {
- BNX2X_ERR("DATA %cSTORM_ASSERT_INDEX 0x%x ="
+ BNX2X_LOG("DATA %cSTORM_ASSERT_INDEX 0x%x ="
" 0x%08x 0x%08x 0x%08x 0x%08x\n",
storm[i], j, row3, row2, row1, row0);
rc++;
@@ -341,6 +340,7 @@ static int bnx2x_mc_assert(struct bnx2x *bp)
}
return rc;
}
+
static void bnx2x_fw_dump(struct bnx2x *bp)
{
u32 mark, offset;
@@ -348,21 +348,22 @@ static void bnx2x_fw_dump(struct bnx2x *bp)
int word;
mark = REG_RD(bp, MCP_REG_MCPR_SCRATCH + 0xf104);
- printk(KERN_ERR PFX "begin fw dump (mark 0x%x)\n", mark);
+ mark = ((mark + 0x3) & ~0x3);
+ printk(KERN_ERR PFX "begin fw dump (mark 0x%x)\n" KERN_ERR, mark);
for (offset = mark - 0x08000000; offset <= 0xF900; offset += 0x8*4) {
for (word = 0; word < 8; word++)
data[word] = htonl(REG_RD(bp, MCP_REG_MCPR_SCRATCH +
offset + 4*word));
data[8] = 0x0;
- printk(KERN_ERR PFX "%s", (char *)data);
+ printk(KERN_CONT "%s", (char *)data);
}
for (offset = 0xF108; offset <= mark - 0x08000000; offset += 0x8*4) {
for (word = 0; word < 8; word++)
data[word] = htonl(REG_RD(bp, MCP_REG_MCPR_SCRATCH +
offset + 4*word));
data[8] = 0x0;
- printk(KERN_ERR PFX "%s", (char *)data);
+ printk(KERN_CONT "%s", (char *)data);
}
printk("\n" KERN_ERR PFX "end of fw dump\n");
}
@@ -427,10 +428,10 @@ static void bnx2x_panic_dump(struct bnx2x *bp)
}
}
- BNX2X_ERR("def_c_idx(%u) def_u_idx(%u) def_t_idx(%u)"
- " def_x_idx(%u) def_att_idx(%u) attn_state(%u)"
+ BNX2X_ERR("def_c_idx(%u) def_u_idx(%u) def_x_idx(%u)"
+ " def_t_idx(%u) def_att_idx(%u) attn_state(%u)"
" spq_prod_idx(%u)\n",
- bp->def_c_idx, bp->def_u_idx, bp->def_t_idx, bp->def_x_idx,
+ bp->def_c_idx, bp->def_u_idx, bp->def_x_idx, bp->def_t_idx,
bp->def_att_idx, bp->attn_state, bp->spq_prod_idx);
@@ -441,7 +442,7 @@ static void bnx2x_panic_dump(struct bnx2x *bp)
DP(BNX2X_MSG_STATS, "stats_state - DISABLE\n");
}
-static void bnx2x_enable_int(struct bnx2x *bp)
+static void bnx2x_int_enable(struct bnx2x *bp)
{
int port = bp->port;
u32 addr = port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0;
@@ -454,18 +455,26 @@ static void bnx2x_enable_int(struct bnx2x *bp)
HC_CONFIG_0_REG_ATTN_BIT_EN_0);
} else {
val |= (HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
+ HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 |
HC_CONFIG_0_REG_INT_LINE_EN_0 |
HC_CONFIG_0_REG_ATTN_BIT_EN_0);
+
+ /* Errata A0.158 workaround */
+ DP(NETIF_MSG_INTR, "write %x to HC %d (addr 0x%x) MSI-X %d\n",
+ val, port, addr, msix);
+
+ REG_WR(bp, addr, val);
+
val &= ~HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0;
}
- DP(NETIF_MSG_INTR, "write %x to HC %d (addr 0x%x) msi %d\n",
+ DP(NETIF_MSG_INTR, "write %x to HC %d (addr 0x%x) MSI-X %d\n",
val, port, addr, msix);
REG_WR(bp, addr, val);
}
-static void bnx2x_disable_int(struct bnx2x *bp)
+static void bnx2x_int_disable(struct bnx2x *bp)
{
int port = bp->port;
u32 addr = port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0;
@@ -484,15 +493,15 @@ static void bnx2x_disable_int(struct bnx2x *bp)
BNX2X_ERR("BUG! proper val not read from IGU!\n");
}
-static void bnx2x_disable_int_sync(struct bnx2x *bp)
+static void bnx2x_int_disable_sync(struct bnx2x *bp)
{
int msix = (bp->flags & USING_MSIX_FLAG) ? 1 : 0;
int i;
atomic_inc(&bp->intr_sem);
- /* prevent the HW from sending interrupts*/
- bnx2x_disable_int(bp);
+ /* prevent the HW from sending interrupts */
+ bnx2x_int_disable(bp);
/* make sure all ISRs are done */
if (msix) {
@@ -775,6 +784,7 @@ static void bnx2x_sp_event(struct bnx2x_fastpath *fp,
mb(); /* force bnx2x_wait_ramrod to see the change */
return;
}
+
switch (command | bp->state) {
case (RAMROD_CMD_ID_ETH_PORT_SETUP | BNX2X_STATE_OPENING_WAIT4_PORT):
DP(NETIF_MSG_IFUP, "got setup ramrod\n");
@@ -787,20 +797,20 @@ static void bnx2x_sp_event(struct bnx2x_fastpath *fp,
fp->state = BNX2X_FP_STATE_HALTED;
break;
- case (RAMROD_CMD_ID_ETH_PORT_DEL | BNX2X_STATE_CLOSING_WAIT4_DELETE):
- DP(NETIF_MSG_IFDOWN, "got delete ramrod\n");
- bp->state = BNX2X_STATE_CLOSING_WAIT4_UNLOAD;
- break;
-
case (RAMROD_CMD_ID_ETH_CFC_DEL | BNX2X_STATE_CLOSING_WAIT4_HALT):
- DP(NETIF_MSG_IFDOWN, "got delete ramrod for MULTI[%d]\n", cid);
- bnx2x_fp(bp, cid, state) = BNX2X_FP_STATE_DELETED;
+ DP(NETIF_MSG_IFDOWN, "got delete ramrod for MULTI[%d]\n",
+ cid);
+ bnx2x_fp(bp, cid, state) = BNX2X_FP_STATE_CLOSED;
break;
case (RAMROD_CMD_ID_ETH_SET_MAC | BNX2X_STATE_OPEN):
DP(NETIF_MSG_IFUP, "got set mac ramrod\n");
break;
+ case (RAMROD_CMD_ID_ETH_SET_MAC | BNX2X_STATE_CLOSING_WAIT4_HALT):
+ DP(NETIF_MSG_IFUP, "got (un)set mac ramrod\n");
+ break;
+
default:
BNX2X_ERR("unexpected ramrod (%d) state is %x\n",
command, bp->state);
@@ -1179,12 +1189,175 @@ static u32 bnx2x_bits_dis(struct bnx2x *bp, u32 reg, u32 bits)
return val;
}
+static int bnx2x_hw_lock(struct bnx2x *bp, u32 resource)
+{
+ u32 cnt;
+ u32 lock_status;
+ u32 resource_bit = (1 << resource);
+ u8 func = bp->port;
+
+ /* Validating that the resource is within range */
+ if (resource > HW_LOCK_MAX_RESOURCE_VALUE) {
+ DP(NETIF_MSG_HW,
+ "resource(0x%x) > HW_LOCK_MAX_RESOURCE_VALUE(0x%x)\n",
+ resource, HW_LOCK_MAX_RESOURCE_VALUE);
+ return -EINVAL;
+ }
+
+ /* Validating that the resource is not already taken */
+ lock_status = REG_RD(bp, MISC_REG_DRIVER_CONTROL_1 + func*8);
+ if (lock_status & resource_bit) {
+ DP(NETIF_MSG_HW, "lock_status 0x%x resource_bit 0x%x\n",
+ lock_status, resource_bit);
+ return -EEXIST;
+ }
+
+ /* Try for 1 second every 5ms */
+ for (cnt = 0; cnt < 200; cnt++) {
+ /* Try to acquire the lock */
+ REG_WR(bp, MISC_REG_DRIVER_CONTROL_1 + func*8 + 4,
+ resource_bit);
+ lock_status = REG_RD(bp, MISC_REG_DRIVER_CONTROL_1 + func*8);
+ if (lock_status & resource_bit)
+ return 0;
+
+ msleep(5);
+ }
+ DP(NETIF_MSG_HW, "Timeout\n");
+ return -EAGAIN;
+}
+
+static int bnx2x_hw_unlock(struct bnx2x *bp, u32 resource)
+{
+ u32 lock_status;
+ u32 resource_bit = (1 << resource);
+ u8 func = bp->port;
+
+ /* Validating that the resource is within range */
+ if (resource > HW_LOCK_MAX_RESOURCE_VALUE) {
+ DP(NETIF_MSG_HW,
+ "resource(0x%x) > HW_LOCK_MAX_RESOURCE_VALUE(0x%x)\n",
+ resource, HW_LOCK_MAX_RESOURCE_VALUE);
+ return -EINVAL;
+ }
+
+ /* Validating that the resource is currently taken */
+ lock_status = REG_RD(bp, MISC_REG_DRIVER_CONTROL_1 + func*8);
+ if (!(lock_status & resource_bit)) {
+ DP(NETIF_MSG_HW, "lock_status 0x%x resource_bit 0x%x\n",
+ lock_status, resource_bit);
+ return -EFAULT;
+ }
+
+ REG_WR(bp, MISC_REG_DRIVER_CONTROL_1 + func*8, resource_bit);
+ return 0;
+}
+
+static int bnx2x_set_gpio(struct bnx2x *bp, int gpio_num, u32 mode)
+{
+ /* The GPIO should be swapped if swap register is set and active */
+ int gpio_port = (REG_RD(bp, NIG_REG_PORT_SWAP) &&
+ REG_RD(bp, NIG_REG_STRAP_OVERRIDE)) ^ bp->port;
+ int gpio_shift = gpio_num +
+ (gpio_port ? MISC_REGISTERS_GPIO_PORT_SHIFT : 0);
+ u32 gpio_mask = (1 << gpio_shift);
+ u32 gpio_reg;
+
+ if (gpio_num > MISC_REGISTERS_GPIO_3) {
+ BNX2X_ERR("Invalid GPIO %d\n", gpio_num);
+ return -EINVAL;
+ }
+
+ bnx2x_hw_lock(bp, HW_LOCK_RESOURCE_GPIO);
+ /* read GPIO and mask except the float bits */
+ gpio_reg = (REG_RD(bp, MISC_REG_GPIO) & MISC_REGISTERS_GPIO_FLOAT);
+
+ switch (mode) {
+ case MISC_REGISTERS_GPIO_OUTPUT_LOW:
+ DP(NETIF_MSG_LINK, "Set GPIO %d (shift %d) -> output low\n",
+ gpio_num, gpio_shift);
+ /* clear FLOAT and set CLR */
+ gpio_reg &= ~(gpio_mask << MISC_REGISTERS_GPIO_FLOAT_POS);
+ gpio_reg |= (gpio_mask << MISC_REGISTERS_GPIO_CLR_POS);
+ break;
+
+ case MISC_REGISTERS_GPIO_OUTPUT_HIGH:
+ DP(NETIF_MSG_LINK, "Set GPIO %d (shift %d) -> output high\n",
+ gpio_num, gpio_shift);
+ /* clear FLOAT and set SET */
+ gpio_reg &= ~(gpio_mask << MISC_REGISTERS_GPIO_FLOAT_POS);
+ gpio_reg |= (gpio_mask << MISC_REGISTERS_GPIO_SET_POS);
+ break;
+
+ case MISC_REGISTERS_GPIO_INPUT_HI_Z :
+ DP(NETIF_MSG_LINK, "Set GPIO %d (shift %d) -> input\n",
+ gpio_num, gpio_shift);
+ /* set FLOAT */
+ gpio_reg |= (gpio_mask << MISC_REGISTERS_GPIO_FLOAT_POS);
+ break;
+
+ default:
+ break;
+ }
+
+ REG_WR(bp, MISC_REG_GPIO, gpio_reg);
+ bnx2x_hw_unlock(bp, HW_LOCK_RESOURCE_GPIO);
+
+ return 0;
+}
+
+static int bnx2x_set_spio(struct bnx2x *bp, int spio_num, u32 mode)
+{
+ u32 spio_mask = (1 << spio_num);
+ u32 spio_reg;
+
+ if ((spio_num < MISC_REGISTERS_SPIO_4) ||
+ (spio_num > MISC_REGISTERS_SPIO_7)) {
+ BNX2X_ERR("Invalid SPIO %d\n", spio_num);
+ return -EINVAL;
+ }
+
+ bnx2x_hw_lock(bp, HW_LOCK_RESOURCE_SPIO);
+ /* read SPIO and mask except the float bits */
+ spio_reg = (REG_RD(bp, MISC_REG_SPIO) & MISC_REGISTERS_SPIO_FLOAT);
+
+ switch (mode) {
+ case MISC_REGISTERS_SPIO_OUTPUT_LOW :
+ DP(NETIF_MSG_LINK, "Set SPIO %d -> output low\n", spio_num);
+ /* clear FLOAT and set CLR */
+ spio_reg &= ~(spio_mask << MISC_REGISTERS_SPIO_FLOAT_POS);
+ spio_reg |= (spio_mask << MISC_REGISTERS_SPIO_CLR_POS);
+ break;
+
+ case MISC_REGISTERS_SPIO_OUTPUT_HIGH :
+ DP(NETIF_MSG_LINK, "Set SPIO %d -> output high\n", spio_num);
+ /* clear FLOAT and set SET */
+ spio_reg &= ~(spio_mask << MISC_REGISTERS_SPIO_FLOAT_POS);
+ spio_reg |= (spio_mask << MISC_REGISTERS_SPIO_SET_POS);
+ break;
+
+ case MISC_REGISTERS_SPIO_INPUT_HI_Z:
+ DP(NETIF_MSG_LINK, "Set SPIO %d -> input\n", spio_num);
+ /* set FLOAT */
+ spio_reg |= (spio_mask << MISC_REGISTERS_SPIO_FLOAT_POS);
+ break;
+
+ default:
+ break;
+ }
+
+ REG_WR(bp, MISC_REG_SPIO, spio_reg);
+ bnx2x_hw_unlock(bp, HW_LOCK_RESOURCE_SPIO);
+
+ return 0;
+}
+
static int bnx2x_mdio22_write(struct bnx2x *bp, u32 reg, u32 val)
{
- int rc;
- u32 tmp, i;
int port = bp->port;
u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
+ u32 tmp;
+ int i, rc;
/* DP(NETIF_MSG_HW, "phy_addr 0x%x reg 0x%x val 0x%08x\n",
bp->phy_addr, reg, val); */
@@ -1236,8 +1409,8 @@ static int bnx2x_mdio22_read(struct bnx2x *bp, u32 reg, u32 *ret_val)
{
int port = bp->port;
u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
- u32 val, i;
- int rc;
+ u32 val;
+ int i, rc;
if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
@@ -1286,58 +1459,54 @@ static int bnx2x_mdio22_read(struct bnx2x *bp, u32 reg, u32 *ret_val)
return rc;
}
-static int bnx2x_mdio45_write(struct bnx2x *bp, u32 reg, u32 addr, u32 val)
+static int bnx2x_mdio45_ctrl_write(struct bnx2x *bp, u32 mdio_ctrl,
+ u32 phy_addr, u32 reg, u32 addr, u32 val)
{
- int rc = 0;
- u32 tmp, i;
- int port = bp->port;
- u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
-
- if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
-
- tmp = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
- tmp &= ~EMAC_MDIO_MODE_AUTO_POLL;
- EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, tmp);
- REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
- udelay(40);
- }
+ u32 tmp;
+ int i, rc = 0;
- /* set clause 45 mode */
- tmp = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
- tmp |= EMAC_MDIO_MODE_CLAUSE_45;
- EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, tmp);
+ /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
+ * (a value of 49==0x31) and make sure that the AUTO poll is off
+ */
+ tmp = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
+ tmp &= ~(EMAC_MDIO_MODE_AUTO_POLL | EMAC_MDIO_MODE_CLOCK_CNT);
+ tmp |= (EMAC_MDIO_MODE_CLAUSE_45 |
+ (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
+ REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, tmp);
+ REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
+ udelay(40);
/* address */
- tmp = ((bp->phy_addr << 21) | (reg << 16) | addr |
+ tmp = ((phy_addr << 21) | (reg << 16) | addr |
EMAC_MDIO_COMM_COMMAND_ADDRESS |
EMAC_MDIO_COMM_START_BUSY);
- EMAC_WR(EMAC_REG_EMAC_MDIO_COMM, tmp);
+ REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
for (i = 0; i < 50; i++) {
udelay(10);
- tmp = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM);
+ tmp = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
udelay(5);
break;
}
}
-
if (tmp & EMAC_MDIO_COMM_START_BUSY) {
BNX2X_ERR("write phy register failed\n");
rc = -EBUSY;
+
} else {
/* data */
- tmp = ((bp->phy_addr << 21) | (reg << 16) | val |
+ tmp = ((phy_addr << 21) | (reg << 16) | val |
EMAC_MDIO_COMM_COMMAND_WRITE_45 |
EMAC_MDIO_COMM_START_BUSY);
- EMAC_WR(EMAC_REG_EMAC_MDIO_COMM, tmp);
+ REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
for (i = 0; i < 50; i++) {
udelay(10);
- tmp = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM);
+ tmp = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
udelay(5);
break;
@@ -1351,75 +1520,78 @@ static int bnx2x_mdio45_write(struct bnx2x *bp, u32 reg, u32 addr, u32 val)
}
}
- /* unset clause 45 mode */
- tmp = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
- tmp &= ~EMAC_MDIO_MODE_CLAUSE_45;
- EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, tmp);
-
- if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
-
- tmp = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
+ /* unset clause 45 mode, set the MDIO clock to a faster value
+ * (0x13 => 6.25Mhz) and restore the AUTO poll if needed
+ */
+ tmp = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
+ tmp &= ~(EMAC_MDIO_MODE_CLAUSE_45 | EMAC_MDIO_MODE_CLOCK_CNT);
+ tmp |= (0x13 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT);
+ if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG)
tmp |= EMAC_MDIO_MODE_AUTO_POLL;
- EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, tmp);
- }
+ REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, tmp);
return rc;
}
-static int bnx2x_mdio45_read(struct bnx2x *bp, u32 reg, u32 addr,
- u32 *ret_val)
+static int bnx2x_mdio45_write(struct bnx2x *bp, u32 phy_addr, u32 reg,
+ u32 addr, u32 val)
{
- int port = bp->port;
- u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
- u32 val, i;
- int rc = 0;
+ u32 emac_base = bp->port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
- if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
+ return bnx2x_mdio45_ctrl_write(bp, emac_base, phy_addr,
+ reg, addr, val);
+}
- val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
- val &= ~EMAC_MDIO_MODE_AUTO_POLL;
- EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, val);
- REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
- udelay(40);
- }
+static int bnx2x_mdio45_ctrl_read(struct bnx2x *bp, u32 mdio_ctrl,
+ u32 phy_addr, u32 reg, u32 addr,
+ u32 *ret_val)
+{
+ u32 val;
+ int i, rc = 0;
- /* set clause 45 mode */
- val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
- val |= EMAC_MDIO_MODE_CLAUSE_45;
- EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, val);
+ /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
+ * (a value of 49==0x31) and make sure that the AUTO poll is off
+ */
+ val = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
+ val &= ~(EMAC_MDIO_MODE_AUTO_POLL | EMAC_MDIO_MODE_CLOCK_CNT);
+ val |= (EMAC_MDIO_MODE_CLAUSE_45 |
+ (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
+ REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, val);
+ REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
+ udelay(40);
/* address */
- val = ((bp->phy_addr << 21) | (reg << 16) | addr |
+ val = ((phy_addr << 21) | (reg << 16) | addr |
EMAC_MDIO_COMM_COMMAND_ADDRESS |
EMAC_MDIO_COMM_START_BUSY);
- EMAC_WR(EMAC_REG_EMAC_MDIO_COMM, val);
+ REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
for (i = 0; i < 50; i++) {
udelay(10);
- val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM);
+ val = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
udelay(5);
break;
}
}
-
if (val & EMAC_MDIO_COMM_START_BUSY) {
BNX2X_ERR("read phy register failed\n");
*ret_val = 0;
rc = -EBUSY;
+
} else {
/* data */
- val = ((bp->phy_addr << 21) | (reg << 16) |
+ val = ((phy_addr << 21) | (reg << 16) |
EMAC_MDIO_COMM_COMMAND_READ_45 |
EMAC_MDIO_COMM_START_BUSY);
- EMAC_WR(EMAC_REG_EMAC_MDIO_COMM, val);
+ REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
for (i = 0; i < 50; i++) {
udelay(10);
- val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM);
+ val = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
val &= EMAC_MDIO_COMM_DATA;
break;
@@ -1436,31 +1608,39 @@ static int bnx2x_mdio45_read(struct bnx2x *bp, u32 reg, u32 addr,
*ret_val = val;
}
- /* unset clause 45 mode */
- val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
- val &= ~EMAC_MDIO_MODE_CLAUSE_45;
- EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, val);
-
- if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
-
- val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
+ /* unset clause 45 mode, set the MDIO clock to a faster value
+ * (0x13 => 6.25Mhz) and restore the AUTO poll if needed
+ */
+ val = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
+ val &= ~(EMAC_MDIO_MODE_CLAUSE_45 | EMAC_MDIO_MODE_CLOCK_CNT);
+ val |= (0x13 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT);
+ if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG)
val |= EMAC_MDIO_MODE_AUTO_POLL;
- EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, val);
- }
+ REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, val);
return rc;
}
-static int bnx2x_mdio45_vwrite(struct bnx2x *bp, u32 reg, u32 addr, u32 val)
+static int bnx2x_mdio45_read(struct bnx2x *bp, u32 phy_addr, u32 reg,
+ u32 addr, u32 *ret_val)
+{
+ u32 emac_base = bp->port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
+
+ return bnx2x_mdio45_ctrl_read(bp, emac_base, phy_addr,
+ reg, addr, ret_val);
+}
+
+static int bnx2x_mdio45_vwrite(struct bnx2x *bp, u32 phy_addr, u32 reg,
+ u32 addr, u32 val)
{
int i;
u32 rd_val;
might_sleep();
for (i = 0; i < 10; i++) {
- bnx2x_mdio45_write(bp, reg, addr, val);
+ bnx2x_mdio45_write(bp, phy_addr, reg, addr, val);
msleep(5);
- bnx2x_mdio45_read(bp, reg, addr, &rd_val);
+ bnx2x_mdio45_read(bp, phy_addr, reg, addr, &rd_val);
/* if the read value is not the same as the value we wrote,
we should write it again */
if (rd_val == val)
@@ -1471,18 +1651,81 @@ static int bnx2x_mdio45_vwrite(struct bnx2x *bp, u32 reg, u32 addr, u32 val)
}
/*
- * link managment
+ * link management
*/
+static void bnx2x_pause_resolve(struct bnx2x *bp, u32 pause_result)
+{
+ switch (pause_result) { /* ASYM P ASYM P */
+ case 0xb: /* 1 0 1 1 */
+ bp->flow_ctrl = FLOW_CTRL_TX;
+ break;
+
+ case 0xe: /* 1 1 1 0 */
+ bp->flow_ctrl = FLOW_CTRL_RX;
+ break;
+
+ case 0x5: /* 0 1 0 1 */
+ case 0x7: /* 0 1 1 1 */
+ case 0xd: /* 1 1 0 1 */
+ case 0xf: /* 1 1 1 1 */
+ bp->flow_ctrl = FLOW_CTRL_BOTH;
+ break;
+
+ default:
+ break;
+ }
+}
+
+static u8 bnx2x_ext_phy_resove_fc(struct bnx2x *bp)
+{
+ u32 ext_phy_addr;
+ u32 ld_pause; /* local */
+ u32 lp_pause; /* link partner */
+ u32 an_complete; /* AN complete */
+ u32 pause_result;
+ u8 ret = 0;
+
+ ext_phy_addr = ((bp->ext_phy_config &
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+
+ /* read twice */
+ bnx2x_mdio45_read(bp, ext_phy_addr,
+ EXT_PHY_KR_AUTO_NEG_DEVAD,
+ EXT_PHY_KR_STATUS, &an_complete);
+ bnx2x_mdio45_read(bp, ext_phy_addr,
+ EXT_PHY_KR_AUTO_NEG_DEVAD,
+ EXT_PHY_KR_STATUS, &an_complete);
+
+ if (an_complete & EXT_PHY_KR_AUTO_NEG_COMPLETE) {
+ ret = 1;
+ bnx2x_mdio45_read(bp, ext_phy_addr,
+ EXT_PHY_KR_AUTO_NEG_DEVAD,
+ EXT_PHY_KR_AUTO_NEG_ADVERT, &ld_pause);
+ bnx2x_mdio45_read(bp, ext_phy_addr,
+ EXT_PHY_KR_AUTO_NEG_DEVAD,
+ EXT_PHY_KR_LP_AUTO_NEG, &lp_pause);
+ pause_result = (ld_pause &
+ EXT_PHY_KR_AUTO_NEG_ADVERT_PAUSE_MASK) >> 8;
+ pause_result |= (lp_pause &
+ EXT_PHY_KR_AUTO_NEG_ADVERT_PAUSE_MASK) >> 10;
+ DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x \n",
+ pause_result);
+ bnx2x_pause_resolve(bp, pause_result);
+ }
+ return ret;
+}
+
static void bnx2x_flow_ctrl_resolve(struct bnx2x *bp, u32 gp_status)
{
- u32 ld_pause; /* local driver */
- u32 lp_pause; /* link partner */
+ u32 ld_pause; /* local driver */
+ u32 lp_pause; /* link partner */
u32 pause_result;
bp->flow_ctrl = 0;
- /* reolve from gp_status in case of AN complete and not sgmii */
+ /* resolve from gp_status in case of AN complete and not sgmii */
if ((bp->req_autoneg & AUTONEG_FLOW_CTRL) &&
(gp_status & MDIO_AN_CL73_OR_37_COMPLETE) &&
(!(bp->phy_flags & PHY_SGMII_FLAG)) &&
@@ -1499,45 +1742,57 @@ static void bnx2x_flow_ctrl_resolve(struct bnx2x *bp, u32 gp_status)
pause_result |= (lp_pause &
MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7;
DP(NETIF_MSG_LINK, "pause_result 0x%x\n", pause_result);
+ bnx2x_pause_resolve(bp, pause_result);
+ } else if (!(bp->req_autoneg & AUTONEG_FLOW_CTRL) ||
+ !(bnx2x_ext_phy_resove_fc(bp))) {
+ /* forced speed */
+ if (bp->req_autoneg & AUTONEG_FLOW_CTRL) {
+ switch (bp->req_flow_ctrl) {
+ case FLOW_CTRL_AUTO:
+ if (bp->dev->mtu <= 4500)
+ bp->flow_ctrl = FLOW_CTRL_BOTH;
+ else
+ bp->flow_ctrl = FLOW_CTRL_TX;
+ break;
- switch (pause_result) { /* ASYM P ASYM P */
- case 0xb: /* 1 0 1 1 */
- bp->flow_ctrl = FLOW_CTRL_TX;
- break;
-
- case 0xe: /* 1 1 1 0 */
- bp->flow_ctrl = FLOW_CTRL_RX;
- break;
+ case FLOW_CTRL_TX:
+ bp->flow_ctrl = FLOW_CTRL_TX;
+ break;
- case 0x5: /* 0 1 0 1 */
- case 0x7: /* 0 1 1 1 */
- case 0xd: /* 1 1 0 1 */
- case 0xf: /* 1 1 1 1 */
- bp->flow_ctrl = FLOW_CTRL_BOTH;
- break;
+ case FLOW_CTRL_RX:
+ if (bp->dev->mtu <= 4500)
+ bp->flow_ctrl = FLOW_CTRL_RX;
+ break;
- default:
- break;
- }
+ case FLOW_CTRL_BOTH:
+ if (bp->dev->mtu <= 4500)
+ bp->flow_ctrl = FLOW_CTRL_BOTH;
+ else
+ bp->flow_ctrl = FLOW_CTRL_TX;
+ break;
- } else { /* forced mode */
- switch (bp->req_flow_ctrl) {
- case FLOW_CTRL_AUTO:
- if (bp->dev->mtu <= 4500)
- bp->flow_ctrl = FLOW_CTRL_BOTH;
- else
- bp->flow_ctrl = FLOW_CTRL_TX;
- break;
+ case FLOW_CTRL_NONE:
+ default:
+ break;
+ }
+ } else { /* forced mode */
+ switch (bp->req_flow_ctrl) {
+ case FLOW_CTRL_AUTO:
+ DP(NETIF_MSG_LINK, "req_flow_ctrl 0x%x while"
+ " req_autoneg 0x%x\n",
+ bp->req_flow_ctrl, bp->req_autoneg);
+ break;
- case FLOW_CTRL_TX:
- case FLOW_CTRL_RX:
- case FLOW_CTRL_BOTH:
- bp->flow_ctrl = bp->req_flow_ctrl;
- break;
+ case FLOW_CTRL_TX:
+ case FLOW_CTRL_RX:
+ case FLOW_CTRL_BOTH:
+ bp->flow_ctrl = bp->req_flow_ctrl;
+ break;
- case FLOW_CTRL_NONE:
- default:
- break;
+ case FLOW_CTRL_NONE:
+ default:
+ break;
+ }
}
}
DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", bp->flow_ctrl);
@@ -1548,9 +1803,9 @@ static void bnx2x_link_settings_status(struct bnx2x *bp, u32 gp_status)
bp->link_status = 0;
if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
- DP(NETIF_MSG_LINK, "link up\n");
+ DP(NETIF_MSG_LINK, "phy link up\n");
- bp->link_up = 1;
+ bp->phy_link_up = 1;
bp->link_status |= LINK_STATUS_LINK_UP;
if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_DUPLEX_STATUS)
@@ -1659,20 +1914,20 @@ static void bnx2x_link_settings_status(struct bnx2x *bp, u32 gp_status)
bp->link_status |= LINK_STATUS_RX_FLOW_CONTROL_ENABLED;
} else { /* link_down */
- DP(NETIF_MSG_LINK, "link down\n");
+ DP(NETIF_MSG_LINK, "phy link down\n");
- bp->link_up = 0;
+ bp->phy_link_up = 0;
bp->line_speed = 0;
bp->duplex = DUPLEX_FULL;
bp->flow_ctrl = 0;
}
- DP(NETIF_MSG_LINK, "gp_status 0x%x link_up %d\n"
+ DP(NETIF_MSG_LINK, "gp_status 0x%x phy_link_up %d\n"
DP_LEVEL " line_speed %d duplex %d flow_ctrl 0x%x"
" link_status 0x%x\n",
- gp_status, bp->link_up, bp->line_speed, bp->duplex, bp->flow_ctrl,
- bp->link_status);
+ gp_status, bp->phy_link_up, bp->line_speed, bp->duplex,
+ bp->flow_ctrl, bp->link_status);
}
static void bnx2x_link_int_ack(struct bnx2x *bp, int is_10g)
@@ -1680,40 +1935,40 @@ static void bnx2x_link_int_ack(struct bnx2x *bp, int is_10g)
int port = bp->port;
/* first reset all status
- * we asume only one line will be change at a time */
+ * we assume only one line will be change at a time */
bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
- (NIG_XGXS0_LINK_STATUS |
- NIG_SERDES0_LINK_STATUS |
- NIG_STATUS_INTERRUPT_XGXS0_LINK10G));
- if (bp->link_up) {
+ (NIG_STATUS_XGXS0_LINK10G |
+ NIG_STATUS_XGXS0_LINK_STATUS |
+ NIG_STATUS_SERDES0_LINK_STATUS));
+ if (bp->phy_link_up) {
if (is_10g) {
/* Disable the 10G link interrupt
* by writing 1 to the status register
*/
- DP(NETIF_MSG_LINK, "10G XGXS link up\n");
+ DP(NETIF_MSG_LINK, "10G XGXS phy link up\n");
bnx2x_bits_en(bp,
NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
- NIG_STATUS_INTERRUPT_XGXS0_LINK10G);
+ NIG_STATUS_XGXS0_LINK10G);
} else if (bp->phy_flags & PHY_XGXS_FLAG) {
/* Disable the link interrupt
* by writing 1 to the relevant lane
* in the status register
*/
- DP(NETIF_MSG_LINK, "1G XGXS link up\n");
+ DP(NETIF_MSG_LINK, "1G XGXS phy link up\n");
bnx2x_bits_en(bp,
NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
((1 << bp->ser_lane) <<
- NIG_XGXS0_LINK_STATUS_SIZE));
+ NIG_STATUS_XGXS0_LINK_STATUS_SIZE));
} else { /* SerDes */
- DP(NETIF_MSG_LINK, "SerDes link up\n");
+ DP(NETIF_MSG_LINK, "SerDes phy link up\n");
/* Disable the link interrupt
* by writing 1 to the status register
*/
bnx2x_bits_en(bp,
NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
- NIG_SERDES0_LINK_STATUS);
+ NIG_STATUS_SERDES0_LINK_STATUS);
}
} else { /* link_down */
@@ -1724,91 +1979,182 @@ static int bnx2x_ext_phy_is_link_up(struct bnx2x *bp)
{
u32 ext_phy_type;
u32 ext_phy_addr;
- u32 local_phy;
- u32 val = 0;
+ u32 val1 = 0, val2;
u32 rx_sd, pcs_status;
if (bp->phy_flags & PHY_XGXS_FLAG) {
- local_phy = bp->phy_addr;
ext_phy_addr = ((bp->ext_phy_config &
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
- bp->phy_addr = (u8)ext_phy_addr;
ext_phy_type = XGXS_EXT_PHY_TYPE(bp);
switch (ext_phy_type) {
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
DP(NETIF_MSG_LINK, "XGXS Direct\n");
- val = 1;
+ val1 = 1;
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
DP(NETIF_MSG_LINK, "XGXS 8705\n");
- bnx2x_mdio45_read(bp, EXT_PHY_OPT_WIS_DEVAD,
- EXT_PHY_OPT_LASI_STATUS, &val);
- DP(NETIF_MSG_LINK, "8705 LASI status is %d\n", val);
-
- bnx2x_mdio45_read(bp, EXT_PHY_OPT_WIS_DEVAD,
- EXT_PHY_OPT_LASI_STATUS, &val);
- DP(NETIF_MSG_LINK, "8705 LASI status is %d\n", val);
-
- bnx2x_mdio45_read(bp, EXT_PHY_OPT_PMA_PMD_DEVAD,
+ bnx2x_mdio45_read(bp, ext_phy_addr,
+ EXT_PHY_OPT_WIS_DEVAD,
+ EXT_PHY_OPT_LASI_STATUS, &val1);
+ DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
+
+ bnx2x_mdio45_read(bp, ext_phy_addr,
+ EXT_PHY_OPT_WIS_DEVAD,
+ EXT_PHY_OPT_LASI_STATUS, &val1);
+ DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
+
+ bnx2x_mdio45_read(bp, ext_phy_addr,
+ EXT_PHY_OPT_PMA_PMD_DEVAD,
EXT_PHY_OPT_PMD_RX_SD, &rx_sd);
- val = (rx_sd & 0x1);
+ DP(NETIF_MSG_LINK, "8705 rx_sd 0x%x\n", rx_sd);
+ val1 = (rx_sd & 0x1);
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
DP(NETIF_MSG_LINK, "XGXS 8706\n");
- bnx2x_mdio45_read(bp, EXT_PHY_OPT_PMA_PMD_DEVAD,
- EXT_PHY_OPT_LASI_STATUS, &val);
- DP(NETIF_MSG_LINK, "8706 LASI status is %d\n", val);
-
- bnx2x_mdio45_read(bp, EXT_PHY_OPT_PMA_PMD_DEVAD,
- EXT_PHY_OPT_LASI_STATUS, &val);
- DP(NETIF_MSG_LINK, "8706 LASI status is %d\n", val);
-
- bnx2x_mdio45_read(bp, EXT_PHY_OPT_PMA_PMD_DEVAD,
+ bnx2x_mdio45_read(bp, ext_phy_addr,
+ EXT_PHY_OPT_PMA_PMD_DEVAD,
+ EXT_PHY_OPT_LASI_STATUS, &val1);
+ DP(NETIF_MSG_LINK, "8706 LASI status 0x%x\n", val1);
+
+ bnx2x_mdio45_read(bp, ext_phy_addr,
+ EXT_PHY_OPT_PMA_PMD_DEVAD,
+ EXT_PHY_OPT_LASI_STATUS, &val1);
+ DP(NETIF_MSG_LINK, "8706 LASI status 0x%x\n", val1);
+
+ bnx2x_mdio45_read(bp, ext_phy_addr,
+ EXT_PHY_OPT_PMA_PMD_DEVAD,
EXT_PHY_OPT_PMD_RX_SD, &rx_sd);
- bnx2x_mdio45_read(bp, EXT_PHY_OPT_PCS_DEVAD,
- EXT_PHY_OPT_PCS_STATUS, &pcs_status);
+ bnx2x_mdio45_read(bp, ext_phy_addr,
+ EXT_PHY_OPT_PCS_DEVAD,
+ EXT_PHY_OPT_PCS_STATUS, &pcs_status);
+ bnx2x_mdio45_read(bp, ext_phy_addr,
+ EXT_PHY_AUTO_NEG_DEVAD,
+ EXT_PHY_OPT_AN_LINK_STATUS, &val2);
+
DP(NETIF_MSG_LINK, "8706 rx_sd 0x%x"
- " pcs_status 0x%x\n", rx_sd, pcs_status);
- /* link is up if both bit 0 of pmd_rx and
- * bit 0 of pcs_status are set
+ " pcs_status 0x%x 1Gbps link_status 0x%x 0x%x\n",
+ rx_sd, pcs_status, val2, (val2 & (1<<1)));
+ /* link is up if both bit 0 of pmd_rx_sd and
+ * bit 0 of pcs_status are set, or if the autoneg bit
+ 1 is set
*/
- val = (rx_sd & pcs_status);
+ val1 = ((rx_sd & pcs_status & 0x1) || (val2 & (1<<1)));
+ break;
+
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
+ bnx2x_hw_lock(bp, HW_LOCK_RESOURCE_8072_MDIO);
+
+ /* clear the interrupt LASI status register */
+ bnx2x_mdio45_ctrl_read(bp, GRCBASE_EMAC0,
+ ext_phy_addr,
+ EXT_PHY_KR_PCS_DEVAD,
+ EXT_PHY_KR_LASI_STATUS, &val2);
+ bnx2x_mdio45_ctrl_read(bp, GRCBASE_EMAC0,
+ ext_phy_addr,
+ EXT_PHY_KR_PCS_DEVAD,
+ EXT_PHY_KR_LASI_STATUS, &val1);
+ DP(NETIF_MSG_LINK, "KR LASI status 0x%x->0x%x\n",
+ val2, val1);
+ /* Check the LASI */
+ bnx2x_mdio45_ctrl_read(bp, GRCBASE_EMAC0,
+ ext_phy_addr,
+ EXT_PHY_KR_PMA_PMD_DEVAD,
+ 0x9003, &val2);
+ bnx2x_mdio45_ctrl_read(bp, GRCBASE_EMAC0,
+ ext_phy_addr,
+ EXT_PHY_KR_PMA_PMD_DEVAD,
+ 0x9003, &val1);
+ DP(NETIF_MSG_LINK, "KR 0x9003 0x%x->0x%x\n",
+ val2, val1);
+ /* Check the link status */
+ bnx2x_mdio45_ctrl_read(bp, GRCBASE_EMAC0,
+ ext_phy_addr,
+ EXT_PHY_KR_PCS_DEVAD,
+ EXT_PHY_KR_PCS_STATUS, &val2);
+ DP(NETIF_MSG_LINK, "KR PCS status 0x%x\n", val2);
+ /* Check the link status on 1.1.2 */
+ bnx2x_mdio45_ctrl_read(bp, GRCBASE_EMAC0,
+ ext_phy_addr,
+ EXT_PHY_OPT_PMA_PMD_DEVAD,
+ EXT_PHY_KR_STATUS, &val2);
+ bnx2x_mdio45_ctrl_read(bp, GRCBASE_EMAC0,
+ ext_phy_addr,
+ EXT_PHY_OPT_PMA_PMD_DEVAD,
+ EXT_PHY_KR_STATUS, &val1);
+ DP(NETIF_MSG_LINK,
+ "KR PMA status 0x%x->0x%x\n", val2, val1);
+ val1 = ((val1 & 4) == 4);
+ /* If 1G was requested assume the link is up */
+ if (!(bp->req_autoneg & AUTONEG_SPEED) &&
+ (bp->req_line_speed == SPEED_1000))
+ val1 = 1;
+ bnx2x_hw_unlock(bp, HW_LOCK_RESOURCE_8072_MDIO);
+ break;
+
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
+ bnx2x_mdio45_read(bp, ext_phy_addr,
+ EXT_PHY_OPT_PMA_PMD_DEVAD,
+ EXT_PHY_OPT_LASI_STATUS, &val2);
+ bnx2x_mdio45_read(bp, ext_phy_addr,
+ EXT_PHY_OPT_PMA_PMD_DEVAD,
+ EXT_PHY_OPT_LASI_STATUS, &val1);
+ DP(NETIF_MSG_LINK,
+ "10G-base-T LASI status 0x%x->0x%x\n", val2, val1);
+ bnx2x_mdio45_read(bp, ext_phy_addr,
+ EXT_PHY_OPT_PMA_PMD_DEVAD,
+ EXT_PHY_KR_STATUS, &val2);
+ bnx2x_mdio45_read(bp, ext_phy_addr,
+ EXT_PHY_OPT_PMA_PMD_DEVAD,
+ EXT_PHY_KR_STATUS, &val1);
+ DP(NETIF_MSG_LINK,
+ "10G-base-T PMA status 0x%x->0x%x\n", val2, val1);
+ val1 = ((val1 & 4) == 4);
+ /* if link is up
+ * print the AN outcome of the SFX7101 PHY
+ */
+ if (val1) {
+ bnx2x_mdio45_read(bp, ext_phy_addr,
+ EXT_PHY_KR_AUTO_NEG_DEVAD,
+ 0x21, &val2);
+ DP(NETIF_MSG_LINK,
+ "SFX7101 AN status 0x%x->%s\n", val2,
+ (val2 & (1<<14)) ? "Master" : "Slave");
+ }
break;
default:
DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
bp->ext_phy_config);
- val = 0;
+ val1 = 0;
break;
}
- bp->phy_addr = local_phy;
} else { /* SerDes */
ext_phy_type = SERDES_EXT_PHY_TYPE(bp);
switch (ext_phy_type) {
case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
DP(NETIF_MSG_LINK, "SerDes Direct\n");
- val = 1;
+ val1 = 1;
break;
case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
DP(NETIF_MSG_LINK, "SerDes 5482\n");
- val = 1;
+ val1 = 1;
break;
default:
DP(NETIF_MSG_LINK, "BAD SerDes ext_phy_config 0x%x\n",
bp->ext_phy_config);
- val = 0;
+ val1 = 0;
break;
}
}
- return val;
+ return val1;
}
static void bnx2x_bmac_enable(struct bnx2x *bp, int is_lb)
@@ -1819,7 +2165,7 @@ static void bnx2x_bmac_enable(struct bnx2x *bp, int is_lb)
u32 wb_write[2];
u32 val;
- DP(NETIF_MSG_LINK, "enableing BigMAC\n");
+ DP(NETIF_MSG_LINK, "enabling BigMAC\n");
/* reset and unreset the BigMac */
REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
(MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
@@ -1933,6 +2279,35 @@ static void bnx2x_bmac_enable(struct bnx2x *bp, int is_lb)
bp->stats_state = STATS_STATE_ENABLE;
}
+static void bnx2x_bmac_rx_disable(struct bnx2x *bp)
+{
+ int port = bp->port;
+ u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
+ NIG_REG_INGRESS_BMAC0_MEM;
+ u32 wb_write[2];
+
+ /* Only if the bmac is out of reset */
+ if (REG_RD(bp, MISC_REG_RESET_REG_2) &
+ (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)) {
+ /* Clear Rx Enable bit in BMAC_CONTROL register */
+#ifdef BNX2X_DMAE_RD
+ bnx2x_read_dmae(bp, bmac_addr +
+ BIGMAC_REGISTER_BMAC_CONTROL, 2);
+ wb_write[0] = *bnx2x_sp(bp, wb_data[0]);
+ wb_write[1] = *bnx2x_sp(bp, wb_data[1]);
+#else
+ wb_write[0] = REG_RD(bp,
+ bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL);
+ wb_write[1] = REG_RD(bp,
+ bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL + 4);
+#endif
+ wb_write[0] &= ~BMAC_CONTROL_RX_ENABLE;
+ REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
+ wb_write, 2);
+ msleep(1);
+ }
+}
+
static void bnx2x_emac_enable(struct bnx2x *bp)
{
int port = bp->port;
@@ -1940,7 +2315,7 @@ static void bnx2x_emac_enable(struct bnx2x *bp)
u32 val;
int timeout;
- DP(NETIF_MSG_LINK, "enableing EMAC\n");
+ DP(NETIF_MSG_LINK, "enabling EMAC\n");
/* reset and unreset the emac core */
REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
(MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
@@ -2033,7 +2408,7 @@ static void bnx2x_emac_enable(struct bnx2x *bp)
EMAC_TX_MODE_EXT_PAUSE_EN);
}
- /* KEEP_VLAN_TAG, promiscous */
+ /* KEEP_VLAN_TAG, promiscuous */
val = REG_RD(bp, emac_base + EMAC_REG_EMAC_RX_MODE);
val |= EMAC_RX_MODE_KEEP_VLAN_TAG | EMAC_RX_MODE_PROMISCUOUS;
EMAC_WR(EMAC_REG_EMAC_RX_MODE, val);
@@ -2161,7 +2536,6 @@ static void bnx2x_pbf_update(struct bnx2x *bp)
u32 count = 1000;
u32 pause = 0;
-
/* disable port */
REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x1);
@@ -2232,7 +2606,7 @@ static void bnx2x_pbf_update(struct bnx2x *bp)
static void bnx2x_update_mng(struct bnx2x *bp)
{
if (!nomcp)
- SHMEM_WR(bp, drv_fw_mb[bp->port].link_status,
+ SHMEM_WR(bp, port_mb[bp->port].link_status,
bp->link_status);
}
@@ -2294,19 +2668,19 @@ static void bnx2x_link_down(struct bnx2x *bp)
DP(BNX2X_MSG_STATS, "stats_state - STOP\n");
}
- /* indicate link down */
+ /* indicate no mac active */
bp->phy_flags &= ~(PHY_BMAC_FLAG | PHY_EMAC_FLAG);
- /* reset BigMac */
- REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
- (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
+ /* update shared memory */
+ bnx2x_update_mng(bp);
- /* ignore drain flag interrupt */
/* activate nig drain */
NIG_WR(NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
- /* update shared memory */
- bnx2x_update_mng(bp);
+ /* reset BigMac */
+ bnx2x_bmac_rx_disable(bp);
+ REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
+ (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
/* indicate link down */
bnx2x_link_report(bp);
@@ -2317,14 +2691,15 @@ static void bnx2x_init_mac_stats(struct bnx2x *bp);
/* This function is called upon link interrupt */
static void bnx2x_link_update(struct bnx2x *bp)
{
- u32 gp_status;
int port = bp->port;
int i;
+ u32 gp_status;
int link_10g;
- DP(NETIF_MSG_LINK, "port %x, is xgxs %x, stat_mask 0x%x,"
+ DP(NETIF_MSG_LINK, "port %x, %s, int_status 0x%x,"
" int_mask 0x%x, saved_mask 0x%x, MI_INT %x, SERDES_LINK %x,"
- " 10G %x, XGXS_LINK %x\n", port, (bp->phy_flags & PHY_XGXS_FLAG),
+ " 10G %x, XGXS_LINK %x\n", port,
+ (bp->phy_flags & PHY_XGXS_FLAG)? "XGXS":"SerDes",
REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4),
REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4), bp->nig_mask,
REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
@@ -2336,7 +2711,7 @@ static void bnx2x_link_update(struct bnx2x *bp)
might_sleep();
MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_GP_STATUS);
/* avoid fast toggling */
- for (i = 0 ; i < 10 ; i++) {
+ for (i = 0; i < 10; i++) {
msleep(10);
bnx2x_mdio22_read(bp, MDIO_GP_STATUS_TOP_AN_STATUS1,
&gp_status);
@@ -2351,7 +2726,8 @@ static void bnx2x_link_update(struct bnx2x *bp)
bnx2x_link_int_ack(bp, link_10g);
/* link is up only if both local phy and external phy are up */
- if (bp->link_up && bnx2x_ext_phy_is_link_up(bp)) {
+ bp->link_up = (bp->phy_link_up && bnx2x_ext_phy_is_link_up(bp));
+ if (bp->link_up) {
if (link_10g) {
bnx2x_bmac_enable(bp, 0);
bnx2x_leds_set(bp, SPEED_10000);
@@ -2427,7 +2803,9 @@ static void bnx2x_reset_unicore(struct bnx2x *bp)
}
}
- BNX2X_ERR("BUG! unicore is still in reset!\n");
+ BNX2X_ERR("BUG! %s (0x%x) is still in reset!\n",
+ (bp->phy_flags & PHY_XGXS_FLAG)? "XGXS":"SerDes",
+ bp->phy_addr);
}
static void bnx2x_set_swap_lanes(struct bnx2x *bp)
@@ -2475,12 +2853,12 @@ static void bnx2x_set_parallel_detection(struct bnx2x *bp)
MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_10G_PARALLEL_DETECT);
bnx2x_mdio22_write(bp,
- MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK,
+ MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK,
MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT);
bnx2x_mdio22_read(bp,
- MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
- &control2);
+ MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
+ &control2);
if (bp->autoneg & AUTONEG_PARALLEL) {
control2 |=
@@ -2490,8 +2868,14 @@ static void bnx2x_set_parallel_detection(struct bnx2x *bp)
~MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN;
}
bnx2x_mdio22_write(bp,
- MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
- control2);
+ MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
+ control2);
+
+ /* Disable parallel detection of HiG */
+ MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_XGXS_BLOCK2);
+ bnx2x_mdio22_write(bp, MDIO_XGXS_BLOCK2_UNICORE_MODE_10G,
+ MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_CX4_XGXS |
+ MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_HIGIG_XGXS);
}
}
@@ -2625,7 +3009,7 @@ static void bnx2x_set_brcm_cl37_advertisment(struct bnx2x *bp)
MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_OVER_1G);
/* set extended capabilities */
- if (bp->advertising & ADVERTISED_2500baseT_Full)
+ if (bp->advertising & ADVERTISED_2500baseX_Full)
val |= MDIO_OVER_1G_UP1_2_5G;
if (bp->advertising & ADVERTISED_10000baseT_Full)
val |= MDIO_OVER_1G_UP1_10G;
@@ -2641,20 +3025,91 @@ static void bnx2x_set_ieee_aneg_advertisment(struct bnx2x *bp)
/* for AN, we are always publishing full duplex */
an_adv = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX;
- /* set pause */
- switch (bp->pause_mode) {
- case PAUSE_SYMMETRIC:
- an_adv |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC;
- break;
- case PAUSE_ASYMMETRIC:
- an_adv |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
- break;
- case PAUSE_BOTH:
- an_adv |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
- break;
- case PAUSE_NONE:
- an_adv |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
- break;
+ /* resolve pause mode and advertisement
+ * Please refer to Table 28B-3 of the 802.3ab-1999 spec */
+ if (bp->req_autoneg & AUTONEG_FLOW_CTRL) {
+ switch (bp->req_flow_ctrl) {
+ case FLOW_CTRL_AUTO:
+ if (bp->dev->mtu <= 4500) {
+ an_adv |=
+ MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
+ bp->advertising |= (ADVERTISED_Pause |
+ ADVERTISED_Asym_Pause);
+ } else {
+ an_adv |=
+ MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
+ bp->advertising |= ADVERTISED_Asym_Pause;
+ }
+ break;
+
+ case FLOW_CTRL_TX:
+ an_adv |=
+ MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
+ bp->advertising |= ADVERTISED_Asym_Pause;
+ break;
+
+ case FLOW_CTRL_RX:
+ if (bp->dev->mtu <= 4500) {
+ an_adv |=
+ MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
+ bp->advertising |= (ADVERTISED_Pause |
+ ADVERTISED_Asym_Pause);
+ } else {
+ an_adv |=
+ MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
+ bp->advertising &= ~(ADVERTISED_Pause |
+ ADVERTISED_Asym_Pause);
+ }
+ break;
+
+ case FLOW_CTRL_BOTH:
+ if (bp->dev->mtu <= 4500) {
+ an_adv |=
+ MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
+ bp->advertising |= (ADVERTISED_Pause |
+ ADVERTISED_Asym_Pause);
+ } else {
+ an_adv |=
+ MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
+ bp->advertising |= ADVERTISED_Asym_Pause;
+ }
+ break;
+
+ case FLOW_CTRL_NONE:
+ default:
+ an_adv |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
+ bp->advertising &= ~(ADVERTISED_Pause |
+ ADVERTISED_Asym_Pause);
+ break;
+ }
+ } else { /* forced mode */
+ switch (bp->req_flow_ctrl) {
+ case FLOW_CTRL_AUTO:
+ DP(NETIF_MSG_LINK, "req_flow_ctrl 0x%x while"
+ " req_autoneg 0x%x\n",
+ bp->req_flow_ctrl, bp->req_autoneg);
+ break;
+
+ case FLOW_CTRL_TX:
+ an_adv |=
+ MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
+ bp->advertising |= ADVERTISED_Asym_Pause;
+ break;
+
+ case FLOW_CTRL_RX:
+ case FLOW_CTRL_BOTH:
+ an_adv |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
+ bp->advertising |= (ADVERTISED_Pause |
+ ADVERTISED_Asym_Pause);
+ break;
+
+ case FLOW_CTRL_NONE:
+ default:
+ an_adv |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
+ bp->advertising &= ~(ADVERTISED_Pause |
+ ADVERTISED_Asym_Pause);
+ break;
+ }
}
MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_COMBO_IEEE0);
@@ -2752,47 +3207,162 @@ static void bnx2x_initialize_sgmii_process(struct bnx2x *bp)
static void bnx2x_link_int_enable(struct bnx2x *bp)
{
int port = bp->port;
+ u32 ext_phy_type;
+ u32 mask;
/* setting the status to report on link up
for either XGXS or SerDes */
bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
- (NIG_XGXS0_LINK_STATUS |
- NIG_STATUS_INTERRUPT_XGXS0_LINK10G |
- NIG_SERDES0_LINK_STATUS));
+ (NIG_STATUS_XGXS0_LINK10G |
+ NIG_STATUS_XGXS0_LINK_STATUS |
+ NIG_STATUS_SERDES0_LINK_STATUS));
if (bp->phy_flags & PHY_XGXS_FLAG) {
- /* TBD -
- * in force mode (not AN) we can enable just the relevant
- * interrupt
- * Even in AN we might enable only one according to the AN
- * speed mask
- */
- bnx2x_bits_en(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
- (NIG_MASK_XGXS0_LINK_STATUS |
- NIG_MASK_XGXS0_LINK10G));
- DP(NETIF_MSG_LINK, "enable XGXS interrupt\n");
+ mask = (NIG_MASK_XGXS0_LINK10G |
+ NIG_MASK_XGXS0_LINK_STATUS);
+ DP(NETIF_MSG_LINK, "enabled XGXS interrupt\n");
+ ext_phy_type = XGXS_EXT_PHY_TYPE(bp);
+ if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
+ (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
+ (ext_phy_type !=
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)) {
+ mask |= NIG_MASK_MI_INT;
+ DP(NETIF_MSG_LINK, "enabled external phy int\n");
+ }
} else { /* SerDes */
- bnx2x_bits_en(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
- NIG_MASK_SERDES0_LINK_STATUS);
- DP(NETIF_MSG_LINK, "enable SerDes interrupt\n");
+ mask = NIG_MASK_SERDES0_LINK_STATUS;
+ DP(NETIF_MSG_LINK, "enabled SerDes interrupt\n");
+ ext_phy_type = SERDES_EXT_PHY_TYPE(bp);
+ if ((ext_phy_type !=
+ PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) &&
+ (ext_phy_type !=
+ PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN)) {
+ mask |= NIG_MASK_MI_INT;
+ DP(NETIF_MSG_LINK, "enabled external phy int\n");
+ }
}
+ bnx2x_bits_en(bp,
+ NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
+ mask);
+ DP(NETIF_MSG_LINK, "port %x, %s, int_status 0x%x,"
+ " int_mask 0x%x, MI_INT %x, SERDES_LINK %x,"
+ " 10G %x, XGXS_LINK %x\n", port,
+ (bp->phy_flags & PHY_XGXS_FLAG)? "XGXS":"SerDes",
+ REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4),
+ REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
+ REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
+ REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c),
+ REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
+ REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68)
+ );
+}
+
+static void bnx2x_bcm8072_external_rom_boot(struct bnx2x *bp)
+{
+ u32 ext_phy_addr = ((bp->ext_phy_config &
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+ u32 fw_ver1, fw_ver2;
+
+ /* Need to wait 200ms after reset */
+ msleep(200);
+ /* Boot port from external ROM
+ * Set ser_boot_ctl bit in the MISC_CTRL1 register
+ */
+ bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0, ext_phy_addr,
+ EXT_PHY_KR_PMA_PMD_DEVAD,
+ EXT_PHY_KR_MISC_CTRL1, 0x0001);
+
+ /* Reset internal microprocessor */
+ bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0, ext_phy_addr,
+ EXT_PHY_KR_PMA_PMD_DEVAD, EXT_PHY_KR_GEN_CTRL,
+ EXT_PHY_KR_ROM_RESET_INTERNAL_MP);
+ /* set micro reset = 0 */
+ bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0, ext_phy_addr,
+ EXT_PHY_KR_PMA_PMD_DEVAD, EXT_PHY_KR_GEN_CTRL,
+ EXT_PHY_KR_ROM_MICRO_RESET);
+ /* Reset internal microprocessor */
+ bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0, ext_phy_addr,
+ EXT_PHY_KR_PMA_PMD_DEVAD, EXT_PHY_KR_GEN_CTRL,
+ EXT_PHY_KR_ROM_RESET_INTERNAL_MP);
+ /* wait for 100ms for code download via SPI port */
+ msleep(100);
+
+ /* Clear ser_boot_ctl bit */
+ bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0, ext_phy_addr,
+ EXT_PHY_KR_PMA_PMD_DEVAD,
+ EXT_PHY_KR_MISC_CTRL1, 0x0000);
+ /* Wait 100ms */
+ msleep(100);
+
+ /* Print the PHY FW version */
+ bnx2x_mdio45_ctrl_read(bp, GRCBASE_EMAC0, ext_phy_addr,
+ EXT_PHY_KR_PMA_PMD_DEVAD,
+ 0xca19, &fw_ver1);
+ bnx2x_mdio45_ctrl_read(bp, GRCBASE_EMAC0, ext_phy_addr,
+ EXT_PHY_KR_PMA_PMD_DEVAD,
+ 0xca1a, &fw_ver2);
+ DP(NETIF_MSG_LINK,
+ "8072 FW version 0x%x:0x%x\n", fw_ver1, fw_ver2);
+}
+
+static void bnx2x_bcm8072_force_10G(struct bnx2x *bp)
+{
+ u32 ext_phy_addr = ((bp->ext_phy_config &
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+
+ /* Force KR or KX */
+ bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0, ext_phy_addr,
+ EXT_PHY_KR_PMA_PMD_DEVAD, EXT_PHY_KR_CTRL,
+ 0x2040);
+ bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0, ext_phy_addr,
+ EXT_PHY_KR_PMA_PMD_DEVAD, EXT_PHY_KR_CTRL2,
+ 0x000b);
+ bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0, ext_phy_addr,
+ EXT_PHY_KR_PMA_PMD_DEVAD, EXT_PHY_KR_PMD_CTRL,
+ 0x0000);
+ bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0, ext_phy_addr,
+ EXT_PHY_KR_AUTO_NEG_DEVAD, EXT_PHY_KR_CTRL,
+ 0x0000);
}
static void bnx2x_ext_phy_init(struct bnx2x *bp)
{
- int port = bp->port;
u32 ext_phy_type;
u32 ext_phy_addr;
- u32 local_phy;
+ u32 cnt;
+ u32 ctrl;
+ u32 val = 0;
if (bp->phy_flags & PHY_XGXS_FLAG) {
- local_phy = bp->phy_addr;
ext_phy_addr = ((bp->ext_phy_config &
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
ext_phy_type = XGXS_EXT_PHY_TYPE(bp);
+ /* Make sure that the soft reset is off (expect for the 8072:
+ * due to the lock, it will be done inside the specific
+ * handling)
+ */
+ if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
+ (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
+ (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN) &&
+ (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072)) {
+ /* Wait for soft reset to get cleared upto 1 sec */
+ for (cnt = 0; cnt < 1000; cnt++) {
+ bnx2x_mdio45_read(bp, ext_phy_addr,
+ EXT_PHY_OPT_PMA_PMD_DEVAD,
+ EXT_PHY_OPT_CNTL, &ctrl);
+ if (!(ctrl & (1<<15)))
+ break;
+ msleep(1);
+ }
+ DP(NETIF_MSG_LINK,
+ "control reg 0x%x (after %d ms)\n", ctrl, cnt);
+ }
+
switch (ext_phy_type) {
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
DP(NETIF_MSG_LINK, "XGXS Direct\n");
@@ -2800,49 +3370,235 @@ static void bnx2x_ext_phy_init(struct bnx2x *bp)
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
DP(NETIF_MSG_LINK, "XGXS 8705\n");
- bnx2x_bits_en(bp,
- NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
- NIG_MASK_MI_INT);
- DP(NETIF_MSG_LINK, "enabled extenal phy int\n");
- bp->phy_addr = ext_phy_type;
- bnx2x_mdio45_vwrite(bp, EXT_PHY_OPT_PMA_PMD_DEVAD,
+ bnx2x_mdio45_vwrite(bp, ext_phy_addr,
+ EXT_PHY_OPT_PMA_PMD_DEVAD,
EXT_PHY_OPT_PMD_MISC_CNTL,
0x8288);
- bnx2x_mdio45_vwrite(bp, EXT_PHY_OPT_PMA_PMD_DEVAD,
+ bnx2x_mdio45_vwrite(bp, ext_phy_addr,
+ EXT_PHY_OPT_PMA_PMD_DEVAD,
EXT_PHY_OPT_PHY_IDENTIFIER,
0x7fbf);
- bnx2x_mdio45_vwrite(bp, EXT_PHY_OPT_PMA_PMD_DEVAD,
+ bnx2x_mdio45_vwrite(bp, ext_phy_addr,
+ EXT_PHY_OPT_PMA_PMD_DEVAD,
EXT_PHY_OPT_CMU_PLL_BYPASS,
0x0100);
- bnx2x_mdio45_vwrite(bp, EXT_PHY_OPT_WIS_DEVAD,
+ bnx2x_mdio45_vwrite(bp, ext_phy_addr,
+ EXT_PHY_OPT_WIS_DEVAD,
EXT_PHY_OPT_LASI_CNTL, 0x1);
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
DP(NETIF_MSG_LINK, "XGXS 8706\n");
- bnx2x_bits_en(bp,
- NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
- NIG_MASK_MI_INT);
- DP(NETIF_MSG_LINK, "enabled extenal phy int\n");
-
- bp->phy_addr = ext_phy_type;
- bnx2x_mdio45_vwrite(bp, EXT_PHY_OPT_PMA_PMD_DEVAD,
- EXT_PHY_OPT_PMD_DIGITAL_CNT,
- 0x400);
- bnx2x_mdio45_vwrite(bp, EXT_PHY_OPT_PMA_PMD_DEVAD,
+
+ if (!(bp->req_autoneg & AUTONEG_SPEED)) {
+ /* Force speed */
+ if (bp->req_line_speed == SPEED_10000) {
+ DP(NETIF_MSG_LINK,
+ "XGXS 8706 force 10Gbps\n");
+ bnx2x_mdio45_vwrite(bp, ext_phy_addr,
+ EXT_PHY_OPT_PMA_PMD_DEVAD,
+ EXT_PHY_OPT_PMD_DIGITAL_CNT,
+ 0x400);
+ } else {
+ /* Force 1Gbps */
+ DP(NETIF_MSG_LINK,
+ "XGXS 8706 force 1Gbps\n");
+
+ bnx2x_mdio45_vwrite(bp, ext_phy_addr,
+ EXT_PHY_OPT_PMA_PMD_DEVAD,
+ EXT_PHY_OPT_CNTL,
+ 0x0040);
+
+ bnx2x_mdio45_vwrite(bp, ext_phy_addr,
+ EXT_PHY_OPT_PMA_PMD_DEVAD,
+ EXT_PHY_OPT_CNTL2,
+ 0x000D);
+ }
+
+ /* Enable LASI */
+ bnx2x_mdio45_vwrite(bp, ext_phy_addr,
+ EXT_PHY_OPT_PMA_PMD_DEVAD,
+ EXT_PHY_OPT_LASI_CNTL,
+ 0x1);
+ } else {
+ /* AUTONEG */
+ /* Allow CL37 through CL73 */
+ DP(NETIF_MSG_LINK, "XGXS 8706 AutoNeg\n");
+ bnx2x_mdio45_vwrite(bp, ext_phy_addr,
+ EXT_PHY_AUTO_NEG_DEVAD,
+ EXT_PHY_OPT_AN_CL37_CL73,
+ 0x040c);
+
+ /* Enable Full-Duplex advertisment on CL37 */
+ bnx2x_mdio45_vwrite(bp, ext_phy_addr,
+ EXT_PHY_AUTO_NEG_DEVAD,
+ EXT_PHY_OPT_AN_CL37_FD,
+ 0x0020);
+ /* Enable CL37 AN */
+ bnx2x_mdio45_vwrite(bp, ext_phy_addr,
+ EXT_PHY_AUTO_NEG_DEVAD,
+ EXT_PHY_OPT_AN_CL37_AN,
+ 0x1000);
+ /* Advertise 10G/1G support */
+ if (bp->advertising &
+ ADVERTISED_1000baseT_Full)
+ val = (1<<5);
+ if (bp->advertising &
+ ADVERTISED_10000baseT_Full)
+ val |= (1<<7);
+
+ bnx2x_mdio45_vwrite(bp, ext_phy_addr,
+ EXT_PHY_AUTO_NEG_DEVAD,
+ EXT_PHY_OPT_AN_ADV, val);
+ /* Enable LASI */
+ bnx2x_mdio45_vwrite(bp, ext_phy_addr,
+ EXT_PHY_OPT_PMA_PMD_DEVAD,
+ EXT_PHY_OPT_LASI_CNTL,
+ 0x1);
+
+ /* Enable clause 73 AN */
+ bnx2x_mdio45_write(bp, ext_phy_addr,
+ EXT_PHY_AUTO_NEG_DEVAD,
+ EXT_PHY_OPT_CNTL,
+ 0x1200);
+ }
+ break;
+
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
+ bnx2x_hw_lock(bp, HW_LOCK_RESOURCE_8072_MDIO);
+ /* Wait for soft reset to get cleared upto 1 sec */
+ for (cnt = 0; cnt < 1000; cnt++) {
+ bnx2x_mdio45_ctrl_read(bp, GRCBASE_EMAC0,
+ ext_phy_addr,
+ EXT_PHY_OPT_PMA_PMD_DEVAD,
+ EXT_PHY_OPT_CNTL, &ctrl);
+ if (!(ctrl & (1<<15)))
+ break;
+ msleep(1);
+ }
+ DP(NETIF_MSG_LINK,
+ "8072 control reg 0x%x (after %d ms)\n",
+ ctrl, cnt);
+
+ bnx2x_bcm8072_external_rom_boot(bp);
+ DP(NETIF_MSG_LINK, "Finshed loading 8072 KR ROM\n");
+
+ /* enable LASI */
+ bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0,
+ ext_phy_addr,
+ EXT_PHY_KR_PMA_PMD_DEVAD,
+ 0x9000, 0x0400);
+ bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0,
+ ext_phy_addr,
+ EXT_PHY_KR_PMA_PMD_DEVAD,
+ EXT_PHY_KR_LASI_CNTL, 0x0004);
+
+ /* If this is forced speed, set to KR or KX
+ * (all other are not supported)
+ */
+ if (!(bp->req_autoneg & AUTONEG_SPEED)) {
+ if (bp->req_line_speed == SPEED_10000) {
+ bnx2x_bcm8072_force_10G(bp);
+ DP(NETIF_MSG_LINK,
+ "Forced speed 10G on 8072\n");
+ /* unlock */
+ bnx2x_hw_unlock(bp,
+ HW_LOCK_RESOURCE_8072_MDIO);
+ break;
+ } else
+ val = (1<<5);
+ } else {
+
+ /* Advertise 10G/1G support */
+ if (bp->advertising &
+ ADVERTISED_1000baseT_Full)
+ val = (1<<5);
+ if (bp->advertising &
+ ADVERTISED_10000baseT_Full)
+ val |= (1<<7);
+ }
+ bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0,
+ ext_phy_addr,
+ EXT_PHY_KR_AUTO_NEG_DEVAD,
+ 0x11, val);
+ /* Add support for CL37 ( passive mode ) I */
+ bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0,
+ ext_phy_addr,
+ EXT_PHY_KR_AUTO_NEG_DEVAD,
+ 0x8370, 0x040c);
+ /* Add support for CL37 ( passive mode ) II */
+ bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0,
+ ext_phy_addr,
+ EXT_PHY_KR_AUTO_NEG_DEVAD,
+ 0xffe4, 0x20);
+ /* Add support for CL37 ( passive mode ) III */
+ bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0,
+ ext_phy_addr,
+ EXT_PHY_KR_AUTO_NEG_DEVAD,
+ 0xffe0, 0x1000);
+ /* Restart autoneg */
+ msleep(500);
+ bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0,
+ ext_phy_addr,
+ EXT_PHY_KR_AUTO_NEG_DEVAD,
+ EXT_PHY_KR_CTRL, 0x1200);
+ DP(NETIF_MSG_LINK, "8072 Autoneg Restart: "
+ "1G %ssupported 10G %ssupported\n",
+ (val & (1<<5)) ? "" : "not ",
+ (val & (1<<7)) ? "" : "not ");
+
+ /* unlock */
+ bnx2x_hw_unlock(bp, HW_LOCK_RESOURCE_8072_MDIO);
+ break;
+
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
+ DP(NETIF_MSG_LINK,
+ "Setting the SFX7101 LASI indication\n");
+ bnx2x_mdio45_vwrite(bp, ext_phy_addr,
+ EXT_PHY_OPT_PMA_PMD_DEVAD,
EXT_PHY_OPT_LASI_CNTL, 0x1);
+ DP(NETIF_MSG_LINK,
+ "Setting the SFX7101 LED to blink on traffic\n");
+ bnx2x_mdio45_vwrite(bp, ext_phy_addr,
+ EXT_PHY_OPT_PMA_PMD_DEVAD,
+ 0xC007, (1<<3));
+
+ /* read modify write pause advertizing */
+ bnx2x_mdio45_read(bp, ext_phy_addr,
+ EXT_PHY_KR_AUTO_NEG_DEVAD,
+ EXT_PHY_KR_AUTO_NEG_ADVERT, &val);
+ val &= ~EXT_PHY_KR_AUTO_NEG_ADVERT_PAUSE_BOTH;
+ /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
+ if (bp->advertising & ADVERTISED_Pause)
+ val |= EXT_PHY_KR_AUTO_NEG_ADVERT_PAUSE;
+
+ if (bp->advertising & ADVERTISED_Asym_Pause) {
+ val |=
+ EXT_PHY_KR_AUTO_NEG_ADVERT_PAUSE_ASYMMETRIC;
+ }
+ DP(NETIF_MSG_LINK, "SFX7101 AN advertize 0x%x\n", val);
+ bnx2x_mdio45_vwrite(bp, ext_phy_addr,
+ EXT_PHY_KR_AUTO_NEG_DEVAD,
+ EXT_PHY_KR_AUTO_NEG_ADVERT, val);
+ /* Restart autoneg */
+ bnx2x_mdio45_read(bp, ext_phy_addr,
+ EXT_PHY_KR_AUTO_NEG_DEVAD,
+ EXT_PHY_KR_CTRL, &val);
+ val |= 0x200;
+ bnx2x_mdio45_write(bp, ext_phy_addr,
+ EXT_PHY_KR_AUTO_NEG_DEVAD,
+ EXT_PHY_KR_CTRL, val);
break;
default:
- DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
- bp->ext_phy_config);
+ BNX2X_ERR("BAD XGXS ext_phy_config 0x%x\n",
+ bp->ext_phy_config);
break;
}
- bp->phy_addr = local_phy;
} else { /* SerDes */
-/* ext_phy_addr = ((bp->ext_phy_config &
+/* ext_phy_addr = ((bp->ext_phy_config &
PORT_HW_CFG_SERDES_EXT_PHY_ADDR_MASK) >>
PORT_HW_CFG_SERDES_EXT_PHY_ADDR_SHIFT);
*/
@@ -2854,10 +3610,6 @@ static void bnx2x_ext_phy_init(struct bnx2x *bp)
case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
DP(NETIF_MSG_LINK, "SerDes 5482\n");
- bnx2x_bits_en(bp,
- NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
- NIG_MASK_MI_INT);
- DP(NETIF_MSG_LINK, "enabled extenal phy int\n");
break;
default:
@@ -2871,8 +3623,22 @@ static void bnx2x_ext_phy_init(struct bnx2x *bp)
static void bnx2x_ext_phy_reset(struct bnx2x *bp)
{
u32 ext_phy_type;
- u32 ext_phy_addr;
- u32 local_phy;
+ u32 ext_phy_addr = ((bp->ext_phy_config &
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+ u32 board = (bp->board & SHARED_HW_CFG_BOARD_TYPE_MASK);
+
+ /* The PHY reset is controled by GPIO 1
+ * Give it 1ms of reset pulse
+ */
+ if ((board != SHARED_HW_CFG_BOARD_TYPE_BCM957710T1002G) &&
+ (board != SHARED_HW_CFG_BOARD_TYPE_BCM957710T1003G)) {
+ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
+ MISC_REGISTERS_GPIO_OUTPUT_LOW);
+ msleep(1);
+ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
+ MISC_REGISTERS_GPIO_OUTPUT_HIGH);
+ }
if (bp->phy_flags & PHY_XGXS_FLAG) {
ext_phy_type = XGXS_EXT_PHY_TYPE(bp);
@@ -2883,15 +3649,24 @@ static void bnx2x_ext_phy_reset(struct bnx2x *bp)
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
- DP(NETIF_MSG_LINK, "XGXS 8705/6\n");
- local_phy = bp->phy_addr;
- ext_phy_addr = ((bp->ext_phy_config &
- PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
- PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
- bp->phy_addr = (u8)ext_phy_addr;
- bnx2x_mdio45_write(bp, EXT_PHY_OPT_PMA_PMD_DEVAD,
+ DP(NETIF_MSG_LINK, "XGXS 8705/8706\n");
+ bnx2x_mdio45_write(bp, ext_phy_addr,
+ EXT_PHY_OPT_PMA_PMD_DEVAD,
EXT_PHY_OPT_CNTL, 0xa040);
- bp->phy_addr = local_phy;
+ break;
+
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
+ DP(NETIF_MSG_LINK, "XGXS 8072\n");
+ bnx2x_hw_lock(bp, HW_LOCK_RESOURCE_8072_MDIO);
+ bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0,
+ ext_phy_addr,
+ EXT_PHY_KR_PMA_PMD_DEVAD,
+ 0, 1<<15);
+ bnx2x_hw_unlock(bp, HW_LOCK_RESOURCE_8072_MDIO);
+ break;
+
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
+ DP(NETIF_MSG_LINK, "XGXS SFX7101\n");
break;
default:
@@ -2930,6 +3705,7 @@ static void bnx2x_link_initialize(struct bnx2x *bp)
NIG_MASK_SERDES0_LINK_STATUS |
NIG_MASK_MI_INT));
+ /* Activate the external PHY */
bnx2x_ext_phy_reset(bp);
bnx2x_set_aer_mmd(bp);
@@ -2994,13 +3770,13 @@ static void bnx2x_link_initialize(struct bnx2x *bp)
/* AN enabled */
bnx2x_set_brcm_cl37_advertisment(bp);
- /* program duplex & pause advertisment (for aneg) */
+ /* program duplex & pause advertisement (for aneg) */
bnx2x_set_ieee_aneg_advertisment(bp);
/* enable autoneg */
bnx2x_set_autoneg(bp);
- /* enalbe and restart AN */
+ /* enable and restart AN */
bnx2x_restart_autoneg(bp);
}
@@ -3010,11 +3786,11 @@ static void bnx2x_link_initialize(struct bnx2x *bp)
bnx2x_initialize_sgmii_process(bp);
}
- /* enable the interrupt */
- bnx2x_link_int_enable(bp);
-
/* init ext phy and enable link state int */
bnx2x_ext_phy_init(bp);
+
+ /* enable the interrupt */
+ bnx2x_link_int_enable(bp);
}
static void bnx2x_phy_deassert(struct bnx2x *bp)
@@ -3073,6 +3849,11 @@ static int bnx2x_phy_init(struct bnx2x *bp)
static void bnx2x_link_reset(struct bnx2x *bp)
{
int port = bp->port;
+ u32 board = (bp->board & SHARED_HW_CFG_BOARD_TYPE_MASK);
+
+ /* update shared memory */
+ bp->link_status = 0;
+ bnx2x_update_mng(bp);
/* disable attentions */
bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
@@ -3081,21 +3862,45 @@ static void bnx2x_link_reset(struct bnx2x *bp)
NIG_MASK_SERDES0_LINK_STATUS |
NIG_MASK_MI_INT));
- bnx2x_ext_phy_reset(bp);
+ /* activate nig drain */
+ NIG_WR(NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
+
+ /* disable nig egress interface */
+ NIG_WR(NIG_REG_BMAC0_OUT_EN + port*4, 0);
+ NIG_WR(NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
+
+ /* Stop BigMac rx */
+ bnx2x_bmac_rx_disable(bp);
+
+ /* disable emac */
+ NIG_WR(NIG_REG_NIG_EMAC0_EN + port*4, 0);
+
+ msleep(10);
+
+ /* The PHY reset is controled by GPIO 1
+ * Hold it as output low
+ */
+ if ((board != SHARED_HW_CFG_BOARD_TYPE_BCM957710T1002G) &&
+ (board != SHARED_HW_CFG_BOARD_TYPE_BCM957710T1003G)) {
+ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
+ MISC_REGISTERS_GPIO_OUTPUT_LOW);
+ DP(NETIF_MSG_LINK, "reset external PHY\n");
+ }
/* reset the SerDes/XGXS */
REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
(0x1ff << (port*16)));
- /* reset EMAC / BMAC and disable NIG interfaces */
- NIG_WR(NIG_REG_BMAC0_IN_EN + port*4, 0);
- NIG_WR(NIG_REG_BMAC0_OUT_EN + port*4, 0);
+ /* reset BigMac */
+ REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
+ (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
- NIG_WR(NIG_REG_NIG_EMAC0_EN + port*4, 0);
+ /* disable nig ingress interface */
+ NIG_WR(NIG_REG_BMAC0_IN_EN + port*4, 0);
NIG_WR(NIG_REG_EMAC0_IN_EN + port*4, 0);
- NIG_WR(NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
- NIG_WR(NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
+ /* set link down */
+ bp->link_up = 0;
}
#ifdef BNX2X_XGXS_LB
@@ -3158,7 +3963,7 @@ static int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
int port = bp->port;
DP(NETIF_MSG_TIMER,
- "spe (%x:%x) command %x hw_cid %x data (%x:%x) left %x\n",
+ "spe (%x:%x) command %d hw_cid %x data (%x:%x) left %x\n",
(u32)U64_HI(bp->spq_mapping), (u32)(U64_LO(bp->spq_mapping) +
(void *)bp->spq_prod_bd - (void *)bp->spq), command,
HW_CID(bp, cid), data_hi, data_lo, bp->spq_left);
@@ -3176,6 +3981,7 @@ static int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
bnx2x_panic();
return -EBUSY;
}
+
/* CID needs port number to be encoded int it */
bp->spq_prod_bd->hdr.conn_and_cmd_data =
cpu_to_le32(((command << SPE_HDR_CMD_ID_SHIFT) |
@@ -3282,8 +4088,8 @@ static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted)
u32 igu_addr = (IGU_ADDR_ATTN_BITS_SET + IGU_PORT_BASE * port) * 8;
u32 aeu_addr = port ? MISC_REG_AEU_MASK_ATTN_FUNC_1 :
MISC_REG_AEU_MASK_ATTN_FUNC_0;
- u32 nig_mask_addr = port ? NIG_REG_MASK_INTERRUPT_PORT1 :
- NIG_REG_MASK_INTERRUPT_PORT0;
+ u32 nig_int_mask_addr = port ? NIG_REG_MASK_INTERRUPT_PORT1 :
+ NIG_REG_MASK_INTERRUPT_PORT0;
if (~bp->aeu_mask & (asserted & 0xff))
BNX2X_ERR("IGU ERROR\n");
@@ -3301,15 +4107,11 @@ static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted)
if (asserted & ATTN_HARD_WIRED_MASK) {
if (asserted & ATTN_NIG_FOR_FUNC) {
- u32 nig_status_port;
- u32 nig_int_addr = port ?
- NIG_REG_STATUS_INTERRUPT_PORT1 :
- NIG_REG_STATUS_INTERRUPT_PORT0;
- bp->nig_mask = REG_RD(bp, nig_mask_addr);
- REG_WR(bp, nig_mask_addr, 0);
+ /* save nig interrupt mask */
+ bp->nig_mask = REG_RD(bp, nig_int_mask_addr);
+ REG_WR(bp, nig_int_mask_addr, 0);
- nig_status_port = REG_RD(bp, nig_int_addr);
bnx2x_link_update(bp);
/* handle unicore attn? */
@@ -3362,15 +4164,132 @@ static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted)
/* now set back the mask */
if (asserted & ATTN_NIG_FOR_FUNC)
- REG_WR(bp, nig_mask_addr, bp->nig_mask);
+ REG_WR(bp, nig_int_mask_addr, bp->nig_mask);
}
-static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted)
+static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn)
{
int port = bp->port;
- int index;
+ int reg_offset;
+ u32 val;
+
+ if (attn & AEU_INPUTS_ATTN_BITS_SPIO5) {
+
+ reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 :
+ MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
+
+ val = REG_RD(bp, reg_offset);
+ val &= ~AEU_INPUTS_ATTN_BITS_SPIO5;
+ REG_WR(bp, reg_offset, val);
+
+ BNX2X_ERR("SPIO5 hw attention\n");
+
+ switch (bp->board & SHARED_HW_CFG_BOARD_TYPE_MASK) {
+ case SHARED_HW_CFG_BOARD_TYPE_BCM957710A1022G:
+ /* Fan failure attention */
+
+ /* The PHY reset is controled by GPIO 1 */
+ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
+ MISC_REGISTERS_GPIO_OUTPUT_LOW);
+ /* Low power mode is controled by GPIO 2 */
+ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
+ MISC_REGISTERS_GPIO_OUTPUT_LOW);
+ /* mark the failure */
+ bp->ext_phy_config &=
+ ~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
+ bp->ext_phy_config |=
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE;
+ SHMEM_WR(bp,
+ dev_info.port_hw_config[port].
+ external_phy_config,
+ bp->ext_phy_config);
+ /* log the failure */
+ printk(KERN_ERR PFX "Fan Failure on Network"
+ " Controller %s has caused the driver to"
+ " shutdown the card to prevent permanent"
+ " damage. Please contact Dell Support for"
+ " assistance\n", bp->dev->name);
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+static inline void bnx2x_attn_int_deasserted1(struct bnx2x *bp, u32 attn)
+{
+ u32 val;
+
+ if (attn & BNX2X_DOORQ_ASSERT) {
+
+ val = REG_RD(bp, DORQ_REG_DORQ_INT_STS_CLR);
+ BNX2X_ERR("DB hw attention 0x%x\n", val);
+ /* DORQ discard attention */
+ if (val & 0x2)
+ BNX2X_ERR("FATAL error from DORQ\n");
+ }
+}
+
+static inline void bnx2x_attn_int_deasserted2(struct bnx2x *bp, u32 attn)
+{
+ u32 val;
+
+ if (attn & AEU_INPUTS_ATTN_BITS_CFC_HW_INTERRUPT) {
+
+ val = REG_RD(bp, CFC_REG_CFC_INT_STS_CLR);
+ BNX2X_ERR("CFC hw attention 0x%x\n", val);
+ /* CFC error attention */
+ if (val & 0x2)
+ BNX2X_ERR("FATAL error from CFC\n");
+ }
+
+ if (attn & AEU_INPUTS_ATTN_BITS_PXP_HW_INTERRUPT) {
+
+ val = REG_RD(bp, PXP_REG_PXP_INT_STS_CLR_0);
+ BNX2X_ERR("PXP hw attention 0x%x\n", val);
+ /* RQ_USDMDP_FIFO_OVERFLOW */
+ if (val & 0x18000)
+ BNX2X_ERR("FATAL error from PXP\n");
+ }
+}
+
+static inline void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn)
+{
+ if (attn & EVEREST_GEN_ATTN_IN_USE_MASK) {
+
+ if (attn & BNX2X_MC_ASSERT_BITS) {
+
+ BNX2X_ERR("MC assert!\n");
+ REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_10, 0);
+ REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_9, 0);
+ REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_8, 0);
+ REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_7, 0);
+ bnx2x_panic();
+
+ } else if (attn & BNX2X_MCP_ASSERT) {
+
+ BNX2X_ERR("MCP assert!\n");
+ REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_11, 0);
+ bnx2x_mc_assert(bp);
+
+ } else
+ BNX2X_ERR("Unknown HW assert! (attn 0x%x)\n", attn);
+ }
+
+ if (attn & EVEREST_LATCHED_ATTN_IN_USE_MASK) {
+
+ REG_WR(bp, MISC_REG_AEU_CLR_LATCH_SIGNAL, 0x7ff);
+ BNX2X_ERR("LATCHED attention 0x%x (masked)\n", attn);
+ }
+}
+
+static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted)
+{
struct attn_route attn;
struct attn_route group_mask;
+ int port = bp->port;
+ int index;
u32 reg_addr;
u32 val;
@@ -3391,64 +4310,14 @@ static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted)
DP(NETIF_MSG_HW, "group[%d]: %llx\n", index,
(unsigned long long)group_mask.sig[0]);
- if (attn.sig[3] & group_mask.sig[3] &
- EVEREST_GEN_ATTN_IN_USE_MASK) {
-
- if (attn.sig[3] & BNX2X_MC_ASSERT_BITS) {
-
- BNX2X_ERR("MC assert!\n");
- bnx2x_panic();
-
- } else if (attn.sig[3] & BNX2X_MCP_ASSERT) {
-
- BNX2X_ERR("MCP assert!\n");
- REG_WR(bp,
- MISC_REG_AEU_GENERAL_ATTN_11, 0);
- bnx2x_mc_assert(bp);
-
- } else {
- BNX2X_ERR("UNKOWEN HW ASSERT!\n");
- }
- }
-
- if (attn.sig[1] & group_mask.sig[1] &
- BNX2X_DOORQ_ASSERT) {
-
- val = REG_RD(bp, DORQ_REG_DORQ_INT_STS_CLR);
- BNX2X_ERR("DB hw attention 0x%x\n", val);
- /* DORQ discard attention */
- if (val & 0x2)
- BNX2X_ERR("FATAL error from DORQ\n");
- }
-
- if (attn.sig[2] & group_mask.sig[2] &
- AEU_INPUTS_ATTN_BITS_CFC_HW_INTERRUPT) {
-
- val = REG_RD(bp, CFC_REG_CFC_INT_STS_CLR);
- BNX2X_ERR("CFC hw attention 0x%x\n", val);
- /* CFC error attention */
- if (val & 0x2)
- BNX2X_ERR("FATAL error from CFC\n");
- }
-
- if (attn.sig[2] & group_mask.sig[2] &
- AEU_INPUTS_ATTN_BITS_PXP_HW_INTERRUPT) {
-
- val = REG_RD(bp, PXP_REG_PXP_INT_STS_CLR_0);
- BNX2X_ERR("PXP hw attention 0x%x\n", val);
- /* RQ_USDMDP_FIFO_OVERFLOW */
- if (val & 0x18000)
- BNX2X_ERR("FATAL error from PXP\n");
- }
-
- if (attn.sig[3] & group_mask.sig[3] &
- EVEREST_LATCHED_ATTN_IN_USE_MASK) {
-
- REG_WR(bp, MISC_REG_AEU_CLR_LATCH_SIGNAL,
- 0x7ff);
- DP(NETIF_MSG_HW, "got latched bits 0x%x\n",
- attn.sig[3]);
- }
+ bnx2x_attn_int_deasserted3(bp,
+ attn.sig[3] & group_mask.sig[3]);
+ bnx2x_attn_int_deasserted1(bp,
+ attn.sig[1] & group_mask.sig[1]);
+ bnx2x_attn_int_deasserted2(bp,
+ attn.sig[2] & group_mask.sig[2]);
+ bnx2x_attn_int_deasserted0(bp,
+ attn.sig[0] & group_mask.sig[0]);
if ((attn.sig[0] & group_mask.sig[0] &
HW_INTERRUT_ASSERT_SET_0) ||
@@ -3456,7 +4325,15 @@ static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted)
HW_INTERRUT_ASSERT_SET_1) ||
(attn.sig[2] & group_mask.sig[2] &
HW_INTERRUT_ASSERT_SET_2))
- BNX2X_ERR("FATAL HW block attention\n");
+ BNX2X_ERR("FATAL HW block attention"
+ " set0 0x%x set1 0x%x"
+ " set2 0x%x\n",
+ (attn.sig[0] & group_mask.sig[0] &
+ HW_INTERRUT_ASSERT_SET_0),
+ (attn.sig[1] & group_mask.sig[1] &
+ HW_INTERRUT_ASSERT_SET_1),
+ (attn.sig[2] & group_mask.sig[2] &
+ HW_INTERRUT_ASSERT_SET_2));
if ((attn.sig[0] & group_mask.sig[0] &
HW_PRTY_ASSERT_SET_0) ||
@@ -3464,7 +4341,7 @@ static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted)
HW_PRTY_ASSERT_SET_1) ||
(attn.sig[2] & group_mask.sig[2] &
HW_PRTY_ASSERT_SET_2))
- BNX2X_ERR("FATAL HW block parity atention\n");
+ BNX2X_ERR("FATAL HW block parity attention\n");
}
}
@@ -3529,7 +4406,7 @@ static void bnx2x_sp_task(struct work_struct *work)
/* Return here if interrupt is disabled */
if (unlikely(atomic_read(&bp->intr_sem) != 0)) {
- DP(NETIF_MSG_INTR, "called but intr_sem not 0, returning\n");
+ DP(BNX2X_MSG_SP, "called but intr_sem not 0, returning\n");
return;
}
@@ -3539,12 +4416,11 @@ static void bnx2x_sp_task(struct work_struct *work)
DP(NETIF_MSG_INTR, "got a slowpath interrupt (updated %x)\n", status);
- if (status & 0x1) {
- /* HW attentions */
+ /* HW attentions */
+ if (status & 0x1)
bnx2x_attn_int(bp);
- }
- /* CStorm events: query_stats, cfc delete ramrods */
+ /* CStorm events: query_stats, port delete ramrod */
if (status & 0x2)
bp->stat_pending = 0;
@@ -3558,6 +4434,7 @@ static void bnx2x_sp_task(struct work_struct *work)
IGU_INT_NOP, 1);
bnx2x_ack_sb(bp, DEF_SB_ID, TSTORM_ID, le16_to_cpu(bp->def_t_idx),
IGU_INT_ENABLE, 1);
+
}
static irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance)
@@ -3567,11 +4444,11 @@ static irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance)
/* Return here if interrupt is disabled */
if (unlikely(atomic_read(&bp->intr_sem) != 0)) {
- DP(NETIF_MSG_INTR, "called but intr_sem not 0, returning\n");
+ DP(BNX2X_MSG_SP, "called but intr_sem not 0, returning\n");
return IRQ_HANDLED;
}
- bnx2x_ack_sb(bp, 16, XSTORM_ID, 0, IGU_INT_DISABLE, 0);
+ bnx2x_ack_sb(bp, DEF_SB_ID, XSTORM_ID, 0, IGU_INT_DISABLE, 0);
#ifdef BNX2X_STOP_ON_ERROR
if (unlikely(bp->panic))
@@ -3906,7 +4783,7 @@ static void bnx2x_stop_stats(struct bnx2x *bp)
while (bp->stats_state != STATS_STATE_DISABLE) {
if (!timeout) {
- BNX2X_ERR("timeout wating for stats stop\n");
+ BNX2X_ERR("timeout waiting for stats stop\n");
break;
}
timeout--;
@@ -4173,39 +5050,37 @@ static void bnx2x_update_net_stats(struct bnx2x *bp)
nstats->rx_bytes = bnx2x_hilo(&estats->total_bytes_received_hi);
- nstats->tx_bytes =
- bnx2x_hilo(&estats->total_bytes_transmitted_hi);
+ nstats->tx_bytes = bnx2x_hilo(&estats->total_bytes_transmitted_hi);
- nstats->rx_dropped = estats->checksum_discard +
- estats->mac_discard;
+ nstats->rx_dropped = estats->checksum_discard + estats->mac_discard;
nstats->tx_dropped = 0;
nstats->multicast =
bnx2x_hilo(&estats->total_multicast_packets_transmitted_hi);
- nstats->collisions =
- estats->single_collision_transmit_frames +
- estats->multiple_collision_transmit_frames +
- estats->late_collision_frames +
- estats->excessive_collision_frames;
+ nstats->collisions = estats->single_collision_transmit_frames +
+ estats->multiple_collision_transmit_frames +
+ estats->late_collision_frames +
+ estats->excessive_collision_frames;
nstats->rx_length_errors = estats->runt_packets_received +
estats->jabber_packets_received;
- nstats->rx_over_errors = estats->no_buff_discard;
+ nstats->rx_over_errors = estats->brb_discard +
+ estats->brb_truncate_discard;
nstats->rx_crc_errors = estats->crc_receive_errors;
nstats->rx_frame_errors = estats->alignment_errors;
- nstats->rx_fifo_errors = estats->brb_discard +
- estats->brb_truncate_discard;
+ nstats->rx_fifo_errors = estats->no_buff_discard;
nstats->rx_missed_errors = estats->xxoverflow_discard;
nstats->rx_errors = nstats->rx_length_errors +
nstats->rx_over_errors +
nstats->rx_crc_errors +
nstats->rx_frame_errors +
- nstats->rx_fifo_errors;
+ nstats->rx_fifo_errors +
+ nstats->rx_missed_errors;
nstats->tx_aborted_errors = estats->late_collision_frames +
- estats->excessive_collision_frames;
+ estats->excessive_collision_frames;
nstats->tx_carrier_errors = estats->false_carrier_detections;
nstats->tx_fifo_errors = 0;
nstats->tx_heartbeat_errors = 0;
@@ -4334,7 +5209,7 @@ static void bnx2x_timer(unsigned long data)
return;
if (atomic_read(&bp->intr_sem) != 0)
- goto bnx2x_restart_timer;
+ goto timer_restart;
if (poll) {
struct bnx2x_fastpath *fp = &bp->fp[0];
@@ -4344,7 +5219,7 @@ static void bnx2x_timer(unsigned long data)
rc = bnx2x_rx_int(fp, 1000);
}
- if (!nomcp && (bp->bc_ver >= 0x040003)) {
+ if (!nomcp) {
int port = bp->port;
u32 drv_pulse;
u32 mcp_pulse;
@@ -4353,9 +5228,9 @@ static void bnx2x_timer(unsigned long data)
bp->fw_drv_pulse_wr_seq &= DRV_PULSE_SEQ_MASK;
/* TBD - add SYSTEM_TIME */
drv_pulse = bp->fw_drv_pulse_wr_seq;
- SHMEM_WR(bp, drv_fw_mb[port].drv_pulse_mb, drv_pulse);
+ SHMEM_WR(bp, func_mb[port].drv_pulse_mb, drv_pulse);
- mcp_pulse = (SHMEM_RD(bp, drv_fw_mb[port].mcp_pulse_mb) &
+ mcp_pulse = (SHMEM_RD(bp, func_mb[port].mcp_pulse_mb) &
MCP_PULSE_SEQ_MASK);
/* The delta between driver pulse and mcp response
* should be 1 (before mcp response) or 0 (after mcp response)
@@ -4369,11 +5244,11 @@ static void bnx2x_timer(unsigned long data)
}
if (bp->stats_state == STATS_STATE_DISABLE)
- goto bnx2x_restart_timer;
+ goto timer_restart;
bnx2x_update_stats(bp);
-bnx2x_restart_timer:
+timer_restart:
mod_timer(&bp->timer, jiffies + bp->current_interval);
}
@@ -4438,6 +5313,9 @@ static void bnx2x_init_def_sb(struct bnx2x *bp,
atten_status_block);
def_sb->atten_status_block.status_block_id = id;
+ bp->def_att_idx = 0;
+ bp->attn_state = 0;
+
reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 :
MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
@@ -4472,6 +5350,8 @@ static void bnx2x_init_def_sb(struct bnx2x *bp,
u_def_status_block);
def_sb->u_def_status_block.status_block_id = id;
+ bp->def_u_idx = 0;
+
REG_WR(bp, BAR_USTRORM_INTMEM +
USTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port), U64_LO(section));
REG_WR(bp, BAR_USTRORM_INTMEM +
@@ -4489,6 +5369,8 @@ static void bnx2x_init_def_sb(struct bnx2x *bp,
c_def_status_block);
def_sb->c_def_status_block.status_block_id = id;
+ bp->def_c_idx = 0;
+
REG_WR(bp, BAR_CSTRORM_INTMEM +
CSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port), U64_LO(section));
REG_WR(bp, BAR_CSTRORM_INTMEM +
@@ -4506,6 +5388,8 @@ static void bnx2x_init_def_sb(struct bnx2x *bp,
t_def_status_block);
def_sb->t_def_status_block.status_block_id = id;
+ bp->def_t_idx = 0;
+
REG_WR(bp, BAR_TSTRORM_INTMEM +
TSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port), U64_LO(section));
REG_WR(bp, BAR_TSTRORM_INTMEM +
@@ -4523,6 +5407,8 @@ static void bnx2x_init_def_sb(struct bnx2x *bp,
x_def_status_block);
def_sb->x_def_status_block.status_block_id = id;
+ bp->def_x_idx = 0;
+
REG_WR(bp, BAR_XSTRORM_INTMEM +
XSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port), U64_LO(section));
REG_WR(bp, BAR_XSTRORM_INTMEM +
@@ -4535,6 +5421,8 @@ static void bnx2x_init_def_sb(struct bnx2x *bp,
REG_WR16(bp, BAR_XSTRORM_INTMEM +
XSTORM_DEF_SB_HC_DISABLE_OFFSET(port, index), 0x1);
+ bp->stat_pending = 0;
+
bnx2x_ack_sb(bp, id, CSTORM_ID, 0, IGU_INT_ENABLE, 0);
}
@@ -4626,7 +5514,7 @@ static void bnx2x_init_rx_rings(struct bnx2x *bp)
fp->rx_bd_prod = fp->rx_comp_prod = ring_prod;
fp->rx_pkt = fp->rx_calls = 0;
- /* Warning! this will genrate an interrupt (to the TSTORM) */
+ /* Warning! this will generate an interrupt (to the TSTORM) */
/* must only be done when chip is initialized */
REG_WR(bp, BAR_TSTRORM_INTMEM +
TSTORM_RCQ_PROD_OFFSET(port, j), ring_prod);
@@ -4678,7 +5566,6 @@ static void bnx2x_init_sp_ring(struct bnx2x *bp)
bp->spq_left = MAX_SPQ_PENDING;
bp->spq_prod_idx = 0;
- bp->dsb_sp_prod_idx = 0;
bp->dsb_sp_prod = BNX2X_SP_DSB_INDEX;
bp->spq_prod_bd = bp->spq;
bp->spq_last_bd = bp->spq_prod_bd + MAX_SP_DESC_CNT;
@@ -4755,6 +5642,42 @@ static void bnx2x_init_ind_table(struct bnx2x *bp)
REG_WR(bp, PRS_REG_A_PRSU_20, 0xf);
}
+static void bnx2x_set_client_config(struct bnx2x *bp)
+{
+#ifdef BCM_VLAN
+ int mode = bp->rx_mode;
+#endif
+ int i, port = bp->port;
+ struct tstorm_eth_client_config tstorm_client = {0};
+
+ tstorm_client.mtu = bp->dev->mtu;
+ tstorm_client.statistics_counter_id = 0;
+ tstorm_client.config_flags =
+ TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE;
+#ifdef BCM_VLAN
+ if (mode && bp->vlgrp) {
+ tstorm_client.config_flags |=
+ TSTORM_ETH_CLIENT_CONFIG_VLAN_REMOVAL_ENABLE;
+ DP(NETIF_MSG_IFUP, "vlan removal enabled\n");
+ }
+#endif
+ if (mode != BNX2X_RX_MODE_PROMISC)
+ tstorm_client.drop_flags =
+ TSTORM_ETH_CLIENT_CONFIG_DROP_MAC_ERR;
+
+ for_each_queue(bp, i) {
+ REG_WR(bp, BAR_TSTRORM_INTMEM +
+ TSTORM_CLIENT_CONFIG_OFFSET(port, i),
+ ((u32 *)&tstorm_client)[0]);
+ REG_WR(bp, BAR_TSTRORM_INTMEM +
+ TSTORM_CLIENT_CONFIG_OFFSET(port, i) + 4,
+ ((u32 *)&tstorm_client)[1]);
+ }
+
+/* DP(NETIF_MSG_IFUP, "tstorm_client: 0x%08x 0x%08x\n",
+ ((u32 *)&tstorm_client)[0], ((u32 *)&tstorm_client)[1]); */
+}
+
static void bnx2x_set_storm_rx_mode(struct bnx2x *bp)
{
int mode = bp->rx_mode;
@@ -4794,41 +5717,9 @@ static void bnx2x_set_storm_rx_mode(struct bnx2x *bp)
/* DP(NETIF_MSG_IFUP, "tstorm_mac_filter[%d]: 0x%08x\n", i,
((u32 *)&tstorm_mac_filter)[i]); */
}
-}
-static void bnx2x_set_client_config(struct bnx2x *bp, int client_id)
-{
-#ifdef BCM_VLAN
- int mode = bp->rx_mode;
-#endif
- int port = bp->port;
- struct tstorm_eth_client_config tstorm_client = {0};
-
- tstorm_client.mtu = bp->dev->mtu;
- tstorm_client.statistics_counter_id = 0;
- tstorm_client.config_flags =
- TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE;
-#ifdef BCM_VLAN
- if (mode && bp->vlgrp) {
- tstorm_client.config_flags |=
- TSTORM_ETH_CLIENT_CONFIG_VLAN_REMOVAL_ENABLE;
- DP(NETIF_MSG_IFUP, "vlan removal enabled\n");
- }
-#endif
- tstorm_client.drop_flags = (TSTORM_ETH_CLIENT_CONFIG_DROP_IP_CS_ERR |
- TSTORM_ETH_CLIENT_CONFIG_DROP_TCP_CS_ERR |
- TSTORM_ETH_CLIENT_CONFIG_DROP_UDP_CS_ERR |
- TSTORM_ETH_CLIENT_CONFIG_DROP_MAC_ERR);
-
- REG_WR(bp, BAR_TSTRORM_INTMEM +
- TSTORM_CLIENT_CONFIG_OFFSET(port, client_id),
- ((u32 *)&tstorm_client)[0]);
- REG_WR(bp, BAR_TSTRORM_INTMEM +
- TSTORM_CLIENT_CONFIG_OFFSET(port, client_id) + 4,
- ((u32 *)&tstorm_client)[1]);
-
-/* DP(NETIF_MSG_IFUP, "tstorm_client: 0x%08x 0x%08x\n",
- ((u32 *)&tstorm_client)[0], ((u32 *)&tstorm_client)[1]); */
+ if (mode != BNX2X_RX_MODE_NONE)
+ bnx2x_set_client_config(bp);
}
static void bnx2x_init_internal(struct bnx2x *bp)
@@ -4836,7 +5727,6 @@ static void bnx2x_init_internal(struct bnx2x *bp)
int port = bp->port;
struct tstorm_eth_function_common_config tstorm_config = {0};
struct stats_indication_flags stats_flags = {0};
- int i;
if (is_multi(bp)) {
tstorm_config.config_flags = MULTI_FLAGS;
@@ -4850,13 +5740,9 @@ static void bnx2x_init_internal(struct bnx2x *bp)
/* DP(NETIF_MSG_IFUP, "tstorm_config: 0x%08x\n",
(*(u32 *)&tstorm_config)); */
- bp->rx_mode = BNX2X_RX_MODE_NONE; /* no rx untill link is up */
+ bp->rx_mode = BNX2X_RX_MODE_NONE; /* no rx until link is up */
bnx2x_set_storm_rx_mode(bp);
- for_each_queue(bp, i)
- bnx2x_set_client_config(bp, i);
-
-
stats_flags.collect_eth = cpu_to_le32(1);
REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_STATS_FLAGS_OFFSET(port),
@@ -4902,7 +5788,7 @@ static void bnx2x_nic_init(struct bnx2x *bp)
bnx2x_init_internal(bp);
bnx2x_init_stats(bp);
bnx2x_init_ind_table(bp);
- bnx2x_enable_int(bp);
+ bnx2x_int_enable(bp);
}
@@ -5265,8 +6151,10 @@ static int bnx2x_function_init(struct bnx2x *bp, int mode)
if (mode & 0x1) { /* init common */
DP(BNX2X_MSG_MCP, "starting common init func %d mode %x\n",
func, mode);
- REG_WR(bp, MISC_REG_RESET_REG_1, 0xffffffff);
- REG_WR(bp, MISC_REG_RESET_REG_2, 0xfffc);
+ REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET,
+ 0xffffffff);
+ REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET,
+ 0xfffc);
bnx2x_init_block(bp, MISC_COMMON_START, MISC_COMMON_END);
REG_WR(bp, MISC_REG_LCPLL_CTRL_REG_2, 0x100);
@@ -5359,7 +6247,7 @@ static int bnx2x_function_init(struct bnx2x *bp, int mode)
REG_RD(bp, USEM_REG_PASSIVE_BUFFER + 8);
#endif
bnx2x_init_block(bp, QM_COMMON_START, QM_COMMON_END);
- /* softrest pulse */
+ /* soft reset pulse */
REG_WR(bp, QM_REG_SOFT_RESET, 1);
REG_WR(bp, QM_REG_SOFT_RESET, 0);
@@ -5413,7 +6301,7 @@ static int bnx2x_function_init(struct bnx2x *bp, int mode)
REG_WR(bp, SRC_REG_SOFT_RST, 1);
for (i = SRC_REG_KEYRSS0_0; i <= SRC_REG_KEYRSS1_9; i += 4) {
REG_WR(bp, i, 0xc0cac01a);
- /* TODO: repleace with something meaningfull */
+ /* TODO: replace with something meaningful */
}
/* SRCH COMMON comes here */
REG_WR(bp, SRC_REG_SOFT_RST, 0);
@@ -5486,6 +6374,28 @@ static int bnx2x_function_init(struct bnx2x *bp, int mode)
enable_blocks_attention(bp);
/* enable_blocks_parity(bp); */
+ switch (bp->board & SHARED_HW_CFG_BOARD_TYPE_MASK) {
+ case SHARED_HW_CFG_BOARD_TYPE_BCM957710A1022G:
+ /* Fan failure is indicated by SPIO 5 */
+ bnx2x_set_spio(bp, MISC_REGISTERS_SPIO_5,
+ MISC_REGISTERS_SPIO_INPUT_HI_Z);
+
+ /* set to active low mode */
+ val = REG_RD(bp, MISC_REG_SPIO_INT);
+ val |= ((1 << MISC_REGISTERS_SPIO_5) <<
+ MISC_REGISTERS_SPIO_INT_OLD_SET_POS);
+ REG_WR(bp, MISC_REG_SPIO_INT, val);
+
+ /* enable interrupt to signal the IGU */
+ val = REG_RD(bp, MISC_REG_SPIO_EVENT_EN);
+ val |= (1 << MISC_REGISTERS_SPIO_5);
+ REG_WR(bp, MISC_REG_SPIO_EVENT_EN, val);
+ break;
+
+ default:
+ break;
+ }
+
} /* end of common init */
/* per port init */
@@ -5645,9 +6555,21 @@ static int bnx2x_function_init(struct bnx2x *bp, int mode)
/* Port MCP comes here */
/* Port DMAE comes here */
+ switch (bp->board & SHARED_HW_CFG_BOARD_TYPE_MASK) {
+ case SHARED_HW_CFG_BOARD_TYPE_BCM957710A1022G:
+ /* add SPIO 5 to group 0 */
+ val = REG_RD(bp, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
+ val |= AEU_INPUTS_ATTN_BITS_SPIO5;
+ REG_WR(bp, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0, val);
+ break;
+
+ default:
+ break;
+ }
+
bnx2x_link_reset(bp);
- /* Reset pciex errors for debug */
+ /* Reset PCIE errors for debug */
REG_WR(bp, 0x2114, 0xffffffff);
REG_WR(bp, 0x2120, 0xffffffff);
REG_WR(bp, 0x2814, 0xffffffff);
@@ -5669,9 +6591,9 @@ static int bnx2x_function_init(struct bnx2x *bp, int mode)
port = bp->port;
bp->fw_drv_pulse_wr_seq =
- (SHMEM_RD(bp, drv_fw_mb[port].drv_pulse_mb) &
+ (SHMEM_RD(bp, func_mb[port].drv_pulse_mb) &
DRV_PULSE_SEQ_MASK);
- bp->fw_mb = SHMEM_RD(bp, drv_fw_mb[port].fw_mb_param);
+ bp->fw_mb = SHMEM_RD(bp, func_mb[port].fw_mb_param);
DP(BNX2X_MSG_MCP, "drv_pulse 0x%x fw_mb 0x%x\n",
bp->fw_drv_pulse_wr_seq, bp->fw_mb);
} else {
@@ -5681,16 +6603,15 @@ static int bnx2x_function_init(struct bnx2x *bp, int mode)
return 0;
}
-
-/* send the MCP a request, block untill there is a reply */
+/* send the MCP a request, block until there is a reply */
static u32 bnx2x_fw_command(struct bnx2x *bp, u32 command)
{
- u32 rc = 0;
- u32 seq = ++bp->fw_seq;
int port = bp->port;
+ u32 seq = ++bp->fw_seq;
+ u32 rc = 0;
- SHMEM_WR(bp, drv_fw_mb[port].drv_mb_header, command|seq);
- DP(BNX2X_MSG_MCP, "wrote command (%x) to FW MB\n", command|seq);
+ SHMEM_WR(bp, func_mb[port].drv_mb_header, (command | seq));
+ DP(BNX2X_MSG_MCP, "wrote command (%x) to FW MB\n", (command | seq));
/* let the FW do it's magic ... */
msleep(100); /* TBD */
@@ -5698,19 +6619,20 @@ static u32 bnx2x_fw_command(struct bnx2x *bp, u32 command)
if (CHIP_REV_IS_SLOW(bp))
msleep(900);
- rc = SHMEM_RD(bp, drv_fw_mb[port].fw_mb_header);
-
+ rc = SHMEM_RD(bp, func_mb[port].fw_mb_header);
DP(BNX2X_MSG_MCP, "read (%x) seq is (%x) from FW MB\n", rc, seq);
/* is this a reply to our command? */
if (seq == (rc & FW_MSG_SEQ_NUMBER_MASK)) {
rc &= FW_MSG_CODE_MASK;
+
} else {
/* FW BUG! */
BNX2X_ERR("FW failed to respond!\n");
bnx2x_fw_dump(bp);
rc = 0;
}
+
return rc;
}
@@ -5869,7 +6791,7 @@ static int bnx2x_alloc_mem(struct bnx2x *bp)
for (i = 0; i < 16*1024; i += 64)
* (u64 *)((char *)bp->t2 + i + 56) = bp->t2_mapping + i + 64;
- /* now sixup the last line in the block to point to the next block */
+ /* now fixup the last line in the block to point to the next block */
*(u64 *)((char *)bp->t2 + 1024*16-8) = bp->t2_mapping;
/* Timer block array (MAX_CONN*8) phys uncached for now 1024 conns */
@@ -5950,22 +6872,19 @@ static void bnx2x_free_msix_irqs(struct bnx2x *bp)
int i;
free_irq(bp->msix_table[0].vector, bp->dev);
- DP(NETIF_MSG_IFDOWN, "rleased sp irq (%d)\n",
+ DP(NETIF_MSG_IFDOWN, "released sp irq (%d)\n",
bp->msix_table[0].vector);
for_each_queue(bp, i) {
- DP(NETIF_MSG_IFDOWN, "about to rlease fp #%d->%d irq "
+ DP(NETIF_MSG_IFDOWN, "about to release fp #%d->%d irq "
"state(%x)\n", i, bp->msix_table[i + 1].vector,
bnx2x_fp(bp, i, state));
- if (bnx2x_fp(bp, i, state) != BNX2X_FP_STATE_CLOSED) {
-
- free_irq(bp->msix_table[i + 1].vector, &bp->fp[i]);
- bnx2x_fp(bp, i, state) = BNX2X_FP_STATE_CLOSED;
-
- } else
- DP(NETIF_MSG_IFDOWN, "irq not freed\n");
+ if (bnx2x_fp(bp, i, state) != BNX2X_FP_STATE_CLOSED)
+ BNX2X_ERR("IRQ of fp #%d being freed while "
+ "state != closed\n", i);
+ free_irq(bp->msix_table[i + 1].vector, &bp->fp[i]);
}
}
@@ -5995,7 +6914,7 @@ static int bnx2x_enable_msix(struct bnx2x *bp)
if (pci_enable_msix(bp->pdev, &bp->msix_table[0],
bp->num_queues + 1)){
- BNX2X_ERR("failed to enable msix\n");
+ BNX2X_LOG("failed to enable MSI-X\n");
return -1;
}
@@ -6010,11 +6929,8 @@ static int bnx2x_enable_msix(struct bnx2x *bp)
static int bnx2x_req_msix_irqs(struct bnx2x *bp)
{
-
int i, rc;
- DP(NETIF_MSG_IFUP, "about to request sp irq\n");
-
rc = request_irq(bp->msix_table[0].vector, bnx2x_msix_sp_int, 0,
bp->dev->name, bp->dev);
@@ -6029,7 +6945,8 @@ static int bnx2x_req_msix_irqs(struct bnx2x *bp)
bp->dev->name, &bp->fp[i]);
if (rc) {
- BNX2X_ERR("request fp #%d irq failed\n", i);
+ BNX2X_ERR("request fp #%d irq failed "
+ "rc %d\n", i, rc);
bnx2x_free_msix_irqs(bp);
return -EBUSY;
}
@@ -6109,8 +7026,8 @@ static int bnx2x_wait_ramrod(struct bnx2x *bp, int state, int idx,
/* can take a while if any port is running */
int timeout = 500;
- /* DP("waiting for state to become %d on IDX [%d]\n",
- state, sb_idx); */
+ DP(NETIF_MSG_IFUP, "%s for state to become %x on IDX [%d]\n",
+ poll ? "polling" : "waiting", state, idx);
might_sleep();
@@ -6128,7 +7045,7 @@ static int bnx2x_wait_ramrod(struct bnx2x *bp, int state, int idx,
mb(); /* state is changed by bnx2x_sp_event()*/
- if (*state_p != state)
+ if (*state_p == state)
return 0;
timeout--;
@@ -6136,17 +7053,17 @@ static int bnx2x_wait_ramrod(struct bnx2x *bp, int state, int idx,
}
-
/* timeout! */
- BNX2X_ERR("timeout waiting for ramrod %d on %d\n", state, idx);
- return -EBUSY;
+ BNX2X_ERR("timeout %s for state %x on IDX [%d]\n",
+ poll ? "polling" : "waiting", state, idx);
+ return -EBUSY;
}
static int bnx2x_setup_leading(struct bnx2x *bp)
{
- /* reset IGU staae */
+ /* reset IGU state */
bnx2x_ack_sb(bp, DEF_SB_ID, CSTORM_ID, 0, IGU_INT_ENABLE, 0);
/* SETUP ramrod */
@@ -6162,12 +7079,13 @@ static int bnx2x_setup_multi(struct bnx2x *bp, int index)
/* reset IGU state */
bnx2x_ack_sb(bp, index, CSTORM_ID, 0, IGU_INT_ENABLE, 0);
+ /* SETUP ramrod */
bp->fp[index].state = BNX2X_FP_STATE_OPENING;
bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_CLIENT_SETUP, index, 0, index, 0);
/* Wait for completion */
return bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_OPEN, index,
- &(bp->fp[index].state), 1);
+ &(bp->fp[index].state), 0);
}
@@ -6177,8 +7095,8 @@ static void bnx2x_set_rx_mode(struct net_device *dev);
static int bnx2x_nic_load(struct bnx2x *bp, int req_irq)
{
- int rc;
- int i = 0;
+ u32 load_code;
+ int i;
bp->state = BNX2X_STATE_OPENING_WAIT4_LOAD;
@@ -6188,26 +7106,28 @@ static int bnx2x_nic_load(struct bnx2x *bp, int req_irq)
initialized, otherwise - not.
*/
if (!nomcp) {
- rc = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_REQ);
- if (rc == FW_MSG_CODE_DRV_LOAD_REFUSED) {
+ load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_REQ);
+ if (!load_code) {
+ BNX2X_ERR("MCP response failure, unloading\n");
+ return -EBUSY;
+ }
+ if (load_code == FW_MSG_CODE_DRV_LOAD_REFUSED) {
+ BNX2X_ERR("MCP refused load request, unloading\n");
return -EBUSY; /* other port in diagnostic mode */
}
} else {
- rc = FW_MSG_CODE_DRV_LOAD_COMMON;
+ load_code = FW_MSG_CODE_DRV_LOAD_COMMON;
}
- DP(NETIF_MSG_IFUP, "set number of queues to %d\n", bp->num_queues);
-
/* if we can't use msix we only need one fp,
* so try to enable msix with the requested number of fp's
* and fallback to inta with one fp
*/
if (req_irq) {
-
if (use_inta) {
bp->num_queues = 1;
} else {
- if (use_multi > 1 && use_multi <= 16)
+ if ((use_multi > 1) && (use_multi <= 16))
/* user requested number */
bp->num_queues = use_multi;
else if (use_multi == 1)
@@ -6216,15 +7136,17 @@ static int bnx2x_nic_load(struct bnx2x *bp, int req_irq)
bp->num_queues = 1;
if (bnx2x_enable_msix(bp)) {
- /* faild to enable msix */
+ /* failed to enable msix */
bp->num_queues = 1;
if (use_multi)
- BNX2X_ERR("Muti requested but failed"
+ BNX2X_ERR("Multi requested but failed"
" to enable MSI-X\n");
}
}
}
+ DP(NETIF_MSG_IFUP, "set number of queues to %d\n", bp->num_queues);
+
if (bnx2x_alloc_mem(bp))
return -ENOMEM;
@@ -6232,13 +7154,13 @@ static int bnx2x_nic_load(struct bnx2x *bp, int req_irq)
if (bp->flags & USING_MSIX_FLAG) {
if (bnx2x_req_msix_irqs(bp)) {
pci_disable_msix(bp->pdev);
- goto out_error;
+ goto load_error;
}
} else {
if (bnx2x_req_irq(bp)) {
BNX2X_ERR("IRQ request failed, aborting\n");
- goto out_error;
+ goto load_error;
}
}
}
@@ -6249,31 +7171,25 @@ static int bnx2x_nic_load(struct bnx2x *bp, int req_irq)
/* Initialize HW */
- if (bnx2x_function_init(bp, (rc == FW_MSG_CODE_DRV_LOAD_COMMON))) {
+ if (bnx2x_function_init(bp,
+ (load_code == FW_MSG_CODE_DRV_LOAD_COMMON))) {
BNX2X_ERR("HW init failed, aborting\n");
- goto out_error;
+ goto load_error;
}
atomic_set(&bp->intr_sem, 0);
- /* Reenable SP tasklet */
- /*if (bp->sp_task_en) { */
- /* tasklet_enable(&bp->sp_task);*/
- /*} else { */
- /* bp->sp_task_en = 1; */
- /*} */
/* Setup NIC internals and enable interrupts */
bnx2x_nic_init(bp);
/* Send LOAD_DONE command to MCP */
if (!nomcp) {
- rc = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE);
- DP(NETIF_MSG_IFUP, "rc = 0x%x\n", rc);
- if (!rc) {
+ load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE);
+ if (!load_code) {
BNX2X_ERR("MCP response failure, unloading\n");
- goto int_disable;
+ goto load_int_disable;
}
}
@@ -6285,11 +7201,11 @@ static int bnx2x_nic_load(struct bnx2x *bp, int req_irq)
napi_enable(&bnx2x_fp(bp, i, napi));
if (bnx2x_setup_leading(bp))
- goto stop_netif;
+ goto load_stop_netif;
for_each_nondefault_queue(bp, i)
if (bnx2x_setup_multi(bp, i))
- goto stop_netif;
+ goto load_stop_netif;
bnx2x_set_mac_addr(bp);
@@ -6313,42 +7229,24 @@ static int bnx2x_nic_load(struct bnx2x *bp, int req_irq)
return 0;
-stop_netif:
+load_stop_netif:
for_each_queue(bp, i)
napi_disable(&bnx2x_fp(bp, i, napi));
-int_disable:
- bnx2x_disable_int_sync(bp);
+load_int_disable:
+ bnx2x_int_disable_sync(bp);
bnx2x_free_skbs(bp);
bnx2x_free_irq(bp);
-out_error:
+load_error:
bnx2x_free_mem(bp);
/* TBD we really need to reset the chip
if we want to recover from this */
- return rc;
+ return -EBUSY;
}
-static void bnx2x_netif_stop(struct bnx2x *bp)
-{
- int i;
-
- bp->rx_mode = BNX2X_RX_MODE_NONE;
- bnx2x_set_storm_rx_mode(bp);
-
- bnx2x_disable_int_sync(bp);
- bnx2x_link_reset(bp);
-
- for_each_queue(bp, i)
- napi_disable(&bnx2x_fp(bp, i, napi));
-
- if (netif_running(bp->dev)) {
- netif_tx_disable(bp->dev);
- bp->dev->trans_start = jiffies; /* prevent tx timeout */
- }
-}
static void bnx2x_reset_chip(struct bnx2x *bp, u32 reset_code)
{
@@ -6401,20 +7299,20 @@ static int bnx2x_stop_multi(struct bnx2x *bp, int index)
int rc;
- /* halt the connnection */
+ /* halt the connection */
bp->fp[index].state = BNX2X_FP_STATE_HALTING;
bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_HALT, index, 0, 0, 0);
rc = bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_HALTED, index,
&(bp->fp[index].state), 1);
- if (rc) /* timout */
+ if (rc) /* timeout */
return rc;
/* delete cfc entry */
bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_CFC_DEL, index, 0, 0, 1);
- return bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_DELETED, index,
+ return bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_CLOSED, index,
&(bp->fp[index].state), 1);
}
@@ -6422,8 +7320,8 @@ static int bnx2x_stop_multi(struct bnx2x *bp, int index)
static void bnx2x_stop_leading(struct bnx2x *bp)
{
-
- /* if the other port is hadling traffic,
+ u16 dsb_sp_prod_idx;
+ /* if the other port is handling traffic,
this can take a lot of time */
int timeout = 500;
@@ -6437,52 +7335,71 @@ static void bnx2x_stop_leading(struct bnx2x *bp)
&(bp->fp[0].state), 1))
return;
- bp->dsb_sp_prod_idx = *bp->dsb_sp_prod;
+ dsb_sp_prod_idx = *bp->dsb_sp_prod;
- /* Send CFC_DELETE ramrod */
+ /* Send PORT_DELETE ramrod */
bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_PORT_DEL, 0, 0, 0, 1);
- /*
- Wait for completion.
+ /* Wait for completion to arrive on default status block
we are going to reset the chip anyway
so there is not much to do if this times out
*/
- while (bp->dsb_sp_prod_idx == *bp->dsb_sp_prod && timeout) {
- timeout--;
- msleep(1);
+ while ((dsb_sp_prod_idx == *bp->dsb_sp_prod) && timeout) {
+ timeout--;
+ msleep(1);
}
-
+ if (!timeout) {
+ DP(NETIF_MSG_IFDOWN, "timeout polling for completion "
+ "dsb_sp_prod 0x%x != dsb_sp_prod_idx 0x%x\n",
+ *bp->dsb_sp_prod, dsb_sp_prod_idx);
+ }
+ bp->state = BNX2X_STATE_CLOSING_WAIT4_UNLOAD;
+ bp->fp[0].state = BNX2X_FP_STATE_CLOSED;
}
-static int bnx2x_nic_unload(struct bnx2x *bp, int fre_irq)
+
+static int bnx2x_nic_unload(struct bnx2x *bp, int free_irq)
{
u32 reset_code = 0;
- int rc;
- int i;
+ int i, timeout;
bp->state = BNX2X_STATE_CLOSING_WAIT4_HALT;
- /* Calling flush_scheduled_work() may deadlock because
- * linkwatch_event() may be on the workqueue and it will try to get
- * the rtnl_lock which we are holding.
- */
+ del_timer_sync(&bp->timer);
- while (bp->in_reset_task)
- msleep(1);
+ bp->rx_mode = BNX2X_RX_MODE_NONE;
+ bnx2x_set_storm_rx_mode(bp);
- /* Delete the timer: do it before disabling interrupts, as it
- may be stil STAT_QUERY ramrod pending after stopping the timer */
- del_timer_sync(&bp->timer);
+ if (netif_running(bp->dev)) {
+ netif_tx_disable(bp->dev);
+ bp->dev->trans_start = jiffies; /* prevent tx timeout */
+ }
+
+ /* Wait until all fast path tasks complete */
+ for_each_queue(bp, i) {
+ struct bnx2x_fastpath *fp = &bp->fp[i];
+
+ timeout = 1000;
+ while (bnx2x_has_work(fp) && (timeout--))
+ msleep(1);
+ if (!timeout)
+ BNX2X_ERR("timeout waiting for queue[%d]\n", i);
+ }
/* Wait until stat ramrod returns and all SP tasks complete */
- while (bp->stat_pending && (bp->spq_left != MAX_SPQ_PENDING))
+ timeout = 1000;
+ while ((bp->stat_pending || (bp->spq_left != MAX_SPQ_PENDING)) &&
+ (timeout--))
msleep(1);
- /* Stop fast path, disable MAC, disable interrupts, disable napi */
- bnx2x_netif_stop(bp);
+ for_each_queue(bp, i)
+ napi_disable(&bnx2x_fp(bp, i, napi));
+ /* Disable interrupts after Tx and Rx are disabled on stack level */
+ bnx2x_int_disable_sync(bp);
if (bp->flags & NO_WOL_FLAG)
reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP;
+
else if (bp->wol) {
u32 emac_base = bp->port ? GRCBASE_EMAC0 : GRCBASE_EMAC1;
u8 *mac_addr = bp->dev->dev_addr;
@@ -6499,28 +7416,37 @@ static int bnx2x_nic_unload(struct bnx2x *bp, int fre_irq)
EMAC_WR(EMAC_REG_EMAC_MAC_MATCH + 4, val);
reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_EN;
+
} else
reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS;
+ /* Close multi and leading connections */
for_each_nondefault_queue(bp, i)
if (bnx2x_stop_multi(bp, i))
- goto error;
-
+ goto unload_error;
bnx2x_stop_leading(bp);
+ if ((bp->state != BNX2X_STATE_CLOSING_WAIT4_UNLOAD) ||
+ (bp->fp[0].state != BNX2X_FP_STATE_CLOSED)) {
+ DP(NETIF_MSG_IFDOWN, "failed to close leading properly!"
+ "state 0x%x fp[0].state 0x%x",
+ bp->state, bp->fp[0].state);
+ }
+
+unload_error:
+ bnx2x_link_reset(bp);
-error:
if (!nomcp)
- rc = bnx2x_fw_command(bp, reset_code);
+ reset_code = bnx2x_fw_command(bp, reset_code);
else
- rc = FW_MSG_CODE_DRV_UNLOAD_COMMON;
+ reset_code = FW_MSG_CODE_DRV_UNLOAD_COMMON;
/* Release IRQs */
- if (fre_irq)
+ if (free_irq)
bnx2x_free_irq(bp);
/* Reset the chip */
- bnx2x_reset_chip(bp, rc);
+ bnx2x_reset_chip(bp, reset_code);
/* Report UNLOAD_DONE to MCP */
if (!nomcp)
@@ -6531,8 +7457,7 @@ error:
bnx2x_free_mem(bp);
bp->state = BNX2X_STATE_CLOSED;
- /* Set link down */
- bp->link_up = 0;
+
netif_carrier_off(bp->dev);
return 0;
@@ -6568,7 +7493,7 @@ static void bnx2x_link_settings_supported(struct bnx2x *bp, u32 switch_cfg)
SUPPORTED_100baseT_Half |
SUPPORTED_100baseT_Full |
SUPPORTED_1000baseT_Full |
- SUPPORTED_2500baseT_Full |
+ SUPPORTED_2500baseX_Full |
SUPPORTED_TP | SUPPORTED_FIBRE |
SUPPORTED_Autoneg |
SUPPORTED_Pause |
@@ -6581,10 +7506,10 @@ static void bnx2x_link_settings_supported(struct bnx2x *bp, u32 switch_cfg)
bp->phy_flags |= PHY_SGMII_FLAG;
- bp->supported |= (/* SUPPORTED_10baseT_Half |
- SUPPORTED_10baseT_Full |
- SUPPORTED_100baseT_Half |
- SUPPORTED_100baseT_Full |*/
+ bp->supported |= (SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
SUPPORTED_1000baseT_Full |
SUPPORTED_TP | SUPPORTED_FIBRE |
SUPPORTED_Autoneg |
@@ -6620,7 +7545,7 @@ static void bnx2x_link_settings_supported(struct bnx2x *bp, u32 switch_cfg)
SUPPORTED_100baseT_Half |
SUPPORTED_100baseT_Full |
SUPPORTED_1000baseT_Full |
- SUPPORTED_2500baseT_Full |
+ SUPPORTED_2500baseX_Full |
SUPPORTED_10000baseT_Full |
SUPPORTED_TP | SUPPORTED_FIBRE |
SUPPORTED_Autoneg |
@@ -6629,12 +7554,46 @@ static void bnx2x_link_settings_supported(struct bnx2x *bp, u32 switch_cfg)
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
+ BNX2X_DEV_INFO("ext_phy_type 0x%x (8705)\n",
+ ext_phy_type);
+
+ bp->supported |= (SUPPORTED_10000baseT_Full |
+ SUPPORTED_FIBRE |
+ SUPPORTED_Pause |
+ SUPPORTED_Asym_Pause);
+ break;
+
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
- BNX2X_DEV_INFO("ext_phy_type 0x%x (8705/6)\n",
+ BNX2X_DEV_INFO("ext_phy_type 0x%x (8706)\n",
+ ext_phy_type);
+
+ bp->supported |= (SUPPORTED_10000baseT_Full |
+ SUPPORTED_1000baseT_Full |
+ SUPPORTED_Autoneg |
+ SUPPORTED_FIBRE |
+ SUPPORTED_Pause |
+ SUPPORTED_Asym_Pause);
+ break;
+
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
+ BNX2X_DEV_INFO("ext_phy_type 0x%x (8072)\n",
ext_phy_type);
bp->supported |= (SUPPORTED_10000baseT_Full |
+ SUPPORTED_1000baseT_Full |
SUPPORTED_FIBRE |
+ SUPPORTED_Autoneg |
+ SUPPORTED_Pause |
+ SUPPORTED_Asym_Pause);
+ break;
+
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
+ BNX2X_DEV_INFO("ext_phy_type 0x%x (SFX7101)\n",
+ ext_phy_type);
+
+ bp->supported |= (SUPPORTED_10000baseT_Full |
+ SUPPORTED_TP |
+ SUPPORTED_Autoneg |
SUPPORTED_Pause |
SUPPORTED_Asym_Pause);
break;
@@ -6691,7 +7650,7 @@ static void bnx2x_link_settings_supported(struct bnx2x *bp, u32 switch_cfg)
SUPPORTED_1000baseT_Full);
if (!(bp->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G))
- bp->supported &= ~SUPPORTED_2500baseT_Full;
+ bp->supported &= ~SUPPORTED_2500baseX_Full;
if (!(bp->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G))
bp->supported &= ~SUPPORTED_10000baseT_Full;
@@ -6711,13 +7670,8 @@ static void bnx2x_link_settings_requested(struct bnx2x *bp)
bp->req_line_speed = 0;
bp->advertising = bp->supported;
} else {
- u32 ext_phy_type;
-
- ext_phy_type = XGXS_EXT_PHY_TYPE(bp);
- if ((ext_phy_type ==
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) ||
- (ext_phy_type ==
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706)) {
+ if (XGXS_EXT_PHY_TYPE(bp) ==
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) {
/* force 10G, no AN */
bp->req_line_speed = SPEED_10000;
bp->advertising =
@@ -6734,8 +7688,7 @@ static void bnx2x_link_settings_requested(struct bnx2x *bp)
break;
case PORT_FEATURE_LINK_SPEED_10M_FULL:
- if (bp->speed_cap_mask &
- PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) {
+ if (bp->supported & SUPPORTED_10baseT_Full) {
bp->req_line_speed = SPEED_10;
bp->advertising = (ADVERTISED_10baseT_Full |
ADVERTISED_TP);
@@ -6749,8 +7702,7 @@ static void bnx2x_link_settings_requested(struct bnx2x *bp)
break;
case PORT_FEATURE_LINK_SPEED_10M_HALF:
- if (bp->speed_cap_mask &
- PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF) {
+ if (bp->supported & SUPPORTED_10baseT_Half) {
bp->req_line_speed = SPEED_10;
bp->req_duplex = DUPLEX_HALF;
bp->advertising = (ADVERTISED_10baseT_Half |
@@ -6765,8 +7717,7 @@ static void bnx2x_link_settings_requested(struct bnx2x *bp)
break;
case PORT_FEATURE_LINK_SPEED_100M_FULL:
- if (bp->speed_cap_mask &
- PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL) {
+ if (bp->supported & SUPPORTED_100baseT_Full) {
bp->req_line_speed = SPEED_100;
bp->advertising = (ADVERTISED_100baseT_Full |
ADVERTISED_TP);
@@ -6780,8 +7731,7 @@ static void bnx2x_link_settings_requested(struct bnx2x *bp)
break;
case PORT_FEATURE_LINK_SPEED_100M_HALF:
- if (bp->speed_cap_mask &
- PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF) {
+ if (bp->supported & SUPPORTED_100baseT_Half) {
bp->req_line_speed = SPEED_100;
bp->req_duplex = DUPLEX_HALF;
bp->advertising = (ADVERTISED_100baseT_Half |
@@ -6796,8 +7746,7 @@ static void bnx2x_link_settings_requested(struct bnx2x *bp)
break;
case PORT_FEATURE_LINK_SPEED_1G:
- if (bp->speed_cap_mask &
- PORT_HW_CFG_SPEED_CAPABILITY_D0_1G) {
+ if (bp->supported & SUPPORTED_1000baseT_Full) {
bp->req_line_speed = SPEED_1000;
bp->advertising = (ADVERTISED_1000baseT_Full |
ADVERTISED_TP);
@@ -6811,10 +7760,9 @@ static void bnx2x_link_settings_requested(struct bnx2x *bp)
break;
case PORT_FEATURE_LINK_SPEED_2_5G:
- if (bp->speed_cap_mask &
- PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G) {
+ if (bp->supported & SUPPORTED_2500baseX_Full) {
bp->req_line_speed = SPEED_2500;
- bp->advertising = (ADVERTISED_2500baseT_Full |
+ bp->advertising = (ADVERTISED_2500baseX_Full |
ADVERTISED_TP);
} else {
BNX2X_ERR("NVRAM config error. "
@@ -6828,15 +7776,7 @@ static void bnx2x_link_settings_requested(struct bnx2x *bp)
case PORT_FEATURE_LINK_SPEED_10G_CX4:
case PORT_FEATURE_LINK_SPEED_10G_KX4:
case PORT_FEATURE_LINK_SPEED_10G_KR:
- if (!(bp->phy_flags & PHY_XGXS_FLAG)) {
- BNX2X_ERR("NVRAM config error. "
- "Invalid link_config 0x%x"
- " phy_flags 0x%x\n",
- bp->link_config, bp->phy_flags);
- return;
- }
- if (bp->speed_cap_mask &
- PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) {
+ if (bp->supported & SUPPORTED_10000baseT_Full) {
bp->req_line_speed = SPEED_10000;
bp->advertising = (ADVERTISED_10000baseT_Full |
ADVERTISED_FIBRE);
@@ -6863,43 +7803,13 @@ static void bnx2x_link_settings_requested(struct bnx2x *bp)
bp->req_flow_ctrl = (bp->link_config &
PORT_FEATURE_FLOW_CONTROL_MASK);
- /* Please refer to Table 28B-3 of the 802.3ab-1999 spec */
- switch (bp->req_flow_ctrl) {
- case FLOW_CTRL_AUTO:
+ if ((bp->req_flow_ctrl == FLOW_CTRL_AUTO) &&
+ (bp->supported & SUPPORTED_Autoneg))
bp->req_autoneg |= AUTONEG_FLOW_CTRL;
- if (bp->dev->mtu <= 4500) {
- bp->pause_mode = PAUSE_BOTH;
- bp->advertising |= (ADVERTISED_Pause |
- ADVERTISED_Asym_Pause);
- } else {
- bp->pause_mode = PAUSE_ASYMMETRIC;
- bp->advertising |= ADVERTISED_Asym_Pause;
- }
- break;
-
- case FLOW_CTRL_TX:
- bp->pause_mode = PAUSE_ASYMMETRIC;
- bp->advertising |= ADVERTISED_Asym_Pause;
- break;
-
- case FLOW_CTRL_RX:
- case FLOW_CTRL_BOTH:
- bp->pause_mode = PAUSE_BOTH;
- bp->advertising |= (ADVERTISED_Pause |
- ADVERTISED_Asym_Pause);
- break;
- case FLOW_CTRL_NONE:
- default:
- bp->pause_mode = PAUSE_NONE;
- bp->advertising &= ~(ADVERTISED_Pause |
- ADVERTISED_Asym_Pause);
- break;
- }
- BNX2X_DEV_INFO("req_autoneg 0x%x req_flow_ctrl 0x%x\n"
- KERN_INFO " pause_mode %d advertising 0x%x\n",
- bp->req_autoneg, bp->req_flow_ctrl,
- bp->pause_mode, bp->advertising);
+ BNX2X_DEV_INFO("req_autoneg 0x%x req_flow_ctrl 0x%x"
+ " advertising 0x%x\n",
+ bp->req_autoneg, bp->req_flow_ctrl, bp->advertising);
}
static void bnx2x_get_hwinfo(struct bnx2x *bp)
@@ -6933,15 +7843,15 @@ static void bnx2x_get_hwinfo(struct bnx2x *bp)
val = SHMEM_RD(bp, validity_map[port]);
if ((val & (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB))
!= (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB))
- BNX2X_ERR("MCP validity signature bad\n");
+ BNX2X_ERR("BAD MCP validity signature\n");
- bp->fw_seq = (SHMEM_RD(bp, drv_fw_mb[port].drv_mb_header) &
+ bp->fw_seq = (SHMEM_RD(bp, func_mb[port].drv_mb_header) &
DRV_MSG_SEQ_NUMBER_MASK);
bp->hw_config = SHMEM_RD(bp, dev_info.shared_hw_config.config);
-
+ bp->board = SHMEM_RD(bp, dev_info.shared_hw_config.board);
bp->serdes_config =
- SHMEM_RD(bp, dev_info.port_hw_config[bp->port].serdes_config);
+ SHMEM_RD(bp, dev_info.port_hw_config[port].serdes_config);
bp->lane_config =
SHMEM_RD(bp, dev_info.port_hw_config[port].lane_config);
bp->ext_phy_config =
@@ -6954,13 +7864,13 @@ static void bnx2x_get_hwinfo(struct bnx2x *bp)
bp->link_config =
SHMEM_RD(bp, dev_info.port_feature_config[port].link_config);
- BNX2X_DEV_INFO("hw_config (%08x) serdes_config (%08x)\n"
+ BNX2X_DEV_INFO("hw_config (%08x) board (%08x) serdes_config (%08x)\n"
KERN_INFO " lane_config (%08x) ext_phy_config (%08x)\n"
KERN_INFO " speed_cap_mask (%08x) link_config (%08x)"
" fw_seq (%08x)\n",
- bp->hw_config, bp->serdes_config, bp->lane_config,
- bp->ext_phy_config, bp->speed_cap_mask,
- bp->link_config, bp->fw_seq);
+ bp->hw_config, bp->board, bp->serdes_config,
+ bp->lane_config, bp->ext_phy_config,
+ bp->speed_cap_mask, bp->link_config, bp->fw_seq);
switch_cfg = (bp->link_config & PORT_FEATURE_CONNECTED_SWITCH_MASK);
bnx2x_link_settings_supported(bp, switch_cfg);
@@ -7014,14 +7924,8 @@ static void bnx2x_get_hwinfo(struct bnx2x *bp)
return;
set_mac: /* only supposed to happen on emulation/FPGA */
- BNX2X_ERR("warning constant MAC workaround active\n");
- bp->dev->dev_addr[0] = 0;
- bp->dev->dev_addr[1] = 0x50;
- bp->dev->dev_addr[2] = 0xc2;
- bp->dev->dev_addr[3] = 0x2c;
- bp->dev->dev_addr[4] = 0x71;
- bp->dev->dev_addr[5] = port ? 0x0d : 0x0e;
-
+ BNX2X_ERR("warning rendom MAC workaround active\n");
+ random_ether_addr(bp->dev->dev_addr);
memcpy(bp->dev->perm_addr, bp->dev->dev_addr, 6);
}
@@ -7048,19 +7952,34 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
}
if (bp->phy_flags & PHY_XGXS_FLAG) {
- cmd->port = PORT_FIBRE;
- } else {
+ u32 ext_phy_type = XGXS_EXT_PHY_TYPE(bp);
+
+ switch (ext_phy_type) {
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
+ cmd->port = PORT_FIBRE;
+ break;
+
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
+ cmd->port = PORT_TP;
+ break;
+
+ default:
+ DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
+ bp->ext_phy_config);
+ }
+ } else
cmd->port = PORT_TP;
- }
cmd->phy_address = bp->phy_addr;
cmd->transceiver = XCVR_INTERNAL;
- if (bp->req_autoneg & AUTONEG_SPEED) {
+ if (bp->req_autoneg & AUTONEG_SPEED)
cmd->autoneg = AUTONEG_ENABLE;
- } else {
+ else
cmd->autoneg = AUTONEG_DISABLE;
- }
cmd->maxtxpkt = 0;
cmd->maxrxpkt = 0;
@@ -7091,8 +8010,10 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
switch (cmd->port) {
case PORT_TP:
- if (!(bp->supported & SUPPORTED_TP))
+ if (!(bp->supported & SUPPORTED_TP)) {
+ DP(NETIF_MSG_LINK, "TP not supported\n");
return -EINVAL;
+ }
if (bp->phy_flags & PHY_XGXS_FLAG) {
bnx2x_link_reset(bp);
@@ -7102,8 +8023,10 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
break;
case PORT_FIBRE:
- if (!(bp->supported & SUPPORTED_FIBRE))
+ if (!(bp->supported & SUPPORTED_FIBRE)) {
+ DP(NETIF_MSG_LINK, "FIBRE not supported\n");
return -EINVAL;
+ }
if (!(bp->phy_flags & PHY_XGXS_FLAG)) {
bnx2x_link_reset(bp);
@@ -7113,12 +8036,15 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
break;
default:
+ DP(NETIF_MSG_LINK, "Unknown port type\n");
return -EINVAL;
}
if (cmd->autoneg == AUTONEG_ENABLE) {
- if (!(bp->supported & SUPPORTED_Autoneg))
+ if (!(bp->supported & SUPPORTED_Autoneg)) {
+ DP(NETIF_MSG_LINK, "Aotoneg not supported\n");
return -EINVAL;
+ }
/* advertise the requested speed and duplex if supported */
cmd->advertising &= bp->supported;
@@ -7133,14 +8059,22 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
switch (cmd->speed) {
case SPEED_10:
if (cmd->duplex == DUPLEX_FULL) {
- if (!(bp->supported & SUPPORTED_10baseT_Full))
+ if (!(bp->supported &
+ SUPPORTED_10baseT_Full)) {
+ DP(NETIF_MSG_LINK,
+ "10M full not supported\n");
return -EINVAL;
+ }
advertising = (ADVERTISED_10baseT_Full |
ADVERTISED_TP);
} else {
- if (!(bp->supported & SUPPORTED_10baseT_Half))
+ if (!(bp->supported &
+ SUPPORTED_10baseT_Half)) {
+ DP(NETIF_MSG_LINK,
+ "10M half not supported\n");
return -EINVAL;
+ }
advertising = (ADVERTISED_10baseT_Half |
ADVERTISED_TP);
@@ -7150,15 +8084,21 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
case SPEED_100:
if (cmd->duplex == DUPLEX_FULL) {
if (!(bp->supported &
- SUPPORTED_100baseT_Full))
+ SUPPORTED_100baseT_Full)) {
+ DP(NETIF_MSG_LINK,
+ "100M full not supported\n");
return -EINVAL;
+ }
advertising = (ADVERTISED_100baseT_Full |
ADVERTISED_TP);
} else {
if (!(bp->supported &
- SUPPORTED_100baseT_Half))
+ SUPPORTED_100baseT_Half)) {
+ DP(NETIF_MSG_LINK,
+ "100M half not supported\n");
return -EINVAL;
+ }
advertising = (ADVERTISED_100baseT_Half |
ADVERTISED_TP);
@@ -7166,39 +8106,54 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
break;
case SPEED_1000:
- if (cmd->duplex != DUPLEX_FULL)
+ if (cmd->duplex != DUPLEX_FULL) {
+ DP(NETIF_MSG_LINK, "1G half not supported\n");
return -EINVAL;
+ }
- if (!(bp->supported & SUPPORTED_1000baseT_Full))
+ if (!(bp->supported & SUPPORTED_1000baseT_Full)) {
+ DP(NETIF_MSG_LINK, "1G full not supported\n");
return -EINVAL;
+ }
advertising = (ADVERTISED_1000baseT_Full |
ADVERTISED_TP);
break;
case SPEED_2500:
- if (cmd->duplex != DUPLEX_FULL)
+ if (cmd->duplex != DUPLEX_FULL) {
+ DP(NETIF_MSG_LINK,
+ "2.5G half not supported\n");
return -EINVAL;
+ }
- if (!(bp->supported & SUPPORTED_2500baseT_Full))
+ if (!(bp->supported & SUPPORTED_2500baseX_Full)) {
+ DP(NETIF_MSG_LINK,
+ "2.5G full not supported\n");
return -EINVAL;
+ }
- advertising = (ADVERTISED_2500baseT_Full |
+ advertising = (ADVERTISED_2500baseX_Full |
ADVERTISED_TP);
break;
case SPEED_10000:
- if (cmd->duplex != DUPLEX_FULL)
+ if (cmd->duplex != DUPLEX_FULL) {
+ DP(NETIF_MSG_LINK, "10G half not supported\n");
return -EINVAL;
+ }
- if (!(bp->supported & SUPPORTED_10000baseT_Full))
+ if (!(bp->supported & SUPPORTED_10000baseT_Full)) {
+ DP(NETIF_MSG_LINK, "10G full not supported\n");
return -EINVAL;
+ }
advertising = (ADVERTISED_10000baseT_Full |
ADVERTISED_FIBRE);
break;
default:
+ DP(NETIF_MSG_LINK, "Unsupported speed\n");
return -EINVAL;
}
@@ -7398,8 +8353,7 @@ static void bnx2x_disable_nvram_access(struct bnx2x *bp)
static int bnx2x_nvram_read_dword(struct bnx2x *bp, u32 offset, u32 *ret_val,
u32 cmd_flags)
{
- int rc;
- int count, i;
+ int count, i, rc;
u32 val;
/* build the command word */
@@ -7452,13 +8406,13 @@ static int bnx2x_nvram_read(struct bnx2x *bp, u32 offset, u8 *ret_buf,
if ((offset & 0x03) || (buf_size & 0x03) || (buf_size == 0)) {
DP(NETIF_MSG_NVM,
- "Invalid paramter: offset 0x%x buf_size 0x%x\n",
+ "Invalid parameter: offset 0x%x buf_size 0x%x\n",
offset, buf_size);
return -EINVAL;
}
if (offset + buf_size > bp->flash_size) {
- DP(NETIF_MSG_NVM, "Invalid paramter: offset (0x%x) +"
+ DP(NETIF_MSG_NVM, "Invalid parameter: offset (0x%x) +"
" buf_size (0x%x) > flash_size (0x%x)\n",
offset, buf_size, bp->flash_size);
return -EINVAL;
@@ -7519,8 +8473,7 @@ static int bnx2x_get_eeprom(struct net_device *dev,
static int bnx2x_nvram_write_dword(struct bnx2x *bp, u32 offset, u32 val,
u32 cmd_flags)
{
- int rc;
- int count, i;
+ int count, i, rc;
/* build the command word */
cmd_flags |= MCPR_NVM_COMMAND_DOIT | MCPR_NVM_COMMAND_WR;
@@ -7557,7 +8510,7 @@ static int bnx2x_nvram_write_dword(struct bnx2x *bp, u32 offset, u32 val,
return rc;
}
-#define BYTE_OFFSET(offset) (8 * (offset & 0x03))
+#define BYTE_OFFSET(offset) (8 * (offset & 0x03))
static int bnx2x_nvram_write1(struct bnx2x *bp, u32 offset, u8 *data_buf,
int buf_size)
@@ -7568,7 +8521,7 @@ static int bnx2x_nvram_write1(struct bnx2x *bp, u32 offset, u8 *data_buf,
u32 val;
if (offset + buf_size > bp->flash_size) {
- DP(NETIF_MSG_NVM, "Invalid paramter: offset (0x%x) +"
+ DP(NETIF_MSG_NVM, "Invalid parameter: offset (0x%x) +"
" buf_size (0x%x) > flash_size (0x%x)\n",
offset, buf_size, bp->flash_size);
return -EINVAL;
@@ -7621,13 +8574,13 @@ static int bnx2x_nvram_write(struct bnx2x *bp, u32 offset, u8 *data_buf,
if ((offset & 0x03) || (buf_size & 0x03) || (buf_size == 0)) {
DP(NETIF_MSG_NVM,
- "Invalid paramter: offset 0x%x buf_size 0x%x\n",
+ "Invalid parameter: offset 0x%x buf_size 0x%x\n",
offset, buf_size);
return -EINVAL;
}
if (offset + buf_size > bp->flash_size) {
- DP(NETIF_MSG_NVM, "Invalid paramter: offset (0x%x) +"
+ DP(NETIF_MSG_NVM, "Invalid parameter: offset (0x%x) +"
" buf_size (0x%x) > flash_size (0x%x)\n",
offset, buf_size, bp->flash_size);
return -EINVAL;
@@ -7788,52 +8741,29 @@ static int bnx2x_set_pauseparam(struct net_device *dev,
DP_LEVEL " autoneg %d rx_pause %d tx_pause %d\n",
epause->cmd, epause->autoneg, epause->rx_pause, epause->tx_pause);
- bp->req_flow_ctrl = FLOW_CTRL_AUTO;
if (epause->autoneg) {
- bp->req_autoneg |= AUTONEG_FLOW_CTRL;
- if (bp->dev->mtu <= 4500) {
- bp->pause_mode = PAUSE_BOTH;
- bp->advertising |= (ADVERTISED_Pause |
- ADVERTISED_Asym_Pause);
- } else {
- bp->pause_mode = PAUSE_ASYMMETRIC;
- bp->advertising |= ADVERTISED_Asym_Pause;
+ if (!(bp->supported & SUPPORTED_Autoneg)) {
+ DP(NETIF_MSG_LINK, "Aotoneg not supported\n");
+ return -EINVAL;
}
- } else {
+ bp->req_autoneg |= AUTONEG_FLOW_CTRL;
+ } else
bp->req_autoneg &= ~AUTONEG_FLOW_CTRL;
- if (epause->rx_pause)
- bp->req_flow_ctrl |= FLOW_CTRL_RX;
- if (epause->tx_pause)
- bp->req_flow_ctrl |= FLOW_CTRL_TX;
-
- switch (bp->req_flow_ctrl) {
- case FLOW_CTRL_AUTO:
- bp->req_flow_ctrl = FLOW_CTRL_NONE;
- bp->pause_mode = PAUSE_NONE;
- bp->advertising &= ~(ADVERTISED_Pause |
- ADVERTISED_Asym_Pause);
- break;
+ bp->req_flow_ctrl = FLOW_CTRL_AUTO;
- case FLOW_CTRL_TX:
- bp->pause_mode = PAUSE_ASYMMETRIC;
- bp->advertising |= ADVERTISED_Asym_Pause;
- break;
+ if (epause->rx_pause)
+ bp->req_flow_ctrl |= FLOW_CTRL_RX;
+ if (epause->tx_pause)
+ bp->req_flow_ctrl |= FLOW_CTRL_TX;
- case FLOW_CTRL_RX:
- case FLOW_CTRL_BOTH:
- bp->pause_mode = PAUSE_BOTH;
- bp->advertising |= (ADVERTISED_Pause |
- ADVERTISED_Asym_Pause);
- break;
- }
- }
+ if (!(bp->req_autoneg & AUTONEG_FLOW_CTRL) &&
+ (bp->req_flow_ctrl == FLOW_CTRL_AUTO))
+ bp->req_flow_ctrl = FLOW_CTRL_NONE;
- DP(NETIF_MSG_LINK, "req_autoneg 0x%x req_flow_ctrl 0x%x\n"
- DP_LEVEL " pause_mode %d advertising 0x%x\n",
- bp->req_autoneg, bp->req_flow_ctrl, bp->pause_mode,
- bp->advertising);
+ DP(NETIF_MSG_LINK, "req_autoneg 0x%x req_flow_ctrl 0x%x\n",
+ bp->req_autoneg, bp->req_flow_ctrl);
bnx2x_stop_stats(bp);
bnx2x_link_initialize(bp);
@@ -7906,81 +8836,87 @@ static void bnx2x_self_test(struct net_device *dev,
static struct {
char string[ETH_GSTRING_LEN];
} bnx2x_stats_str_arr[BNX2X_NUM_STATS] = {
- { "rx_bytes"}, /* 0 */
- { "rx_error_bytes"}, /* 1 */
- { "tx_bytes"}, /* 2 */
- { "tx_error_bytes"}, /* 3 */
- { "rx_ucast_packets"}, /* 4 */
- { "rx_mcast_packets"}, /* 5 */
- { "rx_bcast_packets"}, /* 6 */
- { "tx_ucast_packets"}, /* 7 */
- { "tx_mcast_packets"}, /* 8 */
- { "tx_bcast_packets"}, /* 9 */
- { "tx_mac_errors"}, /* 10 */
- { "tx_carrier_errors"}, /* 11 */
- { "rx_crc_errors"}, /* 12 */
- { "rx_align_errors"}, /* 13 */
- { "tx_single_collisions"}, /* 14 */
- { "tx_multi_collisions"}, /* 15 */
- { "tx_deferred"}, /* 16 */
- { "tx_excess_collisions"}, /* 17 */
- { "tx_late_collisions"}, /* 18 */
- { "tx_total_collisions"}, /* 19 */
- { "rx_fragments"}, /* 20 */
- { "rx_jabbers"}, /* 21 */
- { "rx_undersize_packets"}, /* 22 */
- { "rx_oversize_packets"}, /* 23 */
- { "rx_xon_frames"}, /* 24 */
- { "rx_xoff_frames"}, /* 25 */
- { "tx_xon_frames"}, /* 26 */
- { "tx_xoff_frames"}, /* 27 */
- { "rx_mac_ctrl_frames"}, /* 28 */
- { "rx_filtered_packets"}, /* 29 */
- { "rx_discards"}, /* 30 */
+ { "rx_bytes"},
+ { "rx_error_bytes"},
+ { "tx_bytes"},
+ { "tx_error_bytes"},
+ { "rx_ucast_packets"},
+ { "rx_mcast_packets"},
+ { "rx_bcast_packets"},
+ { "tx_ucast_packets"},
+ { "tx_mcast_packets"},
+ { "tx_bcast_packets"},
+ { "tx_mac_errors"}, /* 10 */
+ { "tx_carrier_errors"},
+ { "rx_crc_errors"},
+ { "rx_align_errors"},
+ { "tx_single_collisions"},
+ { "tx_multi_collisions"},
+ { "tx_deferred"},
+ { "tx_excess_collisions"},
+ { "tx_late_collisions"},
+ { "tx_total_collisions"},
+ { "rx_fragments"}, /* 20 */
+ { "rx_jabbers"},
+ { "rx_undersize_packets"},
+ { "rx_oversize_packets"},
+ { "rx_xon_frames"},
+ { "rx_xoff_frames"},
+ { "tx_xon_frames"},
+ { "tx_xoff_frames"},
+ { "rx_mac_ctrl_frames"},
+ { "rx_filtered_packets"},
+ { "rx_discards"}, /* 30 */
+ { "brb_discard"},
+ { "brb_truncate"},
+ { "xxoverflow"}
};
#define STATS_OFFSET32(offset_name) \
(offsetof(struct bnx2x_eth_stats, offset_name) / 4)
static unsigned long bnx2x_stats_offset_arr[BNX2X_NUM_STATS] = {
- STATS_OFFSET32(total_bytes_received_hi), /* 0 */
- STATS_OFFSET32(stat_IfHCInBadOctets_hi), /* 1 */
- STATS_OFFSET32(total_bytes_transmitted_hi), /* 2 */
- STATS_OFFSET32(stat_IfHCOutBadOctets_hi), /* 3 */
- STATS_OFFSET32(total_unicast_packets_received_hi), /* 4 */
- STATS_OFFSET32(total_multicast_packets_received_hi), /* 5 */
- STATS_OFFSET32(total_broadcast_packets_received_hi), /* 6 */
- STATS_OFFSET32(total_unicast_packets_transmitted_hi), /* 7 */
- STATS_OFFSET32(total_multicast_packets_transmitted_hi), /* 8 */
- STATS_OFFSET32(total_broadcast_packets_transmitted_hi), /* 9 */
- STATS_OFFSET32(stat_Dot3statsInternalMacTransmitErrors), /* 10 */
- STATS_OFFSET32(stat_Dot3StatsCarrierSenseErrors), /* 11 */
- STATS_OFFSET32(crc_receive_errors), /* 12 */
- STATS_OFFSET32(alignment_errors), /* 13 */
- STATS_OFFSET32(single_collision_transmit_frames), /* 14 */
- STATS_OFFSET32(multiple_collision_transmit_frames), /* 15 */
- STATS_OFFSET32(stat_Dot3StatsDeferredTransmissions), /* 16 */
- STATS_OFFSET32(excessive_collision_frames), /* 17 */
- STATS_OFFSET32(late_collision_frames), /* 18 */
- STATS_OFFSET32(number_of_bugs_found_in_stats_spec), /* 19 */
- STATS_OFFSET32(runt_packets_received), /* 20 */
- STATS_OFFSET32(jabber_packets_received), /* 21 */
- STATS_OFFSET32(error_runt_packets_received), /* 22 */
- STATS_OFFSET32(error_jabber_packets_received), /* 23 */
- STATS_OFFSET32(pause_xon_frames_received), /* 24 */
- STATS_OFFSET32(pause_xoff_frames_received), /* 25 */
- STATS_OFFSET32(pause_xon_frames_transmitted), /* 26 */
- STATS_OFFSET32(pause_xoff_frames_transmitted), /* 27 */
- STATS_OFFSET32(control_frames_received), /* 28 */
- STATS_OFFSET32(mac_filter_discard), /* 29 */
- STATS_OFFSET32(no_buff_discard), /* 30 */
+ STATS_OFFSET32(total_bytes_received_hi),
+ STATS_OFFSET32(stat_IfHCInBadOctets_hi),
+ STATS_OFFSET32(total_bytes_transmitted_hi),
+ STATS_OFFSET32(stat_IfHCOutBadOctets_hi),
+ STATS_OFFSET32(total_unicast_packets_received_hi),
+ STATS_OFFSET32(total_multicast_packets_received_hi),
+ STATS_OFFSET32(total_broadcast_packets_received_hi),
+ STATS_OFFSET32(total_unicast_packets_transmitted_hi),
+ STATS_OFFSET32(total_multicast_packets_transmitted_hi),
+ STATS_OFFSET32(total_broadcast_packets_transmitted_hi),
+ STATS_OFFSET32(stat_Dot3statsInternalMacTransmitErrors), /* 10 */
+ STATS_OFFSET32(stat_Dot3StatsCarrierSenseErrors),
+ STATS_OFFSET32(crc_receive_errors),
+ STATS_OFFSET32(alignment_errors),
+ STATS_OFFSET32(single_collision_transmit_frames),
+ STATS_OFFSET32(multiple_collision_transmit_frames),
+ STATS_OFFSET32(stat_Dot3StatsDeferredTransmissions),
+ STATS_OFFSET32(excessive_collision_frames),
+ STATS_OFFSET32(late_collision_frames),
+ STATS_OFFSET32(number_of_bugs_found_in_stats_spec),
+ STATS_OFFSET32(runt_packets_received), /* 20 */
+ STATS_OFFSET32(jabber_packets_received),
+ STATS_OFFSET32(error_runt_packets_received),
+ STATS_OFFSET32(error_jabber_packets_received),
+ STATS_OFFSET32(pause_xon_frames_received),
+ STATS_OFFSET32(pause_xoff_frames_received),
+ STATS_OFFSET32(pause_xon_frames_transmitted),
+ STATS_OFFSET32(pause_xoff_frames_transmitted),
+ STATS_OFFSET32(control_frames_received),
+ STATS_OFFSET32(mac_filter_discard),
+ STATS_OFFSET32(no_buff_discard), /* 30 */
+ STATS_OFFSET32(brb_discard),
+ STATS_OFFSET32(brb_truncate_discard),
+ STATS_OFFSET32(xxoverflow_discard)
};
static u8 bnx2x_stats_len_arr[BNX2X_NUM_STATS] = {
8, 0, 8, 0, 8, 8, 8, 8, 8, 8,
4, 0, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4,
+ 4, 4, 4, 4
};
static void bnx2x_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
@@ -8138,9 +9074,7 @@ static int bnx2x_set_power_state(struct bnx2x *bp, pci_power_t state)
* net_device service functions
*/
-/* Called with rtnl_lock from vlan functions and also netif_tx_lock
- * from set_multicast.
- */
+/* called with netif_tx_lock from set_multicast */
static void bnx2x_set_rx_mode(struct net_device *dev)
{
struct bnx2x *bp = netdev_priv(dev);
@@ -8314,7 +9248,7 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
ETH_TX_BD_ETH_ADDR_TYPE_SHIFT);
tx_bd->general_data |= 1; /* header nbd */
- /* remeber the first bd of the packet */
+ /* remember the first bd of the packet */
tx_buf->first_bd = bd_prod;
DP(NETIF_MSG_TX_QUEUED,
@@ -8334,7 +9268,7 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* for now NS flag is not used in Linux */
pbd->global_data = (len |
- ((skb->protocol == ETH_P_8021Q) <<
+ ((skb->protocol == ntohs(ETH_P_8021Q)) <<
ETH_TX_PARSE_BD_LLC_SNAP_EN_SHIFT));
pbd->ip_hlen = ip_hdrlen(skb) / 2;
pbd->total_hlen = cpu_to_le16(len + pbd->ip_hlen);
@@ -8343,7 +9277,7 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
tx_bd->bd_flags.as_bitfield |=
ETH_TX_BD_FLAGS_TCP_CSUM;
- pbd->tcp_flags = htonl(tcp_flag_word(skb)) & 0xFFFF;
+ pbd->tcp_flags = pbd_tcp_flags(skb);
pbd->total_hlen += cpu_to_le16(tcp_hdrlen(skb) / 2);
pbd->tcp_pseudo_csum = swab16(th->check);
@@ -8387,7 +9321,7 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb_shinfo(skb)->gso_size &&
(skb->len > (bp->dev->mtu + ETH_HLEN))) {
- int hlen = 2 * le32_to_cpu(pbd->total_hlen);
+ int hlen = 2 * le16_to_cpu(pbd->total_hlen);
DP(NETIF_MSG_TX_QUEUED,
"TSO packet len %d hlen %d total len %d tso size %d\n",
@@ -8427,7 +9361,7 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
tx_bd->vlan = cpu_to_le16(pkt_prod);
/* this marks the bd
* as one that has no individual mapping
- * the FW ignors this flag in a bd not maked start
+ * the FW ignores this flag in a bd not marked start
*/
tx_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_SW_LSO;
DP(NETIF_MSG_TX_QUEUED,
@@ -8504,9 +9438,11 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
DP(NETIF_MSG_TX_QUEUED, "doorbell: nbd %u bd %d\n", nbd, bd_prod);
- fp->hw_tx_prods->bds_prod += cpu_to_le16(nbd);
+ fp->hw_tx_prods->bds_prod =
+ cpu_to_le16(le16_to_cpu(fp->hw_tx_prods->bds_prod) + nbd);
mb(); /* FW restriction: must not reorder writing nbd and packets */
- fp->hw_tx_prods->packets_prod += cpu_to_le32(1);
+ fp->hw_tx_prods->packets_prod =
+ cpu_to_le32(le32_to_cpu(fp->hw_tx_prods->packets_prod) + 1);
DOORBELL(bp, fp_index, 0);
mmiowb();
@@ -8525,11 +9461,6 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK;
}
-static struct net_device_stats *bnx2x_get_stats(struct net_device *dev)
-{
- return &dev->stats;
-}
-
/* Called with rtnl_lock */
static int bnx2x_open(struct net_device *dev)
{
@@ -8543,16 +9474,13 @@ static int bnx2x_open(struct net_device *dev)
/* Called with rtnl_lock */
static int bnx2x_close(struct net_device *dev)
{
- int rc;
struct bnx2x *bp = netdev_priv(dev);
/* Unload the driver, release IRQs */
- rc = bnx2x_nic_unload(bp, 1);
- if (rc) {
- BNX2X_ERR("bnx2x_nic_unload failed: %d\n", rc);
- return rc;
- }
- bnx2x_set_power_state(bp, PCI_D3hot);
+ bnx2x_nic_unload(bp, 1);
+
+ if (!CHIP_REV_IS_SLOW(bp))
+ bnx2x_set_power_state(bp, PCI_D3hot);
return 0;
}
@@ -8584,7 +9512,7 @@ static int bnx2x_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
case SIOCGMIIPHY:
data->phy_id = bp->phy_addr;
- /* fallthru */
+ /* fallthrough */
case SIOCGMIIREG: {
u32 mii_regval;
@@ -8633,7 +9561,7 @@ static int bnx2x_change_mtu(struct net_device *dev, int new_mtu)
return -EINVAL;
/* This does not race with packet allocation
- * because the actuall alloc size is
+ * because the actual alloc size is
* only updated as part of load
*/
dev->mtu = new_mtu;
@@ -8666,7 +9594,7 @@ static void bnx2x_vlan_rx_register(struct net_device *dev,
bp->vlgrp = vlgrp;
if (netif_running(dev))
- bnx2x_set_rx_mode(dev);
+ bnx2x_set_client_config(bp);
}
#endif
@@ -8695,14 +9623,18 @@ static void bnx2x_reset_task(struct work_struct *work)
if (!netif_running(bp->dev))
return;
- bp->in_reset_task = 1;
+ rtnl_lock();
- bnx2x_netif_stop(bp);
+ if (bp->state != BNX2X_STATE_OPEN) {
+ DP(NETIF_MSG_TX_ERR, "state is %x, returning\n", bp->state);
+ goto reset_task_exit;
+ }
bnx2x_nic_unload(bp, 0);
bnx2x_nic_load(bp, 0);
- bp->in_reset_task = 0;
+reset_task_exit:
+ rtnl_unlock();
}
static int __devinit bnx2x_init_board(struct pci_dev *pdev,
@@ -8783,8 +9715,6 @@ static int __devinit bnx2x_init_board(struct pci_dev *pdev,
spin_lock_init(&bp->phy_lock);
- bp->in_reset_task = 0;
-
INIT_WORK(&bp->reset_task, bnx2x_reset_task);
INIT_WORK(&bp->sp_task, bnx2x_sp_task);
@@ -8813,7 +9743,7 @@ static int __devinit bnx2x_init_board(struct pci_dev *pdev,
bnx2x_get_hwinfo(bp);
if (CHIP_REV(bp) == CHIP_REV_FPGA) {
- printk(KERN_ERR PFX "FPGA detacted. MCP disabled,"
+ printk(KERN_ERR PFX "FPGA detected. MCP disabled,"
" will only init first device\n");
onefunc = 1;
nomcp = 1;
@@ -8882,14 +9812,32 @@ err_out:
return rc;
}
+static int __devinit bnx2x_get_pcie_width(struct bnx2x *bp)
+{
+ u32 val = REG_RD(bp, PCICFG_OFFSET + PCICFG_LINK_CONTROL);
+
+ val = (val & PCICFG_LINK_WIDTH) >> PCICFG_LINK_WIDTH_SHIFT;
+ return val;
+}
+
+/* return value of 1=2.5GHz 2=5GHz */
+static int __devinit bnx2x_get_pcie_speed(struct bnx2x *bp)
+{
+ u32 val = REG_RD(bp, PCICFG_OFFSET + PCICFG_LINK_CONTROL);
+
+ val = (val & PCICFG_LINK_SPEED) >> PCICFG_LINK_SPEED_SHIFT;
+ return val;
+}
+
static int __devinit bnx2x_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
static int version_printed;
struct net_device *dev = NULL;
struct bnx2x *bp;
- int rc, i;
+ int rc;
int port = PCI_FUNC(pdev->devfn);
+ DECLARE_MAC_BUF(mac);
if (version_printed++ == 0)
printk(KERN_INFO "%s", version);
@@ -8906,6 +9854,7 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev,
if (port && onefunc) {
printk(KERN_ERR PFX "second function disabled. exiting\n");
+ free_netdev(dev);
return 0;
}
@@ -8918,7 +9867,6 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev,
dev->hard_start_xmit = bnx2x_start_xmit;
dev->watchdog_timeo = TX_TIMEOUT;
- dev->get_stats = bnx2x_get_stats;
dev->ethtool_ops = &bnx2x_ethtool_ops;
dev->open = bnx2x_open;
dev->stop = bnx2x_close;
@@ -8944,7 +9892,7 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev,
rc = register_netdev(dev);
if (rc) {
- printk(KERN_ERR PFX "Cannot register net device\n");
+ dev_err(&pdev->dev, "Cannot register net device\n");
if (bp->regview)
iounmap(bp->regview);
if (bp->doorbells)
@@ -8959,32 +9907,30 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev,
pci_set_drvdata(pdev, dev);
bp->name = board_info[ent->driver_data].name;
- printk(KERN_INFO "%s: %s (%c%d) PCI%s %s %dMHz "
- "found at mem %lx, IRQ %d, ",
- dev->name, bp->name,
+ printk(KERN_INFO "%s: %s (%c%d) PCI-E x%d %s found at mem %lx,"
+ " IRQ %d, ", dev->name, bp->name,
((CHIP_ID(bp) & 0xf000) >> 12) + 'A',
((CHIP_ID(bp) & 0x0ff0) >> 4),
- ((bp->flags & PCIX_FLAG) ? "-X" : ""),
- ((bp->flags & PCI_32BIT_FLAG) ? "32-bit" : "64-bit"),
- bp->bus_speed_mhz,
- dev->base_addr,
- bp->pdev->irq);
-
- printk("node addr ");
- for (i = 0; i < 6; i++)
- printk("%2.2x", dev->dev_addr[i]);
- printk("\n");
-
+ bnx2x_get_pcie_width(bp),
+ (bnx2x_get_pcie_speed(bp) == 2) ? "5GHz (Gen2)" : "2.5GHz",
+ dev->base_addr, bp->pdev->irq);
+ printk(KERN_CONT "node addr %s\n", print_mac(mac, dev->dev_addr));
return 0;
}
static void __devexit bnx2x_remove_one(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
- struct bnx2x *bp = netdev_priv(dev);
+ struct bnx2x *bp;
+
+ if (!dev) {
+ /* we get here if init_one() fails */
+ printk(KERN_ERR PFX "BAD net device from bnx2x_init_one\n");
+ return;
+ }
+
+ bp = netdev_priv(dev);
- flush_scheduled_work();
- /*tasklet_kill(&bp->sp_task);*/
unregister_netdev(dev);
if (bp->regview)
@@ -9002,34 +9948,43 @@ static void __devexit bnx2x_remove_one(struct pci_dev *pdev)
static int bnx2x_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct net_device *dev = pci_get_drvdata(pdev);
- struct bnx2x *bp = netdev_priv(dev);
- int rc;
+ struct bnx2x *bp;
+
+ if (!dev)
+ return 0;
if (!netif_running(dev))
return 0;
- rc = bnx2x_nic_unload(bp, 0);
- if (!rc)
- return rc;
+ bp = netdev_priv(dev);
+
+ bnx2x_nic_unload(bp, 0);
netif_device_detach(dev);
- pci_save_state(pdev);
+ pci_save_state(pdev);
bnx2x_set_power_state(bp, pci_choose_state(pdev, state));
+
return 0;
}
static int bnx2x_resume(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
- struct bnx2x *bp = netdev_priv(dev);
+ struct bnx2x *bp;
int rc;
+ if (!dev) {
+ printk(KERN_ERR PFX "BAD net device from bnx2x_init_one\n");
+ return -ENODEV;
+ }
+
if (!netif_running(dev))
return 0;
- pci_restore_state(pdev);
+ bp = netdev_priv(dev);
+ pci_restore_state(pdev);
bnx2x_set_power_state(bp, PCI_D0);
netif_device_attach(dev);
diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h
index 4f7ae6f7745..4f0c0d31e7c 100644
--- a/drivers/net/bnx2x.h
+++ b/drivers/net/bnx2x.h
@@ -1,6 +1,6 @@
/* bnx2x.h: Broadcom Everest network driver.
*
- * Copyright (c) 2007 Broadcom Corporation
+ * Copyright (c) 2007-2008 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,6 +24,8 @@
#define BNX2X_MSG_STATS 0x20000 /* was: NETIF_MSG_TIMER */
#define NETIF_MSG_NVM 0x40000 /* was: NETIF_MSG_HW */
#define NETIF_MSG_DMAE 0x80000 /* was: NETIF_MSG_HW */
+#define BNX2X_MSG_SP 0x100000 /* was: NETIF_MSG_INTR */
+#define BNX2X_MSG_FP 0x200000 /* was: NETIF_MSG_INTR */
#define DP_LEVEL KERN_NOTICE /* was: KERN_DEBUG */
@@ -40,6 +42,12 @@
__LINE__, bp->dev?(bp->dev->name):"?", ##__args); \
} while (0)
+/* for logging (never masked) */
+#define BNX2X_LOG(__fmt, __args...) do { \
+ printk(KERN_NOTICE "[%s:%d(%s)]" __fmt, __FUNCTION__, \
+ __LINE__, bp->dev?(bp->dev->name):"?", ##__args); \
+ } while (0)
+
/* before we have a dev->name use dev_info() */
#define BNX2X_DEV_INFO(__fmt, __args...) do { \
if (bp->msglevel & NETIF_MSG_PROBE) \
@@ -423,8 +431,6 @@ struct bnx2x_fastpath {
#define BNX2X_FP_STATE_OPEN 0xa0000
#define BNX2X_FP_STATE_HALTING 0xb0000
#define BNX2X_FP_STATE_HALTED 0xc0000
-#define BNX2X_FP_STATE_DELETED 0xd0000
-#define BNX2X_FP_STATE_CLOSE_IRQ 0xe0000
int index;
@@ -505,7 +511,6 @@ struct bnx2x {
struct eth_spe *spq;
dma_addr_t spq_mapping;
u16 spq_prod_idx;
- u16 dsb_sp_prod_idx;
struct eth_spe *spq_prod_bd;
struct eth_spe *spq_last_bd;
u16 *dsb_sp_prod;
@@ -517,7 +522,7 @@ struct bnx2x {
*/
u8 stat_pending;
- /* End of fileds used in the performance code paths */
+ /* End of fields used in the performance code paths */
int panic;
int msglevel;
@@ -540,8 +545,6 @@ struct bnx2x {
spinlock_t phy_lock;
struct work_struct reset_task;
- u16 in_reset_task;
-
struct work_struct sp_task;
struct timer_list timer;
@@ -555,7 +558,6 @@ struct bnx2x {
#define CHIP_ID(bp) (((bp)->chip_id) & 0xfffffff0)
#define CHIP_NUM(bp) (((bp)->chip_id) & 0xffff0000)
-#define CHIP_NUM_5710 0x57100000
#define CHIP_REV(bp) (((bp)->chip_id) & 0x0000f000)
#define CHIP_REV_Ax 0x00000000
@@ -574,7 +576,8 @@ struct bnx2x {
u32 fw_mb;
u32 hw_config;
- u32 serdes_config;
+ u32 board;
+ u32 serdes_config;
u32 lane_config;
u32 ext_phy_config;
#define XGXS_EXT_PHY_TYPE(bp) (bp->ext_phy_config & \
@@ -595,11 +598,11 @@ struct bnx2x {
u8 tx_lane_swap;
u8 link_up;
+ u8 phy_link_up;
u32 supported;
/* link settings - missing defines */
#define SUPPORTED_2500baseT_Full (1 << 15)
-#define SUPPORTED_CX4 (1 << 16)
u32 phy_flags;
/*#define PHY_SERDES_FLAG 0x1*/
@@ -644,16 +647,9 @@ struct bnx2x {
#define FLOW_CTRL_BOTH PORT_FEATURE_FLOW_CONTROL_BOTH
#define FLOW_CTRL_NONE PORT_FEATURE_FLOW_CONTROL_NONE
- u32 pause_mode;
-#define PAUSE_NONE 0
-#define PAUSE_SYMMETRIC 1
-#define PAUSE_ASYMMETRIC 2
-#define PAUSE_BOTH 3
-
u32 advertising;
/* link settings - missing defines */
#define ADVERTISED_2500baseT_Full (1 << 15)
-#define ADVERTISED_CX4 (1 << 16)
u32 link_status;
u32 line_speed;
@@ -667,6 +663,8 @@ struct bnx2x {
#define NVRAM_TIMEOUT_COUNT 30000
#define NVRAM_PAGE_SIZE 256
+ u8 wol;
+
int rx_ring_size;
u16 tx_quick_cons_trip_int;
@@ -718,9 +716,6 @@ struct bnx2x {
#endif
char *name;
- u16 bus_speed_mhz;
- u8 wol;
- u8 pad;
/* used to synchronize stats collecting */
int stats_state;
@@ -856,8 +851,8 @@ struct bnx2x {
#define MAX_SPQ_PENDING 8
-#define BNX2X_NUM_STATS 31
-#define BNX2X_NUM_TESTS 2
+#define BNX2X_NUM_STATS 34
+#define BNX2X_NUM_TESTS 1
#define DPM_TRIGER_TYPE 0x40
@@ -867,6 +862,15 @@ struct bnx2x {
DPM_TRIGER_TYPE); \
} while (0)
+/* PCIE link and speed */
+#define PCICFG_LINK_WIDTH 0x1f00000
+#define PCICFG_LINK_WIDTH_SHIFT 20
+#define PCICFG_LINK_SPEED 0xf0000
+#define PCICFG_LINK_SPEED_SHIFT 16
+
+#define BMAC_CONTROL_RX_ENABLE 2
+
+#define pbd_tcp_flags(skb) (ntohl(tcp_flag_word(tcp_hdr(skb)))>>16 & 0xff)
/* stuff added to make the code fit 80Col */
@@ -939,13 +943,13 @@ struct bnx2x {
#define LINK_16GTFD LINK_STATUS_SPEED_AND_DUPLEX_16GTFD
#define LINK_16GXFD LINK_STATUS_SPEED_AND_DUPLEX_16GXFD
-#define NIG_STATUS_INTERRUPT_XGXS0_LINK10G \
+#define NIG_STATUS_XGXS0_LINK10G \
NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK10G
-#define NIG_XGXS0_LINK_STATUS \
+#define NIG_STATUS_XGXS0_LINK_STATUS \
NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS
-#define NIG_XGXS0_LINK_STATUS_SIZE \
+#define NIG_STATUS_XGXS0_LINK_STATUS_SIZE \
NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS_SIZE
-#define NIG_SERDES0_LINK_STATUS \
+#define NIG_STATUS_SERDES0_LINK_STATUS \
NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_SERDES0_LINK_STATUS
#define NIG_MASK_MI_INT \
NIG_MASK_INTERRUPT_PORT0_REG_MASK_EMAC0_MISC_MI_INT
diff --git a/drivers/net/bnx2x_fw_defs.h b/drivers/net/bnx2x_fw_defs.h
index 62a6eb81025..3b968904ca6 100644
--- a/drivers/net/bnx2x_fw_defs.h
+++ b/drivers/net/bnx2x_fw_defs.h
@@ -1,6 +1,6 @@
/* bnx2x_fw_defs.h: Broadcom Everest network driver.
*
- * Copyright (c) 2007 Broadcom Corporation
+ * Copyright (c) 2007-2008 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/net/bnx2x_hsi.h b/drivers/net/bnx2x_hsi.h
index 6fd959c34d1..b21075ccb52 100644
--- a/drivers/net/bnx2x_hsi.h
+++ b/drivers/net/bnx2x_hsi.h
@@ -1,6 +1,6 @@
/* bnx2x_hsi.h: Broadcom Everest network driver.
*
- * Copyright (c) 2007 Broadcom Corporation
+ * Copyright (c) 2007-2008 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -8,169 +8,9 @@
*/
-#define FUNC_0 0
-#define FUNC_1 1
-#define FUNC_MAX 2
-
-
-/* This value (in milliseconds) determines the frequency of the driver
- * issuing the PULSE message code. The firmware monitors this periodic
- * pulse to determine when to switch to an OS-absent mode. */
-#define DRV_PULSE_PERIOD_MS 250
-
-/* This value (in milliseconds) determines how long the driver should
- * wait for an acknowledgement from the firmware before timing out. Once
- * the firmware has timed out, the driver will assume there is no firmware
- * running and there won't be any firmware-driver synchronization during a
- * driver reset. */
-#define FW_ACK_TIME_OUT_MS 5000
-
-#define FW_ACK_POLL_TIME_MS 1
-
-#define FW_ACK_NUM_OF_POLL (FW_ACK_TIME_OUT_MS/FW_ACK_POLL_TIME_MS)
-
-/* LED Blink rate that will achieve ~15.9Hz */
-#define LED_BLINK_RATE_VAL 480
-
-/****************************************************************************
- * Driver <-> FW Mailbox *
- ****************************************************************************/
-struct drv_fw_mb {
- u32 drv_mb_header;
-#define DRV_MSG_CODE_MASK 0xffff0000
-#define DRV_MSG_CODE_LOAD_REQ 0x10000000
-#define DRV_MSG_CODE_LOAD_DONE 0x11000000
-#define DRV_MSG_CODE_UNLOAD_REQ_WOL_EN 0x20000000
-#define DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS 0x20010000
-#define DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP 0x20020000
-#define DRV_MSG_CODE_UNLOAD_DONE 0x21000000
-#define DRV_MSG_CODE_DIAG_ENTER_REQ 0x50000000
-#define DRV_MSG_CODE_DIAG_EXIT_REQ 0x60000000
-#define DRV_MSG_CODE_VALIDATE_KEY 0x70000000
-#define DRV_MSG_CODE_GET_CURR_KEY 0x80000000
-#define DRV_MSG_CODE_GET_UPGRADE_KEY 0x81000000
-#define DRV_MSG_CODE_GET_MANUF_KEY 0x82000000
-#define DRV_MSG_CODE_LOAD_L2B_PRAM 0x90000000
-
-#define DRV_MSG_SEQ_NUMBER_MASK 0x0000ffff
-
- u32 drv_mb_param;
-
- u32 fw_mb_header;
-#define FW_MSG_CODE_MASK 0xffff0000
-#define FW_MSG_CODE_DRV_LOAD_COMMON 0x11000000
-#define FW_MSG_CODE_DRV_LOAD_PORT 0x12000000
-#define FW_MSG_CODE_DRV_LOAD_REFUSED 0x13000000
-#define FW_MSG_CODE_DRV_LOAD_DONE 0x14000000
-#define FW_MSG_CODE_DRV_UNLOAD_COMMON 0x21000000
-#define FW_MSG_CODE_DRV_UNLOAD_PORT 0x22000000
-#define FW_MSG_CODE_DRV_UNLOAD_DONE 0x23000000
-#define FW_MSG_CODE_DIAG_ENTER_DONE 0x50000000
-#define FW_MSG_CODE_DIAG_REFUSE 0x51000000
-#define FW_MSG_CODE_VALIDATE_KEY_SUCCESS 0x70000000
-#define FW_MSG_CODE_VALIDATE_KEY_FAILURE 0x71000000
-#define FW_MSG_CODE_GET_KEY_DONE 0x80000000
-#define FW_MSG_CODE_NO_KEY 0x8f000000
-#define FW_MSG_CODE_LIC_INFO_NOT_READY 0x8f800000
-#define FW_MSG_CODE_L2B_PRAM_LOADED 0x90000000
-#define FW_MSG_CODE_L2B_PRAM_T_LOAD_FAILURE 0x91000000
-#define FW_MSG_CODE_L2B_PRAM_C_LOAD_FAILURE 0x92000000
-#define FW_MSG_CODE_L2B_PRAM_X_LOAD_FAILURE 0x93000000
-#define FW_MSG_CODE_L2B_PRAM_U_LOAD_FAILURE 0x94000000
-
-#define FW_MSG_SEQ_NUMBER_MASK 0x0000ffff
-
- u32 fw_mb_param;
-
- u32 link_status;
- /* Driver should update this field on any link change event */
-
-#define LINK_STATUS_LINK_FLAG_MASK 0x00000001
-#define LINK_STATUS_LINK_UP 0x00000001
-#define LINK_STATUS_SPEED_AND_DUPLEX_MASK 0x0000001E
-#define LINK_STATUS_SPEED_AND_DUPLEX_AN_NOT_COMPLETE (0<<1)
-#define LINK_STATUS_SPEED_AND_DUPLEX_10THD (1<<1)
-#define LINK_STATUS_SPEED_AND_DUPLEX_10TFD (2<<1)
-#define LINK_STATUS_SPEED_AND_DUPLEX_100TXHD (3<<1)
-#define LINK_STATUS_SPEED_AND_DUPLEX_100T4 (4<<1)
-#define LINK_STATUS_SPEED_AND_DUPLEX_100TXFD (5<<1)
-#define LINK_STATUS_SPEED_AND_DUPLEX_1000THD (6<<1)
-#define LINK_STATUS_SPEED_AND_DUPLEX_1000TFD (7<<1)
-#define LINK_STATUS_SPEED_AND_DUPLEX_1000XFD (7<<1)
-#define LINK_STATUS_SPEED_AND_DUPLEX_2500THD (8<<1)
-#define LINK_STATUS_SPEED_AND_DUPLEX_2500TFD (9<<1)
-#define LINK_STATUS_SPEED_AND_DUPLEX_2500XFD (9<<1)
-#define LINK_STATUS_SPEED_AND_DUPLEX_10GTFD (10<<1)
-#define LINK_STATUS_SPEED_AND_DUPLEX_10GXFD (10<<1)
-#define LINK_STATUS_SPEED_AND_DUPLEX_12GTFD (11<<1)
-#define LINK_STATUS_SPEED_AND_DUPLEX_12GXFD (11<<1)
-#define LINK_STATUS_SPEED_AND_DUPLEX_12_5GTFD (12<<1)
-#define LINK_STATUS_SPEED_AND_DUPLEX_12_5GXFD (12<<1)
-#define LINK_STATUS_SPEED_AND_DUPLEX_13GTFD (13<<1)
-#define LINK_STATUS_SPEED_AND_DUPLEX_13GXFD (13<<1)
-#define LINK_STATUS_SPEED_AND_DUPLEX_15GTFD (14<<1)
-#define LINK_STATUS_SPEED_AND_DUPLEX_15GXFD (14<<1)
-#define LINK_STATUS_SPEED_AND_DUPLEX_16GTFD (15<<1)
-#define LINK_STATUS_SPEED_AND_DUPLEX_16GXFD (15<<1)
-
-#define LINK_STATUS_AUTO_NEGOTIATE_FLAG_MASK 0x00000020
-#define LINK_STATUS_AUTO_NEGOTIATE_ENABLED 0x00000020
-
-#define LINK_STATUS_AUTO_NEGOTIATE_COMPLETE 0x00000040
-#define LINK_STATUS_PARALLEL_DETECTION_FLAG_MASK 0x00000080
-#define LINK_STATUS_PARALLEL_DETECTION_USED 0x00000080
-
-#define LINK_STATUS_LINK_PARTNER_1000TFD_CAPABLE 0x00000200
-#define LINK_STATUS_LINK_PARTNER_1000THD_CAPABLE 0x00000400
-#define LINK_STATUS_LINK_PARTNER_100T4_CAPABLE 0x00000800
-#define LINK_STATUS_LINK_PARTNER_100TXFD_CAPABLE 0x00001000
-#define LINK_STATUS_LINK_PARTNER_100TXHD_CAPABLE 0x00002000
-#define LINK_STATUS_LINK_PARTNER_10TFD_CAPABLE 0x00004000
-#define LINK_STATUS_LINK_PARTNER_10THD_CAPABLE 0x00008000
-
-#define LINK_STATUS_TX_FLOW_CONTROL_FLAG_MASK 0x00010000
-#define LINK_STATUS_TX_FLOW_CONTROL_ENABLED 0x00010000
-
-#define LINK_STATUS_RX_FLOW_CONTROL_FLAG_MASK 0x00020000
-#define LINK_STATUS_RX_FLOW_CONTROL_ENABLED 0x00020000
-
-#define LINK_STATUS_LINK_PARTNER_FLOW_CONTROL_MASK 0x000C0000
-#define LINK_STATUS_LINK_PARTNER_NOT_PAUSE_CAPABLE (0<<18)
-#define LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE (1<<18)
-#define LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE (2<<18)
-#define LINK_STATUS_LINK_PARTNER_BOTH_PAUSE (3<<18)
-
-#define LINK_STATUS_SERDES_LINK 0x00100000
-
-#define LINK_STATUS_LINK_PARTNER_2500XFD_CAPABLE 0x00200000
-#define LINK_STATUS_LINK_PARTNER_2500XHD_CAPABLE 0x00400000
-#define LINK_STATUS_LINK_PARTNER_10GXFD_CAPABLE 0x00800000
-#define LINK_STATUS_LINK_PARTNER_12GXFD_CAPABLE 0x01000000
-#define LINK_STATUS_LINK_PARTNER_12_5GXFD_CAPABLE 0x02000000
-#define LINK_STATUS_LINK_PARTNER_13GXFD_CAPABLE 0x04000000
-#define LINK_STATUS_LINK_PARTNER_15GXFD_CAPABLE 0x08000000
-#define LINK_STATUS_LINK_PARTNER_16GXFD_CAPABLE 0x10000000
-
- u32 drv_pulse_mb;
-#define DRV_PULSE_SEQ_MASK 0x00007fff
-#define DRV_PULSE_SYSTEM_TIME_MASK 0xffff0000
- /* The system time is in the format of
- * (year-2001)*12*32 + month*32 + day. */
-#define DRV_PULSE_ALWAYS_ALIVE 0x00008000
- /* Indicate to the firmware not to go into the
- * OS-absent when it is not getting driver pulse.
- * This is used for debugging as well for PXE(MBA). */
-
- u32 mcp_pulse_mb;
-#define MCP_PULSE_SEQ_MASK 0x00007fff
-#define MCP_PULSE_ALWAYS_ALIVE 0x00008000
- /* Indicates to the driver not to assert due to lack
- * of MCP response */
-#define MCP_EVENT_MASK 0xffff0000
-#define MCP_EVENT_OTHER_DRIVER_RESET_REQ 0x00010000
-
-};
-
+#define PORT_0 0
+#define PORT_1 1
+#define PORT_MAX 2
/****************************************************************************
* Shared HW configuration *
@@ -249,7 +89,7 @@ struct shared_hw_cfg { /* NVRAM Offset */
#define SHARED_HW_CFG_SMBUS_TIMING_100KHZ 0x00000000
#define SHARED_HW_CFG_SMBUS_TIMING_400KHZ 0x00001000
-#define SHARED_HW_CFG_HIDE_FUNC1 0x00002000
+#define SHARED_HW_CFG_HIDE_PORT1 0x00002000
u32 power_dissipated; /* 0x11c */
#define SHARED_HW_CFG_POWER_DIS_CMN_MASK 0xff000000
@@ -290,6 +130,8 @@ struct shared_hw_cfg { /* NVRAM Offset */
#define SHARED_HW_CFG_BOARD_TYPE_BCM957710T1015G 0x00000006
#define SHARED_HW_CFG_BOARD_TYPE_BCM957710A1020G 0x00000007
#define SHARED_HW_CFG_BOARD_TYPE_BCM957710T1003G 0x00000008
+#define SHARED_HW_CFG_BOARD_TYPE_BCM957710A1022G 0x00000009
+#define SHARED_HW_CFG_BOARD_TYPE_BCM957710A1021G 0x0000000a
#define SHARED_HW_CFG_BOARD_VER_MASK 0xffff0000
#define SHARED_HW_CFG_BOARD_VER_SHIFT 16
@@ -304,13 +146,12 @@ struct shared_hw_cfg { /* NVRAM Offset */
};
+
/****************************************************************************
* Port HW configuration *
****************************************************************************/
-struct port_hw_cfg { /* function 0: 0x12c-0x2bb, function 1: 0x2bc-0x44b */
+struct port_hw_cfg { /* port 0: 0x12c port 1: 0x2bc */
- /* Fields below are port specific (in anticipation of dual port
- devices */
u32 pci_id;
#define PORT_HW_CFG_PCI_VENDOR_ID_MASK 0xffff0000
#define PORT_HW_CFG_PCI_DEVICE_ID_MASK 0x0000ffff
@@ -420,6 +261,8 @@ struct port_hw_cfg { /* function 0: 0x12c-0x2bb, function 1: 0x2bc-0x44b */
#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706 0x00000500
#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8276 0x00000600
#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481 0x00000700
+#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101 0x00000800
+#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE 0x0000fd00
#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN 0x0000ff00
#define PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK 0x000000ff
@@ -462,11 +305,13 @@ struct port_hw_cfg { /* function 0: 0x12c-0x2bb, function 1: 0x2bc-0x44b */
};
+
/****************************************************************************
* Shared Feature configuration *
****************************************************************************/
struct shared_feat_cfg { /* NVRAM Offset */
- u32 bmc_common; /* 0x450 */
+
+ u32 config; /* 0x450 */
#define SHARED_FEATURE_BMC_ECHO_MODE_EN 0x00000001
};
@@ -475,7 +320,8 @@ struct shared_feat_cfg { /* NVRAM Offset */
/****************************************************************************
* Port Feature configuration *
****************************************************************************/
-struct port_feat_cfg { /* function 0: 0x454-0x4c7, function 1: 0x4c8-0x53b */
+struct port_feat_cfg { /* port 0: 0x454 port 1: 0x4c8 */
+
u32 config;
#define PORT_FEATURE_BAR1_SIZE_MASK 0x0000000f
#define PORT_FEATURE_BAR1_SIZE_SHIFT 0
@@ -609,8 +455,7 @@ struct port_feat_cfg { /* function 0: 0x454-0x4c7, function 1: 0x4c8-0x53b */
#define PORT_FEATURE_SMBUS_ADDR_MASK 0x000000fe
#define PORT_FEATURE_SMBUS_ADDR_SHIFT 1
- u32 iscsib_boot_cfg;
-#define PORT_FEATURE_ISCSIB_SKIP_TARGET_BOOT 0x00000001
+ u32 reserved1;
u32 link_config; /* Used as HW defaults for the driver */
#define PORT_FEATURE_CONNECTED_SWITCH_MASK 0x03000000
@@ -657,20 +502,201 @@ struct port_feat_cfg { /* function 0: 0x454-0x4c7, function 1: 0x4c8-0x53b */
};
+/*****************************************************************************
+ * Device Information *
+ *****************************************************************************/
+struct dev_info { /* size */
+
+ u32 bc_rev; /* 8 bits each: major, minor, build */ /* 4 */
+
+ struct shared_hw_cfg shared_hw_config; /* 40 */
+
+ struct port_hw_cfg port_hw_config[PORT_MAX]; /* 400*2=800 */
+
+ struct shared_feat_cfg shared_feature_config; /* 4 */
+
+ struct port_feat_cfg port_feature_config[PORT_MAX]; /* 116*2=232 */
+
+};
+
+
+#define FUNC_0 0
+#define FUNC_1 1
+#define E1_FUNC_MAX 2
+#define FUNC_MAX E1_FUNC_MAX
+
+
+/* This value (in milliseconds) determines the frequency of the driver
+ * issuing the PULSE message code. The firmware monitors this periodic
+ * pulse to determine when to switch to an OS-absent mode. */
+#define DRV_PULSE_PERIOD_MS 250
+
+/* This value (in milliseconds) determines how long the driver should
+ * wait for an acknowledgement from the firmware before timing out. Once
+ * the firmware has timed out, the driver will assume there is no firmware
+ * running and there won't be any firmware-driver synchronization during a
+ * driver reset. */
+#define FW_ACK_TIME_OUT_MS 5000
+
+#define FW_ACK_POLL_TIME_MS 1
+
+#define FW_ACK_NUM_OF_POLL (FW_ACK_TIME_OUT_MS/FW_ACK_POLL_TIME_MS)
+
+/* LED Blink rate that will achieve ~15.9Hz */
+#define LED_BLINK_RATE_VAL 480
+
/****************************************************************************
- * Device Information *
+ * Driver <-> FW Mailbox *
****************************************************************************/
-struct dev_info { /* size */
+struct drv_port_mb {
+
+ u32 link_status;
+ /* Driver should update this field on any link change event */
+
+#define LINK_STATUS_LINK_FLAG_MASK 0x00000001
+#define LINK_STATUS_LINK_UP 0x00000001
+#define LINK_STATUS_SPEED_AND_DUPLEX_MASK 0x0000001E
+#define LINK_STATUS_SPEED_AND_DUPLEX_AN_NOT_COMPLETE (0<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_10THD (1<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_10TFD (2<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_100TXHD (3<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_100T4 (4<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_100TXFD (5<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_1000THD (6<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_1000TFD (7<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_1000XFD (7<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_2500THD (8<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_2500TFD (9<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_2500XFD (9<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_10GTFD (10<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_10GXFD (10<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_12GTFD (11<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_12GXFD (11<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_12_5GTFD (12<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_12_5GXFD (12<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_13GTFD (13<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_13GXFD (13<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_15GTFD (14<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_15GXFD (14<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_16GTFD (15<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_16GXFD (15<<1)
+
+#define LINK_STATUS_AUTO_NEGOTIATE_FLAG_MASK 0x00000020
+#define LINK_STATUS_AUTO_NEGOTIATE_ENABLED 0x00000020
+
+#define LINK_STATUS_AUTO_NEGOTIATE_COMPLETE 0x00000040
+#define LINK_STATUS_PARALLEL_DETECTION_FLAG_MASK 0x00000080
+#define LINK_STATUS_PARALLEL_DETECTION_USED 0x00000080
+
+#define LINK_STATUS_LINK_PARTNER_1000TFD_CAPABLE 0x00000200
+#define LINK_STATUS_LINK_PARTNER_1000THD_CAPABLE 0x00000400
+#define LINK_STATUS_LINK_PARTNER_100T4_CAPABLE 0x00000800
+#define LINK_STATUS_LINK_PARTNER_100TXFD_CAPABLE 0x00001000
+#define LINK_STATUS_LINK_PARTNER_100TXHD_CAPABLE 0x00002000
+#define LINK_STATUS_LINK_PARTNER_10TFD_CAPABLE 0x00004000
+#define LINK_STATUS_LINK_PARTNER_10THD_CAPABLE 0x00008000
+
+#define LINK_STATUS_TX_FLOW_CONTROL_FLAG_MASK 0x00010000
+#define LINK_STATUS_TX_FLOW_CONTROL_ENABLED 0x00010000
+
+#define LINK_STATUS_RX_FLOW_CONTROL_FLAG_MASK 0x00020000
+#define LINK_STATUS_RX_FLOW_CONTROL_ENABLED 0x00020000
+
+#define LINK_STATUS_LINK_PARTNER_FLOW_CONTROL_MASK 0x000C0000
+#define LINK_STATUS_LINK_PARTNER_NOT_PAUSE_CAPABLE (0<<18)
+#define LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE (1<<18)
+#define LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE (2<<18)
+#define LINK_STATUS_LINK_PARTNER_BOTH_PAUSE (3<<18)
+
+#define LINK_STATUS_SERDES_LINK 0x00100000
+
+#define LINK_STATUS_LINK_PARTNER_2500XFD_CAPABLE 0x00200000
+#define LINK_STATUS_LINK_PARTNER_2500XHD_CAPABLE 0x00400000
+#define LINK_STATUS_LINK_PARTNER_10GXFD_CAPABLE 0x00800000
+#define LINK_STATUS_LINK_PARTNER_12GXFD_CAPABLE 0x01000000
+#define LINK_STATUS_LINK_PARTNER_12_5GXFD_CAPABLE 0x02000000
+#define LINK_STATUS_LINK_PARTNER_13GXFD_CAPABLE 0x04000000
+#define LINK_STATUS_LINK_PARTNER_15GXFD_CAPABLE 0x08000000
+#define LINK_STATUS_LINK_PARTNER_16GXFD_CAPABLE 0x10000000
- u32 bc_rev; /* 8 bits each: major, minor, build */ /* 4 */
+ u32 reserved[3];
- struct shared_hw_cfg shared_hw_config; /* 40 */
+};
+
+
+struct drv_func_mb {
+
+ u32 drv_mb_header;
+#define DRV_MSG_CODE_MASK 0xffff0000
+#define DRV_MSG_CODE_LOAD_REQ 0x10000000
+#define DRV_MSG_CODE_LOAD_DONE 0x11000000
+#define DRV_MSG_CODE_UNLOAD_REQ_WOL_EN 0x20000000
+#define DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS 0x20010000
+#define DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP 0x20020000
+#define DRV_MSG_CODE_UNLOAD_DONE 0x21000000
+#define DRV_MSG_CODE_DIAG_ENTER_REQ 0x50000000
+#define DRV_MSG_CODE_DIAG_EXIT_REQ 0x60000000
+#define DRV_MSG_CODE_VALIDATE_KEY 0x70000000
+#define DRV_MSG_CODE_GET_CURR_KEY 0x80000000
+#define DRV_MSG_CODE_GET_UPGRADE_KEY 0x81000000
+#define DRV_MSG_CODE_GET_MANUF_KEY 0x82000000
+#define DRV_MSG_CODE_LOAD_L2B_PRAM 0x90000000
+
+#define DRV_MSG_SEQ_NUMBER_MASK 0x0000ffff
+
+ u32 drv_mb_param;
+
+ u32 fw_mb_header;
+#define FW_MSG_CODE_MASK 0xffff0000
+#define FW_MSG_CODE_DRV_LOAD_COMMON 0x10100000
+#define FW_MSG_CODE_DRV_LOAD_PORT 0x10110000
+#define FW_MSG_CODE_DRV_LOAD_FUNCTION 0x10120000
+#define FW_MSG_CODE_DRV_LOAD_REFUSED 0x10200000
+#define FW_MSG_CODE_DRV_LOAD_DONE 0x11100000
+#define FW_MSG_CODE_DRV_UNLOAD_COMMON 0x20100000
+#define FW_MSG_CODE_DRV_UNLOAD_PORT 0x20110000
+#define FW_MSG_CODE_DRV_UNLOAD_FUNCTION 0x20120000
+#define FW_MSG_CODE_DRV_UNLOAD_DONE 0x21100000
+#define FW_MSG_CODE_DIAG_ENTER_DONE 0x50100000
+#define FW_MSG_CODE_DIAG_REFUSE 0x50200000
+#define FW_MSG_CODE_DIAG_EXIT_DONE 0x60100000
+#define FW_MSG_CODE_VALIDATE_KEY_SUCCESS 0x70100000
+#define FW_MSG_CODE_VALIDATE_KEY_FAILURE 0x70200000
+#define FW_MSG_CODE_GET_KEY_DONE 0x80100000
+#define FW_MSG_CODE_NO_KEY 0x80f00000
+#define FW_MSG_CODE_LIC_INFO_NOT_READY 0x80f80000
+#define FW_MSG_CODE_L2B_PRAM_LOADED 0x90100000
+#define FW_MSG_CODE_L2B_PRAM_T_LOAD_FAILURE 0x90210000
+#define FW_MSG_CODE_L2B_PRAM_C_LOAD_FAILURE 0x90220000
+#define FW_MSG_CODE_L2B_PRAM_X_LOAD_FAILURE 0x90230000
+#define FW_MSG_CODE_L2B_PRAM_U_LOAD_FAILURE 0x90240000
+
+#define FW_MSG_SEQ_NUMBER_MASK 0x0000ffff
+
+ u32 fw_mb_param;
+
+ u32 drv_pulse_mb;
+#define DRV_PULSE_SEQ_MASK 0x00007fff
+#define DRV_PULSE_SYSTEM_TIME_MASK 0xffff0000
+ /* The system time is in the format of
+ * (year-2001)*12*32 + month*32 + day. */
+#define DRV_PULSE_ALWAYS_ALIVE 0x00008000
+ /* Indicate to the firmware not to go into the
+ * OS-absent when it is not getting driver pulse.
+ * This is used for debugging as well for PXE(MBA). */
- struct port_hw_cfg port_hw_config[FUNC_MAX]; /* 400*2=800 */
+ u32 mcp_pulse_mb;
+#define MCP_PULSE_SEQ_MASK 0x00007fff
+#define MCP_PULSE_ALWAYS_ALIVE 0x00008000
+ /* Indicates to the driver not to assert due to lack
+ * of MCP response */
+#define MCP_EVENT_MASK 0xffff0000
+#define MCP_EVENT_OTHER_DRIVER_RESET_REQ 0x00010000
- struct shared_feat_cfg shared_feature_config; /* 4 */
+ u32 iscsi_boot_signature;
+ u32 iscsi_boot_block_offset;
- struct port_feat_cfg port_feature_config[FUNC_MAX];/* 116*2=232 */
+ u32 reserved[3];
};
@@ -678,9 +704,8 @@ struct dev_info { /* size */
/****************************************************************************
* Management firmware state *
****************************************************************************/
-/* Allocate 320 bytes for management firmware: still not known exactly
- * how much IMD needs. */
-#define MGMTFW_STATE_WORD_SIZE 80
+/* Allocate 440 bytes for management firmware */
+#define MGMTFW_STATE_WORD_SIZE 110
struct mgmtfw_state {
u32 opaque[MGMTFW_STATE_WORD_SIZE];
@@ -691,31 +716,40 @@ struct mgmtfw_state {
* Shared Memory Region *
****************************************************************************/
struct shmem_region { /* SharedMem Offset (size) */
- u32 validity_map[FUNC_MAX]; /* 0x0 (4 * 2 = 0x8) */
-#define SHR_MEM_VALIDITY_PCI_CFG 0x00000001
-#define SHR_MEM_VALIDITY_MB 0x00000002
-#define SHR_MEM_VALIDITY_DEV_INFO 0x00000004
+
+ u32 validity_map[PORT_MAX]; /* 0x0 (4*2 = 0x8) */
+#define SHR_MEM_FORMAT_REV_ID ('A'<<24)
+#define SHR_MEM_FORMAT_REV_MASK 0xff000000
+ /* validity bits */
+#define SHR_MEM_VALIDITY_PCI_CFG 0x00100000
+#define SHR_MEM_VALIDITY_MB 0x00200000
+#define SHR_MEM_VALIDITY_DEV_INFO 0x00400000
+#define SHR_MEM_VALIDITY_RESERVED 0x00000007
/* One licensing bit should be set */
#define SHR_MEM_VALIDITY_LIC_KEY_IN_EFFECT_MASK 0x00000038
#define SHR_MEM_VALIDITY_LIC_MANUF_KEY_IN_EFFECT 0x00000008
#define SHR_MEM_VALIDITY_LIC_UPGRADE_KEY_IN_EFFECT 0x00000010
#define SHR_MEM_VALIDITY_LIC_NO_KEY_IN_EFFECT 0x00000020
+ /* Active MFW */
+#define SHR_MEM_VALIDITY_ACTIVE_MFW_UNKNOWN 0x00000000
+#define SHR_MEM_VALIDITY_ACTIVE_MFW_IPMI 0x00000040
+#define SHR_MEM_VALIDITY_ACTIVE_MFW_UMP 0x00000080
+#define SHR_MEM_VALIDITY_ACTIVE_MFW_NCSI 0x000000c0
+#define SHR_MEM_VALIDITY_ACTIVE_MFW_NONE 0x000001c0
+#define SHR_MEM_VALIDITY_ACTIVE_MFW_MASK 0x000001c0
- struct drv_fw_mb drv_fw_mb[FUNC_MAX]; /* 0x8 (28 * 2 = 0x38) */
-
- struct dev_info dev_info; /* 0x40 (0x438) */
+ struct dev_info dev_info; /* 0x8 (0x438) */
-#ifdef _LICENSE_H
- license_key_t drv_lic_key[FUNC_MAX]; /* 0x478 (52 * 2 = 0x68) */
-#else /* Linux! */
- u8 reserved[52*FUNC_MAX];
-#endif
+ u8 reserved[52*PORT_MAX];
/* FW information (for internal FW use) */
- u32 fw_info_fio_offset; /* 0x4e0 (0x4) */
- struct mgmtfw_state mgmtfw_state; /* 0x4e4 (0x140) */
+ u32 fw_info_fio_offset; /* 0x4a8 (0x4) */
+ struct mgmtfw_state mgmtfw_state; /* 0x4ac (0x1b8) */
+
+ struct drv_port_mb port_mb[PORT_MAX]; /* 0x664 (16*2=0x20) */
+ struct drv_func_mb func_mb[FUNC_MAX]; /* 0x684 (44*2=0x58) */
-}; /* 0x624 */
+}; /* 0x6dc */
#define BCM_5710_FW_MAJOR_VERSION 4
diff --git a/drivers/net/bnx2x_init.h b/drivers/net/bnx2x_init.h
index 04f93bff2ef..dcaecc53bdb 100644
--- a/drivers/net/bnx2x_init.h
+++ b/drivers/net/bnx2x_init.h
@@ -1,6 +1,6 @@
/* bnx2x_init.h: Broadcom Everest network driver.
*
- * Copyright (c) 2007 Broadcom Corporation
+ * Copyright (c) 2007-2008 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -409,7 +409,7 @@ static void bnx2x_init_pxp(struct bnx2x *bp)
pci_read_config_word(bp->pdev,
bp->pcie_cap + PCI_EXP_DEVCTL, (u16 *)&val);
- DP(NETIF_MSG_HW, "read 0x%x from devctl\n", val);
+ DP(NETIF_MSG_HW, "read 0x%x from devctl\n", (u16)val);
w_order = ((val & PCI_EXP_DEVCTL_PAYLOAD) >> 5);
r_order = ((val & PCI_EXP_DEVCTL_READRQ) >> 12);
@@ -472,10 +472,14 @@ static void bnx2x_init_pxp(struct bnx2x *bp)
REG_WR(bp, PXP2_REG_PSWRQ_BW_WR, val);
REG_WR(bp, PXP2_REG_RQ_WR_MBS0, w_order);
- REG_WR(bp, PXP2_REG_RQ_WR_MBS0 + 8, w_order);
+ REG_WR(bp, PXP2_REG_RQ_WR_MBS1, w_order);
REG_WR(bp, PXP2_REG_RQ_RD_MBS0, r_order);
- REG_WR(bp, PXP2_REG_RQ_RD_MBS0 + 8, r_order);
+ REG_WR(bp, PXP2_REG_RQ_RD_MBS1, r_order);
+ if (r_order == MAX_RD_ORD)
+ REG_WR(bp, PXP2_REG_RQ_PDR_LIMIT, 0xe00);
+
+ REG_WR(bp, PXP2_REG_WR_USDMDP_TH, (0x18 << w_order));
REG_WR(bp, PXP2_REG_WR_DMAE_TH, (128 << w_order)/16);
}
diff --git a/drivers/net/bnx2x_reg.h b/drivers/net/bnx2x_reg.h
index 86055297ab0..5a1aa0b5504 100644
--- a/drivers/net/bnx2x_reg.h
+++ b/drivers/net/bnx2x_reg.h
@@ -1,6 +1,6 @@
/* bnx2x_reg.h: Broadcom Everest network driver.
*
- * Copyright (c) 2007 Broadcom Corporation
+ * Copyright (c) 2007-2008 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,6 +24,8 @@
#define BRB1_REG_BRB1_INT_STS 0x6011c
/* [RW 4] Parity mask register #0 read/write */
#define BRB1_REG_BRB1_PRTY_MASK 0x60138
+/* [R 4] Parity register #0 read */
+#define BRB1_REG_BRB1_PRTY_STS 0x6012c
/* [RW 10] At address BRB1_IND_FREE_LIST_PRS_CRDT initialize free head. At
address BRB1_IND_FREE_LIST_PRS_CRDT+1 initialize free tail. At address
BRB1_IND_FREE_LIST_PRS_CRDT+2 initialize parser initial credit. */
@@ -281,6 +283,8 @@
#define CDU_REG_CDU_INT_STS 0x101030
/* [RW 5] Parity mask register #0 read/write */
#define CDU_REG_CDU_PRTY_MASK 0x10104c
+/* [R 5] Parity register #0 read */
+#define CDU_REG_CDU_PRTY_STS 0x101040
/* [RC 32] logging of error data in case of a CDU load error:
{expected_cid[15:0]; xpected_type[2:0]; xpected_region[2:0]; ctive_error;
ype_error; ctual_active; ctual_compressed_context}; */
@@ -308,6 +312,8 @@
#define CFC_REG_CFC_INT_STS_CLR 0x104100
/* [RW 4] Parity mask register #0 read/write */
#define CFC_REG_CFC_PRTY_MASK 0x104118
+/* [R 4] Parity register #0 read */
+#define CFC_REG_CFC_PRTY_STS 0x10410c
/* [RW 21] CID cam access (21:1 - Data; alid - 0) */
#define CFC_REG_CID_CAM 0x104800
#define CFC_REG_CONTROL0 0x104028
@@ -354,6 +360,8 @@
#define CSDM_REG_CSDM_INT_MASK_1 0xc22ac
/* [RW 11] Parity mask register #0 read/write */
#define CSDM_REG_CSDM_PRTY_MASK 0xc22bc
+/* [R 11] Parity register #0 read */
+#define CSDM_REG_CSDM_PRTY_STS 0xc22b0
#define CSDM_REG_ENABLE_IN1 0xc2238
#define CSDM_REG_ENABLE_IN2 0xc223c
#define CSDM_REG_ENABLE_OUT1 0xc2240
@@ -438,6 +446,9 @@
/* [RW 32] Parity mask register #0 read/write */
#define CSEM_REG_CSEM_PRTY_MASK_0 0x200130
#define CSEM_REG_CSEM_PRTY_MASK_1 0x200140
+/* [R 32] Parity register #0 read */
+#define CSEM_REG_CSEM_PRTY_STS_0 0x200124
+#define CSEM_REG_CSEM_PRTY_STS_1 0x200134
#define CSEM_REG_ENABLE_IN 0x2000a4
#define CSEM_REG_ENABLE_OUT 0x2000a8
/* [RW 32] This address space contains all registers and memories that are
@@ -526,6 +537,8 @@
#define CSEM_REG_TS_9_AS 0x20005c
/* [RW 1] Parity mask register #0 read/write */
#define DBG_REG_DBG_PRTY_MASK 0xc0a8
+/* [R 1] Parity register #0 read */
+#define DBG_REG_DBG_PRTY_STS 0xc09c
/* [RW 2] debug only: These bits indicate the credit for PCI request type 4
interface; MUST be configured AFTER pci_ext_buffer_strt_addr_lsb/msb are
configured */
@@ -543,6 +556,8 @@
#define DMAE_REG_DMAE_INT_MASK 0x102054
/* [RW 4] Parity mask register #0 read/write */
#define DMAE_REG_DMAE_PRTY_MASK 0x102064
+/* [R 4] Parity register #0 read */
+#define DMAE_REG_DMAE_PRTY_STS 0x102058
/* [RW 1] Command 0 go. */
#define DMAE_REG_GO_C0 0x102080
/* [RW 1] Command 1 go. */
@@ -623,6 +638,8 @@
#define DORQ_REG_DORQ_INT_STS_CLR 0x170178
/* [RW 2] Parity mask register #0 read/write */
#define DORQ_REG_DORQ_PRTY_MASK 0x170190
+/* [R 2] Parity register #0 read */
+#define DORQ_REG_DORQ_PRTY_STS 0x170184
/* [RW 8] The address to write the DPM CID to STORM. */
#define DORQ_REG_DPM_CID_ADDR 0x170044
/* [RW 5] The DPM mode CID extraction offset. */
@@ -692,6 +709,8 @@
#define HC_REG_CONFIG_1 0x108004
/* [RW 3] Parity mask register #0 read/write */
#define HC_REG_HC_PRTY_MASK 0x1080a0
+/* [R 3] Parity register #0 read */
+#define HC_REG_HC_PRTY_STS 0x108094
/* [RW 17] status block interrupt mask; one in each bit means unmask; zerow
in each bit means mask; bit 0 - default SB; bit 1 - SB_0; bit 2 - SB_1...
bit 16- SB_15; addr 0 - port 0; addr 1 - port 1 */
@@ -1127,6 +1146,7 @@
#define MISC_REG_AEU_GENERAL_ATTN_17 0xa044
#define MISC_REG_AEU_GENERAL_ATTN_18 0xa048
#define MISC_REG_AEU_GENERAL_ATTN_19 0xa04c
+#define MISC_REG_AEU_GENERAL_ATTN_10 0xa028
#define MISC_REG_AEU_GENERAL_ATTN_11 0xa02c
#define MISC_REG_AEU_GENERAL_ATTN_2 0xa008
#define MISC_REG_AEU_GENERAL_ATTN_20 0xa050
@@ -1135,6 +1155,9 @@
#define MISC_REG_AEU_GENERAL_ATTN_4 0xa010
#define MISC_REG_AEU_GENERAL_ATTN_5 0xa014
#define MISC_REG_AEU_GENERAL_ATTN_6 0xa018
+#define MISC_REG_AEU_GENERAL_ATTN_7 0xa01c
+#define MISC_REG_AEU_GENERAL_ATTN_8 0xa020
+#define MISC_REG_AEU_GENERAL_ATTN_9 0xa024
/* [RW 32] first 32b for inverting the input for function 0; for each bit:
0= do not invert; 1= invert; mapped as follows: [0] NIG attention for
function0; [1] NIG attention for function1; [2] GPIO1 mcp; [3] GPIO2 mcp;
@@ -1183,6 +1206,40 @@
starts at 0x0 for the A0 tape-out and increments by one for each
all-layer tape-out. */
#define MISC_REG_CHIP_REV 0xa40c
+/* [RW 32] The following driver registers(1..6) represent 6 drivers and 32
+ clients. Each client can be controlled by one driver only. One in each
+ bit represent that this driver control the appropriate client (Ex: bit 5
+ is set means this driver control client number 5). addr1 = set; addr0 =
+ clear; read from both addresses will give the same result = status. write
+ to address 1 will set a request to control all the clients that their
+ appropriate bit (in the write command) is set. if the client is free (the
+ appropriate bit in all the other drivers is clear) one will be written to
+ that driver register; if the client isn't free the bit will remain zero.
+ if the appropriate bit is set (the driver request to gain control on a
+ client it already controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW
+ interrupt will be asserted). write to address 0 will set a request to
+ free all the clients that their appropriate bit (in the write command) is
+ set. if the appropriate bit is clear (the driver request to free a client
+ it doesn't controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW interrupt will
+ be asserted). */
+#define MISC_REG_DRIVER_CONTROL_1 0xa510
+/* [RW 32] GPIO. [31-28] FLOAT port 0; [27-24] FLOAT port 0; When any of
+ these bits is written as a '1'; the corresponding SPIO bit will turn off
+ it's drivers and become an input. This is the reset state of all GPIO
+ pins. The read value of these bits will be a '1' if that last command
+ (#SET; #CLR; or #FLOAT) for this bit was a #FLOAT. (reset value 0xff).
+ [23-20] CLR port 1; 19-16] CLR port 0; When any of these bits is written
+ as a '1'; the corresponding GPIO bit will drive low. The read value of
+ these bits will be a '1' if that last command (#SET; #CLR; or #FLOAT) for
+ this bit was a #CLR. (reset value 0). [15-12] SET port 1; 11-8] port 0;
+ SET When any of these bits is written as a '1'; the corresponding GPIO
+ bit will drive high (if it has that capability). The read value of these
+ bits will be a '1' if that last command (#SET; #CLR; or #FLOAT) for this
+ bit was a #SET. (reset value 0). [7-4] VALUE port 1; [3-0] VALUE port 0;
+ RO; These bits indicate the read value of each of the eight GPIO pins.
+ This is the result value of the pin; not the drive value. Writing these
+ bits will have not effect. */
+#define MISC_REG_GPIO 0xa490
/* [RW 1] Setting this bit enables a timer in the GRC block to timeout any
access that does not finish within
~misc_registers_grc_timout_val.grc_timeout_val cycles. When this bit is
@@ -1223,6 +1280,8 @@
#define MISC_REG_MISC_INT_MASK 0xa388
/* [RW 1] Parity mask register #0 read/write */
#define MISC_REG_MISC_PRTY_MASK 0xa398
+/* [R 1] Parity register #0 read */
+#define MISC_REG_MISC_PRTY_STS 0xa38c
/* [RW 32] 32 LSB of storm PLL first register; reset val = 0x 071d2911.
inside order of the bits is: [0] P1 divider[0] (reset value 1); [1] P1
divider[1] (reset value 0); [2] P1 divider[2] (reset value 0); [3] P1
@@ -1264,6 +1323,55 @@
/* [RW 20] 20 bit GRC address where the scratch-pad of the MCP that is
shared with the driver resides */
#define MISC_REG_SHARED_MEM_ADDR 0xa2b4
+/* [RW 32] SPIO. [31-24] FLOAT When any of these bits is written as a '1';
+ the corresponding SPIO bit will turn off it's drivers and become an
+ input. This is the reset state of all SPIO pins. The read value of these
+ bits will be a '1' if that last command (#SET; #CL; or #FLOAT) for this
+ bit was a #FLOAT. (reset value 0xff). [23-16] CLR When any of these bits
+ is written as a '1'; the corresponding SPIO bit will drive low. The read
+ value of these bits will be a '1' if that last command (#SET; #CLR; or
+#FLOAT) for this bit was a #CLR. (reset value 0). [15-8] SET When any of
+ these bits is written as a '1'; the corresponding SPIO bit will drive
+ high (if it has that capability). The read value of these bits will be a
+ '1' if that last command (#SET; #CLR; or #FLOAT) for this bit was a #SET.
+ (reset value 0). [7-0] VALUE RO; These bits indicate the read value of
+ each of the eight SPIO pins. This is the result value of the pin; not the
+ drive value. Writing these bits will have not effect. Each 8 bits field
+ is divided as follows: [0] VAUX Enable; when pulsed low; enables supply
+ from VAUX. (This is an output pin only; the FLOAT field is not applicable
+ for this pin); [1] VAUX Disable; when pulsed low; disables supply form
+ VAUX. (This is an output pin only; FLOAT field is not applicable for this
+ pin); [2] SEL_VAUX_B - Control to power switching logic. Drive low to
+ select VAUX supply. (This is an output pin only; it is not controlled by
+ the SET and CLR fields; it is controlled by the Main Power SM; the FLOAT
+ field is not applicable for this pin; only the VALUE fields is relevant -
+ it reflects the output value); [3] reserved; [4] spio_4; [5] spio_5; [6]
+ Bit 0 of UMP device ID select; read by UMP firmware; [7] Bit 1 of UMP
+ device ID select; read by UMP firmware. */
+#define MISC_REG_SPIO 0xa4fc
+/* [RW 8] These bits enable the SPIO_INTs to signals event to the IGU/MC.
+ according to the following map: [3:0] reserved; [4] spio_4 [5] spio_5;
+ [7:0] reserved */
+#define MISC_REG_SPIO_EVENT_EN 0xa2b8
+/* [RW 32] SPIO INT. [31-24] OLD_CLR Writing a '1' to these bit clears the
+ corresponding bit in the #OLD_VALUE register. This will acknowledge an
+ interrupt on the falling edge of corresponding SPIO input (reset value
+ 0). [23-16] OLD_SET Writing a '1' to these bit sets the corresponding bit
+ in the #OLD_VALUE register. This will acknowledge an interrupt on the
+ rising edge of corresponding SPIO input (reset value 0). [15-8] OLD_VALUE
+ RO; These bits indicate the old value of the SPIO input value. When the
+ ~INT_STATE bit is set; this bit indicates the OLD value of the pin such
+ that if ~INT_STATE is set and this bit is '0'; then the interrupt is due
+ to a low to high edge. If ~INT_STATE is set and this bit is '1'; then the
+ interrupt is due to a high to low edge (reset value 0). [7-0] INT_STATE
+ RO; These bits indicate the current SPIO interrupt state for each SPIO
+ pin. This bit is cleared when the appropriate #OLD_SET or #OLD_CLR
+ command bit is written. This bit is set when the SPIO input does not
+ match the current value in #OLD_VALUE (reset value 0). */
+#define MISC_REG_SPIO_INT 0xa500
+/* [RW 1] Set by the MCP to remember if one or more of the drivers is/are
+ loaded; 0-prepare; -unprepare */
+#define MISC_REG_UNPREPARED 0xa424
#define NIG_MASK_INTERRUPT_PORT0_REG_MASK_EMAC0_MISC_MI_INT (0x1<<0)
#define NIG_MASK_INTERRUPT_PORT0_REG_MASK_SERDES0_LINK_STATUS (0x1<<9)
#define NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK10G (0x1<<15)
@@ -1392,6 +1500,9 @@
#define NIG_REG_NIG_INGRESS_EMAC0_NO_CRC 0x10044
/* [RW 1] Input enable for RX PBF LP IF */
#define NIG_REG_PBF_LB_IN_EN 0x100b4
+/* [RW 1] Value of this register will be transmitted to port swap when
+ ~nig_registers_strap_override.strap_override =1 */
+#define NIG_REG_PORT_SWAP 0x10394
/* [RW 1] output enable for RX parser descriptor IF */
#define NIG_REG_PRS_EOP_OUT_EN 0x10104
/* [RW 1] Input enable for RX parser request IF */
@@ -1410,6 +1521,10 @@
#define NIG_REG_STAT2_BRB_OCTET 0x107e0
#define NIG_REG_STATUS_INTERRUPT_PORT0 0x10328
#define NIG_REG_STATUS_INTERRUPT_PORT1 0x1032c
+/* [RW 1] port swap mux selection. If this register equal to 0 then port
+ swap is equal to SPIO pin that inputs from ifmux_serdes_swap. If 1 then
+ ort swap is equal to ~nig_registers_port_swap.port_swap */
+#define NIG_REG_STRAP_OVERRIDE 0x10398
/* [RW 1] output enable for RX_XCM0 IF */
#define NIG_REG_XCM0_OUT_EN 0x100f0
/* [RW 1] output enable for RX_XCM1 IF */
@@ -1499,6 +1614,8 @@
#define PB_REG_PB_INT_STS 0x1c
/* [RW 4] Parity mask register #0 read/write */
#define PB_REG_PB_PRTY_MASK 0x38
+/* [R 4] Parity register #0 read */
+#define PB_REG_PB_PRTY_STS 0x2c
#define PRS_REG_A_PRSU_20 0x40134
/* [R 8] debug only: CFC load request current credit. Transaction based. */
#define PRS_REG_CFC_LD_CURRENT_CREDIT 0x40164
@@ -1590,6 +1707,8 @@
#define PRS_REG_PRS_INT_STS 0x40188
/* [RW 8] Parity mask register #0 read/write */
#define PRS_REG_PRS_PRTY_MASK 0x401a4
+/* [R 8] Parity register #0 read */
+#define PRS_REG_PRS_PRTY_STS 0x40198
/* [RW 8] Context region for pure acknowledge packets. Used in CFC load
request message */
#define PRS_REG_PURE_REGIONS 0x40024
@@ -1718,6 +1837,9 @@
/* [RW 32] Parity mask register #0 read/write */
#define PXP2_REG_PXP2_PRTY_MASK_0 0x120588
#define PXP2_REG_PXP2_PRTY_MASK_1 0x120598
+/* [R 32] Parity register #0 read */
+#define PXP2_REG_PXP2_PRTY_STS_0 0x12057c
+#define PXP2_REG_PXP2_PRTY_STS_1 0x12058c
/* [R 1] Debug only: The 'almost full' indication from each fifo (gives
indication about backpressure) */
#define PXP2_REG_RD_ALMOST_FULL_0 0x120424
@@ -1911,6 +2033,8 @@
#define PXP2_REG_RQ_HC_ENDIAN_M 0x1201a8
/* [WB 53] Onchip address table */
#define PXP2_REG_RQ_ONCHIP_AT 0x122000
+/* [RW 13] Pending read limiter threshold; in Dwords */
+#define PXP2_REG_RQ_PDR_LIMIT 0x12033c
/* [RW 2] Endian mode for qm */
#define PXP2_REG_RQ_QM_ENDIAN_M 0x120194
/* [RW 3] page size in L2P table for QM module; -4k; -8k; -16k; -32k; -64k;
@@ -1921,6 +2045,9 @@
/* [RW 3] Max burst size filed for read requests port 0; 000 - 128B;
001:256B; 010: 512B; 11:1K:100:2K; 01:4K */
#define PXP2_REG_RQ_RD_MBS0 0x120160
+/* [RW 3] Max burst size filed for read requests port 1; 000 - 128B;
+ 001:256B; 010: 512B; 11:1K:100:2K; 01:4K */
+#define PXP2_REG_RQ_RD_MBS1 0x120168
/* [RW 2] Endian mode for src */
#define PXP2_REG_RQ_SRC_ENDIAN_M 0x12019c
/* [RW 3] page size in L2P table for SRC module; -4k; -8k; -16k; -32k; -64k;
@@ -2000,10 +2127,17 @@
/* [RW 3] Max burst size filed for write requests port 0; 000 - 128B;
001:256B; 010: 512B; */
#define PXP2_REG_RQ_WR_MBS0 0x12015c
+/* [RW 3] Max burst size filed for write requests port 1; 000 - 128B;
+ 001:256B; 010: 512B; */
+#define PXP2_REG_RQ_WR_MBS1 0x120164
/* [RW 10] if Number of entries in dmae fifo will be higer than this
threshold then has_payload indication will be asserted; the default value
should be equal to &gt; write MBS size! */
#define PXP2_REG_WR_DMAE_TH 0x120368
+/* [RW 10] if Number of entries in usdmdp fifo will be higer than this
+ threshold then has_payload indication will be asserted; the default value
+ should be equal to &gt; write MBS size! */
+#define PXP2_REG_WR_USDMDP_TH 0x120348
/* [R 1] debug only: Indication if PSWHST arbiter is idle */
#define PXP_REG_HST_ARB_IS_IDLE 0x103004
/* [R 8] debug only: A bit mask for all PSWHST arbiter clients. '1' means
@@ -2021,6 +2155,8 @@
#define PXP_REG_PXP_INT_STS_CLR_0 0x10306c
/* [RW 26] Parity mask register #0 read/write */
#define PXP_REG_PXP_PRTY_MASK 0x103094
+/* [R 26] Parity register #0 read */
+#define PXP_REG_PXP_PRTY_STS 0x103088
/* [RW 4] The activity counter initial increment value sent in the load
request */
#define QM_REG_ACTCTRINITVAL_0 0x168040
@@ -2127,6 +2263,8 @@
#define QM_REG_QM_INT_STS 0x168438
/* [RW 9] Parity mask register #0 read/write */
#define QM_REG_QM_PRTY_MASK 0x168454
+/* [R 9] Parity register #0 read */
+#define QM_REG_QM_PRTY_STS 0x168448
/* [R 32] Current queues in pipeline: Queues from 32 to 63 */
#define QM_REG_QSTATUS_HIGH 0x16802c
/* [R 32] Current queues in pipeline: Queues from 0 to 31 */
@@ -2410,6 +2548,8 @@
#define SRC_REG_SRC_INT_STS 0x404ac
/* [RW 3] Parity mask register #0 read/write */
#define SRC_REG_SRC_PRTY_MASK 0x404c8
+/* [R 3] Parity register #0 read */
+#define SRC_REG_SRC_PRTY_STS 0x404bc
/* [R 4] Used to read the value of the XX protection CAM occupancy counter. */
#define TCM_REG_CAM_OCCUP 0x5017c
/* [RW 1] CDU AG read Interface enable. If 0 - the request input is
@@ -2730,6 +2870,8 @@
#define TSDM_REG_TSDM_INT_MASK_1 0x422ac
/* [RW 11] Parity mask register #0 read/write */
#define TSDM_REG_TSDM_PRTY_MASK 0x422bc
+/* [R 11] Parity register #0 read */
+#define TSDM_REG_TSDM_PRTY_STS 0x422b0
/* [RW 5] The number of time_slots in the arbitration cycle */
#define TSEM_REG_ARB_CYCLE_SIZE 0x180034
/* [RW 3] The source that is associated with arbitration element 0. Source
@@ -2854,6 +2996,9 @@
/* [RW 32] Parity mask register #0 read/write */
#define TSEM_REG_TSEM_PRTY_MASK_0 0x180120
#define TSEM_REG_TSEM_PRTY_MASK_1 0x180130
+/* [R 32] Parity register #0 read */
+#define TSEM_REG_TSEM_PRTY_STS_0 0x180114
+#define TSEM_REG_TSEM_PRTY_STS_1 0x180124
/* [R 5] Used to read the XX protection CAM occupancy counter. */
#define UCM_REG_CAM_OCCUP 0xe0170
/* [RW 1] CDU AG read Interface enable. If 0 - the request input is
@@ -3155,6 +3300,8 @@
#define USDM_REG_USDM_INT_MASK_1 0xc42b0
/* [RW 11] Parity mask register #0 read/write */
#define USDM_REG_USDM_PRTY_MASK 0xc42c0
+/* [R 11] Parity register #0 read */
+#define USDM_REG_USDM_PRTY_STS 0xc42b4
/* [RW 5] The number of time_slots in the arbitration cycle */
#define USEM_REG_ARB_CYCLE_SIZE 0x300034
/* [RW 3] The source that is associated with arbitration element 0. Source
@@ -3279,6 +3426,9 @@
/* [RW 32] Parity mask register #0 read/write */
#define USEM_REG_USEM_PRTY_MASK_0 0x300130
#define USEM_REG_USEM_PRTY_MASK_1 0x300140
+/* [R 32] Parity register #0 read */
+#define USEM_REG_USEM_PRTY_STS_0 0x300124
+#define USEM_REG_USEM_PRTY_STS_1 0x300134
/* [RW 2] The queue index for registration on Aux1 counter flag. */
#define XCM_REG_AUX1_Q 0x20134
/* [RW 2] Per each decision rule the queue index to register to. */
@@ -3684,6 +3834,8 @@
#define XSDM_REG_XSDM_INT_MASK_1 0x1662ac
/* [RW 11] Parity mask register #0 read/write */
#define XSDM_REG_XSDM_PRTY_MASK 0x1662bc
+/* [R 11] Parity register #0 read */
+#define XSDM_REG_XSDM_PRTY_STS 0x1662b0
/* [RW 5] The number of time_slots in the arbitration cycle */
#define XSEM_REG_ARB_CYCLE_SIZE 0x280034
/* [RW 3] The source that is associated with arbitration element 0. Source
@@ -3808,6 +3960,9 @@
/* [RW 32] Parity mask register #0 read/write */
#define XSEM_REG_XSEM_PRTY_MASK_0 0x280130
#define XSEM_REG_XSEM_PRTY_MASK_1 0x280140
+/* [R 32] Parity register #0 read */
+#define XSEM_REG_XSEM_PRTY_STS_0 0x280124
+#define XSEM_REG_XSEM_PRTY_STS_1 0x280134
#define MCPR_NVM_ACCESS_ENABLE_EN (1L<<0)
#define MCPR_NVM_ACCESS_ENABLE_WR_EN (1L<<1)
#define MCPR_NVM_ADDR_NVM_ADDR_VALUE (0xffffffL<<0)
@@ -3847,6 +4002,8 @@
#define EMAC_MDIO_COMM_START_BUSY (1L<<29)
#define EMAC_MDIO_MODE_AUTO_POLL (1L<<4)
#define EMAC_MDIO_MODE_CLAUSE_45 (1L<<31)
+#define EMAC_MDIO_MODE_CLOCK_CNT (0x3fL<<16)
+#define EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT 16
#define EMAC_MODE_25G_MODE (1L<<5)
#define EMAC_MODE_ACPI_RCVD (1L<<20)
#define EMAC_MODE_HALF_DUPLEX (1L<<1)
@@ -3874,6 +4031,17 @@
#define EMAC_RX_MTU_SIZE_JUMBO_ENA (1L<<31)
#define EMAC_TX_MODE_EXT_PAUSE_EN (1L<<3)
#define EMAC_TX_MODE_RESET (1L<<0)
+#define MISC_REGISTERS_GPIO_1 1
+#define MISC_REGISTERS_GPIO_2 2
+#define MISC_REGISTERS_GPIO_3 3
+#define MISC_REGISTERS_GPIO_CLR_POS 16
+#define MISC_REGISTERS_GPIO_FLOAT (0xffL<<24)
+#define MISC_REGISTERS_GPIO_FLOAT_POS 24
+#define MISC_REGISTERS_GPIO_INPUT_HI_Z 2
+#define MISC_REGISTERS_GPIO_OUTPUT_HIGH 1
+#define MISC_REGISTERS_GPIO_OUTPUT_LOW 0
+#define MISC_REGISTERS_GPIO_PORT_SHIFT 4
+#define MISC_REGISTERS_GPIO_SET_POS 8
#define MISC_REGISTERS_RESET_REG_1_CLEAR 0x588
#define MISC_REGISTERS_RESET_REG_1_SET 0x584
#define MISC_REGISTERS_RESET_REG_2_CLEAR 0x598
@@ -3891,6 +4059,25 @@
#define MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_RSTB_HW (0x1<<4)
#define MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_TXD_FIFO_RSTB (0x1<<8)
#define MISC_REGISTERS_RESET_REG_3_SET 0x5a4
+#define MISC_REGISTERS_SPIO_4 4
+#define MISC_REGISTERS_SPIO_5 5
+#define MISC_REGISTERS_SPIO_7 7
+#define MISC_REGISTERS_SPIO_CLR_POS 16
+#define MISC_REGISTERS_SPIO_FLOAT (0xffL<<24)
+#define GRC_MISC_REGISTERS_SPIO_FLOAT7 0x80000000
+#define GRC_MISC_REGISTERS_SPIO_FLOAT6 0x40000000
+#define GRC_MISC_REGISTERS_SPIO_FLOAT5 0x20000000
+#define GRC_MISC_REGISTERS_SPIO_FLOAT4 0x10000000
+#define MISC_REGISTERS_SPIO_FLOAT_POS 24
+#define MISC_REGISTERS_SPIO_INPUT_HI_Z 2
+#define MISC_REGISTERS_SPIO_INT_OLD_SET_POS 16
+#define MISC_REGISTERS_SPIO_OUTPUT_HIGH 1
+#define MISC_REGISTERS_SPIO_OUTPUT_LOW 0
+#define MISC_REGISTERS_SPIO_SET_POS 8
+#define HW_LOCK_MAX_RESOURCE_VALUE 31
+#define HW_LOCK_RESOURCE_8072_MDIO 0
+#define HW_LOCK_RESOURCE_GPIO 1
+#define HW_LOCK_RESOURCE_SPIO 2
#define AEU_INPUTS_ATTN_BITS_BRB_PARITY_ERROR (1<<18)
#define AEU_INPUTS_ATTN_BITS_CCM_HW_INTERRUPT (1<<31)
#define AEU_INPUTS_ATTN_BITS_CDU_HW_INTERRUPT (1<<9)
@@ -3918,6 +4105,7 @@
#define AEU_INPUTS_ATTN_BITS_QM_HW_INTERRUPT (1<<3)
#define AEU_INPUTS_ATTN_BITS_QM_PARITY_ERROR (1<<2)
#define AEU_INPUTS_ATTN_BITS_SEARCHER_PARITY_ERROR (1<<22)
+#define AEU_INPUTS_ATTN_BITS_SPIO5 (1<<15)
#define AEU_INPUTS_ATTN_BITS_TCM_HW_INTERRUPT (1<<27)
#define AEU_INPUTS_ATTN_BITS_TIMERS_HW_INTERRUPT (1<<5)
#define AEU_INPUTS_ATTN_BITS_TSDM_HW_INTERRUPT (1<<25)
@@ -4206,6 +4394,9 @@
#define MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE 0x4000
#define MDIO_XGXS_BLOCK2_TX_LN_SWAP 0x11
#define MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE 0x8000
+#define MDIO_XGXS_BLOCK2_UNICORE_MODE_10G 0x14
+#define MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_CX4_XGXS 0x0001
+#define MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_HIGIG_XGXS 0x0010
#define MDIO_XGXS_BLOCK2_TEST_MODE_LANE 0x15
#define MDIO_REG_BANK_GP_STATUS 0x8120
@@ -4362,11 +4553,13 @@
#define MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1_SGMII_MODE 0x0001
+#define EXT_PHY_AUTO_NEG_DEVAD 0x7
#define EXT_PHY_OPT_PMA_PMD_DEVAD 0x1
#define EXT_PHY_OPT_WIS_DEVAD 0x2
#define EXT_PHY_OPT_PCS_DEVAD 0x3
#define EXT_PHY_OPT_PHY_XS_DEVAD 0x4
#define EXT_PHY_OPT_CNTL 0x0
+#define EXT_PHY_OPT_CNTL2 0x7
#define EXT_PHY_OPT_PMD_RX_SD 0xa
#define EXT_PHY_OPT_PMD_MISC_CNTL 0xca0a
#define EXT_PHY_OPT_PHY_IDENTIFIER 0xc800
@@ -4378,11 +4571,24 @@
#define EXT_PHY_OPT_LASI_STATUS 0x9005
#define EXT_PHY_OPT_PCS_STATUS 0x0020
#define EXT_PHY_OPT_XGXS_LANE_STATUS 0x0018
+#define EXT_PHY_OPT_AN_LINK_STATUS 0x8304
+#define EXT_PHY_OPT_AN_CL37_CL73 0x8370
+#define EXT_PHY_OPT_AN_CL37_FD 0xffe4
+#define EXT_PHY_OPT_AN_CL37_AN 0xffe0
+#define EXT_PHY_OPT_AN_ADV 0x11
#define EXT_PHY_KR_PMA_PMD_DEVAD 0x1
#define EXT_PHY_KR_PCS_DEVAD 0x3
#define EXT_PHY_KR_AUTO_NEG_DEVAD 0x7
#define EXT_PHY_KR_CTRL 0x0000
+#define EXT_PHY_KR_STATUS 0x0001
+#define EXT_PHY_KR_AUTO_NEG_COMPLETE 0x0020
+#define EXT_PHY_KR_AUTO_NEG_ADVERT 0x0010
+#define EXT_PHY_KR_AUTO_NEG_ADVERT_PAUSE 0x0400
+#define EXT_PHY_KR_AUTO_NEG_ADVERT_PAUSE_ASYMMETRIC 0x0800
+#define EXT_PHY_KR_AUTO_NEG_ADVERT_PAUSE_BOTH 0x0C00
+#define EXT_PHY_KR_AUTO_NEG_ADVERT_PAUSE_MASK 0x0C00
+#define EXT_PHY_KR_LP_AUTO_NEG 0x0013
#define EXT_PHY_KR_CTRL2 0x0007
#define EXT_PHY_KR_PCS_STATUS 0x0020
#define EXT_PHY_KR_PMD_CTRL 0x0096
@@ -4391,4 +4597,8 @@
#define EXT_PHY_KR_MISC_CTRL1 0xca85
#define EXT_PHY_KR_GEN_CTRL 0xca10
#define EXT_PHY_KR_ROM_CODE 0xca19
+#define EXT_PHY_KR_ROM_RESET_INTERNAL_MP 0x0188
+#define EXT_PHY_KR_ROM_MICRO_RESET 0x018a
+
+#define EXT_PHY_SFX7101_XGXS_TEST1 0xc00a
diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c
index 57175097513..348371fda59 100644
--- a/drivers/net/cs89x0.c
+++ b/drivers/net/cs89x0.c
@@ -172,30 +172,30 @@ static char version[] __initdata =
them to system IRQ numbers. This mapping is card specific and is set to
the configuration of the Cirrus Eval board for this chip. */
#ifdef CONFIG_ARCH_CLPS7500
-static unsigned int netcard_portlist[] __initdata =
+static unsigned int netcard_portlist[] __used __initdata =
{ 0x80090303, 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0};
static unsigned int cs8900_irq_map[] = {12,0,0,0};
#elif defined(CONFIG_SH_HICOSH4)
-static unsigned int netcard_portlist[] __initdata =
+static unsigned int netcard_portlist[] __used __initdata =
{ 0x0300, 0};
static unsigned int cs8900_irq_map[] = {1,0,0,0};
#elif defined(CONFIG_MACH_IXDP2351)
-static unsigned int netcard_portlist[] __initdata = {IXDP2351_VIRT_CS8900_BASE, 0};
+static unsigned int netcard_portlist[] __used __initdata = {IXDP2351_VIRT_CS8900_BASE, 0};
static unsigned int cs8900_irq_map[] = {IRQ_IXDP2351_CS8900, 0, 0, 0};
#include <asm/irq.h>
#elif defined(CONFIG_ARCH_IXDP2X01)
#include <asm/irq.h>
-static unsigned int netcard_portlist[] __initdata = {IXDP2X01_CS8900_VIRT_BASE, 0};
+static unsigned int netcard_portlist[] __used __initdata = {IXDP2X01_CS8900_VIRT_BASE, 0};
static unsigned int cs8900_irq_map[] = {IRQ_IXDP2X01_CS8900, 0, 0, 0};
#elif defined(CONFIG_ARCH_PNX010X)
#include <asm/irq.h>
#include <asm/arch/gpio.h>
#define CIRRUS_DEFAULT_BASE IO_ADDRESS(EXT_STATIC2_s0_BASE + 0x200000) /* = Physical address 0x48200000 */
#define CIRRUS_DEFAULT_IRQ VH_INTC_INT_NUM_CASCADED_INTERRUPT_1 /* Event inputs bank 1 - ID 35/bit 3 */
-static unsigned int netcard_portlist[] __initdata = {CIRRUS_DEFAULT_BASE, 0};
+static unsigned int netcard_portlist[] __used __initdata = {CIRRUS_DEFAULT_BASE, 0};
static unsigned int cs8900_irq_map[] = {CIRRUS_DEFAULT_IRQ, 0, 0, 0};
#else
-static unsigned int netcard_portlist[] __initdata =
+static unsigned int netcard_portlist[] __used __initdata =
{ 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0};
static unsigned int cs8900_irq_map[] = {10,11,12,5};
#endif
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index d876787ce33..85e66f4c788 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -50,7 +50,7 @@ struct e1000_stats {
int stat_offset;
};
-#define E1000_STAT(m) sizeof(((struct e1000_adapter *)0)->m), \
+#define E1000_STAT(m) FIELD_SIZEOF(struct e1000_adapter, m), \
offsetof(struct e1000_adapter, m)
static const struct e1000_stats e1000_gstrings_stats[] = {
{ "rx_packets", E1000_STAT(stats.gprc) },
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index d4ee8ec34b5..0991648c53d 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -1195,6 +1195,14 @@ e1000_probe(struct pci_dev *pdev,
printk("%s\n", print_mac(mac, netdev->dev_addr));
+ if (adapter->hw.bus_type == e1000_bus_type_pci_express) {
+ DPRINTK(PROBE, WARNING, "This device (id %04x:%04x) will no "
+ "longer be supported by this driver in the future.\n",
+ pdev->vendor, pdev->device);
+ DPRINTK(PROBE, WARNING, "please use the \"e1000e\" "
+ "driver instead.\n");
+ }
+
/* reset the hardware with the new settings */
e1000_reset(adapter);
diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c
index 3beace55b58..7fe20310eb5 100644
--- a/drivers/net/e1000e/82571.c
+++ b/drivers/net/e1000e/82571.c
@@ -438,7 +438,7 @@ static void e1000_release_nvm_82571(struct e1000_hw *hw)
* For non-82573 silicon, write data to EEPROM at offset using SPI interface.
*
* If e1000e_update_nvm_checksum is not called after this function, the
- * EEPROM will most likley contain an invalid checksum.
+ * EEPROM will most likely contain an invalid checksum.
**/
static s32 e1000_write_nvm_82571(struct e1000_hw *hw, u16 offset, u16 words,
u16 *data)
@@ -547,7 +547,7 @@ static s32 e1000_validate_nvm_checksum_82571(struct e1000_hw *hw)
* poll for completion.
*
* If e1000e_update_nvm_checksum is not called after this function, the
- * EEPROM will most likley contain an invalid checksum.
+ * EEPROM will most likely contain an invalid checksum.
**/
static s32 e1000_write_nvm_eewr_82571(struct e1000_hw *hw, u16 offset,
u16 words, u16 *data)
@@ -1053,7 +1053,7 @@ static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw)
/* If SerDes loopback mode is entered, there is no form
* of reset to take the adapter out of that mode. So we
* have to explicitly take the adapter out of loopback
- * mode. This prevents drivers from twidling their thumbs
+ * mode. This prevents drivers from twiddling their thumbs
* if another tool failed to take it out of loopback mode.
*/
ew32(SCTL,
@@ -1098,7 +1098,7 @@ static s32 e1000_valid_led_default_82571(struct e1000_hw *hw, u16 *data)
* e1000e_get_laa_state_82571 - Get locally administered address state
* @hw: pointer to the HW structure
*
- * Retrieve and return the current locally administed address state.
+ * Retrieve and return the current locally administered address state.
**/
bool e1000e_get_laa_state_82571(struct e1000_hw *hw)
{
@@ -1113,7 +1113,7 @@ bool e1000e_get_laa_state_82571(struct e1000_hw *hw)
* @hw: pointer to the HW structure
* @state: enable/disable locally administered address
*
- * Enable/Disable the current locally administed address state.
+ * Enable/Disable the current locally administers address state.
**/
void e1000e_set_laa_state_82571(struct e1000_hw *hw, bool state)
{
@@ -1281,16 +1281,6 @@ static struct e1000_phy_operations e82_phy_ops_m88 = {
static struct e1000_nvm_operations e82571_nvm_ops = {
.acquire_nvm = e1000_acquire_nvm_82571,
- .read_nvm = e1000e_read_nvm_spi,
- .release_nvm = e1000_release_nvm_82571,
- .update_nvm = e1000_update_nvm_checksum_82571,
- .valid_led_default = e1000_valid_led_default_82571,
- .validate_nvm = e1000_validate_nvm_checksum_82571,
- .write_nvm = e1000_write_nvm_82571,
-};
-
-static struct e1000_nvm_operations e82573_nvm_ops = {
- .acquire_nvm = e1000_acquire_nvm_82571,
.read_nvm = e1000e_read_nvm_eerd,
.release_nvm = e1000_release_nvm_82571,
.update_nvm = e1000_update_nvm_checksum_82571,
@@ -1355,6 +1345,6 @@ struct e1000_info e1000_82573_info = {
.get_invariants = e1000_get_invariants_82571,
.mac_ops = &e82571_mac_ops,
.phy_ops = &e82_phy_ops_m88,
- .nvm_ops = &e82573_nvm_ops,
+ .nvm_ops = &e82571_nvm_ops,
};
diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h
index 6232c3e9668..a4f511f549f 100644
--- a/drivers/net/e1000e/defines.h
+++ b/drivers/net/e1000e/defines.h
@@ -66,7 +66,7 @@
#define E1000_WUFC_ARP 0x00000020 /* ARP Request Packet Wakeup Enable */
/* Extended Device Control */
-#define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Defineable Pin 7 */
+#define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Definable Pin 7 */
#define E1000_CTRL_EXT_EE_RST 0x00002000 /* Reinitialize from EEPROM */
#define E1000_CTRL_EXT_RO_DIS 0x00020000 /* Relaxed Ordering disable */
#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000
@@ -75,12 +75,12 @@
#define E1000_CTRL_EXT_IAME 0x08000000 /* Interrupt acknowledge Auto-mask */
#define E1000_CTRL_EXT_INT_TIMER_CLR 0x20000000 /* Clear Interrupt timers after IMS clear */
-/* Receive Decriptor bit definitions */
+/* Receive Descriptor bit definitions */
#define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */
#define E1000_RXD_STAT_EOP 0x02 /* End of Packet */
#define E1000_RXD_STAT_IXSM 0x04 /* Ignore checksum */
#define E1000_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */
-#define E1000_RXD_STAT_UDPCS 0x10 /* UDP xsum caculated */
+#define E1000_RXD_STAT_UDPCS 0x10 /* UDP xsum calculated */
#define E1000_RXD_STAT_TCPCS 0x20 /* TCP xsum calculated */
#define E1000_RXD_ERR_CE 0x01 /* CRC Error */
#define E1000_RXD_ERR_SE 0x02 /* Symbol Error */
@@ -223,7 +223,7 @@
#define E1000_STATUS_LAN_INIT_DONE 0x00000200 /* Lan Init Completion by NVM */
#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Status of Master requests. */
-/* Constants used to intrepret the masked PCI-X bus speed. */
+/* Constants used to interpret the masked PCI-X bus speed. */
#define HALF_DUPLEX 1
#define FULL_DUPLEX 2
@@ -517,7 +517,7 @@
/* PHY 1000 MII Register/Bit Definitions */
/* PHY Registers defined by IEEE */
#define PHY_CONTROL 0x00 /* Control Register */
-#define PHY_STATUS 0x01 /* Status Regiser */
+#define PHY_STATUS 0x01 /* Status Register */
#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */
#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */
#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */
diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h
index 8b88c226e85..327c0620da3 100644
--- a/drivers/net/e1000e/e1000.h
+++ b/drivers/net/e1000e/e1000.h
@@ -42,8 +42,7 @@
struct e1000_info;
#define ndev_printk(level, netdev, format, arg...) \
- printk(level "%s: %s: " format, (netdev)->dev.parent->bus_id, \
- (netdev)->name, ## arg)
+ printk(level "%s: " format, (netdev)->name, ## arg)
#ifdef DEBUG
#define ndev_dbg(netdev, format, arg...) \
diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h
index 3c5862f97db..916025b30fc 100644
--- a/drivers/net/e1000e/hw.h
+++ b/drivers/net/e1000e/hw.h
@@ -184,7 +184,7 @@ enum e1e_registers {
E1000_ICRXDMTC = 0x04120, /* Irq Cause Rx Desc MinThreshold Count */
E1000_ICRXOC = 0x04124, /* Irq Cause Receiver Overrun Count */
E1000_RXCSUM = 0x05000, /* RX Checksum Control - RW */
- E1000_RFCTL = 0x05008, /* Receive Filter Control*/
+ E1000_RFCTL = 0x05008, /* Receive Filter Control */
E1000_MTA = 0x05200, /* Multicast Table Array - RW Array */
E1000_RA = 0x05400, /* Receive Address - RW Array */
E1000_VFTA = 0x05600, /* VLAN Filter Table Array - RW Array */
@@ -202,7 +202,7 @@ enum e1e_registers {
E1000_FACTPS = 0x05B30, /* Function Active and Power State to MNG */
E1000_SWSM = 0x05B50, /* SW Semaphore */
E1000_FWSM = 0x05B54, /* FW Semaphore */
- E1000_HICR = 0x08F00, /* Host Inteface Control */
+ E1000_HICR = 0x08F00, /* Host Interface Control */
};
/* RSS registers */
diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c
index 8f8139de1f4..0ae39550768 100644
--- a/drivers/net/e1000e/ich8lan.c
+++ b/drivers/net/e1000e/ich8lan.c
@@ -671,7 +671,7 @@ static s32 e1000_get_phy_info_ich8lan(struct e1000_hw *hw)
* e1000_check_polarity_ife_ich8lan - Check cable polarity for IFE PHY
* @hw: pointer to the HW structure
*
- * Polarity is determined on the polarity reveral feature being enabled.
+ * Polarity is determined on the polarity reversal feature being enabled.
* This function is only called by other family-specific
* routines.
**/
@@ -947,7 +947,7 @@ static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw)
/* Either we should have a hardware SPI cycle in progress
* bit to check against, in order to start a new cycle or
* FDONE bit should be changed in the hardware so that it
- * is 1 after harware reset, which can then be used as an
+ * is 1 after hardware reset, which can then be used as an
* indication whether a cycle is in progress or has been
* completed.
*/
@@ -1155,7 +1155,7 @@ static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
* which writes the checksum to the shadow ram. The changes in the shadow
* ram are then committed to the EEPROM by processing each bank at a time
* checking for the modified bit and writing only the pending changes.
- * After a succesful commit, the shadow ram is cleared and is ready for
+ * After a successful commit, the shadow ram is cleared and is ready for
* future writes.
**/
static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
@@ -1680,7 +1680,7 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
* - initialize LED identification
* - setup receive address registers
* - setup flow control
- * - setup transmit discriptors
+ * - setup transmit descriptors
* - clear statistics
**/
static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw)
@@ -1961,7 +1961,7 @@ static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw)
E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
ew32(PHY_CTRL, phy_ctrl);
- /* Call gig speed drop workaround on Giga disable before accessing
+ /* Call gig speed drop workaround on Gig disable before accessing
* any PHY registers */
e1000e_gig_downshift_workaround_ich8lan(hw);
@@ -1972,7 +1972,7 @@ static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw)
/**
* e1000_set_kmrn_lock_loss_workaound_ich8lan - Set Kumeran workaround state
* @hw: pointer to the HW structure
- * @state: boolean value used to set the current Kumaran workaround state
+ * @state: boolean value used to set the current Kumeran workaround state
*
* If ICH8, set the current Kumeran workaround state (enabled - TRUE
* /disabled - FALSE).
@@ -2017,7 +2017,7 @@ void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw)
E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
ew32(PHY_CTRL, reg);
- /* Call gig speed drop workaround on Giga disable before
+ /* Call gig speed drop workaround on Gig disable before
* accessing any PHY registers */
if (hw->mac.type == e1000_ich8lan)
e1000e_gig_downshift_workaround_ich8lan(hw);
@@ -2045,7 +2045,7 @@ void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw)
* @hw: pointer to the HW structure
*
* Steps to take when dropping from 1Gb/s (eg. link cable removal (LSC),
- * LPLU, Giga disable, MDIC PHY reset):
+ * LPLU, Gig disable, MDIC PHY reset):
* 1) Set Kumeran Near-end loopback
* 2) Clear Kumeran Near-end loopback
* Should only be called for ICH8[m] devices with IGP_3 Phy.
@@ -2089,10 +2089,10 @@ static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw)
}
/**
- * e1000_led_on_ich8lan - Turn LED's on
+ * e1000_led_on_ich8lan - Turn LEDs on
* @hw: pointer to the HW structure
*
- * Turn on the LED's.
+ * Turn on the LEDs.
**/
static s32 e1000_led_on_ich8lan(struct e1000_hw *hw)
{
@@ -2105,10 +2105,10 @@ static s32 e1000_led_on_ich8lan(struct e1000_hw *hw)
}
/**
- * e1000_led_off_ich8lan - Turn LED's off
+ * e1000_led_off_ich8lan - Turn LEDs off
* @hw: pointer to the HW structure
*
- * Turn off the LED's.
+ * Turn off the LEDs.
**/
static s32 e1000_led_off_ich8lan(struct e1000_hw *hw)
{
diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c
index 16f35fadb74..95f75a43c9f 100644
--- a/drivers/net/e1000e/lib.c
+++ b/drivers/net/e1000e/lib.c
@@ -589,9 +589,6 @@ static s32 e1000_set_default_fc_generic(struct e1000_hw *hw)
s32 ret_val;
u16 nvm_data;
- if (mac->fc != e1000_fc_default)
- return 0;
-
/* Read and store word 0x0F of the EEPROM. This word contains bits
* that determine the hardware's default PAUSE (flow control) mode,
* a bit that determines whether the HW defaults to enabling or
@@ -1107,34 +1104,13 @@ s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw)
(mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
mac->fc = e1000_fc_rx_pause;
hw_dbg(hw, "Flow Control = RX PAUSE frames only.\r\n");
- }
- /* Per the IEEE spec, at this point flow control should be
- * disabled. However, we want to consider that we could
- * be connected to a legacy switch that doesn't advertise
- * desired flow control, but can be forced on the link
- * partner. So if we advertised no flow control, that is
- * what we will resolve to. If we advertised some kind of
- * receive capability (Rx Pause Only or Full Flow Control)
- * and the link partner advertised none, we will configure
- * ourselves to enable Rx Flow Control only. We can do
- * this safely for two reasons: If the link partner really
- * didn't want flow control enabled, and we enable Rx, no
- * harm done since we won't be receiving any PAUSE frames
- * anyway. If the intent on the link partner was to have
- * flow control enabled, then by us enabling RX only, we
- * can at least receive pause frames and process them.
- * This is a good idea because in most cases, since we are
- * predominantly a server NIC, more times than not we will
- * be asked to delay transmission of packets than asking
- * our link partner to pause transmission of frames.
- */
- else if ((mac->original_fc == e1000_fc_none) ||
- (mac->original_fc == e1000_fc_tx_pause)) {
+ } else {
+ /*
+ * Per the IEEE spec, at this point flow control
+ * should be disabled.
+ */
mac->fc = e1000_fc_none;
hw_dbg(hw, "Flow Control = NONE.\r\n");
- } else {
- mac->fc = e1000_fc_rx_pause;
- hw_dbg(hw, "Flow Control = RX PAUSE frames only.\r\n");
}
/* Now we need to do one last check... If we auto-
@@ -1164,7 +1140,7 @@ s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw)
}
/**
- * e1000e_get_speed_and_duplex_copper - Retreive current speed/duplex
+ * e1000e_get_speed_and_duplex_copper - Retrieve current speed/duplex
* @hw: pointer to the HW structure
* @speed: stores the current speed
* @duplex: stores the current duplex
@@ -1200,7 +1176,7 @@ s32 e1000e_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed, u16 *dup
}
/**
- * e1000e_get_speed_and_duplex_fiber_serdes - Retreive current speed/duplex
+ * e1000e_get_speed_and_duplex_fiber_serdes - Retrieve current speed/duplex
* @hw: pointer to the HW structure
* @speed: stores the current speed
* @duplex: stores the current duplex
@@ -1410,7 +1386,7 @@ s32 e1000e_cleanup_led_generic(struct e1000_hw *hw)
* e1000e_blink_led - Blink LED
* @hw: pointer to the HW structure
*
- * Blink the led's which are set to be on.
+ * Blink the LEDs which are set to be on.
**/
s32 e1000e_blink_led(struct e1000_hw *hw)
{
@@ -1515,7 +1491,7 @@ void e1000e_set_pcie_no_snoop(struct e1000_hw *hw, u32 no_snoop)
* @hw: pointer to the HW structure
*
* Returns 0 if successful, else returns -10
- * (-E1000_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not casued
+ * (-E1000_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not caused
* the master requests to be disabled.
*
* Disables PCI-Express master access and verifies there are no pending
@@ -1876,7 +1852,7 @@ static s32 e1000_ready_nvm_eeprom(struct e1000_hw *hw)
}
/**
- * e1000e_read_nvm_spi - Read EEPROM's using SPI
+ * e1000e_read_nvm_spi - Reads EEPROM using SPI
* @hw: pointer to the HW structure
* @offset: offset of word in the EEPROM to read
* @words: number of words to read
@@ -1980,7 +1956,7 @@ s32 e1000e_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
* Writes data to EEPROM at offset using SPI interface.
*
* If e1000e_update_nvm_checksum is not called after this function , the
- * EEPROM will most likley contain an invalid checksum.
+ * EEPROM will most likely contain an invalid checksum.
**/
s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
{
@@ -2222,7 +2198,7 @@ static u8 e1000_calculate_checksum(u8 *buffer, u32 length)
*
* Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND
*
- * This function checks whether the HOST IF is enabled for command operaton
+ * This function checks whether the HOST IF is enabled for command operation
* and also checks whether the previous command is completed. It busy waits
* in case of previous command is not completed.
**/
@@ -2254,7 +2230,7 @@ static s32 e1000_mng_enable_host_if(struct e1000_hw *hw)
}
/**
- * e1000e_check_mng_mode - check managament mode
+ * e1000e_check_mng_mode - check management mode
* @hw: pointer to the HW structure
*
* Reads the firmware semaphore register and returns true (>0) if
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index f58f017ee47..fc5c63f4f57 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -1006,7 +1006,7 @@ static void e1000_irq_enable(struct e1000_adapter *adapter)
* e1000_get_hw_control - get control of the h/w from f/w
* @adapter: address of board private structure
*
- * e1000_get_hw_control sets {CTRL_EXT|FWSM}:DRV_LOAD bit.
+ * e1000_get_hw_control sets {CTRL_EXT|SWSM}:DRV_LOAD bit.
* For ASF and Pass Through versions of f/w this means that
* the driver is loaded. For AMT version (only with 82573)
* of the f/w this means that the network i/f is open.
@@ -1032,7 +1032,7 @@ static void e1000_get_hw_control(struct e1000_adapter *adapter)
* e1000_release_hw_control - release control of the h/w to f/w
* @adapter: address of board private structure
*
- * e1000_release_hw_control resets {CTRL_EXT|FWSM}:DRV_LOAD bit.
+ * e1000_release_hw_control resets {CTRL_EXT|SWSM}:DRV_LOAD bit.
* For ASF and Pass Through versions of f/w this means that the
* driver is no longer loaded. For AMT version (only with 82573) i
* of the f/w this means that the network i/f is closed.
@@ -1055,23 +1055,6 @@ static void e1000_release_hw_control(struct e1000_adapter *adapter)
}
}
-static void e1000_release_manageability(struct e1000_adapter *adapter)
-{
- if (adapter->flags & FLAG_MNG_PT_ENABLED) {
- struct e1000_hw *hw = &adapter->hw;
-
- u32 manc = er32(MANC);
-
- /* re-enable hardware interception of ARP */
- manc |= E1000_MANC_ARP_EN;
- manc &= ~E1000_MANC_EN_MNG2HOST;
-
- /* don't explicitly have to mess with MANC2H since
- * MANC has an enable disable that gates MANC2H */
- ew32(MANC, manc);
- }
-}
-
/**
* @e1000_alloc_ring - allocate memory for a ring structure
**/
@@ -1258,6 +1241,11 @@ void e1000e_free_rx_resources(struct e1000_adapter *adapter)
/**
* e1000_update_itr - update the dynamic ITR value based on statistics
+ * @adapter: pointer to adapter
+ * @itr_setting: current adapter->itr
+ * @packets: the number of packets during this measurement interval
+ * @bytes: the number of bytes during this measurement interval
+ *
* Stores a new ITR value based on packets and byte
* counts during the last interrupt. The advantage of per interrupt
* computation is faster updates and more accurate ITR for the current
@@ -1267,10 +1255,6 @@ void e1000e_free_rx_resources(struct e1000_adapter *adapter)
* while increasing bulk throughput.
* this functionality is controlled by the InterruptThrottleRate module
* parameter (see e1000_param.c)
- * @adapter: pointer to adapter
- * @itr_setting: current adapter->itr
- * @packets: the number of packets during this measurement interval
- * @bytes: the number of bytes during this measurement interval
**/
static unsigned int e1000_update_itr(struct e1000_adapter *adapter,
u16 itr_setting, int packets,
@@ -1383,6 +1367,7 @@ set_itr_now:
/**
* e1000_clean - NAPI Rx polling callback
* @adapter: board private structure
+ * @budget: amount of packets driver is allowed to process this poll
**/
static int e1000_clean(struct napi_struct *napi, int budget)
{
@@ -1561,9 +1546,6 @@ static void e1000_init_manageability(struct e1000_adapter *adapter)
manc = er32(MANC);
- /* disable hardware interception of ARP */
- manc &= ~(E1000_MANC_ARP_EN);
-
/* enable receiving management packets to the host. this will probably
* generate destination unreachable messages from the host OS, but
* the packets will be handled on SMBUS */
@@ -1690,6 +1672,9 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter)
else
rctl |= E1000_RCTL_LPE;
+ /* Enable hardware CRC frame stripping */
+ rctl |= E1000_RCTL_SECRC;
+
/* Setup buffer sizes */
rctl &= ~E1000_RCTL_SZ_4096;
rctl |= E1000_RCTL_BSEX;
@@ -1755,9 +1740,6 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter)
/* Enable Packet split descriptors */
rctl |= E1000_RCTL_DTYP_PS;
-
- /* Enable hardware CRC frame stripping */
- rctl |= E1000_RCTL_SECRC;
psrctl |= adapter->rx_ps_bsize0 >>
E1000_PSRCTL_BSIZE0_SHIFT;
@@ -2008,7 +1990,7 @@ static void e1000_power_down_phy(struct e1000_adapter *adapter)
u16 mii_reg;
/* WoL is enabled */
- if (!adapter->wol)
+ if (adapter->wol)
return;
/* non-copper PHY? */
@@ -2020,7 +2002,7 @@ static void e1000_power_down_phy(struct e1000_adapter *adapter)
e1000_check_reset_block(hw))
return;
- /* managebility (AMT) is enabled */
+ /* manageability (AMT) is enabled */
if (er32(MANC) & E1000_MANC_SMBUS_EN)
return;
@@ -2140,8 +2122,6 @@ void e1000e_reset(struct e1000_adapter *adapter)
phy_data &= ~IGP02E1000_PM_SPD;
e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, phy_data);
}
-
- e1000_release_manageability(adapter);
}
int e1000e_up(struct e1000_adapter *adapter)
@@ -3487,8 +3467,6 @@ static int e1000_suspend(struct pci_dev *pdev, pm_message_t state)
pci_enable_wake(pdev, PCI_D3cold, 0);
}
- e1000_release_manageability(adapter);
-
/* make sure adapter isn't asleep if manageability is enabled */
if (adapter->flags & FLAG_MNG_PT_ENABLED) {
pci_enable_wake(pdev, PCI_D3hot, 1);
@@ -3512,7 +3490,6 @@ static int e1000_suspend(struct pci_dev *pdev, pm_message_t state)
static void e1000e_disable_l1aspm(struct pci_dev *pdev)
{
int pos;
- u32 cap;
u16 val;
/*
@@ -3527,7 +3504,6 @@ static void e1000e_disable_l1aspm(struct pci_dev *pdev)
* active.
*/
pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
- pci_read_config_dword(pdev, pos + PCI_EXP_LNKCAP, &cap);
pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, &val);
if (val & 0x2) {
dev_warn(&pdev->dev, "Disabling L1 ASPM\n");
@@ -4054,8 +4030,6 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
flush_scheduled_work();
- e1000_release_manageability(adapter);
-
/* Release control of h/w to f/w. If f/w is AMT enabled, this
* would have already happened in close and is redundant. */
e1000_release_hw_control(adapter);
diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c
index fc6fee112f1..dab3c468a76 100644
--- a/drivers/net/e1000e/phy.c
+++ b/drivers/net/e1000e/phy.c
@@ -121,7 +121,7 @@ s32 e1000e_phy_reset_dsp(struct e1000_hw *hw)
* @offset: register offset to be read
* @data: pointer to the read data
*
- * Reads the MDI control regsiter in the PHY at offset and stores the
+ * Reads the MDI control register in the PHY at offset and stores the
* information read to data.
**/
static s32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
@@ -1172,7 +1172,7 @@ s32 e1000e_set_d3_lplu_state(struct e1000_hw *hw, bool active)
}
/**
- * e1000e_check_downshift - Checks whether a downshift in speed occured
+ * e1000e_check_downshift - Checks whether a downshift in speed occurred
* @hw: pointer to the HW structure
*
* Success returns 0, Failure returns 1
@@ -1388,8 +1388,8 @@ s32 e1000e_get_cable_length_m88(struct e1000_hw *hw)
*
* The automatic gain control (agc) normalizes the amplitude of the
* received signal, adjusting for the attenuation produced by the
- * cable. By reading the AGC registers, which reperesent the
- * cobination of course and fine gain value, the value can be put
+ * cable. By reading the AGC registers, which represent the
+ * combination of course and fine gain value, the value can be put
* into a lookup table to obtain the approximate cable length
* for each channel.
**/
@@ -1619,7 +1619,7 @@ s32 e1000e_phy_sw_reset(struct e1000_hw *hw)
* Verify the reset block is not blocking us from resetting. Acquire
* semaphore (if necessary) and read/set/write the device control reset
* bit in the PHY. Wait the appropriate delay time for the device to
- * reset and relase the semaphore (if necessary).
+ * reset and release the semaphore (if necessary).
**/
s32 e1000e_phy_hw_reset_generic(struct e1000_hw *hw)
{
diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h
index 88fb53eba71..7c4ead35cfa 100644
--- a/drivers/net/ehea/ehea.h
+++ b/drivers/net/ehea/ehea.h
@@ -40,7 +40,7 @@
#include <asm/io.h>
#define DRV_NAME "ehea"
-#define DRV_VERSION "EHEA_0083"
+#define DRV_VERSION "EHEA_0087"
/* eHEA capability flags */
#define DLPAR_PORT_ADD_REM 1
@@ -386,6 +386,13 @@ struct ehea_port_res {
#define EHEA_MAX_PORTS 16
+
+#define EHEA_NUM_PORTRES_FW_HANDLES 6 /* QP handle, SendCQ handle,
+ RecvCQ handle, EQ handle,
+ SendMR handle, RecvMR handle */
+#define EHEA_NUM_PORT_FW_HANDLES 1 /* EQ handle */
+#define EHEA_NUM_ADAPTER_FW_HANDLES 2 /* MR handle, NEQ handle */
+
struct ehea_adapter {
u64 handle;
struct of_device *ofdev;
@@ -405,6 +412,31 @@ struct ehea_mc_list {
u64 macaddr;
};
+/* kdump support */
+struct ehea_fw_handle_entry {
+ u64 adh; /* Adapter Handle */
+ u64 fwh; /* Firmware Handle */
+};
+
+struct ehea_fw_handle_array {
+ struct ehea_fw_handle_entry *arr;
+ int num_entries;
+ struct semaphore lock;
+};
+
+struct ehea_bcmc_reg_entry {
+ u64 adh; /* Adapter Handle */
+ u32 port_id; /* Logical Port Id */
+ u8 reg_type; /* Registration Type */
+ u64 macaddr;
+};
+
+struct ehea_bcmc_reg_array {
+ struct ehea_bcmc_reg_entry *arr;
+ int num_entries;
+ struct semaphore lock;
+};
+
#define EHEA_PORT_UP 1
#define EHEA_PORT_DOWN 0
#define EHEA_PHY_LINK_UP 1
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index c051c7e09b9..21af674b764 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -35,6 +35,7 @@
#include <linux/if_ether.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
+#include <asm/kexec.h>
#include <net/ip.h>
@@ -98,8 +99,10 @@ static int port_name_cnt;
static LIST_HEAD(adapter_list);
u64 ehea_driver_flags;
struct work_struct ehea_rereg_mr_task;
-
struct semaphore dlpar_mem_lock;
+struct ehea_fw_handle_array ehea_fw_handles;
+struct ehea_bcmc_reg_array ehea_bcmc_regs;
+
static int __devinit ehea_probe_adapter(struct of_device *dev,
const struct of_device_id *id);
@@ -132,6 +135,160 @@ void ehea_dump(void *adr, int len, char *msg)
}
}
+static void ehea_update_firmware_handles(void)
+{
+ struct ehea_fw_handle_entry *arr = NULL;
+ struct ehea_adapter *adapter;
+ int num_adapters = 0;
+ int num_ports = 0;
+ int num_portres = 0;
+ int i = 0;
+ int num_fw_handles, k, l;
+
+ /* Determine number of handles */
+ list_for_each_entry(adapter, &adapter_list, list) {
+ num_adapters++;
+
+ for (k = 0; k < EHEA_MAX_PORTS; k++) {
+ struct ehea_port *port = adapter->port[k];
+
+ if (!port || (port->state != EHEA_PORT_UP))
+ continue;
+
+ num_ports++;
+ num_portres += port->num_def_qps + port->num_add_tx_qps;
+ }
+ }
+
+ num_fw_handles = num_adapters * EHEA_NUM_ADAPTER_FW_HANDLES +
+ num_ports * EHEA_NUM_PORT_FW_HANDLES +
+ num_portres * EHEA_NUM_PORTRES_FW_HANDLES;
+
+ if (num_fw_handles) {
+ arr = kzalloc(num_fw_handles * sizeof(*arr), GFP_KERNEL);
+ if (!arr)
+ return; /* Keep the existing array */
+ } else
+ goto out_update;
+
+ list_for_each_entry(adapter, &adapter_list, list) {
+ for (k = 0; k < EHEA_MAX_PORTS; k++) {
+ struct ehea_port *port = adapter->port[k];
+
+ if (!port || (port->state != EHEA_PORT_UP))
+ continue;
+
+ for (l = 0;
+ l < port->num_def_qps + port->num_add_tx_qps;
+ l++) {
+ struct ehea_port_res *pr = &port->port_res[l];
+
+ arr[i].adh = adapter->handle;
+ arr[i++].fwh = pr->qp->fw_handle;
+ arr[i].adh = adapter->handle;
+ arr[i++].fwh = pr->send_cq->fw_handle;
+ arr[i].adh = adapter->handle;
+ arr[i++].fwh = pr->recv_cq->fw_handle;
+ arr[i].adh = adapter->handle;
+ arr[i++].fwh = pr->eq->fw_handle;
+ arr[i].adh = adapter->handle;
+ arr[i++].fwh = pr->send_mr.handle;
+ arr[i].adh = adapter->handle;
+ arr[i++].fwh = pr->recv_mr.handle;
+ }
+ arr[i].adh = adapter->handle;
+ arr[i++].fwh = port->qp_eq->fw_handle;
+ }
+
+ arr[i].adh = adapter->handle;
+ arr[i++].fwh = adapter->neq->fw_handle;
+
+ if (adapter->mr.handle) {
+ arr[i].adh = adapter->handle;
+ arr[i++].fwh = adapter->mr.handle;
+ }
+ }
+
+out_update:
+ kfree(ehea_fw_handles.arr);
+ ehea_fw_handles.arr = arr;
+ ehea_fw_handles.num_entries = i;
+}
+
+static void ehea_update_bcmc_registrations(void)
+{
+ struct ehea_bcmc_reg_entry *arr = NULL;
+ struct ehea_adapter *adapter;
+ struct ehea_mc_list *mc_entry;
+ int num_registrations = 0;
+ int i = 0;
+ int k;
+
+ /* Determine number of registrations */
+ list_for_each_entry(adapter, &adapter_list, list)
+ for (k = 0; k < EHEA_MAX_PORTS; k++) {
+ struct ehea_port *port = adapter->port[k];
+
+ if (!port || (port->state != EHEA_PORT_UP))
+ continue;
+
+ num_registrations += 2; /* Broadcast registrations */
+
+ list_for_each_entry(mc_entry, &port->mc_list->list,list)
+ num_registrations += 2;
+ }
+
+ if (num_registrations) {
+ arr = kzalloc(num_registrations * sizeof(*arr), GFP_KERNEL);
+ if (!arr)
+ return; /* Keep the existing array */
+ } else
+ goto out_update;
+
+ list_for_each_entry(adapter, &adapter_list, list) {
+ for (k = 0; k < EHEA_MAX_PORTS; k++) {
+ struct ehea_port *port = adapter->port[k];
+
+ if (!port || (port->state != EHEA_PORT_UP))
+ continue;
+
+ arr[i].adh = adapter->handle;
+ arr[i].port_id = port->logical_port_id;
+ arr[i].reg_type = EHEA_BCMC_BROADCAST |
+ EHEA_BCMC_UNTAGGED;
+ arr[i++].macaddr = port->mac_addr;
+
+ arr[i].adh = adapter->handle;
+ arr[i].port_id = port->logical_port_id;
+ arr[i].reg_type = EHEA_BCMC_BROADCAST |
+ EHEA_BCMC_VLANID_ALL;
+ arr[i++].macaddr = port->mac_addr;
+
+ list_for_each_entry(mc_entry,
+ &port->mc_list->list, list) {
+ arr[i].adh = adapter->handle;
+ arr[i].port_id = port->logical_port_id;
+ arr[i].reg_type = EHEA_BCMC_SCOPE_ALL |
+ EHEA_BCMC_MULTICAST |
+ EHEA_BCMC_UNTAGGED;
+ arr[i++].macaddr = mc_entry->macaddr;
+
+ arr[i].adh = adapter->handle;
+ arr[i].port_id = port->logical_port_id;
+ arr[i].reg_type = EHEA_BCMC_SCOPE_ALL |
+ EHEA_BCMC_MULTICAST |
+ EHEA_BCMC_VLANID_ALL;
+ arr[i++].macaddr = mc_entry->macaddr;
+ }
+ }
+ }
+
+out_update:
+ kfree(ehea_bcmc_regs.arr);
+ ehea_bcmc_regs.arr = arr;
+ ehea_bcmc_regs.num_entries = i;
+}
+
static struct net_device_stats *ehea_get_stats(struct net_device *dev)
{
struct ehea_port *port = netdev_priv(dev);
@@ -1601,19 +1758,25 @@ static int ehea_set_mac_addr(struct net_device *dev, void *sa)
memcpy(dev->dev_addr, mac_addr->sa_data, dev->addr_len);
+ down(&ehea_bcmc_regs.lock);
+
/* Deregister old MAC in pHYP */
ret = ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
if (ret)
- goto out_free;
+ goto out_upregs;
port->mac_addr = cb0->port_mac_addr << 16;
/* Register new MAC in pHYP */
ret = ehea_broadcast_reg_helper(port, H_REG_BCMC);
if (ret)
- goto out_free;
+ goto out_upregs;
ret = 0;
+
+out_upregs:
+ ehea_update_bcmc_registrations();
+ up(&ehea_bcmc_regs.lock);
out_free:
kfree(cb0);
out:
@@ -1775,9 +1938,11 @@ static void ehea_set_multicast_list(struct net_device *dev)
}
ehea_promiscuous(dev, 0);
+ down(&ehea_bcmc_regs.lock);
+
if (dev->flags & IFF_ALLMULTI) {
ehea_allmulti(dev, 1);
- return;
+ goto out;
}
ehea_allmulti(dev, 0);
@@ -1803,6 +1968,8 @@ static void ehea_set_multicast_list(struct net_device *dev)
}
out:
+ ehea_update_bcmc_registrations();
+ up(&ehea_bcmc_regs.lock);
return;
}
@@ -2285,6 +2452,8 @@ static int ehea_up(struct net_device *dev)
if (port->state == EHEA_PORT_UP)
return 0;
+ down(&ehea_fw_handles.lock);
+
ret = ehea_port_res_setup(port, port->num_def_qps,
port->num_add_tx_qps);
if (ret) {
@@ -2321,8 +2490,17 @@ static int ehea_up(struct net_device *dev)
}
}
- ret = 0;
+ down(&ehea_bcmc_regs.lock);
+
+ ret = ehea_broadcast_reg_helper(port, H_REG_BCMC);
+ if (ret) {
+ ret = -EIO;
+ goto out_free_irqs;
+ }
+
port->state = EHEA_PORT_UP;
+
+ ret = 0;
goto out;
out_free_irqs:
@@ -2334,6 +2512,12 @@ out:
if (ret)
ehea_info("Failed starting %s. ret=%i", dev->name, ret);
+ ehea_update_bcmc_registrations();
+ up(&ehea_bcmc_regs.lock);
+
+ ehea_update_firmware_handles();
+ up(&ehea_fw_handles.lock);
+
return ret;
}
@@ -2382,16 +2566,27 @@ static int ehea_down(struct net_device *dev)
if (port->state == EHEA_PORT_DOWN)
return 0;
+ down(&ehea_bcmc_regs.lock);
ehea_drop_multicast_list(dev);
+ ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
+
ehea_free_interrupts(dev);
+ down(&ehea_fw_handles.lock);
+
port->state = EHEA_PORT_DOWN;
+ ehea_update_bcmc_registrations();
+ up(&ehea_bcmc_regs.lock);
+
ret = ehea_clean_all_portres(port);
if (ret)
ehea_info("Failed freeing resources for %s. ret=%i",
dev->name, ret);
+ ehea_update_firmware_handles();
+ up(&ehea_fw_handles.lock);
+
return ret;
}
@@ -2920,19 +3115,12 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
dev->watchdog_timeo = EHEA_WATCH_DOG_TIMEOUT;
INIT_WORK(&port->reset_task, ehea_reset_port);
-
- ret = ehea_broadcast_reg_helper(port, H_REG_BCMC);
- if (ret) {
- ret = -EIO;
- goto out_unreg_port;
- }
-
ehea_set_ethtool_ops(dev);
ret = register_netdev(dev);
if (ret) {
ehea_error("register_netdev failed. ret=%d", ret);
- goto out_dereg_bc;
+ goto out_unreg_port;
}
port->lro_max_aggr = lro_max_aggr;
@@ -2949,9 +3137,6 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
return port;
-out_dereg_bc:
- ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
-
out_unreg_port:
ehea_unregister_port(port);
@@ -2971,7 +3156,6 @@ static void ehea_shutdown_single_port(struct ehea_port *port)
{
unregister_netdev(port->netdev);
ehea_unregister_port(port);
- ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
kfree(port->mc_list);
free_netdev(port->netdev);
port->adapter->active_ports--;
@@ -3014,7 +3198,6 @@ static int ehea_setup_ports(struct ehea_adapter *adapter)
i++;
};
-
return 0;
}
@@ -3159,6 +3342,7 @@ static int __devinit ehea_probe_adapter(struct of_device *dev,
ehea_error("Invalid ibmebus device probed");
return -EINVAL;
}
+ down(&ehea_fw_handles.lock);
adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
if (!adapter) {
@@ -3239,7 +3423,10 @@ out_kill_eq:
out_free_ad:
kfree(adapter);
+
out:
+ ehea_update_firmware_handles();
+ up(&ehea_fw_handles.lock);
return ret;
}
@@ -3258,18 +3445,41 @@ static int __devexit ehea_remove(struct of_device *dev)
flush_scheduled_work();
+ down(&ehea_fw_handles.lock);
+
ibmebus_free_irq(adapter->neq->attr.ist1, adapter);
tasklet_kill(&adapter->neq_tasklet);
ehea_destroy_eq(adapter->neq);
ehea_remove_adapter_mr(adapter);
list_del(&adapter->list);
-
kfree(adapter);
+ ehea_update_firmware_handles();
+ up(&ehea_fw_handles.lock);
+
return 0;
}
+void ehea_crash_handler(void)
+{
+ int i;
+
+ if (ehea_fw_handles.arr)
+ for (i = 0; i < ehea_fw_handles.num_entries; i++)
+ ehea_h_free_resource(ehea_fw_handles.arr[i].adh,
+ ehea_fw_handles.arr[i].fwh,
+ FORCE_FREE);
+
+ if (ehea_bcmc_regs.arr)
+ for (i = 0; i < ehea_bcmc_regs.num_entries; i++)
+ ehea_h_reg_dereg_bcmc(ehea_bcmc_regs.arr[i].adh,
+ ehea_bcmc_regs.arr[i].port_id,
+ ehea_bcmc_regs.arr[i].reg_type,
+ ehea_bcmc_regs.arr[i].macaddr,
+ 0, H_DEREG_BCMC);
+}
+
static int ehea_reboot_notifier(struct notifier_block *nb,
unsigned long action, void *unused)
{
@@ -3330,7 +3540,12 @@ int __init ehea_module_init(void)
INIT_WORK(&ehea_rereg_mr_task, ehea_rereg_mrs);
+ memset(&ehea_fw_handles, 0, sizeof(ehea_fw_handles));
+ memset(&ehea_bcmc_regs, 0, sizeof(ehea_bcmc_regs));
+
sema_init(&dlpar_mem_lock, 1);
+ sema_init(&ehea_fw_handles.lock, 1);
+ sema_init(&ehea_bcmc_regs.lock, 1);
ret = check_module_parm();
if (ret)
@@ -3340,12 +3555,18 @@ int __init ehea_module_init(void)
if (ret)
goto out;
- register_reboot_notifier(&ehea_reboot_nb);
+ ret = register_reboot_notifier(&ehea_reboot_nb);
+ if (ret)
+ ehea_info("failed registering reboot notifier");
+
+ ret = crash_shutdown_register(&ehea_crash_handler);
+ if (ret)
+ ehea_info("failed registering crash handler");
ret = ibmebus_register_driver(&ehea_driver);
if (ret) {
ehea_error("failed registering eHEA device driver on ebus");
- goto out;
+ goto out2;
}
ret = driver_create_file(&ehea_driver.driver,
@@ -3353,21 +3574,33 @@ int __init ehea_module_init(void)
if (ret) {
ehea_error("failed to register capabilities attribute, ret=%d",
ret);
- unregister_reboot_notifier(&ehea_reboot_nb);
- ibmebus_unregister_driver(&ehea_driver);
- goto out;
+ goto out3;
}
+ return ret;
+
+out3:
+ ibmebus_unregister_driver(&ehea_driver);
+out2:
+ unregister_reboot_notifier(&ehea_reboot_nb);
+ crash_shutdown_unregister(&ehea_crash_handler);
out:
return ret;
}
static void __exit ehea_module_exit(void)
{
+ int ret;
+
flush_scheduled_work();
driver_remove_file(&ehea_driver.driver, &driver_attr_capabilities);
ibmebus_unregister_driver(&ehea_driver);
unregister_reboot_notifier(&ehea_reboot_nb);
+ ret = crash_shutdown_unregister(&ehea_crash_handler);
+ if (ret)
+ ehea_info("failed unregistering crash handler");
+ kfree(ehea_fw_handles.arr);
+ kfree(ehea_bcmc_regs.arr);
ehea_destroy_busmap();
}
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index 42d94edeee2..af869cf9ae7 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -946,16 +946,11 @@ static int fs_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
struct fs_enet_private *fep = netdev_priv(dev);
struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&rq->ifr_data;
- unsigned long flags;
- int rc;
if (!netif_running(dev))
return -EINVAL;
- spin_lock_irqsave(&fep->lock, flags);
- rc = phy_mii_ioctl(fep->phydev, mii, cmd);
- spin_unlock_irqrestore(&fep->lock, flags);
- return rc;
+ return phy_mii_ioctl(fep->phydev, mii, cmd);
}
extern int fs_mii_connect(struct net_device *dev);
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 0431e9ed0fa..718cf77e345 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -130,8 +130,8 @@ static void free_skb_resources(struct gfar_private *priv);
static void gfar_set_multi(struct net_device *dev);
static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr);
static void gfar_configure_serdes(struct net_device *dev);
-extern int gfar_local_mdio_write(struct gfar_mii *regs, int mii_id, int regnum, u16 value);
-extern int gfar_local_mdio_read(struct gfar_mii *regs, int mii_id, int regnum);
+extern int gfar_local_mdio_write(struct gfar_mii __iomem *regs, int mii_id, int regnum, u16 value);
+extern int gfar_local_mdio_read(struct gfar_mii __iomem *regs, int mii_id, int regnum);
#ifdef CONFIG_GFAR_NAPI
static int gfar_poll(struct napi_struct *napi, int budget);
#endif
@@ -605,7 +605,7 @@ void stop_gfar(struct net_device *dev)
free_skb_resources(priv);
- dma_free_coherent(NULL,
+ dma_free_coherent(&dev->dev,
sizeof(struct txbd8)*priv->tx_ring_size
+ sizeof(struct rxbd8)*priv->rx_ring_size,
priv->tx_bd_base,
@@ -626,7 +626,7 @@ static void free_skb_resources(struct gfar_private *priv)
for (i = 0; i < priv->tx_ring_size; i++) {
if (priv->tx_skbuff[i]) {
- dma_unmap_single(NULL, txbdp->bufPtr,
+ dma_unmap_single(&priv->dev->dev, txbdp->bufPtr,
txbdp->length,
DMA_TO_DEVICE);
dev_kfree_skb_any(priv->tx_skbuff[i]);
@@ -643,7 +643,7 @@ static void free_skb_resources(struct gfar_private *priv)
if(priv->rx_skbuff != NULL) {
for (i = 0; i < priv->rx_ring_size; i++) {
if (priv->rx_skbuff[i]) {
- dma_unmap_single(NULL, rxbdp->bufPtr,
+ dma_unmap_single(&priv->dev->dev, rxbdp->bufPtr,
priv->rx_buffer_size,
DMA_FROM_DEVICE);
@@ -708,7 +708,7 @@ int startup_gfar(struct net_device *dev)
gfar_write(&regs->imask, IMASK_INIT_CLEAR);
/* Allocate memory for the buffer descriptors */
- vaddr = (unsigned long) dma_alloc_coherent(NULL,
+ vaddr = (unsigned long) dma_alloc_coherent(&dev->dev,
sizeof (struct txbd8) * priv->tx_ring_size +
sizeof (struct rxbd8) * priv->rx_ring_size,
&addr, GFP_KERNEL);
@@ -919,7 +919,7 @@ err_irq_fail:
rx_skb_fail:
free_skb_resources(priv);
tx_skb_fail:
- dma_free_coherent(NULL,
+ dma_free_coherent(&dev->dev,
sizeof(struct txbd8)*priv->tx_ring_size
+ sizeof(struct rxbd8)*priv->rx_ring_size,
priv->tx_bd_base,
@@ -1053,7 +1053,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Set buffer length and pointer */
txbdp->length = skb->len;
- txbdp->bufPtr = dma_map_single(NULL, skb->data,
+ txbdp->bufPtr = dma_map_single(&dev->dev, skb->data,
skb->len, DMA_TO_DEVICE);
/* Save the skb pointer so we can free it later */
@@ -1332,7 +1332,7 @@ struct sk_buff * gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp)
*/
skb_reserve(skb, alignamount);
- bdp->bufPtr = dma_map_single(NULL, skb->data,
+ bdp->bufPtr = dma_map_single(&dev->dev, skb->data,
priv->rx_buffer_size, DMA_FROM_DEVICE);
bdp->length = 0;
diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c
index 6a647d95e6e..24327629bf0 100644
--- a/drivers/net/gianfar_mii.c
+++ b/drivers/net/gianfar_mii.c
@@ -51,7 +51,7 @@
* the local mdio pins, which may not be the same as system mdio bus, used for
* controlling the external PHYs, for example.
*/
-int gfar_local_mdio_write(struct gfar_mii *regs, int mii_id,
+int gfar_local_mdio_write(struct gfar_mii __iomem *regs, int mii_id,
int regnum, u16 value)
{
/* Set the PHY address and the register address we want to write */
@@ -77,7 +77,7 @@ int gfar_local_mdio_write(struct gfar_mii *regs, int mii_id,
* and are always tied to the local mdio pins, which may not be the
* same as system mdio bus, used for controlling the external PHYs, for eg.
*/
-int gfar_local_mdio_read(struct gfar_mii *regs, int mii_id, int regnum)
+int gfar_local_mdio_read(struct gfar_mii __iomem *regs, int mii_id, int regnum)
{
u16 value;
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index cfcd15af501..30c9b3b0d13 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -289,7 +289,6 @@ static void ax_bump(struct mkiss *ax)
*ax->rbuff &= ~0x20;
}
}
- spin_unlock_bh(&ax->buflock);
count = ax->rcount;
@@ -297,17 +296,17 @@ static void ax_bump(struct mkiss *ax)
printk(KERN_ERR "mkiss: %s: memory squeeze, dropping packet.\n",
ax->dev->name);
ax->stats.rx_dropped++;
+ spin_unlock_bh(&ax->buflock);
return;
}
- spin_lock_bh(&ax->buflock);
memcpy(skb_put(skb,count), ax->rbuff, count);
- spin_unlock_bh(&ax->buflock);
skb->protocol = ax25_type_trans(skb, ax->dev);
netif_rx(skb);
ax->dev->last_rx = jiffies;
ax->stats.rx_packets++;
ax->stats.rx_bytes += count;
+ spin_unlock_bh(&ax->buflock);
}
static void kiss_unesc(struct mkiss *ax, unsigned char s)
diff --git a/drivers/net/ibm_newemac/rgmii.c b/drivers/net/ibm_newemac/rgmii.c
index 9bc1132fa78..5757788227b 100644
--- a/drivers/net/ibm_newemac/rgmii.c
+++ b/drivers/net/ibm_newemac/rgmii.c
@@ -302,7 +302,6 @@ static int __devexit rgmii_remove(struct of_device *ofdev)
static struct of_device_id rgmii_match[] =
{
{
- .type = "rgmii-interface",
.compatible = "ibm,rgmii",
},
{
diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c
index f69721e4eaa..0447f9bcd27 100644
--- a/drivers/net/igb/igb_ethtool.c
+++ b/drivers/net/igb/igb_ethtool.c
@@ -43,7 +43,7 @@ struct igb_stats {
int stat_offset;
};
-#define IGB_STAT(m) sizeof(((struct igb_adapter *)0)->m), \
+#define IGB_STAT(m) FIELD_SIZEOF(struct igb_adapter, m), \
offsetof(struct igb_adapter, m)
static const struct igb_stats igb_gstrings_stats[] = {
{ "rx_packets", IGB_STAT(stats.gprc) },
diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c
index d4eb8e2d872..6a1f2309209 100644
--- a/drivers/net/igb/igb_main.c
+++ b/drivers/net/igb/igb_main.c
@@ -439,7 +439,7 @@ static int igb_request_irq(struct igb_adapter *adapter)
err = igb_request_msix(adapter);
if (!err) {
/* enable IAM, auto-mask,
- * DO NOT USE EIAME or IAME in legacy mode */
+ * DO NOT USE EIAM or IAM in legacy mode */
wr32(E1000_IAM, IMS_ENABLE_MASK);
goto request_done;
}
@@ -465,14 +465,9 @@ static int igb_request_irq(struct igb_adapter *adapter)
err = request_irq(adapter->pdev->irq, &igb_intr, IRQF_SHARED,
netdev->name, netdev);
- if (err) {
+ if (err)
dev_err(&adapter->pdev->dev, "Error %d getting interrupt\n",
err);
- goto request_done;
- }
-
- /* enable IAM, auto-mask */
- wr32(E1000_IAM, IMS_ENABLE_MASK);
request_done:
return err;
@@ -606,9 +601,6 @@ static void igb_init_manageability(struct igb_adapter *adapter)
u32 manc2h = rd32(E1000_MANC2H);
u32 manc = rd32(E1000_MANC);
- /* disable hardware interception of ARP */
- manc &= ~(E1000_MANC_ARP_EN);
-
/* enable receiving management packets to the host */
/* this will probably generate destination unreachable messages
* from the host OS, but the packets will be handled on SMBUS */
@@ -623,25 +615,6 @@ static void igb_init_manageability(struct igb_adapter *adapter)
}
}
-static void igb_release_manageability(struct igb_adapter *adapter)
-{
- struct e1000_hw *hw = &adapter->hw;
-
- if (adapter->en_mng_pt) {
- u32 manc = rd32(E1000_MANC);
-
- /* re-enable hardware interception of ARP */
- manc |= E1000_MANC_ARP_EN;
- manc &= ~E1000_MANC_EN_MNG2HOST;
-
- /* don't explicitly have to mess with MANC2H since
- * MANC has an enable disable that gates MANC2H */
-
- /* XXX stop the hardware watchdog ? */
- wr32(E1000_MANC, manc);
- }
-}
-
/**
* igb_configure - configure the hardware for RX and TX
* @adapter: private board structure
@@ -843,8 +816,8 @@ void igb_reset(struct igb_adapter *adapter)
wr32(E1000_VET, ETHERNET_IEEE_VLAN_TYPE);
igb_reset_adaptive(&adapter->hw);
- adapter->hw.phy.ops.get_phy_info(&adapter->hw);
- igb_release_manageability(adapter);
+ if (adapter->hw.phy.ops.get_phy_info)
+ adapter->hw.phy.ops.get_phy_info(&adapter->hw);
}
/**
@@ -1178,9 +1151,6 @@ static void __devexit igb_remove(struct pci_dev *pdev)
flush_scheduled_work();
-
- igb_release_manageability(adapter);
-
/* Release control of h/w to f/w. If f/w is AMT enabled, this
* would have already happened in close and is redundant. */
igb_release_hw_control(adapter);
@@ -2083,7 +2053,8 @@ static void igb_set_multi(struct net_device *netdev)
static void igb_update_phy_info(unsigned long data)
{
struct igb_adapter *adapter = (struct igb_adapter *) data;
- adapter->hw.phy.ops.get_phy_info(&adapter->hw);
+ if (adapter->hw.phy.ops.get_phy_info)
+ adapter->hw.phy.ops.get_phy_info(&adapter->hw);
}
/**
@@ -3955,8 +3926,6 @@ static int igb_suspend(struct pci_dev *pdev, pm_message_t state)
pci_enable_wake(pdev, PCI_D3cold, 0);
}
- igb_release_manageability(adapter);
-
/* make sure adapter isn't asleep if manageability is enabled */
if (adapter->en_mng_pt) {
pci_enable_wake(pdev, PCI_D3hot, 1);
diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c
index a267dd86252..75f3a68ee35 100644
--- a/drivers/net/ixgb/ixgb_ethtool.c
+++ b/drivers/net/ixgb/ixgb_ethtool.c
@@ -49,7 +49,7 @@ struct ixgb_stats {
int stat_offset;
};
-#define IXGB_STAT(m) sizeof(((struct ixgb_adapter *)0)->m), \
+#define IXGB_STAT(m) FIELD_SIZEOF(struct ixgb_adapter, m), \
offsetof(struct ixgb_adapter, m)
static struct ixgb_stats ixgb_gstrings_stats[] = {
{"rx_packets", IXGB_STAT(net_stats.rx_packets)},
@@ -67,6 +67,7 @@ static struct ixgb_stats ixgb_gstrings_stats[] = {
{"rx_over_errors", IXGB_STAT(net_stats.rx_over_errors)},
{"rx_crc_errors", IXGB_STAT(net_stats.rx_crc_errors)},
{"rx_frame_errors", IXGB_STAT(net_stats.rx_frame_errors)},
+ {"rx_no_buffer_count", IXGB_STAT(stats.rnbc)},
{"rx_fifo_errors", IXGB_STAT(net_stats.rx_fifo_errors)},
{"rx_missed_errors", IXGB_STAT(net_stats.rx_missed_errors)},
{"tx_aborted_errors", IXGB_STAT(net_stats.tx_aborted_errors)},
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index ead49e54f31..23d0a4afe0e 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -220,7 +220,6 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter,
tx_ring->stats.bytes += tx_buffer_info->length;
if (cleaned) {
struct sk_buff *skb = tx_buffer_info->skb;
-#ifdef NETIF_F_TSO
unsigned int segs, bytecount;
segs = skb_shinfo(skb)->gso_segs ?: 1;
/* multiply data chunks by size of headers */
@@ -228,10 +227,6 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter,
skb->len;
total_tx_packets += segs;
total_tx_bytes += bytecount;
-#else
- total_tx_packets++;
- total_tx_bytes += skb->len;
-#endif
}
ixgbe_unmap_and_free_tx_resource(adapter,
tx_buffer_info);
@@ -1942,6 +1937,10 @@ static int ixgbe_open(struct net_device *netdev)
int err;
u32 num_rx_queues = adapter->num_rx_queues;
+ /* disallow open during test */
+ if (test_bit(__IXGBE_TESTING, &adapter->state))
+ return -EBUSY;
+
try_intr_reinit:
/* allocate transmit descriptors */
err = ixgbe_setup_all_tx_resources(adapter);
@@ -2278,11 +2277,29 @@ static bool ixgbe_tx_csum(struct ixgbe_adapter *adapter,
IXGBE_ADVTXD_DTYP_CTXT);
if (skb->ip_summed == CHECKSUM_PARTIAL) {
- if (skb->protocol == htons(ETH_P_IP))
+ switch (skb->protocol) {
+ case __constant_htons(ETH_P_IP):
type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4;
+ if (ip_hdr(skb)->protocol == IPPROTO_TCP)
+ type_tucmd_mlhl |=
+ IXGBE_ADVTXD_TUCMD_L4T_TCP;
+ break;
+
+ case __constant_htons(ETH_P_IPV6):
+ /* XXX what about other V6 headers?? */
+ if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
+ type_tucmd_mlhl |=
+ IXGBE_ADVTXD_TUCMD_L4T_TCP;
+ break;
- if (skb->sk->sk_protocol == IPPROTO_TCP)
- type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_TCP;
+ default:
+ if (unlikely(net_ratelimit())) {
+ DPRINTK(PROBE, WARNING,
+ "partial checksum but proto=%x!\n",
+ skb->protocol);
+ }
+ break;
+ }
}
context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd_mlhl);
@@ -2778,6 +2795,14 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
hw->mac.type, hw->phy.type,
(part_num >> 8), (part_num & 0xff));
+ if (link_width <= IXGBE_PCI_LINK_WIDTH_4) {
+ dev_warn(&pdev->dev, "PCI-Express bandwidth available for "
+ "this card is not sufficient for optimal "
+ "performance.\n");
+ dev_warn(&pdev->dev, "For optimal performance a x8 "
+ "PCI-Express slot is required.\n");
+ }
+
/* reset the hardware with the new settings */
ixgbe_start_hw(hw);
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index 81bf005ff28..1d210ed4613 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -148,7 +148,7 @@ static void macb_handle_link_change(struct net_device *dev)
if (phydev->duplex)
reg |= MACB_BIT(FD);
- if (phydev->speed)
+ if (phydev->speed == SPEED_100)
reg |= MACB_BIT(SPD);
macb_writel(bp, NCFGR, reg);
diff --git a/drivers/net/niu.c b/drivers/net/niu.c
index 2fe14b0c5c6..d11ba61baa4 100644
--- a/drivers/net/niu.c
+++ b/drivers/net/niu.c
@@ -33,8 +33,8 @@
#define DRV_MODULE_NAME "niu"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "0.6"
-#define DRV_MODULE_RELDATE "January 5, 2008"
+#define DRV_MODULE_VERSION "0.7"
+#define DRV_MODULE_RELDATE "February 18, 2008"
static char version[] __devinitdata =
DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
@@ -1616,12 +1616,13 @@ static int niu_enable_alt_mac(struct niu *np, int index, int on)
if (index >= niu_num_alt_addr(np))
return -EINVAL;
- if (np->flags & NIU_FLAGS_XMAC)
+ if (np->flags & NIU_FLAGS_XMAC) {
reg = XMAC_ADDR_CMPEN;
- else
+ mask = 1 << index;
+ } else {
reg = BMAC_ADDR_CMPEN;
-
- mask = 1 << index;
+ mask = 1 << (index + 1);
+ }
val = nr64_mac(reg);
if (on)
@@ -5147,7 +5148,12 @@ static void niu_set_rx_mode(struct net_device *dev)
index++;
}
} else {
- for (i = 0; i < niu_num_alt_addr(np); i++) {
+ int alt_start;
+ if (np->flags & NIU_FLAGS_XMAC)
+ alt_start = 0;
+ else
+ alt_start = 1;
+ for (i = alt_start; i < niu_num_alt_addr(np); i++) {
err = niu_enable_alt_mac(np, i, 0);
if (err)
printk(KERN_WARNING PFX "%s: Error %d "
diff --git a/drivers/net/niu.h b/drivers/net/niu.h
index 0e8626adc57..59dc05fcd37 100644
--- a/drivers/net/niu.h
+++ b/drivers/net/niu.h
@@ -499,7 +499,7 @@
#define BMAC_ADDR2 0x00110UL
#define BMAC_ADDR2_ADDR2 0x000000000000ffffULL
-#define BMAC_NUM_ALT_ADDR 7
+#define BMAC_NUM_ALT_ADDR 6
#define BMAC_ALT_ADDR0(NUM) (0x00118UL + (NUM)*0x18UL)
#define BMAC_ALT_ADDR0_ADDR0 0x000000000000ffffULL
diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
index 6323988dfa1..fd8158a86f6 100644
--- a/drivers/net/pcmcia/pcnet_cs.c
+++ b/drivers/net/pcmcia/pcnet_cs.c
@@ -590,6 +590,13 @@ static int pcnet_config(struct pcmcia_device *link)
dev->if_port = 0;
}
+ if ((link->conf.ConfigBase == 0x03c0)
+ && (link->manf_id == 0x149) && (link->card_id = 0xc1ab)) {
+ printk(KERN_INFO "pcnet_cs: this is an AX88190 card!\n");
+ printk(KERN_INFO "pcnet_cs: use axnet_cs instead.\n");
+ goto failed;
+ }
+
local_hw_info = get_hwinfo(link);
if (local_hw_info == NULL)
local_hw_info = get_prom(link);
@@ -1567,12 +1574,11 @@ static struct pcmcia_device_id pcnet_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0145),
PCMCIA_DEVICE_MANF_CARD(0x0149, 0x0230),
PCMCIA_DEVICE_MANF_CARD(0x0149, 0x4530),
-/* PCMCIA_DEVICE_MANF_CARD(0x0149, 0xc1ab), conflict with axnet_cs */
+ PCMCIA_DEVICE_MANF_CARD(0x0149, 0xc1ab),
PCMCIA_DEVICE_MANF_CARD(0x0186, 0x0110),
PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x2328),
PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x8041),
PCMCIA_DEVICE_MANF_CARD(0x0213, 0x2452),
-/* PCMCIA_DEVICE_MANF_CARD(0x021b, 0x0202), conflict with axnet_cs */
PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0300),
PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0307),
PCMCIA_DEVICE_MANF_CARD(0x026f, 0x030a),
diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c
index f18eca9831e..250eb1954c3 100644
--- a/drivers/net/pcmcia/smc91c92_cs.c
+++ b/drivers/net/pcmcia/smc91c92_cs.c
@@ -559,8 +559,16 @@ static int mhz_setup(struct pcmcia_device *link)
/* Read the station address from the CIS. It is stored as the last
(fourth) string in the Version 1 Version/ID tuple. */
- if (link->prod_id[3]) {
- station_addr = link->prod_id[3];
+ tuple->DesiredTuple = CISTPL_VERS_1;
+ if (first_tuple(link, tuple, parse) != CS_SUCCESS) {
+ rc = -1;
+ goto free_cfg_mem;
+ }
+ /* Ugh -- the EM1144 card has two VERS_1 tuples!?! */
+ if (next_tuple(link, tuple, parse) != CS_SUCCESS)
+ first_tuple(link, tuple, parse);
+ if (parse->version_1.ns > 3) {
+ station_addr = parse->version_1.str + parse->version_1.ofs[3];
if (cvt_ascii_address(dev, station_addr) == 0) {
rc = 0;
goto free_cfg_mem;
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 6e9f619c491..963630c65ca 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -49,13 +49,13 @@ int mdiobus_register(struct mii_bus *bus)
int i;
int err = 0;
- mutex_init(&bus->mdio_lock);
-
if (NULL == bus || NULL == bus->name ||
NULL == bus->read ||
NULL == bus->write)
return -EINVAL;
+ mutex_init(&bus->mdio_lock);
+
if (bus->reset)
bus->reset(bus);
diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c
index 750d2a99cb4..daf5abab953 100644
--- a/drivers/net/ps3_gelic_wireless.c
+++ b/drivers/net/ps3_gelic_wireless.c
@@ -2690,6 +2690,7 @@ int gelic_wl_driver_probe(struct gelic_card *card)
return -ENOMEM;
/* setup net_device structure */
+ SET_NETDEV_DEV(netdev, &card->dev->core);
gelic_wl_setup_netdev_ops(netdev);
/* setup some of net_device and register it */
diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c
index 202fdf35662..20745fd4e97 100644
--- a/drivers/net/sis190.c
+++ b/drivers/net/sis190.c
@@ -1633,13 +1633,18 @@ static inline void sis190_init_rxfilter(struct net_device *dev)
static int __devinit sis190_get_mac_addr(struct pci_dev *pdev,
struct net_device *dev)
{
- u8 from;
+ int rc;
+
+ rc = sis190_get_mac_addr_from_eeprom(pdev, dev);
+ if (rc < 0) {
+ u8 reg;
- pci_read_config_byte(pdev, 0x73, &from);
+ pci_read_config_byte(pdev, 0x73, &reg);
- return (from & 0x00000001) ?
- sis190_get_mac_addr_from_apc(pdev, dev) :
- sis190_get_mac_addr_from_eeprom(pdev, dev);
+ if (reg & 0x00000001)
+ rc = sis190_get_mac_addr_from_apc(pdev, dev);
+ }
+ return rc;
}
static void sis190_set_speed_auto(struct net_device *dev)
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 9a6295909e4..54c662690f6 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -572,8 +572,9 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
default:
/* set Tx LED (LED_TX) to blink mode on Rx OR Tx activity */
ledctrl |= PHY_M_LED_BLINK_RT(BLINK_84MS) | PHY_M_LEDC_TX_CTRL;
+
/* turn off the Rx LED (LED_RX) */
- ledover &= ~PHY_M_LED_MO_RX;
+ ledover |= PHY_M_LED_MO_RX(MO_LED_OFF);
}
if (hw->chip_id == CHIP_ID_YUKON_EC_U &&
@@ -602,7 +603,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
if (sky2->autoneg == AUTONEG_DISABLE || sky2->speed == SPEED_100) {
/* turn on 100 Mbps LED (LED_LINK100) */
- ledover |= PHY_M_LED_MO_100;
+ ledover |= PHY_M_LED_MO_100(MO_LED_ON);
}
if (ledover)
@@ -3322,82 +3323,80 @@ static void sky2_set_multicast(struct net_device *dev)
/* Can have one global because blinking is controlled by
* ethtool and that is always under RTNL mutex
*/
-static void sky2_led(struct sky2_hw *hw, unsigned port, int on)
+static void sky2_led(struct sky2_port *sky2, enum led_mode mode)
{
- u16 pg;
+ struct sky2_hw *hw = sky2->hw;
+ unsigned port = sky2->port;
- switch (hw->chip_id) {
- case CHIP_ID_YUKON_XL:
+ spin_lock_bh(&sky2->phy_lock);
+ if (hw->chip_id == CHIP_ID_YUKON_EC_U ||
+ hw->chip_id == CHIP_ID_YUKON_EX ||
+ hw->chip_id == CHIP_ID_YUKON_SUPR) {
+ u16 pg;
pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3);
- gm_phy_write(hw, port, PHY_MARV_PHY_CTRL,
- on ? (PHY_M_LEDC_LOS_CTRL(1) |
- PHY_M_LEDC_INIT_CTRL(7) |
- PHY_M_LEDC_STA1_CTRL(7) |
- PHY_M_LEDC_STA0_CTRL(7))
- : 0);
- gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
- break;
+ switch (mode) {
+ case MO_LED_OFF:
+ gm_phy_write(hw, port, PHY_MARV_PHY_CTRL,
+ PHY_M_LEDC_LOS_CTRL(8) |
+ PHY_M_LEDC_INIT_CTRL(8) |
+ PHY_M_LEDC_STA1_CTRL(8) |
+ PHY_M_LEDC_STA0_CTRL(8));
+ break;
+ case MO_LED_ON:
+ gm_phy_write(hw, port, PHY_MARV_PHY_CTRL,
+ PHY_M_LEDC_LOS_CTRL(9) |
+ PHY_M_LEDC_INIT_CTRL(9) |
+ PHY_M_LEDC_STA1_CTRL(9) |
+ PHY_M_LEDC_STA0_CTRL(9));
+ break;
+ case MO_LED_BLINK:
+ gm_phy_write(hw, port, PHY_MARV_PHY_CTRL,
+ PHY_M_LEDC_LOS_CTRL(0xa) |
+ PHY_M_LEDC_INIT_CTRL(0xa) |
+ PHY_M_LEDC_STA1_CTRL(0xa) |
+ PHY_M_LEDC_STA0_CTRL(0xa));
+ break;
+ case MO_LED_NORM:
+ gm_phy_write(hw, port, PHY_MARV_PHY_CTRL,
+ PHY_M_LEDC_LOS_CTRL(1) |
+ PHY_M_LEDC_INIT_CTRL(8) |
+ PHY_M_LEDC_STA1_CTRL(7) |
+ PHY_M_LEDC_STA0_CTRL(7));
+ }
- default:
- gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0);
+ gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
+ } else
gm_phy_write(hw, port, PHY_MARV_LED_OVER,
- on ? PHY_M_LED_ALL : 0);
- }
+ PHY_M_LED_MO_DUP(mode) |
+ PHY_M_LED_MO_10(mode) |
+ PHY_M_LED_MO_100(mode) |
+ PHY_M_LED_MO_1000(mode) |
+ PHY_M_LED_MO_RX(mode) |
+ PHY_M_LED_MO_TX(mode));
+
+ spin_unlock_bh(&sky2->phy_lock);
}
/* blink LED's for finding board */
static int sky2_phys_id(struct net_device *dev, u32 data)
{
struct sky2_port *sky2 = netdev_priv(dev);
- struct sky2_hw *hw = sky2->hw;
- unsigned port = sky2->port;
- u16 ledctrl, ledover = 0;
- long ms;
- int interrupted;
- int onoff = 1;
+ unsigned int i;
- if (!data || data > (u32) (MAX_SCHEDULE_TIMEOUT / HZ))
- ms = jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT);
- else
- ms = data * 1000;
-
- /* save initial values */
- spin_lock_bh(&sky2->phy_lock);
- if (hw->chip_id == CHIP_ID_YUKON_XL) {
- u16 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
- gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3);
- ledctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL);
- gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
- } else {
- ledctrl = gm_phy_read(hw, port, PHY_MARV_LED_CTRL);
- ledover = gm_phy_read(hw, port, PHY_MARV_LED_OVER);
- }
-
- interrupted = 0;
- while (!interrupted && ms > 0) {
- sky2_led(hw, port, onoff);
- onoff = !onoff;
-
- spin_unlock_bh(&sky2->phy_lock);
- interrupted = msleep_interruptible(250);
- spin_lock_bh(&sky2->phy_lock);
-
- ms -= 250;
- }
+ if (data == 0)
+ data = UINT_MAX;
- /* resume regularly scheduled programming */
- if (hw->chip_id == CHIP_ID_YUKON_XL) {
- u16 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
- gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3);
- gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ledctrl);
- gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
- } else {
- gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl);
- gm_phy_write(hw, port, PHY_MARV_LED_OVER, ledover);
+ for (i = 0; i < data; i++) {
+ sky2_led(sky2, MO_LED_ON);
+ if (msleep_interruptible(500))
+ break;
+ sky2_led(sky2, MO_LED_OFF);
+ if (msleep_interruptible(500))
+ break;
}
- spin_unlock_bh(&sky2->phy_lock);
+ sky2_led(sky2, MO_LED_NORM);
return 0;
}
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index 5ab5c1c7c5a..7bb3ba9bcbd 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -1318,18 +1318,21 @@ enum {
BLINK_670MS = 4,/* 670 ms */
};
-/**** PHY_MARV_LED_OVER 16 bit r/w LED control */
-enum {
- PHY_M_LED_MO_DUP = 3<<10,/* Bit 11..10: Duplex */
- PHY_M_LED_MO_10 = 3<<8, /* Bit 9.. 8: Link 10 */
- PHY_M_LED_MO_100 = 3<<6, /* Bit 7.. 6: Link 100 */
- PHY_M_LED_MO_1000 = 3<<4, /* Bit 5.. 4: Link 1000 */
- PHY_M_LED_MO_RX = 3<<2, /* Bit 3.. 2: Rx */
- PHY_M_LED_MO_TX = 3<<0, /* Bit 1.. 0: Tx */
-
- PHY_M_LED_ALL = PHY_M_LED_MO_DUP | PHY_M_LED_MO_10
- | PHY_M_LED_MO_100 | PHY_M_LED_MO_1000
- | PHY_M_LED_MO_RX,
+/***** PHY_MARV_LED_OVER 16 bit r/w Manual LED Override Reg *****/
+#define PHY_M_LED_MO_SGMII(x) ((x)<<14) /* Bit 15..14: SGMII AN Timer */
+
+#define PHY_M_LED_MO_DUP(x) ((x)<<10) /* Bit 11..10: Duplex */
+#define PHY_M_LED_MO_10(x) ((x)<<8) /* Bit 9.. 8: Link 10 */
+#define PHY_M_LED_MO_100(x) ((x)<<6) /* Bit 7.. 6: Link 100 */
+#define PHY_M_LED_MO_1000(x) ((x)<<4) /* Bit 5.. 4: Link 1000 */
+#define PHY_M_LED_MO_RX(x) ((x)<<2) /* Bit 3.. 2: Rx */
+#define PHY_M_LED_MO_TX(x) ((x)<<0) /* Bit 1.. 0: Tx */
+
+enum led_mode {
+ MO_LED_NORM = 0,
+ MO_LED_BLINK = 1,
+ MO_LED_OFF = 2,
+ MO_LED_ON = 3,
};
/***** PHY_MARV_EXT_CTRL_2 16 bit r/w Ext. PHY Specific Ctrl 2 *****/
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index db606b60388..26ffb67f1da 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -8781,7 +8781,7 @@ static int tg3_phys_id(struct net_device *dev, u32 data)
return -EAGAIN;
if (data == 0)
- data = 2;
+ data = UINT_MAX / 2;
for (i = 0; i < (data * 2); i++) {
if ((i % 2) == 0)
diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c
index 3af5b92b48c..0166407d706 100644
--- a/drivers/net/tlan.c
+++ b/drivers/net/tlan.c
@@ -1400,7 +1400,7 @@ static void TLan_SetMulticastList( struct net_device *dev )
*
**************************************************************/
-u32 TLan_HandleInvalid( struct net_device *dev, u16 host_int )
+static u32 TLan_HandleInvalid( struct net_device *dev, u16 host_int )
{
/* printk( "TLAN: Invalid interrupt on %s.\n", dev->name ); */
return 0;
@@ -1432,7 +1432,7 @@ u32 TLan_HandleInvalid( struct net_device *dev, u16 host_int )
*
**************************************************************/
-u32 TLan_HandleTxEOF( struct net_device *dev, u16 host_int )
+static u32 TLan_HandleTxEOF( struct net_device *dev, u16 host_int )
{
TLanPrivateInfo *priv = netdev_priv(dev);
int eoc = 0;
@@ -1518,7 +1518,7 @@ u32 TLan_HandleTxEOF( struct net_device *dev, u16 host_int )
*
**************************************************************/
-u32 TLan_HandleStatOverflow( struct net_device *dev, u16 host_int )
+static u32 TLan_HandleStatOverflow( struct net_device *dev, u16 host_int )
{
TLan_ReadAndClearStats( dev, TLAN_RECORD );
@@ -1554,7 +1554,7 @@ u32 TLan_HandleStatOverflow( struct net_device *dev, u16 host_int )
*
**************************************************************/
-u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int )
+static u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int )
{
TLanPrivateInfo *priv = netdev_priv(dev);
u32 ack = 0;
@@ -1689,7 +1689,7 @@ u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int )
*
**************************************************************/
-u32 TLan_HandleDummy( struct net_device *dev, u16 host_int )
+static u32 TLan_HandleDummy( struct net_device *dev, u16 host_int )
{
printk( "TLAN: Test interrupt on %s.\n", dev->name );
return 1;
@@ -1719,7 +1719,7 @@ u32 TLan_HandleDummy( struct net_device *dev, u16 host_int )
*
**************************************************************/
-u32 TLan_HandleTxEOC( struct net_device *dev, u16 host_int )
+static u32 TLan_HandleTxEOC( struct net_device *dev, u16 host_int )
{
TLanPrivateInfo *priv = netdev_priv(dev);
TLanList *head_list;
@@ -1767,7 +1767,7 @@ u32 TLan_HandleTxEOC( struct net_device *dev, u16 host_int )
*
**************************************************************/
-u32 TLan_HandleStatusCheck( struct net_device *dev, u16 host_int )
+static u32 TLan_HandleStatusCheck( struct net_device *dev, u16 host_int )
{
TLanPrivateInfo *priv = netdev_priv(dev);
u32 ack;
@@ -1842,7 +1842,7 @@ u32 TLan_HandleStatusCheck( struct net_device *dev, u16 host_int )
*
**************************************************************/
-u32 TLan_HandleRxEOC( struct net_device *dev, u16 host_int )
+static u32 TLan_HandleRxEOC( struct net_device *dev, u16 host_int )
{
TLanPrivateInfo *priv = netdev_priv(dev);
dma_addr_t head_list_phys;
@@ -1902,7 +1902,7 @@ u32 TLan_HandleRxEOC( struct net_device *dev, u16 host_int )
*
**************************************************************/
-void TLan_Timer( unsigned long data )
+static void TLan_Timer( unsigned long data )
{
struct net_device *dev = (struct net_device *) data;
TLanPrivateInfo *priv = netdev_priv(dev);
@@ -1983,7 +1983,7 @@ void TLan_Timer( unsigned long data )
*
**************************************************************/
-void TLan_ResetLists( struct net_device *dev )
+static void TLan_ResetLists( struct net_device *dev )
{
TLanPrivateInfo *priv = netdev_priv(dev);
int i;
@@ -2043,7 +2043,7 @@ void TLan_ResetLists( struct net_device *dev )
} /* TLan_ResetLists */
-void TLan_FreeLists( struct net_device *dev )
+static void TLan_FreeLists( struct net_device *dev )
{
TLanPrivateInfo *priv = netdev_priv(dev);
int i;
@@ -2092,7 +2092,7 @@ void TLan_FreeLists( struct net_device *dev )
*
**************************************************************/
-void TLan_PrintDio( u16 io_base )
+static void TLan_PrintDio( u16 io_base )
{
u32 data0, data1;
int i;
@@ -2127,7 +2127,7 @@ void TLan_PrintDio( u16 io_base )
*
**************************************************************/
-void TLan_PrintList( TLanList *list, char *type, int num)
+static void TLan_PrintList( TLanList *list, char *type, int num)
{
int i;
@@ -2163,7 +2163,7 @@ void TLan_PrintList( TLanList *list, char *type, int num)
*
**************************************************************/
-void TLan_ReadAndClearStats( struct net_device *dev, int record )
+static void TLan_ReadAndClearStats( struct net_device *dev, int record )
{
TLanPrivateInfo *priv = netdev_priv(dev);
u32 tx_good, tx_under;
@@ -2238,7 +2238,7 @@ void TLan_ReadAndClearStats( struct net_device *dev, int record )
*
**************************************************************/
-void
+static void
TLan_ResetAdapter( struct net_device *dev )
{
TLanPrivateInfo *priv = netdev_priv(dev);
@@ -2324,7 +2324,7 @@ TLan_ResetAdapter( struct net_device *dev )
-void
+static void
TLan_FinishReset( struct net_device *dev )
{
TLanPrivateInfo *priv = netdev_priv(dev);
@@ -2448,7 +2448,7 @@ TLan_FinishReset( struct net_device *dev )
*
**************************************************************/
-void TLan_SetMac( struct net_device *dev, int areg, char *mac )
+static void TLan_SetMac( struct net_device *dev, int areg, char *mac )
{
int i;
@@ -2490,7 +2490,7 @@ void TLan_SetMac( struct net_device *dev, int areg, char *mac )
*
********************************************************************/
-void TLan_PhyPrint( struct net_device *dev )
+static void TLan_PhyPrint( struct net_device *dev )
{
TLanPrivateInfo *priv = netdev_priv(dev);
u16 i, data0, data1, data2, data3, phy;
@@ -2539,7 +2539,7 @@ void TLan_PhyPrint( struct net_device *dev )
*
********************************************************************/
-void TLan_PhyDetect( struct net_device *dev )
+static void TLan_PhyDetect( struct net_device *dev )
{
TLanPrivateInfo *priv = netdev_priv(dev);
u16 control;
@@ -2586,7 +2586,7 @@ void TLan_PhyDetect( struct net_device *dev )
-void TLan_PhyPowerDown( struct net_device *dev )
+static void TLan_PhyPowerDown( struct net_device *dev )
{
TLanPrivateInfo *priv = netdev_priv(dev);
u16 value;
@@ -2611,7 +2611,7 @@ void TLan_PhyPowerDown( struct net_device *dev )
-void TLan_PhyPowerUp( struct net_device *dev )
+static void TLan_PhyPowerUp( struct net_device *dev )
{
TLanPrivateInfo *priv = netdev_priv(dev);
u16 value;
@@ -2632,7 +2632,7 @@ void TLan_PhyPowerUp( struct net_device *dev )
-void TLan_PhyReset( struct net_device *dev )
+static void TLan_PhyReset( struct net_device *dev )
{
TLanPrivateInfo *priv = netdev_priv(dev);
u16 phy;
@@ -2660,7 +2660,7 @@ void TLan_PhyReset( struct net_device *dev )
-void TLan_PhyStartLink( struct net_device *dev )
+static void TLan_PhyStartLink( struct net_device *dev )
{
TLanPrivateInfo *priv = netdev_priv(dev);
u16 ability;
@@ -2747,7 +2747,7 @@ void TLan_PhyStartLink( struct net_device *dev )
-void TLan_PhyFinishAutoNeg( struct net_device *dev )
+static void TLan_PhyFinishAutoNeg( struct net_device *dev )
{
TLanPrivateInfo *priv = netdev_priv(dev);
u16 an_adv;
@@ -2903,7 +2903,7 @@ void TLan_PhyMonitor( struct net_device *dev )
*
**************************************************************/
-int TLan_MiiReadReg( struct net_device *dev, u16 phy, u16 reg, u16 *val )
+static int TLan_MiiReadReg( struct net_device *dev, u16 phy, u16 reg, u16 *val )
{
u8 nack;
u16 sio, tmp;
@@ -2993,7 +2993,7 @@ int TLan_MiiReadReg( struct net_device *dev, u16 phy, u16 reg, u16 *val )
*
**************************************************************/
-void TLan_MiiSendData( u16 base_port, u32 data, unsigned num_bits )
+static void TLan_MiiSendData( u16 base_port, u32 data, unsigned num_bits )
{
u16 sio;
u32 i;
@@ -3035,7 +3035,7 @@ void TLan_MiiSendData( u16 base_port, u32 data, unsigned num_bits )
*
**************************************************************/
-void TLan_MiiSync( u16 base_port )
+static void TLan_MiiSync( u16 base_port )
{
int i;
u16 sio;
@@ -3074,7 +3074,7 @@ void TLan_MiiSync( u16 base_port )
*
**************************************************************/
-void TLan_MiiWriteReg( struct net_device *dev, u16 phy, u16 reg, u16 val )
+static void TLan_MiiWriteReg( struct net_device *dev, u16 phy, u16 reg, u16 val )
{
u16 sio;
int minten;
@@ -3144,7 +3144,7 @@ void TLan_MiiWriteReg( struct net_device *dev, u16 phy, u16 reg, u16 val )
*
**************************************************************/
-void TLan_EeSendStart( u16 io_base )
+static void TLan_EeSendStart( u16 io_base )
{
u16 sio;
@@ -3184,7 +3184,7 @@ void TLan_EeSendStart( u16 io_base )
*
**************************************************************/
-int TLan_EeSendByte( u16 io_base, u8 data, int stop )
+static int TLan_EeSendByte( u16 io_base, u8 data, int stop )
{
int err;
u8 place;
@@ -3245,7 +3245,7 @@ int TLan_EeSendByte( u16 io_base, u8 data, int stop )
*
**************************************************************/
-void TLan_EeReceiveByte( u16 io_base, u8 *data, int stop )
+static void TLan_EeReceiveByte( u16 io_base, u8 *data, int stop )
{
u8 place;
u16 sio;
@@ -3303,7 +3303,7 @@ void TLan_EeReceiveByte( u16 io_base, u8 *data, int stop )
*
**************************************************************/
-int TLan_EeReadByte( struct net_device *dev, u8 ee_addr, u8 *data )
+static int TLan_EeReadByte( struct net_device *dev, u8 ee_addr, u8 *data )
{
int err;
TLanPrivateInfo *priv = netdev_priv(dev);
diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c
index 35d15e85007..6f33f84d37b 100644
--- a/drivers/net/tsi108_eth.c
+++ b/drivers/net/tsi108_eth.c
@@ -36,6 +36,7 @@
#include <linux/net.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
@@ -297,18 +298,11 @@ static void tsi108_check_phy(struct net_device *dev)
u32 speed;
unsigned long flags;
- /* Do a dummy read, as for some reason the first read
- * after a link becomes up returns link down, even if
- * it's been a while since the link came up.
- */
-
spin_lock_irqsave(&phy_lock, flags);
if (!data->phy_ok)
goto out;
- tsi108_read_mii(data, MII_BMSR);
-
duplex = mii_check_media(&data->mii_if, netif_msg_link(data), data->init_media);
data->init_media = 0;
@@ -345,22 +339,21 @@ static void tsi108_check_phy(struct net_device *dev)
TSI_WRITE(TSI108_MAC_CFG2, mac_cfg2_reg);
TSI_WRITE(TSI108_EC_PORTCTRL, portctrl_reg);
+ }
- if (data->link_up == 0) {
- /* The manual says it can take 3-4 usecs for the speed change
- * to take effect.
- */
- udelay(5);
+ if (data->link_up == 0) {
+ /* The manual says it can take 3-4 usecs for the speed change
+ * to take effect.
+ */
+ udelay(5);
- spin_lock(&data->txlock);
- if (is_valid_ether_addr(dev->dev_addr) && data->txfree)
- netif_wake_queue(dev);
+ spin_lock(&data->txlock);
+ if (is_valid_ether_addr(dev->dev_addr) && data->txfree)
+ netif_wake_queue(dev);
- data->link_up = 1;
- spin_unlock(&data->txlock);
- }
+ data->link_up = 1;
+ spin_unlock(&data->txlock);
}
-
} else {
if (data->link_up == 1) {
netif_stop_queue(dev);
@@ -1274,12 +1267,11 @@ static void tsi108_init_phy(struct net_device *dev)
* PHY_STAT register before the link up status bit is set.
*/
- data->link_up = 1;
+ data->link_up = 0;
while (!((phyval = tsi108_read_mii(data, MII_BMSR)) &
BMSR_LSTATUS)) {
if (i++ > (MII_READ_DELAY / 10)) {
- data->link_up = 0;
break;
}
spin_unlock_irqrestore(&phy_lock, flags);
@@ -1287,6 +1279,7 @@ static void tsi108_init_phy(struct net_device *dev)
spin_lock_irqsave(&phy_lock, flags);
}
+ data->mii_if.supports_gmii = mii_check_gmii_support(&data->mii_if);
printk(KERN_DEBUG "PHY_STAT reg contains %08x\n", phyval);
data->phy_ok = 1;
data->init_media = 1;
@@ -1527,12 +1520,46 @@ static void tsi108_init_mac(struct net_device *dev)
TSI_WRITE(TSI108_EC_INTMASK, ~0);
}
+static int tsi108_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct tsi108_prv_data *data = netdev_priv(dev);
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&data->txlock, flags);
+ rc = mii_ethtool_gset(&data->mii_if, cmd);
+ spin_unlock_irqrestore(&data->txlock, flags);
+
+ return rc;
+}
+
+static int tsi108_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct tsi108_prv_data *data = netdev_priv(dev);
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&data->txlock, flags);
+ rc = mii_ethtool_sset(&data->mii_if, cmd);
+ spin_unlock_irqrestore(&data->txlock, flags);
+
+ return rc;
+}
+
static int tsi108_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
struct tsi108_prv_data *data = netdev_priv(dev);
+ if (!netif_running(dev))
+ return -EINVAL;
return generic_mii_ioctl(&data->mii_if, if_mii(rq), cmd, NULL);
}
+static const struct ethtool_ops tsi108_ethtool_ops = {
+ .get_link = ethtool_op_get_link,
+ .get_settings = tsi108_get_settings,
+ .set_settings = tsi108_set_settings,
+};
+
static int
tsi108_init_one(struct platform_device *pdev)
{
@@ -1584,7 +1611,6 @@ tsi108_init_one(struct platform_device *pdev)
data->mii_if.phy_id = einfo->phy;
data->mii_if.phy_id_mask = 0x1f;
data->mii_if.reg_num_mask = 0x1f;
- data->mii_if.supports_gmii = mii_check_gmii_support(&data->mii_if);
data->phy = einfo->phy;
data->phy_type = einfo->phy_type;
@@ -1598,6 +1624,7 @@ tsi108_init_one(struct platform_device *pdev)
dev->get_stats = tsi108_get_stats;
netif_napi_add(dev, &data->napi, tsi108_poll, 64);
dev->do_ioctl = tsi108_do_ioctl;
+ dev->ethtool_ops = &tsi108_ethtool_ops;
/* Apparently, the Linux networking code won't use scatter-gather
* if the hardware doesn't do checksums. However, it's faster
@@ -1629,6 +1656,7 @@ tsi108_init_one(struct platform_device *pdev)
goto register_fail;
}
+ platform_set_drvdata(pdev, dev);
printk(KERN_INFO "%s: Tsi108 Gigabit Ethernet, MAC: %s\n",
dev->name, print_mac(mac, dev->dev_addr));
#ifdef DEBUG
diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c
index a7afeea156b..a59c1f224aa 100644
--- a/drivers/net/tulip/uli526x.c
+++ b/drivers/net/tulip/uli526x.c
@@ -482,9 +482,11 @@ static void uli526x_init(struct net_device *dev)
struct uli526x_board_info *db = netdev_priv(dev);
unsigned long ioaddr = db->ioaddr;
u8 phy_tmp;
+ u8 timeout;
u16 phy_value;
u16 phy_reg_reset;
+
ULI526X_DBUG(0, "uli526x_init()", 0);
/* Reset M526x MAC controller */
@@ -509,11 +511,19 @@ static void uli526x_init(struct net_device *dev)
/* Parser SROM and media mode */
db->media_mode = uli526x_media_mode;
- /* Phyxcer capability setting */
+ /* phyxcer capability setting */
phy_reg_reset = phy_read(db->ioaddr, db->phy_addr, 0, db->chip_id);
phy_reg_reset = (phy_reg_reset | 0x8000);
phy_write(db->ioaddr, db->phy_addr, 0, phy_reg_reset, db->chip_id);
+
+ /* See IEEE 802.3-2002.pdf (Section 2, Chapter "22.2.4 Management
+ * functions") or phy data sheet for details on phy reset
+ */
udelay(500);
+ timeout = 10;
+ while (timeout-- &&
+ phy_read(db->ioaddr, db->phy_addr, 0, db->chip_id) & 0x8000)
+ udelay(100);
/* Process Phyxcer Media Mode */
uli526x_set_phyxcer(db);
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 3f67a29593b..e2ad98bee6e 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -244,18 +244,6 @@ static int veth_open(struct net_device *dev)
return 0;
}
-static int veth_close(struct net_device *dev)
-{
- struct veth_priv *priv;
-
- if (netif_carrier_ok(dev)) {
- priv = netdev_priv(dev);
- netif_carrier_off(dev);
- netif_carrier_off(priv->peer);
- }
- return 0;
-}
-
static int veth_dev_init(struct net_device *dev)
{
struct veth_net_stats *stats;
@@ -286,13 +274,50 @@ static void veth_setup(struct net_device *dev)
dev->hard_start_xmit = veth_xmit;
dev->get_stats = veth_get_stats;
dev->open = veth_open;
- dev->stop = veth_close;
dev->ethtool_ops = &veth_ethtool_ops;
dev->features |= NETIF_F_LLTX;
dev->init = veth_dev_init;
dev->destructor = veth_dev_free;
}
+static void veth_change_state(struct net_device *dev)
+{
+ struct net_device *peer;
+ struct veth_priv *priv;
+
+ priv = netdev_priv(dev);
+ peer = priv->peer;
+
+ if (netif_carrier_ok(peer)) {
+ if (!netif_carrier_ok(dev))
+ netif_carrier_on(dev);
+ } else {
+ if (netif_carrier_ok(dev))
+ netif_carrier_off(dev);
+ }
+}
+
+static int veth_device_event(struct notifier_block *unused,
+ unsigned long event, void *ptr)
+{
+ struct net_device *dev = ptr;
+
+ if (dev->open != veth_open)
+ goto out;
+
+ switch (event) {
+ case NETDEV_CHANGE:
+ veth_change_state(dev);
+ break;
+ }
+out:
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block veth_notifier_block __read_mostly = {
+ .notifier_call = veth_device_event,
+};
+
/*
* netlink interface
*/
@@ -454,12 +479,14 @@ static struct rtnl_link_ops veth_link_ops = {
static __init int veth_init(void)
{
+ register_netdevice_notifier(&veth_notifier_block);
return rtnl_link_register(&veth_link_ops);
}
static __exit void veth_exit(void)
{
rtnl_link_unregister(&veth_link_ops);
+ unregister_netdevice_notifier(&veth_notifier_block);
}
module_init(veth_init);
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index 7c851b1e6da..8c9d6ae2bb3 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -1893,7 +1893,7 @@ static void rhine_shutdown (struct pci_dev *pdev)
/* Make sure we use pattern 0, 1 and not 4, 5 */
if (rp->quirks & rq6patterns)
- iowrite8(0x04, ioaddr + 0xA7);
+ iowrite8(0x04, ioaddr + WOLcgClr);
if (rp->wolopts & WAKE_MAGIC) {
iowrite8(WOLmagic, ioaddr + WOLcrSet);
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index fdc23678117..19fd4cb0ddf 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -361,6 +361,7 @@ static int virtnet_probe(struct virtio_device *vdev)
netif_napi_add(dev, &vi->napi, virtnet_poll, napi_weight);
vi->dev = dev;
vi->vdev = vdev;
+ vdev->priv = vi;
/* We expect two virtqueues, receive then send. */
vi->rvq = vdev->config->find_vq(vdev, 0, skb_recv_done);
@@ -395,7 +396,6 @@ static int virtnet_probe(struct virtio_device *vdev)
}
pr_debug("virtnet: registered device %s\n", dev->name);
- vdev->priv = vi;
return 0;
unregister:
diff --git a/drivers/net/wireless/ath5k/ath5k.h b/drivers/net/wireless/ath5k/ath5k.h
index c79066b38d3..69dea339261 100644
--- a/drivers/net/wireless/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath5k/ath5k.h
@@ -1035,7 +1035,7 @@ struct ath5k_hw {
unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int,
unsigned int, unsigned int, unsigned int, unsigned int,
unsigned int, unsigned int, unsigned int);
- bool (*ah_setup_xtx_desc)(struct ath5k_hw *, struct ath5k_desc *,
+ int (*ah_setup_xtx_desc)(struct ath5k_hw *, struct ath5k_desc *,
unsigned int, unsigned int, unsigned int, unsigned int,
unsigned int, unsigned int);
int (*ah_proc_tx_desc)(struct ath5k_hw *, struct ath5k_desc *);
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c
index ddc87149fe3..bef967ce34a 100644
--- a/drivers/net/wireless/ath5k/base.c
+++ b/drivers/net/wireless/ath5k/base.c
@@ -668,7 +668,10 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
* return false w/o doing anything. MAC's that do
* support it will return true w/o doing anything.
*/
- if (ah->ah_setup_xtx_desc(ah, NULL, 0, 0, 0, 0, 0, 0))
+ ret = ah->ah_setup_xtx_desc(ah, NULL, 0, 0, 0, 0, 0, 0);
+ if (ret < 0)
+ goto err;
+ if (ret > 0)
__set_bit(ATH_STAT_MRRETRY, sc->status);
/*
@@ -1256,7 +1259,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
if (ctl->flags & IEEE80211_TXCTL_NO_ACK)
flags |= AR5K_TXDESC_NOACK;
- pktlen = skb->len + FCS_LEN;
+ pktlen = skb->len;
if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) {
keyidx = ctl->key_idx;
@@ -1715,6 +1718,7 @@ ath5k_tasklet_rx(unsigned long data)
break;
else if (unlikely(ret)) {
ATH5K_ERR(sc, "error in processing rx descriptor\n");
+ spin_unlock(&sc->rxbuflock);
return;
}
@@ -1952,7 +1956,7 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
}
ds->ds_data = bf->skbaddr;
- ret = ah->ah_setup_tx_desc(ah, ds, skb->len + FCS_LEN,
+ ret = ah->ah_setup_tx_desc(ah, ds, skb->len,
ieee80211_get_hdrlen_from_skb(skb),
AR5K_PKT_TYPE_BEACON, (ctl->power_level * 2), ctl->tx_rate, 1,
AR5K_TXKEYIX_INVALID, antenna, flags, 0, 0);
@@ -2126,8 +2130,9 @@ ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf)
"updated timers based on beacon TSF\n");
ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON,
- "bc_tsf %llx hw_tsf %llx bc_tu %u hw_tu %u nexttbtt %u\n",
- bc_tsf, hw_tsf, bc_tu, hw_tu, nexttbtt);
+ "bc_tsf %llx hw_tsf %llx bc_tu %u hw_tu %u nexttbtt %u\n",
+ (unsigned long long) bc_tsf,
+ (unsigned long long) hw_tsf, bc_tu, hw_tu, nexttbtt);
ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, "intval %u %s %s\n",
intval & AR5K_BEACON_PERIOD,
intval & AR5K_BEACON_ENA ? "AR5K_BEACON_ENA" : "",
@@ -2385,10 +2390,11 @@ ath5k_intr(int irq, void *dev_id)
u64 tsf = ath5k_hw_get_tsf64(ah);
sc->nexttbtt += sc->bintval;
ATH5K_DBG(sc, ATH5K_DEBUG_BEACON,
- "SWBA nexttbtt: %x hw_tu: %x "
- "TSF: %llx\n",
- sc->nexttbtt,
- TSF_TO_TU(tsf), tsf);
+ "SWBA nexttbtt: %x hw_tu: %x "
+ "TSF: %llx\n",
+ sc->nexttbtt,
+ TSF_TO_TU(tsf),
+ (unsigned long long) tsf);
} else {
ath5k_beacon_send(sc);
}
diff --git a/drivers/net/wireless/ath5k/hw.c b/drivers/net/wireless/ath5k/hw.c
index 3a4bf4035a2..c2de2d958e8 100644
--- a/drivers/net/wireless/ath5k/hw.c
+++ b/drivers/net/wireless/ath5k/hw.c
@@ -45,7 +45,7 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *, struct ath5k_desc *,
unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int,
unsigned int, unsigned int, unsigned int, unsigned int, unsigned int,
unsigned int, unsigned int);
-static bool ath5k_hw_setup_xr_tx_desc(struct ath5k_hw *, struct ath5k_desc *,
+static int ath5k_hw_setup_xr_tx_desc(struct ath5k_hw *, struct ath5k_desc *,
unsigned int, unsigned int, unsigned int, unsigned int, unsigned int,
unsigned int);
static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *, struct ath5k_desc *);
@@ -3506,7 +3506,7 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
{
u32 frame_type;
struct ath5k_hw_2w_tx_desc *tx_desc;
- unsigned int buff_len;
+ unsigned int frame_len;
tx_desc = (struct ath5k_hw_2w_tx_desc *)&desc->ds_ctl0;
@@ -3537,22 +3537,25 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
/* Setup control descriptor */
/* Verify and set frame length */
- if (pkt_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN)
+
+ /* remove padding we might have added before */
+ frame_len = pkt_len - (hdr_len & 3) + FCS_LEN;
+
+ if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN)
return -EINVAL;
- tx_desc->tx_control_0 = pkt_len & AR5K_2W_TX_DESC_CTL0_FRAME_LEN;
+ tx_desc->tx_control_0 = frame_len & AR5K_2W_TX_DESC_CTL0_FRAME_LEN;
/* Verify and set buffer length */
- buff_len = pkt_len - FCS_LEN;
/* NB: beacon's BufLen must be a multiple of 4 bytes */
if(type == AR5K_PKT_TYPE_BEACON)
- buff_len = roundup(buff_len, 4);
+ pkt_len = roundup(pkt_len, 4);
- if (buff_len & ~AR5K_2W_TX_DESC_CTL1_BUF_LEN)
+ if (pkt_len & ~AR5K_2W_TX_DESC_CTL1_BUF_LEN)
return -EINVAL;
- tx_desc->tx_control_1 = buff_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN;
+ tx_desc->tx_control_1 = pkt_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN;
/*
* Verify and set header length
@@ -3634,7 +3637,7 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
{
struct ath5k_hw_4w_tx_desc *tx_desc;
struct ath5k_hw_tx_status *tx_status;
- unsigned int buff_len;
+ unsigned int frame_len;
ATH5K_TRACE(ah->ah_sc);
tx_desc = (struct ath5k_hw_4w_tx_desc *)&desc->ds_ctl0;
@@ -3669,22 +3672,25 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
/* Setup control descriptor */
/* Verify and set frame length */
- if (pkt_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN)
+
+ /* remove padding we might have added before */
+ frame_len = pkt_len - (hdr_len & 3) + FCS_LEN;
+
+ if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN)
return -EINVAL;
- tx_desc->tx_control_0 = pkt_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN;
+ tx_desc->tx_control_0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN;
/* Verify and set buffer length */
- buff_len = pkt_len - FCS_LEN;
/* NB: beacon's BufLen must be a multiple of 4 bytes */
if(type == AR5K_PKT_TYPE_BEACON)
- buff_len = roundup(buff_len, 4);
+ pkt_len = roundup(pkt_len, 4);
- if (buff_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN)
+ if (pkt_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN)
return -EINVAL;
- tx_desc->tx_control_1 = buff_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN;
+ tx_desc->tx_control_1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN;
tx_desc->tx_control_0 |=
AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) |
@@ -3737,7 +3743,7 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
/*
* Initialize a 4-word multirate tx descriptor on 5212
*/
-static bool
+static int
ath5k_hw_setup_xr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2, u_int tx_tries2,
unsigned int tx_rate3, u_int tx_tries3)
@@ -3777,10 +3783,10 @@ ath5k_hw_setup_xr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
#undef _XTX_TRIES
- return true;
+ return 1;
}
- return false;
+ return 0;
}
/*
diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig
index 1a2141dabdc..8bc4bc4c330 100644
--- a/drivers/net/wireless/b43/Kconfig
+++ b/drivers/net/wireless/b43/Kconfig
@@ -32,6 +32,7 @@ config B43_PCI_AUTOSELECT
bool
depends on B43 && SSB_PCIHOST_POSSIBLE
select SSB_PCIHOST
+ select SSB_B43_PCI_BRIDGE
default y
# Auto-select SSB PCICORE driver, if possible
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index 08a011f0834..f13346ba9dd 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -14,6 +14,12 @@
#include "lo.h"
#include "phy.h"
+
+/* The unique identifier of the firmware that's officially supported by
+ * this driver version. */
+#define B43_SUPPORTED_FIRMWARE_ID "FW13"
+
+
#ifdef CONFIG_B43_DEBUG
# define B43_DEBUG 1
#else
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index ef65c41af00..51dfce16178 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -58,6 +58,8 @@ MODULE_AUTHOR("Stefano Brivio");
MODULE_AUTHOR("Michael Buesch");
MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(B43_SUPPORTED_FIRMWARE_ID);
+
static int modparam_bad_frames_preempt;
module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);
@@ -1859,11 +1861,11 @@ static int b43_upload_microcode(struct b43_wldev *dev)
err = -EOPNOTSUPP;
goto error;
}
- b43dbg(dev->wl, "Loading firmware version %u.%u "
- "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n",
- fwrev, fwpatch,
- (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF,
- (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F);
+ b43info(dev->wl, "Loading firmware version %u.%u "
+ "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n",
+ fwrev, fwpatch,
+ (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF,
+ (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F);
dev->fw.rev = fwrev;
dev->fw.patch = fwpatch;
@@ -4200,6 +4202,33 @@ static struct ssb_driver b43_ssb_driver = {
.resume = b43_resume,
};
+static void b43_print_driverinfo(void)
+{
+ const char *feat_pci = "", *feat_pcmcia = "", *feat_nphy = "",
+ *feat_leds = "", *feat_rfkill = "";
+
+#ifdef CONFIG_B43_PCI_AUTOSELECT
+ feat_pci = "P";
+#endif
+#ifdef CONFIG_B43_PCMCIA
+ feat_pcmcia = "M";
+#endif
+#ifdef CONFIG_B43_NPHY
+ feat_nphy = "N";
+#endif
+#ifdef CONFIG_B43_LEDS
+ feat_leds = "L";
+#endif
+#ifdef CONFIG_B43_RFKILL
+ feat_rfkill = "R";
+#endif
+ printk(KERN_INFO "Broadcom 43xx driver loaded "
+ "[ Features: %s%s%s%s%s, Firmware-ID: "
+ B43_SUPPORTED_FIRMWARE_ID " ]\n",
+ feat_pci, feat_pcmcia, feat_nphy,
+ feat_leds, feat_rfkill);
+}
+
static int __init b43_init(void)
{
int err;
@@ -4211,6 +4240,7 @@ static int __init b43_init(void)
err = ssb_driver_register(&b43_ssb_driver);
if (err)
goto err_pcmcia_exit;
+ b43_print_driverinfo();
return err;
diff --git a/drivers/net/wireless/b43legacy/Kconfig b/drivers/net/wireless/b43legacy/Kconfig
index 6745579ba96..13c65faf024 100644
--- a/drivers/net/wireless/b43legacy/Kconfig
+++ b/drivers/net/wireless/b43legacy/Kconfig
@@ -25,6 +25,7 @@ config B43LEGACY_PCI_AUTOSELECT
bool
depends on B43LEGACY && SSB_PCIHOST_POSSIBLE
select SSB_PCIHOST
+ select SSB_B43_PCI_BRIDGE
default y
# Auto-select SSB PCICORE driver, if possible
diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h
index c80edd2b904..93d45b71799 100644
--- a/drivers/net/wireless/b43legacy/b43legacy.h
+++ b/drivers/net/wireless/b43legacy/b43legacy.h
@@ -23,6 +23,10 @@
#include "phy.h"
+/* The unique identifier of the firmware that's officially supported by this
+ * driver version. */
+#define B43legacy_SUPPORTED_FIRMWARE_ID "FW10"
+
#define B43legacy_IRQWAIT_MAX_RETRIES 20
#define B43legacy_RX_MAX_SSI 60 /* best guess at max ssi */
diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c
index 6e08405e802..e87b427d5e4 100644
--- a/drivers/net/wireless/b43legacy/dma.c
+++ b/drivers/net/wireless/b43legacy/dma.c
@@ -354,7 +354,8 @@ return 0;
}
-u16 b43legacy_dmacontroller_base(int dma64bit, int controller_idx)
+static u16 b43legacy_dmacontroller_base(enum b43legacy_dmatype type,
+ int controller_idx)
{
static const u16 map64[] = {
B43legacy_MMIO_DMA64_BASE0,
@@ -373,7 +374,7 @@ u16 b43legacy_dmacontroller_base(int dma64bit, int controller_idx)
B43legacy_MMIO_DMA32_BASE5,
};
- if (dma64bit) {
+ if (type == B43legacy_DMA_64BIT) {
B43legacy_WARN_ON(!(controller_idx >= 0 &&
controller_idx < ARRAY_SIZE(map64)));
return map64[controller_idx];
@@ -480,8 +481,9 @@ static void free_ringmemory(struct b43legacy_dmaring *ring)
}
/* Reset the RX DMA channel */
-int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev,
- u16 mmio_base, int dma64)
+static int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev,
+ u16 mmio_base,
+ enum b43legacy_dmatype type)
{
int i;
u32 value;
@@ -489,13 +491,14 @@ int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev,
might_sleep();
- offset = dma64 ? B43legacy_DMA64_RXCTL : B43legacy_DMA32_RXCTL;
+ offset = (type == B43legacy_DMA_64BIT) ?
+ B43legacy_DMA64_RXCTL : B43legacy_DMA32_RXCTL;
b43legacy_write32(dev, mmio_base + offset, 0);
for (i = 0; i < 10; i++) {
- offset = dma64 ? B43legacy_DMA64_RXSTATUS :
- B43legacy_DMA32_RXSTATUS;
+ offset = (type == B43legacy_DMA_64BIT) ?
+ B43legacy_DMA64_RXSTATUS : B43legacy_DMA32_RXSTATUS;
value = b43legacy_read32(dev, mmio_base + offset);
- if (dma64) {
+ if (type == B43legacy_DMA_64BIT) {
value &= B43legacy_DMA64_RXSTAT;
if (value == B43legacy_DMA64_RXSTAT_DISABLED) {
i = -1;
@@ -519,8 +522,9 @@ int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev,
}
/* Reset the RX DMA channel */
-int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev,
- u16 mmio_base, int dma64)
+static int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev,
+ u16 mmio_base,
+ enum b43legacy_dmatype type)
{
int i;
u32 value;
@@ -529,10 +533,10 @@ int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev,
might_sleep();
for (i = 0; i < 10; i++) {
- offset = dma64 ? B43legacy_DMA64_TXSTATUS :
- B43legacy_DMA32_TXSTATUS;
+ offset = (type == B43legacy_DMA_64BIT) ?
+ B43legacy_DMA64_TXSTATUS : B43legacy_DMA32_TXSTATUS;
value = b43legacy_read32(dev, mmio_base + offset);
- if (dma64) {
+ if (type == B43legacy_DMA_64BIT) {
value &= B43legacy_DMA64_TXSTAT;
if (value == B43legacy_DMA64_TXSTAT_DISABLED ||
value == B43legacy_DMA64_TXSTAT_IDLEWAIT ||
@@ -547,13 +551,14 @@ int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev,
}
msleep(1);
}
- offset = dma64 ? B43legacy_DMA64_TXCTL : B43legacy_DMA32_TXCTL;
+ offset = (type == B43legacy_DMA_64BIT) ? B43legacy_DMA64_TXCTL :
+ B43legacy_DMA32_TXCTL;
b43legacy_write32(dev, mmio_base + offset, 0);
for (i = 0; i < 10; i++) {
- offset = dma64 ? B43legacy_DMA64_TXSTATUS :
- B43legacy_DMA32_TXSTATUS;
+ offset = (type == B43legacy_DMA_64BIT) ?
+ B43legacy_DMA64_TXSTATUS : B43legacy_DMA32_TXSTATUS;
value = b43legacy_read32(dev, mmio_base + offset);
- if (dma64) {
+ if (type == B43legacy_DMA_64BIT) {
value &= B43legacy_DMA64_TXSTAT;
if (value == B43legacy_DMA64_TXSTAT_DISABLED) {
i = -1;
@@ -578,6 +583,32 @@ int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev,
return 0;
}
+/* Check if a DMA mapping address is invalid. */
+static bool b43legacy_dma_mapping_error(struct b43legacy_dmaring *ring,
+ dma_addr_t addr,
+ size_t buffersize)
+{
+ if (unlikely(dma_mapping_error(addr)))
+ return 1;
+
+ switch (ring->type) {
+ case B43legacy_DMA_30BIT:
+ if ((u64)addr + buffersize > (1ULL << 30))
+ return 1;
+ break;
+ case B43legacy_DMA_32BIT:
+ if ((u64)addr + buffersize > (1ULL << 32))
+ return 1;
+ break;
+ case B43legacy_DMA_64BIT:
+ /* Currently we can't have addresses beyond 64 bits in the kernel. */
+ break;
+ }
+
+ /* The address is OK. */
+ return 0;
+}
+
static int setup_rx_descbuffer(struct b43legacy_dmaring *ring,
struct b43legacy_dmadesc_generic *desc,
struct b43legacy_dmadesc_meta *meta,
@@ -595,7 +626,7 @@ static int setup_rx_descbuffer(struct b43legacy_dmaring *ring,
return -ENOMEM;
dmaaddr = map_descbuffer(ring, skb->data,
ring->rx_buffersize, 0);
- if (dma_mapping_error(dmaaddr)) {
+ if (b43legacy_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize)) {
/* ugh. try to realloc in zone_dma */
gfp_flags |= GFP_DMA;
@@ -608,7 +639,7 @@ static int setup_rx_descbuffer(struct b43legacy_dmaring *ring,
ring->rx_buffersize, 0);
}
- if (dma_mapping_error(dmaaddr)) {
+ if (b43legacy_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize)) {
dev_kfree_skb_any(skb);
return -EIO;
}
@@ -674,7 +705,7 @@ static int dmacontroller_setup(struct b43legacy_dmaring *ring)
u32 trans = ssb_dma_translation(ring->dev->dev);
if (ring->tx) {
- if (ring->dma64) {
+ if (ring->type == B43legacy_DMA_64BIT) {
u64 ringbase = (u64)(ring->dmabase);
addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
@@ -709,7 +740,7 @@ static int dmacontroller_setup(struct b43legacy_dmaring *ring)
err = alloc_initial_descbuffers(ring);
if (err)
goto out;
- if (ring->dma64) {
+ if (ring->type == B43legacy_DMA_64BIT) {
u64 ringbase = (u64)(ring->dmabase);
addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
@@ -760,16 +791,16 @@ static void dmacontroller_cleanup(struct b43legacy_dmaring *ring)
{
if (ring->tx) {
b43legacy_dmacontroller_tx_reset(ring->dev, ring->mmio_base,
- ring->dma64);
- if (ring->dma64) {
+ ring->type);
+ if (ring->type == B43legacy_DMA_64BIT) {
b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGLO, 0);
b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGHI, 0);
} else
b43legacy_dma_write(ring, B43legacy_DMA32_TXRING, 0);
} else {
b43legacy_dmacontroller_rx_reset(ring->dev, ring->mmio_base,
- ring->dma64);
- if (ring->dma64) {
+ ring->type);
+ if (ring->type == B43legacy_DMA_64BIT) {
b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGLO, 0);
b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGHI, 0);
} else
@@ -824,11 +855,10 @@ static u64 supported_dma_mask(struct b43legacy_wldev *dev)
/* Main initialization function. */
static
-struct b43legacy_dmaring *b43legacy_setup_dmaring(
- struct b43legacy_wldev *dev,
- int controller_index,
- int for_tx,
- int dma64)
+struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev,
+ int controller_index,
+ int for_tx,
+ enum b43legacy_dmatype type)
{
struct b43legacy_dmaring *ring;
int err;
@@ -838,6 +868,7 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(
ring = kzalloc(sizeof(*ring), GFP_KERNEL);
if (!ring)
goto out;
+ ring->type = type;
nr_slots = B43legacy_RXRING_SLOTS;
if (for_tx)
@@ -855,12 +886,12 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(
goto err_kfree_meta;
/* test for ability to dma to txhdr_cache */
- dma_test = dma_map_single(dev->dev->dev,
- ring->txhdr_cache,
- sizeof(struct b43legacy_txhdr_fw3),
- DMA_TO_DEVICE);
+ dma_test = dma_map_single(dev->dev->dev, ring->txhdr_cache,
+ sizeof(struct b43legacy_txhdr_fw3),
+ DMA_TO_DEVICE);
- if (dma_mapping_error(dma_test)) {
+ if (b43legacy_dma_mapping_error(ring, dma_test,
+ sizeof(struct b43legacy_txhdr_fw3))) {
/* ugh realloc */
kfree(ring->txhdr_cache);
ring->txhdr_cache = kcalloc(nr_slots,
@@ -874,7 +905,8 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(
sizeof(struct b43legacy_txhdr_fw3),
DMA_TO_DEVICE);
- if (dma_mapping_error(dma_test))
+ if (b43legacy_dma_mapping_error(ring, dma_test,
+ sizeof(struct b43legacy_txhdr_fw3)))
goto err_kfree_txhdr_cache;
}
@@ -885,11 +917,9 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(
ring->dev = dev;
ring->nr_slots = nr_slots;
- ring->mmio_base = b43legacy_dmacontroller_base(dma64,
- controller_index);
+ ring->mmio_base = b43legacy_dmacontroller_base(type, controller_index);
ring->index = controller_index;
- ring->dma64 = !!dma64;
- if (dma64)
+ if (type == B43legacy_DMA_64BIT)
ring->ops = &dma64_ops;
else
ring->ops = &dma32_ops;
@@ -939,10 +969,10 @@ static void b43legacy_destroy_dmaring(struct b43legacy_dmaring *ring)
if (!ring)
return;
- b43legacydbg(ring->dev->wl, "DMA-%s 0x%04X (%s) max used slots:"
- " %d/%d\n", (ring->dma64) ? "64" : "32", ring->mmio_base,
- (ring->tx) ? "TX" : "RX",
- ring->max_used_slots, ring->nr_slots);
+ b43legacydbg(ring->dev->wl, "DMA-%u 0x%04X (%s) max used slots:"
+ " %d/%d\n", (unsigned int)(ring->type), ring->mmio_base,
+ (ring->tx) ? "TX" : "RX", ring->max_used_slots,
+ ring->nr_slots);
/* Device IRQs are disabled prior entering this function,
* so no need to take care of concurrency with rx handler stuff.
*/
@@ -988,11 +1018,22 @@ int b43legacy_dma_init(struct b43legacy_wldev *dev)
struct b43legacy_dmaring *ring;
int err;
u64 dmamask;
- int dma64 = 0;
+ enum b43legacy_dmatype type;
dmamask = supported_dma_mask(dev);
- if (dmamask == DMA_64BIT_MASK)
- dma64 = 1;
+ switch (dmamask) {
+ default:
+ B43legacy_WARN_ON(1);
+ case DMA_30BIT_MASK:
+ type = B43legacy_DMA_30BIT;
+ break;
+ case DMA_32BIT_MASK:
+ type = B43legacy_DMA_32BIT;
+ break;
+ case DMA_64BIT_MASK:
+ type = B43legacy_DMA_64BIT;
+ break;
+ }
err = ssb_dma_set_mask(dev->dev, dmamask);
if (err) {
@@ -1010,52 +1051,50 @@ int b43legacy_dma_init(struct b43legacy_wldev *dev)
err = -ENOMEM;
/* setup TX DMA channels. */
- ring = b43legacy_setup_dmaring(dev, 0, 1, dma64);
+ ring = b43legacy_setup_dmaring(dev, 0, 1, type);
if (!ring)
goto out;
dma->tx_ring0 = ring;
- ring = b43legacy_setup_dmaring(dev, 1, 1, dma64);
+ ring = b43legacy_setup_dmaring(dev, 1, 1, type);
if (!ring)
goto err_destroy_tx0;
dma->tx_ring1 = ring;
- ring = b43legacy_setup_dmaring(dev, 2, 1, dma64);
+ ring = b43legacy_setup_dmaring(dev, 2, 1, type);
if (!ring)
goto err_destroy_tx1;
dma->tx_ring2 = ring;
- ring = b43legacy_setup_dmaring(dev, 3, 1, dma64);
+ ring = b43legacy_setup_dmaring(dev, 3, 1, type);
if (!ring)
goto err_destroy_tx2;
dma->tx_ring3 = ring;
- ring = b43legacy_setup_dmaring(dev, 4, 1, dma64);
+ ring = b43legacy_setup_dmaring(dev, 4, 1, type);
if (!ring)
goto err_destroy_tx3;
dma->tx_ring4 = ring;
- ring = b43legacy_setup_dmaring(dev, 5, 1, dma64);
+ ring = b43legacy_setup_dmaring(dev, 5, 1, type);
if (!ring)
goto err_destroy_tx4;
dma->tx_ring5 = ring;
/* setup RX DMA channels. */
- ring = b43legacy_setup_dmaring(dev, 0, 0, dma64);
+ ring = b43legacy_setup_dmaring(dev, 0, 0, type);
if (!ring)
goto err_destroy_tx5;
dma->rx_ring0 = ring;
if (dev->dev->id.revision < 5) {
- ring = b43legacy_setup_dmaring(dev, 3, 0, dma64);
+ ring = b43legacy_setup_dmaring(dev, 3, 0, type);
if (!ring)
goto err_destroy_rx0;
dma->rx_ring3 = ring;
}
- b43legacydbg(dev->wl, "%d-bit DMA initialized\n",
- (dmamask == DMA_64BIT_MASK) ? 64 :
- (dmamask == DMA_32BIT_MASK) ? 32 : 30);
+ b43legacydbg(dev->wl, "%u-bit DMA initialized\n", (unsigned int)type);
err = 0;
out:
return err;
@@ -1194,9 +1233,13 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring,
}
meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header,
- sizeof(struct b43legacy_txhdr_fw3), 1);
- if (dma_mapping_error(meta_hdr->dmaaddr))
+ sizeof(struct b43legacy_txhdr_fw3), 1);
+ if (b43legacy_dma_mapping_error(ring, meta_hdr->dmaaddr,
+ sizeof(struct b43legacy_txhdr_fw3))) {
+ ring->current_slot = old_top_slot;
+ ring->used_slots = old_used_slots;
return -EIO;
+ }
ops->fill_descriptor(ring, desc, meta_hdr->dmaaddr,
sizeof(struct b43legacy_txhdr_fw3), 1, 0, 0);
@@ -1211,7 +1254,7 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring,
meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
/* create a bounce buffer in zone_dma on mapping failure. */
- if (dma_mapping_error(meta->dmaaddr)) {
+ if (b43legacy_dma_mapping_error(ring, meta->dmaaddr, skb->len)) {
bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA);
if (!bounce_skb) {
ring->current_slot = old_top_slot;
@@ -1225,7 +1268,7 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring,
skb = bounce_skb;
meta->skb = skb;
meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
- if (dma_mapping_error(meta->dmaaddr)) {
+ if (b43legacy_dma_mapping_error(ring, meta->dmaaddr, skb->len)) {
ring->current_slot = old_top_slot;
ring->used_slots = old_used_slots;
err = -EIO;
diff --git a/drivers/net/wireless/b43legacy/dma.h b/drivers/net/wireless/b43legacy/dma.h
index 26f6ab08de7..2dd488c5be2 100644
--- a/drivers/net/wireless/b43legacy/dma.h
+++ b/drivers/net/wireless/b43legacy/dma.h
@@ -218,6 +218,12 @@ struct b43legacy_dma_ops {
void (*set_current_rxslot)(struct b43legacy_dmaring *ring, int slot);
};
+enum b43legacy_dmatype {
+ B43legacy_DMA_30BIT = 30,
+ B43legacy_DMA_32BIT = 32,
+ B43legacy_DMA_64BIT = 64,
+};
+
struct b43legacy_dmaring {
/* Lowlevel DMA ops. */
const struct b43legacy_dma_ops *ops;
@@ -250,8 +256,8 @@ struct b43legacy_dmaring {
int index;
/* Boolean. Is this a TX ring? */
bool tx;
- /* Boolean. 64bit DMA if true, 32bit DMA otherwise. */
- bool dma64;
+ /* The type of DMA engine used. */
+ enum b43legacy_dmatype type;
/* Boolean. Is this ring stopped at ieee80211 level? */
bool stopped;
/* Lock, only used for TX. */
@@ -284,15 +290,6 @@ void b43legacy_dma_write(struct b43legacy_dmaring *ring,
int b43legacy_dma_init(struct b43legacy_wldev *dev);
void b43legacy_dma_free(struct b43legacy_wldev *dev);
-int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev,
- u16 dmacontroller_mmio_base,
- int dma64);
-int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev,
- u16 dmacontroller_mmio_base,
- int dma64);
-
-u16 b43legacy_dmacontroller_base(int dma64bit, int dmacontroller_idx);
-
void b43legacy_dma_tx_suspend(struct b43legacy_wldev *dev);
void b43legacy_dma_tx_resume(struct b43legacy_wldev *dev);
@@ -320,20 +317,6 @@ void b43legacy_dma_free(struct b43legacy_wldev *dev)
{
}
static inline
-int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev,
- u16 dmacontroller_mmio_base,
- int dma64)
-{
- return 0;
-}
-static inline
-int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev,
- u16 dmacontroller_mmio_base,
- int dma64)
-{
- return 0;
-}
-static inline
void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev,
struct ieee80211_tx_queue_stats *stats)
{
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index 53f7f2e9761..c39de422e22 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -3,7 +3,7 @@
* Broadcom B43legacy wireless driver
*
* Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>
- * Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it>
+ * Copyright (c) 2005-2008 Stefano Brivio <stefano.brivio@polimi.it>
* Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de>
* Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
* Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
@@ -60,6 +60,8 @@ MODULE_AUTHOR("Stefano Brivio");
MODULE_AUTHOR("Michael Buesch");
MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(B43legacy_SUPPORTED_FIRMWARE_ID);
+
#if defined(CONFIG_B43LEGACY_DMA) && defined(CONFIG_B43LEGACY_PIO)
static int modparam_pio;
module_param_named(pio, modparam_pio, int, 0444);
@@ -1640,10 +1642,11 @@ static int b43legacy_upload_microcode(struct b43legacy_wldev *dev)
err = -EOPNOTSUPP;
goto error;
}
- b43legacydbg(dev->wl, "Loading firmware version 0x%X, patch level %u "
- "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", fwrev, fwpatch,
- (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF,
- (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F);
+ b43legacyinfo(dev->wl, "Loading firmware version 0x%X, patch level %u "
+ "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", fwrev, fwpatch,
+ (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF,
+ (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F,
+ fwtime & 0x1F);
dev->fw.rev = fwrev;
dev->fw.patch = fwpatch;
@@ -3806,6 +3809,32 @@ static struct ssb_driver b43legacy_ssb_driver = {
.resume = b43legacy_resume,
};
+static void b43legacy_print_driverinfo(void)
+{
+ const char *feat_pci = "", *feat_leds = "", *feat_rfkill = "",
+ *feat_pio = "", *feat_dma = "";
+
+#ifdef CONFIG_B43LEGACY_PCI_AUTOSELECT
+ feat_pci = "P";
+#endif
+#ifdef CONFIG_B43LEGACY_LEDS
+ feat_leds = "L";
+#endif
+#ifdef CONFIG_B43LEGACY_RFKILL
+ feat_rfkill = "R";
+#endif
+#ifdef CONFIG_B43LEGACY_PIO
+ feat_pio = "I";
+#endif
+#ifdef CONFIG_B43LEGACY_DMA
+ feat_dma = "D";
+#endif
+ printk(KERN_INFO "Broadcom 43xx driver loaded "
+ "[ Features: %s%s%s%s%s, Firmware-ID: "
+ B43legacy_SUPPORTED_FIRMWARE_ID " ]\n",
+ feat_pci, feat_leds, feat_rfkill, feat_pio, feat_dma);
+}
+
static int __init b43legacy_init(void)
{
int err;
@@ -3816,6 +3845,8 @@ static int __init b43legacy_init(void)
if (err)
goto err_dfs_exit;
+ b43legacy_print_driverinfo();
+
return err;
err_dfs_exit:
diff --git a/drivers/net/wireless/bcm43xx/Kconfig b/drivers/net/wireless/bcm43xx/Kconfig
index 0159701e845..afb8f4305c2 100644
--- a/drivers/net/wireless/bcm43xx/Kconfig
+++ b/drivers/net/wireless/bcm43xx/Kconfig
@@ -1,6 +1,6 @@
config BCM43XX
tristate "Broadcom BCM43xx wireless support (DEPRECATED)"
- depends on PCI && IEEE80211 && IEEE80211_SOFTMAC && WLAN_80211 && EXPERIMENTAL
+ depends on PCI && IEEE80211 && IEEE80211_SOFTMAC && WLAN_80211 && (!SSB_B43_PCI_BRIDGE || SSB != y) && EXPERIMENTAL
select WIRELESS_EXT
select FW_LOADER
select HW_RANDOM
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index 3e6ad7b92c8..a56d9fc6354 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -3365,7 +3365,6 @@ static void ipw_rx_queue_reset(struct ipw_priv *priv,
/* Set us so that we have processed and used all buffers, but have
* not restocked the Rx queue with fresh buffers */
rxq->read = rxq->write = 0;
- rxq->processed = RX_QUEUE_SIZE - 1;
rxq->free_count = 0;
spin_unlock_irqrestore(&rxq->lock, flags);
}
@@ -3607,7 +3606,22 @@ static int ipw_load(struct ipw_priv *priv)
* Driver allocates buffers of this size for Rx
*/
-static inline int ipw_queue_space(const struct clx2_queue *q)
+/**
+ * ipw_rx_queue_space - Return number of free slots available in queue.
+ */
+static int ipw_rx_queue_space(const struct ipw_rx_queue *q)
+{
+ int s = q->read - q->write;
+ if (s <= 0)
+ s += RX_QUEUE_SIZE;
+ /* keep some buffer to not confuse full and empty queue */
+ s -= 2;
+ if (s < 0)
+ s = 0;
+ return s;
+}
+
+static inline int ipw_tx_queue_space(const struct clx2_queue *q)
{
int s = q->last_used - q->first_empty;
if (s <= 0)
@@ -4947,7 +4961,7 @@ static int ipw_queue_tx_reclaim(struct ipw_priv *priv,
priv->tx_packets++;
}
done:
- if ((ipw_queue_space(q) > q->low_mark) &&
+ if ((ipw_tx_queue_space(q) > q->low_mark) &&
(qindex >= 0) &&
(priv->status & STATUS_ASSOCIATED) && netif_running(priv->net_dev))
netif_wake_queue(priv->net_dev);
@@ -4965,7 +4979,7 @@ static int ipw_queue_tx_hcmd(struct ipw_priv *priv, int hcmd, void *buf,
struct clx2_queue *q = &txq->q;
struct tfd_frame *tfd;
- if (ipw_queue_space(q) < (sync ? 1 : 2)) {
+ if (ipw_tx_queue_space(q) < (sync ? 1 : 2)) {
IPW_ERROR("No space for Tx\n");
return -EBUSY;
}
@@ -5070,7 +5084,7 @@ static void ipw_rx_queue_restock(struct ipw_priv *priv)
spin_lock_irqsave(&rxq->lock, flags);
write = rxq->write;
- while ((rxq->write != rxq->processed) && (rxq->free_count)) {
+ while ((ipw_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
element = rxq->rx_free.next;
rxb = list_entry(element, struct ipw_rx_mem_buffer, list);
list_del(element);
@@ -5187,7 +5201,6 @@ static struct ipw_rx_queue *ipw_rx_queue_alloc(struct ipw_priv *priv)
/* Set us so that we have processed and used all buffers, but have
* not restocked the Rx queue with fresh buffers */
rxq->read = rxq->write = 0;
- rxq->processed = RX_QUEUE_SIZE - 1;
rxq->free_count = 0;
return rxq;
@@ -8223,13 +8236,17 @@ static void ipw_rx(struct ipw_priv *priv)
struct ieee80211_hdr_4addr *header;
u32 r, w, i;
u8 network_packet;
+ u8 fill_rx = 0;
DECLARE_MAC_BUF(mac);
DECLARE_MAC_BUF(mac2);
DECLARE_MAC_BUF(mac3);
r = ipw_read32(priv, IPW_RX_READ_INDEX);
w = ipw_read32(priv, IPW_RX_WRITE_INDEX);
- i = (priv->rxq->processed + 1) % RX_QUEUE_SIZE;
+ i = priv->rxq->read;
+
+ if (ipw_rx_queue_space (priv->rxq) > (RX_QUEUE_SIZE / 2))
+ fill_rx = 1;
while (i != r) {
rxb = priv->rxq->queue[i];
@@ -8404,11 +8421,17 @@ static void ipw_rx(struct ipw_priv *priv)
list_add_tail(&rxb->list, &priv->rxq->rx_used);
i = (i + 1) % RX_QUEUE_SIZE;
+
+ /* If there are a lot of unsued frames, restock the Rx queue
+ * so the ucode won't assert */
+ if (fill_rx) {
+ priv->rxq->read = i;
+ ipw_rx_queue_replenish(priv);
+ }
}
/* Backtrack one entry */
- priv->rxq->processed = (i ? i : RX_QUEUE_SIZE) - 1;
-
+ priv->rxq->read = i;
ipw_rx_queue_restock(priv);
}
@@ -10336,7 +10359,7 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb,
q->first_empty = ipw_queue_inc_wrap(q->first_empty, q->n_bd);
ipw_write32(priv, q->reg_w, q->first_empty);
- if (ipw_queue_space(q) < q->high_mark)
+ if (ipw_tx_queue_space(q) < q->high_mark)
netif_stop_queue(priv->net_dev);
return NETDEV_TX_OK;
@@ -10357,7 +10380,7 @@ static int ipw_net_is_queue_full(struct net_device *dev, int pri)
struct clx2_tx_queue *txq = &priv->txq[0];
#endif /* CONFIG_IPW2200_QOS */
- if (ipw_queue_space(&txq->q) < txq->q.high_mark)
+ if (ipw_tx_queue_space(&txq->q) < txq->q.high_mark)
return 1;
return 0;
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 5ee1ad69898..40b71bc2c4a 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -687,6 +687,12 @@ static int iwl3945_enqueue_hcmd(struct iwl3945_priv *priv, struct iwl3945_host_c
BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&
!(cmd->meta.flags & CMD_SIZE_HUGE));
+
+ if (iwl3945_is_rfkill(priv)) {
+ IWL_DEBUG_INFO("Not sending command - RF KILL");
+ return -EIO;
+ }
+
if (iwl3945_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) {
IWL_ERROR("No space for Tx\n");
return -ENOSPC;
@@ -1580,7 +1586,7 @@ static inline int iwl3945_eeprom_acquire_semaphore(struct iwl3945_priv *priv)
*/
int iwl3945_eeprom_init(struct iwl3945_priv *priv)
{
- __le16 *e = (__le16 *)&priv->eeprom;
+ u16 *e = (u16 *)&priv->eeprom;
u32 gp = iwl3945_read32(priv, CSR_EEPROM_GP);
u32 r;
int sz = sizeof(priv->eeprom);
@@ -1623,7 +1629,7 @@ int iwl3945_eeprom_init(struct iwl3945_priv *priv)
IWL_ERROR("Time out reading EEPROM[%d]", addr);
return -ETIMEDOUT;
}
- e[addr / 2] = cpu_to_le16(r >> 16);
+ e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16));
}
return 0;
@@ -2806,7 +2812,8 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv,
#endif
/* drop all data frame if we are not associated */
- if ((!iwl3945_is_associated(priv) || !priv->assoc_id) &&
+ if ((!iwl3945_is_associated(priv) ||
+ ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id)) &&
((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) {
IWL_DEBUG_DROP("Dropping - !iwl3945_is_associated\n");
goto drop_unlock;
@@ -4281,7 +4288,7 @@ static void iwl3945_rx_handle(struct iwl3945_priv *priv)
int reclaim;
unsigned long flags;
u8 fill_rx = 0;
- u32 count = 0;
+ u32 count = 8;
/* uCode's read index (stored in shared DRAM) indicates the last Rx
* buffer that the driver may process (last buffer filled by ucode). */
@@ -6256,6 +6263,8 @@ static void __iwl3945_down(struct iwl3945_priv *priv)
STATUS_RF_KILL_HW |
test_bit(STATUS_RF_KILL_SW, &priv->status) <<
STATUS_RF_KILL_SW |
+ test_bit(STATUS_GEO_CONFIGURED, &priv->status) <<
+ STATUS_GEO_CONFIGURED |
test_bit(STATUS_IN_SUSPEND, &priv->status) <<
STATUS_IN_SUSPEND;
goto exit;
@@ -6267,6 +6276,8 @@ static void __iwl3945_down(struct iwl3945_priv *priv)
STATUS_RF_KILL_HW |
test_bit(STATUS_RF_KILL_SW, &priv->status) <<
STATUS_RF_KILL_SW |
+ test_bit(STATUS_GEO_CONFIGURED, &priv->status) <<
+ STATUS_GEO_CONFIGURED |
test_bit(STATUS_IN_SUSPEND, &priv->status) <<
STATUS_IN_SUSPEND |
test_bit(STATUS_FW_ERROR, &priv->status) <<
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index f423241b956..a23d4798653 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -692,6 +692,11 @@ static int iwl4965_enqueue_hcmd(struct iwl4965_priv *priv, struct iwl4965_host_c
BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&
!(cmd->meta.flags & CMD_SIZE_HUGE));
+ if (iwl4965_is_rfkill(priv)) {
+ IWL_DEBUG_INFO("Not sending command - RF KILL");
+ return -EIO;
+ }
+
if (iwl4965_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) {
IWL_ERROR("No space for Tx\n");
return -ENOSPC;
@@ -1654,7 +1659,7 @@ static inline void iwl4965_eeprom_release_semaphore(struct iwl4965_priv *priv)
*/
int iwl4965_eeprom_init(struct iwl4965_priv *priv)
{
- __le16 *e = (__le16 *)&priv->eeprom;
+ u16 *e = (u16 *)&priv->eeprom;
u32 gp = iwl4965_read32(priv, CSR_EEPROM_GP);
u32 r;
int sz = sizeof(priv->eeprom);
@@ -1698,7 +1703,7 @@ int iwl4965_eeprom_init(struct iwl4965_priv *priv)
rc = -ETIMEDOUT;
goto done;
}
- e[addr / 2] = cpu_to_le16(r >> 16);
+ e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16));
}
rc = 0;
@@ -2935,7 +2940,7 @@ static int iwl4965_tx_skb(struct iwl4965_priv *priv,
/* drop all data frame if we are not associated */
if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
(!iwl4965_is_associated(priv) ||
- !priv->assoc_id ||
+ ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id) ||
!priv->assoc_station_added)) {
IWL_DEBUG_DROP("Dropping - !iwl4965_is_associated\n");
goto drop_unlock;
@@ -4664,7 +4669,7 @@ static void iwl4965_rx_handle(struct iwl4965_priv *priv)
int reclaim;
unsigned long flags;
u8 fill_rx = 0;
- u32 count = 0;
+ u32 count = 8;
/* uCode's read index (stored in shared DRAM) indicates the last Rx
* buffer that the driver may process (last buffer filled by ucode). */
@@ -6680,6 +6685,8 @@ static void __iwl4965_down(struct iwl4965_priv *priv)
STATUS_RF_KILL_HW |
test_bit(STATUS_RF_KILL_SW, &priv->status) <<
STATUS_RF_KILL_SW |
+ test_bit(STATUS_GEO_CONFIGURED, &priv->status) <<
+ STATUS_GEO_CONFIGURED |
test_bit(STATUS_IN_SUSPEND, &priv->status) <<
STATUS_IN_SUSPEND;
goto exit;
@@ -6691,6 +6698,8 @@ static void __iwl4965_down(struct iwl4965_priv *priv)
STATUS_RF_KILL_HW |
test_bit(STATUS_RF_KILL_SW, &priv->status) <<
STATUS_RF_KILL_SW |
+ test_bit(STATUS_GEO_CONFIGURED, &priv->status) <<
+ STATUS_GEO_CONFIGURED |
test_bit(STATUS_IN_SUSPEND, &priv->status) <<
STATUS_IN_SUSPEND |
test_bit(STATUS_FW_ERROR, &priv->status) <<
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index eab020338fd..b3c1acbcc65 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -1040,7 +1040,6 @@ int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
lbs_deb_leave(LBS_DEB_CMD);
return ret;
}
-EXPORT_SYMBOL_GPL(lbs_mesh_access);
int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan)
{
@@ -1576,7 +1575,6 @@ done:
lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
return ret;
}
-EXPORT_SYMBOL_GPL(lbs_prepare_and_send_command);
/**
* @brief This function allocates the command buffer and link
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
index aaacd9bd6bd..4e22341b4f3 100644
--- a/drivers/net/wireless/libertas/decl.h
+++ b/drivers/net/wireless/libertas/decl.h
@@ -69,7 +69,6 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev);
int lbs_remove_card(struct lbs_private *priv);
int lbs_start_card(struct lbs_private *priv);
int lbs_stop_card(struct lbs_private *priv);
-int lbs_reset_device(struct lbs_private *priv);
void lbs_host_to_card_done(struct lbs_private *priv);
int lbs_update_channel(struct lbs_private *priv);
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 84fb49ca0fa..4d4e2f3b66a 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -1351,8 +1351,6 @@ done:
lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
return ret;
}
-EXPORT_SYMBOL_GPL(lbs_add_mesh);
-
static void lbs_remove_mesh(struct lbs_private *priv)
{
@@ -1372,7 +1370,6 @@ static void lbs_remove_mesh(struct lbs_private *priv)
free_netdev(mesh_dev);
lbs_deb_leave(LBS_DEB_MESH);
}
-EXPORT_SYMBOL_GPL(lbs_remove_mesh);
/**
* @brief This function finds the CFP in
@@ -1458,20 +1455,6 @@ void lbs_interrupt(struct lbs_private *priv)
}
EXPORT_SYMBOL_GPL(lbs_interrupt);
-int lbs_reset_device(struct lbs_private *priv)
-{
- int ret;
-
- lbs_deb_enter(LBS_DEB_MAIN);
- ret = lbs_prepare_and_send_command(priv, CMD_802_11_RESET,
- CMD_ACT_HALT, 0, 0, NULL);
- msleep_interruptible(10);
-
- lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
- return ret;
-}
-EXPORT_SYMBOL_GPL(lbs_reset_device);
-
static int __init lbs_init_module(void)
{
lbs_deb_enter(LBS_DEB_MAIN);
diff --git a/drivers/net/wireless/p54usb.c b/drivers/net/wireless/p54usb.c
index 60d286eb0b8..e7d4aee8799 100644
--- a/drivers/net/wireless/p54usb.c
+++ b/drivers/net/wireless/p54usb.c
@@ -35,6 +35,7 @@ static struct usb_device_id p54u_table[] __devinitdata = {
{USB_DEVICE(0x0707, 0xee06)}, /* SMC 2862W-G */
{USB_DEVICE(0x083a, 0x4501)}, /* Accton 802.11g WN4501 USB */
{USB_DEVICE(0x083a, 0x4502)}, /* Siemens Gigaset USB Adapter */
+ {USB_DEVICE(0x083a, 0x5501)}, /* Phillips CPWUA054 */
{USB_DEVICE(0x0846, 0x4200)}, /* Netgear WG121 */
{USB_DEVICE(0x0846, 0x4210)}, /* Netgear WG121 the second ? */
{USB_DEVICE(0x0846, 0x4220)}, /* Netgear WG111 */
@@ -62,6 +63,7 @@ static struct usb_device_id p54u_table[] __devinitdata = {
{USB_DEVICE(0x0cde, 0x0008)}, /* Sagem XG703A */
{USB_DEVICE(0x0d8e, 0x3762)}, /* DLink DWL-G120 Cohiba */
{USB_DEVICE(0x09aa, 0x1000)}, /* Spinnaker Proto board */
+ {USB_DEVICE(0x13b1, 0x000a)}, /* Linksys WUSB54G ver 2 */
{USB_DEVICE(0x13B1, 0x000C)}, /* Linksys WUSB54AG */
{USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */
{USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index d3ecf89abd9..d9460aed1f2 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -228,9 +228,9 @@ struct NDIS_WLAN_BSSID_EX {
struct NDIS_802_11_SSID Ssid;
__le32 Privacy;
__le32 Rssi;
- enum NDIS_802_11_NETWORK_TYPE NetworkTypeInUse;
+ __le32 NetworkTypeInUse;
struct NDIS_802_11_CONFIGURATION Configuration;
- enum NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode;
+ __le32 InfrastructureMode;
u8 SupportedRates[NDIS_802_11_LENGTH_RATES_EX];
__le32 IELength;
u8 IEs[0];
@@ -279,11 +279,11 @@ struct RNDIS_CONFIG_PARAMETER_INFOBUFFER {
} __attribute__((packed));
/* these have to match what is in wpa_supplicant */
-enum { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP } wpa_alg;
-enum { CIPHER_NONE, CIPHER_WEP40, CIPHER_TKIP, CIPHER_CCMP, CIPHER_WEP104 }
- wpa_cipher;
-enum { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE, KEY_MGMT_802_1X_NO_WPA,
- KEY_MGMT_WPA_NONE } wpa_key_mgmt;
+enum wpa_alg { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP };
+enum wpa_cipher { CIPHER_NONE, CIPHER_WEP40, CIPHER_TKIP, CIPHER_CCMP,
+ CIPHER_WEP104 };
+enum wpa_key_mgmt { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE,
+ KEY_MGMT_802_1X_NO_WPA, KEY_MGMT_WPA_NONE };
/*
* private data
@@ -2300,7 +2300,7 @@ static void rndis_update_wireless_stats(struct work_struct *work)
struct usbnet *usbdev = priv->usbdev;
struct iw_statistics iwstats;
__le32 rssi, tmp;
- int len, ret, bitrate, j;
+ int len, ret, j;
unsigned long flags;
int update_jiffies = STATS_UPDATE_JIFFIES;
void *buf;
@@ -2352,14 +2352,10 @@ static void rndis_update_wireless_stats(struct work_struct *work)
if (ret == 0)
iwstats.discard.misc += le32_to_cpu(tmp);
- /* Workaround transfer stalls on poor quality links. */
- len = sizeof(tmp);
- ret = rndis_query_oid(usbdev, OID_GEN_LINK_SPEED, &tmp, &len);
- if (ret == 0) {
- bitrate = le32_to_cpu(tmp) * 100;
- if (bitrate > 11000000)
- goto end;
-
+ /* Workaround transfer stalls on poor quality links.
+ * TODO: find right way to fix these stalls (as stalls do not happen
+ * with ndiswrapper/windows driver). */
+ if (iwstats.qual.qual <= 25) {
/* Decrease stats worker interval to catch stalls.
* faster. Faster than 400-500ms causes packet loss,
* Slower doesn't catch stalls fast enough.
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index d6cba138c7a..c69f85ed766 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -960,8 +960,12 @@ static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev,
rt2400pci_disable_radio(rt2x00dev);
break;
case STATE_RADIO_RX_ON:
+ case STATE_RADIO_RX_ON_LINK:
+ rt2400pci_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
+ break;
case STATE_RADIO_RX_OFF:
- rt2400pci_toggle_rx(rt2x00dev, state);
+ case STATE_RADIO_RX_OFF_LINK:
+ rt2400pci_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF);
break;
case STATE_DEEP_SLEEP:
case STATE_SLEEP:
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index e874fdcae20..91e87b53374 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -1112,8 +1112,12 @@ static int rt2500pci_set_device_state(struct rt2x00_dev *rt2x00dev,
rt2500pci_disable_radio(rt2x00dev);
break;
case STATE_RADIO_RX_ON:
+ case STATE_RADIO_RX_ON_LINK:
+ rt2500pci_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
+ break;
case STATE_RADIO_RX_OFF:
- rt2500pci_toggle_rx(rt2x00dev, state);
+ case STATE_RADIO_RX_OFF_LINK:
+ rt2500pci_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF);
break;
case STATE_DEEP_SLEEP:
case STATE_SLEEP:
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index 86ded4066f5..638c3d24310 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -1001,8 +1001,12 @@ static int rt2500usb_set_device_state(struct rt2x00_dev *rt2x00dev,
rt2500usb_disable_radio(rt2x00dev);
break;
case STATE_RADIO_RX_ON:
+ case STATE_RADIO_RX_ON_LINK:
+ rt2500usb_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
+ break;
case STATE_RADIO_RX_OFF:
- rt2500usb_toggle_rx(rt2x00dev, state);
+ case STATE_RADIO_RX_OFF_LINK:
+ rt2500usb_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF);
break;
case STATE_DEEP_SLEEP:
case STATE_SLEEP:
@@ -1839,11 +1843,11 @@ static struct usb_device_id rt2500usb_device_table[] = {
/* Hercules */
{ USB_DEVICE(0x06f8, 0xe000), USB_DEVICE_DATA(&rt2500usb_ops) },
/* Melco */
+ { USB_DEVICE(0x0411, 0x005e), USB_DEVICE_DATA(&rt2500usb_ops) },
{ USB_DEVICE(0x0411, 0x0066), USB_DEVICE_DATA(&rt2500usb_ops) },
{ USB_DEVICE(0x0411, 0x0067), USB_DEVICE_DATA(&rt2500usb_ops) },
{ USB_DEVICE(0x0411, 0x008b), USB_DEVICE_DATA(&rt2500usb_ops) },
{ USB_DEVICE(0x0411, 0x0097), USB_DEVICE_DATA(&rt2500usb_ops) },
-
/* MSI */
{ USB_DEVICE(0x0db0, 0x6861), USB_DEVICE_DATA(&rt2500usb_ops) },
{ USB_DEVICE(0x0db0, 0x6865), USB_DEVICE_DATA(&rt2500usb_ops) },
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
index 72cfe00c1ed..07adc576db4 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -97,12 +97,16 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
libconf.ant.rx = rx;
libconf.ant.tx = tx;
+ if (rx == rt2x00dev->link.ant.active.rx &&
+ tx == rt2x00dev->link.ant.active.tx)
+ return;
+
/*
* Antenna setup changes require the RX to be disabled,
* else the changes will be ignored by the device.
*/
if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
- rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF);
+ rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF_LINK);
/*
* Write new antenna setup to device and reset the link tuner.
@@ -116,7 +120,7 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
rt2x00dev->link.ant.active.tx = libconf.ant.tx;
if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
- rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
+ rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON_LINK);
}
void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index c4be2ac4d7a..0d51f478bcd 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -61,11 +61,33 @@ EXPORT_SYMBOL_GPL(rt2x00lib_get_ring);
/*
* Link tuning handlers
*/
-static void rt2x00lib_start_link_tuner(struct rt2x00_dev *rt2x00dev)
+void rt2x00lib_reset_link_tuner(struct rt2x00_dev *rt2x00dev)
{
+ if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+ return;
+
+ /*
+ * Reset link information.
+ * Both the currently active vgc level as well as
+ * the link tuner counter should be reset. Resetting
+ * the counter is important for devices where the
+ * device should only perform link tuning during the
+ * first minute after being enabled.
+ */
rt2x00dev->link.count = 0;
rt2x00dev->link.vgc_level = 0;
+ /*
+ * Reset the link tuner.
+ */
+ rt2x00dev->ops->lib->reset_tuner(rt2x00dev);
+}
+
+static void rt2x00lib_start_link_tuner(struct rt2x00_dev *rt2x00dev)
+{
+ /*
+ * Clear all (possibly) pre-existing quality statistics.
+ */
memset(&rt2x00dev->link.qual, 0, sizeof(rt2x00dev->link.qual));
/*
@@ -79,10 +101,7 @@ static void rt2x00lib_start_link_tuner(struct rt2x00_dev *rt2x00dev)
rt2x00dev->link.qual.rx_percentage = 50;
rt2x00dev->link.qual.tx_percentage = 50;
- /*
- * Reset the link tuner.
- */
- rt2x00dev->ops->lib->reset_tuner(rt2x00dev);
+ rt2x00lib_reset_link_tuner(rt2x00dev);
queue_delayed_work(rt2x00dev->hw->workqueue,
&rt2x00dev->link.work, LINK_TUNE_INTERVAL);
@@ -93,15 +112,6 @@ static void rt2x00lib_stop_link_tuner(struct rt2x00_dev *rt2x00dev)
cancel_delayed_work_sync(&rt2x00dev->link.work);
}
-void rt2x00lib_reset_link_tuner(struct rt2x00_dev *rt2x00dev)
-{
- if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
- return;
-
- rt2x00lib_stop_link_tuner(rt2x00dev);
- rt2x00lib_start_link_tuner(rt2x00dev);
-}
-
/*
* Ring initialization
*/
@@ -260,19 +270,11 @@ static void rt2x00lib_evaluate_antenna_sample(struct rt2x00_dev *rt2x00dev)
if (sample_a == sample_b)
return;
- if (rt2x00dev->link.ant.flags & ANTENNA_RX_DIVERSITY) {
- if (sample_a > sample_b && rx == ANTENNA_B)
- rx = ANTENNA_A;
- else if (rx == ANTENNA_A)
- rx = ANTENNA_B;
- }
+ if (rt2x00dev->link.ant.flags & ANTENNA_RX_DIVERSITY)
+ rx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B;
- if (rt2x00dev->link.ant.flags & ANTENNA_TX_DIVERSITY) {
- if (sample_a > sample_b && tx == ANTENNA_B)
- tx = ANTENNA_A;
- else if (tx == ANTENNA_A)
- tx = ANTENNA_B;
- }
+ if (rt2x00dev->link.ant.flags & ANTENNA_TX_DIVERSITY)
+ tx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B;
rt2x00lib_config_antenna(rt2x00dev, rx, tx);
}
@@ -293,7 +295,7 @@ static void rt2x00lib_evaluate_antenna_eval(struct rt2x00_dev *rt2x00dev)
* sample the rssi from the other antenna to make a valid
* comparison between the 2 antennas.
*/
- if ((rssi_curr - rssi_old) > -5 || (rssi_curr - rssi_old) < 5)
+ if (abs(rssi_curr - rssi_old) < 5)
return;
rt2x00dev->link.ant.flags |= ANTENNA_MODE_SAMPLE;
@@ -319,15 +321,15 @@ static void rt2x00lib_evaluate_antenna(struct rt2x00_dev *rt2x00dev)
rt2x00dev->link.ant.flags &= ~ANTENNA_TX_DIVERSITY;
if (rt2x00dev->hw->conf.antenna_sel_rx == 0 &&
- rt2x00dev->default_ant.rx != ANTENNA_SW_DIVERSITY)
+ rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY)
rt2x00dev->link.ant.flags |= ANTENNA_RX_DIVERSITY;
if (rt2x00dev->hw->conf.antenna_sel_tx == 0 &&
- rt2x00dev->default_ant.tx != ANTENNA_SW_DIVERSITY)
+ rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY)
rt2x00dev->link.ant.flags |= ANTENNA_TX_DIVERSITY;
if (!(rt2x00dev->link.ant.flags & ANTENNA_RX_DIVERSITY) &&
!(rt2x00dev->link.ant.flags & ANTENNA_TX_DIVERSITY)) {
- rt2x00dev->link.ant.flags &= ~ANTENNA_MODE_SAMPLE;
+ rt2x00dev->link.ant.flags = 0;
return;
}
@@ -441,17 +443,18 @@ static void rt2x00lib_link_tuner(struct work_struct *work)
rt2x00dev->ops->lib->link_tuner(rt2x00dev);
/*
- * Evaluate antenna setup.
- */
- rt2x00lib_evaluate_antenna(rt2x00dev);
-
- /*
* Precalculate a portion of the link signal which is
* in based on the tx/rx success/failure counters.
*/
rt2x00lib_precalculate_link_signal(&rt2x00dev->link.qual);
/*
+ * Evaluate antenna setup, make this the last step since this could
+ * possibly reset some statistics.
+ */
+ rt2x00lib_evaluate_antenna(rt2x00dev);
+
+ /*
* Increase tuner counter, and reschedule the next link tuner run.
*/
rt2x00dev->link.count++;
diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h
index 838421216da..b1915dc7dda 100644
--- a/drivers/net/wireless/rt2x00/rt2x00reg.h
+++ b/drivers/net/wireless/rt2x00/rt2x00reg.h
@@ -85,6 +85,8 @@ enum dev_state {
STATE_RADIO_OFF,
STATE_RADIO_RX_ON,
STATE_RADIO_RX_OFF,
+ STATE_RADIO_RX_ON_LINK,
+ STATE_RADIO_RX_OFF_LINK,
STATE_RADIO_IRQ_ON,
STATE_RADIO_IRQ_OFF,
};
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index b31f0c26c32..e808db98f2f 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -1482,8 +1482,12 @@ static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev,
rt61pci_disable_radio(rt2x00dev);
break;
case STATE_RADIO_RX_ON:
+ case STATE_RADIO_RX_ON_LINK:
+ rt61pci_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
+ break;
case STATE_RADIO_RX_OFF:
- rt61pci_toggle_rx(rt2x00dev, state);
+ case STATE_RADIO_RX_OFF_LINK:
+ rt61pci_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF);
break;
case STATE_DEEP_SLEEP:
case STATE_SLEEP:
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index 4d576ab3e7f..4fac2d414d8 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -1208,8 +1208,12 @@ static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev,
rt73usb_disable_radio(rt2x00dev);
break;
case STATE_RADIO_RX_ON:
+ case STATE_RADIO_RX_ON_LINK:
+ rt73usb_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
+ break;
case STATE_RADIO_RX_OFF:
- rt73usb_toggle_rx(rt2x00dev, state);
+ case STATE_RADIO_RX_OFF_LINK:
+ rt73usb_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF);
break;
case STATE_DEEP_SLEEP:
case STATE_SLEEP:
diff --git a/drivers/net/wireless/rtl8180_dev.c b/drivers/net/wireless/rtl8180_dev.c
index 27ebd689aa2..5e9a8ace0d8 100644
--- a/drivers/net/wireless/rtl8180_dev.c
+++ b/drivers/net/wireless/rtl8180_dev.c
@@ -135,13 +135,15 @@ static void rtl8180_handle_tx(struct ieee80211_hw *dev, unsigned int prio)
while (skb_queue_len(&ring->queue)) {
struct rtl8180_tx_desc *entry = &ring->desc[ring->idx];
struct sk_buff *skb;
- struct ieee80211_tx_status status = { {0} };
+ struct ieee80211_tx_status status;
struct ieee80211_tx_control *control;
u32 flags = le32_to_cpu(entry->flags);
if (flags & RTL8180_TX_DESC_FLAG_OWN)
return;
+ memset(&status, 0, sizeof(status));
+
ring->idx = (ring->idx + 1) % ring->entries;
skb = __skb_dequeue(&ring->queue);
pci_unmap_single(priv->pdev, le32_to_cpu(entry->tx_buf),
diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c
index 0d71716d750..f44505994a0 100644
--- a/drivers/net/wireless/rtl8187_dev.c
+++ b/drivers/net/wireless/rtl8187_dev.c
@@ -113,10 +113,12 @@ void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data)
static void rtl8187_tx_cb(struct urb *urb)
{
- struct ieee80211_tx_status status = { {0} };
+ struct ieee80211_tx_status status;
struct sk_buff *skb = (struct sk_buff *)urb->context;
struct rtl8187_tx_info *info = (struct rtl8187_tx_info *)skb->cb;
+ memset(&status, 0, sizeof(status));
+
usb_free_urb(info->urb);
if (info->control)
memcpy(&status.control, info->control, sizeof(status.control));
diff --git a/drivers/net/wireless/wavelan.h b/drivers/net/wireless/wavelan.h
index 27172cde5a3..9ab360558ff 100644
--- a/drivers/net/wireless/wavelan.h
+++ b/drivers/net/wireless/wavelan.h
@@ -85,7 +85,7 @@ union hacs_u
#define HASR_MMC_INTR 0x0002 /* Interrupt request from MMC */
#define HASR_MMC_BUSY 0x0004 /* MMC busy indication */
#define HASR_PSA_BUSY 0x0008 /* LAN parameter storage area busy */
-};
+} __attribute__ ((packed));
typedef struct ha_t ha_t;
struct ha_t
@@ -292,7 +292,7 @@ struct mmw_t
#define MMW_EXT_ANT_INTERNAL 0x00 /* Internal antenna */
#define MMW_EXT_ANT_EXTERNAL 0x03 /* External antenna */
#define MMW_EXT_ANT_IQ_TEST 0x1C /* IQ test pattern (set to 0) */
-};
+} __attribute__ ((packed));
#define MMW_SIZE 37
@@ -347,7 +347,7 @@ struct mmr_t
unsigned char mmr_unused4[1]; /* unused */
unsigned char mmr_fee_data_l; /* Read data from EEPROM (low) */
unsigned char mmr_fee_data_h; /* Read data from EEPROM (high) */
-};
+} __attribute__ ((packed));
#define MMR_SIZE 36
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 49127e4b42c..76ef2d83919 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -360,11 +360,14 @@ void zd_mac_tx_failed(struct ieee80211_hw *hw)
{
struct sk_buff_head *q = &zd_hw_mac(hw)->ack_wait_queue;
struct sk_buff *skb;
- struct ieee80211_tx_status status = {{0}};
+ struct ieee80211_tx_status status;
skb = skb_dequeue(q);
if (skb == NULL)
return;
+
+ memset(&status, 0, sizeof(status));
+
tx_status(hw, skb, &status, 0);
}
@@ -389,7 +392,8 @@ void zd_mac_tx_to_dev(struct sk_buff *skb, int error)
if (unlikely(error ||
(cb->control->flags & IEEE80211_TXCTL_NO_ACK)))
{
- struct ieee80211_tx_status status = {{0}};
+ struct ieee80211_tx_status status;
+ memset(&status, 0, sizeof(status));
tx_status(hw, skb, &status, !error);
} else {
struct sk_buff_head *q =
@@ -603,7 +607,9 @@ static int filter_ack(struct ieee80211_hw *hw, struct ieee80211_hdr *rx_hdr,
tx_hdr = (struct ieee80211_hdr *)skb->data;
if (likely(!compare_ether_addr(tx_hdr->addr2, rx_hdr->addr1)))
{
- struct ieee80211_tx_status status = {{0}};
+ struct ieee80211_tx_status status;
+
+ memset(&status, 0, sizeof(status));
status.flags = IEEE80211_TX_STATUS_ACK;
status.ack_signal = stats->ssi;
__skb_unlink(skb, q);
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c
index 8ed26480371..f941f609dbf 100644
--- a/drivers/pci/dmar.c
+++ b/drivers/pci/dmar.c
@@ -14,11 +14,12 @@
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307 USA.
*
- * Copyright (C) Ashok Raj <ashok.raj@intel.com>
- * Copyright (C) Shaohua Li <shaohua.li@intel.com>
- * Copyright (C) Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
+ * Copyright (C) 2006-2008 Intel Corporation
+ * Author: Ashok Raj <ashok.raj@intel.com>
+ * Author: Shaohua Li <shaohua.li@intel.com>
+ * Author: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
*
- * This file implements early detection/parsing of DMA Remapping Devices
+ * This file implements early detection/parsing of DMA Remapping Devices
* reported to OS through BIOS via DMA remapping reporting (DMAR) ACPI
* tables.
*/
diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c
index c8c263875c2..9279d5ba62e 100644
--- a/drivers/pci/hotplug/acpiphp_core.c
+++ b/drivers/pci/hotplug/acpiphp_core.c
@@ -392,6 +392,9 @@ static int __init acpiphp_init(void)
{
info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
+ if (acpi_pci_disabled)
+ return 0;
+
acpiphp_debug = debug;
/* read all the ACPI info from the system */
@@ -401,6 +404,9 @@ static int __init acpiphp_init(void)
static void __exit acpiphp_exit(void)
{
+ if (acpi_pci_disabled)
+ return;
+
/* deallocate internal data structures etc. */
acpiphp_glue_exit();
}
diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c
index 750ebd7a4c1..b0a22b92717 100644
--- a/drivers/pci/hotplug/acpiphp_ibm.c
+++ b/drivers/pci/hotplug/acpiphp_ibm.c
@@ -395,33 +395,34 @@ static acpi_status __init ibm_find_acpi_device(acpi_handle handle,
{
acpi_handle *phandle = (acpi_handle *)context;
acpi_status status;
- struct acpi_device_info info;
- struct acpi_buffer info_buffer = {
- .length = sizeof(struct acpi_device_info),
- .pointer = &info,
- };
+ struct acpi_device_info *info;
+ struct acpi_buffer info_buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ int retval = 0;
status = acpi_get_object_info(handle, &info_buffer);
if (ACPI_FAILURE(status)) {
- err("%s: Failed to get device information\n", __FUNCTION__);
- return 0;
+ err("%s: Failed to get device information status=0x%x\n",
+ __FUNCTION__, status);
+ return retval;
}
- info.hardware_id.value[sizeof(info.hardware_id.value) - 1] = '\0';
-
- if (info.current_status && (info.valid & ACPI_VALID_HID) &&
- (!strcmp(info.hardware_id.value, IBM_HARDWARE_ID1) ||
- !strcmp(info.hardware_id.value, IBM_HARDWARE_ID2))) {
- dbg("found hardware: %s, handle: %p\n", info.hardware_id.value,
- handle);
+ info = info_buffer.pointer;
+ info->hardware_id.value[sizeof(info->hardware_id.value) - 1] = '\0';
+
+ if (info->current_status && (info->valid & ACPI_VALID_HID) &&
+ (!strcmp(info->hardware_id.value, IBM_HARDWARE_ID1) ||
+ !strcmp(info->hardware_id.value, IBM_HARDWARE_ID2))) {
+ dbg("found hardware: %s, handle: %p\n",
+ info->hardware_id.value, handle);
*phandle = handle;
/* returning non-zero causes the search to stop
* and returns this value to the caller of
* acpi_walk_namespace, but it also causes some warnings
* in the acpi debug code to print...
*/
- return FOUND_APCI;
+ retval = FOUND_APCI;
}
- return 0;
+ kfree(info);
+ return retval;
}
static int __init ibm_acpiphp_init(void)
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c
index a4c3089f892..977d29b3229 100644
--- a/drivers/pci/intel-iommu.c
+++ b/drivers/pci/intel-iommu.c
@@ -14,9 +14,10 @@
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307 USA.
*
- * Copyright (C) Ashok Raj <ashok.raj@intel.com>
- * Copyright (C) Shaohua Li <shaohua.li@intel.com>
- * Copyright (C) Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
+ * Copyright (C) 2006-2008 Intel Corporation
+ * Author: Ashok Raj <ashok.raj@intel.com>
+ * Author: Shaohua Li <shaohua.li@intel.com>
+ * Author: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
*/
#include <linux/init.h>
diff --git a/drivers/pci/intel-iommu.h b/drivers/pci/intel-iommu.h
index 07f5f6353bd..afc0ad96122 100644
--- a/drivers/pci/intel-iommu.h
+++ b/drivers/pci/intel-iommu.h
@@ -14,8 +14,9 @@
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307 USA.
*
- * Copyright (C) Ashok Raj <ashok.raj@intel.com>
- * Copyright (C) Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
+ * Copyright (C) 2006-2008 Intel Corporation
+ * Author: Ashok Raj <ashok.raj@intel.com>
+ * Author: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
*/
#ifndef _INTEL_IOMMU_H_
diff --git a/drivers/pci/iova.c b/drivers/pci/iova.c
index 8de7ab6c6d0..dbcdd6bfa63 100644
--- a/drivers/pci/iova.c
+++ b/drivers/pci/iova.c
@@ -3,7 +3,8 @@
*
* This file is released under the GPLv2.
*
- * Copyright (C) 2006 Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
+ * Copyright (C) 2006-2008 Intel Corporation
+ * Author: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
*/
#include "iova.h"
diff --git a/drivers/pci/iova.h b/drivers/pci/iova.h
index d521b5b7319..228f6c94b69 100644
--- a/drivers/pci/iova.h
+++ b/drivers/pci/iova.h
@@ -3,7 +3,8 @@
*
* This file is released under the GPLv2.
*
- * Copyright (C) 2006 Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
+ * Copyright (C) 2006-2008 Intel Corporation
+ * Author: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
*
*/
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index e569645d59e..4a23654184f 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -158,6 +158,7 @@ run_osc_out:
/**
* __pci_osc_support_set - register OS support to Firmware
* @flags: OS support bits
+ * @hid: hardware ID
*
* Update OS support fields and doing a _OSC Query to obtain an update
* from Firmware on supported control bits.
@@ -241,8 +242,6 @@ EXPORT_SYMBOL(pci_osc_control_set);
* choose from highest power _SxD to lowest power _SxW
* else // no _PRW at S-state x
* choose highest power _SxD or any lower power
- *
- * currently we simply return _SxD, if present.
*/
static pci_power_t acpi_pci_choose_state(struct pci_dev *pdev,
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index ae3df46eaab..183fddaa38b 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -554,6 +554,7 @@ pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state)
case PM_EVENT_PRETHAW:
/* REVISIT both freeze and pre-thaw "should" use D0 */
case PM_EVENT_SUSPEND:
+ case PM_EVENT_HIBERNATE:
return PCI_D3hot;
default:
printk("Unrecognized suspend event %d\n", state.event);
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index 68aeeb7206d..ef18fcd641e 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -422,7 +422,7 @@ int pci_proc_detach_device(struct pci_dev *dev)
struct proc_dir_entry *e;
if ((e = dev->procent)) {
- if (atomic_read(&e->count))
+ if (atomic_read(&e->count) > 1)
return -EBUSY;
remove_proc_entry(e->name, dev->bus->procdir);
dev->procent = NULL;
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 0a953d43b9a..bbad4a9f264 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -867,13 +867,13 @@ static void quirk_disable_pxb(struct pci_dev *pdev)
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, quirk_disable_pxb);
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, quirk_disable_pxb);
-
-static void __devinit quirk_sb600_sata(struct pci_dev *pdev)
+static void __devinit quirk_amd_ide_mode(struct pci_dev *pdev)
{
- /* set sb600 sata to ahci mode */
- if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
- u8 tmp;
+ /* set sb600/sb700/sb800 sata to ahci mode */
+ u8 tmp;
+ pci_read_config_byte(pdev, PCI_CLASS_DEVICE, &tmp);
+ if (tmp == 0x01) {
pci_read_config_byte(pdev, 0x40, &tmp);
pci_write_config_byte(pdev, 0x40, tmp|1);
pci_write_config_byte(pdev, 0x9, 1);
@@ -881,10 +881,13 @@ static void __devinit quirk_sb600_sata(struct pci_dev *pdev)
pci_write_config_byte(pdev, 0x40, tmp);
pdev->class = PCI_CLASS_STORAGE_SATA_AHCI;
+ dev_info(&pdev->dev, "set SATA to AHCI mode\n");
}
}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_SATA, quirk_sb600_sata);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_SATA, quirk_sb600_sata);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_SATA, quirk_amd_ide_mode);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_SATA, quirk_amd_ide_mode);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_SATA, quirk_amd_ide_mode);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_SATA, quirk_amd_ide_mode);
/*
* Serverworks CSB5 IDE does not fully support native mode
@@ -1775,6 +1778,68 @@ static void __devinit quirk_nvidia_ck804_msi_ht_cap(struct pci_dev *dev)
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE,
quirk_nvidia_ck804_msi_ht_cap);
+/*
+ * Force enable MSI mapping capability on HT bridges */
+static inline void ht_enable_msi_mapping(struct pci_dev *dev)
+{
+ int pos, ttl = 48;
+
+ pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING);
+ while (pos && ttl--) {
+ u8 flags;
+
+ if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS,
+ &flags) == 0) {
+ dev_info(&dev->dev, "Enabling HT MSI Mapping\n");
+
+ pci_write_config_byte(dev, pos + HT_MSI_FLAGS,
+ flags | HT_MSI_FLAGS_ENABLE);
+ }
+ pos = pci_find_next_ht_capability(dev, pos,
+ HT_CAPTYPE_MSI_MAPPING);
+ }
+}
+
+static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev)
+{
+ struct pci_dev *host_bridge;
+ int pos, ttl = 48;
+
+ /*
+ * HT MSI mapping should be disabled on devices that are below
+ * a non-Hypertransport host bridge. Locate the host bridge...
+ */
+ host_bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 0));
+ if (host_bridge == NULL) {
+ dev_warn(&dev->dev,
+ "nv_msi_ht_cap_quirk didn't locate host bridge\n");
+ return;
+ }
+
+ pos = pci_find_ht_capability(host_bridge, HT_CAPTYPE_SLAVE);
+ if (pos != 0) {
+ /* Host bridge is to HT */
+ ht_enable_msi_mapping(dev);
+ return;
+ }
+
+ /* Host bridge is not to HT, disable HT MSI mapping on this device */
+ pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING);
+ while (pos && ttl--) {
+ u8 flags;
+
+ if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS,
+ &flags) == 0) {
+ dev_info(&dev->dev, "Quirk disabling HT MSI mapping");
+ pci_write_config_byte(dev, pos + HT_MSI_FLAGS,
+ flags & ~HT_MSI_FLAGS_ENABLE);
+ }
+ pos = pci_find_next_ht_capability(dev, pos,
+ HT_CAPTYPE_MSI_MAPPING);
+ }
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, nv_msi_ht_cap_quirk);
+
static void __devinit quirk_msi_intx_disable_bug(struct pci_dev *dev)
{
dev->dev_flags |= PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG;
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 262b0439abe..125e7b7f34f 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -206,10 +206,8 @@ pci_setup_bridge(struct pci_bus *bus)
if (bus->resource[2]->flags & IORESOURCE_PREFETCH) {
l = (region.start >> 16) & 0xfff0;
l |= region.end & 0xfff00000;
-#ifdef CONFIG_RESOURCES_64BIT
- bu = region.start >> 32;
- lu = region.end >> 32;
-#endif
+ bu = upper_32_bits(region.start);
+ lu = upper_32_bits(region.end);
DBG(KERN_INFO " PREFETCH window: 0x%016llx-0x%016llx\n",
(unsigned long long)region.start,
(unsigned long long)region.end);
diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c
index 749515534cc..e54ecc580d9 100644
--- a/drivers/pcmcia/i82092.c
+++ b/drivers/pcmcia/i82092.c
@@ -647,7 +647,12 @@ static int i82092aa_set_mem_map(struct pcmcia_socket *socket, struct pccard_mem_
if ( (mem->card_start > 0x3ffffff) || (region.start > region.end) ||
(mem->speed > 1000) ) {
leave("i82092aa_set_mem_map: invalid address / speed");
- printk("invalid mem map for socket %i : %lx to %lx with a start of %x \n",sock,region.start, region.end, mem->card_start);
+ printk("invalid mem map for socket %i: %llx to %llx with a "
+ "start of %x\n",
+ sock,
+ (unsigned long long)region.start,
+ (unsigned long long)region.end,
+ mem->card_start);
return -EINVAL;
}
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index e059f94c79e..f3ee2ad566b 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -388,6 +388,7 @@ static int cmos_procfs(struct device *dev, struct seq_file *seq)
return seq_printf(seq,
"periodic_IRQ\t: %s\n"
"update_IRQ\t: %s\n"
+ "HPET_emulated\t: %s\n"
// "square_wave\t: %s\n"
// "BCD\t\t: %s\n"
"DST_enable\t: %s\n"
@@ -395,6 +396,7 @@ static int cmos_procfs(struct device *dev, struct seq_file *seq)
"batt_status\t: %s\n",
(rtc_control & RTC_PIE) ? "yes" : "no",
(rtc_control & RTC_UIE) ? "yes" : "no",
+ is_hpet_enabled() ? "yes" : "no",
// (rtc_control & RTC_SQWE) ? "yes" : "no",
// (rtc_control & RTC_DM_BINARY) ? "no" : "yes",
(rtc_control & RTC_DST_EN) ? "yes" : "no",
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index d984e0fae63..ccf46c96adb 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -1149,12 +1149,14 @@ static void __dasd_device_process_final_queue(struct dasd_device *device,
{
struct list_head *l, *n;
struct dasd_ccw_req *cqr;
+ struct dasd_block *block;
list_for_each_safe(l, n, final_queue) {
cqr = list_entry(l, struct dasd_ccw_req, devlist);
list_del_init(&cqr->devlist);
- if (cqr->block)
- spin_lock_bh(&cqr->block->queue_lock);
+ block = cqr->block;
+ if (block)
+ spin_lock_bh(&block->queue_lock);
switch (cqr->status) {
case DASD_CQR_SUCCESS:
cqr->status = DASD_CQR_DONE;
@@ -1172,15 +1174,13 @@ static void __dasd_device_process_final_queue(struct dasd_device *device,
cqr, cqr->status);
BUG();
}
- if (cqr->block)
- spin_unlock_bh(&cqr->block->queue_lock);
if (cqr->callback != NULL)
(cqr->callback)(cqr, cqr->callback_data);
+ if (block)
+ spin_unlock_bh(&block->queue_lock);
}
}
-
-
/*
* Take a look at the first request on the ccw queue and check
* if it reached its expire time. If so, terminate the IO.
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index 3faf0538b32..e6c94dbfdea 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -666,7 +666,7 @@ dcssblk_make_request(struct request_queue *q, struct bio *bio)
page_addr = (unsigned long)
page_address(bvec->bv_page) + bvec->bv_offset;
source_addr = dev_info->start + (index<<12) + bytes_done;
- if (unlikely(page_addr & 4095) != 0 || (bvec->bv_len & 4095) != 0)
+ if (unlikely((page_addr & 4095) != 0) || (bvec->bv_len & 4095) != 0)
// More paranoia.
goto fail;
if (bio_data_dir(bio) == READ) {
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c
index 25629b92dec..2c7a1ee6b04 100644
--- a/drivers/s390/char/sclp.c
+++ b/drivers/s390/char/sclp.c
@@ -29,10 +29,10 @@ static ext_int_info_t ext_int_info_hwc;
/* Lock to protect internal data consistency. */
static DEFINE_SPINLOCK(sclp_lock);
-/* Mask of events that we can receive from the sclp interface. */
+/* Mask of events that we can send to the sclp interface. */
static sccb_mask_t sclp_receive_mask;
-/* Mask of events that we can send to the sclp interface. */
+/* Mask of events that we can receive from the sclp interface. */
static sccb_mask_t sclp_send_mask;
/* List of registered event listeners and senders. */
@@ -380,7 +380,7 @@ sclp_interrupt_handler(__u16 code)
}
sclp_running_state = sclp_running_state_idle;
}
- if (evbuf_pending && sclp_receive_mask != 0 &&
+ if (evbuf_pending &&
sclp_activation_state == sclp_activation_state_active)
__sclp_queue_read_req();
spin_unlock(&sclp_lock);
@@ -459,8 +459,8 @@ sclp_dispatch_state_change(void)
reg = NULL;
list_for_each(l, &sclp_reg_list) {
reg = list_entry(l, struct sclp_register, list);
- receive_mask = reg->receive_mask & sclp_receive_mask;
- send_mask = reg->send_mask & sclp_send_mask;
+ receive_mask = reg->send_mask & sclp_receive_mask;
+ send_mask = reg->receive_mask & sclp_send_mask;
if (reg->sclp_receive_mask != receive_mask ||
reg->sclp_send_mask != send_mask) {
reg->sclp_receive_mask = receive_mask;
@@ -615,8 +615,8 @@ struct init_sccb {
u16 mask_length;
sccb_mask_t receive_mask;
sccb_mask_t send_mask;
- sccb_mask_t sclp_send_mask;
sccb_mask_t sclp_receive_mask;
+ sccb_mask_t sclp_send_mask;
} __attribute__((packed));
/* Prepare init mask request. Called while sclp_lock is locked. */
diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h
index aa8186d18ae..bac80e856f9 100644
--- a/drivers/s390/char/sclp.h
+++ b/drivers/s390/char/sclp.h
@@ -122,11 +122,13 @@ struct sclp_req {
/* of some routines it wants to be called from the low level driver */
struct sclp_register {
struct list_head list;
- /* event masks this user is registered for */
+ /* User wants to receive: */
sccb_mask_t receive_mask;
+ /* User wants to send: */
sccb_mask_t send_mask;
- /* actually present events */
+ /* H/W can receive: */
sccb_mask_t sclp_receive_mask;
+ /* H/W can send: */
sccb_mask_t sclp_send_mask;
/* called if event type availability changes */
void (*state_change_fn)(struct sclp_register *);
diff --git a/drivers/s390/char/sclp_config.c b/drivers/s390/char/sclp_config.c
index 9dc77f14fa5..b8f35bc52b7 100644
--- a/drivers/s390/char/sclp_config.c
+++ b/drivers/s390/char/sclp_config.c
@@ -64,7 +64,7 @@ static int __init sclp_conf_init(void)
return rc;
}
- if (!(sclp_conf_register.sclp_receive_mask & EVTYP_CONFMGMDATA_MASK)) {
+ if (!(sclp_conf_register.sclp_send_mask & EVTYP_CONFMGMDATA_MASK)) {
printk(KERN_WARNING TAG "no configuration management.\n");
sclp_unregister(&sclp_conf_register);
rc = -ENOSYS;
diff --git a/drivers/s390/char/sclp_cpi_sys.c b/drivers/s390/char/sclp_cpi_sys.c
index 41617032afd..9f37456222e 100644
--- a/drivers/s390/char/sclp_cpi_sys.c
+++ b/drivers/s390/char/sclp_cpi_sys.c
@@ -129,7 +129,7 @@ static int cpi_req(void)
"to hardware console.\n");
goto out;
}
- if (!(sclp_cpi_event.sclp_send_mask & EVTYP_CTLPROGIDENT_MASK)) {
+ if (!(sclp_cpi_event.sclp_receive_mask & EVTYP_CTLPROGIDENT_MASK)) {
printk(KERN_WARNING "cpi: no control program "
"identification support\n");
rc = -EOPNOTSUPP;
diff --git a/drivers/s390/char/sclp_rw.c b/drivers/s390/char/sclp_rw.c
index ad7195d3de0..da09781b32f 100644
--- a/drivers/s390/char/sclp_rw.c
+++ b/drivers/s390/char/sclp_rw.c
@@ -452,10 +452,10 @@ sclp_emit_buffer(struct sclp_buffer *buffer,
return -EIO;
sccb = buffer->sccb;
- if (sclp_rw_event.sclp_send_mask & EVTYP_MSG_MASK)
+ if (sclp_rw_event.sclp_receive_mask & EVTYP_MSG_MASK)
/* Use normal write message */
sccb->msg_buf.header.type = EVTYP_MSG;
- else if (sclp_rw_event.sclp_send_mask & EVTYP_PMSGCMD_MASK)
+ else if (sclp_rw_event.sclp_receive_mask & EVTYP_PMSGCMD_MASK)
/* Use write priority message */
sccb->msg_buf.header.type = EVTYP_PMSGCMD;
else
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c
index f47f4a768be..92f52720179 100644
--- a/drivers/s390/char/sclp_vt220.c
+++ b/drivers/s390/char/sclp_vt220.c
@@ -202,7 +202,7 @@ sclp_vt220_callback(struct sclp_req *request, void *data)
static int
__sclp_vt220_emit(struct sclp_vt220_request *request)
{
- if (!(sclp_vt220_register.sclp_send_mask & EVTYP_VT220MSG_MASK)) {
+ if (!(sclp_vt220_register.sclp_receive_mask & EVTYP_VT220MSG_MASK)) {
request->sclp_req.status = SCLP_REQ_FAILED;
return -EIO;
}
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index d35dc3f25d0..fec004f62bc 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -32,7 +32,7 @@
#include "io_sch.h"
static struct timer_list recovery_timer;
-static spinlock_t recovery_lock;
+static DEFINE_SPINLOCK(recovery_lock);
static int recovery_phase;
static const unsigned long recovery_delay[] = { 3, 30, 300 };
@@ -1535,7 +1535,7 @@ static int recovery_check(struct device *dev, void *data)
return 0;
}
-static void recovery_func(unsigned long data)
+static void recovery_work_func(struct work_struct *unused)
{
int redo = 0;
@@ -1553,6 +1553,17 @@ static void recovery_func(unsigned long data)
CIO_MSG_EVENT(2, "recovery: end\n");
}
+static DECLARE_WORK(recovery_work, recovery_work_func);
+
+static void recovery_func(unsigned long data)
+{
+ /*
+ * We can't do our recovery in softirq context and it's not
+ * performance critical, so we schedule it.
+ */
+ schedule_work(&recovery_work);
+}
+
void ccw_device_schedule_recovery(void)
{
unsigned long flags;
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c
index 097fc0967e9..2b5bfb7c69e 100644
--- a/drivers/s390/cio/qdio.c
+++ b/drivers/s390/cio/qdio.c
@@ -32,7 +32,7 @@
#include <linux/module.h>
#include <linux/init.h>
-
+#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
@@ -1215,9 +1215,6 @@ tiqdio_is_inbound_q_done(struct qdio_q *q)
if (!no_used)
return 1;
- if (!q->siga_sync && !irq->is_qebsm)
- /* we'll check for more primed buffers in qeth_stop_polling */
- return 0;
if (irq->is_qebsm) {
count = 1;
start_buf = q->first_to_check;
@@ -3332,13 +3329,7 @@ qdio_activate(struct ccw_device *cdev, int flags)
}
}
- wait_event_interruptible_timeout(cdev->private->wait_q,
- ((irq_ptr->state ==
- QDIO_IRQ_STATE_STOPPED) ||
- (irq_ptr->state ==
- QDIO_IRQ_STATE_ERR)),
- QDIO_ACTIVATE_TIMEOUT);
-
+ msleep(QDIO_ACTIVATE_TIMEOUT);
switch (irq_ptr->state) {
case QDIO_IRQ_STATE_STOPPED:
case QDIO_IRQ_STATE_ERR:
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h
index 37870e4e938..da8a272fd75 100644
--- a/drivers/s390/cio/qdio.h
+++ b/drivers/s390/cio/qdio.h
@@ -57,10 +57,10 @@
of the queue to 0 */
#define QDIO_ESTABLISH_TIMEOUT (1*HZ)
-#define QDIO_ACTIVATE_TIMEOUT (5*HZ)
#define QDIO_CLEANUP_CLEAR_TIMEOUT (20*HZ)
#define QDIO_CLEANUP_HALT_TIMEOUT (10*HZ)
#define QDIO_FORCE_CHECK_TIMEOUT (10*HZ)
+#define QDIO_ACTIVATE_TIMEOUT (5) /* 5 ms */
enum qdio_irq_states {
QDIO_IRQ_STATE_INACTIVE,
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c
index c3076217871..d8a5c229c5a 100644
--- a/drivers/s390/net/claw.c
+++ b/drivers/s390/net/claw.c
@@ -1851,8 +1851,7 @@ claw_hw_tx(struct sk_buff *skb, struct net_device *dev, long linkid)
}
}
/* See how many write buffers are required to hold this data */
- numBuffers= ( skb->len + privptr->p_env->write_size - 1) /
- ( privptr->p_env->write_size);
+ numBuffers = DIV_ROUND_UP(skb->len, privptr->p_env->write_size);
/* If that number of buffers isn't available, give up for now */
if (privptr->write_free_count < numBuffers ||
@@ -2114,8 +2113,7 @@ init_ccw_bk(struct net_device *dev)
*/
ccw_blocks_perpage= PAGE_SIZE / CCWBK_SIZE;
ccw_pages_required=
- (ccw_blocks_required+ccw_blocks_perpage -1) /
- ccw_blocks_perpage;
+ DIV_ROUND_UP(ccw_blocks_required, ccw_blocks_perpage);
#ifdef DEBUGMSG
printk(KERN_INFO "%s: %s() > ccw_blocks_perpage=%d\n",
@@ -2131,30 +2129,29 @@ init_ccw_bk(struct net_device *dev)
* provide good performance. With packing buffers support 32k
* buffers are used.
*/
- if (privptr->p_env->read_size < PAGE_SIZE) {
- claw_reads_perpage= PAGE_SIZE / privptr->p_env->read_size;
- claw_read_pages= (privptr->p_env->read_buffers +
- claw_reads_perpage -1) / claw_reads_perpage;
+ if (privptr->p_env->read_size < PAGE_SIZE) {
+ claw_reads_perpage = PAGE_SIZE / privptr->p_env->read_size;
+ claw_read_pages = DIV_ROUND_UP(privptr->p_env->read_buffers,
+ claw_reads_perpage);
}
else { /* > or equal */
- privptr->p_buff_pages_perread=
- (privptr->p_env->read_size + PAGE_SIZE - 1) / PAGE_SIZE;
- claw_read_pages=
- privptr->p_env->read_buffers * privptr->p_buff_pages_perread;
+ privptr->p_buff_pages_perread =
+ DIV_ROUND_UP(privptr->p_env->read_size, PAGE_SIZE);
+ claw_read_pages = privptr->p_env->read_buffers *
+ privptr->p_buff_pages_perread;
}
if (privptr->p_env->write_size < PAGE_SIZE) {
- claw_writes_perpage=
- PAGE_SIZE / privptr->p_env->write_size;
- claw_write_pages=
- (privptr->p_env->write_buffers + claw_writes_perpage -1) /
- claw_writes_perpage;
+ claw_writes_perpage =
+ PAGE_SIZE / privptr->p_env->write_size;
+ claw_write_pages = DIV_ROUND_UP(privptr->p_env->write_buffers,
+ claw_writes_perpage);
}
else { /* > or equal */
- privptr->p_buff_pages_perwrite=
- (privptr->p_env->read_size + PAGE_SIZE - 1) / PAGE_SIZE;
- claw_write_pages=
- privptr->p_env->write_buffers * privptr->p_buff_pages_perwrite;
+ privptr->p_buff_pages_perwrite =
+ DIV_ROUND_UP(privptr->p_env->read_size, PAGE_SIZE);
+ claw_write_pages = privptr->p_env->write_buffers *
+ privptr->p_buff_pages_perwrite;
}
#ifdef DEBUGMSG
if (privptr->p_env->read_size < PAGE_SIZE) {
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index a7a0813b24c..c46666a2480 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -992,6 +992,16 @@ config SCSI_IZIP_SLOW_CTR
Generally, saying N is fine.
+config SCSI_MVSAS
+ tristate "Marvell 88SE6440 SAS/SATA support"
+ depends on PCI && SCSI
+ select SCSI_SAS_LIBSAS
+ help
+ This driver supports Marvell SAS/SATA PCI devices.
+
+ To compiler this driver as a module, choose M here: the module
+ will be called mvsas.
+
config SCSI_NCR53C406A
tristate "NCR53c406a SCSI support"
depends on ISA && SCSI
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 925c26b4fff..23e6ecbd477 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -119,6 +119,7 @@ obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsi/
obj-$(CONFIG_SCSI_IBMVSCSIS) += ibmvscsi/
obj-$(CONFIG_SCSI_HPTIOP) += hptiop.o
obj-$(CONFIG_SCSI_STEX) += stex.o
+obj-$(CONFIG_SCSI_MVSAS) += mvsas.o
obj-$(CONFIG_PS3_ROM) += ps3rom.o
obj-$(CONFIG_ARM) += arm/
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
index 4150c8a8fdc..dfaaae5e73a 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
@@ -89,7 +89,7 @@ ahd_linux_pci_dev_suspend(struct pci_dev *pdev, pm_message_t mesg)
pci_save_state(pdev);
pci_disable_device(pdev);
- if (mesg.event == PM_EVENT_SUSPEND)
+ if (mesg.event & PM_EVENT_SLEEP)
pci_set_power_state(pdev, PCI_D3hot);
return rc;
diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c
index 6d2ae641273..64e62ce59c1 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_core.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_core.c
@@ -695,15 +695,16 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
scb_index = ahc_inb(ahc, SCB_TAG);
scb = ahc_lookup_scb(ahc, scb_index);
if (devinfo.role == ROLE_INITIATOR) {
- if (scb == NULL)
- panic("HOST_MSG_LOOP with "
- "invalid SCB %x\n", scb_index);
+ if (bus_phase == P_MESGOUT) {
+ if (scb == NULL)
+ panic("HOST_MSG_LOOP with "
+ "invalid SCB %x\n",
+ scb_index);
- if (bus_phase == P_MESGOUT)
ahc_setup_initiator_msgout(ahc,
&devinfo,
scb);
- else {
+ } else {
ahc->msg_type =
MSG_TYPE_INITIATOR_MSGIN;
ahc->msgin_index = 0;
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
index dd6e21d6f1d..3d3eaef65fb 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
@@ -134,7 +134,7 @@ ahc_linux_pci_dev_suspend(struct pci_dev *pdev, pm_message_t mesg)
pci_save_state(pdev);
pci_disable_device(pdev);
- if (mesg.event == PM_EVENT_SUSPEND)
+ if (mesg.event & PM_EVENT_SLEEP)
pci_set_power_state(pdev, PCI_D3hot);
return rc;
diff --git a/drivers/scsi/aic94xx/aic94xx_scb.c b/drivers/scsi/aic94xx/aic94xx_scb.c
index 0febad4dd75..ab350504ca5 100644
--- a/drivers/scsi/aic94xx/aic94xx_scb.c
+++ b/drivers/scsi/aic94xx/aic94xx_scb.c
@@ -458,13 +458,19 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
tc_abort = le16_to_cpu(tc_abort);
list_for_each_entry_safe(a, b, &asd_ha->seq.pend_q, list) {
- struct sas_task *task = ascb->uldd_task;
+ struct sas_task *task = a->uldd_task;
+
+ if (a->tc_index != tc_abort)
+ continue;
- if (task && a->tc_index == tc_abort) {
+ if (task) {
failed_dev = task->dev;
sas_task_abort(task);
- break;
+ } else {
+ ASD_DPRINTK("R_T_A for non TASK scb 0x%x\n",
+ a->scb->header.opcode);
}
+ break;
}
if (!failed_dev) {
@@ -478,7 +484,7 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
* that the EH will wake up and do something.
*/
list_for_each_entry_safe(a, b, &asd_ha->seq.pend_q, list) {
- struct sas_task *task = ascb->uldd_task;
+ struct sas_task *task = a->uldd_task;
if (task &&
task->dev == failed_dev &&
diff --git a/drivers/scsi/aic94xx/aic94xx_tmf.c b/drivers/scsi/aic94xx/aic94xx_tmf.c
index b52124f3d3a..144f5ad2045 100644
--- a/drivers/scsi/aic94xx/aic94xx_tmf.c
+++ b/drivers/scsi/aic94xx/aic94xx_tmf.c
@@ -151,8 +151,6 @@ static int asd_clear_nexus_I_T(struct domain_device *dev)
CLEAR_NEXUS_PRE;
scb->clear_nexus.nexus = NEXUS_I_T;
scb->clear_nexus.flags = SEND_Q | EXEC_Q | NOTINQ;
- if (dev->tproto)
- scb->clear_nexus.flags |= SUSPEND_TX;
scb->clear_nexus.conn_handle = cpu_to_le16((u16)(unsigned long)
dev->lldd_dev);
CLEAR_NEXUS_POST;
@@ -169,8 +167,6 @@ static int asd_clear_nexus_I_T_L(struct domain_device *dev, u8 *lun)
CLEAR_NEXUS_PRE;
scb->clear_nexus.nexus = NEXUS_I_T_L;
scb->clear_nexus.flags = SEND_Q | EXEC_Q | NOTINQ;
- if (dev->tproto)
- scb->clear_nexus.flags |= SUSPEND_TX;
memcpy(scb->clear_nexus.ssp_task.lun, lun, 8);
scb->clear_nexus.conn_handle = cpu_to_le16((u16)(unsigned long)
dev->lldd_dev);
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index 4f9ff32cfed..f91f79c8007 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -1387,18 +1387,16 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \
switch(controlcode) {
case ARCMSR_MESSAGE_READ_RQBUFFER: {
- unsigned long *ver_addr;
+ unsigned char *ver_addr;
uint8_t *pQbuffer, *ptmpQbuffer;
int32_t allxfer_len = 0;
- void *tmp;
- tmp = kmalloc(1032, GFP_KERNEL|GFP_DMA);
- ver_addr = (unsigned long *)tmp;
- if (!tmp) {
+ ver_addr = kmalloc(1032, GFP_ATOMIC);
+ if (!ver_addr) {
retvalue = ARCMSR_MESSAGE_FAIL;
goto message_out;
}
- ptmpQbuffer = (uint8_t *) ver_addr;
+ ptmpQbuffer = ver_addr;
while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex)
&& (allxfer_len < 1031)) {
pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex];
@@ -1427,26 +1425,24 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \
}
arcmsr_iop_message_read(acb);
}
- memcpy(pcmdmessagefld->messagedatabuffer, (uint8_t *)ver_addr, allxfer_len);
+ memcpy(pcmdmessagefld->messagedatabuffer, ver_addr, allxfer_len);
pcmdmessagefld->cmdmessage.Length = allxfer_len;
pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
- kfree(tmp);
+ kfree(ver_addr);
}
break;
case ARCMSR_MESSAGE_WRITE_WQBUFFER: {
- unsigned long *ver_addr;
+ unsigned char *ver_addr;
int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex;
uint8_t *pQbuffer, *ptmpuserbuffer;
- void *tmp;
- tmp = kmalloc(1032, GFP_KERNEL|GFP_DMA);
- ver_addr = (unsigned long *)tmp;
- if (!tmp) {
+ ver_addr = kmalloc(1032, GFP_ATOMIC);
+ if (!ver_addr) {
retvalue = ARCMSR_MESSAGE_FAIL;
goto message_out;
}
- ptmpuserbuffer = (uint8_t *)ver_addr;
+ ptmpuserbuffer = ver_addr;
user_len = pcmdmessagefld->cmdmessage.Length;
memcpy(ptmpuserbuffer, pcmdmessagefld->messagedatabuffer, user_len);
wqbuf_lastindex = acb->wqbuf_lastindex;
@@ -1492,7 +1488,7 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \
retvalue = ARCMSR_MESSAGE_FAIL;
}
}
- kfree(tmp);
+ kfree(ver_addr);
}
break;
diff --git a/drivers/scsi/arm/fas216.h b/drivers/scsi/arm/fas216.h
index 3e73e264972..b65f4cf0eec 100644
--- a/drivers/scsi/arm/fas216.h
+++ b/drivers/scsi/arm/fas216.h
@@ -313,7 +313,7 @@ typedef struct {
/* miscellaneous */
int internal_done; /* flag to indicate request done */
- struct scsi_eh_save *ses; /* holds request sense restore info */
+ struct scsi_eh_save ses; /* holds request sense restore info */
unsigned long magic_end;
} FAS216_Info;
diff --git a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c
index de5773443c6..ce0228e26ae 100644
--- a/drivers/scsi/gdth_proc.c
+++ b/drivers/scsi/gdth_proc.c
@@ -694,15 +694,13 @@ static void gdth_ioctl_free(gdth_ha_str *ha, int size, char *buf, ulong64 paddr)
{
ulong flags;
- spin_lock_irqsave(&ha->smp_lock, flags);
-
if (buf == ha->pscratch) {
+ spin_lock_irqsave(&ha->smp_lock, flags);
ha->scratch_busy = FALSE;
+ spin_unlock_irqrestore(&ha->smp_lock, flags);
} else {
pci_free_consistent(ha->pdev, size, buf, paddr);
}
-
- spin_unlock_irqrestore(&ha->smp_lock, flags);
}
#ifdef GDTH_IOCTL_PROC
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 2074701f7e7..c72014a3e7d 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -5140,7 +5140,7 @@ static void ipr_build_ata_ioadl(struct ipr_cmnd *ipr_cmd,
struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl;
struct ipr_ioadl_desc *last_ioadl = NULL;
- int len = qc->nbytes + qc->pad_len;
+ int len = qc->nbytes;
struct scatterlist *sg;
unsigned int si;
@@ -5206,7 +5206,7 @@ static unsigned int ipr_qc_issue(struct ata_queued_cmd *qc)
ioarcb->cmd_pkt.request_type = IPR_RQTYPE_ATA_PASSTHRU;
ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_LINK_DESC;
ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_ULEN_CHK;
- ipr_cmd->dma_use_sg = qc->pad_len ? qc->n_elem + 1 : qc->n_elem;
+ ipr_cmd->dma_use_sg = qc->n_elem;
ipr_build_ata_ioadl(ipr_cmd, qc);
regs->flags |= IPR_ATA_FLAG_STATUS_ON_GOOD_COMPLETION;
diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
index bb152fb9fec..7ed568f180a 100644
--- a/drivers/scsi/ips.c
+++ b/drivers/scsi/ips.c
@@ -1576,7 +1576,7 @@ ips_make_passthru(ips_ha_t *ha, struct scsi_cmnd *SC, ips_scb_t *scb, int intr)
METHOD_TRACE("ips_make_passthru", 1);
scsi_for_each_sg(SC, sg, scsi_sg_count(SC), i)
- length += sg[i].length;
+ length += sg->length;
if (length < sizeof (ips_passthru_t)) {
/* wrong size */
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index 0996f866f14..7cd05b599a1 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -178,8 +178,8 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
task->uldd_task = qc;
if (ata_is_atapi(qc->tf.protocol)) {
memcpy(task->ata_task.atapi_packet, qc->cdb, qc->dev->cdb_len);
- task->total_xfer_len = qc->nbytes + qc->pad_len;
- task->num_scatter = qc->pad_len ? qc->n_elem + 1 : qc->n_elem;
+ task->total_xfer_len = qc->nbytes;
+ task->num_scatter = qc->n_elem;
} else {
for_each_sg(qc->sg, sg, qc->n_elem, si)
xfer += sg->length;
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index f869fba8680..704ea06a6e5 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -51,10 +51,14 @@ static void sas_scsi_task_done(struct sas_task *task)
{
struct task_status_struct *ts = &task->task_status;
struct scsi_cmnd *sc = task->uldd_task;
- struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(sc->device->host);
- unsigned ts_flags = task->task_state_flags;
int hs = 0, stat = 0;
+ if (unlikely(task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
+ /* Aborted tasks will be completed by the error handler */
+ SAS_DPRINTK("task done but aborted\n");
+ return;
+ }
+
if (unlikely(!sc)) {
SAS_DPRINTK("task_done called with non existing SCSI cmnd!\n");
list_del_init(&task->list);
@@ -120,11 +124,7 @@ static void sas_scsi_task_done(struct sas_task *task)
sc->result = (hs << 16) | stat;
list_del_init(&task->list);
sas_free_task(task);
- /* This is very ugly but this is how SCSI Core works. */
- if (ts_flags & SAS_TASK_STATE_ABORTED)
- scsi_eh_finish_cmd(sc, &sas_ha->eh_done_q);
- else
- sc->scsi_done(sc);
+ sc->scsi_done(sc);
}
static enum task_attribute sas_scsi_get_task_attr(struct scsi_cmnd *cmd)
@@ -255,13 +255,34 @@ out:
return res;
}
+static void sas_eh_finish_cmd(struct scsi_cmnd *cmd)
+{
+ struct sas_task *task = TO_SAS_TASK(cmd);
+ struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(cmd->device->host);
+
+ /* remove the aborted task flag to allow the task to be
+ * completed now. At this point, we only get called following
+ * an actual abort of the task, so we should be guaranteed not
+ * to be racing with any completions from the LLD (hence we
+ * don't need the task state lock to clear the flag) */
+ task->task_state_flags &= ~SAS_TASK_STATE_ABORTED;
+ /* Now call task_done. However, task will be free'd after
+ * this */
+ task->task_done(task);
+ /* now finish the command and move it on to the error
+ * handler done list, this also takes it off the
+ * error handler pending list */
+ scsi_eh_finish_cmd(cmd, &sas_ha->eh_done_q);
+}
+
static void sas_scsi_clear_queue_lu(struct list_head *error_q, struct scsi_cmnd *my_cmd)
{
struct scsi_cmnd *cmd, *n;
list_for_each_entry_safe(cmd, n, error_q, eh_entry) {
- if (cmd == my_cmd)
- list_del_init(&cmd->eh_entry);
+ if (cmd->device->sdev_target == my_cmd->device->sdev_target &&
+ cmd->device->lun == my_cmd->device->lun)
+ sas_eh_finish_cmd(cmd);
}
}
@@ -274,7 +295,7 @@ static void sas_scsi_clear_queue_I_T(struct list_head *error_q,
struct domain_device *x = cmd_to_domain_dev(cmd);
if (x == dev)
- list_del_init(&cmd->eh_entry);
+ sas_eh_finish_cmd(cmd);
}
}
@@ -288,7 +309,7 @@ static void sas_scsi_clear_queue_port(struct list_head *error_q,
struct asd_sas_port *x = dev->port;
if (x == port)
- list_del_init(&cmd->eh_entry);
+ sas_eh_finish_cmd(cmd);
}
}
@@ -528,14 +549,14 @@ Again:
case TASK_IS_DONE:
SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__,
task);
- task->task_done(task);
+ sas_eh_finish_cmd(cmd);
if (need_reset)
try_to_reset_cmd_device(shost, cmd);
continue;
case TASK_IS_ABORTED:
SAS_DPRINTK("%s: task 0x%p is aborted\n",
__FUNCTION__, task);
- task->task_done(task);
+ sas_eh_finish_cmd(cmd);
if (need_reset)
try_to_reset_cmd_device(shost, cmd);
continue;
@@ -547,7 +568,7 @@ Again:
"recovered\n",
SAS_ADDR(task->dev),
cmd->device->lun);
- task->task_done(task);
+ sas_eh_finish_cmd(cmd);
if (need_reset)
try_to_reset_cmd_device(shost, cmd);
sas_scsi_clear_queue_lu(work_q, cmd);
@@ -562,7 +583,7 @@ Again:
if (tmf_resp == TMF_RESP_FUNC_COMPLETE) {
SAS_DPRINTK("I_T %016llx recovered\n",
SAS_ADDR(task->dev->sas_addr));
- task->task_done(task);
+ sas_eh_finish_cmd(cmd);
if (need_reset)
try_to_reset_cmd_device(shost, cmd);
sas_scsi_clear_queue_I_T(work_q, task->dev);
@@ -577,7 +598,7 @@ Again:
if (res == TMF_RESP_FUNC_COMPLETE) {
SAS_DPRINTK("clear nexus port:%d "
"succeeded\n", port->id);
- task->task_done(task);
+ sas_eh_finish_cmd(cmd);
if (need_reset)
try_to_reset_cmd_device(shost, cmd);
sas_scsi_clear_queue_port(work_q,
@@ -591,10 +612,10 @@ Again:
if (res == TMF_RESP_FUNC_COMPLETE) {
SAS_DPRINTK("clear nexus ha "
"succeeded\n");
- task->task_done(task);
+ sas_eh_finish_cmd(cmd);
if (need_reset)
try_to_reset_cmd_device(shost, cmd);
- goto out;
+ goto clear_q;
}
}
/* If we are here -- this means that no amount
@@ -606,21 +627,18 @@ Again:
SAS_ADDR(task->dev->sas_addr),
cmd->device->lun);
- task->task_done(task);
+ sas_eh_finish_cmd(cmd);
if (need_reset)
try_to_reset_cmd_device(shost, cmd);
goto clear_q;
}
}
-out:
return list_empty(work_q);
clear_q:
SAS_DPRINTK("--- Exit %s -- clear_q\n", __FUNCTION__);
- list_for_each_entry_safe(cmd, n, work_q, eh_entry) {
- struct sas_task *task = TO_SAS_TASK(cmd);
- list_del_init(&cmd->eh_entry);
- task->task_done(task);
- }
+ list_for_each_entry_safe(cmd, n, work_q, eh_entry)
+ sas_eh_finish_cmd(cmd);
+
return list_empty(work_q);
}
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index 848d97744b4..0819f5f39de 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -55,7 +55,6 @@ void lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_enqueue_node(struct lpfc_vport *, struct lpfc_nodelist *);
void lpfc_dequeue_node(struct lpfc_vport *, struct lpfc_nodelist *);
-void lpfc_disable_node(struct lpfc_vport *, struct lpfc_nodelist *);
struct lpfc_nodelist *lpfc_enable_node(struct lpfc_vport *,
struct lpfc_nodelist *, int);
void lpfc_nlp_set_state(struct lpfc_vport *, struct lpfc_nodelist *, int);
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index bd572d6b60a..976653440fb 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -1694,7 +1694,7 @@ lpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
NLP_STE_UNUSED_NODE);
}
-void
+static void
lpfc_disable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
{
if ((ndlp->nlp_flag & NLP_DELAY_TMO) != 0)
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index f53206411cd..fc0d9501aba 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -648,28 +648,24 @@ lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count)
unsigned long flags;
struct hbq_dmabuf *hbq_buffer;
- if (!phba->hbqs[hbqno].hbq_alloc_buffer) {
+ if (!phba->hbqs[hbqno].hbq_alloc_buffer)
return 0;
- }
start = phba->hbqs[hbqno].buffer_count;
end = count + start;
- if (end > lpfc_hbq_defs[hbqno]->entry_count) {
+ if (end > lpfc_hbq_defs[hbqno]->entry_count)
end = lpfc_hbq_defs[hbqno]->entry_count;
- }
/* Check whether HBQ is still in use */
spin_lock_irqsave(&phba->hbalock, flags);
- if (!phba->hbq_in_use) {
- spin_unlock_irqrestore(&phba->hbalock, flags);
- return 0;
- }
+ if (!phba->hbq_in_use)
+ goto out;
/* Populate HBQ entries */
for (i = start; i < end; i++) {
hbq_buffer = (phba->hbqs[hbqno].hbq_alloc_buffer)(phba);
if (!hbq_buffer)
- return 1;
+ goto err;
hbq_buffer->tag = (i | (hbqno << 16));
if (lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer))
phba->hbqs[hbqno].buffer_count++;
@@ -677,8 +673,12 @@ lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count)
(phba->hbqs[hbqno].hbq_free_buffer)(phba, hbq_buffer);
}
+ out:
spin_unlock_irqrestore(&phba->hbalock, flags);
return 0;
+ err:
+ spin_unlock_irqrestore(&phba->hbalock, flags);
+ return 1;
}
int
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index 4d59ae8491a..b135a1ed4b2 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -151,19 +151,19 @@ mega_setup_mailbox(adapter_t *adapter)
*/
if( adapter->flag & BOARD_IOMAP ) {
- outb_p(adapter->mbox_dma & 0xFF,
+ outb(adapter->mbox_dma & 0xFF,
adapter->host->io_port + MBOX_PORT0);
- outb_p((adapter->mbox_dma >> 8) & 0xFF,
+ outb((adapter->mbox_dma >> 8) & 0xFF,
adapter->host->io_port + MBOX_PORT1);
- outb_p((adapter->mbox_dma >> 16) & 0xFF,
+ outb((adapter->mbox_dma >> 16) & 0xFF,
adapter->host->io_port + MBOX_PORT2);
- outb_p((adapter->mbox_dma >> 24) & 0xFF,
+ outb((adapter->mbox_dma >> 24) & 0xFF,
adapter->host->io_port + MBOX_PORT3);
- outb_p(ENABLE_MBOX_BYTE,
+ outb(ENABLE_MBOX_BYTE,
adapter->host->io_port + ENABLE_MBOX_REGION);
irq_ack(adapter);
diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c
index 651d09b08f2..fd63b06d9ef 100644
--- a/drivers/scsi/mesh.c
+++ b/drivers/scsi/mesh.c
@@ -1759,6 +1759,7 @@ static int mesh_suspend(struct macio_dev *mdev, pm_message_t mesg)
switch (mesg.event) {
case PM_EVENT_SUSPEND:
+ case PM_EVENT_HIBERNATE:
case PM_EVENT_FREEZE:
break;
default:
diff --git a/drivers/scsi/mvsas.c b/drivers/scsi/mvsas.c
new file mode 100644
index 00000000000..d4a6ac3c9c4
--- /dev/null
+++ b/drivers/scsi/mvsas.c
@@ -0,0 +1,2970 @@
+/*
+ mvsas.c - Marvell 88SE6440 SAS/SATA support
+
+ Copyright 2007 Red Hat, Inc.
+ Copyright 2008 Marvell. <kewei@marvell.com>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2,
+ or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty
+ of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with this program; see the file COPYING. If not,
+ write to the Free Software Foundation, 675 Mass Ave, Cambridge,
+ MA 02139, USA.
+
+ ---------------------------------------------------------------
+
+ Random notes:
+ * hardware supports controlling the endian-ness of data
+ structures. this permits elimination of all the le32_to_cpu()
+ and cpu_to_le32() conversions.
+
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/ctype.h>
+#include <scsi/libsas.h>
+#include <asm/io.h>
+
+#define DRV_NAME "mvsas"
+#define DRV_VERSION "0.5"
+#define _MV_DUMP 0
+#define MVS_DISABLE_NVRAM
+#define MVS_DISABLE_MSI
+
+#define mr32(reg) readl(regs + MVS_##reg)
+#define mw32(reg,val) writel((val), regs + MVS_##reg)
+#define mw32_f(reg,val) do { \
+ writel((val), regs + MVS_##reg); \
+ readl(regs + MVS_##reg); \
+ } while (0)
+
+#define MVS_ID_NOT_MAPPED 0xff
+#define MVS_CHIP_SLOT_SZ (1U << mvi->chip->slot_width)
+
+/* offset for D2H FIS in the Received FIS List Structure */
+#define SATA_RECEIVED_D2H_FIS(reg_set) \
+ ((void *) mvi->rx_fis + 0x400 + 0x100 * reg_set + 0x40)
+#define SATA_RECEIVED_PIO_FIS(reg_set) \
+ ((void *) mvi->rx_fis + 0x400 + 0x100 * reg_set + 0x20)
+#define UNASSOC_D2H_FIS(id) \
+ ((void *) mvi->rx_fis + 0x100 * id)
+
+#define for_each_phy(__lseq_mask, __mc, __lseq, __rest) \
+ for ((__mc) = (__lseq_mask), (__lseq) = 0; \
+ (__mc) != 0 && __rest; \
+ (++__lseq), (__mc) >>= 1)
+
+/* driver compile-time configuration */
+enum driver_configuration {
+ MVS_TX_RING_SZ = 1024, /* TX ring size (12-bit) */
+ MVS_RX_RING_SZ = 1024, /* RX ring size (12-bit) */
+ /* software requires power-of-2
+ ring size */
+
+ MVS_SLOTS = 512, /* command slots */
+ MVS_SLOT_BUF_SZ = 8192, /* cmd tbl + IU + status + PRD */
+ MVS_SSP_CMD_SZ = 64, /* SSP command table buffer size */
+ MVS_ATA_CMD_SZ = 96, /* SATA command table buffer size */
+ MVS_OAF_SZ = 64, /* Open address frame buffer size */
+
+ MVS_RX_FIS_COUNT = 17, /* Optional rx'd FISs (max 17) */
+
+ MVS_QUEUE_SIZE = 30, /* Support Queue depth */
+};
+
+/* unchangeable hardware details */
+enum hardware_details {
+ MVS_MAX_PHYS = 8, /* max. possible phys */
+ MVS_MAX_PORTS = 8, /* max. possible ports */
+ MVS_RX_FISL_SZ = 0x400 + (MVS_RX_FIS_COUNT * 0x100),
+};
+
+/* peripheral registers (BAR2) */
+enum peripheral_registers {
+ SPI_CTL = 0x10, /* EEPROM control */
+ SPI_CMD = 0x14, /* EEPROM command */
+ SPI_DATA = 0x18, /* EEPROM data */
+};
+
+enum peripheral_register_bits {
+ TWSI_RDY = (1U << 7), /* EEPROM interface ready */
+ TWSI_RD = (1U << 4), /* EEPROM read access */
+
+ SPI_ADDR_MASK = 0x3ffff, /* bits 17:0 */
+};
+
+/* enhanced mode registers (BAR4) */
+enum hw_registers {
+ MVS_GBL_CTL = 0x04, /* global control */
+ MVS_GBL_INT_STAT = 0x08, /* global irq status */
+ MVS_GBL_PI = 0x0C, /* ports implemented bitmask */
+ MVS_GBL_PORT_TYPE = 0xa0, /* port type */
+
+ MVS_CTL = 0x100, /* SAS/SATA port configuration */
+ MVS_PCS = 0x104, /* SAS/SATA port control/status */
+ MVS_CMD_LIST_LO = 0x108, /* cmd list addr */
+ MVS_CMD_LIST_HI = 0x10C,
+ MVS_RX_FIS_LO = 0x110, /* RX FIS list addr */
+ MVS_RX_FIS_HI = 0x114,
+
+ MVS_TX_CFG = 0x120, /* TX configuration */
+ MVS_TX_LO = 0x124, /* TX (delivery) ring addr */
+ MVS_TX_HI = 0x128,
+
+ MVS_TX_PROD_IDX = 0x12C, /* TX producer pointer */
+ MVS_TX_CONS_IDX = 0x130, /* TX consumer pointer (RO) */
+ MVS_RX_CFG = 0x134, /* RX configuration */
+ MVS_RX_LO = 0x138, /* RX (completion) ring addr */
+ MVS_RX_HI = 0x13C,
+ MVS_RX_CONS_IDX = 0x140, /* RX consumer pointer (RO) */
+
+ MVS_INT_COAL = 0x148, /* Int coalescing config */
+ MVS_INT_COAL_TMOUT = 0x14C, /* Int coalescing timeout */
+ MVS_INT_STAT = 0x150, /* Central int status */
+ MVS_INT_MASK = 0x154, /* Central int enable */
+ MVS_INT_STAT_SRS = 0x158, /* SATA register set status */
+ MVS_INT_MASK_SRS = 0x15C,
+
+ /* ports 1-3 follow after this */
+ MVS_P0_INT_STAT = 0x160, /* port0 interrupt status */
+ MVS_P0_INT_MASK = 0x164, /* port0 interrupt mask */
+ MVS_P4_INT_STAT = 0x200, /* Port 4 interrupt status */
+ MVS_P4_INT_MASK = 0x204, /* Port 4 interrupt enable mask */
+
+ /* ports 1-3 follow after this */
+ MVS_P0_SER_CTLSTAT = 0x180, /* port0 serial control/status */
+ MVS_P4_SER_CTLSTAT = 0x220, /* port4 serial control/status */
+
+ MVS_CMD_ADDR = 0x1B8, /* Command register port (addr) */
+ MVS_CMD_DATA = 0x1BC, /* Command register port (data) */
+
+ /* ports 1-3 follow after this */
+ MVS_P0_CFG_ADDR = 0x1C0, /* port0 phy register address */
+ MVS_P0_CFG_DATA = 0x1C4, /* port0 phy register data */
+ MVS_P4_CFG_ADDR = 0x230, /* Port 4 config address */
+ MVS_P4_CFG_DATA = 0x234, /* Port 4 config data */
+
+ /* ports 1-3 follow after this */
+ MVS_P0_VSR_ADDR = 0x1E0, /* port0 VSR address */
+ MVS_P0_VSR_DATA = 0x1E4, /* port0 VSR data */
+ MVS_P4_VSR_ADDR = 0x250, /* port 4 VSR addr */
+ MVS_P4_VSR_DATA = 0x254, /* port 4 VSR data */
+};
+
+enum hw_register_bits {
+ /* MVS_GBL_CTL */
+ INT_EN = (1U << 1), /* Global int enable */
+ HBA_RST = (1U << 0), /* HBA reset */
+
+ /* MVS_GBL_INT_STAT */
+ INT_XOR = (1U << 4), /* XOR engine event */
+ INT_SAS_SATA = (1U << 0), /* SAS/SATA event */
+
+ /* MVS_GBL_PORT_TYPE */ /* shl for ports 1-3 */
+ SATA_TARGET = (1U << 16), /* port0 SATA target enable */
+ MODE_AUTO_DET_PORT7 = (1U << 15), /* port0 SAS/SATA autodetect */
+ MODE_AUTO_DET_PORT6 = (1U << 14),
+ MODE_AUTO_DET_PORT5 = (1U << 13),
+ MODE_AUTO_DET_PORT4 = (1U << 12),
+ MODE_AUTO_DET_PORT3 = (1U << 11),
+ MODE_AUTO_DET_PORT2 = (1U << 10),
+ MODE_AUTO_DET_PORT1 = (1U << 9),
+ MODE_AUTO_DET_PORT0 = (1U << 8),
+ MODE_AUTO_DET_EN = MODE_AUTO_DET_PORT0 | MODE_AUTO_DET_PORT1 |
+ MODE_AUTO_DET_PORT2 | MODE_AUTO_DET_PORT3 |
+ MODE_AUTO_DET_PORT4 | MODE_AUTO_DET_PORT5 |
+ MODE_AUTO_DET_PORT6 | MODE_AUTO_DET_PORT7,
+ MODE_SAS_PORT7_MASK = (1U << 7), /* port0 SAS(1), SATA(0) mode */
+ MODE_SAS_PORT6_MASK = (1U << 6),
+ MODE_SAS_PORT5_MASK = (1U << 5),
+ MODE_SAS_PORT4_MASK = (1U << 4),
+ MODE_SAS_PORT3_MASK = (1U << 3),
+ MODE_SAS_PORT2_MASK = (1U << 2),
+ MODE_SAS_PORT1_MASK = (1U << 1),
+ MODE_SAS_PORT0_MASK = (1U << 0),
+ MODE_SAS_SATA = MODE_SAS_PORT0_MASK | MODE_SAS_PORT1_MASK |
+ MODE_SAS_PORT2_MASK | MODE_SAS_PORT3_MASK |
+ MODE_SAS_PORT4_MASK | MODE_SAS_PORT5_MASK |
+ MODE_SAS_PORT6_MASK | MODE_SAS_PORT7_MASK,
+
+ /* SAS_MODE value may be
+ * dictated (in hw) by values
+ * of SATA_TARGET & AUTO_DET
+ */
+
+ /* MVS_TX_CFG */
+ TX_EN = (1U << 16), /* Enable TX */
+ TX_RING_SZ_MASK = 0xfff, /* TX ring size, bits 11:0 */
+
+ /* MVS_RX_CFG */
+ RX_EN = (1U << 16), /* Enable RX */
+ RX_RING_SZ_MASK = 0xfff, /* RX ring size, bits 11:0 */
+
+ /* MVS_INT_COAL */
+ COAL_EN = (1U << 16), /* Enable int coalescing */
+
+ /* MVS_INT_STAT, MVS_INT_MASK */
+ CINT_I2C = (1U << 31), /* I2C event */
+ CINT_SW0 = (1U << 30), /* software event 0 */
+ CINT_SW1 = (1U << 29), /* software event 1 */
+ CINT_PRD_BC = (1U << 28), /* PRD BC err for read cmd */
+ CINT_DMA_PCIE = (1U << 27), /* DMA to PCIE timeout */
+ CINT_MEM = (1U << 26), /* int mem parity err */
+ CINT_I2C_SLAVE = (1U << 25), /* slave I2C event */
+ CINT_SRS = (1U << 3), /* SRS event */
+ CINT_CI_STOP = (1U << 1), /* cmd issue stopped */
+ CINT_DONE = (1U << 0), /* cmd completion */
+
+ /* shl for ports 1-3 */
+ CINT_PORT_STOPPED = (1U << 16), /* port0 stopped */
+ CINT_PORT = (1U << 8), /* port0 event */
+ CINT_PORT_MASK_OFFSET = 8,
+ CINT_PORT_MASK = (0xFF << CINT_PORT_MASK_OFFSET),
+
+ /* TX (delivery) ring bits */
+ TXQ_CMD_SHIFT = 29,
+ TXQ_CMD_SSP = 1, /* SSP protocol */
+ TXQ_CMD_SMP = 2, /* SMP protocol */
+ TXQ_CMD_STP = 3, /* STP/SATA protocol */
+ TXQ_CMD_SSP_FREE_LIST = 4, /* add to SSP targ free list */
+ TXQ_CMD_SLOT_RESET = 7, /* reset command slot */
+ TXQ_MODE_I = (1U << 28), /* mode: 0=target,1=initiator */
+ TXQ_PRIO_HI = (1U << 27), /* priority: 0=normal, 1=high */
+ TXQ_SRS_SHIFT = 20, /* SATA register set */
+ TXQ_SRS_MASK = 0x7f,
+ TXQ_PHY_SHIFT = 12, /* PHY bitmap */
+ TXQ_PHY_MASK = 0xff,
+ TXQ_SLOT_MASK = 0xfff, /* slot number */
+
+ /* RX (completion) ring bits */
+ RXQ_GOOD = (1U << 23), /* Response good */
+ RXQ_SLOT_RESET = (1U << 21), /* Slot reset complete */
+ RXQ_CMD_RX = (1U << 20), /* target cmd received */
+ RXQ_ATTN = (1U << 19), /* attention */
+ RXQ_RSP = (1U << 18), /* response frame xfer'd */
+ RXQ_ERR = (1U << 17), /* err info rec xfer'd */
+ RXQ_DONE = (1U << 16), /* cmd complete */
+ RXQ_SLOT_MASK = 0xfff, /* slot number */
+
+ /* mvs_cmd_hdr bits */
+ MCH_PRD_LEN_SHIFT = 16, /* 16-bit PRD table len */
+ MCH_SSP_FR_TYPE_SHIFT = 13, /* SSP frame type */
+
+ /* SSP initiator only */
+ MCH_SSP_FR_CMD = 0x0, /* COMMAND frame */
+
+ /* SSP initiator or target */
+ MCH_SSP_FR_TASK = 0x1, /* TASK frame */
+
+ /* SSP target only */
+ MCH_SSP_FR_XFER_RDY = 0x4, /* XFER_RDY frame */
+ MCH_SSP_FR_RESP = 0x5, /* RESPONSE frame */
+ MCH_SSP_FR_READ = 0x6, /* Read DATA frame(s) */
+ MCH_SSP_FR_READ_RESP = 0x7, /* ditto, plus RESPONSE */
+
+ MCH_PASSTHRU = (1U << 12), /* pass-through (SSP) */
+ MCH_FBURST = (1U << 11), /* first burst (SSP) */
+ MCH_CHK_LEN = (1U << 10), /* chk xfer len (SSP) */
+ MCH_RETRY = (1U << 9), /* tport layer retry (SSP) */
+ MCH_PROTECTION = (1U << 8), /* protection info rec (SSP) */
+ MCH_RESET = (1U << 7), /* Reset (STP/SATA) */
+ MCH_FPDMA = (1U << 6), /* First party DMA (STP/SATA) */
+ MCH_ATAPI = (1U << 5), /* ATAPI (STP/SATA) */
+ MCH_BIST = (1U << 4), /* BIST activate (STP/SATA) */
+ MCH_PMP_MASK = 0xf, /* PMP from cmd FIS (STP/SATA)*/
+
+ CCTL_RST = (1U << 5), /* port logic reset */
+
+ /* 0(LSB first), 1(MSB first) */
+ CCTL_ENDIAN_DATA = (1U << 3), /* PRD data */
+ CCTL_ENDIAN_RSP = (1U << 2), /* response frame */
+ CCTL_ENDIAN_OPEN = (1U << 1), /* open address frame */
+ CCTL_ENDIAN_CMD = (1U << 0), /* command table */
+
+ /* MVS_Px_SER_CTLSTAT (per-phy control) */
+ PHY_SSP_RST = (1U << 3), /* reset SSP link layer */
+ PHY_BCAST_CHG = (1U << 2), /* broadcast(change) notif */
+ PHY_RST_HARD = (1U << 1), /* hard reset + phy reset */
+ PHY_RST = (1U << 0), /* phy reset */
+ PHY_MIN_SPP_PHYS_LINK_RATE_MASK = (0xF << 8),
+ PHY_MAX_SPP_PHYS_LINK_RATE_MASK = (0xF << 12),
+ PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET = (16),
+ PHY_NEG_SPP_PHYS_LINK_RATE_MASK =
+ (0xF << PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET),
+ PHY_READY_MASK = (1U << 20),
+
+ /* MVS_Px_INT_STAT, MVS_Px_INT_MASK (per-phy events) */
+ PHYEV_DEC_ERR = (1U << 24), /* Phy Decoding Error */
+ PHYEV_UNASSOC_FIS = (1U << 19), /* unassociated FIS rx'd */
+ PHYEV_AN = (1U << 18), /* SATA async notification */
+ PHYEV_BIST_ACT = (1U << 17), /* BIST activate FIS */
+ PHYEV_SIG_FIS = (1U << 16), /* signature FIS */
+ PHYEV_POOF = (1U << 12), /* phy ready from 1 -> 0 */
+ PHYEV_IU_BIG = (1U << 11), /* IU too long err */
+ PHYEV_IU_SMALL = (1U << 10), /* IU too short err */
+ PHYEV_UNK_TAG = (1U << 9), /* unknown tag */
+ PHYEV_BROAD_CH = (1U << 8), /* broadcast(CHANGE) */
+ PHYEV_COMWAKE = (1U << 7), /* COMWAKE rx'd */
+ PHYEV_PORT_SEL = (1U << 6), /* port selector present */
+ PHYEV_HARD_RST = (1U << 5), /* hard reset rx'd */
+ PHYEV_ID_TMOUT = (1U << 4), /* identify timeout */
+ PHYEV_ID_FAIL = (1U << 3), /* identify failed */
+ PHYEV_ID_DONE = (1U << 2), /* identify done */
+ PHYEV_HARD_RST_DONE = (1U << 1), /* hard reset done */
+ PHYEV_RDY_CH = (1U << 0), /* phy ready changed state */
+
+ /* MVS_PCS */
+ PCS_EN_SATA_REG_SHIFT = (16), /* Enable SATA Register Set */
+ PCS_EN_PORT_XMT_SHIFT = (12), /* Enable Port Transmit */
+ PCS_EN_PORT_XMT_SHIFT2 = (8), /* For 6480 */
+ PCS_SATA_RETRY = (1U << 8), /* retry ctl FIS on R_ERR */
+ PCS_RSP_RX_EN = (1U << 7), /* raw response rx */
+ PCS_SELF_CLEAR = (1U << 5), /* self-clearing int mode */
+ PCS_FIS_RX_EN = (1U << 4), /* FIS rx enable */
+ PCS_CMD_STOP_ERR = (1U << 3), /* cmd stop-on-err enable */
+ PCS_CMD_RST = (1U << 1), /* reset cmd issue */
+ PCS_CMD_EN = (1U << 0), /* enable cmd issue */
+
+ /* Port n Attached Device Info */
+ PORT_DEV_SSP_TRGT = (1U << 19),
+ PORT_DEV_SMP_TRGT = (1U << 18),
+ PORT_DEV_STP_TRGT = (1U << 17),
+ PORT_DEV_SSP_INIT = (1U << 11),
+ PORT_DEV_SMP_INIT = (1U << 10),
+ PORT_DEV_STP_INIT = (1U << 9),
+ PORT_PHY_ID_MASK = (0xFFU << 24),
+ PORT_DEV_TRGT_MASK = (0x7U << 17),
+ PORT_DEV_INIT_MASK = (0x7U << 9),
+ PORT_DEV_TYPE_MASK = (0x7U << 0),
+
+ /* Port n PHY Status */
+ PHY_RDY = (1U << 2),
+ PHY_DW_SYNC = (1U << 1),
+ PHY_OOB_DTCTD = (1U << 0),
+
+ /* VSR */
+ /* PHYMODE 6 (CDB) */
+ PHY_MODE6_DTL_SPEED = (1U << 27),
+};
+
+enum mvs_info_flags {
+ MVF_MSI = (1U << 0), /* MSI is enabled */
+ MVF_PHY_PWR_FIX = (1U << 1), /* bug workaround */
+};
+
+enum sas_cmd_port_registers {
+ CMD_CMRST_OOB_DET = 0x100, /* COMRESET OOB detect register */
+ CMD_CMWK_OOB_DET = 0x104, /* COMWAKE OOB detect register */
+ CMD_CMSAS_OOB_DET = 0x108, /* COMSAS OOB detect register */
+ CMD_BRST_OOB_DET = 0x10c, /* burst OOB detect register */
+ CMD_OOB_SPACE = 0x110, /* OOB space control register */
+ CMD_OOB_BURST = 0x114, /* OOB burst control register */
+ CMD_PHY_TIMER = 0x118, /* PHY timer control register */
+ CMD_PHY_CONFIG0 = 0x11c, /* PHY config register 0 */
+ CMD_PHY_CONFIG1 = 0x120, /* PHY config register 1 */
+ CMD_SAS_CTL0 = 0x124, /* SAS control register 0 */
+ CMD_SAS_CTL1 = 0x128, /* SAS control register 1 */
+ CMD_SAS_CTL2 = 0x12c, /* SAS control register 2 */
+ CMD_SAS_CTL3 = 0x130, /* SAS control register 3 */
+ CMD_ID_TEST = 0x134, /* ID test register */
+ CMD_PL_TIMER = 0x138, /* PL timer register */
+ CMD_WD_TIMER = 0x13c, /* WD timer register */
+ CMD_PORT_SEL_COUNT = 0x140, /* port selector count register */
+ CMD_APP_MEM_CTL = 0x144, /* Application Memory Control */
+ CMD_XOR_MEM_CTL = 0x148, /* XOR Block Memory Control */
+ CMD_DMA_MEM_CTL = 0x14c, /* DMA Block Memory Control */
+ CMD_PORT_MEM_CTL0 = 0x150, /* Port Memory Control 0 */
+ CMD_PORT_MEM_CTL1 = 0x154, /* Port Memory Control 1 */
+ CMD_SATA_PORT_MEM_CTL0 = 0x158, /* SATA Port Memory Control 0 */
+ CMD_SATA_PORT_MEM_CTL1 = 0x15c, /* SATA Port Memory Control 1 */
+ CMD_XOR_MEM_BIST_CTL = 0x160, /* XOR Memory BIST Control */
+ CMD_XOR_MEM_BIST_STAT = 0x164, /* XOR Memroy BIST Status */
+ CMD_DMA_MEM_BIST_CTL = 0x168, /* DMA Memory BIST Control */
+ CMD_DMA_MEM_BIST_STAT = 0x16c, /* DMA Memory BIST Status */
+ CMD_PORT_MEM_BIST_CTL = 0x170, /* Port Memory BIST Control */
+ CMD_PORT_MEM_BIST_STAT0 = 0x174, /* Port Memory BIST Status 0 */
+ CMD_PORT_MEM_BIST_STAT1 = 0x178, /* Port Memory BIST Status 1 */
+ CMD_STP_MEM_BIST_CTL = 0x17c, /* STP Memory BIST Control */
+ CMD_STP_MEM_BIST_STAT0 = 0x180, /* STP Memory BIST Status 0 */
+ CMD_STP_MEM_BIST_STAT1 = 0x184, /* STP Memory BIST Status 1 */
+ CMD_RESET_COUNT = 0x188, /* Reset Count */
+ CMD_MONTR_DATA_SEL = 0x18C, /* Monitor Data/Select */
+ CMD_PLL_PHY_CONFIG = 0x190, /* PLL/PHY Configuration */
+ CMD_PHY_CTL = 0x194, /* PHY Control and Status */
+ CMD_PHY_TEST_COUNT0 = 0x198, /* Phy Test Count 0 */
+ CMD_PHY_TEST_COUNT1 = 0x19C, /* Phy Test Count 1 */
+ CMD_PHY_TEST_COUNT2 = 0x1A0, /* Phy Test Count 2 */
+ CMD_APP_ERR_CONFIG = 0x1A4, /* Application Error Configuration */
+ CMD_PND_FIFO_CTL0 = 0x1A8, /* Pending FIFO Control 0 */
+ CMD_HOST_CTL = 0x1AC, /* Host Control Status */
+ CMD_HOST_WR_DATA = 0x1B0, /* Host Write Data */
+ CMD_HOST_RD_DATA = 0x1B4, /* Host Read Data */
+ CMD_PHY_MODE_21 = 0x1B8, /* Phy Mode 21 */
+ CMD_SL_MODE0 = 0x1BC, /* SL Mode 0 */
+ CMD_SL_MODE1 = 0x1C0, /* SL Mode 1 */
+ CMD_PND_FIFO_CTL1 = 0x1C4, /* Pending FIFO Control 1 */
+};
+
+/* SAS/SATA configuration port registers, aka phy registers */
+enum sas_sata_config_port_regs {
+ PHYR_IDENTIFY = 0x00, /* info for IDENTIFY frame */
+ PHYR_ADDR_LO = 0x04, /* my SAS address (low) */
+ PHYR_ADDR_HI = 0x08, /* my SAS address (high) */
+ PHYR_ATT_DEV_INFO = 0x0C, /* attached device info */
+ PHYR_ATT_ADDR_LO = 0x10, /* attached dev SAS addr (low) */
+ PHYR_ATT_ADDR_HI = 0x14, /* attached dev SAS addr (high) */
+ PHYR_SATA_CTL = 0x18, /* SATA control */
+ PHYR_PHY_STAT = 0x1C, /* PHY status */
+ PHYR_SATA_SIG0 = 0x20, /*port SATA signature FIS(Byte 0-3) */
+ PHYR_SATA_SIG1 = 0x24, /*port SATA signature FIS(Byte 4-7) */
+ PHYR_SATA_SIG2 = 0x28, /*port SATA signature FIS(Byte 8-11) */
+ PHYR_SATA_SIG3 = 0x2c, /*port SATA signature FIS(Byte 12-15) */
+ PHYR_R_ERR_COUNT = 0x30, /* port R_ERR count register */
+ PHYR_CRC_ERR_COUNT = 0x34, /* port CRC error count register */
+ PHYR_WIDE_PORT = 0x38, /* wide port participating */
+ PHYR_CURRENT0 = 0x80, /* current connection info 0 */
+ PHYR_CURRENT1 = 0x84, /* current connection info 1 */
+ PHYR_CURRENT2 = 0x88, /* current connection info 2 */
+};
+
+/* SAS/SATA Vendor Specific Port Registers */
+enum sas_sata_vsp_regs {
+ VSR_PHY_STAT = 0x00, /* Phy Status */
+ VSR_PHY_MODE1 = 0x01, /* phy tx */
+ VSR_PHY_MODE2 = 0x02, /* tx scc */
+ VSR_PHY_MODE3 = 0x03, /* pll */
+ VSR_PHY_MODE4 = 0x04, /* VCO */
+ VSR_PHY_MODE5 = 0x05, /* Rx */
+ VSR_PHY_MODE6 = 0x06, /* CDR */
+ VSR_PHY_MODE7 = 0x07, /* Impedance */
+ VSR_PHY_MODE8 = 0x08, /* Voltage */
+ VSR_PHY_MODE9 = 0x09, /* Test */
+ VSR_PHY_MODE10 = 0x0A, /* Power */
+ VSR_PHY_MODE11 = 0x0B, /* Phy Mode */
+ VSR_PHY_VS0 = 0x0C, /* Vednor Specific 0 */
+ VSR_PHY_VS1 = 0x0D, /* Vednor Specific 1 */
+};
+
+enum pci_cfg_registers {
+ PCR_PHY_CTL = 0x40,
+ PCR_PHY_CTL2 = 0x90,
+ PCR_DEV_CTRL = 0xE8,
+};
+
+enum pci_cfg_register_bits {
+ PCTL_PWR_ON = (0xFU << 24),
+ PCTL_OFF = (0xFU << 12),
+ PRD_REQ_SIZE = (0x4000),
+ PRD_REQ_MASK = (0x00007000),
+};
+
+enum nvram_layout_offsets {
+ NVR_SIG = 0x00, /* 0xAA, 0x55 */
+ NVR_SAS_ADDR = 0x02, /* 8-byte SAS address */
+};
+
+enum chip_flavors {
+ chip_6320,
+ chip_6440,
+ chip_6480,
+};
+
+enum port_type {
+ PORT_TYPE_SAS = (1L << 1),
+ PORT_TYPE_SATA = (1L << 0),
+};
+
+/* Command Table Format */
+enum ct_format {
+ /* SSP */
+ SSP_F_H = 0x00,
+ SSP_F_IU = 0x18,
+ SSP_F_MAX = 0x4D,
+ /* STP */
+ STP_CMD_FIS = 0x00,
+ STP_ATAPI_CMD = 0x40,
+ STP_F_MAX = 0x10,
+ /* SMP */
+ SMP_F_T = 0x00,
+ SMP_F_DEP = 0x01,
+ SMP_F_MAX = 0x101,
+};
+
+enum status_buffer {
+ SB_EIR_OFF = 0x00, /* Error Information Record */
+ SB_RFB_OFF = 0x08, /* Response Frame Buffer */
+ SB_RFB_MAX = 0x400, /* RFB size*/
+};
+
+enum error_info_rec {
+ CMD_ISS_STPD = (1U << 31), /* Cmd Issue Stopped */
+};
+
+struct mvs_chip_info {
+ u32 n_phy;
+ u32 srs_sz;
+ u32 slot_width;
+};
+
+struct mvs_err_info {
+ __le32 flags;
+ __le32 flags2;
+};
+
+struct mvs_prd {
+ __le64 addr; /* 64-bit buffer address */
+ __le32 reserved;
+ __le32 len; /* 16-bit length */
+};
+
+struct mvs_cmd_hdr {
+ __le32 flags; /* PRD tbl len; SAS, SATA ctl */
+ __le32 lens; /* cmd, max resp frame len */
+ __le32 tags; /* targ port xfer tag; tag */
+ __le32 data_len; /* data xfer len */
+ __le64 cmd_tbl; /* command table address */
+ __le64 open_frame; /* open addr frame address */
+ __le64 status_buf; /* status buffer address */
+ __le64 prd_tbl; /* PRD tbl address */
+ __le32 reserved[4];
+};
+
+struct mvs_slot_info {
+ struct sas_task *task;
+ u32 n_elem;
+ u32 tx;
+
+ /* DMA buffer for storing cmd tbl, open addr frame, status buffer,
+ * and PRD table
+ */
+ void *buf;
+ dma_addr_t buf_dma;
+#if _MV_DUMP
+ u32 cmd_size;
+#endif
+
+ void *response;
+};
+
+struct mvs_port {
+ struct asd_sas_port sas_port;
+ u8 port_attached;
+ u8 taskfileset;
+ u8 wide_port_phymap;
+};
+
+struct mvs_phy {
+ struct mvs_port *port;
+ struct asd_sas_phy sas_phy;
+ struct sas_identify identify;
+ struct scsi_device *sdev;
+ u64 dev_sas_addr;
+ u64 att_dev_sas_addr;
+ u32 att_dev_info;
+ u32 dev_info;
+ u32 phy_type;
+ u32 phy_status;
+ u32 irq_status;
+ u32 frame_rcvd_size;
+ u8 frame_rcvd[32];
+ u8 phy_attached;
+};
+
+struct mvs_info {
+ unsigned long flags;
+
+ spinlock_t lock; /* host-wide lock */
+ struct pci_dev *pdev; /* our device */
+ void __iomem *regs; /* enhanced mode registers */
+ void __iomem *peri_regs; /* peripheral registers */
+
+ u8 sas_addr[SAS_ADDR_SIZE];
+ struct sas_ha_struct sas; /* SCSI/SAS glue */
+ struct Scsi_Host *shost;
+
+ __le32 *tx; /* TX (delivery) DMA ring */
+ dma_addr_t tx_dma;
+ u32 tx_prod; /* cached next-producer idx */
+
+ __le32 *rx; /* RX (completion) DMA ring */
+ dma_addr_t rx_dma;
+ u32 rx_cons; /* RX consumer idx */
+
+ __le32 *rx_fis; /* RX'd FIS area */
+ dma_addr_t rx_fis_dma;
+
+ struct mvs_cmd_hdr *slot; /* DMA command header slots */
+ dma_addr_t slot_dma;
+
+ const struct mvs_chip_info *chip;
+
+ unsigned long tags[MVS_SLOTS];
+ struct mvs_slot_info slot_info[MVS_SLOTS];
+ /* further per-slot information */
+ struct mvs_phy phy[MVS_MAX_PHYS];
+ struct mvs_port port[MVS_MAX_PHYS];
+
+ u32 can_queue; /* per adapter */
+ u32 tag_out; /*Get*/
+ u32 tag_in; /*Give*/
+};
+
+struct mvs_queue_task {
+ struct list_head list;
+
+ void *uldd_task;
+};
+
+static int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
+ void *funcdata);
+static u32 mvs_read_phy_ctl(struct mvs_info *mvi, u32 port);
+static void mvs_write_phy_ctl(struct mvs_info *mvi, u32 port, u32 val);
+static u32 mvs_read_port_irq_stat(struct mvs_info *mvi, u32 port);
+static void mvs_write_port_irq_stat(struct mvs_info *mvi, u32 port, u32 val);
+static void mvs_write_port_irq_mask(struct mvs_info *mvi, u32 port, u32 val);
+static u32 mvs_read_port_irq_mask(struct mvs_info *mvi, u32 port);
+
+static u32 mvs_is_phy_ready(struct mvs_info *mvi, int i);
+static void mvs_detect_porttype(struct mvs_info *mvi, int i);
+static void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st);
+
+static int mvs_scan_finished(struct Scsi_Host *, unsigned long);
+static void mvs_scan_start(struct Scsi_Host *);
+static int mvs_sas_slave_alloc(struct scsi_device *scsi_dev);
+
+static struct scsi_transport_template *mvs_stt;
+
+static const struct mvs_chip_info mvs_chips[] = {
+ [chip_6320] = { 2, 16, 9 },
+ [chip_6440] = { 4, 16, 9 },
+ [chip_6480] = { 8, 32, 10 },
+};
+
+static struct scsi_host_template mvs_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .queuecommand = sas_queuecommand,
+ .target_alloc = sas_target_alloc,
+ .slave_configure = sas_slave_configure,
+ .slave_destroy = sas_slave_destroy,
+ .scan_finished = mvs_scan_finished,
+ .scan_start = mvs_scan_start,
+ .change_queue_depth = sas_change_queue_depth,
+ .change_queue_type = sas_change_queue_type,
+ .bios_param = sas_bios_param,
+ .can_queue = 1,
+ .cmd_per_lun = 1,
+ .this_id = -1,
+ .sg_tablesize = SG_ALL,
+ .max_sectors = SCSI_DEFAULT_MAX_SECTORS,
+ .use_clustering = ENABLE_CLUSTERING,
+ .eh_device_reset_handler = sas_eh_device_reset_handler,
+ .eh_bus_reset_handler = sas_eh_bus_reset_handler,
+ .slave_alloc = mvs_sas_slave_alloc,
+ .target_destroy = sas_target_destroy,
+ .ioctl = sas_ioctl,
+};
+
+static void mvs_hexdump(u32 size, u8 *data, u32 baseaddr)
+{
+ u32 i;
+ u32 run;
+ u32 offset;
+
+ offset = 0;
+ while (size) {
+ printk("%08X : ", baseaddr + offset);
+ if (size >= 16)
+ run = 16;
+ else
+ run = size;
+ size -= run;
+ for (i = 0; i < 16; i++) {
+ if (i < run)
+ printk("%02X ", (u32)data[i]);
+ else
+ printk(" ");
+ }
+ printk(": ");
+ for (i = 0; i < run; i++)
+ printk("%c", isalnum(data[i]) ? data[i] : '.');
+ printk("\n");
+ data = &data[16];
+ offset += run;
+ }
+ printk("\n");
+}
+
+static void mvs_hba_sb_dump(struct mvs_info *mvi, u32 tag,
+ enum sas_protocol proto)
+{
+#if _MV_DUMP
+ u32 offset;
+ struct pci_dev *pdev = mvi->pdev;
+ struct mvs_slot_info *slot = &mvi->slot_info[tag];
+
+ offset = slot->cmd_size + MVS_OAF_SZ +
+ sizeof(struct mvs_prd) * slot->n_elem;
+ dev_printk(KERN_DEBUG, &pdev->dev, "+---->Status buffer[%d] :\n",
+ tag);
+ mvs_hexdump(32, (u8 *) slot->response,
+ (u32) slot->buf_dma + offset);
+#endif
+}
+
+static void mvs_hba_memory_dump(struct mvs_info *mvi, u32 tag,
+ enum sas_protocol proto)
+{
+#if _MV_DUMP
+ u32 sz, w_ptr, r_ptr;
+ u64 addr;
+ void __iomem *regs = mvi->regs;
+ struct pci_dev *pdev = mvi->pdev;
+ struct mvs_slot_info *slot = &mvi->slot_info[tag];
+
+ /*Delivery Queue */
+ sz = mr32(TX_CFG) & TX_RING_SZ_MASK;
+ w_ptr = mr32(TX_PROD_IDX) & TX_RING_SZ_MASK;
+ r_ptr = mr32(TX_CONS_IDX) & TX_RING_SZ_MASK;
+ addr = mr32(TX_HI) << 16 << 16 | mr32(TX_LO);
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "Delivery Queue Size=%04d , WRT_PTR=%04X , RD_PTR=%04X\n",
+ sz, w_ptr, r_ptr);
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "Delivery Queue Base Address=0x%llX (PA)"
+ "(tx_dma=0x%llX), Entry=%04d\n",
+ addr, mvi->tx_dma, w_ptr);
+ mvs_hexdump(sizeof(u32), (u8 *)(&mvi->tx[mvi->tx_prod]),
+ (u32) mvi->tx_dma + sizeof(u32) * w_ptr);
+ /*Command List */
+ addr = mr32(CMD_LIST_HI) << 16 << 16 | mr32(CMD_LIST_LO);
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "Command List Base Address=0x%llX (PA)"
+ "(slot_dma=0x%llX), Header=%03d\n",
+ addr, mvi->slot_dma, tag);
+ dev_printk(KERN_DEBUG, &pdev->dev, "Command Header[%03d]:\n", tag);
+ /*mvs_cmd_hdr */
+ mvs_hexdump(sizeof(struct mvs_cmd_hdr), (u8 *)(&mvi->slot[tag]),
+ (u32) mvi->slot_dma + tag * sizeof(struct mvs_cmd_hdr));
+ /*1.command table area */
+ dev_printk(KERN_DEBUG, &pdev->dev, "+---->Command Table :\n");
+ mvs_hexdump(slot->cmd_size, (u8 *) slot->buf, (u32) slot->buf_dma);
+ /*2.open address frame area */
+ dev_printk(KERN_DEBUG, &pdev->dev, "+---->Open Address Frame :\n");
+ mvs_hexdump(MVS_OAF_SZ, (u8 *) slot->buf + slot->cmd_size,
+ (u32) slot->buf_dma + slot->cmd_size);
+ /*3.status buffer */
+ mvs_hba_sb_dump(mvi, tag, proto);
+ /*4.PRD table */
+ dev_printk(KERN_DEBUG, &pdev->dev, "+---->PRD table :\n");
+ mvs_hexdump(sizeof(struct mvs_prd) * slot->n_elem,
+ (u8 *) slot->buf + slot->cmd_size + MVS_OAF_SZ,
+ (u32) slot->buf_dma + slot->cmd_size + MVS_OAF_SZ);
+#endif
+}
+
+static void mvs_hba_cq_dump(struct mvs_info *mvi)
+{
+#if _MV_DUMP
+ u64 addr;
+ void __iomem *regs = mvi->regs;
+ struct pci_dev *pdev = mvi->pdev;
+ u32 entry = mvi->rx_cons + 1;
+ u32 rx_desc = le32_to_cpu(mvi->rx[entry]);
+
+ /*Completion Queue */
+ addr = mr32(RX_HI) << 16 << 16 | mr32(RX_LO);
+ dev_printk(KERN_DEBUG, &pdev->dev, "Completion Task = 0x%08X\n",
+ (u32) mvi->slot_info[rx_desc & RXQ_SLOT_MASK].task);
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "Completion List Base Address=0x%llX (PA), "
+ "CQ_Entry=%04d, CQ_WP=0x%08X\n",
+ addr, entry - 1, mvi->rx[0]);
+ mvs_hexdump(sizeof(u32), (u8 *)(&rx_desc),
+ mvi->rx_dma + sizeof(u32) * entry);
+#endif
+}
+
+static void mvs_hba_interrupt_enable(struct mvs_info *mvi)
+{
+ void __iomem *regs = mvi->regs;
+ u32 tmp;
+
+ tmp = mr32(GBL_CTL);
+
+ mw32(GBL_CTL, tmp | INT_EN);
+}
+
+static void mvs_hba_interrupt_disable(struct mvs_info *mvi)
+{
+ void __iomem *regs = mvi->regs;
+ u32 tmp;
+
+ tmp = mr32(GBL_CTL);
+
+ mw32(GBL_CTL, tmp & ~INT_EN);
+}
+
+static int mvs_int_rx(struct mvs_info *mvi, bool self_clear);
+
+/* move to PCI layer or libata core? */
+static int pci_go_64(struct pci_dev *pdev)
+{
+ int rc;
+
+ if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
+ rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+ if (rc) {
+ rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "64-bit DMA enable failed\n");
+ return rc;
+ }
+ }
+ } else {
+ rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "32-bit DMA enable failed\n");
+ return rc;
+ }
+ rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "32-bit consistent DMA enable failed\n");
+ return rc;
+ }
+ }
+
+ return rc;
+}
+
+static void mvs_tag_clear(struct mvs_info *mvi, u32 tag)
+{
+ mvi->tag_in = (mvi->tag_in + 1) & (MVS_SLOTS - 1);
+ mvi->tags[mvi->tag_in] = tag;
+}
+
+static void mvs_tag_free(struct mvs_info *mvi, u32 tag)
+{
+ mvi->tag_out = (mvi->tag_out - 1) & (MVS_SLOTS - 1);
+}
+
+static int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out)
+{
+ if (mvi->tag_out != mvi->tag_in) {
+ *tag_out = mvi->tags[mvi->tag_out];
+ mvi->tag_out = (mvi->tag_out + 1) & (MVS_SLOTS - 1);
+ return 0;
+ }
+ return -EBUSY;
+}
+
+static void mvs_tag_init(struct mvs_info *mvi)
+{
+ int i;
+ for (i = 0; i < MVS_SLOTS; ++i)
+ mvi->tags[i] = i;
+ mvi->tag_out = 0;
+ mvi->tag_in = MVS_SLOTS - 1;
+}
+
+#ifndef MVS_DISABLE_NVRAM
+static int mvs_eep_read(void __iomem *regs, u32 addr, u32 *data)
+{
+ int timeout = 1000;
+
+ if (addr & ~SPI_ADDR_MASK)
+ return -EINVAL;
+
+ writel(addr, regs + SPI_CMD);
+ writel(TWSI_RD, regs + SPI_CTL);
+
+ while (timeout-- > 0) {
+ if (readl(regs + SPI_CTL) & TWSI_RDY) {
+ *data = readl(regs + SPI_DATA);
+ return 0;
+ }
+
+ udelay(10);
+ }
+
+ return -EBUSY;
+}
+
+static int mvs_eep_read_buf(void __iomem *regs, u32 addr,
+ void *buf, u32 buflen)
+{
+ u32 addr_end, tmp_addr, i, j;
+ u32 tmp = 0;
+ int rc;
+ u8 *tmp8, *buf8 = buf;
+
+ addr_end = addr + buflen;
+ tmp_addr = ALIGN(addr, 4);
+ if (addr > 0xff)
+ return -EINVAL;
+
+ j = addr & 0x3;
+ if (j) {
+ rc = mvs_eep_read(regs, tmp_addr, &tmp);
+ if (rc)
+ return rc;
+
+ tmp8 = (u8 *)&tmp;
+ for (i = j; i < 4; i++)
+ *buf8++ = tmp8[i];
+
+ tmp_addr += 4;
+ }
+
+ for (j = ALIGN(addr_end, 4); tmp_addr < j; tmp_addr += 4) {
+ rc = mvs_eep_read(regs, tmp_addr, &tmp);
+ if (rc)
+ return rc;
+
+ memcpy(buf8, &tmp, 4);
+ buf8 += 4;
+ }
+
+ if (tmp_addr < addr_end) {
+ rc = mvs_eep_read(regs, tmp_addr, &tmp);
+ if (rc)
+ return rc;
+
+ tmp8 = (u8 *)&tmp;
+ j = addr_end - tmp_addr;
+ for (i = 0; i < j; i++)
+ *buf8++ = tmp8[i];
+
+ tmp_addr += 4;
+ }
+
+ return 0;
+}
+#endif
+
+static int mvs_nvram_read(struct mvs_info *mvi, u32 addr,
+ void *buf, u32 buflen)
+{
+#ifndef MVS_DISABLE_NVRAM
+ void __iomem *regs = mvi->regs;
+ int rc, i;
+ u32 sum;
+ u8 hdr[2], *tmp;
+ const char *msg;
+
+ rc = mvs_eep_read_buf(regs, addr, &hdr, 2);
+ if (rc) {
+ msg = "nvram hdr read failed";
+ goto err_out;
+ }
+ rc = mvs_eep_read_buf(regs, addr + 2, buf, buflen);
+ if (rc) {
+ msg = "nvram read failed";
+ goto err_out;
+ }
+
+ if (hdr[0] != 0x5A) {
+ /* entry id */
+ msg = "invalid nvram entry id";
+ rc = -ENOENT;
+ goto err_out;
+ }
+
+ tmp = buf;
+ sum = ((u32)hdr[0]) + ((u32)hdr[1]);
+ for (i = 0; i < buflen; i++)
+ sum += ((u32)tmp[i]);
+
+ if (sum) {
+ msg = "nvram checksum failure";
+ rc = -EILSEQ;
+ goto err_out;
+ }
+
+ return 0;
+
+err_out:
+ dev_printk(KERN_ERR, &mvi->pdev->dev, "%s", msg);
+ return rc;
+#else
+ /* FIXME , For SAS target mode */
+ memcpy(buf, "\x00\x00\xab\x11\x30\x04\x05\x50", 8);
+ return 0;
+#endif
+}
+
+static void mvs_bytes_dmaed(struct mvs_info *mvi, int i)
+{
+ struct mvs_phy *phy = &mvi->phy[i];
+
+ if (!phy->phy_attached)
+ return;
+
+ if (phy->phy_type & PORT_TYPE_SAS) {
+ struct sas_identify_frame *id;
+
+ id = (struct sas_identify_frame *)phy->frame_rcvd;
+ id->dev_type = phy->identify.device_type;
+ id->initiator_bits = SAS_PROTOCOL_ALL;
+ id->target_bits = phy->identify.target_port_protocols;
+ } else if (phy->phy_type & PORT_TYPE_SATA) {
+ /* TODO */
+ }
+ mvi->sas.sas_phy[i]->frame_rcvd_size = phy->frame_rcvd_size;
+ mvi->sas.notify_port_event(mvi->sas.sas_phy[i],
+ PORTE_BYTES_DMAED);
+}
+
+static int mvs_scan_finished(struct Scsi_Host *shost, unsigned long time)
+{
+ /* give the phy enabling interrupt event time to come in (1s
+ * is empirically about all it takes) */
+ if (time < HZ)
+ return 0;
+ /* Wait for discovery to finish */
+ scsi_flush_work(shost);
+ return 1;
+}
+
+static void mvs_scan_start(struct Scsi_Host *shost)
+{
+ int i;
+ struct mvs_info *mvi = SHOST_TO_SAS_HA(shost)->lldd_ha;
+
+ for (i = 0; i < mvi->chip->n_phy; ++i) {
+ mvs_bytes_dmaed(mvi, i);
+ }
+}
+
+static int mvs_sas_slave_alloc(struct scsi_device *scsi_dev)
+{
+ int rc;
+
+ rc = sas_slave_alloc(scsi_dev);
+
+ return rc;
+}
+
+static void mvs_int_port(struct mvs_info *mvi, int port_no, u32 events)
+{
+ struct pci_dev *pdev = mvi->pdev;
+ struct sas_ha_struct *sas_ha = &mvi->sas;
+ struct mvs_phy *phy = &mvi->phy[port_no];
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+
+ phy->irq_status = mvs_read_port_irq_stat(mvi, port_no);
+ /*
+ * events is port event now ,
+ * we need check the interrupt status which belongs to per port.
+ */
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "Port %d Event = %X\n",
+ port_no, phy->irq_status);
+
+ if (phy->irq_status & (PHYEV_POOF | PHYEV_DEC_ERR)) {
+ if (!mvs_is_phy_ready(mvi, port_no)) {
+ sas_phy_disconnected(sas_phy);
+ sas_ha->notify_phy_event(sas_phy, PHYE_LOSS_OF_SIGNAL);
+ } else
+ mvs_phy_control(sas_phy, PHY_FUNC_LINK_RESET, NULL);
+ }
+ if (!(phy->irq_status & PHYEV_DEC_ERR)) {
+ if (phy->irq_status & PHYEV_COMWAKE) {
+ u32 tmp = mvs_read_port_irq_mask(mvi, port_no);
+ mvs_write_port_irq_mask(mvi, port_no,
+ tmp | PHYEV_SIG_FIS);
+ }
+ if (phy->irq_status & (PHYEV_SIG_FIS | PHYEV_ID_DONE)) {
+ phy->phy_status = mvs_is_phy_ready(mvi, port_no);
+ if (phy->phy_status) {
+ mvs_detect_porttype(mvi, port_no);
+
+ if (phy->phy_type & PORT_TYPE_SATA) {
+ u32 tmp = mvs_read_port_irq_mask(mvi,
+ port_no);
+ tmp &= ~PHYEV_SIG_FIS;
+ mvs_write_port_irq_mask(mvi,
+ port_no, tmp);
+ }
+
+ mvs_update_phyinfo(mvi, port_no, 0);
+ sas_ha->notify_phy_event(sas_phy,
+ PHYE_OOB_DONE);
+ mvs_bytes_dmaed(mvi, port_no);
+ } else {
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "plugin interrupt but phy is gone\n");
+ mvs_phy_control(sas_phy, PHY_FUNC_LINK_RESET,
+ NULL);
+ }
+ } else if (phy->irq_status & PHYEV_BROAD_CH)
+ sas_ha->notify_port_event(sas_phy,
+ PORTE_BROADCAST_RCVD);
+ }
+ mvs_write_port_irq_stat(mvi, port_no, phy->irq_status);
+}
+
+static void mvs_int_sata(struct mvs_info *mvi)
+{
+ /* FIXME */
+}
+
+static void mvs_slot_free(struct mvs_info *mvi, struct sas_task *task,
+ struct mvs_slot_info *slot, u32 slot_idx)
+{
+ if (!sas_protocol_ata(task->task_proto))
+ if (slot->n_elem)
+ pci_unmap_sg(mvi->pdev, task->scatter,
+ slot->n_elem, task->data_dir);
+
+ switch (task->task_proto) {
+ case SAS_PROTOCOL_SMP:
+ pci_unmap_sg(mvi->pdev, &task->smp_task.smp_resp, 1,
+ PCI_DMA_FROMDEVICE);
+ pci_unmap_sg(mvi->pdev, &task->smp_task.smp_req, 1,
+ PCI_DMA_TODEVICE);
+ break;
+
+ case SAS_PROTOCOL_SATA:
+ case SAS_PROTOCOL_STP:
+ case SAS_PROTOCOL_SSP:
+ default:
+ /* do nothing */
+ break;
+ }
+
+ slot->task = NULL;
+ mvs_tag_clear(mvi, slot_idx);
+}
+
+static void mvs_slot_err(struct mvs_info *mvi, struct sas_task *task,
+ u32 slot_idx)
+{
+ struct mvs_slot_info *slot = &mvi->slot_info[slot_idx];
+ u64 err_dw0 = *(u32 *) slot->response;
+ void __iomem *regs = mvi->regs;
+ u32 tmp;
+
+ if (err_dw0 & CMD_ISS_STPD)
+ if (sas_protocol_ata(task->task_proto)) {
+ tmp = mr32(INT_STAT_SRS);
+ mw32(INT_STAT_SRS, tmp & 0xFFFF);
+ }
+
+ mvs_hba_sb_dump(mvi, slot_idx, task->task_proto);
+}
+
+static int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc)
+{
+ u32 slot_idx = rx_desc & RXQ_SLOT_MASK;
+ struct mvs_slot_info *slot = &mvi->slot_info[slot_idx];
+ struct sas_task *task = slot->task;
+ struct task_status_struct *tstat = &task->task_status;
+ struct mvs_port *port = &mvi->port[task->dev->port->id];
+ bool aborted;
+ void *to;
+
+ spin_lock(&task->task_state_lock);
+ aborted = task->task_state_flags & SAS_TASK_STATE_ABORTED;
+ if (!aborted) {
+ task->task_state_flags &=
+ ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR);
+ task->task_state_flags |= SAS_TASK_STATE_DONE;
+ }
+ spin_unlock(&task->task_state_lock);
+
+ if (aborted)
+ return -1;
+
+ memset(tstat, 0, sizeof(*tstat));
+ tstat->resp = SAS_TASK_COMPLETE;
+
+
+ if (unlikely(!port->port_attached)) {
+ tstat->stat = SAS_PHY_DOWN;
+ goto out;
+ }
+
+ /* error info record present */
+ if ((rx_desc & RXQ_ERR) && (*(u64 *) slot->response)) {
+ tstat->stat = SAM_CHECK_COND;
+ mvs_slot_err(mvi, task, slot_idx);
+ goto out;
+ }
+
+ switch (task->task_proto) {
+ case SAS_PROTOCOL_SSP:
+ /* hw says status == 0, datapres == 0 */
+ if (rx_desc & RXQ_GOOD) {
+ tstat->stat = SAM_GOOD;
+ tstat->resp = SAS_TASK_COMPLETE;
+ }
+ /* response frame present */
+ else if (rx_desc & RXQ_RSP) {
+ struct ssp_response_iu *iu =
+ slot->response + sizeof(struct mvs_err_info);
+ sas_ssp_task_response(&mvi->pdev->dev, task, iu);
+ }
+
+ /* should never happen? */
+ else
+ tstat->stat = SAM_CHECK_COND;
+ break;
+
+ case SAS_PROTOCOL_SMP: {
+ struct scatterlist *sg_resp = &task->smp_task.smp_resp;
+ tstat->stat = SAM_GOOD;
+ to = kmap_atomic(sg_page(sg_resp), KM_IRQ0);
+ memcpy(to + sg_resp->offset,
+ slot->response + sizeof(struct mvs_err_info),
+ sg_dma_len(sg_resp));
+ kunmap_atomic(to, KM_IRQ0);
+ break;
+ }
+
+ case SAS_PROTOCOL_SATA:
+ case SAS_PROTOCOL_STP:
+ case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: {
+ struct ata_task_resp *resp =
+ (struct ata_task_resp *)tstat->buf;
+
+ if ((rx_desc & (RXQ_DONE | RXQ_ERR | RXQ_ATTN)) ==
+ RXQ_DONE)
+ tstat->stat = SAM_GOOD;
+ else
+ tstat->stat = SAM_CHECK_COND;
+
+ resp->frame_len = sizeof(struct dev_to_host_fis);
+ memcpy(&resp->ending_fis[0],
+ SATA_RECEIVED_D2H_FIS(port->taskfileset),
+ sizeof(struct dev_to_host_fis));
+ if (resp->ending_fis[2] & ATA_ERR)
+ mvs_hexdump(16, resp->ending_fis, 0);
+ break;
+ }
+
+ default:
+ tstat->stat = SAM_CHECK_COND;
+ break;
+ }
+
+out:
+ mvs_slot_free(mvi, task, slot, slot_idx);
+ task->task_done(task);
+ return tstat->stat;
+}
+
+static void mvs_int_full(struct mvs_info *mvi)
+{
+ void __iomem *regs = mvi->regs;
+ u32 tmp, stat;
+ int i;
+
+ stat = mr32(INT_STAT);
+
+ mvs_int_rx(mvi, false);
+
+ for (i = 0; i < MVS_MAX_PORTS; i++) {
+ tmp = (stat >> i) & (CINT_PORT | CINT_PORT_STOPPED);
+ if (tmp)
+ mvs_int_port(mvi, i, tmp);
+ }
+
+ if (stat & CINT_SRS)
+ mvs_int_sata(mvi);
+
+ mw32(INT_STAT, stat);
+}
+
+static int mvs_int_rx(struct mvs_info *mvi, bool self_clear)
+{
+ void __iomem *regs = mvi->regs;
+ u32 rx_prod_idx, rx_desc;
+ bool attn = false;
+ struct pci_dev *pdev = mvi->pdev;
+
+ /* the first dword in the RX ring is special: it contains
+ * a mirror of the hardware's RX producer index, so that
+ * we don't have to stall the CPU reading that register.
+ * The actual RX ring is offset by one dword, due to this.
+ */
+ rx_prod_idx = mr32(RX_CONS_IDX) & RX_RING_SZ_MASK;
+ if (rx_prod_idx == 0xfff) { /* h/w hasn't touched RX ring yet */
+ mvi->rx_cons = 0xfff;
+ return 0;
+ }
+
+ /* The CMPL_Q may come late, read from register and try again
+ * note: if coalescing is enabled,
+ * it will need to read from register every time for sure
+ */
+ if (mvi->rx_cons == rx_prod_idx)
+ return 0;
+
+ if (mvi->rx_cons == 0xfff)
+ mvi->rx_cons = MVS_RX_RING_SZ - 1;
+
+ while (mvi->rx_cons != rx_prod_idx) {
+
+ /* increment our internal RX consumer pointer */
+ mvi->rx_cons = (mvi->rx_cons + 1) & (MVS_RX_RING_SZ - 1);
+
+ rx_desc = le32_to_cpu(mvi->rx[mvi->rx_cons + 1]);
+
+ mvs_hba_cq_dump(mvi);
+
+ if (unlikely(rx_desc & RXQ_DONE))
+ mvs_slot_complete(mvi, rx_desc);
+ if (rx_desc & RXQ_ATTN) {
+ attn = true;
+ dev_printk(KERN_DEBUG, &pdev->dev, "ATTN %X\n",
+ rx_desc);
+ } else if (rx_desc & RXQ_ERR) {
+ dev_printk(KERN_DEBUG, &pdev->dev, "RXQ_ERR %X\n",
+ rx_desc);
+ }
+ }
+
+ if (attn && self_clear)
+ mvs_int_full(mvi);
+
+ return 0;
+}
+
+static irqreturn_t mvs_interrupt(int irq, void *opaque)
+{
+ struct mvs_info *mvi = opaque;
+ void __iomem *regs = mvi->regs;
+ u32 stat;
+
+ stat = mr32(GBL_INT_STAT);
+
+ /* clear CMD_CMPLT ASAP */
+ mw32_f(INT_STAT, CINT_DONE);
+
+ if (stat == 0 || stat == 0xffffffff)
+ return IRQ_NONE;
+
+ spin_lock(&mvi->lock);
+
+ mvs_int_full(mvi);
+
+ spin_unlock(&mvi->lock);
+
+ return IRQ_HANDLED;
+}
+
+#ifndef MVS_DISABLE_MSI
+static irqreturn_t mvs_msi_interrupt(int irq, void *opaque)
+{
+ struct mvs_info *mvi = opaque;
+
+ spin_lock(&mvi->lock);
+
+ mvs_int_rx(mvi, true);
+
+ spin_unlock(&mvi->lock);
+
+ return IRQ_HANDLED;
+}
+#endif
+
+struct mvs_task_exec_info {
+ struct sas_task *task;
+ struct mvs_cmd_hdr *hdr;
+ struct mvs_port *port;
+ u32 tag;
+ int n_elem;
+};
+
+static int mvs_task_prep_smp(struct mvs_info *mvi,
+ struct mvs_task_exec_info *tei)
+{
+ int elem, rc, i;
+ struct sas_task *task = tei->task;
+ struct mvs_cmd_hdr *hdr = tei->hdr;
+ struct scatterlist *sg_req, *sg_resp;
+ u32 req_len, resp_len, tag = tei->tag;
+ void *buf_tmp;
+ u8 *buf_oaf;
+ dma_addr_t buf_tmp_dma;
+ struct mvs_prd *buf_prd;
+ struct scatterlist *sg;
+ struct mvs_slot_info *slot = &mvi->slot_info[tag];
+ struct asd_sas_port *sas_port = task->dev->port;
+ u32 flags = (tei->n_elem << MCH_PRD_LEN_SHIFT);
+#if _MV_DUMP
+ u8 *buf_cmd;
+ void *from;
+#endif
+ /*
+ * DMA-map SMP request, response buffers
+ */
+ sg_req = &task->smp_task.smp_req;
+ elem = pci_map_sg(mvi->pdev, sg_req, 1, PCI_DMA_TODEVICE);
+ if (!elem)
+ return -ENOMEM;
+ req_len = sg_dma_len(sg_req);
+
+ sg_resp = &task->smp_task.smp_resp;
+ elem = pci_map_sg(mvi->pdev, sg_resp, 1, PCI_DMA_FROMDEVICE);
+ if (!elem) {
+ rc = -ENOMEM;
+ goto err_out;
+ }
+ resp_len = sg_dma_len(sg_resp);
+
+ /* must be in dwords */
+ if ((req_len & 0x3) || (resp_len & 0x3)) {
+ rc = -EINVAL;
+ goto err_out_2;
+ }
+
+ /*
+ * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs
+ */
+
+ /* region 1: command table area (MVS_SSP_CMD_SZ bytes) ************** */
+ buf_tmp = slot->buf;
+ buf_tmp_dma = slot->buf_dma;
+
+#if _MV_DUMP
+ buf_cmd = buf_tmp;
+ hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
+ buf_tmp += req_len;
+ buf_tmp_dma += req_len;
+ slot->cmd_size = req_len;
+#else
+ hdr->cmd_tbl = cpu_to_le64(sg_dma_address(sg_req));
+#endif
+
+ /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
+ buf_oaf = buf_tmp;
+ hdr->open_frame = cpu_to_le64(buf_tmp_dma);
+
+ buf_tmp += MVS_OAF_SZ;
+ buf_tmp_dma += MVS_OAF_SZ;
+
+ /* region 3: PRD table ********************************************* */
+ buf_prd = buf_tmp;
+ if (tei->n_elem)
+ hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
+ else
+ hdr->prd_tbl = 0;
+
+ i = sizeof(struct mvs_prd) * tei->n_elem;
+ buf_tmp += i;
+ buf_tmp_dma += i;
+
+ /* region 4: status buffer (larger the PRD, smaller this buf) ****** */
+ slot->response = buf_tmp;
+ hdr->status_buf = cpu_to_le64(buf_tmp_dma);
+
+ /*
+ * Fill in TX ring and command slot header
+ */
+ slot->tx = mvi->tx_prod;
+ mvi->tx[mvi->tx_prod] = cpu_to_le32((TXQ_CMD_SMP << TXQ_CMD_SHIFT) |
+ TXQ_MODE_I | tag |
+ (sas_port->phy_mask << TXQ_PHY_SHIFT));
+
+ hdr->flags |= flags;
+ hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | ((req_len - 4) / 4));
+ hdr->tags = cpu_to_le32(tag);
+ hdr->data_len = 0;
+
+ /* generate open address frame hdr (first 12 bytes) */
+ buf_oaf[0] = (1 << 7) | (0 << 4) | 0x01; /* initiator, SMP, ftype 1h */
+ buf_oaf[1] = task->dev->linkrate & 0xf;
+ *(u16 *)(buf_oaf + 2) = 0xFFFF; /* SAS SPEC */
+ memcpy(buf_oaf + 4, task->dev->sas_addr, SAS_ADDR_SIZE);
+
+ /* fill in PRD (scatter/gather) table, if any */
+ for_each_sg(task->scatter, sg, tei->n_elem, i) {
+ buf_prd->addr = cpu_to_le64(sg_dma_address(sg));
+ buf_prd->len = cpu_to_le32(sg_dma_len(sg));
+ buf_prd++;
+ }
+
+#if _MV_DUMP
+ /* copy cmd table */
+ from = kmap_atomic(sg_page(sg_req), KM_IRQ0);
+ memcpy(buf_cmd, from + sg_req->offset, req_len);
+ kunmap_atomic(from, KM_IRQ0);
+#endif
+ return 0;
+
+err_out_2:
+ pci_unmap_sg(mvi->pdev, &tei->task->smp_task.smp_resp, 1,
+ PCI_DMA_FROMDEVICE);
+err_out:
+ pci_unmap_sg(mvi->pdev, &tei->task->smp_task.smp_req, 1,
+ PCI_DMA_TODEVICE);
+ return rc;
+}
+
+static void mvs_free_reg_set(struct mvs_info *mvi, struct mvs_port *port)
+{
+ void __iomem *regs = mvi->regs;
+ u32 tmp, offs;
+ u8 *tfs = &port->taskfileset;
+
+ if (*tfs == MVS_ID_NOT_MAPPED)
+ return;
+
+ offs = 1U << ((*tfs & 0x0f) + PCS_EN_SATA_REG_SHIFT);
+ if (*tfs < 16) {
+ tmp = mr32(PCS);
+ mw32(PCS, tmp & ~offs);
+ } else {
+ tmp = mr32(CTL);
+ mw32(CTL, tmp & ~offs);
+ }
+
+ tmp = mr32(INT_STAT_SRS) & (1U << *tfs);
+ if (tmp)
+ mw32(INT_STAT_SRS, tmp);
+
+ *tfs = MVS_ID_NOT_MAPPED;
+}
+
+static u8 mvs_assign_reg_set(struct mvs_info *mvi, struct mvs_port *port)
+{
+ int i;
+ u32 tmp, offs;
+ void __iomem *regs = mvi->regs;
+
+ if (port->taskfileset != MVS_ID_NOT_MAPPED)
+ return 0;
+
+ tmp = mr32(PCS);
+
+ for (i = 0; i < mvi->chip->srs_sz; i++) {
+ if (i == 16)
+ tmp = mr32(CTL);
+ offs = 1U << ((i & 0x0f) + PCS_EN_SATA_REG_SHIFT);
+ if (!(tmp & offs)) {
+ port->taskfileset = i;
+
+ if (i < 16)
+ mw32(PCS, tmp | offs);
+ else
+ mw32(CTL, tmp | offs);
+ tmp = mr32(INT_STAT_SRS) & (1U << i);
+ if (tmp)
+ mw32(INT_STAT_SRS, tmp);
+ return 0;
+ }
+ }
+ return MVS_ID_NOT_MAPPED;
+}
+
+static u32 mvs_get_ncq_tag(struct sas_task *task)
+{
+ u32 tag = 0;
+ struct ata_queued_cmd *qc = task->uldd_task;
+
+ if (qc)
+ tag = qc->tag;
+
+ return tag;
+}
+
+static int mvs_task_prep_ata(struct mvs_info *mvi,
+ struct mvs_task_exec_info *tei)
+{
+ struct sas_task *task = tei->task;
+ struct domain_device *dev = task->dev;
+ struct mvs_cmd_hdr *hdr = tei->hdr;
+ struct asd_sas_port *sas_port = dev->port;
+ struct mvs_slot_info *slot;
+ struct scatterlist *sg;
+ struct mvs_prd *buf_prd;
+ struct mvs_port *port = tei->port;
+ u32 tag = tei->tag;
+ u32 flags = (tei->n_elem << MCH_PRD_LEN_SHIFT);
+ void *buf_tmp;
+ u8 *buf_cmd, *buf_oaf;
+ dma_addr_t buf_tmp_dma;
+ u32 i, req_len, resp_len;
+ const u32 max_resp_len = SB_RFB_MAX;
+
+ if (mvs_assign_reg_set(mvi, port) == MVS_ID_NOT_MAPPED)
+ return -EBUSY;
+
+ slot = &mvi->slot_info[tag];
+ slot->tx = mvi->tx_prod;
+ mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | tag |
+ (TXQ_CMD_STP << TXQ_CMD_SHIFT) |
+ (sas_port->phy_mask << TXQ_PHY_SHIFT) |
+ (port->taskfileset << TXQ_SRS_SHIFT));
+
+ if (task->ata_task.use_ncq)
+ flags |= MCH_FPDMA;
+ if (dev->sata_dev.command_set == ATAPI_COMMAND_SET) {
+ if (task->ata_task.fis.command != ATA_CMD_ID_ATAPI)
+ flags |= MCH_ATAPI;
+ }
+
+ /* FIXME: fill in port multiplier number */
+
+ hdr->flags = cpu_to_le32(flags);
+
+ /* FIXME: the low order order 5 bits for the TAG if enable NCQ */
+ if (task->ata_task.use_ncq) {
+ hdr->tags = cpu_to_le32(mvs_get_ncq_tag(task));
+ /*Fill in task file */
+ task->ata_task.fis.sector_count = hdr->tags << 3;
+ } else
+ hdr->tags = cpu_to_le32(tag);
+ hdr->data_len = cpu_to_le32(task->total_xfer_len);
+
+ /*
+ * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs
+ */
+
+ /* region 1: command table area (MVS_ATA_CMD_SZ bytes) ************** */
+ buf_cmd = buf_tmp = slot->buf;
+ buf_tmp_dma = slot->buf_dma;
+
+ hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
+
+ buf_tmp += MVS_ATA_CMD_SZ;
+ buf_tmp_dma += MVS_ATA_CMD_SZ;
+#if _MV_DUMP
+ slot->cmd_size = MVS_ATA_CMD_SZ;
+#endif
+
+ /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
+ /* used for STP. unused for SATA? */
+ buf_oaf = buf_tmp;
+ hdr->open_frame = cpu_to_le64(buf_tmp_dma);
+
+ buf_tmp += MVS_OAF_SZ;
+ buf_tmp_dma += MVS_OAF_SZ;
+
+ /* region 3: PRD table ********************************************* */
+ buf_prd = buf_tmp;
+ if (tei->n_elem)
+ hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
+ else
+ hdr->prd_tbl = 0;
+
+ i = sizeof(struct mvs_prd) * tei->n_elem;
+ buf_tmp += i;
+ buf_tmp_dma += i;
+
+ /* region 4: status buffer (larger the PRD, smaller this buf) ****** */
+ /* FIXME: probably unused, for SATA. kept here just in case
+ * we get a STP/SATA error information record
+ */
+ slot->response = buf_tmp;
+ hdr->status_buf = cpu_to_le64(buf_tmp_dma);
+
+ req_len = sizeof(struct host_to_dev_fis);
+ resp_len = MVS_SLOT_BUF_SZ - MVS_ATA_CMD_SZ -
+ sizeof(struct mvs_err_info) - i;
+
+ /* request, response lengths */
+ resp_len = min(resp_len, max_resp_len);
+ hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4));
+
+ task->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */
+ /* fill in command FIS and ATAPI CDB */
+ memcpy(buf_cmd, &task->ata_task.fis, sizeof(struct host_to_dev_fis));
+ if (dev->sata_dev.command_set == ATAPI_COMMAND_SET)
+ memcpy(buf_cmd + STP_ATAPI_CMD,
+ task->ata_task.atapi_packet, 16);
+
+ /* generate open address frame hdr (first 12 bytes) */
+ buf_oaf[0] = (1 << 7) | (2 << 4) | 0x1; /* initiator, STP, ftype 1h */
+ buf_oaf[1] = task->dev->linkrate & 0xf;
+ *(u16 *)(buf_oaf + 2) = cpu_to_be16(tag);
+ memcpy(buf_oaf + 4, task->dev->sas_addr, SAS_ADDR_SIZE);
+
+ /* fill in PRD (scatter/gather) table, if any */
+ for_each_sg(task->scatter, sg, tei->n_elem, i) {
+ buf_prd->addr = cpu_to_le64(sg_dma_address(sg));
+ buf_prd->len = cpu_to_le32(sg_dma_len(sg));
+ buf_prd++;
+ }
+
+ return 0;
+}
+
+static int mvs_task_prep_ssp(struct mvs_info *mvi,
+ struct mvs_task_exec_info *tei)
+{
+ struct sas_task *task = tei->task;
+ struct mvs_cmd_hdr *hdr = tei->hdr;
+ struct mvs_port *port = tei->port;
+ struct mvs_slot_info *slot;
+ struct scatterlist *sg;
+ struct mvs_prd *buf_prd;
+ struct ssp_frame_hdr *ssp_hdr;
+ void *buf_tmp;
+ u8 *buf_cmd, *buf_oaf, fburst = 0;
+ dma_addr_t buf_tmp_dma;
+ u32 flags;
+ u32 resp_len, req_len, i, tag = tei->tag;
+ const u32 max_resp_len = SB_RFB_MAX;
+
+ slot = &mvi->slot_info[tag];
+
+ slot->tx = mvi->tx_prod;
+ mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | tag |
+ (TXQ_CMD_SSP << TXQ_CMD_SHIFT) |
+ (port->wide_port_phymap << TXQ_PHY_SHIFT));
+
+ flags = MCH_RETRY;
+ if (task->ssp_task.enable_first_burst) {
+ flags |= MCH_FBURST;
+ fburst = (1 << 7);
+ }
+ hdr->flags = cpu_to_le32(flags |
+ (tei->n_elem << MCH_PRD_LEN_SHIFT) |
+ (MCH_SSP_FR_CMD << MCH_SSP_FR_TYPE_SHIFT));
+
+ hdr->tags = cpu_to_le32(tag);
+ hdr->data_len = cpu_to_le32(task->total_xfer_len);
+
+ /*
+ * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs
+ */
+
+ /* region 1: command table area (MVS_SSP_CMD_SZ bytes) ************** */
+ buf_cmd = buf_tmp = slot->buf;
+ buf_tmp_dma = slot->buf_dma;
+
+ hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
+
+ buf_tmp += MVS_SSP_CMD_SZ;
+ buf_tmp_dma += MVS_SSP_CMD_SZ;
+#if _MV_DUMP
+ slot->cmd_size = MVS_SSP_CMD_SZ;
+#endif
+
+ /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
+ buf_oaf = buf_tmp;
+ hdr->open_frame = cpu_to_le64(buf_tmp_dma);
+
+ buf_tmp += MVS_OAF_SZ;
+ buf_tmp_dma += MVS_OAF_SZ;
+
+ /* region 3: PRD table ********************************************* */
+ buf_prd = buf_tmp;
+ if (tei->n_elem)
+ hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
+ else
+ hdr->prd_tbl = 0;
+
+ i = sizeof(struct mvs_prd) * tei->n_elem;
+ buf_tmp += i;
+ buf_tmp_dma += i;
+
+ /* region 4: status buffer (larger the PRD, smaller this buf) ****** */
+ slot->response = buf_tmp;
+ hdr->status_buf = cpu_to_le64(buf_tmp_dma);
+
+ resp_len = MVS_SLOT_BUF_SZ - MVS_SSP_CMD_SZ - MVS_OAF_SZ -
+ sizeof(struct mvs_err_info) - i;
+ resp_len = min(resp_len, max_resp_len);
+
+ req_len = sizeof(struct ssp_frame_hdr) + 28;
+
+ /* request, response lengths */
+ hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4));
+
+ /* generate open address frame hdr (first 12 bytes) */
+ buf_oaf[0] = (1 << 7) | (1 << 4) | 0x1; /* initiator, SSP, ftype 1h */
+ buf_oaf[1] = task->dev->linkrate & 0xf;
+ *(u16 *)(buf_oaf + 2) = cpu_to_be16(tag);
+ memcpy(buf_oaf + 4, task->dev->sas_addr, SAS_ADDR_SIZE);
+
+ /* fill in SSP frame header (Command Table.SSP frame header) */
+ ssp_hdr = (struct ssp_frame_hdr *)buf_cmd;
+ ssp_hdr->frame_type = SSP_COMMAND;
+ memcpy(ssp_hdr->hashed_dest_addr, task->dev->hashed_sas_addr,
+ HASHED_SAS_ADDR_SIZE);
+ memcpy(ssp_hdr->hashed_src_addr,
+ task->dev->port->ha->hashed_sas_addr, HASHED_SAS_ADDR_SIZE);
+ ssp_hdr->tag = cpu_to_be16(tag);
+
+ /* fill in command frame IU */
+ buf_cmd += sizeof(*ssp_hdr);
+ memcpy(buf_cmd, &task->ssp_task.LUN, 8);
+ buf_cmd[9] = fburst | task->ssp_task.task_attr |
+ (task->ssp_task.task_prio << 3);
+ memcpy(buf_cmd + 12, &task->ssp_task.cdb, 16);
+
+ /* fill in PRD (scatter/gather) table, if any */
+ for_each_sg(task->scatter, sg, tei->n_elem, i) {
+ buf_prd->addr = cpu_to_le64(sg_dma_address(sg));
+ buf_prd->len = cpu_to_le32(sg_dma_len(sg));
+ buf_prd++;
+ }
+
+ return 0;
+}
+
+static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags)
+{
+ struct domain_device *dev = task->dev;
+ struct mvs_info *mvi = dev->port->ha->lldd_ha;
+ struct pci_dev *pdev = mvi->pdev;
+ void __iomem *regs = mvi->regs;
+ struct mvs_task_exec_info tei;
+ struct sas_task *t = task;
+ u32 tag = 0xdeadbeef, rc, n_elem = 0;
+ unsigned long flags;
+ u32 n = num, pass = 0;
+
+ spin_lock_irqsave(&mvi->lock, flags);
+
+ do {
+ tei.port = &mvi->port[dev->port->id];
+
+ if (!tei.port->port_attached) {
+ struct task_status_struct *ts = &t->task_status;
+ ts->stat = SAS_PHY_DOWN;
+ t->task_done(t);
+ rc = 0;
+ goto exec_exit;
+ }
+ if (!sas_protocol_ata(t->task_proto)) {
+ if (t->num_scatter) {
+ n_elem = pci_map_sg(mvi->pdev, t->scatter,
+ t->num_scatter,
+ t->data_dir);
+ if (!n_elem) {
+ rc = -ENOMEM;
+ goto err_out;
+ }
+ }
+ } else {
+ n_elem = t->num_scatter;
+ }
+
+ rc = mvs_tag_alloc(mvi, &tag);
+ if (rc)
+ goto err_out;
+
+ mvi->slot_info[tag].task = t;
+ mvi->slot_info[tag].n_elem = n_elem;
+ memset(mvi->slot_info[tag].buf, 0, MVS_SLOT_BUF_SZ);
+ tei.task = t;
+ tei.hdr = &mvi->slot[tag];
+ tei.tag = tag;
+ tei.n_elem = n_elem;
+
+ switch (t->task_proto) {
+ case SAS_PROTOCOL_SMP:
+ rc = mvs_task_prep_smp(mvi, &tei);
+ break;
+ case SAS_PROTOCOL_SSP:
+ rc = mvs_task_prep_ssp(mvi, &tei);
+ break;
+ case SAS_PROTOCOL_SATA:
+ case SAS_PROTOCOL_STP:
+ case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
+ rc = mvs_task_prep_ata(mvi, &tei);
+ break;
+ default:
+ dev_printk(KERN_ERR, &pdev->dev,
+ "unknown sas_task proto: 0x%x\n",
+ t->task_proto);
+ rc = -EINVAL;
+ break;
+ }
+
+ if (rc)
+ goto err_out_tag;
+
+ /* TODO: select normal or high priority */
+
+ spin_lock(&t->task_state_lock);
+ t->task_state_flags |= SAS_TASK_AT_INITIATOR;
+ spin_unlock(&t->task_state_lock);
+
+ if (n == 1) {
+ spin_unlock_irqrestore(&mvi->lock, flags);
+ mw32(TX_PROD_IDX, mvi->tx_prod);
+ }
+ mvs_hba_memory_dump(mvi, tag, t->task_proto);
+
+ ++pass;
+ mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1);
+
+ if (n == 1)
+ break;
+
+ t = list_entry(t->list.next, struct sas_task, list);
+ } while (--n);
+
+ return 0;
+
+err_out_tag:
+ mvs_tag_free(mvi, tag);
+err_out:
+ dev_printk(KERN_ERR, &pdev->dev, "mvsas exec failed[%d]!\n", rc);
+ if (!sas_protocol_ata(t->task_proto))
+ if (n_elem)
+ pci_unmap_sg(mvi->pdev, t->scatter, n_elem,
+ t->data_dir);
+exec_exit:
+ if (pass)
+ mw32(TX_PROD_IDX, (mvi->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1));
+ spin_unlock_irqrestore(&mvi->lock, flags);
+ return rc;
+}
+
+static int mvs_task_abort(struct sas_task *task)
+{
+ int rc = 1;
+ unsigned long flags;
+ struct mvs_info *mvi = task->dev->port->ha->lldd_ha;
+ struct pci_dev *pdev = mvi->pdev;
+
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ if (task->task_state_flags & SAS_TASK_STATE_DONE) {
+ rc = TMF_RESP_FUNC_COMPLETE;
+ goto out_done;
+ }
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+ /*FIXME*/
+ rc = TMF_RESP_FUNC_COMPLETE;
+
+ switch (task->task_proto) {
+ case SAS_PROTOCOL_SMP:
+ dev_printk(KERN_DEBUG, &pdev->dev, "SMP Abort! ");
+ break;
+ case SAS_PROTOCOL_SSP:
+ dev_printk(KERN_DEBUG, &pdev->dev, "SSP Abort! ");
+ break;
+ case SAS_PROTOCOL_SATA:
+ case SAS_PROTOCOL_STP:
+ case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:{
+ dev_printk(KERN_DEBUG, &pdev->dev, "STP Abort! "
+ "Dump D2H FIS: \n");
+ mvs_hexdump(sizeof(struct host_to_dev_fis),
+ (void *)&task->ata_task.fis, 0);
+ dev_printk(KERN_DEBUG, &pdev->dev, "Dump ATAPI Cmd : \n");
+ mvs_hexdump(16, task->ata_task.atapi_packet, 0);
+ break;
+ }
+ default:
+ break;
+ }
+out_done:
+ return rc;
+}
+
+static void mvs_free(struct mvs_info *mvi)
+{
+ int i;
+
+ if (!mvi)
+ return;
+
+ for (i = 0; i < MVS_SLOTS; i++) {
+ struct mvs_slot_info *slot = &mvi->slot_info[i];
+
+ if (slot->buf)
+ dma_free_coherent(&mvi->pdev->dev, MVS_SLOT_BUF_SZ,
+ slot->buf, slot->buf_dma);
+ }
+
+ if (mvi->tx)
+ dma_free_coherent(&mvi->pdev->dev,
+ sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ,
+ mvi->tx, mvi->tx_dma);
+ if (mvi->rx_fis)
+ dma_free_coherent(&mvi->pdev->dev, MVS_RX_FISL_SZ,
+ mvi->rx_fis, mvi->rx_fis_dma);
+ if (mvi->rx)
+ dma_free_coherent(&mvi->pdev->dev,
+ sizeof(*mvi->rx) * MVS_RX_RING_SZ,
+ mvi->rx, mvi->rx_dma);
+ if (mvi->slot)
+ dma_free_coherent(&mvi->pdev->dev,
+ sizeof(*mvi->slot) * MVS_SLOTS,
+ mvi->slot, mvi->slot_dma);
+#ifdef MVS_ENABLE_PERI
+ if (mvi->peri_regs)
+ iounmap(mvi->peri_regs);
+#endif
+ if (mvi->regs)
+ iounmap(mvi->regs);
+ if (mvi->shost)
+ scsi_host_put(mvi->shost);
+ kfree(mvi->sas.sas_port);
+ kfree(mvi->sas.sas_phy);
+ kfree(mvi);
+}
+
+/* FIXME: locking? */
+static int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
+ void *funcdata)
+{
+ struct mvs_info *mvi = sas_phy->ha->lldd_ha;
+ int rc = 0, phy_id = sas_phy->id;
+ u32 tmp;
+
+ tmp = mvs_read_phy_ctl(mvi, phy_id);
+
+ switch (func) {
+ case PHY_FUNC_SET_LINK_RATE:{
+ struct sas_phy_linkrates *rates = funcdata;
+ u32 lrmin = 0, lrmax = 0;
+
+ lrmin = (rates->minimum_linkrate << 8);
+ lrmax = (rates->maximum_linkrate << 12);
+
+ if (lrmin) {
+ tmp &= ~(0xf << 8);
+ tmp |= lrmin;
+ }
+ if (lrmax) {
+ tmp &= ~(0xf << 12);
+ tmp |= lrmax;
+ }
+ mvs_write_phy_ctl(mvi, phy_id, tmp);
+ break;
+ }
+
+ case PHY_FUNC_HARD_RESET:
+ if (tmp & PHY_RST_HARD)
+ break;
+ mvs_write_phy_ctl(mvi, phy_id, tmp | PHY_RST_HARD);
+ break;
+
+ case PHY_FUNC_LINK_RESET:
+ mvs_write_phy_ctl(mvi, phy_id, tmp | PHY_RST);
+ break;
+
+ case PHY_FUNC_DISABLE:
+ case PHY_FUNC_RELEASE_SPINUP_HOLD:
+ default:
+ rc = -EOPNOTSUPP;
+ }
+
+ return rc;
+}
+
+static void __devinit mvs_phy_init(struct mvs_info *mvi, int phy_id)
+{
+ struct mvs_phy *phy = &mvi->phy[phy_id];
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+
+ sas_phy->enabled = (phy_id < mvi->chip->n_phy) ? 1 : 0;
+ sas_phy->class = SAS;
+ sas_phy->iproto = SAS_PROTOCOL_ALL;
+ sas_phy->tproto = 0;
+ sas_phy->type = PHY_TYPE_PHYSICAL;
+ sas_phy->role = PHY_ROLE_INITIATOR;
+ sas_phy->oob_mode = OOB_NOT_CONNECTED;
+ sas_phy->linkrate = SAS_LINK_RATE_UNKNOWN;
+
+ sas_phy->id = phy_id;
+ sas_phy->sas_addr = &mvi->sas_addr[0];
+ sas_phy->frame_rcvd = &phy->frame_rcvd[0];
+ sas_phy->ha = &mvi->sas;
+ sas_phy->lldd_phy = phy;
+}
+
+static struct mvs_info *__devinit mvs_alloc(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct mvs_info *mvi;
+ unsigned long res_start, res_len, res_flag;
+ struct asd_sas_phy **arr_phy;
+ struct asd_sas_port **arr_port;
+ const struct mvs_chip_info *chip = &mvs_chips[ent->driver_data];
+ int i;
+
+ /*
+ * alloc and init our per-HBA mvs_info struct
+ */
+
+ mvi = kzalloc(sizeof(*mvi), GFP_KERNEL);
+ if (!mvi)
+ return NULL;
+
+ spin_lock_init(&mvi->lock);
+ mvi->pdev = pdev;
+ mvi->chip = chip;
+
+ if (pdev->device == 0x6440 && pdev->revision == 0)
+ mvi->flags |= MVF_PHY_PWR_FIX;
+
+ /*
+ * alloc and init SCSI, SAS glue
+ */
+
+ mvi->shost = scsi_host_alloc(&mvs_sht, sizeof(void *));
+ if (!mvi->shost)
+ goto err_out;
+
+ arr_phy = kcalloc(MVS_MAX_PHYS, sizeof(void *), GFP_KERNEL);
+ arr_port = kcalloc(MVS_MAX_PHYS, sizeof(void *), GFP_KERNEL);
+ if (!arr_phy || !arr_port)
+ goto err_out;
+
+ for (i = 0; i < MVS_MAX_PHYS; i++) {
+ mvs_phy_init(mvi, i);
+ arr_phy[i] = &mvi->phy[i].sas_phy;
+ arr_port[i] = &mvi->port[i].sas_port;
+ }
+
+ SHOST_TO_SAS_HA(mvi->shost) = &mvi->sas;
+ mvi->shost->transportt = mvs_stt;
+ mvi->shost->max_id = 21;
+ mvi->shost->max_lun = ~0;
+ mvi->shost->max_channel = 0;
+ mvi->shost->max_cmd_len = 16;
+
+ mvi->sas.sas_ha_name = DRV_NAME;
+ mvi->sas.dev = &pdev->dev;
+ mvi->sas.lldd_module = THIS_MODULE;
+ mvi->sas.sas_addr = &mvi->sas_addr[0];
+ mvi->sas.sas_phy = arr_phy;
+ mvi->sas.sas_port = arr_port;
+ mvi->sas.num_phys = chip->n_phy;
+ mvi->sas.lldd_max_execute_num = MVS_CHIP_SLOT_SZ - 1;
+ mvi->sas.lldd_queue_size = MVS_QUEUE_SIZE;
+ mvi->can_queue = (MVS_CHIP_SLOT_SZ >> 1) - 1;
+ mvi->sas.lldd_ha = mvi;
+ mvi->sas.core.shost = mvi->shost;
+
+ mvs_tag_init(mvi);
+
+ /*
+ * ioremap main and peripheral registers
+ */
+
+#ifdef MVS_ENABLE_PERI
+ res_start = pci_resource_start(pdev, 2);
+ res_len = pci_resource_len(pdev, 2);
+ if (!res_start || !res_len)
+ goto err_out;
+
+ mvi->peri_regs = ioremap_nocache(res_start, res_len);
+ if (!mvi->peri_regs)
+ goto err_out;
+#endif
+
+ res_start = pci_resource_start(pdev, 4);
+ res_len = pci_resource_len(pdev, 4);
+ if (!res_start || !res_len)
+ goto err_out;
+
+ res_flag = pci_resource_flags(pdev, 4);
+ if (res_flag & IORESOURCE_CACHEABLE)
+ mvi->regs = ioremap(res_start, res_len);
+ else
+ mvi->regs = ioremap_nocache(res_start, res_len);
+
+ if (!mvi->regs)
+ goto err_out;
+
+ /*
+ * alloc and init our DMA areas
+ */
+
+ mvi->tx = dma_alloc_coherent(&pdev->dev,
+ sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ,
+ &mvi->tx_dma, GFP_KERNEL);
+ if (!mvi->tx)
+ goto err_out;
+ memset(mvi->tx, 0, sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ);
+
+ mvi->rx_fis = dma_alloc_coherent(&pdev->dev, MVS_RX_FISL_SZ,
+ &mvi->rx_fis_dma, GFP_KERNEL);
+ if (!mvi->rx_fis)
+ goto err_out;
+ memset(mvi->rx_fis, 0, MVS_RX_FISL_SZ);
+
+ mvi->rx = dma_alloc_coherent(&pdev->dev,
+ sizeof(*mvi->rx) * MVS_RX_RING_SZ,
+ &mvi->rx_dma, GFP_KERNEL);
+ if (!mvi->rx)
+ goto err_out;
+ memset(mvi->rx, 0, sizeof(*mvi->rx) * MVS_RX_RING_SZ);
+
+ mvi->rx[0] = cpu_to_le32(0xfff);
+ mvi->rx_cons = 0xfff;
+
+ mvi->slot = dma_alloc_coherent(&pdev->dev,
+ sizeof(*mvi->slot) * MVS_SLOTS,
+ &mvi->slot_dma, GFP_KERNEL);
+ if (!mvi->slot)
+ goto err_out;
+ memset(mvi->slot, 0, sizeof(*mvi->slot) * MVS_SLOTS);
+
+ for (i = 0; i < MVS_SLOTS; i++) {
+ struct mvs_slot_info *slot = &mvi->slot_info[i];
+
+ slot->buf = dma_alloc_coherent(&pdev->dev, MVS_SLOT_BUF_SZ,
+ &slot->buf_dma, GFP_KERNEL);
+ if (!slot->buf)
+ goto err_out;
+ memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
+ }
+
+ /* finally, read NVRAM to get our SAS address */
+ if (mvs_nvram_read(mvi, NVR_SAS_ADDR, &mvi->sas_addr, 8))
+ goto err_out;
+ return mvi;
+
+err_out:
+ mvs_free(mvi);
+ return NULL;
+}
+
+static u32 mvs_cr32(void __iomem *regs, u32 addr)
+{
+ mw32(CMD_ADDR, addr);
+ return mr32(CMD_DATA);
+}
+
+static void mvs_cw32(void __iomem *regs, u32 addr, u32 val)
+{
+ mw32(CMD_ADDR, addr);
+ mw32(CMD_DATA, val);
+}
+
+static u32 mvs_read_phy_ctl(struct mvs_info *mvi, u32 port)
+{
+ void __iomem *regs = mvi->regs;
+ return (port < 4)?mr32(P0_SER_CTLSTAT + port * 4):
+ mr32(P4_SER_CTLSTAT + (port - 4) * 4);
+}
+
+static void mvs_write_phy_ctl(struct mvs_info *mvi, u32 port, u32 val)
+{
+ void __iomem *regs = mvi->regs;
+ if (port < 4)
+ mw32(P0_SER_CTLSTAT + port * 4, val);
+ else
+ mw32(P4_SER_CTLSTAT + (port - 4) * 4, val);
+}
+
+static u32 mvs_read_port(struct mvs_info *mvi, u32 off, u32 off2, u32 port)
+{
+ void __iomem *regs = mvi->regs + off;
+ void __iomem *regs2 = mvi->regs + off2;
+ return (port < 4)?readl(regs + port * 8):
+ readl(regs2 + (port - 4) * 8);
+}
+
+static void mvs_write_port(struct mvs_info *mvi, u32 off, u32 off2,
+ u32 port, u32 val)
+{
+ void __iomem *regs = mvi->regs + off;
+ void __iomem *regs2 = mvi->regs + off2;
+ if (port < 4)
+ writel(val, regs + port * 8);
+ else
+ writel(val, regs2 + (port - 4) * 8);
+}
+
+static u32 mvs_read_port_cfg_data(struct mvs_info *mvi, u32 port)
+{
+ return mvs_read_port(mvi, MVS_P0_CFG_DATA, MVS_P4_CFG_DATA, port);
+}
+
+static void mvs_write_port_cfg_data(struct mvs_info *mvi, u32 port, u32 val)
+{
+ mvs_write_port(mvi, MVS_P0_CFG_DATA, MVS_P4_CFG_DATA, port, val);
+}
+
+static void mvs_write_port_cfg_addr(struct mvs_info *mvi, u32 port, u32 addr)
+{
+ mvs_write_port(mvi, MVS_P0_CFG_ADDR, MVS_P4_CFG_ADDR, port, addr);
+}
+
+static u32 mvs_read_port_vsr_data(struct mvs_info *mvi, u32 port)
+{
+ return mvs_read_port(mvi, MVS_P0_VSR_DATA, MVS_P4_VSR_DATA, port);
+}
+
+static void mvs_write_port_vsr_data(struct mvs_info *mvi, u32 port, u32 val)
+{
+ mvs_write_port(mvi, MVS_P0_VSR_DATA, MVS_P4_VSR_DATA, port, val);
+}
+
+static void mvs_write_port_vsr_addr(struct mvs_info *mvi, u32 port, u32 addr)
+{
+ mvs_write_port(mvi, MVS_P0_VSR_ADDR, MVS_P4_VSR_ADDR, port, addr);
+}
+
+static u32 mvs_read_port_irq_stat(struct mvs_info *mvi, u32 port)
+{
+ return mvs_read_port(mvi, MVS_P0_INT_STAT, MVS_P4_INT_STAT, port);
+}
+
+static void mvs_write_port_irq_stat(struct mvs_info *mvi, u32 port, u32 val)
+{
+ mvs_write_port(mvi, MVS_P0_INT_STAT, MVS_P4_INT_STAT, port, val);
+}
+
+static u32 mvs_read_port_irq_mask(struct mvs_info *mvi, u32 port)
+{
+ return mvs_read_port(mvi, MVS_P0_INT_MASK, MVS_P4_INT_MASK, port);
+}
+
+static void mvs_write_port_irq_mask(struct mvs_info *mvi, u32 port, u32 val)
+{
+ mvs_write_port(mvi, MVS_P0_INT_MASK, MVS_P4_INT_MASK, port, val);
+}
+
+static void __devinit mvs_phy_hacks(struct mvs_info *mvi)
+{
+ void __iomem *regs = mvi->regs;
+ u32 tmp;
+
+ /* workaround for SATA R-ERR, to ignore phy glitch */
+ tmp = mvs_cr32(regs, CMD_PHY_TIMER);
+ tmp &= ~(1 << 9);
+ tmp |= (1 << 10);
+ mvs_cw32(regs, CMD_PHY_TIMER, tmp);
+
+ /* enable retry 127 times */
+ mvs_cw32(regs, CMD_SAS_CTL1, 0x7f7f);
+
+ /* extend open frame timeout to max */
+ tmp = mvs_cr32(regs, CMD_SAS_CTL0);
+ tmp &= ~0xffff;
+ tmp |= 0x3fff;
+ mvs_cw32(regs, CMD_SAS_CTL0, tmp);
+
+ /* workaround for WDTIMEOUT , set to 550 ms */
+ mvs_cw32(regs, CMD_WD_TIMER, 0xffffff);
+
+ /* not to halt for different port op during wideport link change */
+ mvs_cw32(regs, CMD_APP_ERR_CONFIG, 0xffefbf7d);
+
+ /* workaround for Seagate disk not-found OOB sequence, recv
+ * COMINIT before sending out COMWAKE */
+ tmp = mvs_cr32(regs, CMD_PHY_MODE_21);
+ tmp &= 0x0000ffff;
+ tmp |= 0x00fa0000;
+ mvs_cw32(regs, CMD_PHY_MODE_21, tmp);
+
+ tmp = mvs_cr32(regs, CMD_PHY_TIMER);
+ tmp &= 0x1fffffff;
+ tmp |= (2U << 29); /* 8 ms retry */
+ mvs_cw32(regs, CMD_PHY_TIMER, tmp);
+
+ /* TEST - for phy decoding error, adjust voltage levels */
+ mw32(P0_VSR_ADDR + 0, 0x8);
+ mw32(P0_VSR_DATA + 0, 0x2F0);
+
+ mw32(P0_VSR_ADDR + 8, 0x8);
+ mw32(P0_VSR_DATA + 8, 0x2F0);
+
+ mw32(P0_VSR_ADDR + 16, 0x8);
+ mw32(P0_VSR_DATA + 16, 0x2F0);
+
+ mw32(P0_VSR_ADDR + 24, 0x8);
+ mw32(P0_VSR_DATA + 24, 0x2F0);
+
+}
+
+static void mvs_enable_xmt(struct mvs_info *mvi, int PhyId)
+{
+ void __iomem *regs = mvi->regs;
+ u32 tmp;
+
+ tmp = mr32(PCS);
+ if (mvi->chip->n_phy <= 4)
+ tmp |= 1 << (PhyId + PCS_EN_PORT_XMT_SHIFT);
+ else
+ tmp |= 1 << (PhyId + PCS_EN_PORT_XMT_SHIFT2);
+ mw32(PCS, tmp);
+}
+
+static void mvs_detect_porttype(struct mvs_info *mvi, int i)
+{
+ void __iomem *regs = mvi->regs;
+ u32 reg;
+ struct mvs_phy *phy = &mvi->phy[i];
+
+ /* TODO check & save device type */
+ reg = mr32(GBL_PORT_TYPE);
+
+ if (reg & MODE_SAS_SATA & (1 << i))
+ phy->phy_type |= PORT_TYPE_SAS;
+ else
+ phy->phy_type |= PORT_TYPE_SATA;
+}
+
+static void *mvs_get_d2h_reg(struct mvs_info *mvi, int i, void *buf)
+{
+ u32 *s = (u32 *) buf;
+
+ if (!s)
+ return NULL;
+
+ mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG3);
+ s[3] = mvs_read_port_cfg_data(mvi, i);
+
+ mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG2);
+ s[2] = mvs_read_port_cfg_data(mvi, i);
+
+ mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG1);
+ s[1] = mvs_read_port_cfg_data(mvi, i);
+
+ mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG0);
+ s[0] = mvs_read_port_cfg_data(mvi, i);
+
+ return (void *)s;
+}
+
+static u32 mvs_is_sig_fis_received(u32 irq_status)
+{
+ return irq_status & PHYEV_SIG_FIS;
+}
+
+static void mvs_update_wideport(struct mvs_info *mvi, int i)
+{
+ struct mvs_phy *phy = &mvi->phy[i];
+ struct mvs_port *port = phy->port;
+ int j, no;
+
+ for_each_phy(port->wide_port_phymap, no, j, mvi->chip->n_phy)
+ if (no & 1) {
+ mvs_write_port_cfg_addr(mvi, no, PHYR_WIDE_PORT);
+ mvs_write_port_cfg_data(mvi, no,
+ port->wide_port_phymap);
+ } else {
+ mvs_write_port_cfg_addr(mvi, no, PHYR_WIDE_PORT);
+ mvs_write_port_cfg_data(mvi, no, 0);
+ }
+}
+
+static u32 mvs_is_phy_ready(struct mvs_info *mvi, int i)
+{
+ u32 tmp;
+ struct mvs_phy *phy = &mvi->phy[i];
+ struct mvs_port *port;
+
+ tmp = mvs_read_phy_ctl(mvi, i);
+
+ if ((tmp & PHY_READY_MASK) && !(phy->irq_status & PHYEV_POOF)) {
+ if (!phy->port)
+ phy->phy_attached = 1;
+ return tmp;
+ }
+
+ port = phy->port;
+ if (port) {
+ if (phy->phy_type & PORT_TYPE_SAS) {
+ port->wide_port_phymap &= ~(1U << i);
+ if (!port->wide_port_phymap)
+ port->port_attached = 0;
+ mvs_update_wideport(mvi, i);
+ } else if (phy->phy_type & PORT_TYPE_SATA)
+ port->port_attached = 0;
+ mvs_free_reg_set(mvi, phy->port);
+ phy->port = NULL;
+ phy->phy_attached = 0;
+ phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA);
+ }
+ return 0;
+}
+
+static void mvs_update_phyinfo(struct mvs_info *mvi, int i,
+ int get_st)
+{
+ struct mvs_phy *phy = &mvi->phy[i];
+ struct pci_dev *pdev = mvi->pdev;
+ u32 tmp, j;
+ u64 tmp64;
+
+ mvs_write_port_cfg_addr(mvi, i, PHYR_IDENTIFY);
+ phy->dev_info = mvs_read_port_cfg_data(mvi, i);
+
+ mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_HI);
+ phy->dev_sas_addr = (u64) mvs_read_port_cfg_data(mvi, i) << 32;
+
+ mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_LO);
+ phy->dev_sas_addr |= mvs_read_port_cfg_data(mvi, i);
+
+ if (get_st) {
+ phy->irq_status = mvs_read_port_irq_stat(mvi, i);
+ phy->phy_status = mvs_is_phy_ready(mvi, i);
+ }
+
+ if (phy->phy_status) {
+ u32 phy_st;
+ struct asd_sas_phy *sas_phy = mvi->sas.sas_phy[i];
+
+ mvs_write_port_cfg_addr(mvi, i, PHYR_PHY_STAT);
+ phy_st = mvs_read_port_cfg_data(mvi, i);
+
+ sas_phy->linkrate =
+ (phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
+ PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET;
+
+ /* Updated attached_sas_addr */
+ mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_HI);
+ phy->att_dev_sas_addr =
+ (u64) mvs_read_port_cfg_data(mvi, i) << 32;
+
+ mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_LO);
+ phy->att_dev_sas_addr |= mvs_read_port_cfg_data(mvi, i);
+
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "phy[%d] Get Attached Address 0x%llX ,"
+ " SAS Address 0x%llX\n",
+ i, phy->att_dev_sas_addr, phy->dev_sas_addr);
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "Rate = %x , type = %d\n",
+ sas_phy->linkrate, phy->phy_type);
+
+#if 1
+ /*
+ * If the device is capable of supporting a wide port
+ * on its phys, it may configure the phys as a wide port.
+ */
+ if (phy->phy_type & PORT_TYPE_SAS)
+ for (j = 0; j < mvi->chip->n_phy && j != i; ++j) {
+ if ((mvi->phy[j].phy_attached) &&
+ (mvi->phy[j].phy_type & PORT_TYPE_SAS))
+ if (phy->att_dev_sas_addr ==
+ mvi->phy[j].att_dev_sas_addr - 1) {
+ phy->att_dev_sas_addr =
+ mvi->phy[j].att_dev_sas_addr;
+ break;
+ }
+ }
+
+#endif
+
+ tmp64 = cpu_to_be64(phy->att_dev_sas_addr);
+ memcpy(sas_phy->attached_sas_addr, &tmp64, SAS_ADDR_SIZE);
+
+ if (phy->phy_type & PORT_TYPE_SAS) {
+ mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_DEV_INFO);
+ phy->att_dev_info = mvs_read_port_cfg_data(mvi, i);
+ phy->identify.device_type =
+ phy->att_dev_info & PORT_DEV_TYPE_MASK;
+
+ if (phy->identify.device_type == SAS_END_DEV)
+ phy->identify.target_port_protocols =
+ SAS_PROTOCOL_SSP;
+ else if (phy->identify.device_type != NO_DEVICE)
+ phy->identify.target_port_protocols =
+ SAS_PROTOCOL_SMP;
+ if (phy_st & PHY_OOB_DTCTD)
+ sas_phy->oob_mode = SAS_OOB_MODE;
+ phy->frame_rcvd_size =
+ sizeof(struct sas_identify_frame);
+ } else if (phy->phy_type & PORT_TYPE_SATA) {
+ phy->identify.target_port_protocols = SAS_PROTOCOL_STP;
+ if (mvs_is_sig_fis_received(phy->irq_status)) {
+ if (phy_st & PHY_OOB_DTCTD)
+ sas_phy->oob_mode = SATA_OOB_MODE;
+ phy->frame_rcvd_size =
+ sizeof(struct dev_to_host_fis);
+ mvs_get_d2h_reg(mvi, i,
+ (void *)sas_phy->frame_rcvd);
+ } else {
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "No sig fis\n");
+ }
+ }
+ /* workaround for HW phy decoding error on 1.5g disk drive */
+ mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE6);
+ tmp = mvs_read_port_vsr_data(mvi, i);
+ if (((phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
+ PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET) ==
+ SAS_LINK_RATE_1_5_GBPS)
+ tmp &= ~PHY_MODE6_DTL_SPEED;
+ else
+ tmp |= PHY_MODE6_DTL_SPEED;
+ mvs_write_port_vsr_data(mvi, i, tmp);
+
+ }
+ if (get_st)
+ mvs_write_port_irq_stat(mvi, i, phy->irq_status);
+}
+
+static void mvs_port_formed(struct asd_sas_phy *sas_phy)
+{
+ struct sas_ha_struct *sas_ha = sas_phy->ha;
+ struct mvs_info *mvi = sas_ha->lldd_ha;
+ struct asd_sas_port *sas_port = sas_phy->port;
+ struct mvs_phy *phy = sas_phy->lldd_phy;
+ struct mvs_port *port = &mvi->port[sas_port->id];
+ unsigned long flags;
+
+ spin_lock_irqsave(&mvi->lock, flags);
+ port->port_attached = 1;
+ phy->port = port;
+ port->taskfileset = MVS_ID_NOT_MAPPED;
+ if (phy->phy_type & PORT_TYPE_SAS) {
+ port->wide_port_phymap = sas_port->phy_mask;
+ mvs_update_wideport(mvi, sas_phy->id);
+ }
+ spin_unlock_irqrestore(&mvi->lock, flags);
+}
+
+static int __devinit mvs_hw_init(struct mvs_info *mvi)
+{
+ void __iomem *regs = mvi->regs;
+ int i;
+ u32 tmp, cctl;
+
+ /* make sure interrupts are masked immediately (paranoia) */
+ mw32(GBL_CTL, 0);
+ tmp = mr32(GBL_CTL);
+
+ /* Reset Controller */
+ if (!(tmp & HBA_RST)) {
+ if (mvi->flags & MVF_PHY_PWR_FIX) {
+ pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp);
+ tmp &= ~PCTL_PWR_ON;
+ tmp |= PCTL_OFF;
+ pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp);
+
+ pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &tmp);
+ tmp &= ~PCTL_PWR_ON;
+ tmp |= PCTL_OFF;
+ pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp);
+ }
+
+ /* global reset, incl. COMRESET/H_RESET_N (self-clearing) */
+ mw32_f(GBL_CTL, HBA_RST);
+ }
+
+ /* wait for reset to finish; timeout is just a guess */
+ i = 1000;
+ while (i-- > 0) {
+ msleep(10);
+
+ if (!(mr32(GBL_CTL) & HBA_RST))
+ break;
+ }
+ if (mr32(GBL_CTL) & HBA_RST) {
+ dev_printk(KERN_ERR, &mvi->pdev->dev, "HBA reset failed\n");
+ return -EBUSY;
+ }
+
+ /* Init Chip */
+ /* make sure RST is set; HBA_RST /should/ have done that for us */
+ cctl = mr32(CTL);
+ if (cctl & CCTL_RST)
+ cctl &= ~CCTL_RST;
+ else
+ mw32_f(CTL, cctl | CCTL_RST);
+
+ /* write to device control _AND_ device status register? - A.C. */
+ pci_read_config_dword(mvi->pdev, PCR_DEV_CTRL, &tmp);
+ tmp &= ~PRD_REQ_MASK;
+ tmp |= PRD_REQ_SIZE;
+ pci_write_config_dword(mvi->pdev, PCR_DEV_CTRL, tmp);
+
+ pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp);
+ tmp |= PCTL_PWR_ON;
+ tmp &= ~PCTL_OFF;
+ pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp);
+
+ pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &tmp);
+ tmp |= PCTL_PWR_ON;
+ tmp &= ~PCTL_OFF;
+ pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp);
+
+ mw32_f(CTL, cctl);
+
+ /* reset control */
+ mw32(PCS, 0); /*MVS_PCS */
+
+ mvs_phy_hacks(mvi);
+
+ mw32(CMD_LIST_LO, mvi->slot_dma);
+ mw32(CMD_LIST_HI, (mvi->slot_dma >> 16) >> 16);
+
+ mw32(RX_FIS_LO, mvi->rx_fis_dma);
+ mw32(RX_FIS_HI, (mvi->rx_fis_dma >> 16) >> 16);
+
+ mw32(TX_CFG, MVS_CHIP_SLOT_SZ);
+ mw32(TX_LO, mvi->tx_dma);
+ mw32(TX_HI, (mvi->tx_dma >> 16) >> 16);
+
+ mw32(RX_CFG, MVS_RX_RING_SZ);
+ mw32(RX_LO, mvi->rx_dma);
+ mw32(RX_HI, (mvi->rx_dma >> 16) >> 16);
+
+ /* enable auto port detection */
+ mw32(GBL_PORT_TYPE, MODE_AUTO_DET_EN);
+ msleep(100);
+ /* init and reset phys */
+ for (i = 0; i < mvi->chip->n_phy; i++) {
+ /* FIXME: is this the correct dword order? */
+ u32 lo = *((u32 *)&mvi->sas_addr[0]);
+ u32 hi = *((u32 *)&mvi->sas_addr[4]);
+
+ mvs_detect_porttype(mvi, i);
+
+ /* set phy local SAS address */
+ mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_LO);
+ mvs_write_port_cfg_data(mvi, i, lo);
+ mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_HI);
+ mvs_write_port_cfg_data(mvi, i, hi);
+
+ /* reset phy */
+ tmp = mvs_read_phy_ctl(mvi, i);
+ tmp |= PHY_RST;
+ mvs_write_phy_ctl(mvi, i, tmp);
+ }
+
+ msleep(100);
+
+ for (i = 0; i < mvi->chip->n_phy; i++) {
+ /* clear phy int status */
+ tmp = mvs_read_port_irq_stat(mvi, i);
+ tmp &= ~PHYEV_SIG_FIS;
+ mvs_write_port_irq_stat(mvi, i, tmp);
+
+ /* set phy int mask */
+ tmp = PHYEV_RDY_CH | PHYEV_BROAD_CH | PHYEV_UNASSOC_FIS |
+ PHYEV_ID_DONE | PHYEV_DEC_ERR;
+ mvs_write_port_irq_mask(mvi, i, tmp);
+
+ msleep(100);
+ mvs_update_phyinfo(mvi, i, 1);
+ mvs_enable_xmt(mvi, i);
+ }
+
+ /* FIXME: update wide port bitmaps */
+
+ /* little endian for open address and command table, etc. */
+ /* A.C.
+ * it seems that ( from the spec ) turning on big-endian won't
+ * do us any good on big-endian machines, need further confirmation
+ */
+ cctl = mr32(CTL);
+ cctl |= CCTL_ENDIAN_CMD;
+ cctl |= CCTL_ENDIAN_DATA;
+ cctl &= ~CCTL_ENDIAN_OPEN;
+ cctl |= CCTL_ENDIAN_RSP;
+ mw32_f(CTL, cctl);
+
+ /* reset CMD queue */
+ tmp = mr32(PCS);
+ tmp |= PCS_CMD_RST;
+ mw32(PCS, tmp);
+ /* interrupt coalescing may cause missing HW interrput in some case,
+ * and the max count is 0x1ff, while our max slot is 0x200,
+ * it will make count 0.
+ */
+ tmp = 0;
+ mw32(INT_COAL, tmp);
+
+ tmp = 0x100;
+ mw32(INT_COAL_TMOUT, tmp);
+
+ /* ladies and gentlemen, start your engines */
+ mw32(TX_CFG, 0);
+ mw32(TX_CFG, MVS_CHIP_SLOT_SZ | TX_EN);
+ mw32(RX_CFG, MVS_RX_RING_SZ | RX_EN);
+ /* enable CMD/CMPL_Q/RESP mode */
+ mw32(PCS, PCS_SATA_RETRY | PCS_FIS_RX_EN | PCS_CMD_EN);
+
+ /* re-enable interrupts globally */
+ mvs_hba_interrupt_enable(mvi);
+
+ /* enable completion queue interrupt */
+ tmp = (CINT_PORT_MASK | CINT_DONE | CINT_MEM);
+ mw32(INT_MASK, tmp);
+
+ return 0;
+}
+
+static void __devinit mvs_print_info(struct mvs_info *mvi)
+{
+ struct pci_dev *pdev = mvi->pdev;
+ static int printed_version;
+
+ if (!printed_version++)
+ dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
+
+ dev_printk(KERN_INFO, &pdev->dev, "%u phys, addr %llx\n",
+ mvi->chip->n_phy, SAS_ADDR(mvi->sas_addr));
+}
+
+static int __devinit mvs_pci_init(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ int rc;
+ struct mvs_info *mvi;
+ irq_handler_t irq_handler = mvs_interrupt;
+
+ rc = pci_enable_device(pdev);
+ if (rc)
+ return rc;
+
+ pci_set_master(pdev);
+
+ rc = pci_request_regions(pdev, DRV_NAME);
+ if (rc)
+ goto err_out_disable;
+
+ rc = pci_go_64(pdev);
+ if (rc)
+ goto err_out_regions;
+
+ mvi = mvs_alloc(pdev, ent);
+ if (!mvi) {
+ rc = -ENOMEM;
+ goto err_out_regions;
+ }
+
+ rc = mvs_hw_init(mvi);
+ if (rc)
+ goto err_out_mvi;
+
+#ifndef MVS_DISABLE_MSI
+ if (!pci_enable_msi(pdev)) {
+ u32 tmp;
+ void __iomem *regs = mvi->regs;
+ mvi->flags |= MVF_MSI;
+ irq_handler = mvs_msi_interrupt;
+ tmp = mr32(PCS);
+ mw32(PCS, tmp | PCS_SELF_CLEAR);
+ }
+#endif
+
+ rc = request_irq(pdev->irq, irq_handler, IRQF_SHARED, DRV_NAME, mvi);
+ if (rc)
+ goto err_out_msi;
+
+ rc = scsi_add_host(mvi->shost, &pdev->dev);
+ if (rc)
+ goto err_out_irq;
+
+ rc = sas_register_ha(&mvi->sas);
+ if (rc)
+ goto err_out_shost;
+
+ pci_set_drvdata(pdev, mvi);
+
+ mvs_print_info(mvi);
+
+ scsi_scan_host(mvi->shost);
+
+ return 0;
+
+err_out_shost:
+ scsi_remove_host(mvi->shost);
+err_out_irq:
+ free_irq(pdev->irq, mvi);
+err_out_msi:
+ if (mvi->flags |= MVF_MSI)
+ pci_disable_msi(pdev);
+err_out_mvi:
+ mvs_free(mvi);
+err_out_regions:
+ pci_release_regions(pdev);
+err_out_disable:
+ pci_disable_device(pdev);
+ return rc;
+}
+
+static void __devexit mvs_pci_remove(struct pci_dev *pdev)
+{
+ struct mvs_info *mvi = pci_get_drvdata(pdev);
+
+ pci_set_drvdata(pdev, NULL);
+
+ if (mvi) {
+ sas_unregister_ha(&mvi->sas);
+ mvs_hba_interrupt_disable(mvi);
+ sas_remove_host(mvi->shost);
+ scsi_remove_host(mvi->shost);
+
+ free_irq(pdev->irq, mvi);
+ if (mvi->flags & MVF_MSI)
+ pci_disable_msi(pdev);
+ mvs_free(mvi);
+ pci_release_regions(pdev);
+ }
+ pci_disable_device(pdev);
+}
+
+static struct sas_domain_function_template mvs_transport_ops = {
+ .lldd_execute_task = mvs_task_exec,
+ .lldd_control_phy = mvs_phy_control,
+ .lldd_abort_task = mvs_task_abort,
+ .lldd_port_formed = mvs_port_formed
+};
+
+static struct pci_device_id __devinitdata mvs_pci_table[] = {
+ { PCI_VDEVICE(MARVELL, 0x6320), chip_6320 },
+ { PCI_VDEVICE(MARVELL, 0x6340), chip_6440 },
+ { PCI_VDEVICE(MARVELL, 0x6440), chip_6440 },
+ { PCI_VDEVICE(MARVELL, 0x6480), chip_6480 },
+
+ { } /* terminate list */
+};
+
+static struct pci_driver mvs_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = mvs_pci_table,
+ .probe = mvs_pci_init,
+ .remove = __devexit_p(mvs_pci_remove),
+};
+
+static int __init mvs_init(void)
+{
+ int rc;
+
+ mvs_stt = sas_domain_attach_transport(&mvs_transport_ops);
+ if (!mvs_stt)
+ return -ENOMEM;
+
+ rc = pci_register_driver(&mvs_pci_driver);
+ if (rc)
+ goto err_out;
+
+ return 0;
+
+err_out:
+ sas_release_transport(mvs_stt);
+ return rc;
+}
+
+static void __exit mvs_exit(void)
+{
+ pci_unregister_driver(&mvs_pci_driver);
+ sas_release_transport(mvs_stt);
+}
+
+module_init(mvs_init);
+module_exit(mvs_exit);
+
+MODULE_AUTHOR("Jeff Garzik <jgarzik@pobox.com>");
+MODULE_DESCRIPTION("Marvell 88SE6440 SAS/SATA controller driver");
+MODULE_VERSION(DRV_VERSION);
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, mvs_pci_table);
diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c
index 1479c60441c..2cd899bfe84 100644
--- a/drivers/scsi/qla2xxx/qla_dfs.c
+++ b/drivers/scsi/qla2xxx/qla_dfs.c
@@ -23,7 +23,7 @@ qla2x00_dfs_fce_show(struct seq_file *s, void *unused)
mutex_lock(&ha->fce_mutex);
seq_printf(s, "FCE Trace Buffer\n");
- seq_printf(s, "In Pointer = %llx\n\n", ha->fce_wr);
+ seq_printf(s, "In Pointer = %llx\n\n", (unsigned long long)ha->fce_wr);
seq_printf(s, "Base = %llx\n\n", (unsigned long long) ha->fce_dma);
seq_printf(s, "FCE Enable Registers\n");
seq_printf(s, "%08x %08x %08x %08x %08x %08x\n",
diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c
index 0f029d0d731..fc84db4069f 100644
--- a/drivers/scsi/qla4xxx/ql4_isr.c
+++ b/drivers/scsi/qla4xxx/ql4_isr.c
@@ -100,8 +100,7 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
if (sts_entry->iscsiFlags &ISCSI_FLAG_RESIDUAL_UNDER) {
scsi_set_resid(cmd, residual);
- if (!scsi_status && ((scsi_bufflen(cmd) - residual) <
- cmd->underflow)) {
+ if ((scsi_bufflen(cmd) - residual) < cmd->underflow) {
cmd->result = DID_ERROR << 16;
diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
index 65455ab1f3b..4a1cf6377f6 100644
--- a/drivers/scsi/qlogicpti.c
+++ b/drivers/scsi/qlogicpti.c
@@ -651,7 +651,7 @@ static int qlogicpti_verify_tmon(struct qlogicpti *qpti)
static irqreturn_t qpti_intr(int irq, void *dev_id);
-static void __init qpti_chain_add(struct qlogicpti *qpti)
+static void __devinit qpti_chain_add(struct qlogicpti *qpti)
{
spin_lock_irq(&qptichain_lock);
if (qptichain != NULL) {
@@ -667,7 +667,7 @@ static void __init qpti_chain_add(struct qlogicpti *qpti)
spin_unlock_irq(&qptichain_lock);
}
-static void __init qpti_chain_del(struct qlogicpti *qpti)
+static void __devexit qpti_chain_del(struct qlogicpti *qpti)
{
spin_lock_irq(&qptichain_lock);
if (qptichain == qpti) {
@@ -682,7 +682,7 @@ static void __init qpti_chain_del(struct qlogicpti *qpti)
spin_unlock_irq(&qptichain_lock);
}
-static int __init qpti_map_regs(struct qlogicpti *qpti)
+static int __devinit qpti_map_regs(struct qlogicpti *qpti)
{
struct sbus_dev *sdev = qpti->sdev;
@@ -705,7 +705,7 @@ static int __init qpti_map_regs(struct qlogicpti *qpti)
return 0;
}
-static int __init qpti_register_irq(struct qlogicpti *qpti)
+static int __devinit qpti_register_irq(struct qlogicpti *qpti)
{
struct sbus_dev *sdev = qpti->sdev;
@@ -730,7 +730,7 @@ fail:
return -1;
}
-static void __init qpti_get_scsi_id(struct qlogicpti *qpti)
+static void __devinit qpti_get_scsi_id(struct qlogicpti *qpti)
{
qpti->scsi_id = prom_getintdefault(qpti->prom_node,
"initiator-id",
@@ -783,7 +783,7 @@ static void qpti_get_clock(struct qlogicpti *qpti)
/* The request and response queues must each be aligned
* on a page boundary.
*/
-static int __init qpti_map_queues(struct qlogicpti *qpti)
+static int __devinit qpti_map_queues(struct qlogicpti *qpti)
{
struct sbus_dev *sdev = qpti->sdev;
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 1541c174937..d1777a9a962 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -222,7 +222,7 @@ static struct scsi_host_template sdebug_driver_template = {
.cmd_per_lun = 16,
.max_sectors = 0xffff,
.unchecked_isa_dma = 0,
- .use_clustering = ENABLE_CLUSTERING,
+ .use_clustering = DISABLE_CLUSTERING,
.module = THIS_MODULE,
};
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 135c1d05470..ba21d97d185 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -1014,10 +1014,6 @@ static int scsi_init_sgtable(struct request *req, struct scsi_data_buffer *sdb,
}
req->buffer = NULL;
- if (blk_pc_request(req))
- sdb->length = req->data_len;
- else
- sdb->length = req->nr_sectors << 9;
/*
* Next, walk the list, and fill in the addresses and sizes of
@@ -1026,6 +1022,10 @@ static int scsi_init_sgtable(struct request *req, struct scsi_data_buffer *sdb,
count = blk_rq_map_sg(req->q, req, sdb->table.sgl);
BUG_ON(count > sdb->table.nents);
sdb->table.nents = count;
+ if (blk_pc_request(req))
+ sdb->length = req->data_len;
+ else
+ sdb->length = req->nr_sectors << 9;
return BLKPREP_OK;
}
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index fac7534f3ec..9981682d530 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -231,7 +231,7 @@ static struct {
{ ISCSI_SESSION_FREE, "FREE" },
};
-const char *iscsi_session_state_name(int state)
+static const char *iscsi_session_state_name(int state)
{
int i;
char *name = NULL;
@@ -373,7 +373,7 @@ static void session_recovery_timedout(struct work_struct *work)
scsi_target_unblock(&session->dev);
}
-void __iscsi_unblock_session(struct iscsi_cls_session *session)
+static void __iscsi_unblock_session(struct iscsi_cls_session *session)
{
if (!cancel_delayed_work(&session->recovery_work))
flush_workqueue(iscsi_eh_timer_workq);
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 37df8bbe7f4..7aee64dbfbe 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -1835,8 +1835,7 @@ static int sd_suspend(struct device *dev, pm_message_t mesg)
goto done;
}
- if (mesg.event == PM_EVENT_SUSPEND &&
- sdkp->device->manage_start_stop) {
+ if ((mesg.event & PM_EVENT_SLEEP) && sdkp->device->manage_start_stop) {
sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n");
ret = sd_start_stop_device(sdkp, 0);
}
diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c
index a57fed47b39..a6d96694d0a 100644
--- a/drivers/scsi/ses.c
+++ b/drivers/scsi/ses.c
@@ -33,9 +33,9 @@
#include <scsi/scsi_host.h>
struct ses_device {
- char *page1;
- char *page2;
- char *page10;
+ unsigned char *page1;
+ unsigned char *page2;
+ unsigned char *page10;
short page1_len;
short page2_len;
short page10_len;
@@ -67,7 +67,7 @@ static int ses_probe(struct device *dev)
static int ses_recv_diag(struct scsi_device *sdev, int page_code,
void *buf, int bufflen)
{
- char cmd[] = {
+ unsigned char cmd[] = {
RECEIVE_DIAGNOSTIC,
1, /* Set PCV bit */
page_code,
@@ -85,7 +85,7 @@ static int ses_send_diag(struct scsi_device *sdev, int page_code,
{
u32 result;
- char cmd[] = {
+ unsigned char cmd[] = {
SEND_DIAGNOSTIC,
0x10, /* Set PF bit */
0,
@@ -104,13 +104,13 @@ static int ses_send_diag(struct scsi_device *sdev, int page_code,
static int ses_set_page2_descriptor(struct enclosure_device *edev,
struct enclosure_component *ecomp,
- char *desc)
+ unsigned char *desc)
{
int i, j, count = 0, descriptor = ecomp->number;
struct scsi_device *sdev = to_scsi_device(edev->cdev.dev);
struct ses_device *ses_dev = edev->scratch;
- char *type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11];
- char *desc_ptr = ses_dev->page2 + 8;
+ unsigned char *type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11];
+ unsigned char *desc_ptr = ses_dev->page2 + 8;
/* Clear everything */
memset(desc_ptr, 0, ses_dev->page2_len - 8);
@@ -133,14 +133,14 @@ static int ses_set_page2_descriptor(struct enclosure_device *edev,
return ses_send_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len);
}
-static char *ses_get_page2_descriptor(struct enclosure_device *edev,
+static unsigned char *ses_get_page2_descriptor(struct enclosure_device *edev,
struct enclosure_component *ecomp)
{
int i, j, count = 0, descriptor = ecomp->number;
struct scsi_device *sdev = to_scsi_device(edev->cdev.dev);
struct ses_device *ses_dev = edev->scratch;
- char *type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11];
- char *desc_ptr = ses_dev->page2 + 8;
+ unsigned char *type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11];
+ unsigned char *desc_ptr = ses_dev->page2 + 8;
ses_recv_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len);
@@ -160,17 +160,18 @@ static char *ses_get_page2_descriptor(struct enclosure_device *edev,
static void ses_get_fault(struct enclosure_device *edev,
struct enclosure_component *ecomp)
{
- char *desc;
+ unsigned char *desc;
desc = ses_get_page2_descriptor(edev, ecomp);
- ecomp->fault = (desc[3] & 0x60) >> 4;
+ if (desc)
+ ecomp->fault = (desc[3] & 0x60) >> 4;
}
static int ses_set_fault(struct enclosure_device *edev,
struct enclosure_component *ecomp,
enum enclosure_component_setting val)
{
- char desc[4] = {0 };
+ unsigned char desc[4] = {0 };
switch (val) {
case ENCLOSURE_SETTING_DISABLED:
@@ -190,26 +191,28 @@ static int ses_set_fault(struct enclosure_device *edev,
static void ses_get_status(struct enclosure_device *edev,
struct enclosure_component *ecomp)
{
- char *desc;
+ unsigned char *desc;
desc = ses_get_page2_descriptor(edev, ecomp);
- ecomp->status = (desc[0] & 0x0f);
+ if (desc)
+ ecomp->status = (desc[0] & 0x0f);
}
static void ses_get_locate(struct enclosure_device *edev,
struct enclosure_component *ecomp)
{
- char *desc;
+ unsigned char *desc;
desc = ses_get_page2_descriptor(edev, ecomp);
- ecomp->locate = (desc[2] & 0x02) ? 1 : 0;
+ if (desc)
+ ecomp->locate = (desc[2] & 0x02) ? 1 : 0;
}
static int ses_set_locate(struct enclosure_device *edev,
struct enclosure_component *ecomp,
enum enclosure_component_setting val)
{
- char desc[4] = {0 };
+ unsigned char desc[4] = {0 };
switch (val) {
case ENCLOSURE_SETTING_DISABLED:
@@ -229,7 +232,7 @@ static int ses_set_active(struct enclosure_device *edev,
struct enclosure_component *ecomp,
enum enclosure_component_setting val)
{
- char desc[4] = {0 };
+ unsigned char desc[4] = {0 };
switch (val) {
case ENCLOSURE_SETTING_DISABLED:
@@ -409,11 +412,11 @@ static int ses_intf_add(struct class_device *cdev,
{
struct scsi_device *sdev = to_scsi_device(cdev->dev);
struct scsi_device *tmp_sdev;
- unsigned char *buf = NULL, *hdr_buf, *type_ptr, *desc_ptr,
- *addl_desc_ptr;
+ unsigned char *buf = NULL, *hdr_buf, *type_ptr, *desc_ptr = NULL,
+ *addl_desc_ptr = NULL;
struct ses_device *ses_dev;
u32 result;
- int i, j, types, len, components = 0;
+ int i, j, types, len, page7_len = 0, components = 0;
int err = -ENOMEM;
struct enclosure_device *edev;
struct ses_component *scomp = NULL;
@@ -447,7 +450,7 @@ static int ses_intf_add(struct class_device *cdev,
* traversal routines more complex */
sdev_printk(KERN_ERR, sdev,
"FIXME driver has no support for subenclosures (%d)\n",
- buf[1]);
+ hdr_buf[1]);
goto err_free;
}
@@ -461,9 +464,8 @@ static int ses_intf_add(struct class_device *cdev,
goto recv_failed;
types = buf[10];
- len = buf[11];
- type_ptr = buf + 12 + len;
+ type_ptr = buf + 12 + buf[11];
for (i = 0; i < types; i++, type_ptr += 4) {
if (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE ||
@@ -494,22 +496,21 @@ static int ses_intf_add(struct class_device *cdev,
/* The additional information page --- allows us
* to match up the devices */
result = ses_recv_diag(sdev, 10, hdr_buf, INIT_ALLOC_SIZE);
- if (result)
- goto no_page10;
-
- len = (hdr_buf[2] << 8) + hdr_buf[3] + 4;
- buf = kzalloc(len, GFP_KERNEL);
- if (!buf)
- goto err_free;
-
- result = ses_recv_diag(sdev, 10, buf, len);
- if (result)
- goto recv_failed;
- ses_dev->page10 = buf;
- ses_dev->page10_len = len;
- buf = NULL;
+ if (!result) {
+
+ len = (hdr_buf[2] << 8) + hdr_buf[3] + 4;
+ buf = kzalloc(len, GFP_KERNEL);
+ if (!buf)
+ goto err_free;
+
+ result = ses_recv_diag(sdev, 10, buf, len);
+ if (result)
+ goto recv_failed;
+ ses_dev->page10 = buf;
+ ses_dev->page10_len = len;
+ buf = NULL;
+ }
- no_page10:
scomp = kzalloc(sizeof(struct ses_component) * components, GFP_KERNEL);
if (!scomp)
goto err_free;
@@ -530,7 +531,7 @@ static int ses_intf_add(struct class_device *cdev,
if (result)
goto simple_populate;
- len = (hdr_buf[2] << 8) + hdr_buf[3] + 4;
+ page7_len = len = (hdr_buf[2] << 8) + hdr_buf[3] + 4;
/* add 1 for trailing '\0' we'll use */
buf = kzalloc(len + 1, GFP_KERNEL);
if (!buf)
@@ -547,7 +548,8 @@ static int ses_intf_add(struct class_device *cdev,
len = (desc_ptr[2] << 8) + desc_ptr[3];
/* skip past overall descriptor */
desc_ptr += len + 4;
- addl_desc_ptr = ses_dev->page10 + 8;
+ if (ses_dev->page10)
+ addl_desc_ptr = ses_dev->page10 + 8;
}
type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11];
components = 0;
@@ -557,29 +559,35 @@ static int ses_intf_add(struct class_device *cdev,
struct enclosure_component *ecomp;
if (desc_ptr) {
- len = (desc_ptr[2] << 8) + desc_ptr[3];
- desc_ptr += 4;
- /* Add trailing zero - pushes into
- * reserved space */
- desc_ptr[len] = '\0';
- name = desc_ptr;
+ if (desc_ptr >= buf + page7_len) {
+ desc_ptr = NULL;
+ } else {
+ len = (desc_ptr[2] << 8) + desc_ptr[3];
+ desc_ptr += 4;
+ /* Add trailing zero - pushes into
+ * reserved space */
+ desc_ptr[len] = '\0';
+ name = desc_ptr;
+ }
}
- if (type_ptr[0] != ENCLOSURE_COMPONENT_DEVICE &&
- type_ptr[0] != ENCLOSURE_COMPONENT_ARRAY_DEVICE)
- continue;
- ecomp = enclosure_component_register(edev,
+ if (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE ||
+ type_ptr[0] == ENCLOSURE_COMPONENT_ARRAY_DEVICE) {
+
+ ecomp = enclosure_component_register(edev,
components++,
type_ptr[0],
name);
- if (desc_ptr) {
- desc_ptr += len;
- if (!IS_ERR(ecomp))
+
+ if (!IS_ERR(ecomp) && addl_desc_ptr)
ses_process_descriptor(ecomp,
addl_desc_ptr);
-
- if (addl_desc_ptr)
- addl_desc_ptr += addl_desc_ptr[1] + 2;
}
+ if (desc_ptr)
+ desc_ptr += len;
+
+ if (addl_desc_ptr)
+ addl_desc_ptr += addl_desc_ptr[1] + 2;
+
}
}
kfree(buf);
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 71952703125..0a52d9d2da2 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -17,7 +17,7 @@
Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
*/
-static const char *verstr = "20080117";
+static const char *verstr = "20080221";
#include <linux/module.h>
@@ -1172,7 +1172,7 @@ static int st_open(struct inode *inode, struct file *filp)
STp->try_dio_now = STp->try_dio;
STp->recover_count = 0;
DEB( STp->nbr_waits = STp->nbr_finished = 0;
- STp->nbr_requests = STp->nbr_dio = STp->nbr_pages = STp->nbr_combinable = 0; )
+ STp->nbr_requests = STp->nbr_dio = STp->nbr_pages = 0; )
retval = check_tape(STp, filp);
if (retval < 0)
@@ -1226,8 +1226,8 @@ static int st_flush(struct file *filp, fl_owner_t id)
}
DEBC( if (STp->nbr_requests)
- printk(KERN_DEBUG "%s: Number of r/w requests %d, dio used in %d, pages %d (%d).\n",
- name, STp->nbr_requests, STp->nbr_dio, STp->nbr_pages, STp->nbr_combinable));
+ printk(KERN_DEBUG "%s: Number of r/w requests %d, dio used in %d, pages %d.\n",
+ name, STp->nbr_requests, STp->nbr_dio, STp->nbr_pages));
if (STps->rw == ST_WRITING && !STp->pos_unknown) {
struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
@@ -1422,9 +1422,6 @@ static int setup_buffering(struct scsi_tape *STp, const char __user *buf,
if (STbp->do_dio) {
STp->nbr_dio++;
STp->nbr_pages += STbp->do_dio;
- for (i=1; i < STbp->do_dio; i++)
- if (page_to_pfn(STbp->sg[i].page) == page_to_pfn(STbp->sg[i-1].page) + 1)
- STp->nbr_combinable++;
}
)
} else
diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h
index 6c807571297..5931726fcf9 100644
--- a/drivers/scsi/st.h
+++ b/drivers/scsi/st.h
@@ -164,7 +164,6 @@ struct scsi_tape {
int nbr_requests;
int nbr_dio;
int nbr_pages;
- int nbr_combinable;
unsigned char last_cmnd[6];
unsigned char last_sense[16];
#endif
diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c
index 72f6d801535..654430edf74 100644
--- a/drivers/scsi/stex.c
+++ b/drivers/scsi/stex.c
@@ -461,30 +461,14 @@ static void stex_internal_copy(struct scsi_cmnd *cmd,
}
}
-static int stex_direct_copy(struct scsi_cmnd *cmd,
- const void *src, size_t count)
-{
- size_t cp_len = count;
- int n_elem = 0;
-
- n_elem = scsi_dma_map(cmd);
- if (n_elem < 0)
- return 0;
-
- stex_internal_copy(cmd, src, &cp_len, n_elem, ST_TO_CMD);
-
- scsi_dma_unmap(cmd);
-
- return cp_len == count;
-}
-
static void stex_controller_info(struct st_hba *hba, struct st_ccb *ccb)
{
struct st_frame *p;
size_t count = sizeof(struct st_frame);
p = hba->copy_buffer;
- stex_internal_copy(ccb->cmd, p, &count, ccb->sg_count, ST_FROM_CMD);
+ stex_internal_copy(ccb->cmd, p, &count, scsi_sg_count(ccb->cmd),
+ ST_FROM_CMD);
memset(p->base, 0, sizeof(u32)*6);
*(unsigned long *)(p->base) = pci_resource_start(hba->pdev, 0);
p->rom_addr = 0;
@@ -502,7 +486,8 @@ static void stex_controller_info(struct st_hba *hba, struct st_ccb *ccb)
p->subid =
hba->pdev->subsystem_vendor << 16 | hba->pdev->subsystem_device;
- stex_internal_copy(ccb->cmd, p, &count, ccb->sg_count, ST_TO_CMD);
+ stex_internal_copy(ccb->cmd, p, &count, scsi_sg_count(ccb->cmd),
+ ST_TO_CMD);
}
static void
@@ -569,8 +554,10 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
unsigned char page;
page = cmd->cmnd[2] & 0x3f;
if (page == 0x8 || page == 0x3f) {
- stex_direct_copy(cmd, ms10_caching_page,
- sizeof(ms10_caching_page));
+ size_t cp_len = sizeof(ms10_caching_page);
+ stex_internal_copy(cmd, ms10_caching_page,
+ &cp_len, scsi_sg_count(cmd),
+ ST_TO_CMD);
cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
done(cmd);
} else
@@ -599,8 +586,10 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
if (id != host->max_id - 1)
break;
if (lun == 0 && (cmd->cmnd[1] & INQUIRY_EVPD) == 0) {
- stex_direct_copy(cmd, console_inq_page,
- sizeof(console_inq_page));
+ size_t cp_len = sizeof(console_inq_page);
+ stex_internal_copy(cmd, console_inq_page,
+ &cp_len, scsi_sg_count(cmd),
+ ST_TO_CMD);
cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
done(cmd);
} else
@@ -609,6 +598,7 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
case PASSTHRU_CMD:
if (cmd->cmnd[1] == PASSTHRU_GET_DRVVER) {
struct st_drvver ver;
+ size_t cp_len = sizeof(ver);
ver.major = ST_VER_MAJOR;
ver.minor = ST_VER_MINOR;
ver.oem = ST_OEM;
@@ -616,7 +606,9 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
ver.signature[0] = PASSTHRU_SIGNATURE;
ver.console_id = host->max_id - 1;
ver.host_no = hba->host->host_no;
- cmd->result = stex_direct_copy(cmd, &ver, sizeof(ver)) ?
+ stex_internal_copy(cmd, &ver, &cp_len,
+ scsi_sg_count(cmd), ST_TO_CMD);
+ cmd->result = sizeof(ver) == cp_len ?
DID_OK << 16 | COMMAND_COMPLETE << 8 :
DID_ERROR << 16 | COMMAND_COMPLETE << 8;
done(cmd);
@@ -709,7 +701,7 @@ static void stex_copy_data(struct st_ccb *ccb,
if (ccb->cmd == NULL)
return;
stex_internal_copy(ccb->cmd,
- resp->variable, &count, ccb->sg_count, ST_TO_CMD);
+ resp->variable, &count, scsi_sg_count(ccb->cmd), ST_TO_CMD);
}
static void stex_ys_commands(struct st_hba *hba,
@@ -734,7 +726,7 @@ static void stex_ys_commands(struct st_hba *hba,
count = STEX_EXTRA_SIZE;
stex_internal_copy(ccb->cmd, hba->copy_buffer,
- &count, ccb->sg_count, ST_FROM_CMD);
+ &count, scsi_sg_count(ccb->cmd), ST_FROM_CMD);
inq_data = (ST_INQ *)hba->copy_buffer;
if (inq_data->DeviceTypeQualifier != 0)
ccb->srb_status = SRB_STATUS_SELECTION_TIMEOUT;
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index b82595cf13e..cf627cd1b4c 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -686,7 +686,7 @@ config UART0_RTS_PIN
config SERIAL_BFIN_UART1
bool "Enable UART1"
- depends on SERIAL_BFIN && (BF534 || BF536 || BF537 || BF54x)
+ depends on SERIAL_BFIN && (!BF531 && !BF532 && !BF533 && !BF561)
help
Enable UART1
@@ -699,14 +699,14 @@ config BFIN_UART1_CTSRTS
config UART1_CTS_PIN
int "UART1 CTS pin"
- depends on BFIN_UART1_CTSRTS && (BF53x || BF561)
+ depends on BFIN_UART1_CTSRTS && !BF54x
default -1
help
Refer to ./include/asm-blackfin/gpio.h to see the GPIO map.
config UART1_RTS_PIN
int "UART1 RTS pin"
- depends on BFIN_UART1_CTSRTS && (BF53x || BF561)
+ depends on BFIN_UART1_CTSRTS && !BF54x
default -1
help
Refer to ./include/asm-blackfin/gpio.h to see the GPIO map.
diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c
index fad245b064d..d57bf3e708d 100644
--- a/drivers/serial/atmel_serial.c
+++ b/drivers/serial/atmel_serial.c
@@ -549,7 +549,7 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id)
atmel_handle_transmit(port, pending);
} while (pass_counter++ < ATMEL_ISR_PASS_LIMIT);
- return IRQ_HANDLED;
+ return pass_counter ? IRQ_HANDLED : IRQ_NONE;
}
/*
diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
index ac2a3ef28d5..0aa345b9a38 100644
--- a/drivers/serial/bfin_5xx.c
+++ b/drivers/serial/bfin_5xx.c
@@ -1,30 +1,11 @@
/*
- * File: drivers/serial/bfin_5xx.c
- * Based on: Based on drivers/serial/sa1100.c
- * Author: Aubrey Li <aubrey.li@analog.com>
+ * Blackfin On-Chip Serial Driver
*
- * Created:
- * Description: Driver for blackfin 5xx serial ports
+ * Copyright 2006-2007 Analog Devices Inc.
*
- * Modified:
- * Copyright 2006 Analog Devices Inc.
+ * Enter bugs at http://blackfin.uclinux.org/
*
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#if defined(CONFIG_SERIAL_BFIN_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
@@ -67,14 +48,12 @@
#define DMA_RX_XCOUNT 512
#define DMA_RX_YCOUNT (PAGE_SIZE / DMA_RX_XCOUNT)
-#define DMA_RX_FLUSH_JIFFIES 5
+#define DMA_RX_FLUSH_JIFFIES (HZ / 50)
#ifdef CONFIG_SERIAL_BFIN_DMA
static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart);
#else
-static void bfin_serial_do_work(struct work_struct *work);
static void bfin_serial_tx_chars(struct bfin_serial_port *uart);
-static void local_put_char(struct bfin_serial_port *uart, char ch);
#endif
static void bfin_serial_mctrl_check(struct bfin_serial_port *uart);
@@ -85,23 +64,26 @@ static void bfin_serial_mctrl_check(struct bfin_serial_port *uart);
static void bfin_serial_stop_tx(struct uart_port *port)
{
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+ struct circ_buf *xmit = &uart->port.info->xmit;
+#if !defined(CONFIG_BF54x) && !defined(CONFIG_SERIAL_BFIN_DMA)
+ unsigned short ier;
+#endif
while (!(UART_GET_LSR(uart) & TEMT))
- continue;
+ cpu_relax();
#ifdef CONFIG_SERIAL_BFIN_DMA
disable_dma(uart->tx_dma_channel);
+ xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
+ uart->port.icount.tx += uart->tx_count;
+ uart->tx_count = 0;
+ uart->tx_done = 1;
#else
#ifdef CONFIG_BF54x
- /* Waiting for Transmission Finished */
- while (!(UART_GET_LSR(uart) & TFI))
- continue;
/* Clear TFI bit */
UART_PUT_LSR(uart, TFI);
UART_CLEAR_IER(uart, ETBEI);
#else
- unsigned short ier;
-
ier = UART_GET_IER(uart);
ier &= ~ETBEI;
UART_PUT_IER(uart, ier);
@@ -117,7 +99,8 @@ static void bfin_serial_start_tx(struct uart_port *port)
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
#ifdef CONFIG_SERIAL_BFIN_DMA
- bfin_serial_dma_tx_chars(uart);
+ if (uart->tx_done)
+ bfin_serial_dma_tx_chars(uart);
#else
#ifdef CONFIG_BF54x
UART_SET_IER(uart, ETBEI);
@@ -209,34 +192,27 @@ int kgdb_get_debug_char(void)
}
#endif
-#ifdef CONFIG_SERIAL_BFIN_PIO
-static void local_put_char(struct bfin_serial_port *uart, char ch)
-{
- unsigned short status;
- int flags = 0;
-
- spin_lock_irqsave(&uart->port.lock, flags);
-
- do {
- status = UART_GET_LSR(uart);
- } while (!(status & THRE));
-
- UART_PUT_CHAR(uart, ch);
- SSYNC();
-
- spin_unlock_irqrestore(&uart->port.lock, flags);
-}
+#if ANOMALY_05000230 && defined(CONFIG_SERIAL_BFIN_PIO)
+# define UART_GET_ANOMALY_THRESHOLD(uart) ((uart)->anomaly_threshold)
+# define UART_SET_ANOMALY_THRESHOLD(uart, v) ((uart)->anomaly_threshold = (v))
+#else
+# define UART_GET_ANOMALY_THRESHOLD(uart) 0
+# define UART_SET_ANOMALY_THRESHOLD(uart, v)
+#endif
+#ifdef CONFIG_SERIAL_BFIN_PIO
static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
{
struct tty_struct *tty = uart->port.info->tty;
unsigned int status, ch, flg;
- static int in_break = 0;
+ static struct timeval anomaly_start = { .tv_sec = 0 };
#ifdef CONFIG_KGDB_UART
struct pt_regs *regs = get_irq_regs();
#endif
status = UART_GET_LSR(uart);
+ UART_CLEAR_LSR(uart);
+
ch = UART_GET_CHAR(uart);
uart->port.icount.rx++;
@@ -262,28 +238,56 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
#endif
if (ANOMALY_05000230) {
- /* The BF533 family of processors have a nice misbehavior where
- * they continuously generate characters for a "single" break.
+ /* The BF533 (and BF561) family of processors have a nice anomaly
+ * where they continuously generate characters for a "single" break.
* We have to basically ignore this flood until the "next" valid
- * character comes across. All other Blackfin families operate
- * properly though.
+ * character comes across. Due to the nature of the flood, it is
+ * not possible to reliably catch bytes that are sent too quickly
+ * after this break. So application code talking to the Blackfin
+ * which sends a break signal must allow at least 1.5 character
+ * times after the end of the break for things to stabilize. This
+ * timeout was picked as it must absolutely be larger than 1
+ * character time +/- some percent. So 1.5 sounds good. All other
+ * Blackfin families operate properly. Woo.
* Note: While Anomaly 05000230 does not directly address this,
* the changes that went in for it also fixed this issue.
+ * That anomaly was fixed in 0.5+ silicon. I like bunnies.
*/
- if (in_break) {
- if (ch != 0) {
- in_break = 0;
- ch = UART_GET_CHAR(uart);
- if (bfin_revid() < 5)
- return;
- } else
- return;
+ if (anomaly_start.tv_sec) {
+ struct timeval curr;
+ suseconds_t usecs;
+
+ if ((~ch & (~ch + 1)) & 0xff)
+ goto known_good_char;
+
+ do_gettimeofday(&curr);
+ if (curr.tv_sec - anomaly_start.tv_sec > 1)
+ goto known_good_char;
+
+ usecs = 0;
+ if (curr.tv_sec != anomaly_start.tv_sec)
+ usecs += USEC_PER_SEC;
+ usecs += curr.tv_usec - anomaly_start.tv_usec;
+
+ if (usecs > UART_GET_ANOMALY_THRESHOLD(uart))
+ goto known_good_char;
+
+ if (ch)
+ anomaly_start.tv_sec = 0;
+ else
+ anomaly_start = curr;
+
+ return;
+
+ known_good_char:
+ anomaly_start.tv_sec = 0;
}
}
if (status & BI) {
if (ANOMALY_05000230)
- in_break = 1;
+ if (bfin_revid() < 5)
+ do_gettimeofday(&anomaly_start);
uart->port.icount.brk++;
if (uart_handle_break(&uart->port))
goto ignore_char;
@@ -324,7 +328,6 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
UART_PUT_CHAR(uart, uart->port.x_char);
uart->port.icount.tx++;
uart->port.x_char = 0;
- return;
}
/*
* Check the modem control lines before
@@ -337,9 +340,12 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
return;
}
- local_put_char(uart, xmit->buf[xmit->tail]);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- uart->port.icount.tx++;
+ while ((UART_GET_LSR(uart) & THRE) && xmit->tail != xmit->head) {
+ UART_PUT_CHAR(uart, xmit->buf[xmit->tail]);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ uart->port.icount.tx++;
+ SSYNC();
+ }
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&uart->port);
@@ -352,21 +358,11 @@ static irqreturn_t bfin_serial_rx_int(int irq, void *dev_id)
{
struct bfin_serial_port *uart = dev_id;
-#ifdef CONFIG_BF54x
- unsigned short status;
- spin_lock(&uart->port.lock);
- status = UART_GET_LSR(uart);
- while ((UART_GET_IER(uart) & ERBFI) && (status & DR)) {
- bfin_serial_rx_chars(uart);
- status = UART_GET_LSR(uart);
- }
- spin_unlock(&uart->port.lock);
-#else
spin_lock(&uart->port.lock);
- while ((UART_GET_IIR(uart) & IIR_STATUS) == IIR_RX_READY)
+ while (UART_GET_LSR(uart) & DR)
bfin_serial_rx_chars(uart);
spin_unlock(&uart->port.lock);
-#endif
+
return IRQ_HANDLED;
}
@@ -374,25 +370,16 @@ static irqreturn_t bfin_serial_tx_int(int irq, void *dev_id)
{
struct bfin_serial_port *uart = dev_id;
-#ifdef CONFIG_BF54x
- unsigned short status;
spin_lock(&uart->port.lock);
- status = UART_GET_LSR(uart);
- while ((UART_GET_IER(uart) & ETBEI) && (status & THRE)) {
+ if (UART_GET_LSR(uart) & THRE)
bfin_serial_tx_chars(uart);
- status = UART_GET_LSR(uart);
- }
spin_unlock(&uart->port.lock);
-#else
- spin_lock(&uart->port.lock);
- while ((UART_GET_IIR(uart) & IIR_STATUS) == IIR_TX_READY)
- bfin_serial_tx_chars(uart);
- spin_unlock(&uart->port.lock);
-#endif
+
return IRQ_HANDLED;
}
+#endif
-
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
static void bfin_serial_do_work(struct work_struct *work)
{
struct bfin_serial_port *uart = container_of(work, struct bfin_serial_port, cts_workqueue);
@@ -406,33 +393,27 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)
{
struct circ_buf *xmit = &uart->port.info->xmit;
unsigned short ier;
- int flags = 0;
-
- if (!uart->tx_done)
- return;
uart->tx_done = 0;
+ if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
+ uart->tx_count = 0;
+ uart->tx_done = 1;
+ return;
+ }
+
if (uart->port.x_char) {
UART_PUT_CHAR(uart, uart->port.x_char);
uart->port.icount.tx++;
uart->port.x_char = 0;
- uart->tx_done = 1;
- return;
}
+
/*
* Check the modem control lines before
* transmitting anything.
*/
bfin_serial_mctrl_check(uart);
- if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
- bfin_serial_stop_tx(&uart->port);
- uart->tx_done = 1;
- return;
- }
-
- spin_lock_irqsave(&uart->port.lock, flags);
uart->tx_count = CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE);
if (uart->tx_count > (UART_XMIT_SIZE - xmit->tail))
uart->tx_count = UART_XMIT_SIZE - xmit->tail;
@@ -448,6 +429,7 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)
set_dma_x_count(uart->tx_dma_channel, uart->tx_count);
set_dma_x_modify(uart->tx_dma_channel, 1);
enable_dma(uart->tx_dma_channel);
+
#ifdef CONFIG_BF54x
UART_SET_IER(uart, ETBEI);
#else
@@ -455,7 +437,6 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)
ier |= ETBEI;
UART_PUT_IER(uart, ier);
#endif
- spin_unlock_irqrestore(&uart->port.lock, flags);
}
static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart)
@@ -464,7 +445,11 @@ static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart)
int i, flg, status;
status = UART_GET_LSR(uart);
- uart->port.icount.rx += CIRC_CNT(uart->rx_dma_buf.head, uart->rx_dma_buf.tail, UART_XMIT_SIZE);;
+ UART_CLEAR_LSR(uart);
+
+ uart->port.icount.rx +=
+ CIRC_CNT(uart->rx_dma_buf.head, uart->rx_dma_buf.tail,
+ UART_XMIT_SIZE);
if (status & BI) {
uart->port.icount.brk++;
@@ -490,10 +475,12 @@ static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart)
else
flg = TTY_NORMAL;
- for (i = uart->rx_dma_buf.head; i < uart->rx_dma_buf.tail; i++) {
- if (uart_handle_sysrq_char(&uart->port, uart->rx_dma_buf.buf[i]))
- goto dma_ignore_char;
- uart_insert_char(&uart->port, status, OE, uart->rx_dma_buf.buf[i], flg);
+ for (i = uart->rx_dma_buf.tail; i != uart->rx_dma_buf.head; i++) {
+ if (i >= UART_XMIT_SIZE)
+ i = 0;
+ if (!uart_handle_sysrq_char(&uart->port, uart->rx_dma_buf.buf[i]))
+ uart_insert_char(&uart->port, status, OE,
+ uart->rx_dma_buf.buf[i], flg);
}
dma_ignore_char:
@@ -503,23 +490,23 @@ static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart)
void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart)
{
int x_pos, pos;
- int flags = 0;
-
- bfin_serial_dma_tx_chars(uart);
- spin_lock_irqsave(&uart->port.lock, flags);
- x_pos = DMA_RX_XCOUNT - get_dma_curr_xcount(uart->rx_dma_channel);
+ uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel);
+ x_pos = get_dma_curr_xcount(uart->rx_dma_channel);
+ uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows;
+ if (uart->rx_dma_nrows == DMA_RX_YCOUNT)
+ uart->rx_dma_nrows = 0;
+ x_pos = DMA_RX_XCOUNT - x_pos;
if (x_pos == DMA_RX_XCOUNT)
x_pos = 0;
pos = uart->rx_dma_nrows * DMA_RX_XCOUNT + x_pos;
-
- if (pos>uart->rx_dma_buf.tail) {
- uart->rx_dma_buf.tail = pos;
+ if (pos != uart->rx_dma_buf.tail) {
+ uart->rx_dma_buf.head = pos;
bfin_serial_dma_rx_chars(uart);
- uart->rx_dma_buf.head = uart->rx_dma_buf.tail;
+ uart->rx_dma_buf.tail = uart->rx_dma_buf.head;
}
- spin_unlock_irqrestore(&uart->port.lock, flags);
+
uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES;
add_timer(&(uart->rx_dma_timer));
}
@@ -532,8 +519,8 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)
spin_lock(&uart->port.lock);
if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) {
- clear_dma_irqstat(uart->tx_dma_channel);
disable_dma(uart->tx_dma_channel);
+ clear_dma_irqstat(uart->tx_dma_channel);
#ifdef CONFIG_BF54x
UART_CLEAR_IER(uart, ETBEI);
#else
@@ -541,15 +528,13 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)
ier &= ~ETBEI;
UART_PUT_IER(uart, ier);
#endif
- xmit->tail = (xmit->tail+uart->tx_count) &(UART_XMIT_SIZE -1);
- uart->port.icount.tx+=uart->tx_count;
+ xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
+ uart->port.icount.tx += uart->tx_count;
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&uart->port);
- if (uart_circ_empty(xmit))
- bfin_serial_stop_tx(&uart->port);
- uart->tx_done = 1;
+ bfin_serial_dma_tx_chars(uart);
}
spin_unlock(&uart->port.lock);
@@ -561,18 +546,15 @@ static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id)
struct bfin_serial_port *uart = dev_id;
unsigned short irqstat;
- uart->rx_dma_nrows++;
- if (uart->rx_dma_nrows == DMA_RX_YCOUNT) {
- uart->rx_dma_nrows = 0;
- uart->rx_dma_buf.tail = DMA_RX_XCOUNT*DMA_RX_YCOUNT;
- bfin_serial_dma_rx_chars(uart);
- uart->rx_dma_buf.head = uart->rx_dma_buf.tail = 0;
- }
spin_lock(&uart->port.lock);
irqstat = get_dma_curr_irqstat(uart->rx_dma_channel);
clear_dma_irqstat(uart->rx_dma_channel);
-
spin_unlock(&uart->port.lock);
+
+ del_timer(&(uart->rx_dma_timer));
+ uart->rx_dma_timer.expires = jiffies;
+ add_timer(&(uart->rx_dma_timer));
+
return IRQ_HANDLED;
}
#endif
@@ -599,7 +581,11 @@ static unsigned int bfin_serial_get_mctrl(struct uart_port *port)
if (uart->cts_pin < 0)
return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+# ifdef BF54x
+ if (UART_GET_MSR(uart) & CTS)
+# else
if (gpio_get_value(uart->cts_pin))
+# endif
return TIOCM_DSR | TIOCM_CAR;
else
#endif
@@ -614,9 +600,17 @@ static void bfin_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
return;
if (mctrl & TIOCM_RTS)
+# ifdef BF54x
+ UART_PUT_MCR(uart, UART_GET_MCR(uart) & ~MRTS);
+# else
gpio_set_value(uart->rts_pin, 0);
+# endif
else
+# ifdef BF54x
+ UART_PUT_MCR(uart, UART_GET_MCR(uart) | MRTS);
+# else
gpio_set_value(uart->rts_pin, 1);
+# endif
#endif
}
@@ -627,22 +621,17 @@ static void bfin_serial_mctrl_check(struct bfin_serial_port *uart)
{
#ifdef CONFIG_SERIAL_BFIN_CTSRTS
unsigned int status;
-# ifdef CONFIG_SERIAL_BFIN_DMA
struct uart_info *info = uart->port.info;
struct tty_struct *tty = info->tty;
status = bfin_serial_get_mctrl(&uart->port);
+ uart_handle_cts_change(&uart->port, status & TIOCM_CTS);
if (!(status & TIOCM_CTS)) {
tty->hw_stopped = 1;
+ schedule_work(&uart->cts_workqueue);
} else {
tty->hw_stopped = 0;
}
-# else
- status = bfin_serial_get_mctrl(&uart->port);
- uart_handle_cts_change(&uart->port, status & TIOCM_CTS);
- if (!(status & TIOCM_CTS))
- schedule_work(&uart->cts_workqueue);
-# endif
#endif
}
@@ -743,6 +732,7 @@ static void bfin_serial_shutdown(struct uart_port *port)
disable_dma(uart->rx_dma_channel);
free_dma(uart->rx_dma_channel);
del_timer(&(uart->rx_dma_timer));
+ dma_free_coherent(NULL, PAGE_SIZE, uart->rx_dma_buf.buf, 0);
#else
#ifdef CONFIG_KGDB_UART
if (uart->port.line != CONFIG_KGDB_UART_PORT)
@@ -814,6 +804,8 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
quot = uart_get_divisor(port, baud);
spin_lock_irqsave(&uart->port.lock, flags);
+ UART_SET_ANOMALY_THRESHOLD(uart, USEC_PER_SEC / baud * 15);
+
do {
lsr = UART_GET_LSR(uart);
} while (!(lsr & TEMT));
@@ -956,10 +948,9 @@ static void __init bfin_serial_init_ports(void)
bfin_serial_ports[i].rx_dma_channel =
bfin_serial_resource[i].uart_rx_dma_channel;
init_timer(&(bfin_serial_ports[i].rx_dma_timer));
-#else
- INIT_WORK(&bfin_serial_ports[i].cts_workqueue, bfin_serial_do_work);
#endif
#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+ INIT_WORK(&bfin_serial_ports[i].cts_workqueue, bfin_serial_do_work);
bfin_serial_ports[i].cts_pin =
bfin_serial_resource[i].uart_cts_pin;
bfin_serial_ports[i].rts_pin =
diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c
index 9ce12cb2ceb..a8c116b80bf 100644
--- a/drivers/serial/sh-sci.c
+++ b/drivers/serial/sh-sci.c
@@ -41,6 +41,7 @@
#include <linux/delay.h>
#include <linux/console.h>
#include <linux/platform_device.h>
+#include <linux/serial_sci.h>
#ifdef CONFIG_CPU_FREQ
#include <linux/notifier.h>
@@ -54,7 +55,6 @@
#include <asm/kgdb.h>
#endif
-#include <asm/sci.h>
#include "sh-sci.h"
struct sci_port {
diff --git a/drivers/sh/maple/maple.c b/drivers/sh/maple/maple.c
index 9cfcfd8dad5..617efb1640b 100644
--- a/drivers/sh/maple/maple.c
+++ b/drivers/sh/maple/maple.c
@@ -1,7 +1,7 @@
/*
* Core maple bus functionality
*
- * Copyright (C) 2007 Adrian McMenamin
+ * Copyright (C) 2007, 2008 Adrian McMenamin
*
* Based on 2.4 code by:
*
@@ -18,7 +18,6 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/device.h>
-#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/io.h>
@@ -54,7 +53,7 @@ static struct device maple_bus;
static int subdevice_map[MAPLE_PORTS];
static unsigned long *maple_sendbuf, *maple_sendptr, *maple_lastptr;
static unsigned long maple_pnp_time;
-static int started, scanning, liststatus, realscan;
+static int started, scanning, liststatus, fullscan;
static struct kmem_cache *maple_queue_cache;
struct maple_device_specify {
@@ -62,6 +61,9 @@ struct maple_device_specify {
int unit;
};
+static bool checked[4];
+static struct maple_device *baseunits[4];
+
/**
* maple_driver_register - register a device driver
* automatically makes the driver bus a maple bus
@@ -309,11 +311,9 @@ static void maple_attach_driver(struct maple_device *mdev)
else
break;
- if (realscan) {
- printk(KERN_INFO "Maple device detected: %s\n",
- mdev->product_name);
- printk(KERN_INFO "Maple device: %s\n", mdev->product_licence);
- }
+ printk(KERN_INFO "Maple device detected: %s\n",
+ mdev->product_name);
+ printk(KERN_INFO "Maple device: %s\n", mdev->product_licence);
function = be32_to_cpu(mdev->devinfo.function);
@@ -323,10 +323,9 @@ static void maple_attach_driver(struct maple_device *mdev)
mdev->driver = &maple_dummy_driver;
sprintf(mdev->dev.bus_id, "%d:0.port", mdev->port);
} else {
- if (realscan)
- printk(KERN_INFO
- "Maple bus at (%d, %d): Function 0x%lX\n",
- mdev->port, mdev->unit, function);
+ printk(KERN_INFO
+ "Maple bus at (%d, %d): Function 0x%lX\n",
+ mdev->port, mdev->unit, function);
matched =
bus_for_each_drv(&maple_bus_type, NULL, mdev,
@@ -334,9 +333,8 @@ static void maple_attach_driver(struct maple_device *mdev)
if (matched == 0) {
/* Driver does not exist yet */
- if (realscan)
- printk(KERN_INFO
- "No maple driver found.\n");
+ printk(KERN_INFO
+ "No maple driver found.\n");
mdev->driver = &maple_dummy_driver;
}
sprintf(mdev->dev.bus_id, "%d:0%d.%lX", mdev->port,
@@ -472,9 +470,12 @@ static void maple_response_none(struct maple_device *mdev,
maple_detach_driver(mdev);
return;
}
- if (!started) {
- printk(KERN_INFO "No maple devices attached to port %d\n",
- mdev->port);
+ if (!started || !fullscan) {
+ if (checked[mdev->port] == false) {
+ checked[mdev->port] = true;
+ printk(KERN_INFO "No maple devices attached"
+ " to port %d\n", mdev->port);
+ }
return;
}
maple_clean_submap(mdev);
@@ -485,8 +486,14 @@ static void maple_response_devinfo(struct maple_device *mdev,
char *recvbuf)
{
char submask;
- if ((!started) || (scanning == 2)) {
- maple_attach_driver(mdev);
+ if (!started || (scanning == 2) || !fullscan) {
+ if ((mdev->unit == 0) && (checked[mdev->port] == false)) {
+ checked[mdev->port] = true;
+ maple_attach_driver(mdev);
+ } else {
+ if (mdev->unit != 0)
+ maple_attach_driver(mdev);
+ }
return;
}
if (mdev->unit == 0) {
@@ -505,6 +512,7 @@ static void maple_dma_handler(struct work_struct *work)
struct maple_device *dev;
char *recvbuf;
enum maple_code code;
+ int i;
if (!maple_dma_done())
return;
@@ -557,6 +565,19 @@ static void maple_dma_handler(struct work_struct *work)
} else
scanning = 0;
+ if (!fullscan) {
+ fullscan = 1;
+ for (i = 0; i < MAPLE_PORTS; i++) {
+ if (checked[i] == false) {
+ fullscan = 0;
+ dev = baseunits[i];
+ dev->mq->command =
+ MAPLE_COMMAND_DEVINFO;
+ dev->mq->length = 0;
+ maple_add_packet(dev->mq);
+ }
+ }
+ }
if (started == 0)
started = 1;
}
@@ -694,7 +715,9 @@ static int __init maple_bus_init(void)
/* setup maple ports */
for (i = 0; i < MAPLE_PORTS; i++) {
+ checked[i] = false;
mdev[i] = maple_alloc_dev(i, 0);
+ baseunits[i] = mdev[i];
if (!mdev[i]) {
while (i-- > 0)
maple_free_dev(mdev[i]);
@@ -703,12 +726,9 @@ static int __init maple_bus_init(void)
mdev[i]->mq->command = MAPLE_COMMAND_DEVINFO;
mdev[i]->mq->length = 0;
maple_add_packet(mdev[i]->mq);
- /* delay aids hardware detection */
- mdelay(5);
subdevice_map[i] = 0;
}
- realscan = 1;
/* setup maplebus hardware */
maplebus_dma_reset();
/* initial detection */
diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
index 293b7cab3e5..85687aaf9ca 100644
--- a/drivers/spi/atmel_spi.c
+++ b/drivers/spi/atmel_spi.c
@@ -87,6 +87,16 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi)
unsigned gpio = (unsigned) spi->controller_data;
unsigned active = spi->mode & SPI_CS_HIGH;
u32 mr;
+ int i;
+ u32 csr;
+ u32 cpol = (spi->mode & SPI_CPOL) ? SPI_BIT(CPOL) : 0;
+
+ /* Make sure clock polarity is correct */
+ for (i = 0; i < spi->master->num_chipselect; i++) {
+ csr = spi_readl(as, CSR0 + 4 * i);
+ if ((csr ^ cpol) & SPI_BIT(CPOL))
+ spi_writel(as, CSR0 + 4 * i, csr ^ SPI_BIT(CPOL));
+ }
mr = spi_readl(as, MR);
mr = SPI_BFINS(PCS, ~(1 << spi->chip_select), mr);
diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c
index 365e0e355ae..59deed79e0a 100644
--- a/drivers/spi/pxa2xx_spi.c
+++ b/drivers/spi/pxa2xx_spi.c
@@ -51,13 +51,19 @@ MODULE_LICENSE("GPL");
#define RESET_DMA_CHANNEL (DCSR_NODESC | DMA_INT_MASK)
#define IS_DMA_ALIGNED(x) (((u32)(x)&0x07)==0)
-/* for testing SSCR1 changes that require SSP restart, basically
- * everything except the service and interrupt enables */
-#define SSCR1_CHANGE_MASK (SSCR1_TTELP | SSCR1_TTE | SSCR1_EBCEI | SSCR1_SCFR \
+/*
+ * for testing SSCR1 changes that require SSP restart, basically
+ * everything except the service and interrupt enables, the pxa270 developer
+ * manual says only SSCR1_SCFR, SSCR1_SPH, SSCR1_SPO need to be in this
+ * list, but the PXA255 dev man says all bits without really meaning the
+ * service and interrupt enables
+ */
+#define SSCR1_CHANGE_MASK (SSCR1_TTELP | SSCR1_TTE | SSCR1_SCFR \
| SSCR1_ECRA | SSCR1_ECRB | SSCR1_SCLKDIR \
- | SSCR1_RWOT | SSCR1_TRAIL | SSCR1_PINTE \
- | SSCR1_STRF | SSCR1_EFWR |SSCR1_RFT \
- | SSCR1_TFT | SSCR1_SPH | SSCR1_SPO | SSCR1_LBM)
+ | SSCR1_SFRMDIR | SSCR1_RWOT | SSCR1_TRAIL \
+ | SSCR1_IFS | SSCR1_STRF | SSCR1_EFWR \
+ | SSCR1_RFT | SSCR1_TFT | SSCR1_MWDS \
+ | SSCR1_SPH | SSCR1_SPO | SSCR1_LBM)
#define DEFINE_SSP_REG(reg, off) \
static inline u32 read_##reg(void *p) { return __raw_readl(p + (off)); } \
@@ -973,9 +979,6 @@ static void pump_transfers(unsigned long data)
if (drv_data->ssp_type == PXA25x_SSP)
DCMD(drv_data->tx_channel) |= DCMD_ENDIRQEN;
- /* Fix me, need to handle cs polarity */
- drv_data->cs_control(PXA2XX_CS_ASSERT);
-
/* Clear status and start DMA engine */
cr1 = chip->cr1 | dma_thresh | drv_data->dma_cr1;
write_SSSR(drv_data->clear_sr, reg);
@@ -985,9 +988,6 @@ static void pump_transfers(unsigned long data)
/* Ensure we have the correct interrupt handler */
drv_data->transfer_handler = interrupt_transfer;
- /* Fix me, need to handle cs polarity */
- drv_data->cs_control(PXA2XX_CS_ASSERT);
-
/* Clear status */
cr1 = chip->cr1 | chip->threshold | drv_data->int_cr1;
write_SSSR(drv_data->clear_sr, reg);
@@ -998,16 +998,29 @@ static void pump_transfers(unsigned long data)
|| (read_SSCR1(reg) & SSCR1_CHANGE_MASK) !=
(cr1 & SSCR1_CHANGE_MASK)) {
+ /* stop the SSP, and update the other bits */
write_SSCR0(cr0 & ~SSCR0_SSE, reg);
if (drv_data->ssp_type != PXA25x_SSP)
write_SSTO(chip->timeout, reg);
- write_SSCR1(cr1, reg);
+ /* first set CR1 without interrupt and service enables */
+ write_SSCR1(cr1 & SSCR1_CHANGE_MASK, reg);
+ /* restart the SSP */
write_SSCR0(cr0, reg);
+
} else {
if (drv_data->ssp_type != PXA25x_SSP)
write_SSTO(chip->timeout, reg);
- write_SSCR1(cr1, reg);
}
+
+ /* FIXME, need to handle cs polarity,
+ * this driver uses struct pxa2xx_spi_chip.cs_control to
+ * specify a CS handling function, and it ignores most
+ * struct spi_device.mode[s], including SPI_CS_HIGH */
+ drv_data->cs_control(PXA2XX_CS_ASSERT);
+
+ /* after chip select, release the data by enabling service
+ * requests and interrupts, without changing any mode bits */
+ write_SSCR1(cr1, reg);
}
static void pump_messages(struct work_struct *work)
diff --git a/drivers/ssb/Kconfig b/drivers/ssb/Kconfig
index d976660cb7f..adea792fb67 100644
--- a/drivers/ssb/Kconfig
+++ b/drivers/ssb/Kconfig
@@ -35,6 +35,11 @@ config SSB_PCIHOST
If unsure, say Y
+config SSB_B43_PCI_BRIDGE
+ bool
+ depends on SSB_PCIHOST
+ default n
+
config SSB_PCMCIAHOST_POSSIBLE
bool
depends on SSB && (PCMCIA = y || PCMCIA = SSB) && EXPERIMENTAL
@@ -105,6 +110,12 @@ config SSB_DRIVER_MIPS
If unsure, say N
+# Assumption: We are on embedded, if we compile the MIPS core.
+config SSB_EMBEDDED
+ bool
+ depends on SSB_DRIVER_MIPS
+ default y
+
config SSB_DRIVER_EXTIF
bool "SSB Broadcom EXTIF core driver (EXPERIMENTAL)"
depends on SSB_DRIVER_MIPS && EXPERIMENTAL
diff --git a/drivers/ssb/Makefile b/drivers/ssb/Makefile
index 7be39759580..de94c2eb7a3 100644
--- a/drivers/ssb/Makefile
+++ b/drivers/ssb/Makefile
@@ -1,5 +1,6 @@
# core
ssb-y += main.o scan.o
+ssb-$(CONFIG_SSB_EMBEDDED) += embedded.o
# host support
ssb-$(CONFIG_SSB_PCIHOST) += pci.o pcihost_wrapper.o
@@ -13,6 +14,6 @@ ssb-$(CONFIG_SSB_DRIVER_PCICORE) += driver_pcicore.o
# b43 pci-ssb-bridge driver
# Not strictly a part of SSB, but kept here for convenience
-ssb-$(CONFIG_SSB_PCIHOST) += b43_pci_bridge.o
+ssb-$(CONFIG_SSB_B43_PCI_BRIDGE) += b43_pci_bridge.o
obj-$(CONFIG_SSB) += ssb.o
diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c
index 6fbf1c53b6f..e586321a473 100644
--- a/drivers/ssb/driver_chipcommon.c
+++ b/drivers/ssb/driver_chipcommon.c
@@ -39,12 +39,14 @@ static inline void chipco_write32(struct ssb_chipcommon *cc,
ssb_write32(cc->dev, offset, value);
}
-static inline void chipco_write32_masked(struct ssb_chipcommon *cc, u16 offset,
- u32 mask, u32 value)
+static inline u32 chipco_write32_masked(struct ssb_chipcommon *cc, u16 offset,
+ u32 mask, u32 value)
{
value &= mask;
value |= chipco_read32(cc, offset) & ~mask;
chipco_write32(cc, offset, value);
+
+ return value;
}
void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc,
@@ -356,14 +358,29 @@ u32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc, u32 mask)
return chipco_read32(cc, SSB_CHIPCO_GPIOIN) & mask;
}
-void ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value)
+u32 ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value)
+{
+ return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value);
+}
+
+u32 ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value)
+{
+ return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value);
+}
+
+u32 ssb_chipco_gpio_control(struct ssb_chipcommon *cc, u32 mask, u32 value)
+{
+ return chipco_write32_masked(cc, SSB_CHIPCO_GPIOCTL, mask, value);
+}
+
+u32 ssb_chipco_gpio_intmask(struct ssb_chipcommon *cc, u32 mask, u32 value)
{
- chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value);
+ return chipco_write32_masked(cc, SSB_CHIPCO_GPIOIRQ, mask, value);
}
-void ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value)
+u32 ssb_chipco_gpio_polarity(struct ssb_chipcommon *cc, u32 mask, u32 value)
{
- chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value);
+ return chipco_write32_masked(cc, SSB_CHIPCO_GPIOPOL, mask, value);
}
#ifdef CONFIG_SSB_SERIAL
@@ -376,6 +393,7 @@ int ssb_chipco_serial_init(struct ssb_chipcommon *cc,
unsigned int irq;
u32 baud_base, div;
u32 i, n;
+ unsigned int ccrev = cc->dev->id.revision;
plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT);
irq = ssb_mips_irq(cc->dev);
@@ -387,14 +405,39 @@ int ssb_chipco_serial_init(struct ssb_chipcommon *cc,
chipco_read32(cc, SSB_CHIPCO_CLOCK_M2));
div = 1;
} else {
- if (cc->dev->id.revision >= 11) {
+ if (ccrev == 20) {
+ /* BCM5354 uses constant 25MHz clock */
+ baud_base = 25000000;
+ div = 48;
+ /* Set the override bit so we don't divide it */
+ chipco_write32(cc, SSB_CHIPCO_CORECTL,
+ chipco_read32(cc, SSB_CHIPCO_CORECTL)
+ | SSB_CHIPCO_CORECTL_UARTCLK0);
+ } else if ((ccrev >= 11) && (ccrev != 15)) {
/* Fixed ALP clock */
baud_base = 20000000;
+ if (cc->capabilities & SSB_CHIPCO_CAP_PMU) {
+ /* FIXME: baud_base is different for devices with a PMU */
+ SSB_WARN_ON(1);
+ }
div = 1;
+ if (ccrev >= 21) {
+ /* Turn off UART clock before switching clocksource. */
+ chipco_write32(cc, SSB_CHIPCO_CORECTL,
+ chipco_read32(cc, SSB_CHIPCO_CORECTL)
+ & ~SSB_CHIPCO_CORECTL_UARTCLKEN);
+ }
/* Set the override bit so we don't divide it */
chipco_write32(cc, SSB_CHIPCO_CORECTL,
- SSB_CHIPCO_CORECTL_UARTCLK0);
- } else if (cc->dev->id.revision >= 3) {
+ chipco_read32(cc, SSB_CHIPCO_CORECTL)
+ | SSB_CHIPCO_CORECTL_UARTCLK0);
+ if (ccrev >= 21) {
+ /* Re-enable the UART clock. */
+ chipco_write32(cc, SSB_CHIPCO_CORECTL,
+ chipco_read32(cc, SSB_CHIPCO_CORECTL)
+ | SSB_CHIPCO_CORECTL_UARTCLKEN);
+ }
+ } else if (ccrev >= 3) {
/* Internal backplane clock */
baud_base = ssb_clockspeed(bus);
div = chipco_read32(cc, SSB_CHIPCO_CLKDIV)
@@ -406,7 +449,7 @@ int ssb_chipco_serial_init(struct ssb_chipcommon *cc,
}
/* Clock source depends on strapping if UartClkOverride is unset */
- if ((cc->dev->id.revision > 0) &&
+ if ((ccrev > 0) &&
!(chipco_read32(cc, SSB_CHIPCO_CORECTL) & SSB_CHIPCO_CORECTL_UARTCLK0)) {
if ((cc->capabilities & SSB_CHIPCO_CAP_UARTCLK) ==
SSB_CHIPCO_CAP_UARTCLK_INT) {
@@ -428,7 +471,7 @@ int ssb_chipco_serial_init(struct ssb_chipcommon *cc,
cc_mmio = cc->dev->bus->mmio + (cc->dev->core_index * SSB_CORE_SIZE);
uart_regs = cc_mmio + SSB_CHIPCO_UART0_DATA;
/* Offset changed at after rev 0 */
- if (cc->dev->id.revision == 0)
+ if (ccrev == 0)
uart_regs += (i * 8);
else
uart_regs += (i * 256);
diff --git a/drivers/ssb/driver_extif.c b/drivers/ssb/driver_extif.c
index fe55eb8b038..c3e1d3e6d61 100644
--- a/drivers/ssb/driver_extif.c
+++ b/drivers/ssb/driver_extif.c
@@ -27,12 +27,14 @@ static inline void extif_write32(struct ssb_extif *extif, u16 offset, u32 value)
ssb_write32(extif->dev, offset, value);
}
-static inline void extif_write32_masked(struct ssb_extif *extif, u16 offset,
- u32 mask, u32 value)
+static inline u32 extif_write32_masked(struct ssb_extif *extif, u16 offset,
+ u32 mask, u32 value)
{
value &= mask;
value |= extif_read32(extif, offset) & ~mask;
extif_write32(extif, offset, value);
+
+ return value;
}
#ifdef CONFIG_SSB_SERIAL
@@ -110,20 +112,35 @@ void ssb_extif_get_clockcontrol(struct ssb_extif *extif,
*m = extif_read32(extif, SSB_EXTIF_CLOCK_SB);
}
+void ssb_extif_watchdog_timer_set(struct ssb_extif *extif,
+ u32 ticks)
+{
+ extif_write32(extif, SSB_EXTIF_WATCHDOG, ticks);
+}
+
u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask)
{
return extif_read32(extif, SSB_EXTIF_GPIO_IN) & mask;
}
-void ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value)
+u32 ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value)
{
return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUT(0),
mask, value);
}
-void ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value)
+u32 ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value)
{
return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUTEN(0),
mask, value);
}
+u32 ssb_extif_gpio_polarity(struct ssb_extif *extif, u32 mask, u32 value)
+{
+ return extif_write32_masked(extif, SSB_EXTIF_GPIO_INTPOL, mask, value);
+}
+
+u32 ssb_extif_gpio_intmask(struct ssb_extif *extif, u32 mask, u32 value)
+{
+ return extif_write32_masked(extif, SSB_EXTIF_GPIO_INTMASK, mask, value);
+}
diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c
index 2faaa906d5d..07ab48d9cea 100644
--- a/drivers/ssb/driver_pcicore.c
+++ b/drivers/ssb/driver_pcicore.c
@@ -11,6 +11,7 @@
#include <linux/ssb/ssb.h>
#include <linux/pci.h>
#include <linux/delay.h>
+#include <linux/ssb/ssb_embedded.h>
#include "ssb_private.h"
@@ -27,6 +28,18 @@ void pcicore_write32(struct ssb_pcicore *pc, u16 offset, u32 value)
ssb_write32(pc->dev, offset, value);
}
+static inline
+u16 pcicore_read16(struct ssb_pcicore *pc, u16 offset)
+{
+ return ssb_read16(pc->dev, offset);
+}
+
+static inline
+void pcicore_write16(struct ssb_pcicore *pc, u16 offset, u16 value)
+{
+ ssb_write16(pc->dev, offset, value);
+}
+
/**************************************************
* Code for hostmode operation.
**************************************************/
@@ -66,6 +79,7 @@ int pcibios_plat_dev_init(struct pci_dev *d)
base = &ssb_pcicore_pcibus_iobase;
else
base = &ssb_pcicore_pcibus_membase;
+ res->flags |= IORESOURCE_PCI_FIXED;
if (res->end) {
size = res->end - res->start + 1;
if (*base & (size - 1))
@@ -88,10 +102,12 @@ int pcibios_plat_dev_init(struct pci_dev *d)
static void __init ssb_fixup_pcibridge(struct pci_dev *dev)
{
+ u8 lat;
+
if (dev->bus->number != 0 || PCI_SLOT(dev->devfn) != 0)
return;
- ssb_printk(KERN_INFO "PCI: fixing up bridge\n");
+ ssb_printk(KERN_INFO "PCI: Fixing up bridge %s\n", pci_name(dev));
/* Enable PCI bridge bus mastering and memory space */
pci_set_master(dev);
@@ -101,7 +117,10 @@ static void __init ssb_fixup_pcibridge(struct pci_dev *dev)
pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3);
/* Make sure our latency is high enough to handle the devices behind us */
- pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xa8);
+ lat = 168;
+ ssb_printk(KERN_INFO "PCI: Fixing latency timer of device %s to %u\n",
+ pci_name(dev), lat);
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
}
DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_fixup_pcibridge);
@@ -117,8 +136,10 @@ static u32 get_cfgspace_addr(struct ssb_pcicore *pc,
u32 addr = 0;
u32 tmp;
- if (unlikely(pc->cardbusmode && dev > 1))
+ /* We do only have one cardbus device behind the bridge. */
+ if (pc->cardbusmode && (dev >= 1))
goto out;
+
if (bus == 0) {
/* Type 0 transaction */
if (unlikely(dev >= SSB_PCI_SLOT_MAX))
@@ -279,14 +300,14 @@ static struct resource ssb_pcicore_mem_resource = {
.name = "SSB PCIcore external memory",
.start = SSB_PCI_DMA,
.end = SSB_PCI_DMA + SSB_PCI_DMA_SZ - 1,
- .flags = IORESOURCE_MEM,
+ .flags = IORESOURCE_MEM | IORESOURCE_PCI_FIXED,
};
static struct resource ssb_pcicore_io_resource = {
.name = "SSB PCIcore external I/O",
.start = 0x100,
.end = 0x7FF,
- .flags = IORESOURCE_IO,
+ .flags = IORESOURCE_IO | IORESOURCE_PCI_FIXED,
};
static struct pci_controller ssb_pcicore_controller = {
@@ -318,7 +339,16 @@ static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc)
pcicore_write32(pc, SSB_PCICORE_ARBCTL, val);
udelay(1); /* Assertion time demanded by the PCI standard */
- /*TODO cardbus mode */
+ if (pc->dev->bus->has_cardbus_slot) {
+ ssb_dprintk(KERN_INFO PFX "CardBus slot detected\n");
+ pc->cardbusmode = 1;
+ /* GPIO 1 resets the bridge */
+ ssb_gpio_out(pc->dev->bus, 1, 1);
+ ssb_gpio_outen(pc->dev->bus, 1, 1);
+ pcicore_write16(pc, SSB_PCICORE_SPROM(0),
+ pcicore_read16(pc, SSB_PCICORE_SPROM(0))
+ | 0x0400);
+ }
/* 64MB I/O window */
pcicore_write32(pc, SSB_PCICORE_SBTOPCI0,
@@ -344,7 +374,8 @@ static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc)
/* Ok, ready to run, register it to the system.
* The following needs change, if we want to port hostmode
* to non-MIPS platform. */
- set_io_port_base((unsigned long)ioremap_nocache(SSB_PCI_MEM, 0x04000000));
+ ssb_pcicore_controller.io_map_base = (unsigned long)ioremap_nocache(SSB_PCI_MEM, 0x04000000);
+ set_io_port_base(ssb_pcicore_controller.io_map_base);
/* Give some time to the PCI controller to configure itself with the new
* values. Not waiting at this point causes crashes of the machine. */
mdelay(10);
@@ -362,7 +393,7 @@ static int pcicore_is_in_hostmode(struct ssb_pcicore *pc)
chipid_top != 0x5300)
return 0;
- if (bus->sprom.r1.boardflags_lo & SSB_PCICORE_BFL_NOPCI)
+ if (bus->sprom.boardflags_lo & SSB_PCICORE_BFL_NOPCI)
return 0;
/* The 200-pin BCM4712 package does not bond out PCI. Even when
diff --git a/drivers/ssb/embedded.c b/drivers/ssb/embedded.c
new file mode 100644
index 00000000000..d3ade821555
--- /dev/null
+++ b/drivers/ssb/embedded.c
@@ -0,0 +1,132 @@
+/*
+ * Sonics Silicon Backplane
+ * Embedded systems support code
+ *
+ * Copyright 2005-2008, Broadcom Corporation
+ * Copyright 2006-2008, Michael Buesch <mb@bu3sch.de>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/ssb/ssb.h>
+#include <linux/ssb/ssb_embedded.h>
+
+#include "ssb_private.h"
+
+
+int ssb_watchdog_timer_set(struct ssb_bus *bus, u32 ticks)
+{
+ if (ssb_chipco_available(&bus->chipco)) {
+ ssb_chipco_watchdog_timer_set(&bus->chipco, ticks);
+ return 0;
+ }
+ if (ssb_extif_available(&bus->extif)) {
+ ssb_extif_watchdog_timer_set(&bus->extif, ticks);
+ return 0;
+ }
+ return -ENODEV;
+}
+
+u32 ssb_gpio_in(struct ssb_bus *bus, u32 mask)
+{
+ unsigned long flags;
+ u32 res = 0;
+
+ spin_lock_irqsave(&bus->gpio_lock, flags);
+ if (ssb_chipco_available(&bus->chipco))
+ res = ssb_chipco_gpio_in(&bus->chipco, mask);
+ else if (ssb_extif_available(&bus->extif))
+ res = ssb_extif_gpio_in(&bus->extif, mask);
+ else
+ SSB_WARN_ON(1);
+ spin_unlock_irqrestore(&bus->gpio_lock, flags);
+
+ return res;
+}
+EXPORT_SYMBOL(ssb_gpio_in);
+
+u32 ssb_gpio_out(struct ssb_bus *bus, u32 mask, u32 value)
+{
+ unsigned long flags;
+ u32 res = 0;
+
+ spin_lock_irqsave(&bus->gpio_lock, flags);
+ if (ssb_chipco_available(&bus->chipco))
+ res = ssb_chipco_gpio_out(&bus->chipco, mask, value);
+ else if (ssb_extif_available(&bus->extif))
+ res = ssb_extif_gpio_out(&bus->extif, mask, value);
+ else
+ SSB_WARN_ON(1);
+ spin_unlock_irqrestore(&bus->gpio_lock, flags);
+
+ return res;
+}
+EXPORT_SYMBOL(ssb_gpio_out);
+
+u32 ssb_gpio_outen(struct ssb_bus *bus, u32 mask, u32 value)
+{
+ unsigned long flags;
+ u32 res = 0;
+
+ spin_lock_irqsave(&bus->gpio_lock, flags);
+ if (ssb_chipco_available(&bus->chipco))
+ res = ssb_chipco_gpio_outen(&bus->chipco, mask, value);
+ else if (ssb_extif_available(&bus->extif))
+ res = ssb_extif_gpio_outen(&bus->extif, mask, value);
+ else
+ SSB_WARN_ON(1);
+ spin_unlock_irqrestore(&bus->gpio_lock, flags);
+
+ return res;
+}
+EXPORT_SYMBOL(ssb_gpio_outen);
+
+u32 ssb_gpio_control(struct ssb_bus *bus, u32 mask, u32 value)
+{
+ unsigned long flags;
+ u32 res = 0;
+
+ spin_lock_irqsave(&bus->gpio_lock, flags);
+ if (ssb_chipco_available(&bus->chipco))
+ res = ssb_chipco_gpio_control(&bus->chipco, mask, value);
+ spin_unlock_irqrestore(&bus->gpio_lock, flags);
+
+ return res;
+}
+EXPORT_SYMBOL(ssb_gpio_control);
+
+u32 ssb_gpio_intmask(struct ssb_bus *bus, u32 mask, u32 value)
+{
+ unsigned long flags;
+ u32 res = 0;
+
+ spin_lock_irqsave(&bus->gpio_lock, flags);
+ if (ssb_chipco_available(&bus->chipco))
+ res = ssb_chipco_gpio_intmask(&bus->chipco, mask, value);
+ else if (ssb_extif_available(&bus->extif))
+ res = ssb_extif_gpio_intmask(&bus->extif, mask, value);
+ else
+ SSB_WARN_ON(1);
+ spin_unlock_irqrestore(&bus->gpio_lock, flags);
+
+ return res;
+}
+EXPORT_SYMBOL(ssb_gpio_intmask);
+
+u32 ssb_gpio_polarity(struct ssb_bus *bus, u32 mask, u32 value)
+{
+ unsigned long flags;
+ u32 res = 0;
+
+ spin_lock_irqsave(&bus->gpio_lock, flags);
+ if (ssb_chipco_available(&bus->chipco))
+ res = ssb_chipco_gpio_polarity(&bus->chipco, mask, value);
+ else if (ssb_extif_available(&bus->extif))
+ res = ssb_extif_gpio_polarity(&bus->extif, mask, value);
+ else
+ SSB_WARN_ON(1);
+ spin_unlock_irqrestore(&bus->gpio_lock, flags);
+
+ return res;
+}
+EXPORT_SYMBOL(ssb_gpio_polarity);
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
index 9028ed5715a..bedb2b4ee9d 100644
--- a/drivers/ssb/main.c
+++ b/drivers/ssb/main.c
@@ -557,6 +557,7 @@ static int ssb_fetch_invariants(struct ssb_bus *bus,
goto out;
memcpy(&bus->boardinfo, &iv.boardinfo, sizeof(iv.boardinfo));
memcpy(&bus->sprom, &iv.sprom, sizeof(iv.sprom));
+ bus->has_cardbus_slot = iv.has_cardbus_slot;
out:
return err;
}
@@ -569,6 +570,9 @@ static int ssb_bus_register(struct ssb_bus *bus,
spin_lock_init(&bus->bar_lock);
INIT_LIST_HEAD(&bus->list);
+#ifdef CONFIG_SSB_EMBEDDED
+ spin_lock_init(&bus->gpio_lock);
+#endif
/* Powerup the bus */
err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1);
diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h
index a789364264a..21eca2b5118 100644
--- a/drivers/ssb/ssb_private.h
+++ b/drivers/ssb/ssb_private.h
@@ -120,10 +120,10 @@ extern int ssb_devices_thaw(struct ssb_bus *bus);
extern struct ssb_bus *ssb_pci_dev_to_bus(struct pci_dev *pdev);
/* b43_pci_bridge.c */
-#ifdef CONFIG_SSB_PCIHOST
+#ifdef CONFIG_SSB_B43_PCI_BRIDGE
extern int __init b43_pci_ssb_bridge_init(void);
extern void __exit b43_pci_ssb_bridge_exit(void);
-#else /* CONFIG_SSB_PCIHOST */
+#else /* CONFIG_SSB_B43_PCI_BRIDGR */
static inline int b43_pci_ssb_bridge_init(void)
{
return 0;
diff --git a/drivers/thermal/thermal.c b/drivers/thermal/thermal.c
index e782b3e7fcd..8b86e53ccf7 100644
--- a/drivers/thermal/thermal.c
+++ b/drivers/thermal/thermal.c
@@ -306,12 +306,23 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
{
struct thermal_cooling_device_instance *dev;
struct thermal_cooling_device_instance *pos;
+ struct thermal_zone_device *pos1;
+ struct thermal_cooling_device *pos2;
int result;
if (trip >= tz->trips || (trip < 0 && trip != THERMAL_TRIPS_NONE))
return -EINVAL;
- if (!tz || !cdev)
+ list_for_each_entry(pos1, &thermal_tz_list, node) {
+ if (pos1 == tz)
+ break;
+ }
+ list_for_each_entry(pos2, &thermal_cdev_list, node) {
+ if (pos2 == cdev)
+ break;
+ }
+
+ if (tz != pos1 || cdev != pos2)
return -EINVAL;
dev =
@@ -437,20 +448,20 @@ struct thermal_cooling_device *thermal_cooling_device_register(char *type,
int result;
if (strlen(type) >= THERMAL_NAME_LENGTH)
- return NULL;
+ return ERR_PTR(-EINVAL);
if (!ops || !ops->get_max_state || !ops->get_cur_state ||
!ops->set_cur_state)
- return NULL;
+ return ERR_PTR(-EINVAL);
cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL);
if (!cdev)
- return NULL;
+ return ERR_PTR(-ENOMEM);
result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id);
if (result) {
kfree(cdev);
- return NULL;
+ return ERR_PTR(result);
}
strcpy(cdev->type, type);
@@ -462,7 +473,7 @@ struct thermal_cooling_device *thermal_cooling_device_register(char *type,
if (result) {
release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
kfree(cdev);
- return NULL;
+ return ERR_PTR(result);
}
/* sys I/F */
@@ -498,7 +509,7 @@ struct thermal_cooling_device *thermal_cooling_device_register(char *type,
unregister:
release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
device_unregister(&cdev->device);
- return NULL;
+ return ERR_PTR(result);
}
EXPORT_SYMBOL(thermal_cooling_device_register);
@@ -570,17 +581,17 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
int count;
if (strlen(type) >= THERMAL_NAME_LENGTH)
- return NULL;
+ return ERR_PTR(-EINVAL);
if (trips > THERMAL_MAX_TRIPS || trips < 0)
- return NULL;
+ return ERR_PTR(-EINVAL);
if (!ops || !ops->get_temp)
- return NULL;
+ return ERR_PTR(-EINVAL);
tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL);
if (!tz)
- return NULL;
+ return ERR_PTR(-ENOMEM);
INIT_LIST_HEAD(&tz->cooling_devices);
idr_init(&tz->idr);
@@ -588,7 +599,7 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id);
if (result) {
kfree(tz);
- return NULL;
+ return ERR_PTR(result);
}
strcpy(tz->type, type);
@@ -601,7 +612,7 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
if (result) {
release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
kfree(tz);
- return NULL;
+ return ERR_PTR(result);
}
/* sys I/F */
@@ -643,7 +654,7 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
unregister:
release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
device_unregister(&tz->device);
- return NULL;
+ return ERR_PTR(result);
}
EXPORT_SYMBOL(thermal_zone_device_register);
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
index 2a77e9d42c6..e8a01f26454 100644
--- a/drivers/uio/uio.c
+++ b/drivers/uio/uio.c
@@ -57,29 +57,29 @@ struct uio_map {
};
#define to_map(map) container_of(map, struct uio_map, kobj)
-
-static ssize_t map_attr_show(struct kobject *kobj, struct kobj_attribute *attr,
- char *buf)
+static ssize_t map_addr_show(struct uio_mem *mem, char *buf)
{
- struct uio_map *map = to_map(kobj);
- struct uio_mem *mem = map->mem;
-
- if (strncmp(attr->attr.name, "addr", 4) == 0)
- return sprintf(buf, "0x%lx\n", mem->addr);
-
- if (strncmp(attr->attr.name, "size", 4) == 0)
- return sprintf(buf, "0x%lx\n", mem->size);
+ return sprintf(buf, "0x%lx\n", mem->addr);
+}
- return -ENODEV;
+static ssize_t map_size_show(struct uio_mem *mem, char *buf)
+{
+ return sprintf(buf, "0x%lx\n", mem->size);
}
-static struct kobj_attribute attr_attribute =
- __ATTR(addr, S_IRUGO, map_attr_show, NULL);
-static struct kobj_attribute size_attribute =
- __ATTR(size, S_IRUGO, map_attr_show, NULL);
+struct uio_sysfs_entry {
+ struct attribute attr;
+ ssize_t (*show)(struct uio_mem *, char *);
+ ssize_t (*store)(struct uio_mem *, const char *, size_t);
+};
+
+static struct uio_sysfs_entry addr_attribute =
+ __ATTR(addr, S_IRUGO, map_addr_show, NULL);
+static struct uio_sysfs_entry size_attribute =
+ __ATTR(size, S_IRUGO, map_size_show, NULL);
static struct attribute *attrs[] = {
- &attr_attribute.attr,
+ &addr_attribute.attr,
&size_attribute.attr,
NULL, /* need to NULL terminate the list of attributes */
};
@@ -90,8 +90,28 @@ static void map_release(struct kobject *kobj)
kfree(map);
}
+static ssize_t map_type_show(struct kobject *kobj, struct attribute *attr,
+ char *buf)
+{
+ struct uio_map *map = to_map(kobj);
+ struct uio_mem *mem = map->mem;
+ struct uio_sysfs_entry *entry;
+
+ entry = container_of(attr, struct uio_sysfs_entry, attr);
+
+ if (!entry->show)
+ return -EIO;
+
+ return entry->show(mem, buf);
+}
+
+static struct sysfs_ops uio_sysfs_ops = {
+ .show = map_type_show,
+};
+
static struct kobj_type map_attr_type = {
.release = map_release,
+ .sysfs_ops = &uio_sysfs_ops,
.default_attrs = attrs,
};
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index bcc42136c93..0147ea39340 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -496,13 +496,10 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
otherwise it is scheduled, and with high data rates data can get lost. */
tty->low_latency = 1;
- if (usb_autopm_get_interface(acm->control)) {
- mutex_unlock(&open_mutex);
- return -EIO;
- }
+ if (usb_autopm_get_interface(acm->control) < 0)
+ goto early_bail;
mutex_lock(&acm->mutex);
- mutex_unlock(&open_mutex);
if (acm->used++) {
usb_autopm_put_interface(acm->control);
goto done;
@@ -536,6 +533,7 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
done:
err_out:
mutex_unlock(&acm->mutex);
+ mutex_unlock(&open_mutex);
return rv;
full_bailout:
@@ -544,6 +542,8 @@ bail_out:
usb_autopm_put_interface(acm->control);
acm->used--;
mutex_unlock(&acm->mutex);
+early_bail:
+ mutex_unlock(&open_mutex);
return -EIO;
}
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
index ad632f2d6f9..0647164d36d 100644
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -428,6 +428,7 @@ static int usblp_open(struct inode *inode, struct file *file)
usblp->rcomplete = 0;
if (handle_bidir(usblp) < 0) {
+ usb_autopm_put_interface(intf);
usblp->used = 0;
file->private_data = NULL;
retval = -EIO;
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index d42c561c75f..f90ab5e94c5 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -28,11 +28,23 @@
* devices is broken...
*/
static const struct usb_device_id usb_quirk_list[] = {
+ /* Action Semiconductor flash disk */
+ { USB_DEVICE(0x10d6, 0x2200), .driver_info = USB_QUIRK_STRING_FETCH_255},
+
/* CBM - Flash disk */
{ USB_DEVICE(0x0204, 0x6025), .driver_info = USB_QUIRK_RESET_RESUME },
/* HP 5300/5370C scanner */
{ USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 },
+ /* Creative SB Audigy 2 NX */
+ { USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Roland SC-8820 */
+ { USB_DEVICE(0x0582, 0x0007), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Edirol SD-20 */
+ { USB_DEVICE(0x0582, 0x0027), .driver_info = USB_QUIRK_RESET_RESUME },
+
/* INTEL VALUE SSD */
{ USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME },
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index a70e255402b..e9987230814 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -1561,6 +1561,7 @@ done_set_intf:
memcpy(req->buf, buf, n);
req->complete = rndis_response_complete;
rndis_free_response(dev->rndis_config, buf);
+ value = n;
}
/* else stalls ... spec says to avoid that */
}
diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c
index 9fdabc8fcac..4f6bfa100f2 100644
--- a/drivers/usb/gadget/printer.c
+++ b/drivers/usb/gadget/printer.c
@@ -1299,7 +1299,7 @@ printer_unbind(struct usb_gadget *gadget)
printer_req_free(dev->in_ep, req);
}
- if (dev->current_rx_req != NULL);
+ if (dev->current_rx_req != NULL)
printer_req_free(dev->out_ep, dev->current_rx_req);
while (!list_empty(&dev->rx_reqs)) {
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index d97b16b52ef..bf8be2a41a4 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -69,10 +69,9 @@ config USB_EHCI_BIG_ENDIAN_DESC
default y
config USB_EHCI_FSL
- bool
- depends on USB_EHCI_HCD
+ bool "Support for Freescale on-chip EHCI USB controller"
+ depends on USB_EHCI_HCD && FSL_SOC
select USB_EHCI_ROOT_HUB_TT
- default y if MPC834x || PPC_MPC831x
---help---
Variation of ARC USB block used in some Freescale chips.
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 4caa6a8b9a3..b8ad55aff84 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -862,18 +862,18 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
/* reschedule QH iff another request is queued */
if (!list_empty (&qh->qtd_list)
&& HC_IS_RUNNING (hcd->state)) {
- int schedule_status;
-
- schedule_status = qh_schedule (ehci, qh);
- spin_unlock_irqrestore (&ehci->lock, flags);
-
- if (schedule_status != 0) {
- // shouldn't happen often, but ...
- // FIXME kill those tds' urbs
- err ("can't reschedule qh %p, err %d",
- qh, schedule_status);
- }
- return status;
+ rc = qh_schedule(ehci, qh);
+
+ /* An error here likely indicates handshake failure
+ * or no space left in the schedule. Neither fault
+ * should happen often ...
+ *
+ * FIXME kill the now-dysfunctional queued urbs
+ */
+ if (rc != 0)
+ ehci_err(ehci,
+ "can't reschedule qh %p, err %d",
+ qh, rc);
}
break;
@@ -1014,7 +1014,7 @@ MODULE_LICENSE ("GPL");
#endif
#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
- !defined(PS3_SYSTEM_BUS_DRIVER)
+ !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER)
#error "missing bus glue for ehci-hcd"
#endif
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index ba370c56172..59be276ccd9 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -1766,6 +1766,7 @@ sl811h_suspend(struct platform_device *dev, pm_message_t state)
retval = sl811h_bus_suspend(hcd);
break;
case PM_EVENT_SUSPEND:
+ case PM_EVENT_HIBERNATE:
case PM_EVENT_PRETHAW: /* explicitly discard hw state */
port_power(sl811, 0);
break;
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
index ac283b09a63..3033d694520 100644
--- a/drivers/usb/host/u132-hcd.c
+++ b/drivers/usb/host/u132-hcd.c
@@ -3213,15 +3213,20 @@ static int u132_suspend(struct platform_device *pdev, pm_message_t state)
dev_err(&u132->platform_dev->dev, "device is being removed\n");
return -ESHUTDOWN;
} else {
- int retval = 0;
- if (state.event == PM_EVENT_FREEZE) {
+ int retval = 0, ports;
+
+ switch (state.event) {
+ case PM_EVENT_FREEZE:
retval = u132_bus_suspend(hcd);
- } else if (state.event == PM_EVENT_SUSPEND) {
- int ports = MAX_U132_PORTS;
+ break;
+ case PM_EVENT_SUSPEND:
+ case PM_EVENT_HIBERNATE:
+ ports = MAX_U132_PORTS;
while (ports-- > 0) {
port_power(u132, ports, 0);
}
- }
+ break;
+ }
if (retval == 0)
pdev->dev.power.power_state = state;
return retval;
diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c
index 8208496dfc6..c730d20eec6 100644
--- a/drivers/usb/misc/ldusb.c
+++ b/drivers/usb/misc/ldusb.c
@@ -61,6 +61,7 @@
#define USB_DEVICE_ID_VERNIER_GOTEMP 0x0002
#define USB_DEVICE_ID_VERNIER_SKIP 0x0003
#define USB_DEVICE_ID_VERNIER_CYCLOPS 0x0004
+#define USB_DEVICE_ID_VERNIER_LCSPEC 0x0006
#define USB_VENDOR_ID_MICROCHIP 0x04d8
#define USB_DEVICE_ID_PICDEM 0x000c
@@ -92,6 +93,7 @@ static struct usb_device_id ld_usb_table [] = {
{ USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) },
{ USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS) },
{ USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICDEM) },
+ { USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LCSPEC) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, ld_usb_table);
diff --git a/drivers/usb/misc/trancevibrator.c b/drivers/usb/misc/trancevibrator.c
index 67e2fc20eee..03368edf3f2 100644
--- a/drivers/usb/misc/trancevibrator.c
+++ b/drivers/usb/misc/trancevibrator.c
@@ -59,13 +59,14 @@ static ssize_t set_speed(struct device *dev, struct device_attribute *attr,
{
struct usb_interface *intf = to_usb_interface(dev);
struct trancevibrator *tv = usb_get_intfdata(intf);
- int temp, retval;
+ int temp, retval, old;
temp = simple_strtoul(buf, NULL, 10);
if (temp > 255)
temp = 255;
else if (temp < 0)
temp = 0;
+ old = tv->speed;
tv->speed = temp;
dev_dbg(&tv->udev->dev, "speed = %d\n", tv->speed);
@@ -77,6 +78,7 @@ static ssize_t set_speed(struct device *dev, struct device_attribute *attr,
tv->speed, /* speed value */
0, NULL, 0, USB_CTRL_GET_TIMEOUT);
if (retval) {
+ tv->speed = old;
dev_dbg(&tv->udev->dev, "retval = %d\n", retval);
return retval;
}
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 90dcc625f70..76db2fef465 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -393,8 +393,8 @@ static const char *ftdi_chip_name[] = {
#define FTDI_STATUS_B1_MASK (FTDI_RS_BI)
/* End TIOCMIWAIT */
-#define FTDI_IMPL_ASYNC_FLAGS = ( ASYNC_SPD_HI | ASYNC_SPD_VHI \
- ASYNC_SPD_CUST | ASYNC_SPD_SHI | ASYNC_SPD_WARP )
+#define FTDI_IMPL_ASYNC_FLAGS = (ASYNC_SPD_HI | ASYNC_SPD_VHI \
+ | ASYNC_SPD_CUST | ASYNC_SPD_SHI | ASYNC_SPD_WARP)
/* function prototypes for a FTDI serial converter */
static int ftdi_sio_probe (struct usb_serial *serial, const struct usb_device_id *id);
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 5e8bf1bc1e5..af2674c5741 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -113,6 +113,9 @@ static int option_send_setup(struct usb_serial_port *port);
#define NOVATELWIRELESS_VENDOR_ID 0x1410
#define DELL_VENDOR_ID 0x413C
+#define KYOCERA_VENDOR_ID 0x0c88
+#define KYOCERA_PRODUCT_KPC680 0x180a
+
#define ANYDATA_VENDOR_ID 0x16d5
#define ANYDATA_PRODUCT_ADU_E100A 0x6501
#define ANYDATA_PRODUCT_ADU_500A 0x6502
@@ -121,6 +124,8 @@ static int option_send_setup(struct usb_serial_port *port);
#define BANDRICH_PRODUCT_C100_1 0x1002
#define BANDRICH_PRODUCT_C100_2 0x1003
+#define QUALCOMM_VENDOR_ID 0x05C6
+
static struct usb_device_id option_ids[] = {
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
@@ -174,18 +179,23 @@ static struct usb_device_id option_ids[] = {
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x2410) }, /* Novatel EU740 */
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x4100) }, /* Novatel U727 */
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x4400) }, /* Novatel MC950 */
+ { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x5010) }, /* Novatel U727 */
{ USB_DEVICE(DELL_VENDOR_ID, 0x8114) }, /* Dell Wireless 5700 Mobile Broadband CDMA/EVDO Mini-Card == Novatel Expedite EV620 CDMA/EV-DO */
{ USB_DEVICE(DELL_VENDOR_ID, 0x8115) }, /* Dell Wireless 5500 Mobile Broadband HSDPA Mini-Card == Novatel Expedite EU740 HSDPA/3G */
{ USB_DEVICE(DELL_VENDOR_ID, 0x8116) }, /* Dell Wireless 5505 Mobile Broadband HSDPA Mini-Card == Novatel Expedite EU740 HSDPA/3G */
{ USB_DEVICE(DELL_VENDOR_ID, 0x8117) }, /* Dell Wireless 5700 Mobile Broadband CDMA/EVDO ExpressCard == Novatel Merlin XV620 CDMA/EV-DO */
{ USB_DEVICE(DELL_VENDOR_ID, 0x8118) }, /* Dell Wireless 5510 Mobile Broadband HSDPA ExpressCard == Novatel Merlin XU870 HSDPA/3G */
{ USB_DEVICE(DELL_VENDOR_ID, 0x8128) }, /* Dell Wireless 5700 Mobile Broadband CDMA/EVDO Mini-Card == Novatel Expedite E720 CDMA/EV-DO */
+ { USB_DEVICE(DELL_VENDOR_ID, 0x8129) }, /* Dell Wireless 5700 Mobile Broadband CDMA/EVDO Mini-Card == Novatel Expedite ET620 CDMA/EV-DO */
+ { USB_DEVICE(DELL_VENDOR_ID, 0x8133) }, /* Dell Wireless 5720 == Novatel EV620 CDMA/EV-DO */
{ USB_DEVICE(DELL_VENDOR_ID, 0x8136) }, /* Dell Wireless HSDPA 5520 == Novatel Expedite EU860D */
{ USB_DEVICE(DELL_VENDOR_ID, 0x8137) }, /* Dell Wireless HSDPA 5520 */
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) },
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) },
{ USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_1) },
{ USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_2) },
+ { USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC680) },
+ { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, option_ids);
@@ -247,10 +257,10 @@ static int debug;
struct option_port_private {
/* Input endpoints and buffer for this port */
struct urb *in_urbs[N_IN_URB];
- char in_buffer[N_IN_URB][IN_BUFLEN];
+ u8 *in_buffer[N_IN_URB];
/* Output endpoints and buffer for this port */
struct urb *out_urbs[N_OUT_URB];
- char out_buffer[N_OUT_URB][OUT_BUFLEN];
+ u8 *out_buffer[N_OUT_URB];
unsigned long out_busy; /* Bit vector of URBs in use */
/* Settings for the port */
@@ -737,9 +747,10 @@ static int option_send_setup(struct usb_serial_port *port)
static int option_startup(struct usb_serial *serial)
{
- int i, err;
+ int i, j, err;
struct usb_serial_port *port;
struct option_port_private *portdata;
+ u8 *buffer;
dbg("%s", __FUNCTION__);
@@ -753,6 +764,20 @@ static int option_startup(struct usb_serial *serial)
return (1);
}
+ for (j = 0; j < N_IN_URB; j++) {
+ buffer = (u8 *)__get_free_page(GFP_KERNEL);
+ if (!buffer)
+ goto bail_out_error;
+ portdata->in_buffer[j] = buffer;
+ }
+
+ for (j = 0; j < N_OUT_URB; j++) {
+ buffer = kmalloc(OUT_BUFLEN, GFP_KERNEL);
+ if (!buffer)
+ goto bail_out_error2;
+ portdata->out_buffer[j] = buffer;
+ }
+
usb_set_serial_port_data(port, portdata);
if (! port->interrupt_in_urb)
@@ -766,6 +791,16 @@ static int option_startup(struct usb_serial *serial)
option_setup_urbs(serial);
return (0);
+
+bail_out_error2:
+ for (j = 0; j < N_OUT_URB; j++)
+ kfree(portdata->out_buffer[j]);
+bail_out_error:
+ for (j = 0; j < N_IN_URB; j++)
+ if (portdata->in_buffer[j])
+ free_page((unsigned long)portdata->in_buffer[j]);
+ kfree(portdata);
+ return 1;
}
static void option_shutdown(struct usb_serial *serial)
@@ -794,12 +829,14 @@ static void option_shutdown(struct usb_serial *serial)
for (j = 0; j < N_IN_URB; j++) {
if (portdata->in_urbs[j]) {
usb_free_urb(portdata->in_urbs[j]);
+ free_page((unsigned long)portdata->in_buffer[j]);
portdata->in_urbs[j] = NULL;
}
}
for (j = 0; j < N_OUT_URB; j++) {
if (portdata->out_urbs[j]) {
usb_free_urb(portdata->out_urbs[j]);
+ kfree(portdata->out_buffer[j]);
portdata->out_urbs[j] = NULL;
}
}
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index 4c925e3e8a6..e3d44ae8d44 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -178,7 +178,6 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x1199, 0x0112), .driver_info = DEVICE_1_PORT }, /* Sierra Wireless AirCard 580 */
{ USB_DEVICE(0x0F3D, 0x0112), .driver_info = DEVICE_1_PORT }, /* Airprime/Sierra PC 5220 */
- { USB_DEVICE(0x05C6, 0x6613), .driver_info = DEVICE_1_PORT }, /* Onda H600/ZTE MF330 */
{ USB_DEVICE(0x1199, 0x0FFF), .driver_info = DEVICE_INSTALLER},
{ }
diff --git a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c
index a41ce21c069..958f5b17847 100644
--- a/drivers/usb/storage/protocol.c
+++ b/drivers/usb/storage/protocol.c
@@ -150,13 +150,14 @@ void usb_stor_transparent_scsi_command(struct scsi_cmnd *srb,
/* Copy a buffer of length buflen to/from the srb's transfer buffer.
* Update the **sgptr and *offset variables so that the next copy will
- * pick up from where this one left off. */
-
+ * pick up from where this one left off.
+ */
unsigned int usb_stor_access_xfer_buf(unsigned char *buffer,
unsigned int buflen, struct scsi_cmnd *srb, struct scatterlist **sgptr,
unsigned int *offset, enum xfer_buf_dir dir)
{
unsigned int cnt;
+ struct scatterlist *sg = *sgptr;
/* We have to go through the list one entry
* at a time. Each s-g entry contains some number of pages, and
@@ -164,22 +165,23 @@ unsigned int usb_stor_access_xfer_buf(unsigned char *buffer,
* in kernel-addressable memory then kmap() will return its address.
* If the page is not directly accessible -- such as a user buffer
* located in high memory -- then kmap() will map it to a temporary
- * position in the kernel's virtual address space. */
- struct scatterlist *sg = *sgptr;
+ * position in the kernel's virtual address space.
+ */
if (!sg)
sg = scsi_sglist(srb);
+ buflen = min(buflen, scsi_bufflen(srb));
/* This loop handles a single s-g list entry, which may
- * include multiple pages. Find the initial page structure
- * and the starting offset within the page, and update
- * the *offset and **sgptr values for the next loop. */
+ * include multiple pages. Find the initial page structure
+ * and the starting offset within the page, and update
+ * the *offset and **sgptr values for the next loop.
+ */
cnt = 0;
- while (cnt < buflen) {
+ while (cnt < buflen && sg) {
struct page *page = sg_page(sg) +
((sg->offset + *offset) >> PAGE_SHIFT);
- unsigned int poff =
- (sg->offset + *offset) & (PAGE_SIZE-1);
+ unsigned int poff = (sg->offset + *offset) & (PAGE_SIZE-1);
unsigned int sglen = sg->length - *offset;
if (sglen > buflen - cnt) {
@@ -222,14 +224,15 @@ unsigned int usb_stor_access_xfer_buf(unsigned char *buffer,
}
/* Store the contents of buffer into srb's transfer buffer and set the
- * SCSI residue. */
+ * SCSI residue.
+ */
void usb_stor_set_xfer_buf(unsigned char *buffer,
unsigned int buflen, struct scsi_cmnd *srb)
{
unsigned int offset = 0;
struct scatterlist *sg = NULL;
- usb_stor_access_xfer_buf(buffer, buflen, srb, &sg, &offset,
+ buflen = usb_stor_access_xfer_buf(buffer, buflen, srb, &sg, &offset,
TO_XFER_BUF);
if (buflen < scsi_bufflen(srb))
scsi_set_resid(srb, scsi_bufflen(srb) - buflen);
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index d9f4912f873..5780ed15f1a 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -891,17 +891,6 @@ int usb_stor_Bulk_max_lun(struct us_data *us)
if (result > 0)
return us->iobuf[0];
- /*
- * Some devices (i.e. Iomega Zip100) need this -- apparently
- * the bulk pipes get STALLed when the GetMaxLUN request is
- * processed. This is, in theory, harmless to all other devices
- * (regardless of if they stall or not).
- */
- if (result == -EPIPE) {
- usb_stor_clear_halt(us, us->recv_bulk_pipe);
- usb_stor_clear_halt(us, us->send_bulk_pipe);
- }
-
/*
* Some devices don't like GetMaxLUN. They may STALL the control
* pipe, they may return a zero-length result, they may do nothing at
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index fe12737e0e2..99679a8cfa0 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -357,7 +357,7 @@ UNUSUAL_DEV( 0x04b0, 0x040f, 0x0100, 0x0200,
US_FL_FIX_CAPACITY),
/* Reported by Emil Larsson <emil@swip.net> */
-UNUSUAL_DEV( 0x04b0, 0x0411, 0x0100, 0x0101,
+UNUSUAL_DEV( 0x04b0, 0x0411, 0x0100, 0x0110,
"NIKON",
"NIKON DSC D80",
US_SC_DEVICE, US_PR_DEVICE, NULL,
@@ -759,6 +759,18 @@ UNUSUAL_DEV( 0x0595, 0x4343, 0x0000, 0x2210,
"Digital Camera EX-20 DSC",
US_SC_8070, US_PR_DEVICE, NULL, 0 ),
+/* Reported by Andre Welter <a.r.welter@gmx.de>
+ * This antique device predates the release of the Bulk-only Transport
+ * spec, and if it gets a Get-Max-LUN then it requires the host to do a
+ * Clear-Halt on the bulk endpoints. The SINGLE_LUN flag will prevent
+ * us from sending the request.
+ */
+UNUSUAL_DEV( 0x059b, 0x0001, 0x0100, 0x0100,
+ "Iomega",
+ "ZIP 100",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_SINGLE_LUN ),
+
/* Reported by <Hendryk.Pfeiffer@gmx.de> */
UNUSUAL_DEV( 0x059f, 0x0643, 0x0000, 0x0000,
"LaCie",
@@ -1412,6 +1424,17 @@ UNUSUAL_DEV( 0x0ed1, 0x7636, 0x0103, 0x0103,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE | US_FL_GO_SLOW | US_FL_MAX_SECTORS_64),
+/* Patch by Leonid Petrov mail at lpetrov.net
+ * Reported by Robert Spitzenpfeil <robert@spitzenpfeil.org>
+ * http://www.qbik.ch/usb/devices/showdev.php?id=1705
+ * Updated to 103 device by MJ Ray mjr at phonecoop.coop
+ */
+UNUSUAL_DEV( 0x0f19, 0x0103, 0x0100, 0x0100,
+ "Oracom Co., Ltd",
+ "ORC-200M",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE ),
+
/* David Kuehling <dvdkhlng@gmx.de>:
* for MP3-Player AVOX WSX-300ER (bought in Japan). Reports lots of SCSI
* errors when trying to write.
@@ -1477,6 +1500,15 @@ UNUSUAL_DEV( 0x1019, 0x0c55, 0x0000, 0x0110,
US_SC_DEVICE, US_PR_DEVICE, usb_stor_ucr61s2b_init,
0 ),
+/* Reported by Fabio Venturi <f.venturi@tdnet.it>
+ * The device reports a vendor-specific bDeviceClass.
+ */
+UNUSUAL_DEV( 0x10d6, 0x2200, 0x0100, 0x0100,
+ "Actions Semiconductor",
+ "Mtp device",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ 0),
+
/* Reported by Kevin Lloyd <linux@sierrawireless.com>
* Entry is needed for the initializer function override,
* which instructs the device to load as a modem
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index d775eb6590b..62f9c6e387c 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -1913,61 +1913,6 @@ static int atyfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
par->mmaped = 1;
return 0;
}
-
-static struct {
- u32 yoffset;
- u8 r[2][256];
- u8 g[2][256];
- u8 b[2][256];
-} atyfb_save;
-
-static void atyfb_save_palette(struct atyfb_par *par, int enter)
-{
- int i, tmp;
-
- for (i = 0; i < 256; i++) {
- tmp = aty_ld_8(DAC_CNTL, par) & 0xfc;
- if (M64_HAS(EXTRA_BRIGHT))
- tmp |= 0x2;
- aty_st_8(DAC_CNTL, tmp, par);
- aty_st_8(DAC_MASK, 0xff, par);
-
- aty_st_8(DAC_R_INDEX, i, par);
- atyfb_save.r[enter][i] = aty_ld_8(DAC_DATA, par);
- atyfb_save.g[enter][i] = aty_ld_8(DAC_DATA, par);
- atyfb_save.b[enter][i] = aty_ld_8(DAC_DATA, par);
- aty_st_8(DAC_W_INDEX, i, par);
- aty_st_8(DAC_DATA, atyfb_save.r[1 - enter][i], par);
- aty_st_8(DAC_DATA, atyfb_save.g[1 - enter][i], par);
- aty_st_8(DAC_DATA, atyfb_save.b[1 - enter][i], par);
- }
-}
-
-static void atyfb_palette(int enter)
-{
- struct atyfb_par *par;
- struct fb_info *info;
- int i;
-
- for (i = 0; i < FB_MAX; i++) {
- info = registered_fb[i];
- if (info && info->fbops == &atyfb_ops) {
- par = (struct atyfb_par *) info->par;
-
- atyfb_save_palette(par, enter);
- if (enter) {
- atyfb_save.yoffset = info->var.yoffset;
- info->var.yoffset = 0;
- set_off_pitch(par, info);
- } else {
- info->var.yoffset = atyfb_save.yoffset;
- set_off_pitch(par, info);
- }
- aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, par);
- break;
- }
- }
-}
#endif /* __sparc__ */
@@ -2670,10 +2615,6 @@ static int __devinit aty_init(struct fb_info *info)
goto aty_init_exit;
}
-#ifdef __sparc__
- atyfb_save_palette(par, 0);
-#endif
-
#ifdef CONFIG_FB_ATY_CT
if (!noaccel && M64_HAS(INTEGRATED))
aty_init_cursor(info);
@@ -2900,8 +2841,6 @@ static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
#ifdef __sparc__
-extern void (*prom_palette) (int);
-
static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
struct fb_info *info, unsigned long addr)
{
@@ -3536,9 +3475,6 @@ static int __devinit atyfb_pci_probe(struct pci_dev *pdev, const struct pci_devi
goto err_release_io;
#ifdef __sparc__
- if (!prom_palette)
- prom_palette = atyfb_palette;
-
/*
* Add /dev/fb mmap values.
*/
diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c
index 41f6dbf61be..fdc9f43ec30 100644
--- a/drivers/video/cg14.c
+++ b/drivers/video/cg14.c
@@ -16,6 +16,7 @@
#include <linux/init.h>
#include <linux/fb.h>
#include <linux/mm.h>
+#include <linux/uaccess.h>
#include <asm/io.h>
#include <asm/prom.h>
diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c
index 6796ba62c3c..777389c4098 100644
--- a/drivers/video/chipsfb.c
+++ b/drivers/video/chipsfb.c
@@ -459,7 +459,7 @@ static int chipsfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
if (state.event == pdev->dev.power.power_state.event)
return 0;
- if (state.event != PM_EVENT_SUSPEND)
+ if (!(state.event & PM_EVENT_SLEEP))
goto done;
acquire_console_sem();
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c
index 74517b1b26a..596652d2831 100644
--- a/drivers/video/nvidia/nvidia.c
+++ b/drivers/video/nvidia/nvidia.c
@@ -1066,7 +1066,7 @@ static int nvidiafb_suspend(struct pci_dev *dev, pm_message_t mesg)
acquire_console_sem();
par->pm_state = mesg.event;
- if (mesg.event == PM_EVENT_SUSPEND) {
+ if (mesg.event & PM_EVENT_SLEEP) {
fb_set_suspend(info, 1);
nvidiafb_blank(FB_BLANK_POWERDOWN, info);
nvidia_write_regs(par, &par->SavedReg);
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index 10f912df2da..97facb121c7 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -1046,7 +1046,7 @@ pxafb_freq_policy(struct notifier_block *nb, unsigned long val, void *data)
switch (val) {
case CPUFREQ_ADJUST:
case CPUFREQ_INCOMPATIBLE:
- printk(KERN_DEBUG "min dma period: %d ps, "
+ pr_debug("min dma period: %d ps, "
"new clock %d kHz\n", pxafb_display_dma_period(var),
policy->max);
// TODO: fill in min/max values
@@ -1361,7 +1361,7 @@ static int __init pxafb_parse_options(struct device *dev, char *options)
}
#endif
-int __init pxafb_probe(struct platform_device *dev)
+static int __init pxafb_probe(struct platform_device *dev)
{
struct pxafb_info *fbi;
struct pxafb_mach_info *inf;
@@ -1486,7 +1486,7 @@ static struct platform_driver pxafb_driver = {
};
#ifndef MODULE
-int __devinit pxafb_setup(char *options)
+static int __devinit pxafb_setup(char *options)
{
# ifdef CONFIG_FB_PXA_PARAMETERS
if (options)
@@ -1501,7 +1501,7 @@ MODULE_PARM_DESC(options, "LCD parameters (see Documentation/fb/pxafb.txt)");
# endif
#endif
-int __devinit pxafb_init(void)
+static int __devinit pxafb_init(void)
{
#ifndef MODULE
char *option = NULL;
diff --git a/drivers/video/sbuslib.c b/drivers/video/sbuslib.c
index 963a454b707..4deaac05b93 100644
--- a/drivers/video/sbuslib.c
+++ b/drivers/video/sbuslib.c
@@ -9,6 +9,7 @@
#include <linux/string.h>
#include <linux/fb.h>
#include <linux/mm.h>
+#include <linux/uaccess.h>
#include <asm/oplib.h>
#include <asm/fbio.h>
diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c
index be27b9c1ed7..93361656316 100644
--- a/drivers/video/uvesafb.c
+++ b/drivers/video/uvesafb.c
@@ -44,7 +44,7 @@ static struct fb_fix_screeninfo uvesafb_fix __devinitdata = {
static int mtrr __devinitdata = 3; /* enable mtrr by default */
static int blank = 1; /* enable blanking by default */
-static int ypan __devinitdata = 1; /* 0: scroll, 1: ypan, 2: ywrap */
+static int ypan = 1; /* 0: scroll, 1: ypan, 2: ywrap */
static int pmi_setpal __devinitdata = 1; /* use PMI for palette changes */
static int nocrtc __devinitdata; /* ignore CRTC settings */
static int noedid __devinitdata; /* don't try DDC transfers */
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index afcdc69e37d..254d115cafa 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -402,6 +402,18 @@ config IT8712F_WDT
To compile this driver as a module, choose M here: the
module will be called it8712f_wdt.
+config HP_WATCHDOG
+ tristate "HP Proliant iLO 2 Hardware Watchdog Timer"
+ depends on X86
+ help
+ A software monitoring watchdog and NMI sourcing driver. This driver
+ will detect lockups and provide stack trace. Also, when an NMI
+ occurs this driver will make the necessary BIOS calls to log
+ the cause of the NMI. This is a driver that will only load on a
+ HP ProLiant system with a minimum of iLO2 support.
+ To compile this driver as a module, choose M here: the
+ module will be called hpwdt.
+
config SC1200_WDT
tristate "National Semiconductor PC87307/PC97307 (ala SC1200) Watchdog"
depends on X86
@@ -633,6 +645,19 @@ config WDT_RM9K_GPI
To compile this driver as a module, choose M here: the
module will be called rm9k_wdt.
+config SIBYTE_WDOG
+ tristate "Sibyte SoC hardware watchdog"
+ depends on CPU_SB1
+ help
+ Watchdog driver for the built in watchdog hardware in Sibyte
+ SoC processors. There are apparently two watchdog timers
+ on such processors; this driver supports only the first one,
+ because currently Linux only supports exporting one watchdog
+ to userspace.
+
+ To compile this driver as a loadable module, choose M here.
+ The module will be called sb_wdog.
+
config AR7_WDT
tristate "TI AR7 Watchdog Timer"
depends on AR7
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index ebc21146d40..f3fb170fe5c 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -67,6 +67,7 @@ obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o
obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o
obj-$(CONFIG_ITCO_WDT) += iTCO_wdt.o iTCO_vendor_support.o
obj-$(CONFIG_IT8712F_WDT) += it8712f_wdt.o
+obj-$(CONFIG_HP_WATCHDOG) += hpwdt.o
obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
obj-$(CONFIG_PC87413_WDT) += pc87413_wdt.o
@@ -92,6 +93,7 @@ obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o
obj-$(CONFIG_INDYDOG) += indydog.o
obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o
obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o
+obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o
obj-$(CONFIG_AR7_WDT) += ar7_wdt.o
obj-$(CONFIG_TXX9_WDT) += txx9wdt.o
diff --git a/drivers/watchdog/bfin_wdt.c b/drivers/watchdog/bfin_wdt.c
index 472be10f068..1237113dc14 100644
--- a/drivers/watchdog/bfin_wdt.c
+++ b/drivers/watchdog/bfin_wdt.c
@@ -29,6 +29,7 @@
#define stamp(fmt, args...) pr_debug("%s:%i: " fmt "\n", __func__, __LINE__, ## args)
#define stampit() stamp("here i am")
+#define pr_init(fmt, args...) ({ static const __initdata char __fmt[] = fmt; printk(__fmt, ## args); })
#define WATCHDOG_NAME "bfin-wdt"
#define PFX WATCHDOG_NAME ": "
@@ -445,19 +446,19 @@ static int __init bfin_wdt_init(void)
ret = register_reboot_notifier(&bfin_wdt_notifier);
if (ret) {
- printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", ret);
+ pr_init(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", ret);
return ret;
}
ret = misc_register(&bfin_wdt_miscdev);
if (ret) {
- printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+ pr_init(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
unregister_reboot_notifier(&bfin_wdt_notifier);
return ret;
}
- printk(KERN_INFO PFX "initialized: timeout=%d sec (nowayout=%d)\n",
+ pr_init(KERN_INFO PFX "initialized: timeout=%d sec (nowayout=%d)\n",
timeout, nowayout);
return 0;
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c
new file mode 100644
index 00000000000..a2e174b09fe
--- /dev/null
+++ b/drivers/watchdog/hpwdt.c
@@ -0,0 +1,926 @@
+/*
+ * HP WatchDog Driver
+ * based on
+ *
+ * SoftDog 0.05: A Software Watchdog Device
+ *
+ * (c) Copyright 2007 Hewlett-Packard Development Company, L.P.
+ * Thomas Mingarelli <thomas.mingarelli@hp.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/kdebug.h>
+#include <linux/moduleparam.h>
+#include <linux/notifier.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/reboot.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/watchdog.h>
+#include <linux/dmi.h>
+#include <linux/efi.h>
+#include <linux/string.h>
+#include <linux/bootmem.h>
+#include <linux/slab.h>
+#include <asm/dmi.h>
+#include <asm/desc.h>
+#include <asm/kdebug.h>
+
+#define PCI_BIOS32_SD_VALUE 0x5F32335F /* "_32_" */
+#define CRU_BIOS_SIGNATURE_VALUE 0x55524324
+#define PCI_BIOS32_PARAGRAPH_LEN 16
+#define PCI_ROM_BASE1 0x000F0000
+#define ROM_SIZE 0x10000
+
+struct bios32_service_dir {
+ u32 signature;
+ u32 entry_point;
+ u8 revision;
+ u8 length;
+ u8 checksum;
+ u8 reserved[5];
+};
+
+/*
+ * smbios_entry_point - defines SMBIOS entry point structure
+ *
+ * anchor[4] - anchor string (_SM_)
+ * checksum - checksum of the entry point structure
+ * length - length of the entry point structure
+ * major_ver - major version (02h for revision 2.1)
+ * minor_ver - minor version (01h for revision 2.1)
+ * max_struct_size - size of the largest SMBIOS structure
+ * revision - entry point structure revision implemented
+ * formatted_area[5] - reserved
+ * intermediate_anchor[5] - intermediate anchor string (_DMI_)
+ * intermediate_checksum - intermediate checksum
+ * table_length - structure table length
+ * table_address - structure table address
+ * table_num_structs - number of SMBIOS structures present
+ * bcd_revision - BCD revision
+ */
+struct smbios_entry_point {
+ u8 anchor[4];
+ u8 checksum;
+ u8 length;
+ u8 major_ver;
+ u8 minor_ver;
+ u16 max_struct_size;
+ u8 revision;
+ u8 formatted_area[5];
+ u8 intermediate_anchor[5];
+ u8 intermediate_checksum;
+ u16 table_length;
+ u64 table_address;
+ u16 table_num_structs;
+ u8 bcd_revision;
+};
+
+/* type 212 */
+struct smbios_cru64_info {
+ u8 type;
+ u8 byte_length;
+ u16 handle;
+ u32 signature;
+ u64 physical_address;
+ u32 double_length;
+ u32 double_offset;
+};
+#define SMBIOS_CRU64_INFORMATION 212
+
+struct cmn_registers {
+ union {
+ struct {
+ u8 ral;
+ u8 rah;
+ u16 rea2;
+ };
+ u32 reax;
+ } u1;
+ union {
+ struct {
+ u8 rbl;
+ u8 rbh;
+ u8 reb2l;
+ u8 reb2h;
+ };
+ u32 rebx;
+ } u2;
+ union {
+ struct {
+ u8 rcl;
+ u8 rch;
+ u16 rec2;
+ };
+ u32 recx;
+ } u3;
+ union {
+ struct {
+ u8 rdl;
+ u8 rdh;
+ u16 red2;
+ };
+ u32 redx;
+ } u4;
+
+ u32 resi;
+ u32 redi;
+ u16 rds;
+ u16 res;
+ u32 reflags;
+} __attribute__((packed));
+
+#define DEFAULT_MARGIN 30
+static unsigned int soft_margin = DEFAULT_MARGIN; /* in seconds */
+static unsigned int reload; /* the computed soft_margin */
+static int nowayout = WATCHDOG_NOWAYOUT;
+static char expect_release;
+static unsigned long hpwdt_is_open;
+
+static void __iomem *pci_mem_addr; /* the PCI-memory address */
+static unsigned long __iomem *hpwdt_timer_reg;
+static unsigned long __iomem *hpwdt_timer_con;
+
+static DEFINE_SPINLOCK(rom_lock);
+
+static void *cru_rom_addr;
+
+static struct cmn_registers cmn_regs;
+
+static struct pci_device_id hpwdt_devices[] = {
+ {
+ .vendor = PCI_VENDOR_ID_COMPAQ,
+ .device = 0xB203,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {0}, /* terminate list */
+};
+MODULE_DEVICE_TABLE(pci, hpwdt_devices);
+
+/*
+ * bios_checksum
+ */
+static int __devinit bios_checksum(const char __iomem *ptr, int len)
+{
+ char sum = 0;
+ int i;
+
+ /*
+ * calculate checksum of size bytes. This should add up
+ * to zero if we have a valid header.
+ */
+ for (i = 0; i < len; i++)
+ sum += ptr[i];
+
+ return ((sum == 0) && (len > 0));
+}
+
+#ifndef CONFIG_X86_64
+/* --32 Bit Bios------------------------------------------------------------ */
+
+#define HPWDT_ARCH 32
+
+asmlinkage void asminline_call(struct cmn_registers *pi86Regs,
+ unsigned long *pRomEntry)
+{
+ asm("pushl %ebp \n\t"
+ "movl %esp, %ebp \n\t"
+ "pusha \n\t"
+ "pushf \n\t"
+ "push %es \n\t"
+ "push %ds \n\t"
+ "pop %es \n\t"
+ "movl 8(%ebp),%eax \n\t"
+ "movl 4(%eax),%ebx \n\t"
+ "movl 8(%eax),%ecx \n\t"
+ "movl 12(%eax),%edx \n\t"
+ "movl 16(%eax),%esi \n\t"
+ "movl 20(%eax),%edi \n\t"
+ "movl (%eax),%eax \n\t"
+ "push %cs \n\t"
+ "call *12(%ebp) \n\t"
+ "pushf \n\t"
+ "pushl %eax \n\t"
+ "movl 8(%ebp),%eax \n\t"
+ "movl %ebx,4(%eax) \n\t"
+ "movl %ecx,8(%eax) \n\t"
+ "movl %edx,12(%eax) \n\t"
+ "movl %esi,16(%eax) \n\t"
+ "movl %edi,20(%eax) \n\t"
+ "movw %ds,24(%eax) \n\t"
+ "movw %es,26(%eax) \n\t"
+ "popl %ebx \n\t"
+ "movl %ebx,(%eax) \n\t"
+ "popl %ebx \n\t"
+ "movl %ebx,28(%eax) \n\t"
+ "pop %es \n\t"
+ "popf \n\t"
+ "popa \n\t"
+ "leave \n\t" "ret");
+}
+
+/*
+ * cru_detect
+ *
+ * Routine Description:
+ * This function uses the 32-bit BIOS Service Directory record to
+ * search for a $CRU record.
+ *
+ * Return Value:
+ * 0 : SUCCESS
+ * <0 : FAILURE
+ */
+static int __devinit cru_detect(unsigned long map_entry,
+ unsigned long map_offset)
+{
+ void *bios32_map;
+ unsigned long *bios32_entrypoint;
+ unsigned long cru_physical_address;
+ unsigned long cru_length;
+ unsigned long physical_bios_base = 0;
+ unsigned long physical_bios_offset = 0;
+ int retval = -ENODEV;
+
+ bios32_map = ioremap(map_entry, (2 * PAGE_SIZE));
+
+ if (bios32_map == NULL)
+ return -ENODEV;
+
+ bios32_entrypoint = bios32_map + map_offset;
+
+ cmn_regs.u1.reax = CRU_BIOS_SIGNATURE_VALUE;
+
+ asminline_call(&cmn_regs, bios32_entrypoint);
+
+ if (cmn_regs.u1.ral != 0) {
+ printk(KERN_WARNING
+ "hpwdt: Call succeeded but with an error: 0x%x\n",
+ cmn_regs.u1.ral);
+ } else {
+ physical_bios_base = cmn_regs.u2.rebx;
+ physical_bios_offset = cmn_regs.u4.redx;
+ cru_length = cmn_regs.u3.recx;
+ cru_physical_address =
+ physical_bios_base + physical_bios_offset;
+
+ /* If the values look OK, then map it in. */
+ if ((physical_bios_base + physical_bios_offset)) {
+ cru_rom_addr =
+ ioremap(cru_physical_address, cru_length);
+ if (cru_rom_addr)
+ retval = 0;
+ }
+
+ printk(KERN_DEBUG "hpwdt: CRU Base Address: 0x%lx\n",
+ physical_bios_base);
+ printk(KERN_DEBUG "hpwdt: CRU Offset Address: 0x%lx\n",
+ physical_bios_offset);
+ printk(KERN_DEBUG "hpwdt: CRU Length: 0x%lx\n",
+ cru_length);
+ printk(KERN_DEBUG "hpwdt: CRU Mapped Address: 0x%x\n",
+ (unsigned int)&cru_rom_addr);
+ }
+ iounmap(bios32_map);
+ return retval;
+}
+
+/*
+ * bios32_present
+ *
+ * Routine Description:
+ * This function finds the 32-bit BIOS Service Directory
+ *
+ * Return Value:
+ * 0 : SUCCESS
+ * <0 : FAILURE
+ */
+static int __devinit bios32_present(const char __iomem *p)
+{
+ struct bios32_service_dir *bios_32_ptr;
+ int length;
+ unsigned long map_entry, map_offset;
+
+ bios_32_ptr = (struct bios32_service_dir *) p;
+
+ /*
+ * Search for signature by checking equal to the swizzled value
+ * instead of calling another routine to perform a strcmp.
+ */
+ if (bios_32_ptr->signature == PCI_BIOS32_SD_VALUE) {
+ length = bios_32_ptr->length * PCI_BIOS32_PARAGRAPH_LEN;
+ if (bios_checksum(p, length)) {
+ /*
+ * According to the spec, we're looking for the
+ * first 4KB-aligned address below the entrypoint
+ * listed in the header. The Service Directory code
+ * is guaranteed to occupy no more than 2 4KB pages.
+ */
+ map_entry = bios_32_ptr->entry_point & ~(PAGE_SIZE - 1);
+ map_offset = bios_32_ptr->entry_point - map_entry;
+
+ return cru_detect(map_entry, map_offset);
+ }
+ }
+ return -ENODEV;
+}
+
+static int __devinit detect_cru_service(void)
+{
+ char __iomem *p, *q;
+ int rc = -1;
+
+ /*
+ * Search from 0x0f0000 through 0x0fffff, inclusive.
+ */
+ p = ioremap(PCI_ROM_BASE1, ROM_SIZE);
+ if (p == NULL)
+ return -ENOMEM;
+
+ for (q = p; q < p + ROM_SIZE; q += 16) {
+ rc = bios32_present(q);
+ if (!rc)
+ break;
+ }
+ iounmap(p);
+ return rc;
+}
+
+#else
+/* --64 Bit Bios------------------------------------------------------------ */
+
+#define HPWDT_ARCH 64
+
+asmlinkage void asminline_call(struct cmn_registers *pi86Regs,
+ unsigned long *pRomEntry)
+{
+ asm("pushq %rbp \n\t"
+ "movq %rsp, %rbp \n\t"
+ "pushq %rax \n\t"
+ "pushq %rbx \n\t"
+ "pushq %rdx \n\t"
+ "pushq %r12 \n\t"
+ "pushq %r9 \n\t"
+ "movq %rsi, %r12 \n\t"
+ "movq %rdi, %r9 \n\t"
+ "movl 4(%r9),%ebx \n\t"
+ "movl 8(%r9),%ecx \n\t"
+ "movl 12(%r9),%edx \n\t"
+ "movl 16(%r9),%esi \n\t"
+ "movl 20(%r9),%edi \n\t"
+ "movl (%r9),%eax \n\t"
+ "call *%r12 \n\t"
+ "pushfq \n\t"
+ "popq %r12 \n\t"
+ "popfq \n\t"
+ "movl %eax, (%r9) \n\t"
+ "movl %ebx, 4(%r9) \n\t"
+ "movl %ecx, 8(%r9) \n\t"
+ "movl %edx, 12(%r9) \n\t"
+ "movl %esi, 16(%r9) \n\t"
+ "movl %edi, 20(%r9) \n\t"
+ "movq %r12, %rax \n\t"
+ "movl %eax, 28(%r9) \n\t"
+ "popq %r9 \n\t"
+ "popq %r12 \n\t"
+ "popq %rdx \n\t"
+ "popq %rbx \n\t"
+ "popq %rax \n\t"
+ "leave \n\t" "ret");
+}
+
+/*
+ * dmi_find_cru
+ *
+ * Routine Description:
+ * This function checks wether or not a SMBIOS/DMI record is
+ * the 64bit CRU info or not
+ *
+ * Return Value:
+ * 0 : SUCCESS - if record found
+ * <0 : FAILURE - if record not found
+ */
+static void __devinit dmi_find_cru(const struct dmi_header *dm)
+{
+ struct smbios_cru64_info *smbios_cru64_ptr;
+ unsigned long cru_physical_address;
+
+ if (dm->type == SMBIOS_CRU64_INFORMATION) {
+ smbios_cru64_ptr = (struct smbios_cru64_info *) dm;
+ if (smbios_cru64_ptr->signature == CRU_BIOS_SIGNATURE_VALUE) {
+ cru_physical_address =
+ smbios_cru64_ptr->physical_address +
+ smbios_cru64_ptr->double_offset;
+ cru_rom_addr = ioremap(cru_physical_address,
+ smbios_cru64_ptr->double_length);
+ }
+ }
+}
+
+/*
+ * dmi_table
+ *
+ * Routine Description:
+ * Decode the SMBIOS/DMI table and check if we have a 64bit CRU record
+ * or not.
+ *
+ * We have to be cautious here. We have seen BIOSes with DMI pointers
+ * pointing to completely the wrong place for example
+ */
+static void __devinit dmi_table(u8 *buf, int len, int num,
+ void (*decode)(const struct dmi_header *))
+{
+ u8 *data = buf;
+ int i = 0;
+
+ /*
+ * Stop when we see all the items the table claimed to have
+ * OR we run off the end of the table (also happens)
+ */
+ while ((i < num) && (data - buf + sizeof(struct dmi_header)) <= len) {
+ const struct dmi_header *dm = (const struct dmi_header *)data;
+
+ /*
+ * We want to know the total length (formated area and strings)
+ * before decoding to make sure we won't run off the table in
+ * dmi_decode or dmi_string
+ */
+ data += dm->length;
+ while ((data - buf < len - 1) && (data[0] || data[1]))
+ data++;
+ if (data - buf < len - 1)
+ decode(dm);
+ data += 2;
+ i++;
+ }
+}
+
+/*
+ * smbios_present
+ *
+ * Routine Description:
+ * This function parses the SMBIOS entry point table to retrieve
+ * the 64 bit CRU Service.
+ *
+ * Return Value:
+ * 0 : SUCCESS
+ * <0 : FAILURE
+ */
+static int __devinit smbios_present(const char __iomem *p)
+{
+ struct smbios_entry_point *eps =
+ (struct smbios_entry_point *) p;
+ int length;
+ u8 *buf;
+
+ /* check if we have indeed the SMBIOS table entry point */
+ if ((strncmp((char *)eps->anchor, "_SM_",
+ sizeof(eps->anchor))) == 0) {
+ length = eps->length;
+
+ /* SMBIOS v2.1 implementation might use 0x1e */
+ if ((length == 0x1e) &&
+ (eps->major_ver == 2) &&
+ (eps->minor_ver == 1))
+ length = 0x1f;
+
+ /*
+ * Now we will check:
+ * - SMBIOS checksum must be 0
+ * - intermediate anchor should be _DMI_
+ * - intermediate checksum should be 0
+ */
+ if ((bios_checksum(p, length)) &&
+ (strncmp((char *)eps->intermediate_anchor, "_DMI_",
+ sizeof(eps->intermediate_anchor)) == 0) &&
+ (bios_checksum(p+0x10, 15))) {
+ buf = ioremap(eps->table_address, eps->table_length);
+ if (buf == NULL)
+ return -ENODEV;
+
+
+ /* Scan the DMI table for the 64 bit CRU service */
+ dmi_table(buf, eps->table_length,
+ eps->table_num_structs, dmi_find_cru);
+
+ iounmap(buf);
+ return 0;
+ }
+ }
+
+ return -ENODEV;
+}
+
+static int __devinit smbios_scan_machine(void)
+{
+ char __iomem *p, *q;
+ int rc;
+
+ if (efi_enabled) {
+ if (efi.smbios == EFI_INVALID_TABLE_ADDR)
+ return -ENODEV;
+
+ p = ioremap(efi.smbios, 32);
+ if (p == NULL)
+ return -ENOMEM;
+
+ rc = smbios_present(p);
+ iounmap(p);
+ } else {
+ /*
+ * Search from 0x0f0000 through 0x0fffff, inclusive.
+ */
+ p = ioremap(PCI_ROM_BASE1, ROM_SIZE);
+ if (p == NULL)
+ return -ENOMEM;
+
+ for (q = p; q < p + ROM_SIZE; q += 16) {
+ rc = smbios_present(q);
+ if (!rc) {
+ break;
+ }
+ }
+ iounmap(p);
+ }
+}
+
+static int __devinit detect_cru_service(void)
+{
+ cru_rom_addr = NULL;
+
+ smbios_scan_machine(); /* will become dmi_walk(dmi_find_cru); */
+
+ /* if cru_rom_addr has been set then we found a CRU service */
+ return ((cru_rom_addr != NULL)? 0: -ENODEV);
+}
+
+/* ------------------------------------------------------------------------- */
+
+#endif
+
+/*
+ * NMI Handler
+ */
+static int hpwdt_pretimeout(struct notifier_block *nb, unsigned long ulReason,
+ void *data)
+{
+ static unsigned long rom_pl;
+ static int die_nmi_called;
+
+ if (ulReason != DIE_NMI && ulReason != DIE_NMI_IPI)
+ return NOTIFY_OK;
+
+ spin_lock_irqsave(&rom_lock, rom_pl);
+ if (!die_nmi_called)
+ asminline_call(&cmn_regs, cru_rom_addr);
+ die_nmi_called = 1;
+ spin_unlock_irqrestore(&rom_lock, rom_pl);
+ if (cmn_regs.u1.ral == 0) {
+ printk(KERN_WARNING "hpwdt: An NMI occurred, "
+ "but unable to determine source.\n");
+ } else {
+ panic("An NMI occurred, please see the Integrated "
+ "Management Log for details.\n");
+ }
+
+ return NOTIFY_STOP;
+}
+
+/*
+ * Watchdog operations
+ */
+static void hpwdt_start(void)
+{
+ reload = (soft_margin * 1000) / 128;
+ iowrite16(reload, hpwdt_timer_reg);
+ iowrite16(0x85, hpwdt_timer_con);
+}
+
+static void hpwdt_stop(void)
+{
+ unsigned long data;
+
+ data = ioread16(hpwdt_timer_con);
+ data &= 0xFE;
+ iowrite16(data, hpwdt_timer_con);
+}
+
+static void hpwdt_ping(void)
+{
+ iowrite16(reload, hpwdt_timer_reg);
+}
+
+static int hpwdt_change_timer(int new_margin)
+{
+ /* Arbitrary, can't find the card's limits */
+ if (new_margin < 30 || new_margin > 600) {
+ printk(KERN_WARNING
+ "hpwdt: New value passed in is invalid: %d seconds.\n",
+ new_margin);
+ return -EINVAL;
+ }
+
+ soft_margin = new_margin;
+ printk(KERN_DEBUG
+ "hpwdt: New timer passed in is %d seconds.\n",
+ new_margin);
+ reload = (soft_margin * 1000) / 128;
+
+ return 0;
+}
+
+/*
+ * /dev/watchdog handling
+ */
+static int hpwdt_open(struct inode *inode, struct file *file)
+{
+ /* /dev/watchdog can only be opened once */
+ if (test_and_set_bit(0, &hpwdt_is_open))
+ return -EBUSY;
+
+ /* Start the watchdog */
+ hpwdt_start();
+ hpwdt_ping();
+
+ return nonseekable_open(inode, file);
+}
+
+static int hpwdt_release(struct inode *inode, struct file *file)
+{
+ /* Stop the watchdog */
+ if (expect_release == 42) {
+ hpwdt_stop();
+ } else {
+ printk(KERN_CRIT
+ "hpwdt: Unexpected close, not stopping watchdog!\n");
+ hpwdt_ping();
+ }
+
+ expect_release = 0;
+
+ /* /dev/watchdog is being closed, make sure it can be re-opened */
+ clear_bit(0, &hpwdt_is_open);
+
+ return 0;
+}
+
+static ssize_t hpwdt_write(struct file *file, const char __user *data,
+ size_t len, loff_t *ppos)
+{
+ /* See if we got the magic character 'V' and reload the timer */
+ if (len) {
+ if (!nowayout) {
+ size_t i;
+
+ /* note: just in case someone wrote the magic character
+ * five months ago... */
+ expect_release = 0;
+
+ /* scan to see whether or not we got the magic char. */
+ for (i = 0; i != len; i++) {
+ char c;
+ if (get_user(c, data+i))
+ return -EFAULT;
+ if (c == 'V')
+ expect_release = 42;
+ }
+ }
+
+ /* someone wrote to us, we should reload the timer */
+ hpwdt_ping();
+ }
+
+ return len;
+}
+
+static struct watchdog_info ident = {
+ .options = WDIOF_SETTIMEOUT |
+ WDIOF_KEEPALIVEPING |
+ WDIOF_MAGICCLOSE,
+ .identity = "HP iLO2 HW Watchdog Timer",
+};
+
+static long hpwdt_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ int __user *p = argp;
+ int new_margin;
+ int ret = -ENOTTY;
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ ret = 0;
+ if (copy_to_user(argp, &ident, sizeof(ident)))
+ ret = -EFAULT;
+ break;
+
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ ret = put_user(0, p);
+ break;
+
+ case WDIOC_KEEPALIVE:
+ hpwdt_ping();
+ ret = 0;
+ break;
+
+ case WDIOC_SETTIMEOUT:
+ ret = get_user(new_margin, p);
+ if (ret)
+ break;
+
+ ret = hpwdt_change_timer(new_margin);
+ if (ret)
+ break;
+
+ hpwdt_ping();
+ /* Fall */
+ case WDIOC_GETTIMEOUT:
+ ret = put_user(soft_margin, p);
+ break;
+ }
+ return ret;
+}
+
+/*
+ * Kernel interfaces
+ */
+static struct file_operations hpwdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = hpwdt_write,
+ .unlocked_ioctl = hpwdt_ioctl,
+ .open = hpwdt_open,
+ .release = hpwdt_release,
+};
+
+static struct miscdevice hpwdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &hpwdt_fops,
+};
+
+static struct notifier_block die_notifier = {
+ .notifier_call = hpwdt_pretimeout,
+ .priority = 0x7FFFFFFF,
+};
+
+/*
+ * Init & Exit
+ */
+
+static int __devinit hpwdt_init_one(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ int retval;
+
+ /*
+ * First let's find out if we are on an iLO2 server. We will
+ * not run on a legacy ASM box.
+ */
+ if (dev->subsystem_vendor != PCI_VENDOR_ID_HP) {
+ dev_warn(&dev->dev,
+ "This server does not have an iLO2 ASIC.\n");
+ return -ENODEV;
+ }
+
+ if (pci_enable_device(dev)) {
+ dev_warn(&dev->dev,
+ "Not possible to enable PCI Device: 0x%x:0x%x.\n",
+ ent->vendor, ent->device);
+ return -ENODEV;
+ }
+
+ pci_mem_addr = pci_iomap(dev, 1, 0x80);
+ if (!pci_mem_addr) {
+ dev_warn(&dev->dev,
+ "Unable to detect the iLO2 server memory.\n");
+ retval = -ENOMEM;
+ goto error_pci_iomap;
+ }
+ hpwdt_timer_reg = pci_mem_addr + 0x70;
+ hpwdt_timer_con = pci_mem_addr + 0x72;
+
+ /* Make sure that we have a valid soft_margin */
+ if (hpwdt_change_timer(soft_margin))
+ hpwdt_change_timer(DEFAULT_MARGIN);
+
+ /*
+ * We need to map the ROM to get the CRU service.
+ * For 32 bit Operating Systems we need to go through the 32 Bit
+ * BIOS Service Directory
+ * For 64 bit Operating Systems we get that service through SMBIOS.
+ */
+ retval = detect_cru_service();
+ if (retval < 0) {
+ dev_warn(&dev->dev,
+ "Unable to detect the %d Bit CRU Service.\n",
+ HPWDT_ARCH);
+ goto error_get_cru;
+ }
+
+ /*
+ * We know this is the only CRU call we need to make so lets keep as
+ * few instructions as possible once the NMI comes in.
+ */
+ cmn_regs.u1.rah = 0x0D;
+ cmn_regs.u1.ral = 0x02;
+
+ retval = register_die_notifier(&die_notifier);
+ if (retval != 0) {
+ dev_warn(&dev->dev,
+ "Unable to register a die notifier (err=%d).\n",
+ retval);
+ goto error_die_notifier;
+ }
+
+ retval = misc_register(&hpwdt_miscdev);
+ if (retval < 0) {
+ dev_warn(&dev->dev,
+ "Unable to register miscdev on minor=%d (err=%d).\n",
+ WATCHDOG_MINOR, retval);
+ goto error_misc_register;
+ }
+
+ printk(KERN_INFO
+ "hp Watchdog Timer Driver: 1.00"
+ ", timer margin: %d seconds( nowayout=%d).\n",
+ soft_margin, nowayout);
+
+ return 0;
+
+error_misc_register:
+ unregister_die_notifier(&die_notifier);
+error_die_notifier:
+ if (cru_rom_addr)
+ iounmap(cru_rom_addr);
+error_get_cru:
+ pci_iounmap(dev, pci_mem_addr);
+error_pci_iomap:
+ pci_disable_device(dev);
+ return retval;
+}
+
+static void __devexit hpwdt_exit(struct pci_dev *dev)
+{
+ if (!nowayout)
+ hpwdt_stop();
+
+ misc_deregister(&hpwdt_miscdev);
+ unregister_die_notifier(&die_notifier);
+
+ if (cru_rom_addr)
+ iounmap(cru_rom_addr);
+ pci_iounmap(dev, pci_mem_addr);
+ pci_disable_device(dev);
+}
+
+static struct pci_driver hpwdt_driver = {
+ .name = "hpwdt",
+ .id_table = hpwdt_devices,
+ .probe = hpwdt_init_one,
+ .remove = __devexit_p(hpwdt_exit),
+};
+
+static void __exit hpwdt_cleanup(void)
+{
+ pci_unregister_driver(&hpwdt_driver);
+}
+
+static int __init hpwdt_init(void)
+{
+ return pci_register_driver(&hpwdt_driver);
+}
+
+MODULE_AUTHOR("Tom Mingarelli");
+MODULE_DESCRIPTION("hp watchdog driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+
+module_param(soft_margin, int, 0);
+MODULE_PARM_DESC(soft_margin, "Watchdog timeout in seconds");
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+module_init(hpwdt_init);
+module_exit(hpwdt_cleanup);
diff --git a/drivers/watchdog/mtx-1_wdt.c b/drivers/watchdog/mtx-1_wdt.c
index 98451747d3c..789831b3fa0 100644
--- a/drivers/watchdog/mtx-1_wdt.c
+++ b/drivers/watchdog/mtx-1_wdt.c
@@ -45,10 +45,13 @@
#include <linux/completion.h>
#include <linux/jiffies.h>
#include <linux/watchdog.h>
+#include <linux/platform_device.h>
+
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/mach-au1x00/au1000.h>
+#include <asm/gpio.h>
#define MTX1_WDT_INTERVAL (5 * HZ)
@@ -61,6 +64,7 @@ static struct {
volatile int queue;
int default_ticks;
unsigned long inuse;
+ unsigned gpio;
} mtx1_wdt_device;
static void mtx1_wdt_trigger(unsigned long unused)
@@ -73,7 +77,8 @@ static void mtx1_wdt_trigger(unsigned long unused)
* toggle GPIO2_15
*/
tmp = au_readl(GPIO2_DIR);
- tmp = (tmp & ~(1<<15)) | ((~tmp) & (1<<15));
+ tmp = (tmp & ~(1 << mtx1_wdt_device.gpio)) |
+ ((~tmp) & (1 << mtx1_wdt_device.gpio));
au_writel (tmp, GPIO2_DIR);
if (mtx1_wdt_device.queue && ticks)
@@ -93,7 +98,7 @@ static void mtx1_wdt_start(void)
{
if (!mtx1_wdt_device.queue) {
mtx1_wdt_device.queue = 1;
- au_writel (au_readl(GPIO2_DIR) | (u32)(1<<15), GPIO2_DIR);
+ gpio_set_value(mtx1_wdt_device.gpio, 1);
mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL);
}
mtx1_wdt_device.running++;
@@ -103,7 +108,7 @@ static int mtx1_wdt_stop(void)
{
if (mtx1_wdt_device.queue) {
mtx1_wdt_device.queue = 0;
- au_writel (au_readl(GPIO2_DIR) & ~((u32)(1<<15)), GPIO2_DIR);
+ gpio_set_value(mtx1_wdt_device.gpio, 0);
}
ticks = mtx1_wdt_device.default_ticks;
@@ -197,10 +202,12 @@ static struct miscdevice mtx1_wdt_misc = {
};
-static int __init mtx1_wdt_init(void)
+static int mtx1_wdt_probe(struct platform_device *pdev)
{
int ret;
+ mtx1_wdt_device.gpio = pdev->resource[0].start;
+
if ((ret = misc_register(&mtx1_wdt_misc)) < 0) {
printk(KERN_ERR " mtx-1_wdt : failed to register\n");
return ret;
@@ -222,13 +229,30 @@ static int __init mtx1_wdt_init(void)
return 0;
}
-static void __exit mtx1_wdt_exit(void)
+static int mtx1_wdt_remove(struct platform_device *pdev)
{
if (mtx1_wdt_device.queue) {
mtx1_wdt_device.queue = 0;
wait_for_completion(&mtx1_wdt_device.stop);
}
misc_deregister(&mtx1_wdt_misc);
+ return 0;
+}
+
+static struct platform_driver mtx1_wdt = {
+ .probe = mtx1_wdt_probe,
+ .remove = mtx1_wdt_remove,
+ .driver.name = "mtx1-wdt",
+};
+
+static int __init mtx1_wdt_init(void)
+{
+ return platform_driver_register(&mtx1_wdt);
+}
+
+static void __exit mtx1_wdt_exit(void)
+{
+ platform_driver_unregister(&mtx1_wdt);
}
module_init(mtx1_wdt_init);
@@ -237,3 +261,4 @@ module_exit(mtx1_wdt_exit);
MODULE_AUTHOR("Michael Stickel, Florian Fainelli");
MODULE_DESCRIPTION("Driver for the MTX-1 watchdog");
MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/sb_wdog.c b/drivers/watchdog/sb_wdog.c
new file mode 100644
index 00000000000..b9443143369
--- /dev/null
+++ b/drivers/watchdog/sb_wdog.c
@@ -0,0 +1,353 @@
+/*
+ * Watchdog driver for SiByte SB1 SoCs
+ *
+ * Copyright (C) 2007 OnStor, Inc. * Andrew Sharp <andy.sharp@onstor.com>
+ *
+ * This driver is intended to make the second of two hardware watchdogs
+ * on the Sibyte 12XX and 11XX SoCs available to the user. There are two
+ * such devices available on the SoC, but it seems that there isn't an
+ * enumeration class for watchdogs in Linux like there is for RTCs.
+ * The second is used rather than the first because it uses IRQ 1,
+ * thereby avoiding all that IRQ 0 problematic nonsense.
+ *
+ * I have not tried this driver on a 1480 processor; it might work
+ * just well enough to really screw things up.
+ *
+ * It is a simple timer, and there is an interrupt that is raised the
+ * first time the timer expires. The second time it expires, the chip
+ * is reset and there is no way to redirect that NMI. Which could
+ * be problematic in some cases where this chip is sitting on the HT
+ * bus and has just taken responsibility for providing a cache block.
+ * Since the reset can't be redirected to the external reset pin, it is
+ * possible that other HT connected processors might hang and not reset.
+ * For Linux, a soft reset would probably be even worse than a hard reset.
+ * There you have it.
+ *
+ * The timer takes 23 bits of a 64 bit register (?) as a count value,
+ * and decrements the count every microsecond, for a max value of
+ * 0x7fffff usec or about 8.3ish seconds.
+ *
+ * This watchdog borrows some user semantics from the softdog driver,
+ * in that if you close the fd, it leaves the watchdog running, unless
+ * you previously wrote a 'V' to the fd, in which case it disables
+ * the watchdog when you close the fd like some other drivers.
+ *
+ * Based on various other watchdog drivers, which are probably all
+ * loosely based on something Alan Cox wrote years ago.
+ *
+ * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
+ * http://www.redhat.com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 1 or 2 as published by the Free Software Foundation.
+ *
+ */
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/reboot.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/interrupt.h>
+
+#include <asm/sibyte/sb1250.h>
+#include <asm/sibyte/sb1250_regs.h>
+#include <asm/sibyte/sb1250_int.h>
+#include <asm/sibyte/sb1250_scd.h>
+
+
+/*
+ * set the initial count value of a timer
+ *
+ * wdog is the iomem address of the cfg register
+ */
+void sbwdog_set(char __iomem *wdog, unsigned long t)
+{
+ __raw_writeb(0, wdog - 0x10);
+ __raw_writeq(t & 0x7fffffUL, wdog);
+}
+
+/*
+ * cause the timer to [re]load it's initial count and start counting
+ * all over again
+ *
+ * wdog is the iomem address of the cfg register
+ */
+void sbwdog_pet(char __iomem *wdog)
+{
+ __raw_writeb(__raw_readb(wdog) | 1, wdog);
+}
+
+static unsigned long sbwdog_gate; /* keeps it to one thread only */
+static char __iomem *kern_dog = (char __iomem *)(IO_BASE + (A_SCD_WDOG_CFG_0));
+static char __iomem *user_dog = (char __iomem *)(IO_BASE + (A_SCD_WDOG_CFG_1));
+static unsigned long timeout = 0x7fffffUL; /* useconds: 8.3ish secs. */
+static int expect_close;
+
+static struct watchdog_info ident = {
+ .options = WDIOF_CARDRESET | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+ .identity = "SiByte Watchdog",
+};
+
+/*
+ * Allow only a single thread to walk the dog
+ */
+static int sbwdog_open(struct inode *inode, struct file *file)
+{
+ nonseekable_open(inode, file);
+ if (test_and_set_bit(0, &sbwdog_gate)) {
+ return -EBUSY;
+ }
+ __module_get(THIS_MODULE);
+
+ /*
+ * Activate the timer
+ */
+ sbwdog_set(user_dog, timeout);
+ __raw_writeb(1, user_dog);
+
+ return 0;
+}
+
+/*
+ * Put the dog back in the kennel.
+ */
+static int sbwdog_release(struct inode *inode, struct file *file)
+{
+ if (expect_close == 42) {
+ __raw_writeb(0, user_dog);
+ module_put(THIS_MODULE);
+ } else {
+ printk(KERN_CRIT "%s: Unexpected close, not stopping watchdog!\n",
+ ident.identity);
+ sbwdog_pet(user_dog);
+ }
+ clear_bit(0, &sbwdog_gate);
+ expect_close = 0;
+
+ return 0;
+}
+
+/*
+ * 42 - the answer
+ */
+static ssize_t sbwdog_write(struct file *file, const char __user *data,
+ size_t len, loff_t *ppos)
+{
+ int i;
+
+ if (len) {
+ /*
+ * restart the timer
+ */
+ expect_close = 0;
+
+ for (i = 0; i != len; i++) {
+ char c;
+
+ if (get_user(c, data + i)) {
+ return -EFAULT;
+ }
+ if (c == 'V') {
+ expect_close = 42;
+ }
+ }
+ sbwdog_pet(user_dog);
+ }
+
+ return len;
+}
+
+static int sbwdog_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret = -ENOTTY;
+ unsigned long time;
+ void __user *argp = (void __user *)arg;
+ int __user *p = argp;
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ ret = copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
+ break;
+
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ ret = put_user(0, p);
+ break;
+
+ case WDIOC_SETTIMEOUT:
+ ret = get_user(time, p);
+ if (ret) {
+ break;
+ }
+
+ time *= 1000000;
+ if (time > 0x7fffffUL) {
+ ret = -EINVAL;
+ break;
+ }
+ timeout = time;
+ sbwdog_set(user_dog, timeout);
+ sbwdog_pet(user_dog);
+
+ case WDIOC_GETTIMEOUT:
+ /*
+ * get the remaining count from the ... count register
+ * which is 1*8 before the config register
+ */
+ ret = put_user(__raw_readq(user_dog - 8) / 1000000, p);
+ break;
+
+ case WDIOC_KEEPALIVE:
+ sbwdog_pet(user_dog);
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+
+/*
+ * Notifier for system down
+ */
+static int
+sbwdog_notify_sys(struct notifier_block *this, unsigned long code, void *erf)
+{
+ if (code == SYS_DOWN || code == SYS_HALT) {
+ /*
+ * sit and sit
+ */
+ __raw_writeb(0, user_dog);
+ __raw_writeb(0, kern_dog);
+ }
+
+ return NOTIFY_DONE;
+}
+
+static const struct file_operations sbwdog_fops =
+{
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = sbwdog_write,
+ .ioctl = sbwdog_ioctl,
+ .open = sbwdog_open,
+ .release = sbwdog_release,
+};
+
+static struct miscdevice sbwdog_miscdev =
+{
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &sbwdog_fops,
+};
+
+static struct notifier_block sbwdog_notifier = {
+ .notifier_call = sbwdog_notify_sys,
+};
+
+/*
+ * interrupt handler
+ *
+ * doesn't do a whole lot for user, but oh so cleverly written so kernel
+ * code can use it to re-up the watchdog, thereby saving the kernel from
+ * having to create and maintain a timer, just to tickle another timer,
+ * which is just so wrong.
+ */
+irqreturn_t sbwdog_interrupt(int irq, void *addr)
+{
+ unsigned long wd_init;
+ char *wd_cfg_reg = (char *)addr;
+ u8 cfg;
+
+ cfg = __raw_readb(wd_cfg_reg);
+ wd_init = __raw_readq(wd_cfg_reg - 8) & 0x7fffff;
+
+ /*
+ * if it's the second watchdog timer, it's for those users
+ */
+ if (wd_cfg_reg == user_dog) {
+ printk(KERN_CRIT
+ "%s in danger of initiating system reset in %ld.%01ld seconds\n",
+ ident.identity, wd_init / 1000000, (wd_init / 100000) % 10);
+ } else {
+ cfg |= 1;
+ }
+
+ __raw_writeb(cfg, wd_cfg_reg);
+
+ return IRQ_HANDLED;
+}
+
+static int __init sbwdog_init(void)
+{
+ int ret;
+
+ /*
+ * register a reboot notifier
+ */
+ ret = register_reboot_notifier(&sbwdog_notifier);
+ if (ret) {
+ printk (KERN_ERR "%s: cannot register reboot notifier (err=%d)\n",
+ ident.identity, ret);
+ return ret;
+ }
+
+ /*
+ * get the resources
+ */
+ ret = misc_register(&sbwdog_miscdev);
+ if (ret == 0) {
+ printk(KERN_INFO "%s: timeout is %ld.%ld secs\n", ident.identity,
+ timeout / 1000000, (timeout / 100000) % 10);
+ }
+
+ ret = request_irq(1, sbwdog_interrupt, IRQF_DISABLED | IRQF_SHARED,
+ ident.identity, (void *)user_dog);
+ if (ret) {
+ printk(KERN_ERR "%s: failed to request irq 1 - %d\n", ident.identity,
+ ret);
+ misc_deregister(&sbwdog_miscdev);
+ }
+
+ return ret;
+}
+
+static void __exit sbwdog_exit(void)
+{
+ misc_deregister(&sbwdog_miscdev);
+}
+
+module_init(sbwdog_init);
+module_exit(sbwdog_exit);
+
+MODULE_AUTHOR("Andrew Sharp <andy.sharp@onstor.com>");
+MODULE_DESCRIPTION("SiByte Watchdog");
+
+module_param(timeout, ulong, 0);
+MODULE_PARM_DESC(timeout,
+ "Watchdog timeout in microseconds (max/default 8388607 or 8.3ish secs)");
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+
+/*
+ * example code that can be put in a platform code area to utilize the
+ * first watchdog timer for the kernels own purpose.
+
+ void
+platform_wd_setup(void)
+{
+ int ret;
+
+ ret = request_irq(0, sbwdog_interrupt, IRQF_DISABLED | IRQF_SHARED,
+ "Kernel Watchdog", IOADDR(A_SCD_WDOG_CFG_0));
+ if (ret) {
+ printk(KERN_CRIT "Watchdog IRQ zero(0) failed to be requested - %d\n",
+ ret);
+ }
+}
+
+
+ */