aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorDmitry Torokhov <dtor@insightbb.com>2006-08-04 22:50:27 -0400
committerDmitry Torokhov <dtor@insightbb.com>2006-08-04 22:50:27 -0400
commitd932cb7e630cae3b6b5307b767d296ff1a597c5e (patch)
treef930d068a12a256fabef0864bcdf8e85f095369e /drivers
parent73b59a3b1c09e4bfc678400b77b96134dcfbf112 (diff)
parentf5d635f649607b09b0b4620d25d028fd2b1b7ea5 (diff)
Merge rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6 into for-linus
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/Kconfig6
-rw-r--r--drivers/acpi/ac.c2
-rw-r--r--drivers/acpi/battery.c6
-rw-r--r--drivers/acpi/bus.c4
-rw-r--r--drivers/acpi/button.c4
-rw-r--r--drivers/acpi/cm_sbs.c46
-rw-r--r--drivers/acpi/dispatcher/dsinit.c10
-rw-r--r--drivers/acpi/dispatcher/dsmethod.c23
-rw-r--r--drivers/acpi/dispatcher/dswexec.c4
-rw-r--r--drivers/acpi/dock.c14
-rw-r--r--drivers/acpi/ec.c2
-rw-r--r--drivers/acpi/event.c2
-rw-r--r--drivers/acpi/events/evregion.c44
-rw-r--r--drivers/acpi/events/evxface.c44
-rw-r--r--drivers/acpi/events/evxfregn.c13
-rw-r--r--drivers/acpi/executer/exconfig.c1
-rw-r--r--drivers/acpi/executer/exconvrt.c3
-rw-r--r--drivers/acpi/executer/exmutex.c4
-rw-r--r--drivers/acpi/executer/exsystem.c8
-rw-r--r--drivers/acpi/fan.c2
-rw-r--r--drivers/acpi/hotkey.c10
-rw-r--r--drivers/acpi/namespace/nsalloc.c13
-rw-r--r--drivers/acpi/osl.c90
-rw-r--r--drivers/acpi/parser/psutils.c2
-rw-r--r--drivers/acpi/pci_link.c7
-rw-r--r--drivers/acpi/power.c2
-rw-r--r--drivers/acpi/processor_core.c2
-rw-r--r--drivers/acpi/processor_idle.c2
-rw-r--r--drivers/acpi/sleep/proc.c6
-rw-r--r--drivers/acpi/system.c6
-rw-r--r--drivers/acpi/tables/tbget.c12
-rw-r--r--drivers/acpi/tables/tbinstal.c21
-rw-r--r--drivers/acpi/tables/tbrsdt.c27
-rw-r--r--drivers/acpi/tables/tbxface.c32
-rw-r--r--drivers/acpi/thermal.c27
-rw-r--r--drivers/acpi/utilities/utalloc.c2
-rw-r--r--drivers/acpi/utilities/utdebug.c4
-rw-r--r--drivers/acpi/utilities/utdelete.c13
-rw-r--r--drivers/acpi/utilities/utmisc.c25
-rw-r--r--drivers/acpi/utilities/utmutex.c8
-rw-r--r--drivers/acpi/utilities/utstate.c7
-rw-r--r--drivers/atm/Kconfig2
-rw-r--r--drivers/base/Kconfig2
-rw-r--r--drivers/base/bus.c5
-rw-r--r--drivers/base/core.c30
-rw-r--r--drivers/base/topology.c2
-rw-r--r--drivers/block/Kconfig10
-rw-r--r--drivers/block/aoe/aoechr.c2
-rw-r--r--drivers/block/cciss.c86
-rw-r--r--drivers/block/cpqarray.c2
-rw-r--r--drivers/block/nbd.c19
-rw-r--r--drivers/block/pktcdvd.c6
-rw-r--r--drivers/block/rd.c2
-rw-r--r--drivers/bluetooth/bcm203x.c1
-rw-r--r--drivers/bluetooth/hci_ldisc.c4
-rw-r--r--drivers/bluetooth/hci_usb.c25
-rw-r--r--drivers/cdrom/cdrom.c2
-rw-r--r--drivers/char/hvsi.c2
-rw-r--r--drivers/char/hw_random/geode-rng.c6
-rw-r--r--drivers/char/hw_random/intel-rng.c2
-rw-r--r--drivers/char/ip2/ip2main.c7
-rw-r--r--drivers/char/mem.c4
-rw-r--r--drivers/char/nsc_gpio.c6
-rw-r--r--drivers/char/pc8736x_gpio.c58
-rw-r--r--drivers/char/pcmcia/synclink_cs.c14
-rw-r--r--drivers/char/rtc.c47
-rw-r--r--drivers/char/scx200_gpio.c72
-rw-r--r--drivers/char/snsc.c7
-rw-r--r--drivers/char/snsc_event.c15
-rw-r--r--drivers/char/specialix.c6
-rw-r--r--drivers/char/synclink.c14
-rw-r--r--drivers/char/synclink_gt.c14
-rw-r--r--drivers/char/synclinkmp.c14
-rw-r--r--drivers/char/tpm/tpm.c1
-rw-r--r--drivers/char/tpm/tpm_tis.c77
-rw-r--r--drivers/char/vr41xx_giu.c1
-rw-r--r--drivers/connector/cn_proc.c20
-rw-r--r--drivers/cpufreq/cpufreq.c119
-rw-r--r--drivers/cpufreq/cpufreq_conservative.c2
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c20
-rw-r--r--drivers/cpufreq/cpufreq_userspace.c3
-rw-r--r--drivers/crypto/padlock-aes.c9
-rw-r--r--drivers/dma/ioatdma.c2
-rw-r--r--drivers/edac/edac_mc.c687
-rw-r--r--drivers/fc4/fc.c4
-rw-r--r--drivers/hwmon/abituguru.c21
-rw-r--r--drivers/i2c/algos/i2c-algo-bit.c4
-rw-r--r--drivers/i2c/algos/i2c-algo-ite.c4
-rw-r--r--drivers/i2c/algos/i2c-algo-pca.c6
-rw-r--r--drivers/i2c/algos/i2c-algo-pcf.c8
-rw-r--r--drivers/i2c/algos/i2c-algo-sibyte.c4
-rw-r--r--drivers/i2c/busses/i2c-iop3xx.c17
-rw-r--r--drivers/i2c/busses/i2c-iop3xx.h2
-rw-r--r--drivers/i2c/busses/i2c-powermac.c4
-rw-r--r--drivers/i2c/busses/scx200_acb.c20
-rw-r--r--drivers/i2c/chips/pca9539.c12
-rw-r--r--drivers/i2c/i2c-core.c4
-rw-r--r--drivers/ide/Kconfig15
-rw-r--r--drivers/ide/ide-disk.c2
-rw-r--r--drivers/ide/ide-dma.c2
-rw-r--r--drivers/ide/ide-iops.c2
-rw-r--r--drivers/ide/ide.c5
-rw-r--r--drivers/ide/legacy/ide-cs.c81
-rw-r--r--drivers/ide/pci/generic.c8
-rw-r--r--drivers/ide/pci/it821x.c11
-rw-r--r--drivers/infiniband/core/addr.c30
-rw-r--r--drivers/infiniband/core/cm.c25
-rw-r--r--drivers/infiniband/core/cma.c22
-rw-r--r--drivers/infiniband/core/fmr_pool.c8
-rw-r--r--drivers/infiniband/core/mad.c22
-rw-r--r--drivers/infiniband/core/sa_query.c10
-rw-r--r--drivers/infiniband/core/user_mad.c87
-rw-r--r--drivers/infiniband/core/uverbs.h2
-rw-r--r--drivers/infiniband/core/uverbs_cmd.c42
-rw-r--r--drivers/infiniband/core/uverbs_main.c8
-rw-r--r--drivers/infiniband/hw/ipath/ipath_driver.c76
-rw-r--r--drivers/infiniband/hw/ipath/ipath_keys.c15
-rw-r--r--drivers/infiniband/hw/ipath/ipath_verbs.c5
-rw-r--r--drivers/infiniband/hw/mthca/mthca_allocator.c15
-rw-r--r--drivers/infiniband/hw/mthca/mthca_av.c5
-rw-r--r--drivers/infiniband/hw/mthca/mthca_cmd.c5
-rw-r--r--drivers/infiniband/hw/mthca/mthca_qp.c13
-rw-r--r--drivers/infiniband/hw/mthca/mthca_srq.c3
-rw-r--r--drivers/infiniband/ulp/ipoib/Kconfig3
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib.h1
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c23
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_multicast.c8
-rw-r--r--drivers/infiniband/ulp/iser/iser_verbs.c2
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c22
-rw-r--r--drivers/isdn/hisax/asuscom.c6
-rw-r--r--drivers/isdn/hisax/avm_a1.c2
-rw-r--r--drivers/isdn/hisax/avm_pci.c8
-rw-r--r--drivers/isdn/hisax/bkm_a4t.c4
-rw-r--r--drivers/isdn/hisax/bkm_a8.c16
-rw-r--r--drivers/isdn/hisax/config.c2
-rw-r--r--drivers/isdn/hisax/diva.c14
-rw-r--r--drivers/isdn/hisax/enternow_pci.c4
-rw-r--r--drivers/isdn/hisax/gazel.c8
-rw-r--r--drivers/isdn/hisax/hfc4s8s_l1.c2
-rw-r--r--drivers/isdn/hisax/hfc_2bds0.c4
-rw-r--r--drivers/isdn/hisax/hfc_2bs0.c4
-rw-r--r--drivers/isdn/hisax/hfc_pci.c6
-rw-r--r--drivers/isdn/hisax/hfcscard.c6
-rw-r--r--drivers/isdn/hisax/icc.c8
-rw-r--r--drivers/isdn/hisax/icc.h2
-rw-r--r--drivers/isdn/hisax/ipacx.c18
-rw-r--r--drivers/isdn/hisax/isurf.c4
-rw-r--r--drivers/isdn/hisax/ix1_micro.c6
-rw-r--r--drivers/isdn/hisax/jade.c6
-rw-r--r--drivers/isdn/hisax/mic.c2
-rw-r--r--drivers/isdn/hisax/netjet.c2
-rw-r--r--drivers/isdn/hisax/niccy.c4
-rw-r--r--drivers/isdn/hisax/nj_s.c4
-rw-r--r--drivers/isdn/hisax/nj_u.c4
-rw-r--r--drivers/isdn/hisax/s0box.c2
-rw-r--r--drivers/isdn/hisax/saphir.c2
-rw-r--r--drivers/isdn/hisax/sportster.c4
-rw-r--r--drivers/isdn/hisax/teleint.c2
-rw-r--r--drivers/isdn/hisax/teles0.c2
-rw-r--r--drivers/isdn/hisax/telespci.c4
-rw-r--r--drivers/isdn/hisax/w6692.c10
-rw-r--r--drivers/isdn/i4l/isdn_common.c12
-rw-r--r--drivers/isdn/i4l/isdn_ppp.c2
-rw-r--r--drivers/leds/Kconfig7
-rw-r--r--drivers/leds/Makefile1
-rw-r--r--drivers/leds/leds-net48xx.c116
-rw-r--r--drivers/macintosh/Kconfig14
-rw-r--r--drivers/macintosh/adbhid.c14
-rw-r--r--drivers/macintosh/macio_asic.c2
-rw-r--r--drivers/macintosh/smu.c53
-rw-r--r--drivers/macintosh/therm_pm72.c218
-rw-r--r--drivers/macintosh/therm_pm72.h33
-rw-r--r--drivers/macintosh/via-pmu-backlight.c68
-rw-r--r--drivers/macintosh/via-pmu-led.c2
-rw-r--r--drivers/macintosh/via-pmu.c39
-rw-r--r--drivers/md/md.c86
-rw-r--r--drivers/md/raid1.c5
-rw-r--r--drivers/md/raid10.c4
-rw-r--r--drivers/md/raid5.c84
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.c15
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.c24
-rw-r--r--drivers/media/dvb/frontends/nxt200x.c4
-rw-r--r--drivers/media/dvb/frontends/or51211.c2
-rw-r--r--drivers/media/dvb/frontends/sp8870.c2
-rw-r--r--drivers/media/dvb/frontends/sp887x.c2
-rw-r--r--drivers/media/dvb/ttpci/av7110.c4
-rw-r--r--drivers/media/dvb/ttpci/av7110_v4l.c12
-rw-r--r--drivers/media/dvb/ttpci/budget-av.c3
-rw-r--r--drivers/media/dvb/ttpci/budget-ci.c2
-rw-r--r--drivers/media/dvb/ttpci/budget-core.c57
-rw-r--r--drivers/media/dvb/ttpci/budget-patch.c2
-rw-r--r--drivers/media/dvb/ttpci/budget.c5
-rw-r--r--drivers/media/dvb/ttpci/budget.h7
-rw-r--r--drivers/media/video/Kconfig4
-rw-r--r--drivers/media/video/bt8xx/Kconfig2
-rw-r--r--drivers/media/video/bt8xx/bttv-driver.c15
-rw-r--r--drivers/media/video/bt8xx/bttv-vbi.c15
-rw-r--r--drivers/media/video/compat_ioctl32.c24
-rw-r--r--drivers/media/video/cpia2/Kconfig2
-rw-r--r--drivers/media/video/cx88/cx88-blackbird.c3
-rw-r--r--drivers/media/video/cx88/cx88-input.c2
-rw-r--r--drivers/media/video/cx88/cx88-video.c5
-rw-r--r--drivers/media/video/msp3400-driver.c10
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.c8
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-io.c9
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-io.h2
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-ioread.c5
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-sysfs.c85
-rw-r--r--drivers/media/video/saa7134/saa7134-alsa.c10
-rw-r--r--drivers/media/video/saa7134/saa7134-core.c16
-rw-r--r--drivers/media/video/saa7134/saa7134-oss.c10
-rw-r--r--drivers/media/video/saa7134/saa7134-video.c6
-rw-r--r--drivers/media/video/saa7134/saa7134.h4
-rw-r--r--drivers/media/video/stradis.c1
-rw-r--r--drivers/media/video/tuner-core.c31
-rw-r--r--drivers/media/video/tuner-simple.c19
-rw-r--r--drivers/media/video/usbvideo/Kconfig8
-rw-r--r--drivers/media/video/v4l2-common.c24
-rw-r--r--drivers/media/video/videodev.c29
-rw-r--r--drivers/media/video/vivi.c4
-rw-r--r--drivers/message/fusion/Kconfig2
-rw-r--r--drivers/message/fusion/Makefile1
-rw-r--r--drivers/message/fusion/mptbase.c99
-rw-r--r--drivers/message/fusion/mptbase.h13
-rw-r--r--drivers/message/fusion/mptctl.c4
-rw-r--r--drivers/message/fusion/mptctl.h5
-rw-r--r--drivers/message/fusion/mptfc.c14
-rw-r--r--drivers/message/fusion/mptsas.c109
-rw-r--r--drivers/message/fusion/mptscsih.c118
-rw-r--r--drivers/message/fusion/mptspi.c10
-rw-r--r--drivers/message/i2o/core.h3
-rw-r--r--drivers/message/i2o/i2o_config.c4
-rw-r--r--drivers/mfd/ucb1x00-core.c2
-rw-r--r--drivers/mfd/ucb1x00.h1
-rw-r--r--drivers/mmc/sdhci.c6
-rw-r--r--drivers/net/3c59x.c166
-rw-r--r--drivers/net/8139cp.c35
-rw-r--r--drivers/net/8139too.c39
-rw-r--r--drivers/net/appletalk/Kconfig2
-rw-r--r--drivers/net/b44.c27
-rw-r--r--drivers/net/bnx2.c32
-rw-r--r--drivers/net/cassini.c25
-rw-r--r--drivers/net/chelsio/sge.c2
-rw-r--r--drivers/net/declance.c7
-rw-r--r--drivers/net/dl2k.c43
-rw-r--r--drivers/net/dummy.c1
-rw-r--r--drivers/net/e1000/e1000.h13
-rw-r--r--drivers/net/e1000/e1000_ethtool.c141
-rw-r--r--drivers/net/e1000/e1000_hw.c1772
-rw-r--r--drivers/net/e1000/e1000_hw.h398
-rw-r--r--drivers/net/e1000/e1000_main.c446
-rw-r--r--drivers/net/e1000/e1000_osdep.h13
-rw-r--r--drivers/net/e1000/e1000_param.c199
-rw-r--r--drivers/net/eepro100.c6
-rw-r--r--drivers/net/epic100.c93
-rw-r--r--drivers/net/fealnx.c36
-rw-r--r--drivers/net/forcedeth.c51
-rw-r--r--drivers/net/gt96100eth.c3
-rw-r--r--drivers/net/gt96100eth.h2
-rw-r--r--drivers/net/hamachi.c16
-rw-r--r--drivers/net/hamradio/bpqether.c7
-rw-r--r--drivers/net/ifb.c1
-rw-r--r--drivers/net/irda/ali-ircc.c3
-rw-r--r--drivers/net/irda/smsc-ircc2.c2
-rw-r--r--drivers/net/ixgb/ixgb_main.c6
-rw-r--r--drivers/net/loopback.c2
-rw-r--r--drivers/net/myri10ge/myri10ge.c58
-rw-r--r--drivers/net/natsemi.c117
-rw-r--r--drivers/net/ne2k-pci.c9
-rw-r--r--drivers/net/ni5010.c52
-rw-r--r--drivers/net/ns83820.c41
-rw-r--r--drivers/net/pci-skeleton.c19
-rw-r--r--drivers/net/pcnet32.c520
-rw-r--r--drivers/net/phy/cicada.c42
-rw-r--r--drivers/net/phy/phy.c8
-rw-r--r--drivers/net/r8169.c40
-rw-r--r--drivers/net/s2io.c671
-rw-r--r--drivers/net/s2io.h15
-rw-r--r--drivers/net/sk98lin/h/xmac_ii.h2
-rw-r--r--drivers/net/skge.c5
-rw-r--r--drivers/net/skge.h4
-rw-r--r--drivers/net/sky2.c52
-rw-r--r--drivers/net/sky2.h2
-rw-r--r--drivers/net/smc91x.h18
-rw-r--r--drivers/net/spider_net.c580
-rw-r--r--drivers/net/spider_net.h73
-rw-r--r--drivers/net/starfire.c123
-rw-r--r--drivers/net/sundance.c106
-rw-r--r--drivers/net/sunhme.c9
-rw-r--r--drivers/net/sunlance.c8
-rw-r--r--drivers/net/tg3.c124
-rw-r--r--drivers/net/tulip/winbond-840.c29
-rw-r--r--drivers/net/tulip/xircom_tulip_cb.c27
-rw-r--r--drivers/net/typhoon.c4
-rw-r--r--drivers/net/via-rhine.c121
-rw-r--r--drivers/net/via-velocity.c119
-rw-r--r--drivers/net/via-velocity.h4
-rw-r--r--drivers/net/wan/Kconfig12
-rw-r--r--drivers/net/wan/Makefile1
-rw-r--r--drivers/net/wan/c101.c30
-rw-r--r--drivers/net/wan/hd6457x.c26
-rw-r--r--drivers/net/wan/hdlc_cisco.c14
-rw-r--r--drivers/net/wan/hdlc_fr.c14
-rw-r--r--drivers/net/wan/hdlc_generic.c65
-rw-r--r--drivers/net/wan/hdlc_ppp.c1
-rw-r--r--drivers/net/wan/hdlc_raw.c1
-rw-r--r--drivers/net/wan/hdlc_raw_eth.c1
-rw-r--r--drivers/net/wan/hdlc_x25.c1
-rw-r--r--drivers/net/wan/n2.c3
-rw-r--r--drivers/net/wan/wanxl.c5
-rw-r--r--drivers/net/wireless/Kconfig2
-rw-r--r--drivers/net/wireless/Makefile1
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.c33
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.h24
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_radio.c7
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_wx.c2
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_xmit.c5
-rw-r--r--drivers/net/wireless/hostap/hostap_plx.c2
-rw-r--r--drivers/net/wireless/orinoco.c4
-rw-r--r--drivers/net/wireless/spectrum_cs.c37
-rw-r--r--drivers/net/wireless/zd1201.c2
-rw-r--r--drivers/net/wireless/zd1211rw/Kconfig19
-rw-r--r--drivers/net/wireless/zd1211rw/Makefile11
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.c1615
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.h827
-rw-r--r--drivers/net/wireless/zd1211rw/zd_def.h48
-rw-r--r--drivers/net/wireless/zd1211rw/zd_ieee80211.c191
-rw-r--r--drivers/net/wireless/zd1211rw/zd_ieee80211.h85
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c1057
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.h190
-rw-r--r--drivers/net/wireless/zd1211rw/zd_netdev.c267
-rw-r--r--drivers/net/wireless/zd1211rw/zd_netdev.h45
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf.c151
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf.h82
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf_al2230.c308
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf_rf2959.c279
-rw-r--r--drivers/net/wireless/zd1211rw/zd_types.h71
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c1309
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.h240
-rw-r--r--drivers/net/wireless/zd1211rw/zd_util.c82
-rw-r--r--drivers/net/wireless/zd1211rw/zd_util.h (renamed from drivers/w1/w1_io.h)27
-rw-r--r--drivers/net/yellowfin.c39
-rw-r--r--drivers/pci/hotplug/Kconfig5
-rw-r--r--drivers/pci/hotplug/acpiphp_core.c3
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c2
-rw-r--r--drivers/pci/msi.c4
-rw-r--r--drivers/pci/pci.c11
-rw-r--r--drivers/pci/pci.h10
-rw-r--r--drivers/pci/pcie/portdrv_pci.c38
-rw-r--r--drivers/pci/probe.c1
-rw-r--r--drivers/pci/quirks.c115
-rw-r--r--drivers/pci/search.c48
-rw-r--r--drivers/pcmcia/Kconfig2
-rw-r--r--drivers/pcmcia/pcmcia_ioctl.c16
-rw-r--r--drivers/pcmcia/pcmcia_resource.c15
-rw-r--r--drivers/pnp/interface.c12
-rw-r--r--drivers/pnp/pnpbios/core.c2
-rw-r--r--drivers/rtc/Kconfig10
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/rtc-isl1208.c591
-rw-r--r--drivers/rtc/rtc-vr41xx.c2
-rw-r--r--drivers/s390/block/dasd_devmap.c8
-rw-r--r--drivers/s390/block/dasd_eckd.c20
-rw-r--r--drivers/s390/block/dasd_fba.c4
-rw-r--r--drivers/s390/block/dasd_genhd.c8
-rw-r--r--drivers/s390/block/dasd_ioctl.c2
-rw-r--r--drivers/s390/block/xpram.c74
-rw-r--r--drivers/s390/char/con3215.c2
-rw-r--r--drivers/s390/char/ctrlchar.c2
-rw-r--r--drivers/s390/char/defkeymap.c6
-rw-r--r--drivers/s390/char/fs3270.c12
-rw-r--r--drivers/s390/char/keyboard.c6
-rw-r--r--drivers/s390/char/raw3270.c86
-rw-r--r--drivers/s390/char/raw3270.h2
-rw-r--r--drivers/s390/char/tape_34xx.c6
-rw-r--r--drivers/s390/char/tape_class.c10
-rw-r--r--drivers/s390/char/tape_core.c18
-rw-r--r--drivers/s390/char/tty3270.c24
-rw-r--r--drivers/s390/char/vmlogrdr.c6
-rw-r--r--drivers/s390/char/vmwatchdog.c2
-rw-r--r--drivers/s390/cio/ccwgroup.c12
-rw-r--r--drivers/s390/cio/chsc.c34
-rw-r--r--drivers/s390/cio/cio.c4
-rw-r--r--drivers/s390/cio/cio.h3
-rw-r--r--drivers/s390/cio/cmf.c5
-rw-r--r--drivers/s390/cio/css.c36
-rw-r--r--drivers/s390/cio/css.h4
-rw-r--r--drivers/s390/cio/device.c14
-rw-r--r--drivers/s390/cio/device_fsm.c88
-rw-r--r--drivers/s390/cio/device_pgid.c122
-rw-r--r--drivers/s390/cio/device_status.c7
-rw-r--r--drivers/s390/cio/qdio.c2
-rw-r--r--drivers/s390/net/claw.c2
-rw-r--r--drivers/s390/net/ctcmain.c21
-rw-r--r--drivers/s390/net/iucv.c2
-rw-r--r--drivers/s390/net/netiucv.c2
-rw-r--r--drivers/s390/net/qeth_main.c27
-rw-r--r--drivers/s390/net/qeth_sys.c4
-rw-r--r--drivers/s390/net/smsgiucv.c14
-rw-r--r--drivers/s390/s390mach.c10
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c2
-rw-r--r--drivers/s390/scsi/zfcp_scsi.c47
-rw-r--r--drivers/sbus/sbus.c2
-rw-r--r--drivers/scsi/53c7xx.c8
-rw-r--r--drivers/scsi/NCR53C9x.c18
-rw-r--r--drivers/scsi/NCR_D700.c14
-rw-r--r--drivers/scsi/aha152x.c43
-rw-r--r--drivers/scsi/ahci.c27
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_core.c2
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.c21
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.h1
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.c1
-rw-r--r--drivers/scsi/aic7xxx/aicasm/Makefile2
-rw-r--r--drivers/scsi/arm/fas216.c2
-rw-r--r--drivers/scsi/ata_piix.c165
-rw-r--r--drivers/scsi/atari_NCR5380.c2
-rw-r--r--drivers/scsi/constants.c126
-rw-r--r--drivers/scsi/esp.c16
-rw-r--r--drivers/scsi/ibmvscsi/iseries_vscsi.c2
-rw-r--r--drivers/scsi/ibmvscsi/rpa_vscsi.c1
-rw-r--r--drivers/scsi/jazz_esp.c2
-rw-r--r--drivers/scsi/libata-core.c289
-rw-r--r--drivers/scsi/libata-eh.c464
-rw-r--r--drivers/scsi/libata-scsi.c124
-rw-r--r--drivers/scsi/lpfc/lpfc.h9
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c89
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h1
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c65
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c4
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c59
-rw-r--r--drivers/scsi/lpfc/lpfc_mem.c5
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c11
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c64
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c55
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h2
-rw-r--r--drivers/scsi/mac53c94.c2
-rw-r--r--drivers/scsi/mesh.c2
-rw-r--r--drivers/scsi/pluto.c2
-rw-r--r--drivers/scsi/qlogicpti.c4
-rw-r--r--drivers/scsi/sata_promise.c7
-rw-r--r--drivers/scsi/sata_sil.c105
-rw-r--r--drivers/scsi/sata_sil24.c134
-rw-r--r--drivers/scsi/sata_vsc.c2
-rw-r--r--drivers/scsi/scsi.c11
-rw-r--r--drivers/scsi/scsi_debug.c72
-rw-r--r--drivers/scsi/scsi_error.c210
-rw-r--r--drivers/scsi/scsi_ioctl.c5
-rw-r--r--drivers/scsi/scsi_lib.c88
-rw-r--r--drivers/scsi/scsi_priv.h1
-rw-r--r--drivers/scsi/scsi_transport_sas.c64
-rw-r--r--drivers/scsi/sd.c3
-rw-r--r--drivers/scsi/seagate.c2
-rw-r--r--drivers/scsi/sr.c5
-rw-r--r--drivers/scsi/st.c7
-rw-r--r--drivers/scsi/sun3_NCR5380.c2
-rw-r--r--drivers/scsi/sun3x_esp.c2
-rw-r--r--drivers/scsi/wd33c93.c2
-rw-r--r--drivers/serial/8250.c25
-rw-r--r--drivers/serial/at91_serial.c5
-rw-r--r--drivers/serial/dz.c2
-rw-r--r--drivers/serial/ip22zilog.c3
-rw-r--r--drivers/serial/serial_core.c1
-rw-r--r--drivers/serial/sunsab.c7
-rw-r--r--drivers/serial/sunsu.c40
-rw-r--r--drivers/serial/sunzilog.c125
-rw-r--r--drivers/serial/vr41xx_siu.c1
-rw-r--r--drivers/usb/Kconfig3
-rw-r--r--drivers/usb/Makefile2
-rw-r--r--drivers/usb/class/cdc-acm.c49
-rw-r--r--drivers/usb/core/Kconfig3
-rw-r--r--drivers/usb/core/devio.c20
-rw-r--r--drivers/usb/core/file.c13
-rw-r--r--drivers/usb/core/hub.c10
-rw-r--r--drivers/usb/core/inode.c2
-rw-r--r--drivers/usb/gadget/Kconfig2
-rw-r--r--drivers/usb/gadget/at91_udc.c176
-rw-r--r--drivers/usb/gadget/at91_udc.h1
-rw-r--r--drivers/usb/gadget/dummy_hcd.c6
-rw-r--r--drivers/usb/gadget/epautoconf.c16
-rw-r--r--drivers/usb/gadget/ether.c8
-rw-r--r--drivers/usb/gadget/file_storage.c2
-rw-r--r--drivers/usb/gadget/rndis.c2
-rw-r--r--drivers/usb/gadget/rndis.h2
-rw-r--r--drivers/usb/gadget/serial.c2
-rw-r--r--drivers/usb/gadget/zero.c2
-rw-r--r--drivers/usb/host/ehci-au1xxx.c23
-rw-r--r--drivers/usb/host/ehci-hcd.c9
-rw-r--r--drivers/usb/host/ohci-at91.c88
-rw-r--r--drivers/usb/host/ohci-au1xxx.c7
-rw-r--r--drivers/usb/host/ohci-ep93xx.c225
-rw-r--r--drivers/usb/host/ohci-hcd.c8
-rw-r--r--drivers/usb/host/ohci-hub.c4
-rw-r--r--drivers/usb/host/pci-quirks.c8
-rw-r--r--drivers/usb/host/uhci-q.c4
-rw-r--r--drivers/usb/input/ati_remote.c5
-rw-r--r--drivers/usb/input/hid-core.c4
-rw-r--r--drivers/usb/misc/Kconfig10
-rw-r--r--drivers/usb/misc/Makefile2
-rw-r--r--drivers/usb/misc/cy7c63.c244
-rw-r--r--drivers/usb/misc/cypress_cy7c63.c284
-rw-r--r--drivers/usb/misc/usblcd.c6
-rw-r--r--drivers/usb/mon/mon_text.c7
-rw-r--r--drivers/usb/net/rtl8150.c86
-rw-r--r--drivers/usb/serial/Kconfig35
-rw-r--r--drivers/usb/serial/Makefile2
-rw-r--r--drivers/usb/serial/airprime.c2
-rw-r--r--drivers/usb/serial/anydata.c123
-rw-r--r--drivers/usb/serial/ark3116.c2
-rw-r--r--drivers/usb/serial/belkin_sa.c2
-rw-r--r--drivers/usb/serial/bus.c2
-rw-r--r--drivers/usb/serial/console.c3
-rw-r--r--drivers/usb/serial/cp2101.c2
-rw-r--r--drivers/usb/serial/cyberjack.c2
-rw-r--r--drivers/usb/serial/cypress_m8.c2
-rw-r--r--drivers/usb/serial/digi_acceleport.c2
-rw-r--r--drivers/usb/serial/empeg.c2
-rw-r--r--drivers/usb/serial/ezusb.c2
-rw-r--r--drivers/usb/serial/ftdi_sio.c109
-rw-r--r--drivers/usb/serial/ftdi_sio.h19
-rw-r--r--drivers/usb/serial/funsoft.c2
-rw-r--r--drivers/usb/serial/garmin_gps.c3
-rw-r--r--drivers/usb/serial/generic.c3
-rw-r--r--drivers/usb/serial/hp4x.c2
-rw-r--r--drivers/usb/serial/io_edgeport.c2
-rw-r--r--drivers/usb/serial/io_ti.c2
-rw-r--r--drivers/usb/serial/ipaq.c26
-rw-r--r--drivers/usb/serial/ipw.c4
-rw-r--r--drivers/usb/serial/ir-usb.c2
-rw-r--r--drivers/usb/serial/keyspan.c2
-rw-r--r--drivers/usb/serial/keyspan_pda.c3
-rw-r--r--drivers/usb/serial/kl5kusb105.c2
-rw-r--r--drivers/usb/serial/kobil_sct.c2
-rw-r--r--drivers/usb/serial/mct_u232.c2
-rw-r--r--drivers/usb/serial/navman.c2
-rw-r--r--drivers/usb/serial/omninet.c2
-rw-r--r--drivers/usb/serial/option.c82
-rw-r--r--drivers/usb/serial/pl2303.c5
-rw-r--r--drivers/usb/serial/pl2303.h9
-rw-r--r--drivers/usb/serial/safe_serial.c2
-rw-r--r--drivers/usb/serial/sierra.c75
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c2
-rw-r--r--drivers/usb/serial/usb-serial.c25
-rw-r--r--drivers/usb/serial/usb-serial.h300
-rw-r--r--drivers/usb/serial/visor.c39
-rw-r--r--drivers/usb/serial/whiteheat.c2
-rw-r--r--drivers/usb/storage/scsiglue.c12
-rw-r--r--drivers/usb/storage/transport.c2
-rw-r--r--drivers/usb/storage/unusual_devs.h89
-rw-r--r--drivers/usb/storage/usb.c42
-rw-r--r--drivers/usb/storage/usb.h4
-rw-r--r--drivers/video/68328fb.c1
-rw-r--r--drivers/video/Kconfig58
-rw-r--r--drivers/video/Makefile2
-rw-r--r--drivers/video/S3triofb.c1
-rw-r--r--drivers/video/amifb.c1
-rw-r--r--drivers/video/arcfb.c1
-rw-r--r--drivers/video/asiliantfb.c1
-rw-r--r--drivers/video/atafb.c1
-rw-r--r--drivers/video/aty/aty128fb.c70
-rw-r--r--drivers/video/aty/atyfb_base.c57
-rw-r--r--drivers/video/aty/radeon_base.c19
-rw-r--r--drivers/video/aty/radeon_pm.c146
-rw-r--r--drivers/video/aty/radeonfb.h6
-rw-r--r--drivers/video/backlight/Kconfig4
-rw-r--r--drivers/video/chipsfb.c4
-rw-r--r--drivers/video/cirrusfb.c1
-rw-r--r--drivers/video/console/dummycon.c2
-rw-r--r--drivers/video/console/fbcon.c1
-rw-r--r--drivers/video/console/mdacon.c5
-rw-r--r--drivers/video/console/newport_con.c1
-rw-r--r--drivers/video/console/promcon.c1
-rw-r--r--drivers/video/console/softcursor.c1
-rw-r--r--drivers/video/console/sticon.c1
-rw-r--r--drivers/video/console/vgacon.c2
-rw-r--r--drivers/video/controlfb.c1
-rw-r--r--drivers/video/cyber2000fb.c1
-rw-r--r--drivers/video/cyberfb.c1
-rw-r--r--drivers/video/dnfb.c1
-rw-r--r--drivers/video/epson1355fb.c1
-rw-r--r--drivers/video/fb_notify.c46
-rw-r--r--drivers/video/fbcmap.c1
-rw-r--r--drivers/video/fbmem.c56
-rw-r--r--drivers/video/fbmon.c1
-rw-r--r--drivers/video/g364fb.c1
-rw-r--r--drivers/video/geode/gx1fb_core.c1
-rw-r--r--drivers/video/geode/gxfb_core.c1
-rw-r--r--drivers/video/hgafb.c1
-rw-r--r--drivers/video/hitfb.c1
-rw-r--r--drivers/video/hpfb.c1
-rw-r--r--drivers/video/i810/i810_main.c1
-rw-r--r--drivers/video/igafb.c1
-rw-r--r--drivers/video/imacfb.c2
-rw-r--r--drivers/video/imsttfb.c1
-rw-r--r--drivers/video/intelfb/intelfbdrv.c2
-rw-r--r--drivers/video/intelfb/intelfbhw.c1
-rw-r--r--drivers/video/kyro/fbdev.c1
-rw-r--r--drivers/video/macfb.c1
-rw-r--r--drivers/video/matrox/matroxfb_base.h1
-rw-r--r--drivers/video/maxinefb.c1
-rw-r--r--drivers/video/mbx/Makefile4
-rw-r--r--drivers/video/mbx/mbxdebugfs.c188
-rw-r--r--drivers/video/mbx/mbxfb.c683
-rw-r--r--drivers/video/mbx/reg_bits.h418
-rw-r--r--drivers/video/mbx/regs.h195
-rw-r--r--drivers/video/modedb.c1
-rw-r--r--drivers/video/neofb.c1
-rw-r--r--drivers/video/nvidia/nv_backlight.c32
-rw-r--r--drivers/video/nvidia/nv_proto.h2
-rw-r--r--drivers/video/nvidia/nvidia.c21
-rw-r--r--drivers/video/offb.c308
-rw-r--r--drivers/video/platinumfb.c1
-rw-r--r--drivers/video/pm2fb.c1
-rw-r--r--drivers/video/pm3fb.c1
-rw-r--r--drivers/video/pmag-aa-fb.c1
-rw-r--r--drivers/video/pvr2fb.c1
-rw-r--r--drivers/video/q40fb.c1
-rw-r--r--drivers/video/retz3fb.c1
-rw-r--r--drivers/video/riva/fbdev.c52
-rw-r--r--drivers/video/s3c2410fb.c1
-rw-r--r--drivers/video/savage/savagefb_driver.c1
-rw-r--r--drivers/video/sis/sis_main.c6
-rw-r--r--drivers/video/skeletonfb.c1
-rw-r--r--drivers/video/sun3fb.c1
-rw-r--r--drivers/video/tdfxfb.c1
-rw-r--r--drivers/video/tgafb.c1
-rw-r--r--drivers/video/tx3912fb.c1
-rw-r--r--drivers/video/valkyriefb.c1
-rw-r--r--drivers/video/vesafb.c2
-rw-r--r--drivers/video/vfb.c1
-rw-r--r--drivers/video/vga16fb.c2
-rw-r--r--drivers/video/virgefb.c1
-rw-r--r--drivers/w1/masters/ds2482.c2
633 files changed, 20165 insertions, 7298 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index fef7bab1224..56c5ba87462 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -107,7 +107,6 @@ config ACPI_BUTTON
config ACPI_VIDEO
tristate "Video"
depends on X86
- default y
help
This driver implement the ACPI Extensions For Display Adapters
for integrated graphics devices on motherboard, as specified in
@@ -135,8 +134,7 @@ config ACPI_FAN
config ACPI_DOCK
tristate "Dock"
- depends on !ACPI_IBM_DOCK
- default y
+ depends on EXPERIMENTAL
help
This driver adds support for ACPI controlled docking stations
@@ -214,6 +212,7 @@ config ACPI_IBM
config ACPI_IBM_DOCK
bool "Legacy Docking Station Support"
depends on ACPI_IBM
+ depends on ACPI_DOCK=n
default n
---help---
Allows the ibm_acpi driver to handle docking station events.
@@ -357,7 +356,6 @@ config ACPI_SBS
tristate "Smart Battery System (EXPERIMENTAL)"
depends on X86 && I2C
depends on EXPERIMENTAL
- default y
help
This driver adds support for the Smart Battery System.
Depends on I2C (Device Drivers ---> I2C support)
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c
index 24ccf81d135..96309b9660d 100644
--- a/drivers/acpi/ac.c
+++ b/drivers/acpi/ac.c
@@ -72,7 +72,7 @@ struct acpi_ac {
unsigned long state;
};
-static struct file_operations acpi_ac_fops = {
+static const struct file_operations acpi_ac_fops = {
.open = acpi_ac_open_fs,
.read = seq_read,
.llseek = seq_lseek,
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 24bf4dca88c..6e5221707d9 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -557,7 +557,7 @@ static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file)
return single_open(file, acpi_battery_read_alarm, PDE(inode)->data);
}
-static struct file_operations acpi_battery_info_ops = {
+static const struct file_operations acpi_battery_info_ops = {
.open = acpi_battery_info_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -565,7 +565,7 @@ static struct file_operations acpi_battery_info_ops = {
.owner = THIS_MODULE,
};
-static struct file_operations acpi_battery_state_ops = {
+static const struct file_operations acpi_battery_state_ops = {
.open = acpi_battery_state_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -573,7 +573,7 @@ static struct file_operations acpi_battery_state_ops = {
.owner = THIS_MODULE,
};
-static struct file_operations acpi_battery_alarm_ops = {
+static const struct file_operations acpi_battery_alarm_ops = {
.open = acpi_battery_alarm_open_fs,
.read = seq_read,
.write = acpi_battery_write_alarm,
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index ea5a0496a4f..b2977695e12 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -192,8 +192,8 @@ int acpi_bus_set_power(acpi_handle handle, int state)
/* Make sure this is a valid target state */
if (!device->flags.power_manageable) {
- printk(KERN_DEBUG "Device `[%s]' is not power manageable",
- device->kobj.name);
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable",
+ device->kobj.name));
return -ENODEV;
}
/*
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index fd1ba05eab6..5ef885e82c7 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -87,14 +87,14 @@ struct acpi_button {
unsigned long pushed;
};
-static struct file_operations acpi_button_info_fops = {
+static const struct file_operations acpi_button_info_fops = {
.open = acpi_button_info_open_fs,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
-static struct file_operations acpi_button_state_fops = {
+static const struct file_operations acpi_button_state_fops = {
.open = acpi_button_state_open_fs,
.read = seq_read,
.llseek = seq_lseek,
diff --git a/drivers/acpi/cm_sbs.c b/drivers/acpi/cm_sbs.c
index 574a75a166c..a01ce6700bf 100644
--- a/drivers/acpi/cm_sbs.c
+++ b/drivers/acpi/cm_sbs.c
@@ -39,50 +39,43 @@ ACPI_MODULE_NAME("cm_sbs")
static struct proc_dir_entry *acpi_ac_dir;
static struct proc_dir_entry *acpi_battery_dir;
-static struct semaphore cm_sbs_sem;
+static DEFINE_MUTEX(cm_sbs_mutex);
-static int lock_ac_dir_cnt = 0;
-static int lock_battery_dir_cnt = 0;
+static int lock_ac_dir_cnt;
+static int lock_battery_dir_cnt;
struct proc_dir_entry *acpi_lock_ac_dir(void)
{
-
- down(&cm_sbs_sem);
- if (!acpi_ac_dir) {
+ mutex_lock(&cm_sbs_mutex);
+ if (!acpi_ac_dir)
acpi_ac_dir = proc_mkdir(ACPI_AC_CLASS, acpi_root_dir);
- }
if (acpi_ac_dir) {
lock_ac_dir_cnt++;
} else {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Cannot create %s\n", ACPI_AC_CLASS));
}
- up(&cm_sbs_sem);
+ mutex_unlock(&cm_sbs_mutex);
return acpi_ac_dir;
}
-
EXPORT_SYMBOL(acpi_lock_ac_dir);
void acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir_param)
{
-
- down(&cm_sbs_sem);
- if (acpi_ac_dir_param) {
+ mutex_lock(&cm_sbs_mutex);
+ if (acpi_ac_dir_param)
lock_ac_dir_cnt--;
- }
if (lock_ac_dir_cnt == 0 && acpi_ac_dir_param && acpi_ac_dir) {
remove_proc_entry(ACPI_AC_CLASS, acpi_root_dir);
acpi_ac_dir = 0;
}
- up(&cm_sbs_sem);
+ mutex_unlock(&cm_sbs_mutex);
}
-
EXPORT_SYMBOL(acpi_unlock_ac_dir);
struct proc_dir_entry *acpi_lock_battery_dir(void)
{
-
- down(&cm_sbs_sem);
+ mutex_lock(&cm_sbs_mutex);
if (!acpi_battery_dir) {
acpi_battery_dir =
proc_mkdir(ACPI_BATTERY_CLASS, acpi_root_dir);
@@ -93,39 +86,28 @@ struct proc_dir_entry *acpi_lock_battery_dir(void)
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Cannot create %s\n", ACPI_BATTERY_CLASS));
}
- up(&cm_sbs_sem);
+ mutex_unlock(&cm_sbs_mutex);
return acpi_battery_dir;
}
-
EXPORT_SYMBOL(acpi_lock_battery_dir);
void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir_param)
{
-
- down(&cm_sbs_sem);
- if (acpi_battery_dir_param) {
+ mutex_lock(&cm_sbs_mutex);
+ if (acpi_battery_dir_param)
lock_battery_dir_cnt--;
- }
if (lock_battery_dir_cnt == 0 && acpi_battery_dir_param
&& acpi_battery_dir) {
remove_proc_entry(ACPI_BATTERY_CLASS, acpi_root_dir);
acpi_battery_dir = 0;
}
- up(&cm_sbs_sem);
+ mutex_unlock(&cm_sbs_mutex);
return;
}
-
EXPORT_SYMBOL(acpi_unlock_battery_dir);
static int __init acpi_cm_sbs_init(void)
{
-
- if (acpi_disabled)
- return 0;
-
- init_MUTEX(&cm_sbs_sem);
-
return 0;
}
-
subsys_initcall(acpi_cm_sbs_init);
diff --git a/drivers/acpi/dispatcher/dsinit.c b/drivers/acpi/dispatcher/dsinit.c
index daf51b5b587..1888c055d10 100644
--- a/drivers/acpi/dispatcher/dsinit.c
+++ b/drivers/acpi/dispatcher/dsinit.c
@@ -116,16 +116,6 @@ acpi_ds_init_one_object(acpi_handle obj_handle,
case ACPI_TYPE_METHOD:
- /*
- * Set the execution data width (32 or 64) based upon the
- * revision number of the parent ACPI table.
- * TBD: This is really for possible future support of integer width
- * on a per-table basis. Currently, we just use a global for the width.
- */
- if (info->table_desc->pointer->revision == 1) {
- node->flags |= ANOBJ_DATA_WIDTH_32;
- }
-
info->method_count++;
break;
diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c
index a39a33f4847..cf888add319 100644
--- a/drivers/acpi/dispatcher/dsmethod.c
+++ b/drivers/acpi/dispatcher/dsmethod.c
@@ -134,7 +134,7 @@ acpi_ds_create_method_mutex(union acpi_operand_object *method_desc)
union acpi_operand_object *mutex_desc;
acpi_status status;
- ACPI_FUNCTION_NAME(ds_create_method_mutex);
+ ACPI_FUNCTION_TRACE(ds_create_method_mutex);
/* Create the new mutex object */
@@ -493,7 +493,7 @@ acpi_ds_restart_control_method(struct acpi_walk_state *walk_state,
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
"****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n",
- (char *)&walk_state->method_node->name,
+ acpi_ut_get_node_name(walk_state->method_node),
walk_state->method_call_op, return_desc));
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
@@ -610,6 +610,7 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
acpi_os_release_mutex(method_desc->method.mutex->mutex.
os_mutex);
+ method_desc->method.mutex->mutex.owner_thread = NULL;
}
}
@@ -620,27 +621,11 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
*/
method_node = walk_state->method_node;
- /* Lock namespace for possible update */
-
- status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
- if (ACPI_FAILURE(status)) {
- return_VOID;
- }
-
- /*
- * Delete any namespace entries created immediately underneath
- * the method
- */
- if (method_node && method_node->child) {
- acpi_ns_delete_namespace_subtree(method_node);
- }
-
/*
- * Delete any namespace entries created anywhere else within
+ * Delete any namespace objects created anywhere within
* the namespace by the execution of this method
*/
acpi_ns_delete_namespace_by_owner(method_desc->method.owner_id);
- status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
}
/* Decrement the thread count on the method */
diff --git a/drivers/acpi/dispatcher/dswexec.c b/drivers/acpi/dispatcher/dswexec.c
index b1ded62d0df..d7a616c3104 100644
--- a/drivers/acpi/dispatcher/dswexec.c
+++ b/drivers/acpi/dispatcher/dswexec.c
@@ -313,10 +313,10 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state,
case AML_CLASS_EXECUTE:
case AML_CLASS_CREATE:
/*
- * Most operators with arguments.
+ * Most operators with arguments (except create_xxx_field operators)
* Start a new result/operand state
*/
- if (walk_state->opcode != AML_CREATE_FIELD_OP) {
+ if (walk_state->op_info->object_type != ACPI_TYPE_BUFFER_FIELD) {
status = acpi_ds_result_stack_push(walk_state);
}
break;
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index 510a9452429..578b99b71d9 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -58,8 +58,8 @@ struct dock_dependent_device {
};
#define DOCK_DOCKING 0x00000001
-#define DOCK_EVENT KOBJ_DOCK
-#define UNDOCK_EVENT KOBJ_UNDOCK
+#define DOCK_EVENT 3
+#define UNDOCK_EVENT 2
static struct dock_station *dock_station;
@@ -322,11 +322,10 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event)
static void dock_event(struct dock_station *ds, u32 event, int num)
{
- struct acpi_device *device;
-
- device = dock_create_acpi_device(ds->handle);
- if (device)
- kobject_uevent(&device->kobj, num);
+ /*
+ * we don't do events until someone tells me that
+ * they would like to have them.
+ */
}
/**
@@ -627,6 +626,7 @@ static int dock_add(acpi_handle handle)
INIT_LIST_HEAD(&dock_station->hotplug_devices);
spin_lock_init(&dock_station->dd_lock);
spin_lock_init(&dock_station->hp_lock);
+ ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
/* Find dependent devices */
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 8c5d7df7d34..e5d79636285 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -929,7 +929,7 @@ static int acpi_ec_info_open_fs(struct inode *inode, struct file *file)
return single_open(file, acpi_ec_read_info, PDE(inode)->data);
}
-static struct file_operations acpi_ec_info_ops = {
+static const struct file_operations acpi_ec_info_ops = {
.open = acpi_ec_info_open_fs,
.read = seq_read,
.llseek = seq_lseek,
diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c
index a901b23e95e..959a893c8d1 100644
--- a/drivers/acpi/event.c
+++ b/drivers/acpi/event.c
@@ -99,7 +99,7 @@ static unsigned int acpi_system_poll_event(struct file *file, poll_table * wait)
return 0;
}
-static struct file_operations acpi_system_event_ops = {
+static const struct file_operations acpi_system_event_ops = {
.open = acpi_system_open_event,
.read = acpi_system_read_event,
.release = acpi_system_close_event,
diff --git a/drivers/acpi/events/evregion.c b/drivers/acpi/events/evregion.c
index 094a17e4c86..21caae04fe8 100644
--- a/drivers/acpi/events/evregion.c
+++ b/drivers/acpi/events/evregion.c
@@ -528,34 +528,40 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj,
}
}
- /* Call the setup handler with the deactivate notification */
+ /*
+ * If the region has been activated, call the setup handler
+ * with the deactivate notification
+ */
+ if (region_obj->region.flags & AOPOBJ_SETUP_COMPLETE) {
+ region_setup = handler_obj->address_space.setup;
+ status =
+ region_setup(region_obj,
+ ACPI_REGION_DEACTIVATE,
+ handler_obj->address_space.
+ context, region_context);
- region_setup = handler_obj->address_space.setup;
- status =
- region_setup(region_obj, ACPI_REGION_DEACTIVATE,
- handler_obj->address_space.context,
- region_context);
+ /* Init routine may fail, Just ignore errors */
- /* Init routine may fail, Just ignore errors */
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status,
+ "from region handler - deactivate, [%s]",
+ acpi_ut_get_region_name
+ (region_obj->region.
+ space_id)));
+ }
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "from region init, [%s]",
- acpi_ut_get_region_name
- (region_obj->region.space_id)));
+ region_obj->region.flags &=
+ ~(AOPOBJ_SETUP_COMPLETE);
}
- region_obj->region.flags &= ~(AOPOBJ_SETUP_COMPLETE);
-
/*
* Remove handler reference in the region
*
- * NOTE: this doesn't mean that the region goes away
- * The region is just inaccessible as indicated to
- * the _REG method
+ * NOTE: this doesn't mean that the region goes away, the region
+ * is just inaccessible as indicated to the _REG method
*
- * If the region is on the handler's list
- * this better be the region's handler
+ * If the region is on the handler's list, this must be the
+ * region's handler
*/
region_obj->region.handler = NULL;
acpi_ut_remove_reference(handler_obj);
diff --git a/drivers/acpi/events/evxface.c b/drivers/acpi/events/evxface.c
index 4f948df17ab..923fd2b4695 100644
--- a/drivers/acpi/events/evxface.c
+++ b/drivers/acpi/events/evxface.c
@@ -428,7 +428,7 @@ acpi_remove_notify_handler(acpi_handle device,
node = acpi_ns_map_handle_to_node(device);
if (!node) {
status = AE_BAD_PARAMETER;
- goto unlock;
+ goto unlock_and_exit;
}
/* Root Object */
@@ -442,7 +442,7 @@ acpi_remove_notify_handler(acpi_handle device,
((handler_type & ACPI_DEVICE_NOTIFY) &&
!acpi_gbl_device_notify.handler)) {
status = AE_NOT_EXIST;
- goto unlock;
+ goto unlock_and_exit;
}
/* Make sure all deferred tasks are completed */
@@ -474,7 +474,7 @@ acpi_remove_notify_handler(acpi_handle device,
if (!acpi_ev_is_notify_object(node)) {
status = AE_TYPE;
- goto unlock;
+ goto unlock_and_exit;
}
/* Check for an existing internal object */
@@ -482,17 +482,21 @@ acpi_remove_notify_handler(acpi_handle device,
obj_desc = acpi_ns_get_attached_object(node);
if (!obj_desc) {
status = AE_NOT_EXIST;
- goto unlock;
+ goto unlock_and_exit;
}
/* Object exists - make sure there's an existing handler */
if (handler_type & ACPI_SYSTEM_NOTIFY) {
notify_obj = obj_desc->common_notify.system_notify;
- if ((!notify_obj) ||
- (notify_obj->notify.handler != handler)) {
+ if (!notify_obj) {
+ status = AE_NOT_EXIST;
+ goto unlock_and_exit;
+ }
+
+ if (notify_obj->notify.handler != handler) {
status = AE_BAD_PARAMETER;
- goto unlock;
+ goto unlock_and_exit;
}
/* Make sure all deferred tasks are completed */
@@ -510,10 +514,14 @@ acpi_remove_notify_handler(acpi_handle device,
if (handler_type & ACPI_DEVICE_NOTIFY) {
notify_obj = obj_desc->common_notify.device_notify;
- if ((!notify_obj) ||
- (notify_obj->notify.handler != handler)) {
+ if (!notify_obj) {
+ status = AE_NOT_EXIST;
+ goto unlock_and_exit;
+ }
+
+ if (notify_obj->notify.handler != handler) {
status = AE_BAD_PARAMETER;
- goto unlock;
+ goto unlock_and_exit;
}
/* Make sure all deferred tasks are completed */
@@ -530,9 +538,9 @@ acpi_remove_notify_handler(acpi_handle device,
}
}
-unlock:
+ unlock_and_exit:
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
-exit:
+ exit:
if (ACPI_FAILURE(status))
ACPI_EXCEPTION((AE_INFO, status, "Removing notify handler"));
return_ACPI_STATUS(status);
@@ -586,7 +594,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
if (!gpe_event_info) {
status = AE_BAD_PARAMETER;
- goto unlock;
+ goto unlock_and_exit;
}
/* Make sure that there isn't a handler there already */
@@ -594,7 +602,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
ACPI_GPE_DISPATCH_HANDLER) {
status = AE_ALREADY_EXISTS;
- goto unlock;
+ goto unlock_and_exit;
}
/* Allocate and init handler object */
@@ -602,7 +610,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
handler = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_handler_info));
if (!handler) {
status = AE_NO_MEMORY;
- goto unlock;
+ goto unlock_and_exit;
}
handler->address = address;
@@ -613,7 +621,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
status = acpi_ev_disable_gpe(gpe_event_info);
if (ACPI_FAILURE(status)) {
- goto unlock;
+ goto unlock_and_exit;
}
/* Install the handler */
@@ -628,9 +636,9 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
-unlock:
+ unlock_and_exit:
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
-exit:
+ exit:
if (ACPI_FAILURE(status))
ACPI_EXCEPTION((AE_INFO, status,
"Installing notify handler failed"));
diff --git a/drivers/acpi/events/evxfregn.c b/drivers/acpi/events/evxfregn.c
index e8b86a0baad..83b12a9afa3 100644
--- a/drivers/acpi/events/evxfregn.c
+++ b/drivers/acpi/events/evxfregn.c
@@ -155,7 +155,11 @@ acpi_remove_address_space_handler(acpi_handle device,
/* Convert and validate the device handle */
node = acpi_ns_map_handle_to_node(device);
- if (!node) {
+ if (!node ||
+ ((node->type != ACPI_TYPE_DEVICE) &&
+ (node->type != ACPI_TYPE_PROCESSOR) &&
+ (node->type != ACPI_TYPE_THERMAL) &&
+ (node != acpi_gbl_root_node))) {
status = AE_BAD_PARAMETER;
goto unlock_and_exit;
}
@@ -178,6 +182,13 @@ acpi_remove_address_space_handler(acpi_handle device,
if (handler_obj->address_space.space_id == space_id) {
+ /* Handler must be the same as the installed handler */
+
+ if (handler_obj->address_space.handler != handler) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
/* Matched space_id, first dereference this in the Regions */
ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
diff --git a/drivers/acpi/executer/exconfig.c b/drivers/acpi/executer/exconfig.c
index 83fed079a27..c8341fa5fe0 100644
--- a/drivers/acpi/executer/exconfig.c
+++ b/drivers/acpi/executer/exconfig.c
@@ -502,7 +502,6 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle)
* (Offset contains the table_id)
*/
acpi_ns_delete_namespace_by_owner(table_info->owner_id);
- acpi_ut_release_owner_id(&table_info->owner_id);
/* Delete the table itself */
diff --git a/drivers/acpi/executer/exconvrt.c b/drivers/acpi/executer/exconvrt.c
index b732e399b1e..544e81a6a43 100644
--- a/drivers/acpi/executer/exconvrt.c
+++ b/drivers/acpi/executer/exconvrt.c
@@ -170,6 +170,9 @@ acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc,
return_ACPI_STATUS(AE_NO_MEMORY);
}
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Converted value: %8.8X%8.8X\n",
+ ACPI_FORMAT_UINT64(result)));
+
/* Save the Result */
return_desc->integer.value = result;
diff --git a/drivers/acpi/executer/exmutex.c b/drivers/acpi/executer/exmutex.c
index d8ac2877cf0..3a39c2e8e10 100644
--- a/drivers/acpi/executer/exmutex.c
+++ b/drivers/acpi/executer/exmutex.c
@@ -267,9 +267,9 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
&& (obj_desc->mutex.os_mutex != ACPI_GLOBAL_LOCK)) {
ACPI_ERROR((AE_INFO,
"Thread %X cannot release Mutex [%4.4s] acquired by thread %X",
- walk_state->thread->thread_id,
+ (u32) walk_state->thread->thread_id,
acpi_ut_get_node_name(obj_desc->mutex.node),
- obj_desc->mutex.owner_thread->thread_id));
+ (u32) obj_desc->mutex.owner_thread->thread_id));
return_ACPI_STATUS(AE_AML_NOT_OWNER);
}
diff --git a/drivers/acpi/executer/exsystem.c b/drivers/acpi/executer/exsystem.c
index 6b5d1e6ce94..28aef3e69ec 100644
--- a/drivers/acpi/executer/exsystem.c
+++ b/drivers/acpi/executer/exsystem.c
@@ -60,7 +60,7 @@ ACPI_MODULE_NAME("exsystem")
*
* DESCRIPTION: Implements a semaphore wait with a check to see if the
* semaphore is available immediately. If it is not, the
- * interpreter is released.
+ * interpreter is released before waiting.
*
******************************************************************************/
acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout)
@@ -110,9 +110,9 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout)
*
* RETURN: Status
*
- * DESCRIPTION: Implements a semaphore wait with a check to see if the
- * semaphore is available immediately. If it is not, the
- * interpreter is released.
+ * DESCRIPTION: Implements a mutex wait with a check to see if the
+ * mutex is available immediately. If it is not, the
+ * interpreter is released before waiting.
*
******************************************************************************/
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index daed2460924..045c89477e5 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -120,7 +120,7 @@ acpi_fan_write_state(struct file *file, const char __user * buffer,
return count;
}
-static struct file_operations acpi_fan_state_ops = {
+static const struct file_operations acpi_fan_state_ops = {
.open = acpi_fan_state_open_fs,
.read = seq_read,
.write = acpi_fan_write_state,
diff --git a/drivers/acpi/hotkey.c b/drivers/acpi/hotkey.c
index fd81a0f5222..32c9d88fd19 100644
--- a/drivers/acpi/hotkey.c
+++ b/drivers/acpi/hotkey.c
@@ -184,7 +184,7 @@ static union acpi_hotkey *get_hotkey_by_event(struct
*hotkey_list, int event);
/* event based config */
-static struct file_operations hotkey_config_fops = {
+static const struct file_operations hotkey_config_fops = {
.open = hotkey_open_config,
.read = seq_read,
.write = hotkey_write_config,
@@ -193,7 +193,7 @@ static struct file_operations hotkey_config_fops = {
};
/* polling based config */
-static struct file_operations hotkey_poll_config_fops = {
+static const struct file_operations hotkey_poll_config_fops = {
.open = hotkey_poll_open_config,
.read = seq_read,
.write = hotkey_write_config,
@@ -202,7 +202,7 @@ static struct file_operations hotkey_poll_config_fops = {
};
/* hotkey driver info */
-static struct file_operations hotkey_info_fops = {
+static const struct file_operations hotkey_info_fops = {
.open = hotkey_info_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -210,7 +210,7 @@ static struct file_operations hotkey_info_fops = {
};
/* action */
-static struct file_operations hotkey_action_fops = {
+static const struct file_operations hotkey_action_fops = {
.open = hotkey_action_open_fs,
.read = seq_read,
.write = hotkey_execute_aml_method,
@@ -219,7 +219,7 @@ static struct file_operations hotkey_action_fops = {
};
/* polling results */
-static struct file_operations hotkey_polling_fops = {
+static const struct file_operations hotkey_polling_fops = {
.open = hotkey_polling_open_fs,
.read = seq_read,
.llseek = seq_lseek,
diff --git a/drivers/acpi/namespace/nsalloc.c b/drivers/acpi/namespace/nsalloc.c
index dc3f0739a46..55b407aae26 100644
--- a/drivers/acpi/namespace/nsalloc.c
+++ b/drivers/acpi/namespace/nsalloc.c
@@ -386,14 +386,17 @@ void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node)
* specific ID. Used to delete entire ACPI tables. All
* reference counts are updated.
*
+ * MUTEX: Locks namespace during deletion walk.
+ *
******************************************************************************/
void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id)
{
struct acpi_namespace_node *child_node;
struct acpi_namespace_node *deletion_node;
- u32 level;
struct acpi_namespace_node *parent_node;
+ u32 level;
+ acpi_status status;
ACPI_FUNCTION_TRACE_U32(ns_delete_namespace_by_owner, owner_id);
@@ -401,6 +404,13 @@ void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id)
return_VOID;
}
+ /* Lock namespace for possible update */
+
+ status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE(status)) {
+ return_VOID;
+ }
+
deletion_node = NULL;
parent_node = acpi_gbl_root_node;
child_node = NULL;
@@ -469,5 +479,6 @@ void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id)
}
}
+ (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
return_VOID;
}
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index eedb05c6dc7..b7d1514cd19 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -36,7 +36,6 @@
#include <linux/delay.h>
#include <linux/workqueue.h>
#include <linux/nmi.h>
-#include <linux/kthread.h>
#include <acpi/acpi.h>
#include <asm/io.h>
#include <acpi/acpi_bus.h>
@@ -136,16 +135,6 @@ void acpi_os_vprintf(const char *fmt, va_list args)
#endif
}
-
-extern int acpi_in_resume;
-void *acpi_os_allocate(acpi_size size)
-{
- if (acpi_in_resume)
- return kmalloc(size, GFP_ATOMIC);
- else
- return kmalloc(size, GFP_KERNEL);
-}
-
acpi_status acpi_os_get_root_pointer(u32 flags, struct acpi_pointer *addr)
{
if (efi_enabled) {
@@ -593,16 +582,6 @@ static void acpi_os_execute_deferred(void *context)
return;
}
-static int acpi_os_execute_thread(void *context)
-{
- struct acpi_os_dpc *dpc = (struct acpi_os_dpc *)context;
- if (dpc) {
- dpc->function(dpc->context);
- kfree(dpc);
- }
- do_exit(0);
-}
-
/*******************************************************************************
*
* FUNCTION: acpi_os_execute
@@ -624,10 +603,16 @@ acpi_status acpi_os_execute(acpi_execute_type type,
acpi_status status = AE_OK;
struct acpi_os_dpc *dpc;
struct work_struct *task;
- struct task_struct *p;
+
+ ACPI_FUNCTION_TRACE("os_queue_for_execution");
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Scheduling function [%p(%p)] for deferred execution.\n",
+ function, context));
if (!function)
- return AE_BAD_PARAMETER;
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+
/*
* Allocate/initialize DPC structure. Note that this memory will be
* freed by the callee. The kernel handles the tq_struct list in a
@@ -638,34 +623,27 @@ acpi_status acpi_os_execute(acpi_execute_type type,
* We can save time and code by allocating the DPC and tq_structs
* from the same memory.
*/
- if (type == OSL_NOTIFY_HANDLER) {
- dpc = kmalloc(sizeof(struct acpi_os_dpc), GFP_KERNEL);
- } else {
- dpc = kmalloc(sizeof(struct acpi_os_dpc) +
- sizeof(struct work_struct), GFP_ATOMIC);
- }
+
+ dpc =
+ kmalloc(sizeof(struct acpi_os_dpc) + sizeof(struct work_struct),
+ GFP_ATOMIC);
if (!dpc)
- return AE_NO_MEMORY;
+ return_ACPI_STATUS(AE_NO_MEMORY);
+
dpc->function = function;
dpc->context = context;
- if (type == OSL_NOTIFY_HANDLER) {
- p = kthread_create(acpi_os_execute_thread, dpc, "kacpid_notify");
- if (!IS_ERR(p)) {
- wake_up_process(p);
- } else {
- status = AE_NO_MEMORY;
- kfree(dpc);
- }
- } else {
- task = (void *)(dpc + 1);
- INIT_WORK(task, acpi_os_execute_deferred, (void *)dpc);
- if (!queue_work(kacpid_wq, task)) {
- status = AE_ERROR;
- kfree(dpc);
- }
+ task = (void *)(dpc + 1);
+ INIT_WORK(task, acpi_os_execute_deferred, (void *)dpc);
+
+ if (!queue_work(kacpid_wq, task)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Call to queue_work() failed.\n"));
+ kfree(dpc);
+ status = AE_ERROR;
}
- return status;
+
+ return_ACPI_STATUS(status);
}
EXPORT_SYMBOL(acpi_os_execute);
@@ -1115,26 +1093,6 @@ acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object)
return (AE_OK);
}
-/*******************************************************************************
- *
- * FUNCTION: acpi_os_acquire_object
- *
- * PARAMETERS: Cache - Handle to cache object
- * ReturnObject - Where the object is returned
- *
- * RETURN: Status
- *
- * DESCRIPTION: Return a zero-filled object.
- *
- ******************************************************************************/
-
-void *acpi_os_acquire_object(acpi_cache_t * cache)
-{
- void *object = kmem_cache_zalloc(cache, GFP_KERNEL);
- WARN_ON(!object);
- return object;
-}
-
/******************************************************************************
*
* FUNCTION: acpi_os_validate_interface
diff --git a/drivers/acpi/parser/psutils.c b/drivers/acpi/parser/psutils.c
index 182474ae8ce..d405387b741 100644
--- a/drivers/acpi/parser/psutils.c
+++ b/drivers/acpi/parser/psutils.c
@@ -139,12 +139,10 @@ union acpi_parse_object *acpi_ps_alloc_op(u16 opcode)
/* The generic op (default) is by far the most common (16 to 1) */
op = acpi_os_acquire_object(acpi_gbl_ps_node_cache);
- memset(op, 0, sizeof(struct acpi_parse_obj_common));
} else {
/* Extended parseop */
op = acpi_os_acquire_object(acpi_gbl_ps_node_ext_cache);
- memset(op, 0, sizeof(struct acpi_parse_obj_named));
}
/* Initialize the Op */
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index 8197c0e4076..7f3e7e77e79 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -780,11 +780,6 @@ static int acpi_pci_link_resume(struct acpi_pci_link *link)
return 0;
}
-/*
- * FIXME: this is a workaround to avoid nasty warning. It will be removed
- * after every device calls pci_disable_device in .resume.
- */
-int acpi_in_resume;
static int irqrouter_resume(struct sys_device *dev)
{
struct list_head *node = NULL;
@@ -794,7 +789,6 @@ static int irqrouter_resume(struct sys_device *dev)
/* Make sure SCI is enabled again (Apple firmware bug?) */
acpi_set_register(ACPI_BITREG_SCI_ENABLE, 1, ACPI_MTX_DO_NOT_LOCK);
- acpi_in_resume = 1;
list_for_each(node, &acpi_link.entries) {
link = list_entry(node, struct acpi_pci_link, node);
if (!link) {
@@ -803,7 +797,6 @@ static int irqrouter_resume(struct sys_device *dev)
}
acpi_pci_link_resume(link);
}
- acpi_in_resume = 0;
return 0;
}
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index 5d3447f4582..fec225d1b6b 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -80,7 +80,7 @@ struct acpi_power_resource {
static struct list_head acpi_power_resource_list;
-static struct file_operations acpi_power_fops = {
+static const struct file_operations acpi_power_fops = {
.open = acpi_power_open_fs,
.read = seq_read,
.llseek = seq_lseek,
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index 52674323b14..b13d64415b7 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -102,7 +102,7 @@ static struct acpi_driver acpi_processor_driver = {
#define INSTALL_NOTIFY_HANDLER 1
#define UNINSTALL_NOTIFY_HANDLER 2
-static struct file_operations acpi_processor_info_fops = {
+static const struct file_operations acpi_processor_info_fops = {
.open = acpi_processor_info_open_fs,
.read = seq_read,
.llseek = seq_lseek,
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 8e9c26aae8f..71066066d62 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -1070,7 +1070,7 @@ static int acpi_processor_power_open_fs(struct inode *inode, struct file *file)
PDE(inode)->data);
}
-static struct file_operations acpi_processor_power_fops = {
+static const struct file_operations acpi_processor_power_fops = {
.open = acpi_processor_power_open_fs,
.read = seq_read,
.llseek = seq_lseek,
diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c
index 4696a85a98b..34962578039 100644
--- a/drivers/acpi/sleep/proc.c
+++ b/drivers/acpi/sleep/proc.c
@@ -434,7 +434,7 @@ acpi_system_wakeup_device_open_fs(struct inode *inode, struct file *file)
PDE(inode)->data);
}
-static struct file_operations acpi_system_wakeup_device_fops = {
+static const struct file_operations acpi_system_wakeup_device_fops = {
.open = acpi_system_wakeup_device_open_fs,
.read = seq_read,
.write = acpi_system_write_wakeup_device,
@@ -443,7 +443,7 @@ static struct file_operations acpi_system_wakeup_device_fops = {
};
#ifdef CONFIG_ACPI_SLEEP_PROC_SLEEP
-static struct file_operations acpi_system_sleep_fops = {
+static const struct file_operations acpi_system_sleep_fops = {
.open = acpi_system_sleep_open_fs,
.read = seq_read,
.write = acpi_system_write_sleep,
@@ -452,7 +452,7 @@ static struct file_operations acpi_system_sleep_fops = {
};
#endif /* CONFIG_ACPI_SLEEP_PROC_SLEEP */
-static struct file_operations acpi_system_alarm_fops = {
+static const struct file_operations acpi_system_alarm_fops = {
.open = acpi_system_alarm_open_fs,
.read = seq_read,
.write = acpi_system_write_alarm,
diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c
index c3bb7faad75..d86dcb3c236 100644
--- a/drivers/acpi/system.c
+++ b/drivers/acpi/system.c
@@ -57,7 +57,7 @@ static int acpi_system_info_open_fs(struct inode *inode, struct file *file)
return single_open(file, acpi_system_read_info, PDE(inode)->data);
}
-static struct file_operations acpi_system_info_ops = {
+static const struct file_operations acpi_system_info_ops = {
.open = acpi_system_info_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -67,7 +67,7 @@ static struct file_operations acpi_system_info_ops = {
static ssize_t acpi_system_read_dsdt(struct file *, char __user *, size_t,
loff_t *);
-static struct file_operations acpi_system_dsdt_ops = {
+static const struct file_operations acpi_system_dsdt_ops = {
.read = acpi_system_read_dsdt,
};
@@ -94,7 +94,7 @@ acpi_system_read_dsdt(struct file *file,
static ssize_t acpi_system_read_fadt(struct file *, char __user *, size_t,
loff_t *);
-static struct file_operations acpi_system_fadt_ops = {
+static const struct file_operations acpi_system_fadt_ops = {
.read = acpi_system_read_fadt,
};
diff --git a/drivers/acpi/tables/tbget.c b/drivers/acpi/tables/tbget.c
index 99eacceff56..7856db759af 100644
--- a/drivers/acpi/tables/tbget.c
+++ b/drivers/acpi/tables/tbget.c
@@ -320,6 +320,16 @@ acpi_tb_get_this_table(struct acpi_pointer *address,
ACPI_FUNCTION_TRACE(tb_get_this_table);
+ /* Validate minimum length */
+
+ if (header->length < sizeof(struct acpi_table_header)) {
+ ACPI_ERROR((AE_INFO,
+ "Table length (%X) is smaller than minimum (%X)",
+ header->length, sizeof(struct acpi_table_header)));
+
+ return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
+ }
+
/*
* Flags contains the current processor mode (Virtual or Physical
* addressing) The pointer_type is either Logical or Physical
@@ -356,7 +366,7 @@ acpi_tb_get_this_table(struct acpi_pointer *address,
*/
status = acpi_os_map_memory(address->pointer.physical,
(acpi_size) header->length,
- (void *)&full_table);
+ ACPI_CAST_PTR(void, &full_table));
if (ACPI_FAILURE(status)) {
ACPI_ERROR((AE_INFO,
"Could not map memory for table [%4.4s] at %8.8X%8.8X for length %X",
diff --git a/drivers/acpi/tables/tbinstal.c b/drivers/acpi/tables/tbinstal.c
index 7ca2df75bb1..1668a232fb6 100644
--- a/drivers/acpi/tables/tbinstal.c
+++ b/drivers/acpi/tables/tbinstal.c
@@ -256,7 +256,7 @@ acpi_tb_init_table_descriptor(acpi_table_type table_type,
status = acpi_ut_allocate_owner_id(&table_desc->owner_id);
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ goto error_exit1;
}
/* Install the table into the global data structure */
@@ -274,8 +274,8 @@ acpi_tb_init_table_descriptor(acpi_table_type table_type,
* at this location, so return an error.
*/
if (list_head->next) {
- ACPI_FREE(table_desc);
- return_ACPI_STATUS(AE_ALREADY_EXISTS);
+ status = AE_ALREADY_EXISTS;
+ goto error_exit2;
}
table_desc->next = list_head->next;
@@ -335,6 +335,17 @@ acpi_tb_init_table_descriptor(acpi_table_type table_type,
table_info->owner_id = table_desc->owner_id;
table_info->installed_desc = table_desc;
return_ACPI_STATUS(AE_OK);
+
+ /* Error exit with cleanup */
+
+ error_exit2:
+
+ acpi_ut_release_owner_id(&table_desc->owner_id);
+
+ error_exit1:
+
+ ACPI_FREE(table_desc);
+ return_ACPI_STATUS(status);
}
/*******************************************************************************
@@ -525,6 +536,10 @@ struct acpi_table_desc *acpi_tb_uninstall_table(struct acpi_table_desc
acpi_tb_delete_single_table(table_desc);
+ /* Free the owner ID associated with this table */
+
+ acpi_ut_release_owner_id(&table_desc->owner_id);
+
/* Free the table descriptor */
next_desc = table_desc->next;
diff --git a/drivers/acpi/tables/tbrsdt.c b/drivers/acpi/tables/tbrsdt.c
index abcb08c2592..0ad3dbb9ebc 100644
--- a/drivers/acpi/tables/tbrsdt.c
+++ b/drivers/acpi/tables/tbrsdt.c
@@ -183,6 +183,17 @@ acpi_status acpi_tb_validate_rsdt(struct acpi_table_header *table_ptr)
ACPI_FUNCTION_ENTRY();
+ /* Validate minimum length */
+
+ if (table_ptr->length < sizeof(struct acpi_table_header)) {
+ ACPI_ERROR((AE_INFO,
+ "RSDT/XSDT length (%X) is smaller than minimum (%X)",
+ table_ptr->length,
+ sizeof(struct acpi_table_header)));
+
+ return (AE_INVALID_TABLE_LENGTH);
+ }
+
/* Search for appropriate signature, RSDT or XSDT */
if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) {
@@ -210,7 +221,7 @@ acpi_status acpi_tb_validate_rsdt(struct acpi_table_header *table_ptr)
ACPI_ERROR((AE_INFO, "Looking for XSDT"));
}
- ACPI_DUMP_BUFFER((char *)table_ptr, 48);
+ ACPI_DUMP_BUFFER(ACPI_CAST_PTR(char, table_ptr), 48);
return (AE_BAD_SIGNATURE);
}
@@ -258,7 +269,7 @@ acpi_status acpi_tb_get_table_rsdt(void)
status = acpi_tb_validate_rsdt(table_info.pointer);
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ goto error_cleanup;
}
/* Get the number of tables defined in the RSDT or XSDT */
@@ -270,14 +281,14 @@ acpi_status acpi_tb_get_table_rsdt(void)
status = acpi_tb_convert_to_xsdt(&table_info);
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ goto error_cleanup;
}
/* Save the table pointers and allocation info */
status = acpi_tb_init_table_descriptor(ACPI_TABLE_ID_XSDT, &table_info);
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ goto error_cleanup;
}
acpi_gbl_XSDT =
@@ -285,4 +296,12 @@ acpi_status acpi_tb_get_table_rsdt(void)
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "XSDT located at %p\n", acpi_gbl_XSDT));
return_ACPI_STATUS(status);
+
+ error_cleanup:
+
+ /* Free table allocated by acpi_tb_get_table */
+
+ acpi_tb_delete_single_table(&table_info);
+
+ return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c
index 4e91f298481..7767987be15 100644
--- a/drivers/acpi/tables/tbxface.c
+++ b/drivers/acpi/tables/tbxface.c
@@ -134,8 +134,8 @@ ACPI_EXPORT_SYMBOL(acpi_load_tables)
* RETURN: Status
*
* DESCRIPTION: This function is called to load a table from the caller's
- * buffer. The buffer must contain an entire ACPI Table including
- * a valid header. The header fields will be verified, and if it
+ * buffer. The buffer must contain an entire ACPI Table including
+ * a valid header. The header fields will be verified, and if it
* is determined that the table is invalid, the call will fail.
*
******************************************************************************/
@@ -245,15 +245,18 @@ acpi_status acpi_unload_table(acpi_table_type table_type)
/* Find all tables of the requested type */
table_desc = acpi_gbl_table_lists[table_type].next;
+ if (!table_desc) {
+ return_ACPI_STATUS(AE_NOT_EXIST);
+ }
+
while (table_desc) {
/*
- * Delete all namespace entries owned by this table. Note that these
- * entries can appear anywhere in the namespace by virtue of the AML
- * "Scope" operator. Thus, we need to track ownership by an ID, not
+ * Delete all namespace objects owned by this table. Note that these
+ * objects can appear anywhere in the namespace by virtue of the AML
+ * "Scope" operator. Thus, we need to track ownership by an ID, not
* simply a position within the hierarchy
*/
acpi_ns_delete_namespace_by_owner(table_desc->owner_id);
- acpi_ut_release_owner_id(&table_desc->owner_id);
table_desc = table_desc->next;
}
@@ -275,12 +278,12 @@ ACPI_EXPORT_SYMBOL(acpi_unload_table)
* see acpi_gbl_acpi_table_flag
* out_table_header - pointer to the struct acpi_table_header if successful
*
- * DESCRIPTION: This function is called to get an ACPI table header. The caller
+ * DESCRIPTION: This function is called to get an ACPI table header. The caller
* supplies an pointer to a data area sufficient to contain an ACPI
* struct acpi_table_header structure.
*
* The header contains a length field that can be used to determine
- * the size of the buffer needed to contain the entire table. This
+ * the size of the buffer needed to contain the entire table. This
* function is not valid for the RSD PTR table since it does not
* have a standard header and is fixed length.
*
@@ -322,7 +325,8 @@ acpi_get_table_header(acpi_table_type table_type,
/* Copy the header to the caller's buffer */
- ACPI_MEMCPY((void *)out_table_header, (void *)tbl_ptr,
+ ACPI_MEMCPY(ACPI_CAST_PTR(void, out_table_header),
+ ACPI_CAST_PTR(void, tbl_ptr),
sizeof(struct acpi_table_header));
return_ACPI_STATUS(status);
@@ -344,10 +348,10 @@ ACPI_EXPORT_SYMBOL(acpi_get_table_header)
*
* RETURN: Status
*
- * DESCRIPTION: This function is called to get an ACPI table. The caller
+ * DESCRIPTION: This function is called to get an ACPI table. The caller
* supplies an out_buffer large enough to contain the entire ACPI
- * table. The caller should call the acpi_get_table_header function
- * first to determine the buffer size needed. Upon completion
+ * table. The caller should call the acpi_get_table_header function
+ * first to determine the buffer size needed. Upon completion
* the out_buffer->Length field will indicate the number of bytes
* copied into the out_buffer->buf_ptr buffer. This table will be
* a complete table including the header.
@@ -417,7 +421,9 @@ acpi_get_table(acpi_table_type table_type,
/* Copy the table to the buffer */
- ACPI_MEMCPY((void *)ret_buffer->pointer, (void *)tbl_ptr, table_length);
+ ACPI_MEMCPY(ACPI_CAST_PTR(void, ret_buffer->pointer),
+ ACPI_CAST_PTR(void, tbl_ptr), table_length);
+
return_ACPI_STATUS(AE_OK);
}
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 503c0b99db1..5753d06b786 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -176,21 +176,21 @@ struct acpi_thermal {
struct timer_list timer;
};
-static struct file_operations acpi_thermal_state_fops = {
+static const struct file_operations acpi_thermal_state_fops = {
.open = acpi_thermal_state_open_fs,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
-static struct file_operations acpi_thermal_temp_fops = {
+static const struct file_operations acpi_thermal_temp_fops = {
.open = acpi_thermal_temp_open_fs,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
-static struct file_operations acpi_thermal_trip_fops = {
+static const struct file_operations acpi_thermal_trip_fops = {
.open = acpi_thermal_trip_open_fs,
.read = seq_read,
.write = acpi_thermal_write_trip_points,
@@ -198,7 +198,7 @@ static struct file_operations acpi_thermal_trip_fops = {
.release = single_release,
};
-static struct file_operations acpi_thermal_cooling_fops = {
+static const struct file_operations acpi_thermal_cooling_fops = {
.open = acpi_thermal_cooling_open_fs,
.read = seq_read,
.write = acpi_thermal_write_cooling_mode,
@@ -206,7 +206,7 @@ static struct file_operations acpi_thermal_cooling_fops = {
.release = single_release,
};
-static struct file_operations acpi_thermal_polling_fops = {
+static const struct file_operations acpi_thermal_polling_fops = {
.open = acpi_thermal_polling_open_fs,
.read = seq_read,
.write = acpi_thermal_write_polling,
@@ -1359,13 +1359,28 @@ static int acpi_thermal_remove(struct acpi_device *device, int type)
static int acpi_thermal_resume(struct acpi_device *device, int state)
{
struct acpi_thermal *tz = NULL;
+ int i;
if (!device || !acpi_driver_data(device))
return -EINVAL;
tz = (struct acpi_thermal *)acpi_driver_data(device);
- acpi_thermal_check(tz);
+ acpi_thermal_get_temperature(tz);
+
+ for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
+ if (tz->trips.active[i].flags.valid) {
+ tz->temperature = tz->trips.active[i].temperature;
+ tz->trips.active[i].flags.enabled = 0;
+
+ acpi_thermal_active(tz);
+
+ tz->state.active |= tz->trips.active[i].flags.enabled;
+ tz->state.active_index = i;
+ }
+ }
+
+ acpi_thermal_check(tz);
return AE_OK;
}
diff --git a/drivers/acpi/utilities/utalloc.c b/drivers/acpi/utilities/utalloc.c
index 5cff17dc78b..f6cbc0b1bfd 100644
--- a/drivers/acpi/utilities/utalloc.c
+++ b/drivers/acpi/utilities/utalloc.c
@@ -285,6 +285,7 @@ acpi_ut_initialize_buffer(struct acpi_buffer * buffer,
return (status);
}
+#ifdef NOT_USED_BY_LINUX
/*******************************************************************************
*
* FUNCTION: acpi_ut_allocate
@@ -360,3 +361,4 @@ void *acpi_ut_allocate_zeroed(acpi_size size,
return (allocation);
}
+#endif
diff --git a/drivers/acpi/utilities/utdebug.c b/drivers/acpi/utilities/utdebug.c
index 5ec1cfcc611..bb1eaf9aa65 100644
--- a/drivers/acpi/utilities/utdebug.c
+++ b/drivers/acpi/utilities/utdebug.c
@@ -47,7 +47,7 @@
ACPI_MODULE_NAME("utdebug")
#ifdef ACPI_DEBUG_OUTPUT
-static u32 acpi_gbl_prev_thread_id = 0xFFFFFFFF;
+static acpi_thread_id acpi_gbl_prev_thread_id;
static char *acpi_gbl_fn_entry_str = "----Entry";
static char *acpi_gbl_fn_exit_str = "----Exit-";
@@ -181,7 +181,7 @@ acpi_ut_debug_print(u32 requested_debug_level,
if (ACPI_LV_THREADS & acpi_dbg_level) {
acpi_os_printf
("\n**** Context Switch from TID %X to TID %X ****\n\n",
- acpi_gbl_prev_thread_id, thread_id);
+ (u32) acpi_gbl_prev_thread_id, (u32) thread_id);
}
acpi_gbl_prev_thread_id = thread_id;
diff --git a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/utilities/utdelete.c
index 38ebe1c5433..9d3f1149ba2 100644
--- a/drivers/acpi/utilities/utdelete.c
+++ b/drivers/acpi/utilities/utdelete.c
@@ -447,11 +447,16 @@ acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action)
*/
switch (ACPI_GET_OBJECT_TYPE(object)) {
case ACPI_TYPE_DEVICE:
+ case ACPI_TYPE_PROCESSOR:
+ case ACPI_TYPE_POWER:
+ case ACPI_TYPE_THERMAL:
- acpi_ut_update_ref_count(object->device.system_notify,
- action);
- acpi_ut_update_ref_count(object->device.device_notify,
- action);
+ /* Update the notify objects for these types (if present) */
+
+ acpi_ut_update_ref_count(object->common_notify.
+ system_notify, action);
+ acpi_ut_update_ref_count(object->common_notify.
+ device_notify, action);
break;
case ACPI_TYPE_PACKAGE:
diff --git a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c
index 33268310c73..6d8a8211be9 100644
--- a/drivers/acpi/utilities/utmisc.c
+++ b/drivers/acpi/utilities/utmisc.c
@@ -65,7 +65,7 @@ ACPI_MODULE_NAME("utmisc")
u8 acpi_ut_is_aml_table(struct acpi_table_header *table)
{
- /* Ignore tables that contain AML */
+ /* These are the only tables that contain executable AML */
if (ACPI_COMPARE_NAME(table->signature, DSDT_SIG) ||
ACPI_COMPARE_NAME(table->signature, PSDT_SIG) ||
@@ -419,10 +419,15 @@ void acpi_ut_set_integer_width(u8 revision)
{
if (revision <= 1) {
+
+ /* 32-bit case */
+
acpi_gbl_integer_bit_width = 32;
acpi_gbl_integer_nybble_width = 8;
acpi_gbl_integer_byte_width = 4;
} else {
+ /* 64-bit case (ACPI 2.0+) */
+
acpi_gbl_integer_bit_width = 64;
acpi_gbl_integer_nybble_width = 16;
acpi_gbl_integer_byte_width = 8;
@@ -502,6 +507,7 @@ acpi_ut_display_init_pathname(u8 type,
* FUNCTION: acpi_ut_valid_acpi_char
*
* PARAMETERS: Char - The character to be examined
+ * Position - Byte position (0-3)
*
* RETURN: TRUE if the character is valid, FALSE otherwise
*
@@ -609,7 +615,9 @@ acpi_name acpi_ut_repair_name(acpi_name name)
*
* RETURN: Status and Converted value
*
- * DESCRIPTION: Convert a string into an unsigned value.
+ * DESCRIPTION: Convert a string into an unsigned value. Performs either a
+ * 32-bit or 64-bit conversion, depending on the current mode
+ * of the interpreter.
* NOTE: Does not support Octal strings, not needed.
*
******************************************************************************/
@@ -627,7 +635,7 @@ acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer)
u8 sign_of0x = 0;
u8 term = 0;
- ACPI_FUNCTION_TRACE(ut_stroul64);
+ ACPI_FUNCTION_TRACE_STR(ut_stroul64, string);
switch (base) {
case ACPI_ANY_BASE:
@@ -675,11 +683,13 @@ acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer)
}
}
+ /*
+ * Perform a 32-bit or 64-bit conversion, depending upon the current
+ * execution mode of the interpreter
+ */
dividend = (mode32) ? ACPI_UINT32_MAX : ACPI_UINT64_MAX;
- /* At least one character in the string here */
-
- /* Main loop: convert the string to a 64-bit integer */
+ /* Main loop: convert the string to a 32- or 64-bit integer */
while (*string) {
if (ACPI_IS_DIGIT(*string)) {
@@ -754,6 +764,9 @@ acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer)
all_done:
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Converted value: %8.8X%8.8X\n",
+ ACPI_FORMAT_UINT64(return_value)));
+
*ret_integer = return_value;
return_ACPI_STATUS(AE_OK);
diff --git a/drivers/acpi/utilities/utmutex.c b/drivers/acpi/utilities/utmutex.c
index dfc8f30ca89..c39062a047c 100644
--- a/drivers/acpi/utilities/utmutex.c
+++ b/drivers/acpi/utilities/utmutex.c
@@ -244,14 +244,14 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id)
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
"Thread %X attempting to acquire Mutex [%s]\n",
- this_thread_id, acpi_ut_get_mutex_name(mutex_id)));
+ (u32) this_thread_id, acpi_ut_get_mutex_name(mutex_id)));
status = acpi_os_acquire_mutex(acpi_gbl_mutex_info[mutex_id].mutex,
ACPI_WAIT_FOREVER);
if (ACPI_SUCCESS(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
"Thread %X acquired Mutex [%s]\n",
- this_thread_id,
+ (u32) this_thread_id,
acpi_ut_get_mutex_name(mutex_id)));
acpi_gbl_mutex_info[mutex_id].use_count++;
@@ -259,7 +259,7 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id)
} else {
ACPI_EXCEPTION((AE_INFO, status,
"Thread %X could not acquire Mutex [%X]",
- this_thread_id, mutex_id));
+ (u32) this_thread_id, mutex_id));
}
return (status);
@@ -285,7 +285,7 @@ acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id)
this_thread_id = acpi_os_get_thread_id();
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
- "Thread %X releasing Mutex [%s]\n", this_thread_id,
+ "Thread %X releasing Mutex [%s]\n", (u32) this_thread_id,
acpi_ut_get_mutex_name(mutex_id)));
if (mutex_id > ACPI_MAX_MUTEX) {
diff --git a/drivers/acpi/utilities/utstate.c b/drivers/acpi/utilities/utstate.c
index 0f5c5bb5def..eaa13d05c85 100644
--- a/drivers/acpi/utilities/utstate.c
+++ b/drivers/acpi/utilities/utstate.c
@@ -199,6 +199,13 @@ struct acpi_thread_state *acpi_ut_create_thread_state(void)
state->common.descriptor_type = ACPI_DESC_TYPE_STATE_THREAD;
state->thread.thread_id = acpi_os_get_thread_id();
+ /* Check for invalid thread ID - zero is very bad, it will break things */
+
+ if (!state->thread.thread_id) {
+ ACPI_ERROR((AE_INFO, "Invalid zero ID from AcpiOsGetThreadId"));
+ state->thread.thread_id = (acpi_thread_id) 1;
+ }
+
return_PTR((struct acpi_thread_state *)state);
}
diff --git a/drivers/atm/Kconfig b/drivers/atm/Kconfig
index 01a9f1cb774..cfa5af883e1 100644
--- a/drivers/atm/Kconfig
+++ b/drivers/atm/Kconfig
@@ -398,7 +398,7 @@ config ATM_FORE200E_USE_TASKLET
default n
help
This defers work to be done by the interrupt handler to a
- tasklet instead of hanlding everything at interrupt time. This
+ tasklet instead of handling everything at interrupt time. This
may improve the responsive of the host.
config ATM_FORE200E_TX_RETRY
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index 80502dc6ed6..0b4e2243693 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -20,7 +20,7 @@ config PREVENT_FIRMWARE_BUILD
config FW_LOADER
tristate "Userspace firmware loading support"
- select HOTPLUG
+ depends on HOTPLUG
---help---
This option is provided for the case where no in-kernel-tree modules
require userspace firmware loading support, but a module built outside
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 83fa8b291a5..2e954d07175 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -129,7 +129,7 @@ static struct kobj_type ktype_bus = {
};
-decl_subsys(bus, &ktype_bus, NULL);
+static decl_subsys(bus, &ktype_bus, NULL);
#ifdef CONFIG_HOTPLUG
@@ -598,12 +598,13 @@ void put_bus(struct bus_type * bus)
*
* Note that kset_find_obj increments bus' reference count.
*/
-
+#if 0
struct bus_type * find_bus(char * name)
{
struct kobject * k = kset_find_obj(&bus_subsys.kset, name);
return k ? to_bus(k) : NULL;
}
+#endif /* 0 */
/**
diff --git a/drivers/base/core.c b/drivers/base/core.c
index b21f864c9ce..be6b5bc0677 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -559,20 +559,20 @@ static void device_create_release(struct device *dev)
/**
* device_create - creates a device and registers it with sysfs
- * @cs: pointer to the struct class that this device should be registered to.
- * @parent: pointer to the parent struct device of this new device, if any.
- * @dev: the dev_t for the char device to be added.
- * @fmt: string for the class device's name
+ * @class: pointer to the struct class that this device should be registered to
+ * @parent: pointer to the parent struct device of this new device, if any
+ * @devt: the dev_t for the char device to be added
+ * @fmt: string for the device's name
+ *
+ * This function can be used by char device classes. A struct device
+ * will be created in sysfs, registered to the specified class.
*
- * This function can be used by char device classes. A struct
- * device will be created in sysfs, registered to the specified
- * class.
* A "dev" file will be created, showing the dev_t for the device, if
* the dev_t is not 0,0.
- * If a pointer to a parent struct device is passed in, the newly
- * created struct device will be a child of that device in sysfs. The
- * pointer to the struct device will be returned from the call. Any
- * further sysfs files that might be required can be created using this
+ * If a pointer to a parent struct device is passed in, the newly created
+ * struct device will be a child of that device in sysfs.
+ * The pointer to the struct device will be returned from the call.
+ * Any further sysfs files that might be required can be created using this
* pointer.
*
* Note: the struct class passed to this function must have previously
@@ -620,11 +620,11 @@ EXPORT_SYMBOL_GPL(device_create);
/**
* device_destroy - removes a device that was created with device_create()
- * @class: the pointer to the struct class that this device was registered * with.
- * @dev: the dev_t of the device that was previously registered.
+ * @class: pointer to the struct class that this device was registered with
+ * @devt: the dev_t of the device that was previously registered
*
- * This call unregisters and cleans up a class device that was created with a
- * call to class_device_create()
+ * This call unregisters and cleans up a device that was created with a
+ * call to device_create().
*/
void device_destroy(struct class *class, dev_t devt)
{
diff --git a/drivers/base/topology.c b/drivers/base/topology.c
index c2d62163238..3ef9d514b91 100644
--- a/drivers/base/topology.c
+++ b/drivers/base/topology.c
@@ -139,7 +139,7 @@ static int __cpuinit topology_sysfs_init(void)
(void *)(long)i);
}
- register_cpu_notifier(&topology_cpu_notifier);
+ register_hotcpu_notifier(&topology_cpu_notifier);
return 0;
}
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index 93d94749310..b5382cedf0c 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -400,6 +400,16 @@ config BLK_DEV_RAM_SIZE
what are you doing. If you are using IBM S/390, then set this to
8192.
+config BLK_DEV_RAM_BLOCKSIZE
+ int "Default RAM disk block size (bytes)"
+ depends on BLK_DEV_RAM
+ default "1024"
+ help
+ The default value is 1024 kilobytes. PAGE_SIZE is a much more
+ efficient choice however. The default is kept to ensure initrd
+ setups function - apparently needed by the rd_load_image routine
+ that supposes the filesystem in the image uses a 1024 blocksize.
+
config BLK_DEV_INITRD
bool "Initial RAM filesystem and RAM disk (initramfs/initrd) support"
depends on BROKEN || !FRV
diff --git a/drivers/block/aoe/aoechr.c b/drivers/block/aoe/aoechr.c
index 5327f553b4f..1bc1cf9603f 100644
--- a/drivers/block/aoe/aoechr.c
+++ b/drivers/block/aoe/aoechr.c
@@ -162,7 +162,7 @@ aoechr_open(struct inode *inode, struct file *filp)
{
int n, i;
- n = MINOR(inode->i_rdev);
+ n = iminor(inode);
filp->private_data = (void *) (unsigned long) n;
for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 1c4df22dfd2..7b0eca703a6 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -1233,6 +1233,50 @@ static inline void complete_buffers(struct bio *bio, int status)
}
}
+static void cciss_check_queues(ctlr_info_t *h)
+{
+ int start_queue = h->next_to_run;
+ int i;
+
+ /* check to see if we have maxed out the number of commands that can
+ * be placed on the queue. If so then exit. We do this check here
+ * in case the interrupt we serviced was from an ioctl and did not
+ * free any new commands.
+ */
+ if ((find_first_zero_bit(h->cmd_pool_bits, NR_CMDS)) == NR_CMDS)
+ return;
+
+ /* We have room on the queue for more commands. Now we need to queue
+ * them up. We will also keep track of the next queue to run so
+ * that every queue gets a chance to be started first.
+ */
+ for (i = 0; i < h->highest_lun + 1; i++) {
+ int curr_queue = (start_queue + i) % (h->highest_lun + 1);
+ /* make sure the disk has been added and the drive is real
+ * because this can be called from the middle of init_one.
+ */
+ if (!(h->drv[curr_queue].queue) || !(h->drv[curr_queue].heads))
+ continue;
+ blk_start_queue(h->gendisk[curr_queue]->queue);
+
+ /* check to see if we have maxed out the number of commands
+ * that can be placed on the queue.
+ */
+ if ((find_first_zero_bit(h->cmd_pool_bits, NR_CMDS)) == NR_CMDS) {
+ if (curr_queue == start_queue) {
+ h->next_to_run =
+ (start_queue + 1) % (h->highest_lun + 1);
+ break;
+ } else {
+ h->next_to_run = curr_queue;
+ break;
+ }
+ } else {
+ curr_queue = (curr_queue + 1) % (h->highest_lun + 1);
+ }
+ }
+}
+
static void cciss_softirq_done(struct request *rq)
{
CommandList_struct *cmd = rq->completion_data;
@@ -1264,6 +1308,7 @@ static void cciss_softirq_done(struct request *rq)
spin_lock_irqsave(&h->lock, flags);
end_that_request_last(rq, rq->errors);
cmd_free(h, cmd, 1);
+ cciss_check_queues(h);
spin_unlock_irqrestore(&h->lock, flags);
}
@@ -2528,8 +2573,6 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs)
CommandList_struct *c;
unsigned long flags;
__u32 a, a1, a2;
- int j;
- int start_queue = h->next_to_run;
if (interrupt_not_for_us(h))
return IRQ_NONE;
@@ -2588,45 +2631,6 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs)
}
}
- /* check to see if we have maxed out the number of commands that can
- * be placed on the queue. If so then exit. We do this check here
- * in case the interrupt we serviced was from an ioctl and did not
- * free any new commands.
- */
- if ((find_first_zero_bit(h->cmd_pool_bits, NR_CMDS)) == NR_CMDS)
- goto cleanup;
-
- /* We have room on the queue for more commands. Now we need to queue
- * them up. We will also keep track of the next queue to run so
- * that every queue gets a chance to be started first.
- */
- for (j = 0; j < h->highest_lun + 1; j++) {
- int curr_queue = (start_queue + j) % (h->highest_lun + 1);
- /* make sure the disk has been added and the drive is real
- * because this can be called from the middle of init_one.
- */
- if (!(h->drv[curr_queue].queue) || !(h->drv[curr_queue].heads))
- continue;
- blk_start_queue(h->gendisk[curr_queue]->queue);
-
- /* check to see if we have maxed out the number of commands
- * that can be placed on the queue.
- */
- if ((find_first_zero_bit(h->cmd_pool_bits, NR_CMDS)) == NR_CMDS) {
- if (curr_queue == start_queue) {
- h->next_to_run =
- (start_queue + 1) % (h->highest_lun + 1);
- goto cleanup;
- } else {
- h->next_to_run = curr_queue;
- goto cleanup;
- }
- } else {
- curr_queue = (curr_queue + 1) % (h->highest_lun + 1);
- }
- }
-
- cleanup:
spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
return IRQ_HANDLED;
}
diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
index 757f42dd8e8..78082edc14b 100644
--- a/drivers/block/cpqarray.c
+++ b/drivers/block/cpqarray.c
@@ -1739,8 +1739,6 @@ static void getgeometry(int ctlr)
(log_index < id_ctlr_buf->nr_drvs)
&& (log_unit < NWD);
log_unit++) {
- struct gendisk *disk = ida_gendisk[ctlr][log_unit];
-
size = sizeof(sense_log_drv_stat_t);
/*
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 0a1b1ea36dd..bdbade9a5cf 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -300,6 +300,15 @@ static struct request *nbd_read_stat(struct nbd_device *lo)
lo->disk->disk_name, result);
goto harderror;
}
+
+ if (ntohl(reply.magic) != NBD_REPLY_MAGIC) {
+ printk(KERN_ERR "%s: Wrong magic (0x%lx)\n",
+ lo->disk->disk_name,
+ (unsigned long)ntohl(reply.magic));
+ result = -EPROTO;
+ goto harderror;
+ }
+
req = nbd_find_request(lo, reply.handle);
if (unlikely(IS_ERR(req))) {
result = PTR_ERR(req);
@@ -312,13 +321,6 @@ static struct request *nbd_read_stat(struct nbd_device *lo)
goto harderror;
}
- if (ntohl(reply.magic) != NBD_REPLY_MAGIC) {
- printk(KERN_ERR "%s: Wrong magic (0x%lx)\n",
- lo->disk->disk_name,
- (unsigned long)ntohl(reply.magic));
- result = -EPROTO;
- goto harderror;
- }
if (ntohl(reply.error)) {
printk(KERN_ERR "%s: Other side returned error (%d)\n",
lo->disk->disk_name, ntohl(reply.error));
@@ -339,7 +341,8 @@ static struct request *nbd_read_stat(struct nbd_device *lo)
printk(KERN_ERR "%s: Receive data failed (result %d)\n",
lo->disk->disk_name,
result);
- goto harderror;
+ req->errors++;
+ return req;
}
dprintk(DBG_RX, "%s: request %p: got %d bytes data\n",
lo->disk->disk_name, req, bvec->bv_len);
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index bde2c64b634..451b996bba9 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -2577,19 +2577,19 @@ static int pkt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cm
case PKT_CTRL_CMD_SETUP:
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- mutex_lock(&ctl_mutex);
+ mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
ret = pkt_setup_dev(&ctrl_cmd);
mutex_unlock(&ctl_mutex);
break;
case PKT_CTRL_CMD_TEARDOWN:
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- mutex_lock(&ctl_mutex);
+ mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
ret = pkt_remove_dev(&ctrl_cmd);
mutex_unlock(&ctl_mutex);
break;
case PKT_CTRL_CMD_STATUS:
- mutex_lock(&ctl_mutex);
+ mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
pkt_get_status(&ctrl_cmd);
mutex_unlock(&ctl_mutex);
break;
diff --git a/drivers/block/rd.c b/drivers/block/rd.c
index 3cf246abb5e..a3f64bfe6b5 100644
--- a/drivers/block/rd.c
+++ b/drivers/block/rd.c
@@ -84,7 +84,7 @@ int rd_size = CONFIG_BLK_DEV_RAM_SIZE; /* Size of the RAM disks */
* behaviour. The default is still BLOCK_SIZE (needed by rd_load_image that
* supposes the filesystem in the image uses a BLOCK_SIZE blocksize).
*/
-static int rd_blocksize = BLOCK_SIZE; /* blocksize of the RAM disks */
+static int rd_blocksize = CONFIG_BLK_DEV_RAM_BLOCKSIZE;
/*
* Copyright (C) 2000 Linus Torvalds.
diff --git a/drivers/bluetooth/bcm203x.c b/drivers/bluetooth/bcm203x.c
index 6f67141f4de..13ba729cdd5 100644
--- a/drivers/bluetooth/bcm203x.c
+++ b/drivers/bluetooth/bcm203x.c
@@ -234,6 +234,7 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id
data->fw_data = kmalloc(firmware->size, GFP_KERNEL);
if (!data->fw_data) {
BT_ERR("Can't allocate memory for firmware image");
+ release_firmware(firmware);
usb_free_urb(data->urb);
kfree(data->buffer);
kfree(data);
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 1994270c16e..93ba25b7ea3 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -191,7 +191,7 @@ static int hci_uart_flush(struct hci_dev *hdev)
/* Flush any pending characters in the driver and discipline. */
tty_ldisc_flush(tty);
- if (tty->driver->flush_buffer)
+ if (tty->driver && tty->driver->flush_buffer)
tty->driver->flush_buffer(tty);
if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
@@ -290,7 +290,7 @@ static int hci_uart_tty_open(struct tty_struct *tty)
if (tty->ldisc.flush_buffer)
tty->ldisc.flush_buffer(tty);
- if (tty->driver->flush_buffer)
+ if (tty->driver && tty->driver->flush_buffer)
tty->driver->flush_buffer(tty);
return 0;
diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c
index 6a0c2230f82..e2d4beac742 100644
--- a/drivers/bluetooth/hci_usb.c
+++ b/drivers/bluetooth/hci_usb.c
@@ -67,6 +67,8 @@ static int ignore = 0;
static int ignore_dga = 0;
static int ignore_csr = 0;
static int ignore_sniffer = 0;
+static int disable_scofix = 0;
+static int force_scofix = 0;
static int reset = 0;
#ifdef CONFIG_BT_HCIUSB_SCO
@@ -107,9 +109,12 @@ static struct usb_device_id blacklist_ids[] = {
{ USB_DEVICE(0x0a5c, 0x2033), .driver_info = HCI_IGNORE },
/* Broadcom BCM2035 */
- { USB_DEVICE(0x0a5c, 0x200a), .driver_info = HCI_RESET | HCI_BROKEN_ISOC },
+ { USB_DEVICE(0x0a5c, 0x200a), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU },
{ USB_DEVICE(0x0a5c, 0x2009), .driver_info = HCI_BCM92035 },
+ /* IBM/Lenovo ThinkPad with Broadcom chip */
+ { USB_DEVICE(0x0a5c, 0x201e), .driver_info = HCI_WRONG_SCO_MTU },
+
/* Microsoft Wireless Transceiver for Bluetooth 2.0 */
{ USB_DEVICE(0x045e, 0x009c), .driver_info = HCI_RESET },
@@ -119,11 +124,13 @@ static struct usb_device_id blacklist_ids[] = {
/* ISSC Bluetooth Adapter v3.1 */
{ USB_DEVICE(0x1131, 0x1001), .driver_info = HCI_RESET },
- /* RTX Telecom based adapter with buggy SCO support */
+ /* RTX Telecom based adapters with buggy SCO support */
{ USB_DEVICE(0x0400, 0x0807), .driver_info = HCI_BROKEN_ISOC },
+ { USB_DEVICE(0x0400, 0x080a), .driver_info = HCI_BROKEN_ISOC },
- /* Belkin F8T012 */
+ /* Belkin F8T012 and F8T013 devices */
{ USB_DEVICE(0x050d, 0x0012), .driver_info = HCI_WRONG_SCO_MTU },
+ { USB_DEVICE(0x050d, 0x0013), .driver_info = HCI_WRONG_SCO_MTU },
/* Digianswer devices */
{ USB_DEVICE(0x08fd, 0x0001), .driver_info = HCI_DIGIANSWER },
@@ -990,8 +997,10 @@ static int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id
if (reset || id->driver_info & HCI_RESET)
set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks);
- if (id->driver_info & HCI_WRONG_SCO_MTU)
- set_bit(HCI_QUIRK_FIXUP_BUFFER_SIZE, &hdev->quirks);
+ if (force_scofix || id->driver_info & HCI_WRONG_SCO_MTU) {
+ if (!disable_scofix)
+ set_bit(HCI_QUIRK_FIXUP_BUFFER_SIZE, &hdev->quirks);
+ }
if (id->driver_info & HCI_SNIFFER) {
if (le16_to_cpu(udev->descriptor.bcdDevice) > 0x997)
@@ -1161,6 +1170,12 @@ MODULE_PARM_DESC(ignore_csr, "Ignore devices with id 0a12:0001");
module_param(ignore_sniffer, bool, 0644);
MODULE_PARM_DESC(ignore_sniffer, "Ignore devices with id 0a12:0002");
+module_param(disable_scofix, bool, 0644);
+MODULE_PARM_DESC(disable_scofix, "Disable fixup of wrong SCO buffer size");
+
+module_param(force_scofix, bool, 0644);
+MODULE_PARM_DESC(force_scofix, "Force fixup of wrong SCO buffers size");
+
module_param(reset, bool, 0644);
MODULE_PARM_DESC(reset, "Send HCI reset command on initialization");
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index ca27ee89240..d239cf8b20b 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -1837,7 +1837,7 @@ static int dvd_read_bca(struct cdrom_device_info *cdi, dvd_struct *s)
init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ);
cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
cgc.cmd[7] = s->type;
- cgc.cmd[9] = cgc.buflen = 0xff;
+ cgc.cmd[9] = cgc.buflen & 0xff;
if ((ret = cdo->generic_packet(cdi, &cgc)))
return ret;
diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c
index 56612a2dca6..41db8060e8f 100644
--- a/drivers/char/hvsi.c
+++ b/drivers/char/hvsi.c
@@ -1299,7 +1299,7 @@ static int __init hvsi_console_init(void)
hp->inbuf_end = hp->inbuf;
hp->state = HVSI_CLOSED;
hp->vtermno = *vtermno;
- hp->virq = irq_create_mapping(NULL, irq[0], 0);
+ hp->virq = irq_create_mapping(NULL, irq[0]);
if (hp->virq == NO_IRQ) {
printk(KERN_ERR "%s: couldn't create irq mapping for 0x%x\n",
__FUNCTION__, irq[0]);
diff --git a/drivers/char/hw_random/geode-rng.c b/drivers/char/hw_random/geode-rng.c
index be61f22ee7b..d37ced0d132 100644
--- a/drivers/char/hw_random/geode-rng.c
+++ b/drivers/char/hw_random/geode-rng.c
@@ -107,10 +107,14 @@ found:
if (err) {
printk(KERN_ERR PFX "RNG registering failed (%d)\n",
err);
- goto out;
+ goto err_unmap;
}
out:
return err;
+
+err_unmap:
+ iounmap(mem);
+ goto out;
}
static void __exit mod_exit(void)
diff --git a/drivers/char/hw_random/intel-rng.c b/drivers/char/hw_random/intel-rng.c
index 6594bd5645f..ccd7e710223 100644
--- a/drivers/char/hw_random/intel-rng.c
+++ b/drivers/char/hw_random/intel-rng.c
@@ -164,7 +164,7 @@ static int __init mod_init(void)
if (err) {
printk(KERN_ERR PFX "RNG registering failed (%d)\n",
err);
- goto out;
+ goto err_unmap;
}
out:
return err;
diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c
index 518ece7ac65..7907ae88c2f 100644
--- a/drivers/char/ip2/ip2main.c
+++ b/drivers/char/ip2/ip2main.c
@@ -3186,3 +3186,10 @@ ip2trace (unsigned short pn, unsigned char cat, unsigned char label, unsigned lo
MODULE_LICENSE("GPL");
+
+static struct pci_device_id ip2main_pci_tbl[] __devinitdata = {
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_IP2EX) },
+ { }
+};
+
+MODULE_DEVICE_TABLE(pci, ip2main_pci_tbl);
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index e97c32ceb79..917b2040266 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -95,7 +95,7 @@ static inline int valid_phys_addr_range(unsigned long addr, size_t count)
return 1;
}
-static inline int valid_mmap_phys_addr_range(unsigned long addr, size_t size)
+static inline int valid_mmap_phys_addr_range(unsigned long pfn, size_t size)
{
return 1;
}
@@ -242,7 +242,7 @@ static int mmap_mem(struct file * file, struct vm_area_struct * vma)
{
size_t size = vma->vm_end - vma->vm_start;
- if (!valid_mmap_phys_addr_range(vma->vm_pgoff << PAGE_SHIFT, size))
+ if (!valid_mmap_phys_addr_range(vma->vm_pgoff, size))
return -EINVAL;
vma->vm_page_prot = phys_mem_access_prot(file, vma->vm_pgoff,
diff --git a/drivers/char/nsc_gpio.c b/drivers/char/nsc_gpio.c
index 5b91e4e2564..7719bd75810 100644
--- a/drivers/char/nsc_gpio.c
+++ b/drivers/char/nsc_gpio.c
@@ -68,13 +68,11 @@ ssize_t nsc_gpio_write(struct file *file, const char __user *data,
amp->gpio_config(m, ~1, 0);
break;
case 'T':
- dev_dbg(dev, "GPIO%d output is push pull\n",
- m);
+ dev_dbg(dev, "GPIO%d output is push pull\n", m);
amp->gpio_config(m, ~2, 2);
break;
case 't':
- dev_dbg(dev, "GPIO%d output is open drain\n",
- m);
+ dev_dbg(dev, "GPIO%d output is open drain\n", m);
amp->gpio_config(m, ~2, 0);
break;
case 'P':
diff --git a/drivers/char/pc8736x_gpio.c b/drivers/char/pc8736x_gpio.c
index 4005ee0aa11..84e5a68635f 100644
--- a/drivers/char/pc8736x_gpio.c
+++ b/drivers/char/pc8736x_gpio.c
@@ -3,18 +3,18 @@
National Semiconductor PC8736x GPIO driver. Allows a user space
process to play with the GPIO pins.
- Copyright (c) 2005 Jim Cromie <jim.cromie@gmail.com>
+ Copyright (c) 2005,2006 Jim Cromie <jim.cromie@gmail.com>
adapted from linux/drivers/char/scx200_gpio.c
Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>,
*/
-#include <linux/config.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/cdev.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/mutex.h>
@@ -25,7 +25,7 @@
#define DEVNAME "pc8736x_gpio"
MODULE_AUTHOR("Jim Cromie <jim.cromie@gmail.com>");
-MODULE_DESCRIPTION("NatSemi PC-8736x GPIO Pin Driver");
+MODULE_DESCRIPTION("NatSemi/Winbond PC-8736x GPIO Pin Driver");
MODULE_LICENSE("GPL");
static int major; /* default to dynamic major */
@@ -38,14 +38,14 @@ static u8 pc8736x_gpio_shadow[4];
#define SIO_BASE1 0x2E /* 1st command-reg to check */
#define SIO_BASE2 0x4E /* alt command-reg to check */
-#define SIO_BASE_OFFSET 0x20
#define SIO_SID 0x20 /* SuperI/O ID Register */
#define SIO_SID_VALUE 0xe9 /* Expected value in SuperI/O ID Register */
#define SIO_CF1 0x21 /* chip config, bit0 is chip enable */
-#define PC8736X_GPIO_SIZE 16
+#define PC8736X_GPIO_RANGE 16 /* ioaddr range */
+#define PC8736X_GPIO_CT 32 /* minors matching 4 8 bit ports */
#define SIO_UNIT_SEL 0x7 /* unit select reg */
#define SIO_UNIT_ACT 0x30 /* unit enable */
@@ -212,14 +212,12 @@ static void pc8736x_gpio_change(unsigned index)
pc8736x_gpio_set(index, !pc8736x_gpio_current(index));
}
-static struct nsc_gpio_ops pc8736x_access = {
+static struct nsc_gpio_ops pc8736x_gpio_ops = {
.owner = THIS_MODULE,
.gpio_config = pc8736x_gpio_configure,
.gpio_dump = nsc_gpio_dump,
.gpio_get = pc8736x_gpio_get,
.gpio_set = pc8736x_gpio_set,
- .gpio_set_high = pc8736x_gpio_set_high,
- .gpio_set_low = pc8736x_gpio_set_low,
.gpio_change = pc8736x_gpio_change,
.gpio_current = pc8736x_gpio_current
};
@@ -227,16 +225,16 @@ static struct nsc_gpio_ops pc8736x_access = {
static int pc8736x_gpio_open(struct inode *inode, struct file *file)
{
unsigned m = iminor(inode);
- file->private_data = &pc8736x_access;
+ file->private_data = &pc8736x_gpio_ops;
dev_dbg(&pdev->dev, "open %d\n", m);
- if (m > 63)
+ if (m >= PC8736X_GPIO_CT)
return -EINVAL;
return nonseekable_open(inode, file);
}
-static const struct file_operations pc8736x_gpio_fops = {
+static const struct file_operations pc8736x_gpio_fileops = {
.owner = THIS_MODULE,
.open = pc8736x_gpio_open,
.write = nsc_gpio_write,
@@ -255,9 +253,12 @@ static void __init pc8736x_init_shadow(void)
}
+static struct cdev pc8736x_gpio_cdev;
+
static int __init pc8736x_gpio_init(void)
{
- int rc = 0;
+ int rc;
+ dev_t devid;
pdev = platform_device_alloc(DEVNAME, 0);
if (!pdev)
@@ -275,7 +276,7 @@ static int __init pc8736x_gpio_init(void)
dev_err(&pdev->dev, "no device found\n");
goto undo_platform_dev_add;
}
- pc8736x_access.dev = &pdev->dev;
+ pc8736x_gpio_ops.dev = &pdev->dev;
/* Verify that chip and it's GPIO unit are both enabled.
My BIOS does this, so I take minimum action here
@@ -297,7 +298,7 @@ static int __init pc8736x_gpio_init(void)
pc8736x_gpio_base = (superio_inb(SIO_BASE_HADDR) << 8
| superio_inb(SIO_BASE_LADDR));
- if (!request_region(pc8736x_gpio_base, 16, DEVNAME)) {
+ if (!request_region(pc8736x_gpio_base, PC8736X_GPIO_RANGE, DEVNAME)) {
rc = -ENODEV;
dev_err(&pdev->dev, "GPIO ioport %x busy\n",
pc8736x_gpio_base);
@@ -305,10 +306,17 @@ static int __init pc8736x_gpio_init(void)
}
dev_info(&pdev->dev, "GPIO ioport %x reserved\n", pc8736x_gpio_base);
- rc = register_chrdev(major, DEVNAME, &pc8736x_gpio_fops);
+ if (major) {
+ devid = MKDEV(major, 0);
+ rc = register_chrdev_region(devid, PC8736X_GPIO_CT, DEVNAME);
+ } else {
+ rc = alloc_chrdev_region(&devid, 0, PC8736X_GPIO_CT, DEVNAME);
+ major = MAJOR(devid);
+ }
+
if (rc < 0) {
dev_err(&pdev->dev, "register-chrdev failed: %d\n", rc);
- goto undo_platform_dev_add;
+ goto undo_request_region;
}
if (!major) {
major = rc;
@@ -316,8 +324,15 @@ static int __init pc8736x_gpio_init(void)
}
pc8736x_init_shadow();
+
+ /* ignore minor errs, and succeed */
+ cdev_init(&pc8736x_gpio_cdev, &pc8736x_gpio_fileops);
+ cdev_add(&pc8736x_gpio_cdev, devid, PC8736X_GPIO_CT);
+
return 0;
+undo_request_region:
+ release_region(pc8736x_gpio_base, PC8736X_GPIO_RANGE);
undo_platform_dev_add:
platform_device_del(pdev);
undo_platform_dev_alloc:
@@ -328,14 +343,15 @@ undo_platform_dev_alloc:
static void __exit pc8736x_gpio_cleanup(void)
{
- dev_dbg(&pdev->dev, " cleanup\n");
+ dev_dbg(&pdev->dev, "cleanup\n");
- release_region(pc8736x_gpio_base, 16);
+ cdev_del(&pc8736x_gpio_cdev);
+ unregister_chrdev_region(MKDEV(major,0), PC8736X_GPIO_CT);
+ release_region(pc8736x_gpio_base, PC8736X_GPIO_RANGE);
- unregister_chrdev(major, DEVNAME);
+ platform_device_del(pdev);
+ platform_device_put(pdev);
}
-EXPORT_SYMBOL(pc8736x_access);
-
module_init(pc8736x_gpio_init);
module_exit(pc8736x_gpio_cleanup);
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 17bc8abd5df..00f574cbb0d 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -1174,8 +1174,12 @@ static void dcd_change(MGSLPC_INFO *info)
else
info->input_signal_events.dcd_down++;
#ifdef CONFIG_HDLC
- if (info->netcount)
- hdlc_set_carrier(info->serial_signals & SerialSignal_DCD, info->netdev);
+ if (info->netcount) {
+ if (info->serial_signals & SerialSignal_DCD)
+ netif_carrier_on(info->netdev);
+ else
+ netif_carrier_off(info->netdev);
+ }
#endif
wake_up_interruptible(&info->status_event_wait_q);
wake_up_interruptible(&info->event_wait_q);
@@ -4251,8 +4255,10 @@ static int hdlcdev_open(struct net_device *dev)
spin_lock_irqsave(&info->lock, flags);
get_signals(info);
spin_unlock_irqrestore(&info->lock, flags);
- hdlc_set_carrier(info->serial_signals & SerialSignal_DCD, dev);
-
+ if (info->serial_signals & SerialSignal_DCD)
+ netif_carrier_on(dev);
+ else
+ netif_carrier_off(dev);
return 0;
}
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index cc7bd1a3095..6e6a7c7a7ef 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -46,13 +46,12 @@
* 1.11a Daniele Bellucci: Audit create_proc_read_entry in rtc_init
* 1.12 Venkatesh Pallipadi: Hooks for emulating rtc on HPET base-timer
* CONFIG_HPET_EMULATE_RTC
+ * 1.12a Maciej W. Rozycki: Handle memory-mapped chips properly.
* 1.12ac Alan Cox: Allow read access to the day of week register
*/
#define RTC_VERSION "1.12ac"
-#define RTC_IO_EXTENT 0x8
-
/*
* Note that *all* calls to CMOS_READ and CMOS_WRITE are done with
* interrupts disabled. Due to the index-port/data-port (0x70/0x71)
@@ -337,7 +336,15 @@ static ssize_t rtc_read(struct file *file, char __user *buf,
if (rtc_has_irq == 0)
return -EIO;
- if (count < sizeof(unsigned))
+ /*
+ * Historically this function used to assume that sizeof(unsigned long)
+ * is the same in userspace and kernelspace. This lead to problems
+ * for configurations with multiple ABIs such a the MIPS o32 and 64
+ * ABIs supported on the same kernel. So now we support read of both
+ * 4 and 8 bytes and assume that's the sizeof(unsigned long) in the
+ * userspace ABI.
+ */
+ if (count != sizeof(unsigned int) && count != sizeof(unsigned long))
return -EINVAL;
add_wait_queue(&rtc_wait, &wait);
@@ -368,10 +375,12 @@ static ssize_t rtc_read(struct file *file, char __user *buf,
schedule();
} while (1);
- if (count < sizeof(unsigned long))
- retval = put_user(data, (unsigned int __user *)buf) ?: sizeof(int);
+ if (count == sizeof(unsigned int))
+ retval = put_user(data, (unsigned int __user *)buf) ?: sizeof(int);
else
retval = put_user(data, (unsigned long __user *)buf) ?: sizeof(long);
+ if (!retval)
+ retval = count;
out:
current->state = TASK_RUNNING;
remove_wait_queue(&rtc_wait, &wait);
@@ -923,6 +932,9 @@ static int __init rtc_init(void)
struct sparc_isa_device *isa_dev;
#endif
#endif
+#ifndef __sparc__
+ void *r;
+#endif
#ifdef __sparc__
for_each_ebus(ebus) {
@@ -964,8 +976,13 @@ found:
}
no_irq:
#else
- if (!request_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc")) {
- printk(KERN_ERR "rtc: I/O port %d is not free.\n", RTC_PORT (0));
+ if (RTC_IOMAPPED)
+ r = request_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc");
+ else
+ r = request_mem_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc");
+ if (!r) {
+ printk(KERN_ERR "rtc: I/O resource %lx is not free.\n",
+ (long)(RTC_PORT(0)));
return -EIO;
}
@@ -979,7 +996,10 @@ no_irq:
if(request_irq(RTC_IRQ, rtc_int_handler_ptr, IRQF_DISABLED, "rtc", NULL)) {
/* Yeah right, seeing as irq 8 doesn't even hit the bus. */
printk(KERN_ERR "rtc: IRQ %d is not free.\n", RTC_IRQ);
- release_region(RTC_PORT(0), RTC_IO_EXTENT);
+ if (RTC_IOMAPPED)
+ release_region(RTC_PORT(0), RTC_IO_EXTENT);
+ else
+ release_mem_region(RTC_PORT(0), RTC_IO_EXTENT);
return -EIO;
}
hpet_rtc_timer_init();
@@ -1079,7 +1099,10 @@ static void __exit rtc_exit (void)
if (rtc_has_irq)
free_irq (rtc_irq, &rtc_port);
#else
- release_region (RTC_PORT (0), RTC_IO_EXTENT);
+ if (RTC_IOMAPPED)
+ release_region(RTC_PORT(0), RTC_IO_EXTENT);
+ else
+ release_mem_region(RTC_PORT(0), RTC_IO_EXTENT);
#ifdef RTC_IRQ
if (rtc_has_irq)
free_irq (RTC_IRQ, NULL);
@@ -1222,7 +1245,7 @@ static int rtc_proc_open(struct inode *inode, struct file *file)
void rtc_get_rtc_time(struct rtc_time *rtc_tm)
{
- unsigned long uip_watchdog = jiffies;
+ unsigned long uip_watchdog = jiffies, flags;
unsigned char ctrl;
#ifdef CONFIG_MACH_DECSTATION
unsigned int real_year;
@@ -1249,7 +1272,7 @@ void rtc_get_rtc_time(struct rtc_time *rtc_tm)
* RTC has RTC_DAY_OF_WEEK, we should usually ignore it, as it is
* only updated by the RTC when initially set to a non-zero value.
*/
- spin_lock_irq(&rtc_lock);
+ spin_lock_irqsave(&rtc_lock, flags);
rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS);
rtc_tm->tm_min = CMOS_READ(RTC_MINUTES);
rtc_tm->tm_hour = CMOS_READ(RTC_HOURS);
@@ -1263,7 +1286,7 @@ void rtc_get_rtc_time(struct rtc_time *rtc_tm)
real_year = CMOS_READ(RTC_DEC_YEAR);
#endif
ctrl = CMOS_READ(RTC_CONTROL);
- spin_unlock_irq(&rtc_lock);
+ spin_unlock_irqrestore(&rtc_lock, flags);
if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
{
diff --git a/drivers/char/scx200_gpio.c b/drivers/char/scx200_gpio.c
index 425c58719db..b956c7babd1 100644
--- a/drivers/char/scx200_gpio.c
+++ b/drivers/char/scx200_gpio.c
@@ -5,7 +5,6 @@
Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com> */
-#include <linux/config.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/module.h>
@@ -22,37 +21,37 @@
#include <linux/scx200_gpio.h>
#include <linux/nsc_gpio.h>
-#define NAME "scx200_gpio"
-#define DEVNAME NAME
+#define DRVNAME "scx200_gpio"
static struct platform_device *pdev;
MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
-MODULE_DESCRIPTION("NatSemi SCx200 GPIO Pin Driver");
+MODULE_DESCRIPTION("NatSemi/AMD SCx200 GPIO Pin Driver");
MODULE_LICENSE("GPL");
static int major = 0; /* default to dynamic major */
module_param(major, int, 0);
MODULE_PARM_DESC(major, "Major device number");
-struct nsc_gpio_ops scx200_access = {
+#define MAX_PINS 32 /* 64 later, when known ok */
+
+struct nsc_gpio_ops scx200_gpio_ops = {
.owner = THIS_MODULE,
.gpio_config = scx200_gpio_configure,
.gpio_dump = nsc_gpio_dump,
.gpio_get = scx200_gpio_get,
.gpio_set = scx200_gpio_set,
- .gpio_set_high = scx200_gpio_set_high,
- .gpio_set_low = scx200_gpio_set_low,
.gpio_change = scx200_gpio_change,
.gpio_current = scx200_gpio_current
};
+EXPORT_SYMBOL(scx200_gpio_ops);
static int scx200_gpio_open(struct inode *inode, struct file *file)
{
unsigned m = iminor(inode);
- file->private_data = &scx200_access;
+ file->private_data = &scx200_gpio_ops;
- if (m > 63)
+ if (m >= MAX_PINS)
return -EINVAL;
return nonseekable_open(inode, file);
}
@@ -62,8 +61,7 @@ static int scx200_gpio_release(struct inode *inode, struct file *file)
return 0;
}
-
-static const struct file_operations scx200_gpio_fops = {
+static const struct file_operations scx200_gpio_fileops = {
.owner = THIS_MODULE,
.write = nsc_gpio_write,
.read = nsc_gpio_read,
@@ -71,21 +69,20 @@ static const struct file_operations scx200_gpio_fops = {
.release = scx200_gpio_release,
};
-struct cdev *scx200_devices;
-static int num_pins = 32;
+struct cdev scx200_gpio_cdev; /* use 1 cdev for all pins */
static int __init scx200_gpio_init(void)
{
- int rc, i;
- dev_t dev = MKDEV(major, 0);
+ int rc;
+ dev_t devid;
if (!scx200_gpio_present()) {
- printk(KERN_ERR NAME ": no SCx200 gpio present\n");
+ printk(KERN_ERR DRVNAME ": no SCx200 gpio present\n");
return -ENODEV;
}
/* support dev_dbg() with pdev->dev */
- pdev = platform_device_alloc(DEVNAME, 0);
+ pdev = platform_device_alloc(DRVNAME, 0);
if (!pdev)
return -ENOMEM;
@@ -94,37 +91,25 @@ static int __init scx200_gpio_init(void)
goto undo_malloc;
/* nsc_gpio uses dev_dbg(), so needs this */
- scx200_access.dev = &pdev->dev;
-
- if (major)
- rc = register_chrdev_region(dev, num_pins, "scx200_gpio");
- else {
- rc = alloc_chrdev_region(&dev, 0, num_pins, "scx200_gpio");
- major = MAJOR(dev);
+ scx200_gpio_ops.dev = &pdev->dev;
+
+ if (major) {
+ devid = MKDEV(major, 0);
+ rc = register_chrdev_region(devid, MAX_PINS, "scx200_gpio");
+ } else {
+ rc = alloc_chrdev_region(&devid, 0, MAX_PINS, "scx200_gpio");
+ major = MAJOR(devid);
}
if (rc < 0) {
dev_err(&pdev->dev, "SCx200 chrdev_region err: %d\n", rc);
goto undo_platform_device_add;
}
- scx200_devices = kzalloc(num_pins * sizeof(struct cdev), GFP_KERNEL);
- if (!scx200_devices) {
- rc = -ENOMEM;
- goto undo_chrdev_region;
- }
- for (i = 0; i < num_pins; i++) {
- struct cdev *cdev = &scx200_devices[i];
- cdev_init(cdev, &scx200_gpio_fops);
- cdev->owner = THIS_MODULE;
- rc = cdev_add(cdev, MKDEV(major, i), 1);
- /* tolerate 'minor' errors */
- if (rc)
- dev_err(&pdev->dev, "Error %d on minor %d", rc, i);
- }
+
+ cdev_init(&scx200_gpio_cdev, &scx200_gpio_fileops);
+ cdev_add(&scx200_gpio_cdev, devid, MAX_PINS);
return 0; /* succeed */
-undo_chrdev_region:
- unregister_chrdev_region(dev, num_pins);
undo_platform_device_add:
platform_device_del(pdev);
undo_malloc:
@@ -135,10 +120,11 @@ undo_malloc:
static void __exit scx200_gpio_cleanup(void)
{
- kfree(scx200_devices);
- unregister_chrdev_region(MKDEV(major, 0), num_pins);
+ cdev_del(&scx200_gpio_cdev);
+ /* cdev_put(&scx200_gpio_cdev); */
+
+ unregister_chrdev_region(MKDEV(major, 0), MAX_PINS);
platform_device_unregister(pdev);
- /* kfree(pdev); */
}
module_init(scx200_gpio_init);
diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c
index afc6eda602f..07e0b75f233 100644
--- a/drivers/char/snsc.c
+++ b/drivers/char/snsc.c
@@ -374,7 +374,12 @@ scdrv_init(void)
struct sysctl_data_s *scd;
void *salbuf;
dev_t first_dev, dev;
- nasid_t event_nasid = ia64_sn_get_console_nasid();
+ nasid_t event_nasid;
+
+ if (!ia64_platform_is("sn2"))
+ return -ENODEV;
+
+ event_nasid = ia64_sn_get_console_nasid();
if (alloc_chrdev_region(&first_dev, 0, num_cnodes,
SYSCTL_BASENAME) < 0) {
diff --git a/drivers/char/snsc_event.c b/drivers/char/snsc_event.c
index 8b2210b633d..d12d4f629ce 100644
--- a/drivers/char/snsc_event.c
+++ b/drivers/char/snsc_event.c
@@ -220,20 +220,7 @@ scdrv_dispatch_event(char *event, int len)
" Sending SIGPWR to init...\n");
/* give a SIGPWR signal to init proc */
-
- /* first find init's task */
- read_lock(&tasklist_lock);
- for_each_process(p) {
- if (p->pid == 1)
- break;
- }
- if (p) {
- force_sig(SIGPWR, p);
- } else {
- printk(KERN_ERR "Failed to signal init!\n");
- snsc_shutting_down = 0; /* so can try again (?) */
- }
- read_unlock(&tasklist_lock);
+ kill_proc(1, SIGPWR, 0);
} else {
/* print to system log */
printk("%s|$(0x%x)%s\n", severity, esp_code, desc);
diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c
index cb2859249d4..a1d303f9a33 100644
--- a/drivers/char/specialix.c
+++ b/drivers/char/specialix.c
@@ -2584,6 +2584,12 @@ static void __exit specialix_exit_module(void)
func_exit();
}
+static struct pci_device_id specialx_pci_tbl[] __devinitdata = {
+ { PCI_DEVICE(PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_IO8) },
+ { }
+};
+MODULE_DEVICE_TABLE(pci, specialx_pci_tbl);
+
module_init(specialix_init_module);
module_exit(specialix_exit_module);
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index df782dd1098..78b1b1a2732 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -1344,8 +1344,12 @@ static void mgsl_isr_io_pin( struct mgsl_struct *info )
} else
info->input_signal_events.dcd_down++;
#ifdef CONFIG_HDLC
- if (info->netcount)
- hdlc_set_carrier(status & MISCSTATUS_DCD, info->netdev);
+ if (info->netcount) {
+ if (status & MISCSTATUS_DCD)
+ netif_carrier_on(info->netdev);
+ else
+ netif_carrier_off(info->netdev);
+ }
#endif
}
if (status & MISCSTATUS_CTS_LATCHED)
@@ -7844,8 +7848,10 @@ static int hdlcdev_open(struct net_device *dev)
spin_lock_irqsave(&info->irq_spinlock, flags);
usc_get_serial_signals(info);
spin_unlock_irqrestore(&info->irq_spinlock, flags);
- hdlc_set_carrier(info->serial_signals & SerialSignal_DCD, dev);
-
+ if (info->serial_signals & SerialSignal_DCD)
+ netif_carrier_on(dev);
+ else
+ netif_carrier_off(dev);
return 0;
}
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
index e829594195c..b2dbbdb1bf8 100644
--- a/drivers/char/synclink_gt.c
+++ b/drivers/char/synclink_gt.c
@@ -1497,8 +1497,10 @@ static int hdlcdev_open(struct net_device *dev)
spin_lock_irqsave(&info->lock, flags);
get_signals(info);
spin_unlock_irqrestore(&info->lock, flags);
- hdlc_set_carrier(info->signals & SerialSignal_DCD, dev);
-
+ if (info->signals & SerialSignal_DCD)
+ netif_carrier_on(dev);
+ else
+ netif_carrier_off(dev);
return 0;
}
@@ -1997,8 +1999,12 @@ static void dcd_change(struct slgt_info *info)
info->input_signal_events.dcd_down++;
}
#ifdef CONFIG_HDLC
- if (info->netcount)
- hdlc_set_carrier(info->signals & SerialSignal_DCD, info->netdev);
+ if (info->netcount) {
+ if (info->signals & SerialSignal_DCD)
+ netif_carrier_on(info->netdev);
+ else
+ netif_carrier_off(info->netdev);
+ }
#endif
wake_up_interruptible(&info->status_event_wait_q);
wake_up_interruptible(&info->event_wait_q);
diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c
index 1e443a233f5..66f3754fbbd 100644
--- a/drivers/char/synclinkmp.c
+++ b/drivers/char/synclinkmp.c
@@ -1752,8 +1752,10 @@ static int hdlcdev_open(struct net_device *dev)
spin_lock_irqsave(&info->lock, flags);
get_signals(info);
spin_unlock_irqrestore(&info->lock, flags);
- hdlc_set_carrier(info->serial_signals & SerialSignal_DCD, dev);
-
+ if (info->serial_signals & SerialSignal_DCD)
+ netif_carrier_on(dev);
+ else
+ netif_carrier_off(dev);
return 0;
}
@@ -2522,8 +2524,12 @@ void isr_io_pin( SLMP_INFO *info, u16 status )
} else
info->input_signal_events.dcd_down++;
#ifdef CONFIG_HDLC
- if (info->netcount)
- hdlc_set_carrier(status & SerialSignal_DCD, info->netdev);
+ if (info->netcount) {
+ if (status & SerialSignal_DCD)
+ netif_carrier_on(info->netdev);
+ else
+ netif_carrier_off(info->netdev);
+ }
#endif
}
if (status & MISCSTATUS_CTS_LATCHED)
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index 6889e7db3af..a082a2e3425 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -1141,6 +1141,7 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend
put_device(dev);
clear_bit(chip->dev_num, dev_mask);
kfree(chip);
+ kfree(devname);
return NULL;
}
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index 3232b193259..ee7ac6f43c6 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -424,6 +424,7 @@ static irqreturn_t tis_int_handler(int irq, void *dev_id, struct pt_regs *regs)
iowrite32(interrupt,
chip->vendor.iobase +
TPM_INT_STATUS(chip->vendor.locality));
+ ioread32(chip->vendor.iobase + TPM_INT_STATUS(chip->vendor.locality));
return IRQ_HANDLED;
}
@@ -431,23 +432,19 @@ static int interrupts = 1;
module_param(interrupts, bool, 0444);
MODULE_PARM_DESC(interrupts, "Enable interrupts");
-static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
- const struct pnp_device_id *pnp_id)
+static int tpm_tis_init(struct device *dev, resource_size_t start,
+ resource_size_t len)
{
u32 vendor, intfcaps, intmask;
int rc, i;
- unsigned long start, len;
struct tpm_chip *chip;
- start = pnp_mem_start(pnp_dev, 0);
- len = pnp_mem_len(pnp_dev, 0);
-
if (!start)
start = TIS_MEM_BASE;
if (!len)
len = TIS_MEM_LEN;
- if (!(chip = tpm_register_hardware(&pnp_dev->dev, &tpm_tis)))
+ if (!(chip = tpm_register_hardware(dev, &tpm_tis)))
return -ENODEV;
chip->vendor.iobase = ioremap(start, len);
@@ -464,7 +461,7 @@ static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
- dev_info(&pnp_dev->dev,
+ dev_info(dev,
"1.2 TPM (device-id 0x%X, rev-id %d)\n",
vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0)));
@@ -472,26 +469,26 @@ static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
intfcaps =
ioread32(chip->vendor.iobase +
TPM_INTF_CAPS(chip->vendor.locality));
- dev_dbg(&pnp_dev->dev, "TPM interface capabilities (0x%x):\n",
+ dev_dbg(dev, "TPM interface capabilities (0x%x):\n",
intfcaps);
if (intfcaps & TPM_INTF_BURST_COUNT_STATIC)
- dev_dbg(&pnp_dev->dev, "\tBurst Count Static\n");
+ dev_dbg(dev, "\tBurst Count Static\n");
if (intfcaps & TPM_INTF_CMD_READY_INT)
- dev_dbg(&pnp_dev->dev, "\tCommand Ready Int Support\n");
+ dev_dbg(dev, "\tCommand Ready Int Support\n");
if (intfcaps & TPM_INTF_INT_EDGE_FALLING)
- dev_dbg(&pnp_dev->dev, "\tInterrupt Edge Falling\n");
+ dev_dbg(dev, "\tInterrupt Edge Falling\n");
if (intfcaps & TPM_INTF_INT_EDGE_RISING)
- dev_dbg(&pnp_dev->dev, "\tInterrupt Edge Rising\n");
+ dev_dbg(dev, "\tInterrupt Edge Rising\n");
if (intfcaps & TPM_INTF_INT_LEVEL_LOW)
- dev_dbg(&pnp_dev->dev, "\tInterrupt Level Low\n");
+ dev_dbg(dev, "\tInterrupt Level Low\n");
if (intfcaps & TPM_INTF_INT_LEVEL_HIGH)
- dev_dbg(&pnp_dev->dev, "\tInterrupt Level High\n");
+ dev_dbg(dev, "\tInterrupt Level High\n");
if (intfcaps & TPM_INTF_LOCALITY_CHANGE_INT)
- dev_dbg(&pnp_dev->dev, "\tLocality Change Int Support\n");
+ dev_dbg(dev, "\tLocality Change Int Support\n");
if (intfcaps & TPM_INTF_STS_VALID_INT)
- dev_dbg(&pnp_dev->dev, "\tSts Valid Int Support\n");
+ dev_dbg(dev, "\tSts Valid Int Support\n");
if (intfcaps & TPM_INTF_DATA_AVAIL_INT)
- dev_dbg(&pnp_dev->dev, "\tData Avail Int Support\n");
+ dev_dbg(dev, "\tData Avail Int Support\n");
if (request_locality(chip, 0) != 0) {
rc = -ENODEV;
@@ -594,6 +591,16 @@ out_err:
return rc;
}
+static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
+ const struct pnp_device_id *pnp_id)
+{
+ resource_size_t start, len;
+ start = pnp_mem_start(pnp_dev, 0);
+ len = pnp_mem_len(pnp_dev, 0);
+
+ return tpm_tis_init(&pnp_dev->dev, start, len);
+}
+
static int tpm_tis_pnp_suspend(struct pnp_dev *dev, pm_message_t msg)
{
return tpm_pm_suspend(&dev->dev, msg);
@@ -628,8 +635,36 @@ module_param_string(hid, tpm_pnp_tbl[TIS_HID_USR_IDX].id,
sizeof(tpm_pnp_tbl[TIS_HID_USR_IDX].id), 0444);
MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe");
+static struct device_driver tis_drv = {
+ .name = "tpm_tis",
+ .bus = &platform_bus_type,
+ .owner = THIS_MODULE,
+ .suspend = tpm_pm_suspend,
+ .resume = tpm_pm_resume,
+};
+
+static struct platform_device *pdev;
+
+static int force;
+module_param(force, bool, 0444);
+MODULE_PARM_DESC(force, "Force device probe rather than using ACPI entry");
static int __init init_tis(void)
{
+ int rc;
+
+ if (force) {
+ rc = driver_register(&tis_drv);
+ if (rc < 0)
+ return rc;
+ if (IS_ERR(pdev=platform_device_register_simple("tpm_tis", -1, NULL, 0)))
+ return PTR_ERR(pdev);
+ if((rc=tpm_tis_init(&pdev->dev, 0, 0)) != 0) {
+ platform_device_unregister(pdev);
+ driver_unregister(&tis_drv);
+ }
+ return rc;
+ }
+
return pnp_register_driver(&tis_pnp_driver);
}
@@ -654,7 +689,11 @@ static void __exit cleanup_tis(void)
tpm_remove_hardware(chip->dev);
}
spin_unlock(&tis_lock);
- pnp_unregister_driver(&tis_pnp_driver);
+ if (force) {
+ platform_device_unregister(pdev);
+ driver_unregister(&tis_drv);
+ } else
+ pnp_unregister_driver(&tis_pnp_driver);
}
module_init(init_tis);
diff --git a/drivers/char/vr41xx_giu.c b/drivers/char/vr41xx_giu.c
index 1b9b1f1d4c4..8116a47b80f 100644
--- a/drivers/char/vr41xx_giu.c
+++ b/drivers/char/vr41xx_giu.c
@@ -33,6 +33,7 @@
#include <asm/cpu.h>
#include <asm/io.h>
#include <asm/vr41xx/giu.h>
+#include <asm/vr41xx/irq.h>
#include <asm/vr41xx/vr41xx.h>
MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>");
diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c
index 498aa37bca2..3ece6923134 100644
--- a/drivers/connector/cn_proc.c
+++ b/drivers/connector/cn_proc.c
@@ -51,6 +51,7 @@ void proc_fork_connector(struct task_struct *task)
struct cn_msg *msg;
struct proc_event *ev;
__u8 buffer[CN_PROC_MSG_SIZE];
+ struct timespec ts;
if (atomic_read(&proc_event_num_listeners) < 1)
return;
@@ -58,7 +59,8 @@ void proc_fork_connector(struct task_struct *task)
msg = (struct cn_msg*)buffer;
ev = (struct proc_event*)msg->data;
get_seq(&msg->seq, &ev->cpu);
- ktime_get_ts(&ev->timestamp); /* get high res monotonic timestamp */
+ ktime_get_ts(&ts); /* get high res monotonic timestamp */
+ ev->timestamp_ns = timespec_to_ns(&ts);
ev->what = PROC_EVENT_FORK;
ev->event_data.fork.parent_pid = task->real_parent->pid;
ev->event_data.fork.parent_tgid = task->real_parent->tgid;
@@ -76,6 +78,7 @@ void proc_exec_connector(struct task_struct *task)
{
struct cn_msg *msg;
struct proc_event *ev;
+ struct timespec ts;
__u8 buffer[CN_PROC_MSG_SIZE];
if (atomic_read(&proc_event_num_listeners) < 1)
@@ -84,7 +87,8 @@ void proc_exec_connector(struct task_struct *task)
msg = (struct cn_msg*)buffer;
ev = (struct proc_event*)msg->data;
get_seq(&msg->seq, &ev->cpu);
- ktime_get_ts(&ev->timestamp);
+ ktime_get_ts(&ts); /* get high res monotonic timestamp */
+ ev->timestamp_ns = timespec_to_ns(&ts);
ev->what = PROC_EVENT_EXEC;
ev->event_data.exec.process_pid = task->pid;
ev->event_data.exec.process_tgid = task->tgid;
@@ -100,6 +104,7 @@ void proc_id_connector(struct task_struct *task, int which_id)
struct cn_msg *msg;
struct proc_event *ev;
__u8 buffer[CN_PROC_MSG_SIZE];
+ struct timespec ts;
if (atomic_read(&proc_event_num_listeners) < 1)
return;
@@ -118,7 +123,8 @@ void proc_id_connector(struct task_struct *task, int which_id)
} else
return;
get_seq(&msg->seq, &ev->cpu);
- ktime_get_ts(&ev->timestamp);
+ ktime_get_ts(&ts); /* get high res monotonic timestamp */
+ ev->timestamp_ns = timespec_to_ns(&ts);
memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
msg->ack = 0; /* not used */
@@ -131,6 +137,7 @@ void proc_exit_connector(struct task_struct *task)
struct cn_msg *msg;
struct proc_event *ev;
__u8 buffer[CN_PROC_MSG_SIZE];
+ struct timespec ts;
if (atomic_read(&proc_event_num_listeners) < 1)
return;
@@ -138,7 +145,8 @@ void proc_exit_connector(struct task_struct *task)
msg = (struct cn_msg*)buffer;
ev = (struct proc_event*)msg->data;
get_seq(&msg->seq, &ev->cpu);
- ktime_get_ts(&ev->timestamp);
+ ktime_get_ts(&ts); /* get high res monotonic timestamp */
+ ev->timestamp_ns = timespec_to_ns(&ts);
ev->what = PROC_EVENT_EXIT;
ev->event_data.exit.process_pid = task->pid;
ev->event_data.exit.process_tgid = task->tgid;
@@ -164,6 +172,7 @@ static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack)
struct cn_msg *msg;
struct proc_event *ev;
__u8 buffer[CN_PROC_MSG_SIZE];
+ struct timespec ts;
if (atomic_read(&proc_event_num_listeners) < 1)
return;
@@ -171,7 +180,8 @@ static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack)
msg = (struct cn_msg*)buffer;
ev = (struct proc_event*)msg->data;
msg->seq = rcvd_seq;
- ktime_get_ts(&ev->timestamp);
+ ktime_get_ts(&ts); /* get high res monotonic timestamp */
+ ev->timestamp_ns = timespec_to_ns(&ts);
ev->cpu = -1;
ev->what = PROC_EVENT_NONE;
ev->event_data.ack.err = err;
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 1ba4039777e..b3df613ae4e 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -284,39 +284,69 @@ EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
* SYSFS INTERFACE *
*********************************************************************/
+static struct cpufreq_governor *__find_governor(const char *str_governor)
+{
+ struct cpufreq_governor *t;
+
+ list_for_each_entry(t, &cpufreq_governor_list, governor_list)
+ if (!strnicmp(str_governor,t->name,CPUFREQ_NAME_LEN))
+ return t;
+
+ return NULL;
+}
+
/**
* cpufreq_parse_governor - parse a governor string
*/
static int cpufreq_parse_governor (char *str_governor, unsigned int *policy,
struct cpufreq_governor **governor)
{
+ int err = -EINVAL;
+
if (!cpufreq_driver)
- return -EINVAL;
+ goto out;
+
if (cpufreq_driver->setpolicy) {
if (!strnicmp(str_governor, "performance", CPUFREQ_NAME_LEN)) {
*policy = CPUFREQ_POLICY_PERFORMANCE;
- return 0;
+ err = 0;
} else if (!strnicmp(str_governor, "powersave", CPUFREQ_NAME_LEN)) {
*policy = CPUFREQ_POLICY_POWERSAVE;
- return 0;
+ err = 0;
}
- return -EINVAL;
- } else {
+ } else if (cpufreq_driver->target) {
struct cpufreq_governor *t;
+
mutex_lock(&cpufreq_governor_mutex);
- if (!cpufreq_driver || !cpufreq_driver->target)
- goto out;
- list_for_each_entry(t, &cpufreq_governor_list, governor_list) {
- if (!strnicmp(str_governor,t->name,CPUFREQ_NAME_LEN)) {
- *governor = t;
+
+ t = __find_governor(str_governor);
+
+ if (t == NULL) {
+ char *name = kasprintf(GFP_KERNEL, "cpufreq_%s", str_governor);
+
+ if (name) {
+ int ret;
+
mutex_unlock(&cpufreq_governor_mutex);
- return 0;
+ ret = request_module(name);
+ mutex_lock(&cpufreq_governor_mutex);
+
+ if (ret == 0)
+ t = __find_governor(str_governor);
}
+
+ kfree(name);
}
-out:
+
+ if (t != NULL) {
+ *governor = t;
+ err = 0;
+ }
+
mutex_unlock(&cpufreq_governor_mutex);
}
- return -EINVAL;
+ out:
+ return err;
}
@@ -364,10 +394,12 @@ static ssize_t store_##file_name \
if (ret != 1) \
return -EINVAL; \
\
+ lock_cpu_hotplug(); \
mutex_lock(&policy->lock); \
ret = __cpufreq_set_policy(policy, &new_policy); \
policy->user_policy.object = policy->object; \
mutex_unlock(&policy->lock); \
+ unlock_cpu_hotplug(); \
\
return ret ? ret : count; \
}
@@ -423,6 +455,8 @@ static ssize_t store_scaling_governor (struct cpufreq_policy * policy,
if (cpufreq_parse_governor(str_governor, &new_policy.policy, &new_policy.governor))
return -EINVAL;
+ lock_cpu_hotplug();
+
/* Do not use cpufreq_set_policy here or the user_policy.max
will be wrongly overridden */
mutex_lock(&policy->lock);
@@ -432,6 +466,8 @@ static ssize_t store_scaling_governor (struct cpufreq_policy * policy,
policy->user_policy.governor = policy->governor;
mutex_unlock(&policy->lock);
+ unlock_cpu_hotplug();
+
return ret ? ret : count;
}
@@ -1193,20 +1229,18 @@ EXPORT_SYMBOL(cpufreq_unregister_notifier);
*********************************************************************/
+/* Must be called with lock_cpu_hotplug held */
int __cpufreq_driver_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
int retval = -EINVAL;
- lock_cpu_hotplug();
dprintk("target for CPU %u: %u kHz, relation %u\n", policy->cpu,
target_freq, relation);
if (cpu_online(policy->cpu) && cpufreq_driver->target)
retval = cpufreq_driver->target(policy, target_freq, relation);
- unlock_cpu_hotplug();
-
return retval;
}
EXPORT_SYMBOL_GPL(__cpufreq_driver_target);
@@ -1221,17 +1255,23 @@ int cpufreq_driver_target(struct cpufreq_policy *policy,
if (!policy)
return -EINVAL;
+ lock_cpu_hotplug();
mutex_lock(&policy->lock);
ret = __cpufreq_driver_target(policy, target_freq, relation);
mutex_unlock(&policy->lock);
+ unlock_cpu_hotplug();
cpufreq_cpu_put(policy);
return ret;
}
EXPORT_SYMBOL_GPL(cpufreq_driver_target);
+/*
+ * Locking: Must be called with the lock_cpu_hotplug() lock held
+ * when "event" is CPUFREQ_GOV_LIMITS
+ */
static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event)
{
@@ -1253,43 +1293,23 @@ static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event)
}
-int cpufreq_governor(unsigned int cpu, unsigned int event)
-{
- int ret = 0;
- struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
-
- if (!policy)
- return -EINVAL;
-
- mutex_lock(&policy->lock);
- ret = __cpufreq_governor(policy, event);
- mutex_unlock(&policy->lock);
-
- cpufreq_cpu_put(policy);
- return ret;
-}
-EXPORT_SYMBOL_GPL(cpufreq_governor);
-
-
int cpufreq_register_governor(struct cpufreq_governor *governor)
{
- struct cpufreq_governor *t;
+ int err;
if (!governor)
return -EINVAL;
mutex_lock(&cpufreq_governor_mutex);
- list_for_each_entry(t, &cpufreq_governor_list, governor_list) {
- if (!strnicmp(governor->name,t->name,CPUFREQ_NAME_LEN)) {
- mutex_unlock(&cpufreq_governor_mutex);
- return -EBUSY;
- }
+ err = -EBUSY;
+ if (__find_governor(governor->name) == NULL) {
+ err = 0;
+ list_add(&governor->governor_list, &cpufreq_governor_list);
}
- list_add(&governor->governor_list, &cpufreq_governor_list);
mutex_unlock(&cpufreq_governor_mutex);
- return 0;
+ return err;
}
EXPORT_SYMBOL_GPL(cpufreq_register_governor);
@@ -1338,6 +1358,9 @@ int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu)
EXPORT_SYMBOL(cpufreq_get_policy);
+/*
+ * Locking: Must be called with the lock_cpu_hotplug() lock held
+ */
static int __cpufreq_set_policy(struct cpufreq_policy *data, struct cpufreq_policy *policy)
{
int ret = 0;
@@ -1348,6 +1371,11 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, struct cpufreq_poli
memcpy(&policy->cpuinfo, &data->cpuinfo, sizeof(struct cpufreq_cpuinfo));
+ if (policy->min > data->min && policy->min > policy->max) {
+ ret = -EINVAL;
+ goto error_out;
+ }
+
/* verify the cpu speed can be set within this limit */
ret = cpufreq_driver->verify(policy);
if (ret)
@@ -1432,6 +1460,8 @@ int cpufreq_set_policy(struct cpufreq_policy *policy)
if (!data)
return -EINVAL;
+ lock_cpu_hotplug();
+
/* lock this CPU */
mutex_lock(&data->lock);
@@ -1442,6 +1472,8 @@ int cpufreq_set_policy(struct cpufreq_policy *policy)
data->user_policy.governor = data->governor;
mutex_unlock(&data->lock);
+
+ unlock_cpu_hotplug();
cpufreq_cpu_put(data);
return ret;
@@ -1465,6 +1497,7 @@ int cpufreq_update_policy(unsigned int cpu)
if (!data)
return -ENODEV;
+ lock_cpu_hotplug();
mutex_lock(&data->lock);
dprintk("updating policy for CPU %u\n", cpu);
@@ -1490,7 +1523,7 @@ int cpufreq_update_policy(unsigned int cpu)
ret = __cpufreq_set_policy(data, &policy);
mutex_unlock(&data->lock);
-
+ unlock_cpu_hotplug();
cpufreq_cpu_put(data);
return ret;
}
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index b3ebc8f0197..c4c578defab 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -525,7 +525,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
break;
case CPUFREQ_GOV_LIMITS:
- lock_cpu_hotplug();
mutex_lock(&dbs_mutex);
if (policy->max < this_dbs_info->cur_policy->cur)
__cpufreq_driver_target(
@@ -536,7 +535,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
this_dbs_info->cur_policy,
policy->min, CPUFREQ_RELATION_L);
mutex_unlock(&dbs_mutex);
- unlock_cpu_hotplug();
break;
}
return 0;
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 87299924e73..52cf1f02182 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -239,6 +239,8 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
total_ticks = (unsigned int) cputime64_sub(cur_jiffies,
this_dbs_info->prev_cpu_wall);
this_dbs_info->prev_cpu_wall = cur_jiffies;
+ if (!total_ticks)
+ return;
/*
* Every sampling_rate, we check, if current idle time is less
* than 20% (default), then we try to increase frequency
@@ -304,7 +306,12 @@ static void do_dbs_timer(void *data)
unsigned int cpu = smp_processor_id();
struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, cpu);
+ if (!dbs_info->enable)
+ return;
+
+ lock_cpu_hotplug();
dbs_check_cpu(dbs_info);
+ unlock_cpu_hotplug();
queue_delayed_work_on(cpu, kondemand_wq, &dbs_info->work,
usecs_to_jiffies(dbs_tuners_ins.sampling_rate));
}
@@ -319,11 +326,11 @@ static inline void dbs_timer_init(unsigned int cpu)
return;
}
-static inline void dbs_timer_exit(unsigned int cpu)
+static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info)
{
- struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, cpu);
-
- cancel_rearming_delayed_workqueue(kondemand_wq, &dbs_info->work);
+ dbs_info->enable = 0;
+ cancel_delayed_work(&dbs_info->work);
+ flush_workqueue(kondemand_wq);
}
static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
@@ -396,8 +403,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
case CPUFREQ_GOV_STOP:
mutex_lock(&dbs_mutex);
- dbs_timer_exit(policy->cpu);
- this_dbs_info->enable = 0;
+ dbs_timer_exit(this_dbs_info);
sysfs_remove_group(&policy->kobj, &dbs_attr_group);
dbs_enable--;
if (dbs_enable == 0)
@@ -408,7 +414,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
break;
case CPUFREQ_GOV_LIMITS:
- lock_cpu_hotplug();
mutex_lock(&dbs_mutex);
if (policy->max < this_dbs_info->cur_policy->cur)
__cpufreq_driver_target(this_dbs_info->cur_policy,
@@ -419,7 +424,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
policy->min,
CPUFREQ_RELATION_L);
mutex_unlock(&dbs_mutex);
- unlock_cpu_hotplug();
break;
}
return 0;
diff --git a/drivers/cpufreq/cpufreq_userspace.c b/drivers/cpufreq/cpufreq_userspace.c
index 44ae5e5b94c..a06c204589c 100644
--- a/drivers/cpufreq/cpufreq_userspace.c
+++ b/drivers/cpufreq/cpufreq_userspace.c
@@ -18,6 +18,7 @@
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/cpufreq.h>
+#include <linux/cpu.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/sysfs.h>
@@ -70,6 +71,7 @@ static int cpufreq_set(unsigned int freq, struct cpufreq_policy *policy)
dprintk("cpufreq_set for cpu %u, freq %u kHz\n", policy->cpu, freq);
+ lock_cpu_hotplug();
mutex_lock(&userspace_mutex);
if (!cpu_is_managed[policy->cpu])
goto err;
@@ -92,6 +94,7 @@ static int cpufreq_set(unsigned int freq, struct cpufreq_policy *policy)
err:
mutex_unlock(&userspace_mutex);
+ unlock_cpu_hotplug();
return ret;
}
diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c
index 17ee684144f..b643d71298a 100644
--- a/drivers/crypto/padlock-aes.c
+++ b/drivers/crypto/padlock-aes.c
@@ -59,6 +59,9 @@
#define AES_EXTENDED_KEY_SIZE 64 /* in uint32_t units */
#define AES_EXTENDED_KEY_SIZE_B (AES_EXTENDED_KEY_SIZE * sizeof(uint32_t))
+/* Whenever making any changes to the following
+ * structure *make sure* you keep E, d_data
+ * and cword aligned on 16 Bytes boundaries!!! */
struct aes_ctx {
struct {
struct cword encrypt;
@@ -66,8 +69,10 @@ struct aes_ctx {
} cword;
u32 *D;
int key_length;
- u32 E[AES_EXTENDED_KEY_SIZE];
- u32 d_data[AES_EXTENDED_KEY_SIZE];
+ u32 E[AES_EXTENDED_KEY_SIZE]
+ __attribute__ ((__aligned__(PADLOCK_ALIGNMENT)));
+ u32 d_data[AES_EXTENDED_KEY_SIZE]
+ __attribute__ ((__aligned__(PADLOCK_ALIGNMENT)));
};
/* ====== Key management routines ====== */
diff --git a/drivers/dma/ioatdma.c b/drivers/dma/ioatdma.c
index 78bf46d917b..dbd4d6c3698 100644
--- a/drivers/dma/ioatdma.c
+++ b/drivers/dma/ioatdma.c
@@ -828,7 +828,7 @@ static int __init ioat_init_module(void)
/* if forced, worst case is that rmmod hangs */
__unsafe(THIS_MODULE);
- return pci_module_init(&ioat_pci_drv);
+ return pci_register_driver(&ioat_pci_drv);
}
module_init(ioat_init_module);
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index 3a7cfe88b16..4bde30bb3be 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -1,6 +1,6 @@
/*
* edac_mc kernel module
- * (C) 2005 Linux Networx (http://lnxi.com)
+ * (C) 2005, 2006 Linux Networx (http://lnxi.com)
* This file may be distributed under the terms of the
* GNU General Public License.
*
@@ -33,13 +33,8 @@
#include <asm/edac.h>
#include "edac_mc.h"
-#define EDAC_MC_VERSION "Ver: 2.0.0 " __DATE__
+#define EDAC_MC_VERSION "Ver: 2.0.1 " __DATE__
-/* For now, disable the EDAC sysfs code. The sysfs interface that EDAC
- * presents to user space needs more thought, and is likely to change
- * substantially.
- */
-#define DISABLE_EDAC_SYSFS
#ifdef CONFIG_EDAC_DEBUG
/* Values of 0 to 4 will generate output */
@@ -64,31 +59,12 @@ static int check_pci_parity = 0; /* default YES check PCI parity */
static int panic_on_pci_parity; /* default no panic on PCI Parity */
static atomic_t pci_parity_count = ATOMIC_INIT(0);
-/* Structure of the whitelist and blacklist arrays */
-struct edac_pci_device_list {
- unsigned int vendor; /* Vendor ID */
- unsigned int device; /* Deviice ID */
-};
-
-#define MAX_LISTED_PCI_DEVICES 32
-
-/* List of PCI devices (vendor-id:device-id) that should be skipped */
-static struct edac_pci_device_list pci_blacklist[MAX_LISTED_PCI_DEVICES];
-static int pci_blacklist_count;
-
-/* List of PCI devices (vendor-id:device-id) that should be scanned */
-static struct edac_pci_device_list pci_whitelist[MAX_LISTED_PCI_DEVICES];
-static int pci_whitelist_count ;
-
-#ifndef DISABLE_EDAC_SYSFS
static struct kobject edac_pci_kobj; /* /sys/devices/system/edac/pci */
static struct completion edac_pci_kobj_complete;
-#endif /* DISABLE_EDAC_SYSFS */
#endif /* CONFIG_PCI */
/* START sysfs data and methods */
-#ifndef DISABLE_EDAC_SYSFS
static const char *mem_types[] = {
[MEM_EMPTY] = "Empty",
@@ -147,18 +123,10 @@ static struct completion edac_memctrl_kobj_complete;
* /sys/devices/system/edac/mc;
* data structures and methods
*/
-#if 0
-static ssize_t memctrl_string_show(void *ptr, char *buffer)
-{
- char *value = (char*) ptr;
- return sprintf(buffer, "%s\n", value);
-}
-#endif
-
static ssize_t memctrl_int_show(void *ptr, char *buffer)
{
int *value = (int*) ptr;
- return sprintf(buffer, "%d\n", *value);
+ return sprintf(buffer, "%u\n", *value);
}
static ssize_t memctrl_int_store(void *ptr, const char *buffer, size_t count)
@@ -224,11 +192,6 @@ struct memctrl_dev_attribute attr_##_name = { \
.store = _store, \
};
-/* cwrow<id> attribute f*/
-#if 0
-MEMCTRL_STRING_ATTR(mc_version,EDAC_MC_VERSION,S_IRUGO,memctrl_string_show,NULL);
-#endif
-
/* csrow<id> control files */
MEMCTRL_ATTR(panic_on_ue,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store);
MEMCTRL_ATTR(log_ue,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store);
@@ -257,8 +220,6 @@ static struct kobj_type ktype_memctrl = {
.default_attrs = (struct attribute **) memctrl_attr,
};
-#endif /* DISABLE_EDAC_SYSFS */
-
/* Initialize the main sysfs entries for edac:
* /sys/devices/system/edac
*
@@ -268,11 +229,6 @@ static struct kobj_type ktype_memctrl = {
* !0 FAILURE
*/
static int edac_sysfs_memctrl_setup(void)
-#ifdef DISABLE_EDAC_SYSFS
-{
- return 0;
-}
-#else
{
int err=0;
@@ -304,7 +260,6 @@ static int edac_sysfs_memctrl_setup(void)
return err;
}
-#endif /* DISABLE_EDAC_SYSFS */
/*
* MC teardown:
@@ -312,7 +267,6 @@ static int edac_sysfs_memctrl_setup(void)
*/
static void edac_sysfs_memctrl_teardown(void)
{
-#ifndef DISABLE_EDAC_SYSFS
debugf0("MC: " __FILE__ ": %s()\n", __func__);
/* Unregister the MC's kobject and wait for reference count to reach
@@ -324,144 +278,9 @@ static void edac_sysfs_memctrl_teardown(void)
/* Unregister the 'edac' object */
sysdev_class_unregister(&edac_class);
-#endif /* DISABLE_EDAC_SYSFS */
}
#ifdef CONFIG_PCI
-
-#ifndef DISABLE_EDAC_SYSFS
-
-/*
- * /sys/devices/system/edac/pci;
- * data structures and methods
- */
-
-struct list_control {
- struct edac_pci_device_list *list;
- int *count;
-};
-
-#if 0
-/* Output the list as: vendor_id:device:id<,vendor_id:device_id> */
-static ssize_t edac_pci_list_string_show(void *ptr, char *buffer)
-{
- struct list_control *listctl;
- struct edac_pci_device_list *list;
- char *p = buffer;
- int len=0;
- int i;
-
- listctl = ptr;
- list = listctl->list;
-
- for (i = 0; i < *(listctl->count); i++, list++ ) {
- if (len > 0)
- len += snprintf(p + len, (PAGE_SIZE-len), ",");
-
- len += snprintf(p + len,
- (PAGE_SIZE-len),
- "%x:%x",
- list->vendor,list->device);
- }
-
- len += snprintf(p + len,(PAGE_SIZE-len), "\n");
- return (ssize_t) len;
-}
-
-/**
- *
- * Scan string from **s to **e looking for one 'vendor:device' tuple
- * where each field is a hex value
- *
- * return 0 if an entry is NOT found
- * return 1 if an entry is found
- * fill in *vendor_id and *device_id with values found
- *
- * In both cases, make sure *s has been moved forward toward *e
- */
-static int parse_one_device(const char **s,const char **e,
- unsigned int *vendor_id, unsigned int *device_id)
-{
- const char *runner, *p;
-
- /* if null byte, we are done */
- if (!**s) {
- (*s)++; /* keep *s moving */
- return 0;
- }
-
- /* skip over newlines & whitespace */
- if ((**s == '\n') || isspace(**s)) {
- (*s)++;
- return 0;
- }
-
- if (!isxdigit(**s)) {
- (*s)++;
- return 0;
- }
-
- /* parse vendor_id */
- runner = *s;
-
- while (runner < *e) {
- /* scan for vendor:device delimiter */
- if (*runner == ':') {
- *vendor_id = simple_strtol((char*) *s, (char**) &p, 16);
- runner = p + 1;
- break;
- }
-
- runner++;
- }
-
- if (!isxdigit(*runner)) {
- *s = ++runner;
- return 0;
- }
-
- /* parse device_id */
- if (runner < *e) {
- *device_id = simple_strtol((char*)runner, (char**)&p, 16);
- runner = p;
- }
-
- *s = runner;
- return 1;
-}
-
-static ssize_t edac_pci_list_string_store(void *ptr, const char *buffer,
- size_t count)
-{
- struct list_control *listctl;
- struct edac_pci_device_list *list;
- unsigned int vendor_id, device_id;
- const char *s, *e;
- int *index;
-
- s = (char*)buffer;
- e = s + count;
- listctl = ptr;
- list = listctl->list;
- index = listctl->count;
- *index = 0;
-
- while (*index < MAX_LISTED_PCI_DEVICES) {
- if (parse_one_device(&s,&e,&vendor_id,&device_id)) {
- list[ *index ].vendor = vendor_id;
- list[ *index ].device = device_id;
- (*index)++;
- }
-
- /* check for all data consume */
- if (s >= e)
- break;
- }
-
- return count;
-}
-
-#endif
static ssize_t edac_pci_int_show(void *ptr, char *buffer)
{
int *value = ptr;
@@ -529,31 +348,6 @@ struct edac_pci_dev_attribute edac_pci_attr_##_name = { \
.store = _store, \
};
-#if 0
-static struct list_control pci_whitelist_control = {
- .list = pci_whitelist,
- .count = &pci_whitelist_count
-};
-
-static struct list_control pci_blacklist_control = {
- .list = pci_blacklist,
- .count = &pci_blacklist_count
-};
-
-/* whitelist attribute */
-EDAC_PCI_STRING_ATTR(pci_parity_whitelist,
- &pci_whitelist_control,
- S_IRUGO|S_IWUSR,
- edac_pci_list_string_show,
- edac_pci_list_string_store);
-
-EDAC_PCI_STRING_ATTR(pci_parity_blacklist,
- &pci_blacklist_control,
- S_IRUGO|S_IWUSR,
- edac_pci_list_string_show,
- edac_pci_list_string_store);
-#endif
-
/* PCI Parity control files */
EDAC_PCI_ATTR(check_pci_parity, S_IRUGO|S_IWUSR, edac_pci_int_show,
edac_pci_int_store);
@@ -582,18 +376,11 @@ static struct kobj_type ktype_edac_pci = {
.default_attrs = (struct attribute **) edac_pci_attr,
};
-#endif /* DISABLE_EDAC_SYSFS */
-
/**
* edac_sysfs_pci_setup()
*
*/
static int edac_sysfs_pci_setup(void)
-#ifdef DISABLE_EDAC_SYSFS
-{
- return 0;
-}
-#else
{
int err;
@@ -617,16 +404,13 @@ static int edac_sysfs_pci_setup(void)
return err;
}
-#endif /* DISABLE_EDAC_SYSFS */
static void edac_sysfs_pci_teardown(void)
{
-#ifndef DISABLE_EDAC_SYSFS
debugf0("%s()\n", __func__);
init_completion(&edac_pci_kobj_complete);
kobject_unregister(&edac_pci_kobj);
wait_for_completion(&edac_pci_kobj_complete);
-#endif
}
@@ -756,36 +540,6 @@ static void edac_pci_dev_parity_test(struct pci_dev *dev)
}
/*
- * check_dev_on_list: Scan for a PCI device on a white/black list
- * @list: an EDAC &edac_pci_device_list white/black list pointer
- * @free_index: index of next free entry on the list
- * @pci_dev: PCI Device pointer
- *
- * see if list contains the device.
- *
- * Returns: 0 not found
- * 1 found on list
- */
-static int check_dev_on_list(struct edac_pci_device_list *list,
- int free_index, struct pci_dev *dev)
-{
- int i;
- int rc = 0; /* Assume not found */
- unsigned short vendor=dev->vendor;
- unsigned short device=dev->device;
-
- /* Scan the list, looking for a vendor/device match */
- for (i = 0; i < free_index; i++, list++ ) {
- if ((list->vendor == vendor ) && (list->device == device )) {
- rc = 1;
- break;
- }
- }
-
- return rc;
-}
-
-/*
* pci_dev parity list iterator
* Scan the PCI device list for one iteration, looking for SERRORs
* Master Parity ERRORS or Parity ERRORs on primary or secondary devices
@@ -799,22 +553,7 @@ static inline void edac_pci_dev_parity_iterator(pci_parity_check_fn_t fn)
* bumped until we are done with it
*/
while((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
- /* if whitelist exists then it has priority, so only scan
- * those devices on the whitelist
- */
- if (pci_whitelist_count > 0 ) {
- if (check_dev_on_list(pci_whitelist,
- pci_whitelist_count, dev))
- fn(dev);
- } else {
- /*
- * if no whitelist, then check if this devices is
- * blacklisted
- */
- if (!check_dev_on_list(pci_blacklist,
- pci_blacklist_count, dev))
- fn(dev);
- }
+ fn(dev);
}
}
@@ -855,154 +594,101 @@ static inline void clear_pci_parity_errors(void)
#else /* CONFIG_PCI */
-static inline void do_pci_parity_check(void)
-{
- /* no-op */
-}
-
-static inline void clear_pci_parity_errors(void)
-{
- /* no-op */
-}
-
-static void edac_sysfs_pci_teardown(void)
-{
-}
+/* pre-process these away */
+#define do_pci_parity_check()
+#define clear_pci_parity_errors()
+#define edac_sysfs_pci_teardown()
+#define edac_sysfs_pci_setup() (0)
-static int edac_sysfs_pci_setup(void)
-{
- return 0;
-}
#endif /* CONFIG_PCI */
-#ifndef DISABLE_EDAC_SYSFS
-
-/* EDAC sysfs CSROW data structures and methods */
-
-/* Set of more detailed csrow<id> attribute show/store functions */
-static ssize_t csrow_ch0_dimm_label_show(struct csrow_info *csrow, char *data)
-{
- ssize_t size = 0;
-
- if (csrow->nr_channels > 0) {
- size = snprintf(data, EDAC_MC_LABEL_LEN,"%s\n",
- csrow->channels[0].label);
- }
-
- return size;
-}
+/* EDAC sysfs CSROW data structures and methods
+ */
-static ssize_t csrow_ch1_dimm_label_show(struct csrow_info *csrow, char *data)
+/* Set of more default csrow<id> attribute show/store functions */
+static ssize_t csrow_ue_count_show(struct csrow_info *csrow, char *data, int private)
{
- ssize_t size = 0;
-
- if (csrow->nr_channels > 0) {
- size = snprintf(data, EDAC_MC_LABEL_LEN, "%s\n",
- csrow->channels[1].label);
- }
-
- return size;
+ return sprintf(data,"%u\n", csrow->ue_count);
}
-static ssize_t csrow_ch0_dimm_label_store(struct csrow_info *csrow,
- const char *data, size_t size)
+static ssize_t csrow_ce_count_show(struct csrow_info *csrow, char *data, int private)
{
- ssize_t max_size = 0;
-
- if (csrow->nr_channels > 0) {
- max_size = min((ssize_t)size,(ssize_t)EDAC_MC_LABEL_LEN-1);
- strncpy(csrow->channels[0].label, data, max_size);
- csrow->channels[0].label[max_size] = '\0';
- }
-
- return size;
+ return sprintf(data,"%u\n", csrow->ce_count);
}
-static ssize_t csrow_ch1_dimm_label_store(struct csrow_info *csrow,
- const char *data, size_t size)
+static ssize_t csrow_size_show(struct csrow_info *csrow, char *data, int private)
{
- ssize_t max_size = 0;
-
- if (csrow->nr_channels > 1) {
- max_size = min((ssize_t)size,(ssize_t)EDAC_MC_LABEL_LEN-1);
- strncpy(csrow->channels[1].label, data, max_size);
- csrow->channels[1].label[max_size] = '\0';
- }
-
- return max_size;
+ return sprintf(data,"%u\n", PAGES_TO_MiB(csrow->nr_pages));
}
-static ssize_t csrow_ue_count_show(struct csrow_info *csrow, char *data)
+static ssize_t csrow_mem_type_show(struct csrow_info *csrow, char *data, int private)
{
- return sprintf(data,"%u\n", csrow->ue_count);
+ return sprintf(data,"%s\n", mem_types[csrow->mtype]);
}
-static ssize_t csrow_ce_count_show(struct csrow_info *csrow, char *data)
+static ssize_t csrow_dev_type_show(struct csrow_info *csrow, char *data, int private)
{
- return sprintf(data,"%u\n", csrow->ce_count);
+ return sprintf(data,"%s\n", dev_types[csrow->dtype]);
}
-static ssize_t csrow_ch0_ce_count_show(struct csrow_info *csrow, char *data)
+static ssize_t csrow_edac_mode_show(struct csrow_info *csrow, char *data, int private)
{
- ssize_t size = 0;
-
- if (csrow->nr_channels > 0) {
- size = sprintf(data,"%u\n", csrow->channels[0].ce_count);
- }
-
- return size;
+ return sprintf(data,"%s\n", edac_caps[csrow->edac_mode]);
}
-static ssize_t csrow_ch1_ce_count_show(struct csrow_info *csrow, char *data)
+/* show/store functions for DIMM Label attributes */
+static ssize_t channel_dimm_label_show(struct csrow_info *csrow,
+ char *data, int channel)
{
- ssize_t size = 0;
-
- if (csrow->nr_channels > 1) {
- size = sprintf(data,"%u\n", csrow->channels[1].ce_count);
- }
-
- return size;
+ return snprintf(data, EDAC_MC_LABEL_LEN,"%s",
+ csrow->channels[channel].label);
}
-static ssize_t csrow_size_show(struct csrow_info *csrow, char *data)
+static ssize_t channel_dimm_label_store(struct csrow_info *csrow,
+ const char *data,
+ size_t count,
+ int channel)
{
- return sprintf(data,"%u\n", PAGES_TO_MiB(csrow->nr_pages));
-}
+ ssize_t max_size = 0;
-static ssize_t csrow_mem_type_show(struct csrow_info *csrow, char *data)
-{
- return sprintf(data,"%s\n", mem_types[csrow->mtype]);
-}
+ max_size = min((ssize_t)count,(ssize_t)EDAC_MC_LABEL_LEN-1);
+ strncpy(csrow->channels[channel].label, data, max_size);
+ csrow->channels[channel].label[max_size] = '\0';
-static ssize_t csrow_dev_type_show(struct csrow_info *csrow, char *data)
-{
- return sprintf(data,"%s\n", dev_types[csrow->dtype]);
+ return max_size;
}
-static ssize_t csrow_edac_mode_show(struct csrow_info *csrow, char *data)
+/* show function for dynamic chX_ce_count attribute */
+static ssize_t channel_ce_count_show(struct csrow_info *csrow,
+ char *data,
+ int channel)
{
- return sprintf(data,"%s\n", edac_caps[csrow->edac_mode]);
+ return sprintf(data, "%u\n", csrow->channels[channel].ce_count);
}
+/* csrow specific attribute structure */
struct csrowdev_attribute {
struct attribute attr;
- ssize_t (*show)(struct csrow_info *,char *);
- ssize_t (*store)(struct csrow_info *, const char *,size_t);
+ ssize_t (*show)(struct csrow_info *,char *,int);
+ ssize_t (*store)(struct csrow_info *, const char *,size_t,int);
+ int private;
};
#define to_csrow(k) container_of(k, struct csrow_info, kobj)
#define to_csrowdev_attr(a) container_of(a, struct csrowdev_attribute, attr)
-/* Set of show/store higher level functions for csrow objects */
-static ssize_t csrowdev_show(struct kobject *kobj, struct attribute *attr,
- char *buffer)
+/* Set of show/store higher level functions for default csrow attributes */
+static ssize_t csrowdev_show(struct kobject *kobj,
+ struct attribute *attr,
+ char *buffer)
{
struct csrow_info *csrow = to_csrow(kobj);
struct csrowdev_attribute *csrowdev_attr = to_csrowdev_attr(attr);
if (csrowdev_attr->show)
- return csrowdev_attr->show(csrow, buffer);
-
+ return csrowdev_attr->show(csrow,
+ buffer,
+ csrowdev_attr->private);
return -EIO;
}
@@ -1013,8 +699,10 @@ static ssize_t csrowdev_store(struct kobject *kobj, struct attribute *attr,
struct csrowdev_attribute * csrowdev_attr = to_csrowdev_attr(attr);
if (csrowdev_attr->store)
- return csrowdev_attr->store(csrow, buffer, count);
-
+ return csrowdev_attr->store(csrow,
+ buffer,
+ count,
+ csrowdev_attr->private);
return -EIO;
}
@@ -1023,69 +711,157 @@ static struct sysfs_ops csrowfs_ops = {
.store = csrowdev_store
};
-#define CSROWDEV_ATTR(_name,_mode,_show,_store) \
+#define CSROWDEV_ATTR(_name,_mode,_show,_store,_private) \
struct csrowdev_attribute attr_##_name = { \
.attr = {.name = __stringify(_name), .mode = _mode }, \
.show = _show, \
.store = _store, \
+ .private = _private, \
};
-/* cwrow<id>/attribute files */
-CSROWDEV_ATTR(size_mb,S_IRUGO,csrow_size_show,NULL);
-CSROWDEV_ATTR(dev_type,S_IRUGO,csrow_dev_type_show,NULL);
-CSROWDEV_ATTR(mem_type,S_IRUGO,csrow_mem_type_show,NULL);
-CSROWDEV_ATTR(edac_mode,S_IRUGO,csrow_edac_mode_show,NULL);
-CSROWDEV_ATTR(ue_count,S_IRUGO,csrow_ue_count_show,NULL);
-CSROWDEV_ATTR(ce_count,S_IRUGO,csrow_ce_count_show,NULL);
-CSROWDEV_ATTR(ch0_ce_count,S_IRUGO,csrow_ch0_ce_count_show,NULL);
-CSROWDEV_ATTR(ch1_ce_count,S_IRUGO,csrow_ch1_ce_count_show,NULL);
-
-/* control/attribute files */
-CSROWDEV_ATTR(ch0_dimm_label,S_IRUGO|S_IWUSR,
- csrow_ch0_dimm_label_show,
- csrow_ch0_dimm_label_store);
-CSROWDEV_ATTR(ch1_dimm_label,S_IRUGO|S_IWUSR,
- csrow_ch1_dimm_label_show,
- csrow_ch1_dimm_label_store);
+/* default cwrow<id>/attribute files */
+CSROWDEV_ATTR(size_mb,S_IRUGO,csrow_size_show,NULL,0);
+CSROWDEV_ATTR(dev_type,S_IRUGO,csrow_dev_type_show,NULL,0);
+CSROWDEV_ATTR(mem_type,S_IRUGO,csrow_mem_type_show,NULL,0);
+CSROWDEV_ATTR(edac_mode,S_IRUGO,csrow_edac_mode_show,NULL,0);
+CSROWDEV_ATTR(ue_count,S_IRUGO,csrow_ue_count_show,NULL,0);
+CSROWDEV_ATTR(ce_count,S_IRUGO,csrow_ce_count_show,NULL,0);
-/* Attributes of the CSROW<id> object */
-static struct csrowdev_attribute *csrow_attr[] = {
+/* default attributes of the CSROW<id> object */
+static struct csrowdev_attribute *default_csrow_attr[] = {
&attr_dev_type,
&attr_mem_type,
&attr_edac_mode,
&attr_size_mb,
&attr_ue_count,
&attr_ce_count,
- &attr_ch0_ce_count,
- &attr_ch1_ce_count,
- &attr_ch0_dimm_label,
- &attr_ch1_dimm_label,
NULL,
};
-/* No memory to release */
+
+/* possible dynamic channel DIMM Label attribute files */
+CSROWDEV_ATTR(ch0_dimm_label,S_IRUGO|S_IWUSR,
+ channel_dimm_label_show,
+ channel_dimm_label_store,
+ 0 );
+CSROWDEV_ATTR(ch1_dimm_label,S_IRUGO|S_IWUSR,
+ channel_dimm_label_show,
+ channel_dimm_label_store,
+ 1 );
+CSROWDEV_ATTR(ch2_dimm_label,S_IRUGO|S_IWUSR,
+ channel_dimm_label_show,
+ channel_dimm_label_store,
+ 2 );
+CSROWDEV_ATTR(ch3_dimm_label,S_IRUGO|S_IWUSR,
+ channel_dimm_label_show,
+ channel_dimm_label_store,
+ 3 );
+CSROWDEV_ATTR(ch4_dimm_label,S_IRUGO|S_IWUSR,
+ channel_dimm_label_show,
+ channel_dimm_label_store,
+ 4 );
+CSROWDEV_ATTR(ch5_dimm_label,S_IRUGO|S_IWUSR,
+ channel_dimm_label_show,
+ channel_dimm_label_store,
+ 5 );
+
+/* Total possible dynamic DIMM Label attribute file table */
+static struct csrowdev_attribute *dynamic_csrow_dimm_attr[] = {
+ &attr_ch0_dimm_label,
+ &attr_ch1_dimm_label,
+ &attr_ch2_dimm_label,
+ &attr_ch3_dimm_label,
+ &attr_ch4_dimm_label,
+ &attr_ch5_dimm_label
+};
+
+/* possible dynamic channel ce_count attribute files */
+CSROWDEV_ATTR(ch0_ce_count,S_IRUGO|S_IWUSR,
+ channel_ce_count_show,
+ NULL,
+ 0 );
+CSROWDEV_ATTR(ch1_ce_count,S_IRUGO|S_IWUSR,
+ channel_ce_count_show,
+ NULL,
+ 1 );
+CSROWDEV_ATTR(ch2_ce_count,S_IRUGO|S_IWUSR,
+ channel_ce_count_show,
+ NULL,
+ 2 );
+CSROWDEV_ATTR(ch3_ce_count,S_IRUGO|S_IWUSR,
+ channel_ce_count_show,
+ NULL,
+ 3 );
+CSROWDEV_ATTR(ch4_ce_count,S_IRUGO|S_IWUSR,
+ channel_ce_count_show,
+ NULL,
+ 4 );
+CSROWDEV_ATTR(ch5_ce_count,S_IRUGO|S_IWUSR,
+ channel_ce_count_show,
+ NULL,
+ 5 );
+
+/* Total possible dynamic ce_count attribute file table */
+static struct csrowdev_attribute *dynamic_csrow_ce_count_attr[] = {
+ &attr_ch0_ce_count,
+ &attr_ch1_ce_count,
+ &attr_ch2_ce_count,
+ &attr_ch3_ce_count,
+ &attr_ch4_ce_count,
+ &attr_ch5_ce_count
+};
+
+
+#define EDAC_NR_CHANNELS 6
+
+/* Create dynamic CHANNEL files, indexed by 'chan', under specifed CSROW */
+static int edac_create_channel_files(struct kobject *kobj, int chan)
+{
+ int err=-ENODEV;
+
+ if (chan >= EDAC_NR_CHANNELS)
+ return err;
+
+ /* create the DIMM label attribute file */
+ err = sysfs_create_file(kobj,
+ (struct attribute *) dynamic_csrow_dimm_attr[chan]);
+
+ if (!err) {
+ /* create the CE Count attribute file */
+ err = sysfs_create_file(kobj,
+ (struct attribute *) dynamic_csrow_ce_count_attr[chan]);
+ } else {
+ debugf1("%s() dimm labels and ce_count files created", __func__);
+ }
+
+ return err;
+}
+
+/* No memory to release for this kobj */
static void edac_csrow_instance_release(struct kobject *kobj)
{
struct csrow_info *cs;
- debugf1("%s()\n", __func__);
cs = container_of(kobj, struct csrow_info, kobj);
complete(&cs->kobj_complete);
}
+/* the kobj_type instance for a CSROW */
static struct kobj_type ktype_csrow = {
.release = edac_csrow_instance_release,
.sysfs_ops = &csrowfs_ops,
- .default_attrs = (struct attribute **) csrow_attr,
+ .default_attrs = (struct attribute **) default_csrow_attr,
};
/* Create a CSROW object under specifed edac_mc_device */
-static int edac_create_csrow_object(struct kobject *edac_mci_kobj,
- struct csrow_info *csrow, int index)
+static int edac_create_csrow_object(
+ struct kobject *edac_mci_kobj,
+ struct csrow_info *csrow,
+ int index)
{
int err = 0;
+ int chan;
- debugf0("%s()\n", __func__);
memset(&csrow->kobj, 0, sizeof(csrow->kobj));
/* generate ..../edac/mc/mc<id>/csrow<index> */
@@ -1095,21 +871,27 @@ static int edac_create_csrow_object(struct kobject *edac_mci_kobj,
/* name this instance of csrow<id> */
err = kobject_set_name(&csrow->kobj,"csrow%d",index);
+ if (err)
+ goto error_exit;
+ /* Instanstiate the csrow object */
+ err = kobject_register(&csrow->kobj);
if (!err) {
- /* Instanstiate the csrow object */
- err = kobject_register(&csrow->kobj);
-
- if (err)
- debugf0("Failed to register CSROW%d\n",index);
- else
- debugf0("Registered CSROW%d\n",index);
+ /* Create the dyanmic attribute files on this csrow,
+ * namely, the DIMM labels and the channel ce_count
+ */
+ for (chan = 0; chan < csrow->nr_channels; chan++) {
+ err = edac_create_channel_files(&csrow->kobj,chan);
+ if (err)
+ break;
+ }
}
+error_exit:
return err;
}
-/* sysfs data structures and methods for the MCI kobjects */
+/* default sysfs methods and data structures for the main MCI kobject */
static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci,
const char *data, size_t count)
@@ -1135,6 +917,7 @@ static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci,
return count;
}
+/* default attribute files for the MCI object */
static ssize_t mci_ue_count_show(struct mem_ctl_info *mci, char *data)
{
return sprintf(data,"%d\n", mci->ue_count);
@@ -1160,71 +943,11 @@ static ssize_t mci_seconds_show(struct mem_ctl_info *mci, char *data)
return sprintf(data,"%ld\n", (jiffies - mci->start_time) / HZ);
}
-static ssize_t mci_mod_name_show(struct mem_ctl_info *mci, char *data)
-{
- return sprintf(data,"%s %s\n", mci->mod_name, mci->mod_ver);
-}
-
static ssize_t mci_ctl_name_show(struct mem_ctl_info *mci, char *data)
{
return sprintf(data,"%s\n", mci->ctl_name);
}
-static int mci_output_edac_cap(char *buf, unsigned long edac_cap)
-{
- char *p = buf;
- int bit_idx;
-
- for (bit_idx = 0; bit_idx < 8 * sizeof(edac_cap); bit_idx++) {
- if ((edac_cap >> bit_idx) & 0x1)
- p += sprintf(p, "%s ", edac_caps[bit_idx]);
- }
-
- return p - buf;
-}
-
-static ssize_t mci_edac_capability_show(struct mem_ctl_info *mci, char *data)
-{
- char *p = data;
-
- p += mci_output_edac_cap(p,mci->edac_ctl_cap);
- p += sprintf(p, "\n");
- return p - data;
-}
-
-static ssize_t mci_edac_current_capability_show(struct mem_ctl_info *mci,
- char *data)
-{
- char *p = data;
-
- p += mci_output_edac_cap(p,mci->edac_cap);
- p += sprintf(p, "\n");
- return p - data;
-}
-
-static int mci_output_mtype_cap(char *buf, unsigned long mtype_cap)
-{
- char *p = buf;
- int bit_idx;
-
- for (bit_idx = 0; bit_idx < 8 * sizeof(mtype_cap); bit_idx++) {
- if ((mtype_cap >> bit_idx) & 0x1)
- p += sprintf(p, "%s ", mem_types[bit_idx]);
- }
-
- return p - buf;
-}
-
-static ssize_t mci_supported_mem_type_show(struct mem_ctl_info *mci,
- char *data)
-{
- char *p = data;
-
- p += mci_output_mtype_cap(p,mci->mtype_cap);
- p += sprintf(p, "\n");
- return p - data;
-}
-
static ssize_t mci_size_mb_show(struct mem_ctl_info *mci, char *data)
{
int total_pages, csrow_idx;
@@ -1251,6 +974,7 @@ struct mcidev_attribute {
#define to_mci(k) container_of(k, struct mem_ctl_info, edac_mci_kobj)
#define to_mcidev_attr(a) container_of(a, struct mcidev_attribute, attr)
+/* MCI show/store functions for top most object */
static ssize_t mcidev_show(struct kobject *kobj, struct attribute *attr,
char *buffer)
{
@@ -1287,31 +1011,21 @@ struct mcidev_attribute mci_attr_##_name = { \
.store = _store, \
};
-/* Control file */
+/* default Control file */
MCIDEV_ATTR(reset_counters,S_IWUSR,NULL,mci_reset_counters_store);
-/* Attribute files */
+/* default Attribute files */
MCIDEV_ATTR(mc_name,S_IRUGO,mci_ctl_name_show,NULL);
-MCIDEV_ATTR(module_name,S_IRUGO,mci_mod_name_show,NULL);
-MCIDEV_ATTR(edac_capability,S_IRUGO,mci_edac_capability_show,NULL);
MCIDEV_ATTR(size_mb,S_IRUGO,mci_size_mb_show,NULL);
MCIDEV_ATTR(seconds_since_reset,S_IRUGO,mci_seconds_show,NULL);
MCIDEV_ATTR(ue_noinfo_count,S_IRUGO,mci_ue_noinfo_show,NULL);
MCIDEV_ATTR(ce_noinfo_count,S_IRUGO,mci_ce_noinfo_show,NULL);
MCIDEV_ATTR(ue_count,S_IRUGO,mci_ue_count_show,NULL);
MCIDEV_ATTR(ce_count,S_IRUGO,mci_ce_count_show,NULL);
-MCIDEV_ATTR(edac_current_capability,S_IRUGO,
- mci_edac_current_capability_show,NULL);
-MCIDEV_ATTR(supported_mem_type,S_IRUGO,
- mci_supported_mem_type_show,NULL);
static struct mcidev_attribute *mci_attr[] = {
&mci_attr_reset_counters,
- &mci_attr_module_name,
&mci_attr_mc_name,
- &mci_attr_edac_capability,
- &mci_attr_edac_current_capability,
- &mci_attr_supported_mem_type,
&mci_attr_size_mb,
&mci_attr_seconds_since_reset,
&mci_attr_ue_noinfo_count,
@@ -1339,7 +1053,6 @@ static struct kobj_type ktype_mci = {
.default_attrs = (struct attribute **) mci_attr,
};
-#endif /* DISABLE_EDAC_SYSFS */
#define EDAC_DEVICE_SYMLINK "device"
@@ -1352,11 +1065,6 @@ static struct kobj_type ktype_mci = {
* !0 Failure
*/
static int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
-#ifdef DISABLE_EDAC_SYSFS
-{
- return 0;
-}
-#else
{
int i;
int err;
@@ -1368,7 +1076,6 @@ static int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
/* set the name of the mc<id> object */
err = kobject_set_name(edac_mci_kobj,"mc%d",mci->mc_idx);
-
if (err)
return err;
@@ -1378,14 +1085,12 @@ static int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
/* register the mc<id> kobject */
err = kobject_register(edac_mci_kobj);
-
if (err)
return err;
/* create a symlink for the device */
err = sysfs_create_link(edac_mci_kobj, &mci->dev->kobj,
EDAC_DEVICE_SYMLINK);
-
if (err)
goto fail0;
@@ -1398,7 +1103,6 @@ static int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
/* Only expose populated CSROWs */
if (csrow->nr_pages > 0) {
err = edac_create_csrow_object(edac_mci_kobj,csrow,i);
-
if (err)
goto fail1;
}
@@ -1422,14 +1126,12 @@ fail0:
wait_for_completion(&mci->kobj_complete);
return err;
}
-#endif /* DISABLE_EDAC_SYSFS */
/*
* remove a Memory Controller instance
*/
static void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
{
-#ifndef DISABLE_EDAC_SYSFS
int i;
debugf0("%s()\n", __func__);
@@ -1447,7 +1149,6 @@ static void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
init_completion(&mci->kobj_complete);
kobject_unregister(&mci->edac_mci_kobj);
wait_for_completion(&mci->kobj_complete);
-#endif /* DISABLE_EDAC_SYSFS */
}
/* END OF sysfs data and methods */
diff --git a/drivers/fc4/fc.c b/drivers/fc4/fc.c
index 66d03f242d3..1a159e8843c 100644
--- a/drivers/fc4/fc.c
+++ b/drivers/fc4/fc.c
@@ -429,7 +429,7 @@ static inline void fcp_scsi_receive(fc_channel *fc, int token, int status, fc_hd
if (fcmd->data) {
if (SCpnt->use_sg)
- dma_unmap_sg(fc->dev, (struct scatterlist *)SCpnt->buffer,
+ dma_unmap_sg(fc->dev, (struct scatterlist *)SCpnt->request_buffer,
SCpnt->use_sg,
SCpnt->sc_data_direction);
else
@@ -810,7 +810,7 @@ static int fcp_scsi_queue_it(fc_channel *fc, Scsi_Cmnd *SCpnt, fcp_cmnd *fcmd, i
SCpnt->request_bufflen,
SCpnt->sc_data_direction);
} else {
- struct scatterlist *sg = (struct scatterlist *)SCpnt->buffer;
+ struct scatterlist *sg = (struct scatterlist *)SCpnt->request_buffer;
int nents;
FCD(("XXX: Use_sg %d %d\n", SCpnt->use_sg, sg->length))
diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c
index 59122cc0a50..cc15c4f2e9e 100644
--- a/drivers/hwmon/abituguru.c
+++ b/drivers/hwmon/abituguru.c
@@ -142,6 +142,14 @@ static const u8 abituguru_pwm_max[5] = { 0, 255, 255, 75, 75 };
static int force;
module_param(force, bool, 0);
MODULE_PARM_DESC(force, "Set to one to force detection.");
+static int bank1_types[ABIT_UGURU_MAX_BANK1_SENSORS] = { -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
+module_param_array(bank1_types, int, NULL, 0);
+MODULE_PARM_DESC(bank1_types, "Bank1 sensortype autodetection override:\n"
+ " -1 autodetect\n"
+ " 0 volt sensor\n"
+ " 1 temp sensor\n"
+ " 2 not connected");
static int fan_sensors;
module_param(fan_sensors, int, 0);
MODULE_PARM_DESC(fan_sensors, "Number of fan sensors on the uGuru "
@@ -397,6 +405,15 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data,
u8 val, buf[3];
int ret = ABIT_UGURU_NC;
+ /* If overriden by the user return the user selected type */
+ if (bank1_types[sensor_addr] >= ABIT_UGURU_IN_SENSOR &&
+ bank1_types[sensor_addr] <= ABIT_UGURU_NC) {
+ ABIT_UGURU_DEBUG(2, "assuming sensor type %d for bank1 sensor "
+ "%d because of \"bank1_types\" module param\n",
+ bank1_types[sensor_addr], (int)sensor_addr);
+ return bank1_types[sensor_addr];
+ }
+
/* First read the sensor and the current settings */
if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1, sensor_addr, &val,
1, ABIT_UGURU_MAX_RETRIES) != 1)
@@ -514,7 +531,7 @@ abituguru_detect_no_bank2_sensors(struct abituguru_data *data)
{
int i;
- if (fan_sensors) {
+ if (fan_sensors > 0 && fan_sensors <= ABIT_UGURU_MAX_BANK2_SENSORS) {
data->bank2_sensors = fan_sensors;
ABIT_UGURU_DEBUG(2, "assuming %d fan sensors because of "
"\"fan_sensors\" module param\n",
@@ -568,7 +585,7 @@ abituguru_detect_no_pwms(struct abituguru_data *data)
{
int i, j;
- if (pwms) {
+ if (pwms > 0 && pwms <= ABIT_UGURU_MAX_PWMS) {
data->pwms = pwms;
ABIT_UGURU_DEBUG(2, "assuming %d PWM outputs because of "
"\"pwms\" module param\n", (int)data->pwms);
diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c
index df05df1a0ef..ab230c033f9 100644
--- a/drivers/i2c/algos/i2c-algo-bit.c
+++ b/drivers/i2c/algos/i2c-algo-bit.c
@@ -372,7 +372,6 @@ static inline int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
while (count > 0) {
inval = i2c_inb(i2c_adap);
-/*printk("%#02x ",inval); if ( ! (count % 16) ) printk("\n"); */
if (inval>=0) {
*temp = inval;
rdcount++;
@@ -544,8 +543,7 @@ int i2c_bit_add_bus(struct i2c_adapter *adap)
adap->timeout = 100; /* default values, should */
adap->retries = 3; /* be replaced by defines */
- i2c_add_adapter(adap);
- return 0;
+ return i2c_add_adapter(adap);
}
diff --git a/drivers/i2c/algos/i2c-algo-ite.c b/drivers/i2c/algos/i2c-algo-ite.c
index 2db7bfc8522..70d8eefb5ef 100644
--- a/drivers/i2c/algos/i2c-algo-ite.c
+++ b/drivers/i2c/algos/i2c-algo-ite.c
@@ -742,10 +742,8 @@ int i2c_iic_add_bus(struct i2c_adapter *adap)
adap->retries = 3; /* be replaced by defines */
adap->flags = 0;
- i2c_add_adapter(adap);
iic_init(iic_adap);
-
- return 0;
+ return i2c_add_adapter(adap);
}
diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c
index 82946acab4c..b88a6fcf7bd 100644
--- a/drivers/i2c/algos/i2c-algo-pca.c
+++ b/drivers/i2c/algos/i2c-algo-pca.c
@@ -374,10 +374,10 @@ int i2c_pca_add_bus(struct i2c_adapter *adap)
adap->timeout = 100; /* default values, should */
adap->retries = 3; /* be replaced by defines */
- rval = pca_init(pca_adap);
+ if ((rval = pca_init(pca_adap)))
+ return rval;
- if (!rval)
- i2c_add_adapter(adap);
+ rval = i2c_add_adapter(adap);
return rval;
}
diff --git a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c
index 6e498df1f71..5b24930adb5 100644
--- a/drivers/i2c/algos/i2c-algo-pcf.c
+++ b/drivers/i2c/algos/i2c-algo-pcf.c
@@ -479,9 +479,11 @@ int i2c_pcf_add_bus(struct i2c_adapter *adap)
adap->timeout = 100; /* default values, should */
adap->retries = 3; /* be replaced by defines */
- rval = pcf_init_8584(pcf_adap);
- if (!rval)
- i2c_add_adapter(adap);
+ if ((rval = pcf_init_8584(pcf_adap)))
+ return rval;
+
+ rval = i2c_add_adapter(adap);
+
return rval;
}
diff --git a/drivers/i2c/algos/i2c-algo-sibyte.c b/drivers/i2c/algos/i2c-algo-sibyte.c
index 3df3f09995c..32d41c6fac0 100644
--- a/drivers/i2c/algos/i2c-algo-sibyte.c
+++ b/drivers/i2c/algos/i2c-algo-sibyte.c
@@ -173,9 +173,7 @@ int i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed)
printk("\n");
}
- i2c_add_adapter(i2c_adap);
-
- return 0;
+ return i2c_add_adapter(i2c_adap);
}
diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c
index aca7e166860..48c56939c86 100644
--- a/drivers/i2c/busses/i2c-iop3xx.c
+++ b/drivers/i2c/busses/i2c-iop3xx.c
@@ -21,6 +21,9 @@
* - Make it work with IXP46x chips
* - Cleanup function names, coding style, etc
*
+ * - writing to slave address causes latchup on iop331.
+ * fix: driver refuses to address self.
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2.
@@ -73,12 +76,6 @@ iop3xx_i2c_reset(struct i2c_algo_iop3xx_data *iop3xx_adap)
}
static void
-iop3xx_i2c_set_slave_addr(struct i2c_algo_iop3xx_data *iop3xx_adap)
-{
- __raw_writel(MYSAR, iop3xx_adap->ioaddr + SAR_OFFSET);
-}
-
-static void
iop3xx_i2c_enable(struct i2c_algo_iop3xx_data *iop3xx_adap)
{
u32 cr = IOP3XX_ICR_GCD | IOP3XX_ICR_SCLEN | IOP3XX_ICR_UE;
@@ -248,6 +245,13 @@ iop3xx_i2c_send_target_addr(struct i2c_algo_iop3xx_data *iop3xx_adap,
int status;
int rc;
+ /* avoid writing to my slave address (hangs on 80331),
+ * forbidden in Intel developer manual
+ */
+ if (msg->addr == MYSAR) {
+ return -EBUSY;
+ }
+
__raw_writel(iic_cook_addr(msg), iop3xx_adap->ioaddr + DBR_OFFSET);
cr &= ~(IOP3XX_ICR_MSTOP | IOP3XX_ICR_NACK);
@@ -498,7 +502,6 @@ iop3xx_i2c_probe(struct platform_device *pdev)
spin_lock_init(&adapter_data->lock);
iop3xx_i2c_reset(adapter_data);
- iop3xx_i2c_set_slave_addr(adapter_data);
iop3xx_i2c_enable(adapter_data);
platform_set_drvdata(pdev, new_adapter);
diff --git a/drivers/i2c/busses/i2c-iop3xx.h b/drivers/i2c/busses/i2c-iop3xx.h
index e46ebaea7b1..8485861f6a3 100644
--- a/drivers/i2c/busses/i2c-iop3xx.h
+++ b/drivers/i2c/busses/i2c-iop3xx.h
@@ -80,7 +80,7 @@
#define IOP3XX_GPOD_I2C0 0x00c0 /* clear these bits to enable ch0 */
#define IOP3XX_GPOD_I2C1 0x0030 /* clear these bits to enable ch1 */
-#define MYSAR 0x02 /* SWAG a suitable slave address */
+#define MYSAR 0 /* default slave address */
#define I2C_ERR 321
#define I2C_ERR_BERR (I2C_ERR+0)
diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c
index 2a0b3be7cdd..53bb4359386 100644
--- a/drivers/i2c/busses/i2c-powermac.c
+++ b/drivers/i2c/busses/i2c-powermac.c
@@ -148,8 +148,6 @@ static int i2c_powermac_master_xfer( struct i2c_adapter *adap,
int read;
int addrdir;
- if (num != 1)
- return -EINVAL;
if (msgs->flags & I2C_M_TEN)
return -EINVAL;
read = (msgs->flags & I2C_M_RD) != 0;
@@ -166,7 +164,7 @@ static int i2c_powermac_master_xfer( struct i2c_adapter *adap,
rc = pmac_i2c_xfer(bus, addrdir, 0, 0, msgs->buf, msgs->len);
bail:
pmac_i2c_close(bus);
- return rc < 0 ? rc : msgs->len;
+ return rc < 0 ? rc : 1;
}
static u32 i2c_powermac_func(struct i2c_adapter * adapter)
diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c
index 22a3eda0416..ced309ff056 100644
--- a/drivers/i2c/busses/scx200_acb.c
+++ b/drivers/i2c/busses/scx200_acb.c
@@ -184,21 +184,21 @@ static void scx200_acb_machine(struct scx200_acb_iface *iface, u8 status)
break;
case state_read:
- /* Set ACK if receiving the last byte */
- if (iface->len == 1)
+ /* Set ACK if _next_ byte will be the last one */
+ if (iface->len == 2)
outb(inb(ACBCTL1) | ACBCTL1_ACK, ACBCTL1);
else
outb(inb(ACBCTL1) & ~ACBCTL1_ACK, ACBCTL1);
- *iface->ptr++ = inb(ACBSDA);
- --iface->len;
-
- if (iface->len == 0) {
+ if (iface->len == 1) {
iface->result = 0;
iface->state = state_idle;
outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
}
+ *iface->ptr++ = inb(ACBSDA);
+ --iface->len;
+
break;
case state_write:
@@ -307,8 +307,12 @@ static s32 scx200_acb_smbus_xfer(struct i2c_adapter *adapter,
buffer = (u8 *)&cur_word;
break;
- case I2C_SMBUS_BLOCK_DATA:
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ if (rw == I2C_SMBUS_READ)
+ data->block[0] = I2C_SMBUS_BLOCK_MAX; /* For now */
len = data->block[0];
+ if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
+ return -EINVAL;
buffer = &data->block[1];
break;
@@ -372,7 +376,7 @@ static u32 scx200_acb_func(struct i2c_adapter *adapter)
{
return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
- I2C_FUNC_SMBUS_BLOCK_DATA;
+ I2C_FUNC_SMBUS_I2C_BLOCK;
}
/* For now, we only handle combined mode (smbus) */
diff --git a/drivers/i2c/chips/pca9539.c b/drivers/i2c/chips/pca9539.c
index 54b6e6a4bee..cb22280cdd2 100644
--- a/drivers/i2c/chips/pca9539.c
+++ b/drivers/i2c/chips/pca9539.c
@@ -134,11 +134,13 @@ static int pca9539_detect(struct i2c_adapter *adapter, int address, int kind)
new_client->driver = &pca9539_driver;
new_client->flags = 0;
- /* Detection: the pca9539 only has 8 registers (0-7).
- A read of 7 should succeed, but a read of 8 should fail. */
- if ((i2c_smbus_read_byte_data(new_client, 7) < 0) ||
- (i2c_smbus_read_byte_data(new_client, 8) >= 0))
- goto exit_kfree;
+ if (kind < 0) {
+ /* Detection: the pca9539 only has 8 registers (0-7).
+ A read of 7 should succeed, but a read of 8 should fail. */
+ if ((i2c_smbus_read_byte_data(new_client, 7) < 0) ||
+ (i2c_smbus_read_byte_data(new_client, 8) >= 0))
+ goto exit_kfree;
+ }
strlcpy(new_client->name, "pca9539", I2C_NAME_SIZE);
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index a45155f799d..9cb277d6aa4 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -756,9 +756,9 @@ int i2c_probe(struct i2c_adapter *adapter,
"parameter for adapter %d, "
"addr 0x%02x\n", adap_id,
address_data->ignore[j + 1]);
+ ignore = 1;
+ break;
}
- ignore = 1;
- break;
}
if (ignore)
continue;
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index d1266fe2d1a..b6fb167e20f 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -682,6 +682,7 @@ config BLK_DEV_SVWKS
config BLK_DEV_SGIIOC4
tristate "Silicon Graphics IOC4 chipset ATA/ATAPI support"
depends on (IA64_SGI_SN2 || IA64_GENERIC) && SGI_IOC4
+ select IDEPCI_SHARE_IRQ
help
This driver adds PIO & MultiMode DMA-2 support for the SGI IOC4
chipset, which has one channel and can support two devices.
@@ -773,20 +774,6 @@ config BLK_DEV_IDEDMA_PMAC
to transfer data to and from memory. Saying Y is safe and improves
performance.
-config BLK_DEV_IDE_PMAC_BLINK
- bool "Blink laptop LED on drive activity (DEPRECATED)"
- depends on BLK_DEV_IDE_PMAC && ADB_PMU
- select ADB_PMU_LED
- select LEDS_TRIGGERS
- select LEDS_TRIGGER_IDE_DISK
- help
- This option enables the use of the sleep LED as a hard drive
- activity LED.
- This option is deprecated, it only selects ADB_PMU_LED and
- LEDS_TRIGGER_IDE_DISK and changes the code in the new led class
- device to default to the ide-disk trigger (which should be set
- from userspace via sysfs).
-
config BLK_DEV_IDE_SWARM
tristate "IDE for Sibyte evaluation boards"
depends on SIBYTE_SB1xxx_SOC
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index f712e4cfd9d..7cf3eb02352 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -776,7 +776,7 @@ static void update_ordered(ide_drive_t *drive)
* not available so we don't need to recheck that.
*/
capacity = idedisk_capacity(drive);
- barrier = ide_id_has_flush_cache(id) &&
+ barrier = ide_id_has_flush_cache(id) && !drive->noflush &&
(drive->addressing == 0 || capacity <= (1ULL << 28) ||
ide_id_has_flush_cache_ext(id));
diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
index 98918fb6b2c..7c3a13e1cf6 100644
--- a/drivers/ide/ide-dma.c
+++ b/drivers/ide/ide-dma.c
@@ -750,7 +750,7 @@ void ide_dma_verbose(ide_drive_t *drive)
goto bug_dma_off;
printk(", DMA");
} else if (id->field_valid & 1) {
- printk(", BUG");
+ goto bug_dma_off;
}
return;
bug_dma_off:
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index 657165297dc..77703acaec1 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -23,6 +23,7 @@
#include <linux/hdreg.h>
#include <linux/ide.h>
#include <linux/bitops.h>
+#include <linux/nmi.h>
#include <asm/byteorder.h>
#include <asm/irq.h>
@@ -1243,6 +1244,7 @@ int ide_wait_not_busy(ide_hwif_t *hwif, unsigned long timeout)
if (stat == 0xff)
return -ENODEV;
touch_softlockup_watchdog();
+ touch_nmi_watchdog();
}
return -EBUSY;
}
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index 05fbd9298db..defd4b4bd37 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -1539,7 +1539,7 @@ static int __init ide_setup(char *s)
const char *hd_words[] = {
"none", "noprobe", "nowerr", "cdrom", "serialize",
"autotune", "noautotune", "minus8", "swapdata", "bswap",
- "minus11", "remap", "remap63", "scsi", NULL };
+ "noflush", "remap", "remap63", "scsi", NULL };
unit = s[2] - 'a';
hw = unit / MAX_DRIVES;
unit = unit % MAX_DRIVES;
@@ -1578,6 +1578,9 @@ static int __init ide_setup(char *s)
case -10: /* "bswap" */
drive->bswap = 1;
goto done;
+ case -11: /* noflush */
+ drive->noflush = 1;
+ goto done;
case -12: /* "remap" */
drive->remap_0_to_1 = 1;
goto done;
diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c
index b7e459e4f28..602797a4420 100644
--- a/drivers/ide/legacy/ide-cs.c
+++ b/drivers/ide/legacy/ide-cs.c
@@ -146,16 +146,7 @@ static void ide_detach(struct pcmcia_device *link)
kfree(link->priv);
} /* ide_detach */
-static void idecs_mmio_fixup(ide_hwif_t *hwif)
-{
- default_hwif_mmiops(hwif);
- hwif->mmio = 2;
-
- ide_undecoded_slave(hwif);
-}
-
-static int idecs_register(unsigned long io, unsigned long ctl,
- unsigned long irq, struct pcmcia_device *handle, int is_mmio)
+static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq, struct pcmcia_device *handle)
{
hw_regs_t hw;
memset(&hw, 0, sizeof(hw));
@@ -163,19 +154,7 @@ static int idecs_register(unsigned long io, unsigned long ctl,
hw.irq = irq;
hw.chipset = ide_pci;
hw.dev = &handle->dev;
-
- if(is_mmio)
- return ide_register_hw_with_fixup(&hw, NULL, idecs_mmio_fixup);
- else
- return ide_register_hw_with_fixup(&hw, NULL, ide_undecoded_slave);
-}
-
-void outb_io(unsigned char value, unsigned long port) {
- outb(value, port);
-}
-
-void outb_mem(unsigned char value, unsigned long port) {
- writeb(value, (void __iomem *) port);
+ return ide_register_hw_with_fixup(&hw, NULL, ide_undecoded_slave);
}
/*======================================================================
@@ -201,8 +180,7 @@ static int ide_config(struct pcmcia_device *link)
} *stk = NULL;
cistpl_cftable_entry_t *cfg;
int i, pass, last_ret = 0, last_fn = 0, hd, is_kme = 0;
- unsigned long io_base, ctl_base, is_mmio, try_slave;
- void (*my_outb)(unsigned char, unsigned long);
+ unsigned long io_base, ctl_base;
DEBUG(0, "ide_config(0x%p)\n", link);
@@ -232,7 +210,7 @@ static int ide_config(struct pcmcia_device *link)
/* Not sure if this is right... look up the current Vcc */
CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link, &stk->conf));
- pass = io_base = ctl_base = is_mmio = try_slave = 0;
+ pass = io_base = ctl_base = 0;
tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
tuple.Attributes = 0;
CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
@@ -280,45 +258,11 @@ static int ide_config(struct pcmcia_device *link)
goto next_entry;
io_base = link->io.BasePort1;
ctl_base = link->io.BasePort1 + 0x0e;
-
- if (io->win[0].len >= 0x20)
- try_slave = 1;
-
} else goto next_entry;
/* If we've got this far, we're done */
break;
}
- if ((cfg->mem.nwin > 0) || (stk->dflt.mem.nwin > 0)) {
- win_req_t req;
- memreq_t map;
- cistpl_mem_t *mem = (cfg->mem.nwin) ? &cfg->mem : &stk->dflt.mem;
-
- if (mem->win[0].len < 16)
- goto next_entry;
-
- req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM;
- req.Attributes |= WIN_ENABLE;
- req.Base = mem->win[0].host_addr;
- req.Size = 0;
-
- req.AccessSpeed = 0;
- if (pcmcia_request_window(&link, &req, &link->win) != 0)
- goto next_entry;
- map.Page = 0; map.CardOffset = mem->win[0].card_addr;
- if (pcmcia_map_mem_page(link->win, &map) != 0)
- goto next_entry;
-
- io_base = (unsigned long) ioremap(req.Base, req.Size);
- ctl_base = io_base + 0x0e;
- is_mmio = 1;
-
- if (mem->win[0].len >= 0x20)
- try_slave = 1;
-
- break;
- }
-
next_entry:
if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
memcpy(&stk->dflt, cfg, sizeof(stk->dflt));
@@ -334,26 +278,21 @@ static int ide_config(struct pcmcia_device *link)
CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
- if(is_mmio)
- my_outb = outb_mem;
- else
- my_outb = outb_io;
-
/* disable drive interrupts during IDE probe */
- my_outb(0x02, ctl_base);
+ outb(0x02, ctl_base);
/* special setup for KXLC005 card */
if (is_kme)
- my_outb(0x81, ctl_base+1);
+ outb(0x81, ctl_base+1);
/* retry registration in case device is still spinning up */
for (hd = -1, i = 0; i < 10; i++) {
- hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ, link, is_mmio);
+ hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ, link);
if (hd >= 0) break;
- if (try_slave) {
- my_outb(0x02, ctl_base + 0x10);
+ if (link->io.NumPorts1 == 0x20) {
+ outb(0x02, ctl_base + 0x10);
hd = idecs_register(io_base + 0x10, ctl_base + 0x10,
- link->irq.AssignedIRQ, link, is_mmio);
+ link->irq.AssignedIRQ, link);
if (hd >= 0) {
io_base += 0x10;
ctl_base += 0x10;
diff --git a/drivers/ide/pci/generic.c b/drivers/ide/pci/generic.c
index f82e8210972..2f962cfa3f7 100644
--- a/drivers/ide/pci/generic.c
+++ b/drivers/ide/pci/generic.c
@@ -212,6 +212,9 @@ static int __devinit generic_init_one(struct pci_dev *dev, const struct pci_devi
(!(PCI_FUNC(dev->devfn) & 1)))
goto out;
+ if (dev->vendor == PCI_VENDOR_ID_JMICRON && PCI_FUNC(dev->devfn) != 1)
+ goto out;
+
pci_read_config_word(dev, PCI_COMMAND, &command);
if (!(command & PCI_COMMAND_IO)) {
printk(KERN_INFO "Skipping disabled %s IDE controller.\n", d->name);
@@ -239,6 +242,11 @@ static struct pci_device_id generic_pci_tbl[] = {
{ PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12},
{ PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13},
{ PCI_VENDOR_ID_NETCELL,PCI_DEVICE_ID_REVOLUTION, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14},
+ { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15},
+ { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16},
+ { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 17},
+ { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 18},
+ { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 19},
/* Must come last. If you add entries adjust this table appropriately and the init_one code */
{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 0},
{ 0, },
diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c
index 3cb04424d35..e9bad185968 100644
--- a/drivers/ide/pci/it821x.c
+++ b/drivers/ide/pci/it821x.c
@@ -498,9 +498,14 @@ static int config_chipset_for_dma (ide_drive_t *drive)
{
u8 speed = ide_dma_speed(drive, it821x_ratemask(drive));
- config_it821x_chipset_for_pio(drive, !speed);
- it821x_tune_chipset(drive, speed);
- return ide_dma_enable(drive);
+ if (speed) {
+ config_it821x_chipset_for_pio(drive, 0);
+ it821x_tune_chipset(drive, speed);
+
+ return ide_dma_enable(drive);
+ }
+
+ return 0;
}
/**
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
index d294bbc42f0..1205e802782 100644
--- a/drivers/infiniband/core/addr.c
+++ b/drivers/infiniband/core/addr.c
@@ -35,6 +35,7 @@
#include <net/arp.h>
#include <net/neighbour.h>
#include <net/route.h>
+#include <net/netevent.h>
#include <rdma/ib_addr.h>
MODULE_AUTHOR("Sean Hefty");
@@ -326,25 +327,22 @@ void rdma_addr_cancel(struct rdma_dev_addr *addr)
}
EXPORT_SYMBOL(rdma_addr_cancel);
-static int addr_arp_recv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *pkt, struct net_device *orig_dev)
+static int netevent_callback(struct notifier_block *self, unsigned long event,
+ void *ctx)
{
- struct arphdr *arp_hdr;
+ if (event == NETEVENT_NEIGH_UPDATE) {
+ struct neighbour *neigh = ctx;
- arp_hdr = (struct arphdr *) skb->nh.raw;
-
- if (arp_hdr->ar_op == htons(ARPOP_REQUEST) ||
- arp_hdr->ar_op == htons(ARPOP_REPLY))
- set_timeout(jiffies);
-
- kfree_skb(skb);
+ if (neigh->dev->type == ARPHRD_INFINIBAND &&
+ (neigh->nud_state & NUD_VALID)) {
+ set_timeout(jiffies);
+ }
+ }
return 0;
}
-static struct packet_type addr_arp = {
- .type = __constant_htons(ETH_P_ARP),
- .func = addr_arp_recv,
- .af_packet_priv = (void*) 1,
+static struct notifier_block nb = {
+ .notifier_call = netevent_callback
};
static int addr_init(void)
@@ -353,13 +351,13 @@ static int addr_init(void)
if (!addr_wq)
return -ENOMEM;
- dev_add_pack(&addr_arp);
+ register_netevent_notifier(&nb);
return 0;
}
static void addr_cleanup(void)
{
- dev_remove_pack(&addr_arp);
+ unregister_netevent_notifier(&nb);
destroy_workqueue(addr_wq);
}
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
index 3f6705f3083..0de335b7bfc 100644
--- a/drivers/infiniband/core/cm.c
+++ b/drivers/infiniband/core/cm.c
@@ -701,7 +701,7 @@ static void cm_reset_to_idle(struct cm_id_private *cm_id_priv)
}
}
-void ib_destroy_cm_id(struct ib_cm_id *cm_id)
+static void cm_destroy_id(struct ib_cm_id *cm_id, int err)
{
struct cm_id_private *cm_id_priv;
struct cm_work *work;
@@ -735,12 +735,22 @@ retest:
sizeof cm_id_priv->av.port->cm_dev->ca_guid,
NULL, 0);
break;
+ case IB_CM_REQ_RCVD:
+ if (err == -ENOMEM) {
+ /* Do not reject to allow future retries. */
+ cm_reset_to_idle(cm_id_priv);
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ } else {
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ ib_send_cm_rej(cm_id, IB_CM_REJ_CONSUMER_DEFINED,
+ NULL, 0, NULL, 0);
+ }
+ break;
case IB_CM_MRA_REQ_RCVD:
case IB_CM_REP_SENT:
case IB_CM_MRA_REP_RCVD:
ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
/* Fall through */
- case IB_CM_REQ_RCVD:
case IB_CM_MRA_REQ_SENT:
case IB_CM_REP_RCVD:
case IB_CM_MRA_REP_SENT:
@@ -775,6 +785,11 @@ retest:
kfree(cm_id_priv->private_data);
kfree(cm_id_priv);
}
+
+void ib_destroy_cm_id(struct ib_cm_id *cm_id)
+{
+ cm_destroy_id(cm_id, 0);
+}
EXPORT_SYMBOL(ib_destroy_cm_id);
int ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, __be64 service_mask,
@@ -960,8 +975,10 @@ int ib_send_cm_req(struct ib_cm_id *cm_id,
cm_id_priv->timewait_info = cm_create_timewait_info(cm_id_priv->
id.local_id);
- if (IS_ERR(cm_id_priv->timewait_info))
+ if (IS_ERR(cm_id_priv->timewait_info)) {
+ ret = PTR_ERR(cm_id_priv->timewait_info);
goto out;
+ }
ret = cm_init_av_by_path(param->primary_path, &cm_id_priv->av);
if (ret)
@@ -1163,7 +1180,7 @@ static void cm_process_work(struct cm_id_private *cm_id_priv,
}
cm_deref_id(cm_id_priv);
if (ret)
- ib_destroy_cm_id(&cm_id_priv->id);
+ cm_destroy_id(&cm_id_priv->id, ret);
}
static void cm_format_mra(struct cm_mra_msg *mra_msg,
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index 863f64befc7..d6f99d5720f 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -262,14 +262,14 @@ static void cma_detach_from_dev(struct rdma_id_private *id_priv)
static int cma_acquire_ib_dev(struct rdma_id_private *id_priv)
{
struct cma_device *cma_dev;
- union ib_gid *gid;
+ union ib_gid gid;
int ret = -ENODEV;
- gid = ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr);
+ ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid),
mutex_lock(&lock);
list_for_each_entry(cma_dev, &dev_list, list) {
- ret = ib_find_cached_gid(cma_dev->device, gid,
+ ret = ib_find_cached_gid(cma_dev->device, &gid,
&id_priv->id.port_num, NULL);
if (!ret) {
cma_attach_to_dev(id_priv, cma_dev);
@@ -812,6 +812,7 @@ static int cma_ib_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
cma_modify_qp_err(&id_priv->id);
status = ib_event->param.rej_rcvd.reason;
event = RDMA_CM_EVENT_REJECTED;
+ private_data_len = IB_CM_REJ_PRIVATE_DATA_SIZE;
break;
default:
printk(KERN_ERR "RDMA CMA: unexpected IB CM event: %d",
@@ -1134,8 +1135,8 @@ static int cma_query_ib_route(struct rdma_id_private *id_priv, int timeout_ms,
struct ib_sa_path_rec path_rec;
memset(&path_rec, 0, sizeof path_rec);
- path_rec.sgid = *ib_addr_get_sgid(addr);
- path_rec.dgid = *ib_addr_get_dgid(addr);
+ ib_addr_get_sgid(addr, &path_rec.sgid);
+ ib_addr_get_dgid(addr, &path_rec.dgid);
path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(addr));
path_rec.numb_path = 1;
@@ -1263,7 +1264,7 @@ static int cma_bind_loopback(struct rdma_id_private *id_priv)
{
struct cma_device *cma_dev;
struct ib_port_attr port_attr;
- union ib_gid *gid;
+ union ib_gid gid;
u16 pkey;
int ret;
u8 p;
@@ -1284,8 +1285,7 @@ static int cma_bind_loopback(struct rdma_id_private *id_priv)
}
port_found:
- gid = ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr);
- ret = ib_get_cached_gid(cma_dev->device, p, 0, gid);
+ ret = ib_get_cached_gid(cma_dev->device, p, 0, &gid);
if (ret)
goto out;
@@ -1293,6 +1293,7 @@ port_found:
if (ret)
goto out;
+ ib_addr_set_sgid(&id_priv->id.route.addr.dev_addr, &gid);
ib_addr_set_pkey(&id_priv->id.route.addr.dev_addr, pkey);
id_priv->id.port_num = p;
cma_attach_to_dev(id_priv, cma_dev);
@@ -1339,6 +1340,7 @@ static int cma_resolve_loopback(struct rdma_id_private *id_priv)
{
struct cma_work *work;
struct sockaddr_in *src_in, *dst_in;
+ union ib_gid gid;
int ret;
work = kzalloc(sizeof *work, GFP_KERNEL);
@@ -1351,8 +1353,8 @@ static int cma_resolve_loopback(struct rdma_id_private *id_priv)
goto err;
}
- ib_addr_set_dgid(&id_priv->id.route.addr.dev_addr,
- ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr));
+ ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid);
+ ib_addr_set_dgid(&id_priv->id.route.addr.dev_addr, &gid);
if (cma_zero_addr(&id_priv->id.route.addr.src_addr)) {
src_in = (struct sockaddr_in *)&id_priv->id.route.addr.src_addr;
diff --git a/drivers/infiniband/core/fmr_pool.c b/drivers/infiniband/core/fmr_pool.c
index 615fe9cc6c5..86a3b2d401d 100644
--- a/drivers/infiniband/core/fmr_pool.c
+++ b/drivers/infiniband/core/fmr_pool.c
@@ -426,7 +426,7 @@ EXPORT_SYMBOL(ib_flush_fmr_pool);
struct ib_pool_fmr *ib_fmr_pool_map_phys(struct ib_fmr_pool *pool_handle,
u64 *page_list,
int list_len,
- u64 *io_virtual_address)
+ u64 io_virtual_address)
{
struct ib_fmr_pool *pool = pool_handle;
struct ib_pool_fmr *fmr;
@@ -440,7 +440,7 @@ struct ib_pool_fmr *ib_fmr_pool_map_phys(struct ib_fmr_pool *pool_handle,
fmr = ib_fmr_cache_lookup(pool,
page_list,
list_len,
- *io_virtual_address);
+ io_virtual_address);
if (fmr) {
/* found in cache */
++fmr->ref_count;
@@ -464,7 +464,7 @@ struct ib_pool_fmr *ib_fmr_pool_map_phys(struct ib_fmr_pool *pool_handle,
spin_unlock_irqrestore(&pool->pool_lock, flags);
result = ib_map_phys_fmr(fmr->fmr, page_list, list_len,
- *io_virtual_address);
+ io_virtual_address);
if (result) {
spin_lock_irqsave(&pool->pool_lock, flags);
@@ -481,7 +481,7 @@ struct ib_pool_fmr *ib_fmr_pool_map_phys(struct ib_fmr_pool *pool_handle,
fmr->ref_count = 1;
if (pool->cache_bucket) {
- fmr->io_virtual_address = *io_virtual_address;
+ fmr->io_virtual_address = io_virtual_address;
fmr->page_list_len = list_len;
memcpy(fmr->page_list, page_list, list_len * sizeof(*page_list));
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
index 5ed4dab52a6..1c3cfbbe6a9 100644
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -167,6 +167,15 @@ static int is_vendor_method_in_use(
return 0;
}
+int ib_response_mad(struct ib_mad *mad)
+{
+ return ((mad->mad_hdr.method & IB_MGMT_METHOD_RESP) ||
+ (mad->mad_hdr.method == IB_MGMT_METHOD_TRAP_REPRESS) ||
+ ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_BM) &&
+ (mad->mad_hdr.attr_mod & IB_BM_ATTR_MOD_RESP)));
+}
+EXPORT_SYMBOL(ib_response_mad);
+
/*
* ib_register_mad_agent - Register to send/receive MADs
*/
@@ -570,13 +579,6 @@ int ib_unregister_mad_agent(struct ib_mad_agent *mad_agent)
}
EXPORT_SYMBOL(ib_unregister_mad_agent);
-static inline int response_mad(struct ib_mad *mad)
-{
- /* Trap represses are responses although response bit is reset */
- return ((mad->mad_hdr.method == IB_MGMT_METHOD_TRAP_REPRESS) ||
- (mad->mad_hdr.method & IB_MGMT_METHOD_RESP));
-}
-
static void dequeue_mad(struct ib_mad_list_head *mad_list)
{
struct ib_mad_queue *mad_queue;
@@ -723,7 +725,7 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv,
switch (ret)
{
case IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY:
- if (response_mad(&mad_priv->mad.mad) &&
+ if (ib_response_mad(&mad_priv->mad.mad) &&
mad_agent_priv->agent.recv_handler) {
local->mad_priv = mad_priv;
local->recv_mad_agent = mad_agent_priv;
@@ -1551,7 +1553,7 @@ find_mad_agent(struct ib_mad_port_private *port_priv,
unsigned long flags;
spin_lock_irqsave(&port_priv->reg_lock, flags);
- if (response_mad(mad)) {
+ if (ib_response_mad(mad)) {
u32 hi_tid;
struct ib_mad_agent_private *entry;
@@ -1799,7 +1801,7 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv,
}
/* Complete corresponding request */
- if (response_mad(mad_recv_wc->recv_buf.mad)) {
+ if (ib_response_mad(mad_recv_wc->recv_buf.mad)) {
spin_lock_irqsave(&mad_agent_priv->lock, flags);
mad_send_wr = ib_find_send_mad(mad_agent_priv, mad_recv_wc);
if (!mad_send_wr) {
diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c
index e911c99ff84..aeda484ffd8 100644
--- a/drivers/infiniband/core/sa_query.c
+++ b/drivers/infiniband/core/sa_query.c
@@ -488,13 +488,13 @@ static void init_mad(struct ib_sa_mad *mad, struct ib_mad_agent *agent)
spin_unlock_irqrestore(&tid_lock, flags);
}
-static int send_mad(struct ib_sa_query *query, int timeout_ms)
+static int send_mad(struct ib_sa_query *query, int timeout_ms, gfp_t gfp_mask)
{
unsigned long flags;
int ret, id;
retry:
- if (!idr_pre_get(&query_idr, GFP_ATOMIC))
+ if (!idr_pre_get(&query_idr, gfp_mask))
return -ENOMEM;
spin_lock_irqsave(&idr_lock, flags);
ret = idr_get_new(&query_idr, query, &id);
@@ -630,7 +630,7 @@ int ib_sa_path_rec_get(struct ib_device *device, u8 port_num,
*sa_query = &query->sa_query;
- ret = send_mad(&query->sa_query, timeout_ms);
+ ret = send_mad(&query->sa_query, timeout_ms, gfp_mask);
if (ret < 0)
goto err2;
@@ -752,7 +752,7 @@ int ib_sa_service_rec_query(struct ib_device *device, u8 port_num, u8 method,
*sa_query = &query->sa_query;
- ret = send_mad(&query->sa_query, timeout_ms);
+ ret = send_mad(&query->sa_query, timeout_ms, gfp_mask);
if (ret < 0)
goto err2;
@@ -844,7 +844,7 @@ int ib_sa_mcmember_rec_query(struct ib_device *device, u8 port_num,
*sa_query = &query->sa_query;
- ret = send_mad(&query->sa_query, timeout_ms);
+ ret = send_mad(&query->sa_query, timeout_ms, gfp_mask);
if (ret < 0)
goto err2;
diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c
index afe70a549c2..1273f8807e8 100644
--- a/drivers/infiniband/core/user_mad.c
+++ b/drivers/infiniband/core/user_mad.c
@@ -112,8 +112,10 @@ struct ib_umad_device {
struct ib_umad_file {
struct ib_umad_port *port;
struct list_head recv_list;
+ struct list_head send_list;
struct list_head port_list;
spinlock_t recv_lock;
+ spinlock_t send_lock;
wait_queue_head_t recv_wait;
struct ib_mad_agent *agent[IB_UMAD_MAX_AGENTS];
int agents_dead;
@@ -177,12 +179,21 @@ static int queue_packet(struct ib_umad_file *file,
return ret;
}
+static void dequeue_send(struct ib_umad_file *file,
+ struct ib_umad_packet *packet)
+ {
+ spin_lock_irq(&file->send_lock);
+ list_del(&packet->list);
+ spin_unlock_irq(&file->send_lock);
+ }
+
static void send_handler(struct ib_mad_agent *agent,
struct ib_mad_send_wc *send_wc)
{
struct ib_umad_file *file = agent->context;
struct ib_umad_packet *packet = send_wc->send_buf->context[0];
+ dequeue_send(file, packet);
ib_destroy_ah(packet->msg->ah);
ib_free_send_mad(packet->msg);
@@ -370,6 +381,51 @@ static int copy_rmpp_mad(struct ib_mad_send_buf *msg, const char __user *buf)
return 0;
}
+static int same_destination(struct ib_user_mad_hdr *hdr1,
+ struct ib_user_mad_hdr *hdr2)
+{
+ if (!hdr1->grh_present && !hdr2->grh_present)
+ return (hdr1->lid == hdr2->lid);
+
+ if (hdr1->grh_present && hdr2->grh_present)
+ return !memcmp(hdr1->gid, hdr2->gid, 16);
+
+ return 0;
+}
+
+static int is_duplicate(struct ib_umad_file *file,
+ struct ib_umad_packet *packet)
+{
+ struct ib_umad_packet *sent_packet;
+ struct ib_mad_hdr *sent_hdr, *hdr;
+
+ hdr = (struct ib_mad_hdr *) packet->mad.data;
+ list_for_each_entry(sent_packet, &file->send_list, list) {
+ sent_hdr = (struct ib_mad_hdr *) sent_packet->mad.data;
+
+ if ((hdr->tid != sent_hdr->tid) ||
+ (hdr->mgmt_class != sent_hdr->mgmt_class))
+ continue;
+
+ /*
+ * No need to be overly clever here. If two new operations have
+ * the same TID, reject the second as a duplicate. This is more
+ * restrictive than required by the spec.
+ */
+ if (!ib_response_mad((struct ib_mad *) hdr)) {
+ if (!ib_response_mad((struct ib_mad *) sent_hdr))
+ return 1;
+ continue;
+ } else if (!ib_response_mad((struct ib_mad *) sent_hdr))
+ continue;
+
+ if (same_destination(&packet->mad.hdr, &sent_packet->mad.hdr))
+ return 1;
+ }
+
+ return 0;
+}
+
static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
size_t count, loff_t *pos)
{
@@ -379,7 +435,6 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
struct ib_ah_attr ah_attr;
struct ib_ah *ah;
struct ib_rmpp_mad *rmpp_mad;
- u8 method;
__be64 *tid;
int ret, data_len, hdr_len, copy_offset, rmpp_active;
@@ -473,28 +528,36 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
}
/*
- * If userspace is generating a request that will generate a
- * response, we need to make sure the high-order part of the
- * transaction ID matches the agent being used to send the
- * MAD.
+ * Set the high-order part of the transaction ID to make MADs from
+ * different agents unique, and allow routing responses back to the
+ * original requestor.
*/
- method = ((struct ib_mad_hdr *) packet->msg->mad)->method;
-
- if (!(method & IB_MGMT_METHOD_RESP) &&
- method != IB_MGMT_METHOD_TRAP_REPRESS &&
- method != IB_MGMT_METHOD_SEND) {
+ if (!ib_response_mad(packet->msg->mad)) {
tid = &((struct ib_mad_hdr *) packet->msg->mad)->tid;
*tid = cpu_to_be64(((u64) agent->hi_tid) << 32 |
(be64_to_cpup(tid) & 0xffffffff));
+ rmpp_mad->mad_hdr.tid = *tid;
+ }
+
+ spin_lock_irq(&file->send_lock);
+ ret = is_duplicate(file, packet);
+ if (!ret)
+ list_add_tail(&packet->list, &file->send_list);
+ spin_unlock_irq(&file->send_lock);
+ if (ret) {
+ ret = -EINVAL;
+ goto err_msg;
}
ret = ib_post_send_mad(packet->msg, NULL);
if (ret)
- goto err_msg;
+ goto err_send;
up_read(&file->port->mutex);
return count;
+err_send:
+ dequeue_send(file, packet);
err_msg:
ib_free_send_mad(packet->msg);
err_ah:
@@ -657,7 +720,9 @@ static int ib_umad_open(struct inode *inode, struct file *filp)
}
spin_lock_init(&file->recv_lock);
+ spin_lock_init(&file->send_lock);
INIT_LIST_HEAD(&file->recv_list);
+ INIT_LIST_HEAD(&file->send_list);
init_waitqueue_head(&file->recv_wait);
file->port = port;
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h
index bb9bee56a82..102a59c033f 100644
--- a/drivers/infiniband/core/uverbs.h
+++ b/drivers/infiniband/core/uverbs.h
@@ -42,6 +42,7 @@
#include <linux/kref.h>
#include <linux/idr.h>
#include <linux/mutex.h>
+#include <linux/completion.h>
#include <rdma/ib_verbs.h>
#include <rdma/ib_user_verbs.h>
@@ -69,6 +70,7 @@
struct ib_uverbs_device {
struct kref ref;
+ struct completion comp;
int devnum;
struct cdev *dev;
struct class_device *class_dev;
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index bdf5d509819..30923eb68ec 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -42,6 +42,13 @@
#include "uverbs.h"
+static struct lock_class_key pd_lock_key;
+static struct lock_class_key mr_lock_key;
+static struct lock_class_key cq_lock_key;
+static struct lock_class_key qp_lock_key;
+static struct lock_class_key ah_lock_key;
+static struct lock_class_key srq_lock_key;
+
#define INIT_UDATA(udata, ibuf, obuf, ilen, olen) \
do { \
(udata)->inbuf = (void __user *) (ibuf); \
@@ -76,12 +83,13 @@
*/
static void init_uobj(struct ib_uobject *uobj, u64 user_handle,
- struct ib_ucontext *context)
+ struct ib_ucontext *context, struct lock_class_key *key)
{
uobj->user_handle = user_handle;
uobj->context = context;
kref_init(&uobj->ref);
init_rwsem(&uobj->mutex);
+ lockdep_set_class(&uobj->mutex, key);
uobj->live = 0;
}
@@ -470,7 +478,7 @@ ssize_t ib_uverbs_alloc_pd(struct ib_uverbs_file *file,
if (!uobj)
return -ENOMEM;
- init_uobj(uobj, 0, file->ucontext);
+ init_uobj(uobj, 0, file->ucontext, &pd_lock_key);
down_write(&uobj->mutex);
pd = file->device->ib_dev->alloc_pd(file->device->ib_dev,
@@ -591,7 +599,7 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file,
if (!obj)
return -ENOMEM;
- init_uobj(&obj->uobject, 0, file->ucontext);
+ init_uobj(&obj->uobject, 0, file->ucontext, &mr_lock_key);
down_write(&obj->uobject.mutex);
/*
@@ -770,7 +778,7 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file,
if (!obj)
return -ENOMEM;
- init_uobj(&obj->uobject, cmd.user_handle, file->ucontext);
+ init_uobj(&obj->uobject, cmd.user_handle, file->ucontext, &cq_lock_key);
down_write(&obj->uobject.mutex);
if (cmd.comp_channel >= 0) {
@@ -1051,13 +1059,14 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
if (!obj)
return -ENOMEM;
- init_uobj(&obj->uevent.uobject, cmd.user_handle, file->ucontext);
+ init_uobj(&obj->uevent.uobject, cmd.user_handle, file->ucontext, &qp_lock_key);
down_write(&obj->uevent.uobject.mutex);
+ srq = cmd.is_srq ? idr_read_srq(cmd.srq_handle, file->ucontext) : NULL;
pd = idr_read_pd(cmd.pd_handle, file->ucontext);
scq = idr_read_cq(cmd.send_cq_handle, file->ucontext);
- rcq = idr_read_cq(cmd.recv_cq_handle, file->ucontext);
- srq = cmd.is_srq ? idr_read_srq(cmd.srq_handle, file->ucontext) : NULL;
+ rcq = cmd.recv_cq_handle == cmd.send_cq_handle ?
+ scq : idr_read_cq(cmd.recv_cq_handle, file->ucontext);
if (!pd || !scq || !rcq || (cmd.is_srq && !srq)) {
ret = -EINVAL;
@@ -1125,7 +1134,8 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
put_pd_read(pd);
put_cq_read(scq);
- put_cq_read(rcq);
+ if (rcq != scq)
+ put_cq_read(rcq);
if (srq)
put_srq_read(srq);
@@ -1150,7 +1160,7 @@ err_put:
put_pd_read(pd);
if (scq)
put_cq_read(scq);
- if (rcq)
+ if (rcq && rcq != scq)
put_cq_read(rcq);
if (srq)
put_srq_read(srq);
@@ -1751,7 +1761,7 @@ ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file,
if (!uobj)
return -ENOMEM;
- init_uobj(uobj, cmd.user_handle, file->ucontext);
+ init_uobj(uobj, cmd.user_handle, file->ucontext, &ah_lock_key);
down_write(&uobj->mutex);
pd = idr_read_pd(cmd.pd_handle, file->ucontext);
@@ -1775,7 +1785,7 @@ ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file,
ah = ib_create_ah(pd, &attr);
if (IS_ERR(ah)) {
ret = PTR_ERR(ah);
- goto err;
+ goto err_put;
}
ah->uobject = uobj;
@@ -1811,6 +1821,9 @@ err_copy:
err_destroy:
ib_destroy_ah(ah);
+err_put:
+ put_pd_read(pd);
+
err:
put_uobj_write(uobj);
return ret;
@@ -1963,7 +1976,7 @@ ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file,
if (!obj)
return -ENOMEM;
- init_uobj(&obj->uobject, cmd.user_handle, file->ucontext);
+ init_uobj(&obj->uobject, cmd.user_handle, file->ucontext, &srq_lock_key);
down_write(&obj->uobject.mutex);
pd = idr_read_pd(cmd.pd_handle, file->ucontext);
@@ -1984,7 +1997,7 @@ ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file,
srq = pd->device->create_srq(pd, &attr, &udata);
if (IS_ERR(srq)) {
ret = PTR_ERR(srq);
- goto err;
+ goto err_put;
}
srq->device = pd->device;
@@ -2029,6 +2042,9 @@ err_copy:
err_destroy:
ib_destroy_srq(srq);
+err_put:
+ put_pd_read(pd);
+
err:
put_uobj_write(&obj->uobject);
return ret;
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index e725cccc7cd..4e16314e8e6 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -122,7 +122,7 @@ static void ib_uverbs_release_dev(struct kref *ref)
struct ib_uverbs_device *dev =
container_of(ref, struct ib_uverbs_device, ref);
- kfree(dev);
+ complete(&dev->comp);
}
void ib_uverbs_release_ucq(struct ib_uverbs_file *file,
@@ -740,6 +740,7 @@ static void ib_uverbs_add_one(struct ib_device *device)
return;
kref_init(&uverbs_dev->ref);
+ init_completion(&uverbs_dev->comp);
spin_lock(&map_lock);
uverbs_dev->devnum = find_first_zero_bit(dev_map, IB_UVERBS_MAX_DEVICES);
@@ -793,6 +794,8 @@ err_cdev:
err:
kref_put(&uverbs_dev->ref, ib_uverbs_release_dev);
+ wait_for_completion(&uverbs_dev->comp);
+ kfree(uverbs_dev);
return;
}
@@ -812,7 +815,10 @@ static void ib_uverbs_remove_one(struct ib_device *device)
spin_unlock(&map_lock);
clear_bit(uverbs_dev->devnum, dev_map);
+
kref_put(&uverbs_dev->ref, ib_uverbs_release_dev);
+ wait_for_completion(&uverbs_dev->comp);
+ kfree(uverbs_dev);
}
static int uverbs_event_get_sb(struct file_system_type *fs_type, int flags,
diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c
index 823131d58b3..f98518d912b 100644
--- a/drivers/infiniband/hw/ipath/ipath_driver.c
+++ b/drivers/infiniband/hw/ipath/ipath_driver.c
@@ -859,6 +859,38 @@ static void ipath_rcv_layer(struct ipath_devdata *dd, u32 etail,
__ipath_layer_rcv_lid(dd, hdr);
}
+static void ipath_rcv_hdrerr(struct ipath_devdata *dd,
+ u32 eflags,
+ u32 l,
+ u32 etail,
+ u64 *rc)
+{
+ char emsg[128];
+ struct ipath_message_header *hdr;
+
+ get_rhf_errstring(eflags, emsg, sizeof emsg);
+ hdr = (struct ipath_message_header *)&rc[1];
+ ipath_cdbg(PKT, "RHFerrs %x hdrqtail=%x typ=%u "
+ "tlen=%x opcode=%x egridx=%x: %s\n",
+ eflags, l,
+ ipath_hdrget_rcv_type((__le32 *) rc),
+ ipath_hdrget_length_in_bytes((__le32 *) rc),
+ be32_to_cpu(hdr->bth[0]) >> 24,
+ etail, emsg);
+
+ /* Count local link integrity errors. */
+ if (eflags & (INFINIPATH_RHF_H_ICRCERR | INFINIPATH_RHF_H_VCRCERR)) {
+ u8 n = (dd->ipath_ibcctrl >>
+ INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT) &
+ INFINIPATH_IBCC_PHYERRTHRESHOLD_MASK;
+
+ if (++dd->ipath_lli_counter > n) {
+ dd->ipath_lli_counter = 0;
+ dd->ipath_lli_errors++;
+ }
+ }
+}
+
/*
* ipath_kreceive - receive a packet
* @dd: the infinipath device
@@ -875,7 +907,6 @@ void ipath_kreceive(struct ipath_devdata *dd)
struct ipath_message_header *hdr;
u32 eflags, i, etype, tlen, pkttot = 0, updegr=0, reloop=0;
static u64 totcalls; /* stats, may eventually remove */
- char emsg[128];
if (!dd->ipath_hdrqtailptr) {
ipath_dev_err(dd,
@@ -938,26 +969,9 @@ reloop:
"%x\n", etype);
}
- if (eflags & ~(INFINIPATH_RHF_H_TIDERR |
- INFINIPATH_RHF_H_IHDRERR)) {
- get_rhf_errstring(eflags, emsg, sizeof emsg);
- ipath_cdbg(PKT, "RHFerrs %x hdrqtail=%x typ=%u "
- "tlen=%x opcode=%x egridx=%x: %s\n",
- eflags, l, etype, tlen, bthbytes[0],
- ipath_hdrget_index((__le32 *) rc), emsg);
- /* Count local link integrity errors. */
- if (eflags & (INFINIPATH_RHF_H_ICRCERR |
- INFINIPATH_RHF_H_VCRCERR)) {
- u8 n = (dd->ipath_ibcctrl >>
- INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT) &
- INFINIPATH_IBCC_PHYERRTHRESHOLD_MASK;
-
- if (++dd->ipath_lli_counter > n) {
- dd->ipath_lli_counter = 0;
- dd->ipath_lli_errors++;
- }
- }
- } else if (etype == RCVHQ_RCV_TYPE_NON_KD) {
+ if (unlikely(eflags))
+ ipath_rcv_hdrerr(dd, eflags, l, etail, rc);
+ else if (etype == RCVHQ_RCV_TYPE_NON_KD) {
int ret = __ipath_verbs_rcv(dd, rc + 1,
ebuf, tlen);
if (ret == -ENODEV)
@@ -981,25 +995,7 @@ reloop:
else if (etype == RCVHQ_RCV_TYPE_EXPECTED)
ipath_dbg("Bug: Expected TID, opcode %x; ignored\n",
be32_to_cpu(hdr->bth[0]) & 0xff);
- else if (eflags & (INFINIPATH_RHF_H_TIDERR |
- INFINIPATH_RHF_H_IHDRERR)) {
- /*
- * This is a type 3 packet, only the LRH is in the
- * rcvhdrq, the rest of the header is in the eager
- * buffer.
- */
- u8 opcode;
- if (ebuf) {
- bthbytes = (u8 *) ebuf;
- opcode = *bthbytes;
- }
- else
- opcode = 0;
- get_rhf_errstring(eflags, emsg, sizeof emsg);
- ipath_dbg("Err %x (%s), opcode %x, egrbuf %x, "
- "len %x\n", eflags, emsg, opcode, etail,
- tlen);
- } else {
+ else {
/*
* error packet, type of error unknown.
* Probably type 3, but we don't know, so don't
diff --git a/drivers/infiniband/hw/ipath/ipath_keys.c b/drivers/infiniband/hw/ipath/ipath_keys.c
index 46773c673a1..a5ca279370a 100644
--- a/drivers/infiniband/hw/ipath/ipath_keys.c
+++ b/drivers/infiniband/hw/ipath/ipath_keys.c
@@ -197,6 +197,21 @@ int ipath_rkey_ok(struct ipath_ibdev *dev, struct ipath_sge_state *ss,
size_t off;
int ret;
+ /*
+ * We use RKEY == zero for physical addresses
+ * (see ipath_get_dma_mr).
+ */
+ if (rkey == 0) {
+ sge->mr = NULL;
+ sge->vaddr = phys_to_virt(vaddr);
+ sge->length = len;
+ sge->sge_length = len;
+ ss->sg_list = NULL;
+ ss->num_sge = 1;
+ ret = 1;
+ goto bail;
+ }
+
mr = rkt->table[(rkey >> (32 - ib_ipath_lkey_table_size))];
if (unlikely(mr == NULL || mr->lkey != rkey)) {
ret = 0;
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c
index 56ac336dd1e..d70a9b6b523 100644
--- a/drivers/infiniband/hw/ipath/ipath_verbs.c
+++ b/drivers/infiniband/hw/ipath/ipath_verbs.c
@@ -191,10 +191,6 @@ void ipath_skip_sge(struct ipath_sge_state *ss, u32 length)
{
struct ipath_sge *sge = &ss->sge;
- while (length > sge->sge_length) {
- length -= sge->sge_length;
- ss->sge = *ss->sg_list++;
- }
while (length) {
u32 len = sge->length;
@@ -627,6 +623,7 @@ static int ipath_query_device(struct ib_device *ibdev,
props->device_cap_flags = IB_DEVICE_BAD_PKEY_CNTR |
IB_DEVICE_BAD_QKEY_CNTR | IB_DEVICE_SHUTDOWN_PORT |
IB_DEVICE_SYS_IMAGE_GUID;
+ props->page_size_cap = PAGE_SIZE;
props->vendor_id = ipath_layer_get_vendorid(dev->dd);
props->vendor_part_id = ipath_layer_get_deviceid(dev->dd);
props->hw_ver = ipath_layer_get_pcirev(dev->dd);
diff --git a/drivers/infiniband/hw/mthca/mthca_allocator.c b/drivers/infiniband/hw/mthca/mthca_allocator.c
index 9ba3211cef7..25157f57a6d 100644
--- a/drivers/infiniband/hw/mthca/mthca_allocator.c
+++ b/drivers/infiniband/hw/mthca/mthca_allocator.c
@@ -108,14 +108,15 @@ void mthca_alloc_cleanup(struct mthca_alloc *alloc)
* serialize access to the array.
*/
+#define MTHCA_ARRAY_MASK (PAGE_SIZE / sizeof (void *) - 1)
+
void *mthca_array_get(struct mthca_array *array, int index)
{
int p = (index * sizeof (void *)) >> PAGE_SHIFT;
- if (array->page_list[p].page) {
- int i = index & (PAGE_SIZE / sizeof (void *) - 1);
- return array->page_list[p].page[i];
- } else
+ if (array->page_list[p].page)
+ return array->page_list[p].page[index & MTHCA_ARRAY_MASK];
+ else
return NULL;
}
@@ -130,8 +131,7 @@ int mthca_array_set(struct mthca_array *array, int index, void *value)
if (!array->page_list[p].page)
return -ENOMEM;
- array->page_list[p].page[index & (PAGE_SIZE / sizeof (void *) - 1)] =
- value;
+ array->page_list[p].page[index & MTHCA_ARRAY_MASK] = value;
++array->page_list[p].used;
return 0;
@@ -144,7 +144,8 @@ void mthca_array_clear(struct mthca_array *array, int index)
if (--array->page_list[p].used == 0) {
free_page((unsigned long) array->page_list[p].page);
array->page_list[p].page = NULL;
- }
+ } else
+ array->page_list[p].page[index & MTHCA_ARRAY_MASK] = NULL;
if (array->page_list[p].used < 0)
pr_debug("Array %p index %d page %d with ref count %d < 0\n",
diff --git a/drivers/infiniband/hw/mthca/mthca_av.c b/drivers/infiniband/hw/mthca/mthca_av.c
index b12aa03be25..e215041b2db 100644
--- a/drivers/infiniband/hw/mthca/mthca_av.c
+++ b/drivers/infiniband/hw/mthca/mthca_av.c
@@ -303,9 +303,10 @@ int mthca_ah_query(struct ib_ah *ibah, struct ib_ah_attr *attr)
memset(attr, 0, sizeof *attr);
attr->dlid = be16_to_cpu(ah->av->dlid);
attr->sl = be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 28;
- attr->static_rate = ah->av->msg_sr & 0x7;
- attr->src_path_bits = ah->av->g_slid & 0x7F;
attr->port_num = be32_to_cpu(ah->av->port_pd) >> 24;
+ attr->static_rate = mthca_rate_to_ib(dev, ah->av->msg_sr & 0x7,
+ attr->port_num);
+ attr->src_path_bits = ah->av->g_slid & 0x7F;
attr->ah_flags = mthca_ah_grh_present(ah) ? IB_AH_GRH : 0;
if (attr->ah_flags) {
diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c
index d0f7731802c..deabc14b4ea 100644
--- a/drivers/infiniband/hw/mthca/mthca_cmd.c
+++ b/drivers/infiniband/hw/mthca/mthca_cmd.c
@@ -778,11 +778,12 @@ int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status)
((dev->fw_ver & 0xffff0000ull) >> 16) |
((dev->fw_ver & 0x0000ffffull) << 16);
+ MTHCA_GET(lg, outbox, QUERY_FW_MAX_CMD_OFFSET);
+ dev->cmd.max_cmds = 1 << lg;
+
mthca_dbg(dev, "FW version %012llx, max commands %d\n",
(unsigned long long) dev->fw_ver, dev->cmd.max_cmds);
- MTHCA_GET(lg, outbox, QUERY_FW_MAX_CMD_OFFSET);
- dev->cmd.max_cmds = 1 << lg;
MTHCA_GET(dev->catas_err.addr, outbox, QUERY_FW_ERR_START_OFFSET);
MTHCA_GET(dev->catas_err.size, outbox, QUERY_FW_ERR_SIZE_OFFSET);
diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c
index 490fc783bb0..cd8b6721ac9 100644
--- a/drivers/infiniband/hw/mthca/mthca_qp.c
+++ b/drivers/infiniband/hw/mthca/mthca_qp.c
@@ -222,9 +222,8 @@ static void *get_send_wqe(struct mthca_qp *qp, int n)
(PAGE_SIZE - 1));
}
-static void mthca_wq_init(struct mthca_wq *wq)
+static void mthca_wq_reset(struct mthca_wq *wq)
{
- /* mthca_alloc_qp_common() initializes the locks */
wq->next_ind = 0;
wq->last_comp = wq->max - 1;
wq->head = 0;
@@ -845,10 +844,10 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq), qp->qpn,
qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL);
- mthca_wq_init(&qp->sq);
+ mthca_wq_reset(&qp->sq);
qp->sq.last = get_send_wqe(qp, qp->sq.max - 1);
- mthca_wq_init(&qp->rq);
+ mthca_wq_reset(&qp->rq);
qp->rq.last = get_recv_wqe(qp, qp->rq.max - 1);
if (mthca_is_memfree(dev)) {
@@ -1112,9 +1111,9 @@ static int mthca_alloc_qp_common(struct mthca_dev *dev,
qp->atomic_rd_en = 0;
qp->resp_depth = 0;
qp->sq_policy = send_policy;
- mthca_wq_init(&qp->sq);
- mthca_wq_init(&qp->rq);
- /* these are initialized separately so lockdep can tell them apart */
+ mthca_wq_reset(&qp->sq);
+ mthca_wq_reset(&qp->rq);
+
spin_lock_init(&qp->sq.lock);
spin_lock_init(&qp->rq.lock);
diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c
index fab417c5cf4..b60a9d79ae5 100644
--- a/drivers/infiniband/hw/mthca/mthca_srq.c
+++ b/drivers/infiniband/hw/mthca/mthca_srq.c
@@ -370,7 +370,8 @@ int mthca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
return -EINVAL;
if (attr_mask & IB_SRQ_LIMIT) {
- if (attr->srq_limit > srq->max)
+ u32 max_wr = mthca_is_memfree(dev) ? srq->max - 1 : srq->max;
+ if (attr->srq_limit > max_wr)
return -EINVAL;
mutex_lock(&srq->mutex);
diff --git a/drivers/infiniband/ulp/ipoib/Kconfig b/drivers/infiniband/ulp/ipoib/Kconfig
index 13d6d01c72c..d74653d7de1 100644
--- a/drivers/infiniband/ulp/ipoib/Kconfig
+++ b/drivers/infiniband/ulp/ipoib/Kconfig
@@ -6,8 +6,7 @@ config INFINIBAND_IPOIB
transports IP packets over InfiniBand so you can use your IB
device as a fancy NIC.
- The IPoIB protocol is defined by the IETF ipoib working
- group: <http://www.ietf.org/html.charters/ipoib-charter.html>.
+ See Documentation/infiniband/ipoib.txt for more information
config INFINIBAND_IPOIB_DEBUG
bool "IP-over-InfiniBand debugging" if EMBEDDED
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index 3f89f5e1903..474aa214ab5 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -212,6 +212,7 @@ struct ipoib_path {
struct ipoib_neigh {
struct ipoib_ah *ah;
+ union ib_gid dgid;
struct sk_buff_head queue;
struct neighbour *neighbour;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index 1c6ea1c682a..cf71d2a5515 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -404,6 +404,8 @@ static void path_rec_completion(int status,
list_for_each_entry(neigh, &path->neigh_list, list) {
kref_get(&path->ah->ref);
neigh->ah = path->ah;
+ memcpy(&neigh->dgid.raw, &path->pathrec.dgid.raw,
+ sizeof(union ib_gid));
while ((skb = __skb_dequeue(&neigh->queue)))
__skb_queue_tail(&skqueue, skb);
@@ -510,6 +512,8 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
if (path->ah) {
kref_get(&path->ah->ref);
neigh->ah = path->ah;
+ memcpy(&neigh->dgid.raw, &path->pathrec.dgid.raw,
+ sizeof(union ib_gid));
ipoib_send(dev, skb, path->ah,
be32_to_cpup((__be32 *) skb->dst->neighbour->ha));
@@ -633,6 +637,25 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
neigh = *to_ipoib_neigh(skb->dst->neighbour);
if (likely(neigh->ah)) {
+ if (unlikely(memcmp(&neigh->dgid.raw,
+ skb->dst->neighbour->ha + 4,
+ sizeof(union ib_gid)))) {
+ spin_lock(&priv->lock);
+ /*
+ * It's safe to call ipoib_put_ah() inside
+ * priv->lock here, because we know that
+ * path->ah will always hold one more reference,
+ * so ipoib_put_ah() will never do more than
+ * decrement the ref count.
+ */
+ ipoib_put_ah(neigh->ah);
+ list_del(&neigh->list);
+ ipoib_neigh_free(neigh);
+ spin_unlock(&priv->lock);
+ ipoib_path_lookup(skb, dev);
+ goto out;
+ }
+
ipoib_send(dev, skb, neigh->ah,
be32_to_cpup((__be32 *) skb->dst->neighbour->ha));
goto out;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
index ab40488182b..b5e6a7be603 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
@@ -264,6 +264,10 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast,
if (!ah) {
ipoib_warn(priv, "ib_address_create failed\n");
} else {
+ spin_lock_irq(&priv->lock);
+ mcast->ah = ah;
+ spin_unlock_irq(&priv->lock);
+
ipoib_dbg_mcast(priv, "MGID " IPOIB_GID_FMT
" AV %p, LID 0x%04x, SL %d\n",
IPOIB_GID_ARG(mcast->mcmember.mgid),
@@ -271,10 +275,6 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast,
be16_to_cpu(mcast->mcmember.mlid),
mcast->mcmember.sl);
}
-
- spin_lock_irq(&priv->lock);
- mcast->ah = ah;
- spin_unlock_irq(&priv->lock);
}
/* actually send any queued packets */
diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
index ff117bbf81b..72febf1f8ff 100644
--- a/drivers/infiniband/ulp/iser/iser_verbs.c
+++ b/drivers/infiniband/ulp/iser/iser_verbs.c
@@ -594,7 +594,7 @@ int iser_reg_page_vec(struct iser_conn *ib_conn,
mem = ib_fmr_pool_map_phys(ib_conn->fmr_pool,
page_list,
page_vec->length,
- &io_addr);
+ io_addr);
if (IS_ERR(mem)) {
status = (int)PTR_ERR(mem);
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 4e22afef720..8257d5a2c8f 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -77,6 +77,14 @@ MODULE_PARM_DESC(topspin_workarounds,
static const u8 topspin_oui[3] = { 0x00, 0x05, 0xad };
+static int mellanox_workarounds = 1;
+
+module_param(mellanox_workarounds, int, 0444);
+MODULE_PARM_DESC(mellanox_workarounds,
+ "Enable workarounds for Mellanox SRP target bugs if != 0");
+
+static const u8 mellanox_oui[3] = { 0x00, 0x02, 0xc9 };
+
static void srp_add_one(struct ib_device *device);
static void srp_remove_one(struct ib_device *device);
static void srp_completion(struct ib_cq *cq, void *target_ptr);
@@ -526,8 +534,10 @@ static int srp_reconnect_target(struct srp_target_port *target)
while (ib_poll_cq(target->cq, 1, &wc) > 0)
; /* nothing */
+ spin_lock_irq(target->scsi_host->host_lock);
list_for_each_entry_safe(req, tmp, &target->req_queue, list)
srp_reset_req(target, req);
+ spin_unlock_irq(target->scsi_host->host_lock);
target->rx_head = 0;
target->tx_head = 0;
@@ -567,7 +577,7 @@ err:
return ret;
}
-static int srp_map_fmr(struct srp_device *dev, struct scatterlist *scat,
+static int srp_map_fmr(struct srp_target_port *target, struct scatterlist *scat,
int sg_cnt, struct srp_request *req,
struct srp_direct_buf *buf)
{
@@ -577,10 +587,15 @@ static int srp_map_fmr(struct srp_device *dev, struct scatterlist *scat,
int page_cnt;
int i, j;
int ret;
+ struct srp_device *dev = target->srp_host->dev;
if (!dev->fmr_pool)
return -ENODEV;
+ if ((sg_dma_address(&scat[0]) & ~dev->fmr_page_mask) &&
+ mellanox_workarounds && !memcmp(&target->ioc_guid, mellanox_oui, 3))
+ return -EINVAL;
+
len = page_cnt = 0;
for (i = 0; i < sg_cnt; ++i) {
if (sg_dma_address(&scat[i]) & ~dev->fmr_page_mask) {
@@ -615,9 +630,10 @@ static int srp_map_fmr(struct srp_device *dev, struct scatterlist *scat,
(sg_dma_address(&scat[i]) & dev->fmr_page_mask) + j;
req->fmr = ib_fmr_pool_map_phys(dev->fmr_pool,
- dma_pages, page_cnt, &io_addr);
+ dma_pages, page_cnt, io_addr);
if (IS_ERR(req->fmr)) {
ret = PTR_ERR(req->fmr);
+ req->fmr = NULL;
goto out;
}
@@ -682,7 +698,7 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target,
buf->va = cpu_to_be64(sg_dma_address(scat));
buf->key = cpu_to_be32(target->srp_host->dev->mr->rkey);
buf->len = cpu_to_be32(sg_dma_len(scat));
- } else if (srp_map_fmr(target->srp_host->dev, scat, count, req,
+ } else if (srp_map_fmr(target, scat, count, req,
(void *) cmd->add_data)) {
/*
* FMR mapping failed, and the scatterlist has more
diff --git a/drivers/isdn/hisax/asuscom.c b/drivers/isdn/hisax/asuscom.c
index a98c5e38bbb..93ff941c48f 100644
--- a/drivers/isdn/hisax/asuscom.c
+++ b/drivers/isdn/hisax/asuscom.c
@@ -297,7 +297,7 @@ Asus_card_msg(struct IsdnCardState *cs, int mt, void *arg)
}
#ifdef __ISAPNP__
-static struct isapnp_device_id asus_ids[] __initdata = {
+static struct isapnp_device_id asus_ids[] __devinitdata = {
{ ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1688),
ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1688),
(unsigned long) "Asus1688 PnP" },
@@ -313,11 +313,11 @@ static struct isapnp_device_id asus_ids[] __initdata = {
{ 0, }
};
-static struct isapnp_device_id *ipid __initdata = &asus_ids[0];
+static struct isapnp_device_id *ipid __devinitdata = &asus_ids[0];
static struct pnp_card *pnp_c __devinitdata = NULL;
#endif
-int __init
+int __devinit
setup_asuscom(struct IsdnCard *card)
{
int bytecnt;
diff --git a/drivers/isdn/hisax/avm_a1.c b/drivers/isdn/hisax/avm_a1.c
index 9a8b02557ff..729e906bdc6 100644
--- a/drivers/isdn/hisax/avm_a1.c
+++ b/drivers/isdn/hisax/avm_a1.c
@@ -178,7 +178,7 @@ AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-int __init
+int __devinit
setup_avm_a1(struct IsdnCard *card)
{
u_char val;
diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c
index 04f5917bf5a..369afd3a3a4 100644
--- a/drivers/isdn/hisax/avm_pci.c
+++ b/drivers/isdn/hisax/avm_pci.c
@@ -639,7 +639,7 @@ clear_pending_hdlc_ints(struct IsdnCardState *cs)
}
#endif /* 0 */
-static void __init
+static void
inithdlc(struct IsdnCardState *cs)
{
cs->bcs[0].BC_SetStack = setstack_hdlc;
@@ -727,13 +727,13 @@ AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
}
#ifdef CONFIG_PCI
-static struct pci_dev *dev_avm __initdata = NULL;
+static struct pci_dev *dev_avm __devinitdata = NULL;
#endif
#ifdef __ISAPNP__
-static struct pnp_card *pnp_avm_c __initdata = NULL;
+static struct pnp_card *pnp_avm_c __devinitdata = NULL;
#endif
-int __init
+int __devinit
setup_avm_pcipnp(struct IsdnCard *card)
{
u_int val, ver;
diff --git a/drivers/isdn/hisax/bkm_a4t.c b/drivers/isdn/hisax/bkm_a4t.c
index 3cf1f242178..87a630128a6 100644
--- a/drivers/isdn/hisax/bkm_a4t.c
+++ b/drivers/isdn/hisax/bkm_a4t.c
@@ -255,9 +255,9 @@ BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return (0);
}
-static struct pci_dev *dev_a4t __initdata = NULL;
+static struct pci_dev *dev_a4t __devinitdata = NULL;
-int __init
+int __devinit
setup_bkm_a4t(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
diff --git a/drivers/isdn/hisax/bkm_a8.c b/drivers/isdn/hisax/bkm_a8.c
index 15681f3e73b..dae090a9a48 100644
--- a/drivers/isdn/hisax/bkm_a8.c
+++ b/drivers/isdn/hisax/bkm_a8.c
@@ -260,7 +260,7 @@ BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return (0);
}
-static int __init
+static int __devinit
sct_alloc_io(u_int adr, u_int len)
{
if (!request_region(adr, len, "scitel")) {
@@ -272,16 +272,16 @@ sct_alloc_io(u_int adr, u_int len)
return(0);
}
-static struct pci_dev *dev_a8 __initdata = NULL;
-static u16 sub_vendor_id __initdata = 0;
-static u16 sub_sys_id __initdata = 0;
-static u_char pci_bus __initdata = 0;
-static u_char pci_device_fn __initdata = 0;
-static u_char pci_irq __initdata = 0;
+static struct pci_dev *dev_a8 __devinitdata = NULL;
+static u16 sub_vendor_id __devinitdata = 0;
+static u16 sub_sys_id __devinitdata = 0;
+static u_char pci_bus __devinitdata = 0;
+static u_char pci_device_fn __devinitdata = 0;
+static u_char pci_irq __devinitdata = 0;
#endif /* CONFIG_PCI */
-int __init
+int __devinit
setup_sct_quadro(struct IsdnCard *card)
{
#ifdef CONFIG_PCI
diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c
index 5333be5d2c4..e10350360f2 100644
--- a/drivers/isdn/hisax/config.c
+++ b/drivers/isdn/hisax/config.c
@@ -1875,7 +1875,7 @@ static void EChannel_proc_rcv(struct hisax_d_if *d_if)
#ifdef CONFIG_PCI
#include <linux/pci.h>
-static struct pci_device_id hisax_pci_tbl[] __initdata = {
+static struct pci_device_id hisax_pci_tbl[] __devinitdata = {
#ifdef CONFIG_HISAX_FRITZPCI
{PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1, PCI_ANY_ID, PCI_ANY_ID},
#endif
diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c
index 323a02ef384..e294fa3918f 100644
--- a/drivers/isdn/hisax/diva.c
+++ b/drivers/isdn/hisax/diva.c
@@ -887,13 +887,13 @@ Diva_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-static struct pci_dev *dev_diva __initdata = NULL;
-static struct pci_dev *dev_diva_u __initdata = NULL;
-static struct pci_dev *dev_diva201 __initdata = NULL;
-static struct pci_dev *dev_diva202 __initdata = NULL;
+static struct pci_dev *dev_diva __devinitdata = NULL;
+static struct pci_dev *dev_diva_u __devinitdata = NULL;
+static struct pci_dev *dev_diva201 __devinitdata = NULL;
+static struct pci_dev *dev_diva202 __devinitdata = NULL;
#ifdef __ISAPNP__
-static struct isapnp_device_id diva_ids[] __initdata = {
+static struct isapnp_device_id diva_ids[] __devinitdata = {
{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
(unsigned long) "Diva picola" },
@@ -915,12 +915,12 @@ static struct isapnp_device_id diva_ids[] __initdata = {
{ 0, }
};
-static struct isapnp_device_id *ipid __initdata = &diva_ids[0];
+static struct isapnp_device_id *ipid __devinitdata = &diva_ids[0];
static struct pnp_card *pnp_c __devinitdata = NULL;
#endif
-int __init
+int __devinit
setup_diva(struct IsdnCard *card)
{
int bytecnt = 8;
diff --git a/drivers/isdn/hisax/enternow_pci.c b/drivers/isdn/hisax/enternow_pci.c
index 8fcbe2e7d76..76c7d29d1b2 100644
--- a/drivers/isdn/hisax/enternow_pci.c
+++ b/drivers/isdn/hisax/enternow_pci.c
@@ -301,10 +301,10 @@ enpci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
}
-static struct pci_dev *dev_netjet __initdata = NULL;
+static struct pci_dev *dev_netjet __devinitdata = NULL;
/* called by config.c */
-int __init
+int __devinit
setup_enternow_pci(struct IsdnCard *card)
{
int bytecnt;
diff --git a/drivers/isdn/hisax/gazel.c b/drivers/isdn/hisax/gazel.c
index 3e7d9230358..fe293726777 100644
--- a/drivers/isdn/hisax/gazel.c
+++ b/drivers/isdn/hisax/gazel.c
@@ -484,7 +484,7 @@ reserve_regions(struct IsdnCard *card, struct IsdnCardState *cs)
return 1;
}
-static int __init
+static int __devinit
setup_gazelisa(struct IsdnCard *card, struct IsdnCardState *cs)
{
printk(KERN_INFO "Gazel: ISA PnP card automatic recognition\n");
@@ -532,9 +532,9 @@ setup_gazelisa(struct IsdnCard *card, struct IsdnCardState *cs)
return (0);
}
-static struct pci_dev *dev_tel __initdata = NULL;
+static struct pci_dev *dev_tel __devinitdata = NULL;
-static int __init
+static int __devinit
setup_gazelpci(struct IsdnCardState *cs)
{
u_int pci_ioaddr0 = 0, pci_ioaddr1 = 0;
@@ -621,7 +621,7 @@ setup_gazelpci(struct IsdnCardState *cs)
return (0);
}
-int __init
+int __devinit
setup_gazel(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
diff --git a/drivers/isdn/hisax/hfc4s8s_l1.c b/drivers/isdn/hisax/hfc4s8s_l1.c
index 0f967b3df79..3a5ca8a68fc 100644
--- a/drivers/isdn/hisax/hfc4s8s_l1.c
+++ b/drivers/isdn/hisax/hfc4s8s_l1.c
@@ -1703,7 +1703,7 @@ hfc4s8s_module_init(void)
/* driver module exit : */
/* release the HFC-4s/8s hardware */
/*************************************/
-static void
+static void __exit
hfc4s8s_module_exit(void)
{
pci_unregister_driver(&hfc4s8s_driver);
diff --git a/drivers/isdn/hisax/hfc_2bds0.c b/drivers/isdn/hisax/hfc_2bds0.c
index 637a261c931..6360e821472 100644
--- a/drivers/isdn/hisax/hfc_2bds0.c
+++ b/drivers/isdn/hisax/hfc_2bds0.c
@@ -1015,7 +1015,7 @@ hfc_dbusy_timer(struct IsdnCardState *cs)
{
}
-static unsigned int __init
+static unsigned int
*init_send_hfcd(int cnt)
{
int i, *send;
@@ -1030,7 +1030,7 @@ static unsigned int __init
return(send);
}
-void __init
+void
init2bds0(struct IsdnCardState *cs)
{
cs->setstack_d = setstack_hfcd;
diff --git a/drivers/isdn/hisax/hfc_2bs0.c b/drivers/isdn/hisax/hfc_2bs0.c
index c964539cc43..d0520ad3067 100644
--- a/drivers/isdn/hisax/hfc_2bs0.c
+++ b/drivers/isdn/hisax/hfc_2bs0.c
@@ -551,7 +551,7 @@ setstack_hfc(struct PStack *st, struct BCState *bcs)
return (0);
}
-static void __init
+static void
init_send(struct BCState *bcs)
{
int i;
@@ -565,7 +565,7 @@ init_send(struct BCState *bcs)
bcs->hw.hfc.send[i] = 0x1fff;
}
-void __init
+void
inithfc(struct IsdnCardState *cs)
{
init_send(&cs->bcs[0]);
diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c
index 7241e73879b..1df60ca9481 100644
--- a/drivers/isdn/hisax/hfc_pci.c
+++ b/drivers/isdn/hisax/hfc_pci.c
@@ -1581,7 +1581,7 @@ hfcpci_bh(struct IsdnCardState *cs)
/********************************/
/* called for card init message */
/********************************/
-static void __init
+static void
inithfcpci(struct IsdnCardState *cs)
{
cs->bcs[0].BC_SetStack = setstack_2b;
@@ -1638,11 +1638,11 @@ hfcpci_card_msg(struct IsdnCardState *cs, int mt, void *arg)
/* this variable is used as card index when more than one cards are present */
-static struct pci_dev *dev_hfcpci __initdata = NULL;
+static struct pci_dev *dev_hfcpci __devinitdata = NULL;
#endif /* CONFIG_PCI */
-int __init
+int __devinit
setup_hfcpci(struct IsdnCard *card)
{
u_long flags;
diff --git a/drivers/isdn/hisax/hfcscard.c b/drivers/isdn/hisax/hfcscard.c
index 86ab1c13f6b..4e7f472877e 100644
--- a/drivers/isdn/hisax/hfcscard.c
+++ b/drivers/isdn/hisax/hfcscard.c
@@ -139,7 +139,7 @@ hfcs_card_msg(struct IsdnCardState *cs, int mt, void *arg)
}
#ifdef __ISAPNP__
-static struct isapnp_device_id hfc_ids[] __initdata = {
+static struct isapnp_device_id hfc_ids[] __devinitdata = {
{ ISAPNP_VENDOR('A', 'N', 'X'), ISAPNP_FUNCTION(0x1114),
ISAPNP_VENDOR('A', 'N', 'X'), ISAPNP_FUNCTION(0x1114),
(unsigned long) "Acer P10" },
@@ -164,11 +164,11 @@ static struct isapnp_device_id hfc_ids[] __initdata = {
{ 0, }
};
-static struct isapnp_device_id *ipid __initdata = &hfc_ids[0];
+static struct isapnp_device_id *ipid __devinitdata = &hfc_ids[0];
static struct pnp_card *pnp_c __devinitdata = NULL;
#endif
-int __init
+int __devinit
setup_hfcs(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
diff --git a/drivers/isdn/hisax/icc.c b/drivers/isdn/hisax/icc.c
index c615752b96a..2cf7b665609 100644
--- a/drivers/isdn/hisax/icc.c
+++ b/drivers/isdn/hisax/icc.c
@@ -24,10 +24,10 @@
#define DBUSY_TIMER_VALUE 80
#define ARCOFI_USE 0
-static char *ICCVer[] __initdata =
+static char *ICCVer[] =
{"2070 A1/A3", "2070 B1", "2070 B2/B3", "2070 V2.4"};
-void __init
+void
ICCVersion(struct IsdnCardState *cs, char *s)
{
int val;
@@ -613,7 +613,7 @@ dbusy_timer_handler(struct IsdnCardState *cs)
}
}
-void __init
+void
initicc(struct IsdnCardState *cs)
{
cs->setstack_d = setstack_icc;
@@ -646,7 +646,7 @@ initicc(struct IsdnCardState *cs)
ph_command(cs, ICC_CMD_DI);
}
-void __init
+void
clear_pending_icc_ints(struct IsdnCardState *cs)
{
int val, eval;
diff --git a/drivers/isdn/hisax/icc.h b/drivers/isdn/hisax/icc.h
index b3bb3d5de53..e7f593967e4 100644
--- a/drivers/isdn/hisax/icc.h
+++ b/drivers/isdn/hisax/icc.h
@@ -65,7 +65,7 @@
#define ICC_IND_AIL 0xE
#define ICC_IND_DC 0xF
-extern void __init ICCVersion(struct IsdnCardState *cs, char *s);
+extern void ICCVersion(struct IsdnCardState *cs, char *s);
extern void initicc(struct IsdnCardState *cs);
extern void icc_interrupt(struct IsdnCardState *cs, u_char val);
extern void clear_pending_icc_ints(struct IsdnCardState *cs);
diff --git a/drivers/isdn/hisax/ipacx.c b/drivers/isdn/hisax/ipacx.c
index df5fc92a89b..00afd553890 100644
--- a/drivers/isdn/hisax/ipacx.c
+++ b/drivers/isdn/hisax/ipacx.c
@@ -38,8 +38,8 @@ static void dbusy_timer_handler(struct IsdnCardState *cs);
static void dch_empty_fifo(struct IsdnCardState *cs, int count);
static void dch_fill_fifo(struct IsdnCardState *cs);
static inline void dch_int(struct IsdnCardState *cs);
-static void __devinit dch_setstack(struct PStack *st, struct IsdnCardState *cs);
-static void __devinit dch_init(struct IsdnCardState *cs);
+static void dch_setstack(struct PStack *st, struct IsdnCardState *cs);
+static void dch_init(struct IsdnCardState *cs);
static void bch_l2l1(struct PStack *st, int pr, void *arg);
static void bch_empty_fifo(struct BCState *bcs, int count);
static void bch_fill_fifo(struct BCState *bcs);
@@ -48,8 +48,8 @@ static void bch_mode(struct BCState *bcs, int mode, int bc);
static void bch_close_state(struct BCState *bcs);
static int bch_open_state(struct IsdnCardState *cs, struct BCState *bcs);
static int bch_setstack(struct PStack *st, struct BCState *bcs);
-static void __devinit bch_init(struct IsdnCardState *cs, int hscx);
-static void __init clear_pending_ints(struct IsdnCardState *cs);
+static void bch_init(struct IsdnCardState *cs, int hscx);
+static void clear_pending_ints(struct IsdnCardState *cs);
//----------------------------------------------------------
// Issue Layer 1 command to chip
@@ -408,7 +408,7 @@ dch_int(struct IsdnCardState *cs)
//----------------------------------------------------------
//----------------------------------------------------------
-static void __devinit
+static void
dch_setstack(struct PStack *st, struct IsdnCardState *cs)
{
st->l1.l1hw = dch_l2l1;
@@ -416,7 +416,7 @@ dch_setstack(struct PStack *st, struct IsdnCardState *cs)
//----------------------------------------------------------
//----------------------------------------------------------
-static void __devinit
+static void
dch_init(struct IsdnCardState *cs)
{
printk(KERN_INFO "HiSax: IPACX ISDN driver v0.1.0\n");
@@ -823,7 +823,7 @@ bch_setstack(struct PStack *st, struct BCState *bcs)
//----------------------------------------------------------
//----------------------------------------------------------
-static void __devinit
+static void
bch_init(struct IsdnCardState *cs, int hscx)
{
cs->bcs[hscx].BC_SetStack = bch_setstack;
@@ -861,7 +861,7 @@ interrupt_ipacx(struct IsdnCardState *cs)
//----------------------------------------------------------
// Clears chip interrupt status
//----------------------------------------------------------
-static void __init
+static void
clear_pending_ints(struct IsdnCardState *cs)
{
int ista;
@@ -883,7 +883,7 @@ clear_pending_ints(struct IsdnCardState *cs)
// Does chip configuration work
// Work to do depends on bit mask in part
//----------------------------------------------------------
-void __init
+void
init_ipacx(struct IsdnCardState *cs, int part)
{
if (part &1) { // initialise chip
diff --git a/drivers/isdn/hisax/isurf.c b/drivers/isdn/hisax/isurf.c
index 33747afc984..715a1a8cd69 100644
--- a/drivers/isdn/hisax/isurf.c
+++ b/drivers/isdn/hisax/isurf.c
@@ -196,10 +196,10 @@ isurf_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) {
}
#ifdef __ISAPNP__
-static struct pnp_card *pnp_c __initdata = NULL;
+static struct pnp_card *pnp_c __devinitdata = NULL;
#endif
-int __init
+int __devinit
setup_isurf(struct IsdnCard *card)
{
int ver;
diff --git a/drivers/isdn/hisax/ix1_micro.c b/drivers/isdn/hisax/ix1_micro.c
index 908a7e14442..39717506c67 100644
--- a/drivers/isdn/hisax/ix1_micro.c
+++ b/drivers/isdn/hisax/ix1_micro.c
@@ -210,7 +210,7 @@ ix1_card_msg(struct IsdnCardState *cs, int mt, void *arg)
}
#ifdef __ISAPNP__
-static struct isapnp_device_id itk_ids[] __initdata = {
+static struct isapnp_device_id itk_ids[] __devinitdata = {
{ ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x25),
ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x25),
(unsigned long) "ITK micro 2" },
@@ -220,12 +220,12 @@ static struct isapnp_device_id itk_ids[] __initdata = {
{ 0, }
};
-static struct isapnp_device_id *ipid __initdata = &itk_ids[0];
+static struct isapnp_device_id *ipid __devinitdata = &itk_ids[0];
static struct pnp_card *pnp_c __devinitdata = NULL;
#endif
-int __init
+int __devinit
setup_ix1micro(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
diff --git a/drivers/isdn/hisax/jade.c b/drivers/isdn/hisax/jade.c
index 2659fecc267..43d61d1bc5b 100644
--- a/drivers/isdn/hisax/jade.c
+++ b/drivers/isdn/hisax/jade.c
@@ -19,7 +19,7 @@
#include <linux/interrupt.h>
-int __init
+int
JadeVersion(struct IsdnCardState *cs, char *s)
{
int ver,i;
@@ -253,7 +253,7 @@ setstack_jade(struct PStack *st, struct BCState *bcs)
return (0);
}
-void __init
+void
clear_pending_jade_ints(struct IsdnCardState *cs)
{
int val;
@@ -279,7 +279,7 @@ clear_pending_jade_ints(struct IsdnCardState *cs)
cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR, 0xF8);
}
-void __init
+void
initjade(struct IsdnCardState *cs)
{
cs->bcs[0].BC_SetStack = setstack_jade;
diff --git a/drivers/isdn/hisax/mic.c b/drivers/isdn/hisax/mic.c
index fe11f226b28..8c82519593a 100644
--- a/drivers/isdn/hisax/mic.c
+++ b/drivers/isdn/hisax/mic.c
@@ -189,7 +189,7 @@ mic_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-int __init
+int __devinit
setup_mic(struct IsdnCard *card)
{
int bytecnt;
diff --git a/drivers/isdn/hisax/netjet.c b/drivers/isdn/hisax/netjet.c
index 47a47ef0968..38f648f9b0e 100644
--- a/drivers/isdn/hisax/netjet.c
+++ b/drivers/isdn/hisax/netjet.c
@@ -909,7 +909,7 @@ setstack_tiger(struct PStack *st, struct BCState *bcs)
}
-void __init
+void
inittiger(struct IsdnCardState *cs)
{
if (!(cs->bcs[0].hw.tiger.send = kmalloc(NETJET_DMA_TXSIZE * sizeof(unsigned int),
diff --git a/drivers/isdn/hisax/niccy.c b/drivers/isdn/hisax/niccy.c
index 79a97b1c381..489022bdef7 100644
--- a/drivers/isdn/hisax/niccy.c
+++ b/drivers/isdn/hisax/niccy.c
@@ -232,12 +232,12 @@ niccy_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-static struct pci_dev *niccy_dev __initdata = NULL;
+static struct pci_dev *niccy_dev __devinitdata = NULL;
#ifdef __ISAPNP__
static struct pnp_card *pnp_c __devinitdata = NULL;
#endif
-int __init
+int __devinit
setup_niccy(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
diff --git a/drivers/isdn/hisax/nj_s.c b/drivers/isdn/hisax/nj_s.c
index e5b900a6fa0..80025fd890f 100644
--- a/drivers/isdn/hisax/nj_s.c
+++ b/drivers/isdn/hisax/nj_s.c
@@ -148,9 +148,9 @@ NETjet_S_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-static struct pci_dev *dev_netjet __initdata = NULL;
+static struct pci_dev *dev_netjet __devinitdata = NULL;
-int __init
+int __devinit
setup_netjet_s(struct IsdnCard *card)
{
int bytecnt,cfg;
diff --git a/drivers/isdn/hisax/nj_u.c b/drivers/isdn/hisax/nj_u.c
index 7002b09936d..37497162d53 100644
--- a/drivers/isdn/hisax/nj_u.c
+++ b/drivers/isdn/hisax/nj_u.c
@@ -128,9 +128,9 @@ NETjet_U_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-static struct pci_dev *dev_netjet __initdata = NULL;
+static struct pci_dev *dev_netjet __devinitdata = NULL;
-int __init
+int __devinit
setup_netjet_u(struct IsdnCard *card)
{
int bytecnt;
diff --git a/drivers/isdn/hisax/s0box.c b/drivers/isdn/hisax/s0box.c
index 7b63085ea6e..e76042d323e 100644
--- a/drivers/isdn/hisax/s0box.c
+++ b/drivers/isdn/hisax/s0box.c
@@ -211,7 +211,7 @@ S0Box_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-int __init
+int __devinit
setup_s0box(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
diff --git a/drivers/isdn/hisax/saphir.c b/drivers/isdn/hisax/saphir.c
index 821776e1561..d943d365890 100644
--- a/drivers/isdn/hisax/saphir.c
+++ b/drivers/isdn/hisax/saphir.c
@@ -241,7 +241,7 @@ saphir_card_msg(struct IsdnCardState *cs, int mt, void *arg)
}
-int __init
+int __devinit
setup_saphir(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
diff --git a/drivers/isdn/hisax/sportster.c b/drivers/isdn/hisax/sportster.c
index cdf35dc564c..a49b694eb73 100644
--- a/drivers/isdn/hisax/sportster.c
+++ b/drivers/isdn/hisax/sportster.c
@@ -184,7 +184,7 @@ Sportster_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-static int __init
+static int __devinit
get_io_range(struct IsdnCardState *cs)
{
int i, j, adr;
@@ -209,7 +209,7 @@ get_io_range(struct IsdnCardState *cs)
}
}
-int __init
+int __devinit
setup_sportster(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
diff --git a/drivers/isdn/hisax/teleint.c b/drivers/isdn/hisax/teleint.c
index a2b1816af37..e94dc6f5bd6 100644
--- a/drivers/isdn/hisax/teleint.c
+++ b/drivers/isdn/hisax/teleint.c
@@ -261,7 +261,7 @@ TeleInt_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-int __init
+int __devinit
setup_TeleInt(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
diff --git a/drivers/isdn/hisax/teles0.c b/drivers/isdn/hisax/teles0.c
index 2b7df8f9823..f94af0930a1 100644
--- a/drivers/isdn/hisax/teles0.c
+++ b/drivers/isdn/hisax/teles0.c
@@ -265,7 +265,7 @@ Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-int __init
+int __devinit
setup_teles0(struct IsdnCard *card)
{
u_char val;
diff --git a/drivers/isdn/hisax/telespci.c b/drivers/isdn/hisax/telespci.c
index 9382cdf04d8..dca446865f2 100644
--- a/drivers/isdn/hisax/telespci.c
+++ b/drivers/isdn/hisax/telespci.c
@@ -284,9 +284,9 @@ TelesPCI_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-static struct pci_dev *dev_tel __initdata = NULL;
+static struct pci_dev *dev_tel __devinitdata = NULL;
-int __init
+int __devinit
setup_telespci(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c
index 6c68419c05f..0595293b865 100644
--- a/drivers/isdn/hisax/w6692.c
+++ b/drivers/isdn/hisax/w6692.c
@@ -44,11 +44,11 @@ static const char *w6692_revision = "$Revision: 1.18.2.4 $";
#define DBUSY_TIMER_VALUE 80
-static char *W6692Ver[] __initdata =
+static char *W6692Ver[] =
{"W6692 V00", "W6692 V01", "W6692 V10",
"W6692 V11"};
-static void __init
+static void
W6692Version(struct IsdnCardState *cs, char *s)
{
int val;
@@ -897,7 +897,7 @@ static void resetW6692(struct IsdnCardState *cs)
}
}
-static void __init initW6692(struct IsdnCardState *cs, int part)
+static void initW6692(struct IsdnCardState *cs, int part)
{
if (part & 1) {
cs->setstack_d = setstack_W6692;
@@ -992,9 +992,9 @@ w6692_card_msg(struct IsdnCardState *cs, int mt, void *arg)
static int id_idx ;
-static struct pci_dev *dev_w6692 __initdata = NULL;
+static struct pci_dev *dev_w6692 __devinitdata = NULL;
-int __init
+int __devinit
setup_w6692(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
index 9f6c6375ff7..c3d79eef9e3 100644
--- a/drivers/isdn/i4l/isdn_common.c
+++ b/drivers/isdn/i4l/isdn_common.c
@@ -1059,7 +1059,7 @@ isdn_info_update(void)
static ssize_t
isdn_read(struct file *file, char __user *buf, size_t count, loff_t * off)
{
- uint minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ uint minor = iminor(file->f_dentry->d_inode);
int len = 0;
int drvidx;
int chidx;
@@ -1163,7 +1163,7 @@ isdn_read(struct file *file, char __user *buf, size_t count, loff_t * off)
static ssize_t
isdn_write(struct file *file, const char __user *buf, size_t count, loff_t * off)
{
- uint minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ uint minor = iminor(file->f_dentry->d_inode);
int drvidx;
int chidx;
int retval;
@@ -1225,7 +1225,7 @@ static unsigned int
isdn_poll(struct file *file, poll_table * wait)
{
unsigned int mask = 0;
- unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ unsigned int minor = iminor(file->f_dentry->d_inode);
int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
lock_kernel();
@@ -1266,7 +1266,7 @@ isdn_poll(struct file *file, poll_table * wait)
static int
isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
{
- uint minor = MINOR(inode->i_rdev);
+ uint minor = iminor(inode);
isdn_ctrl c;
int drvidx;
int chidx;
@@ -1717,7 +1717,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
static int
isdn_open(struct inode *ino, struct file *filep)
{
- uint minor = MINOR(ino->i_rdev);
+ uint minor = iminor(ino);
int drvidx;
int chidx;
int retval = -ENODEV;
@@ -1779,7 +1779,7 @@ isdn_open(struct inode *ino, struct file *filep)
static int
isdn_close(struct inode *ino, struct file *filep)
{
- uint minor = MINOR(ino->i_rdev);
+ uint minor = iminor(ino);
lock_kernel();
if (minor == ISDN_MINOR_STATUS) {
diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c
index 29e7667ec96..119412d6bd1 100644
--- a/drivers/isdn/i4l/isdn_ppp.c
+++ b/drivers/isdn/i4l/isdn_ppp.c
@@ -667,7 +667,7 @@ isdn_ppp_poll(struct file *file, poll_table * wait)
if (is->debug & 0x2)
printk(KERN_DEBUG "isdn_ppp_poll: minor: %d\n",
- MINOR(file->f_dentry->d_inode->i_rdev));
+ iminor(file->f_dentry->d_inode));
/* just registers wait_queue hook. This doesn't really wait. */
poll_wait(file, &is->wq, wait);
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 96509989e92..9c39b98d5a5 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -69,6 +69,13 @@ config LEDS_AMS_DELTA
help
This option enables support for the LEDs on Amstrad Delta (E3).
+config LEDS_NET48XX
+ tristate "LED Support for Soekris net48xx series Error LED"
+ depends on LEDS_CLASS && SCx200_GPIO
+ help
+ This option enables support for the Soekris net4801 and net4826 error
+ LED.
+
comment "LED Triggers"
config LEDS_TRIGGERS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 88d3b6eaa6a..6aa2aed7539 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_LEDS_IXP4XX) += leds-ixp4xx-gpio.o
obj-$(CONFIG_LEDS_TOSA) += leds-tosa.o
obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o
obj-$(CONFIG_LEDS_AMS_DELTA) += leds-ams-delta.o
+obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o
# LED Triggers
obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o
diff --git a/drivers/leds/leds-net48xx.c b/drivers/leds/leds-net48xx.c
new file mode 100644
index 00000000000..713c4a8aa77
--- /dev/null
+++ b/drivers/leds/leds-net48xx.c
@@ -0,0 +1,116 @@
+/*
+ * LEDs driver for Soekris net48xx
+ *
+ * Copyright (C) 2006 Chris Boot <bootc@bootc.net>
+ *
+ * Based on leds-ams-delta.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/err.h>
+#include <asm/io.h>
+#include <linux/scx200_gpio.h>
+
+#define DRVNAME "net48xx-led"
+#define NET48XX_ERROR_LED_GPIO 20
+
+static struct platform_device *pdev;
+
+static void net48xx_error_led_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ if (value)
+ scx200_gpio_set_high(NET48XX_ERROR_LED_GPIO);
+ else
+ scx200_gpio_set_low(NET48XX_ERROR_LED_GPIO);
+}
+
+static struct led_classdev net48xx_error_led = {
+ .name = "net48xx:error",
+ .brightness_set = net48xx_error_led_set,
+};
+
+#ifdef CONFIG_PM
+static int net48xx_led_suspend(struct platform_device *dev,
+ pm_message_t state)
+{
+ led_classdev_suspend(&net48xx_error_led);
+ return 0;
+}
+
+static int net48xx_led_resume(struct platform_device *dev)
+{
+ led_classdev_resume(&net48xx_error_led);
+ return 0;
+}
+#else
+#define net48xx_led_suspend NULL
+#define net48xx_led_resume NULL
+#endif
+
+static int net48xx_led_probe(struct platform_device *pdev)
+{
+ return led_classdev_register(&pdev->dev, &net48xx_error_led);
+}
+
+static int net48xx_led_remove(struct platform_device *pdev)
+{
+ led_classdev_unregister(&net48xx_error_led);
+ return 0;
+}
+
+static struct platform_driver net48xx_led_driver = {
+ .probe = net48xx_led_probe,
+ .remove = net48xx_led_remove,
+ .suspend = net48xx_led_suspend,
+ .resume = net48xx_led_resume,
+ .driver = {
+ .name = DRVNAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init net48xx_led_init(void)
+{
+ int ret;
+
+ if (!scx200_gpio_present()) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ ret = platform_driver_register(&net48xx_led_driver);
+ if (ret < 0)
+ goto out;
+
+ pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0);
+ if (IS_ERR(pdev)) {
+ ret = PTR_ERR(pdev);
+ platform_driver_unregister(&net48xx_led_driver);
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+static void __exit net48xx_led_exit(void)
+{
+ platform_device_unregister(pdev);
+ platform_driver_unregister(&net48xx_led_driver);
+}
+
+module_init(net48xx_led_init);
+module_exit(net48xx_led_exit);
+
+MODULE_AUTHOR("Chris Boot <bootc@bootc.net>");
+MODULE_DESCRIPTION("Soekris net48xx LED driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index 54f3f6b94ef..d5d649f5ccd 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -90,6 +90,15 @@ config ADB_PMU_LED
and the ide-disk LED trigger and configure appropriately through
sysfs.
+config ADB_PMU_LED_IDE
+ bool "Use front LED as IDE LED by default"
+ depends on ADB_PMU_LED
+ select LEDS_TRIGGERS
+ select LEDS_TRIGGER_IDE_DISK
+ help
+ This option makes the front LED default to the IDE trigger
+ so that it blinks on IDE activity.
+
config PMAC_SMU
bool "Support for SMU based PowerMacs"
depends on PPC_PMAC64
@@ -100,7 +109,7 @@ config PMAC_SMU
config PMAC_APM_EMU
tristate "APM emulation"
- depends on PPC_PMAC && PPC32 && PM
+ depends on PPC_PMAC && PPC32 && PM && ADB_PMU
config PMAC_MEDIABAY
bool "Support PowerBook hotswap media bay"
@@ -113,7 +122,8 @@ config PMAC_MEDIABAY
config PMAC_BACKLIGHT
bool "Backlight control for LCD screens"
- depends on ADB_PMU && (BROKEN || !PPC64)
+ depends on ADB_PMU && FB = y && (BROKEN || !PPC64)
+ select FB_BACKLIGHT
help
Say Y here to enable Macintosh specific extensions of the generic
backlight code. With this enabled, the brightness keys on older
diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c
index 545be1ed692..c69d23bb255 100644
--- a/drivers/macintosh/adbhid.c
+++ b/drivers/macintosh/adbhid.c
@@ -45,14 +45,11 @@
#include <linux/pmu.h>
#include <asm/machdep.h>
+#include <asm/backlight.h>
#ifdef CONFIG_PPC_PMAC
#include <asm/pmac_feature.h>
#endif
-#ifdef CONFIG_PMAC_BACKLIGHT
-#include <asm/backlight.h>
-#endif
-
MODULE_AUTHOR("Franz Sirl <Franz.Sirl-kernel@lauterbach.com>");
#define KEYB_KEYREG 0 /* register # for key up/down data */
@@ -237,11 +234,6 @@ static struct adb_ids keyboard_ids;
static struct adb_ids mouse_ids;
static struct adb_ids buttons_ids;
-#ifdef CONFIG_PMAC_BACKLIGHT
-/* Exported to via-pmu.c */
-int disable_kernel_backlight = 0;
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
/* Kind of keyboard, see Apple technote 1152 */
#define ADB_KEYBOARD_UNKNOWN 0
#define ADB_KEYBOARD_ANSI 0x0100
@@ -527,7 +519,7 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto
case 0xa: /* brightness decrease */
#ifdef CONFIG_PMAC_BACKLIGHT
- if (!disable_kernel_backlight && down)
+ if (down)
pmac_backlight_key_down();
#endif
input_report_key(adbhid[id]->input, KEY_BRIGHTNESSDOWN, down);
@@ -535,7 +527,7 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto
case 0x9: /* brightness increase */
#ifdef CONFIG_PMAC_BACKLIGHT
- if (!disable_kernel_backlight && down)
+ if (down)
pmac_backlight_key_up();
#endif
input_report_key(adbhid[id]->input, KEY_BRIGHTNESSUP, down);
diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c
index 80c0c665b5f..82657bc86d1 100644
--- a/drivers/macintosh/macio_asic.c
+++ b/drivers/macintosh/macio_asic.c
@@ -330,7 +330,7 @@ static void macio_create_fixup_irq(struct macio_dev *dev, int index,
{
unsigned int irq;
- irq = irq_create_mapping(NULL, line, 0);
+ irq = irq_create_mapping(NULL, line);
if (irq != NO_IRQ) {
dev->interrupt[index].start = irq;
dev->interrupt[index].flags = IORESOURCE_IRQ;
diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c
index f139a74696f..00ef4689814 100644
--- a/drivers/macintosh/smu.c
+++ b/drivers/macintosh/smu.c
@@ -75,9 +75,11 @@ struct smu_device {
struct of_device *of_dev;
int doorbell; /* doorbell gpio */
u32 __iomem *db_buf; /* doorbell buffer */
- int db_irq;
+ struct device_node *db_node;
+ unsigned int db_irq;
int msg;
- int msg_irq;
+ struct device_node *msg_node;
+ unsigned int msg_irq;
struct smu_cmd_buf *cmd_buf; /* command buffer virtual */
u32 cmd_buf_abs; /* command buffer absolute */
struct list_head cmd_list;
@@ -93,6 +95,7 @@ struct smu_device {
*/
static struct smu_device *smu;
static DEFINE_MUTEX(smu_part_access);
+static int smu_irq_inited;
static void smu_i2c_retry(unsigned long data);
@@ -257,6 +260,10 @@ int smu_queue_cmd(struct smu_cmd *cmd)
smu_start_cmd();
spin_unlock_irqrestore(&smu->lock, flags);
+ /* Workaround for early calls when irq isn't available */
+ if (!smu_irq_inited || smu->db_irq == NO_IRQ)
+ smu_spinwait_cmd(cmd);
+
return 0;
}
EXPORT_SYMBOL(smu_queue_cmd);
@@ -478,14 +485,15 @@ int __init smu_init (void)
smu->cmd_buf_abs = (u32)smu_cmdbuf_abs;
smu->cmd_buf = (struct smu_cmd_buf *)abs_to_virt(smu_cmdbuf_abs);
- np = of_find_node_by_name(NULL, "smu-doorbell");
- if (np == NULL) {
+ smu->db_node = of_find_node_by_name(NULL, "smu-doorbell");
+ if (smu->db_node == NULL) {
printk(KERN_ERR "SMU: Can't find doorbell GPIO !\n");
goto fail;
}
- data = (u32 *)get_property(np, "reg", NULL);
+ data = (u32 *)get_property(smu->db_node, "reg", NULL);
if (data == NULL) {
- of_node_put(np);
+ of_node_put(smu->db_node);
+ smu->db_node = NULL;
printk(KERN_ERR "SMU: Can't find doorbell GPIO address !\n");
goto fail;
}
@@ -497,25 +505,21 @@ int __init smu_init (void)
smu->doorbell = *data;
if (smu->doorbell < 0x50)
smu->doorbell += 0x50;
- smu->db_irq = irq_of_parse_and_map(np, 0);
-
- of_node_put(np);
/* Now look for the smu-interrupt GPIO */
do {
- np = of_find_node_by_name(NULL, "smu-interrupt");
- if (np == NULL)
+ smu->msg_node = of_find_node_by_name(NULL, "smu-interrupt");
+ if (smu->msg_node == NULL)
break;
- data = (u32 *)get_property(np, "reg", NULL);
+ data = (u32 *)get_property(smu->msg_node, "reg", NULL);
if (data == NULL) {
- of_node_put(np);
+ of_node_put(smu->msg_node);
+ smu->msg_node = NULL;
break;
}
smu->msg = *data;
if (smu->msg < 0x50)
smu->msg += 0x50;
- smu->msg_irq = irq_of_parse_and_map(np, 0);
- of_node_put(np);
} while(0);
/* Doorbell buffer is currently hard-coded, I didn't find a proper
@@ -547,6 +551,19 @@ static int smu_late_init(void)
smu->i2c_timer.function = smu_i2c_retry;
smu->i2c_timer.data = (unsigned long)smu;
+ if (smu->db_node) {
+ smu->db_irq = irq_of_parse_and_map(smu->db_node, 0);
+ if (smu->db_irq == NO_IRQ)
+ printk(KERN_ERR "smu: failed to map irq for node %s\n",
+ smu->db_node->full_name);
+ }
+ if (smu->msg_node) {
+ smu->msg_irq = irq_of_parse_and_map(smu->msg_node, 0);
+ if (smu->msg_irq == NO_IRQ)
+ printk(KERN_ERR "smu: failed to map irq for node %s\n",
+ smu->msg_node->full_name);
+ }
+
/*
* Try to request the interrupts
*/
@@ -571,6 +588,7 @@ static int smu_late_init(void)
}
}
+ smu_irq_inited = 1;
return 0;
}
/* This has to be before arch_initcall as the low i2c stuff relies on the
@@ -742,6 +760,11 @@ static void smu_i2c_low_completion(struct smu_cmd *scmd, void *misc)
if (fail && --cmd->retries > 0) {
DPRINTK("SMU: i2c failure, starting timer...\n");
BUG_ON(cmd != smu->cmd_i2c_cur);
+ if (!smu_irq_inited) {
+ mdelay(5);
+ smu_i2c_retry(0);
+ return;
+ }
mod_timer(&smu->i2c_timer, jiffies + msecs_to_jiffies(5));
return;
}
diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c
index c1fe0b368f7..20bf67244e2 100644
--- a/drivers/macintosh/therm_pm72.c
+++ b/drivers/macintosh/therm_pm72.c
@@ -95,6 +95,17 @@
* - Use min/max macros here or there
* - Latest darwin updated U3H min fan speed to 20% PWM
*
+ * July. 06, 2006 : 1.3
+ * - Fix setting of RPM fans on Xserve G5 (they were going too fast)
+ * - Add missing slots fan control loop for Xserve G5
+ * - Lower fixed slots fan speed from 50% to 40% on desktop G5s. We
+ * still can't properly implement the control loop for these, so let's
+ * reduce the noise a little bit, it appears that 40% still gives us
+ * a pretty good air flow
+ * - Add code to "tickle" the FCU regulary so it doesn't think that
+ * we are gone while in fact, the machine just didn't need any fan
+ * speed change lately
+ *
*/
#include <linux/types.h>
@@ -121,7 +132,7 @@
#include "therm_pm72.h"
-#define VERSION "1.2b2"
+#define VERSION "1.3"
#undef DEBUG
@@ -146,6 +157,7 @@ static struct basckside_pid_params backside_params;
static struct backside_pid_state backside_state;
static struct drives_pid_state drives_state;
static struct dimm_pid_state dimms_state;
+static struct slots_pid_state slots_state;
static int state;
static int cpu_count;
static int cpu_pid_type;
@@ -154,7 +166,8 @@ static struct completion ctrl_complete;
static int critical_state;
static int rackmac;
static s32 dimm_output_clamp;
-
+static int fcu_rpm_shift;
+static int fcu_tickle_ticks;
static DECLARE_MUTEX(driver_lock);
/*
@@ -495,13 +508,20 @@ static int start_fcu(void)
rc = fan_write_reg(0x2e, &buf, 1);
if (rc < 0)
return -EIO;
+ rc = fan_read_reg(0, &buf, 1);
+ if (rc < 0)
+ return -EIO;
+ fcu_rpm_shift = (buf == 1) ? 2 : 3;
+ printk(KERN_DEBUG "FCU Initialized, RPM fan shift is %d\n",
+ fcu_rpm_shift);
+
return 0;
}
static int set_rpm_fan(int fan_index, int rpm)
{
unsigned char buf[2];
- int rc, id;
+ int rc, id, min, max;
if (fcu_fans[fan_index].type != FCU_FAN_RPM)
return -EINVAL;
@@ -509,12 +529,15 @@ static int set_rpm_fan(int fan_index, int rpm)
if (id == FCU_FAN_ABSENT_ID)
return -EINVAL;
- if (rpm < 300)
- rpm = 300;
- else if (rpm > 8191)
- rpm = 8191;
- buf[0] = rpm >> 5;
- buf[1] = rpm << 3;
+ min = 2400 >> fcu_rpm_shift;
+ max = 56000 >> fcu_rpm_shift;
+
+ if (rpm < min)
+ rpm = min;
+ else if (rpm > max)
+ rpm = max;
+ buf[0] = rpm >> (8 - fcu_rpm_shift);
+ buf[1] = rpm << fcu_rpm_shift;
rc = fan_write_reg(0x10 + (id * 2), buf, 2);
if (rc < 0)
return -EIO;
@@ -551,7 +574,7 @@ static int get_rpm_fan(int fan_index, int programmed)
if (rc != 2)
return -EIO;
- return (buf[0] << 5) | buf[1] >> 3;
+ return (buf[0] << (8 - fcu_rpm_shift)) | buf[1] >> fcu_rpm_shift;
}
static int set_pwm_fan(int fan_index, int pwm)
@@ -609,6 +632,26 @@ static int get_pwm_fan(int fan_index)
return (buf[0] * 1000) / 2559;
}
+static void tickle_fcu(void)
+{
+ int pwm;
+
+ pwm = get_pwm_fan(SLOTS_FAN_PWM_INDEX);
+
+ DBG("FCU Tickle, slots fan is: %d\n", pwm);
+ if (pwm < 0)
+ pwm = 100;
+
+ if (!rackmac) {
+ pwm = SLOTS_FAN_DEFAULT_PWM;
+ } else if (pwm < SLOTS_PID_OUTPUT_MIN)
+ pwm = SLOTS_PID_OUTPUT_MIN;
+
+ /* That is hopefully enough to make the FCU happy */
+ set_pwm_fan(SLOTS_FAN_PWM_INDEX, pwm);
+}
+
+
/*
* Utility routine to read the CPU calibration EEPROM data
* from the device-tree
@@ -715,6 +758,9 @@ BUILD_SHOW_FUNC_INT(backside_fan_pwm, backside_state.pwm)
BUILD_SHOW_FUNC_FIX(drives_temperature, drives_state.last_temp)
BUILD_SHOW_FUNC_INT(drives_fan_rpm, drives_state.rpm)
+BUILD_SHOW_FUNC_FIX(slots_temperature, slots_state.last_temp)
+BUILD_SHOW_FUNC_INT(slots_fan_pwm, slots_state.pwm)
+
BUILD_SHOW_FUNC_FIX(dimms_temperature, dimms_state.last_temp)
static DEVICE_ATTR(cpu0_temperature,S_IRUGO,show_cpu0_temperature,NULL);
@@ -735,6 +781,9 @@ static DEVICE_ATTR(backside_fan_pwm,S_IRUGO,show_backside_fan_pwm,NULL);
static DEVICE_ATTR(drives_temperature,S_IRUGO,show_drives_temperature,NULL);
static DEVICE_ATTR(drives_fan_rpm,S_IRUGO,show_drives_fan_rpm,NULL);
+static DEVICE_ATTR(slots_temperature,S_IRUGO,show_slots_temperature,NULL);
+static DEVICE_ATTR(slots_fan_pwm,S_IRUGO,show_slots_fan_pwm,NULL);
+
static DEVICE_ATTR(dimms_temperature,S_IRUGO,show_dimms_temperature,NULL);
/*
@@ -1076,6 +1125,9 @@ static void do_monitor_cpu_rack(struct cpu_pid_state *state)
fan_min = dimm_output_clamp;
fan_min = max(fan_min, (int)state->mpu.rminn_intake_fan);
+ DBG(" CPU min mpu = %d, min dimm = %d\n",
+ state->mpu.rminn_intake_fan, dimm_output_clamp);
+
state->rpm = max(state->rpm, (int)fan_min);
state->rpm = min(state->rpm, (int)state->mpu.rmaxn_intake_fan);
state->intake_rpm = state->rpm;
@@ -1374,7 +1426,8 @@ static void do_monitor_drives(struct drives_pid_state *state)
DBG(" current rpm: %d\n", state->rpm);
/* Get some sensor readings */
- temp = le16_to_cpu(i2c_smbus_read_word_data(state->monitor, DS1775_TEMP)) << 8;
+ temp = le16_to_cpu(i2c_smbus_read_word_data(state->monitor,
+ DS1775_TEMP)) << 8;
state->last_temp = temp;
DBG(" temp: %d.%03d, target: %d.%03d\n", FIX32TOPRINT(temp),
FIX32TOPRINT(DRIVES_PID_INPUT_TARGET));
@@ -1575,7 +1628,7 @@ static int init_dimms_state(struct dimm_pid_state *state)
}
/*
- * Dispose of the state data for the drives control loop
+ * Dispose of the state data for the DIMM control loop
*/
static void dispose_dimms_state(struct dimm_pid_state *state)
{
@@ -1588,6 +1641,127 @@ static void dispose_dimms_state(struct dimm_pid_state *state)
state->monitor = NULL;
}
+/*
+ * Slots fan control loop
+ */
+static void do_monitor_slots(struct slots_pid_state *state)
+{
+ s32 temp, integral, derivative;
+ s64 integ_p, deriv_p, prop_p, sum;
+ int i, rc;
+
+ if (--state->ticks != 0)
+ return;
+ state->ticks = SLOTS_PID_INTERVAL;
+
+ DBG("slots:\n");
+
+ /* Check fan status */
+ rc = get_pwm_fan(SLOTS_FAN_PWM_INDEX);
+ if (rc < 0) {
+ printk(KERN_WARNING "Error %d reading slots fan !\n", rc);
+ /* XXX What do we do now ? */
+ } else
+ state->pwm = rc;
+ DBG(" current pwm: %d\n", state->pwm);
+
+ /* Get some sensor readings */
+ temp = le16_to_cpu(i2c_smbus_read_word_data(state->monitor,
+ DS1775_TEMP)) << 8;
+ state->last_temp = temp;
+ DBG(" temp: %d.%03d, target: %d.%03d\n", FIX32TOPRINT(temp),
+ FIX32TOPRINT(SLOTS_PID_INPUT_TARGET));
+
+ /* Store temperature and error in history array */
+ state->cur_sample = (state->cur_sample + 1) % SLOTS_PID_HISTORY_SIZE;
+ state->sample_history[state->cur_sample] = temp;
+ state->error_history[state->cur_sample] = temp - SLOTS_PID_INPUT_TARGET;
+
+ /* If first loop, fill the history table */
+ if (state->first) {
+ for (i = 0; i < (SLOTS_PID_HISTORY_SIZE - 1); i++) {
+ state->cur_sample = (state->cur_sample + 1) %
+ SLOTS_PID_HISTORY_SIZE;
+ state->sample_history[state->cur_sample] = temp;
+ state->error_history[state->cur_sample] =
+ temp - SLOTS_PID_INPUT_TARGET;
+ }
+ state->first = 0;
+ }
+
+ /* Calculate the integral term */
+ sum = 0;
+ integral = 0;
+ for (i = 0; i < SLOTS_PID_HISTORY_SIZE; i++)
+ integral += state->error_history[i];
+ integral *= SLOTS_PID_INTERVAL;
+ DBG(" integral: %08x\n", integral);
+ integ_p = ((s64)SLOTS_PID_G_r) * (s64)integral;
+ DBG(" integ_p: %d\n", (int)(integ_p >> 36));
+ sum += integ_p;
+
+ /* Calculate the derivative term */
+ derivative = state->error_history[state->cur_sample] -
+ state->error_history[(state->cur_sample + SLOTS_PID_HISTORY_SIZE - 1)
+ % SLOTS_PID_HISTORY_SIZE];
+ derivative /= SLOTS_PID_INTERVAL;
+ deriv_p = ((s64)SLOTS_PID_G_d) * (s64)derivative;
+ DBG(" deriv_p: %d\n", (int)(deriv_p >> 36));
+ sum += deriv_p;
+
+ /* Calculate the proportional term */
+ prop_p = ((s64)SLOTS_PID_G_p) * (s64)(state->error_history[state->cur_sample]);
+ DBG(" prop_p: %d\n", (int)(prop_p >> 36));
+ sum += prop_p;
+
+ /* Scale sum */
+ sum >>= 36;
+
+ DBG(" sum: %d\n", (int)sum);
+ state->pwm = (s32)sum;
+
+ state->pwm = max(state->pwm, SLOTS_PID_OUTPUT_MIN);
+ state->pwm = min(state->pwm, SLOTS_PID_OUTPUT_MAX);
+
+ DBG("** DRIVES PWM: %d\n", (int)state->pwm);
+ set_pwm_fan(SLOTS_FAN_PWM_INDEX, state->pwm);
+}
+
+/*
+ * Initialize the state structure for the slots bay fan control loop
+ */
+static int init_slots_state(struct slots_pid_state *state)
+{
+ state->ticks = 1;
+ state->first = 1;
+ state->pwm = 50;
+
+ state->monitor = attach_i2c_chip(XSERVE_SLOTS_LM75, "slots_temp");
+ if (state->monitor == NULL)
+ return -ENODEV;
+
+ device_create_file(&of_dev->dev, &dev_attr_slots_temperature);
+ device_create_file(&of_dev->dev, &dev_attr_slots_fan_pwm);
+
+ return 0;
+}
+
+/*
+ * Dispose of the state data for the slots control loop
+ */
+static void dispose_slots_state(struct slots_pid_state *state)
+{
+ if (state->monitor == NULL)
+ return;
+
+ device_remove_file(&of_dev->dev, &dev_attr_slots_temperature);
+ device_remove_file(&of_dev->dev, &dev_attr_slots_fan_pwm);
+
+ detach_i2c_chip(state->monitor);
+ state->monitor = NULL;
+}
+
+
static int call_critical_overtemp(void)
{
char *argv[] = { critical_overtemp_path, NULL };
@@ -1617,14 +1791,17 @@ static int main_control_loop(void *x)
goto out;
}
- /* Set the PCI fan once for now */
- set_pwm_fan(SLOTS_FAN_PWM_INDEX, SLOTS_FAN_DEFAULT_PWM);
+ /* Set the PCI fan once for now on non-RackMac */
+ if (!rackmac)
+ set_pwm_fan(SLOTS_FAN_PWM_INDEX, SLOTS_FAN_DEFAULT_PWM);
/* Initialize ADCs */
initialize_adc(&cpu_state[0]);
if (cpu_state[1].monitor != NULL)
initialize_adc(&cpu_state[1]);
+ fcu_tickle_ticks = FCU_TICKLE_TICKS;
+
up(&driver_lock);
while (state == state_attached) {
@@ -1634,6 +1811,12 @@ static int main_control_loop(void *x)
down(&driver_lock);
+ /* Tickle the FCU just in case */
+ if (--fcu_tickle_ticks < 0) {
+ fcu_tickle_ticks = FCU_TICKLE_TICKS;
+ tickle_fcu();
+ }
+
/* First, we always calculate the new DIMMs state on an Xserve */
if (rackmac)
do_monitor_dimms(&dimms_state);
@@ -1654,7 +1837,9 @@ static int main_control_loop(void *x)
}
/* Then, the rest */
do_monitor_backside(&backside_state);
- if (!rackmac)
+ if (rackmac)
+ do_monitor_slots(&slots_state);
+ else
do_monitor_drives(&drives_state);
up(&driver_lock);
@@ -1696,6 +1881,7 @@ static void dispose_control_loops(void)
dispose_cpu_state(&cpu_state[1]);
dispose_backside_state(&backside_state);
dispose_drives_state(&drives_state);
+ dispose_slots_state(&slots_state);
dispose_dimms_state(&dimms_state);
}
@@ -1745,6 +1931,8 @@ static int create_control_loops(void)
goto fail;
if (rackmac && init_dimms_state(&dimms_state))
goto fail;
+ if (rackmac && init_slots_state(&slots_state))
+ goto fail;
if (!rackmac && init_drives_state(&drives_state))
goto fail;
diff --git a/drivers/macintosh/therm_pm72.h b/drivers/macintosh/therm_pm72.h
index fc7e9b7ecaf..393cc9df94e 100644
--- a/drivers/macintosh/therm_pm72.h
+++ b/drivers/macintosh/therm_pm72.h
@@ -105,6 +105,7 @@ static char * critical_overtemp_path = "/sbin/critical_overtemp";
#define DRIVES_DALLAS_ID 0x94
#define BACKSIDE_MAX_ID 0x98
#define XSERVE_DIMMS_LM87 0x25a
+#define XSERVE_SLOTS_LM75 0x290
/*
* Some MAX6690, DS1775, LM87 register definitions
@@ -198,7 +199,7 @@ struct drives_pid_state
#define SLOTS_FAN_PWM_DEFAULT_ID 2
#define SLOTS_FAN_PWM_INDEX 2
-#define SLOTS_FAN_DEFAULT_PWM 50 /* Do better here ! */
+#define SLOTS_FAN_DEFAULT_PWM 40 /* Do better here ! */
/*
@@ -206,7 +207,7 @@ struct drives_pid_state
*/
#define DIMM_PID_G_d 0
#define DIMM_PID_G_p 0
-#define DIMM_PID_G_r 0x6553600
+#define DIMM_PID_G_r 0x06553600
#define DIMM_PID_INPUT_TARGET 3276800
#define DIMM_PID_INTERVAL 1
#define DIMM_PID_OUTPUT_MAX 14000
@@ -226,6 +227,31 @@ struct dimm_pid_state
};
+/*
+ * PID factors for the Xserve Slots control loop
+ */
+#define SLOTS_PID_G_d 0
+#define SLOTS_PID_G_p 0
+#define SLOTS_PID_G_r 0x00100000
+#define SLOTS_PID_INPUT_TARGET 3200000
+#define SLOTS_PID_INTERVAL 1
+#define SLOTS_PID_OUTPUT_MAX 100
+#define SLOTS_PID_OUTPUT_MIN 20
+#define SLOTS_PID_HISTORY_SIZE 20
+
+struct slots_pid_state
+{
+ int ticks;
+ struct i2c_client * monitor;
+ s32 sample_history[SLOTS_PID_HISTORY_SIZE];
+ s32 error_history[SLOTS_PID_HISTORY_SIZE];
+ int cur_sample;
+ s32 last_temp;
+ int first;
+ int pwm;
+};
+
+
/* Desktops */
@@ -283,6 +309,9 @@ struct cpu_pid_state
s32 pump_max;
};
+/* Tickle FCU every 10 seconds */
+#define FCU_TICKLE_TICKS 10
+
/*
* Driver state
*/
diff --git a/drivers/macintosh/via-pmu-backlight.c b/drivers/macintosh/via-pmu-backlight.c
index b42d05f2aaf..d3f8d75bcbb 100644
--- a/drivers/macintosh/via-pmu-backlight.c
+++ b/drivers/macintosh/via-pmu-backlight.c
@@ -15,8 +15,9 @@
#define MAX_PMU_LEVEL 0xFF
-static struct device_node *vias;
static struct backlight_properties pmu_backlight_data;
+static spinlock_t pmu_backlight_lock;
+static int sleeping;
static int pmu_backlight_get_level_brightness(struct fb_info *info,
int level)
@@ -40,23 +41,36 @@ static int pmu_backlight_update_status(struct backlight_device *bd)
{
struct fb_info *info = class_get_devdata(&bd->class_dev);
struct adb_request req;
- int pmulevel, level = bd->props->brightness;
+ unsigned long flags;
+ int level = bd->props->brightness;
- if (vias == NULL)
- return -ENODEV;
+ spin_lock_irqsave(&pmu_backlight_lock, flags);
+
+ /* Don't update brightness when sleeping */
+ if (sleeping)
+ goto out;
if (bd->props->power != FB_BLANK_UNBLANK ||
bd->props->fb_blank != FB_BLANK_UNBLANK)
level = 0;
- pmulevel = pmu_backlight_get_level_brightness(info, level);
+ if (level > 0) {
+ int pmulevel = pmu_backlight_get_level_brightness(info, level);
- pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT, pmulevel);
- pmu_wait_complete(&req);
+ pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT, pmulevel);
+ pmu_wait_complete(&req);
- pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
- PMU_POW_BACKLIGHT | (level > 0 ? PMU_POW_ON : PMU_POW_OFF));
- pmu_wait_complete(&req);
+ pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
+ PMU_POW_BACKLIGHT | PMU_POW_ON);
+ pmu_wait_complete(&req);
+ } else {
+ pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
+ PMU_POW_BACKLIGHT | PMU_POW_OFF);
+ pmu_wait_complete(&req);
+ }
+
+out:
+ spin_unlock_irqrestore(&pmu_backlight_lock, flags);
return 0;
}
@@ -73,15 +87,39 @@ static struct backlight_properties pmu_backlight_data = {
.max_brightness = (FB_BACKLIGHT_LEVELS - 1),
};
-void __init pmu_backlight_init(struct device_node *in_vias)
+#ifdef CONFIG_PM
+static int pmu_backlight_sleep_call(struct pmu_sleep_notifier *self, int when)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&pmu_backlight_lock, flags);
+
+ switch (when) {
+ case PBOOK_SLEEP_REQUEST:
+ sleeping = 1;
+ break;
+ case PBOOK_WAKE:
+ sleeping = 0;
+ break;
+ }
+
+ spin_unlock_irqrestore(&pmu_backlight_lock, flags);
+
+ return PBOOK_SLEEP_OK;
+}
+
+static struct pmu_sleep_notifier pmu_backlight_sleep_notif = {
+ .notifier_call = pmu_backlight_sleep_call,
+};
+#endif
+
+void __init pmu_backlight_init()
{
struct backlight_device *bd;
struct fb_info *info;
char name[10];
int level, autosave;
- vias = in_vias;
-
/* Special case for the old PowerBook since I can't test on it */
autosave =
machine_is_compatible("AAPL,3400/2400") ||
@@ -141,6 +179,10 @@ void __init pmu_backlight_init(struct device_node *in_vias)
pmac_backlight = bd;
mutex_unlock(&pmac_backlight_mutex);
+#ifdef CONFIG_PM
+ pmu_register_sleep_notifier(&pmu_backlight_sleep_notif);
+#endif
+
printk("pmubl: Backlight initialized (%s)\n", name);
return;
diff --git a/drivers/macintosh/via-pmu-led.c b/drivers/macintosh/via-pmu-led.c
index af8375ed0f5..5189d5454b1 100644
--- a/drivers/macintosh/via-pmu-led.c
+++ b/drivers/macintosh/via-pmu-led.c
@@ -74,7 +74,7 @@ static void pmu_led_set(struct led_classdev *led_cdev,
static struct led_classdev pmu_led = {
.name = "pmu-front-led",
-#ifdef CONFIG_BLK_DEV_IDE_PMAC_BLINK
+#ifdef CONFIG_ADB_PMU_LED_IDE
.default_trigger = "ide-disk",
#endif
.brightness_set = pmu_led_set,
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index 06ca80bfd6b..ea386801e21 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -16,7 +16,6 @@
* a sleep or a freq. switch
* - Move sleep code out of here to pmac_pm, merge into new
* common PM infrastructure
- * - Move backlight code out as well
* - Save/Restore PCI space properly
*
*/
@@ -60,9 +59,7 @@
#include <asm/mmu_context.h>
#include <asm/cputable.h>
#include <asm/time.h>
-#ifdef CONFIG_PMAC_BACKLIGHT
#include <asm/backlight.h>
-#endif
#include "via-pmu-event.h"
@@ -177,10 +174,6 @@ static int query_batt_timer = BATTERY_POLLING_COUNT;
static struct adb_request batt_req;
static struct proc_dir_entry *proc_pmu_batt[PMU_MAX_BATTERIES];
-#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT)
-extern int disable_kernel_backlight;
-#endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */
-
int __fake_sleep;
int asleep;
BLOCKING_NOTIFIER_HEAD(sleep_notifier_list);
@@ -466,7 +459,7 @@ static int __init via_pmu_dev_init(void)
#ifdef CONFIG_PMAC_BACKLIGHT
/* Initialize backlight */
- pmu_backlight_init(vias);
+ pmu_backlight_init();
#endif
#ifdef CONFIG_PPC32
@@ -1403,11 +1396,8 @@ next:
else if ((1 << pirq) & PMU_INT_SNDBRT) {
#ifdef CONFIG_PMAC_BACKLIGHT
if (len == 3)
-#ifdef CONFIG_INPUT_ADBHID
- if (!disable_kernel_backlight)
-#endif /* CONFIG_INPUT_ADBHID */
- pmac_backlight_set_legacy_brightness(data[1] >> 4);
-#endif /* CONFIG_PMAC_BACKLIGHT */
+ pmac_backlight_set_legacy_brightness_pmu(data[1] >> 4);
+#endif
}
/* Tick interrupt */
else if ((1 << pirq) & PMU_INT_TICK) {
@@ -2414,7 +2404,7 @@ struct pmu_private {
spinlock_t lock;
#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT)
int backlight_locker;
-#endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */
+#endif
};
static LIST_HEAD(all_pmu_pvt);
@@ -2464,7 +2454,7 @@ pmu_open(struct inode *inode, struct file *file)
spin_lock_irqsave(&all_pvt_lock, flags);
#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT)
pp->backlight_locker = 0;
-#endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */
+#endif
list_add(&pp->list, &all_pmu_pvt);
spin_unlock_irqrestore(&all_pvt_lock, flags);
file->private_data = pp;
@@ -2559,13 +2549,12 @@ pmu_release(struct inode *inode, struct file *file)
spin_lock_irqsave(&all_pvt_lock, flags);
list_del(&pp->list);
spin_unlock_irqrestore(&all_pvt_lock, flags);
+
#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT)
- if (pp->backlight_locker) {
- spin_lock_irqsave(&pmu_lock, flags);
- disable_kernel_backlight--;
- spin_unlock_irqrestore(&pmu_lock, flags);
- }
-#endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */
+ if (pp->backlight_locker)
+ pmac_backlight_enable();
+#endif
+
kfree(pp);
}
unlock_kernel();
@@ -2642,18 +2631,18 @@ pmu_ioctl(struct inode * inode, struct file *filp,
#ifdef CONFIG_INPUT_ADBHID
case PMU_IOC_GRAB_BACKLIGHT: {
struct pmu_private *pp = filp->private_data;
- unsigned long flags;
if (pp->backlight_locker)
return 0;
+
pp->backlight_locker = 1;
- spin_lock_irqsave(&pmu_lock, flags);
- disable_kernel_backlight++;
- spin_unlock_irqrestore(&pmu_lock, flags);
+ pmac_backlight_disable();
+
return 0;
}
#endif /* CONFIG_INPUT_ADBHID */
#endif /* CONFIG_PMAC_BACKLIGHT_LEGACY */
+
case PMU_IOC_GET_MODEL:
return put_user(pmu_kind, argp);
case PMU_IOC_HAS_ADB:
diff --git a/drivers/md/md.c b/drivers/md/md.c
index e4e161372a3..b6d16022a53 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -110,7 +110,7 @@ static ctl_table raid_table[] = {
.procname = "speed_limit_min",
.data = &sysctl_speed_limit_min,
.maxlen = sizeof(int),
- .mode = 0644,
+ .mode = S_IRUGO|S_IWUSR,
.proc_handler = &proc_dointvec,
},
{
@@ -118,7 +118,7 @@ static ctl_table raid_table[] = {
.procname = "speed_limit_max",
.data = &sysctl_speed_limit_max,
.maxlen = sizeof(int),
- .mode = 0644,
+ .mode = S_IRUGO|S_IWUSR,
.proc_handler = &proc_dointvec,
},
{ .ctl_name = 0 }
@@ -129,7 +129,7 @@ static ctl_table raid_dir_table[] = {
.ctl_name = DEV_RAID,
.procname = "raid",
.maxlen = 0,
- .mode = 0555,
+ .mode = S_IRUGO|S_IXUGO,
.child = raid_table,
},
{ .ctl_name = 0 }
@@ -1062,6 +1062,11 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version)
if (rdev->sb_size & bmask)
rdev-> sb_size = (rdev->sb_size | bmask)+1;
+ if (sb->level == cpu_to_le32(LEVEL_MULTIPATH))
+ rdev->desc_nr = -1;
+ else
+ rdev->desc_nr = le32_to_cpu(sb->dev_number);
+
if (refdev == 0)
ret = 1;
else {
@@ -1171,7 +1176,6 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev)
}
if (mddev->level != LEVEL_MULTIPATH) {
int role;
- rdev->desc_nr = le32_to_cpu(sb->dev_number);
role = le16_to_cpu(sb->dev_roles[rdev->desc_nr]);
switch(role) {
case 0xffff: /* spare */
@@ -1779,8 +1783,8 @@ state_store(mdk_rdev_t *rdev, const char *buf, size_t len)
}
return err ? err : len;
}
-static struct rdev_sysfs_entry
-rdev_state = __ATTR(state, 0644, state_show, state_store);
+static struct rdev_sysfs_entry rdev_state =
+__ATTR(state, S_IRUGO|S_IWUSR, state_show, state_store);
static ssize_t
super_show(mdk_rdev_t *rdev, char *page)
@@ -1811,7 +1815,7 @@ errors_store(mdk_rdev_t *rdev, const char *buf, size_t len)
return -EINVAL;
}
static struct rdev_sysfs_entry rdev_errors =
-__ATTR(errors, 0644, errors_show, errors_store);
+__ATTR(errors, S_IRUGO|S_IWUSR, errors_show, errors_store);
static ssize_t
slot_show(mdk_rdev_t *rdev, char *page)
@@ -1845,7 +1849,7 @@ slot_store(mdk_rdev_t *rdev, const char *buf, size_t len)
static struct rdev_sysfs_entry rdev_slot =
-__ATTR(slot, 0644, slot_show, slot_store);
+__ATTR(slot, S_IRUGO|S_IWUSR, slot_show, slot_store);
static ssize_t
offset_show(mdk_rdev_t *rdev, char *page)
@@ -1867,7 +1871,7 @@ offset_store(mdk_rdev_t *rdev, const char *buf, size_t len)
}
static struct rdev_sysfs_entry rdev_offset =
-__ATTR(offset, 0644, offset_show, offset_store);
+__ATTR(offset, S_IRUGO|S_IWUSR, offset_show, offset_store);
static ssize_t
rdev_size_show(mdk_rdev_t *rdev, char *page)
@@ -1891,7 +1895,7 @@ rdev_size_store(mdk_rdev_t *rdev, const char *buf, size_t len)
}
static struct rdev_sysfs_entry rdev_size =
-__ATTR(size, 0644, rdev_size_show, rdev_size_store);
+__ATTR(size, S_IRUGO|S_IWUSR, rdev_size_show, rdev_size_store);
static struct attribute *rdev_default_attrs[] = {
&rdev_state.attr,
@@ -1922,6 +1926,8 @@ rdev_attr_store(struct kobject *kobj, struct attribute *attr,
if (!entry->store)
return -EIO;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
return entry->store(rdev, page, length);
}
@@ -2128,7 +2134,7 @@ safe_delay_store(mddev_t *mddev, const char *cbuf, size_t len)
return len;
}
static struct md_sysfs_entry md_safe_delay =
-__ATTR(safe_mode_delay, 0644,safe_delay_show, safe_delay_store);
+__ATTR(safe_mode_delay, S_IRUGO|S_IWUSR,safe_delay_show, safe_delay_store);
static ssize_t
level_show(mddev_t *mddev, char *page)
@@ -2163,7 +2169,7 @@ level_store(mddev_t *mddev, const char *buf, size_t len)
}
static struct md_sysfs_entry md_level =
-__ATTR(level, 0644, level_show, level_store);
+__ATTR(level, S_IRUGO|S_IWUSR, level_show, level_store);
static ssize_t
@@ -2188,7 +2194,7 @@ layout_store(mddev_t *mddev, const char *buf, size_t len)
return len;
}
static struct md_sysfs_entry md_layout =
-__ATTR(layout, 0655, layout_show, layout_store);
+__ATTR(layout, S_IRUGO|S_IWUSR, layout_show, layout_store);
static ssize_t
@@ -2219,7 +2225,7 @@ raid_disks_store(mddev_t *mddev, const char *buf, size_t len)
return rv ? rv : len;
}
static struct md_sysfs_entry md_raid_disks =
-__ATTR(raid_disks, 0644, raid_disks_show, raid_disks_store);
+__ATTR(raid_disks, S_IRUGO|S_IWUSR, raid_disks_show, raid_disks_store);
static ssize_t
chunk_size_show(mddev_t *mddev, char *page)
@@ -2243,7 +2249,7 @@ chunk_size_store(mddev_t *mddev, const char *buf, size_t len)
return len;
}
static struct md_sysfs_entry md_chunk_size =
-__ATTR(chunk_size, 0644, chunk_size_show, chunk_size_store);
+__ATTR(chunk_size, S_IRUGO|S_IWUSR, chunk_size_show, chunk_size_store);
static ssize_t
resync_start_show(mddev_t *mddev, char *page)
@@ -2267,7 +2273,7 @@ resync_start_store(mddev_t *mddev, const char *buf, size_t len)
return len;
}
static struct md_sysfs_entry md_resync_start =
-__ATTR(resync_start, 0644, resync_start_show, resync_start_store);
+__ATTR(resync_start, S_IRUGO|S_IWUSR, resync_start_show, resync_start_store);
/*
* The array state can be:
@@ -2437,7 +2443,8 @@ array_state_store(mddev_t *mddev, const char *buf, size_t len)
else
return len;
}
-static struct md_sysfs_entry md_array_state = __ATTR(array_state, 0644, array_state_show, array_state_store);
+static struct md_sysfs_entry md_array_state =
+__ATTR(array_state, S_IRUGO|S_IWUSR, array_state_show, array_state_store);
static ssize_t
null_show(mddev_t *mddev, char *page)
@@ -2497,7 +2504,7 @@ new_dev_store(mddev_t *mddev, const char *buf, size_t len)
}
static struct md_sysfs_entry md_new_device =
-__ATTR(new_dev, 0200, null_show, new_dev_store);
+__ATTR(new_dev, S_IWUSR, null_show, new_dev_store);
static ssize_t
size_show(mddev_t *mddev, char *page)
@@ -2535,7 +2542,7 @@ size_store(mddev_t *mddev, const char *buf, size_t len)
}
static struct md_sysfs_entry md_size =
-__ATTR(component_size, 0644, size_show, size_store);
+__ATTR(component_size, S_IRUGO|S_IWUSR, size_show, size_store);
/* Metdata version.
@@ -2583,7 +2590,7 @@ metadata_store(mddev_t *mddev, const char *buf, size_t len)
}
static struct md_sysfs_entry md_metadata =
-__ATTR(metadata_version, 0644, metadata_show, metadata_store);
+__ATTR(metadata_version, S_IRUGO|S_IWUSR, metadata_show, metadata_store);
static ssize_t
action_show(mddev_t *mddev, char *page)
@@ -2651,12 +2658,11 @@ mismatch_cnt_show(mddev_t *mddev, char *page)
(unsigned long long) mddev->resync_mismatches);
}
-static struct md_sysfs_entry
-md_scan_mode = __ATTR(sync_action, S_IRUGO|S_IWUSR, action_show, action_store);
+static struct md_sysfs_entry md_scan_mode =
+__ATTR(sync_action, S_IRUGO|S_IWUSR, action_show, action_store);
-static struct md_sysfs_entry
-md_mismatches = __ATTR_RO(mismatch_cnt);
+static struct md_sysfs_entry md_mismatches = __ATTR_RO(mismatch_cnt);
static ssize_t
sync_min_show(mddev_t *mddev, char *page)
@@ -2715,15 +2721,14 @@ static ssize_t
sync_speed_show(mddev_t *mddev, char *page)
{
unsigned long resync, dt, db;
- resync = (mddev->curr_resync - atomic_read(&mddev->recovery_active));
+ resync = (mddev->curr_mark_cnt - atomic_read(&mddev->recovery_active));
dt = ((jiffies - mddev->resync_mark) / HZ);
if (!dt) dt++;
db = resync - (mddev->resync_mark_cnt);
return sprintf(page, "%ld\n", db/dt/2); /* K/sec */
}
-static struct md_sysfs_entry
-md_sync_speed = __ATTR_RO(sync_speed);
+static struct md_sysfs_entry md_sync_speed = __ATTR_RO(sync_speed);
static ssize_t
sync_completed_show(mddev_t *mddev, char *page)
@@ -2739,8 +2744,7 @@ sync_completed_show(mddev_t *mddev, char *page)
return sprintf(page, "%lu / %lu\n", resync, max_blocks);
}
-static struct md_sysfs_entry
-md_sync_completed = __ATTR_RO(sync_completed);
+static struct md_sysfs_entry md_sync_completed = __ATTR_RO(sync_completed);
static ssize_t
suspend_lo_show(mddev_t *mddev, char *page)
@@ -2857,6 +2861,8 @@ md_attr_store(struct kobject *kobj, struct attribute *attr,
if (!entry->store)
return -EIO;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
rv = mddev_lock(mddev);
if (!rv) {
rv = entry->store(mddev, page, length);
@@ -3091,7 +3097,6 @@ static int do_md_run(mddev_t * mddev)
}
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
- md_wakeup_thread(mddev->thread);
if (mddev->sb_dirty)
md_update_sb(mddev);
@@ -3112,7 +3117,7 @@ static int do_md_run(mddev_t * mddev)
* start recovery here. If we leave it to md_check_recovery,
* it will remove the drives and not do the right thing
*/
- if (mddev->degraded) {
+ if (mddev->degraded && !mddev->sync_thread) {
struct list_head *rtmp;
int spares = 0;
ITERATE_RDEV(mddev,rdev,rtmp)
@@ -3133,10 +3138,11 @@ static int do_md_run(mddev_t * mddev)
mdname(mddev));
/* leave the spares where they are, it shouldn't hurt */
mddev->recovery = 0;
- } else
- md_wakeup_thread(mddev->sync_thread);
+ }
}
}
+ md_wakeup_thread(mddev->thread);
+ md_wakeup_thread(mddev->sync_thread); /* possibly kick off a reshape */
mddev->changed = 1;
md_new_event(mddev);
@@ -4586,6 +4592,8 @@ void md_error(mddev_t *mddev, mdk_rdev_t *rdev)
__builtin_return_address(0),__builtin_return_address(1),
__builtin_return_address(2),__builtin_return_address(3));
*/
+ if (!mddev->pers)
+ return;
if (!mddev->pers->error_handler)
return;
mddev->pers->error_handler(mddev,rdev);
@@ -4683,12 +4691,13 @@ static void status_resync(struct seq_file *seq, mddev_t * mddev)
*/
dt = ((jiffies - mddev->resync_mark) / HZ);
if (!dt) dt++;
- db = resync - (mddev->resync_mark_cnt/2);
- rt = (dt * ((unsigned long)(max_blocks-resync) / (db/100+1)))/100;
+ db = (mddev->curr_mark_cnt - atomic_read(&mddev->recovery_active))
+ - mddev->resync_mark_cnt;
+ rt = (dt * ((unsigned long)(max_blocks-resync) / (db/2/100+1)))/100;
seq_printf(seq, " finish=%lu.%lumin", rt / 60, (rt % 60)/6);
- seq_printf(seq, " speed=%ldK/sec", db/dt);
+ seq_printf(seq, " speed=%ldK/sec", db/2/dt);
}
static void *md_seq_start(struct seq_file *seq, loff_t *pos)
@@ -5199,6 +5208,7 @@ void md_do_sync(mddev_t *mddev)
j += sectors;
if (j>1) mddev->curr_resync = j;
+ mddev->curr_mark_cnt = io_sectors;
if (last_check == 0)
/* this is the earliers that rebuilt will be
* visible in /proc/mdstat
@@ -5645,8 +5655,8 @@ static int set_ro(const char *val, struct kernel_param *kp)
return -EINVAL;
}
-module_param_call(start_ro, set_ro, get_ro, NULL, 0600);
-module_param(start_dirty_degraded, int, 0644);
+module_param_call(start_ro, set_ro, get_ro, NULL, S_IRUSR|S_IWUSR);
+module_param(start_dirty_degraded, int, S_IRUGO|S_IWUSR);
EXPORT_SYMBOL(register_md_personality);
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index cead918578a..1efe22a2d04 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1145,7 +1145,7 @@ static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error)
long sectors_to_go = r1_bio->sectors;
/* make sure these bits doesn't get cleared. */
do {
- bitmap_end_sync(mddev->bitmap, r1_bio->sector,
+ bitmap_end_sync(mddev->bitmap, s,
&sync_blocks, 1);
s += sync_blocks;
sectors_to_go -= sync_blocks;
@@ -1509,6 +1509,9 @@ static void raid1d(mddev_t *mddev)
s<<9, conf->tmppage, READ) == 0)
/* Well, this device is dead */
md_error(mddev, rdev);
+ else
+ printk(KERN_INFO "raid1:%s: read error corrected (%d sectors at %llu on %s)\n",
+ mdname(mddev), s, (unsigned long long)(sect + rdev->data_offset), bdevname(rdev->bdev, b));
}
}
} else {
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 7f636283a1b..016ddb831c9 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -1492,6 +1492,10 @@ static void raid10d(mddev_t *mddev)
s<<9, conf->tmppage, READ) == 0)
/* Well, this device is dead */
md_error(mddev, rdev);
+ else
+ printk(KERN_INFO "raid10:%s: read error corrected (%d sectors at %llu on %s)\n",
+ mdname(mddev), s, (unsigned long long)(sect+rdev->data_offset), bdevname(rdev->bdev, b));
+
rdev_dec_pending(rdev, mddev);
rcu_read_lock();
}
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 7433871f4b3..45006600716 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -18,6 +18,30 @@
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+/*
+ * BITMAP UNPLUGGING:
+ *
+ * The sequencing for updating the bitmap reliably is a little
+ * subtle (and I got it wrong the first time) so it deserves some
+ * explanation.
+ *
+ * We group bitmap updates into batches. Each batch has a number.
+ * We may write out several batches at once, but that isn't very important.
+ * conf->bm_write is the number of the last batch successfully written.
+ * conf->bm_flush is the number of the last batch that was closed to
+ * new additions.
+ * When we discover that we will need to write to any block in a stripe
+ * (in add_stripe_bio) we update the in-memory bitmap and record in sh->bm_seq
+ * the number of the batch it will be in. This is bm_flush+1.
+ * When we are ready to do a write, if that batch hasn't been written yet,
+ * we plug the array and queue the stripe for later.
+ * When an unplug happens, we increment bm_flush, thus closing the current
+ * batch.
+ * When we notice that bm_flush > bm_write, we write out all pending updates
+ * to the bitmap, and advance bm_write to where bm_flush was.
+ * This may occasionally write a bit out twice, but is sure never to
+ * miss any bits.
+ */
#include <linux/module.h>
#include <linux/slab.h>
@@ -88,12 +112,14 @@ static void __release_stripe(raid5_conf_t *conf, struct stripe_head *sh)
BUG_ON(!list_empty(&sh->lru));
BUG_ON(atomic_read(&conf->active_stripes)==0);
if (test_bit(STRIPE_HANDLE, &sh->state)) {
- if (test_bit(STRIPE_DELAYED, &sh->state))
+ if (test_bit(STRIPE_DELAYED, &sh->state)) {
list_add_tail(&sh->lru, &conf->delayed_list);
- else if (test_bit(STRIPE_BIT_DELAY, &sh->state) &&
- conf->seq_write == sh->bm_seq)
+ blk_plug_device(conf->mddev->queue);
+ } else if (test_bit(STRIPE_BIT_DELAY, &sh->state) &&
+ sh->bm_seq - conf->seq_write > 0) {
list_add_tail(&sh->lru, &conf->bitmap_list);
- else {
+ blk_plug_device(conf->mddev->queue);
+ } else {
clear_bit(STRIPE_BIT_DELAY, &sh->state);
list_add_tail(&sh->lru, &conf->handle_list);
}
@@ -270,7 +296,7 @@ static struct stripe_head *get_active_stripe(raid5_conf_t *conf, sector_t sector
< (conf->max_nr_stripes *3/4)
|| !conf->inactive_blocked),
conf->device_lock,
- unplug_slaves(conf->mddev)
+ raid5_unplug_device(conf->mddev->queue)
);
conf->inactive_blocked = 0;
} else
@@ -281,7 +307,8 @@ static struct stripe_head *get_active_stripe(raid5_conf_t *conf, sector_t sector
} else {
if (!test_bit(STRIPE_HANDLE, &sh->state))
atomic_inc(&conf->active_stripes);
- if (list_empty(&sh->lru))
+ if (list_empty(&sh->lru) &&
+ !test_bit(STRIPE_EXPANDING, &sh->state))
BUG();
list_del_init(&sh->lru);
}
@@ -496,6 +523,8 @@ static int raid5_end_read_request(struct bio * bi, unsigned int bytes_done,
raid5_conf_t *conf = sh->raid_conf;
int disks = sh->disks, i;
int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags);
+ char b[BDEVNAME_SIZE];
+ mdk_rdev_t *rdev;
if (bi->bi_size)
return 1;
@@ -543,25 +572,39 @@ static int raid5_end_read_request(struct bio * bi, unsigned int bytes_done,
set_bit(R5_UPTODATE, &sh->dev[i].flags);
#endif
if (test_bit(R5_ReadError, &sh->dev[i].flags)) {
- printk(KERN_INFO "raid5: read error corrected!!\n");
+ rdev = conf->disks[i].rdev;
+ printk(KERN_INFO "raid5:%s: read error corrected (%lu sectors at %llu on %s)\n",
+ mdname(conf->mddev), STRIPE_SECTORS,
+ (unsigned long long)sh->sector + rdev->data_offset,
+ bdevname(rdev->bdev, b));
clear_bit(R5_ReadError, &sh->dev[i].flags);
clear_bit(R5_ReWrite, &sh->dev[i].flags);
}
if (atomic_read(&conf->disks[i].rdev->read_errors))
atomic_set(&conf->disks[i].rdev->read_errors, 0);
} else {
+ const char *bdn = bdevname(conf->disks[i].rdev->bdev, b);
int retry = 0;
+ rdev = conf->disks[i].rdev;
+
clear_bit(R5_UPTODATE, &sh->dev[i].flags);
- atomic_inc(&conf->disks[i].rdev->read_errors);
+ atomic_inc(&rdev->read_errors);
if (conf->mddev->degraded)
- printk(KERN_WARNING "raid5: read error not correctable.\n");
+ printk(KERN_WARNING "raid5:%s: read error not correctable (sector %llu on %s).\n",
+ mdname(conf->mddev),
+ (unsigned long long)sh->sector + rdev->data_offset,
+ bdn);
else if (test_bit(R5_ReWrite, &sh->dev[i].flags))
/* Oh, no!!! */
- printk(KERN_WARNING "raid5: read error NOT corrected!!\n");
- else if (atomic_read(&conf->disks[i].rdev->read_errors)
+ printk(KERN_WARNING "raid5:%s: read error NOT corrected!! (sector %llu on %s).\n",
+ mdname(conf->mddev),
+ (unsigned long long)sh->sector + rdev->data_offset,
+ bdn);
+ else if (atomic_read(&rdev->read_errors)
> conf->max_nr_stripes)
printk(KERN_WARNING
- "raid5: Too many read errors, failing device.\n");
+ "raid5:%s: Too many read errors, failing device %s.\n",
+ mdname(conf->mddev), bdn);
else
retry = 1;
if (retry)
@@ -569,7 +612,7 @@ static int raid5_end_read_request(struct bio * bi, unsigned int bytes_done,
else {
clear_bit(R5_ReadError, &sh->dev[i].flags);
clear_bit(R5_ReWrite, &sh->dev[i].flags);
- md_error(conf->mddev, conf->disks[i].rdev);
+ md_error(conf->mddev, rdev);
}
}
rdev_dec_pending(conf->disks[i].rdev, conf->mddev);
@@ -1270,9 +1313,9 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in
(unsigned long long)sh->sector, dd_idx);
if (conf->mddev->bitmap && firstwrite) {
- sh->bm_seq = conf->seq_write;
bitmap_startwrite(conf->mddev->bitmap, sh->sector,
STRIPE_SECTORS, 0);
+ sh->bm_seq = conf->seq_flush+1;
set_bit(STRIPE_BIT_DELAY, &sh->state);
}
@@ -2554,13 +2597,6 @@ static int raid5_issue_flush(request_queue_t *q, struct gendisk *disk,
return ret;
}
-static inline void raid5_plug_device(raid5_conf_t *conf)
-{
- spin_lock_irq(&conf->device_lock);
- blk_plug_device(conf->mddev->queue);
- spin_unlock_irq(&conf->device_lock);
-}
-
static int make_request(request_queue_t *q, struct bio * bi)
{
mddev_t *mddev = q->queuedata;
@@ -2670,7 +2706,6 @@ static int make_request(request_queue_t *q, struct bio * bi)
goto retry;
}
finish_wait(&conf->wait_for_overlap, &w);
- raid5_plug_device(conf);
handle_stripe(sh, NULL);
release_stripe(sh);
} else {
@@ -2923,7 +2958,7 @@ static void raid5d (mddev_t *mddev)
while (1) {
struct list_head *first;
- if (conf->seq_flush - conf->seq_write > 0) {
+ if (conf->seq_flush != conf->seq_write) {
int seq = conf->seq_flush;
spin_unlock_irq(&conf->device_lock);
bitmap_unplug(mddev->bitmap);
@@ -3246,9 +3281,6 @@ static int run(mddev_t *mddev)
set_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
mddev->sync_thread = md_register_thread(md_do_sync, mddev,
"%s_reshape");
- /* FIXME if md_register_thread fails?? */
- md_wakeup_thread(mddev->sync_thread);
-
}
/* read-ahead size must cover two whole stripes, which is
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index 59ac35ddd51..57b34cda99f 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -526,7 +526,9 @@ static int dvb_frontend_thread(void *data)
fepriv->delay = 3*HZ;
fepriv->status = 0;
fepriv->wakeup = 0;
- fepriv->reinitialise = 1;
+ fepriv->reinitialise = 0;
+
+ dvb_frontend_init(fe);
while (1) {
up(&fepriv->sem); /* is locked when we enter the thread... */
@@ -1013,17 +1015,18 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
return ret;
if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
+
+ /* normal tune mode when opened R/W */
+ fepriv->tune_mode_flags &= ~FE_TUNE_MODE_ONESHOT;
+ fepriv->tone = -1;
+ fepriv->voltage = -1;
+
ret = dvb_frontend_start (fe);
if (ret)
dvb_generic_release (inode, file);
/* empty event queue */
fepriv->events.eventr = fepriv->events.eventw = 0;
-
- /* normal tune mode when opened R/W */
- fepriv->tune_mode_flags &= ~FE_TUNE_MODE_ONESHOT;
- fepriv->tone = -1;
- fepriv->voltage = -1;
}
return ret;
diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c
index a189683454b..2be33f27c69 100644
--- a/drivers/media/dvb/frontends/dvb-pll.c
+++ b/drivers/media/dvb/frontends/dvb-pll.c
@@ -194,11 +194,11 @@ struct dvb_pll_desc dvb_pll_tda665x = {
{ 253834000, 36249333, 166667, 0xca, 0x62 /* 011 0 0 0 10 */ },
{ 383834000, 36249333, 166667, 0xca, 0xa2 /* 101 0 0 0 10 */ },
{ 443834000, 36249333, 166667, 0xca, 0xc2 /* 110 0 0 0 10 */ },
- { 444000000, 36249333, 166667, 0xca, 0xc3 /* 110 0 0 0 11 */ },
- { 583834000, 36249333, 166667, 0xca, 0x63 /* 011 0 0 0 11 */ },
- { 793834000, 36249333, 166667, 0xca, 0xa3 /* 101 0 0 0 11 */ },
- { 444834000, 36249333, 166667, 0xca, 0xc3 /* 110 0 0 0 11 */ },
- { 861000000, 36249333, 166667, 0xca, 0xe3 /* 111 0 0 0 11 */ },
+ { 444000000, 36249333, 166667, 0xca, 0xc4 /* 110 0 0 1 00 */ },
+ { 583834000, 36249333, 166667, 0xca, 0x64 /* 011 0 0 1 00 */ },
+ { 793834000, 36249333, 166667, 0xca, 0xa4 /* 101 0 0 1 00 */ },
+ { 444834000, 36249333, 166667, 0xca, 0xc4 /* 110 0 0 1 00 */ },
+ { 861000000, 36249333, 166667, 0xca, 0xe4 /* 111 0 0 1 00 */ },
}
};
EXPORT_SYMBOL(dvb_pll_tda665x);
@@ -613,7 +613,21 @@ static struct dvb_tuner_ops dvb_pll_tuner_ops = {
int dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, struct dvb_pll_desc *desc)
{
+ u8 b1 [] = { 0 };
+ struct i2c_msg msg = { .addr = pll_addr, .flags = I2C_M_RD, .buf = b1, .len = 1 };
struct dvb_pll_priv *priv = NULL;
+ int ret;
+
+ if (i2c != NULL) {
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ ret = i2c_transfer (i2c, &msg, 1);
+ if (ret != 1)
+ return -1;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
priv = kzalloc(sizeof(struct dvb_pll_priv), GFP_KERNEL);
if (priv == NULL)
diff --git a/drivers/media/dvb/frontends/nxt200x.c b/drivers/media/dvb/frontends/nxt200x.c
index 55671cb5255..87c286ee6a0 100644
--- a/drivers/media/dvb/frontends/nxt200x.c
+++ b/drivers/media/dvb/frontends/nxt200x.c
@@ -896,9 +896,9 @@ static int nxt2002_init(struct dvb_frontend* fe)
}
ret = nxt2002_load_firmware(fe, fw);
+ release_firmware(fw);
if (ret) {
printk("nxt2002: Writing firmware to device failed\n");
- release_firmware(fw);
return ret;
}
printk("nxt2002: Firmware upload complete\n");
@@ -960,9 +960,9 @@ static int nxt2004_init(struct dvb_frontend* fe)
}
ret = nxt2004_load_firmware(fe, fw);
+ release_firmware(fw);
if (ret) {
printk("nxt2004: Writing firmware to device failed\n");
- release_firmware(fw);
return ret;
}
printk("nxt2004: Firmware upload complete\n");
diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c
index 26bed616fab..2bf124b5368 100644
--- a/drivers/media/dvb/frontends/or51211.c
+++ b/drivers/media/dvb/frontends/or51211.c
@@ -437,10 +437,10 @@ static int or51211_init(struct dvb_frontend* fe)
}
ret = or51211_load_firmware(fe, fw);
+ release_firmware(fw);
if (ret) {
printk(KERN_WARNING "or51211: Writing firmware to "
"device failed!\n");
- release_firmware(fw);
return ret;
}
printk(KERN_INFO "or51211: Firmware upload complete.\n");
diff --git a/drivers/media/dvb/frontends/sp8870.c b/drivers/media/dvb/frontends/sp8870.c
index 44ec5b9a469..d98fd5c2e13 100644
--- a/drivers/media/dvb/frontends/sp8870.c
+++ b/drivers/media/dvb/frontends/sp8870.c
@@ -318,7 +318,6 @@ static int sp8870_init (struct dvb_frontend* fe)
printk("sp8870: waiting for firmware upload (%s)...\n", SP8870_DEFAULT_FIRMWARE);
if (state->config->request_firmware(fe, &fw, SP8870_DEFAULT_FIRMWARE)) {
printk("sp8870: no firmware upload (timeout or file not found?)\n");
- release_firmware(fw);
return -EIO;
}
@@ -327,6 +326,7 @@ static int sp8870_init (struct dvb_frontend* fe)
release_firmware(fw);
return -EIO;
}
+ release_firmware(fw);
printk("sp8870: firmware upload complete\n");
/* enable TS output and interface pins */
diff --git a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c
index b0a2b02f660..5c2f8f4e0ae 100644
--- a/drivers/media/dvb/frontends/sp887x.c
+++ b/drivers/media/dvb/frontends/sp887x.c
@@ -520,9 +520,9 @@ static int sp887x_init(struct dvb_frontend* fe)
}
ret = sp887x_initial_setup(fe, fw);
+ release_firmware(fw);
if (ret) {
printk("sp887x: writing firmware to device failed\n");
- release_firmware(fw);
return ret;
}
printk("sp887x: firmware upload complete\n");
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index 500f15c10aa..4506165c5de 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -2203,8 +2203,8 @@ static int frontend_init(struct av7110 *av7110)
av7110->fe->ops.tuner_ops.set_params = nexusca_stv0297_tuner_set_params;
/* set TDA9819 into DVB mode */
- saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9198 pin9(STD)
- saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9198 pin30(VIF)
+ saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD)
+ saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF)
/* tuner on this needs a slower i2c bus speed */
av7110->dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240;
diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c
index 64055461559..6ffe53fdcf5 100644
--- a/drivers/media/dvb/ttpci/av7110_v4l.c
+++ b/drivers/media/dvb/ttpci/av7110_v4l.c
@@ -272,8 +272,8 @@ static int av7110_dvb_c_switch(struct saa7146_fh *fh)
if (ves1820_writereg(dev, 0x09, 0x0f, 0x60))
dprintk(1, "setting band in demodulator failed.\n");
} else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
- saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // TDA9198 pin9(STD)
- saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); // TDA9198 pin30(VIF)
+ saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // TDA9819 pin9(STD)
+ saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); // TDA9819 pin30(VIF)
}
if (i2c_writereg(av7110, 0x48, 0x02, 0xd0) != 1)
dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num);
@@ -308,8 +308,8 @@ static int av7110_dvb_c_switch(struct saa7146_fh *fh)
if (ves1820_writereg(dev, 0x09, 0x0f, 0x20))
dprintk(1, "setting band in demodulator failed.\n");
} else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
- saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO); // TDA9198 pin9(STD)
- saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // TDA9198 pin30(VIF)
+ saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD)
+ saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF)
}
}
@@ -750,8 +750,8 @@ int av7110_init_analog_module(struct av7110 *av7110)
if (ves1820_writereg(av7110->dev, 0x09, 0x0f, 0x20))
dprintk(1, "setting band in demodulator failed.\n");
} else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
- saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9198 pin9(STD)
- saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9198 pin30(VIF)
+ saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD)
+ saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF)
}
/* init the saa7113 */
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
index 5f111d40773..2d21fec23b4 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -1303,6 +1303,9 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio
budget_av->budget.dvb_adapter.priv = budget_av;
frontend_init(budget_av);
ciintf_init(budget_av);
+
+ ttpci_budget_init_hooks(&budget_av->budget);
+
return 0;
}
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index 4b966eea383..ffbbb3e34be 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -1101,6 +1101,8 @@ static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio
budget_ci->budget.dvb_adapter.priv = budget_ci;
frontend_init(budget_ci);
+ ttpci_budget_init_hooks(&budget_ci->budget);
+
return 0;
}
diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c
index e4cf7775e07..e15562f8166 100644
--- a/drivers/media/dvb/ttpci/budget-core.c
+++ b/drivers/media/dvb/ttpci/budget-core.c
@@ -63,9 +63,6 @@ static int stop_ts_capture(struct budget *budget)
{
dprintk(2, "budget: %p\n", budget);
- if (--budget->feeding)
- return budget->feeding;
-
saa7146_write(budget->dev, MC1, MASK_20); // DMA3 off
SAA7146_IER_DISABLE(budget->dev, MASK_10);
return 0;
@@ -77,8 +74,8 @@ static int start_ts_capture(struct budget *budget)
dprintk(2, "budget: %p\n", budget);
- if (budget->feeding)
- return ++budget->feeding;
+ if (!budget->feeding || !budget->fe_synced)
+ return 0;
saa7146_write(dev, MC1, MASK_20); // DMA3 off
@@ -139,7 +136,33 @@ static int start_ts_capture(struct budget *budget)
SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */
saa7146_write(dev, MC1, (MASK_04 | MASK_20)); /* DMA3 on */
- return ++budget->feeding;
+ return 0;
+}
+
+static int budget_read_fe_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ struct budget *budget = (struct budget *) fe->dvb->priv;
+ int synced;
+ int ret;
+
+ if (budget->read_fe_status)
+ ret = budget->read_fe_status(fe, status);
+ else
+ ret = -EINVAL;
+
+ if (!ret) {
+ synced = (*status & FE_HAS_LOCK);
+ if (synced != budget->fe_synced) {
+ budget->fe_synced = synced;
+ spin_lock(&budget->feedlock);
+ if (synced)
+ start_ts_capture(budget);
+ else
+ stop_ts_capture(budget);
+ spin_unlock(&budget->feedlock);
+ }
+ }
+ return ret;
}
static void vpeirq(unsigned long data)
@@ -267,7 +290,7 @@ static int budget_start_feed(struct dvb_demux_feed *feed)
{
struct dvb_demux *demux = feed->demux;
struct budget *budget = (struct budget *) demux->priv;
- int status;
+ int status = 0;
dprintk(2, "budget: %p\n", budget);
@@ -276,7 +299,8 @@ static int budget_start_feed(struct dvb_demux_feed *feed)
spin_lock(&budget->feedlock);
feed->pusi_seen = 0; /* have a clean section start */
- status = start_ts_capture(budget);
+ if (budget->feeding++ == 0)
+ status = start_ts_capture(budget);
spin_unlock(&budget->feedlock);
return status;
}
@@ -285,12 +309,13 @@ static int budget_stop_feed(struct dvb_demux_feed *feed)
{
struct dvb_demux *demux = feed->demux;
struct budget *budget = (struct budget *) demux->priv;
- int status;
+ int status = 0;
dprintk(2, "budget: %p\n", budget);
spin_lock(&budget->feedlock);
- status = stop_ts_capture(budget);
+ if (--budget->feeding == 0)
+ status = stop_ts_capture(budget);
spin_unlock(&budget->feedlock);
return status;
}
@@ -470,6 +495,14 @@ err:
return ret;
}
+void ttpci_budget_init_hooks(struct budget *budget)
+{
+ if (budget->dvb_frontend && !budget->read_fe_status) {
+ budget->read_fe_status = budget->dvb_frontend->ops.read_status;
+ budget->dvb_frontend->ops.read_status = budget_read_fe_status;
+ }
+}
+
int ttpci_budget_deinit(struct budget *budget)
{
struct saa7146_dev *dev = budget->dev;
@@ -508,11 +541,8 @@ void ttpci_budget_set_video_port(struct saa7146_dev *dev, int video_port)
spin_lock(&budget->feedlock);
budget->video_port = video_port;
if (budget->feeding) {
- int oldfeeding = budget->feeding;
- budget->feeding = 1;
stop_ts_capture(budget);
start_ts_capture(budget);
- budget->feeding = oldfeeding;
}
spin_unlock(&budget->feedlock);
}
@@ -520,6 +550,7 @@ void ttpci_budget_set_video_port(struct saa7146_dev *dev, int video_port)
EXPORT_SYMBOL_GPL(ttpci_budget_debiread);
EXPORT_SYMBOL_GPL(ttpci_budget_debiwrite);
EXPORT_SYMBOL_GPL(ttpci_budget_init);
+EXPORT_SYMBOL_GPL(ttpci_budget_init_hooks);
EXPORT_SYMBOL_GPL(ttpci_budget_deinit);
EXPORT_SYMBOL_GPL(ttpci_budget_irq10_handler);
EXPORT_SYMBOL_GPL(ttpci_budget_set_video_port);
diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c
index ee60ce90a40..57227441891 100644
--- a/drivers/media/dvb/ttpci/budget-patch.c
+++ b/drivers/media/dvb/ttpci/budget-patch.c
@@ -617,6 +617,8 @@ static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_exte
budget->dvb_adapter.priv = budget;
frontend_init(budget);
+ ttpci_budget_init_hooks(budget);
+
return 0;
}
diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c
index 35761f13c12..863dffb4ed8 100644
--- a/drivers/media/dvb/ttpci/budget.c
+++ b/drivers/media/dvb/ttpci/budget.c
@@ -375,9 +375,6 @@ static void frontend_init(struct budget *budget)
if (budget->dvb_frontend) {
budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
- budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
- budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;
- budget->dvb_frontend->ops.set_tone = budget_set_tone;
break;
}
break;
@@ -474,6 +471,8 @@ static int budget_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_
budget->dvb_adapter.priv = budget;
frontend_init(budget);
+ ttpci_budget_init_hooks(budget);
+
return 0;
}
diff --git a/drivers/media/dvb/ttpci/budget.h b/drivers/media/dvb/ttpci/budget.h
index ecea3a13030..e8a5c79178e 100644
--- a/drivers/media/dvb/ttpci/budget.h
+++ b/drivers/media/dvb/ttpci/budget.h
@@ -52,9 +52,6 @@ struct budget {
struct dmx_frontend hw_frontend;
struct dmx_frontend mem_frontend;
- int fe_synced;
- struct mutex pid_mutex;
-
int ci_present;
int video_port;
@@ -74,6 +71,9 @@ struct budget {
struct dvb_adapter dvb_adapter;
struct dvb_frontend *dvb_frontend;
+ int (*read_fe_status)(struct dvb_frontend *fe, fe_status_t *status);
+ int fe_synced;
+
void *priv;
};
@@ -106,6 +106,7 @@ static struct saa7146_pci_extension_data x_var = { \
extern int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
struct saa7146_pci_extension_data *info,
struct module *owner);
+extern void ttpci_budget_init_hooks(struct budget *budget);
extern int ttpci_budget_deinit(struct budget *budget);
extern void ttpci_budget_irq10_handler(struct saa7146_dev *dev, u32 * isr);
extern void ttpci_budget_set_video_port(struct saa7146_dev *dev, int video_port);
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 6d532f170ce..fe56862d51e 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -145,7 +145,7 @@ config VIDEO_SAA5246A
config VIDEO_SAA5249
tristate "SAA5249 Teletext processor"
- depends on VIDEO_DEV && I2C
+ depends on VIDEO_DEV && I2C && VIDEO_V4L1
help
Support for I2C bus based teletext using the SAA5249 chip. At the
moment this is only useful on some European WinTV cards.
@@ -155,7 +155,7 @@ config VIDEO_SAA5249
config TUNER_3036
tristate "SAB3036 tuner"
- depends on VIDEO_DEV && I2C
+ depends on VIDEO_DEV && I2C && VIDEO_V4L1
help
Say Y here to include support for Philips SAB3036 compatible tuners.
If in doubt, say N.
diff --git a/drivers/media/video/bt8xx/Kconfig b/drivers/media/video/bt8xx/Kconfig
index 153f6a4a96c..cdcf5565071 100644
--- a/drivers/media/video/bt8xx/Kconfig
+++ b/drivers/media/video/bt8xx/Kconfig
@@ -1,6 +1,6 @@
config VIDEO_BT848
tristate "BT848 Video For Linux"
- depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2
+ depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L1
select I2C_ALGOBIT
select FW_LOADER
select VIDEO_BTCX
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index 5764a89d356..20dff7c316e 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -3923,7 +3923,12 @@ static int __devinit bttv_register_video(struct bttv *btv)
goto err;
printk(KERN_INFO "bttv%d: registered device video%d\n",
btv->c.nr,btv->video_dev->minor & 0x1f);
- video_device_create_file(btv->video_dev, &class_device_attr_card);
+ if (class_device_create_file(&btv->video_dev->class_dev,
+ &class_device_attr_card)<0) {
+ printk(KERN_ERR "bttv%d: class_device_create_file 'card' "
+ "failed\n", btv->c.nr);
+ goto err;
+ }
/* vbi */
btv->vbi_dev = vdev_init(btv, &bttv_vbi_template, "vbi");
@@ -4287,6 +4292,8 @@ static struct pci_driver bttv_pci_driver = {
static int bttv_init_module(void)
{
+ int ret;
+
bttv_num = 0;
printk(KERN_INFO "bttv: driver version %d.%d.%d loaded\n",
@@ -4308,7 +4315,11 @@ static int bttv_init_module(void)
bttv_check_chipset();
- bus_register(&bttv_sub_bus_type);
+ ret = bus_register(&bttv_sub_bus_type);
+ if (ret < 0) {
+ printk(KERN_WARNING "bttv: bus_register error: %d\n", ret);
+ return ret;
+ }
return pci_register_driver(&bttv_pci_driver);
}
diff --git a/drivers/media/video/bt8xx/bttv-vbi.c b/drivers/media/video/bt8xx/bttv-vbi.c
index 8c9f0f7cf46..63676e7bd63 100644
--- a/drivers/media/video/bt8xx/bttv-vbi.c
+++ b/drivers/media/video/bt8xx/bttv-vbi.c
@@ -31,11 +31,16 @@
#include <asm/io.h>
#include "bttvp.h"
-/* Offset from line sync pulse leading edge (0H) in 1 / sampling_rate:
- bt8x8 /HRESET pulse starts at 0H and has length 64 / fCLKx1 (E|O_VTC
- HSFMT = 0). VBI_HDELAY (always 0) is an offset from the trailing edge
- of /HRESET in 1 / fCLKx1, and the sampling_rate tvnorm->Fsc is fCLKx2. */
-#define VBI_OFFSET ((64 + 0) * 2)
+/* Offset from line sync pulse leading edge (0H) to start of VBI capture,
+ in fCLKx2 pixels. According to the datasheet, VBI capture starts
+ VBI_HDELAY fCLKx1 pixels from the tailing edgeof /HRESET, and /HRESET
+ is 64 fCLKx1 pixels wide. VBI_HDELAY is set to 0, so this should be
+ (64 + 0) * 2 = 128 fCLKx2 pixels. But it's not! The datasheet is
+ Just Plain Wrong. The real value appears to be different for
+ different revisions of the bt8x8 chips, and to be affected by the
+ horizontal scaling factor. Experimentally, the value is measured
+ to be about 244. */
+#define VBI_OFFSET 244
#define VBI_DEFLINES 16
#define VBI_MAXLINES 32
diff --git a/drivers/media/video/compat_ioctl32.c b/drivers/media/video/compat_ioctl32.c
index 353d02b67c3..9dddff42ec1 100644
--- a/drivers/media/video/compat_ioctl32.c
+++ b/drivers/media/video/compat_ioctl32.c
@@ -490,6 +490,23 @@ static inline int put_v4l2_input(struct v4l2_input *kp, struct v4l2_input __user
return 0;
}
+struct video_code32
+{
+ char loadwhat[16]; /* name or tag of file being passed */
+ compat_int_t datasize;
+ unsigned char *data;
+};
+
+static inline int microcode32(struct video_code *kp, struct video_code32 __user *up)
+{
+ if(!access_ok(VERIFY_READ, up, sizeof(struct video_code32)) ||
+ copy_from_user(kp->loadwhat, up->loadwhat, sizeof (up->loadwhat)) ||
+ get_user(kp->datasize, &up->datasize) ||
+ copy_from_user(kp->data, up->data, up->datasize))
+ return -EFAULT;
+ return 0;
+}
+
#define VIDIOCGTUNER32 _IOWR('v',4, struct video_tuner32)
#define VIDIOCSTUNER32 _IOW('v',5, struct video_tuner32)
#define VIDIOCGWIN32 _IOR('v',9, struct video_window32)
@@ -498,6 +515,7 @@ static inline int put_v4l2_input(struct v4l2_input *kp, struct v4l2_input __user
#define VIDIOCSFBUF32 _IOW('v',12, struct video_buffer32)
#define VIDIOCGFREQ32 _IOR('v',14, u32)
#define VIDIOCSFREQ32 _IOW('v',15, u32)
+#define VIDIOCSMICROCODE32 _IOW('v',27, struct video_code32)
/* VIDIOC_ENUMINPUT32 is VIDIOC_ENUMINPUT minus 4 bytes of padding alignement */
#define VIDIOC_ENUMINPUT32 VIDIOC_ENUMINPUT - _IOC(0, 0, 0, 4)
@@ -590,6 +608,7 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg
struct video_tuner vt;
struct video_buffer vb;
struct video_window vw;
+ struct video_code vc;
struct v4l2_format v2f;
struct v4l2_buffer v2b;
struct v4l2_framebuffer v2fb;
@@ -628,6 +647,7 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg
case VIDIOC_G_INPUT32: cmd = VIDIOC_G_INPUT; break;
case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break;
case VIDIOC_TRY_FMT32: cmd = VIDIOC_TRY_FMT; break;
+ case VIDIOCSMICROCODE32: cmd = VIDIOCSMICROCODE; break;
};
switch(cmd) {
@@ -703,6 +723,10 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg
case VIDIOC_G_FBUF:
case VIDIOC_G_INPUT:
compatible_arg = 0;
+ case VIDIOCSMICROCODE:
+ err = microcode32(&karg.vc, up);
+ compatible_arg = 0;
+ break;
};
if(err)
diff --git a/drivers/media/video/cpia2/Kconfig b/drivers/media/video/cpia2/Kconfig
index 513cc092738..e39a9615200 100644
--- a/drivers/media/video/cpia2/Kconfig
+++ b/drivers/media/video/cpia2/Kconfig
@@ -1,6 +1,6 @@
config VIDEO_CPIA2
tristate "CPiA2 Video For Linux"
- depends on VIDEO_DEV && USB
+ depends on VIDEO_DEV && USB && VIDEO_V4L1
---help---
This is the video4linux driver for cameras based on Vision's CPiA2
(Colour Processor Interface ASIC), such as the Digital Blue QX5
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
index 349632b48e9..b60177f173c 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -453,11 +453,13 @@ static int blackbird_load_firmware(struct cx8802_dev *dev)
if (firmware->size != BLACKBIRD_FIRM_IMAGE_SIZE) {
dprintk(0, "ERROR: Firmware size mismatch (have %zd, expected %d)\n",
firmware->size, BLACKBIRD_FIRM_IMAGE_SIZE);
+ release_firmware(firmware);
return -1;
}
if (0 != memcmp(firmware->data, magic, 8)) {
dprintk(0, "ERROR: Firmware magic mismatch, wrong file?\n");
+ release_firmware(firmware);
return -1;
}
@@ -478,6 +480,7 @@ static int blackbird_load_firmware(struct cx8802_dev *dev)
}
if (checksum) {
dprintk(0, "ERROR: Firmware load failed (checksum mismatch).\n");
+ release_firmware(firmware);
return -1;
}
release_firmware(firmware);
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index 72b630a91f4..c2556464899 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -89,7 +89,7 @@ static void cx88_ir_handle_key(struct cx88_IR *ir)
auxgpio = cx_read(MO_GP1_IO);
/* Take out the parity part */
- gpio+=(gpio & 0x7fd) + (auxgpio & 0xef);
+ gpio=(gpio & 0x7fd) + (auxgpio & 0xef);
} else
auxgpio = gpio;
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index 2225d4b9414..547cdbdb644 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -1180,7 +1180,6 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING |
V4L2_CAP_VBI_CAPTURE |
- V4L2_CAP_VIDEO_OVERLAY |
0;
if (UNSET != core->tuner_type)
cap->capabilities |= V4L2_CAP_TUNER;
@@ -1226,7 +1225,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
struct v4l2_format *f = arg;
return cx8800_try_fmt(dev,fh,f);
}
-#ifdef HAVE_V4L1
+#ifdef CONFIG_V4L1_COMPAT
/* --- streaming capture ------------------------------------- */
case VIDIOCGMBUF:
{
@@ -1585,7 +1584,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
*id = 0;
return 0;
}
-#ifdef HAVE_V4L1
+#ifdef CONFIG_V4L1_COMPAT
case VIDIOCSTUNER:
{
struct video_tuner *v = arg;
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c
index dbb75a7db19..56246b8578f 100644
--- a/drivers/media/video/msp3400-driver.c
+++ b/drivers/media/video/msp3400-driver.c
@@ -362,7 +362,7 @@ int msp_sleep(struct msp_state *state, int timeout)
}
/* ------------------------------------------------------------------------ */
-
+#ifdef CONFIG_VIDEO_V4L1
static int msp_mode_v4l2_to_v4l1(int rxsubchans, int audmode)
{
if (rxsubchans == V4L2_TUNER_SUB_MONO)
@@ -384,6 +384,7 @@ static int msp_mode_v4l1_to_v4l2(int mode)
return V4L2_TUNER_MODE_LANG1;
return V4L2_TUNER_MODE_MONO;
}
+#endif
static int msp_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
{
@@ -509,6 +510,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
/* --- v4l ioctls --- */
/* take care: bttv does userspace copying, we'll get a
kernel pointer here... */
+#ifdef CONFIG_VIDEO_V4L1
case VIDIOCGAUDIO:
{
struct video_audio *va = arg;
@@ -577,6 +579,12 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
}
case VIDIOCSFREQ:
+ {
+ /* new channel -- kick audio carrier scan */
+ msp_wake_thread(client);
+ break;
+ }
+#endif
case VIDIOC_S_FREQUENCY:
{
/* new channel -- kick audio carrier scan */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index 9b48abcf608..be1e5cc7808 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -852,7 +852,6 @@ unsigned long pvr2_hdw_get_sn(struct pvr2_hdw *hdw)
return hdw->serial_number;
}
-
int pvr2_hdw_get_unit_number(struct pvr2_hdw *hdw)
{
return hdw->unit_number;
@@ -2318,7 +2317,6 @@ void pvr2_hdw_poll_trigger_unlocked(struct pvr2_hdw *hdw)
}
}
-
/* Return name for this driver instance */
const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw)
{
@@ -2542,6 +2540,10 @@ static void pvr2_ctl_timeout(unsigned long data)
}
+/* Issue a command and get a response from the device. This extended
+ version includes a probe flag (which if set means that device errors
+ should not be logged or treated as fatal) and a timeout in jiffies.
+ This can be used to non-lethally probe the health of endpoint 1. */
static int pvr2_send_request_ex(struct pvr2_hdw *hdw,
unsigned int timeout,int probe_fl,
void *write_data,unsigned int write_len,
@@ -2970,6 +2972,7 @@ int pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *hdw)
}
+/* Stop / start video stream transport */
static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl)
{
int status;
@@ -3068,6 +3071,7 @@ int pvr2_hdw_gpio_chg_out(struct pvr2_hdw *hdw,u32 msk,u32 val)
}
+/* Find I2C address of eeprom */
static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw)
{
int result;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-io.c b/drivers/media/video/pvrusb2/pvrusb2-io.c
index 681f79c8064..1e393762546 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-io.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-io.c
@@ -26,6 +26,8 @@
#include <linux/slab.h>
#include <linux/mutex.h>
+static const char *pvr2_buffer_state_decode(enum pvr2_buffer_state);
+
#define BUFFER_SIG 0x47653271
// #define SANITY_CHECK_BUFFERS
@@ -515,6 +517,10 @@ void pvr2_stream_set_callback(struct pvr2_stream *sp,
}
/* Query / set the nominal buffer count */
+int pvr2_stream_get_buffer_count(struct pvr2_stream *sp)
+{
+ return sp->buffer_target_count;
+}
int pvr2_stream_set_buffer_count(struct pvr2_stream *sp,unsigned int cnt)
{
@@ -553,7 +559,6 @@ int pvr2_stream_get_ready_count(struct pvr2_stream *sp)
return sp->r_count;
}
-
void pvr2_stream_kill(struct pvr2_stream *sp)
{
struct pvr2_buffer *bp;
@@ -607,7 +612,6 @@ int pvr2_buffer_queue(struct pvr2_buffer *bp)
return ret;
}
-
int pvr2_buffer_set_buffer(struct pvr2_buffer *bp,void *ptr,unsigned int cnt)
{
int ret = 0;
@@ -646,7 +650,6 @@ int pvr2_buffer_get_status(struct pvr2_buffer *bp)
return bp->status;
}
-
int pvr2_buffer_get_id(struct pvr2_buffer *bp)
{
return bp->id;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-io.h b/drivers/media/video/pvrusb2/pvrusb2-io.h
index 96285ad234a..93279cc2a35 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-io.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-io.h
@@ -47,6 +47,7 @@ void pvr2_stream_set_callback(struct pvr2_stream *,
void *data);
/* Query / set the nominal buffer count */
+int pvr2_stream_get_buffer_count(struct pvr2_stream *);
int pvr2_stream_set_buffer_count(struct pvr2_stream *,unsigned int);
/* Get a pointer to a buffer that is either idle, ready, or is specified
@@ -58,6 +59,7 @@ struct pvr2_buffer *pvr2_stream_get_buffer(struct pvr2_stream *sp,int id);
/* Find out how many buffers are idle or ready */
int pvr2_stream_get_ready_count(struct pvr2_stream *);
+
/* Kill all pending buffers and throw away any ready buffers as well */
void pvr2_stream_kill(struct pvr2_stream *);
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ioread.c b/drivers/media/video/pvrusb2/pvrusb2-ioread.c
index f7a2e225a00..b71f9a961f8 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-ioread.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-ioread.c
@@ -213,7 +213,9 @@ int pvr2_ioread_setup(struct pvr2_ioread *cp,struct pvr2_stream *sp)
" pvr2_ioread_setup (tear-down) id=%p",cp);
pvr2_ioread_stop(cp);
pvr2_stream_kill(cp->stream);
- pvr2_stream_set_buffer_count(cp->stream,0);
+ if (pvr2_stream_get_buffer_count(cp->stream)) {
+ pvr2_stream_set_buffer_count(cp->stream,0);
+ }
cp->stream = NULL;
}
if (sp) {
@@ -251,7 +253,6 @@ int pvr2_ioread_set_enabled(struct pvr2_ioread *cp,int fl)
return ret;
}
-
static int pvr2_ioread_get_buffer(struct pvr2_ioread *cp)
{
int stat;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
index 6af55a8b6f0..d1dda5caf40 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
@@ -44,12 +44,16 @@ struct pvr2_sysfs {
struct kobj_type ktype;
struct class_device_attribute attr_v4l_minor_number;
struct class_device_attribute attr_unit_number;
+ int v4l_minor_number_created_ok;
+ int unit_number_created_ok;
};
#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
struct pvr2_sysfs_debugifc {
struct class_device_attribute attr_debugcmd;
struct class_device_attribute attr_debuginfo;
+ int debugcmd_created_ok;
+ int debuginfo_created_ok;
};
#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
@@ -67,6 +71,7 @@ struct pvr2_sysfs_ctl_item {
struct pvr2_sysfs_ctl_item *item_next;
struct attribute *attr_gen[7];
struct attribute_group grp;
+ int created_ok;
char name[80];
};
@@ -487,6 +492,7 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id)
struct pvr2_sysfs_func_set *fp;
struct pvr2_ctrl *cptr;
unsigned int cnt,acnt;
+ int ret;
if ((ctl_id < 0) || (ctl_id >= (sizeof(funcs)/sizeof(funcs[0])))) {
return;
@@ -589,7 +595,13 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id)
cip->grp.name = cip->name;
cip->grp.attrs = cip->attr_gen;
- sysfs_create_group(&sfp->class_dev->kobj,&cip->grp);
+ ret = sysfs_create_group(&sfp->class_dev->kobj,&cip->grp);
+ if (ret) {
+ printk(KERN_WARNING "%s: sysfs_create_group error: %d\n",
+ __FUNCTION__, ret);
+ return;
+ }
+ cip->created_ok = !0;
}
#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
@@ -600,6 +612,8 @@ static ssize_t debugcmd_store(struct class_device *,const char *,size_t count);
static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp)
{
struct pvr2_sysfs_debugifc *dip;
+ int ret;
+
dip = kmalloc(sizeof(*dip),GFP_KERNEL);
if (!dip) return;
memset(dip,0,sizeof(*dip));
@@ -613,17 +627,34 @@ static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp)
dip->attr_debuginfo.attr.mode = S_IRUGO;
dip->attr_debuginfo.show = debuginfo_show;
sfp->debugifc = dip;
- class_device_create_file(sfp->class_dev,&dip->attr_debugcmd);
- class_device_create_file(sfp->class_dev,&dip->attr_debuginfo);
+ ret = class_device_create_file(sfp->class_dev,&dip->attr_debugcmd);
+ if (ret < 0) {
+ printk(KERN_WARNING "%s: class_device_create_file error: %d\n",
+ __FUNCTION__, ret);
+ } else {
+ dip->debugcmd_created_ok = !0;
+ }
+ ret = class_device_create_file(sfp->class_dev,&dip->attr_debuginfo);
+ if (ret < 0) {
+ printk(KERN_WARNING "%s: class_device_create_file error: %d\n",
+ __FUNCTION__, ret);
+ } else {
+ dip->debuginfo_created_ok = !0;
+ }
}
static void pvr2_sysfs_tear_down_debugifc(struct pvr2_sysfs *sfp)
{
if (!sfp->debugifc) return;
- class_device_remove_file(sfp->class_dev,
- &sfp->debugifc->attr_debuginfo);
- class_device_remove_file(sfp->class_dev,&sfp->debugifc->attr_debugcmd);
+ if (sfp->debugifc->debuginfo_created_ok) {
+ class_device_remove_file(sfp->class_dev,
+ &sfp->debugifc->attr_debuginfo);
+ }
+ if (sfp->debugifc->debugcmd_created_ok) {
+ class_device_remove_file(sfp->class_dev,
+ &sfp->debugifc->attr_debugcmd);
+ }
kfree(sfp->debugifc);
sfp->debugifc = NULL;
}
@@ -645,7 +676,9 @@ static void pvr2_sysfs_tear_down_controls(struct pvr2_sysfs *sfp)
struct pvr2_sysfs_ctl_item *cip1,*cip2;
for (cip1 = sfp->item_first; cip1; cip1 = cip2) {
cip2 = cip1->item_next;
- sysfs_remove_group(&sfp->class_dev->kobj,&cip1->grp);
+ if (cip1->created_ok) {
+ sysfs_remove_group(&sfp->class_dev->kobj,&cip1->grp);
+ }
pvr2_sysfs_trace("Destroying pvr2_sysfs_ctl_item id=%p",cip1);
kfree(cip1);
}
@@ -675,8 +708,14 @@ static void class_dev_destroy(struct pvr2_sysfs *sfp)
pvr2_sysfs_tear_down_debugifc(sfp);
#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
pvr2_sysfs_tear_down_controls(sfp);
- class_device_remove_file(sfp->class_dev,&sfp->attr_v4l_minor_number);
- class_device_remove_file(sfp->class_dev,&sfp->attr_unit_number);
+ if (sfp->v4l_minor_number_created_ok) {
+ class_device_remove_file(sfp->class_dev,
+ &sfp->attr_v4l_minor_number);
+ }
+ if (sfp->unit_number_created_ok) {
+ class_device_remove_file(sfp->class_dev,
+ &sfp->attr_unit_number);
+ }
pvr2_sysfs_trace("Destroying class_dev id=%p",sfp->class_dev);
sfp->class_dev->class_data = NULL;
class_device_unregister(sfp->class_dev);
@@ -709,6 +748,8 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
{
struct usb_device *usb_dev;
struct class_device *class_dev;
+ int ret;
+
usb_dev = pvr2_hdw_get_dev(sfp->channel.hdw);
if (!usb_dev) return;
class_dev = kmalloc(sizeof(*class_dev),GFP_KERNEL);
@@ -733,20 +774,40 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
sfp->class_dev = class_dev;
class_dev->class_data = sfp;
- class_device_register(class_dev);
+ ret = class_device_register(class_dev);
+ if (ret) {
+ printk(KERN_ERR "%s: class_device_register failed\n",
+ __FUNCTION__);
+ kfree(class_dev);
+ return;
+ }
sfp->attr_v4l_minor_number.attr.owner = THIS_MODULE;
sfp->attr_v4l_minor_number.attr.name = "v4l_minor_number";
sfp->attr_v4l_minor_number.attr.mode = S_IRUGO;
sfp->attr_v4l_minor_number.show = v4l_minor_number_show;
sfp->attr_v4l_minor_number.store = NULL;
- class_device_create_file(sfp->class_dev,&sfp->attr_v4l_minor_number);
+ ret = class_device_create_file(sfp->class_dev,
+ &sfp->attr_v4l_minor_number);
+ if (ret < 0) {
+ printk(KERN_WARNING "%s: class_device_create_file error: %d\n",
+ __FUNCTION__, ret);
+ } else {
+ sfp->v4l_minor_number_created_ok = !0;
+ }
+
sfp->attr_unit_number.attr.owner = THIS_MODULE;
sfp->attr_unit_number.attr.name = "unit_number";
sfp->attr_unit_number.attr.mode = S_IRUGO;
sfp->attr_unit_number.show = unit_number_show;
sfp->attr_unit_number.store = NULL;
- class_device_create_file(sfp->class_dev,&sfp->attr_unit_number);
+ ret = class_device_create_file(sfp->class_dev,&sfp->attr_unit_number);
+ if (ret < 0) {
+ printk(KERN_WARNING "%s: class_device_create_file error: %d\n",
+ __FUNCTION__, ret);
+ } else {
+ sfp->unit_number_created_ok = !0;
+ }
pvr2_sysfs_add_controls(sfp);
#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
index f1fd69e7f11..d73cff1970a 100644
--- a/drivers/media/video/saa7134/saa7134-alsa.c
+++ b/drivers/media/video/saa7134/saa7134-alsa.c
@@ -997,9 +997,9 @@ static int saa7134_alsa_init(void)
struct saa7134_dev *dev = NULL;
struct list_head *list;
- if (!dmasound_init && !dmasound_exit) {
- dmasound_init = alsa_device_init;
- dmasound_exit = alsa_device_exit;
+ if (!saa7134_dmasound_init && !saa7134_dmasound_exit) {
+ saa7134_dmasound_init = alsa_device_init;
+ saa7134_dmasound_exit = alsa_device_exit;
} else {
printk(KERN_WARNING "saa7134 ALSA: can't load, DMA sound handler already assigned (probably to OSS)\n");
return -EBUSY;
@@ -1036,8 +1036,8 @@ static void saa7134_alsa_exit(void)
snd_card_free(snd_saa7134_cards[idx]);
}
- dmasound_init = NULL;
- dmasound_exit = NULL;
+ saa7134_dmasound_init = NULL;
+ saa7134_dmasound_exit = NULL;
printk(KERN_INFO "saa7134 ALSA driver for DMA sound unloaded\n");
return;
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index 6e97cc84ba8..be3a81fc90a 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -95,8 +95,8 @@ LIST_HEAD(saa7134_devlist);
static LIST_HEAD(mops_list);
static unsigned int saa7134_devcount;
-int (*dmasound_init)(struct saa7134_dev *dev);
-int (*dmasound_exit)(struct saa7134_dev *dev);
+int (*saa7134_dmasound_init)(struct saa7134_dev *dev);
+int (*saa7134_dmasound_exit)(struct saa7134_dev *dev);
#define dprintk(fmt, arg...) if (core_debug) \
printk(KERN_DEBUG "%s/core: " fmt, dev->name , ## arg)
@@ -1008,8 +1008,8 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
/* check for signal */
saa7134_irq_video_intl(dev);
- if (dmasound_init && !dev->dmasound.priv_data) {
- dmasound_init(dev);
+ if (saa7134_dmasound_init && !dev->dmasound.priv_data) {
+ saa7134_dmasound_init(dev);
}
return 0;
@@ -1036,8 +1036,8 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev)
struct saa7134_mpeg_ops *mops;
/* Release DMA sound modules if present */
- if (dmasound_exit && dev->dmasound.priv_data) {
- dmasound_exit(dev);
+ if (saa7134_dmasound_exit && dev->dmasound.priv_data) {
+ saa7134_dmasound_exit(dev);
}
/* debugging ... */
@@ -1169,8 +1169,8 @@ EXPORT_SYMBOL(saa7134_boards);
/* ----------------- for the DMA sound modules --------------- */
-EXPORT_SYMBOL(dmasound_init);
-EXPORT_SYMBOL(dmasound_exit);
+EXPORT_SYMBOL(saa7134_dmasound_init);
+EXPORT_SYMBOL(saa7134_dmasound_exit);
EXPORT_SYMBOL(saa7134_pgtable_free);
EXPORT_SYMBOL(saa7134_pgtable_build);
EXPORT_SYMBOL(saa7134_pgtable_alloc);
diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c
index 3895d05804a..2e3ba5f3145 100644
--- a/drivers/media/video/saa7134/saa7134-oss.c
+++ b/drivers/media/video/saa7134/saa7134-oss.c
@@ -993,9 +993,9 @@ static int saa7134_oss_init(void)
struct saa7134_dev *dev = NULL;
struct list_head *list;
- if (!dmasound_init && !dmasound_exit) {
- dmasound_init = oss_device_init;
- dmasound_exit = oss_device_exit;
+ if (!saa7134_dmasound_init && !saa7134_dmasound_exit) {
+ saa7134_dmasound_init = oss_device_init;
+ saa7134_dmasound_exit = oss_device_exit;
} else {
printk(KERN_WARNING "saa7134 OSS: can't load, DMA sound handler already assigned (probably to ALSA)\n");
return -EBUSY;
@@ -1037,8 +1037,8 @@ static void saa7134_oss_exit(void)
}
- dmasound_init = NULL;
- dmasound_exit = NULL;
+ saa7134_dmasound_init = NULL;
+ saa7134_dmasound_exit = NULL;
printk(KERN_INFO "saa7134 OSS driver for DMA sound unloaded\n");
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
index e4156ec9c6d..8656f2400e1 100644
--- a/drivers/media/video/saa7134/saa7134-video.c
+++ b/drivers/media/video/saa7134/saa7134-video.c
@@ -40,7 +40,7 @@
static unsigned int video_debug = 0;
static unsigned int gbuffers = 8;
-static unsigned int noninterlaced = 0;
+static unsigned int noninterlaced = 1;
static unsigned int gbufsize = 720*576*4;
static unsigned int gbufsize_max = 720*576*4;
module_param(video_debug, int, 0644);
@@ -48,7 +48,7 @@ MODULE_PARM_DESC(video_debug,"enable debug messages [video]");
module_param(gbuffers, int, 0444);
MODULE_PARM_DESC(gbuffers,"number of capture buffers, range 2-32");
module_param(noninterlaced, int, 0644);
-MODULE_PARM_DESC(noninterlaced,"video input is noninterlaced");
+MODULE_PARM_DESC(noninterlaced,"capture non interlaced video");
#define dprintk(fmt, arg...) if (video_debug) \
printk(KERN_DEBUG "%s/video: " fmt, dev->name , ## arg)
@@ -2087,7 +2087,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
struct v4l2_format *f = arg;
return saa7134_try_fmt(dev,fh,f);
}
-#ifdef HAVE_V4L1
+#ifdef CONFIG_V4L1_COMPAT
case VIDIOCGMBUF:
{
struct video_mbuf *mbuf = arg;
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index d5ee99c574c..c04ce6152fd 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -586,8 +586,8 @@ void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf);
int saa7134_set_dmabits(struct saa7134_dev *dev);
-extern int (*dmasound_init)(struct saa7134_dev *dev);
-extern int (*dmasound_exit)(struct saa7134_dev *dev);
+extern int (*saa7134_dmasound_init)(struct saa7134_dev *dev);
+extern int (*saa7134_dmasound_exit)(struct saa7134_dev *dev);
/* ----------------------------------------------------------- */
diff --git a/drivers/media/video/stradis.c b/drivers/media/video/stradis.c
index b36ba9fa3a2..5686547ba76 100644
--- a/drivers/media/video/stradis.c
+++ b/drivers/media/video/stradis.c
@@ -2181,7 +2181,6 @@ static struct pci_device_id stradis_pci_tbl[] = {
{ 0 }
};
-MODULE_DEVICE_TABLE(pci, stradis_pci_tbl);
static struct pci_driver stradis_driver = {
.name = "stradis",
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index f7eb402d5f2..40590bae5ff 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -196,14 +196,6 @@ static void set_type(struct i2c_client *c, unsigned int type,
i2c_master_send(c, buffer, 4);
default_tuner_init(c);
break;
- case TUNER_LG_TDVS_H06XF:
- /* Set the Auxiliary Byte. */
- buffer[2] &= ~0x20;
- buffer[2] |= 0x18;
- buffer[3] = 0x20;
- i2c_master_send(c, buffer, 4);
- default_tuner_init(c);
- break;
case TUNER_PHILIPS_TD1316:
buffer[0] = 0x0b;
buffer[1] = 0xdc;
@@ -598,6 +590,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
if (t->standby)
t->standby (client);
break;
+#ifdef CONFIG_VIDEO_V4L1
case VIDIOCSAUDIO:
if (check_mode(t, "VIDIOCSAUDIO") == EINVAL)
return 0;
@@ -607,17 +600,6 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
/* Should be implemented, since bttv calls it */
tuner_dbg("VIDIOCSAUDIO not implemented.\n");
break;
- case TDA9887_SET_CONFIG:
- if (t->type == TUNER_TDA9887) {
- int *i = arg;
-
- t->tda9887_config = *i;
- set_freq(client, t->tv_freq);
- }
- break;
- /* --- v4l ioctls --- */
- /* take care: bttv does userspace copying, we'll get a
- kernel pointer here... */
case VIDIOCSCHAN:
{
static const v4l2_std_id map[] = {
@@ -701,7 +683,18 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
return 0;
}
+#endif
+ case TDA9887_SET_CONFIG:
+ if (t->type == TUNER_TDA9887) {
+ int *i = arg;
+ t->tda9887_config = *i;
+ set_freq(client, t->tv_freq);
+ }
+ break;
+ /* --- v4l ioctls --- */
+ /* take care: bttv does userspace copying, we'll get a
+ kernel pointer here... */
case VIDIOC_S_STD:
{
v4l2_std_id *id = arg;
diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c
index d071c5cbf01..abe37cf632c 100644
--- a/drivers/media/video/tuner-simple.c
+++ b/drivers/media/video/tuner-simple.c
@@ -339,7 +339,20 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
if (4 != (rc = i2c_master_send(c,buffer,4)))
tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
- if (t->type == TUNER_MICROTUNE_4042FI5) {
+ switch (t->type) {
+ case TUNER_LG_TDVS_H06XF:
+ /* Set the Auxiliary Byte. */
+ buffer[0] = buffer[2];
+ buffer[0] &= ~0x20;
+ buffer[0] |= 0x18;
+ buffer[1] = 0x20;
+ tuner_dbg("tv 0x%02x 0x%02x\n",buffer[0],buffer[1]);
+
+ if (2 != (rc = i2c_master_send(c,buffer,2)))
+ tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc);
+ break;
+ case TUNER_MICROTUNE_4042FI5:
+ {
// FIXME - this may also work for other tuners
unsigned long timeout = jiffies + msecs_to_jiffies(1);
u8 status_byte = 0;
@@ -364,10 +377,12 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
buffer[2] = config;
buffer[3] = cb;
tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
- buffer[0],buffer[1],buffer[2],buffer[3]);
+ buffer[0],buffer[1],buffer[2],buffer[3]);
if (4 != (rc = i2c_master_send(c,buffer,4)))
tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
+ break;
+ }
}
}
diff --git a/drivers/media/video/usbvideo/Kconfig b/drivers/media/video/usbvideo/Kconfig
index 59fb899f31f..a0fd82b924f 100644
--- a/drivers/media/video/usbvideo/Kconfig
+++ b/drivers/media/video/usbvideo/Kconfig
@@ -3,7 +3,7 @@ config VIDEO_USBVIDEO
config USB_VICAM
tristate "USB 3com HomeConnect (aka vicam) support (EXPERIMENTAL)"
- depends on USB && VIDEO_V4L1 && EXPERIMENTAL
+ depends on USB && VIDEO_DEV && VIDEO_V4L1 && EXPERIMENTAL
select VIDEO_USBVIDEO
---help---
Say Y here if you have 3com homeconnect camera (vicam).
@@ -13,7 +13,7 @@ config USB_VICAM
config USB_IBMCAM
tristate "USB IBM (Xirlink) C-it Camera support"
- depends on USB && VIDEO_V4L1
+ depends on USB && VIDEO_DEV && VIDEO_V4L1
select VIDEO_USBVIDEO
---help---
Say Y here if you want to connect a IBM "C-It" camera, also known as
@@ -28,7 +28,7 @@ config USB_IBMCAM
config USB_KONICAWC
tristate "USB Konica Webcam support"
- depends on USB && VIDEO_V4L1
+ depends on USB && VIDEO_DEV && VIDEO_V4L1
select VIDEO_USBVIDEO
---help---
Say Y here if you want support for webcams based on a Konica
@@ -39,7 +39,7 @@ config USB_KONICAWC
config USB_QUICKCAM_MESSENGER
tristate "USB Logitech Quickcam Messenger"
- depends on USB && VIDEO_DEV
+ depends on USB && VIDEO_DEV && VIDEO_V4L1
select VIDEO_USBVIDEO
---help---
Say Y or M here to enable support for the USB Logitech Quickcam
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index f06dc19e504..2ecbeffb559 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -202,7 +202,7 @@ static char *v4l2_memory_names[] = {
/* ------------------------------------------------------------------ */
/* debug help functions */
-#ifdef HAVE_V4L1
+#ifdef CONFIG_V4L1_COMPAT
static const char *v4l1_ioctls[] = {
[_IOC_NR(VIDIOCGCAP)] = "VIDIOCGCAP",
[_IOC_NR(VIDIOCGCHAN)] = "VIDIOCGCHAN",
@@ -301,7 +301,7 @@ static const char *v4l2_ioctls[] = {
#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
static const char *v4l2_int_ioctls[] = {
-#ifdef HAVE_VIDEO_DECODER
+#ifdef CONFIG_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",
@@ -367,7 +367,7 @@ void v4l_printk_ioctl(unsigned int cmd)
(_IOC_NR(cmd) < V4L2_INT_IOCTLS) ?
v4l2_int_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd);
break;
-#ifdef HAVE_V4L1
+#ifdef CONFIG_V4L1_COMPAT
case 'v':
printk("v4l1 ioctl %s, dir=%s (0x%08x)\n",
(_IOC_NR(cmd) < V4L1_IOCTLS) ?
@@ -414,6 +414,7 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
printk ("%s: tuner type=%d\n", s, *p);
break;
}
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
case DECODER_SET_VBI_BYPASS:
case DECODER_ENABLE_OUTPUT:
case DECODER_GET_STATUS:
@@ -424,6 +425,7 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
case VIDIOCCAPTURE:
case VIDIOCSYNC:
case VIDIOCSWRITEMODE:
+#endif
case TUNER_SET_TYPE_ADDR:
case TUNER_SET_STANDBY:
case TDA9887_SET_CONFIG:
@@ -755,6 +757,7 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
p->afc);
break;
}
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
case VIDIOCGVBIFMT:
case VIDIOCSVBIFMT:
{
@@ -924,6 +927,14 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
p->clipcount);
break;
}
+ case VIDIOCGFREQ:
+ case VIDIOCSFREQ:
+ {
+ unsigned long *p=arg;
+ printk ("%s: value=%lu\n", s, *p);
+ break;
+ }
+#endif
case VIDIOC_INT_AUDIO_CLOCK_FREQ:
case VIDIOC_INT_I2S_CLOCK_FREQ:
case VIDIOC_INT_S_STANDBY:
@@ -933,13 +944,6 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
printk ("%s: value=%d\n", s, *p);
break;
}
- case VIDIOCGFREQ:
- case VIDIOCSFREQ:
- {
- unsigned long *p=arg;
- printk ("%s: value=%lu\n", s, *p);
- break;
- }
case VIDIOC_G_STD:
case VIDIOC_S_STD:
case VIDIOC_QUERYSTD:
diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c
index b26ebaff226..0fc90cd393f 100644
--- a/drivers/media/video/videodev.c
+++ b/drivers/media/video/videodev.c
@@ -760,7 +760,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
ret=vfd->vidioc_overlay(file, fh, *i);
break;
}
-#ifdef HAVE_V4L1
+#ifdef CONFIG_V4L1_COMPAT
/* --- streaming capture ------------------------------------- */
case VIDIOCGMBUF:
{
@@ -1512,6 +1512,7 @@ int video_register_device(struct video_device *vfd, int type, int nr)
int i=0;
int base;
int end;
+ int ret;
char *name_base;
switch(type)
@@ -1537,6 +1538,8 @@ int video_register_device(struct video_device *vfd, int type, int nr)
name_base = "radio";
break;
default:
+ printk(KERN_ERR "%s called with unknown type: %d\n",
+ __FUNCTION__, type);
return -1;
}
@@ -1571,9 +1574,18 @@ int video_register_device(struct video_device *vfd, int type, int nr)
vfd->class_dev.class = &video_class;
vfd->class_dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor);
sprintf(vfd->class_dev.class_id, "%s%d", name_base, i - base);
- class_device_register(&vfd->class_dev);
- class_device_create_file(&vfd->class_dev,
- &class_device_attr_name);
+ ret = class_device_register(&vfd->class_dev);
+ if (ret < 0) {
+ printk(KERN_ERR "%s: class_device_register failed\n",
+ __FUNCTION__);
+ goto fail_minor;
+ }
+ ret = class_device_create_file(&vfd->class_dev, &class_device_attr_name);
+ if (ret < 0) {
+ printk(KERN_ERR "%s: class_device_create_file 'name' failed\n",
+ __FUNCTION__);
+ goto fail_classdev;
+ }
#if 1
/* needed until all drivers are fixed */
@@ -1583,6 +1595,15 @@ int video_register_device(struct video_device *vfd, int type, int nr)
"http://lwn.net/Articles/36850/\n", vfd->name);
#endif
return 0;
+
+fail_classdev:
+ class_device_unregister(&vfd->class_dev);
+fail_minor:
+ mutex_lock(&videodev_lock);
+ video_device[vfd->minor] = NULL;
+ vfd->minor = -1;
+ mutex_unlock(&videodev_lock);
+ return ret;
}
/**
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index 41d23c8acbd..38bd0c1018c 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -986,7 +986,7 @@ static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p)
file->f_flags & O_NONBLOCK));
}
-#ifdef HAVE_V4L1
+#ifdef CONFIG_V4L1_COMPAT
static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf)
{
struct vivi_fh *fh=priv;
@@ -1328,7 +1328,7 @@ static struct video_device vivi = {
.vidioc_s_ctrl = vidioc_s_ctrl,
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
-#ifdef HAVE_V4L1
+#ifdef CONFIG_V4L1_COMPAT
.vidiocgmbuf = vidiocgmbuf,
#endif
.tvnorms = tvnorms,
diff --git a/drivers/message/fusion/Kconfig b/drivers/message/fusion/Kconfig
index bbc22985288..ea31d847051 100644
--- a/drivers/message/fusion/Kconfig
+++ b/drivers/message/fusion/Kconfig
@@ -48,10 +48,8 @@ config FUSION_SAS
List of supported controllers:
LSISAS1064
- LSISAS1066
LSISAS1068
LSISAS1064E
- LSISAS1066E
LSISAS1068E
config FUSION_MAX_SGE
diff --git a/drivers/message/fusion/Makefile b/drivers/message/fusion/Makefile
index b114236f439..341691390e8 100644
--- a/drivers/message/fusion/Makefile
+++ b/drivers/message/fusion/Makefile
@@ -9,7 +9,6 @@
#EXTRA_CFLAGS += -DMPT_DEBUG_EXIT
#EXTRA_CFLAGS += -DMPT_DEBUG_FAIL
-
#
# driver/module specifics...
#
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index 43308df6462..29d0635cce1 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -436,8 +436,6 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
*/
if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) {
freereq = 0;
- devtverboseprintk((MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p does not return Request frame\n",
- ioc->name, pEvReply));
} else {
devtverboseprintk((MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
ioc->name, pEvReply));
@@ -678,19 +676,19 @@ int
mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, int cb_idx)
{
MPT_ADAPTER *ioc;
+ const struct pci_device_id *id;
- if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) {
+ if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
return -EINVAL;
- }
MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
/* call per pci device probe entry point */
list_for_each_entry(ioc, &ioc_list, list) {
- if(dd_cbfunc->probe) {
- dd_cbfunc->probe(ioc->pcidev,
- ioc->pcidev->driver->id_table);
- }
+ id = ioc->pcidev->driver ?
+ ioc->pcidev->driver->id_table : NULL;
+ if (dd_cbfunc->probe)
+ dd_cbfunc->probe(ioc->pcidev, id);
}
return 0;
@@ -1056,9 +1054,8 @@ mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
dinitprintk((MYIOC_s_INFO_FMT
"host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
- ioc->name,
- ioc->HostPageBuffer,
- ioc->HostPageBuffer_dma,
+ ioc->name, ioc->HostPageBuffer,
+ (u32)ioc->HostPageBuffer_dma,
host_page_buffer_sz));
ioc->alloc_total += host_page_buffer_sz;
ioc->HostPageBuffer_sz = host_page_buffer_sz;
@@ -1380,6 +1377,7 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
printk(KERN_WARNING MYNAM
": WARNING - %s did not initialize properly! (%d)\n",
ioc->name, r);
+
list_del(&ioc->list);
if (ioc->alt_ioc)
ioc->alt_ioc->alt_ioc = NULL;
@@ -1762,9 +1760,9 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
* chips (mpt_adapter_disable,
* mpt_diag_reset)
*/
- ioc->cached_fw = NULL;
ddlprintk((MYIOC_s_INFO_FMT ": mpt_upload: alt_%s has cached_fw=%p \n",
ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
+ ioc->alt_ioc->cached_fw = NULL;
}
} else {
printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
@@ -1885,7 +1883,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
/* FIXME? Examine results here? */
}
-out:
+ out:
if ((ret != 0) && irq_allocated) {
free_irq(ioc->pci_irq, ioc);
if (mpt_msi_enable)
@@ -2670,6 +2668,7 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
dinitprintk((MYIOC_s_INFO_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
ioc->name, count));
+ ioc->aen_event_read_flag=0;
return r;
}
@@ -2737,6 +2736,8 @@ mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
+ ioc->alloc_total += size;
+ ioc->alt_ioc->alloc_total -= size;
} else {
if ( (ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma) ) )
ioc->alloc_total += size;
@@ -3166,6 +3167,7 @@ KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
static int
mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
{
+ MPT_ADAPTER *iocp=NULL;
u32 diag0val;
u32 doorbell;
int hard_reset_done = 0;
@@ -3301,17 +3303,23 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
/* FIXME? Examine results here? */
}
- if (ioc->cached_fw) {
+ if (ioc->cached_fw)
+ iocp = ioc;
+ else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
+ iocp = ioc->alt_ioc;
+ if (iocp) {
/* If the DownloadBoot operation fails, the
* IOC will be left unusable. This is a fatal error
* case. _diag_reset will return < 0
*/
for (count = 0; count < 30; count ++) {
- diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+ diag0val = CHIPREG_READ32(&iocp->chip->Diagnostic);
if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
break;
}
+ dprintk((MYIOC_s_INFO_FMT "cached_fw: diag0val=%x count=%d\n",
+ iocp->name, diag0val, count));
/* wait 1 sec */
if (sleepFlag == CAN_SLEEP) {
msleep (1000);
@@ -3320,7 +3328,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
}
}
if ((count = mpt_downloadboot(ioc,
- (MpiFwHeader_t *)ioc->cached_fw, sleepFlag)) < 0) {
+ (MpiFwHeader_t *)iocp->cached_fw, sleepFlag)) < 0) {
printk(KERN_WARNING MYNAM
": firmware downloadboot failure (%d)!\n", count);
}
@@ -3907,18 +3915,18 @@ WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
if (sleepFlag == CAN_SLEEP) {
while (--cntdn) {
+ msleep (1);
intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
break;
- msleep (1);
count++;
}
} else {
while (--cntdn) {
+ mdelay (1);
intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
break;
- mdelay (1);
count++;
}
}
@@ -4883,6 +4891,7 @@ mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
if (!pIoc4)
return;
+ ioc->alloc_total += iocpage4sz;
} else {
ioc4_dma = ioc->spi_data.IocPg4_dma;
iocpage4sz = ioc->spi_data.IocPg4Sz;
@@ -4899,6 +4908,7 @@ mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
} else {
pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
ioc->spi_data.pIocPg4 = NULL;
+ ioc->alloc_total -= iocpage4sz;
}
}
@@ -5030,19 +5040,18 @@ SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
EventAck_t *pAck;
if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
- printk(MYIOC_s_WARN_FMT "Unable to allocate event ACK "
- "request frame for Event=%x EventContext=%x EventData=%x!\n",
- ioc->name, evnp->Event, le32_to_cpu(evnp->EventContext),
- le32_to_cpu(evnp->Data[0]));
+ dfailprintk((MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
+ ioc->name,__FUNCTION__));
return -1;
}
- memset(pAck, 0, sizeof(*pAck));
- dprintk((MYIOC_s_INFO_FMT "Sending EventAck\n", ioc->name));
+ devtverboseprintk((MYIOC_s_INFO_FMT "Sending EventAck\n", ioc->name));
pAck->Function = MPI_FUNCTION_EVENT_ACK;
pAck->ChainOffset = 0;
+ pAck->Reserved[0] = pAck->Reserved[1] = 0;
pAck->MsgFlags = 0;
+ pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
pAck->Event = evnp->Event;
pAck->EventContext = evnp->EventContext;
@@ -5704,9 +5713,9 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr)
break;
case MPI_EVENT_EVENT_CHANGE:
if (evData0)
- ds = "Events(ON) Change";
+ ds = "Events ON";
else
- ds = "Events(OFF) Change";
+ ds = "Events OFF";
break;
case MPI_EVENT_INTEGRATED_RAID:
{
@@ -5777,8 +5786,27 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr)
break;
case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
snprintf(evStr, EVENT_DESCR_STR_SZ,
- "SAS Device Status Change: No Persistancy "
- "Added: id=%d", id);
+ "SAS Device Status Change: No Persistancy: id=%d", id);
+ break;
+ case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
+ snprintf(evStr, EVENT_DESCR_STR_SZ,
+ "SAS Device Status Change: Internal Device Reset : id=%d", id);
+ break;
+ case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
+ snprintf(evStr, EVENT_DESCR_STR_SZ,
+ "SAS Device Status Change: Internal Task Abort : id=%d", id);
+ break;
+ case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
+ snprintf(evStr, EVENT_DESCR_STR_SZ,
+ "SAS Device Status Change: Internal Abort Task Set : id=%d", id);
+ break;
+ case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
+ snprintf(evStr, EVENT_DESCR_STR_SZ,
+ "SAS Device Status Change: Internal Clear Task Set : id=%d", id);
+ break;
+ case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
+ snprintf(evStr, EVENT_DESCR_STR_SZ,
+ "SAS Device Status Change: Internal Query Task : id=%d", id);
break;
default:
snprintf(evStr, EVENT_DESCR_STR_SZ,
@@ -6034,7 +6062,7 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply
* @ioc: Pointer to MPT_ADAPTER structure
* @log_info: U32 LogInfo reply word from the IOC
*
- * Refer to lsi/fc_log.h.
+ * Refer to lsi/mpi_log_fc.h.
*/
static void
mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
@@ -6131,8 +6159,10 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
"Invalid SAS Address", /* 01h */
NULL, /* 02h */
"Invalid Page", /* 03h */
- NULL, /* 04h */
- "Task Terminated" /* 05h */
+ "Diag Message Error", /* 04h */
+ "Task Terminated", /* 05h */
+ "Enclosure Management", /* 06h */
+ "Target Mode" /* 07h */
};
static char *pl_code_str[] = {
NULL, /* 00h */
@@ -6158,7 +6188,7 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
"IO Executed", /* 14h */
"Persistant Reservation Out Not Affiliation Owner", /* 15h */
"Open Transmit DMA Abort", /* 16h */
- NULL, /* 17h */
+ "IO Device Missing Delay Retry", /* 17h */
NULL, /* 18h */
NULL, /* 19h */
NULL, /* 1Ah */
@@ -6238,7 +6268,7 @@ static void
mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
{
u32 status = ioc_status & MPI_IOCSTATUS_MASK;
- char *desc = "";
+ char *desc = NULL;
switch (status) {
case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
@@ -6348,7 +6378,7 @@ mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
desc = "Others";
break;
}
- if (desc != "")
+ if (desc != NULL)
printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04x): %s\n", ioc->name, status, desc);
}
@@ -6386,7 +6416,6 @@ EXPORT_SYMBOL(mpt_alloc_fw_memory);
EXPORT_SYMBOL(mpt_free_fw_memory);
EXPORT_SYMBOL(mptbase_sas_persist_operation);
-
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
* fusion_init - Fusion MPT base driver initialization routine.
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
index a5ce10b67d0..d4cb144ab40 100644
--- a/drivers/message/fusion/mptbase.h
+++ b/drivers/message/fusion/mptbase.h
@@ -75,8 +75,8 @@
#define COPYRIGHT "Copyright (c) 1999-2005 " MODULEAUTHOR
#endif
-#define MPT_LINUX_VERSION_COMMON "3.04.00"
-#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.00"
+#define MPT_LINUX_VERSION_COMMON "3.04.01"
+#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.01"
#define WHAT_MAGIC_STRING "@" "(" "#" ")"
#define show_mptmod_ver(s,ver) \
@@ -307,8 +307,8 @@ typedef struct _SYSIF_REGS
u32 HostIndex; /* 50 Host Index register */
u32 Reserved4[15]; /* 54-8F */
u32 Fubar; /* 90 For Fubar usage */
- u32 Reserved5[1050];/* 94-10F8 */
- u32 Reset_1078; /* 10FC Reset 1078 */
+ u32 Reserved5[1050];/* 94-10F8 */
+ u32 Reset_1078; /* 10FC Reset 1078 */
} SYSIF_REGS;
/*
@@ -363,6 +363,7 @@ typedef struct _VirtDevice {
#define MPT_TARGET_FLAGS_VALID_56 0x10
#define MPT_TARGET_FLAGS_SAF_TE_ISSUED 0x20
#define MPT_TARGET_FLAGS_RAID_COMPONENT 0x40
+#define MPT_TARGET_FLAGS_LED_ON 0x80
/*
* /proc/mpt interface
@@ -634,7 +635,6 @@ typedef struct _MPT_ADAPTER
u16 handle;
int sas_index; /* index refrencing */
MPT_SAS_MGMT sas_mgmt;
- int num_ports;
struct work_struct sas_persist_task;
struct work_struct fc_setup_reset_work;
@@ -644,7 +644,6 @@ typedef struct _MPT_ADAPTER
struct work_struct fc_rescan_work;
char fc_rescan_work_q_name[KOBJ_NAME_LEN];
struct workqueue_struct *fc_rescan_work_q;
- u8 port_serial_number;
} MPT_ADAPTER;
/*
@@ -982,7 +981,7 @@ typedef struct _MPT_SCSI_HOST {
wait_queue_head_t scandv_waitq;
int scandv_wait_done;
long last_queue_full;
- u8 mpt_pq_filter;
+ u16 tm_iocstatus;
} MPT_SCSI_HOST;
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c
index b4967bb8a7d..30975ccd994 100644
--- a/drivers/message/fusion/mptctl.c
+++ b/drivers/message/fusion/mptctl.c
@@ -2332,7 +2332,7 @@ done_free_mem:
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/* Prototype Routine for the HP HOST INFO command.
+/* Prototype Routine for the HOST INFO command.
*
* Outputs: None.
* Return: 0 if successful
@@ -2568,7 +2568,7 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/* Prototype Routine for the HP TARGET INFO command.
+/* Prototype Routine for the TARGET INFO command.
*
* Outputs: None.
* Return: 0 if successful
diff --git a/drivers/message/fusion/mptctl.h b/drivers/message/fusion/mptctl.h
index a2f8a97992e..043941882c6 100644
--- a/drivers/message/fusion/mptctl.h
+++ b/drivers/message/fusion/mptctl.h
@@ -354,9 +354,6 @@ struct mpt_ioctl_command32 {
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- * HP Specific IOCTL Defines and Structures
- */
#define CPQFCTS_IOC_MAGIC 'Z'
#define HP_IOC_MAGIC 'Z'
@@ -364,8 +361,6 @@ struct mpt_ioctl_command32 {
#define HP_GETHOSTINFO1 _IOR(HP_IOC_MAGIC, 20, hp_host_info_rev0_t)
#define HP_GETTARGETINFO _IOR(HP_IOC_MAGIC, 21, hp_target_info_t)
-/* All HP IOCTLs must include this header
- */
typedef struct _hp_header {
unsigned int iocnum;
unsigned int host;
diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c
index a8f2fa98545..90da7d63b08 100644
--- a/drivers/message/fusion/mptfc.c
+++ b/drivers/message/fusion/mptfc.c
@@ -77,10 +77,6 @@ MODULE_DESCRIPTION(my_NAME);
MODULE_LICENSE("GPL");
/* Command line args */
-static int mpt_pq_filter = 0;
-module_param(mpt_pq_filter, int, 0);
-MODULE_PARM_DESC(mpt_pq_filter, " Enable peripheral qualifier filter: enable=1 (default=0)");
-
#define MPTFC_DEV_LOSS_TMO (60)
static int mptfc_dev_loss_tmo = MPTFC_DEV_LOSS_TMO; /* reasonable default */
module_param(mptfc_dev_loss_tmo, int, 0);
@@ -513,8 +509,7 @@ mptfc_slave_alloc(struct scsi_device *sdev)
if (vtarget->num_luns == 0) {
vtarget->ioc_id = hd->ioc->id;
- vtarget->tflags = MPT_TARGET_FLAGS_Q_YES |
- MPT_TARGET_FLAGS_VALID_INQUIRY;
+ vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
hd->Targets[sdev->id] = vtarget;
}
@@ -1129,13 +1124,6 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
hd->timer.data = (unsigned long) hd;
hd->timer.function = mptscsih_timer_expired;
- hd->mpt_pq_filter = mpt_pq_filter;
-
- ddvprintk((MYIOC_s_INFO_FMT
- "mpt_pq_filter %x\n",
- ioc->name,
- mpt_pq_filter));
-
init_waitqueue_head(&hd->scandv_waitq);
hd->scandv_wait_done = 0;
hd->last_queue_full = 0;
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c
index f7bd8b11ed3..f66f2203143 100644
--- a/drivers/message/fusion/mptsas.c
+++ b/drivers/message/fusion/mptsas.c
@@ -67,20 +67,19 @@
#define my_VERSION MPT_LINUX_VERSION_COMMON
#define MYNAM "mptsas"
+/*
+ * Reserved channel for integrated raid
+ */
+#define MPTSAS_RAID_CHANNEL 1
+
MODULE_AUTHOR(MODULEAUTHOR);
MODULE_DESCRIPTION(my_NAME);
MODULE_LICENSE("GPL");
-static int mpt_pq_filter;
-module_param(mpt_pq_filter, int, 0);
-MODULE_PARM_DESC(mpt_pq_filter,
- "Enable peripheral qualifier filter: enable=1 "
- "(default=0)");
-
static int mpt_pt_clear;
module_param(mpt_pt_clear, int, 0);
MODULE_PARM_DESC(mpt_pt_clear,
- "Clear persistency table: enable=1 "
+ " Clear persistency table: enable=1 "
"(default=MPTSCSIH_PT_CLEAR=0)");
static int mptsasDoneCtx = -1;
@@ -144,7 +143,6 @@ struct mptsas_devinfo {
* Specific details on ports, wide/narrow
*/
struct mptsas_portinfo_details{
- u8 port_id; /* port number provided to transport */
u16 num_phys; /* number of phys belong to this port */
u64 phy_bitmask; /* TODO, extend support for 255 phys */
struct sas_rphy *rphy; /* transport layer rphy object */
@@ -350,10 +348,10 @@ mptsas_port_delete(struct mptsas_portinfo_details * port_details)
port_info = port_details->port_info;
phy_info = port_info->phy_info;
- dsaswideprintk((KERN_DEBUG "%s: [%p]: port=%02d num_phys=%02d "
+ dsaswideprintk((KERN_DEBUG "%s: [%p]: num_phys=%02d "
"bitmask=0x%016llX\n",
- __FUNCTION__, port_details, port_details->port_id,
- port_details->num_phys, port_details->phy_bitmask));
+ __FUNCTION__, port_details, port_details->num_phys,
+ port_details->phy_bitmask));
for (i = 0; i < port_info->num_phys; i++, phy_info++) {
if(phy_info->port_details != port_details)
@@ -462,9 +460,8 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
* phy be removed by firmware events.
*/
dsaswideprintk((KERN_DEBUG
- "%s: [%p]: port=%d deleting phy = %d\n",
- __FUNCTION__, port_details,
- port_details->port_id, i));
+ "%s: [%p]: deleting phy = %d\n",
+ __FUNCTION__, port_details, i));
port_details->num_phys--;
port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
@@ -493,7 +490,6 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
goto out;
port_details->num_phys = 1;
port_details->port_info = port_info;
- port_details->port_id = ioc->port_serial_number++;
if (phy_info->phy_id < 64 )
port_details->phy_bitmask |=
(1 << phy_info->phy_id);
@@ -525,12 +521,8 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
mptsas_get_port(phy_info_cmp);
port_details->starget =
mptsas_get_starget(phy_info_cmp);
- port_details->port_id =
- phy_info_cmp->port_details->port_id;
port_details->num_phys =
phy_info_cmp->port_details->num_phys;
-// port_info->port_serial_number--;
- ioc->port_serial_number--;
if (!phy_info_cmp->port_details->num_phys)
kfree(phy_info_cmp->port_details);
} else
@@ -554,11 +546,11 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
if (!port_details)
continue;
dsaswideprintk((KERN_DEBUG
- "%s: [%p]: phy_id=%02d port_id=%02d num_phys=%02d "
+ "%s: [%p]: phy_id=%02d num_phys=%02d "
"bitmask=0x%016llX\n",
__FUNCTION__,
- port_details, i, port_details->port_id,
- port_details->num_phys, port_details->phy_bitmask));
+ port_details, i, port_details->num_phys,
+ port_details->phy_bitmask));
dsaswideprintk((KERN_DEBUG"\t\tport = %p rphy=%p\n",
port_details->port, port_details->rphy));
}
@@ -651,16 +643,13 @@ mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
static int
mptsas_slave_configure(struct scsi_device *sdev)
{
- struct Scsi_Host *host = sdev->host;
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
- /*
- * RAID volumes placed beyond the last expected port.
- * Ignore sending sas mode pages in that case..
- */
- if (sdev->channel < hd->ioc->num_ports)
- sas_read_port_mode_page(sdev);
+ if (sdev->channel == MPTSAS_RAID_CHANNEL)
+ goto out;
+
+ sas_read_port_mode_page(sdev);
+ out:
return mptscsih_slave_configure(sdev);
}
@@ -689,10 +678,7 @@ mptsas_target_alloc(struct scsi_target *starget)
hd->Targets[target_id] = vtarget;
- /*
- * RAID volumes placed beyond the last expected port.
- */
- if (starget->channel == hd->ioc->num_ports)
+ if (starget->channel == MPTSAS_RAID_CHANNEL)
goto out;
rphy = dev_to_rphy(starget->dev.parent);
@@ -743,7 +729,7 @@ mptsas_target_destroy(struct scsi_target *starget)
if (!starget->hostdata)
return;
- if (starget->channel == hd->ioc->num_ports)
+ if (starget->channel == MPTSAS_RAID_CHANNEL)
goto out;
rphy = dev_to_rphy(starget->dev.parent);
@@ -783,10 +769,7 @@ mptsas_slave_alloc(struct scsi_device *sdev)
starget = scsi_target(sdev);
vdev->vtarget = starget->hostdata;
- /*
- * RAID volumes placed beyond the last expected port.
- */
- if (sdev->channel == hd->ioc->num_ports)
+ if (sdev->channel == MPTSAS_RAID_CHANNEL)
goto out;
rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
@@ -1608,11 +1591,7 @@ static int mptsas_probe_one_phy(struct device *dev,
if (phy_info->sas_port_add_phy) {
if (!port) {
- port = sas_port_alloc(dev,
- phy_info->port_details->port_id);
- dsaswideprintk((KERN_DEBUG
- "sas_port_alloc: port=%p dev=%p port_id=%d\n",
- port, dev, phy_info->port_details->port_id));
+ port = sas_port_alloc_num(dev);
if (!port) {
error = -ENOMEM;
goto out;
@@ -1625,6 +1604,9 @@ static int mptsas_probe_one_phy(struct device *dev,
goto out;
}
mptsas_set_port(phy_info, port);
+ dsaswideprintk((KERN_DEBUG
+ "sas_port_alloc: port=%p dev=%p port_id=%d\n",
+ port, dev, port->port_identifier));
}
dsaswideprintk((KERN_DEBUG "sas_port_add_phy: phy_id=%d\n",
phy_info->phy_id));
@@ -1736,7 +1718,6 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
hba = NULL;
}
mutex_unlock(&ioc->sas_topology_mutex);
- ioc->num_ports = port_info->num_phys;
for (i = 0; i < port_info->num_phys; i++) {
mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
@@ -1939,7 +1920,8 @@ mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
expander_sas_address)
continue;
#ifdef MPT_DEBUG_SAS_WIDE
- dev_printk(KERN_DEBUG, &port->dev, "delete\n");
+ dev_printk(KERN_DEBUG, &port->dev,
+ "delete port (%d)\n", port->port_identifier);
#endif
sas_port_delete(port);
mptsas_port_delete(phy_info->port_details);
@@ -1984,7 +1966,7 @@ mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
goto out;
for (i=0; i<ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
- scsi_add_device(ioc->sh, ioc->num_ports,
+ scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
}
out:
@@ -2185,7 +2167,8 @@ mptsas_hotplug_work(void *arg)
ioc->name, ds, ev->channel, ev->id, phy_info->phy_id);
#ifdef MPT_DEBUG_SAS_WIDE
- dev_printk(KERN_DEBUG, &port->dev, "delete\n");
+ dev_printk(KERN_DEBUG, &port->dev,
+ "delete port (%d)\n", port->port_identifier);
#endif
sas_port_delete(port);
mptsas_port_delete(phy_info->port_details);
@@ -2289,35 +2272,26 @@ mptsas_hotplug_work(void *arg)
mptsas_set_rphy(phy_info, rphy);
break;
case MPTSAS_ADD_RAID:
- sdev = scsi_device_lookup(
- ioc->sh,
- ioc->num_ports,
- ev->id,
- 0);
+ sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
+ ev->id, 0);
if (sdev) {
scsi_device_put(sdev);
break;
}
printk(MYIOC_s_INFO_FMT
"attaching raid volume, channel %d, id %d\n",
- ioc->name, ioc->num_ports, ev->id);
- scsi_add_device(ioc->sh,
- ioc->num_ports,
- ev->id,
- 0);
+ ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
+ scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, ev->id, 0);
mpt_findImVolumes(ioc);
break;
case MPTSAS_DEL_RAID:
- sdev = scsi_device_lookup(
- ioc->sh,
- ioc->num_ports,
- ev->id,
- 0);
+ sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
+ ev->id, 0);
if (!sdev)
break;
printk(MYIOC_s_INFO_FMT
"removing raid volume, channel %d, id %d\n",
- ioc->name, ioc->num_ports, ev->id);
+ ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
vdevice = sdev->hostdata;
vdevice->vtarget->deleted = 1;
mptsas_target_reset(ioc, vdevice->vtarget);
@@ -2723,7 +2697,6 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
hd->timer.data = (unsigned long) hd;
hd->timer.function = mptscsih_timer_expired;
- hd->mpt_pq_filter = mpt_pq_filter;
ioc->sas_data.ptClear = mpt_pt_clear;
if (ioc->sas_data.ptClear==1) {
@@ -2731,12 +2704,6 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
}
- ddvprintk((MYIOC_s_INFO_FMT
- "mpt_pq_filter %x mpt_pq_filter %x\n",
- ioc->name,
- mpt_pq_filter,
- mpt_pq_filter));
-
init_waitqueue_head(&hd->scandv_waitq);
hd->scandv_wait_done = 0;
hd->last_queue_full = 0;
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
index 8242b16e316..30524dc54b1 100644
--- a/drivers/message/fusion/mptscsih.c
+++ b/drivers/message/fusion/mptscsih.c
@@ -66,6 +66,7 @@
#include "mptbase.h"
#include "mptscsih.h"
+#include "lsi/mpi_log_sas.h"
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
#define my_NAME "Fusion MPT SCSI Host driver"
@@ -127,7 +128,7 @@ static void mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx);
static void mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);
static int mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd);
static int mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout );
-static u32 SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc);
+static int SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc);
static int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout);
@@ -497,6 +498,34 @@ nextSGEset:
return SUCCESS;
} /* mptscsih_AddSGE() */
+static void
+mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget,
+ U32 SlotStatus)
+{
+ MPT_FRAME_HDR *mf;
+ SEPRequest_t *SEPMsg;
+
+ if (ioc->bus_type == FC)
+ return;
+
+ if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
+ dfailprintk((MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
+ ioc->name,__FUNCTION__));
+ return;
+ }
+
+ SEPMsg = (SEPRequest_t *)mf;
+ SEPMsg->Function = MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
+ SEPMsg->Bus = vtarget->bus_id;
+ SEPMsg->TargetID = vtarget->target_id;
+ SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS;
+ SEPMsg->SlotStatus = SlotStatus;
+ devtverboseprintk((MYIOC_s_WARN_FMT
+ "Sending SEP cmd=%x id=%d bus=%d\n",
+ ioc->name, SlotStatus, SEPMsg->TargetID, SEPMsg->Bus));
+ mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
+}
+
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
* mptscsih_io_done - Main SCSI IO callback routine registered to
@@ -520,6 +549,8 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
SCSIIORequest_t *pScsiReq;
SCSIIOReply_t *pScsiReply;
u16 req_idx, req_idx_MR;
+ VirtDevice *vdev;
+ VirtTarget *vtarget;
hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
@@ -538,6 +569,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
}
sc = hd->ScsiLookup[req_idx];
+ hd->ScsiLookup[req_idx] = NULL;
if (sc == NULL) {
MPIHeader_t *hdr = (MPIHeader_t *)mf;
@@ -553,6 +585,12 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
return 1;
}
+ if ((unsigned char *)mf != sc->host_scribble) {
+ mptscsih_freeChainBuffers(ioc, req_idx);
+ return 1;
+ }
+
+ sc->host_scribble = NULL;
sc->result = DID_OK << 16; /* Set default reply as OK */
pScsiReq = (SCSIIORequest_t *) mf;
pScsiReply = (SCSIIOReply_t *) mr;
@@ -640,10 +678,36 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
hd->sel_timeout[pScsiReq->TargetID]++;
+
+ vdev = sc->device->hostdata;
+ if (!vdev)
+ break;
+ vtarget = vdev->vtarget;
+ if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) {
+ mptscsih_issue_sep_command(ioc, vtarget,
+ MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED);
+ vtarget->tflags &= ~MPT_TARGET_FLAGS_LED_ON;
+ }
break;
- case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
+ if ( ioc->bus_type == SAS ) {
+ u16 ioc_status = le16_to_cpu(pScsiReply->IOCStatus);
+ if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
+ u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
+ log_info &=SAS_LOGINFO_MASK;
+ if (log_info == SAS_LOGINFO_NEXUS_LOSS) {
+ sc->result = (DID_BUS_BUSY << 16);
+ break;
+ }
+ }
+ }
+
+ /*
+ * Allow non-SAS & non-NEXUS_LOSS to drop into below code
+ */
+
+ case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
/* Linux handles an unsolicited DID_RESET better
* than an unsolicited DID_ABORT.
@@ -658,7 +722,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
sc->result=DID_SOFT_ERROR << 16;
else /* Sufficient data transfer occurred */
sc->result = (DID_OK << 16) | scsi_status;
- dreplyprintk((KERN_NOTICE
+ dreplyprintk((KERN_NOTICE
"RESIDUAL_MISMATCH: result=%x on id=%d\n", sc->result, sc->device->id));
break;
@@ -784,8 +848,6 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
sc->request_bufflen, sc->sc_data_direction);
}
- hd->ScsiLookup[req_idx] = NULL;
-
sc->scsi_done(sc); /* Issue the command callback */
/* Free Chain buffers */
@@ -827,9 +889,17 @@ mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
dmfprintk(( "flush: ScsiDone (mf=%p,sc=%p)\n",
mf, SCpnt));
+ /* Free Chain buffers */
+ mptscsih_freeChainBuffers(ioc, ii);
+
+ /* Free Message frames */
+ mpt_free_msg_frame(ioc, mf);
+
+ if ((unsigned char *)mf != SCpnt->host_scribble)
+ continue;
+
/* Set status, free OS resources (SG DMA buffers)
* Do OS callback
- * Free driver resources (chain, msg buffers)
*/
if (SCpnt->use_sg) {
pci_unmap_sg(ioc->pcidev,
@@ -845,12 +915,6 @@ mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
SCpnt->result = DID_RESET << 16;
SCpnt->host_scribble = NULL;
- /* Free Chain buffers */
- mptscsih_freeChainBuffers(ioc, ii);
-
- /* Free Message frames */
- mpt_free_msg_frame(ioc, mf);
-
SCpnt->scsi_done(SCpnt); /* Issue the command callback */
}
}
@@ -887,10 +951,10 @@ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
if ((sc = hd->ScsiLookup[ii]) != NULL) {
mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(hd->ioc, ii);
-
+ if (mf == NULL)
+ continue;
dsprintk(( "search_running: found (sc=%p, mf = %p) target %d, lun %d \n",
hd->ScsiLookup[ii], mf, mf->TargetID, mf->LUN[1]));
-
if ((mf->TargetID != ((u8)vdevice->vtarget->target_id)) || (mf->LUN[1] != ((u8) vdevice->lun)))
continue;
@@ -899,6 +963,8 @@ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
hd->ScsiLookup[ii] = NULL;
mptscsih_freeChainBuffers(hd->ioc, ii);
mpt_free_msg_frame(hd->ioc, (MPT_FRAME_HDR *)mf);
+ if ((unsigned char *)mf != sc->host_scribble)
+ continue;
if (sc->use_sg) {
pci_unmap_sg(hd->ioc->pcidev,
(struct scatterlist *) sc->request_buffer,
@@ -1341,8 +1407,8 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
goto fail;
}
+ SCpnt->host_scribble = (unsigned char *)mf;
hd->ScsiLookup[my_idx] = SCpnt;
- SCpnt->host_scribble = NULL;
mpt_put_msg_frame(hd->ioc->DoneCtx, hd->ioc, mf);
dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
@@ -1529,6 +1595,12 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, in
rc = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
}
+ /*
+ * Check IOCStatus from TM reply message
+ */
+ if (hd->tm_iocstatus != MPI_IOCSTATUS_SUCCESS)
+ rc = FAILED;
+
dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc));
return rc;
@@ -1654,6 +1726,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
int scpnt_idx;
int retval;
VirtDevice *vdev;
+ ulong sn = SCpnt->serial_number;
/* If we can't locate our host adapter structure, return FAILED status.
*/
@@ -1707,6 +1780,11 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
vdev->vtarget->bus_id, vdev->vtarget->target_id, vdev->lun,
ctx2abort, mptscsih_get_tm_timeout(hd->ioc));
+ if (SCPNT_TO_LOOKUP_IDX(SCpnt) == scpnt_idx &&
+ SCpnt->serial_number == sn) {
+ retval = FAILED;
+ }
+
printk (KERN_WARNING MYNAM ": %s: task abort: %s (sc=%p)\n",
hd->ioc->name,
((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
@@ -2023,6 +2101,7 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *m
DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply);
iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+ hd->tm_iocstatus = iocstatus;
dtmprintk((MYIOC_s_WARN_FMT " SCSI TaskMgmt (%d) IOCStatus=%04x IOCLogInfo=%08x\n",
ioc->name, tmType, iocstatus, le32_to_cpu(pScsiTmReply->IOCLogInfo)));
/* Error? (anything non-zero?) */
@@ -2401,6 +2480,13 @@ mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR
ioc->events[idx].data[1] = (sense_data[13] << 8) || sense_data[12];
ioc->eventContext++;
+ if (hd->ioc->pcidev->vendor ==
+ PCI_VENDOR_ID_IBM) {
+ mptscsih_issue_sep_command(hd->ioc,
+ vdev->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
+ vdev->vtarget->tflags |=
+ MPT_TARGET_FLAGS_LED_ON;
+ }
}
}
} else {
@@ -2409,7 +2495,7 @@ mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR
}
}
-static u32
+static int
SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc)
{
MPT_SCSI_HOST *hd;
diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c
index 0a1ff762205..e4cc3dd5fc9 100644
--- a/drivers/message/fusion/mptspi.c
+++ b/drivers/message/fusion/mptspi.c
@@ -83,10 +83,6 @@ static int mpt_saf_te = MPTSCSIH_SAF_TE;
module_param(mpt_saf_te, int, 0);
MODULE_PARM_DESC(mpt_saf_te, " Force enabling SEP Processor: enable=1 (default=MPTSCSIH_SAF_TE=0)");
-static int mpt_pq_filter = 0;
-module_param(mpt_pq_filter, int, 0);
-MODULE_PARM_DESC(mpt_pq_filter, " Enable peripheral qualifier filter: enable=1 (default=0)");
-
static void mptspi_write_offset(struct scsi_target *, int);
static void mptspi_write_width(struct scsi_target *, int);
static int mptspi_write_spi_device_pg1(struct scsi_target *,
@@ -1047,14 +1043,12 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
hd->timer.function = mptscsih_timer_expired;
ioc->spi_data.Saf_Te = mpt_saf_te;
- hd->mpt_pq_filter = mpt_pq_filter;
hd->negoNvram = MPT_SCSICFG_USE_NVRAM;
ddvprintk((MYIOC_s_INFO_FMT
- "saf_te %x mpt_pq_filter %x\n",
+ "saf_te %x\n",
ioc->name,
- mpt_saf_te,
- mpt_pq_filter));
+ mpt_saf_te));
ioc->spi_data.noQas = 0;
init_waitqueue_head(&hd->scandv_waitq);
diff --git a/drivers/message/i2o/core.h b/drivers/message/i2o/core.h
index 184974cc734..dc388a3ff5e 100644
--- a/drivers/message/i2o/core.h
+++ b/drivers/message/i2o/core.h
@@ -38,6 +38,9 @@ extern struct device_attribute i2o_device_attrs[];
extern void i2o_device_remove(struct i2o_device *);
extern int i2o_device_parse_lct(struct i2o_controller *);
+int i2o_parm_issue(struct i2o_device *i2o_dev, int cmd, void *oplist,
+ int oplen, void *reslist, int reslen);
+
/* IOP */
extern struct i2o_controller *i2o_iop_alloc(void);
diff --git a/drivers/message/i2o/i2o_config.c b/drivers/message/i2o/i2o_config.c
index 89daf67b764..7d23e082bf2 100644
--- a/drivers/message/i2o/i2o_config.c
+++ b/drivers/message/i2o/i2o_config.c
@@ -36,9 +36,9 @@
#include <asm/uaccess.h>
-#define SG_TABLESIZE 30
+#include "core.h"
-extern int i2o_parm_issue(struct i2o_device *, int, void *, int, void *, int);
+#define SG_TABLESIZE 30
static int i2o_cfg_ioctl(struct inode *, struct file *, unsigned int,
unsigned long);
diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index 632bc218c86..2bf32721eb5 100644
--- a/drivers/mfd/ucb1x00-core.c
+++ b/drivers/mfd/ucb1x00-core.c
@@ -479,7 +479,7 @@ static int ucb1x00_probe(struct mcp *mcp)
mcp_enable(mcp);
id = mcp_reg_read(mcp, UCB_ID);
- if (id != UCB_ID_1200 && id != UCB_ID_1300) {
+ if (id != UCB_ID_1200 && id != UCB_ID_1300 && id != UCB_ID_TC35143) {
printk(KERN_WARNING "UCB1x00 ID not found: %04x\n", id);
goto err_disable;
}
diff --git a/drivers/mfd/ucb1x00.h b/drivers/mfd/ucb1x00.h
index 9c9a647d8b7..ca8df8072d4 100644
--- a/drivers/mfd/ucb1x00.h
+++ b/drivers/mfd/ucb1x00.h
@@ -94,6 +94,7 @@
#define UCB_ID 0x0c
#define UCB_ID_1200 0x1004
#define UCB_ID_1300 0x1005
+#define UCB_ID_TC35143 0x9712
#define UCB_MODE 0x0d
#define UCB_MODE_DYN_VFLAG_ENA (1 << 12)
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index 893319108ba..4e21b3b9d33 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -565,7 +565,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
if (cmd->data)
flags |= SDHCI_CMD_DATA;
- writel(SDHCI_MAKE_CMD(cmd->opcode, flags),
+ writew(SDHCI_MAKE_CMD(cmd->opcode, flags),
host->ioaddr + SDHCI_COMMAND);
}
@@ -1193,10 +1193,8 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
version = (version & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT;
if (version != 0) {
printk(KERN_ERR "%s: Unknown controller version (%d). "
- "Cowardly refusing to continue.\n", host->slot_descr,
+ "You may experience problems.\n", host->slot_descr,
version);
- ret = -ENODEV;
- goto unmap;
}
caps = readl(host->ioaddr + SDHCI_CAPABILITIES);
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 2819de79442..80e8ca013e4 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -17,172 +17,6 @@
410 Severn Ave., Suite 210
Annapolis MD 21403
- Linux Kernel Additions:
-
- 0.99H+lk0.9 - David S. Miller - softnet, PCI DMA updates
- 0.99H+lk1.0 - Jeff Garzik <jgarzik@pobox.com>
- Remove compatibility defines for kernel versions < 2.2.x.
- Update for new 2.3.x module interface
- LK1.1.2 (March 19, 2000)
- * New PCI interface (jgarzik)
-
- LK1.1.3 25 April 2000, Andrew Morton <andrewm@uow.edu.au>
- - Merged with 3c575_cb.c
- - Don't set RxComplete in boomerang interrupt enable reg
- - spinlock in vortex_timer to protect mdio functions
- - disable local interrupts around call to vortex_interrupt in
- vortex_tx_timeout() (So vortex_interrupt can use spin_lock())
- - Select window 3 in vortex_timer()'s write to Wn3_MAC_Ctrl
- - In vortex_start_xmit(), move the lock to _after_ we've altered
- vp->cur_tx and vp->tx_full. This defeats the race between
- vortex_start_xmit() and vortex_interrupt which was identified
- by Bogdan Costescu.
- - Merged back support for six new cards from various sources
- - Set vortex_have_pci if pci_module_init returns zero (fixes cardbus
- insertion oops)
- - Tell it that 3c905C has NWAY for 100bT autoneg
- - Fix handling of SetStatusEnd in 'Too much work..' code, as
- per 2.3.99's 3c575_cb (Dave Hinds).
- - Split ISR into two for vortex & boomerang
- - Fix MOD_INC/DEC races
- - Handle resource allocation failures.
- - Fix 3CCFE575CT LED polarity
- - Make tx_interrupt_mitigation the default
-
- LK1.1.4 25 April 2000, Andrew Morton <andrewm@uow.edu.au>
- - Add extra TxReset to vortex_up() to fix 575_cb hotplug initialisation probs.
- - Put vortex_info_tbl into __devinitdata
- - In the vortex_error StatsFull HACK, disable stats in vp->intr_enable as well
- as in the hardware.
- - Increased the loop counter in issue_and_wait from 2,000 to 4,000.
-
- LK1.1.5 28 April 2000, andrewm
- - Added powerpc defines (John Daniel <jdaniel@etresoft.com> said these work...)
- - Some extra diagnostics
- - In vortex_error(), reset the Tx on maxCollisions. Otherwise most
- chips usually get a Tx timeout.
- - Added extra_reset module parm
- - Replaced some inline timer manip with mod_timer
- (Franois romieu <Francois.Romieu@nic.fr>)
- - In vortex_up(), don't make Wn3_config initialisation dependent upon has_nway
- (this came across from 3c575_cb).
-
- LK1.1.6 06 Jun 2000, andrewm
- - Backed out the PPC defines.
- - Use del_timer_sync(), mod_timer().
- - Fix wrapped ulong comparison in boomerang_rx()
- - Add IS_TORNADO, use it to suppress 3c905C checksum error msg
- (Donald Becker, I Lee Hetherington <ilh@sls.lcs.mit.edu>)
- - Replace union wn3_config with BFINS/BFEXT manipulation for
- sparc64 (Pete Zaitcev, Peter Jones)
- - In vortex_error, do_tx_reset and vortex_tx_timeout(Vortex):
- do a netif_wake_queue() to better recover from errors. (Anders Pedersen,
- Donald Becker)
- - Print a warning on out-of-memory (rate limited to 1 per 10 secs)
- - Added two more Cardbus 575 NICs: 5b57 and 6564 (Paul Wagland)
-
- LK1.1.7 2 Jul 2000 andrewm
- - Better handling of shared IRQs
- - Reset the transmitter on a Tx reclaim error
- - Fixed crash under OOM during vortex_open() (Mark Hemment)
- - Fix Rx cessation problem during OOM (help from Mark Hemment)
- - The spinlocks around the mdio access were blocking interrupts for 300uS.
- Fix all this to use spin_lock_bh() within mdio_read/write
- - Only write to TxFreeThreshold if it's a boomerang - other NICs don't
- have one.
- - Added 802.3x MAC-layer flow control support
-
- LK1.1.8 13 Aug 2000 andrewm
- - Ignore request_region() return value - already reserved if Cardbus.
- - Merged some additional Cardbus flags from Don's 0.99Qk
- - Some fixes for 3c556 (Fred Maciel)
- - Fix for EISA initialisation (Jan Rekorajski)
- - Renamed MII_XCVR_PWR and EEPROM_230 to align with 3c575_cb and D. Becker's drivers
- - Fixed MII_XCVR_PWR for 3CCFE575CT
- - Added INVERT_LED_PWR, used it.
- - Backed out the extra_reset stuff
-
- LK1.1.9 12 Sep 2000 andrewm
- - Backed out the tx_reset_resume flags. It was a no-op.
- - In vortex_error, don't reset the Tx on txReclaim errors
- - In vortex_error, don't reset the Tx on maxCollisions errors.
- Hence backed out all the DownListPtr logic here.
- - In vortex_error, give Tornado cards a partial TxReset on
- maxCollisions (David Hinds). Defined MAX_COLLISION_RESET for this.
- - Redid some driver flags and device names based on pcmcia_cs-3.1.20.
- - Fixed a bug where, if vp->tx_full is set when the interface
- is downed, it remains set when the interface is upped. Bad
- things happen.
-
- LK1.1.10 17 Sep 2000 andrewm
- - Added EEPROM_8BIT for 3c555 (Fred Maciel)
- - Added experimental support for the 3c556B Laptop Hurricane (Louis Gerbarg)
- - Add HAS_NWAY to "3c900 Cyclone 10Mbps TPO"
-
- LK1.1.11 13 Nov 2000 andrewm
- - Dump MOD_INC/DEC_USE_COUNT, use SET_MODULE_OWNER
-
- LK1.1.12 1 Jan 2001 andrewm (2.4.0-pre1)
- - Call pci_enable_device before we request our IRQ (Tobias Ringstrom)
- - Add 3c590 PCI latency timer hack to vortex_probe1 (from 0.99Ra)
- - Added extended issue_and_wait for the 3c905CX.
- - Look for an MII on PHY index 24 first (3c905CX oddity).
- - Add HAS_NWAY to 3cSOHO100-TX (Brett Frankenberger)
- - Don't free skbs we don't own on oom path in vortex_open().
-
- LK1.1.13 27 Jan 2001
- - Added explicit `medialock' flag so we can truly
- lock the media type down with `options'.
- - "check ioremap return and some tidbits" (Arnaldo Carvalho de Melo <acme@conectiva.com.br>)
- - Added and used EEPROM_NORESET for 3c556B PM resumes.
- - Fixed leakage of vp->rx_ring.
- - Break out separate HAS_HWCKSM device capability flag.
- - Kill vp->tx_full (ANK)
- - Merge zerocopy fragment handling (ANK?)
-
- LK1.1.14 15 Feb 2001
- - Enable WOL. Can be turned on with `enable_wol' module option.
- - EISA and PCI initialisation fixes (jgarzik, Manfred Spraul)
- - If a device's internalconfig register reports it has NWAY,
- use it, even if autoselect is enabled.
-
- LK1.1.15 6 June 2001 akpm
- - Prevent double counting of received bytes (Lars Christensen)
- - Add ethtool support (jgarzik)
- - Add module parm descriptions (Andrzej M. Krzysztofowicz)
- - Implemented alloc_etherdev() API
- - Special-case the 'Tx error 82' message.
-
- LK1.1.16 18 July 2001 akpm
- - Make NETIF_F_SG dependent upon nr_free_highpages(), not on CONFIG_HIGHMEM
- - Lessen verbosity of bootup messages
- - Fix WOL - use new PM API functions.
- - Use netif_running() instead of vp->open in suspend/resume.
- - Don't reset the interface logic on open/close/rmmod. It upsets
- autonegotiation, and hence DHCP (from 0.99T).
- - Back out EEPROM_NORESET flag because of the above (we do it for all
- NICs).
- - Correct 3c982 identification string
- - Rename wait_for_completion() to issue_and_wait() to avoid completion.h
- clash.
-
- LK1.1.17 18Dec01 akpm
- - PCI ID 9805 is a Python-T, not a dual-port Cyclone. Apparently.
- And it has NWAY.
- - Mask our advertised modes (vp->advertising) with our capabilities
- (MII reg5) when deciding which duplex mode to use.
- - Add `global_options' as default for options[]. Ditto global_enable_wol,
- global_full_duplex.
-
- LK1.1.18 01Jul02 akpm
- - Fix for undocumented transceiver power-up bit on some 3c566B's
- (Donald Becker, Rahul Karnik)
-
- - See http://www.zip.com.au/~akpm/linux/#3c59x-2.3 for more details.
- - Also see Documentation/networking/vortex.txt
-
- LK1.1.19 10Nov02 Marc Zyngier <maz@wild-wind.fr.eu.org>
- - EISA sysfs integration.
*/
/*
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index 1959654cbec..1428bb7715a 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -1836,9 +1836,10 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (pdev->vendor == PCI_VENDOR_ID_REALTEK &&
pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pci_rev < 0x20) {
- printk(KERN_ERR PFX "pci dev %s (id %04x:%04x rev %02x) is not an 8139C+ compatible chip\n",
- pci_name(pdev), pdev->vendor, pdev->device, pci_rev);
- printk(KERN_ERR PFX "Try the \"8139too\" driver instead.\n");
+ dev_err(&pdev->dev,
+ "This (id %04x:%04x rev %02x) is not an 8139C+ compatible chip\n",
+ pdev->vendor, pdev->device, pci_rev);
+ dev_err(&pdev->dev, "Try the \"8139too\" driver instead.\n");
return -ENODEV;
}
@@ -1876,14 +1877,13 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
pciaddr = pci_resource_start(pdev, 1);
if (!pciaddr) {
rc = -EIO;
- printk(KERN_ERR PFX "no MMIO resource for pci dev %s\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "no MMIO resource\n");
goto err_out_res;
}
if (pci_resource_len(pdev, 1) < CP_REGS_SIZE) {
rc = -EIO;
- printk(KERN_ERR PFX "MMIO resource (%llx) too small on pci dev %s\n",
- (unsigned long long)pci_resource_len(pdev, 1), pci_name(pdev));
+ dev_err(&pdev->dev, "MMIO resource (%llx) too small\n",
+ (unsigned long long)pci_resource_len(pdev, 1));
goto err_out_res;
}
@@ -1897,14 +1897,15 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
if (rc) {
- printk(KERN_ERR PFX "No usable DMA configuration, "
- "aborting.\n");
+ dev_err(&pdev->dev,
+ "No usable DMA configuration, aborting.\n");
goto err_out_res;
}
rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
if (rc) {
- printk(KERN_ERR PFX "No usable consistent DMA configuration, "
- "aborting.\n");
+ dev_err(&pdev->dev,
+ "No usable consistent DMA configuration, "
+ "aborting.\n");
goto err_out_res;
}
}
@@ -1915,9 +1916,9 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
regs = ioremap(pciaddr, CP_REGS_SIZE);
if (!regs) {
rc = -EIO;
- printk(KERN_ERR PFX "Cannot map PCI MMIO (%llx@%llx) on pci dev %s\n",
- (unsigned long long)pci_resource_len(pdev, 1),
- (unsigned long long)pciaddr, pci_name(pdev));
+ dev_err(&pdev->dev, "Cannot map PCI MMIO (%Lx@%Lx)\n",
+ (unsigned long long)pci_resource_len(pdev, 1),
+ (unsigned long long)pciaddr);
goto err_out_res;
}
dev->base_addr = (unsigned long) regs;
@@ -1986,7 +1987,8 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
/* enable busmastering and memory-write-invalidate */
pci_set_master(pdev);
- if (cp->wol_enabled) cp_set_d3_state (cp);
+ if (cp->wol_enabled)
+ cp_set_d3_state (cp);
return 0;
@@ -2011,7 +2013,8 @@ static void cp_remove_one (struct pci_dev *pdev)
BUG_ON(!dev);
unregister_netdev(dev);
iounmap(cp->regs);
- if (cp->wol_enabled) pci_set_power_state (pdev, PCI_D0);
+ if (cp->wol_enabled)
+ pci_set_power_state (pdev, PCI_D0);
pci_release_regions(pdev);
pci_clear_mwi(pdev);
pci_disable_device(pdev);
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index 717506b2b13..e4f4eaff767 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -768,7 +768,7 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
/* dev and priv zeroed in alloc_etherdev */
dev = alloc_etherdev (sizeof (*tp));
if (dev == NULL) {
- printk (KERN_ERR PFX "%s: Unable to alloc new net device\n", pci_name(pdev));
+ dev_err(&pdev->dev, "Unable to alloc new net device\n");
return -ENOMEM;
}
SET_MODULE_OWNER(dev);
@@ -800,31 +800,31 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
#ifdef USE_IO_OPS
/* make sure PCI base addr 0 is PIO */
if (!(pio_flags & IORESOURCE_IO)) {
- printk (KERN_ERR PFX "%s: region #0 not a PIO resource, aborting\n", pci_name(pdev));
+ dev_err(&pdev->dev, "region #0 not a PIO resource, aborting\n");
rc = -ENODEV;
goto err_out;
}
/* check for weird/broken PCI region reporting */
if (pio_len < RTL_MIN_IO_SIZE) {
- printk (KERN_ERR PFX "%s: Invalid PCI I/O region size(s), aborting\n", pci_name(pdev));
+ dev_err(&pdev->dev, "Invalid PCI I/O region size(s), aborting\n");
rc = -ENODEV;
goto err_out;
}
#else
/* make sure PCI base addr 1 is MMIO */
if (!(mmio_flags & IORESOURCE_MEM)) {
- printk (KERN_ERR PFX "%s: region #1 not an MMIO resource, aborting\n", pci_name(pdev));
+ dev_err(&pdev->dev, "region #1 not an MMIO resource, aborting\n");
rc = -ENODEV;
goto err_out;
}
if (mmio_len < RTL_MIN_IO_SIZE) {
- printk (KERN_ERR PFX "%s: Invalid PCI mem region size(s), aborting\n", pci_name(pdev));
+ dev_err(&pdev->dev, "Invalid PCI mem region size(s), aborting\n");
rc = -ENODEV;
goto err_out;
}
#endif
- rc = pci_request_regions (pdev, "8139too");
+ rc = pci_request_regions (pdev, DRV_NAME);
if (rc)
goto err_out;
disable_dev_on_err = 1;
@@ -835,7 +835,7 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
#ifdef USE_IO_OPS
ioaddr = ioport_map(pio_start, pio_len);
if (!ioaddr) {
- printk (KERN_ERR PFX "%s: cannot map PIO, aborting\n", pci_name(pdev));
+ dev_err(&pdev->dev, "cannot map PIO, aborting\n");
rc = -EIO;
goto err_out;
}
@@ -846,7 +846,7 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
/* ioremap MMIO region */
ioaddr = pci_iomap(pdev, 1, 0);
if (ioaddr == NULL) {
- printk (KERN_ERR PFX "%s: cannot remap MMIO, aborting\n", pci_name(pdev));
+ dev_err(&pdev->dev, "cannot remap MMIO, aborting\n");
rc = -EIO;
goto err_out;
}
@@ -860,8 +860,7 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
/* check for missing/broken hardware */
if (RTL_R32 (TxConfig) == 0xFFFFFFFF) {
- printk (KERN_ERR PFX "%s: Chip not responding, ignoring board\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "Chip not responding, ignoring board\n");
rc = -EIO;
goto err_out;
}
@@ -875,9 +874,10 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
}
/* if unknown chip, assume array element #0, original RTL-8139 in this case */
- printk (KERN_DEBUG PFX "%s: unknown chip version, assuming RTL-8139\n",
- pci_name(pdev));
- printk (KERN_DEBUG PFX "%s: TxConfig = 0x%lx\n", pci_name(pdev), RTL_R32 (TxConfig));
+ dev_printk (KERN_DEBUG, &pdev->dev,
+ "unknown chip version, assuming RTL-8139\n");
+ dev_printk (KERN_DEBUG, &pdev->dev,
+ "TxConfig = 0x%lx\n", RTL_R32 (TxConfig));
tp->chipset = 0;
match:
@@ -954,9 +954,11 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
if (pdev->vendor == PCI_VENDOR_ID_REALTEK &&
pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pci_rev >= 0x20) {
- printk(KERN_INFO PFX "pci dev %s (id %04x:%04x rev %02x) is an enhanced 8139C+ chip\n",
- pci_name(pdev), pdev->vendor, pdev->device, pci_rev);
- printk(KERN_INFO PFX "Use the \"8139cp\" driver for improved performance and stability.\n");
+ dev_info(&pdev->dev,
+ "This (id %04x:%04x rev %02x) is an enhanced 8139C+ chip\n",
+ pdev->vendor, pdev->device, pci_rev);
+ dev_info(&pdev->dev,
+ "Use the \"8139cp\" driver for improved performance and stability.\n");
}
i = rtl8139_init_board (pdev, &dev);
@@ -1707,6 +1709,7 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
void __iomem *ioaddr = tp->mmio_addr;
unsigned int entry;
unsigned int len = skb->len;
+ unsigned long flags;
/* Calculate the next Tx descriptor entry. */
entry = tp->cur_tx % NUM_TX_DESC;
@@ -1723,7 +1726,7 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
return 0;
}
- spin_lock_irq(&tp->lock);
+ spin_lock_irqsave(&tp->lock, flags);
RTL_W32_F (TxStatus0 + (entry * sizeof (u32)),
tp->tx_flag | max(len, (unsigned int)ETH_ZLEN));
@@ -1734,7 +1737,7 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx)
netif_stop_queue (dev);
- spin_unlock_irq(&tp->lock);
+ spin_unlock_irqrestore(&tp->lock, flags);
if (netif_msg_tx_queued(tp))
printk (KERN_DEBUG "%s: Queued Tx packet size %u to slot %d.\n",
diff --git a/drivers/net/appletalk/Kconfig b/drivers/net/appletalk/Kconfig
index b14e89004c3..0a0e0cd81a2 100644
--- a/drivers/net/appletalk/Kconfig
+++ b/drivers/net/appletalk/Kconfig
@@ -29,7 +29,7 @@ config ATALK
even politically correct people are allowed to say Y here.
config DEV_APPLETALK
- bool "Appletalk interfaces support"
+ tristate "Appletalk interfaces support"
depends on ATALK
help
AppleTalk is the protocol that Apple computers can use to communicate
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index cd98d31dee8..bea0fc0ede2 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -2120,13 +2120,14 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
err = pci_enable_device(pdev);
if (err) {
- printk(KERN_ERR PFX "Cannot enable PCI device, "
+ dev_err(&pdev->dev, "Cannot enable PCI device, "
"aborting.\n");
return err;
}
if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
- printk(KERN_ERR PFX "Cannot find proper PCI device "
+ dev_err(&pdev->dev,
+ "Cannot find proper PCI device "
"base address, aborting.\n");
err = -ENODEV;
goto err_out_disable_pdev;
@@ -2134,8 +2135,8 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
err = pci_request_regions(pdev, DRV_MODULE_NAME);
if (err) {
- printk(KERN_ERR PFX "Cannot obtain PCI resources, "
- "aborting.\n");
+ dev_err(&pdev->dev,
+ "Cannot obtain PCI resources, aborting.\n");
goto err_out_disable_pdev;
}
@@ -2143,15 +2144,13 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
err = pci_set_dma_mask(pdev, (u64) B44_DMA_MASK);
if (err) {
- printk(KERN_ERR PFX "No usable DMA configuration, "
- "aborting.\n");
+ dev_err(&pdev->dev, "No usable DMA configuration, aborting.\n");
goto err_out_free_res;
}
err = pci_set_consistent_dma_mask(pdev, (u64) B44_DMA_MASK);
if (err) {
- printk(KERN_ERR PFX "No usable DMA configuration, "
- "aborting.\n");
+ dev_err(&pdev->dev, "No usable DMA configuration, aborting.\n");
goto err_out_free_res;
}
@@ -2160,7 +2159,7 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
dev = alloc_etherdev(sizeof(*bp));
if (!dev) {
- printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
+ dev_err(&pdev->dev, "Etherdev alloc failed, aborting.\n");
err = -ENOMEM;
goto err_out_free_res;
}
@@ -2181,8 +2180,7 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
bp->regs = ioremap(b44reg_base, b44reg_len);
if (bp->regs == 0UL) {
- printk(KERN_ERR PFX "Cannot map device registers, "
- "aborting.\n");
+ dev_err(&pdev->dev, "Cannot map device registers, aborting.\n");
err = -ENOMEM;
goto err_out_free_dev;
}
@@ -2212,8 +2210,8 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
err = b44_get_invariants(bp);
if (err) {
- printk(KERN_ERR PFX "Problem fetching invariants of chip, "
- "aborting.\n");
+ dev_err(&pdev->dev,
+ "Problem fetching invariants of chip, aborting.\n");
goto err_out_iounmap;
}
@@ -2233,8 +2231,7 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
err = register_netdev(dev);
if (err) {
- printk(KERN_ERR PFX "Cannot register net device, "
- "aborting.\n");
+ dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
goto err_out_iounmap;
}
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 4f4db5ae503..db73de0d251 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -1639,7 +1639,7 @@ bnx2_tx_int(struct bnx2 *bp)
skb = tx_buf->skb;
#ifdef BCM_TSO
/* partial BD completions possible with TSO packets */
- if (skb_shinfo(skb)->gso_size) {
+ if (skb_is_gso(skb)) {
u16 last_idx, last_ring_idx;
last_idx = sw_cons +
@@ -5575,20 +5575,20 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
/* enable device (incl. PCI PM wakeup), and bus-mastering */
rc = pci_enable_device(pdev);
if (rc) {
- printk(KERN_ERR PFX "Cannot enable PCI device, aborting.");
+ dev_err(&pdev->dev, "Cannot enable PCI device, aborting.");
goto err_out;
}
if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
- printk(KERN_ERR PFX "Cannot find PCI device base address, "
- "aborting.\n");
+ dev_err(&pdev->dev,
+ "Cannot find PCI device base address, aborting.\n");
rc = -ENODEV;
goto err_out_disable;
}
rc = pci_request_regions(pdev, DRV_MODULE_NAME);
if (rc) {
- printk(KERN_ERR PFX "Cannot obtain PCI resources, aborting.\n");
+ dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting.\n");
goto err_out_disable;
}
@@ -5596,15 +5596,15 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
if (bp->pm_cap == 0) {
- printk(KERN_ERR PFX "Cannot find power management capability, "
- "aborting.\n");
+ dev_err(&pdev->dev,
+ "Cannot find power management capability, aborting.\n");
rc = -EIO;
goto err_out_release;
}
bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
if (bp->pcix_cap == 0) {
- printk(KERN_ERR PFX "Cannot find PCIX capability, aborting.\n");
+ dev_err(&pdev->dev, "Cannot find PCIX capability, aborting.\n");
rc = -EIO;
goto err_out_release;
}
@@ -5612,14 +5612,14 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0) {
bp->flags |= USING_DAC_FLAG;
if (pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK) != 0) {
- printk(KERN_ERR PFX "pci_set_consistent_dma_mask "
- "failed, aborting.\n");
+ dev_err(&pdev->dev,
+ "pci_set_consistent_dma_mask failed, aborting.\n");
rc = -EIO;
goto err_out_release;
}
}
else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) {
- printk(KERN_ERR PFX "System does not support DMA, aborting.\n");
+ dev_err(&pdev->dev, "System does not support DMA, aborting.\n");
rc = -EIO;
goto err_out_release;
}
@@ -5639,7 +5639,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
bp->regview = ioremap_nocache(dev->base_addr, mem_len);
if (!bp->regview) {
- printk(KERN_ERR PFX "Cannot map register space, aborting.\n");
+ dev_err(&pdev->dev, "Cannot map register space, aborting.\n");
rc = -ENOMEM;
goto err_out_release;
}
@@ -5711,8 +5711,8 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
else if ((CHIP_ID(bp) == CHIP_ID_5706_A1) &&
!(bp->flags & PCIX_FLAG)) {
- printk(KERN_ERR PFX "5706 A1 can only be used in a PCIX bus, "
- "aborting.\n");
+ dev_err(&pdev->dev,
+ "5706 A1 can only be used in a PCIX bus, aborting.\n");
goto err_out_unmap;
}
@@ -5733,7 +5733,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
if ((reg & BNX2_DEV_INFO_SIGNATURE_MAGIC_MASK) !=
BNX2_DEV_INFO_SIGNATURE_MAGIC) {
- printk(KERN_ERR PFX "Firmware not running, aborting.\n");
+ dev_err(&pdev->dev, "Firmware not running, aborting.\n");
rc = -ENODEV;
goto err_out_unmap;
}
@@ -5895,7 +5895,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
#endif
if ((rc = register_netdev(dev))) {
- printk(KERN_ERR PFX "Cannot register net device\n");
+ dev_err(&pdev->dev, "Cannot register net device\n");
if (bp->regview)
iounmap(bp->regview);
pci_release_regions(pdev);
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c
index d33130f6470..a31544ccb3c 100644
--- a/drivers/net/cassini.c
+++ b/drivers/net/cassini.c
@@ -4887,13 +4887,12 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
err = pci_enable_device(pdev);
if (err) {
- printk(KERN_ERR PFX "Cannot enable PCI device, "
- "aborting.\n");
+ dev_err(&pdev->dev, "Cannot enable PCI device, aborting.\n");
return err;
}
if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
- printk(KERN_ERR PFX "Cannot find proper PCI device "
+ dev_err(&pdev->dev, "Cannot find proper PCI device "
"base address, aborting.\n");
err = -ENODEV;
goto err_out_disable_pdev;
@@ -4901,7 +4900,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
dev = alloc_etherdev(sizeof(*cp));
if (!dev) {
- printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
+ dev_err(&pdev->dev, "Etherdev alloc failed, aborting.\n");
err = -ENOMEM;
goto err_out_disable_pdev;
}
@@ -4910,8 +4909,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
err = pci_request_regions(pdev, dev->name);
if (err) {
- printk(KERN_ERR PFX "Cannot obtain PCI resources, "
- "aborting.\n");
+ dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting.\n");
goto err_out_free_netdev;
}
pci_set_master(pdev);
@@ -4941,7 +4939,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
if (pci_write_config_byte(pdev,
PCI_CACHE_LINE_SIZE,
cas_cacheline_size)) {
- printk(KERN_ERR PFX "Could not set PCI cache "
+ dev_err(&pdev->dev, "Could not set PCI cache "
"line size\n");
goto err_write_cacheline;
}
@@ -4955,7 +4953,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
err = pci_set_consistent_dma_mask(pdev,
DMA_64BIT_MASK);
if (err < 0) {
- printk(KERN_ERR PFX "Unable to obtain 64-bit DMA "
+ dev_err(&pdev->dev, "Unable to obtain 64-bit DMA "
"for consistent allocations\n");
goto err_out_free_res;
}
@@ -4963,7 +4961,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
} else {
err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
if (err) {
- printk(KERN_ERR PFX "No usable DMA configuration, "
+ dev_err(&pdev->dev, "No usable DMA configuration, "
"aborting.\n");
goto err_out_free_res;
}
@@ -5023,8 +5021,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
/* give us access to cassini registers */
cp->regs = pci_iomap(pdev, 0, casreg_len);
if (cp->regs == 0UL) {
- printk(KERN_ERR PFX "Cannot map device registers, "
- "aborting.\n");
+ dev_err(&pdev->dev, "Cannot map device registers, aborting.\n");
goto err_out_free_res;
}
cp->casreg_len = casreg_len;
@@ -5040,8 +5037,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
pci_alloc_consistent(pdev, sizeof(struct cas_init_block),
&cp->block_dvma);
if (!cp->init_block) {
- printk(KERN_ERR PFX "Cannot allocate init block, "
- "aborting.\n");
+ dev_err(&pdev->dev, "Cannot allocate init block, aborting.\n");
goto err_out_iounmap;
}
@@ -5085,8 +5081,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
dev->features |= NETIF_F_HIGHDMA;
if (register_netdev(dev)) {
- printk(KERN_ERR PFX "Cannot register net device, "
- "aborting.\n");
+ dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
goto err_out_free_consistent;
}
diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c
index 87f94d939ff..61b3754f50f 100644
--- a/drivers/net/chelsio/sge.c
+++ b/drivers/net/chelsio/sge.c
@@ -1417,7 +1417,7 @@ int t1_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct cpl_tx_pkt *cpl;
#ifdef NETIF_F_TSO
- if (skb_shinfo(skb)->gso_size) {
+ if (skb_is_gso(skb)) {
int eth_type;
struct cpl_tx_pkt_lso *hdr;
diff --git a/drivers/net/declance.c b/drivers/net/declance.c
index 2038ca7e49c..6ad5796121c 100644
--- a/drivers/net/declance.c
+++ b/drivers/net/declance.c
@@ -703,8 +703,8 @@ static irqreturn_t lance_dma_merr_int(const int irq, void *dev_id,
return IRQ_HANDLED;
}
-static irqreturn_t
-lance_interrupt(const int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t lance_interrupt(const int irq, void *dev_id,
+ struct pt_regs *regs)
{
struct net_device *dev = (struct net_device *) dev_id;
struct lance_private *lp = netdev_priv(dev);
@@ -1253,7 +1253,7 @@ static int __init dec_lance_init(const int type, const int slot)
return 0;
err_out_free_dev:
- kfree(dev);
+ free_netdev(dev);
err_out:
return ret;
@@ -1299,6 +1299,7 @@ static void __exit dec_lance_cleanup(void)
while (root_lance_dev) {
struct net_device *dev = root_lance_dev;
struct lance_private *lp = netdev_priv(dev);
+
unregister_netdev(dev);
#ifdef CONFIG_TC
if (lp->slot >= 0)
diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c
index 4b6ddb70f92..402961e68c8 100644
--- a/drivers/net/dl2k.c
+++ b/drivers/net/dl2k.c
@@ -9,49 +9,10 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
*/
-/*
- Rev Date Description
- ==========================================================================
- 0.01 2001/05/03 Created DL2000-based linux driver
- 0.02 2001/05/21 Added VLAN and hardware checksum support.
- 1.00 2001/06/26 Added jumbo frame support.
- 1.01 2001/08/21 Added two parameters, rx_coalesce and rx_timeout.
- 1.02 2001/10/08 Supported fiber media.
- Added flow control parameters.
- 1.03 2001/10/12 Changed the default media to 1000mbps_fd for
- the fiber devices.
- 1.04 2001/11/08 Fixed Tx stopped when tx very busy.
- 1.05 2001/11/22 Fixed Tx stopped when unidirectional tx busy.
- 1.06 2001/12/13 Fixed disconnect bug at 10Mbps mode.
- Fixed tx_full flag incorrect.
- Added tx_coalesce paramter.
- 1.07 2002/01/03 Fixed miscount of RX frame error.
- 1.08 2002/01/17 Fixed the multicast bug.
- 1.09 2002/03/07 Move rx-poll-now to re-fill loop.
- Added rio_timer() to watch rx buffers.
- 1.10 2002/04/16 Fixed miscount of carrier error.
- 1.11 2002/05/23 Added ISR schedule scheme
- Fixed miscount of rx frame error for DGE-550SX.
- Fixed VLAN bug.
- 1.12 2002/06/13 Lock tx_coalesce=1 on 10/100Mbps mode.
- 1.13 2002/08/13 1. Fix disconnection (many tx:carrier/rx:frame
- errs) with some mainboards.
- 2. Use definition "DRV_NAME" "DRV_VERSION"
- "DRV_RELDATE" for flexibility.
- 1.14 2002/08/14 Support ethtool.
- 1.15 2002/08/27 Changed the default media to Auto-Negotiation
- for the fiber devices.
- 1.16 2002/09/04 More power down time for fiber devices auto-
- negotiation.
- Fix disconnect bug after ifup and ifdown.
- 1.17 2002/10/03 Fix RMON statistics overflow.
- Always use I/O mapping to access eeprom,
- avoid system freezing with some chipsets.
-*/
#define DRV_NAME "D-Link DL2000-based linux driver"
-#define DRV_VERSION "v1.17b"
-#define DRV_RELDATE "2006/03/10"
+#define DRV_VERSION "v1.18"
+#define DRV_RELDATE "2006/06/27"
#include "dl2k.h"
#include <linux/dma-mapping.h>
diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c
index 36d511729f7..2146cf74425 100644
--- a/drivers/net/dummy.c
+++ b/drivers/net/dummy.c
@@ -132,6 +132,7 @@ static int __init dummy_init_module(void)
for (i = 0; i < numdummies && !err; i++)
err = dummy_init_one(i);
if (err) {
+ i--;
while (--i >= 0)
dummy_free_one(i);
}
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index 3042d33e2d4..d304297c496 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -68,7 +68,6 @@
#ifdef NETIF_F_TSO
#include <net/checksum.h>
#endif
-#include <linux/workqueue.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
@@ -111,6 +110,9 @@ struct e1000_adapter;
#define E1000_MIN_RXD 80
#define E1000_MAX_82544_RXD 4096
+/* this is the size past which hardware will drop packets when setting LPE=0 */
+#define MAXIMUM_ETHERNET_VLAN_SIZE 1522
+
/* Supported Rx Buffer Sizes */
#define E1000_RXBUFFER_128 128 /* Used for packet split */
#define E1000_RXBUFFER_256 256 /* Used for packet split */
@@ -143,6 +145,7 @@ struct e1000_adapter;
#define AUTO_ALL_MODES 0
#define E1000_EEPROM_82544_APM 0x0004
+#define E1000_EEPROM_ICH8_APME 0x0004
#define E1000_EEPROM_APME 0x0400
#ifndef E1000_MASTER_SLAVE
@@ -254,7 +257,6 @@ struct e1000_adapter {
spinlock_t tx_queue_lock;
#endif
atomic_t irq_sem;
- struct work_struct watchdog_task;
struct work_struct reset_task;
uint8_t fc_autoneg;
@@ -339,8 +341,14 @@ struct e1000_adapter {
#ifdef NETIF_F_TSO
boolean_t tso_force;
#endif
+ boolean_t smart_power_down; /* phy smart power down */
+ unsigned long flags;
};
+enum e1000_state_t {
+ __E1000_DRIVER_TESTING,
+ __E1000_RESETTING,
+};
/* e1000_main.c */
extern char e1000_driver_name[];
@@ -348,6 +356,7 @@ extern char e1000_driver_version[];
int e1000_up(struct e1000_adapter *adapter);
void e1000_down(struct e1000_adapter *adapter);
void e1000_reset(struct e1000_adapter *adapter);
+void e1000_reinit_locked(struct e1000_adapter *adapter);
int e1000_setup_all_tx_resources(struct e1000_adapter *adapter);
void e1000_free_all_tx_resources(struct e1000_adapter *adapter);
int e1000_setup_all_rx_resources(struct e1000_adapter *adapter);
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index d1966489176..88a82ba88f5 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -109,7 +109,8 @@ e1000_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
SUPPORTED_1000baseT_Full|
SUPPORTED_Autoneg |
SUPPORTED_TP);
-
+ if (hw->phy_type == e1000_phy_ife)
+ ecmd->supported &= ~SUPPORTED_1000baseT_Full;
ecmd->advertising = ADVERTISED_TP;
if (hw->autoneg == 1) {
@@ -203,11 +204,9 @@ e1000_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
/* reset the link */
- if (netif_running(adapter->netdev)) {
- e1000_down(adapter);
- e1000_reset(adapter);
- e1000_up(adapter);
- } else
+ if (netif_running(adapter->netdev))
+ e1000_reinit_locked(adapter);
+ else
e1000_reset(adapter);
return 0;
@@ -254,10 +253,9 @@ e1000_set_pauseparam(struct net_device *netdev,
hw->original_fc = hw->fc;
if (adapter->fc_autoneg == AUTONEG_ENABLE) {
- if (netif_running(adapter->netdev)) {
- e1000_down(adapter);
- e1000_up(adapter);
- } else
+ if (netif_running(adapter->netdev))
+ e1000_reinit_locked(adapter);
+ else
e1000_reset(adapter);
} else
return ((hw->media_type == e1000_media_type_fiber) ?
@@ -279,10 +277,9 @@ e1000_set_rx_csum(struct net_device *netdev, uint32_t data)
struct e1000_adapter *adapter = netdev_priv(netdev);
adapter->rx_csum = data;
- if (netif_running(netdev)) {
- e1000_down(adapter);
- e1000_up(adapter);
- } else
+ if (netif_running(netdev))
+ e1000_reinit_locked(adapter);
+ else
e1000_reset(adapter);
return 0;
}
@@ -577,6 +574,7 @@ e1000_get_drvinfo(struct net_device *netdev,
case e1000_82572:
case e1000_82573:
case e1000_80003es2lan:
+ case e1000_ich8lan:
sprintf(firmware_version, "%d.%d-%d",
(eeprom_data & 0xF000) >> 12,
(eeprom_data & 0x0FF0) >> 4,
@@ -631,6 +629,9 @@ e1000_set_ringparam(struct net_device *netdev,
tx_ring_size = sizeof(struct e1000_tx_ring) * adapter->num_tx_queues;
rx_ring_size = sizeof(struct e1000_rx_ring) * adapter->num_rx_queues;
+ while (test_and_set_bit(__E1000_RESETTING, &adapter->flags))
+ msleep(1);
+
if (netif_running(adapter->netdev))
e1000_down(adapter);
@@ -691,9 +692,11 @@ e1000_set_ringparam(struct net_device *netdev,
adapter->rx_ring = rx_new;
adapter->tx_ring = tx_new;
if ((err = e1000_up(adapter)))
- return err;
+ goto err_setup;
}
+ clear_bit(__E1000_RESETTING, &adapter->flags);
+
return 0;
err_setup_tx:
e1000_free_all_rx_resources(adapter);
@@ -701,6 +704,8 @@ err_setup_rx:
adapter->rx_ring = rx_old;
adapter->tx_ring = tx_old;
e1000_up(adapter);
+err_setup:
+ clear_bit(__E1000_RESETTING, &adapter->flags);
return err;
}
@@ -754,6 +759,7 @@ e1000_reg_test(struct e1000_adapter *adapter, uint64_t *data)
toggle = 0x7FFFF3FF;
break;
case e1000_82573:
+ case e1000_ich8lan:
toggle = 0x7FFFF033;
break;
default:
@@ -773,11 +779,12 @@ e1000_reg_test(struct e1000_adapter *adapter, uint64_t *data)
}
/* restore previous status */
E1000_WRITE_REG(&adapter->hw, STATUS, before);
-
- REG_PATTERN_TEST(FCAL, 0xFFFFFFFF, 0xFFFFFFFF);
- REG_PATTERN_TEST(FCAH, 0x0000FFFF, 0xFFFFFFFF);
- REG_PATTERN_TEST(FCT, 0x0000FFFF, 0xFFFFFFFF);
- REG_PATTERN_TEST(VET, 0x0000FFFF, 0xFFFFFFFF);
+ if (adapter->hw.mac_type != e1000_ich8lan) {
+ REG_PATTERN_TEST(FCAL, 0xFFFFFFFF, 0xFFFFFFFF);
+ REG_PATTERN_TEST(FCAH, 0x0000FFFF, 0xFFFFFFFF);
+ REG_PATTERN_TEST(FCT, 0x0000FFFF, 0xFFFFFFFF);
+ REG_PATTERN_TEST(VET, 0x0000FFFF, 0xFFFFFFFF);
+ }
REG_PATTERN_TEST(RDTR, 0x0000FFFF, 0xFFFFFFFF);
REG_PATTERN_TEST(RDBAH, 0xFFFFFFFF, 0xFFFFFFFF);
REG_PATTERN_TEST(RDLEN, 0x000FFF80, 0x000FFFFF);
@@ -790,20 +797,22 @@ e1000_reg_test(struct e1000_adapter *adapter, uint64_t *data)
REG_PATTERN_TEST(TDLEN, 0x000FFF80, 0x000FFFFF);
REG_SET_AND_CHECK(RCTL, 0xFFFFFFFF, 0x00000000);
- REG_SET_AND_CHECK(RCTL, 0x06DFB3FE, 0x003FFFFB);
+ before = (adapter->hw.mac_type == e1000_ich8lan ?
+ 0x06C3B33E : 0x06DFB3FE);
+ REG_SET_AND_CHECK(RCTL, before, 0x003FFFFB);
REG_SET_AND_CHECK(TCTL, 0xFFFFFFFF, 0x00000000);
if (adapter->hw.mac_type >= e1000_82543) {
- REG_SET_AND_CHECK(RCTL, 0x06DFB3FE, 0xFFFFFFFF);
+ REG_SET_AND_CHECK(RCTL, before, 0xFFFFFFFF);
REG_PATTERN_TEST(RDBAL, 0xFFFFFFF0, 0xFFFFFFFF);
- REG_PATTERN_TEST(TXCW, 0xC000FFFF, 0x0000FFFF);
+ if (adapter->hw.mac_type != e1000_ich8lan)
+ REG_PATTERN_TEST(TXCW, 0xC000FFFF, 0x0000FFFF);
REG_PATTERN_TEST(TDBAL, 0xFFFFFFF0, 0xFFFFFFFF);
REG_PATTERN_TEST(TIDV, 0x0000FFFF, 0x0000FFFF);
-
- for (i = 0; i < E1000_RAR_ENTRIES; i++) {
- REG_PATTERN_TEST(RA + ((i << 1) << 2), 0xFFFFFFFF,
- 0xFFFFFFFF);
+ value = (adapter->hw.mac_type == e1000_ich8lan ?
+ E1000_RAR_ENTRIES_ICH8LAN : E1000_RAR_ENTRIES);
+ for (i = 0; i < value; i++) {
REG_PATTERN_TEST(RA + (((i << 1) + 1) << 2), 0x8003FFFF,
0xFFFFFFFF);
}
@@ -817,7 +826,9 @@ e1000_reg_test(struct e1000_adapter *adapter, uint64_t *data)
}
- for (i = 0; i < E1000_MC_TBL_SIZE; i++)
+ value = (adapter->hw.mac_type == e1000_ich8lan ?
+ E1000_MC_TBL_SIZE_ICH8LAN : E1000_MC_TBL_SIZE);
+ for (i = 0; i < value; i++)
REG_PATTERN_TEST(MTA + (i << 2), 0xFFFFFFFF, 0xFFFFFFFF);
*data = 0;
@@ -889,6 +900,8 @@ e1000_intr_test(struct e1000_adapter *adapter, uint64_t *data)
/* Test each interrupt */
for (; i < 10; i++) {
+ if (adapter->hw.mac_type == e1000_ich8lan && i == 8)
+ continue;
/* Interrupt to test */
mask = 1 << i;
@@ -1246,18 +1259,33 @@ e1000_integrated_phy_loopback(struct e1000_adapter *adapter)
} else if (adapter->hw.phy_type == e1000_phy_gg82563) {
e1000_write_phy_reg(&adapter->hw,
GG82563_PHY_KMRN_MODE_CTRL,
- 0x1CE);
+ 0x1CC);
}
- /* force 1000, set loopback */
- e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x4140);
- /* Now set up the MAC to the same speed/duplex as the PHY. */
ctrl_reg = E1000_READ_REG(&adapter->hw, CTRL);
- ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */
- ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
- E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
- E1000_CTRL_SPD_1000 |/* Force Speed to 1000 */
- E1000_CTRL_FD); /* Force Duplex to FULL */
+
+ if (adapter->hw.phy_type == e1000_phy_ife) {
+ /* force 100, set loopback */
+ e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x6100);
+
+ /* Now set up the MAC to the same speed/duplex as the PHY. */
+ ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */
+ ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
+ E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
+ E1000_CTRL_SPD_100 |/* Force Speed to 100 */
+ E1000_CTRL_FD); /* Force Duplex to FULL */
+ } else {
+ /* force 1000, set loopback */
+ e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x4140);
+
+ /* Now set up the MAC to the same speed/duplex as the PHY. */
+ ctrl_reg = E1000_READ_REG(&adapter->hw, CTRL);
+ ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */
+ ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
+ E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
+ E1000_CTRL_SPD_1000 |/* Force Speed to 1000 */
+ E1000_CTRL_FD); /* Force Duplex to FULL */
+ }
if (adapter->hw.media_type == e1000_media_type_copper &&
adapter->hw.phy_type == e1000_phy_m88) {
@@ -1317,6 +1345,7 @@ e1000_set_phy_loopback(struct e1000_adapter *adapter)
case e1000_82572:
case e1000_82573:
case e1000_80003es2lan:
+ case e1000_ich8lan:
return e1000_integrated_phy_loopback(adapter);
break;
@@ -1568,6 +1597,7 @@ e1000_diag_test(struct net_device *netdev,
struct e1000_adapter *adapter = netdev_priv(netdev);
boolean_t if_running = netif_running(netdev);
+ set_bit(__E1000_DRIVER_TESTING, &adapter->flags);
if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
/* Offline tests */
@@ -1582,7 +1612,8 @@ e1000_diag_test(struct net_device *netdev,
eth_test->flags |= ETH_TEST_FL_FAILED;
if (if_running)
- e1000_down(adapter);
+ /* indicate we're in test mode */
+ dev_close(netdev);
else
e1000_reset(adapter);
@@ -1607,8 +1638,9 @@ e1000_diag_test(struct net_device *netdev,
adapter->hw.autoneg = autoneg;
e1000_reset(adapter);
+ clear_bit(__E1000_DRIVER_TESTING, &adapter->flags);
if (if_running)
- e1000_up(adapter);
+ dev_open(netdev);
} else {
/* Online tests */
if (e1000_link_test(adapter, &data[4]))
@@ -1619,6 +1651,8 @@ e1000_diag_test(struct net_device *netdev,
data[1] = 0;
data[2] = 0;
data[3] = 0;
+
+ clear_bit(__E1000_DRIVER_TESTING, &adapter->flags);
}
msleep_interruptible(4 * 1000);
}
@@ -1778,21 +1812,18 @@ e1000_phys_id(struct net_device *netdev, uint32_t data)
mod_timer(&adapter->blink_timer, jiffies);
msleep_interruptible(data * 1000);
del_timer_sync(&adapter->blink_timer);
- } else if (adapter->hw.mac_type < e1000_82573) {
- E1000_WRITE_REG(&adapter->hw, LEDCTL,
- (E1000_LEDCTL_LED2_BLINK_RATE |
- E1000_LEDCTL_LED0_BLINK | E1000_LEDCTL_LED2_BLINK |
- (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED2_MODE_SHIFT) |
- (E1000_LEDCTL_MODE_LINK_ACTIVITY << E1000_LEDCTL_LED0_MODE_SHIFT) |
- (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED1_MODE_SHIFT)));
+ } else if (adapter->hw.phy_type == e1000_phy_ife) {
+ if (!adapter->blink_timer.function) {
+ init_timer(&adapter->blink_timer);
+ adapter->blink_timer.function = e1000_led_blink_callback;
+ adapter->blink_timer.data = (unsigned long) adapter;
+ }
+ mod_timer(&adapter->blink_timer, jiffies);
msleep_interruptible(data * 1000);
+ del_timer_sync(&adapter->blink_timer);
+ e1000_write_phy_reg(&(adapter->hw), IFE_PHY_SPECIAL_CONTROL_LED, 0);
} else {
- E1000_WRITE_REG(&adapter->hw, LEDCTL,
- (E1000_LEDCTL_LED2_BLINK_RATE |
- E1000_LEDCTL_LED1_BLINK | E1000_LEDCTL_LED2_BLINK |
- (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED2_MODE_SHIFT) |
- (E1000_LEDCTL_MODE_LINK_ACTIVITY << E1000_LEDCTL_LED1_MODE_SHIFT) |
- (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED0_MODE_SHIFT)));
+ e1000_blink_led_start(&adapter->hw);
msleep_interruptible(data * 1000);
}
@@ -1807,10 +1838,8 @@ static int
e1000_nway_reset(struct net_device *netdev)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
- if (netif_running(netdev)) {
- e1000_down(adapter);
- e1000_up(adapter);
- }
+ if (netif_running(netdev))
+ e1000_reinit_locked(adapter);
return 0;
}
diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
index 3959039b16e..583518ae49c 100644
--- a/drivers/net/e1000/e1000_hw.c
+++ b/drivers/net/e1000/e1000_hw.c
@@ -101,7 +101,8 @@ static void e1000_write_reg_io(struct e1000_hw *hw, uint32_t offset,
#define E1000_WRITE_REG_IO(a, reg, val) \
e1000_write_reg_io((a), E1000_##reg, val)
-static int32_t e1000_configure_kmrn_for_10_100(struct e1000_hw *hw);
+static int32_t e1000_configure_kmrn_for_10_100(struct e1000_hw *hw,
+ uint16_t duplex);
static int32_t e1000_configure_kmrn_for_1000(struct e1000_hw *hw);
/* IGP cable length table */
@@ -156,6 +157,14 @@ e1000_set_phy_type(struct e1000_hw *hw)
hw->phy_type = e1000_phy_igp;
break;
}
+ case IGP03E1000_E_PHY_ID:
+ hw->phy_type = e1000_phy_igp_3;
+ break;
+ case IFE_E_PHY_ID:
+ case IFE_PLUS_E_PHY_ID:
+ case IFE_C_E_PHY_ID:
+ hw->phy_type = e1000_phy_ife;
+ break;
case GG82563_E_PHY_ID:
if (hw->mac_type == e1000_80003es2lan) {
hw->phy_type = e1000_phy_gg82563;
@@ -332,6 +341,7 @@ e1000_set_mac_type(struct e1000_hw *hw)
break;
case E1000_DEV_ID_82541EI:
case E1000_DEV_ID_82541EI_MOBILE:
+ case E1000_DEV_ID_82541ER_LOM:
hw->mac_type = e1000_82541;
break;
case E1000_DEV_ID_82541ER:
@@ -341,6 +351,7 @@ e1000_set_mac_type(struct e1000_hw *hw)
hw->mac_type = e1000_82541_rev_2;
break;
case E1000_DEV_ID_82547EI:
+ case E1000_DEV_ID_82547EI_MOBILE:
hw->mac_type = e1000_82547;
break;
case E1000_DEV_ID_82547GI:
@@ -354,6 +365,7 @@ e1000_set_mac_type(struct e1000_hw *hw)
case E1000_DEV_ID_82572EI_COPPER:
case E1000_DEV_ID_82572EI_FIBER:
case E1000_DEV_ID_82572EI_SERDES:
+ case E1000_DEV_ID_82572EI:
hw->mac_type = e1000_82572;
break;
case E1000_DEV_ID_82573E:
@@ -361,16 +373,29 @@ e1000_set_mac_type(struct e1000_hw *hw)
case E1000_DEV_ID_82573L:
hw->mac_type = e1000_82573;
break;
+ case E1000_DEV_ID_80003ES2LAN_COPPER_SPT:
+ case E1000_DEV_ID_80003ES2LAN_SERDES_SPT:
case E1000_DEV_ID_80003ES2LAN_COPPER_DPT:
case E1000_DEV_ID_80003ES2LAN_SERDES_DPT:
hw->mac_type = e1000_80003es2lan;
break;
+ case E1000_DEV_ID_ICH8_IGP_M_AMT:
+ case E1000_DEV_ID_ICH8_IGP_AMT:
+ case E1000_DEV_ID_ICH8_IGP_C:
+ case E1000_DEV_ID_ICH8_IFE:
+ case E1000_DEV_ID_ICH8_IGP_M:
+ hw->mac_type = e1000_ich8lan;
+ break;
default:
/* Should never have loaded on this device */
return -E1000_ERR_MAC_TYPE;
}
switch(hw->mac_type) {
+ case e1000_ich8lan:
+ hw->swfwhw_semaphore_present = TRUE;
+ hw->asf_firmware_present = TRUE;
+ break;
case e1000_80003es2lan:
hw->swfw_sync_present = TRUE;
/* fall through */
@@ -423,6 +448,7 @@ e1000_set_media_type(struct e1000_hw *hw)
case e1000_82542_rev2_1:
hw->media_type = e1000_media_type_fiber;
break;
+ case e1000_ich8lan:
case e1000_82573:
/* The STATUS_TBIMODE bit is reserved or reused for the this
* device.
@@ -527,6 +553,14 @@ e1000_reset_hw(struct e1000_hw *hw)
} while(timeout);
}
+ /* Workaround for ICH8 bit corruption issue in FIFO memory */
+ if (hw->mac_type == e1000_ich8lan) {
+ /* Set Tx and Rx buffer allocation to 8k apiece. */
+ E1000_WRITE_REG(hw, PBA, E1000_PBA_8K);
+ /* Set Packet Buffer Size to 16k. */
+ E1000_WRITE_REG(hw, PBS, E1000_PBS_16K);
+ }
+
/* Issue a global reset to the MAC. This will reset the chip's
* transmit, receive, DMA, and link units. It will not effect
* the current PCI configuration. The global reset bit is self-
@@ -550,6 +584,20 @@ e1000_reset_hw(struct e1000_hw *hw)
/* Reset is performed on a shadow of the control register */
E1000_WRITE_REG(hw, CTRL_DUP, (ctrl | E1000_CTRL_RST));
break;
+ case e1000_ich8lan:
+ if (!hw->phy_reset_disable &&
+ e1000_check_phy_reset_block(hw) == E1000_SUCCESS) {
+ /* e1000_ich8lan PHY HW reset requires MAC CORE reset
+ * at the same time to make sure the interface between
+ * MAC and the external PHY is reset.
+ */
+ ctrl |= E1000_CTRL_PHY_RST;
+ }
+
+ e1000_get_software_flag(hw);
+ E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST));
+ msec_delay(5);
+ break;
default:
E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST));
break;
@@ -591,6 +639,7 @@ e1000_reset_hw(struct e1000_hw *hw)
/* fall through */
case e1000_82571:
case e1000_82572:
+ case e1000_ich8lan:
case e1000_80003es2lan:
ret_val = e1000_get_auto_rd_done(hw);
if(ret_val)
@@ -633,6 +682,12 @@ e1000_reset_hw(struct e1000_hw *hw)
e1000_pci_set_mwi(hw);
}
+ if (hw->mac_type == e1000_ich8lan) {
+ uint32_t kab = E1000_READ_REG(hw, KABGTXD);
+ kab |= E1000_KABGTXD_BGSQLBIAS;
+ E1000_WRITE_REG(hw, KABGTXD, kab);
+ }
+
return E1000_SUCCESS;
}
@@ -675,9 +730,12 @@ e1000_init_hw(struct e1000_hw *hw)
/* Disabling VLAN filtering. */
DEBUGOUT("Initializing the IEEE VLAN\n");
- if (hw->mac_type < e1000_82545_rev_3)
- E1000_WRITE_REG(hw, VET, 0);
- e1000_clear_vfta(hw);
+ /* VET hardcoded to standard value and VFTA removed in ICH8 LAN */
+ if (hw->mac_type != e1000_ich8lan) {
+ if (hw->mac_type < e1000_82545_rev_3)
+ E1000_WRITE_REG(hw, VET, 0);
+ e1000_clear_vfta(hw);
+ }
/* For 82542 (rev 2.0), disable MWI and put the receiver into reset */
if(hw->mac_type == e1000_82542_rev2_0) {
@@ -705,8 +763,14 @@ e1000_init_hw(struct e1000_hw *hw)
/* Zero out the Multicast HASH table */
DEBUGOUT("Zeroing the MTA\n");
mta_size = E1000_MC_TBL_SIZE;
- for(i = 0; i < mta_size; i++)
+ if (hw->mac_type == e1000_ich8lan)
+ mta_size = E1000_MC_TBL_SIZE_ICH8LAN;
+ for(i = 0; i < mta_size; i++) {
E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
+ /* use write flush to prevent Memory Write Block (MWB) from
+ * occuring when accessing our register space */
+ E1000_WRITE_FLUSH(hw);
+ }
/* Set the PCI priority bit correctly in the CTRL register. This
* determines if the adapter gives priority to receives, or if it
@@ -744,6 +808,10 @@ e1000_init_hw(struct e1000_hw *hw)
break;
}
+ /* More time needed for PHY to initialize */
+ if (hw->mac_type == e1000_ich8lan)
+ msec_delay(15);
+
/* Call a subroutine to configure the link and setup flow control. */
ret_val = e1000_setup_link(hw);
@@ -757,6 +825,7 @@ e1000_init_hw(struct e1000_hw *hw)
case e1000_82571:
case e1000_82572:
case e1000_82573:
+ case e1000_ich8lan:
case e1000_80003es2lan:
ctrl |= E1000_TXDCTL_COUNT_DESC;
break;
@@ -795,6 +864,7 @@ e1000_init_hw(struct e1000_hw *hw)
/* Fall through */
case e1000_82571:
case e1000_82572:
+ case e1000_ich8lan:
ctrl = E1000_READ_REG(hw, TXDCTL1);
ctrl = (ctrl & ~E1000_TXDCTL_WTHRESH) | E1000_TXDCTL_FULL_TX_DESC_WB;
if(hw->mac_type >= e1000_82571)
@@ -818,6 +888,11 @@ e1000_init_hw(struct e1000_hw *hw)
*/
e1000_clear_hw_cntrs(hw);
+ /* ICH8 No-snoop bits are opposite polarity.
+ * Set to snoop by default after reset. */
+ if (hw->mac_type == e1000_ich8lan)
+ e1000_set_pci_ex_no_snoop(hw, PCI_EX_82566_SNOOP_ALL);
+
if (hw->device_id == E1000_DEV_ID_82546GB_QUAD_COPPER ||
hw->device_id == E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3) {
ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
@@ -905,6 +980,7 @@ e1000_setup_link(struct e1000_hw *hw)
*/
if (hw->fc == e1000_fc_default) {
switch (hw->mac_type) {
+ case e1000_ich8lan:
case e1000_82573:
hw->fc = e1000_fc_full;
break;
@@ -971,9 +1047,12 @@ e1000_setup_link(struct e1000_hw *hw)
*/
DEBUGOUT("Initializing the Flow Control address, type and timer regs\n");
- E1000_WRITE_REG(hw, FCAL, FLOW_CONTROL_ADDRESS_LOW);
- E1000_WRITE_REG(hw, FCAH, FLOW_CONTROL_ADDRESS_HIGH);
- E1000_WRITE_REG(hw, FCT, FLOW_CONTROL_TYPE);
+ /* FCAL/H and FCT are hardcoded to standard values in e1000_ich8lan. */
+ if (hw->mac_type != e1000_ich8lan) {
+ E1000_WRITE_REG(hw, FCT, FLOW_CONTROL_TYPE);
+ E1000_WRITE_REG(hw, FCAH, FLOW_CONTROL_ADDRESS_HIGH);
+ E1000_WRITE_REG(hw, FCAL, FLOW_CONTROL_ADDRESS_LOW);
+ }
E1000_WRITE_REG(hw, FCTTV, hw->fc_pause_time);
@@ -1237,12 +1316,13 @@ e1000_copper_link_igp_setup(struct e1000_hw *hw)
/* Wait 10ms for MAC to configure PHY from eeprom settings */
msec_delay(15);
-
+ if (hw->mac_type != e1000_ich8lan) {
/* Configure activity LED after PHY reset */
led_ctrl = E1000_READ_REG(hw, LEDCTL);
led_ctrl &= IGP_ACTIVITY_LED_MASK;
led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
+ }
/* disable lplu d3 during driver init */
ret_val = e1000_set_d3_lplu_state(hw, FALSE);
@@ -1478,8 +1558,7 @@ e1000_copper_link_ggp_setup(struct e1000_hw *hw)
if (ret_val)
return ret_val;
- /* Enable Pass False Carrier on the PHY */
- phy_data |= GG82563_KMCR_PASS_FALSE_CARRIER;
+ phy_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
ret_val = e1000_write_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL,
phy_data);
@@ -1561,28 +1640,40 @@ e1000_copper_link_mgp_setup(struct e1000_hw *hw)
phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
if(hw->disable_polarity_correction == 1)
phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
- ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
- if(ret_val)
- return ret_val;
-
- /* Force TX_CLK in the Extended PHY Specific Control Register
- * to 25MHz clock.
- */
- ret_val = e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
- if(ret_val)
+ ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+ if (ret_val)
return ret_val;
- phy_data |= M88E1000_EPSCR_TX_CLK_25;
-
if (hw->phy_revision < M88E1011_I_REV_4) {
- /* Configure Master and Slave downshift values */
- phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
+ /* Force TX_CLK in the Extended PHY Specific Control Register
+ * to 25MHz clock.
+ */
+ ret_val = e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data |= M88E1000_EPSCR_TX_CLK_25;
+
+ if ((hw->phy_revision == E1000_REVISION_2) &&
+ (hw->phy_id == M88E1111_I_PHY_ID)) {
+ /* Vidalia Phy, set the downshift counter to 5x */
+ phy_data &= ~(M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK);
+ phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X;
+ ret_val = e1000_write_phy_reg(hw,
+ M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
+ } else {
+ /* Configure Master and Slave downshift values */
+ phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
- phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
+ phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
- ret_val = e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
- if(ret_val)
- return ret_val;
+ ret_val = e1000_write_phy_reg(hw,
+ M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
+ }
}
/* SW Reset the PHY so all changes take effect */
@@ -1620,6 +1711,10 @@ e1000_copper_link_autoneg(struct e1000_hw *hw)
if(hw->autoneg_advertised == 0)
hw->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+ /* IFE phy only supports 10/100 */
+ if (hw->phy_type == e1000_phy_ife)
+ hw->autoneg_advertised &= AUTONEG_ADVERTISE_10_100_ALL;
+
DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
ret_val = e1000_phy_setup_autoneg(hw);
if(ret_val) {
@@ -1717,6 +1812,26 @@ e1000_setup_copper_link(struct e1000_hw *hw)
DEBUGFUNC("e1000_setup_copper_link");
+ switch (hw->mac_type) {
+ case e1000_80003es2lan:
+ case e1000_ich8lan:
+ /* Set the mac to wait the maximum time between each
+ * iteration and increase the max iterations when
+ * polling the phy; this fixes erroneous timeouts at 10Mbps. */
+ ret_val = e1000_write_kmrn_reg(hw, GG82563_REG(0x34, 4), 0xFFFF);
+ if (ret_val)
+ return ret_val;
+ ret_val = e1000_read_kmrn_reg(hw, GG82563_REG(0x34, 9), &reg_data);
+ if (ret_val)
+ return ret_val;
+ reg_data |= 0x3F;
+ ret_val = e1000_write_kmrn_reg(hw, GG82563_REG(0x34, 9), reg_data);
+ if (ret_val)
+ return ret_val;
+ default:
+ break;
+ }
+
/* Check if it is a valid PHY and set PHY mode if necessary. */
ret_val = e1000_copper_link_preconfig(hw);
if(ret_val)
@@ -1724,10 +1839,8 @@ e1000_setup_copper_link(struct e1000_hw *hw)
switch (hw->mac_type) {
case e1000_80003es2lan:
- ret_val = e1000_read_kmrn_reg(hw, E1000_KUMCTRLSTA_OFFSET_INB_CTRL,
- &reg_data);
- if (ret_val)
- return ret_val;
+ /* Kumeran registers are written-only */
+ reg_data = E1000_KUMCTRLSTA_INB_CTRL_LINK_STATUS_TX_TIMEOUT_DEFAULT;
reg_data |= E1000_KUMCTRLSTA_INB_CTRL_DIS_PADDING;
ret_val = e1000_write_kmrn_reg(hw, E1000_KUMCTRLSTA_OFFSET_INB_CTRL,
reg_data);
@@ -1739,6 +1852,7 @@ e1000_setup_copper_link(struct e1000_hw *hw)
}
if (hw->phy_type == e1000_phy_igp ||
+ hw->phy_type == e1000_phy_igp_3 ||
hw->phy_type == e1000_phy_igp_2) {
ret_val = e1000_copper_link_igp_setup(hw);
if(ret_val)
@@ -1803,7 +1917,7 @@ e1000_setup_copper_link(struct e1000_hw *hw)
* hw - Struct containing variables accessed by shared code
******************************************************************************/
static int32_t
-e1000_configure_kmrn_for_10_100(struct e1000_hw *hw)
+e1000_configure_kmrn_for_10_100(struct e1000_hw *hw, uint16_t duplex)
{
int32_t ret_val = E1000_SUCCESS;
uint32_t tipg;
@@ -1823,6 +1937,18 @@ e1000_configure_kmrn_for_10_100(struct e1000_hw *hw)
tipg |= DEFAULT_80003ES2LAN_TIPG_IPGT_10_100;
E1000_WRITE_REG(hw, TIPG, tipg);
+ ret_val = e1000_read_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, &reg_data);
+
+ if (ret_val)
+ return ret_val;
+
+ if (duplex == HALF_DUPLEX)
+ reg_data |= GG82563_KMCR_PASS_FALSE_CARRIER;
+ else
+ reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
+
+ ret_val = e1000_write_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data);
+
return ret_val;
}
@@ -1847,6 +1973,14 @@ e1000_configure_kmrn_for_1000(struct e1000_hw *hw)
tipg |= DEFAULT_80003ES2LAN_TIPG_IPGT_1000;
E1000_WRITE_REG(hw, TIPG, tipg);
+ ret_val = e1000_read_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, &reg_data);
+
+ if (ret_val)
+ return ret_val;
+
+ reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
+ ret_val = e1000_write_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data);
+
return ret_val;
}
@@ -1869,10 +2003,13 @@ e1000_phy_setup_autoneg(struct e1000_hw *hw)
if(ret_val)
return ret_val;
- /* Read the MII 1000Base-T Control Register (Address 9). */
- ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg);
- if(ret_val)
- return ret_val;
+ if (hw->phy_type != e1000_phy_ife) {
+ /* Read the MII 1000Base-T Control Register (Address 9). */
+ ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg);
+ if (ret_val)
+ return ret_val;
+ } else
+ mii_1000t_ctrl_reg=0;
/* Need to parse both autoneg_advertised and fc and set up
* the appropriate PHY registers. First we will parse for
@@ -1923,6 +2060,9 @@ e1000_phy_setup_autoneg(struct e1000_hw *hw)
if(hw->autoneg_advertised & ADVERTISE_1000_FULL) {
DEBUGOUT("Advertise 1000mb Full duplex\n");
mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
+ if (hw->phy_type == e1000_phy_ife) {
+ DEBUGOUT("e1000_phy_ife is a 10/100 PHY. Gigabit speed is not supported.\n");
+ }
}
/* Check for a software override of the flow control settings, and
@@ -1984,9 +2124,11 @@ e1000_phy_setup_autoneg(struct e1000_hw *hw)
DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
- ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg);
- if(ret_val)
- return ret_val;
+ if (hw->phy_type != e1000_phy_ife) {
+ ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg);
+ if (ret_val)
+ return ret_val;
+ }
return E1000_SUCCESS;
}
@@ -2089,6 +2231,18 @@ e1000_phy_force_speed_duplex(struct e1000_hw *hw)
/* Need to reset the PHY or these changes will be ignored */
mii_ctrl_reg |= MII_CR_RESET;
+ /* Disable MDI-X support for 10/100 */
+ } else if (hw->phy_type == e1000_phy_ife) {
+ ret_val = e1000_read_phy_reg(hw, IFE_PHY_MDIX_CONTROL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data &= ~IFE_PMC_AUTO_MDIX;
+ phy_data &= ~IFE_PMC_FORCE_MDIX;
+
+ ret_val = e1000_write_phy_reg(hw, IFE_PHY_MDIX_CONTROL, phy_data);
+ if (ret_val)
+ return ret_val;
} else {
/* Clear Auto-Crossover to force MDI manually. IGP requires MDI
* forced whenever speed or duplex are forced.
@@ -2721,8 +2875,12 @@ e1000_check_for_link(struct e1000_hw *hw)
*/
if(hw->tbi_compatibility_en) {
uint16_t speed, duplex;
- e1000_get_speed_and_duplex(hw, &speed, &duplex);
- if(speed != SPEED_1000) {
+ ret_val = e1000_get_speed_and_duplex(hw, &speed, &duplex);
+ if (ret_val) {
+ DEBUGOUT("Error getting link speed and duplex\n");
+ return ret_val;
+ }
+ if (speed != SPEED_1000) {
/* If link speed is not set to gigabit speed, we do not need
* to enable TBI compatibility.
*/
@@ -2889,7 +3047,13 @@ e1000_get_speed_and_duplex(struct e1000_hw *hw,
if (*speed == SPEED_1000)
ret_val = e1000_configure_kmrn_for_1000(hw);
else
- ret_val = e1000_configure_kmrn_for_10_100(hw);
+ ret_val = e1000_configure_kmrn_for_10_100(hw, *duplex);
+ if (ret_val)
+ return ret_val;
+ }
+
+ if ((hw->phy_type == e1000_phy_igp_3) && (*speed == SPEED_1000)) {
+ ret_val = e1000_kumeran_lock_loss_workaround(hw);
if (ret_val)
return ret_val;
}
@@ -3079,6 +3243,9 @@ e1000_swfw_sync_acquire(struct e1000_hw *hw, uint16_t mask)
DEBUGFUNC("e1000_swfw_sync_acquire");
+ if (hw->swfwhw_semaphore_present)
+ return e1000_get_software_flag(hw);
+
if (!hw->swfw_sync_present)
return e1000_get_hw_eeprom_semaphore(hw);
@@ -3118,6 +3285,11 @@ e1000_swfw_sync_release(struct e1000_hw *hw, uint16_t mask)
DEBUGFUNC("e1000_swfw_sync_release");
+ if (hw->swfwhw_semaphore_present) {
+ e1000_release_software_flag(hw);
+ return;
+ }
+
if (!hw->swfw_sync_present) {
e1000_put_hw_eeprom_semaphore(hw);
return;
@@ -3160,7 +3332,8 @@ e1000_read_phy_reg(struct e1000_hw *hw,
if (e1000_swfw_sync_acquire(hw, swfw))
return -E1000_ERR_SWFW_SYNC;
- if((hw->phy_type == e1000_phy_igp ||
+ if ((hw->phy_type == e1000_phy_igp ||
+ hw->phy_type == e1000_phy_igp_3 ||
hw->phy_type == e1000_phy_igp_2) &&
(reg_addr > MAX_PHY_MULTI_PAGE_REG)) {
ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
@@ -3299,7 +3472,8 @@ e1000_write_phy_reg(struct e1000_hw *hw,
if (e1000_swfw_sync_acquire(hw, swfw))
return -E1000_ERR_SWFW_SYNC;
- if((hw->phy_type == e1000_phy_igp ||
+ if ((hw->phy_type == e1000_phy_igp ||
+ hw->phy_type == e1000_phy_igp_3 ||
hw->phy_type == e1000_phy_igp_2) &&
(reg_addr > MAX_PHY_MULTI_PAGE_REG)) {
ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
@@ -3514,7 +3688,7 @@ e1000_phy_hw_reset(struct e1000_hw *hw)
E1000_WRITE_FLUSH(hw);
if (hw->mac_type >= e1000_82571)
- msec_delay(10);
+ msec_delay_irq(10);
e1000_swfw_sync_release(hw, swfw);
} else {
/* Read the Extended Device Control Register, assert the PHY_RESET_DIR
@@ -3544,6 +3718,12 @@ e1000_phy_hw_reset(struct e1000_hw *hw)
ret_val = e1000_get_phy_cfg_done(hw);
e1000_release_software_semaphore(hw);
+ if ((hw->mac_type == e1000_ich8lan) &&
+ (hw->phy_type == e1000_phy_igp_3)) {
+ ret_val = e1000_init_lcd_from_nvm(hw);
+ if (ret_val)
+ return ret_val;
+ }
return ret_val;
}
@@ -3572,9 +3752,11 @@ e1000_phy_reset(struct e1000_hw *hw)
case e1000_82541_rev_2:
case e1000_82571:
case e1000_82572:
+ case e1000_ich8lan:
ret_val = e1000_phy_hw_reset(hw);
if(ret_val)
return ret_val;
+
break;
default:
ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &phy_data);
@@ -3597,11 +3779,120 @@ e1000_phy_reset(struct e1000_hw *hw)
}
/******************************************************************************
+* Work-around for 82566 power-down: on D3 entry-
+* 1) disable gigabit link
+* 2) write VR power-down enable
+* 3) read it back
+* if successful continue, else issue LCD reset and repeat
+*
+* hw - struct containing variables accessed by shared code
+******************************************************************************/
+void
+e1000_phy_powerdown_workaround(struct e1000_hw *hw)
+{
+ int32_t reg;
+ uint16_t phy_data;
+ int32_t retry = 0;
+
+ DEBUGFUNC("e1000_phy_powerdown_workaround");
+
+ if (hw->phy_type != e1000_phy_igp_3)
+ return;
+
+ do {
+ /* Disable link */
+ reg = E1000_READ_REG(hw, PHY_CTRL);
+ E1000_WRITE_REG(hw, PHY_CTRL, reg | E1000_PHY_CTRL_GBE_DISABLE |
+ E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
+
+ /* Write VR power-down enable */
+ e1000_read_phy_reg(hw, IGP3_VR_CTRL, &phy_data);
+ e1000_write_phy_reg(hw, IGP3_VR_CTRL, phy_data |
+ IGP3_VR_CTRL_MODE_SHUT);
+
+ /* Read it back and test */
+ e1000_read_phy_reg(hw, IGP3_VR_CTRL, &phy_data);
+ if ((phy_data & IGP3_VR_CTRL_MODE_SHUT) || retry)
+ break;
+
+ /* Issue PHY reset and repeat at most one more time */
+ reg = E1000_READ_REG(hw, CTRL);
+ E1000_WRITE_REG(hw, CTRL, reg | E1000_CTRL_PHY_RST);
+ retry++;
+ } while (retry);
+
+ return;
+
+}
+
+/******************************************************************************
+* Work-around for 82566 Kumeran PCS lock loss:
+* On link status change (i.e. PCI reset, speed change) and link is up and
+* speed is gigabit-
+* 0) if workaround is optionally disabled do nothing
+* 1) wait 1ms for Kumeran link to come up
+* 2) check Kumeran Diagnostic register PCS lock loss bit
+* 3) if not set the link is locked (all is good), otherwise...
+* 4) reset the PHY
+* 5) repeat up to 10 times
+* Note: this is only called for IGP3 copper when speed is 1gb.
+*
+* hw - struct containing variables accessed by shared code
+******************************************************************************/
+int32_t
+e1000_kumeran_lock_loss_workaround(struct e1000_hw *hw)
+{
+ int32_t ret_val;
+ int32_t reg;
+ int32_t cnt;
+ uint16_t phy_data;
+
+ if (hw->kmrn_lock_loss_workaround_disabled)
+ return E1000_SUCCESS;
+
+ /* Make sure link is up before proceeding. If not just return.
+ * Attempting this while link is negotiating fouls up link
+ * stability */
+ ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
+ ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
+
+ if (phy_data & MII_SR_LINK_STATUS) {
+ for (cnt = 0; cnt < 10; cnt++) {
+ /* read once to clear */
+ ret_val = e1000_read_phy_reg(hw, IGP3_KMRN_DIAG, &phy_data);
+ if (ret_val)
+ return ret_val;
+ /* and again to get new status */
+ ret_val = e1000_read_phy_reg(hw, IGP3_KMRN_DIAG, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ /* check for PCS lock */
+ if (!(phy_data & IGP3_KMRN_DIAG_PCS_LOCK_LOSS))
+ return E1000_SUCCESS;
+
+ /* Issue PHY reset */
+ e1000_phy_hw_reset(hw);
+ msec_delay_irq(5);
+ }
+ /* Disable GigE link negotiation */
+ reg = E1000_READ_REG(hw, PHY_CTRL);
+ E1000_WRITE_REG(hw, PHY_CTRL, reg | E1000_PHY_CTRL_GBE_DISABLE |
+ E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
+
+ /* unable to acquire PCS lock */
+ return E1000_ERR_PHY;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
* Probes the expected PHY address for known PHY IDs
*
* hw - Struct containing variables accessed by shared code
******************************************************************************/
-static int32_t
+int32_t
e1000_detect_gig_phy(struct e1000_hw *hw)
{
int32_t phy_init_status, ret_val;
@@ -3613,8 +3904,8 @@ e1000_detect_gig_phy(struct e1000_hw *hw)
/* The 82571 firmware may still be configuring the PHY. In this
* case, we cannot access the PHY until the configuration is done. So
* we explicitly set the PHY values. */
- if(hw->mac_type == e1000_82571 ||
- hw->mac_type == e1000_82572) {
+ if (hw->mac_type == e1000_82571 ||
+ hw->mac_type == e1000_82572) {
hw->phy_id = IGP01E1000_I_PHY_ID;
hw->phy_type = e1000_phy_igp_2;
return E1000_SUCCESS;
@@ -3631,7 +3922,7 @@ e1000_detect_gig_phy(struct e1000_hw *hw)
/* Read the PHY ID Registers to identify which PHY is onboard. */
ret_val = e1000_read_phy_reg(hw, PHY_ID1, &phy_id_high);
- if(ret_val)
+ if (ret_val)
return ret_val;
hw->phy_id = (uint32_t) (phy_id_high << 16);
@@ -3669,6 +3960,12 @@ e1000_detect_gig_phy(struct e1000_hw *hw)
case e1000_80003es2lan:
if (hw->phy_id == GG82563_E_PHY_ID) match = TRUE;
break;
+ case e1000_ich8lan:
+ if (hw->phy_id == IGP03E1000_E_PHY_ID) match = TRUE;
+ if (hw->phy_id == IFE_E_PHY_ID) match = TRUE;
+ if (hw->phy_id == IFE_PLUS_E_PHY_ID) match = TRUE;
+ if (hw->phy_id == IFE_C_E_PHY_ID) match = TRUE;
+ break;
default:
DEBUGOUT1("Invalid MAC type %d\n", hw->mac_type);
return -E1000_ERR_CONFIG;
@@ -3784,6 +4081,53 @@ e1000_phy_igp_get_info(struct e1000_hw *hw,
}
/******************************************************************************
+* Get PHY information from various PHY registers for ife PHY only.
+*
+* hw - Struct containing variables accessed by shared code
+* phy_info - PHY information structure
+******************************************************************************/
+int32_t
+e1000_phy_ife_get_info(struct e1000_hw *hw,
+ struct e1000_phy_info *phy_info)
+{
+ int32_t ret_val;
+ uint16_t phy_data, polarity;
+
+ DEBUGFUNC("e1000_phy_ife_get_info");
+
+ phy_info->downshift = (e1000_downshift)hw->speed_downgraded;
+ phy_info->extended_10bt_distance = e1000_10bt_ext_dist_enable_normal;
+
+ ret_val = e1000_read_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL, &phy_data);
+ if (ret_val)
+ return ret_val;
+ phy_info->polarity_correction =
+ (phy_data & IFE_PSC_AUTO_POLARITY_DISABLE) >>
+ IFE_PSC_AUTO_POLARITY_DISABLE_SHIFT;
+
+ if (phy_info->polarity_correction == e1000_polarity_reversal_enabled) {
+ ret_val = e1000_check_polarity(hw, &polarity);
+ if (ret_val)
+ return ret_val;
+ } else {
+ /* Polarity is forced. */
+ polarity = (phy_data & IFE_PSC_FORCE_POLARITY) >>
+ IFE_PSC_FORCE_POLARITY_SHIFT;
+ }
+ phy_info->cable_polarity = polarity;
+
+ ret_val = e1000_read_phy_reg(hw, IFE_PHY_MDIX_CONTROL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_info->mdix_mode =
+ (phy_data & (IFE_PMC_AUTO_MDIX | IFE_PMC_FORCE_MDIX)) >>
+ IFE_PMC_MDIX_MODE_SHIFT;
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
* Get PHY information from various PHY registers fot m88 PHY only.
*
* hw - Struct containing variables accessed by shared code
@@ -3898,9 +4242,12 @@ e1000_phy_get_info(struct e1000_hw *hw,
return -E1000_ERR_CONFIG;
}
- if(hw->phy_type == e1000_phy_igp ||
+ if (hw->phy_type == e1000_phy_igp ||
+ hw->phy_type == e1000_phy_igp_3 ||
hw->phy_type == e1000_phy_igp_2)
return e1000_phy_igp_get_info(hw, phy_info);
+ else if (hw->phy_type == e1000_phy_ife)
+ return e1000_phy_ife_get_info(hw, phy_info);
else
return e1000_phy_m88_get_info(hw, phy_info);
}
@@ -4049,6 +4396,35 @@ e1000_init_eeprom_params(struct e1000_hw *hw)
eeprom->use_eerd = TRUE;
eeprom->use_eewr = FALSE;
break;
+ case e1000_ich8lan:
+ {
+ int32_t i = 0;
+ uint32_t flash_size = E1000_READ_ICH8_REG(hw, ICH8_FLASH_GFPREG);
+
+ eeprom->type = e1000_eeprom_ich8;
+ eeprom->use_eerd = FALSE;
+ eeprom->use_eewr = FALSE;
+ eeprom->word_size = E1000_SHADOW_RAM_WORDS;
+
+ /* Zero the shadow RAM structure. But don't load it from NVM
+ * so as to save time for driver init */
+ if (hw->eeprom_shadow_ram != NULL) {
+ for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
+ hw->eeprom_shadow_ram[i].modified = FALSE;
+ hw->eeprom_shadow_ram[i].eeprom_word = 0xFFFF;
+ }
+ }
+
+ hw->flash_base_addr = (flash_size & ICH8_GFPREG_BASE_MASK) *
+ ICH8_FLASH_SECTOR_SIZE;
+
+ hw->flash_bank_size = ((flash_size >> 16) & ICH8_GFPREG_BASE_MASK) + 1;
+ hw->flash_bank_size -= (flash_size & ICH8_GFPREG_BASE_MASK);
+ hw->flash_bank_size *= ICH8_FLASH_SECTOR_SIZE;
+ hw->flash_bank_size /= 2 * sizeof(uint16_t);
+
+ break;
+ }
default:
break;
}
@@ -4469,7 +4845,10 @@ e1000_read_eeprom(struct e1000_hw *hw,
return ret_val;
}
- if(eeprom->type == e1000_eeprom_spi) {
+ if (eeprom->type == e1000_eeprom_ich8)
+ return e1000_read_eeprom_ich8(hw, offset, words, data);
+
+ if (eeprom->type == e1000_eeprom_spi) {
uint16_t word_in;
uint8_t read_opcode = EEPROM_READ_OPCODE_SPI;
@@ -4636,7 +5015,10 @@ e1000_is_onboard_nvm_eeprom(struct e1000_hw *hw)
DEBUGFUNC("e1000_is_onboard_nvm_eeprom");
- if(hw->mac_type == e1000_82573) {
+ if (hw->mac_type == e1000_ich8lan)
+ return FALSE;
+
+ if (hw->mac_type == e1000_82573) {
eecd = E1000_READ_REG(hw, EECD);
/* Isolate bits 15 & 16 */
@@ -4686,8 +5068,22 @@ e1000_validate_eeprom_checksum(struct e1000_hw *hw)
}
}
- for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) {
- if(e1000_read_eeprom(hw, i, 1, &eeprom_data) < 0) {
+ if (hw->mac_type == e1000_ich8lan) {
+ /* Drivers must allocate the shadow ram structure for the
+ * EEPROM checksum to be updated. Otherwise, this bit as well
+ * as the checksum must both be set correctly for this
+ * validation to pass.
+ */
+ e1000_read_eeprom(hw, 0x19, 1, &eeprom_data);
+ if ((eeprom_data & 0x40) == 0) {
+ eeprom_data |= 0x40;
+ e1000_write_eeprom(hw, 0x19, 1, &eeprom_data);
+ e1000_update_eeprom_checksum(hw);
+ }
+ }
+
+ for (i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) {
+ if (e1000_read_eeprom(hw, i, 1, &eeprom_data) < 0) {
DEBUGOUT("EEPROM Read Error\n");
return -E1000_ERR_EEPROM;
}
@@ -4713,6 +5109,7 @@ e1000_validate_eeprom_checksum(struct e1000_hw *hw)
int32_t
e1000_update_eeprom_checksum(struct e1000_hw *hw)
{
+ uint32_t ctrl_ext;
uint16_t checksum = 0;
uint16_t i, eeprom_data;
@@ -4731,6 +5128,14 @@ e1000_update_eeprom_checksum(struct e1000_hw *hw)
return -E1000_ERR_EEPROM;
} else if (hw->eeprom.type == e1000_eeprom_flash) {
e1000_commit_shadow_ram(hw);
+ } else if (hw->eeprom.type == e1000_eeprom_ich8) {
+ e1000_commit_shadow_ram(hw);
+ /* Reload the EEPROM, or else modifications will not appear
+ * until after next adapter reset. */
+ ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+ ctrl_ext |= E1000_CTRL_EXT_EE_RST;
+ E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+ msec_delay(10);
}
return E1000_SUCCESS;
}
@@ -4770,6 +5175,9 @@ e1000_write_eeprom(struct e1000_hw *hw,
if(eeprom->use_eewr == TRUE)
return e1000_write_eeprom_eewr(hw, offset, words, data);
+ if (eeprom->type == e1000_eeprom_ich8)
+ return e1000_write_eeprom_ich8(hw, offset, words, data);
+
/* Prepare the EEPROM for writing */
if (e1000_acquire_eeprom(hw) != E1000_SUCCESS)
return -E1000_ERR_EEPROM;
@@ -4957,11 +5365,17 @@ e1000_commit_shadow_ram(struct e1000_hw *hw)
uint32_t flop = 0;
uint32_t i = 0;
int32_t error = E1000_SUCCESS;
-
- /* The flop register will be used to determine if flash type is STM */
- flop = E1000_READ_REG(hw, FLOP);
+ uint32_t old_bank_offset = 0;
+ uint32_t new_bank_offset = 0;
+ uint32_t sector_retries = 0;
+ uint8_t low_byte = 0;
+ uint8_t high_byte = 0;
+ uint8_t temp_byte = 0;
+ boolean_t sector_write_failed = FALSE;
if (hw->mac_type == e1000_82573) {
+ /* The flop register will be used to determine if flash type is STM */
+ flop = E1000_READ_REG(hw, FLOP);
for (i=0; i < attempts; i++) {
eecd = E1000_READ_REG(hw, EECD);
if ((eecd & E1000_EECD_FLUPD) == 0) {
@@ -4995,6 +5409,106 @@ e1000_commit_shadow_ram(struct e1000_hw *hw)
}
}
+ if (hw->mac_type == e1000_ich8lan && hw->eeprom_shadow_ram != NULL) {
+ /* We're writing to the opposite bank so if we're on bank 1,
+ * write to bank 0 etc. We also need to erase the segment that
+ * is going to be written */
+ if (!(E1000_READ_REG(hw, EECD) & E1000_EECD_SEC1VAL)) {
+ new_bank_offset = hw->flash_bank_size * 2;
+ old_bank_offset = 0;
+ e1000_erase_ich8_4k_segment(hw, 1);
+ } else {
+ old_bank_offset = hw->flash_bank_size * 2;
+ new_bank_offset = 0;
+ e1000_erase_ich8_4k_segment(hw, 0);
+ }
+
+ do {
+ sector_write_failed = FALSE;
+ /* Loop for every byte in the shadow RAM,
+ * which is in units of words. */
+ for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
+ /* Determine whether to write the value stored
+ * in the other NVM bank or a modified value stored
+ * in the shadow RAM */
+ if (hw->eeprom_shadow_ram[i].modified == TRUE) {
+ low_byte = (uint8_t)hw->eeprom_shadow_ram[i].eeprom_word;
+ e1000_read_ich8_byte(hw, (i << 1) + old_bank_offset,
+ &temp_byte);
+ udelay(100);
+ error = e1000_verify_write_ich8_byte(hw,
+ (i << 1) + new_bank_offset,
+ low_byte);
+ if (error != E1000_SUCCESS)
+ sector_write_failed = TRUE;
+ high_byte =
+ (uint8_t)(hw->eeprom_shadow_ram[i].eeprom_word >> 8);
+ e1000_read_ich8_byte(hw, (i << 1) + old_bank_offset + 1,
+ &temp_byte);
+ udelay(100);
+ } else {
+ e1000_read_ich8_byte(hw, (i << 1) + old_bank_offset,
+ &low_byte);
+ udelay(100);
+ error = e1000_verify_write_ich8_byte(hw,
+ (i << 1) + new_bank_offset, low_byte);
+ if (error != E1000_SUCCESS)
+ sector_write_failed = TRUE;
+ e1000_read_ich8_byte(hw, (i << 1) + old_bank_offset + 1,
+ &high_byte);
+ }
+
+ /* If the word is 0x13, then make sure the signature bits
+ * (15:14) are 11b until the commit has completed.
+ * This will allow us to write 10b which indicates the
+ * signature is valid. We want to do this after the write
+ * has completed so that we don't mark the segment valid
+ * while the write is still in progress */
+ if (i == E1000_ICH8_NVM_SIG_WORD)
+ high_byte = E1000_ICH8_NVM_SIG_MASK | high_byte;
+
+ error = e1000_verify_write_ich8_byte(hw,
+ (i << 1) + new_bank_offset + 1, high_byte);
+ if (error != E1000_SUCCESS)
+ sector_write_failed = TRUE;
+
+ if (sector_write_failed == FALSE) {
+ /* Clear the now not used entry in the cache */
+ hw->eeprom_shadow_ram[i].modified = FALSE;
+ hw->eeprom_shadow_ram[i].eeprom_word = 0xFFFF;
+ }
+ }
+
+ /* Don't bother writing the segment valid bits if sector
+ * programming failed. */
+ if (sector_write_failed == FALSE) {
+ /* Finally validate the new segment by setting bit 15:14
+ * to 10b in word 0x13 , this can be done without an
+ * erase as well since these bits are 11 to start with
+ * and we need to change bit 14 to 0b */
+ e1000_read_ich8_byte(hw,
+ E1000_ICH8_NVM_SIG_WORD * 2 + 1 + new_bank_offset,
+ &high_byte);
+ high_byte &= 0xBF;
+ error = e1000_verify_write_ich8_byte(hw,
+ E1000_ICH8_NVM_SIG_WORD * 2 + 1 + new_bank_offset,
+ high_byte);
+ if (error != E1000_SUCCESS)
+ sector_write_failed = TRUE;
+
+ /* And invalidate the previously valid segment by setting
+ * its signature word (0x13) high_byte to 0b. This can be
+ * done without an erase because flash erase sets all bits
+ * to 1's. We can write 1's to 0's without an erase */
+ error = e1000_verify_write_ich8_byte(hw,
+ E1000_ICH8_NVM_SIG_WORD * 2 + 1 + old_bank_offset,
+ 0);
+ if (error != E1000_SUCCESS)
+ sector_write_failed = TRUE;
+ }
+ } while (++sector_retries < 10 && sector_write_failed == TRUE);
+ }
+
return error;
}
@@ -5102,15 +5616,19 @@ e1000_init_rx_addrs(struct e1000_hw *hw)
* the other port. */
if ((hw->mac_type == e1000_82571) && (hw->laa_is_present == TRUE))
rar_num -= 1;
+ if (hw->mac_type == e1000_ich8lan)
+ rar_num = E1000_RAR_ENTRIES_ICH8LAN;
+
/* Zero out the other 15 receive addresses. */
DEBUGOUT("Clearing RAR[1-15]\n");
for(i = 1; i < rar_num; i++) {
E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0);
+ E1000_WRITE_FLUSH(hw);
E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0);
+ E1000_WRITE_FLUSH(hw);
}
}
-#if 0
/******************************************************************************
* Updates the MAC's list of multicast addresses.
*
@@ -5145,6 +5663,8 @@ e1000_mc_addr_list_update(struct e1000_hw *hw,
/* Clear RAR[1-15] */
DEBUGOUT(" Clearing RAR[1-15]\n");
num_rar_entry = E1000_RAR_ENTRIES;
+ if (hw->mac_type == e1000_ich8lan)
+ num_rar_entry = E1000_RAR_ENTRIES_ICH8LAN;
/* Reserve a spot for the Locally Administered Address to work around
* an 82571 issue in which a reset on one port will reload the MAC on
* the other port. */
@@ -5153,14 +5673,19 @@ e1000_mc_addr_list_update(struct e1000_hw *hw,
for(i = rar_used_count; i < num_rar_entry; i++) {
E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0);
+ E1000_WRITE_FLUSH(hw);
E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0);
+ E1000_WRITE_FLUSH(hw);
}
/* Clear the MTA */
DEBUGOUT(" Clearing MTA\n");
num_mta_entry = E1000_NUM_MTA_REGISTERS;
+ if (hw->mac_type == e1000_ich8lan)
+ num_mta_entry = E1000_NUM_MTA_REGISTERS_ICH8LAN;
for(i = 0; i < num_mta_entry; i++) {
E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
+ E1000_WRITE_FLUSH(hw);
}
/* Add the new addresses */
@@ -5194,7 +5719,6 @@ e1000_mc_addr_list_update(struct e1000_hw *hw,
}
DEBUGOUT("MC Update Complete\n");
}
-#endif /* 0 */
/******************************************************************************
* Hashes an address to determine its location in the multicast table
@@ -5217,24 +5741,46 @@ e1000_hash_mc_addr(struct e1000_hw *hw,
* LSB MSB
*/
case 0:
- /* [47:36] i.e. 0x563 for above example address */
- hash_value = ((mc_addr[4] >> 4) | (((uint16_t) mc_addr[5]) << 4));
+ if (hw->mac_type == e1000_ich8lan) {
+ /* [47:38] i.e. 0x158 for above example address */
+ hash_value = ((mc_addr[4] >> 6) | (((uint16_t) mc_addr[5]) << 2));
+ } else {
+ /* [47:36] i.e. 0x563 for above example address */
+ hash_value = ((mc_addr[4] >> 4) | (((uint16_t) mc_addr[5]) << 4));
+ }
break;
case 1:
- /* [46:35] i.e. 0xAC6 for above example address */
- hash_value = ((mc_addr[4] >> 3) | (((uint16_t) mc_addr[5]) << 5));
+ if (hw->mac_type == e1000_ich8lan) {
+ /* [46:37] i.e. 0x2B1 for above example address */
+ hash_value = ((mc_addr[4] >> 5) | (((uint16_t) mc_addr[5]) << 3));
+ } else {
+ /* [46:35] i.e. 0xAC6 for above example address */
+ hash_value = ((mc_addr[4] >> 3) | (((uint16_t) mc_addr[5]) << 5));
+ }
break;
case 2:
- /* [45:34] i.e. 0x5D8 for above example address */
- hash_value = ((mc_addr[4] >> 2) | (((uint16_t) mc_addr[5]) << 6));
+ if (hw->mac_type == e1000_ich8lan) {
+ /*[45:36] i.e. 0x163 for above example address */
+ hash_value = ((mc_addr[4] >> 4) | (((uint16_t) mc_addr[5]) << 4));
+ } else {
+ /* [45:34] i.e. 0x5D8 for above example address */
+ hash_value = ((mc_addr[4] >> 2) | (((uint16_t) mc_addr[5]) << 6));
+ }
break;
case 3:
- /* [43:32] i.e. 0x634 for above example address */
- hash_value = ((mc_addr[4]) | (((uint16_t) mc_addr[5]) << 8));
+ if (hw->mac_type == e1000_ich8lan) {
+ /* [43:34] i.e. 0x18D for above example address */
+ hash_value = ((mc_addr[4] >> 2) | (((uint16_t) mc_addr[5]) << 6));
+ } else {
+ /* [43:32] i.e. 0x634 for above example address */
+ hash_value = ((mc_addr[4]) | (((uint16_t) mc_addr[5]) << 8));
+ }
break;
}
hash_value &= 0xFFF;
+ if (hw->mac_type == e1000_ich8lan)
+ hash_value &= 0x3FF;
return hash_value;
}
@@ -5262,6 +5808,8 @@ e1000_mta_set(struct e1000_hw *hw,
* register are determined by the lower 5 bits of the value.
*/
hash_reg = (hash_value >> 5) & 0x7F;
+ if (hw->mac_type == e1000_ich8lan)
+ hash_reg &= 0x1F;
hash_bit = hash_value & 0x1F;
mta = E1000_READ_REG_ARRAY(hw, MTA, hash_reg);
@@ -5275,9 +5823,12 @@ e1000_mta_set(struct e1000_hw *hw,
if((hw->mac_type == e1000_82544) && ((hash_reg & 0x1) == 1)) {
temp = E1000_READ_REG_ARRAY(hw, MTA, (hash_reg - 1));
E1000_WRITE_REG_ARRAY(hw, MTA, hash_reg, mta);
+ E1000_WRITE_FLUSH(hw);
E1000_WRITE_REG_ARRAY(hw, MTA, (hash_reg - 1), temp);
+ E1000_WRITE_FLUSH(hw);
} else {
E1000_WRITE_REG_ARRAY(hw, MTA, hash_reg, mta);
+ E1000_WRITE_FLUSH(hw);
}
}
@@ -5334,7 +5885,9 @@ e1000_rar_set(struct e1000_hw *hw,
}
E1000_WRITE_REG_ARRAY(hw, RA, (index << 1), rar_low);
+ E1000_WRITE_FLUSH(hw);
E1000_WRITE_REG_ARRAY(hw, RA, ((index << 1) + 1), rar_high);
+ E1000_WRITE_FLUSH(hw);
}
/******************************************************************************
@@ -5351,12 +5904,18 @@ e1000_write_vfta(struct e1000_hw *hw,
{
uint32_t temp;
- if((hw->mac_type == e1000_82544) && ((offset & 0x1) == 1)) {
+ if (hw->mac_type == e1000_ich8lan)
+ return;
+
+ if ((hw->mac_type == e1000_82544) && ((offset & 0x1) == 1)) {
temp = E1000_READ_REG_ARRAY(hw, VFTA, (offset - 1));
E1000_WRITE_REG_ARRAY(hw, VFTA, offset, value);
+ E1000_WRITE_FLUSH(hw);
E1000_WRITE_REG_ARRAY(hw, VFTA, (offset - 1), temp);
+ E1000_WRITE_FLUSH(hw);
} else {
E1000_WRITE_REG_ARRAY(hw, VFTA, offset, value);
+ E1000_WRITE_FLUSH(hw);
}
}
@@ -5373,6 +5932,9 @@ e1000_clear_vfta(struct e1000_hw *hw)
uint32_t vfta_offset = 0;
uint32_t vfta_bit_in_reg = 0;
+ if (hw->mac_type == e1000_ich8lan)
+ return;
+
if (hw->mac_type == e1000_82573) {
if (hw->mng_cookie.vlan_id != 0) {
/* The VFTA is a 4096b bit-field, each identifying a single VLAN
@@ -5392,6 +5954,7 @@ e1000_clear_vfta(struct e1000_hw *hw)
* manageability unit */
vfta_value = (offset == vfta_offset) ? vfta_bit_in_reg : 0;
E1000_WRITE_REG_ARRAY(hw, VFTA, offset, vfta_value);
+ E1000_WRITE_FLUSH(hw);
}
}
@@ -5421,9 +5984,18 @@ e1000_id_led_init(struct e1000_hw * hw)
DEBUGOUT("EEPROM Read Error\n");
return -E1000_ERR_EEPROM;
}
- if((eeprom_data== ID_LED_RESERVED_0000) ||
- (eeprom_data == ID_LED_RESERVED_FFFF)) eeprom_data = ID_LED_DEFAULT;
- for(i = 0; i < 4; i++) {
+
+ if ((hw->mac_type == e1000_82573) &&
+ (eeprom_data == ID_LED_RESERVED_82573))
+ eeprom_data = ID_LED_DEFAULT_82573;
+ else if ((eeprom_data == ID_LED_RESERVED_0000) ||
+ (eeprom_data == ID_LED_RESERVED_FFFF)) {
+ if (hw->mac_type == e1000_ich8lan)
+ eeprom_data = ID_LED_DEFAULT_ICH8LAN;
+ else
+ eeprom_data = ID_LED_DEFAULT;
+ }
+ for (i = 0; i < 4; i++) {
temp = (eeprom_data >> (i << 2)) & led_mask;
switch(temp) {
case ID_LED_ON1_DEF2:
@@ -5519,6 +6091,44 @@ e1000_setup_led(struct e1000_hw *hw)
}
/******************************************************************************
+ * Used on 82571 and later Si that has LED blink bits.
+ * Callers must use their own timer and should have already called
+ * e1000_id_led_init()
+ * Call e1000_cleanup led() to stop blinking
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+e1000_blink_led_start(struct e1000_hw *hw)
+{
+ int16_t i;
+ uint32_t ledctl_blink = 0;
+
+ DEBUGFUNC("e1000_id_led_blink_on");
+
+ if (hw->mac_type < e1000_82571) {
+ /* Nothing to do */
+ return E1000_SUCCESS;
+ }
+ if (hw->media_type == e1000_media_type_fiber) {
+ /* always blink LED0 for PCI-E fiber */
+ ledctl_blink = E1000_LEDCTL_LED0_BLINK |
+ (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED0_MODE_SHIFT);
+ } else {
+ /* set the blink bit for each LED that's "on" (0x0E) in ledctl_mode2 */
+ ledctl_blink = hw->ledctl_mode2;
+ for (i=0; i < 4; i++)
+ if (((hw->ledctl_mode2 >> (i * 8)) & 0xFF) ==
+ E1000_LEDCTL_MODE_LED_ON)
+ ledctl_blink |= (E1000_LEDCTL_LED0_BLINK << (i * 8));
+ }
+
+ E1000_WRITE_REG(hw, LEDCTL, ledctl_blink);
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
* Restores the saved state of the SW controlable LED.
*
* hw - Struct containing variables accessed by shared code
@@ -5548,6 +6158,10 @@ e1000_cleanup_led(struct e1000_hw *hw)
return ret_val;
/* Fall Through */
default:
+ if (hw->phy_type == e1000_phy_ife) {
+ e1000_write_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED, 0);
+ break;
+ }
/* Restore LEDCTL settings */
E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_default);
break;
@@ -5592,7 +6206,10 @@ e1000_led_on(struct e1000_hw *hw)
/* Clear SW Defineable Pin 0 to turn on the LED */
ctrl &= ~E1000_CTRL_SWDPIN0;
ctrl |= E1000_CTRL_SWDPIO0;
- } else if(hw->media_type == e1000_media_type_copper) {
+ } else if (hw->phy_type == e1000_phy_ife) {
+ e1000_write_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED,
+ (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_ON));
+ } else if (hw->media_type == e1000_media_type_copper) {
E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode2);
return E1000_SUCCESS;
}
@@ -5640,7 +6257,10 @@ e1000_led_off(struct e1000_hw *hw)
/* Set SW Defineable Pin 0 to turn off the LED */
ctrl |= E1000_CTRL_SWDPIN0;
ctrl |= E1000_CTRL_SWDPIO0;
- } else if(hw->media_type == e1000_media_type_copper) {
+ } else if (hw->phy_type == e1000_phy_ife) {
+ e1000_write_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED,
+ (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_OFF));
+ } else if (hw->media_type == e1000_media_type_copper) {
E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode1);
return E1000_SUCCESS;
}
@@ -5678,12 +6298,16 @@ e1000_clear_hw_cntrs(struct e1000_hw *hw)
temp = E1000_READ_REG(hw, XOFFRXC);
temp = E1000_READ_REG(hw, XOFFTXC);
temp = E1000_READ_REG(hw, FCRUC);
+
+ if (hw->mac_type != e1000_ich8lan) {
temp = E1000_READ_REG(hw, PRC64);
temp = E1000_READ_REG(hw, PRC127);
temp = E1000_READ_REG(hw, PRC255);
temp = E1000_READ_REG(hw, PRC511);
temp = E1000_READ_REG(hw, PRC1023);
temp = E1000_READ_REG(hw, PRC1522);
+ }
+
temp = E1000_READ_REG(hw, GPRC);
temp = E1000_READ_REG(hw, BPRC);
temp = E1000_READ_REG(hw, MPRC);
@@ -5703,12 +6327,16 @@ e1000_clear_hw_cntrs(struct e1000_hw *hw)
temp = E1000_READ_REG(hw, TOTH);
temp = E1000_READ_REG(hw, TPR);
temp = E1000_READ_REG(hw, TPT);
+
+ if (hw->mac_type != e1000_ich8lan) {
temp = E1000_READ_REG(hw, PTC64);
temp = E1000_READ_REG(hw, PTC127);
temp = E1000_READ_REG(hw, PTC255);
temp = E1000_READ_REG(hw, PTC511);
temp = E1000_READ_REG(hw, PTC1023);
temp = E1000_READ_REG(hw, PTC1522);
+ }
+
temp = E1000_READ_REG(hw, MPTC);
temp = E1000_READ_REG(hw, BPTC);
@@ -5731,6 +6359,9 @@ e1000_clear_hw_cntrs(struct e1000_hw *hw)
temp = E1000_READ_REG(hw, IAC);
temp = E1000_READ_REG(hw, ICRXOC);
+
+ if (hw->mac_type == e1000_ich8lan) return;
+
temp = E1000_READ_REG(hw, ICRXPTC);
temp = E1000_READ_REG(hw, ICRXATC);
temp = E1000_READ_REG(hw, ICTXPTC);
@@ -5911,6 +6542,7 @@ e1000_get_bus_info(struct e1000_hw *hw)
hw->bus_width = e1000_bus_width_pciex_1;
break;
case e1000_82571:
+ case e1000_ich8lan:
case e1000_80003es2lan:
hw->bus_type = e1000_bus_type_pci_express;
hw->bus_speed = e1000_bus_speed_2500;
@@ -5948,8 +6580,6 @@ e1000_get_bus_info(struct e1000_hw *hw)
break;
}
}
-
-#if 0
/******************************************************************************
* Reads a value from one of the devices registers using port I/O (as opposed
* memory mapped I/O). Only 82544 and newer devices support port I/O.
@@ -5967,7 +6597,6 @@ e1000_read_reg_io(struct e1000_hw *hw,
e1000_io_write(hw, io_addr, offset);
return e1000_io_read(hw, io_data);
}
-#endif /* 0 */
/******************************************************************************
* Writes a value to one of the devices registers using port I/O (as opposed to
@@ -6012,8 +6641,6 @@ e1000_get_cable_length(struct e1000_hw *hw,
{
int32_t ret_val;
uint16_t agc_value = 0;
- uint16_t cur_agc, min_agc = IGP01E1000_AGC_LENGTH_TABLE_SIZE;
- uint16_t max_agc = 0;
uint16_t i, phy_data;
uint16_t cable_length;
@@ -6086,6 +6713,8 @@ e1000_get_cable_length(struct e1000_hw *hw,
break;
}
} else if(hw->phy_type == e1000_phy_igp) { /* For IGP PHY */
+ uint16_t cur_agc_value;
+ uint16_t min_agc_value = IGP01E1000_AGC_LENGTH_TABLE_SIZE;
uint16_t agc_reg_array[IGP01E1000_PHY_CHANNEL_NUM] =
{IGP01E1000_PHY_AGC_A,
IGP01E1000_PHY_AGC_B,
@@ -6098,23 +6727,23 @@ e1000_get_cable_length(struct e1000_hw *hw,
if(ret_val)
return ret_val;
- cur_agc = phy_data >> IGP01E1000_AGC_LENGTH_SHIFT;
+ cur_agc_value = phy_data >> IGP01E1000_AGC_LENGTH_SHIFT;
- /* Array bound check. */
- if((cur_agc >= IGP01E1000_AGC_LENGTH_TABLE_SIZE - 1) ||
- (cur_agc == 0))
+ /* Value bound check. */
+ if ((cur_agc_value >= IGP01E1000_AGC_LENGTH_TABLE_SIZE - 1) ||
+ (cur_agc_value == 0))
return -E1000_ERR_PHY;
- agc_value += cur_agc;
+ agc_value += cur_agc_value;
/* Update minimal AGC value. */
- if(min_agc > cur_agc)
- min_agc = cur_agc;
+ if (min_agc_value > cur_agc_value)
+ min_agc_value = cur_agc_value;
}
/* Remove the minimal AGC result for length < 50m */
- if(agc_value < IGP01E1000_PHY_CHANNEL_NUM * e1000_igp_cable_length_50) {
- agc_value -= min_agc;
+ if (agc_value < IGP01E1000_PHY_CHANNEL_NUM * e1000_igp_cable_length_50) {
+ agc_value -= min_agc_value;
/* Get the average length of the remaining 3 channels */
agc_value /= (IGP01E1000_PHY_CHANNEL_NUM - 1);
@@ -6130,7 +6759,10 @@ e1000_get_cable_length(struct e1000_hw *hw,
IGP01E1000_AGC_RANGE) : 0;
*max_length = e1000_igp_cable_length_table[agc_value] +
IGP01E1000_AGC_RANGE;
- } else if (hw->phy_type == e1000_phy_igp_2) {
+ } else if (hw->phy_type == e1000_phy_igp_2 ||
+ hw->phy_type == e1000_phy_igp_3) {
+ uint16_t cur_agc_index, max_agc_index = 0;
+ uint16_t min_agc_index = IGP02E1000_AGC_LENGTH_TABLE_SIZE - 1;
uint16_t agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] =
{IGP02E1000_PHY_AGC_A,
IGP02E1000_PHY_AGC_B,
@@ -6145,19 +6777,27 @@ e1000_get_cable_length(struct e1000_hw *hw,
/* Getting bits 15:9, which represent the combination of course and
* fine gain values. The result is a number that can be put into
* the lookup table to obtain the approximate cable length. */
- cur_agc = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) &
- IGP02E1000_AGC_LENGTH_MASK;
+ cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) &
+ IGP02E1000_AGC_LENGTH_MASK;
- /* Remove min & max AGC values from calculation. */
- if (e1000_igp_2_cable_length_table[min_agc] > e1000_igp_2_cable_length_table[cur_agc])
- min_agc = cur_agc;
- if (e1000_igp_2_cable_length_table[max_agc] < e1000_igp_2_cable_length_table[cur_agc])
- max_agc = cur_agc;
+ /* Array index bound check. */
+ if ((cur_agc_index >= IGP02E1000_AGC_LENGTH_TABLE_SIZE) ||
+ (cur_agc_index == 0))
+ return -E1000_ERR_PHY;
- agc_value += e1000_igp_2_cable_length_table[cur_agc];
+ /* Remove min & max AGC values from calculation. */
+ if (e1000_igp_2_cable_length_table[min_agc_index] >
+ e1000_igp_2_cable_length_table[cur_agc_index])
+ min_agc_index = cur_agc_index;
+ if (e1000_igp_2_cable_length_table[max_agc_index] <
+ e1000_igp_2_cable_length_table[cur_agc_index])
+ max_agc_index = cur_agc_index;
+
+ agc_value += e1000_igp_2_cable_length_table[cur_agc_index];
}
- agc_value -= (e1000_igp_2_cable_length_table[min_agc] + e1000_igp_2_cable_length_table[max_agc]);
+ agc_value -= (e1000_igp_2_cable_length_table[min_agc_index] +
+ e1000_igp_2_cable_length_table[max_agc_index]);
agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2);
/* Calculate cable length with the error range of +/- 10 meters. */
@@ -6203,7 +6843,8 @@ e1000_check_polarity(struct e1000_hw *hw,
return ret_val;
*polarity = (phy_data & M88E1000_PSSR_REV_POLARITY) >>
M88E1000_PSSR_REV_POLARITY_SHIFT;
- } else if(hw->phy_type == e1000_phy_igp ||
+ } else if (hw->phy_type == e1000_phy_igp ||
+ hw->phy_type == e1000_phy_igp_3 ||
hw->phy_type == e1000_phy_igp_2) {
/* Read the Status register to check the speed */
ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS,
@@ -6229,6 +6870,13 @@ e1000_check_polarity(struct e1000_hw *hw,
* 100 Mbps this bit is always 0) */
*polarity = phy_data & IGP01E1000_PSSR_POLARITY_REVERSED;
}
+ } else if (hw->phy_type == e1000_phy_ife) {
+ ret_val = e1000_read_phy_reg(hw, IFE_PHY_EXTENDED_STATUS_CONTROL,
+ &phy_data);
+ if (ret_val)
+ return ret_val;
+ *polarity = (phy_data & IFE_PESC_POLARITY_REVERSED) >>
+ IFE_PESC_POLARITY_REVERSED_SHIFT;
}
return E1000_SUCCESS;
}
@@ -6256,7 +6904,8 @@ e1000_check_downshift(struct e1000_hw *hw)
DEBUGFUNC("e1000_check_downshift");
- if(hw->phy_type == e1000_phy_igp ||
+ if (hw->phy_type == e1000_phy_igp ||
+ hw->phy_type == e1000_phy_igp_3 ||
hw->phy_type == e1000_phy_igp_2) {
ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_LINK_HEALTH,
&phy_data);
@@ -6273,6 +6922,9 @@ e1000_check_downshift(struct e1000_hw *hw)
hw->speed_downgraded = (phy_data & M88E1000_PSSR_DOWNSHIFT) >>
M88E1000_PSSR_DOWNSHIFT_SHIFT;
+ } else if (hw->phy_type == e1000_phy_ife) {
+ /* e1000_phy_ife supports 10/100 speed only */
+ hw->speed_downgraded = FALSE;
}
return E1000_SUCCESS;
@@ -6317,7 +6969,9 @@ e1000_config_dsp_after_link_change(struct e1000_hw *hw,
if(speed == SPEED_1000) {
- e1000_get_cable_length(hw, &min_length, &max_length);
+ ret_val = e1000_get_cable_length(hw, &min_length, &max_length);
+ if (ret_val)
+ return ret_val;
if((hw->dsp_config_state == e1000_dsp_config_enabled) &&
min_length >= e1000_igp_cable_length_50) {
@@ -6525,20 +7179,27 @@ static int32_t
e1000_set_d3_lplu_state(struct e1000_hw *hw,
boolean_t active)
{
+ uint32_t phy_ctrl = 0;
int32_t ret_val;
uint16_t phy_data;
DEBUGFUNC("e1000_set_d3_lplu_state");
- if(hw->phy_type != e1000_phy_igp && hw->phy_type != e1000_phy_igp_2)
+ if (hw->phy_type != e1000_phy_igp && hw->phy_type != e1000_phy_igp_2
+ && hw->phy_type != e1000_phy_igp_3)
return E1000_SUCCESS;
/* During driver activity LPLU should not be used or it will attain link
* from the lowest speeds starting from 10Mbps. The capability is used for
* Dx transitions and states */
- if(hw->mac_type == e1000_82541_rev_2 || hw->mac_type == e1000_82547_rev_2) {
+ if (hw->mac_type == e1000_82541_rev_2 || hw->mac_type == e1000_82547_rev_2) {
ret_val = e1000_read_phy_reg(hw, IGP01E1000_GMII_FIFO, &phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
+ } else if (hw->mac_type == e1000_ich8lan) {
+ /* MAC writes into PHY register based on the state transition
+ * and start auto-negotiation. SW driver can overwrite the settings
+ * in CSR PHY power control E1000_PHY_CTRL register. */
+ phy_ctrl = E1000_READ_REG(hw, PHY_CTRL);
} else {
ret_val = e1000_read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, &phy_data);
if(ret_val)
@@ -6553,11 +7214,16 @@ e1000_set_d3_lplu_state(struct e1000_hw *hw,
if(ret_val)
return ret_val;
} else {
+ if (hw->mac_type == e1000_ich8lan) {
+ phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU;
+ E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl);
+ } else {
phy_data &= ~IGP02E1000_PM_D3_LPLU;
ret_val = e1000_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT,
phy_data);
if (ret_val)
return ret_val;
+ }
}
/* LPLU and SmartSpeed are mutually exclusive. LPLU is used during
@@ -6593,17 +7259,22 @@ e1000_set_d3_lplu_state(struct e1000_hw *hw,
(hw->autoneg_advertised == AUTONEG_ADVERTISE_10_100_ALL)) {
if(hw->mac_type == e1000_82541_rev_2 ||
- hw->mac_type == e1000_82547_rev_2) {
+ hw->mac_type == e1000_82547_rev_2) {
phy_data |= IGP01E1000_GMII_FLEX_SPD;
ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO, phy_data);
if(ret_val)
return ret_val;
} else {
+ if (hw->mac_type == e1000_ich8lan) {
+ phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU;
+ E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl);
+ } else {
phy_data |= IGP02E1000_PM_D3_LPLU;
ret_val = e1000_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT,
phy_data);
if (ret_val)
return ret_val;
+ }
}
/* When LPLU is enabled we should disable SmartSpeed */
@@ -6638,6 +7309,7 @@ static int32_t
e1000_set_d0_lplu_state(struct e1000_hw *hw,
boolean_t active)
{
+ uint32_t phy_ctrl = 0;
int32_t ret_val;
uint16_t phy_data;
DEBUGFUNC("e1000_set_d0_lplu_state");
@@ -6645,15 +7317,24 @@ e1000_set_d0_lplu_state(struct e1000_hw *hw,
if(hw->mac_type <= e1000_82547_rev_2)
return E1000_SUCCESS;
+ if (hw->mac_type == e1000_ich8lan) {
+ phy_ctrl = E1000_READ_REG(hw, PHY_CTRL);
+ } else {
ret_val = e1000_read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, &phy_data);
if(ret_val)
return ret_val;
+ }
if (!active) {
+ if (hw->mac_type == e1000_ich8lan) {
+ phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU;
+ E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl);
+ } else {
phy_data &= ~IGP02E1000_PM_D0_LPLU;
ret_val = e1000_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, phy_data);
if (ret_val)
return ret_val;
+ }
/* LPLU and SmartSpeed are mutually exclusive. LPLU is used during
* Dx states where the power conservation is most important. During
@@ -6686,10 +7367,15 @@ e1000_set_d0_lplu_state(struct e1000_hw *hw,
} else {
+ if (hw->mac_type == e1000_ich8lan) {
+ phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU;
+ E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl);
+ } else {
phy_data |= IGP02E1000_PM_D0_LPLU;
ret_val = e1000_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, phy_data);
if (ret_val)
return ret_val;
+ }
/* When LPLU is enabled we should disable SmartSpeed */
ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &phy_data);
@@ -6928,8 +7614,10 @@ e1000_mng_write_cmd_header(struct e1000_hw * hw,
length >>= 2;
/* The device driver writes the relevant command block into the ram area. */
- for (i = 0; i < length; i++)
+ for (i = 0; i < length; i++) {
E1000_WRITE_REG_ARRAY_DWORD(hw, HOST_IF, i, *((uint32_t *) hdr + i));
+ E1000_WRITE_FLUSH(hw);
+ }
return E1000_SUCCESS;
}
@@ -6961,15 +7649,18 @@ e1000_mng_write_commit(
* returns - TRUE when the mode is IAMT or FALSE.
****************************************************************************/
boolean_t
-e1000_check_mng_mode(
- struct e1000_hw *hw)
+e1000_check_mng_mode(struct e1000_hw *hw)
{
uint32_t fwsm;
fwsm = E1000_READ_REG(hw, FWSM);
- if((fwsm & E1000_FWSM_MODE_MASK) ==
- (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT))
+ if (hw->mac_type == e1000_ich8lan) {
+ if ((fwsm & E1000_FWSM_MODE_MASK) ==
+ (E1000_MNG_ICH_IAMT_MODE << E1000_FWSM_MODE_SHIFT))
+ return TRUE;
+ } else if ((fwsm & E1000_FWSM_MODE_MASK) ==
+ (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT))
return TRUE;
return FALSE;
@@ -7209,7 +7900,6 @@ e1000_set_pci_express_master_disable(struct e1000_hw *hw)
E1000_WRITE_REG(hw, CTRL, ctrl);
}
-#if 0
/***************************************************************************
*
* Enables PCI-Express master access.
@@ -7233,7 +7923,6 @@ e1000_enable_pciex_master(struct e1000_hw *hw)
ctrl &= ~E1000_CTRL_GIO_MASTER_DISABLE;
E1000_WRITE_REG(hw, CTRL, ctrl);
}
-#endif /* 0 */
/*******************************************************************************
*
@@ -7299,8 +7988,10 @@ e1000_get_auto_rd_done(struct e1000_hw *hw)
case e1000_82572:
case e1000_82573:
case e1000_80003es2lan:
- while(timeout) {
- if (E1000_READ_REG(hw, EECD) & E1000_EECD_AUTO_RD) break;
+ case e1000_ich8lan:
+ while (timeout) {
+ if (E1000_READ_REG(hw, EECD) & E1000_EECD_AUTO_RD)
+ break;
else msec_delay(1);
timeout--;
}
@@ -7340,7 +8031,7 @@ e1000_get_phy_cfg_done(struct e1000_hw *hw)
switch (hw->mac_type) {
default:
- msec_delay(10);
+ msec_delay_irq(10);
break;
case e1000_80003es2lan:
/* Separate *_CFG_DONE_* bit for each port */
@@ -7523,6 +8214,13 @@ int32_t
e1000_check_phy_reset_block(struct e1000_hw *hw)
{
uint32_t manc = 0;
+ uint32_t fwsm = 0;
+
+ if (hw->mac_type == e1000_ich8lan) {
+ fwsm = E1000_READ_REG(hw, FWSM);
+ return (fwsm & E1000_FWSM_RSPCIPHY) ? E1000_SUCCESS
+ : E1000_BLK_PHY_RESET;
+ }
if (hw->mac_type > e1000_82547_rev_2)
manc = E1000_READ_REG(hw, MANC);
@@ -7549,6 +8247,8 @@ e1000_arc_subsystem_valid(struct e1000_hw *hw)
if((fwsm & E1000_FWSM_MODE_MASK) != 0)
return TRUE;
break;
+ case e1000_ich8lan:
+ return TRUE;
default:
break;
}
@@ -7556,4 +8256,846 @@ e1000_arc_subsystem_valid(struct e1000_hw *hw)
}
+/******************************************************************************
+ * Configure PCI-Ex no-snoop
+ *
+ * hw - Struct containing variables accessed by shared code.
+ * no_snoop - Bitmap of no-snoop events.
+ *
+ * returns: E1000_SUCCESS
+ *
+ *****************************************************************************/
+int32_t
+e1000_set_pci_ex_no_snoop(struct e1000_hw *hw, uint32_t no_snoop)
+{
+ uint32_t gcr_reg = 0;
+
+ DEBUGFUNC("e1000_set_pci_ex_no_snoop");
+
+ if (hw->bus_type == e1000_bus_type_unknown)
+ e1000_get_bus_info(hw);
+
+ if (hw->bus_type != e1000_bus_type_pci_express)
+ return E1000_SUCCESS;
+
+ if (no_snoop) {
+ gcr_reg = E1000_READ_REG(hw, GCR);
+ gcr_reg &= ~(PCI_EX_NO_SNOOP_ALL);
+ gcr_reg |= no_snoop;
+ E1000_WRITE_REG(hw, GCR, gcr_reg);
+ }
+ if (hw->mac_type == e1000_ich8lan) {
+ uint32_t ctrl_ext;
+
+ E1000_WRITE_REG(hw, GCR, PCI_EX_82566_SNOOP_ALL);
+
+ ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+ ctrl_ext |= E1000_CTRL_EXT_RO_DIS;
+ E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+ }
+
+ return E1000_SUCCESS;
+}
+
+/***************************************************************************
+ *
+ * Get software semaphore FLAG bit (SWFLAG).
+ * SWFLAG is used to synchronize the access to all shared resource between
+ * SW, FW and HW.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ ***************************************************************************/
+int32_t
+e1000_get_software_flag(struct e1000_hw *hw)
+{
+ int32_t timeout = PHY_CFG_TIMEOUT;
+ uint32_t extcnf_ctrl;
+
+ DEBUGFUNC("e1000_get_software_flag");
+
+ if (hw->mac_type == e1000_ich8lan) {
+ while (timeout) {
+ extcnf_ctrl = E1000_READ_REG(hw, EXTCNF_CTRL);
+ extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG;
+ E1000_WRITE_REG(hw, EXTCNF_CTRL, extcnf_ctrl);
+
+ extcnf_ctrl = E1000_READ_REG(hw, EXTCNF_CTRL);
+ if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)
+ break;
+ msec_delay_irq(1);
+ timeout--;
+ }
+
+ if (!timeout) {
+ DEBUGOUT("FW or HW locks the resource too long.\n");
+ return -E1000_ERR_CONFIG;
+ }
+ }
+
+ return E1000_SUCCESS;
+}
+
+/***************************************************************************
+ *
+ * Release software semaphore FLAG bit (SWFLAG).
+ * SWFLAG is used to synchronize the access to all shared resource between
+ * SW, FW and HW.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ ***************************************************************************/
+void
+e1000_release_software_flag(struct e1000_hw *hw)
+{
+ uint32_t extcnf_ctrl;
+
+ DEBUGFUNC("e1000_release_software_flag");
+
+ if (hw->mac_type == e1000_ich8lan) {
+ extcnf_ctrl= E1000_READ_REG(hw, EXTCNF_CTRL);
+ extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
+ E1000_WRITE_REG(hw, EXTCNF_CTRL, extcnf_ctrl);
+ }
+
+ return;
+}
+
+/***************************************************************************
+ *
+ * Disable dynamic power down mode in ife PHY.
+ * It can be used to workaround band-gap problem.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ ***************************************************************************/
+int32_t
+e1000_ife_disable_dynamic_power_down(struct e1000_hw *hw)
+{
+ uint16_t phy_data;
+ int32_t ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_ife_disable_dynamic_power_down");
+
+ if (hw->phy_type == e1000_phy_ife) {
+ ret_val = e1000_read_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data |= IFE_PSC_DISABLE_DYNAMIC_POWER_DOWN;
+ ret_val = e1000_write_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL, phy_data);
+ }
+
+ return ret_val;
+}
+
+/***************************************************************************
+ *
+ * Enable dynamic power down mode in ife PHY.
+ * It can be used to workaround band-gap problem.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ ***************************************************************************/
+int32_t
+e1000_ife_enable_dynamic_power_down(struct e1000_hw *hw)
+{
+ uint16_t phy_data;
+ int32_t ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_ife_enable_dynamic_power_down");
+
+ if (hw->phy_type == e1000_phy_ife) {
+ ret_val = e1000_read_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data &= ~IFE_PSC_DISABLE_DYNAMIC_POWER_DOWN;
+ ret_val = e1000_write_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL, phy_data);
+ }
+
+ return ret_val;
+}
+
+/******************************************************************************
+ * Reads a 16 bit word or words from the EEPROM using the ICH8's flash access
+ * register.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset of word in the EEPROM to read
+ * data - word read from the EEPROM
+ * words - number of words to read
+ *****************************************************************************/
+int32_t
+e1000_read_eeprom_ich8(struct e1000_hw *hw, uint16_t offset, uint16_t words,
+ uint16_t *data)
+{
+ int32_t error = E1000_SUCCESS;
+ uint32_t flash_bank = 0;
+ uint32_t act_offset = 0;
+ uint32_t bank_offset = 0;
+ uint16_t word = 0;
+ uint16_t i = 0;
+
+ /* We need to know which is the valid flash bank. In the event
+ * that we didn't allocate eeprom_shadow_ram, we may not be
+ * managing flash_bank. So it cannot be trusted and needs
+ * to be updated with each read.
+ */
+ /* Value of bit 22 corresponds to the flash bank we're on. */
+ flash_bank = (E1000_READ_REG(hw, EECD) & E1000_EECD_SEC1VAL) ? 1 : 0;
+
+ /* Adjust offset appropriately if we're on bank 1 - adjust for word size */
+ bank_offset = flash_bank * (hw->flash_bank_size * 2);
+
+ error = e1000_get_software_flag(hw);
+ if (error != E1000_SUCCESS)
+ return error;
+
+ for (i = 0; i < words; i++) {
+ if (hw->eeprom_shadow_ram != NULL &&
+ hw->eeprom_shadow_ram[offset+i].modified == TRUE) {
+ data[i] = hw->eeprom_shadow_ram[offset+i].eeprom_word;
+ } else {
+ /* The NVM part needs a byte offset, hence * 2 */
+ act_offset = bank_offset + ((offset + i) * 2);
+ error = e1000_read_ich8_word(hw, act_offset, &word);
+ if (error != E1000_SUCCESS)
+ break;
+ data[i] = word;
+ }
+ }
+
+ e1000_release_software_flag(hw);
+
+ return error;
+}
+
+/******************************************************************************
+ * Writes a 16 bit word or words to the EEPROM using the ICH8's flash access
+ * register. Actually, writes are written to the shadow ram cache in the hw
+ * structure hw->e1000_shadow_ram. e1000_commit_shadow_ram flushes this to
+ * the NVM, which occurs when the NVM checksum is updated.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset of word in the EEPROM to write
+ * words - number of words to write
+ * data - words to write to the EEPROM
+ *****************************************************************************/
+int32_t
+e1000_write_eeprom_ich8(struct e1000_hw *hw, uint16_t offset, uint16_t words,
+ uint16_t *data)
+{
+ uint32_t i = 0;
+ int32_t error = E1000_SUCCESS;
+
+ error = e1000_get_software_flag(hw);
+ if (error != E1000_SUCCESS)
+ return error;
+
+ /* A driver can write to the NVM only if it has eeprom_shadow_ram
+ * allocated. Subsequent reads to the modified words are read from
+ * this cached structure as well. Writes will only go into this
+ * cached structure unless it's followed by a call to
+ * e1000_update_eeprom_checksum() where it will commit the changes
+ * and clear the "modified" field.
+ */
+ if (hw->eeprom_shadow_ram != NULL) {
+ for (i = 0; i < words; i++) {
+ if ((offset + i) < E1000_SHADOW_RAM_WORDS) {
+ hw->eeprom_shadow_ram[offset+i].modified = TRUE;
+ hw->eeprom_shadow_ram[offset+i].eeprom_word = data[i];
+ } else {
+ error = -E1000_ERR_EEPROM;
+ break;
+ }
+ }
+ } else {
+ /* Drivers have the option to not allocate eeprom_shadow_ram as long
+ * as they don't perform any NVM writes. An attempt in doing so
+ * will result in this error.
+ */
+ error = -E1000_ERR_EEPROM;
+ }
+
+ e1000_release_software_flag(hw);
+
+ return error;
+}
+
+/******************************************************************************
+ * This function does initial flash setup so that a new read/write/erase cycle
+ * can be started.
+ *
+ * hw - The pointer to the hw structure
+ ****************************************************************************/
+int32_t
+e1000_ich8_cycle_init(struct e1000_hw *hw)
+{
+ union ich8_hws_flash_status hsfsts;
+ int32_t error = E1000_ERR_EEPROM;
+ int32_t i = 0;
+
+ DEBUGFUNC("e1000_ich8_cycle_init");
+
+ hsfsts.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFSTS);
+
+ /* May be check the Flash Des Valid bit in Hw status */
+ if (hsfsts.hsf_status.fldesvalid == 0) {
+ DEBUGOUT("Flash descriptor invalid. SW Sequencing must be used.");
+ return error;
+ }
+
+ /* Clear FCERR in Hw status by writing 1 */
+ /* Clear DAEL in Hw status by writing a 1 */
+ hsfsts.hsf_status.flcerr = 1;
+ hsfsts.hsf_status.dael = 1;
+
+ E1000_WRITE_ICH8_REG16(hw, ICH8_FLASH_HSFSTS, hsfsts.regval);
+
+ /* Either we should have a hardware SPI cycle in progress bit to check
+ * against, in order to start a new cycle or FDONE bit should be changed
+ * in the hardware so that it is 1 after harware reset, which can then be
+ * used as an indication whether a cycle is in progress or has been
+ * completed .. we should also have some software semaphore mechanism to
+ * guard FDONE or the cycle in progress bit so that two threads access to
+ * those bits can be sequentiallized or a way so that 2 threads dont
+ * start the cycle at the same time */
+
+ if (hsfsts.hsf_status.flcinprog == 0) {
+ /* There is no cycle running at present, so we can start a cycle */
+ /* Begin by setting Flash Cycle Done. */
+ hsfsts.hsf_status.flcdone = 1;
+ E1000_WRITE_ICH8_REG16(hw, ICH8_FLASH_HSFSTS, hsfsts.regval);
+ error = E1000_SUCCESS;
+ } else {
+ /* otherwise poll for sometime so the current cycle has a chance
+ * to end before giving up. */
+ for (i = 0; i < ICH8_FLASH_COMMAND_TIMEOUT; i++) {
+ hsfsts.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFSTS);
+ if (hsfsts.hsf_status.flcinprog == 0) {
+ error = E1000_SUCCESS;
+ break;
+ }
+ udelay(1);
+ }
+ if (error == E1000_SUCCESS) {
+ /* Successful in waiting for previous cycle to timeout,
+ * now set the Flash Cycle Done. */
+ hsfsts.hsf_status.flcdone = 1;
+ E1000_WRITE_ICH8_REG16(hw, ICH8_FLASH_HSFSTS, hsfsts.regval);
+ } else {
+ DEBUGOUT("Flash controller busy, cannot get access");
+ }
+ }
+ return error;
+}
+
+/******************************************************************************
+ * This function starts a flash cycle and waits for its completion
+ *
+ * hw - The pointer to the hw structure
+ ****************************************************************************/
+int32_t
+e1000_ich8_flash_cycle(struct e1000_hw *hw, uint32_t timeout)
+{
+ union ich8_hws_flash_ctrl hsflctl;
+ union ich8_hws_flash_status hsfsts;
+ int32_t error = E1000_ERR_EEPROM;
+ uint32_t i = 0;
+
+ /* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */
+ hsflctl.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFCTL);
+ hsflctl.hsf_ctrl.flcgo = 1;
+ E1000_WRITE_ICH8_REG16(hw, ICH8_FLASH_HSFCTL, hsflctl.regval);
+
+ /* wait till FDONE bit is set to 1 */
+ do {
+ hsfsts.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFSTS);
+ if (hsfsts.hsf_status.flcdone == 1)
+ break;
+ udelay(1);
+ i++;
+ } while (i < timeout);
+ if (hsfsts.hsf_status.flcdone == 1 && hsfsts.hsf_status.flcerr == 0) {
+ error = E1000_SUCCESS;
+ }
+ return error;
+}
+
+/******************************************************************************
+ * Reads a byte or word from the NVM using the ICH8 flash access registers.
+ *
+ * hw - The pointer to the hw structure
+ * index - The index of the byte or word to read.
+ * size - Size of data to read, 1=byte 2=word
+ * data - Pointer to the word to store the value read.
+ *****************************************************************************/
+int32_t
+e1000_read_ich8_data(struct e1000_hw *hw, uint32_t index,
+ uint32_t size, uint16_t* data)
+{
+ union ich8_hws_flash_status hsfsts;
+ union ich8_hws_flash_ctrl hsflctl;
+ uint32_t flash_linear_address;
+ uint32_t flash_data = 0;
+ int32_t error = -E1000_ERR_EEPROM;
+ int32_t count = 0;
+
+ DEBUGFUNC("e1000_read_ich8_data");
+
+ if (size < 1 || size > 2 || data == 0x0 ||
+ index > ICH8_FLASH_LINEAR_ADDR_MASK)
+ return error;
+
+ flash_linear_address = (ICH8_FLASH_LINEAR_ADDR_MASK & index) +
+ hw->flash_base_addr;
+
+ do {
+ udelay(1);
+ /* Steps */
+ error = e1000_ich8_cycle_init(hw);
+ if (error != E1000_SUCCESS)
+ break;
+
+ hsflctl.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFCTL);
+ /* 0b/1b corresponds to 1 or 2 byte size, respectively. */
+ hsflctl.hsf_ctrl.fldbcount = size - 1;
+ hsflctl.hsf_ctrl.flcycle = ICH8_CYCLE_READ;
+ E1000_WRITE_ICH8_REG16(hw, ICH8_FLASH_HSFCTL, hsflctl.regval);
+
+ /* Write the last 24 bits of index into Flash Linear address field in
+ * Flash Address */
+ /* TODO: TBD maybe check the index against the size of flash */
+
+ E1000_WRITE_ICH8_REG(hw, ICH8_FLASH_FADDR, flash_linear_address);
+
+ error = e1000_ich8_flash_cycle(hw, ICH8_FLASH_COMMAND_TIMEOUT);
+
+ /* Check if FCERR is set to 1, if set to 1, clear it and try the whole
+ * sequence a few more times, else read in (shift in) the Flash Data0,
+ * the order is least significant byte first msb to lsb */
+ if (error == E1000_SUCCESS) {
+ flash_data = E1000_READ_ICH8_REG(hw, ICH8_FLASH_FDATA0);
+ if (size == 1) {
+ *data = (uint8_t)(flash_data & 0x000000FF);
+ } else if (size == 2) {
+ *data = (uint16_t)(flash_data & 0x0000FFFF);
+ }
+ break;
+ } else {
+ /* If we've gotten here, then things are probably completely hosed,
+ * but if the error condition is detected, it won't hurt to give
+ * it another try...ICH8_FLASH_CYCLE_REPEAT_COUNT times.
+ */
+ hsfsts.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFSTS);
+ if (hsfsts.hsf_status.flcerr == 1) {
+ /* Repeat for some time before giving up. */
+ continue;
+ } else if (hsfsts.hsf_status.flcdone == 0) {
+ DEBUGOUT("Timeout error - flash cycle did not complete.");
+ break;
+ }
+ }
+ } while (count++ < ICH8_FLASH_CYCLE_REPEAT_COUNT);
+
+ return error;
+}
+
+/******************************************************************************
+ * Writes One /two bytes to the NVM using the ICH8 flash access registers.
+ *
+ * hw - The pointer to the hw structure
+ * index - The index of the byte/word to read.
+ * size - Size of data to read, 1=byte 2=word
+ * data - The byte(s) to write to the NVM.
+ *****************************************************************************/
+int32_t
+e1000_write_ich8_data(struct e1000_hw *hw, uint32_t index, uint32_t size,
+ uint16_t data)
+{
+ union ich8_hws_flash_status hsfsts;
+ union ich8_hws_flash_ctrl hsflctl;
+ uint32_t flash_linear_address;
+ uint32_t flash_data = 0;
+ int32_t error = -E1000_ERR_EEPROM;
+ int32_t count = 0;
+
+ DEBUGFUNC("e1000_write_ich8_data");
+
+ if (size < 1 || size > 2 || data > size * 0xff ||
+ index > ICH8_FLASH_LINEAR_ADDR_MASK)
+ return error;
+
+ flash_linear_address = (ICH8_FLASH_LINEAR_ADDR_MASK & index) +
+ hw->flash_base_addr;
+
+ do {
+ udelay(1);
+ /* Steps */
+ error = e1000_ich8_cycle_init(hw);
+ if (error != E1000_SUCCESS)
+ break;
+
+ hsflctl.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFCTL);
+ /* 0b/1b corresponds to 1 or 2 byte size, respectively. */
+ hsflctl.hsf_ctrl.fldbcount = size -1;
+ hsflctl.hsf_ctrl.flcycle = ICH8_CYCLE_WRITE;
+ E1000_WRITE_ICH8_REG16(hw, ICH8_FLASH_HSFCTL, hsflctl.regval);
+
+ /* Write the last 24 bits of index into Flash Linear address field in
+ * Flash Address */
+ E1000_WRITE_ICH8_REG(hw, ICH8_FLASH_FADDR, flash_linear_address);
+
+ if (size == 1)
+ flash_data = (uint32_t)data & 0x00FF;
+ else
+ flash_data = (uint32_t)data;
+
+ E1000_WRITE_ICH8_REG(hw, ICH8_FLASH_FDATA0, flash_data);
+
+ /* check if FCERR is set to 1 , if set to 1, clear it and try the whole
+ * sequence a few more times else done */
+ error = e1000_ich8_flash_cycle(hw, ICH8_FLASH_COMMAND_TIMEOUT);
+ if (error == E1000_SUCCESS) {
+ break;
+ } else {
+ /* If we're here, then things are most likely completely hosed,
+ * but if the error condition is detected, it won't hurt to give
+ * it another try...ICH8_FLASH_CYCLE_REPEAT_COUNT times.
+ */
+ hsfsts.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFSTS);
+ if (hsfsts.hsf_status.flcerr == 1) {
+ /* Repeat for some time before giving up. */
+ continue;
+ } else if (hsfsts.hsf_status.flcdone == 0) {
+ DEBUGOUT("Timeout error - flash cycle did not complete.");
+ break;
+ }
+ }
+ } while (count++ < ICH8_FLASH_CYCLE_REPEAT_COUNT);
+
+ return error;
+}
+
+/******************************************************************************
+ * Reads a single byte from the NVM using the ICH8 flash access registers.
+ *
+ * hw - pointer to e1000_hw structure
+ * index - The index of the byte to read.
+ * data - Pointer to a byte to store the value read.
+ *****************************************************************************/
+int32_t
+e1000_read_ich8_byte(struct e1000_hw *hw, uint32_t index, uint8_t* data)
+{
+ int32_t status = E1000_SUCCESS;
+ uint16_t word = 0;
+
+ status = e1000_read_ich8_data(hw, index, 1, &word);
+ if (status == E1000_SUCCESS) {
+ *data = (uint8_t)word;
+ }
+
+ return status;
+}
+
+/******************************************************************************
+ * Writes a single byte to the NVM using the ICH8 flash access registers.
+ * Performs verification by reading back the value and then going through
+ * a retry algorithm before giving up.
+ *
+ * hw - pointer to e1000_hw structure
+ * index - The index of the byte to write.
+ * byte - The byte to write to the NVM.
+ *****************************************************************************/
+int32_t
+e1000_verify_write_ich8_byte(struct e1000_hw *hw, uint32_t index, uint8_t byte)
+{
+ int32_t error = E1000_SUCCESS;
+ int32_t program_retries;
+ uint8_t temp_byte;
+
+ e1000_write_ich8_byte(hw, index, byte);
+ udelay(100);
+
+ for (program_retries = 0; program_retries < 100; program_retries++) {
+ e1000_read_ich8_byte(hw, index, &temp_byte);
+ if (temp_byte == byte)
+ break;
+ udelay(10);
+ e1000_write_ich8_byte(hw, index, byte);
+ udelay(100);
+ }
+ if (program_retries == 100)
+ error = E1000_ERR_EEPROM;
+
+ return error;
+}
+
+/******************************************************************************
+ * Writes a single byte to the NVM using the ICH8 flash access registers.
+ *
+ * hw - pointer to e1000_hw structure
+ * index - The index of the byte to read.
+ * data - The byte to write to the NVM.
+ *****************************************************************************/
+int32_t
+e1000_write_ich8_byte(struct e1000_hw *hw, uint32_t index, uint8_t data)
+{
+ int32_t status = E1000_SUCCESS;
+ uint16_t word = (uint16_t)data;
+
+ status = e1000_write_ich8_data(hw, index, 1, word);
+
+ return status;
+}
+
+/******************************************************************************
+ * Reads a word from the NVM using the ICH8 flash access registers.
+ *
+ * hw - pointer to e1000_hw structure
+ * index - The starting byte index of the word to read.
+ * data - Pointer to a word to store the value read.
+ *****************************************************************************/
+int32_t
+e1000_read_ich8_word(struct e1000_hw *hw, uint32_t index, uint16_t *data)
+{
+ int32_t status = E1000_SUCCESS;
+ status = e1000_read_ich8_data(hw, index, 2, data);
+ return status;
+}
+
+/******************************************************************************
+ * Writes a word to the NVM using the ICH8 flash access registers.
+ *
+ * hw - pointer to e1000_hw structure
+ * index - The starting byte index of the word to read.
+ * data - The word to write to the NVM.
+ *****************************************************************************/
+int32_t
+e1000_write_ich8_word(struct e1000_hw *hw, uint32_t index, uint16_t data)
+{
+ int32_t status = E1000_SUCCESS;
+ status = e1000_write_ich8_data(hw, index, 2, data);
+ return status;
+}
+
+/******************************************************************************
+ * Erases the bank specified. Each bank is a 4k block. Segments are 0 based.
+ * segment N is 4096 * N + flash_reg_addr.
+ *
+ * hw - pointer to e1000_hw structure
+ * segment - 0 for first segment, 1 for second segment, etc.
+ *****************************************************************************/
+int32_t
+e1000_erase_ich8_4k_segment(struct e1000_hw *hw, uint32_t segment)
+{
+ union ich8_hws_flash_status hsfsts;
+ union ich8_hws_flash_ctrl hsflctl;
+ uint32_t flash_linear_address;
+ int32_t count = 0;
+ int32_t error = E1000_ERR_EEPROM;
+ int32_t iteration, seg_size;
+ int32_t sector_size;
+ int32_t j = 0;
+ int32_t error_flag = 0;
+
+ hsfsts.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFSTS);
+
+ /* Determine HW Sector size: Read BERASE bits of Hw flash Status register */
+ /* 00: The Hw sector is 256 bytes, hence we need to erase 16
+ * consecutive sectors. The start index for the nth Hw sector can be
+ * calculated as = segment * 4096 + n * 256
+ * 01: The Hw sector is 4K bytes, hence we need to erase 1 sector.
+ * The start index for the nth Hw sector can be calculated
+ * as = segment * 4096
+ * 10: Error condition
+ * 11: The Hw sector size is much bigger than the size asked to
+ * erase...error condition */
+ if (hsfsts.hsf_status.berasesz == 0x0) {
+ /* Hw sector size 256 */
+ sector_size = seg_size = ICH8_FLASH_SEG_SIZE_256;
+ iteration = ICH8_FLASH_SECTOR_SIZE / ICH8_FLASH_SEG_SIZE_256;
+ } else if (hsfsts.hsf_status.berasesz == 0x1) {
+ sector_size = seg_size = ICH8_FLASH_SEG_SIZE_4K;
+ iteration = 1;
+ } else if (hsfsts.hsf_status.berasesz == 0x3) {
+ sector_size = seg_size = ICH8_FLASH_SEG_SIZE_64K;
+ iteration = 1;
+ } else {
+ return error;
+ }
+
+ for (j = 0; j < iteration ; j++) {
+ do {
+ count++;
+ /* Steps */
+ error = e1000_ich8_cycle_init(hw);
+ if (error != E1000_SUCCESS) {
+ error_flag = 1;
+ break;
+ }
+
+ /* Write a value 11 (block Erase) in Flash Cycle field in Hw flash
+ * Control */
+ hsflctl.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFCTL);
+ hsflctl.hsf_ctrl.flcycle = ICH8_CYCLE_ERASE;
+ E1000_WRITE_ICH8_REG16(hw, ICH8_FLASH_HSFCTL, hsflctl.regval);
+
+ /* Write the last 24 bits of an index within the block into Flash
+ * Linear address field in Flash Address. This probably needs to
+ * be calculated here based off the on-chip segment size and the
+ * software segment size assumed (4K) */
+ /* TBD */
+ flash_linear_address = segment * sector_size + j * seg_size;
+ flash_linear_address &= ICH8_FLASH_LINEAR_ADDR_MASK;
+ flash_linear_address += hw->flash_base_addr;
+
+ E1000_WRITE_ICH8_REG(hw, ICH8_FLASH_FADDR, flash_linear_address);
+
+ error = e1000_ich8_flash_cycle(hw, 1000000);
+ /* Check if FCERR is set to 1. If 1, clear it and try the whole
+ * sequence a few more times else Done */
+ if (error == E1000_SUCCESS) {
+ break;
+ } else {
+ hsfsts.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFSTS);
+ if (hsfsts.hsf_status.flcerr == 1) {
+ /* repeat for some time before giving up */
+ continue;
+ } else if (hsfsts.hsf_status.flcdone == 0) {
+ error_flag = 1;
+ break;
+ }
+ }
+ } while ((count < ICH8_FLASH_CYCLE_REPEAT_COUNT) && !error_flag);
+ if (error_flag == 1)
+ break;
+ }
+ if (error_flag != 1)
+ error = E1000_SUCCESS;
+ return error;
+}
+
+/******************************************************************************
+ *
+ * Reverse duplex setting without breaking the link.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ *****************************************************************************/
+int32_t
+e1000_duplex_reversal(struct e1000_hw *hw)
+{
+ int32_t ret_val;
+ uint16_t phy_data;
+
+ if (hw->phy_type != e1000_phy_igp_3)
+ return E1000_SUCCESS;
+
+ ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data ^= MII_CR_FULL_DUPLEX;
+
+ ret_val = e1000_write_phy_reg(hw, PHY_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000_read_phy_reg(hw, IGP3E1000_PHY_MISC_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data |= IGP3_PHY_MISC_DUPLEX_MANUAL_SET;
+ ret_val = e1000_write_phy_reg(hw, IGP3E1000_PHY_MISC_CTRL, phy_data);
+
+ return ret_val;
+}
+
+int32_t
+e1000_init_lcd_from_nvm_config_region(struct e1000_hw *hw,
+ uint32_t cnf_base_addr, uint32_t cnf_size)
+{
+ uint32_t ret_val = E1000_SUCCESS;
+ uint16_t word_addr, reg_data, reg_addr;
+ uint16_t i;
+
+ /* cnf_base_addr is in DWORD */
+ word_addr = (uint16_t)(cnf_base_addr << 1);
+
+ /* cnf_size is returned in size of dwords */
+ for (i = 0; i < cnf_size; i++) {
+ ret_val = e1000_read_eeprom(hw, (word_addr + i*2), 1, &reg_data);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000_read_eeprom(hw, (word_addr + i*2 + 1), 1, &reg_addr);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000_get_software_flag(hw);
+ if (ret_val != E1000_SUCCESS)
+ return ret_val;
+
+ ret_val = e1000_write_phy_reg_ex(hw, (uint32_t)reg_addr, reg_data);
+
+ e1000_release_software_flag(hw);
+ }
+
+ return ret_val;
+}
+
+
+int32_t
+e1000_init_lcd_from_nvm(struct e1000_hw *hw)
+{
+ uint32_t reg_data, cnf_base_addr, cnf_size, ret_val, loop;
+
+ if (hw->phy_type != e1000_phy_igp_3)
+ return E1000_SUCCESS;
+
+ /* Check if SW needs configure the PHY */
+ reg_data = E1000_READ_REG(hw, FEXTNVM);
+ if (!(reg_data & FEXTNVM_SW_CONFIG))
+ return E1000_SUCCESS;
+
+ /* Wait for basic configuration completes before proceeding*/
+ loop = 0;
+ do {
+ reg_data = E1000_READ_REG(hw, STATUS) & E1000_STATUS_LAN_INIT_DONE;
+ udelay(100);
+ loop++;
+ } while ((!reg_data) && (loop < 50));
+
+ /* Clear the Init Done bit for the next init event */
+ reg_data = E1000_READ_REG(hw, STATUS);
+ reg_data &= ~E1000_STATUS_LAN_INIT_DONE;
+ E1000_WRITE_REG(hw, STATUS, reg_data);
+
+ /* Make sure HW does not configure LCD from PHY extended configuration
+ before SW configuration */
+ reg_data = E1000_READ_REG(hw, EXTCNF_CTRL);
+ if ((reg_data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE) == 0x0000) {
+ reg_data = E1000_READ_REG(hw, EXTCNF_SIZE);
+ cnf_size = reg_data & E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH;
+ cnf_size >>= 16;
+ if (cnf_size) {
+ reg_data = E1000_READ_REG(hw, EXTCNF_CTRL);
+ cnf_base_addr = reg_data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER;
+ /* cnf_base_addr is in DWORD */
+ cnf_base_addr >>= 16;
+
+ /* Configure LCD from extended configuration region. */
+ ret_val = e1000_init_lcd_from_nvm_config_region(hw, cnf_base_addr,
+ cnf_size);
+ if (ret_val)
+ return ret_val;
+ }
+ }
+
+ return E1000_SUCCESS;
+}
+
+
diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h
index 467c9ed944f..f9341e3276b 100644
--- a/drivers/net/e1000/e1000_hw.h
+++ b/drivers/net/e1000/e1000_hw.h
@@ -62,6 +62,7 @@ typedef enum {
e1000_82572,
e1000_82573,
e1000_80003es2lan,
+ e1000_ich8lan,
e1000_num_macs
} e1000_mac_type;
@@ -70,6 +71,7 @@ typedef enum {
e1000_eeprom_spi,
e1000_eeprom_microwire,
e1000_eeprom_flash,
+ e1000_eeprom_ich8,
e1000_eeprom_none, /* No NVM support */
e1000_num_eeprom_types
} e1000_eeprom_type;
@@ -98,6 +100,11 @@ typedef enum {
e1000_fc_default = 0xFF
} e1000_fc_type;
+struct e1000_shadow_ram {
+ uint16_t eeprom_word;
+ boolean_t modified;
+};
+
/* PCI bus types */
typedef enum {
e1000_bus_type_unknown = 0,
@@ -218,6 +225,8 @@ typedef enum {
e1000_phy_igp,
e1000_phy_igp_2,
e1000_phy_gg82563,
+ e1000_phy_igp_3,
+ e1000_phy_ife,
e1000_phy_undefined = 0xFF
} e1000_phy_type;
@@ -313,6 +322,10 @@ int32_t e1000_read_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t *phy
int32_t e1000_write_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t data);
int32_t e1000_phy_hw_reset(struct e1000_hw *hw);
int32_t e1000_phy_reset(struct e1000_hw *hw);
+void e1000_phy_powerdown_workaround(struct e1000_hw *hw);
+int32_t e1000_kumeran_lock_loss_workaround(struct e1000_hw *hw);
+int32_t e1000_init_lcd_from_nvm_config_region(struct e1000_hw *hw, uint32_t cnf_base_addr, uint32_t cnf_size);
+int32_t e1000_init_lcd_from_nvm(struct e1000_hw *hw);
int32_t e1000_phy_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info);
int32_t e1000_validate_mdi_setting(struct e1000_hw *hw);
int32_t e1000_read_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t *data);
@@ -331,6 +344,7 @@ uint32_t e1000_enable_mng_pass_thru(struct e1000_hw *hw);
#define E1000_MNG_DHCP_COOKIE_OFFSET 0x6F0 /* Cookie offset */
#define E1000_MNG_DHCP_COOKIE_LENGTH 0x10 /* Cookie length */
#define E1000_MNG_IAMT_MODE 0x3
+#define E1000_MNG_ICH_IAMT_MODE 0x2
#define E1000_IAMT_SIGNATURE 0x544D4149 /* Intel(R) Active Management Technology signature */
#define E1000_MNG_DHCP_COOKIE_STATUS_PARSING_SUPPORT 0x1 /* DHCP parsing enabled */
@@ -388,6 +402,8 @@ int32_t e1000_read_part_num(struct e1000_hw *hw, uint32_t * part_num);
int32_t e1000_read_mac_addr(struct e1000_hw * hw);
int32_t e1000_swfw_sync_acquire(struct e1000_hw *hw, uint16_t mask);
void e1000_swfw_sync_release(struct e1000_hw *hw, uint16_t mask);
+void e1000_release_software_flag(struct e1000_hw *hw);
+int32_t e1000_get_software_flag(struct e1000_hw *hw);
/* Filters (multicast, vlan, receive) */
void e1000_mc_addr_list_update(struct e1000_hw *hw, uint8_t * mc_addr_list, uint32_t mc_addr_count, uint32_t pad, uint32_t rar_used_count);
@@ -401,6 +417,7 @@ int32_t e1000_setup_led(struct e1000_hw *hw);
int32_t e1000_cleanup_led(struct e1000_hw *hw);
int32_t e1000_led_on(struct e1000_hw *hw);
int32_t e1000_led_off(struct e1000_hw *hw);
+int32_t e1000_blink_led_start(struct e1000_hw *hw);
/* Adaptive IFS Functions */
@@ -422,6 +439,29 @@ int32_t e1000_disable_pciex_master(struct e1000_hw *hw);
int32_t e1000_get_software_semaphore(struct e1000_hw *hw);
void e1000_release_software_semaphore(struct e1000_hw *hw);
int32_t e1000_check_phy_reset_block(struct e1000_hw *hw);
+int32_t e1000_set_pci_ex_no_snoop(struct e1000_hw *hw, uint32_t no_snoop);
+
+int32_t e1000_read_ich8_byte(struct e1000_hw *hw, uint32_t index,
+ uint8_t *data);
+int32_t e1000_verify_write_ich8_byte(struct e1000_hw *hw, uint32_t index,
+ uint8_t byte);
+int32_t e1000_write_ich8_byte(struct e1000_hw *hw, uint32_t index,
+ uint8_t byte);
+int32_t e1000_read_ich8_word(struct e1000_hw *hw, uint32_t index,
+ uint16_t *data);
+int32_t e1000_read_ich8_data(struct e1000_hw *hw, uint32_t index,
+ uint32_t size, uint16_t *data);
+int32_t e1000_read_eeprom_ich8(struct e1000_hw *hw, uint16_t offset,
+ uint16_t words, uint16_t *data);
+int32_t e1000_write_eeprom_ich8(struct e1000_hw *hw, uint16_t offset,
+ uint16_t words, uint16_t *data);
+int32_t e1000_erase_ich8_4k_segment(struct e1000_hw *hw, uint32_t segment);
+
+
+#define E1000_READ_REG_IO(a, reg) \
+ e1000_read_reg_io((a), E1000_##reg)
+#define E1000_WRITE_REG_IO(a, reg, val) \
+ e1000_write_reg_io((a), E1000_##reg, val)
/* PCI Device IDs */
#define E1000_DEV_ID_82542 0x1000
@@ -446,6 +486,7 @@ int32_t e1000_check_phy_reset_block(struct e1000_hw *hw);
#define E1000_DEV_ID_82546EB_QUAD_COPPER 0x101D
#define E1000_DEV_ID_82541EI 0x1013
#define E1000_DEV_ID_82541EI_MOBILE 0x1018
+#define E1000_DEV_ID_82541ER_LOM 0x1014
#define E1000_DEV_ID_82541ER 0x1078
#define E1000_DEV_ID_82547GI 0x1075
#define E1000_DEV_ID_82541GI 0x1076
@@ -457,18 +498,28 @@ int32_t e1000_check_phy_reset_block(struct e1000_hw *hw);
#define E1000_DEV_ID_82546GB_PCIE 0x108A
#define E1000_DEV_ID_82546GB_QUAD_COPPER 0x1099
#define E1000_DEV_ID_82547EI 0x1019
+#define E1000_DEV_ID_82547EI_MOBILE 0x101A
#define E1000_DEV_ID_82571EB_COPPER 0x105E
#define E1000_DEV_ID_82571EB_FIBER 0x105F
#define E1000_DEV_ID_82571EB_SERDES 0x1060
#define E1000_DEV_ID_82572EI_COPPER 0x107D
#define E1000_DEV_ID_82572EI_FIBER 0x107E
#define E1000_DEV_ID_82572EI_SERDES 0x107F
+#define E1000_DEV_ID_82572EI 0x10B9
#define E1000_DEV_ID_82573E 0x108B
#define E1000_DEV_ID_82573E_IAMT 0x108C
#define E1000_DEV_ID_82573L 0x109A
#define E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3 0x10B5
#define E1000_DEV_ID_80003ES2LAN_COPPER_DPT 0x1096
#define E1000_DEV_ID_80003ES2LAN_SERDES_DPT 0x1098
+#define E1000_DEV_ID_80003ES2LAN_COPPER_SPT 0x10BA
+#define E1000_DEV_ID_80003ES2LAN_SERDES_SPT 0x10BB
+
+#define E1000_DEV_ID_ICH8_IGP_M_AMT 0x1049
+#define E1000_DEV_ID_ICH8_IGP_AMT 0x104A
+#define E1000_DEV_ID_ICH8_IGP_C 0x104B
+#define E1000_DEV_ID_ICH8_IFE 0x104C
+#define E1000_DEV_ID_ICH8_IGP_M 0x104D
#define NODE_ADDRESS_SIZE 6
@@ -539,6 +590,14 @@ int32_t e1000_check_phy_reset_block(struct e1000_hw *hw);
E1000_IMS_RXSEQ | \
E1000_IMS_LSC)
+/* Additional interrupts need to be handled for e1000_ich8lan:
+ DSW = The FW changed the status of the DISSW bit in FWSM
+ PHYINT = The LAN connected device generates an interrupt
+ EPRST = Manageability reset event */
+#define IMS_ICH8LAN_ENABLE_MASK (\
+ E1000_IMS_DSW | \
+ E1000_IMS_PHYINT | \
+ E1000_IMS_EPRST)
/* Number of high/low register pairs in the RAR. The RAR (Receive Address
* Registers) holds the directed and multicast addresses that we monitor. We
@@ -546,6 +605,7 @@ int32_t e1000_check_phy_reset_block(struct e1000_hw *hw);
* E1000_RAR_ENTRIES - 1 multicast addresses.
*/
#define E1000_RAR_ENTRIES 15
+#define E1000_RAR_ENTRIES_ICH8LAN 7
#define MIN_NUMBER_OF_DESCRIPTORS 8
#define MAX_NUMBER_OF_DESCRIPTORS 0xFFF8
@@ -767,6 +827,9 @@ struct e1000_data_desc {
#define E1000_MC_TBL_SIZE 128 /* Multicast Filter Table (4096 bits) */
#define E1000_VLAN_FILTER_TBL_SIZE 128 /* VLAN Filter Table (4096 bits) */
+#define E1000_NUM_UNICAST_ICH8LAN 7
+#define E1000_MC_TBL_SIZE_ICH8LAN 32
+
/* Receive Address Register */
struct e1000_rar {
@@ -776,6 +839,7 @@ struct e1000_rar {
/* Number of entries in the Multicast Table Array (MTA). */
#define E1000_NUM_MTA_REGISTERS 128
+#define E1000_NUM_MTA_REGISTERS_ICH8LAN 32
/* IPv4 Address Table Entry */
struct e1000_ipv4_at_entry {
@@ -786,6 +850,7 @@ struct e1000_ipv4_at_entry {
/* Four wakeup IP addresses are supported */
#define E1000_WAKEUP_IP_ADDRESS_COUNT_MAX 4
#define E1000_IP4AT_SIZE E1000_WAKEUP_IP_ADDRESS_COUNT_MAX
+#define E1000_IP4AT_SIZE_ICH8LAN 3
#define E1000_IP6AT_SIZE 1
/* IPv6 Address Table Entry */
@@ -844,6 +909,7 @@ struct e1000_ffvt_entry {
#define E1000_FLA 0x0001C /* Flash Access - RW */
#define E1000_MDIC 0x00020 /* MDI Control - RW */
#define E1000_SCTL 0x00024 /* SerDes Control - RW */
+#define E1000_FEXTNVM 0x00028 /* Future Extended NVM register */
#define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */
#define E1000_FCAH 0x0002C /* Flow Control Address High -RW */
#define E1000_FCT 0x00030 /* Flow Control Type - RW */
@@ -872,6 +938,8 @@ struct e1000_ffvt_entry {
#define E1000_LEDCTL 0x00E00 /* LED Control - RW */
#define E1000_EXTCNF_CTRL 0x00F00 /* Extended Configuration Control */
#define E1000_EXTCNF_SIZE 0x00F08 /* Extended Configuration Size */
+#define E1000_PHY_CTRL 0x00F10 /* PHY Control Register in CSR */
+#define FEXTNVM_SW_CONFIG 0x0001
#define E1000_PBA 0x01000 /* Packet Buffer Allocation - RW */
#define E1000_PBS 0x01008 /* Packet Buffer Size */
#define E1000_EEMNGCTL 0x01010 /* MNG EEprom Control */
@@ -899,11 +967,13 @@ struct e1000_ffvt_entry {
#define E1000_RDH0 E1000_RDH /* RX Desc Head (0) - RW */
#define E1000_RDT0 E1000_RDT /* RX Desc Tail (0) - RW */
#define E1000_RDTR0 E1000_RDTR /* RX Delay Timer (0) - RW */
-#define E1000_RXDCTL 0x02828 /* RX Descriptor Control - RW */
+#define E1000_RXDCTL 0x02828 /* RX Descriptor Control queue 0 - RW */
+#define E1000_RXDCTL1 0x02928 /* RX Descriptor Control queue 1 - RW */
#define E1000_RADV 0x0282C /* RX Interrupt Absolute Delay Timer - RW */
#define E1000_RSRPD 0x02C00 /* RX Small Packet Detect - RW */
#define E1000_RAID 0x02C08 /* Receive Ack Interrupt Delay - RW */
#define E1000_TXDMAC 0x03000 /* TX DMA Control - RW */
+#define E1000_KABGTXD 0x03004 /* AFE Band Gap Transmit Ref Data */
#define E1000_TDFH 0x03410 /* TX Data FIFO Head - RW */
#define E1000_TDFT 0x03418 /* TX Data FIFO Tail - RW */
#define E1000_TDFHS 0x03420 /* TX Data FIFO Head Saved - RW */
@@ -1050,6 +1120,7 @@ struct e1000_ffvt_entry {
#define E1000_82542_FLA E1000_FLA
#define E1000_82542_MDIC E1000_MDIC
#define E1000_82542_SCTL E1000_SCTL
+#define E1000_82542_FEXTNVM E1000_FEXTNVM
#define E1000_82542_FCAL E1000_FCAL
#define E1000_82542_FCAH E1000_FCAH
#define E1000_82542_FCT E1000_FCT
@@ -1073,6 +1144,19 @@ struct e1000_ffvt_entry {
#define E1000_82542_RDLEN0 E1000_82542_RDLEN
#define E1000_82542_RDH0 E1000_82542_RDH
#define E1000_82542_RDT0 E1000_82542_RDT
+#define E1000_82542_SRRCTL(_n) (0x280C + ((_n) << 8)) /* Split and Replication
+ * RX Control - RW */
+#define E1000_82542_DCA_RXCTRL(_n) (0x02814 + ((_n) << 8))
+#define E1000_82542_RDBAH3 0x02B04 /* RX Desc Base High Queue 3 - RW */
+#define E1000_82542_RDBAL3 0x02B00 /* RX Desc Low Queue 3 - RW */
+#define E1000_82542_RDLEN3 0x02B08 /* RX Desc Length Queue 3 - RW */
+#define E1000_82542_RDH3 0x02B10 /* RX Desc Head Queue 3 - RW */
+#define E1000_82542_RDT3 0x02B18 /* RX Desc Tail Queue 3 - RW */
+#define E1000_82542_RDBAL2 0x02A00 /* RX Desc Base Low Queue 2 - RW */
+#define E1000_82542_RDBAH2 0x02A04 /* RX Desc Base High Queue 2 - RW */
+#define E1000_82542_RDLEN2 0x02A08 /* RX Desc Length Queue 2 - RW */
+#define E1000_82542_RDH2 0x02A10 /* RX Desc Head Queue 2 - RW */
+#define E1000_82542_RDT2 0x02A18 /* RX Desc Tail Queue 2 - RW */
#define E1000_82542_RDTR1 0x00130
#define E1000_82542_RDBAL1 0x00138
#define E1000_82542_RDBAH1 0x0013C
@@ -1110,11 +1194,14 @@ struct e1000_ffvt_entry {
#define E1000_82542_FLOP E1000_FLOP
#define E1000_82542_EXTCNF_CTRL E1000_EXTCNF_CTRL
#define E1000_82542_EXTCNF_SIZE E1000_EXTCNF_SIZE
+#define E1000_82542_PHY_CTRL E1000_PHY_CTRL
#define E1000_82542_ERT E1000_ERT
#define E1000_82542_RXDCTL E1000_RXDCTL
+#define E1000_82542_RXDCTL1 E1000_RXDCTL1
#define E1000_82542_RADV E1000_RADV
#define E1000_82542_RSRPD E1000_RSRPD
#define E1000_82542_TXDMAC E1000_TXDMAC
+#define E1000_82542_KABGTXD E1000_KABGTXD
#define E1000_82542_TDFHS E1000_TDFHS
#define E1000_82542_TDFTS E1000_TDFTS
#define E1000_82542_TDFPC E1000_TDFPC
@@ -1310,13 +1397,16 @@ struct e1000_hw_stats {
/* Structure containing variables used by the shared code (e1000_hw.c) */
struct e1000_hw {
- uint8_t __iomem *hw_addr;
+ uint8_t *hw_addr;
uint8_t *flash_address;
e1000_mac_type mac_type;
e1000_phy_type phy_type;
uint32_t phy_init_script;
e1000_media_type media_type;
void *back;
+ struct e1000_shadow_ram *eeprom_shadow_ram;
+ uint32_t flash_bank_size;
+ uint32_t flash_base_addr;
e1000_fc_type fc;
e1000_bus_speed bus_speed;
e1000_bus_width bus_width;
@@ -1328,6 +1418,7 @@ struct e1000_hw {
uint32_t asf_firmware_present;
uint32_t eeprom_semaphore_present;
uint32_t swfw_sync_present;
+ uint32_t swfwhw_semaphore_present;
unsigned long io_base;
uint32_t phy_id;
uint32_t phy_revision;
@@ -1387,6 +1478,7 @@ struct e1000_hw {
boolean_t in_ifs_mode;
boolean_t mng_reg_access_disabled;
boolean_t leave_av_bit_off;
+ boolean_t kmrn_lock_loss_workaround_disabled;
};
@@ -1435,6 +1527,7 @@ struct e1000_hw {
#define E1000_CTRL_RTE 0x20000000 /* Routing tag enable */
#define E1000_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */
#define E1000_CTRL_PHY_RST 0x80000000 /* PHY Reset */
+#define E1000_CTRL_SW2FW_INT 0x02000000 /* Initiate an interrupt to manageability engine */
/* Device Status */
#define E1000_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */
@@ -1449,6 +1542,8 @@ struct e1000_hw {
#define E1000_STATUS_SPEED_10 0x00000000 /* Speed 10Mb/s */
#define E1000_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */
#define E1000_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */
+#define E1000_STATUS_LAN_INIT_DONE 0x00000200 /* Lan Init Completion
+ by EEPROM/Flash */
#define E1000_STATUS_ASDV 0x00000300 /* Auto speed detect value */
#define E1000_STATUS_DOCK_CI 0x00000800 /* Change in Dock/Undock state. Clear on write '0'. */
#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Status of Master requests. */
@@ -1506,6 +1601,10 @@ struct e1000_hw {
#define E1000_STM_OPCODE 0xDB00
#define E1000_HICR_FW_RESET 0xC0
+#define E1000_SHADOW_RAM_WORDS 2048
+#define E1000_ICH8_NVM_SIG_WORD 0x13
+#define E1000_ICH8_NVM_SIG_MASK 0xC0
+
/* EEPROM Read */
#define E1000_EERD_START 0x00000001 /* Start Read */
#define E1000_EERD_DONE 0x00000010 /* Read Done */
@@ -1551,7 +1650,6 @@ struct e1000_hw {
#define E1000_CTRL_EXT_WR_WMARK_320 0x01000000
#define E1000_CTRL_EXT_WR_WMARK_384 0x02000000
#define E1000_CTRL_EXT_WR_WMARK_448 0x03000000
-#define E1000_CTRL_EXT_CANC 0x04000000 /* Interrupt delay cancellation */
#define E1000_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */
#define E1000_CTRL_EXT_IAME 0x08000000 /* Interrupt acknowledge Auto-mask */
#define E1000_CTRL_EXT_INT_TIMER_CLR 0x20000000 /* Clear Interrupt timers after IMS clear */
@@ -1591,12 +1689,31 @@ struct e1000_hw {
#define E1000_KUMCTRLSTA_FIFO_CTRL_TX_BYPASS 0x00000800
/* In-Band Control */
+#define E1000_KUMCTRLSTA_INB_CTRL_LINK_STATUS_TX_TIMEOUT_DEFAULT 0x00000500
#define E1000_KUMCTRLSTA_INB_CTRL_DIS_PADDING 0x00000010
/* Half-Duplex Control */
#define E1000_KUMCTRLSTA_HD_CTRL_10_100_DEFAULT 0x00000004
#define E1000_KUMCTRLSTA_HD_CTRL_1000_DEFAULT 0x00000000
+#define E1000_KUMCTRLSTA_OFFSET_K0S_CTRL 0x0000001E
+
+#define E1000_KUMCTRLSTA_DIAG_FELPBK 0x2000
+#define E1000_KUMCTRLSTA_DIAG_NELPBK 0x1000
+
+#define E1000_KUMCTRLSTA_K0S_100_EN 0x2000
+#define E1000_KUMCTRLSTA_K0S_GBE_EN 0x1000
+#define E1000_KUMCTRLSTA_K0S_ENTRY_LATENCY_MASK 0x0003
+
+#define E1000_KABGTXD_BGSQLBIAS 0x00050000
+
+#define E1000_PHY_CTRL_SPD_EN 0x00000001
+#define E1000_PHY_CTRL_D0A_LPLU 0x00000002
+#define E1000_PHY_CTRL_NOND0A_LPLU 0x00000004
+#define E1000_PHY_CTRL_NOND0A_GBE_DISABLE 0x00000008
+#define E1000_PHY_CTRL_GBE_DISABLE 0x00000040
+#define E1000_PHY_CTRL_B2B_EN 0x00000080
+
/* LED Control */
#define E1000_LEDCTL_LED0_MODE_MASK 0x0000000F
#define E1000_LEDCTL_LED0_MODE_SHIFT 0
@@ -1666,6 +1783,9 @@ struct e1000_hw {
#define E1000_ICR_RXD_FIFO_PAR1 0x01000000 /* queue 1 Rx descriptor FIFO parity error */
#define E1000_ICR_TXD_FIFO_PAR1 0x02000000 /* queue 1 Tx descriptor FIFO parity error */
#define E1000_ICR_ALL_PARITY 0x03F00000 /* all parity error bits */
+#define E1000_ICR_DSW 0x00000020 /* FW changed the status of DISSW bit in the FWSM */
+#define E1000_ICR_PHYINT 0x00001000 /* LAN connected device generates an interrupt */
+#define E1000_ICR_EPRST 0x00100000 /* ME handware reset occurs */
/* Interrupt Cause Set */
#define E1000_ICS_TXDW E1000_ICR_TXDW /* Transmit desc written back */
@@ -1692,6 +1812,9 @@ struct e1000_hw {
#define E1000_ICS_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity error */
#define E1000_ICS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */
#define E1000_ICS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */
+#define E1000_ICS_DSW E1000_ICR_DSW
+#define E1000_ICS_PHYINT E1000_ICR_PHYINT
+#define E1000_ICS_EPRST E1000_ICR_EPRST
/* Interrupt Mask Set */
#define E1000_IMS_TXDW E1000_ICR_TXDW /* Transmit desc written back */
@@ -1718,6 +1841,9 @@ struct e1000_hw {
#define E1000_IMS_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity error */
#define E1000_IMS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */
#define E1000_IMS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */
+#define E1000_IMS_DSW E1000_ICR_DSW
+#define E1000_IMS_PHYINT E1000_ICR_PHYINT
+#define E1000_IMS_EPRST E1000_ICR_EPRST
/* Interrupt Mask Clear */
#define E1000_IMC_TXDW E1000_ICR_TXDW /* Transmit desc written back */
@@ -1744,6 +1870,9 @@ struct e1000_hw {
#define E1000_IMC_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity error */
#define E1000_IMC_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */
#define E1000_IMC_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */
+#define E1000_IMC_DSW E1000_ICR_DSW
+#define E1000_IMC_PHYINT E1000_ICR_PHYINT
+#define E1000_IMC_EPRST E1000_ICR_EPRST
/* Receive Control */
#define E1000_RCTL_RST 0x00000001 /* Software reset */
@@ -1918,9 +2047,10 @@ struct e1000_hw {
#define E1000_MRQC_RSS_FIELD_MASK 0xFFFF0000
#define E1000_MRQC_RSS_FIELD_IPV4_TCP 0x00010000
#define E1000_MRQC_RSS_FIELD_IPV4 0x00020000
-#define E1000_MRQC_RSS_FIELD_IPV6_TCP 0x00040000
+#define E1000_MRQC_RSS_FIELD_IPV6_TCP_EX 0x00040000
#define E1000_MRQC_RSS_FIELD_IPV6_EX 0x00080000
#define E1000_MRQC_RSS_FIELD_IPV6 0x00100000
+#define E1000_MRQC_RSS_FIELD_IPV6_TCP 0x00200000
/* Definitions for power management and wakeup registers */
/* Wake Up Control */
@@ -2010,6 +2140,15 @@ struct e1000_hw {
#define E1000_FWSM_MODE_SHIFT 1
#define E1000_FWSM_FW_VALID 0x00008000 /* FW established a valid mode */
+#define E1000_FWSM_RSPCIPHY 0x00000040 /* Reset PHY on PCI reset */
+#define E1000_FWSM_DISSW 0x10000000 /* FW disable SW Write Access */
+#define E1000_FWSM_SKUSEL_MASK 0x60000000 /* LAN SKU select */
+#define E1000_FWSM_SKUEL_SHIFT 29
+#define E1000_FWSM_SKUSEL_EMB 0x0 /* Embedded SKU */
+#define E1000_FWSM_SKUSEL_CONS 0x1 /* Consumer SKU */
+#define E1000_FWSM_SKUSEL_PERF_100 0x2 /* Perf & Corp 10/100 SKU */
+#define E1000_FWSM_SKUSEL_PERF_GBE 0x3 /* Perf & Copr GbE SKU */
+
/* FFLT Debug Register */
#define E1000_FFLT_DBG_INVC 0x00100000 /* Invalid /C/ code handling */
@@ -2082,6 +2221,8 @@ struct e1000_host_command_info {
E1000_GCR_TXDSCW_NO_SNOOP | \
E1000_GCR_TXDSCR_NO_SNOOP)
+#define PCI_EX_82566_SNOOP_ALL PCI_EX_NO_SNOOP_ALL
+
#define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000
/* Function Active and Power State to MNG */
#define E1000_FACTPS_FUNC0_POWER_STATE_MASK 0x00000003
@@ -2140,8 +2281,10 @@ struct e1000_host_command_info {
#define EEPROM_PHY_CLASS_WORD 0x0007
#define EEPROM_INIT_CONTROL1_REG 0x000A
#define EEPROM_INIT_CONTROL2_REG 0x000F
+#define EEPROM_SWDEF_PINS_CTRL_PORT_1 0x0010
#define EEPROM_INIT_CONTROL3_PORT_B 0x0014
#define EEPROM_INIT_3GIO_3 0x001A
+#define EEPROM_SWDEF_PINS_CTRL_PORT_0 0x0020
#define EEPROM_INIT_CONTROL3_PORT_A 0x0024
#define EEPROM_CFG 0x0012
#define EEPROM_FLASH_VERSION 0x0032
@@ -2153,10 +2296,16 @@ struct e1000_host_command_info {
/* Word definitions for ID LED Settings */
#define ID_LED_RESERVED_0000 0x0000
#define ID_LED_RESERVED_FFFF 0xFFFF
+#define ID_LED_RESERVED_82573 0xF746
+#define ID_LED_DEFAULT_82573 0x1811
#define ID_LED_DEFAULT ((ID_LED_OFF1_ON2 << 12) | \
(ID_LED_OFF1_OFF2 << 8) | \
(ID_LED_DEF1_DEF2 << 4) | \
(ID_LED_DEF1_DEF2))
+#define ID_LED_DEFAULT_ICH8LAN ((ID_LED_DEF1_DEF2 << 12) | \
+ (ID_LED_DEF1_OFF2 << 8) | \
+ (ID_LED_DEF1_ON2 << 4) | \
+ (ID_LED_DEF1_DEF2))
#define ID_LED_DEF1_DEF2 0x1
#define ID_LED_DEF1_ON2 0x2
#define ID_LED_DEF1_OFF2 0x3
@@ -2191,6 +2340,11 @@ struct e1000_host_command_info {
#define EEPROM_WORD0F_ASM_DIR 0x2000
#define EEPROM_WORD0F_ANE 0x0800
#define EEPROM_WORD0F_SWPDIO_EXT 0x00F0
+#define EEPROM_WORD0F_LPLU 0x0001
+
+/* Mask bits for fields in Word 0x10/0x20 of the EEPROM */
+#define EEPROM_WORD1020_GIGA_DISABLE 0x0010
+#define EEPROM_WORD1020_GIGA_DISABLE_NON_D0A 0x0008
/* Mask bits for fields in Word 0x1a of the EEPROM */
#define EEPROM_WORD1A_ASPM_MASK 0x000C
@@ -2265,23 +2419,29 @@ struct e1000_host_command_info {
#define E1000_EXTCNF_CTRL_D_UD_OWNER 0x00000010
#define E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP 0x00000020
#define E1000_EXTCNF_CTRL_MDIO_HW_OWNERSHIP 0x00000040
-#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER 0x1FFF0000
+#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER 0x0FFF0000
#define E1000_EXTCNF_SIZE_EXT_PHY_LENGTH 0x000000FF
#define E1000_EXTCNF_SIZE_EXT_DOCK_LENGTH 0x0000FF00
#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH 0x00FF0000
+#define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE 0x00000001
+#define E1000_EXTCNF_CTRL_SWFLAG 0x00000020
/* PBA constants */
+#define E1000_PBA_8K 0x0008 /* 8KB, default Rx allocation */
#define E1000_PBA_12K 0x000C /* 12KB, default Rx allocation */
#define E1000_PBA_16K 0x0010 /* 16KB, default TX allocation */
#define E1000_PBA_22K 0x0016
#define E1000_PBA_24K 0x0018
#define E1000_PBA_30K 0x001E
#define E1000_PBA_32K 0x0020
+#define E1000_PBA_34K 0x0022
#define E1000_PBA_38K 0x0026
#define E1000_PBA_40K 0x0028
#define E1000_PBA_48K 0x0030 /* 48KB, default RX allocation */
+#define E1000_PBS_16K E1000_PBA_16K
+
/* Flow Control Constants */
#define FLOW_CONTROL_ADDRESS_LOW 0x00C28001
#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100
@@ -2336,7 +2496,7 @@ struct e1000_host_command_info {
/* Number of milliseconds we wait for Eeprom auto read bit done after MAC reset */
#define AUTO_READ_DONE_TIMEOUT 10
/* Number of milliseconds we wait for PHY configuration done after MAC reset */
-#define PHY_CFG_TIMEOUT 40
+#define PHY_CFG_TIMEOUT 100
#define E1000_TX_BUFFER_SIZE ((uint32_t)1514)
@@ -2764,6 +2924,17 @@ struct e1000_host_command_info {
#define M88E1000_EPSCR_TX_CLK_25 0x0070 /* 25 MHz TX_CLK */
#define M88E1000_EPSCR_TX_CLK_0 0x0000 /* NO TX_CLK */
+/* M88EC018 Rev 2 specific DownShift settings */
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK 0x0E00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_1X 0x0000
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_2X 0x0200
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_3X 0x0400
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_4X 0x0600
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X 0x0800
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_6X 0x0A00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_7X 0x0C00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_8X 0x0E00
+
/* IGP01E1000 Specific Port Config Register - R/W */
#define IGP01E1000_PSCFR_AUTO_MDIX_PAR_DETECT 0x0010
#define IGP01E1000_PSCFR_PRE_EN 0x0020
@@ -2990,6 +3161,221 @@ struct e1000_host_command_info {
#define L1LXT971A_PHY_ID 0x001378E0
#define GG82563_E_PHY_ID 0x01410CA0
+
+/* Bits...
+ * 15-5: page
+ * 4-0: register offset
+ */
+#define PHY_PAGE_SHIFT 5
+#define PHY_REG(page, reg) \
+ (((page) << PHY_PAGE_SHIFT) | ((reg) & MAX_PHY_REG_ADDRESS))
+
+#define IGP3_PHY_PORT_CTRL \
+ PHY_REG(769, 17) /* Port General Configuration */
+#define IGP3_PHY_RATE_ADAPT_CTRL \
+ PHY_REG(769, 25) /* Rate Adapter Control Register */
+
+#define IGP3_KMRN_FIFO_CTRL_STATS \
+ PHY_REG(770, 16) /* KMRN FIFO's control/status register */
+#define IGP3_KMRN_POWER_MNG_CTRL \
+ PHY_REG(770, 17) /* KMRN Power Management Control Register */
+#define IGP3_KMRN_INBAND_CTRL \
+ PHY_REG(770, 18) /* KMRN Inband Control Register */
+#define IGP3_KMRN_DIAG \
+ PHY_REG(770, 19) /* KMRN Diagnostic register */
+#define IGP3_KMRN_DIAG_PCS_LOCK_LOSS 0x0002 /* RX PCS is not synced */
+#define IGP3_KMRN_ACK_TIMEOUT \
+ PHY_REG(770, 20) /* KMRN Acknowledge Timeouts register */
+
+#define IGP3_VR_CTRL \
+ PHY_REG(776, 18) /* Voltage regulator control register */
+#define IGP3_VR_CTRL_MODE_SHUT 0x0200 /* Enter powerdown, shutdown VRs */
+
+#define IGP3_CAPABILITY \
+ PHY_REG(776, 19) /* IGP3 Capability Register */
+
+/* Capabilities for SKU Control */
+#define IGP3_CAP_INITIATE_TEAM 0x0001 /* Able to initiate a team */
+#define IGP3_CAP_WFM 0x0002 /* Support WoL and PXE */
+#define IGP3_CAP_ASF 0x0004 /* Support ASF */
+#define IGP3_CAP_LPLU 0x0008 /* Support Low Power Link Up */
+#define IGP3_CAP_DC_AUTO_SPEED 0x0010 /* Support AC/DC Auto Link Speed */
+#define IGP3_CAP_SPD 0x0020 /* Support Smart Power Down */
+#define IGP3_CAP_MULT_QUEUE 0x0040 /* Support 2 tx & 2 rx queues */
+#define IGP3_CAP_RSS 0x0080 /* Support RSS */
+#define IGP3_CAP_8021PQ 0x0100 /* Support 802.1Q & 802.1p */
+#define IGP3_CAP_AMT_CB 0x0200 /* Support active manageability and circuit breaker */
+
+#define IGP3_PPC_JORDAN_EN 0x0001
+#define IGP3_PPC_JORDAN_GIGA_SPEED 0x0002
+
+#define IGP3_KMRN_PMC_EE_IDLE_LINK_DIS 0x0001
+#define IGP3_KMRN_PMC_K0S_ENTRY_LATENCY_MASK 0x001E
+#define IGP3_KMRN_PMC_K0S_MODE1_EN_GIGA 0x0020
+#define IGP3_KMRN_PMC_K0S_MODE1_EN_100 0x0040
+
+#define IGP3E1000_PHY_MISC_CTRL 0x1B /* Misc. Ctrl register */
+#define IGP3_PHY_MISC_DUPLEX_MANUAL_SET 0x1000 /* Duplex Manual Set */
+
+#define IGP3_KMRN_EXT_CTRL PHY_REG(770, 18)
+#define IGP3_KMRN_EC_DIS_INBAND 0x0080
+
+#define IGP03E1000_E_PHY_ID 0x02A80390
+#define IFE_E_PHY_ID 0x02A80330 /* 10/100 PHY */
+#define IFE_PLUS_E_PHY_ID 0x02A80320
+#define IFE_C_E_PHY_ID 0x02A80310
+
+#define IFE_PHY_EXTENDED_STATUS_CONTROL 0x10 /* 100BaseTx Extended Status, Control and Address */
+#define IFE_PHY_SPECIAL_CONTROL 0x11 /* 100BaseTx PHY special control register */
+#define IFE_PHY_RCV_FALSE_CARRIER 0x13 /* 100BaseTx Receive False Carrier Counter */
+#define IFE_PHY_RCV_DISCONNECT 0x14 /* 100BaseTx Receive Disconnet Counter */
+#define IFE_PHY_RCV_ERROT_FRAME 0x15 /* 100BaseTx Receive Error Frame Counter */
+#define IFE_PHY_RCV_SYMBOL_ERR 0x16 /* Receive Symbol Error Counter */
+#define IFE_PHY_PREM_EOF_ERR 0x17 /* 100BaseTx Receive Premature End Of Frame Error Counter */
+#define IFE_PHY_RCV_EOF_ERR 0x18 /* 10BaseT Receive End Of Frame Error Counter */
+#define IFE_PHY_TX_JABBER_DETECT 0x19 /* 10BaseT Transmit Jabber Detect Counter */
+#define IFE_PHY_EQUALIZER 0x1A /* PHY Equalizer Control and Status */
+#define IFE_PHY_SPECIAL_CONTROL_LED 0x1B /* PHY special control and LED configuration */
+#define IFE_PHY_MDIX_CONTROL 0x1C /* MDI/MDI-X Control register */
+#define IFE_PHY_HWI_CONTROL 0x1D /* Hardware Integrity Control (HWI) */
+
+#define IFE_PESC_REDUCED_POWER_DOWN_DISABLE 0x2000 /* Defaut 1 = Disable auto reduced power down */
+#define IFE_PESC_100BTX_POWER_DOWN 0x0400 /* Indicates the power state of 100BASE-TX */
+#define IFE_PESC_10BTX_POWER_DOWN 0x0200 /* Indicates the power state of 10BASE-T */
+#define IFE_PESC_POLARITY_REVERSED 0x0100 /* Indicates 10BASE-T polarity */
+#define IFE_PESC_PHY_ADDR_MASK 0x007C /* Bit 6:2 for sampled PHY address */
+#define IFE_PESC_SPEED 0x0002 /* Auto-negotiation speed result 1=100Mbs, 0=10Mbs */
+#define IFE_PESC_DUPLEX 0x0001 /* Auto-negotiation duplex result 1=Full, 0=Half */
+#define IFE_PESC_POLARITY_REVERSED_SHIFT 8
+
+#define IFE_PSC_DISABLE_DYNAMIC_POWER_DOWN 0x0100 /* 1 = Dyanmic Power Down disabled */
+#define IFE_PSC_FORCE_POLARITY 0x0020 /* 1=Reversed Polarity, 0=Normal */
+#define IFE_PSC_AUTO_POLARITY_DISABLE 0x0010 /* 1=Auto Polarity Disabled, 0=Enabled */
+#define IFE_PSC_JABBER_FUNC_DISABLE 0x0001 /* 1=Jabber Disabled, 0=Normal Jabber Operation */
+#define IFE_PSC_FORCE_POLARITY_SHIFT 5
+#define IFE_PSC_AUTO_POLARITY_DISABLE_SHIFT 4
+
+#define IFE_PMC_AUTO_MDIX 0x0080 /* 1=enable MDI/MDI-X feature, default 0=disabled */
+#define IFE_PMC_FORCE_MDIX 0x0040 /* 1=force MDIX-X, 0=force MDI */
+#define IFE_PMC_MDIX_STATUS 0x0020 /* 1=MDI-X, 0=MDI */
+#define IFE_PMC_AUTO_MDIX_COMPLETE 0x0010 /* Resolution algorthm is completed */
+#define IFE_PMC_MDIX_MODE_SHIFT 6
+#define IFE_PHC_MDIX_RESET_ALL_MASK 0x0000 /* Disable auto MDI-X */
+
+#define IFE_PHC_HWI_ENABLE 0x8000 /* Enable the HWI feature */
+#define IFE_PHC_ABILITY_CHECK 0x4000 /* 1= Test Passed, 0=failed */
+#define IFE_PHC_TEST_EXEC 0x2000 /* PHY launch test pulses on the wire */
+#define IFE_PHC_HIGHZ 0x0200 /* 1 = Open Circuit */
+#define IFE_PHC_LOWZ 0x0400 /* 1 = Short Circuit */
+#define IFE_PHC_LOW_HIGH_Z_MASK 0x0600 /* Mask for indication type of problem on the line */
+#define IFE_PHC_DISTANCE_MASK 0x01FF /* Mask for distance to the cable problem, in 80cm granularity */
+#define IFE_PHC_RESET_ALL_MASK 0x0000 /* Disable HWI */
+#define IFE_PSCL_PROBE_MODE 0x0020 /* LED Probe mode */
+#define IFE_PSCL_PROBE_LEDS_OFF 0x0006 /* Force LEDs 0 and 2 off */
+#define IFE_PSCL_PROBE_LEDS_ON 0x0007 /* Force LEDs 0 and 2 on */
+
+#define ICH8_FLASH_COMMAND_TIMEOUT 500 /* 500 ms , should be adjusted */
+#define ICH8_FLASH_CYCLE_REPEAT_COUNT 10 /* 10 cycles , should be adjusted */
+#define ICH8_FLASH_SEG_SIZE_256 256
+#define ICH8_FLASH_SEG_SIZE_4K 4096
+#define ICH8_FLASH_SEG_SIZE_64K 65536
+
+#define ICH8_CYCLE_READ 0x0
+#define ICH8_CYCLE_RESERVED 0x1
+#define ICH8_CYCLE_WRITE 0x2
+#define ICH8_CYCLE_ERASE 0x3
+
+#define ICH8_FLASH_GFPREG 0x0000
+#define ICH8_FLASH_HSFSTS 0x0004
+#define ICH8_FLASH_HSFCTL 0x0006
+#define ICH8_FLASH_FADDR 0x0008
+#define ICH8_FLASH_FDATA0 0x0010
+#define ICH8_FLASH_FRACC 0x0050
+#define ICH8_FLASH_FREG0 0x0054
+#define ICH8_FLASH_FREG1 0x0058
+#define ICH8_FLASH_FREG2 0x005C
+#define ICH8_FLASH_FREG3 0x0060
+#define ICH8_FLASH_FPR0 0x0074
+#define ICH8_FLASH_FPR1 0x0078
+#define ICH8_FLASH_SSFSTS 0x0090
+#define ICH8_FLASH_SSFCTL 0x0092
+#define ICH8_FLASH_PREOP 0x0094
+#define ICH8_FLASH_OPTYPE 0x0096
+#define ICH8_FLASH_OPMENU 0x0098
+
+#define ICH8_FLASH_REG_MAPSIZE 0x00A0
+#define ICH8_FLASH_SECTOR_SIZE 4096
+#define ICH8_GFPREG_BASE_MASK 0x1FFF
+#define ICH8_FLASH_LINEAR_ADDR_MASK 0x00FFFFFF
+
+/* ICH8 GbE Flash Hardware Sequencing Flash Status Register bit breakdown */
+/* Offset 04h HSFSTS */
+union ich8_hws_flash_status {
+ struct ich8_hsfsts {
+#ifdef E1000_BIG_ENDIAN
+ uint16_t reserved2 :6;
+ uint16_t fldesvalid :1;
+ uint16_t flockdn :1;
+ uint16_t flcdone :1;
+ uint16_t flcerr :1;
+ uint16_t dael :1;
+ uint16_t berasesz :2;
+ uint16_t flcinprog :1;
+ uint16_t reserved1 :2;
+#else
+ uint16_t flcdone :1; /* bit 0 Flash Cycle Done */
+ uint16_t flcerr :1; /* bit 1 Flash Cycle Error */
+ uint16_t dael :1; /* bit 2 Direct Access error Log */
+ uint16_t berasesz :2; /* bit 4:3 Block/Sector Erase Size */
+ uint16_t flcinprog :1; /* bit 5 flash SPI cycle in Progress */
+ uint16_t reserved1 :2; /* bit 13:6 Reserved */
+ uint16_t reserved2 :6; /* bit 13:6 Reserved */
+ uint16_t fldesvalid :1; /* bit 14 Flash Descriptor Valid */
+ uint16_t flockdn :1; /* bit 15 Flash Configuration Lock-Down */
+#endif
+ } hsf_status;
+ uint16_t regval;
+};
+
+/* ICH8 GbE Flash Hardware Sequencing Flash control Register bit breakdown */
+/* Offset 06h FLCTL */
+union ich8_hws_flash_ctrl {
+ struct ich8_hsflctl {
+#ifdef E1000_BIG_ENDIAN
+ uint16_t fldbcount :2;
+ uint16_t flockdn :6;
+ uint16_t flcgo :1;
+ uint16_t flcycle :2;
+ uint16_t reserved :5;
+#else
+ uint16_t flcgo :1; /* 0 Flash Cycle Go */
+ uint16_t flcycle :2; /* 2:1 Flash Cycle */
+ uint16_t reserved :5; /* 7:3 Reserved */
+ uint16_t fldbcount :2; /* 9:8 Flash Data Byte Count */
+ uint16_t flockdn :6; /* 15:10 Reserved */
+#endif
+ } hsf_ctrl;
+ uint16_t regval;
+};
+
+/* ICH8 Flash Region Access Permissions */
+union ich8_hws_flash_regacc {
+ struct ich8_flracc {
+#ifdef E1000_BIG_ENDIAN
+ uint32_t gmwag :8;
+ uint32_t gmrag :8;
+ uint32_t grwa :8;
+ uint32_t grra :8;
+#else
+ uint32_t grra :8; /* 0:7 GbE region Read Access */
+ uint32_t grwa :8; /* 8:15 GbE region Write Access */
+ uint32_t gmrag :8; /* 23:16 GbE Master Read Access Grant */
+ uint32_t gmwag :8; /* 31:24 GbE Master Write Access Grant */
+#endif
+ } hsf_flregacc;
+ uint16_t regval;
+};
+
/* Miscellaneous PHY bit definitions. */
#define PHY_PREAMBLE 0xFFFFFFFF
#define PHY_SOF 0x01
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index f77624f5f17..627f224d78b 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -36,7 +36,7 @@ static char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
#else
#define DRIVERNAPI "-NAPI"
#endif
-#define DRV_VERSION "7.0.38-k4"DRIVERNAPI
+#define DRV_VERSION "7.1.9-k4"DRIVERNAPI
char e1000_driver_version[] = DRV_VERSION;
static char e1000_copyright[] = "Copyright (c) 1999-2006 Intel Corporation.";
@@ -73,6 +73,11 @@ static struct pci_device_id e1000_pci_tbl[] = {
INTEL_E1000_ETHERNET_DEVICE(0x1026),
INTEL_E1000_ETHERNET_DEVICE(0x1027),
INTEL_E1000_ETHERNET_DEVICE(0x1028),
+ INTEL_E1000_ETHERNET_DEVICE(0x1049),
+ INTEL_E1000_ETHERNET_DEVICE(0x104A),
+ INTEL_E1000_ETHERNET_DEVICE(0x104B),
+ INTEL_E1000_ETHERNET_DEVICE(0x104C),
+ INTEL_E1000_ETHERNET_DEVICE(0x104D),
INTEL_E1000_ETHERNET_DEVICE(0x105E),
INTEL_E1000_ETHERNET_DEVICE(0x105F),
INTEL_E1000_ETHERNET_DEVICE(0x1060),
@@ -96,6 +101,8 @@ static struct pci_device_id e1000_pci_tbl[] = {
INTEL_E1000_ETHERNET_DEVICE(0x109A),
INTEL_E1000_ETHERNET_DEVICE(0x10B5),
INTEL_E1000_ETHERNET_DEVICE(0x10B9),
+ INTEL_E1000_ETHERNET_DEVICE(0x10BA),
+ INTEL_E1000_ETHERNET_DEVICE(0x10BB),
/* required last entry */
{0,}
};
@@ -133,7 +140,6 @@ static void e1000_clean_rx_ring(struct e1000_adapter *adapter,
static void e1000_set_multi(struct net_device *netdev);
static void e1000_update_phy_info(unsigned long data);
static void e1000_watchdog(unsigned long data);
-static void e1000_watchdog_task(struct e1000_adapter *adapter);
static void e1000_82547_tx_fifo_stall(unsigned long data);
static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
static struct net_device_stats * e1000_get_stats(struct net_device *netdev);
@@ -178,8 +184,8 @@ static void e1000_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid);
static void e1000_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid);
static void e1000_restore_vlan(struct e1000_adapter *adapter);
-#ifdef CONFIG_PM
static int e1000_suspend(struct pci_dev *pdev, pm_message_t state);
+#ifdef CONFIG_PM
static int e1000_resume(struct pci_dev *pdev);
#endif
static void e1000_shutdown(struct pci_dev *pdev);
@@ -206,8 +212,8 @@ static struct pci_driver e1000_driver = {
.probe = e1000_probe,
.remove = __devexit_p(e1000_remove),
/* Power Managment Hooks */
-#ifdef CONFIG_PM
.suspend = e1000_suspend,
+#ifdef CONFIG_PM
.resume = e1000_resume,
#endif
.shutdown = e1000_shutdown,
@@ -261,6 +267,44 @@ e1000_exit_module(void)
module_exit(e1000_exit_module);
+static int e1000_request_irq(struct e1000_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ int flags, err = 0;
+
+ flags = IRQF_SHARED;
+#ifdef CONFIG_PCI_MSI
+ if (adapter->hw.mac_type > e1000_82547_rev_2) {
+ adapter->have_msi = TRUE;
+ if ((err = pci_enable_msi(adapter->pdev))) {
+ DPRINTK(PROBE, ERR,
+ "Unable to allocate MSI interrupt Error: %d\n", err);
+ adapter->have_msi = FALSE;
+ }
+ }
+ if (adapter->have_msi)
+ flags &= ~IRQF_SHARED;
+#endif
+ if ((err = request_irq(adapter->pdev->irq, &e1000_intr, flags,
+ netdev->name, netdev)))
+ DPRINTK(PROBE, ERR,
+ "Unable to allocate interrupt Error: %d\n", err);
+
+ return err;
+}
+
+static void e1000_free_irq(struct e1000_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+
+ free_irq(adapter->pdev->irq, netdev);
+
+#ifdef CONFIG_PCI_MSI
+ if (adapter->have_msi)
+ pci_disable_msi(adapter->pdev);
+#endif
+}
+
/**
* e1000_irq_disable - Mask off interrupt generation on the NIC
* @adapter: board private structure
@@ -329,6 +373,7 @@ e1000_release_hw_control(struct e1000_adapter *adapter)
{
uint32_t ctrl_ext;
uint32_t swsm;
+ uint32_t extcnf;
/* Let firmware taken over control of h/w */
switch (adapter->hw.mac_type) {
@@ -343,6 +388,11 @@ e1000_release_hw_control(struct e1000_adapter *adapter)
swsm = E1000_READ_REG(&adapter->hw, SWSM);
E1000_WRITE_REG(&adapter->hw, SWSM,
swsm & ~E1000_SWSM_DRV_LOAD);
+ case e1000_ich8lan:
+ extcnf = E1000_READ_REG(&adapter->hw, CTRL_EXT);
+ E1000_WRITE_REG(&adapter->hw, CTRL_EXT,
+ extcnf & ~E1000_CTRL_EXT_DRV_LOAD);
+ break;
default:
break;
}
@@ -364,6 +414,7 @@ e1000_get_hw_control(struct e1000_adapter *adapter)
{
uint32_t ctrl_ext;
uint32_t swsm;
+ uint32_t extcnf;
/* Let firmware know the driver has taken over */
switch (adapter->hw.mac_type) {
case e1000_82571:
@@ -378,6 +429,11 @@ e1000_get_hw_control(struct e1000_adapter *adapter)
E1000_WRITE_REG(&adapter->hw, SWSM,
swsm | E1000_SWSM_DRV_LOAD);
break;
+ case e1000_ich8lan:
+ extcnf = E1000_READ_REG(&adapter->hw, EXTCNF_CTRL);
+ E1000_WRITE_REG(&adapter->hw, EXTCNF_CTRL,
+ extcnf | E1000_EXTCNF_CTRL_SWFLAG);
+ break;
default:
break;
}
@@ -387,18 +443,10 @@ int
e1000_up(struct e1000_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
- int i, err;
+ int i;
/* hardware has been reset, we need to reload some things */
- /* Reset the PHY if it was previously powered down */
- if (adapter->hw.media_type == e1000_media_type_copper) {
- uint16_t mii_reg;
- e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &mii_reg);
- if (mii_reg & MII_CR_POWER_DOWN)
- e1000_phy_hw_reset(&adapter->hw);
- }
-
e1000_set_multi(netdev);
e1000_restore_vlan(adapter);
@@ -415,24 +463,6 @@ e1000_up(struct e1000_adapter *adapter)
E1000_DESC_UNUSED(ring));
}
-#ifdef CONFIG_PCI_MSI
- if (adapter->hw.mac_type > e1000_82547_rev_2) {
- adapter->have_msi = TRUE;
- if ((err = pci_enable_msi(adapter->pdev))) {
- DPRINTK(PROBE, ERR,
- "Unable to allocate MSI interrupt Error: %d\n", err);
- adapter->have_msi = FALSE;
- }
- }
-#endif
- if ((err = request_irq(adapter->pdev->irq, &e1000_intr,
- IRQF_SHARED | IRQF_SAMPLE_RANDOM,
- netdev->name, netdev))) {
- DPRINTK(PROBE, ERR,
- "Unable to allocate interrupt Error: %d\n", err);
- return err;
- }
-
adapter->tx_queue_len = netdev->tx_queue_len;
mod_timer(&adapter->watchdog_timer, jiffies);
@@ -445,21 +475,60 @@ e1000_up(struct e1000_adapter *adapter)
return 0;
}
+/**
+ * e1000_power_up_phy - restore link in case the phy was powered down
+ * @adapter: address of board private structure
+ *
+ * The phy may be powered down to save power and turn off link when the
+ * driver is unloaded and wake on lan is not enabled (among others)
+ * *** this routine MUST be followed by a call to e1000_reset ***
+ *
+ **/
+
+static void e1000_power_up_phy(struct e1000_adapter *adapter)
+{
+ uint16_t mii_reg = 0;
+
+ /* Just clear the power down bit to wake the phy back up */
+ if (adapter->hw.media_type == e1000_media_type_copper) {
+ /* according to the manual, the phy will retain its
+ * settings across a power-down/up cycle */
+ e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &mii_reg);
+ mii_reg &= ~MII_CR_POWER_DOWN;
+ e1000_write_phy_reg(&adapter->hw, PHY_CTRL, mii_reg);
+ }
+}
+
+static void e1000_power_down_phy(struct e1000_adapter *adapter)
+{
+ boolean_t mng_mode_enabled = (adapter->hw.mac_type >= e1000_82571) &&
+ e1000_check_mng_mode(&adapter->hw);
+ /* Power down the PHY so no link is implied when interface is down
+ * The PHY cannot be powered down if any of the following is TRUE
+ * (a) WoL is enabled
+ * (b) AMT is active
+ * (c) SoL/IDER session is active */
+ if (!adapter->wol && adapter->hw.mac_type >= e1000_82540 &&
+ adapter->hw.mac_type != e1000_ich8lan &&
+ adapter->hw.media_type == e1000_media_type_copper &&
+ !(E1000_READ_REG(&adapter->hw, MANC) & E1000_MANC_SMBUS_EN) &&
+ !mng_mode_enabled &&
+ !e1000_check_phy_reset_block(&adapter->hw)) {
+ uint16_t mii_reg = 0;
+ e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &mii_reg);
+ mii_reg |= MII_CR_POWER_DOWN;
+ e1000_write_phy_reg(&adapter->hw, PHY_CTRL, mii_reg);
+ mdelay(1);
+ }
+}
+
void
e1000_down(struct e1000_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
- boolean_t mng_mode_enabled = (adapter->hw.mac_type >= e1000_82571) &&
- e1000_check_mng_mode(&adapter->hw);
e1000_irq_disable(adapter);
- free_irq(adapter->pdev->irq, netdev);
-#ifdef CONFIG_PCI_MSI
- if (adapter->hw.mac_type > e1000_82547_rev_2 &&
- adapter->have_msi == TRUE)
- pci_disable_msi(adapter->pdev);
-#endif
del_timer_sync(&adapter->tx_fifo_stall_timer);
del_timer_sync(&adapter->watchdog_timer);
del_timer_sync(&adapter->phy_info_timer);
@@ -476,23 +545,17 @@ e1000_down(struct e1000_adapter *adapter)
e1000_reset(adapter);
e1000_clean_all_tx_rings(adapter);
e1000_clean_all_rx_rings(adapter);
+}
- /* Power down the PHY so no link is implied when interface is down *
- * The PHY cannot be powered down if any of the following is TRUE *
- * (a) WoL is enabled
- * (b) AMT is active
- * (c) SoL/IDER session is active */
- if (!adapter->wol && adapter->hw.mac_type >= e1000_82540 &&
- adapter->hw.media_type == e1000_media_type_copper &&
- !(E1000_READ_REG(&adapter->hw, MANC) & E1000_MANC_SMBUS_EN) &&
- !mng_mode_enabled &&
- !e1000_check_phy_reset_block(&adapter->hw)) {
- uint16_t mii_reg;
- e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &mii_reg);
- mii_reg |= MII_CR_POWER_DOWN;
- e1000_write_phy_reg(&adapter->hw, PHY_CTRL, mii_reg);
- mdelay(1);
- }
+void
+e1000_reinit_locked(struct e1000_adapter *adapter)
+{
+ WARN_ON(in_interrupt());
+ while (test_and_set_bit(__E1000_RESETTING, &adapter->flags))
+ msleep(1);
+ e1000_down(adapter);
+ e1000_up(adapter);
+ clear_bit(__E1000_RESETTING, &adapter->flags);
}
void
@@ -518,6 +581,9 @@ e1000_reset(struct e1000_adapter *adapter)
case e1000_82573:
pba = E1000_PBA_12K;
break;
+ case e1000_ich8lan:
+ pba = E1000_PBA_8K;
+ break;
default:
pba = E1000_PBA_48K;
break;
@@ -542,6 +608,12 @@ e1000_reset(struct e1000_adapter *adapter)
/* Set the FC high water mark to 90% of the FIFO size.
* Required to clear last 3 LSB */
fc_high_water_mark = ((pba * 9216)/10) & 0xFFF8;
+ /* We can't use 90% on small FIFOs because the remainder
+ * would be less than 1 full frame. In this case, we size
+ * it to allow at least a full frame above the high water
+ * mark. */
+ if (pba < E1000_PBA_16K)
+ fc_high_water_mark = (pba * 1024) - 1600;
adapter->hw.fc_high_water = fc_high_water_mark;
adapter->hw.fc_low_water = fc_high_water_mark - 8;
@@ -564,6 +636,23 @@ e1000_reset(struct e1000_adapter *adapter)
e1000_reset_adaptive(&adapter->hw);
e1000_phy_get_info(&adapter->hw, &adapter->phy_info);
+
+ if (!adapter->smart_power_down &&
+ (adapter->hw.mac_type == e1000_82571 ||
+ adapter->hw.mac_type == e1000_82572)) {
+ uint16_t phy_data = 0;
+ /* speed up time to link by disabling smart power down, ignore
+ * the return value of this function because there is nothing
+ * different we would do if it failed */
+ e1000_read_phy_reg(&adapter->hw, IGP02E1000_PHY_POWER_MGMT,
+ &phy_data);
+ phy_data &= ~IGP02E1000_PM_SPD;
+ e1000_write_phy_reg(&adapter->hw, IGP02E1000_PHY_POWER_MGMT,
+ phy_data);
+ }
+
+ if (adapter->hw.mac_type < e1000_ich8lan)
+ /* FIXME: this code is duplicate and wrong for PCI Express */
if (adapter->en_mng_pt) {
manc = E1000_READ_REG(&adapter->hw, MANC);
manc |= (E1000_MANC_ARP_EN | E1000_MANC_EN_MNG2HOST);
@@ -590,6 +679,7 @@ e1000_probe(struct pci_dev *pdev,
struct net_device *netdev;
struct e1000_adapter *adapter;
unsigned long mmio_start, mmio_len;
+ unsigned long flash_start, flash_len;
static int cards_found = 0;
static int e1000_ksp3_port_a = 0; /* global ksp3 port a indication */
@@ -599,10 +689,12 @@ e1000_probe(struct pci_dev *pdev,
if ((err = pci_enable_device(pdev)))
return err;
- if (!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK))) {
+ if (!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK)) &&
+ !(err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))) {
pci_using_dac = 1;
} else {
- if ((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK))) {
+ if ((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) &&
+ (err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK))) {
E1000_ERR("No usable DMA configuration, aborting\n");
return err;
}
@@ -682,6 +774,19 @@ e1000_probe(struct pci_dev *pdev,
if ((err = e1000_sw_init(adapter)))
goto err_sw_init;
+ /* Flash BAR mapping must happen after e1000_sw_init
+ * because it depends on mac_type */
+ if ((adapter->hw.mac_type == e1000_ich8lan) &&
+ (pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) {
+ flash_start = pci_resource_start(pdev, 1);
+ flash_len = pci_resource_len(pdev, 1);
+ adapter->hw.flash_address = ioremap(flash_start, flash_len);
+ if (!adapter->hw.flash_address) {
+ err = -EIO;
+ goto err_flashmap;
+ }
+ }
+
if ((err = e1000_check_phy_reset_block(&adapter->hw)))
DPRINTK(PROBE, INFO, "PHY reset is blocked due to SOL/IDER session.\n");
@@ -700,6 +805,8 @@ e1000_probe(struct pci_dev *pdev,
NETIF_F_HW_VLAN_TX |
NETIF_F_HW_VLAN_RX |
NETIF_F_HW_VLAN_FILTER;
+ if (adapter->hw.mac_type == e1000_ich8lan)
+ netdev->features &= ~NETIF_F_HW_VLAN_FILTER;
}
#ifdef NETIF_F_TSO
@@ -715,11 +822,17 @@ e1000_probe(struct pci_dev *pdev,
if (pci_using_dac)
netdev->features |= NETIF_F_HIGHDMA;
- /* hard_start_xmit is safe against parallel locking */
netdev->features |= NETIF_F_LLTX;
adapter->en_mng_pt = e1000_enable_mng_pass_thru(&adapter->hw);
+ /* initialize eeprom parameters */
+
+ if (e1000_init_eeprom_params(&adapter->hw)) {
+ E1000_ERR("EEPROM initialization failed\n");
+ return -EIO;
+ }
+
/* before reading the EEPROM, reset the controller to
* put the device in a known good starting state */
@@ -758,9 +871,6 @@ e1000_probe(struct pci_dev *pdev,
adapter->watchdog_timer.function = &e1000_watchdog;
adapter->watchdog_timer.data = (unsigned long) adapter;
- INIT_WORK(&adapter->watchdog_task,
- (void (*)(void *))e1000_watchdog_task, adapter);
-
init_timer(&adapter->phy_info_timer);
adapter->phy_info_timer.function = &e1000_update_phy_info;
adapter->phy_info_timer.data = (unsigned long) adapter;
@@ -790,6 +900,11 @@ e1000_probe(struct pci_dev *pdev,
EEPROM_INIT_CONTROL2_REG, 1, &eeprom_data);
eeprom_apme_mask = E1000_EEPROM_82544_APM;
break;
+ case e1000_ich8lan:
+ e1000_read_eeprom(&adapter->hw,
+ EEPROM_INIT_CONTROL1_REG, 1, &eeprom_data);
+ eeprom_apme_mask = E1000_EEPROM_ICH8_APME;
+ break;
case e1000_82546:
case e1000_82546_rev_3:
case e1000_82571:
@@ -849,6 +964,9 @@ e1000_probe(struct pci_dev *pdev,
return 0;
err_register:
+ if (adapter->hw.flash_address)
+ iounmap(adapter->hw.flash_address);
+err_flashmap:
err_sw_init:
err_eeprom:
iounmap(adapter->hw.hw_addr);
@@ -882,6 +1000,7 @@ e1000_remove(struct pci_dev *pdev)
flush_scheduled_work();
if (adapter->hw.mac_type >= e1000_82540 &&
+ adapter->hw.mac_type != e1000_ich8lan &&
adapter->hw.media_type == e1000_media_type_copper) {
manc = E1000_READ_REG(&adapter->hw, MANC);
if (manc & E1000_MANC_SMBUS_EN) {
@@ -910,6 +1029,8 @@ e1000_remove(struct pci_dev *pdev)
#endif
iounmap(adapter->hw.hw_addr);
+ if (adapter->hw.flash_address)
+ iounmap(adapter->hw.flash_address);
pci_release_regions(pdev);
free_netdev(netdev);
@@ -947,7 +1068,7 @@ e1000_sw_init(struct e1000_adapter *adapter)
pci_read_config_word(pdev, PCI_COMMAND, &hw->pci_cmd_word);
- adapter->rx_buffer_len = MAXIMUM_ETHERNET_FRAME_SIZE;
+ adapter->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE;
adapter->rx_ps_bsize0 = E1000_RXBUFFER_128;
hw->max_frame_size = netdev->mtu +
ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
@@ -960,13 +1081,6 @@ e1000_sw_init(struct e1000_adapter *adapter)
return -EIO;
}
- /* initialize eeprom parameters */
-
- if (e1000_init_eeprom_params(hw)) {
- E1000_ERR("EEPROM initialization failed\n");
- return -EIO;
- }
-
switch (hw->mac_type) {
default:
break;
@@ -1078,6 +1192,10 @@ e1000_open(struct net_device *netdev)
struct e1000_adapter *adapter = netdev_priv(netdev);
int err;
+ /* disallow open during test */
+ if (test_bit(__E1000_DRIVER_TESTING, &adapter->flags))
+ return -EBUSY;
+
/* allocate transmit descriptors */
if ((err = e1000_setup_all_tx_resources(adapter)))
@@ -1088,6 +1206,12 @@ e1000_open(struct net_device *netdev)
if ((err = e1000_setup_all_rx_resources(adapter)))
goto err_setup_rx;
+ err = e1000_request_irq(adapter);
+ if (err)
+ goto err_up;
+
+ e1000_power_up_phy(adapter);
+
if ((err = e1000_up(adapter)))
goto err_up;
adapter->mng_vlan_id = E1000_MNG_VLAN_NONE;
@@ -1131,7 +1255,10 @@ e1000_close(struct net_device *netdev)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
+ WARN_ON(test_bit(__E1000_RESETTING, &adapter->flags));
e1000_down(adapter);
+ e1000_power_down_phy(adapter);
+ e1000_free_irq(adapter);
e1000_free_all_tx_resources(adapter);
e1000_free_all_rx_resources(adapter);
@@ -1189,8 +1316,7 @@ e1000_setup_tx_resources(struct e1000_adapter *adapter,
int size;
size = sizeof(struct e1000_buffer) * txdr->count;
-
- txdr->buffer_info = vmalloc_node(size, pcibus_to_node(pdev->bus));
+ txdr->buffer_info = vmalloc(size);
if (!txdr->buffer_info) {
DPRINTK(PROBE, ERR,
"Unable to allocate memory for the transmit descriptor ring\n");
@@ -1302,11 +1428,11 @@ e1000_configure_tx(struct e1000_adapter *adapter)
tdba = adapter->tx_ring[0].dma;
tdlen = adapter->tx_ring[0].count *
sizeof(struct e1000_tx_desc);
- E1000_WRITE_REG(hw, TDBAL, (tdba & 0x00000000ffffffffULL));
- E1000_WRITE_REG(hw, TDBAH, (tdba >> 32));
E1000_WRITE_REG(hw, TDLEN, tdlen);
- E1000_WRITE_REG(hw, TDH, 0);
+ E1000_WRITE_REG(hw, TDBAH, (tdba >> 32));
+ E1000_WRITE_REG(hw, TDBAL, (tdba & 0x00000000ffffffffULL));
E1000_WRITE_REG(hw, TDT, 0);
+ E1000_WRITE_REG(hw, TDH, 0);
adapter->tx_ring[0].tdh = E1000_TDH;
adapter->tx_ring[0].tdt = E1000_TDT;
break;
@@ -1418,7 +1544,7 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter,
int size, desc_len;
size = sizeof(struct e1000_buffer) * rxdr->count;
- rxdr->buffer_info = vmalloc_node(size, pcibus_to_node(pdev->bus));
+ rxdr->buffer_info = vmalloc(size);
if (!rxdr->buffer_info) {
DPRINTK(PROBE, ERR,
"Unable to allocate memory for the receive descriptor ring\n");
@@ -1560,9 +1686,6 @@ e1000_setup_rctl(struct e1000_adapter *adapter)
E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
(adapter->hw.mc_filter_type << E1000_RCTL_MO_SHIFT);
- if (adapter->hw.mac_type > e1000_82543)
- rctl |= E1000_RCTL_SECRC;
-
if (adapter->hw.tbi_compatibility_on == 1)
rctl |= E1000_RCTL_SBP;
else
@@ -1628,7 +1751,7 @@ e1000_setup_rctl(struct e1000_adapter *adapter)
rfctl |= E1000_RFCTL_IPV6_DIS;
E1000_WRITE_REG(&adapter->hw, RFCTL, rfctl);
- rctl |= E1000_RCTL_DTYP_PS | E1000_RCTL_SECRC;
+ rctl |= E1000_RCTL_DTYP_PS;
psrctl |= adapter->rx_ps_bsize0 >>
E1000_PSRCTL_BSIZE0_SHIFT;
@@ -1712,11 +1835,11 @@ e1000_configure_rx(struct e1000_adapter *adapter)
case 1:
default:
rdba = adapter->rx_ring[0].dma;
- E1000_WRITE_REG(hw, RDBAL, (rdba & 0x00000000ffffffffULL));
- E1000_WRITE_REG(hw, RDBAH, (rdba >> 32));
E1000_WRITE_REG(hw, RDLEN, rdlen);
- E1000_WRITE_REG(hw, RDH, 0);
+ E1000_WRITE_REG(hw, RDBAH, (rdba >> 32));
+ E1000_WRITE_REG(hw, RDBAL, (rdba & 0x00000000ffffffffULL));
E1000_WRITE_REG(hw, RDT, 0);
+ E1000_WRITE_REG(hw, RDH, 0);
adapter->rx_ring[0].rdh = E1000_RDH;
adapter->rx_ring[0].rdt = E1000_RDT;
break;
@@ -1741,9 +1864,6 @@ e1000_configure_rx(struct e1000_adapter *adapter)
E1000_WRITE_REG(hw, RXCSUM, rxcsum);
}
- if (hw->mac_type == e1000_82573)
- E1000_WRITE_REG(hw, ERT, 0x0100);
-
/* Enable Receives */
E1000_WRITE_REG(hw, RCTL, rctl);
}
@@ -2083,6 +2203,12 @@ e1000_set_multi(struct net_device *netdev)
uint32_t rctl;
uint32_t hash_value;
int i, rar_entries = E1000_RAR_ENTRIES;
+ int mta_reg_count = (hw->mac_type == e1000_ich8lan) ?
+ E1000_NUM_MTA_REGISTERS_ICH8LAN :
+ E1000_NUM_MTA_REGISTERS;
+
+ if (adapter->hw.mac_type == e1000_ich8lan)
+ rar_entries = E1000_RAR_ENTRIES_ICH8LAN;
/* reserve RAR[14] for LAA over-write work-around */
if (adapter->hw.mac_type == e1000_82571)
@@ -2121,14 +2247,18 @@ e1000_set_multi(struct net_device *netdev)
mc_ptr = mc_ptr->next;
} else {
E1000_WRITE_REG_ARRAY(hw, RA, i << 1, 0);
+ E1000_WRITE_FLUSH(hw);
E1000_WRITE_REG_ARRAY(hw, RA, (i << 1) + 1, 0);
+ E1000_WRITE_FLUSH(hw);
}
}
/* clear the old settings from the multicast hash table */
- for (i = 0; i < E1000_NUM_MTA_REGISTERS; i++)
+ for (i = 0; i < mta_reg_count; i++) {
E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
+ E1000_WRITE_FLUSH(hw);
+ }
/* load any remaining addresses into the hash table */
@@ -2201,19 +2331,19 @@ static void
e1000_watchdog(unsigned long data)
{
struct e1000_adapter *adapter = (struct e1000_adapter *) data;
-
- /* Do the rest outside of interrupt context */
- schedule_work(&adapter->watchdog_task);
-}
-
-static void
-e1000_watchdog_task(struct e1000_adapter *adapter)
-{
struct net_device *netdev = adapter->netdev;
struct e1000_tx_ring *txdr = adapter->tx_ring;
uint32_t link, tctl;
-
- e1000_check_for_link(&adapter->hw);
+ int32_t ret_val;
+
+ ret_val = e1000_check_for_link(&adapter->hw);
+ if ((ret_val == E1000_ERR_PHY) &&
+ (adapter->hw.phy_type == e1000_phy_igp_3) &&
+ (E1000_READ_REG(&adapter->hw, CTRL) & E1000_PHY_CTRL_GBE_DISABLE)) {
+ /* See e1000_kumeran_lock_loss_workaround() */
+ DPRINTK(LINK, INFO,
+ "Gigabit has been disabled, downgrading speed\n");
+ }
if (adapter->hw.mac_type == e1000_82573) {
e1000_enable_tx_pkt_filtering(&adapter->hw);
if (adapter->mng_vlan_id != adapter->hw.mng_cookie.vlan_id)
@@ -2394,7 +2524,7 @@ e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
uint8_t ipcss, ipcso, tucss, tucso, hdr_len;
int err;
- if (skb_shinfo(skb)->gso_size) {
+ if (skb_is_gso(skb)) {
if (skb_header_cloned(skb)) {
err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
if (err)
@@ -2519,7 +2649,7 @@ e1000_tx_map(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
* tso gets written back prematurely before the data is fully
* DMA'd to the controller */
if (!skb->data_len && tx_ring->last_tx_tso &&
- !skb_shinfo(skb)->gso_size) {
+ !skb_is_gso(skb)) {
tx_ring->last_tx_tso = 0;
size -= 4;
}
@@ -2779,9 +2909,10 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
case e1000_82571:
case e1000_82572:
case e1000_82573:
+ case e1000_ich8lan:
pull_size = min((unsigned int)4, skb->data_len);
if (!__pskb_pull_tail(skb, pull_size)) {
- printk(KERN_ERR
+ DPRINTK(DRV, ERR,
"__pskb_pull_tail failed.\n");
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
@@ -2806,8 +2937,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
#ifdef NETIF_F_TSO
/* Controller Erratum workaround */
- if (!skb->data_len && tx_ring->last_tx_tso &&
- !skb_shinfo(skb)->gso_size)
+ if (!skb->data_len && tx_ring->last_tx_tso && !skb_is_gso(skb))
count++;
#endif
@@ -2919,8 +3049,7 @@ e1000_reset_task(struct net_device *netdev)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
- e1000_down(adapter);
- e1000_up(adapter);
+ e1000_reinit_locked(adapter);
}
/**
@@ -2964,6 +3093,7 @@ e1000_change_mtu(struct net_device *netdev, int new_mtu)
/* Adapter-specific max frame size limits. */
switch (adapter->hw.mac_type) {
case e1000_undefined ... e1000_82542_rev2_1:
+ case e1000_ich8lan:
if (max_frame > MAXIMUM_ETHERNET_FRAME_SIZE) {
DPRINTK(PROBE, ERR, "Jumbo Frames not supported.\n");
return -EINVAL;
@@ -2997,7 +3127,7 @@ e1000_change_mtu(struct net_device *netdev, int new_mtu)
break;
}
- /* NOTE: dev_alloc_skb reserves 16 bytes, and typically NET_IP_ALIGN
+ /* NOTE: netdev_alloc_skb reserves 16 bytes, and typically NET_IP_ALIGN
* means we reserve 2 more, this pushes us to allocate from the next
* larger slab size
* i.e. RXBUFFER_2048 --> size-4096 slab */
@@ -3018,7 +3148,6 @@ e1000_change_mtu(struct net_device *netdev, int new_mtu)
adapter->rx_buffer_len = E1000_RXBUFFER_16384;
/* adjust allocation if LPE protects us, and we aren't using SBP */
-#define MAXIMUM_ETHERNET_VLAN_SIZE 1522
if (!adapter->hw.tbi_compatibility_on &&
((max_frame == MAXIMUM_ETHERNET_FRAME_SIZE) ||
(max_frame == MAXIMUM_ETHERNET_VLAN_SIZE)))
@@ -3026,10 +3155,8 @@ e1000_change_mtu(struct net_device *netdev, int new_mtu)
netdev->mtu = new_mtu;
- if (netif_running(netdev)) {
- e1000_down(adapter);
- e1000_up(adapter);
- }
+ if (netif_running(netdev))
+ e1000_reinit_locked(adapter);
adapter->hw.max_frame_size = max_frame;
@@ -3074,12 +3201,15 @@ e1000_update_stats(struct e1000_adapter *adapter)
adapter->stats.bprc += E1000_READ_REG(hw, BPRC);
adapter->stats.mprc += E1000_READ_REG(hw, MPRC);
adapter->stats.roc += E1000_READ_REG(hw, ROC);
+
+ if (adapter->hw.mac_type != e1000_ich8lan) {
adapter->stats.prc64 += E1000_READ_REG(hw, PRC64);
adapter->stats.prc127 += E1000_READ_REG(hw, PRC127);
adapter->stats.prc255 += E1000_READ_REG(hw, PRC255);
adapter->stats.prc511 += E1000_READ_REG(hw, PRC511);
adapter->stats.prc1023 += E1000_READ_REG(hw, PRC1023);
adapter->stats.prc1522 += E1000_READ_REG(hw, PRC1522);
+ }
adapter->stats.symerrs += E1000_READ_REG(hw, SYMERRS);
adapter->stats.mpc += E1000_READ_REG(hw, MPC);
@@ -3107,12 +3237,16 @@ e1000_update_stats(struct e1000_adapter *adapter)
adapter->stats.totl += E1000_READ_REG(hw, TOTL);
adapter->stats.toth += E1000_READ_REG(hw, TOTH);
adapter->stats.tpr += E1000_READ_REG(hw, TPR);
+
+ if (adapter->hw.mac_type != e1000_ich8lan) {
adapter->stats.ptc64 += E1000_READ_REG(hw, PTC64);
adapter->stats.ptc127 += E1000_READ_REG(hw, PTC127);
adapter->stats.ptc255 += E1000_READ_REG(hw, PTC255);
adapter->stats.ptc511 += E1000_READ_REG(hw, PTC511);
adapter->stats.ptc1023 += E1000_READ_REG(hw, PTC1023);
adapter->stats.ptc1522 += E1000_READ_REG(hw, PTC1522);
+ }
+
adapter->stats.mptc += E1000_READ_REG(hw, MPTC);
adapter->stats.bptc += E1000_READ_REG(hw, BPTC);
@@ -3134,6 +3268,8 @@ e1000_update_stats(struct e1000_adapter *adapter)
if (hw->mac_type > e1000_82547_rev_2) {
adapter->stats.iac += E1000_READ_REG(hw, IAC);
adapter->stats.icrxoc += E1000_READ_REG(hw, ICRXOC);
+
+ if (adapter->hw.mac_type != e1000_ich8lan) {
adapter->stats.icrxptc += E1000_READ_REG(hw, ICRXPTC);
adapter->stats.icrxatc += E1000_READ_REG(hw, ICRXATC);
adapter->stats.ictxptc += E1000_READ_REG(hw, ICTXPTC);
@@ -3141,6 +3277,7 @@ e1000_update_stats(struct e1000_adapter *adapter)
adapter->stats.ictxqec += E1000_READ_REG(hw, ICTXQEC);
adapter->stats.ictxqmtc += E1000_READ_REG(hw, ICTXQMTC);
adapter->stats.icrxdmtc += E1000_READ_REG(hw, ICRXDMTC);
+ }
}
/* Fill out the OS statistics structure */
@@ -3249,8 +3386,8 @@ e1000_intr(int irq, void *data, struct pt_regs *regs)
E1000_WRITE_REG(hw, IMC, ~0);
E1000_WRITE_FLUSH(hw);
}
- if (likely(netif_rx_schedule_prep(&adapter->polling_netdev[0])))
- __netif_rx_schedule(&adapter->polling_netdev[0]);
+ if (likely(netif_rx_schedule_prep(netdev)))
+ __netif_rx_schedule(netdev);
else
e1000_irq_enable(adapter);
#else
@@ -3293,34 +3430,26 @@ e1000_clean(struct net_device *poll_dev, int *budget)
{
struct e1000_adapter *adapter;
int work_to_do = min(*budget, poll_dev->quota);
- int tx_cleaned = 0, i = 0, work_done = 0;
+ int tx_cleaned = 0, work_done = 0;
/* Must NOT use netdev_priv macro here. */
adapter = poll_dev->priv;
/* Keep link state information with original netdev */
- if (!netif_carrier_ok(adapter->netdev))
+ if (!netif_carrier_ok(poll_dev))
goto quit_polling;
- while (poll_dev != &adapter->polling_netdev[i]) {
- i++;
- BUG_ON(i == adapter->num_rx_queues);
+ /* e1000_clean is called per-cpu. This lock protects
+ * tx_ring[0] from being cleaned by multiple cpus
+ * simultaneously. A failure obtaining the lock means
+ * tx_ring[0] is currently being cleaned anyway. */
+ if (spin_trylock(&adapter->tx_queue_lock)) {
+ tx_cleaned = e1000_clean_tx_irq(adapter,
+ &adapter->tx_ring[0]);
+ spin_unlock(&adapter->tx_queue_lock);
}
- if (likely(adapter->num_tx_queues == 1)) {
- /* e1000_clean is called per-cpu. This lock protects
- * tx_ring[0] from being cleaned by multiple cpus
- * simultaneously. A failure obtaining the lock means
- * tx_ring[0] is currently being cleaned anyway. */
- if (spin_trylock(&adapter->tx_queue_lock)) {
- tx_cleaned = e1000_clean_tx_irq(adapter,
- &adapter->tx_ring[0]);
- spin_unlock(&adapter->tx_queue_lock);
- }
- } else
- tx_cleaned = e1000_clean_tx_irq(adapter, &adapter->tx_ring[i]);
-
- adapter->clean_rx(adapter, &adapter->rx_ring[i],
+ adapter->clean_rx(adapter, &adapter->rx_ring[0],
&work_done, work_to_do);
*budget -= work_done;
@@ -3328,7 +3457,7 @@ e1000_clean(struct net_device *poll_dev, int *budget)
/* If no Tx and not enough Rx work done, exit the polling mode */
if ((!tx_cleaned && (work_done == 0)) ||
- !netif_running(adapter->netdev)) {
+ !netif_running(poll_dev)) {
quit_polling:
netif_rx_complete(poll_dev);
e1000_irq_enable(adapter);
@@ -3543,11 +3672,15 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter,
length = le16_to_cpu(rx_desc->length);
+ /* adjust length to remove Ethernet CRC */
+ length -= 4;
+
if (unlikely(!(status & E1000_RXD_STAT_EOP))) {
/* All receives must fit into a single buffer */
E1000_DBG("%s: Receive packet consumed multiple"
" buffers\n", netdev->name);
- dev_kfree_skb_irq(skb);
+ /* recycle */
+ buffer_info-> skb = skb;
goto next_desc;
}
@@ -3575,7 +3708,7 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter,
#define E1000_CB_LENGTH 256
if (length < E1000_CB_LENGTH) {
struct sk_buff *new_skb =
- dev_alloc_skb(length + NET_IP_ALIGN);
+ netdev_alloc_skb(netdev, length + NET_IP_ALIGN);
if (new_skb) {
skb_reserve(new_skb, NET_IP_ALIGN);
new_skb->dev = netdev;
@@ -3675,7 +3808,6 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
buffer_info = &rx_ring->buffer_info[i];
while (staterr & E1000_RXD_STAT_DD) {
- buffer_info = &rx_ring->buffer_info[i];
ps_page = &rx_ring->ps_page[i];
ps_page_dma = &rx_ring->ps_page_dma[i];
#ifdef CONFIG_E1000_NAPI
@@ -3747,8 +3879,9 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
pci_dma_sync_single_for_device(pdev,
ps_page_dma->ps_page_dma[0],
PAGE_SIZE, PCI_DMA_FROMDEVICE);
+ /* remove the CRC */
+ l1 -= 4;
skb_put(skb, l1);
- length += l1;
goto copydone;
} /* if */
}
@@ -3767,6 +3900,10 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
skb->truesize += length;
}
+ /* strip the ethernet crc, problem is we're using pages now so
+ * this whole operation can get a little cpu intensive */
+ pskb_trim(skb, skb->len - 4);
+
copydone:
e1000_rx_checksum(adapter, staterr,
le16_to_cpu(rx_desc->wb.lower.hi_dword.csum_ip.csum), skb);
@@ -3842,7 +3979,7 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
while (cleaned_count--) {
if (!(skb = buffer_info->skb))
- skb = dev_alloc_skb(bufsz);
+ skb = netdev_alloc_skb(netdev, bufsz);
else {
skb_trim(skb, 0);
goto map_skb;
@@ -3860,7 +3997,7 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
DPRINTK(RX_ERR, ERR, "skb align check failed: %u bytes "
"at %p\n", bufsz, skb->data);
/* Try again, without freeing the previous */
- skb = dev_alloc_skb(bufsz);
+ skb = netdev_alloc_skb(netdev, bufsz);
/* Failed allocation, critical failure */
if (!skb) {
dev_kfree_skb(oldskb);
@@ -3984,7 +4121,8 @@ e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
rx_desc->read.buffer_addr[j+1] = ~0;
}
- skb = dev_alloc_skb(adapter->rx_ps_bsize0 + NET_IP_ALIGN);
+ skb = netdev_alloc_skb(netdev,
+ adapter->rx_ps_bsize0 + NET_IP_ALIGN);
if (unlikely(!skb)) {
adapter->alloc_rx_buff_failed++;
@@ -4180,10 +4318,9 @@ e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
return retval;
}
}
- if (netif_running(adapter->netdev)) {
- e1000_down(adapter);
- e1000_up(adapter);
- } else
+ if (netif_running(adapter->netdev))
+ e1000_reinit_locked(adapter);
+ else
e1000_reset(adapter);
break;
case M88E1000_PHY_SPEC_CTRL:
@@ -4200,10 +4337,9 @@ e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
case PHY_CTRL:
if (mii_reg & MII_CR_POWER_DOWN)
break;
- if (netif_running(adapter->netdev)) {
- e1000_down(adapter);
- e1000_up(adapter);
- } else
+ if (netif_running(adapter->netdev))
+ e1000_reinit_locked(adapter);
+ else
e1000_reset(adapter);
break;
}
@@ -4277,18 +4413,21 @@ e1000_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
ctrl |= E1000_CTRL_VME;
E1000_WRITE_REG(&adapter->hw, CTRL, ctrl);
+ if (adapter->hw.mac_type != e1000_ich8lan) {
/* enable VLAN receive filtering */
rctl = E1000_READ_REG(&adapter->hw, RCTL);
rctl |= E1000_RCTL_VFE;
rctl &= ~E1000_RCTL_CFIEN;
E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
e1000_update_mng_vlan(adapter);
+ }
} else {
/* disable VLAN tag insert/strip */
ctrl = E1000_READ_REG(&adapter->hw, CTRL);
ctrl &= ~E1000_CTRL_VME;
E1000_WRITE_REG(&adapter->hw, CTRL, ctrl);
+ if (adapter->hw.mac_type != e1000_ich8lan) {
/* disable VLAN filtering */
rctl = E1000_READ_REG(&adapter->hw, RCTL);
rctl &= ~E1000_RCTL_VFE;
@@ -4297,6 +4436,7 @@ e1000_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id);
adapter->mng_vlan_id = E1000_MNG_VLAN_NONE;
}
+ }
}
e1000_irq_enable(adapter);
@@ -4458,12 +4598,16 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state)
struct e1000_adapter *adapter = netdev_priv(netdev);
uint32_t ctrl, ctrl_ext, rctl, manc, status;
uint32_t wufc = adapter->wol;
+#ifdef CONFIG_PM
int retval = 0;
+#endif
netif_device_detach(netdev);
- if (netif_running(netdev))
+ if (netif_running(netdev)) {
+ WARN_ON(test_bit(__E1000_RESETTING, &adapter->flags));
e1000_down(adapter);
+ }
#ifdef CONFIG_PM
/* Implement our own version of pci_save_state(pdev) because pci-
@@ -4521,7 +4665,9 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state)
pci_enable_wake(pdev, PCI_D3cold, 0);
}
+ /* FIXME: this code is incorrect for PCI Express */
if (adapter->hw.mac_type >= e1000_82540 &&
+ adapter->hw.mac_type != e1000_ich8lan &&
adapter->hw.media_type == e1000_media_type_copper) {
manc = E1000_READ_REG(&adapter->hw, MANC);
if (manc & E1000_MANC_SMBUS_EN) {
@@ -4532,6 +4678,9 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state)
}
}
+ if (adapter->hw.phy_type == e1000_phy_igp_3)
+ e1000_phy_powerdown_workaround(&adapter->hw);
+
/* Release control of h/w to f/w. If f/w is AMT enabled, this
* would have already happened in close and is redundant. */
e1000_release_hw_control(adapter);
@@ -4567,7 +4716,9 @@ e1000_resume(struct pci_dev *pdev)
netif_device_attach(netdev);
+ /* FIXME: this code is incorrect for PCI Express */
if (adapter->hw.mac_type >= e1000_82540 &&
+ adapter->hw.mac_type != e1000_ich8lan &&
adapter->hw.media_type == e1000_media_type_copper) {
manc = E1000_READ_REG(&adapter->hw, MANC);
manc &= ~(E1000_MANC_ARP_EN);
@@ -4601,6 +4752,7 @@ static void
e1000_netpoll(struct net_device *netdev)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
+
disable_irq(adapter->pdev->irq);
e1000_intr(adapter->pdev->irq, netdev, NULL);
e1000_clean_tx_irq(adapter, adapter->tx_ring);
diff --git a/drivers/net/e1000/e1000_osdep.h b/drivers/net/e1000/e1000_osdep.h
index 048d052be29..2d3e8b06cab 100644
--- a/drivers/net/e1000/e1000_osdep.h
+++ b/drivers/net/e1000/e1000_osdep.h
@@ -127,4 +127,17 @@ typedef enum {
#define E1000_WRITE_FLUSH(a) E1000_READ_REG(a, STATUS)
+#define E1000_WRITE_ICH8_REG(a, reg, value) ( \
+ writel((value), ((a)->flash_address + reg)))
+
+#define E1000_READ_ICH8_REG(a, reg) ( \
+ readl((a)->flash_address + reg))
+
+#define E1000_WRITE_ICH8_REG16(a, reg, value) ( \
+ writew((value), ((a)->flash_address + reg)))
+
+#define E1000_READ_ICH8_REG16(a, reg) ( \
+ readw((a)->flash_address + reg))
+
+
#endif /* _E1000_OSDEP_H_ */
diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c
index e55f8969a0f..0ef413172c6 100644
--- a/drivers/net/e1000/e1000_param.c
+++ b/drivers/net/e1000/e1000_param.c
@@ -45,6 +45,16 @@
*/
#define E1000_PARAM_INIT { [0 ... E1000_MAX_NIC] = OPTION_UNSET }
+/* Module Parameters are always initialized to -1, so that the driver
+ * can tell the difference between no user specified value or the
+ * user asking for the default value.
+ * The true default values are loaded in when e1000_check_options is called.
+ *
+ * This is a GCC extension to ANSI C.
+ * See the item "Labeled Elements in Initializers" in the section
+ * "Extensions to the C Language Family" of the GCC documentation.
+ */
+
#define E1000_PARAM(X, desc) \
static int __devinitdata X[E1000_MAX_NIC+1] = E1000_PARAM_INIT; \
static int num_##X = 0; \
@@ -183,6 +193,24 @@ E1000_PARAM(RxAbsIntDelay, "Receive Absolute Interrupt Delay");
E1000_PARAM(InterruptThrottleRate, "Interrupt Throttling Rate");
+/* Enable Smart Power Down of the PHY
+ *
+ * Valid Range: 0, 1
+ *
+ * Default Value: 0 (disabled)
+ */
+
+E1000_PARAM(SmartPowerDownEnable, "Enable PHY smart power down");
+
+/* Enable Kumeran Lock Loss workaround
+ *
+ * Valid Range: 0, 1
+ *
+ * Default Value: 1 (enabled)
+ */
+
+E1000_PARAM(KumeranLockLoss, "Enable Kumeran lock loss workaround");
+
#define AUTONEG_ADV_DEFAULT 0x2F
#define AUTONEG_ADV_MASK 0x2F
#define FLOW_CONTROL_DEFAULT FLOW_CONTROL_FULL
@@ -296,6 +324,7 @@ e1000_check_options(struct e1000_adapter *adapter)
DPRINTK(PROBE, NOTICE,
"Warning: no configuration for board #%i\n", bd);
DPRINTK(PROBE, NOTICE, "Using defaults for all values\n");
+ bd = E1000_MAX_NIC;
}
{ /* Transmit Descriptor Count */
@@ -313,14 +342,9 @@ e1000_check_options(struct e1000_adapter *adapter)
opt.arg.r.max = mac_type < e1000_82544 ?
E1000_MAX_TXD : E1000_MAX_82544_TXD;
- if (num_TxDescriptors > bd) {
- tx_ring->count = TxDescriptors[bd];
- e1000_validate_option(&tx_ring->count, &opt, adapter);
- E1000_ROUNDUP(tx_ring->count,
- REQ_TX_DESCRIPTOR_MULTIPLE);
- } else {
- tx_ring->count = opt.def;
- }
+ tx_ring->count = TxDescriptors[bd];
+ e1000_validate_option(&tx_ring->count, &opt, adapter);
+ E1000_ROUNDUP(tx_ring->count, REQ_TX_DESCRIPTOR_MULTIPLE);
for (i = 0; i < adapter->num_tx_queues; i++)
tx_ring[i].count = tx_ring->count;
}
@@ -339,14 +363,9 @@ e1000_check_options(struct e1000_adapter *adapter)
opt.arg.r.max = mac_type < e1000_82544 ? E1000_MAX_RXD :
E1000_MAX_82544_RXD;
- if (num_RxDescriptors > bd) {
- rx_ring->count = RxDescriptors[bd];
- e1000_validate_option(&rx_ring->count, &opt, adapter);
- E1000_ROUNDUP(rx_ring->count,
- REQ_RX_DESCRIPTOR_MULTIPLE);
- } else {
- rx_ring->count = opt.def;
- }
+ rx_ring->count = RxDescriptors[bd];
+ e1000_validate_option(&rx_ring->count, &opt, adapter);
+ E1000_ROUNDUP(rx_ring->count, REQ_RX_DESCRIPTOR_MULTIPLE);
for (i = 0; i < adapter->num_rx_queues; i++)
rx_ring[i].count = rx_ring->count;
}
@@ -358,13 +377,9 @@ e1000_check_options(struct e1000_adapter *adapter)
.def = OPTION_ENABLED
};
- if (num_XsumRX > bd) {
- int rx_csum = XsumRX[bd];
- e1000_validate_option(&rx_csum, &opt, adapter);
- adapter->rx_csum = rx_csum;
- } else {
- adapter->rx_csum = opt.def;
- }
+ int rx_csum = XsumRX[bd];
+ e1000_validate_option(&rx_csum, &opt, adapter);
+ adapter->rx_csum = rx_csum;
}
{ /* Flow Control */
@@ -384,13 +399,9 @@ e1000_check_options(struct e1000_adapter *adapter)
.p = fc_list }}
};
- if (num_FlowControl > bd) {
- int fc = FlowControl[bd];
- e1000_validate_option(&fc, &opt, adapter);
- adapter->hw.fc = adapter->hw.original_fc = fc;
- } else {
- adapter->hw.fc = adapter->hw.original_fc = opt.def;
- }
+ int fc = FlowControl[bd];
+ e1000_validate_option(&fc, &opt, adapter);
+ adapter->hw.fc = adapter->hw.original_fc = fc;
}
{ /* Transmit Interrupt Delay */
struct e1000_option opt = {
@@ -402,13 +413,8 @@ e1000_check_options(struct e1000_adapter *adapter)
.max = MAX_TXDELAY }}
};
- if (num_TxIntDelay > bd) {
- adapter->tx_int_delay = TxIntDelay[bd];
- e1000_validate_option(&adapter->tx_int_delay, &opt,
- adapter);
- } else {
- adapter->tx_int_delay = opt.def;
- }
+ adapter->tx_int_delay = TxIntDelay[bd];
+ e1000_validate_option(&adapter->tx_int_delay, &opt, adapter);
}
{ /* Transmit Absolute Interrupt Delay */
struct e1000_option opt = {
@@ -420,13 +426,9 @@ e1000_check_options(struct e1000_adapter *adapter)
.max = MAX_TXABSDELAY }}
};
- if (num_TxAbsIntDelay > bd) {
- adapter->tx_abs_int_delay = TxAbsIntDelay[bd];
- e1000_validate_option(&adapter->tx_abs_int_delay, &opt,
- adapter);
- } else {
- adapter->tx_abs_int_delay = opt.def;
- }
+ adapter->tx_abs_int_delay = TxAbsIntDelay[bd];
+ e1000_validate_option(&adapter->tx_abs_int_delay, &opt,
+ adapter);
}
{ /* Receive Interrupt Delay */
struct e1000_option opt = {
@@ -438,13 +440,8 @@ e1000_check_options(struct e1000_adapter *adapter)
.max = MAX_RXDELAY }}
};
- if (num_RxIntDelay > bd) {
- adapter->rx_int_delay = RxIntDelay[bd];
- e1000_validate_option(&adapter->rx_int_delay, &opt,
- adapter);
- } else {
- adapter->rx_int_delay = opt.def;
- }
+ adapter->rx_int_delay = RxIntDelay[bd];
+ e1000_validate_option(&adapter->rx_int_delay, &opt, adapter);
}
{ /* Receive Absolute Interrupt Delay */
struct e1000_option opt = {
@@ -456,13 +453,9 @@ e1000_check_options(struct e1000_adapter *adapter)
.max = MAX_RXABSDELAY }}
};
- if (num_RxAbsIntDelay > bd) {
- adapter->rx_abs_int_delay = RxAbsIntDelay[bd];
- e1000_validate_option(&adapter->rx_abs_int_delay, &opt,
- adapter);
- } else {
- adapter->rx_abs_int_delay = opt.def;
- }
+ adapter->rx_abs_int_delay = RxAbsIntDelay[bd];
+ e1000_validate_option(&adapter->rx_abs_int_delay, &opt,
+ adapter);
}
{ /* Interrupt Throttling Rate */
struct e1000_option opt = {
@@ -474,26 +467,44 @@ e1000_check_options(struct e1000_adapter *adapter)
.max = MAX_ITR }}
};
- if (num_InterruptThrottleRate > bd) {
- adapter->itr = InterruptThrottleRate[bd];
- switch (adapter->itr) {
- case 0:
- DPRINTK(PROBE, INFO, "%s turned off\n",
- opt.name);
- break;
- case 1:
- DPRINTK(PROBE, INFO, "%s set to dynamic mode\n",
- opt.name);
- break;
- default:
- e1000_validate_option(&adapter->itr, &opt,
- adapter);
- break;
- }
- } else {
- adapter->itr = opt.def;
+ adapter->itr = InterruptThrottleRate[bd];
+ switch (adapter->itr) {
+ case 0:
+ DPRINTK(PROBE, INFO, "%s turned off\n", opt.name);
+ break;
+ case 1:
+ DPRINTK(PROBE, INFO, "%s set to dynamic mode\n",
+ opt.name);
+ break;
+ default:
+ e1000_validate_option(&adapter->itr, &opt, adapter);
+ break;
}
}
+ { /* Smart Power Down */
+ struct e1000_option opt = {
+ .type = enable_option,
+ .name = "PHY Smart Power Down",
+ .err = "defaulting to Disabled",
+ .def = OPTION_DISABLED
+ };
+
+ int spd = SmartPowerDownEnable[bd];
+ e1000_validate_option(&spd, &opt, adapter);
+ adapter->smart_power_down = spd;
+ }
+ { /* Kumeran Lock Loss Workaround */
+ struct e1000_option opt = {
+ .type = enable_option,
+ .name = "Kumeran Lock Loss Workaround",
+ .err = "defaulting to Enabled",
+ .def = OPTION_ENABLED
+ };
+
+ int kmrn_lock_loss = KumeranLockLoss[bd];
+ e1000_validate_option(&kmrn_lock_loss, &opt, adapter);
+ adapter->hw.kmrn_lock_loss_workaround_disabled = !kmrn_lock_loss;
+ }
switch (adapter->hw.media_type) {
case e1000_media_type_fiber:
@@ -519,17 +530,18 @@ static void __devinit
e1000_check_fiber_options(struct e1000_adapter *adapter)
{
int bd = adapter->bd_number;
- if (num_Speed > bd) {
+ bd = bd > E1000_MAX_NIC ? E1000_MAX_NIC : bd;
+ if ((Speed[bd] != OPTION_UNSET)) {
DPRINTK(PROBE, INFO, "Speed not valid for fiber adapters, "
"parameter ignored\n");
}
- if (num_Duplex > bd) {
+ if ((Duplex[bd] != OPTION_UNSET)) {
DPRINTK(PROBE, INFO, "Duplex not valid for fiber adapters, "
"parameter ignored\n");
}
- if ((num_AutoNeg > bd) && (AutoNeg[bd] != 0x20)) {
+ if ((AutoNeg[bd] != OPTION_UNSET) && (AutoNeg[bd] != 0x20)) {
DPRINTK(PROBE, INFO, "AutoNeg other than 1000/Full is "
"not valid for fiber adapters, "
"parameter ignored\n");
@@ -548,6 +560,7 @@ e1000_check_copper_options(struct e1000_adapter *adapter)
{
int speed, dplx, an;
int bd = adapter->bd_number;
+ bd = bd > E1000_MAX_NIC ? E1000_MAX_NIC : bd;
{ /* Speed */
struct e1000_opt_list speed_list[] = {{ 0, "" },
@@ -564,12 +577,8 @@ e1000_check_copper_options(struct e1000_adapter *adapter)
.p = speed_list }}
};
- if (num_Speed > bd) {
- speed = Speed[bd];
- e1000_validate_option(&speed, &opt, adapter);
- } else {
- speed = opt.def;
- }
+ speed = Speed[bd];
+ e1000_validate_option(&speed, &opt, adapter);
}
{ /* Duplex */
struct e1000_opt_list dplx_list[] = {{ 0, "" },
@@ -591,15 +600,11 @@ e1000_check_copper_options(struct e1000_adapter *adapter)
"Speed/Duplex/AutoNeg parameter ignored.\n");
return;
}
- if (num_Duplex > bd) {
- dplx = Duplex[bd];
- e1000_validate_option(&dplx, &opt, adapter);
- } else {
- dplx = opt.def;
- }
+ dplx = Duplex[bd];
+ e1000_validate_option(&dplx, &opt, adapter);
}
- if ((num_AutoNeg > bd) && (speed != 0 || dplx != 0)) {
+ if (AutoNeg[bd] != OPTION_UNSET && (speed != 0 || dplx != 0)) {
DPRINTK(PROBE, INFO,
"AutoNeg specified along with Speed or Duplex, "
"parameter ignored\n");
@@ -648,19 +653,15 @@ e1000_check_copper_options(struct e1000_adapter *adapter)
.p = an_list }}
};
- if (num_AutoNeg > bd) {
- an = AutoNeg[bd];
- e1000_validate_option(&an, &opt, adapter);
- } else {
- an = opt.def;
- }
+ an = AutoNeg[bd];
+ e1000_validate_option(&an, &opt, adapter);
adapter->hw.autoneg_advertised = an;
}
switch (speed + dplx) {
case 0:
adapter->hw.autoneg = adapter->fc_autoneg = 1;
- if ((num_Speed > bd) && (speed != 0 || dplx != 0))
+ if (Speed[bd] != OPTION_UNSET || Duplex[bd] != OPTION_UNSET)
DPRINTK(PROBE, INFO,
"Speed and duplex autonegotiation enabled\n");
break;
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
index 2ad32754292..e445988c92e 100644
--- a/drivers/net/eepro100.c
+++ b/drivers/net/eepro100.c
@@ -555,12 +555,12 @@ static int __devinit eepro100_init_one (struct pci_dev *pdev,
if (!request_region(pci_resource_start(pdev, 1),
pci_resource_len(pdev, 1), "eepro100")) {
- printk (KERN_ERR "eepro100: cannot reserve I/O ports\n");
+ dev_err(&pdev->dev, "eepro100: cannot reserve I/O ports\n");
goto err_out_none;
}
if (!request_mem_region(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0), "eepro100")) {
- printk (KERN_ERR "eepro100: cannot reserve MMIO region\n");
+ dev_err(&pdev->dev, "eepro100: cannot reserve MMIO region\n");
goto err_out_free_pio_region;
}
@@ -573,7 +573,7 @@ static int __devinit eepro100_init_one (struct pci_dev *pdev,
ioaddr = pci_iomap(pdev, pci_bar, 0);
if (!ioaddr) {
- printk (KERN_ERR "eepro100: cannot remap IO\n");
+ dev_err(&pdev->dev, "eepro100: cannot remap IO\n");
goto err_out_free_mmio_region;
}
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index 9f3e09a3d88..a67650ccf08 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -19,62 +19,15 @@
Information and updates available at
http://www.scyld.com/network/epic100.html
+ [this link no longer provides anything useful -jgarzik]
---------------------------------------------------------------------
- Linux kernel-specific changes:
-
- LK1.1.2 (jgarzik):
- * Merge becker version 1.09 (4/08/2000)
-
- LK1.1.3:
- * Major bugfix to 1.09 driver (Francis Romieu)
-
- LK1.1.4 (jgarzik):
- * Merge becker test version 1.09 (5/29/2000)
-
- LK1.1.5:
- * Fix locking (jgarzik)
- * Limit 83c175 probe to ethernet-class PCI devices (rgooch)
-
- LK1.1.6:
- * Merge becker version 1.11
- * Move pci_enable_device before any PCI BAR len checks
-
- LK1.1.7:
- * { fill me in }
-
- LK1.1.8:
- * ethtool driver info support (jgarzik)
-
- LK1.1.9:
- * ethtool media get/set support (jgarzik)
-
- LK1.1.10:
- * revert MII transceiver init change (jgarzik)
-
- LK1.1.11:
- * implement ETHTOOL_[GS]SET, _NWAY_RST, _[GS]MSGLVL, _GLINK (jgarzik)
- * replace some MII-related magic numbers with constants
-
- LK1.1.12:
- * fix power-up sequence
-
- LK1.1.13:
- * revert version 1.1.12, power-up sequence "fix"
-
- LK1.1.14 (Kryzsztof Halasa):
- * fix spurious bad initializations
- * pound phy a la SMSC's app note on the subject
-
- AC1.1.14ac
- * fix power up/down for ethtool that broke in 1.11
-
*/
#define DRV_NAME "epic100"
-#define DRV_VERSION "1.11+LK1.1.14+AC1.1.14"
-#define DRV_RELDATE "June 2, 2004"
+#define DRV_VERSION "2.0"
+#define DRV_RELDATE "June 27, 2006"
/* The user-configurable values.
These may be modified when a driver module is loaded.*/
@@ -204,19 +157,15 @@ typedef enum {
struct epic_chip_info {
const char *name;
- int io_size; /* Needed for I/O region check or ioremap(). */
int drv_flags; /* Driver use, intended as capability flags. */
};
/* indexed by chip_t */
static const struct epic_chip_info pci_id_tbl[] = {
- { "SMSC EPIC/100 83c170",
- EPIC_TOTAL_SIZE, TYPE2_INTR | NO_MII | MII_PWRDWN },
- { "SMSC EPIC/100 83c170",
- EPIC_TOTAL_SIZE, TYPE2_INTR },
- { "SMSC EPIC/C 83c175",
- EPIC_TOTAL_SIZE, TYPE2_INTR | MII_PWRDWN },
+ { "SMSC EPIC/100 83c170", TYPE2_INTR | NO_MII | MII_PWRDWN },
+ { "SMSC EPIC/100 83c170", TYPE2_INTR },
+ { "SMSC EPIC/C 83c175", TYPE2_INTR | MII_PWRDWN },
};
@@ -385,8 +334,8 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
goto out;
irq = pdev->irq;
- if (pci_resource_len(pdev, 0) < pci_id_tbl[chip_idx].io_size) {
- printk (KERN_ERR "card %d: no PCI region space\n", card_idx);
+ if (pci_resource_len(pdev, 0) < EPIC_TOTAL_SIZE) {
+ dev_err(&pdev->dev, "no PCI region space\n");
ret = -ENODEV;
goto err_out_disable;
}
@@ -401,7 +350,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
dev = alloc_etherdev(sizeof (*ep));
if (!dev) {
- printk (KERN_ERR "card %d: no memory for eth device\n", card_idx);
+ dev_err(&pdev->dev, "no memory for eth device\n");
goto err_out_free_res;
}
SET_MODULE_OWNER(dev);
@@ -413,7 +362,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
ioaddr = pci_resource_start (pdev, 1);
ioaddr = (long) ioremap (ioaddr, pci_resource_len (pdev, 1));
if (!ioaddr) {
- printk (KERN_ERR DRV_NAME " %d: ioremap failed\n", card_idx);
+ dev_err(&pdev->dev, "ioremap failed\n");
goto err_out_free_netdev;
}
#endif
@@ -473,8 +422,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
((u16 *)dev->dev_addr)[i] = le16_to_cpu(inw(ioaddr + LAN0 + i*4));
if (debug > 2) {
- printk(KERN_DEBUG DRV_NAME "(%s): EEPROM contents\n",
- pci_name(pdev));
+ dev_printk(KERN_DEBUG, &pdev->dev, "EEPROM contents:\n");
for (i = 0; i < 64; i++)
printk(" %4.4x%s", read_eeprom(ioaddr, i),
i % 16 == 15 ? "\n" : "");
@@ -496,21 +444,23 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
int mii_status = mdio_read(dev, phy, MII_BMSR);
if (mii_status != 0xffff && mii_status != 0x0000) {
ep->phys[phy_idx++] = phy;
- printk(KERN_INFO DRV_NAME "(%s): MII transceiver #%d control "
- "%4.4x status %4.4x.\n",
- pci_name(pdev), phy, mdio_read(dev, phy, 0), mii_status);
+ dev_info(&pdev->dev,
+ "MII transceiver #%d control "
+ "%4.4x status %4.4x.\n",
+ phy, mdio_read(dev, phy, 0), mii_status);
}
}
ep->mii_phy_cnt = phy_idx;
if (phy_idx != 0) {
phy = ep->phys[0];
ep->mii.advertising = mdio_read(dev, phy, MII_ADVERTISE);
- printk(KERN_INFO DRV_NAME "(%s): Autonegotiation advertising %4.4x link "
+ dev_info(&pdev->dev,
+ "Autonegotiation advertising %4.4x link "
"partner %4.4x.\n",
- pci_name(pdev), ep->mii.advertising, mdio_read(dev, phy, 5));
+ ep->mii.advertising, mdio_read(dev, phy, 5));
} else if ( ! (ep->chip_flags & NO_MII)) {
- printk(KERN_WARNING DRV_NAME "(%s): ***WARNING***: No MII transceiver found!\n",
- pci_name(pdev));
+ dev_warn(&pdev->dev,
+ "***WARNING***: No MII transceiver found!\n");
/* Use the known PHY address of the EPII. */
ep->phys[0] = 3;
}
@@ -525,8 +475,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
/* The lower four bits are the media type. */
if (duplex) {
ep->mii.force_media = ep->mii.full_duplex = 1;
- printk(KERN_INFO DRV_NAME "(%s): Forced full duplex operation requested.\n",
- pci_name(pdev));
+ dev_info(&pdev->dev, "Forced full duplex requested.\n");
}
dev->if_port = ep->default_port = option;
diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c
index c701951dcd6..97d34fee8c1 100644
--- a/drivers/net/fealnx.c
+++ b/drivers/net/fealnx.c
@@ -124,7 +124,9 @@ MODULE_PARM_DESC(multicast_filter_limit, "fealnx maximum number of filtered mult
MODULE_PARM_DESC(options, "fealnx: Bits 0-3: media type, bit 17: full duplex");
MODULE_PARM_DESC(full_duplex, "fealnx full duplex setting(s) (1)");
-#define MIN_REGION_SIZE 136
+enum {
+ MIN_REGION_SIZE = 136,
+};
/* A chip capabilities table, matching the entries in pci_tbl[] above. */
enum chip_capability_flags {
@@ -146,14 +148,13 @@ enum phy_type_flags {
struct chip_info {
char *chip_name;
- int io_size;
int flags;
};
-static const struct chip_info skel_netdrv_tbl[] = {
- {"100/10M Ethernet PCI Adapter", 136, HAS_MII_XCVR},
- {"100/10M Ethernet PCI Adapter", 136, HAS_CHIP_XCVR},
- {"1000/100/10M Ethernet PCI Adapter", 136, HAS_MII_XCVR},
+static const struct chip_info skel_netdrv_tbl[] __devinitdata = {
+ { "100/10M Ethernet PCI Adapter", HAS_MII_XCVR },
+ { "100/10M Ethernet PCI Adapter", HAS_CHIP_XCVR },
+ { "1000/100/10M Ethernet PCI Adapter", HAS_MII_XCVR },
};
/* Offsets to the Command and Status Registers. */
@@ -504,13 +505,14 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
len = pci_resource_len(pdev, bar);
if (len < MIN_REGION_SIZE) {
- printk(KERN_ERR "%s: region size %ld too small, aborting\n",
- boardname, len);
+ dev_err(&pdev->dev,
+ "region size %ld too small, aborting\n", len);
return -ENODEV;
}
i = pci_request_regions(pdev, boardname);
- if (i) return i;
+ if (i)
+ return i;
irq = pdev->irq;
@@ -576,9 +578,9 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
if (mii_status != 0xffff && mii_status != 0x0000) {
np->phys[phy_idx++] = phy;
- printk(KERN_INFO
- "%s: MII PHY found at address %d, status "
- "0x%4.4x.\n", dev->name, phy, mii_status);
+ dev_info(&pdev->dev,
+ "MII PHY found at address %d, status "
+ "0x%4.4x.\n", phy, mii_status);
/* get phy type */
{
unsigned int data;
@@ -601,10 +603,10 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
}
np->mii_cnt = phy_idx;
- if (phy_idx == 0) {
- printk(KERN_WARNING "%s: MII PHY not found -- this device may "
- "not operate correctly.\n", dev->name);
- }
+ if (phy_idx == 0)
+ dev_warn(&pdev->dev,
+ "MII PHY not found -- this device may "
+ "not operate correctly.\n");
} else {
np->phys[0] = 32;
/* 89/6/23 add, (begin) */
@@ -630,7 +632,7 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
np->mii.full_duplex = full_duplex[card_idx];
if (np->mii.full_duplex) {
- printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name);
+ dev_info(&pdev->dev, "Media type forced to Full Duplex.\n");
/* 89/6/13 add, (begin) */
// if (np->PHYType==MarvellPHY)
if ((np->PHYType == MarvellPHY) || (np->PHYType == LevelOnePHY)) {
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 037d870712f..11b8f1b43dd 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -240,10 +240,12 @@ enum {
#define NVREG_RNDSEED_FORCE2 0x2d00
#define NVREG_RNDSEED_FORCE3 0x7400
- NvRegUnknownSetupReg1 = 0xA0,
-#define NVREG_UNKSETUP1_VAL 0x16070f
- NvRegUnknownSetupReg2 = 0xA4,
-#define NVREG_UNKSETUP2_VAL 0x16
+ NvRegTxDeferral = 0xA0,
+#define NVREG_TX_DEFERRAL_DEFAULT 0x15050f
+#define NVREG_TX_DEFERRAL_RGMII_10_100 0x16070f
+#define NVREG_TX_DEFERRAL_RGMII_1000 0x14050f
+ NvRegRxDeferral = 0xA4,
+#define NVREG_RX_DEFERRAL_DEFAULT 0x16
NvRegMacAddrA = 0xA8,
NvRegMacAddrB = 0xAC,
NvRegMulticastAddrA = 0xB0,
@@ -269,8 +271,10 @@ enum {
#define NVREG_LINKSPEED_MASK (0xFFF)
NvRegUnknownSetupReg5 = 0x130,
#define NVREG_UNKSETUP5_BIT31 (1<<31)
- NvRegUnknownSetupReg3 = 0x13c,
-#define NVREG_UNKSETUP3_VAL1 0x200010
+ NvRegTxWatermark = 0x13c,
+#define NVREG_TX_WM_DESC1_DEFAULT 0x0200010
+#define NVREG_TX_WM_DESC2_3_DEFAULT 0x1e08000
+#define NVREG_TX_WM_DESC2_3_1000 0xfe08000
NvRegTxRxControl = 0x144,
#define NVREG_TXRXCTL_KICK 0x0001
#define NVREG_TXRXCTL_BIT1 0x0002
@@ -658,7 +662,7 @@ static const struct register_test nv_registers_test[] = {
{ NvRegMisc1, 0x03c },
{ NvRegOffloadConfig, 0x03ff },
{ NvRegMulticastAddrA, 0xffffffff },
- { NvRegUnknownSetupReg3, 0x0ff },
+ { NvRegTxWatermark, 0x0ff },
{ NvRegWakeUpFlags, 0x07777 },
{ 0,0 }
};
@@ -1495,7 +1499,7 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
np->tx_skbuff[nr] = skb;
#ifdef NETIF_F_TSO
- if (skb_shinfo(skb)->gso_size)
+ if (skb_is_gso(skb))
tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->gso_size << NV_TX2_TSO_SHIFT);
else
#endif
@@ -2127,7 +2131,7 @@ static int nv_update_linkspeed(struct net_device *dev)
int newdup = np->duplex;
int mii_status;
int retval = 0;
- u32 control_1000, status_1000, phyreg, pause_flags;
+ u32 control_1000, status_1000, phyreg, pause_flags, txreg;
/* BMSR_LSTATUS is latched, read it twice:
* we want the current value.
@@ -2245,6 +2249,26 @@ set_speed:
phyreg |= PHY_1000;
writel(phyreg, base + NvRegPhyInterface);
+ if (phyreg & PHY_RGMII) {
+ if ((np->linkspeed & NVREG_LINKSPEED_MASK) == NVREG_LINKSPEED_1000)
+ txreg = NVREG_TX_DEFERRAL_RGMII_1000;
+ else
+ txreg = NVREG_TX_DEFERRAL_RGMII_10_100;
+ } else {
+ txreg = NVREG_TX_DEFERRAL_DEFAULT;
+ }
+ writel(txreg, base + NvRegTxDeferral);
+
+ if (np->desc_ver == DESC_VER_1) {
+ txreg = NVREG_TX_WM_DESC1_DEFAULT;
+ } else {
+ if ((np->linkspeed & NVREG_LINKSPEED_MASK) == NVREG_LINKSPEED_1000)
+ txreg = NVREG_TX_WM_DESC2_3_1000;
+ else
+ txreg = NVREG_TX_WM_DESC2_3_DEFAULT;
+ }
+ writel(txreg, base + NvRegTxWatermark);
+
writel(NVREG_MISC1_FORCE | ( np->duplex ? 0 : NVREG_MISC1_HD),
base + NvRegMisc1);
pci_push(base);
@@ -3910,7 +3934,10 @@ static int nv_open(struct net_device *dev)
/* 5) continue setup */
writel(np->linkspeed, base + NvRegLinkSpeed);
- writel(NVREG_UNKSETUP3_VAL1, base + NvRegUnknownSetupReg3);
+ if (np->desc_ver == DESC_VER_1)
+ writel(NVREG_TX_WM_DESC1_DEFAULT, base + NvRegTxWatermark);
+ else
+ writel(NVREG_TX_WM_DESC2_3_DEFAULT, base + NvRegTxWatermark);
writel(np->txrxctl_bits, base + NvRegTxRxControl);
writel(np->vlanctl_bits, base + NvRegVlanControl);
pci_push(base);
@@ -3932,8 +3959,8 @@ static int nv_open(struct net_device *dev)
writel(readl(base + NvRegReceiverStatus), base + NvRegReceiverStatus);
get_random_bytes(&i, sizeof(i));
writel(NVREG_RNDSEED_FORCE | (i&NVREG_RNDSEED_MASK), base + NvRegRandomSeed);
- writel(NVREG_UNKSETUP1_VAL, base + NvRegUnknownSetupReg1);
- writel(NVREG_UNKSETUP2_VAL, base + NvRegUnknownSetupReg2);
+ writel(NVREG_TX_DEFERRAL_DEFAULT, base + NvRegTxDeferral);
+ writel(NVREG_RX_DEFERRAL_DEFAULT, base + NvRegRxDeferral);
if (poll_interval == -1) {
if (optimization_mode == NV_OPTIMIZATION_MODE_THROUGHPUT)
writel(NVREG_POLL_DEFAULT_THROUGHPUT, base + NvRegPollingInterval);
diff --git a/drivers/net/gt96100eth.c b/drivers/net/gt96100eth.c
index 49dacc6e35a..2b4db741447 100644
--- a/drivers/net/gt96100eth.c
+++ b/drivers/net/gt96100eth.c
@@ -699,7 +699,6 @@ static int __init gt96100_probe1(struct pci_dev *pci, int port_num)
memset(gp, 0, sizeof(*gp)); // clear it
gp->port_num = port_num;
- gp->io_size = GT96100_ETH_IO_SIZE;
gp->port_offset = port_num * GT96100_ETH_IO_SIZE;
gp->phy_addr = phy_addr;
gp->chip_rev = chip_rev;
@@ -1531,7 +1530,7 @@ static void gt96100_cleanup_module(void)
+ sizeof(gt96100_td_t) * TX_RING_SIZE,
gp->rx_ring);
free_netdev(gtif->dev);
- release_region(gtif->iobase, gp->io_size);
+ release_region(gtif->iobase, GT96100_ETH_IO_SIZE);
}
}
}
diff --git a/drivers/net/gt96100eth.h b/drivers/net/gt96100eth.h
index 2a8331938b8..3b62a87c7d7 100644
--- a/drivers/net/gt96100eth.h
+++ b/drivers/net/gt96100eth.h
@@ -331,7 +331,6 @@ struct gt96100_private {
mib_counters_t mib;
struct net_device_stats stats;
- int io_size;
int port_num; // 0 or 1
int chip_rev;
u32 port_offset;
@@ -340,7 +339,6 @@ struct gt96100_private {
u32 last_psr; // last value of the port status register
int options; /* User-settable misc. driver options. */
- int drv_flags;
struct timer_list timer;
spinlock_t lock; /* Serialise access to device */
};
diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c
index 7bcd939c6ed..409c6aab041 100644
--- a/drivers/net/hamachi.c
+++ b/drivers/net/hamachi.c
@@ -20,22 +20,15 @@
Support and updates available at
http://www.scyld.com/network/hamachi.html
+ [link no longer provides useful info -jgarzik]
or
http://www.parl.clemson.edu/~keithu/hamachi.html
-
-
- Linux kernel changelog:
-
- LK1.0.1:
- - fix lack of pci_dev<->dev association
- - ethtool support (jgarzik)
-
*/
#define DRV_NAME "hamachi"
-#define DRV_VERSION "1.01+LK1.0.1"
-#define DRV_RELDATE "5/18/2001"
+#define DRV_VERSION "2.0"
+#define DRV_RELDATE "June 27, 2006"
/* A few user-configurable values. */
@@ -608,7 +601,8 @@ static int __devinit hamachi_init_one (struct pci_dev *pdev,
pci_set_master(pdev);
i = pci_request_regions(pdev, DRV_NAME);
- if (i) return i;
+ if (i)
+ return i;
irq = pdev->irq;
ioaddr = ioremap(base, 0x400);
diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c
index 0641f54fc63..889f338132f 100644
--- a/drivers/net/hamradio/bpqether.c
+++ b/drivers/net/hamradio/bpqether.c
@@ -122,6 +122,12 @@ struct bpqdev {
static LIST_HEAD(bpq_devices);
+/*
+ * bpqether network devices are paired with ethernet devices below them, so
+ * form a special "super class" of normal ethernet devices; split their locks
+ * off into a separate class since they always nest.
+ */
+static struct lock_class_key bpq_netdev_xmit_lock_key;
/* ------------------------------------------------------------------------ */
@@ -528,6 +534,7 @@ static int bpq_new_device(struct net_device *edev)
err = register_netdevice(ndev);
if (err)
goto error;
+ lockdep_set_class(&ndev->_xmit_lock, &bpq_netdev_xmit_lock_key);
/* List protected by RTNL */
list_add_rcu(&bpq->bpq_list, &bpq_devices);
diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c
index 3a42afab503..43e3f33ed5e 100644
--- a/drivers/net/ifb.c
+++ b/drivers/net/ifb.c
@@ -271,6 +271,7 @@ static int __init ifb_init_module(void)
for (i = 0; i < numifbs && !err; i++)
err = ifb_init_one(i);
if (err) {
+ i--;
while (--i >= 0)
ifb_free_one(i);
}
diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c
index bf1fca5a3fa..e3c8cd5eca6 100644
--- a/drivers/net/irda/ali-ircc.c
+++ b/drivers/net/irda/ali-ircc.c
@@ -146,7 +146,7 @@ static int __init ali_ircc_init(void)
{
ali_chip_t *chip;
chipio_t info;
- int ret = -ENODEV;
+ int ret;
int cfg, cfg_base;
int reg, revision;
int i = 0;
@@ -160,6 +160,7 @@ static int __init ali_ircc_init(void)
return ret;
}
+ ret = -ENODEV;
/* Probe for all the ALi chipsets we know about */
for (chip= chips; chip->name; chip++, i++)
diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c
index a4674044bd6..2eff45bedc7 100644
--- a/drivers/net/irda/smsc-ircc2.c
+++ b/drivers/net/irda/smsc-ircc2.c
@@ -2353,7 +2353,7 @@ static int __init smsc_superio_lpc(unsigned short cfg_base)
#ifdef CONFIG_PCI
#define PCIID_VENDOR_INTEL 0x8086
#define PCIID_VENDOR_ALI 0x10b9
-static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __devinitdata = {
+static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __initdata = {
{
.vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */
.device = 0x24cc,
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
index b91e082483f..7bbd447289b 100644
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ixgb/ixgb_main.c
@@ -1173,7 +1173,7 @@ ixgb_tso(struct ixgb_adapter *adapter, struct sk_buff *skb)
uint16_t ipcse, tucse, mss;
int err;
- if(likely(skb_shinfo(skb)->gso_size)) {
+ if (likely(skb_is_gso(skb))) {
if (skb_header_cloned(skb)) {
err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
if (err)
@@ -1281,7 +1281,7 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb,
while(len) {
buffer_info = &tx_ring->buffer_info[i];
- size = min(len, IXGB_MAX_JUMBO_FRAME_SIZE);
+ size = min(len, IXGB_MAX_DATA_PER_TXD);
buffer_info->length = size;
buffer_info->dma =
pci_map_single(adapter->pdev,
@@ -1306,7 +1306,7 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb,
while(len) {
buffer_info = &tx_ring->buffer_info[i];
- size = min(len, IXGB_MAX_JUMBO_FRAME_SIZE);
+ size = min(len, IXGB_MAX_DATA_PER_TXD);
buffer_info->length = size;
buffer_info->dma =
pci_map_page(adapter->pdev,
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index 43fef7de8cb..997cbce9af6 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -139,7 +139,7 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
#endif
#ifdef LOOPBACK_TSO
- if (skb_shinfo(skb)->gso_size) {
+ if (skb_is_gso(skb)) {
BUG_ON(skb->protocol != htons(ETH_P_IP));
BUG_ON(skb->nh.iph->protocol != IPPROTO_TCP);
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index 72aad42db7b..06440a86bae 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -177,6 +177,7 @@ struct myri10ge_priv {
struct work_struct watchdog_work;
struct timer_list watchdog_timer;
int watchdog_tx_done;
+ int watchdog_tx_req;
int watchdog_resets;
int tx_linearized;
int pause;
@@ -188,7 +189,6 @@ struct myri10ge_priv {
int vendor_specific_offset;
u32 devctl;
u16 msi_flags;
- u32 pm_state[16];
u32 read_dma;
u32 write_dma;
u32 read_write_dma;
@@ -449,6 +449,7 @@ static int myri10ge_load_hotplug_firmware(struct myri10ge_priv *mgp, u32 * size)
struct mcp_gen_header *hdr;
size_t hdr_offset;
int status;
+ unsigned i;
if ((status = request_firmware(&fw, mgp->fw_name, dev)) < 0) {
dev_err(dev, "Unable to load %s firmware image via hotplug\n",
@@ -480,18 +481,12 @@ static int myri10ge_load_hotplug_firmware(struct myri10ge_priv *mgp, u32 * size)
goto abort_with_fw;
crc = crc32(~0, fw->data, fw->size);
- if (mgp->tx.boundary == 2048) {
- /* Avoid PCI burst on chipset with unaligned completions. */
- int i;
- __iomem u32 *ptr = (__iomem u32 *) (mgp->sram +
- MYRI10GE_FW_OFFSET);
- for (i = 0; i < fw->size / 4; i++) {
- __raw_writel(((u32 *) fw->data)[i], ptr + i);
- wmb();
- }
- } else {
- myri10ge_pio_copy(mgp->sram + MYRI10GE_FW_OFFSET, fw->data,
- fw->size);
+ for (i = 0; i < fw->size; i += 256) {
+ myri10ge_pio_copy(mgp->sram + MYRI10GE_FW_OFFSET + i,
+ fw->data + i,
+ min(256U, (unsigned)(fw->size - i)));
+ mb();
+ readb(mgp->sram);
}
/* corruption checking is good for parity recovery and buggy chipset */
memcpy_fromio(fw->data, mgp->sram + MYRI10GE_FW_OFFSET, fw->size);
@@ -621,7 +616,7 @@ static int myri10ge_load_firmware(struct myri10ge_priv *mgp)
return -ENXIO;
}
dev_info(&mgp->pdev->dev, "handoff confirmed\n");
- myri10ge_dummy_rdma(mgp, mgp->tx.boundary != 4096);
+ myri10ge_dummy_rdma(mgp, 1);
return 0;
}
@@ -1289,6 +1284,7 @@ static const char myri10ge_gstrings_stats[][ETH_GSTRING_LEN] = {
"tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors",
"tx_heartbeat_errors", "tx_window_errors",
/* device-specific stats */
+ "tx_boundary", "WC", "irq", "MSI",
"read_dma_bw_MBs", "write_dma_bw_MBs", "read_write_dma_bw_MBs",
"serial_number", "tx_pkt_start", "tx_pkt_done",
"tx_req", "tx_done", "rx_small_cnt", "rx_big_cnt",
@@ -1327,6 +1323,10 @@ myri10ge_get_ethtool_stats(struct net_device *netdev,
for (i = 0; i < MYRI10GE_NET_STATS_LEN; i++)
data[i] = ((unsigned long *)&mgp->stats)[i];
+ data[i++] = (unsigned int)mgp->tx.boundary;
+ data[i++] = (unsigned int)(mgp->mtrr >= 0);
+ data[i++] = (unsigned int)mgp->pdev->irq;
+ data[i++] = (unsigned int)mgp->msi_enabled;
data[i++] = (unsigned int)mgp->read_dma;
data[i++] = (unsigned int)mgp->write_dma;
data[i++] = (unsigned int)mgp->read_write_dma;
@@ -2112,7 +2112,7 @@ abort_linearize:
}
idx = (idx + 1) & tx->mask;
} while (idx != last_idx);
- if (skb_shinfo(skb)->gso_size) {
+ if (skb_is_gso(skb)) {
printk(KERN_ERR
"myri10ge: %s: TSO but wanted to linearize?!?!?\n",
mgp->dev->name);
@@ -2197,8 +2197,6 @@ static int myri10ge_change_mtu(struct net_device *dev, int new_mtu)
* any other device, except if forced with myri10ge_ecrc_enable > 1.
*/
-#define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_PCIE 0x005d
-
static void myri10ge_enable_ecrc(struct myri10ge_priv *mgp)
{
struct pci_dev *bridge = mgp->pdev->bus->self;
@@ -2410,14 +2408,20 @@ static int myri10ge_resume(struct pci_dev *pdev)
return -EIO;
}
myri10ge_restore_state(mgp);
- pci_enable_device(pdev);
+
+ status = pci_enable_device(pdev);
+ if (status < 0) {
+ dev_err(&pdev->dev, "failed to enable device\n");
+ return -EIO;
+ }
+
pci_set_master(pdev);
status = request_irq(pdev->irq, myri10ge_intr, IRQF_SHARED,
netdev->name, mgp);
if (status != 0) {
dev_err(&pdev->dev, "failed to allocate IRQ\n");
- goto abort_with_msi;
+ goto abort_with_enabled;
}
myri10ge_reset(mgp);
@@ -2436,7 +2440,8 @@ static int myri10ge_resume(struct pci_dev *pdev)
return 0;
-abort_with_msi:
+abort_with_enabled:
+ pci_disable_device(pdev);
return -EIO;
}
@@ -2538,7 +2543,8 @@ static void myri10ge_watchdog_timer(unsigned long arg)
mgp = (struct myri10ge_priv *)arg;
if (mgp->tx.req != mgp->tx.done &&
- mgp->tx.done == mgp->watchdog_tx_done)
+ mgp->tx.done == mgp->watchdog_tx_done &&
+ mgp->watchdog_tx_req != mgp->watchdog_tx_done)
/* nic seems like it might be stuck.. */
schedule_work(&mgp->watchdog_work);
else
@@ -2547,6 +2553,7 @@ static void myri10ge_watchdog_timer(unsigned long arg)
jiffies + myri10ge_watchdog_timeout * HZ);
mgp->watchdog_tx_done = mgp->tx.done;
+ mgp->watchdog_tx_req = mgp->tx.req;
}
static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
@@ -2737,11 +2744,10 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
dev_err(&pdev->dev, "register_netdev failed: %d\n", status);
goto abort_with_irq;
}
-
- printk(KERN_INFO "myri10ge: %s: %s IRQ %d, tx bndry %d, fw %s, WC %s\n",
- netdev->name, (mgp->msi_enabled ? "MSI" : "xPIC"),
- pdev->irq, mgp->tx.boundary, mgp->fw_name,
- (mgp->mtrr >= 0 ? "Enabled" : "Disabled"));
+ dev_info(dev, "%s IRQ %d, tx bndry %d, fw %s, WC %s\n",
+ (mgp->msi_enabled ? "MSI" : "xPIC"),
+ pdev->irq, mgp->tx.boundary, mgp->fw_name,
+ (mgp->mtrr >= 0 ? "Enabled" : "Disabled"));
return 0;
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index 9df2628be1e..db0475a1102 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -20,120 +20,9 @@
Support information and updates available at
http://www.scyld.com/network/netsemi.html
+ [link no longer provides useful info -jgarzik]
- Linux kernel modifications:
-
- Version 1.0.1:
- - Spinlock fixes
- - Bug fixes and better intr performance (Tjeerd)
- Version 1.0.2:
- - Now reads correct MAC address from eeprom
- Version 1.0.3:
- - Eliminate redundant priv->tx_full flag
- - Call netif_start_queue from dev->tx_timeout
- - wmb() in start_tx() to flush data
- - Update Tx locking
- - Clean up PCI enable (davej)
- Version 1.0.4:
- - Merge Donald Becker's natsemi.c version 1.07
- Version 1.0.5:
- - { fill me in }
- Version 1.0.6:
- * ethtool support (jgarzik)
- * Proper initialization of the card (which sometimes
- fails to occur and leaves the card in a non-functional
- state). (uzi)
-
- * Some documented register settings to optimize some
- of the 100Mbit autodetection circuitry in rev C cards. (uzi)
-
- * Polling of the PHY intr for stuff like link state
- change and auto- negotiation to finally work properly. (uzi)
-
- * One-liner removal of a duplicate declaration of
- netdev_error(). (uzi)
-
- Version 1.0.7: (Manfred Spraul)
- * pci dma
- * SMP locking update
- * full reset added into tx_timeout
- * correct multicast hash generation (both big and little endian)
- [copied from a natsemi driver version
- from Myrio Corporation, Greg Smith]
- * suspend/resume
-
- version 1.0.8 (Tim Hockin <thockin@sun.com>)
- * ETHTOOL_* support
- * Wake on lan support (Erik Gilling)
- * MXDMA fixes for serverworks
- * EEPROM reload
-
- version 1.0.9 (Manfred Spraul)
- * Main change: fix lack of synchronize
- netif_close/netif_suspend against a last interrupt
- or packet.
- * do not enable superflous interrupts (e.g. the
- drivers relies on TxDone - TxIntr not needed)
- * wait that the hardware has really stopped in close
- and suspend.
- * workaround for the (at least) gcc-2.95.1 compiler
- problem. Also simplifies the code a bit.
- * disable_irq() in tx_timeout - needed to protect
- against rx interrupts.
- * stop the nic before switching into silent rx mode
- for wol (required according to docu).
-
- version 1.0.10:
- * use long for ee_addr (various)
- * print pointers properly (DaveM)
- * include asm/irq.h (?)
-
- version 1.0.11:
- * check and reset if PHY errors appear (Adrian Sun)
- * WoL cleanup (Tim Hockin)
- * Magic number cleanup (Tim Hockin)
- * Don't reload EEPROM on every reset (Tim Hockin)
- * Save and restore EEPROM state across reset (Tim Hockin)
- * MDIO Cleanup (Tim Hockin)
- * Reformat register offsets/bits (jgarzik)
-
- version 1.0.12:
- * ETHTOOL_* further support (Tim Hockin)
-
- version 1.0.13:
- * ETHTOOL_[G]EEPROM support (Tim Hockin)
-
- version 1.0.13:
- * crc cleanup (Matt Domsch <Matt_Domsch@dell.com>)
-
- version 1.0.14:
- * Cleanup some messages and autoneg in ethtool (Tim Hockin)
-
- version 1.0.15:
- * Get rid of cable_magic flag
- * use new (National provided) solution for cable magic issue
-
- version 1.0.16:
- * call netdev_rx() for RxErrors (Manfred Spraul)
- * formatting and cleanups
- * change options and full_duplex arrays to be zero
- initialized
- * enable only the WoL and PHY interrupts in wol mode
-
- version 1.0.17:
- * only do cable_magic on 83815 and early 83816 (Tim Hockin)
- * create a function for rx refill (Manfred Spraul)
- * combine drain_ring and init_ring (Manfred Spraul)
- * oom handling (Manfred Spraul)
- * hands_off instead of playing with netif_device_{de,a}ttach
- (Manfred Spraul)
- * be sure to write the MAC back to the chip (Manfred Spraul)
- * lengthen EEPROM timeout, and always warn about timeouts
- (Manfred Spraul)
- * comments update (Manfred)
- * do the right thing on a phy-reset (Manfred and Tim)
-
TODO:
* big endian support with CFG:BEM instead of cpu_to_le32
*/
@@ -165,8 +54,8 @@
#include <asm/uaccess.h>
#define DRV_NAME "natsemi"
-#define DRV_VERSION "1.07+LK1.0.17"
-#define DRV_RELDATE "Sep 27, 2002"
+#define DRV_VERSION "2.0"
+#define DRV_RELDATE "June 27, 2006"
#define RX_OFFSET 2
diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c
index fa50eb88940..34bdba9eec7 100644
--- a/drivers/net/ne2k-pci.c
+++ b/drivers/net/ne2k-pci.c
@@ -231,12 +231,12 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
irq = pdev->irq;
if (!ioaddr || ((pci_resource_flags (pdev, 0) & IORESOURCE_IO) == 0)) {
- printk (KERN_ERR PFX "no I/O resource at PCI BAR #0\n");
+ dev_err(&pdev->dev, "no I/O resource at PCI BAR #0\n");
return -ENODEV;
}
if (request_region (ioaddr, NE_IO_EXTENT, DRV_NAME) == NULL) {
- printk (KERN_ERR PFX "I/O resource 0x%x @ 0x%lx busy\n",
+ dev_err(&pdev->dev, "I/O resource 0x%x @ 0x%lx busy\n",
NE_IO_EXTENT, ioaddr);
return -EBUSY;
}
@@ -263,7 +263,7 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
/* Allocate net_device, dev->priv; fill in 8390 specific dev fields. */
dev = alloc_ei_netdev();
if (!dev) {
- printk (KERN_ERR PFX "cannot allocate ethernet device\n");
+ dev_err(&pdev->dev, "cannot allocate ethernet device\n");
goto err_out_free_res;
}
SET_MODULE_OWNER(dev);
@@ -281,7 +281,8 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
while ((inb(ioaddr + EN0_ISR) & ENISR_RESET) == 0)
/* Limit wait: '2' avoids jiffy roll-over. */
if (jiffies - reset_start_time > 2) {
- printk(KERN_ERR PFX "Card failure (no reset ack).\n");
+ dev_err(&pdev->dev,
+ "Card failure (no reset ack).\n");
goto err_out_free_netdev;
}
diff --git a/drivers/net/ni5010.c b/drivers/net/ni5010.c
index a68bf474f6e..d4be207d321 100644
--- a/drivers/net/ni5010.c
+++ b/drivers/net/ni5010.c
@@ -1,17 +1,12 @@
/* ni5010.c: A network driver for the MiCom-Interlan NI5010 ethercard.
*
- * Copyright 1996,1997 Jan-Pascal van Best and Andreas Mohr.
+ * Copyright 1996,1997,2006 Jan-Pascal van Best and Andreas Mohr.
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* The authors may be reached as:
- * jvbest@wi.leidenuniv.nl a.mohr@mailto.de
- * or by snail mail as
- * Jan-Pascal van Best Andreas Mohr
- * Klikspaanweg 58-4 Stauferstr. 6
- * 2324 LZ Leiden D-71272 Renningen
- * The Netherlands Germany
+ * janpascal@vanbest.org andi@lisas.de
*
* Sources:
* Donald Becker's "skeleton.c"
@@ -27,8 +22,9 @@
* 970503 v0.93: Fixed auto-irq failure on warm reboot (JB)
* 970623 v1.00: First kernel version (AM)
* 970814 v1.01: Added detection of onboard receive buffer size (AM)
+ * 060611 v1.02: slight cleanup: email addresses, driver modernization.
* Bugs:
- * - None known...
+ * - not SMP-safe (no locking of I/O accesses)
* - Note that you have to patch ifconfig for the new /proc/net/dev
* format. It gives incorrect stats otherwise.
*
@@ -39,7 +35,7 @@
* Complete merge with Andreas' driver
* Implement ring buffers (Is this useful? You can't squeeze
* too many packet in a 2k buffer!)
- * Implement DMA (Again, is this useful? Some docs says DMA is
+ * Implement DMA (Again, is this useful? Some docs say DMA is
* slower than programmed I/O)
*
* Compile with:
@@ -47,7 +43,7 @@
* -DMODULE -c ni5010.c
*
* Insert with e.g.:
- * insmod ni5010.o io=0x300 irq=5
+ * insmod ni5010.ko io=0x300 irq=5
*/
#include <linux/module.h>
@@ -69,15 +65,15 @@
#include "ni5010.h"
-static const char *boardname = "NI5010";
-static char *version =
- "ni5010.c: v1.00 06/23/97 Jan-Pascal van Best and Andreas Mohr\n";
+static const char boardname[] = "NI5010";
+static char version[] __initdata =
+ "ni5010.c: v1.02 20060611 Jan-Pascal van Best and Andreas Mohr\n";
/* bufsize_rcv == 0 means autoprobing */
static unsigned int bufsize_rcv;
-#define jumpered_interrupts /* IRQ line jumpered on board */
-#undef jumpered_dma /* No DMA used */
+#define JUMPERED_INTERRUPTS /* IRQ line jumpered on board */
+#undef JUMPERED_DMA /* No DMA used */
#undef FULL_IODETECT /* Only detect in portlist */
#ifndef FULL_IODETECT
@@ -281,7 +277,7 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr)
PRINTK2((KERN_DEBUG "%s: I/O #4 passed!\n", dev->name));
-#ifdef jumpered_interrupts
+#ifdef JUMPERED_INTERRUPTS
if (dev->irq == 0xff)
;
else if (dev->irq < 2) {
@@ -305,7 +301,7 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr)
} else if (dev->irq == 2) {
dev->irq = 9;
}
-#endif /* jumpered_irq */
+#endif /* JUMPERED_INTERRUPTS */
PRINTK2((KERN_DEBUG "%s: I/O #9 passed!\n", dev->name));
/* DMA is not supported (yet?), so no use detecting it */
@@ -334,7 +330,7 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr)
outw(0, IE_GP); /* Point GP at start of packet */
outb(0, IE_RBUF); /* set buffer byte 0 to 0 again */
}
- printk("// bufsize rcv/xmt=%d/%d\n", bufsize_rcv, NI5010_BUFSIZE);
+ printk("-> bufsize rcv/xmt=%d/%d\n", bufsize_rcv, NI5010_BUFSIZE);
memset(dev->priv, 0, sizeof(struct ni5010_local));
dev->open = ni5010_open;
@@ -354,11 +350,9 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr)
outb(0xff, EDLC_XCLR); /* Kill all pending xmt interrupts */
printk(KERN_INFO "%s: NI5010 found at 0x%x, using IRQ %d", dev->name, ioaddr, dev->irq);
- if (dev->dma) printk(" & DMA %d", dev->dma);
+ if (dev->dma)
+ printk(" & DMA %d", dev->dma);
printk(".\n");
-
- printk(KERN_INFO "Join the NI5010 driver development team!\n");
- printk(KERN_INFO "Mail to a.mohr@mailto.de or jvbest@wi.leidenuniv.nl\n");
return 0;
out:
release_region(dev->base_addr, NI5010_IO_EXTENT);
@@ -371,7 +365,7 @@ out:
*
* This routine should set everything up anew at each open, even
* registers that "should" only need to be set once at boot, so that
- * there is non-reboot way to recover if something goes wrong.
+ * there is a non-reboot way to recover if something goes wrong.
*/
static int ni5010_open(struct net_device *dev)
@@ -390,13 +384,13 @@ static int ni5010_open(struct net_device *dev)
* Always allocate the DMA channel after the IRQ,
* and clean up on failure.
*/
-#ifdef jumpered_dma
+#ifdef JUMPERED_DMA
if (request_dma(dev->dma, cardname)) {
printk(KERN_WARNING "%s: Cannot get dma %#2x\n", dev->name, dev->dma);
free_irq(dev->irq, NULL);
return -EAGAIN;
}
-#endif /* jumpered_dma */
+#endif /* JUMPERED_DMA */
PRINTK3((KERN_DEBUG "%s: passed open() #2\n", dev->name));
/* Reset the hardware here. Don't forget to set the station address. */
@@ -633,7 +627,7 @@ static int ni5010_close(struct net_device *dev)
int ioaddr = dev->base_addr;
PRINTK2((KERN_DEBUG "%s: entering ni5010_close\n", dev->name));
-#ifdef jumpered_interrupts
+#ifdef JUMPERED_INTERRUPTS
free_irq(dev->irq, NULL);
#endif
/* Put card in held-RESET state */
@@ -771,7 +765,7 @@ module_param(irq, int, 0);
MODULE_PARM_DESC(io, "ni5010 I/O base address");
MODULE_PARM_DESC(irq, "ni5010 IRQ number");
-int init_module(void)
+static int __init ni5010_init_module(void)
{
PRINTK2((KERN_DEBUG "%s: entering init_module\n", boardname));
/*
@@ -792,13 +786,15 @@ int init_module(void)
return 0;
}
-void cleanup_module(void)
+static void __exit ni5010_cleanup_module(void)
{
PRINTK2((KERN_DEBUG "%s: entering cleanup_module\n", boardname));
unregister_netdev(dev_ni5010);
release_region(dev_ni5010->base_addr, NI5010_IO_EXTENT);
free_netdev(dev_ni5010);
}
+module_init(ni5010_init_module);
+module_exit(ni5010_cleanup_module);
#endif /* MODULE */
MODULE_LICENSE("GPL");
diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c
index 70429108c40..0e76859c90a 100644
--- a/drivers/net/ns83820.c
+++ b/drivers/net/ns83820.c
@@ -803,7 +803,7 @@ static int ns83820_setup_rx(struct net_device *ndev)
writel(dev->IMR_cache, dev->base + IMR);
writel(1, dev->base + IER);
- spin_unlock_irq(&dev->misc_lock);
+ spin_unlock(&dev->misc_lock);
kick_rx(ndev);
@@ -1012,8 +1012,6 @@ static void do_tx_done(struct net_device *ndev)
struct ns83820 *dev = PRIV(ndev);
u32 cmdsts, tx_done_idx, *desc;
- spin_lock_irq(&dev->tx_lock);
-
dprintk("do_tx_done(%p)\n", ndev);
tx_done_idx = dev->tx_done_idx;
desc = dev->tx_descs + (tx_done_idx * DESC_SIZE);
@@ -1069,7 +1067,6 @@ static void do_tx_done(struct net_device *ndev)
netif_start_queue(ndev);
netif_wake_queue(ndev);
}
- spin_unlock_irq(&dev->tx_lock);
}
static void ns83820_cleanup_tx(struct ns83820 *dev)
@@ -1281,11 +1278,13 @@ static struct ethtool_ops ops = {
.get_link = ns83820_get_link
};
+/* this function is called in irq context from the ISR */
static void ns83820_mib_isr(struct ns83820 *dev)
{
- spin_lock(&dev->misc_lock);
+ unsigned long flags;
+ spin_lock_irqsave(&dev->misc_lock, flags);
ns83820_update_stats(dev);
- spin_unlock(&dev->misc_lock);
+ spin_unlock_irqrestore(&dev->misc_lock, flags);
}
static void ns83820_do_isr(struct net_device *ndev, u32 isr);
@@ -1307,6 +1306,8 @@ static irqreturn_t ns83820_irq(int foo, void *data, struct pt_regs *regs)
static void ns83820_do_isr(struct net_device *ndev, u32 isr)
{
struct ns83820 *dev = PRIV(ndev);
+ unsigned long flags;
+
#ifdef DEBUG
if (isr & ~(ISR_PHY | ISR_RXDESC | ISR_RXEARLY | ISR_RXOK | ISR_RXERR | ISR_TXIDLE | ISR_TXOK | ISR_TXDESC))
Dprintk("odd isr? 0x%08x\n", isr);
@@ -1321,10 +1322,10 @@ static void ns83820_do_isr(struct net_device *ndev, u32 isr)
if ((ISR_RXDESC | ISR_RXOK) & isr) {
prefetch(dev->rx_info.next_rx_desc);
- spin_lock_irq(&dev->misc_lock);
+ spin_lock_irqsave(&dev->misc_lock, flags);
dev->IMR_cache &= ~(ISR_RXDESC | ISR_RXOK);
writel(dev->IMR_cache, dev->base + IMR);
- spin_unlock_irq(&dev->misc_lock);
+ spin_unlock_irqrestore(&dev->misc_lock, flags);
tasklet_schedule(&dev->rx_tasklet);
//rx_irq(ndev);
@@ -1370,16 +1371,18 @@ static void ns83820_do_isr(struct net_device *ndev, u32 isr)
* work has accumulated
*/
if ((ISR_TXDESC | ISR_TXIDLE | ISR_TXOK | ISR_TXERR) & isr) {
+ spin_lock_irqsave(&dev->tx_lock, flags);
do_tx_done(ndev);
+ spin_unlock_irqrestore(&dev->tx_lock, flags);
/* Disable TxOk if there are no outstanding tx packets.
*/
if ((dev->tx_done_idx == dev->tx_free_idx) &&
(dev->IMR_cache & ISR_TXOK)) {
- spin_lock_irq(&dev->misc_lock);
+ spin_lock_irqsave(&dev->misc_lock, flags);
dev->IMR_cache &= ~ISR_TXOK;
writel(dev->IMR_cache, dev->base + IMR);
- spin_unlock_irq(&dev->misc_lock);
+ spin_unlock_irqrestore(&dev->misc_lock, flags);
}
}
@@ -1390,10 +1393,10 @@ static void ns83820_do_isr(struct net_device *ndev, u32 isr)
* nature are expected, we must enable TxOk.
*/
if ((ISR_TXIDLE & isr) && (dev->tx_done_idx != dev->tx_free_idx)) {
- spin_lock_irq(&dev->misc_lock);
+ spin_lock_irqsave(&dev->misc_lock, flags);
dev->IMR_cache |= ISR_TXOK;
writel(dev->IMR_cache, dev->base + IMR);
- spin_unlock_irq(&dev->misc_lock);
+ spin_unlock_irqrestore(&dev->misc_lock, flags);
}
/* MIB interrupt: one of the statistics counters is about to overflow */
@@ -1455,7 +1458,7 @@ static void ns83820_tx_timeout(struct net_device *ndev)
u32 tx_done_idx, *desc;
unsigned long flags;
- local_irq_save(flags);
+ spin_lock_irqsave(&dev->tx_lock, flags);
tx_done_idx = dev->tx_done_idx;
desc = dev->tx_descs + (tx_done_idx * DESC_SIZE);
@@ -1482,7 +1485,7 @@ static void ns83820_tx_timeout(struct net_device *ndev)
ndev->name,
tx_done_idx, dev->tx_free_idx, le32_to_cpu(desc[DESC_CMDSTS]));
- local_irq_restore(flags);
+ spin_unlock_irqrestore(&dev->tx_lock, flags);
}
static void ns83820_tx_watch(unsigned long data)
@@ -1832,7 +1835,7 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
} else if (!pci_set_dma_mask(pci_dev, DMA_32BIT_MASK)) {
using_dac = 0;
} else {
- printk(KERN_WARNING "ns83820.c: pci_set_dma_mask failed!\n");
+ dev_warn(&pci_dev->dev, "pci_set_dma_mask failed!\n");
return -ENODEV;
}
@@ -1855,7 +1858,7 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
err = pci_enable_device(pci_dev);
if (err) {
- printk(KERN_INFO "ns83820: pci_enable_dev failed: %d\n", err);
+ dev_info(&pci_dev->dev, "pci_enable_dev failed: %d\n", err);
goto out_free;
}
@@ -1884,8 +1887,8 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
err = request_irq(pci_dev->irq, ns83820_irq, IRQF_SHARED,
DRV_NAME, ndev);
if (err) {
- printk(KERN_INFO "ns83820: unable to register irq %d\n",
- pci_dev->irq);
+ dev_info(&pci_dev->dev, "unable to register irq %d, err %d\n",
+ pci_dev->irq, err);
goto out_disable;
}
@@ -1899,7 +1902,7 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
rtnl_lock();
err = dev_alloc_name(ndev, ndev->name);
if (err < 0) {
- printk(KERN_INFO "ns83820: unable to get netdev name: %d\n", err);
+ dev_info(&pci_dev->dev, "unable to get netdev name: %d\n", err);
goto out_free_irq;
}
diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c
index 3388ee1313e..e0e29396404 100644
--- a/drivers/net/pci-skeleton.c
+++ b/drivers/net/pci-skeleton.c
@@ -601,7 +601,7 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev,
/* dev zeroed in alloc_etherdev */
dev = alloc_etherdev (sizeof (*tp));
if (dev == NULL) {
- printk (KERN_ERR PFX "unable to alloc new ethernet\n");
+ dev_err(&pdev->dev, "unable to alloc new ethernet\n");
DPRINTK ("EXIT, returning -ENOMEM\n");
return -ENOMEM;
}
@@ -631,14 +631,14 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev,
/* make sure PCI base addr 0 is PIO */
if (!(pio_flags & IORESOURCE_IO)) {
- printk (KERN_ERR PFX "region #0 not a PIO resource, aborting\n");
+ dev_err(&pdev->dev, "region #0 not a PIO resource, aborting\n");
rc = -ENODEV;
goto err_out;
}
/* make sure PCI base addr 1 is MMIO */
if (!(mmio_flags & IORESOURCE_MEM)) {
- printk (KERN_ERR PFX "region #1 not an MMIO resource, aborting\n");
+ dev_err(&pdev->dev, "region #1 not an MMIO resource, aborting\n");
rc = -ENODEV;
goto err_out;
}
@@ -646,12 +646,12 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev,
/* check for weird/broken PCI region reporting */
if ((pio_len < NETDRV_MIN_IO_SIZE) ||
(mmio_len < NETDRV_MIN_IO_SIZE)) {
- printk (KERN_ERR PFX "Invalid PCI region size(s), aborting\n");
+ dev_err(&pdev->dev, "Invalid PCI region size(s), aborting\n");
rc = -ENODEV;
goto err_out;
}
- rc = pci_request_regions (pdev, "pci-skeleton");
+ rc = pci_request_regions (pdev, MODNAME);
if (rc)
goto err_out;
@@ -663,7 +663,7 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev,
/* ioremap MMIO region */
ioaddr = ioremap (mmio_start, mmio_len);
if (ioaddr == NULL) {
- printk (KERN_ERR PFX "cannot remap MMIO, aborting\n");
+ dev_err(&pdev->dev, "cannot remap MMIO, aborting\n");
rc = -EIO;
goto err_out_free_res;
}
@@ -699,9 +699,10 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev,
}
/* if unknown chip, assume array element #0, original RTL-8139 in this case */
- printk (KERN_DEBUG PFX "PCI device %s: unknown chip version, assuming RTL-8139\n",
- pci_name(pdev));
- printk (KERN_DEBUG PFX "PCI device %s: TxConfig = 0x%lx\n", pci_name(pdev), NETDRV_R32 (TxConfig));
+ dev_printk (KERN_DEBUG, &pdev->dev,
+ "unknown chip version, assuming RTL-8139\n");
+ dev_printk (KERN_DEBUG, &pdev->dev, "TxConfig = 0x%lx\n",
+ NETDRV_R32 (TxConfig));
tp->chipset = 0;
match:
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index d768f3d1ac2..4daafe30335 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -58,18 +58,15 @@ static const char *const version =
* PCI device identifiers for "new style" Linux PCI Device Drivers
*/
static struct pci_device_id pcnet32_pci_tbl[] = {
- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE_HOME,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE_HOME), },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE), },
/*
* Adapters that were sold with IBM's RS/6000 or pSeries hardware have
* the incorrect vendor id.
*/
- { PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_AMD_LANCE,
- PCI_ANY_ID, PCI_ANY_ID,
- PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, 0},
+ { PCI_DEVICE(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_AMD_LANCE),
+ .class = (PCI_CLASS_NETWORK_ETHERNET << 8), .class_mask = 0xffff00, },
{ } /* terminate list */
};
@@ -188,6 +185,23 @@ static int homepna[MAX_UNITS];
#define PCNET32_TOTAL_SIZE 0x20
+#define CSR0 0
+#define CSR0_INIT 0x1
+#define CSR0_START 0x2
+#define CSR0_STOP 0x4
+#define CSR0_TXPOLL 0x8
+#define CSR0_INTEN 0x40
+#define CSR0_IDON 0x0100
+#define CSR0_NORMAL (CSR0_START | CSR0_INTEN)
+#define PCNET32_INIT_LOW 1
+#define PCNET32_INIT_HIGH 2
+#define CSR3 3
+#define CSR4 4
+#define CSR5 5
+#define CSR5_SUSPEND 0x0001
+#define CSR15 15
+#define PCNET32_MC_FILTER 8
+
/* The PCNET32 Rx and Tx ring descriptors. */
struct pcnet32_rx_head {
u32 base;
@@ -277,7 +291,6 @@ struct pcnet32_private {
u32 phymask;
};
-static void pcnet32_probe_vlbus(void);
static int pcnet32_probe_pci(struct pci_dev *, const struct pci_device_id *);
static int pcnet32_probe1(unsigned long, int, struct pci_dev *);
static int pcnet32_open(struct net_device *);
@@ -419,6 +432,238 @@ static struct pcnet32_access pcnet32_dwio = {
.reset = pcnet32_dwio_reset
};
+static void pcnet32_netif_stop(struct net_device *dev)
+{
+ dev->trans_start = jiffies;
+ netif_poll_disable(dev);
+ netif_tx_disable(dev);
+}
+
+static void pcnet32_netif_start(struct net_device *dev)
+{
+ netif_wake_queue(dev);
+ netif_poll_enable(dev);
+}
+
+/*
+ * Allocate space for the new sized tx ring.
+ * Free old resources
+ * Save new resources.
+ * Any failure keeps old resources.
+ * Must be called with lp->lock held.
+ */
+static void pcnet32_realloc_tx_ring(struct net_device *dev,
+ struct pcnet32_private *lp,
+ unsigned int size)
+{
+ dma_addr_t new_ring_dma_addr;
+ dma_addr_t *new_dma_addr_list;
+ struct pcnet32_tx_head *new_tx_ring;
+ struct sk_buff **new_skb_list;
+
+ pcnet32_purge_tx_ring(dev);
+
+ new_tx_ring = pci_alloc_consistent(lp->pci_dev,
+ sizeof(struct pcnet32_tx_head) *
+ (1 << size),
+ &new_ring_dma_addr);
+ if (new_tx_ring == NULL) {
+ if (netif_msg_drv(lp))
+ printk("\n" KERN_ERR
+ "%s: Consistent memory allocation failed.\n",
+ dev->name);
+ return;
+ }
+ memset(new_tx_ring, 0, sizeof(struct pcnet32_tx_head) * (1 << size));
+
+ new_dma_addr_list = kcalloc((1 << size), sizeof(dma_addr_t),
+ GFP_ATOMIC);
+ if (!new_dma_addr_list) {
+ if (netif_msg_drv(lp))
+ printk("\n" KERN_ERR
+ "%s: Memory allocation failed.\n", dev->name);
+ goto free_new_tx_ring;
+ }
+
+ new_skb_list = kcalloc((1 << size), sizeof(struct sk_buff *),
+ GFP_ATOMIC);
+ if (!new_skb_list) {
+ if (netif_msg_drv(lp))
+ printk("\n" KERN_ERR
+ "%s: Memory allocation failed.\n", dev->name);
+ goto free_new_lists;
+ }
+
+ kfree(lp->tx_skbuff);
+ kfree(lp->tx_dma_addr);
+ pci_free_consistent(lp->pci_dev,
+ sizeof(struct pcnet32_tx_head) *
+ lp->tx_ring_size, lp->tx_ring,
+ lp->tx_ring_dma_addr);
+
+ lp->tx_ring_size = (1 << size);
+ lp->tx_mod_mask = lp->tx_ring_size - 1;
+ lp->tx_len_bits = (size << 12);
+ lp->tx_ring = new_tx_ring;
+ lp->tx_ring_dma_addr = new_ring_dma_addr;
+ lp->tx_dma_addr = new_dma_addr_list;
+ lp->tx_skbuff = new_skb_list;
+ return;
+
+ free_new_lists:
+ kfree(new_dma_addr_list);
+ free_new_tx_ring:
+ pci_free_consistent(lp->pci_dev,
+ sizeof(struct pcnet32_tx_head) *
+ (1 << size),
+ new_tx_ring,
+ new_ring_dma_addr);
+ return;
+}
+
+/*
+ * Allocate space for the new sized rx ring.
+ * Re-use old receive buffers.
+ * alloc extra buffers
+ * free unneeded buffers
+ * free unneeded buffers
+ * Save new resources.
+ * Any failure keeps old resources.
+ * Must be called with lp->lock held.
+ */
+static void pcnet32_realloc_rx_ring(struct net_device *dev,
+ struct pcnet32_private *lp,
+ unsigned int size)
+{
+ dma_addr_t new_ring_dma_addr;
+ dma_addr_t *new_dma_addr_list;
+ struct pcnet32_rx_head *new_rx_ring;
+ struct sk_buff **new_skb_list;
+ int new, overlap;
+
+ new_rx_ring = pci_alloc_consistent(lp->pci_dev,
+ sizeof(struct pcnet32_rx_head) *
+ (1 << size),
+ &new_ring_dma_addr);
+ if (new_rx_ring == NULL) {
+ if (netif_msg_drv(lp))
+ printk("\n" KERN_ERR
+ "%s: Consistent memory allocation failed.\n",
+ dev->name);
+ return;
+ }
+ memset(new_rx_ring, 0, sizeof(struct pcnet32_rx_head) * (1 << size));
+
+ new_dma_addr_list = kcalloc((1 << size), sizeof(dma_addr_t),
+ GFP_ATOMIC);
+ if (!new_dma_addr_list) {
+ if (netif_msg_drv(lp))
+ printk("\n" KERN_ERR
+ "%s: Memory allocation failed.\n", dev->name);
+ goto free_new_rx_ring;
+ }
+
+ new_skb_list = kcalloc((1 << size), sizeof(struct sk_buff *),
+ GFP_ATOMIC);
+ if (!new_skb_list) {
+ if (netif_msg_drv(lp))
+ printk("\n" KERN_ERR
+ "%s: Memory allocation failed.\n", dev->name);
+ goto free_new_lists;
+ }
+
+ /* first copy the current receive buffers */
+ overlap = min(size, lp->rx_ring_size);
+ for (new = 0; new < overlap; new++) {
+ new_rx_ring[new] = lp->rx_ring[new];
+ new_dma_addr_list[new] = lp->rx_dma_addr[new];
+ new_skb_list[new] = lp->rx_skbuff[new];
+ }
+ /* now allocate any new buffers needed */
+ for (; new < size; new++ ) {
+ struct sk_buff *rx_skbuff;
+ new_skb_list[new] = dev_alloc_skb(PKT_BUF_SZ);
+ if (!(rx_skbuff = new_skb_list[new])) {
+ /* keep the original lists and buffers */
+ if (netif_msg_drv(lp))
+ printk(KERN_ERR
+ "%s: pcnet32_realloc_rx_ring dev_alloc_skb failed.\n",
+ dev->name);
+ goto free_all_new;
+ }
+ skb_reserve(rx_skbuff, 2);
+
+ new_dma_addr_list[new] =
+ pci_map_single(lp->pci_dev, rx_skbuff->data,
+ PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
+ new_rx_ring[new].base = (u32) le32_to_cpu(new_dma_addr_list[new]);
+ new_rx_ring[new].buf_length = le16_to_cpu(2 - PKT_BUF_SZ);
+ new_rx_ring[new].status = le16_to_cpu(0x8000);
+ }
+ /* and free any unneeded buffers */
+ for (; new < lp->rx_ring_size; new++) {
+ if (lp->rx_skbuff[new]) {
+ pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[new],
+ PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(lp->rx_skbuff[new]);
+ }
+ }
+
+ kfree(lp->rx_skbuff);
+ kfree(lp->rx_dma_addr);
+ pci_free_consistent(lp->pci_dev,
+ sizeof(struct pcnet32_rx_head) *
+ lp->rx_ring_size, lp->rx_ring,
+ lp->rx_ring_dma_addr);
+
+ lp->rx_ring_size = (1 << size);
+ lp->rx_mod_mask = lp->rx_ring_size - 1;
+ lp->rx_len_bits = (size << 4);
+ lp->rx_ring = new_rx_ring;
+ lp->rx_ring_dma_addr = new_ring_dma_addr;
+ lp->rx_dma_addr = new_dma_addr_list;
+ lp->rx_skbuff = new_skb_list;
+ return;
+
+ free_all_new:
+ for (; --new >= lp->rx_ring_size; ) {
+ if (new_skb_list[new]) {
+ pci_unmap_single(lp->pci_dev, new_dma_addr_list[new],
+ PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(new_skb_list[new]);
+ }
+ }
+ kfree(new_skb_list);
+ free_new_lists:
+ kfree(new_dma_addr_list);
+ free_new_rx_ring:
+ pci_free_consistent(lp->pci_dev,
+ sizeof(struct pcnet32_rx_head) *
+ (1 << size),
+ new_rx_ring,
+ new_ring_dma_addr);
+ return;
+}
+
+static void pcnet32_purge_rx_ring(struct net_device *dev)
+{
+ struct pcnet32_private *lp = dev->priv;
+ int i;
+
+ /* free all allocated skbuffs */
+ for (i = 0; i < lp->rx_ring_size; i++) {
+ lp->rx_ring[i].status = 0; /* CPU owns buffer */
+ wmb(); /* Make sure adapter sees owner change */
+ if (lp->rx_skbuff[i]) {
+ pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i],
+ PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
+ dev_kfree_skb_any(lp->rx_skbuff[i]);
+ }
+ lp->rx_skbuff[i] = NULL;
+ lp->rx_dma_addr[i] = 0;
+ }
+}
+
#ifdef CONFIG_NET_POLL_CONTROLLER
static void pcnet32_poll_controller(struct net_device *dev)
{
@@ -519,10 +764,10 @@ static void pcnet32_get_ringparam(struct net_device *dev,
{
struct pcnet32_private *lp = dev->priv;
- ering->tx_max_pending = TX_MAX_RING_SIZE - 1;
- ering->tx_pending = lp->tx_ring_size - 1;
- ering->rx_max_pending = RX_MAX_RING_SIZE - 1;
- ering->rx_pending = lp->rx_ring_size - 1;
+ ering->tx_max_pending = TX_MAX_RING_SIZE;
+ ering->tx_pending = lp->tx_ring_size;
+ ering->rx_max_pending = RX_MAX_RING_SIZE;
+ ering->rx_pending = lp->rx_ring_size;
}
static int pcnet32_set_ringparam(struct net_device *dev,
@@ -530,56 +775,53 @@ static int pcnet32_set_ringparam(struct net_device *dev,
{
struct pcnet32_private *lp = dev->priv;
unsigned long flags;
+ unsigned int size;
+ ulong ioaddr = dev->base_addr;
int i;
if (ering->rx_mini_pending || ering->rx_jumbo_pending)
return -EINVAL;
if (netif_running(dev))
- pcnet32_close(dev);
+ pcnet32_netif_stop(dev);
spin_lock_irqsave(&lp->lock, flags);
- pcnet32_free_ring(dev);
- lp->tx_ring_size =
- min(ering->tx_pending, (unsigned int)TX_MAX_RING_SIZE);
- lp->rx_ring_size =
- min(ering->rx_pending, (unsigned int)RX_MAX_RING_SIZE);
+ lp->a.write_csr(ioaddr, CSR0, CSR0_STOP); /* stop the chip */
+
+ size = min(ering->tx_pending, (unsigned int)TX_MAX_RING_SIZE);
/* set the minimum ring size to 4, to allow the loopback test to work
* unchanged.
*/
for (i = 2; i <= PCNET32_LOG_MAX_TX_BUFFERS; i++) {
- if (lp->tx_ring_size <= (1 << i))
+ if (size <= (1 << i))
break;
}
- lp->tx_ring_size = (1 << i);
- lp->tx_mod_mask = lp->tx_ring_size - 1;
- lp->tx_len_bits = (i << 12);
-
+ if ((1 << i) != lp->tx_ring_size)
+ pcnet32_realloc_tx_ring(dev, lp, i);
+
+ size = min(ering->rx_pending, (unsigned int)RX_MAX_RING_SIZE);
for (i = 2; i <= PCNET32_LOG_MAX_RX_BUFFERS; i++) {
- if (lp->rx_ring_size <= (1 << i))
+ if (size <= (1 << i))
break;
}
- lp->rx_ring_size = (1 << i);
- lp->rx_mod_mask = lp->rx_ring_size - 1;
- lp->rx_len_bits = (i << 4);
+ if ((1 << i) != lp->rx_ring_size)
+ pcnet32_realloc_rx_ring(dev, lp, i);
+
+ dev->weight = lp->rx_ring_size / 2;
- if (pcnet32_alloc_ring(dev, dev->name)) {
- pcnet32_free_ring(dev);
- spin_unlock_irqrestore(&lp->lock, flags);
- return -ENOMEM;
+ if (netif_running(dev)) {
+ pcnet32_netif_start(dev);
+ pcnet32_restart(dev, CSR0_NORMAL);
}
spin_unlock_irqrestore(&lp->lock, flags);
- if (pcnet32_debug & NETIF_MSG_DRV)
- printk(KERN_INFO PFX
+ if (netif_msg_drv(lp))
+ printk(KERN_INFO
"%s: Ring Param Settings: RX: %d, TX: %d\n", dev->name,
lp->rx_ring_size, lp->tx_ring_size);
- if (netif_running(dev))
- pcnet32_open(dev);
-
return 0;
}
@@ -633,29 +875,27 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
unsigned long flags;
unsigned long ticks;
- *data1 = 1; /* status of test, default to fail */
rc = 1; /* default to fail */
if (netif_running(dev))
pcnet32_close(dev);
spin_lock_irqsave(&lp->lock, flags);
+ lp->a.write_csr(ioaddr, CSR0, CSR0_STOP); /* stop the chip */
+
+ numbuffs = min(numbuffs, (int)min(lp->rx_ring_size, lp->tx_ring_size));
/* Reset the PCNET32 */
lp->a.reset(ioaddr);
+ lp->a.write_csr(ioaddr, CSR4, 0x0915);
/* switch pcnet32 to 32bit mode */
lp->a.write_bcr(ioaddr, 20, 2);
- lp->init_block.mode =
- le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);
- lp->init_block.filter[0] = 0;
- lp->init_block.filter[1] = 0;
-
/* purge & init rings but don't actually restart */
pcnet32_restart(dev, 0x0000);
- lp->a.write_csr(ioaddr, 0, 0x0004); /* Set STOP bit */
+ lp->a.write_csr(ioaddr, CSR0, CSR0_STOP); /* Set STOP bit */
/* Initialize Transmit buffers. */
size = data_len + 15;
@@ -697,14 +937,15 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
}
}
- x = a->read_bcr(ioaddr, 32); /* set internal loopback in BSR32 */
- x = x | 0x0002;
- a->write_bcr(ioaddr, 32, x);
+ x = a->read_bcr(ioaddr, 32); /* set internal loopback in BCR32 */
+ a->write_bcr(ioaddr, 32, x | 0x0002);
- lp->a.write_csr(ioaddr, 15, 0x0044); /* set int loopback in CSR15 */
+ /* set int loopback in CSR15 */
+ x = a->read_csr(ioaddr, CSR15) & 0xfffc;
+ lp->a.write_csr(ioaddr, CSR15, x | 0x0044);
teststatus = le16_to_cpu(0x8000);
- lp->a.write_csr(ioaddr, 0, 0x0002); /* Set STRT bit */
+ lp->a.write_csr(ioaddr, CSR0, CSR0_START); /* Set STRT bit */
/* Check status of descriptors */
for (x = 0; x < numbuffs; x++) {
@@ -712,7 +953,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
rmb();
while ((lp->rx_ring[x].status & teststatus) && (ticks < 200)) {
spin_unlock_irqrestore(&lp->lock, flags);
- mdelay(1);
+ msleep(1);
spin_lock_irqsave(&lp->lock, flags);
rmb();
ticks++;
@@ -725,7 +966,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
}
}
- lp->a.write_csr(ioaddr, 0, 0x0004); /* Set STOP bit */
+ lp->a.write_csr(ioaddr, CSR0, CSR0_STOP); /* Set STOP bit */
wmb();
if (netif_msg_hw(lp) && netif_msg_pktdata(lp)) {
printk(KERN_DEBUG "%s: RX loopback packets:\n", dev->name);
@@ -758,25 +999,24 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
}
x++;
}
- if (!rc) {
- *data1 = 0;
- }
clean_up:
+ *data1 = rc;
pcnet32_purge_tx_ring(dev);
- x = a->read_csr(ioaddr, 15) & 0xFFFF;
- a->write_csr(ioaddr, 15, (x & ~0x0044)); /* reset bits 6 and 2 */
- x = a->read_bcr(ioaddr, 32); /* reset internal loopback */
- x = x & ~0x0002;
- a->write_bcr(ioaddr, 32, x);
+ x = a->read_csr(ioaddr, CSR15);
+ a->write_csr(ioaddr, CSR15, (x & ~0x0044)); /* reset bits 6 and 2 */
- spin_unlock_irqrestore(&lp->lock, flags);
+ x = a->read_bcr(ioaddr, 32); /* reset internal loopback */
+ a->write_bcr(ioaddr, 32, (x & ~0x0002));
if (netif_running(dev)) {
+ spin_unlock_irqrestore(&lp->lock, flags);
pcnet32_open(dev);
} else {
+ pcnet32_purge_rx_ring(dev);
lp->a.write_bcr(ioaddr, 20, 4); /* return to 16bit mode */
+ spin_unlock_irqrestore(&lp->lock, flags);
}
return (rc);
@@ -839,6 +1079,43 @@ static int pcnet32_phys_id(struct net_device *dev, u32 data)
return 0;
}
+/*
+ * lp->lock must be held.
+ */
+static int pcnet32_suspend(struct net_device *dev, unsigned long *flags,
+ int can_sleep)
+{
+ int csr5;
+ struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_access *a = &lp->a;
+ ulong ioaddr = dev->base_addr;
+ int ticks;
+
+ /* set SUSPEND (SPND) - CSR5 bit 0 */
+ csr5 = a->read_csr(ioaddr, CSR5);
+ a->write_csr(ioaddr, CSR5, csr5 | CSR5_SUSPEND);
+
+ /* poll waiting for bit to be set */
+ ticks = 0;
+ while (!(a->read_csr(ioaddr, CSR5) & CSR5_SUSPEND)) {
+ spin_unlock_irqrestore(&lp->lock, *flags);
+ if (can_sleep)
+ msleep(1);
+ else
+ mdelay(1);
+ spin_lock_irqsave(&lp->lock, *flags);
+ ticks++;
+ if (ticks > 200) {
+ if (netif_msg_hw(lp))
+ printk(KERN_DEBUG
+ "%s: Error getting into suspend!\n",
+ dev->name);
+ return 0;
+ }
+ }
+ return 1;
+}
+
#define PCNET32_REGS_PER_PHY 32
#define PCNET32_MAX_PHYS 32
static int pcnet32_get_regs_len(struct net_device *dev)
@@ -857,32 +1134,13 @@ static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs,
struct pcnet32_private *lp = dev->priv;
struct pcnet32_access *a = &lp->a;
ulong ioaddr = dev->base_addr;
- int ticks;
unsigned long flags;
spin_lock_irqsave(&lp->lock, flags);
- csr0 = a->read_csr(ioaddr, 0);
- if (!(csr0 & 0x0004)) { /* If not stopped */
- /* set SUSPEND (SPND) - CSR5 bit 0 */
- a->write_csr(ioaddr, 5, 0x0001);
-
- /* poll waiting for bit to be set */
- ticks = 0;
- while (!(a->read_csr(ioaddr, 5) & 0x0001)) {
- spin_unlock_irqrestore(&lp->lock, flags);
- mdelay(1);
- spin_lock_irqsave(&lp->lock, flags);
- ticks++;
- if (ticks > 200) {
- if (netif_msg_hw(lp))
- printk(KERN_DEBUG
- "%s: Error getting into suspend!\n",
- dev->name);
- break;
- }
- }
- }
+ csr0 = a->read_csr(ioaddr, CSR0);
+ if (!(csr0 & CSR0_STOP)) /* If not stopped */
+ pcnet32_suspend(dev, &flags, 1);
/* read address PROM */
for (i = 0; i < 16; i += 2)
@@ -919,9 +1177,12 @@ static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs,
}
}
- if (!(csr0 & 0x0004)) { /* If not stopped */
+ if (!(csr0 & CSR0_STOP)) { /* If not stopped */
+ int csr5;
+
/* clear SUSPEND (SPND) - CSR5 bit 0 */
- a->write_csr(ioaddr, 5, 0x0000);
+ csr5 = a->read_csr(ioaddr, CSR5);
+ a->write_csr(ioaddr, CSR5, csr5 & (~CSR5_SUSPEND));
}
spin_unlock_irqrestore(&lp->lock, flags);
@@ -952,7 +1213,7 @@ static struct ethtool_ops pcnet32_ethtool_ops = {
/* only probes for non-PCI devices, the rest are handled by
* pci_register_driver via pcnet32_probe_pci */
-static void __devinit pcnet32_probe_vlbus(void)
+static void __devinit pcnet32_probe_vlbus(unsigned int *pcnet32_portlist)
{
unsigned int *port, ioaddr;
@@ -1436,7 +1697,7 @@ static int pcnet32_alloc_ring(struct net_device *dev, char *name)
lp->tx_ring_size,
&lp->tx_ring_dma_addr);
if (lp->tx_ring == NULL) {
- if (pcnet32_debug & NETIF_MSG_DRV)
+ if (netif_msg_drv(lp))
printk("\n" KERN_ERR PFX
"%s: Consistent memory allocation failed.\n",
name);
@@ -1448,52 +1709,48 @@ static int pcnet32_alloc_ring(struct net_device *dev, char *name)
lp->rx_ring_size,
&lp->rx_ring_dma_addr);
if (lp->rx_ring == NULL) {
- if (pcnet32_debug & NETIF_MSG_DRV)
+ if (netif_msg_drv(lp))
printk("\n" KERN_ERR PFX
"%s: Consistent memory allocation failed.\n",
name);
return -ENOMEM;
}
- lp->tx_dma_addr = kmalloc(sizeof(dma_addr_t) * lp->tx_ring_size,
+ lp->tx_dma_addr = kcalloc(lp->tx_ring_size, sizeof(dma_addr_t),
GFP_ATOMIC);
if (!lp->tx_dma_addr) {
- if (pcnet32_debug & NETIF_MSG_DRV)
+ if (netif_msg_drv(lp))
printk("\n" KERN_ERR PFX
"%s: Memory allocation failed.\n", name);
return -ENOMEM;
}
- memset(lp->tx_dma_addr, 0, sizeof(dma_addr_t) * lp->tx_ring_size);
- lp->rx_dma_addr = kmalloc(sizeof(dma_addr_t) * lp->rx_ring_size,
+ lp->rx_dma_addr = kcalloc(lp->rx_ring_size, sizeof(dma_addr_t),
GFP_ATOMIC);
if (!lp->rx_dma_addr) {
- if (pcnet32_debug & NETIF_MSG_DRV)
+ if (netif_msg_drv(lp))
printk("\n" KERN_ERR PFX
"%s: Memory allocation failed.\n", name);
return -ENOMEM;
}
- memset(lp->rx_dma_addr, 0, sizeof(dma_addr_t) * lp->rx_ring_size);
- lp->tx_skbuff = kmalloc(sizeof(struct sk_buff *) * lp->tx_ring_size,
+ lp->tx_skbuff = kcalloc(lp->tx_ring_size, sizeof(struct sk_buff *),
GFP_ATOMIC);
if (!lp->tx_skbuff) {
- if (pcnet32_debug & NETIF_MSG_DRV)
+ if (netif_msg_drv(lp))
printk("\n" KERN_ERR PFX
"%s: Memory allocation failed.\n", name);
return -ENOMEM;
}
- memset(lp->tx_skbuff, 0, sizeof(struct sk_buff *) * lp->tx_ring_size);
- lp->rx_skbuff = kmalloc(sizeof(struct sk_buff *) * lp->rx_ring_size,
+ lp->rx_skbuff = kcalloc(lp->rx_ring_size, sizeof(struct sk_buff *),
GFP_ATOMIC);
if (!lp->rx_skbuff) {
- if (pcnet32_debug & NETIF_MSG_DRV)
+ if (netif_msg_drv(lp))
printk("\n" KERN_ERR PFX
"%s: Memory allocation failed.\n", name);
return -ENOMEM;
}
- memset(lp->rx_skbuff, 0, sizeof(struct sk_buff *) * lp->rx_ring_size);
return 0;
}
@@ -1757,16 +2014,7 @@ static int pcnet32_open(struct net_device *dev)
err_free_ring:
/* free any allocated skbuffs */
- for (i = 0; i < lp->rx_ring_size; i++) {
- lp->rx_ring[i].status = 0;
- if (lp->rx_skbuff[i]) {
- pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i],
- PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
- dev_kfree_skb(lp->rx_skbuff[i]);
- }
- lp->rx_skbuff[i] = NULL;
- lp->rx_dma_addr[i] = 0;
- }
+ pcnet32_purge_rx_ring(dev);
/*
* Switch back to 16bit mode to avoid problems with dumb
@@ -2348,7 +2596,6 @@ static int pcnet32_close(struct net_device *dev)
{
unsigned long ioaddr = dev->base_addr;
struct pcnet32_private *lp = dev->priv;
- int i;
unsigned long flags;
del_timer_sync(&lp->watchdog_timer);
@@ -2379,31 +2626,8 @@ static int pcnet32_close(struct net_device *dev)
spin_lock_irqsave(&lp->lock, flags);
- /* free all allocated skbuffs */
- for (i = 0; i < lp->rx_ring_size; i++) {
- lp->rx_ring[i].status = 0;
- wmb(); /* Make sure adapter sees owner change */
- if (lp->rx_skbuff[i]) {
- pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i],
- PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
- dev_kfree_skb(lp->rx_skbuff[i]);
- }
- lp->rx_skbuff[i] = NULL;
- lp->rx_dma_addr[i] = 0;
- }
-
- for (i = 0; i < lp->tx_ring_size; i++) {
- lp->tx_ring[i].status = 0; /* CPU owns buffer */
- wmb(); /* Make sure adapter sees owner change */
- if (lp->tx_skbuff[i]) {
- pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[i],
- lp->tx_skbuff[i]->len,
- PCI_DMA_TODEVICE);
- dev_kfree_skb(lp->tx_skbuff[i]);
- }
- lp->tx_skbuff[i] = NULL;
- lp->tx_dma_addr[i] = 0;
- }
+ pcnet32_purge_rx_ring(dev);
+ pcnet32_purge_tx_ring(dev);
spin_unlock_irqrestore(&lp->lock, flags);
@@ -2433,6 +2657,7 @@ static void pcnet32_load_multicast(struct net_device *dev)
volatile struct pcnet32_init_block *ib = &lp->init_block;
volatile u16 *mcast_table = (u16 *) & ib->filter;
struct dev_mc_list *dmi = dev->mc_list;
+ unsigned long ioaddr = dev->base_addr;
char *addrs;
int i;
u32 crc;
@@ -2441,6 +2666,10 @@ static void pcnet32_load_multicast(struct net_device *dev)
if (dev->flags & IFF_ALLMULTI) {
ib->filter[0] = 0xffffffff;
ib->filter[1] = 0xffffffff;
+ lp->a.write_csr(ioaddr, PCNET32_MC_FILTER, 0xffff);
+ lp->a.write_csr(ioaddr, PCNET32_MC_FILTER+1, 0xffff);
+ lp->a.write_csr(ioaddr, PCNET32_MC_FILTER+2, 0xffff);
+ lp->a.write_csr(ioaddr, PCNET32_MC_FILTER+3, 0xffff);
return;
}
/* clear the multicast filter */
@@ -2462,6 +2691,9 @@ static void pcnet32_load_multicast(struct net_device *dev)
le16_to_cpu(le16_to_cpu(mcast_table[crc >> 4]) |
(1 << (crc & 0xf)));
}
+ for (i = 0; i < 4; i++)
+ lp->a.write_csr(ioaddr, PCNET32_MC_FILTER + i,
+ le16_to_cpu(mcast_table[i]));
return;
}
@@ -2472,8 +2704,11 @@ static void pcnet32_set_multicast_list(struct net_device *dev)
{
unsigned long ioaddr = dev->base_addr, flags;
struct pcnet32_private *lp = dev->priv;
+ int csr15, suspended;
spin_lock_irqsave(&lp->lock, flags);
+ suspended = pcnet32_suspend(dev, &flags, 0);
+ csr15 = lp->a.read_csr(ioaddr, CSR15);
if (dev->flags & IFF_PROMISC) {
/* Log any net taps. */
if (netif_msg_hw(lp))
@@ -2482,15 +2717,24 @@ static void pcnet32_set_multicast_list(struct net_device *dev)
lp->init_block.mode =
le16_to_cpu(0x8000 | (lp->options & PCNET32_PORT_PORTSEL) <<
7);
+ lp->a.write_csr(ioaddr, CSR15, csr15 | 0x8000);
} else {
lp->init_block.mode =
le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);
+ lp->a.write_csr(ioaddr, CSR15, csr15 & 0x7fff);
pcnet32_load_multicast(dev);
}
- lp->a.write_csr(ioaddr, 0, 0x0004); /* Temporarily stop the lance. */
- pcnet32_restart(dev, 0x0042); /* Resume normal operation */
- netif_wake_queue(dev);
+ if (suspended) {
+ int csr5;
+ /* clear SUSPEND (SPND) - CSR5 bit 0 */
+ csr5 = lp->a.read_csr(ioaddr, CSR5);
+ lp->a.write_csr(ioaddr, CSR5, csr5 & (~CSR5_SUSPEND));
+ } else {
+ lp->a.write_csr(ioaddr, CSR0, CSR0_STOP);
+ pcnet32_restart(dev, CSR0_NORMAL);
+ netif_wake_queue(dev);
+ }
spin_unlock_irqrestore(&lp->lock, flags);
}
@@ -2730,7 +2974,7 @@ static int __init pcnet32_init_module(void)
/* should we find any remaining VLbus devices ? */
if (pcnet32vlb)
- pcnet32_probe_vlbus();
+ pcnet32_probe_vlbus(pcnet32_portlist);
if (cards_found && (pcnet32_debug & NETIF_MSG_PROBE))
printk(KERN_INFO PFX "%d cards_found.\n", cards_found);
diff --git a/drivers/net/phy/cicada.c b/drivers/net/phy/cicada.c
index 3efb715c28d..ae60e6e4107 100644
--- a/drivers/net/phy/cicada.c
+++ b/drivers/net/phy/cicada.c
@@ -103,7 +103,22 @@ static int cis820x_config_intr(struct phy_device *phydev)
return err;
}
-/* Cicada 820x */
+/* Cicada 8201, a.k.a Vitesse VSC8201 */
+static struct phy_driver cis8201_driver = {
+ .phy_id = 0x000fc410,
+ .name = "Cicada Cis8201",
+ .phy_id_mask = 0x000ffff0,
+ .features = PHY_GBIT_FEATURES,
+ .flags = PHY_HAS_INTERRUPT,
+ .config_init = &cis820x_config_init,
+ .config_aneg = &genphy_config_aneg,
+ .read_status = &genphy_read_status,
+ .ack_interrupt = &cis820x_ack_interrupt,
+ .config_intr = &cis820x_config_intr,
+ .driver = { .owner = THIS_MODULE,},
+};
+
+/* Cicada 8204 */
static struct phy_driver cis8204_driver = {
.phy_id = 0x000fc440,
.name = "Cicada Cis8204",
@@ -118,15 +133,30 @@ static struct phy_driver cis8204_driver = {
.driver = { .owner = THIS_MODULE,},
};
-static int __init cis8204_init(void)
+static int __init cicada_init(void)
{
- return phy_driver_register(&cis8204_driver);
+ int ret;
+
+ ret = phy_driver_register(&cis8204_driver);
+ if (ret)
+ goto err1;
+
+ ret = phy_driver_register(&cis8201_driver);
+ if (ret)
+ goto err2;
+ return 0;
+
+err2:
+ phy_driver_unregister(&cis8204_driver);
+err1:
+ return ret;
}
-static void __exit cis8204_exit(void)
+static void __exit cicada_exit(void)
{
phy_driver_unregister(&cis8204_driver);
+ phy_driver_unregister(&cis8201_driver);
}
-module_init(cis8204_init);
-module_exit(cis8204_exit);
+module_init(cicada_init);
+module_exit(cicada_exit);
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 7d5c2233c25..f5aad77288f 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -419,9 +419,8 @@ void phy_start_machine(struct phy_device *phydev,
/* phy_stop_machine
*
- * description: Stops the state machine timer, sets the state to
- * UP (unless it wasn't up yet), and then frees the interrupt,
- * if it is in use. This function must be called BEFORE
+ * description: Stops the state machine timer, sets the state to UP
+ * (unless it wasn't up yet). This function must be called BEFORE
* phy_detach.
*/
void phy_stop_machine(struct phy_device *phydev)
@@ -433,9 +432,6 @@ void phy_stop_machine(struct phy_device *phydev)
phydev->state = PHY_UP;
spin_unlock(&phydev->lock);
- if (phydev->irq != PHY_POLL)
- phy_stop_interrupts(phydev);
-
phydev->adjust_state = NULL;
}
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 16a0ef1b136..4c2f575faad 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -1406,7 +1406,7 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
dev = alloc_etherdev(sizeof (*tp));
if (dev == NULL) {
if (netif_msg_drv(&debug))
- printk(KERN_ERR PFX "unable to alloc new ethernet\n");
+ dev_err(&pdev->dev, "unable to alloc new ethernet\n");
goto err_out;
}
@@ -1418,10 +1418,8 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
/* enable device (incl. PCI PM wakeup and hotplug setup) */
rc = pci_enable_device(pdev);
if (rc < 0) {
- if (netif_msg_probe(tp)) {
- printk(KERN_ERR PFX "%s: enable failure\n",
- pci_name(pdev));
- }
+ if (netif_msg_probe(tp))
+ dev_err(&pdev->dev, "enable failure\n");
goto err_out_free_dev;
}
@@ -1437,37 +1435,32 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
pci_read_config_word(pdev, pm_cap + PCI_PM_CTRL, &pwr_command);
acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK;
} else {
- if (netif_msg_probe(tp)) {
- printk(KERN_ERR PFX
+ if (netif_msg_probe(tp))
+ dev_err(&pdev->dev,
"PowerManagement capability not found.\n");
- }
}
/* make sure PCI base addr 1 is MMIO */
if (!(pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) {
- if (netif_msg_probe(tp)) {
- printk(KERN_ERR PFX
+ if (netif_msg_probe(tp))
+ dev_err(&pdev->dev,
"region #1 not an MMIO resource, aborting\n");
- }
rc = -ENODEV;
goto err_out_mwi;
}
/* check for weird/broken PCI region reporting */
if (pci_resource_len(pdev, 1) < R8169_REGS_SIZE) {
- if (netif_msg_probe(tp)) {
- printk(KERN_ERR PFX
+ if (netif_msg_probe(tp))
+ dev_err(&pdev->dev,
"Invalid PCI region size(s), aborting\n");
- }
rc = -ENODEV;
goto err_out_mwi;
}
rc = pci_request_regions(pdev, MODULENAME);
if (rc < 0) {
- if (netif_msg_probe(tp)) {
- printk(KERN_ERR PFX "%s: could not request regions.\n",
- pci_name(pdev));
- }
+ if (netif_msg_probe(tp))
+ dev_err(&pdev->dev, "could not request regions.\n");
goto err_out_mwi;
}
@@ -1480,10 +1473,9 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
} else {
rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
if (rc < 0) {
- if (netif_msg_probe(tp)) {
- printk(KERN_ERR PFX
+ if (netif_msg_probe(tp))
+ dev_err(&pdev->dev,
"DMA configuration failed.\n");
- }
goto err_out_free_res;
}
}
@@ -1494,7 +1486,7 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
ioaddr = ioremap(pci_resource_start(pdev, 1), R8169_REGS_SIZE);
if (ioaddr == NULL) {
if (netif_msg_probe(tp))
- printk(KERN_ERR PFX "cannot remap MMIO, aborting\n");
+ dev_err(&pdev->dev, "cannot remap MMIO, aborting\n");
rc = -EIO;
goto err_out_free_res;
}
@@ -1526,9 +1518,9 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
if (i < 0) {
/* Unknown chip: assume array element #0, original RTL-8169 */
if (netif_msg_probe(tp)) {
- printk(KERN_DEBUG PFX "PCI device %s: "
+ dev_printk(KERN_DEBUG, &pdev->dev,
"unknown chip version, assuming %s\n",
- pci_name(pdev), rtl_chip_info[0].name);
+ rtl_chip_info[0].name);
}
i++;
}
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index c6b77acb35e..132ed32bce1 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -76,7 +76,7 @@
#include "s2io.h"
#include "s2io-regs.h"
-#define DRV_VERSION "2.0.14.2"
+#define DRV_VERSION "2.0.15.2"
/* S2io Driver name & version. */
static char s2io_driver_name[] = "Neterion";
@@ -370,38 +370,50 @@ static const u64 fix_mac[] = {
END_SIGN
};
+MODULE_AUTHOR("Raghavendra Koushik <raghavendra.koushik@neterion.com>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+
/* Module Loadable parameters. */
-static unsigned int tx_fifo_num = 1;
-static unsigned int tx_fifo_len[MAX_TX_FIFOS] =
- {DEFAULT_FIFO_0_LEN, [1 ...(MAX_TX_FIFOS - 1)] = DEFAULT_FIFO_1_7_LEN};
-static unsigned int rx_ring_num = 1;
-static unsigned int rx_ring_sz[MAX_RX_RINGS] =
- {[0 ...(MAX_RX_RINGS - 1)] = SMALL_BLK_CNT};
-static unsigned int rts_frm_len[MAX_RX_RINGS] =
- {[0 ...(MAX_RX_RINGS - 1)] = 0 };
-static unsigned int rx_ring_mode = 1;
-static unsigned int use_continuous_tx_intrs = 1;
-static unsigned int rmac_pause_time = 0x100;
-static unsigned int mc_pause_threshold_q0q3 = 187;
-static unsigned int mc_pause_threshold_q4q7 = 187;
-static unsigned int shared_splits;
-static unsigned int tmac_util_period = 5;
-static unsigned int rmac_util_period = 5;
-static unsigned int bimodal = 0;
-static unsigned int l3l4hdr_size = 128;
-#ifndef CONFIG_S2IO_NAPI
-static unsigned int indicate_max_pkts;
-#endif
+S2IO_PARM_INT(tx_fifo_num, 1);
+S2IO_PARM_INT(rx_ring_num, 1);
+
+
+S2IO_PARM_INT(rx_ring_mode, 1);
+S2IO_PARM_INT(use_continuous_tx_intrs, 1);
+S2IO_PARM_INT(rmac_pause_time, 0x100);
+S2IO_PARM_INT(mc_pause_threshold_q0q3, 187);
+S2IO_PARM_INT(mc_pause_threshold_q4q7, 187);
+S2IO_PARM_INT(shared_splits, 0);
+S2IO_PARM_INT(tmac_util_period, 5);
+S2IO_PARM_INT(rmac_util_period, 5);
+S2IO_PARM_INT(bimodal, 0);
+S2IO_PARM_INT(l3l4hdr_size, 128);
/* Frequency of Rx desc syncs expressed as power of 2 */
-static unsigned int rxsync_frequency = 3;
+S2IO_PARM_INT(rxsync_frequency, 3);
/* Interrupt type. Values can be 0(INTA), 1(MSI), 2(MSI_X) */
-static unsigned int intr_type = 0;
+S2IO_PARM_INT(intr_type, 0);
/* Large receive offload feature */
-static unsigned int lro = 0;
+S2IO_PARM_INT(lro, 0);
/* Max pkts to be aggregated by LRO at one time. If not specified,
* aggregation happens until we hit max IP pkt size(64K)
*/
-static unsigned int lro_max_pkts = 0xFFFF;
+S2IO_PARM_INT(lro_max_pkts, 0xFFFF);
+#ifndef CONFIG_S2IO_NAPI
+S2IO_PARM_INT(indicate_max_pkts, 0);
+#endif
+
+static unsigned int tx_fifo_len[MAX_TX_FIFOS] =
+ {DEFAULT_FIFO_0_LEN, [1 ...(MAX_TX_FIFOS - 1)] = DEFAULT_FIFO_1_7_LEN};
+static unsigned int rx_ring_sz[MAX_RX_RINGS] =
+ {[0 ...(MAX_RX_RINGS - 1)] = SMALL_BLK_CNT};
+static unsigned int rts_frm_len[MAX_RX_RINGS] =
+ {[0 ...(MAX_RX_RINGS - 1)] = 0 };
+
+module_param_array(tx_fifo_len, uint, NULL, 0);
+module_param_array(rx_ring_sz, uint, NULL, 0);
+module_param_array(rts_frm_len, uint, NULL, 0);
/*
* S2IO device table.
@@ -464,10 +476,9 @@ static int init_shared_mem(struct s2io_nic *nic)
size += config->tx_cfg[i].fifo_len;
}
if (size > MAX_AVAILABLE_TXDS) {
- DBG_PRINT(ERR_DBG, "%s: Requested TxDs too high, ",
- __FUNCTION__);
+ DBG_PRINT(ERR_DBG, "s2io: Requested TxDs too high, ");
DBG_PRINT(ERR_DBG, "Requested: %d, max supported: 8192\n", size);
- return FAILURE;
+ return -EINVAL;
}
lst_size = (sizeof(TxD_t) * config->max_txds);
@@ -547,6 +558,7 @@ static int init_shared_mem(struct s2io_nic *nic)
nic->ufo_in_band_v = kmalloc((sizeof(u64) * size), GFP_KERNEL);
if (!nic->ufo_in_band_v)
return -ENOMEM;
+ memset(nic->ufo_in_band_v, 0, size);
/* Allocation and initialization of RXDs in Rings */
size = 0;
@@ -1213,7 +1225,7 @@ static int init_nic(struct s2io_nic *nic)
break;
}
- /* Enable Tx FIFO partition 0. */
+ /* Enable all configured Tx FIFO partitions */
val64 = readq(&bar0->tx_fifo_partition_0);
val64 |= (TX_FIFO_PARTITION_EN);
writeq(val64, &bar0->tx_fifo_partition_0);
@@ -1650,7 +1662,7 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
writeq(temp64, &bar0->general_int_mask);
/*
* If Hercules adapter enable GPIO otherwise
- * disabled all PCIX, Flash, MDIO, IIC and GPIO
+ * disable all PCIX, Flash, MDIO, IIC and GPIO
* interrupts for now.
* TODO
*/
@@ -1976,7 +1988,6 @@ static int start_nic(struct s2io_nic *nic)
XENA_dev_config_t __iomem *bar0 = nic->bar0;
struct net_device *dev = nic->dev;
register u64 val64 = 0;
- u16 interruptible;
u16 subid, i;
mac_info_t *mac_control;
struct config_param *config;
@@ -2047,16 +2058,6 @@ static int start_nic(struct s2io_nic *nic)
return FAILURE;
}
- /* Enable select interrupts */
- if (nic->intr_type != INTA)
- en_dis_able_nic_intrs(nic, ENA_ALL_INTRS, DISABLE_INTRS);
- else {
- interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR;
- interruptible |= TX_PIC_INTR | RX_PIC_INTR;
- interruptible |= TX_MAC_INTR | RX_MAC_INTR;
- en_dis_able_nic_intrs(nic, interruptible, ENABLE_INTRS);
- }
-
/*
* With some switches, link might be already up at this point.
* Because of this weird behavior, when we enable laser,
@@ -2130,7 +2131,7 @@ static struct sk_buff *s2io_txdl_getskb(fifo_info_t *fifo_data, TxD_t *txdlp, in
frag->size, PCI_DMA_TODEVICE);
}
}
- txdlp->Host_Control = 0;
+ memset(txdlp,0, (sizeof(TxD_t) * fifo_data->max_txds));
return(skb);
}
@@ -2382,9 +2383,14 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
skb->data = (void *) (unsigned long)tmp;
skb->tail = (void *) (unsigned long)tmp;
- ((RxD3_t*)rxdp)->Buffer0_ptr =
- pci_map_single(nic->pdev, ba->ba_0, BUF0_LEN,
+ if (!(((RxD3_t*)rxdp)->Buffer0_ptr))
+ ((RxD3_t*)rxdp)->Buffer0_ptr =
+ pci_map_single(nic->pdev, ba->ba_0, BUF0_LEN,
PCI_DMA_FROMDEVICE);
+ else
+ pci_dma_sync_single_for_device(nic->pdev,
+ (dma_addr_t) ((RxD3_t*)rxdp)->Buffer0_ptr,
+ BUF0_LEN, PCI_DMA_FROMDEVICE);
rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
if (nic->rxd_mode == RXD_MODE_3B) {
/* Two buffer mode */
@@ -2397,10 +2403,13 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
(nic->pdev, skb->data, dev->mtu + 4,
PCI_DMA_FROMDEVICE);
- /* Buffer-1 will be dummy buffer not used */
- ((RxD3_t*)rxdp)->Buffer1_ptr =
- pci_map_single(nic->pdev, ba->ba_1, BUF1_LEN,
- PCI_DMA_FROMDEVICE);
+ /* Buffer-1 will be dummy buffer. Not used */
+ if (!(((RxD3_t*)rxdp)->Buffer1_ptr)) {
+ ((RxD3_t*)rxdp)->Buffer1_ptr =
+ pci_map_single(nic->pdev,
+ ba->ba_1, BUF1_LEN,
+ PCI_DMA_FROMDEVICE);
+ }
rxdp->Control_2 |= SET_BUFFER1_SIZE_3(1);
rxdp->Control_2 |= SET_BUFFER2_SIZE_3
(dev->mtu + 4);
@@ -2625,23 +2634,23 @@ no_rx:
}
#endif
+#ifdef CONFIG_NET_POLL_CONTROLLER
/**
- * s2io_netpoll - Rx interrupt service handler for netpoll support
+ * s2io_netpoll - netpoll event handler entry point
* @dev : pointer to the device structure.
* Description:
- * Polling 'interrupt' - used by things like netconsole to send skbs
- * without having to re-enable interrupts. It's not called while
- * the interrupt routine is executing.
+ * This function will be called by upper layer to check for events on the
+ * interface in situations where interrupts are disabled. It is used for
+ * specific in-kernel networking tasks, such as remote consoles and kernel
+ * debugging over the network (example netdump in RedHat).
*/
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
static void s2io_netpoll(struct net_device *dev)
{
nic_t *nic = dev->priv;
mac_info_t *mac_control;
struct config_param *config;
XENA_dev_config_t __iomem *bar0 = nic->bar0;
- u64 val64;
+ u64 val64 = 0xFFFFFFFFFFFFFFFFULL;
int i;
disable_irq(dev->irq);
@@ -2650,9 +2659,17 @@ static void s2io_netpoll(struct net_device *dev)
mac_control = &nic->mac_control;
config = &nic->config;
- val64 = readq(&bar0->rx_traffic_int);
writeq(val64, &bar0->rx_traffic_int);
+ writeq(val64, &bar0->tx_traffic_int);
+ /* we need to free up the transmitted skbufs or else netpoll will
+ * run out of skbs and will fail and eventually netpoll application such
+ * as netdump will fail.
+ */
+ for (i = 0; i < config->tx_fifo_num; i++)
+ tx_intr_handler(&mac_control->fifos[i]);
+
+ /* check for received packet and indicate up to network */
for (i = 0; i < config->rx_ring_num; i++)
rx_intr_handler(&mac_control->rings[i]);
@@ -2719,7 +2736,7 @@ static void rx_intr_handler(ring_info_t *ring_data)
/* If your are next to put index then it's FIFO full condition */
if ((get_block == put_block) &&
(get_info.offset + 1) == put_info.offset) {
- DBG_PRINT(ERR_DBG, "%s: Ring Full\n",dev->name);
+ DBG_PRINT(INTR_DBG, "%s: Ring Full\n",dev->name);
break;
}
skb = (struct sk_buff *) ((unsigned long)rxdp->Host_Control);
@@ -2739,18 +2756,15 @@ static void rx_intr_handler(ring_info_t *ring_data)
HEADER_SNAP_SIZE,
PCI_DMA_FROMDEVICE);
} else if (nic->rxd_mode == RXD_MODE_3B) {
- pci_unmap_single(nic->pdev, (dma_addr_t)
+ pci_dma_sync_single_for_cpu(nic->pdev, (dma_addr_t)
((RxD3_t*)rxdp)->Buffer0_ptr,
BUF0_LEN, PCI_DMA_FROMDEVICE);
pci_unmap_single(nic->pdev, (dma_addr_t)
- ((RxD3_t*)rxdp)->Buffer1_ptr,
- BUF1_LEN, PCI_DMA_FROMDEVICE);
- pci_unmap_single(nic->pdev, (dma_addr_t)
((RxD3_t*)rxdp)->Buffer2_ptr,
dev->mtu + 4,
PCI_DMA_FROMDEVICE);
} else {
- pci_unmap_single(nic->pdev, (dma_addr_t)
+ pci_dma_sync_single_for_cpu(nic->pdev, (dma_addr_t)
((RxD3_t*)rxdp)->Buffer0_ptr, BUF0_LEN,
PCI_DMA_FROMDEVICE);
pci_unmap_single(nic->pdev, (dma_addr_t)
@@ -3338,7 +3352,7 @@ static void s2io_reset(nic_t * sp)
/* Clear certain PCI/PCI-X fields after reset */
if (sp->device_type == XFRAME_II_DEVICE) {
- /* Clear parity err detect bit */
+ /* Clear "detected parity error" bit */
pci_write_config_word(sp->pdev, PCI_STATUS, 0x8000);
/* Clearing PCIX Ecc status register */
@@ -3539,7 +3553,7 @@ static void restore_xmsi_data(nic_t *nic)
u64 val64;
int i;
- for (i=0; i< nic->avail_msix_vectors; i++) {
+ for (i=0; i < MAX_REQUESTED_MSI_X; i++) {
writeq(nic->msix_info[i].addr, &bar0->xmsi_address);
writeq(nic->msix_info[i].data, &bar0->xmsi_data);
val64 = (BIT(7) | BIT(15) | vBIT(i, 26, 6));
@@ -3558,7 +3572,7 @@ static void store_xmsi_data(nic_t *nic)
int i;
/* Store and display */
- for (i=0; i< nic->avail_msix_vectors; i++) {
+ for (i=0; i < MAX_REQUESTED_MSI_X; i++) {
val64 = (BIT(15) | vBIT(i, 26, 6));
writeq(val64, &bar0->xmsi_access);
if (wait_for_msix_trans(nic, i)) {
@@ -3749,101 +3763,19 @@ static int s2io_open(struct net_device *dev)
if (err) {
DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n",
dev->name);
- if (err == -ENODEV)
- goto hw_init_failed;
- else
- goto hw_enable_failed;
- }
-
- /* Store the values of the MSIX table in the nic_t structure */
- store_xmsi_data(sp);
-
- /* After proper initialization of H/W, register ISR */
- if (sp->intr_type == MSI) {
- err = request_irq((int) sp->pdev->irq, s2io_msi_handle,
- IRQF_SHARED, sp->name, dev);
- if (err) {
- DBG_PRINT(ERR_DBG, "%s: MSI registration \
-failed\n", dev->name);
- goto isr_registration_failed;
- }
- }
- if (sp->intr_type == MSI_X) {
- int i;
-
- for (i=1; (sp->s2io_entries[i].in_use == MSIX_FLG); i++) {
- if (sp->s2io_entries[i].type == MSIX_FIFO_TYPE) {
- sprintf(sp->desc1, "%s:MSI-X-%d-TX",
- dev->name, i);
- err = request_irq(sp->entries[i].vector,
- s2io_msix_fifo_handle, 0, sp->desc1,
- sp->s2io_entries[i].arg);
- DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc1,
- (unsigned long long)sp->msix_info[i].addr);
- } else {
- sprintf(sp->desc2, "%s:MSI-X-%d-RX",
- dev->name, i);
- err = request_irq(sp->entries[i].vector,
- s2io_msix_ring_handle, 0, sp->desc2,
- sp->s2io_entries[i].arg);
- DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc2,
- (unsigned long long)sp->msix_info[i].addr);
- }
- if (err) {
- DBG_PRINT(ERR_DBG, "%s: MSI-X-%d registration \
-failed\n", dev->name, i);
- DBG_PRINT(ERR_DBG, "Returned: %d\n", err);
- goto isr_registration_failed;
- }
- sp->s2io_entries[i].in_use = MSIX_REGISTERED_SUCCESS;
- }
- }
- if (sp->intr_type == INTA) {
- err = request_irq((int) sp->pdev->irq, s2io_isr, IRQF_SHARED,
- sp->name, dev);
- if (err) {
- DBG_PRINT(ERR_DBG, "%s: ISR registration failed\n",
- dev->name);
- goto isr_registration_failed;
- }
+ goto hw_init_failed;
}
if (s2io_set_mac_addr(dev, dev->dev_addr) == FAILURE) {
DBG_PRINT(ERR_DBG, "Set Mac Address Failed\n");
+ s2io_card_down(sp);
err = -ENODEV;
- goto setting_mac_address_failed;
+ goto hw_init_failed;
}
netif_start_queue(dev);
return 0;
-setting_mac_address_failed:
- if (sp->intr_type != MSI_X)
- free_irq(sp->pdev->irq, dev);
-isr_registration_failed:
- del_timer_sync(&sp->alarm_timer);
- if (sp->intr_type == MSI_X) {
- int i;
- u16 msi_control; /* Temp variable */
-
- for (i=1; (sp->s2io_entries[i].in_use ==
- MSIX_REGISTERED_SUCCESS); i++) {
- int vector = sp->entries[i].vector;
- void *arg = sp->s2io_entries[i].arg;
-
- free_irq(vector, arg);
- }
- pci_disable_msix(sp->pdev);
-
- /* Temp */
- pci_read_config_word(sp->pdev, 0x42, &msi_control);
- msi_control &= 0xFFFE; /* Disable MSI */
- pci_write_config_word(sp->pdev, 0x42, msi_control);
- }
- else if (sp->intr_type == MSI)
- pci_disable_msi(sp->pdev);
-hw_enable_failed:
- s2io_reset(sp);
hw_init_failed:
if (sp->intr_type == MSI_X) {
if (sp->entries)
@@ -3874,7 +3806,7 @@ static int s2io_close(struct net_device *dev)
flush_scheduled_work();
netif_stop_queue(dev);
/* Reset card, kill tasklet and free Tx and Rx buffers. */
- s2io_card_down(sp, 1);
+ s2io_card_down(sp);
sp->device_close_flag = TRUE; /* Device is shut down. */
return 0;
@@ -3901,13 +3833,11 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
TxD_t *txdp;
TxFIFO_element_t __iomem *tx_fifo;
unsigned long flags;
-#ifdef NETIF_F_TSO
- int mss;
-#endif
u16 vlan_tag = 0;
int vlan_priority = 0;
mac_info_t *mac_control;
struct config_param *config;
+ int offload_type;
mac_control = &sp->mac_control;
config = &sp->config;
@@ -3955,13 +3885,11 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
return 0;
}
- txdp->Control_1 = 0;
- txdp->Control_2 = 0;
+ offload_type = s2io_offload_type(skb);
#ifdef NETIF_F_TSO
- mss = skb_shinfo(skb)->gso_size;
- if (skb_shinfo(skb)->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) {
+ if (offload_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) {
txdp->Control_1 |= TXD_TCP_LSO_EN;
- txdp->Control_1 |= TXD_TCP_LSO_MSS(mss);
+ txdp->Control_1 |= TXD_TCP_LSO_MSS(s2io_tcp_mss(skb));
}
#endif
if (skb->ip_summed == CHECKSUM_HW) {
@@ -3979,10 +3907,10 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
}
frg_len = skb->len - skb->data_len;
- if (skb_shinfo(skb)->gso_type == SKB_GSO_UDP) {
+ if (offload_type == SKB_GSO_UDP) {
int ufo_size;
- ufo_size = skb_shinfo(skb)->gso_size;
+ ufo_size = s2io_udp_mss(skb);
ufo_size &= ~7;
txdp->Control_1 |= TXD_UFO_EN;
txdp->Control_1 |= TXD_UFO_MSS(ufo_size);
@@ -3999,16 +3927,13 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
sp->ufo_in_band_v,
sizeof(u64), PCI_DMA_TODEVICE);
txdp++;
- txdp->Control_1 = 0;
- txdp->Control_2 = 0;
}
txdp->Buffer_Pointer = pci_map_single
(sp->pdev, skb->data, frg_len, PCI_DMA_TODEVICE);
txdp->Host_Control = (unsigned long) skb;
txdp->Control_1 |= TXD_BUFFER0_SIZE(frg_len);
-
- if (skb_shinfo(skb)->gso_type == SKB_GSO_UDP)
+ if (offload_type == SKB_GSO_UDP)
txdp->Control_1 |= TXD_UFO_EN;
frg_cnt = skb_shinfo(skb)->nr_frags;
@@ -4023,12 +3948,12 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
(sp->pdev, frag->page, frag->page_offset,
frag->size, PCI_DMA_TODEVICE);
txdp->Control_1 = TXD_BUFFER0_SIZE(frag->size);
- if (skb_shinfo(skb)->gso_type == SKB_GSO_UDP)
+ if (offload_type == SKB_GSO_UDP)
txdp->Control_1 |= TXD_UFO_EN;
}
txdp->Control_1 |= TXD_GATHER_CODE_LAST;
- if (skb_shinfo(skb)->gso_type == SKB_GSO_UDP)
+ if (offload_type == SKB_GSO_UDP)
frg_cnt++; /* as Txd0 was used for inband header */
tx_fifo = mac_control->tx_FIFO_start[queue];
@@ -4037,13 +3962,9 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
val64 = (TX_FIFO_LAST_TXD_NUM(frg_cnt) | TX_FIFO_FIRST_LIST |
TX_FIFO_LAST_LIST);
-
-#ifdef NETIF_F_TSO
- if (mss)
- val64 |= TX_FIFO_SPECIAL_FUNC;
-#endif
- if (skb_shinfo(skb)->gso_type == SKB_GSO_UDP)
+ if (offload_type)
val64 |= TX_FIFO_SPECIAL_FUNC;
+
writeq(val64, &tx_fifo->List_Control);
mmiowb();
@@ -4077,13 +3998,41 @@ s2io_alarm_handle(unsigned long data)
mod_timer(&sp->alarm_timer, jiffies + HZ / 2);
}
+static int s2io_chk_rx_buffers(nic_t *sp, int rng_n)
+{
+ int rxb_size, level;
+
+ if (!sp->lro) {
+ rxb_size = atomic_read(&sp->rx_bufs_left[rng_n]);
+ level = rx_buffer_level(sp, rxb_size, rng_n);
+
+ if ((level == PANIC) && (!TASKLET_IN_USE)) {
+ int ret;
+ DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", __FUNCTION__);
+ DBG_PRINT(INTR_DBG, "PANIC levels\n");
+ if ((ret = fill_rx_buffers(sp, rng_n)) == -ENOMEM) {
+ DBG_PRINT(ERR_DBG, "Out of memory in %s",
+ __FUNCTION__);
+ clear_bit(0, (&sp->tasklet_status));
+ return -1;
+ }
+ clear_bit(0, (&sp->tasklet_status));
+ } else if (level == LOW)
+ tasklet_schedule(&sp->task);
+
+ } else if (fill_rx_buffers(sp, rng_n) == -ENOMEM) {
+ DBG_PRINT(ERR_DBG, "%s:Out of memory", sp->dev->name);
+ DBG_PRINT(ERR_DBG, " in Rx Intr!!\n");
+ }
+ return 0;
+}
+
static irqreturn_t
s2io_msi_handle(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = (struct net_device *) dev_id;
nic_t *sp = dev->priv;
int i;
- int ret;
mac_info_t *mac_control;
struct config_param *config;
@@ -4105,35 +4054,8 @@ s2io_msi_handle(int irq, void *dev_id, struct pt_regs *regs)
* reallocate the buffers from the interrupt handler itself,
* else schedule a tasklet to reallocate the buffers.
*/
- for (i = 0; i < config->rx_ring_num; i++) {
- if (!sp->lro) {
- int rxb_size = atomic_read(&sp->rx_bufs_left[i]);
- int level = rx_buffer_level(sp, rxb_size, i);
-
- if ((level == PANIC) && (!TASKLET_IN_USE)) {
- DBG_PRINT(INTR_DBG, "%s: Rx BD hit ",
- dev->name);
- DBG_PRINT(INTR_DBG, "PANIC levels\n");
- if ((ret = fill_rx_buffers(sp, i)) == -ENOMEM) {
- DBG_PRINT(ERR_DBG, "%s:Out of memory",
- dev->name);
- DBG_PRINT(ERR_DBG, " in ISR!!\n");
- clear_bit(0, (&sp->tasklet_status));
- atomic_dec(&sp->isr_cnt);
- return IRQ_HANDLED;
- }
- clear_bit(0, (&sp->tasklet_status));
- } else if (level == LOW) {
- tasklet_schedule(&sp->task);
- }
- }
- else if (fill_rx_buffers(sp, i) == -ENOMEM) {
- DBG_PRINT(ERR_DBG, "%s:Out of memory",
- dev->name);
- DBG_PRINT(ERR_DBG, " in Rx Intr!!\n");
- break;
- }
- }
+ for (i = 0; i < config->rx_ring_num; i++)
+ s2io_chk_rx_buffers(sp, i);
atomic_dec(&sp->isr_cnt);
return IRQ_HANDLED;
@@ -4144,39 +4066,13 @@ s2io_msix_ring_handle(int irq, void *dev_id, struct pt_regs *regs)
{
ring_info_t *ring = (ring_info_t *)dev_id;
nic_t *sp = ring->nic;
- struct net_device *dev = (struct net_device *) dev_id;
- int rxb_size, level, rng_n;
atomic_inc(&sp->isr_cnt);
- rx_intr_handler(ring);
- rng_n = ring->ring_no;
- if (!sp->lro) {
- rxb_size = atomic_read(&sp->rx_bufs_left[rng_n]);
- level = rx_buffer_level(sp, rxb_size, rng_n);
-
- if ((level == PANIC) && (!TASKLET_IN_USE)) {
- int ret;
- DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", __FUNCTION__);
- DBG_PRINT(INTR_DBG, "PANIC levels\n");
- if ((ret = fill_rx_buffers(sp, rng_n)) == -ENOMEM) {
- DBG_PRINT(ERR_DBG, "Out of memory in %s",
- __FUNCTION__);
- clear_bit(0, (&sp->tasklet_status));
- return IRQ_HANDLED;
- }
- clear_bit(0, (&sp->tasklet_status));
- } else if (level == LOW) {
- tasklet_schedule(&sp->task);
- }
- }
- else if (fill_rx_buffers(sp, rng_n) == -ENOMEM) {
- DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
- DBG_PRINT(ERR_DBG, " in Rx Intr!!\n");
- }
+ rx_intr_handler(ring);
+ s2io_chk_rx_buffers(sp, ring->ring_no);
atomic_dec(&sp->isr_cnt);
-
return IRQ_HANDLED;
}
@@ -4341,37 +4237,8 @@ static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs)
* else schedule a tasklet to reallocate the buffers.
*/
#ifndef CONFIG_S2IO_NAPI
- for (i = 0; i < config->rx_ring_num; i++) {
- if (!sp->lro) {
- int ret;
- int rxb_size = atomic_read(&sp->rx_bufs_left[i]);
- int level = rx_buffer_level(sp, rxb_size, i);
-
- if ((level == PANIC) && (!TASKLET_IN_USE)) {
- DBG_PRINT(INTR_DBG, "%s: Rx BD hit ",
- dev->name);
- DBG_PRINT(INTR_DBG, "PANIC levels\n");
- if ((ret = fill_rx_buffers(sp, i)) == -ENOMEM) {
- DBG_PRINT(ERR_DBG, "%s:Out of memory",
- dev->name);
- DBG_PRINT(ERR_DBG, " in ISR!!\n");
- clear_bit(0, (&sp->tasklet_status));
- atomic_dec(&sp->isr_cnt);
- writeq(org_mask, &bar0->general_int_mask);
- return IRQ_HANDLED;
- }
- clear_bit(0, (&sp->tasklet_status));
- } else if (level == LOW) {
- tasklet_schedule(&sp->task);
- }
- }
- else if (fill_rx_buffers(sp, i) == -ENOMEM) {
- DBG_PRINT(ERR_DBG, "%s:Out of memory",
- dev->name);
- DBG_PRINT(ERR_DBG, " in Rx intr!!\n");
- break;
- }
- }
+ for (i = 0; i < config->rx_ring_num; i++)
+ s2io_chk_rx_buffers(sp, i);
#endif
writeq(org_mask, &bar0->general_int_mask);
atomic_dec(&sp->isr_cnt);
@@ -4401,6 +4268,8 @@ static void s2io_updt_stats(nic_t *sp)
if (cnt == 5)
break; /* Updt failed */
} while(1);
+ } else {
+ memset(sp->mac_control.stats_info, 0, sizeof(StatInfo_t));
}
}
@@ -5035,7 +4904,8 @@ static int write_eeprom(nic_t * sp, int off, u64 data, int cnt)
}
static void s2io_vpd_read(nic_t *nic)
{
- u8 vpd_data[256],data;
+ u8 *vpd_data;
+ u8 data;
int i=0, cnt, fail = 0;
int vpd_addr = 0x80;
@@ -5048,6 +4918,10 @@ static void s2io_vpd_read(nic_t *nic)
vpd_addr = 0x50;
}
+ vpd_data = kmalloc(256, GFP_KERNEL);
+ if (!vpd_data)
+ return;
+
for (i = 0; i < 256; i +=4 ) {
pci_write_config_byte(nic->pdev, (vpd_addr + 2), i);
pci_read_config_byte(nic->pdev, (vpd_addr + 2), &data);
@@ -5070,6 +4944,7 @@ static void s2io_vpd_read(nic_t *nic)
memset(nic->product_name, 0, vpd_data[1]);
memcpy(nic->product_name, &vpd_data[3], vpd_data[1]);
}
+ kfree(vpd_data);
}
/**
@@ -5388,7 +5263,7 @@ static int s2io_link_test(nic_t * sp, uint64_t * data)
else
*data = 0;
- return 0;
+ return *data;
}
/**
@@ -5846,6 +5721,19 @@ static int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
return 0;
}
+static u32 s2io_ethtool_op_get_tso(struct net_device *dev)
+{
+ return (dev->features & NETIF_F_TSO) != 0;
+}
+static int s2io_ethtool_op_set_tso(struct net_device *dev, u32 data)
+{
+ if (data)
+ dev->features |= (NETIF_F_TSO | NETIF_F_TSO6);
+ else
+ dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
+
+ return 0;
+}
static struct ethtool_ops netdev_ethtool_ops = {
.get_settings = s2io_ethtool_gset,
@@ -5866,8 +5754,8 @@ static struct ethtool_ops netdev_ethtool_ops = {
.get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
#ifdef NETIF_F_TSO
- .get_tso = ethtool_op_get_tso,
- .set_tso = ethtool_op_set_tso,
+ .get_tso = s2io_ethtool_op_get_tso,
+ .set_tso = s2io_ethtool_op_set_tso,
#endif
.get_ufo = ethtool_op_get_ufo,
.set_ufo = ethtool_op_set_ufo,
@@ -5919,7 +5807,7 @@ static int s2io_change_mtu(struct net_device *dev, int new_mtu)
dev->mtu = new_mtu;
if (netif_running(dev)) {
- s2io_card_down(sp, 0);
+ s2io_card_down(sp);
netif_stop_queue(dev);
if (s2io_card_up(sp)) {
DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
@@ -6216,43 +6104,106 @@ static int rxd_owner_bit_reset(nic_t *sp)
}
-static void s2io_card_down(nic_t * sp, int flag)
+static int s2io_add_isr(nic_t * sp)
{
- int cnt = 0;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
- unsigned long flags;
- register u64 val64 = 0;
+ int ret = 0;
struct net_device *dev = sp->dev;
+ int err = 0;
- del_timer_sync(&sp->alarm_timer);
- /* If s2io_set_link task is executing, wait till it completes. */
- while (test_and_set_bit(0, &(sp->link_state))) {
- msleep(50);
+ if (sp->intr_type == MSI)
+ ret = s2io_enable_msi(sp);
+ else if (sp->intr_type == MSI_X)
+ ret = s2io_enable_msi_x(sp);
+ if (ret) {
+ DBG_PRINT(ERR_DBG, "%s: Defaulting to INTA\n", dev->name);
+ sp->intr_type = INTA;
}
- atomic_set(&sp->card_state, CARD_DOWN);
- /* disable Tx and Rx traffic on the NIC */
- stop_nic(sp);
- if (flag) {
- if (sp->intr_type == MSI_X) {
- int i;
- u16 msi_control;
+ /* Store the values of the MSIX table in the nic_t structure */
+ store_xmsi_data(sp);
- for (i=1; (sp->s2io_entries[i].in_use ==
- MSIX_REGISTERED_SUCCESS); i++) {
- int vector = sp->entries[i].vector;
- void *arg = sp->s2io_entries[i].arg;
+ /* After proper initialization of H/W, register ISR */
+ if (sp->intr_type == MSI) {
+ err = request_irq((int) sp->pdev->irq, s2io_msi_handle,
+ IRQF_SHARED, sp->name, dev);
+ if (err) {
+ pci_disable_msi(sp->pdev);
+ DBG_PRINT(ERR_DBG, "%s: MSI registration failed\n",
+ dev->name);
+ return -1;
+ }
+ }
+ if (sp->intr_type == MSI_X) {
+ int i;
- free_irq(vector, arg);
+ for (i=1; (sp->s2io_entries[i].in_use == MSIX_FLG); i++) {
+ if (sp->s2io_entries[i].type == MSIX_FIFO_TYPE) {
+ sprintf(sp->desc[i], "%s:MSI-X-%d-TX",
+ dev->name, i);
+ err = request_irq(sp->entries[i].vector,
+ s2io_msix_fifo_handle, 0, sp->desc[i],
+ sp->s2io_entries[i].arg);
+ DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc[i],
+ (unsigned long long)sp->msix_info[i].addr);
+ } else {
+ sprintf(sp->desc[i], "%s:MSI-X-%d-RX",
+ dev->name, i);
+ err = request_irq(sp->entries[i].vector,
+ s2io_msix_ring_handle, 0, sp->desc[i],
+ sp->s2io_entries[i].arg);
+ DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc[i],
+ (unsigned long long)sp->msix_info[i].addr);
}
- pci_read_config_word(sp->pdev, 0x42, &msi_control);
- msi_control &= 0xFFFE; /* Disable MSI */
- pci_write_config_word(sp->pdev, 0x42, msi_control);
- pci_disable_msix(sp->pdev);
- } else {
- free_irq(sp->pdev->irq, dev);
- if (sp->intr_type == MSI)
- pci_disable_msi(sp->pdev);
+ if (err) {
+ DBG_PRINT(ERR_DBG,"%s:MSI-X-%d registration "
+ "failed\n", dev->name, i);
+ DBG_PRINT(ERR_DBG, "Returned: %d\n", err);
+ return -1;
+ }
+ sp->s2io_entries[i].in_use = MSIX_REGISTERED_SUCCESS;
+ }
+ }
+ if (sp->intr_type == INTA) {
+ err = request_irq((int) sp->pdev->irq, s2io_isr, IRQF_SHARED,
+ sp->name, dev);
+ if (err) {
+ DBG_PRINT(ERR_DBG, "%s: ISR registration failed\n",
+ dev->name);
+ return -1;
+ }
+ }
+ return 0;
+}
+static void s2io_rem_isr(nic_t * sp)
+{
+ int cnt = 0;
+ struct net_device *dev = sp->dev;
+
+ if (sp->intr_type == MSI_X) {
+ int i;
+ u16 msi_control;
+
+ for (i=1; (sp->s2io_entries[i].in_use ==
+ MSIX_REGISTERED_SUCCESS); i++) {
+ int vector = sp->entries[i].vector;
+ void *arg = sp->s2io_entries[i].arg;
+
+ free_irq(vector, arg);
+ }
+ pci_read_config_word(sp->pdev, 0x42, &msi_control);
+ msi_control &= 0xFFFE; /* Disable MSI */
+ pci_write_config_word(sp->pdev, 0x42, msi_control);
+
+ pci_disable_msix(sp->pdev);
+ } else {
+ free_irq(sp->pdev->irq, dev);
+ if (sp->intr_type == MSI) {
+ u16 val;
+
+ pci_disable_msi(sp->pdev);
+ pci_read_config_word(sp->pdev, 0x4c, &val);
+ val ^= 0x1;
+ pci_write_config_word(sp->pdev, 0x4c, val);
}
}
/* Waiting till all Interrupt handlers are complete */
@@ -6263,6 +6214,26 @@ static void s2io_card_down(nic_t * sp, int flag)
break;
cnt++;
} while(cnt < 5);
+}
+
+static void s2io_card_down(nic_t * sp)
+{
+ int cnt = 0;
+ XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ unsigned long flags;
+ register u64 val64 = 0;
+
+ del_timer_sync(&sp->alarm_timer);
+ /* If s2io_set_link task is executing, wait till it completes. */
+ while (test_and_set_bit(0, &(sp->link_state))) {
+ msleep(50);
+ }
+ atomic_set(&sp->card_state, CARD_DOWN);
+
+ /* disable Tx and Rx traffic on the NIC */
+ stop_nic(sp);
+
+ s2io_rem_isr(sp);
/* Kill tasklet. */
tasklet_kill(&sp->task);
@@ -6314,23 +6285,16 @@ static int s2io_card_up(nic_t * sp)
mac_info_t *mac_control;
struct config_param *config;
struct net_device *dev = (struct net_device *) sp->dev;
+ u16 interruptible;
/* Initialize the H/W I/O registers */
if (init_nic(sp) != 0) {
DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n",
dev->name);
+ s2io_reset(sp);
return -ENODEV;
}
- if (sp->intr_type == MSI)
- ret = s2io_enable_msi(sp);
- else if (sp->intr_type == MSI_X)
- ret = s2io_enable_msi_x(sp);
- if (ret) {
- DBG_PRINT(ERR_DBG, "%s: Defaulting to INTA\n", dev->name);
- sp->intr_type = INTA;
- }
-
/*
* Initializing the Rx buffers. For now we are considering only 1
* Rx ring and initializing buffers into 30 Rx blocks
@@ -6354,28 +6318,46 @@ static int s2io_card_up(nic_t * sp)
s2io_set_multicast(dev);
if (sp->lro) {
- /* Initialize max aggregatable pkts based on MTU */
+ /* Initialize max aggregatable pkts per session based on MTU */
sp->lro_max_aggr_per_sess = ((1<<16) - 1) / dev->mtu;
/* Check if we can use(if specified) user provided value */
if (lro_max_pkts < sp->lro_max_aggr_per_sess)
sp->lro_max_aggr_per_sess = lro_max_pkts;
}
- /* Enable tasklet for the device */
- tasklet_init(&sp->task, s2io_tasklet, (unsigned long) dev);
-
/* Enable Rx Traffic and interrupts on the NIC */
if (start_nic(sp)) {
DBG_PRINT(ERR_DBG, "%s: Starting NIC failed\n", dev->name);
- tasklet_kill(&sp->task);
s2io_reset(sp);
- free_irq(dev->irq, dev);
+ free_rx_buffers(sp);
+ return -ENODEV;
+ }
+
+ /* Add interrupt service routine */
+ if (s2io_add_isr(sp) != 0) {
+ if (sp->intr_type == MSI_X)
+ s2io_rem_isr(sp);
+ s2io_reset(sp);
free_rx_buffers(sp);
return -ENODEV;
}
S2IO_TIMER_CONF(sp->alarm_timer, s2io_alarm_handle, sp, (HZ/2));
+ /* Enable tasklet for the device */
+ tasklet_init(&sp->task, s2io_tasklet, (unsigned long) dev);
+
+ /* Enable select interrupts */
+ if (sp->intr_type != INTA)
+ en_dis_able_nic_intrs(sp, ENA_ALL_INTRS, DISABLE_INTRS);
+ else {
+ interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR;
+ interruptible |= TX_PIC_INTR | RX_PIC_INTR;
+ interruptible |= TX_MAC_INTR | RX_MAC_INTR;
+ en_dis_able_nic_intrs(sp, interruptible, ENABLE_INTRS);
+ }
+
+
atomic_set(&sp->card_state, CARD_UP);
return 0;
}
@@ -6395,7 +6377,7 @@ static void s2io_restart_nic(unsigned long data)
struct net_device *dev = (struct net_device *) data;
nic_t *sp = dev->priv;
- s2io_card_down(sp, 0);
+ s2io_card_down(sp);
if (s2io_card_up(sp)) {
DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
dev->name);
@@ -6437,7 +6419,7 @@ static void s2io_tx_watchdog(struct net_device *dev)
* @cksum : FCS checksum of the frame.
* @ring_no : the ring from which this RxD was extracted.
* Description:
- * This function is called by the Tx interrupt serivce routine to perform
+ * This function is called by the Rx interrupt serivce routine to perform
* some OS related operations on the SKB before passing it to the upper
* layers. It mainly checks if the checksum is OK, if so adds it to the
* SKBs cksum variable, increments the Rx packet count and passes the SKB
@@ -6697,33 +6679,6 @@ static void s2io_init_pci(nic_t * sp)
pci_read_config_word(sp->pdev, PCI_COMMAND, &pci_cmd);
}
-MODULE_AUTHOR("Raghavendra Koushik <raghavendra.koushik@neterion.com>");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRV_VERSION);
-
-module_param(tx_fifo_num, int, 0);
-module_param(rx_ring_num, int, 0);
-module_param(rx_ring_mode, int, 0);
-module_param_array(tx_fifo_len, uint, NULL, 0);
-module_param_array(rx_ring_sz, uint, NULL, 0);
-module_param_array(rts_frm_len, uint, NULL, 0);
-module_param(use_continuous_tx_intrs, int, 1);
-module_param(rmac_pause_time, int, 0);
-module_param(mc_pause_threshold_q0q3, int, 0);
-module_param(mc_pause_threshold_q4q7, int, 0);
-module_param(shared_splits, int, 0);
-module_param(tmac_util_period, int, 0);
-module_param(rmac_util_period, int, 0);
-module_param(bimodal, bool, 0);
-module_param(l3l4hdr_size, int , 0);
-#ifndef CONFIG_S2IO_NAPI
-module_param(indicate_max_pkts, int, 0);
-#endif
-module_param(rxsync_frequency, int, 0);
-module_param(intr_type, int, 0);
-module_param(lro, int, 0);
-module_param(lro_max_pkts, int, 0);
-
static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type)
{
if ( tx_fifo_num > 8) {
@@ -6831,8 +6786,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
}
if (dev_intr_type != MSI_X) {
if (pci_request_regions(pdev, s2io_driver_name)) {
- DBG_PRINT(ERR_DBG, "Request Regions failed\n"),
- pci_disable_device(pdev);
+ DBG_PRINT(ERR_DBG, "Request Regions failed\n");
+ pci_disable_device(pdev);
return -ENODEV;
}
}
@@ -6956,7 +6911,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
/* initialize the shared memory used by the NIC and the host */
if (init_shared_mem(sp)) {
DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n",
- __FUNCTION__);
+ dev->name);
ret = -ENOMEM;
goto mem_alloc_failed;
}
@@ -7093,6 +7048,9 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
dev->addr_len = ETH_ALEN;
memcpy(dev->dev_addr, sp->def_mac_addr, ETH_ALEN);
+ /* reset Nic and bring it to known state */
+ s2io_reset(sp);
+
/*
* Initialize the tasklet status and link state flags
* and the card state parameter
@@ -7130,11 +7088,11 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
goto register_failed;
}
s2io_vpd_read(sp);
- DBG_PRINT(ERR_DBG, "%s: Neterion %s",dev->name, sp->product_name);
- DBG_PRINT(ERR_DBG, "(rev %d), Driver version %s\n",
- get_xena_rev_id(sp->pdev),
- s2io_driver_version);
DBG_PRINT(ERR_DBG, "Copyright(c) 2002-2005 Neterion Inc.\n");
+ DBG_PRINT(ERR_DBG, "%s: Neterion %s (rev %d)\n",dev->name,
+ sp->product_name, get_xena_rev_id(sp->pdev));
+ DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name,
+ s2io_driver_version);
DBG_PRINT(ERR_DBG, "%s: MAC ADDR: "
"%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name,
sp->def_mac_addr[0].mac_addr[0],
@@ -7435,8 +7393,13 @@ static int verify_l3_l4_lro_capable(lro_t *l_lro, struct iphdr *ip,
if (ip->ihl != 5) /* IP has options */
return -1;
+ /* If we see CE codepoint in IP header, packet is not mergeable */
+ if (INET_ECN_is_ce(ipv4_get_dsfield(ip)))
+ return -1;
+
+ /* If we see ECE or CWR flags in TCP header, packet is not mergeable */
if (tcp->urg || tcp->psh || tcp->rst || tcp->syn || tcp->fin ||
- !tcp->ack) {
+ tcp->ece || tcp->cwr || !tcp->ack) {
/*
* Currently recognize only the ack control word and
* any other control field being set would result in
@@ -7590,18 +7553,16 @@ static void queue_rx_frame(struct sk_buff *skb)
static void lro_append_pkt(nic_t *sp, lro_t *lro, struct sk_buff *skb,
u32 tcp_len)
{
- struct sk_buff *tmp, *first = lro->parent;
+ struct sk_buff *first = lro->parent;
first->len += tcp_len;
first->data_len = lro->frags_len;
skb_pull(skb, (skb->len - tcp_len));
- if ((tmp = skb_shinfo(first)->frag_list)) {
- while (tmp->next)
- tmp = tmp->next;
- tmp->next = skb;
- }
+ if (skb_shinfo(first)->frag_list)
+ lro->last_frag->next = skb;
else
skb_shinfo(first)->frag_list = skb;
+ lro->last_frag = skb;
sp->mac_control.stats_info->sw_stat.clubbed_frms_cnt++;
return;
}
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h
index c43f5217970..5ed49c3be1e 100644
--- a/drivers/net/s2io.h
+++ b/drivers/net/s2io.h
@@ -719,6 +719,7 @@ struct msix_info_st {
/* Data structure to represent a LRO session */
typedef struct lro {
struct sk_buff *parent;
+ struct sk_buff *last_frag;
u8 *l2h;
struct iphdr *iph;
struct tcphdr *tcph;
@@ -829,8 +830,7 @@ struct s2io_nic {
#define MSIX_FLG 0xA5
struct msix_entry *entries;
struct s2io_msix_entry *s2io_entries;
- char desc1[35];
- char desc2[35];
+ char desc[MAX_REQUESTED_MSI_X][25];
int avail_msix_vectors; /* No. of MSI-X vectors granted by system */
@@ -1002,7 +1002,7 @@ static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag);
static struct ethtool_ops netdev_ethtool_ops;
static void s2io_set_link(unsigned long data);
static int s2io_set_swapper(nic_t * sp);
-static void s2io_card_down(nic_t *nic, int flag);
+static void s2io_card_down(nic_t *nic);
static int s2io_card_up(nic_t *nic);
static int get_xena_rev_id(struct pci_dev *pdev);
static void restore_xmsi_data(nic_t *nic);
@@ -1012,4 +1012,13 @@ static void clear_lro_session(lro_t *lro);
static void queue_rx_frame(struct sk_buff *skb);
static void update_L3L4_header(nic_t *sp, lro_t *lro);
static void lro_append_pkt(nic_t *sp, lro_t *lro, struct sk_buff *skb, u32 tcp_len);
+
+#define s2io_tcp_mss(skb) skb_shinfo(skb)->gso_size
+#define s2io_udp_mss(skb) skb_shinfo(skb)->gso_size
+#define s2io_offload_type(skb) skb_shinfo(skb)->gso_type
+
+#define S2IO_PARM_INT(X, def_val) \
+ static unsigned int X = def_val;\
+ module_param(X , uint, 0);
+
#endif /* _S2IO_H */
diff --git a/drivers/net/sk98lin/h/xmac_ii.h b/drivers/net/sk98lin/h/xmac_ii.h
index 2b19f8ad031..7f8e6d0084c 100644
--- a/drivers/net/sk98lin/h/xmac_ii.h
+++ b/drivers/net/sk98lin/h/xmac_ii.h
@@ -1473,7 +1473,7 @@ extern "C" {
#define GM_TXCR_FORCE_JAM (1<<15) /* Bit 15: Force Jam / Flow-Control */
#define GM_TXCR_CRC_DIS (1<<14) /* Bit 14: Disable insertion of CRC */
#define GM_TXCR_PAD_DIS (1<<13) /* Bit 13: Disable padding of packets */
-#define GM_TXCR_COL_THR_MSK (1<<10) /* Bit 12..10: Collision Threshold */
+#define GM_TXCR_COL_THR_MSK (7<<10) /* Bit 12..10: Collision Threshold */
#define TX_COL_THR(x) (SHIFT10(x) & GM_TXCR_COL_THR_MSK)
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index 82200bfaa8e..7de9a07b2ac 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -516,10 +516,7 @@ static int skge_set_pauseparam(struct net_device *dev,
/* Chip internal frequency for clock calculations */
static inline u32 hwkhz(const struct skge_hw *hw)
{
- if (hw->chip_id == CHIP_ID_GENESIS)
- return 53215; /* or: 53.125 MHz */
- else
- return 78215; /* or: 78.125 MHz */
+ return (hw->chip_id == CHIP_ID_GENESIS) ? 53125 : 78125;
}
/* Chip HZ to microseconds */
diff --git a/drivers/net/skge.h b/drivers/net/skge.h
index ed19ff47ce1..593387b3c0d 100644
--- a/drivers/net/skge.h
+++ b/drivers/net/skge.h
@@ -1734,11 +1734,11 @@ enum {
GM_TXCR_FORCE_JAM = 1<<15, /* Bit 15: Force Jam / Flow-Control */
GM_TXCR_CRC_DIS = 1<<14, /* Bit 14: Disable insertion of CRC */
GM_TXCR_PAD_DIS = 1<<13, /* Bit 13: Disable padding of packets */
- GM_TXCR_COL_THR_MSK = 1<<10, /* Bit 12..10: Collision Threshold */
+ GM_TXCR_COL_THR_MSK = 7<<10, /* Bit 12..10: Collision Threshold */
};
#define TX_COL_THR(x) (((x)<<10) & GM_TXCR_COL_THR_MSK)
-#define TX_COL_DEF 0x04
+#define TX_COL_DEF 0x04 /* late collision after 64 byte */
/* GM_RX_CTRL 16 bit r/w Receive Control Register */
enum {
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 418f169a6a3..de91609ca11 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -50,7 +50,7 @@
#include "sky2.h"
#define DRV_NAME "sky2"
-#define DRV_VERSION "1.4"
+#define DRV_VERSION "1.5"
#define PFX DRV_NAME " "
/*
@@ -65,6 +65,7 @@
#define RX_MAX_PENDING (RX_LE_SIZE/2 - 2)
#define RX_DEF_PENDING RX_MAX_PENDING
#define RX_SKB_ALIGN 8
+#define RX_BUF_WRITE 16
#define TX_RING_SIZE 512
#define TX_DEF_PENDING (TX_RING_SIZE - 1)
@@ -234,7 +235,6 @@ static void sky2_set_power_state(struct sky2_hw *hw, pci_power_t state)
}
if (hw->chip_id == CHIP_ID_YUKON_EC_U) {
- sky2_write16(hw, B0_CTST, Y2_HW_WOL_ON);
sky2_pci_write32(hw, PCI_DEV_REG3, 0);
reg1 = sky2_pci_read32(hw, PCI_DEV_REG4);
reg1 &= P_ASPM_CONTROL_MSK;
@@ -243,6 +243,7 @@ static void sky2_set_power_state(struct sky2_hw *hw, pci_power_t state)
}
sky2_pci_write32(hw, PCI_DEV_REG1, reg1);
+ udelay(100);
break;
@@ -255,6 +256,7 @@ static void sky2_set_power_state(struct sky2_hw *hw, pci_power_t state)
else
reg1 |= (PCI_Y2_PHY1_POWD | PCI_Y2_PHY2_POWD);
sky2_pci_write32(hw, PCI_DEV_REG1, reg1);
+ udelay(100);
if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
sky2_write8(hw, B2_Y2_CLK_GATE, 0);
@@ -1159,7 +1161,7 @@ static unsigned tx_le_req(const struct sk_buff *skb)
count = sizeof(dma_addr_t) / sizeof(u32);
count += skb_shinfo(skb)->nr_frags * count;
- if (skb_shinfo(skb)->gso_size)
+ if (skb_is_gso(skb))
++count;
if (skb->ip_summed == CHECKSUM_HW)
@@ -1389,7 +1391,7 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done)
}
sky2->tx_cons = put;
- if (tx_avail(sky2) > MAX_SKB_TX_LE)
+ if (tx_avail(sky2) > MAX_SKB_TX_LE + 4)
netif_wake_queue(dev);
}
@@ -1888,9 +1890,6 @@ resubmit:
re->skb->ip_summed = CHECKSUM_NONE;
sky2_rx_add(sky2, re->mapaddr);
- /* Tell receiver about new buffers. */
- sky2_put_idx(sky2->hw, rxqaddr[sky2->port], sky2->rx_put);
-
return skb;
oversize:
@@ -1937,7 +1936,9 @@ static inline int sky2_more_work(const struct sky2_hw *hw)
/* Process status response ring */
static int sky2_status_intr(struct sky2_hw *hw, int to_do)
{
+ struct sky2_port *sky2;
int work_done = 0;
+ unsigned buf_write[2] = { 0, 0 };
u16 hwidx = sky2_read16(hw, STAT_PUT_IDX);
rmb();
@@ -1945,7 +1946,6 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
while (hw->st_idx != hwidx) {
struct sky2_status_le *le = hw->st_le + hw->st_idx;
struct net_device *dev;
- struct sky2_port *sky2;
struct sk_buff *skb;
u32 status;
u16 length;
@@ -1978,6 +1978,14 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
#endif
netif_receive_skb(skb);
+ /* Update receiver after 16 frames */
+ if (++buf_write[le->link] == RX_BUF_WRITE) {
+ sky2_put_idx(hw, rxqaddr[le->link],
+ sky2->rx_put);
+ buf_write[le->link] = 0;
+ }
+
+ /* Stop after net poll weight */
if (++work_done >= to_do)
goto exit_loop;
break;
@@ -2016,6 +2024,16 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
}
exit_loop:
+ if (buf_write[0]) {
+ sky2 = netdev_priv(hw->dev[0]);
+ sky2_put_idx(hw, Q_R1, sky2->rx_put);
+ }
+
+ if (buf_write[1]) {
+ sky2 = netdev_priv(hw->dev[1]);
+ sky2_put_idx(hw, Q_R2, sky2->rx_put);
+ }
+
return work_done;
}
@@ -2186,9 +2204,6 @@ static int sky2_poll(struct net_device *dev0, int *budget)
int work_done = 0;
u32 status = sky2_read32(hw, B0_Y2_SP_EISR);
- if (!~status)
- goto out;
-
if (status & Y2_IS_HW_ERR)
sky2_hw_intr(hw);
@@ -2225,7 +2240,7 @@ static int sky2_poll(struct net_device *dev0, int *budget)
if (sky2_more_work(hw))
return 1;
-out:
+
netif_rx_complete(dev0);
sky2_read32(hw, B0_Y2_SP_LISR);
@@ -2286,7 +2301,7 @@ static inline u32 sky2_clk2us(const struct sky2_hw *hw, u32 clk)
}
-static int __devinit sky2_reset(struct sky2_hw *hw)
+static int sky2_reset(struct sky2_hw *hw)
{
u16 status;
u8 t8, pmd_type;
@@ -3437,17 +3452,14 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state)
return -EINVAL;
del_timer_sync(&hw->idle_timer);
+ netif_poll_disable(hw->dev[0]);
for (i = 0; i < hw->ports; i++) {
struct net_device *dev = hw->dev[i];
- if (dev) {
- if (!netif_running(dev))
- continue;
-
+ if (netif_running(dev)) {
sky2_down(dev);
netif_device_detach(dev);
- netif_poll_disable(dev);
}
}
@@ -3474,9 +3486,8 @@ static int sky2_resume(struct pci_dev *pdev)
for (i = 0; i < hw->ports; i++) {
struct net_device *dev = hw->dev[i];
- if (dev && netif_running(dev)) {
+ if (netif_running(dev)) {
netif_device_attach(dev);
- netif_poll_enable(dev);
err = sky2_up(dev);
if (err) {
@@ -3488,6 +3499,7 @@ static int sky2_resume(struct pci_dev *pdev)
}
}
+ netif_poll_enable(hw->dev[0]);
sky2_idle_start(hw);
out:
return err;
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index 8a0bc5525f0..2db8d19b22d 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -1480,7 +1480,7 @@ enum {
GM_TXCR_FORCE_JAM = 1<<15, /* Bit 15: Force Jam / Flow-Control */
GM_TXCR_CRC_DIS = 1<<14, /* Bit 14: Disable insertion of CRC */
GM_TXCR_PAD_DIS = 1<<13, /* Bit 13: Disable padding of packets */
- GM_TXCR_COL_THR_MSK = 1<<10, /* Bit 12..10: Collision Threshold */
+ GM_TXCR_COL_THR_MSK = 7<<10, /* Bit 12..10: Collision Threshold */
};
#define TX_COL_THR(x) (((x)<<10) & GM_TXCR_COL_THR_MSK)
diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h
index b4028049ed7..4ec4b4d23ae 100644
--- a/drivers/net/smc91x.h
+++ b/drivers/net/smc91x.h
@@ -354,6 +354,24 @@ static inline void LPD7_SMC_outsw (unsigned char* a, int r,
#define SMC_IRQ_FLAGS (0)
+#elif defined(CONFIG_ARCH_VERSATILE)
+
+#define SMC_CAN_USE_8BIT 1
+#define SMC_CAN_USE_16BIT 1
+#define SMC_CAN_USE_32BIT 1
+#define SMC_NOWAIT 1
+
+#define SMC_inb(a, r) readb((a) + (r))
+#define SMC_inw(a, r) readw((a) + (r))
+#define SMC_inl(a, r) readl((a) + (r))
+#define SMC_outb(v, a, r) writeb(v, (a) + (r))
+#define SMC_outw(v, a, r) writew(v, (a) + (r))
+#define SMC_outl(v, a, r) writel(v, (a) + (r))
+#define SMC_insl(a, r, p, l) readsl((a) + (r), p, l)
+#define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l)
+
+#define SMC_IRQ_FLAGS (0)
+
#else
#define SMC_CAN_USE_8BIT 1
diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c
index fb1d5a8a45c..647f62e9707 100644
--- a/drivers/net/spider_net.c
+++ b/drivers/net/spider_net.c
@@ -84,7 +84,7 @@ MODULE_DEVICE_TABLE(pci, spider_net_pci_tbl);
*
* returns the content of the specified SMMIO register.
*/
-static u32
+static inline u32
spider_net_read_reg(struct spider_net_card *card, u32 reg)
{
u32 value;
@@ -101,7 +101,7 @@ spider_net_read_reg(struct spider_net_card *card, u32 reg)
* @reg: register to write to
* @value: value to write into the specified SMMIO register
*/
-static void
+static inline void
spider_net_write_reg(struct spider_net_card *card, u32 reg, u32 value)
{
value = cpu_to_le32(value);
@@ -259,39 +259,10 @@ spider_net_get_mac_address(struct net_device *netdev)
*
* returns the status as in the dmac_cmd_status field of the descriptor
*/
-static enum spider_net_descr_status
+static inline int
spider_net_get_descr_status(struct spider_net_descr *descr)
{
- u32 cmd_status;
-
- cmd_status = descr->dmac_cmd_status;
- cmd_status >>= SPIDER_NET_DESCR_IND_PROC_SHIFT;
- /* no need to mask out any bits, as cmd_status is 32 bits wide only
- * (and unsigned) */
- return cmd_status;
-}
-
-/**
- * spider_net_set_descr_status -- sets the status of a descriptor
- * @descr: descriptor to change
- * @status: status to set in the descriptor
- *
- * changes the status to the specified value. Doesn't change other bits
- * in the status
- */
-static void
-spider_net_set_descr_status(struct spider_net_descr *descr,
- enum spider_net_descr_status status)
-{
- u32 cmd_status;
- /* read the status */
- cmd_status = descr->dmac_cmd_status;
- /* clean the upper 4 bits */
- cmd_status &= SPIDER_NET_DESCR_IND_PROC_MASKO;
- /* add the status to it */
- cmd_status |= ((u32)status)<<SPIDER_NET_DESCR_IND_PROC_SHIFT;
- /* and write it back */
- descr->dmac_cmd_status = cmd_status;
+ return descr->dmac_cmd_status & SPIDER_NET_DESCR_IND_PROC_MASK;
}
/**
@@ -328,24 +299,23 @@ spider_net_free_chain(struct spider_net_card *card,
static int
spider_net_init_chain(struct spider_net_card *card,
struct spider_net_descr_chain *chain,
- struct spider_net_descr *start_descr, int no)
+ struct spider_net_descr *start_descr,
+ int direction, int no)
{
int i;
struct spider_net_descr *descr;
dma_addr_t buf;
- atomic_set(&card->rx_chain_refill,0);
-
descr = start_descr;
memset(descr, 0, sizeof(*descr) * no);
/* set up the hardware pointers in each descriptor */
for (i=0; i<no; i++, descr++) {
- spider_net_set_descr_status(descr, SPIDER_NET_DESCR_NOT_IN_USE);
+ descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
buf = pci_map_single(card->pdev, descr,
SPIDER_NET_DESCR_SIZE,
- PCI_DMA_BIDIRECTIONAL);
+ direction);
if (buf == DMA_ERROR_CODE)
goto iommu_error;
@@ -360,10 +330,11 @@ spider_net_init_chain(struct spider_net_card *card,
start_descr->prev = descr-1;
descr = start_descr;
- for (i=0; i < no; i++, descr++) {
- descr->next_descr_addr = descr->next->bus_addr;
- }
+ if (direction == PCI_DMA_FROMDEVICE)
+ for (i=0; i < no; i++, descr++)
+ descr->next_descr_addr = descr->next->bus_addr;
+ spin_lock_init(&chain->lock);
chain->head = start_descr;
chain->tail = start_descr;
@@ -375,7 +346,7 @@ iommu_error:
if (descr->bus_addr)
pci_unmap_single(card->pdev, descr->bus_addr,
SPIDER_NET_DESCR_SIZE,
- PCI_DMA_BIDIRECTIONAL);
+ direction);
return -ENOMEM;
}
@@ -396,7 +367,7 @@ spider_net_free_rx_chain_contents(struct spider_net_card *card)
dev_kfree_skb(descr->skb);
pci_unmap_single(card->pdev, descr->buf_addr,
SPIDER_NET_MAX_FRAME,
- PCI_DMA_BIDIRECTIONAL);
+ PCI_DMA_FROMDEVICE);
}
descr = descr->next;
}
@@ -446,15 +417,16 @@ spider_net_prepare_rx_descr(struct spider_net_card *card,
skb_reserve(descr->skb, SPIDER_NET_RXBUF_ALIGN - offset);
/* io-mmu-map the skb */
buf = pci_map_single(card->pdev, descr->skb->data,
- SPIDER_NET_MAX_FRAME, PCI_DMA_BIDIRECTIONAL);
+ SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE);
descr->buf_addr = buf;
if (buf == DMA_ERROR_CODE) {
dev_kfree_skb_any(descr->skb);
if (netif_msg_rx_err(card) && net_ratelimit())
pr_err("Could not iommu-map rx buffer\n");
- spider_net_set_descr_status(descr, SPIDER_NET_DESCR_NOT_IN_USE);
+ descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
} else {
- descr->dmac_cmd_status = SPIDER_NET_DMAC_RX_CARDOWNED;
+ descr->dmac_cmd_status = SPIDER_NET_DESCR_CARDOWNED |
+ SPIDER_NET_DMAC_NOINTR_COMPLETE;
}
return error;
@@ -468,7 +440,7 @@ spider_net_prepare_rx_descr(struct spider_net_card *card,
* chip by writing to the appropriate register. DMA is enabled in
* spider_net_enable_rxdmac.
*/
-static void
+static inline void
spider_net_enable_rxchtails(struct spider_net_card *card)
{
/* assume chain is aligned correctly */
@@ -483,7 +455,7 @@ spider_net_enable_rxchtails(struct spider_net_card *card)
* spider_net_enable_rxdmac enables the DMA controller by setting RX_DMA_EN
* in the GDADMACCNTR register
*/
-static void
+static inline void
spider_net_enable_rxdmac(struct spider_net_card *card)
{
wmb();
@@ -500,23 +472,24 @@ spider_net_enable_rxdmac(struct spider_net_card *card)
static void
spider_net_refill_rx_chain(struct spider_net_card *card)
{
- struct spider_net_descr_chain *chain;
-
- chain = &card->rx_chain;
+ struct spider_net_descr_chain *chain = &card->rx_chain;
+ unsigned long flags;
/* one context doing the refill (and a second context seeing that
* and omitting it) is ok. If called by NAPI, we'll be called again
* as spider_net_decode_one_descr is called several times. If some
* interrupt calls us, the NAPI is about to clean up anyway. */
- if (atomic_inc_return(&card->rx_chain_refill) == 1)
- while (spider_net_get_descr_status(chain->head) ==
- SPIDER_NET_DESCR_NOT_IN_USE) {
- if (spider_net_prepare_rx_descr(card, chain->head))
- break;
- chain->head = chain->head->next;
- }
+ if (!spin_trylock_irqsave(&chain->lock, flags))
+ return;
+
+ while (spider_net_get_descr_status(chain->head) ==
+ SPIDER_NET_DESCR_NOT_IN_USE) {
+ if (spider_net_prepare_rx_descr(card, chain->head))
+ break;
+ chain->head = chain->head->next;
+ }
- atomic_dec(&card->rx_chain_refill);
+ spin_unlock_irqrestore(&chain->lock, flags);
}
/**
@@ -554,111 +527,6 @@ error:
}
/**
- * spider_net_release_tx_descr - processes a used tx descriptor
- * @card: card structure
- * @descr: descriptor to release
- *
- * releases a used tx descriptor (unmapping, freeing of skb)
- */
-static void
-spider_net_release_tx_descr(struct spider_net_card *card,
- struct spider_net_descr *descr)
-{
- struct sk_buff *skb;
-
- /* unmap the skb */
- skb = descr->skb;
- pci_unmap_single(card->pdev, descr->buf_addr, skb->len,
- PCI_DMA_BIDIRECTIONAL);
-
- dev_kfree_skb_any(skb);
-
- /* set status to not used */
- spider_net_set_descr_status(descr, SPIDER_NET_DESCR_NOT_IN_USE);
-}
-
-/**
- * spider_net_release_tx_chain - processes sent tx descriptors
- * @card: adapter structure
- * @brutal: if set, don't care about whether descriptor seems to be in use
- *
- * returns 0 if the tx ring is empty, otherwise 1.
- *
- * spider_net_release_tx_chain releases the tx descriptors that spider has
- * finished with (if non-brutal) or simply release tx descriptors (if brutal).
- * If some other context is calling this function, we return 1 so that we're
- * scheduled again (if we were scheduled) and will not loose initiative.
- */
-static int
-spider_net_release_tx_chain(struct spider_net_card *card, int brutal)
-{
- struct spider_net_descr_chain *tx_chain = &card->tx_chain;
- enum spider_net_descr_status status;
-
- if (atomic_inc_return(&card->tx_chain_release) != 1) {
- atomic_dec(&card->tx_chain_release);
- return 1;
- }
-
- for (;;) {
- status = spider_net_get_descr_status(tx_chain->tail);
- switch (status) {
- case SPIDER_NET_DESCR_CARDOWNED:
- if (!brutal)
- goto out;
- /* fallthrough, if we release the descriptors
- * brutally (then we don't care about
- * SPIDER_NET_DESCR_CARDOWNED) */
- case SPIDER_NET_DESCR_RESPONSE_ERROR:
- case SPIDER_NET_DESCR_PROTECTION_ERROR:
- case SPIDER_NET_DESCR_FORCE_END:
- if (netif_msg_tx_err(card))
- pr_err("%s: forcing end of tx descriptor "
- "with status x%02x\n",
- card->netdev->name, status);
- card->netdev_stats.tx_dropped++;
- break;
-
- case SPIDER_NET_DESCR_COMPLETE:
- card->netdev_stats.tx_packets++;
- card->netdev_stats.tx_bytes +=
- tx_chain->tail->skb->len;
- break;
-
- default: /* any other value (== SPIDER_NET_DESCR_NOT_IN_USE) */
- goto out;
- }
- spider_net_release_tx_descr(card, tx_chain->tail);
- tx_chain->tail = tx_chain->tail->next;
- }
-out:
- atomic_dec(&card->tx_chain_release);
-
- netif_wake_queue(card->netdev);
-
- if (status == SPIDER_NET_DESCR_CARDOWNED)
- return 1;
- return 0;
-}
-
-/**
- * spider_net_cleanup_tx_ring - cleans up the TX ring
- * @card: card structure
- *
- * spider_net_cleanup_tx_ring is called by the tx_timer (as we don't use
- * interrupts to cleanup our TX ring) and returns sent packets to the stack
- * by freeing them
- */
-static void
-spider_net_cleanup_tx_ring(struct spider_net_card *card)
-{
- if ( (spider_net_release_tx_chain(card, 0)) &&
- (card->netdev->flags & IFF_UP) ) {
- mod_timer(&card->tx_timer, jiffies + SPIDER_NET_TX_TIMER);
- }
-}
-
-/**
* spider_net_get_multicast_hash - generates hash for multicast filter table
* @addr: multicast address
*
@@ -761,97 +629,6 @@ spider_net_disable_rxdmac(struct spider_net_card *card)
}
/**
- * spider_net_stop - called upon ifconfig down
- * @netdev: interface device structure
- *
- * always returns 0
- */
-int
-spider_net_stop(struct net_device *netdev)
-{
- struct spider_net_card *card = netdev_priv(netdev);
-
- tasklet_kill(&card->rxram_full_tl);
- netif_poll_disable(netdev);
- netif_carrier_off(netdev);
- netif_stop_queue(netdev);
- del_timer_sync(&card->tx_timer);
-
- /* disable/mask all interrupts */
- spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK, 0);
- spider_net_write_reg(card, SPIDER_NET_GHIINT1MSK, 0);
- spider_net_write_reg(card, SPIDER_NET_GHIINT2MSK, 0);
-
- /* free_irq(netdev->irq, netdev);*/
- free_irq(to_pci_dev(netdev->class_dev.dev)->irq, netdev);
-
- spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR,
- SPIDER_NET_DMA_TX_FEND_VALUE);
-
- /* turn off DMA, force end */
- spider_net_disable_rxdmac(card);
-
- /* release chains */
- spider_net_release_tx_chain(card, 1);
-
- spider_net_free_chain(card, &card->tx_chain);
- spider_net_free_chain(card, &card->rx_chain);
-
- return 0;
-}
-
-/**
- * spider_net_get_next_tx_descr - returns the next available tx descriptor
- * @card: device structure to get descriptor from
- *
- * returns the address of the next descriptor, or NULL if not available.
- */
-static struct spider_net_descr *
-spider_net_get_next_tx_descr(struct spider_net_card *card)
-{
- /* check, if head points to not-in-use descr */
- if ( spider_net_get_descr_status(card->tx_chain.head) ==
- SPIDER_NET_DESCR_NOT_IN_USE ) {
- return card->tx_chain.head;
- } else {
- return NULL;
- }
-}
-
-/**
- * spider_net_set_txdescr_cmdstat - sets the tx descriptor command field
- * @descr: descriptor structure to fill out
- * @skb: packet to consider
- *
- * fills out the command and status field of the descriptor structure,
- * depending on hardware checksum settings.
- */
-static void
-spider_net_set_txdescr_cmdstat(struct spider_net_descr *descr,
- struct sk_buff *skb)
-{
- /* make sure the other fields in the descriptor are written */
- wmb();
-
- if (skb->ip_summed != CHECKSUM_HW) {
- descr->dmac_cmd_status = SPIDER_NET_DMAC_CMDSTAT_NOCS;
- return;
- }
-
- /* is packet ip?
- * if yes: tcp? udp? */
- if (skb->protocol == htons(ETH_P_IP)) {
- if (skb->nh.iph->protocol == IPPROTO_TCP)
- descr->dmac_cmd_status = SPIDER_NET_DMAC_CMDSTAT_TCPCS;
- else if (skb->nh.iph->protocol == IPPROTO_UDP)
- descr->dmac_cmd_status = SPIDER_NET_DMAC_CMDSTAT_UDPCS;
- else /* the stack should checksum non-tcp and non-udp
- packets on his own: NETIF_F_IP_CSUM */
- descr->dmac_cmd_status = SPIDER_NET_DMAC_CMDSTAT_NOCS;
- }
-}
-
-/**
* spider_net_prepare_tx_descr - fill tx descriptor with skb data
* @card: card structure
* @descr: descriptor structure to fill out
@@ -864,13 +641,12 @@ spider_net_set_txdescr_cmdstat(struct spider_net_descr *descr,
*/
static int
spider_net_prepare_tx_descr(struct spider_net_card *card,
- struct spider_net_descr *descr,
struct sk_buff *skb)
{
+ struct spider_net_descr *descr = card->tx_chain.head;
dma_addr_t buf;
- buf = pci_map_single(card->pdev, skb->data,
- skb->len, PCI_DMA_BIDIRECTIONAL);
+ buf = pci_map_single(card->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
if (buf == DMA_ERROR_CODE) {
if (netif_msg_tx_err(card) && net_ratelimit())
pr_err("could not iommu-map packet (%p, %i). "
@@ -880,10 +656,101 @@ spider_net_prepare_tx_descr(struct spider_net_card *card,
descr->buf_addr = buf;
descr->buf_size = skb->len;
+ descr->next_descr_addr = 0;
descr->skb = skb;
descr->data_status = 0;
- spider_net_set_txdescr_cmdstat(descr,skb);
+ descr->dmac_cmd_status =
+ SPIDER_NET_DESCR_CARDOWNED | SPIDER_NET_DMAC_NOCS;
+ if (skb->protocol == htons(ETH_P_IP))
+ switch (skb->nh.iph->protocol) {
+ case IPPROTO_TCP:
+ descr->dmac_cmd_status |= SPIDER_NET_DMAC_TCP;
+ break;
+ case IPPROTO_UDP:
+ descr->dmac_cmd_status |= SPIDER_NET_DMAC_UDP;
+ break;
+ }
+
+ descr->prev->next_descr_addr = descr->bus_addr;
+
+ return 0;
+}
+
+/**
+ * spider_net_release_tx_descr - processes a used tx descriptor
+ * @card: card structure
+ * @descr: descriptor to release
+ *
+ * releases a used tx descriptor (unmapping, freeing of skb)
+ */
+static inline void
+spider_net_release_tx_descr(struct spider_net_card *card)
+{
+ struct spider_net_descr *descr = card->tx_chain.tail;
+ struct sk_buff *skb;
+
+ card->tx_chain.tail = card->tx_chain.tail->next;
+ descr->dmac_cmd_status |= SPIDER_NET_DESCR_NOT_IN_USE;
+
+ /* unmap the skb */
+ skb = descr->skb;
+ pci_unmap_single(card->pdev, descr->buf_addr, skb->len,
+ PCI_DMA_TODEVICE);
+ dev_kfree_skb_any(skb);
+}
+
+/**
+ * spider_net_release_tx_chain - processes sent tx descriptors
+ * @card: adapter structure
+ * @brutal: if set, don't care about whether descriptor seems to be in use
+ *
+ * returns 0 if the tx ring is empty, otherwise 1.
+ *
+ * spider_net_release_tx_chain releases the tx descriptors that spider has
+ * finished with (if non-brutal) or simply release tx descriptors (if brutal).
+ * If some other context is calling this function, we return 1 so that we're
+ * scheduled again (if we were scheduled) and will not loose initiative.
+ */
+static int
+spider_net_release_tx_chain(struct spider_net_card *card, int brutal)
+{
+ struct spider_net_descr_chain *chain = &card->tx_chain;
+ int status;
+
+ spider_net_read_reg(card, SPIDER_NET_GDTDMACCNTR);
+
+ while (chain->tail != chain->head) {
+ status = spider_net_get_descr_status(chain->tail);
+ switch (status) {
+ case SPIDER_NET_DESCR_COMPLETE:
+ card->netdev_stats.tx_packets++;
+ card->netdev_stats.tx_bytes += chain->tail->skb->len;
+ break;
+
+ case SPIDER_NET_DESCR_CARDOWNED:
+ if (!brutal)
+ return 1;
+ /* fallthrough, if we release the descriptors
+ * brutally (then we don't care about
+ * SPIDER_NET_DESCR_CARDOWNED) */
+
+ case SPIDER_NET_DESCR_RESPONSE_ERROR:
+ case SPIDER_NET_DESCR_PROTECTION_ERROR:
+ case SPIDER_NET_DESCR_FORCE_END:
+ if (netif_msg_tx_err(card))
+ pr_err("%s: forcing end of tx descriptor "
+ "with status x%02x\n",
+ card->netdev->name, status);
+ card->netdev_stats.tx_errors++;
+ break;
+
+ default:
+ card->netdev_stats.tx_dropped++;
+ return 1;
+ }
+ spider_net_release_tx_descr(card);
+ }
return 0;
}
@@ -896,18 +763,32 @@ spider_net_prepare_tx_descr(struct spider_net_card *card,
* spider_net_kick_tx_dma writes the current tx chain head as start address
* of the tx descriptor chain and enables the transmission DMA engine
*/
-static void
-spider_net_kick_tx_dma(struct spider_net_card *card,
- struct spider_net_descr *descr)
+static inline void
+spider_net_kick_tx_dma(struct spider_net_card *card)
{
- /* this is the only descriptor in the output chain.
- * Enable TX DMA */
+ struct spider_net_descr *descr;
- spider_net_write_reg(card, SPIDER_NET_GDTDCHA,
- descr->bus_addr);
+ if (spider_net_read_reg(card, SPIDER_NET_GDTDMACCNTR) &
+ SPIDER_NET_TX_DMA_EN)
+ goto out;
- spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR,
- SPIDER_NET_DMA_TX_VALUE);
+ descr = card->tx_chain.tail;
+ for (;;) {
+ if (spider_net_get_descr_status(descr) ==
+ SPIDER_NET_DESCR_CARDOWNED) {
+ spider_net_write_reg(card, SPIDER_NET_GDTDCHA,
+ descr->bus_addr);
+ spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR,
+ SPIDER_NET_DMA_TX_VALUE);
+ break;
+ }
+ if (descr == card->tx_chain.head)
+ break;
+ descr = descr->next;
+ }
+
+out:
+ mod_timer(&card->tx_timer, jiffies + SPIDER_NET_TX_TIMER);
}
/**
@@ -915,47 +796,69 @@ spider_net_kick_tx_dma(struct spider_net_card *card,
* @skb: packet to send out
* @netdev: interface device structure
*
- * returns 0 on success, <0 on failure
+ * returns 0 on success, !0 on failure
*/
static int
spider_net_xmit(struct sk_buff *skb, struct net_device *netdev)
{
struct spider_net_card *card = netdev_priv(netdev);
- struct spider_net_descr *descr;
+ struct spider_net_descr_chain *chain = &card->tx_chain;
+ struct spider_net_descr *descr = chain->head;
+ unsigned long flags;
int result;
+ spin_lock_irqsave(&chain->lock, flags);
+
spider_net_release_tx_chain(card, 0);
- descr = spider_net_get_next_tx_descr(card);
+ if (chain->head->next == chain->tail->prev) {
+ card->netdev_stats.tx_dropped++;
+ result = NETDEV_TX_LOCKED;
+ goto out;
+ }
- if (!descr)
- goto error;
+ if (spider_net_get_descr_status(descr) != SPIDER_NET_DESCR_NOT_IN_USE) {
+ result = NETDEV_TX_LOCKED;
+ goto out;
+ }
- result = spider_net_prepare_tx_descr(card, descr, skb);
- if (result)
- goto error;
+ if (spider_net_prepare_tx_descr(card, skb) != 0) {
+ card->netdev_stats.tx_dropped++;
+ result = NETDEV_TX_BUSY;
+ goto out;
+ }
+
+ result = NETDEV_TX_OK;
+ spider_net_kick_tx_dma(card);
card->tx_chain.head = card->tx_chain.head->next;
- if (spider_net_get_descr_status(descr->prev) !=
- SPIDER_NET_DESCR_CARDOWNED) {
- /* make sure the current descriptor is in memory. Then
- * kicking it on again makes sense, if the previous is not
- * card-owned anymore. Check the previous descriptor twice
- * to omit an mb() in heavy traffic cases */
- mb();
- if (spider_net_get_descr_status(descr->prev) !=
- SPIDER_NET_DESCR_CARDOWNED)
- spider_net_kick_tx_dma(card, descr);
- }
+out:
+ spin_unlock_irqrestore(&chain->lock, flags);
+ netif_wake_queue(netdev);
+ return result;
+}
- mod_timer(&card->tx_timer, jiffies + SPIDER_NET_TX_TIMER);
+/**
+ * spider_net_cleanup_tx_ring - cleans up the TX ring
+ * @card: card structure
+ *
+ * spider_net_cleanup_tx_ring is called by the tx_timer (as we don't use
+ * interrupts to cleanup our TX ring) and returns sent packets to the stack
+ * by freeing them
+ */
+static void
+spider_net_cleanup_tx_ring(struct spider_net_card *card)
+{
+ unsigned long flags;
- return NETDEV_TX_OK;
+ spin_lock_irqsave(&card->tx_chain.lock, flags);
-error:
- card->netdev_stats.tx_dropped++;
- return NETDEV_TX_BUSY;
+ if ((spider_net_release_tx_chain(card, 0) != 0) &&
+ (card->netdev->flags & IFF_UP))
+ spider_net_kick_tx_dma(card);
+
+ spin_unlock_irqrestore(&card->tx_chain.lock, flags);
}
/**
@@ -1002,7 +905,7 @@ spider_net_pass_skb_up(struct spider_net_descr *descr,
/* unmap descriptor */
pci_unmap_single(card->pdev, descr->buf_addr, SPIDER_NET_MAX_FRAME,
- PCI_DMA_BIDIRECTIONAL);
+ PCI_DMA_FROMDEVICE);
/* the cases we'll throw away the packet immediately */
if (data_error & SPIDER_NET_DESTROY_RX_FLAGS) {
@@ -1067,14 +970,11 @@ spider_net_pass_skb_up(struct spider_net_descr *descr,
static int
spider_net_decode_one_descr(struct spider_net_card *card, int napi)
{
- enum spider_net_descr_status status;
- struct spider_net_descr *descr;
- struct spider_net_descr_chain *chain;
+ struct spider_net_descr_chain *chain = &card->rx_chain;
+ struct spider_net_descr *descr = chain->tail;
+ int status;
int result;
- chain = &card->rx_chain;
- descr = chain->tail;
-
status = spider_net_get_descr_status(descr);
if (status == SPIDER_NET_DESCR_CARDOWNED) {
@@ -1103,7 +1003,7 @@ spider_net_decode_one_descr(struct spider_net_card *card, int napi)
card->netdev->name, status);
card->netdev_stats.rx_dropped++;
pci_unmap_single(card->pdev, descr->buf_addr,
- SPIDER_NET_MAX_FRAME, PCI_DMA_BIDIRECTIONAL);
+ SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE);
dev_kfree_skb_irq(descr->skb);
goto refill;
}
@@ -1119,7 +1019,7 @@ spider_net_decode_one_descr(struct spider_net_card *card, int napi)
/* ok, we've got a packet in descr */
result = spider_net_pass_skb_up(descr, card, napi);
refill:
- spider_net_set_descr_status(descr, SPIDER_NET_DESCR_NOT_IN_USE);
+ descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
/* change the descriptor state: */
if (!napi)
spider_net_refill_rx_chain(card);
@@ -1291,21 +1191,6 @@ spider_net_set_mac(struct net_device *netdev, void *p)
}
/**
- * spider_net_enable_txdmac - enables a TX DMA controller
- * @card: card structure
- *
- * spider_net_enable_txdmac enables the TX DMA controller by setting the
- * descriptor chain tail address
- */
-static void
-spider_net_enable_txdmac(struct spider_net_card *card)
-{
- /* assume chain is aligned correctly */
- spider_net_write_reg(card, SPIDER_NET_GDTDCHA,
- card->tx_chain.tail->bus_addr);
-}
-
-/**
* spider_net_handle_rxram_full - cleans up RX ring upon RX RAM full interrupt
* @card: card structure
*
@@ -1653,7 +1538,6 @@ spider_net_enable_card(struct spider_net_card *card)
{ SPIDER_NET_GMRWOLCTRL, 0 },
{ SPIDER_NET_GTESTMD, 0x10000000 },
{ SPIDER_NET_GTTQMSK, 0x00400040 },
- { SPIDER_NET_GTESTMD, 0 },
{ SPIDER_NET_GMACINTEN, 0 },
@@ -1692,9 +1576,6 @@ spider_net_enable_card(struct spider_net_card *card)
spider_net_write_reg(card, SPIDER_NET_GRXDMAEN, SPIDER_NET_WOL_VALUE);
- /* set chain tail adress for TX chain */
- spider_net_enable_txdmac(card);
-
spider_net_write_reg(card, SPIDER_NET_GMACLENLMT,
SPIDER_NET_LENLMT_VALUE);
spider_net_write_reg(card, SPIDER_NET_GMACMODE,
@@ -1709,6 +1590,9 @@ spider_net_enable_card(struct spider_net_card *card)
SPIDER_NET_INT1_MASK_VALUE);
spider_net_write_reg(card, SPIDER_NET_GHIINT2MSK,
SPIDER_NET_INT2_MASK_VALUE);
+
+ spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR,
+ SPIDER_NET_GDTDCEIDIS);
}
/**
@@ -1728,10 +1612,12 @@ spider_net_open(struct net_device *netdev)
result = -ENOMEM;
if (spider_net_init_chain(card, &card->tx_chain,
- card->descr, tx_descriptors))
+ card->descr,
+ PCI_DMA_TODEVICE, tx_descriptors))
goto alloc_tx_failed;
if (spider_net_init_chain(card, &card->rx_chain,
- card->descr + tx_descriptors, rx_descriptors))
+ card->descr + tx_descriptors,
+ PCI_DMA_FROMDEVICE, rx_descriptors))
goto alloc_rx_failed;
/* allocate rx skbs */
@@ -1938,7 +1824,7 @@ spider_net_workaround_rxramfull(struct spider_net_card *card)
/* empty sequencer data */
for (sequencer = 0; sequencer < SPIDER_NET_FIRMWARE_SEQS;
sequencer++) {
- spider_net_write_reg(card, SPIDER_NET_GSnPRGDAT +
+ spider_net_write_reg(card, SPIDER_NET_GSnPRGADR +
sequencer * 8, 0x0);
for (i = 0; i < SPIDER_NET_FIRMWARE_SEQWORDS; i++) {
spider_net_write_reg(card, SPIDER_NET_GSnPRGDAT +
@@ -1955,6 +1841,49 @@ spider_net_workaround_rxramfull(struct spider_net_card *card)
}
/**
+ * spider_net_stop - called upon ifconfig down
+ * @netdev: interface device structure
+ *
+ * always returns 0
+ */
+int
+spider_net_stop(struct net_device *netdev)
+{
+ struct spider_net_card *card = netdev_priv(netdev);
+
+ tasklet_kill(&card->rxram_full_tl);
+ netif_poll_disable(netdev);
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+ del_timer_sync(&card->tx_timer);
+
+ /* disable/mask all interrupts */
+ spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK, 0);
+ spider_net_write_reg(card, SPIDER_NET_GHIINT1MSK, 0);
+ spider_net_write_reg(card, SPIDER_NET_GHIINT2MSK, 0);
+
+ /* free_irq(netdev->irq, netdev);*/
+ free_irq(to_pci_dev(netdev->class_dev.dev)->irq, netdev);
+
+ spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR,
+ SPIDER_NET_DMA_TX_FEND_VALUE);
+
+ /* turn off DMA, force end */
+ spider_net_disable_rxdmac(card);
+
+ /* release chains */
+ if (spin_trylock(&card->tx_chain.lock)) {
+ spider_net_release_tx_chain(card, 1);
+ spin_unlock(&card->tx_chain.lock);
+ }
+
+ spider_net_free_chain(card, &card->tx_chain);
+ spider_net_free_chain(card, &card->rx_chain);
+
+ return 0;
+}
+
+/**
* spider_net_tx_timeout_task - task scheduled by the watchdog timeout
* function (to be called not under interrupt status)
* @data: data, is interface device structure
@@ -1982,7 +1911,7 @@ spider_net_tx_timeout_task(void *data)
goto out;
spider_net_open(netdev);
- spider_net_kick_tx_dma(card, card->tx_chain.head);
+ spider_net_kick_tx_dma(card);
netif_device_attach(netdev);
out:
@@ -2065,7 +1994,6 @@ spider_net_setup_netdev(struct spider_net_card *card)
pci_set_drvdata(card->pdev, netdev);
- atomic_set(&card->tx_chain_release,0);
card->rxram_full_tl.data = (unsigned long) card;
card->rxram_full_tl.func =
(void (*)(unsigned long)) spider_net_handle_rxram_full;
@@ -2079,7 +2007,7 @@ spider_net_setup_netdev(struct spider_net_card *card)
spider_net_setup_netdev_ops(netdev);
- netdev->features = NETIF_F_HW_CSUM;
+ netdev->features = NETIF_F_HW_CSUM | NETIF_F_LLTX;
/* some time: NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX |
* NETIF_F_HW_VLAN_FILTER */
diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h
index 3b8d951cf73..f6dcf180ae3 100644
--- a/drivers/net/spider_net.h
+++ b/drivers/net/spider_net.h
@@ -208,7 +208,10 @@ extern char spider_net_driver_name[];
#define SPIDER_NET_DMA_RX_VALUE 0x80000000
#define SPIDER_NET_DMA_RX_FEND_VALUE 0x00030003
/* to set TX_DMA_EN */
-#define SPIDER_NET_DMA_TX_VALUE 0x80000000
+#define SPIDER_NET_TX_DMA_EN 0x80000000
+#define SPIDER_NET_GDTDCEIDIS 0x00000002
+#define SPIDER_NET_DMA_TX_VALUE SPIDER_NET_TX_DMA_EN | \
+ SPIDER_NET_GDTDCEIDIS
#define SPIDER_NET_DMA_TX_FEND_VALUE 0x00030003
/* SPIDER_NET_UA_DESCR_VALUE is OR'ed with the unicast address */
@@ -329,55 +332,23 @@ enum spider_net_int2_status {
(~SPIDER_NET_TXINT) & \
(~SPIDER_NET_RXINT) )
-#define SPIDER_NET_GPREXEC 0x80000000
-#define SPIDER_NET_GPRDAT_MASK 0x0000ffff
+#define SPIDER_NET_GPREXEC 0x80000000
+#define SPIDER_NET_GPRDAT_MASK 0x0000ffff
-/* descriptor bits
- *
- * 1010 descriptor ready
- * 0 descr in middle of chain
- * 000 fixed to 0
- *
- * 0 no interrupt on completion
- * 000 fixed to 0
- * 1 no ipsec processing
- * 1 last descriptor for this frame
- * 00 no checksum
- * 10 tcp checksum
- * 11 udp checksum
- *
- * 00 fixed to 0
- * 0 fixed to 0
- * 0 no interrupt on response errors
- * 0 no interrupt on invalid descr
- * 0 no interrupt on dma process termination
- * 0 no interrupt on descr chain end
- * 0 no interrupt on descr complete
- *
- * 000 fixed to 0
- * 0 response error interrupt status
- * 0 invalid descr status
- * 0 dma termination status
- * 0 descr chain end status
- * 0 descr complete status */
-#define SPIDER_NET_DMAC_CMDSTAT_NOCS 0xa00c0000
-#define SPIDER_NET_DMAC_CMDSTAT_TCPCS 0xa00e0000
-#define SPIDER_NET_DMAC_CMDSTAT_UDPCS 0xa00f0000
-#define SPIDER_NET_DESCR_IND_PROC_SHIFT 28
-#define SPIDER_NET_DESCR_IND_PROC_MASKO 0x0fffffff
-
-/* descr ready, descr is in middle of chain, get interrupt on completion */
-#define SPIDER_NET_DMAC_RX_CARDOWNED 0xa0800000
-
-enum spider_net_descr_status {
- SPIDER_NET_DESCR_COMPLETE = 0x00, /* used in rx and tx */
- SPIDER_NET_DESCR_RESPONSE_ERROR = 0x01, /* used in rx and tx */
- SPIDER_NET_DESCR_PROTECTION_ERROR = 0x02, /* used in rx and tx */
- SPIDER_NET_DESCR_FRAME_END = 0x04, /* used in rx */
- SPIDER_NET_DESCR_FORCE_END = 0x05, /* used in rx and tx */
- SPIDER_NET_DESCR_CARDOWNED = 0x0a, /* used in rx and tx */
- SPIDER_NET_DESCR_NOT_IN_USE /* any other value */
-};
+#define SPIDER_NET_DMAC_NOINTR_COMPLETE 0x00800000
+#define SPIDER_NET_DMAC_NOCS 0x00040000
+#define SPIDER_NET_DMAC_TCP 0x00020000
+#define SPIDER_NET_DMAC_UDP 0x00030000
+#define SPIDER_NET_TXDCEST 0x08000000
+
+#define SPIDER_NET_DESCR_IND_PROC_MASK 0xF0000000
+#define SPIDER_NET_DESCR_COMPLETE 0x00000000 /* used in rx and tx */
+#define SPIDER_NET_DESCR_RESPONSE_ERROR 0x10000000 /* used in rx and tx */
+#define SPIDER_NET_DESCR_PROTECTION_ERROR 0x20000000 /* used in rx and tx */
+#define SPIDER_NET_DESCR_FRAME_END 0x40000000 /* used in rx */
+#define SPIDER_NET_DESCR_FORCE_END 0x50000000 /* used in rx and tx */
+#define SPIDER_NET_DESCR_CARDOWNED 0xA0000000 /* used in rx and tx */
+#define SPIDER_NET_DESCR_NOT_IN_USE 0xF0000000
struct spider_net_descr {
/* as defined by the hardware */
@@ -398,7 +369,7 @@ struct spider_net_descr {
} __attribute__((aligned(32)));
struct spider_net_descr_chain {
- /* we walk from tail to head */
+ spinlock_t lock;
struct spider_net_descr *head;
struct spider_net_descr *tail;
};
@@ -453,8 +424,6 @@ struct spider_net_card {
struct spider_net_descr_chain tx_chain;
struct spider_net_descr_chain rx_chain;
- atomic_t rx_chain_refill;
- atomic_t tx_chain_release;
struct net_device_stats netdev_stats;
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
index ed1f59901ff..c0a62b00ffc 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -22,129 +22,13 @@
Support and updates available at
http://www.scyld.com/network/starfire.html
+ [link no longer provides useful info -jgarzik]
- -----------------------------------------------------------
-
- Linux kernel-specific changes:
-
- LK1.1.1 (jgarzik):
- - Use PCI driver interface
- - Fix MOD_xxx races
- - softnet fixups
-
- LK1.1.2 (jgarzik):
- - Merge Becker version 0.15
-
- LK1.1.3 (Andrew Morton)
- - Timer cleanups
-
- LK1.1.4 (jgarzik):
- - Merge Becker version 1.03
-
- LK1.2.1 (Ion Badulescu <ionut@cs.columbia.edu>)
- - Support hardware Rx/Tx checksumming
- - Use the GFP firmware taken from Adaptec's Netware driver
-
- LK1.2.2 (Ion Badulescu)
- - Backported to 2.2.x
-
- LK1.2.3 (Ion Badulescu)
- - Fix the flaky mdio interface
- - More compat clean-ups
-
- LK1.2.4 (Ion Badulescu)
- - More 2.2.x initialization fixes
-
- LK1.2.5 (Ion Badulescu)
- - Several fixes from Manfred Spraul
-
- LK1.2.6 (Ion Badulescu)
- - Fixed ifup/ifdown/ifup problem in 2.4.x
-
- LK1.2.7 (Ion Badulescu)
- - Removed unused code
- - Made more functions static and __init
-
- LK1.2.8 (Ion Badulescu)
- - Quell bogus error messages, inform about the Tx threshold
- - Removed #ifdef CONFIG_PCI, this driver is PCI only
-
- LK1.2.9 (Ion Badulescu)
- - Merged Jeff Garzik's changes from 2.4.4-pre5
- - Added 2.2.x compatibility stuff required by the above changes
-
- LK1.2.9a (Ion Badulescu)
- - More updates from Jeff Garzik
-
- LK1.3.0 (Ion Badulescu)
- - Merged zerocopy support
-
- LK1.3.1 (Ion Badulescu)
- - Added ethtool support
- - Added GPIO (media change) interrupt support
-
- LK1.3.2 (Ion Badulescu)
- - Fixed 2.2.x compatibility issues introduced in 1.3.1
- - Fixed ethtool ioctl returning uninitialized memory
-
- LK1.3.3 (Ion Badulescu)
- - Initialize the TxMode register properly
- - Don't dereference dev->priv after freeing it
-
- LK1.3.4 (Ion Badulescu)
- - Fixed initialization timing problems
- - Fixed interrupt mask definitions
-
- LK1.3.5 (jgarzik)
- - ethtool NWAY_RST, GLINK, [GS]MSGLVL support
-
- LK1.3.6:
- - Sparc64 support and fixes (Ion Badulescu)
- - Better stats and error handling (Ion Badulescu)
- - Use new pci_set_mwi() PCI API function (jgarzik)
-
- LK1.3.7 (Ion Badulescu)
- - minimal implementation of tx_timeout()
- - correctly shutdown the Rx/Tx engines in netdev_close()
- - added calls to netif_carrier_on/off
- (patch from Stefan Rompf <srompf@isg.de>)
- - VLAN support
-
- LK1.3.8 (Ion Badulescu)
- - adjust DMA burst size on sparc64
- - 64-bit support
- - reworked zerocopy support for 64-bit buffers
- - working and usable interrupt mitigation/latency
- - reduced Tx interrupt frequency for lower interrupt overhead
-
- LK1.3.9 (Ion Badulescu)
- - bugfix for mcast filter
- - enable the right kind of Tx interrupts (TxDMADone, not TxDone)
-
- LK1.4.0 (Ion Badulescu)
- - NAPI support
-
- LK1.4.1 (Ion Badulescu)
- - flush PCI posting buffers after disabling Rx interrupts
- - put the chip to a D3 slumber on driver unload
- - added config option to enable/disable NAPI
-
- LK1.4.2 (Ion Badulescu)
- - finally added firmware (GPL'ed by Adaptec)
- - removed compatibility code for 2.2.x
-
- LK1.4.2.1 (Ion Badulescu)
- - fixed 32/64 bit issues on i386 + CONFIG_HIGHMEM
- - added 32-bit padding to outgoing skb's, removed previous workaround
-
-TODO: - fix forced speed/duplexing code (broken a long time ago, when
- somebody converted the driver to use the generic MII code)
- - fix VLAN support
*/
#define DRV_NAME "starfire"
-#define DRV_VERSION "1.03+LK1.4.2.1"
-#define DRV_RELDATE "October 3, 2005"
+#define DRV_VERSION "2.0"
+#define DRV_RELDATE "June 27, 2006"
#include <linux/module.h>
#include <linux/kernel.h>
@@ -846,7 +730,6 @@ static int __devinit starfire_init_one(struct pci_dev *pdev,
goto err_out_free_netdev;
}
- /* ioremap is borken in Linux-2.2.x/sparc64 */
base = ioremap(ioaddr, io_size);
if (!base) {
printk(KERN_ERR DRV_NAME " %d: cannot remap %#x @ %#lx, aborting\n",
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c
index 643fceae3db..ac17377b3e9 100644
--- a/drivers/net/sundance.c
+++ b/drivers/net/sundance.c
@@ -16,91 +16,13 @@
Support and updates available at
http://www.scyld.com/network/sundance.html
+ [link no longer provides useful info -jgarzik]
-
- Version LK1.01a (jgarzik):
- - Replace some MII-related magic numbers with constants
-
- Version LK1.02 (D-Link):
- - Add new board to PCI ID list
- - Fix multicast bug
-
- Version LK1.03 (D-Link):
- - New Rx scheme, reduce Rx congestion
- - Option to disable flow control
-
- Version LK1.04 (D-Link):
- - Tx timeout recovery
- - More support for ethtool.
-
- Version LK1.04a:
- - Remove unused/constant members from struct pci_id_info
- (which then allows removal of 'drv_flags' from private struct)
- (jgarzik)
- - If no phy is found, fail to load that board (jgarzik)
- - Always start phy id scan at id 1 to avoid problems (Donald Becker)
- - Autodetect where mii_preable_required is needed,
- default to not needed. (Donald Becker)
-
- Version LK1.04b:
- - Remove mii_preamble_required module parameter (Donald Becker)
- - Add per-interface mii_preamble_required (setting is autodetected)
- (Donald Becker)
- - Remove unnecessary cast from void pointer (jgarzik)
- - Re-align comments in private struct (jgarzik)
-
- Version LK1.04c (jgarzik):
- - Support bitmapped message levels (NETIF_MSG_xxx), and the
- two ethtool ioctls that get/set them
- - Don't hand-code MII ethtool support, use standard API/lib
-
- Version LK1.04d:
- - Merge from Donald Becker's sundance.c: (Jason Lunz)
- * proper support for variably-sized MTUs
- * default to PIO, to fix chip bugs
- - Add missing unregister_netdev (Jason Lunz)
- - Add CONFIG_SUNDANCE_MMIO config option (jgarzik)
- - Better rx buf size calculation (Donald Becker)
-
- Version LK1.05 (D-Link):
- - Fix DFE-580TX packet drop issue (for DL10050C)
- - Fix reset_tx logic
-
- Version LK1.06 (D-Link):
- - Fix crash while unloading driver
-
- Versin LK1.06b (D-Link):
- - New tx scheme, adaptive tx_coalesce
-
- Version LK1.07 (D-Link):
- - Fix tx bugs in big-endian machines
- - Remove unused max_interrupt_work module parameter, the new
- NAPI-like rx scheme doesn't need it.
- - Remove redundancy get_stats() in intr_handler(), those
- I/O access could affect performance in ARM-based system
- - Add Linux software VLAN support
-
- Version LK1.08 (Philippe De Muyter phdm@macqel.be):
- - Fix bug of custom mac address
- (StationAddr register only accept word write)
-
- Version LK1.09 (D-Link):
- - Fix the flowctrl bug.
- - Set Pause bit in MII ANAR if flow control enabled.
-
- Version LK1.09a (ICPlus):
- - Add the delay time in reading the contents of EEPROM
-
- Version LK1.10 (Philippe De Muyter phdm@macqel.be):
- - Make 'unblock interface after Tx underrun' work
-
- Version LK1.11 (Pedro Alejandro Lopez-Valencia palopezv at gmail.com):
- - Add support for IC Plus Corporation IP100A chipset
*/
#define DRV_NAME "sundance"
-#define DRV_VERSION "1.01+LK1.11"
-#define DRV_RELDATE "14-Jun-2006"
+#define DRV_VERSION "1.1"
+#define DRV_RELDATE "27-Jun-2006"
/* The user-configurable values.
@@ -282,15 +204,15 @@ IVc. Errata
#define USE_IO_OPS 1
#endif
-static struct pci_device_id sundance_pci_tbl[] = {
- {0x1186, 0x1002, 0x1186, 0x1002, 0, 0, 0},
- {0x1186, 0x1002, 0x1186, 0x1003, 0, 0, 1},
- {0x1186, 0x1002, 0x1186, 0x1012, 0, 0, 2},
- {0x1186, 0x1002, 0x1186, 0x1040, 0, 0, 3},
- {0x1186, 0x1002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
- {0x13F0, 0x0201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
- {0x13F0, 0x0200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
- {0,}
+static const struct pci_device_id sundance_pci_tbl[] = {
+ { 0x1186, 0x1002, 0x1186, 0x1002, 0, 0, 0 },
+ { 0x1186, 0x1002, 0x1186, 0x1003, 0, 0, 1 },
+ { 0x1186, 0x1002, 0x1186, 0x1012, 0, 0, 2 },
+ { 0x1186, 0x1002, 0x1186, 0x1040, 0, 0, 3 },
+ { 0x1186, 0x1002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
+ { 0x13F0, 0x0201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 },
+ { 0x13F0, 0x0200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6 },
+ { }
};
MODULE_DEVICE_TABLE(pci, sundance_pci_tbl);
@@ -301,7 +223,7 @@ enum {
struct pci_id_info {
const char *name;
};
-static const struct pci_id_info pci_id_tbl[] = {
+static const struct pci_id_info pci_id_tbl[] __devinitdata = {
{"D-Link DFE-550TX FAST Ethernet Adapter"},
{"D-Link DFE-550FX 100Mbps Fiber-optics Adapter"},
{"D-Link DFE-580TX 4 port Server Adapter"},
@@ -309,7 +231,7 @@ static const struct pci_id_info pci_id_tbl[] = {
{"D-Link DL10050-based FAST Ethernet Adapter"},
{"Sundance Technology Alta"},
{"IC Plus Corporation IP100A FAST Ethernet Adapter"},
- {NULL,}, /* 0 terminated list. */
+ { } /* terminate list. */
};
/* This driver was written to use PCI memory space, however x86-oriented
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index 8673fd4c08c..c6f5bc3c042 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -3255,12 +3255,7 @@ static void __devexit happy_meal_pci_remove(struct pci_dev *pdev)
}
static struct pci_device_id happymeal_pci_ids[] = {
- {
- .vendor = PCI_VENDOR_ID_SUN,
- .device = PCI_DEVICE_ID_SUN_HAPPYMEAL,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- },
+ { PCI_DEVICE(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_HAPPYMEAL) },
{ } /* Terminating entry */
};
@@ -3275,7 +3270,7 @@ static struct pci_driver hme_pci_driver = {
static int __init happy_meal_pci_init(void)
{
- return pci_module_init(&hme_pci_driver);
+ return pci_register_driver(&hme_pci_driver);
}
static void happy_meal_pci_exit(void)
diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c
index 1ef9fd39a79..0e3fdf7c6dd 100644
--- a/drivers/net/sunlance.c
+++ b/drivers/net/sunlance.c
@@ -1537,7 +1537,7 @@ static int __init sparc_lance_init(void)
{
if ((idprom->id_machtype == (SM_SUN4|SM_4_330)) ||
(idprom->id_machtype == (SM_SUN4|SM_4_470))) {
- memset(&sun4_sdev, 0, sizeof(sdev));
+ memset(&sun4_sdev, 0, sizeof(struct sbus_dev));
sun4_sdev.reg_addrs[0].phys_addr = sun4_eth_physaddr;
sun4_sdev.irqs[0] = 6;
return sparc_lance_probe_one(&sun4_sdev, NULL, NULL);
@@ -1547,16 +1547,16 @@ static int __init sparc_lance_init(void)
static int __exit sunlance_sun4_remove(void)
{
- struct lance_private *lp = dev_get_drvdata(&sun4_sdev->dev);
+ struct lance_private *lp = dev_get_drvdata(&sun4_sdev.ofdev.dev);
struct net_device *net_dev = lp->dev;
unregister_netdevice(net_dev);
- lance_free_hwresources(root_lance_dev);
+ lance_free_hwresources(lp);
free_netdev(net_dev);
- dev_set_drvdata(&sun4_sdev->dev, NULL);
+ dev_set_drvdata(&sun4_sdev.ofdev.dev, NULL);
return 0;
}
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index f645921aff8..6f97962dd06 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -68,8 +68,8 @@
#define DRV_MODULE_NAME "tg3"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "3.62"
-#define DRV_MODULE_RELDATE "June 30, 2006"
+#define DRV_MODULE_VERSION "3.64"
+#define DRV_MODULE_RELDATE "July 31, 2006"
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
@@ -3097,7 +3097,7 @@ static int tg3_alloc_rx_skb(struct tg3 *tp, u32 opaque_key,
* Callers depend upon this behavior and assume that
* we leave everything unchanged if we fail.
*/
- skb = dev_alloc_skb(skb_size);
+ skb = netdev_alloc_skb(tp->dev, skb_size);
if (skb == NULL)
return -ENOMEM;
@@ -3270,7 +3270,7 @@ static int tg3_rx(struct tg3 *tp, int budget)
tg3_recycle_rx(tp, opaque_key,
desc_idx, *post_ptr);
- copy_skb = dev_alloc_skb(len + 2);
+ copy_skb = netdev_alloc_skb(tp->dev, len + 2);
if (copy_skb == NULL)
goto drop_it_no_recycle;
@@ -3590,6 +3590,28 @@ static irqreturn_t tg3_test_isr(int irq, void *dev_id,
static int tg3_init_hw(struct tg3 *, int);
static int tg3_halt(struct tg3 *, int, int);
+/* Restart hardware after configuration changes, self-test, etc.
+ * Invoked with tp->lock held.
+ */
+static int tg3_restart_hw(struct tg3 *tp, int reset_phy)
+{
+ int err;
+
+ err = tg3_init_hw(tp, reset_phy);
+ if (err) {
+ printk(KERN_ERR PFX "%s: Failed to re-initialize device, "
+ "aborting.\n", tp->dev->name);
+ tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
+ tg3_full_unlock(tp);
+ del_timer_sync(&tp->timer);
+ tp->irq_sync = 0;
+ netif_poll_enable(tp->dev);
+ dev_close(tp->dev);
+ tg3_full_lock(tp, 0);
+ }
+ return err;
+}
+
#ifdef CONFIG_NET_POLL_CONTROLLER
static void tg3_poll_controller(struct net_device *dev)
{
@@ -3630,13 +3652,15 @@ static void tg3_reset_task(void *_data)
}
tg3_halt(tp, RESET_KIND_SHUTDOWN, 0);
- tg3_init_hw(tp, 1);
+ if (tg3_init_hw(tp, 1))
+ goto out;
tg3_netif_start(tp);
if (restart_timer)
mod_timer(&tp->timer, jiffies + 1);
+out:
tp->tg3_flags &= ~TG3_FLAG_IN_RESET_TASK;
tg3_full_unlock(tp);
@@ -4124,6 +4148,7 @@ static inline void tg3_set_mtu(struct net_device *dev, struct tg3 *tp,
static int tg3_change_mtu(struct net_device *dev, int new_mtu)
{
struct tg3 *tp = netdev_priv(dev);
+ int err;
if (new_mtu < TG3_MIN_MTU || new_mtu > TG3_MAX_MTU(tp))
return -EINVAL;
@@ -4144,13 +4169,14 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu)
tg3_set_mtu(dev, tp, new_mtu);
- tg3_init_hw(tp, 0);
+ err = tg3_restart_hw(tp, 0);
- tg3_netif_start(tp);
+ if (!err)
+ tg3_netif_start(tp);
tg3_full_unlock(tp);
- return 0;
+ return err;
}
/* Free up pending packets in all rx/tx rings.
@@ -4232,7 +4258,7 @@ static void tg3_free_rings(struct tg3 *tp)
* end up in the driver. tp->{tx,}lock are held and thus
* we may not sleep.
*/
-static void tg3_init_rings(struct tg3 *tp)
+static int tg3_init_rings(struct tg3 *tp)
{
u32 i;
@@ -4281,18 +4307,38 @@ static void tg3_init_rings(struct tg3 *tp)
/* Now allocate fresh SKBs for each rx ring. */
for (i = 0; i < tp->rx_pending; i++) {
- if (tg3_alloc_rx_skb(tp, RXD_OPAQUE_RING_STD,
- -1, i) < 0)
+ if (tg3_alloc_rx_skb(tp, RXD_OPAQUE_RING_STD, -1, i) < 0) {
+ printk(KERN_WARNING PFX
+ "%s: Using a smaller RX standard ring, "
+ "only %d out of %d buffers were allocated "
+ "successfully.\n",
+ tp->dev->name, i, tp->rx_pending);
+ if (i == 0)
+ return -ENOMEM;
+ tp->rx_pending = i;
break;
+ }
}
if (tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) {
for (i = 0; i < tp->rx_jumbo_pending; i++) {
if (tg3_alloc_rx_skb(tp, RXD_OPAQUE_RING_JUMBO,
- -1, i) < 0)
+ -1, i) < 0) {
+ printk(KERN_WARNING PFX
+ "%s: Using a smaller RX jumbo ring, "
+ "only %d out of %d buffers were "
+ "allocated successfully.\n",
+ tp->dev->name, i, tp->rx_jumbo_pending);
+ if (i == 0) {
+ tg3_free_rings(tp);
+ return -ENOMEM;
+ }
+ tp->rx_jumbo_pending = i;
break;
+ }
}
}
+ return 0;
}
/*
@@ -5815,6 +5861,7 @@ static int tg3_set_mac_addr(struct net_device *dev, void *p)
{
struct tg3 *tp = netdev_priv(dev);
struct sockaddr *addr = p;
+ int err = 0;
if (!is_valid_ether_addr(addr->sa_data))
return -EINVAL;
@@ -5832,9 +5879,9 @@ static int tg3_set_mac_addr(struct net_device *dev, void *p)
tg3_full_lock(tp, 1);
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
- tg3_init_hw(tp, 0);
-
- tg3_netif_start(tp);
+ err = tg3_restart_hw(tp, 0);
+ if (!err)
+ tg3_netif_start(tp);
tg3_full_unlock(tp);
} else {
spin_lock_bh(&tp->lock);
@@ -5842,7 +5889,7 @@ static int tg3_set_mac_addr(struct net_device *dev, void *p)
spin_unlock_bh(&tp->lock);
}
- return 0;
+ return err;
}
/* tp->lock is held. */
@@ -5942,7 +5989,9 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
* can only do this after the hardware has been
* successfully reset.
*/
- tg3_init_rings(tp);
+ err = tg3_init_rings(tp);
+ if (err)
+ return err;
/* This value is determined during the probe time DMA
* engine test, tg3_test_dma.
@@ -7956,7 +8005,7 @@ static void tg3_get_ringparam(struct net_device *dev, struct ethtool_ringparam *
static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
{
struct tg3 *tp = netdev_priv(dev);
- int irq_sync = 0;
+ int irq_sync = 0, err = 0;
if ((ering->rx_pending > TG3_RX_RING_SIZE - 1) ||
(ering->rx_jumbo_pending > TG3_RX_JUMBO_RING_SIZE - 1) ||
@@ -7980,13 +8029,14 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e
if (netif_running(dev)) {
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
- tg3_init_hw(tp, 1);
- tg3_netif_start(tp);
+ err = tg3_restart_hw(tp, 1);
+ if (!err)
+ tg3_netif_start(tp);
}
tg3_full_unlock(tp);
- return 0;
+ return err;
}
static void tg3_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
@@ -8001,7 +8051,7 @@ static void tg3_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam
static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
{
struct tg3 *tp = netdev_priv(dev);
- int irq_sync = 0;
+ int irq_sync = 0, err = 0;
if (netif_running(dev)) {
tg3_netif_stop(tp);
@@ -8025,13 +8075,14 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam
if (netif_running(dev)) {
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
- tg3_init_hw(tp, 1);
- tg3_netif_start(tp);
+ err = tg3_restart_hw(tp, 1);
+ if (!err)
+ tg3_netif_start(tp);
}
tg3_full_unlock(tp);
- return 0;
+ return err;
}
static u32 tg3_get_rx_csum(struct net_device *dev)
@@ -8567,7 +8618,7 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode)
err = -EIO;
tx_len = 1514;
- skb = dev_alloc_skb(tx_len);
+ skb = netdev_alloc_skb(tp->dev, tx_len);
if (!skb)
return -ENOMEM;
@@ -8666,7 +8717,9 @@ static int tg3_test_loopback(struct tg3 *tp)
if (!netif_running(tp->dev))
return TG3_LOOPBACK_FAILED;
- tg3_reset_hw(tp, 1);
+ err = tg3_reset_hw(tp, 1);
+ if (err)
+ return TG3_LOOPBACK_FAILED;
if (tg3_run_loopback(tp, TG3_MAC_LOOPBACK))
err |= TG3_MAC_LOOPBACK_FAILED;
@@ -8740,8 +8793,8 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
if (netif_running(dev)) {
tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
- tg3_init_hw(tp, 1);
- tg3_netif_start(tp);
+ if (!tg3_restart_hw(tp, 1))
+ tg3_netif_start(tp);
}
tg3_full_unlock(tp);
@@ -10078,6 +10131,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
static struct pci_device_id write_reorder_chipsets[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD,
PCI_DEVICE_ID_AMD_FE_GATE_700C) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD,
+ PCI_DEVICE_ID_AMD_8131_BRIDGE) },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA,
PCI_DEVICE_ID_VIA_8385_0) },
{ },
@@ -11697,7 +11752,8 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
tg3_full_lock(tp, 0);
tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
- tg3_init_hw(tp, 1);
+ if (tg3_restart_hw(tp, 1))
+ goto out;
tp->timer.expires = jiffies + tp->timer_offset;
add_timer(&tp->timer);
@@ -11705,6 +11761,7 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
netif_device_attach(dev);
tg3_netif_start(tp);
+out:
tg3_full_unlock(tp);
}
@@ -11731,16 +11788,19 @@ static int tg3_resume(struct pci_dev *pdev)
tg3_full_lock(tp, 0);
tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
- tg3_init_hw(tp, 1);
+ err = tg3_restart_hw(tp, 1);
+ if (err)
+ goto out;
tp->timer.expires = jiffies + tp->timer_offset;
add_timer(&tp->timer);
tg3_netif_start(tp);
+out:
tg3_full_unlock(tp);
- return 0;
+ return err;
}
static struct pci_driver tg3_driver = {
diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c
index b4c0d101a7d..7f414815cc6 100644
--- a/drivers/net/tulip/winbond-840.c
+++ b/drivers/net/tulip/winbond-840.c
@@ -224,24 +224,21 @@ static const struct pci_device_id w840_pci_tbl[] = {
};
MODULE_DEVICE_TABLE(pci, w840_pci_tbl);
+enum {
+ netdev_res_size = 128, /* size of PCI BAR resource */
+};
+
struct pci_id_info {
const char *name;
- struct match_info {
- int pci, pci_mask, subsystem, subsystem_mask;
- int revision, revision_mask; /* Only 8 bits. */
- } id;
- int io_size; /* Needed for I/O region check or ioremap(). */
- int drv_flags; /* Driver use, intended as capability flags. */
+ int drv_flags; /* Driver use, intended as capability flags. */
};
-static struct pci_id_info pci_id_tbl[] = {
- {"Winbond W89c840", /* Sometime a Level-One switch card. */
- { 0x08401050, 0xffffffff, 0x81530000, 0xffff0000 },
- 128, CanHaveMII | HasBrokenTx | FDXOnNoMII},
- {"Winbond W89c840", { 0x08401050, 0xffffffff, },
- 128, CanHaveMII | HasBrokenTx},
- {"Compex RL100-ATX", { 0x201111F6, 0xffffffff,},
- 128, CanHaveMII | HasBrokenTx},
- {NULL,}, /* 0 terminated list. */
+
+static const struct pci_id_info pci_id_tbl[] __devinitdata = {
+ { /* Sometime a Level-One switch card. */
+ "Winbond W89c840", CanHaveMII | HasBrokenTx | FDXOnNoMII},
+ { "Winbond W89c840", CanHaveMII | HasBrokenTx},
+ { "Compex RL100-ATX", CanHaveMII | HasBrokenTx},
+ { } /* terminate list. */
};
/* This driver was written to use PCI memory space, however some x86 systems
@@ -399,7 +396,7 @@ static int __devinit w840_probe1 (struct pci_dev *pdev,
#ifdef USE_IO_OPS
bar = 0;
#endif
- ioaddr = pci_iomap(pdev, bar, pci_id_tbl[chip_idx].io_size);
+ ioaddr = pci_iomap(pdev, bar, netdev_res_size);
if (!ioaddr)
goto err_out_free_res;
diff --git a/drivers/net/tulip/xircom_tulip_cb.c b/drivers/net/tulip/xircom_tulip_cb.c
index 091ebb7a62f..17ca7dc42e6 100644
--- a/drivers/net/tulip/xircom_tulip_cb.c
+++ b/drivers/net/tulip/xircom_tulip_cb.c
@@ -10,26 +10,11 @@
410 Severn Ave., Suite 210
Annapolis MD 21403
- -----------------------------------------------------------
-
- Linux kernel-specific changes:
-
- LK1.0 (Ion Badulescu)
- - Major cleanup
- - Use 2.4 PCI API
- - Support ethtool
- - Rewrite perfect filter/hash code
- - Use interrupts for media changes
-
- LK1.1 (Ion Badulescu)
- - Disallow negotiation of unsupported full-duplex modes
*/
#define DRV_NAME "xircom_tulip_cb"
-#define DRV_VERSION "0.91+LK1.1"
-#define DRV_RELDATE "October 11, 2001"
-
-#define CARDBUS 1
+#define DRV_VERSION "0.92"
+#define DRV_RELDATE "June 27, 2006"
/* A few user-configurable values. */
@@ -306,10 +291,10 @@ struct xircom_private {
struct xircom_tx_desc tx_ring[TX_RING_SIZE];
/* The saved address of a sent-in-place packet/buffer, for skfree(). */
struct sk_buff* tx_skbuff[TX_RING_SIZE];
-#ifdef CARDBUS
+
/* The X3201-3 requires 4-byte aligned tx bufs */
struct sk_buff* tx_aligned_skbuff[TX_RING_SIZE];
-#endif
+
/* The addresses of receive-in-place skbuffs. */
struct sk_buff* rx_skbuff[RX_RING_SIZE];
u16 setup_frame[PKT_SETUP_SZ / sizeof(u16)]; /* Pseudo-Tx frame to init address table. */
@@ -908,10 +893,8 @@ static void xircom_init_ring(struct net_device *dev)
tp->tx_skbuff[i] = NULL;
tp->tx_ring[i].status = 0;
tp->tx_ring[i].buffer2 = virt_to_bus(&tp->tx_ring[i+1]);
-#ifdef CARDBUS
if (tp->chip_id == X3201_3)
tp->tx_aligned_skbuff[i] = dev_alloc_skb(PKT_BUF_SZ);
-#endif /* CARDBUS */
}
tp->tx_ring[i-1].buffer2 = virt_to_bus(&tp->tx_ring[0]);
}
@@ -931,12 +914,10 @@ xircom_start_xmit(struct sk_buff *skb, struct net_device *dev)
entry = tp->cur_tx % TX_RING_SIZE;
tp->tx_skbuff[entry] = skb;
-#ifdef CARDBUS
if (tp->chip_id == X3201_3) {
memcpy(tp->tx_aligned_skbuff[entry]->data,skb->data,skb->len);
tp->tx_ring[entry].buffer1 = virt_to_bus(tp->tx_aligned_skbuff[entry]->data);
} else
-#endif
tp->tx_ring[entry].buffer1 = virt_to_bus(skb->data);
if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index 063816f2b11..4103c37172f 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -805,7 +805,7 @@ typhoon_start_tx(struct sk_buff *skb, struct net_device *dev)
* If problems develop with TSO, check this first.
*/
numDesc = skb_shinfo(skb)->nr_frags + 1;
- if(skb_tso_size(skb))
+ if (skb_is_gso(skb))
numDesc++;
/* When checking for free space in the ring, we need to also
@@ -845,7 +845,7 @@ typhoon_start_tx(struct sk_buff *skb, struct net_device *dev)
TYPHOON_TX_PF_VLAN_TAG_SHIFT);
}
- if(skb_tso_size(skb)) {
+ if (skb_is_gso(skb)) {
first_txd->processFlags |= TYPHOON_TX_PF_TCP_SEGMENT;
first_txd->numDesc++;
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index 98b6f3207d3..d3d0ec97031 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -25,117 +25,13 @@
version. He may or may not be interested in bug reports on this
code. You can find his versions at:
http://www.scyld.com/network/via-rhine.html
-
-
- Linux kernel version history:
-
- LK1.1.0:
- - Jeff Garzik: softnet 'n stuff
-
- LK1.1.1:
- - Justin Guyett: softnet and locking fixes
- - Jeff Garzik: use PCI interface
-
- LK1.1.2:
- - Urban Widmark: minor cleanups, merges from Becker 1.03a/1.04 versions
-
- LK1.1.3:
- - Urban Widmark: use PCI DMA interface (with thanks to the eepro100.c
- code) update "Theory of Operation" with
- softnet/locking changes
- - Dave Miller: PCI DMA and endian fixups
- - Jeff Garzik: MOD_xxx race fixes, updated PCI resource allocation
-
- LK1.1.4:
- - Urban Widmark: fix gcc 2.95.2 problem and
- remove writel's to fixed address 0x7c
-
- LK1.1.5:
- - Urban Widmark: mdio locking, bounce buffer changes
- merges from Beckers 1.05 version
- added netif_running_on/off support
-
- LK1.1.6:
- - Urban Widmark: merges from Beckers 1.08b version (VT6102 + mdio)
- set netif_running_on/off on startup, del_timer_sync
-
- LK1.1.7:
- - Manfred Spraul: added reset into tx_timeout
-
- LK1.1.9:
- - Urban Widmark: merges from Beckers 1.10 version
- (media selection + eeprom reload)
- - David Vrabel: merges from D-Link "1.11" version
- (disable WOL and PME on startup)
-
- LK1.1.10:
- - Manfred Spraul: use "singlecopy" for unaligned buffers
- don't allocate bounce buffers for !ReqTxAlign cards
-
- LK1.1.11:
- - David Woodhouse: Set dev->base_addr before the first time we call
- wait_for_reset(). It's a lot happier that way.
- Free np->tx_bufs only if we actually allocated it.
-
- LK1.1.12:
- - Martin Eriksson: Allow Memory-Mapped IO to be enabled.
-
- LK1.1.13 (jgarzik):
- - Add ethtool support
- - Replace some MII-related magic numbers with constants
-
- LK1.1.14 (Ivan G.):
- - fixes comments for Rhine-III
- - removes W_MAX_TIMEOUT (unused)
- - adds HasDavicomPhy for Rhine-I (basis: linuxfet driver; my card
- is R-I and has Davicom chip, flag is referenced in kernel driver)
- - sends chip_id as a parameter to wait_for_reset since np is not
- initialized on first call
- - changes mmio "else if (chip_id==VT6102)" to "else" so it will work
- for Rhine-III's (documentation says same bit is correct)
- - transmit frame queue message is off by one - fixed
- - adds IntrNormalSummary to "Something Wicked" exclusion list
- so normal interrupts will not trigger the message (src: Donald Becker)
- (Roger Luethi)
- - show confused chip where to continue after Tx error
- - location of collision counter is chip specific
- - allow selecting backoff algorithm (module parameter)
-
- LK1.1.15 (jgarzik):
- - Use new MII lib helper generic_mii_ioctl
-
- LK1.1.16 (Roger Luethi)
- - Etherleak fix
- - Handle Tx buffer underrun
- - Fix bugs in full duplex handling
- - New reset code uses "force reset" cmd on Rhine-II
- - Various clean ups
-
- LK1.1.17 (Roger Luethi)
- - Fix race in via_rhine_start_tx()
- - On errors, wait for Tx engine to turn off before scavenging
- - Handle Tx descriptor write-back race on Rhine-II
- - Force flushing for PCI posted writes
- - More reset code changes
-
- LK1.1.18 (Roger Luethi)
- - No filtering multicast in promisc mode (Edward Peng)
- - Fix for Rhine-I Tx timeouts
-
- LK1.1.19 (Roger Luethi)
- - Increase Tx threshold for unspecified errors
-
- LK1.2.0-2.6 (Roger Luethi)
- - Massive clean-up
- - Rewrite PHY, media handling (remove options, full_duplex, backoff)
- - Fix Tx engine race for good
- - Craig Brind: Zero padded aligned buffers for short packets.
+ [link no longer provides useful info -jgarzik]
*/
#define DRV_NAME "via-rhine"
-#define DRV_VERSION "1.2.0-2.6"
-#define DRV_RELDATE "June-10-2004"
+#define DRV_VERSION "1.4.0"
+#define DRV_RELDATE "June-27-2006"
/* A few user-configurable values.
@@ -356,12 +252,11 @@ enum rhine_quirks {
/* Beware of PCI posted writes */
#define IOSYNC do { ioread8(ioaddr + StationAddr); } while (0)
-static struct pci_device_id rhine_pci_tbl[] =
-{
- {0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, /* VT86C100A */
- {0x1106, 0x3065, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, /* VT6102 */
- {0x1106, 0x3106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, /* 6105{,L,LOM} */
- {0x1106, 0x3053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, /* VT6105M */
+static const struct pci_device_id rhine_pci_tbl[] = {
+ { 0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, }, /* VT86C100A */
+ { 0x1106, 0x3065, PCI_ANY_ID, PCI_ANY_ID, }, /* VT6102 */
+ { 0x1106, 0x3106, PCI_ANY_ID, PCI_ANY_ID, }, /* 6105{,L,LOM} */
+ { 0x1106, 0x3053, PCI_ANY_ID, PCI_ANY_ID, }, /* VT6105M */
{ } /* terminate list */
};
MODULE_DEVICE_TABLE(pci, rhine_pci_tbl);
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index ba2972ba375..aa9cd92f46b 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -229,7 +229,8 @@ static int rx_copybreak = 200;
module_param(rx_copybreak, int, 0644);
MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames");
-static void velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr, struct velocity_info_tbl *info);
+static void velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr,
+ const struct velocity_info_tbl *info);
static int velocity_get_pci_info(struct velocity_info *, struct pci_dev *pdev);
static void velocity_print_info(struct velocity_info *vptr);
static int velocity_open(struct net_device *dev);
@@ -294,9 +295,9 @@ static void velocity_unregister_notifier(void)
* Internal board variants. At the moment we have only one
*/
-static struct velocity_info_tbl chip_info_table[] = {
- {CHIP_TYPE_VT6110, "VIA Networking Velocity Family Gigabit Ethernet Adapter", 256, 1, 0x00FFFFFFUL},
- {0, NULL}
+static const struct velocity_info_tbl chip_info_table[] __devinitdata = {
+ {CHIP_TYPE_VT6110, "VIA Networking Velocity Family Gigabit Ethernet Adapter", 1, 0x00FFFFFFUL},
+ { }
};
/*
@@ -304,10 +305,9 @@ static struct velocity_info_tbl chip_info_table[] = {
* device driver. Used for hotplug autoloading.
*/
-static struct pci_device_id velocity_id_table[] __devinitdata = {
- {PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_612X,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) chip_info_table},
- {0, }
+static const struct pci_device_id velocity_id_table[] __devinitdata = {
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_612X) },
+ { }
};
MODULE_DEVICE_TABLE(pci, velocity_id_table);
@@ -341,7 +341,7 @@ static char __devinit *get_chip_name(enum chip_type chip_id)
static void __devexit velocity_remove1(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
#ifdef CONFIG_PM
unsigned long flags;
@@ -686,21 +686,23 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi
static int first = 1;
struct net_device *dev;
int i;
- struct velocity_info_tbl *info = (struct velocity_info_tbl *) ent->driver_data;
+ const struct velocity_info_tbl *info = &chip_info_table[ent->driver_data];
struct velocity_info *vptr;
struct mac_regs __iomem * regs;
int ret = -ENOMEM;
+ /* FIXME: this driver, like almost all other ethernet drivers,
+ * can support more than MAX_UNITS.
+ */
if (velocity_nics >= MAX_UNITS) {
- printk(KERN_NOTICE VELOCITY_NAME ": already found %d NICs.\n",
- velocity_nics);
+ dev_notice(&pdev->dev, "already found %d NICs.\n",
+ velocity_nics);
return -ENODEV;
}
dev = alloc_etherdev(sizeof(struct velocity_info));
-
- if (dev == NULL) {
- printk(KERN_ERR VELOCITY_NAME ": allocate net device failed.\n");
+ if (!dev) {
+ dev_err(&pdev->dev, "allocate net device failed.\n");
goto out;
}
@@ -708,7 +710,7 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
- vptr = dev->priv;
+ vptr = netdev_priv(dev);
if (first) {
@@ -731,17 +733,17 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi
ret = velocity_get_pci_info(vptr, pdev);
if (ret < 0) {
- printk(KERN_ERR VELOCITY_NAME ": Failed to find PCI device.\n");
+ /* error message already printed */
goto err_disable;
}
ret = pci_request_regions(pdev, VELOCITY_NAME);
if (ret < 0) {
- printk(KERN_ERR VELOCITY_NAME ": Failed to find PCI device.\n");
+ dev_err(&pdev->dev, "No PCI resources.\n");
goto err_disable;
}
- regs = ioremap(vptr->memaddr, vptr->io_size);
+ regs = ioremap(vptr->memaddr, VELOCITY_IO_SIZE);
if (regs == NULL) {
ret = -EIO;
goto err_release_res;
@@ -859,13 +861,14 @@ static void __devinit velocity_print_info(struct velocity_info *vptr)
* discovered.
*/
-static void __devinit velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr, struct velocity_info_tbl *info)
+static void __devinit velocity_init_info(struct pci_dev *pdev,
+ struct velocity_info *vptr,
+ const struct velocity_info_tbl *info)
{
memset(vptr, 0, sizeof(struct velocity_info));
vptr->pdev = pdev;
vptr->chip_id = info->chip_id;
- vptr->io_size = info->io_size;
vptr->num_txq = info->txqueue;
vptr->multicast_limit = MCAM_SIZE;
spin_lock_init(&vptr->lock);
@@ -883,8 +886,7 @@ static void __devinit velocity_init_info(struct pci_dev *pdev, struct velocity_i
static int __devinit velocity_get_pci_info(struct velocity_info *vptr, struct pci_dev *pdev)
{
-
- if(pci_read_config_byte(pdev, PCI_REVISION_ID, &vptr->rev_id) < 0)
+ if (pci_read_config_byte(pdev, PCI_REVISION_ID, &vptr->rev_id) < 0)
return -EIO;
pci_set_master(pdev);
@@ -892,24 +894,20 @@ static int __devinit velocity_get_pci_info(struct velocity_info *vptr, struct pc
vptr->ioaddr = pci_resource_start(pdev, 0);
vptr->memaddr = pci_resource_start(pdev, 1);
- if(!(pci_resource_flags(pdev, 0) & IORESOURCE_IO))
- {
- printk(KERN_ERR "%s: region #0 is not an I/O resource, aborting.\n",
- pci_name(pdev));
+ if (!(pci_resource_flags(pdev, 0) & IORESOURCE_IO)) {
+ dev_err(&pdev->dev,
+ "region #0 is not an I/O resource, aborting.\n");
return -EINVAL;
}
- if((pci_resource_flags(pdev, 1) & IORESOURCE_IO))
- {
- printk(KERN_ERR "%s: region #1 is an I/O resource, aborting.\n",
- pci_name(pdev));
+ if ((pci_resource_flags(pdev, 1) & IORESOURCE_IO)) {
+ dev_err(&pdev->dev,
+ "region #1 is an I/O resource, aborting.\n");
return -EINVAL;
}
- if(pci_resource_len(pdev, 1) < 256)
- {
- printk(KERN_ERR "%s: region #1 is too small.\n",
- pci_name(pdev));
+ if (pci_resource_len(pdev, 1) < VELOCITY_IO_SIZE) {
+ dev_err(&pdev->dev, "region #1 is too small.\n");
return -EINVAL;
}
vptr->pdev = pdev;
@@ -1728,7 +1726,7 @@ static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_
static int velocity_open(struct net_device *dev)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
int ret;
vptr->rx_buf_sz = (dev->mtu <= 1504 ? PKT_BUF_SZ : dev->mtu + 32);
@@ -1785,7 +1783,7 @@ err_free_desc_rings:
static int velocity_change_mtu(struct net_device *dev, int new_mtu)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
unsigned long flags;
int oldmtu = dev->mtu;
int ret = 0;
@@ -1861,7 +1859,7 @@ static void velocity_shutdown(struct velocity_info *vptr)
static int velocity_close(struct net_device *dev)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
netif_stop_queue(dev);
velocity_shutdown(vptr);
@@ -1894,7 +1892,7 @@ static int velocity_close(struct net_device *dev)
static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
int qnum = 0;
struct tx_desc *td_ptr;
struct velocity_td_info *tdinfo;
@@ -2049,7 +2047,7 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
static int velocity_intr(int irq, void *dev_instance, struct pt_regs *regs)
{
struct net_device *dev = dev_instance;
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
u32 isr_status;
int max_count = 0;
@@ -2104,7 +2102,7 @@ static int velocity_intr(int irq, void *dev_instance, struct pt_regs *regs)
static void velocity_set_multi(struct net_device *dev)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
struct mac_regs __iomem * regs = vptr->mac_regs;
u8 rx_mode;
int i;
@@ -2153,7 +2151,7 @@ static void velocity_set_multi(struct net_device *dev)
static struct net_device_stats *velocity_get_stats(struct net_device *dev)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
/* If the hardware is down, don't touch MII */
if(!netif_running(dev))
@@ -2196,7 +2194,7 @@ static struct net_device_stats *velocity_get_stats(struct net_device *dev)
static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
int ret;
/* If we are asked for information and the device is power
@@ -2744,7 +2742,7 @@ static u32 check_connection_type(struct mac_regs __iomem * regs)
if (PHYSR0 & PHYSR0_SPDG)
status |= VELOCITY_SPEED_1000;
- if (PHYSR0 & PHYSR0_SPD10)
+ else if (PHYSR0 & PHYSR0_SPD10)
status |= VELOCITY_SPEED_10;
else
status |= VELOCITY_SPEED_100;
@@ -2825,7 +2823,7 @@ static void enable_flow_control_ability(struct velocity_info *vptr)
static int velocity_ethtool_up(struct net_device *dev)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
if (!netif_running(dev))
pci_set_power_state(vptr->pdev, PCI_D0);
return 0;
@@ -2841,20 +2839,29 @@ static int velocity_ethtool_up(struct net_device *dev)
static void velocity_ethtool_down(struct net_device *dev)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
if (!netif_running(dev))
pci_set_power_state(vptr->pdev, PCI_D3hot);
}
static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
struct mac_regs __iomem * regs = vptr->mac_regs;
u32 status;
status = check_connection_type(vptr->mac_regs);
- cmd->supported = SUPPORTED_TP | SUPPORTED_Autoneg | SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full;
- if (status & VELOCITY_SPEED_100)
+ cmd->supported = SUPPORTED_TP |
+ SUPPORTED_Autoneg |
+ SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_1000baseT_Half |
+ SUPPORTED_1000baseT_Full;
+ if (status & VELOCITY_SPEED_1000)
+ cmd->speed = SPEED_1000;
+ else if (status & VELOCITY_SPEED_100)
cmd->speed = SPEED_100;
else
cmd->speed = SPEED_10;
@@ -2873,7 +2880,7 @@ static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd
static int velocity_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
u32 curr_status;
u32 new_status = 0;
int ret = 0;
@@ -2896,14 +2903,14 @@ static int velocity_set_settings(struct net_device *dev, struct ethtool_cmd *cmd
static u32 velocity_get_link(struct net_device *dev)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
struct mac_regs __iomem * regs = vptr->mac_regs;
- return BYTE_REG_BITS_IS_ON(PHYSR0_LINKGD, &regs->PHYSR0) ? 0 : 1;
+ return BYTE_REG_BITS_IS_ON(PHYSR0_LINKGD, &regs->PHYSR0) ? 1 : 0;
}
static void velocity_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
strcpy(info->driver, VELOCITY_NAME);
strcpy(info->version, VELOCITY_VERSION);
strcpy(info->bus_info, pci_name(vptr->pdev));
@@ -2911,7 +2918,7 @@ static void velocity_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo
static void velocity_ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
wol->supported = WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_ARP;
wol->wolopts |= WAKE_MAGIC;
/*
@@ -2927,7 +2934,7 @@ static void velocity_ethtool_get_wol(struct net_device *dev, struct ethtool_woli
static int velocity_ethtool_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
if (!(wol->wolopts & (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_ARP)))
return -EFAULT;
@@ -2992,7 +2999,7 @@ static struct ethtool_ops velocity_ethtool_ops = {
static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
struct mac_regs __iomem * regs = vptr->mac_regs;
unsigned long flags;
struct mii_ioctl_data *miidata = if_mii(ifr);
diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h
index f1b2640ebdc..496c3d59744 100644
--- a/drivers/net/via-velocity.h
+++ b/drivers/net/via-velocity.h
@@ -31,6 +31,8 @@
#define VELOCITY_FULL_DRV_NAM "VIA Networking Velocity Family Gigabit Ethernet Adapter Driver"
#define VELOCITY_VERSION "1.13"
+#define VELOCITY_IO_SIZE 256
+
#define PKT_BUF_SZ 1540
#define MAX_UNITS 8
@@ -1191,7 +1193,6 @@ enum chip_type {
struct velocity_info_tbl {
enum chip_type chip_id;
char *name;
- int io_size;
int txqueue;
u32 flags;
};
@@ -1751,7 +1752,6 @@ struct velocity_info {
struct mac_regs __iomem * mac_regs;
unsigned long memaddr;
unsigned long ioaddr;
- u32 io_size;
u8 rev_id;
diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig
index b5328b0ff92..54b8e492ef9 100644
--- a/drivers/net/wan/Kconfig
+++ b/drivers/net/wan/Kconfig
@@ -134,18 +134,6 @@ config SEALEVEL_4021
The driver will be compiled as a module: the
module will be called sealevel.
-config SYNCLINK_SYNCPPP
- tristate "SyncLink HDLC/SYNCPPP support"
- depends on WAN
- help
- Enables HDLC/SYNCPPP support for the SyncLink WAN driver.
-
- Normally the SyncLink WAN driver works with the main PPP driver
- <file:drivers/net/ppp_generic.c> and pppd program.
- HDLC/SYNCPPP support allows use of the Cisco HDLC/PPP driver
- <file:drivers/net/wan/syncppp.c>. The SyncLink WAN driver (in
- character devices) must also be enabled.
-
# Generic HDLC
config HDLC
tristate "Generic HDLC layer"
diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile
index 823c6d5ab90..316ca6869d5 100644
--- a/drivers/net/wan/Makefile
+++ b/drivers/net/wan/Makefile
@@ -28,7 +28,6 @@ obj-$(CONFIG_COSA) += syncppp.o cosa.o
obj-$(CONFIG_FARSYNC) += syncppp.o farsync.o
obj-$(CONFIG_DSCC4) += dscc4.o
obj-$(CONFIG_LANMEDIA) += syncppp.o
-obj-$(CONFIG_SYNCLINK_SYNCPPP) += syncppp.o
obj-$(CONFIG_X25_ASY) += x25_asy.o
obj-$(CONFIG_LANMEDIA) += lmc/
diff --git a/drivers/net/wan/c101.c b/drivers/net/wan/c101.c
index c92ac9fde08..435e91ec462 100644
--- a/drivers/net/wan/c101.c
+++ b/drivers/net/wan/c101.c
@@ -116,27 +116,33 @@ static inline void openwin(card_t *card, u8 page)
#include "hd6457x.c"
+static inline void set_carrier(port_t *port)
+{
+ if (!sca_in(MSCI1_OFFSET + ST3, port) & ST3_DCD)
+ netif_carrier_on(port_to_dev(port));
+ else
+ netif_carrier_off(port_to_dev(port));
+}
+
+
static void sca_msci_intr(port_t *port)
{
- struct net_device *dev = port_to_dev(port);
- card_t* card = port_to_card(port);
- u8 stat = sca_in(MSCI1_OFFSET + ST1, card); /* read MSCI ST1 status */
+ u8 stat = sca_in(MSCI1_OFFSET + ST1, port); /* read MSCI ST1 status */
/* Reset MSCI TX underrun status bit */
- sca_out(stat & ST1_UDRN, MSCI0_OFFSET + ST1, card);
+ sca_out(stat & ST1_UDRN, MSCI0_OFFSET + ST1, port);
if (stat & ST1_UDRN) {
- struct net_device_stats *stats = hdlc_stats(dev);
+ struct net_device_stats *stats = hdlc_stats(port_to_dev(port));
stats->tx_errors++; /* TX Underrun error detected */
stats->tx_fifo_errors++;
}
/* Reset MSCI CDCD status bit - uses ch#2 DCD input */
- sca_out(stat & ST1_CDCD, MSCI1_OFFSET + ST1, card);
+ sca_out(stat & ST1_CDCD, MSCI1_OFFSET + ST1, port);
if (stat & ST1_CDCD)
- hdlc_set_carrier(!(sca_in(MSCI1_OFFSET + ST3, card) & ST3_DCD),
- dev);
+ set_carrier(port);
}
@@ -190,8 +196,7 @@ static int c101_open(struct net_device *dev)
sca_out(IE1_UDRN, MSCI0_OFFSET + IE1, port);
sca_out(IE0_TXINT, MSCI0_OFFSET + IE0, port);
- hdlc_set_carrier(!(sca_in(MSCI1_OFFSET + ST3, port) & ST3_DCD), dev);
- printk(KERN_DEBUG "0x%X\n", sca_in(MSCI1_OFFSET + ST3, port));
+ set_carrier(port);
/* enable MSCI1 CDCD interrupt */
sca_out(IE1_CDCD, MSCI1_OFFSET + IE1, port);
@@ -378,7 +383,7 @@ static int __init c101_run(unsigned long irq, unsigned long winbase)
}
sca_init_sync_port(card); /* Set up C101 memory */
- hdlc_set_carrier(!(sca_in(MSCI1_OFFSET + ST3, card) & ST3_DCD), dev);
+ set_carrier(card);
printk(KERN_INFO "%s: Moxa C101 on IRQ%u,"
" using %u TX + %u RX packets rings\n",
@@ -443,4 +448,5 @@ module_exit(c101_cleanup);
MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
MODULE_DESCRIPTION("Moxa C101 serial port driver");
MODULE_LICENSE("GPL v2");
-module_param(hw, charp, 0444); /* hw=irq,ram:irq,... */
+module_param(hw, charp, 0444);
+MODULE_PARM_DESC(hw, "irq,ram:irq,...");
diff --git a/drivers/net/wan/hd6457x.c b/drivers/net/wan/hd6457x.c
index d3743321a97..dce2bb317b8 100644
--- a/drivers/net/wan/hd6457x.c
+++ b/drivers/net/wan/hd6457x.c
@@ -168,6 +168,23 @@ static inline u32 buffer_offset(port_t *port, u16 desc, int transmit)
}
+static inline void sca_set_carrier(port_t *port)
+{
+ if (!(sca_in(get_msci(port) + ST3, port_to_card(port)) & ST3_DCD)) {
+#ifdef DEBUG_LINK
+ printk(KERN_DEBUG "%s: sca_set_carrier on\n",
+ port_to_dev(port)->name);
+#endif
+ netif_carrier_on(port_to_dev(port));
+ } else {
+#ifdef DEBUG_LINK
+ printk(KERN_DEBUG "%s: sca_set_carrier off\n",
+ port_to_dev(port)->name);
+#endif
+ netif_carrier_off(port_to_dev(port));
+ }
+}
+
static void sca_init_sync_port(port_t *port)
{
@@ -237,9 +254,7 @@ static void sca_init_sync_port(port_t *port)
sca_out(DIR_BOFE, DIR_TX(phy_node(port)), card);
}
}
-
- hdlc_set_carrier(!(sca_in(get_msci(port) + ST3, card) & ST3_DCD),
- port_to_dev(port));
+ sca_set_carrier(port);
}
@@ -262,8 +277,7 @@ static inline void sca_msci_intr(port_t *port)
}
if (stat & ST1_CDCD)
- hdlc_set_carrier(!(sca_in(msci + ST3, card) & ST3_DCD),
- port_to_dev(port));
+ sca_set_carrier(port);
}
#endif
@@ -566,7 +580,7 @@ static void sca_open(struct net_device *dev)
- all DMA interrupts
*/
- hdlc_set_carrier(!(sca_in(msci + ST3, card) & ST3_DCD), dev);
+ sca_set_carrier(port);
#ifdef __HD64570_H
/* MSCI TX INT and RX INT A IRQ enable */
diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c
index 1fd04662c4f..f289daba0c7 100644
--- a/drivers/net/wan/hdlc_cisco.c
+++ b/drivers/net/wan/hdlc_cisco.c
@@ -192,9 +192,7 @@ static int cisco_rx(struct sk_buff *skb)
"uptime %ud%uh%um%us)\n",
dev->name, days, hrs,
min, sec);
-#if 0
- netif_carrier_on(dev);
-#endif
+ netif_dormant_off(dev);
hdlc->state.cisco.up = 1;
}
}
@@ -227,9 +225,7 @@ static void cisco_timer(unsigned long arg)
hdlc->state.cisco.settings.timeout * HZ)) {
hdlc->state.cisco.up = 0;
printk(KERN_INFO "%s: Link down\n", dev->name);
-#if 0
- netif_carrier_off(dev);
-#endif
+ netif_dormant_on(dev);
}
cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ,
@@ -265,10 +261,7 @@ static void cisco_stop(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
del_timer_sync(&hdlc->state.cisco.timer);
-#if 0
- if (netif_carrier_ok(dev))
- netif_carrier_off(dev);
-#endif
+ netif_dormant_on(dev);
hdlc->state.cisco.up = 0;
hdlc->state.cisco.request_sent = 0;
}
@@ -328,6 +321,7 @@ int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
dev->type = ARPHRD_CISCO;
dev->flags = IFF_POINTOPOINT | IFF_NOARP;
dev->addr_len = 0;
+ netif_dormant_on(dev);
return 0;
}
diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c
index 523afe17564..7bb737bbdeb 100644
--- a/drivers/net/wan/hdlc_fr.c
+++ b/drivers/net/wan/hdlc_fr.c
@@ -301,7 +301,7 @@ static int pvc_open(struct net_device *dev)
if (pvc->open_count++ == 0) {
hdlc_device *hdlc = dev_to_hdlc(pvc->master);
if (hdlc->state.fr.settings.lmi == LMI_NONE)
- pvc->state.active = hdlc->carrier;
+ pvc->state.active = netif_carrier_ok(pvc->master);
pvc_carrier(pvc->state.active, pvc);
hdlc->state.fr.dce_changed = 1;
@@ -545,11 +545,7 @@ static void fr_set_link_state(int reliable, struct net_device *dev)
hdlc->state.fr.reliable = reliable;
if (reliable) {
-#if 0
- if (!netif_carrier_ok(dev))
- netif_carrier_on(dev);
-#endif
-
+ netif_dormant_off(dev);
hdlc->state.fr.n391cnt = 0; /* Request full status */
hdlc->state.fr.dce_changed = 1;
@@ -562,11 +558,7 @@ static void fr_set_link_state(int reliable, struct net_device *dev)
}
}
} else {
-#if 0
- if (netif_carrier_ok(dev))
- netif_carrier_off(dev);
-#endif
-
+ netif_dormant_on(dev);
while (pvc) { /* Deactivate all PVCs */
pvc_carrier(0, pvc);
pvc->state.exist = pvc->state.active = 0;
diff --git a/drivers/net/wan/hdlc_generic.c b/drivers/net/wan/hdlc_generic.c
index b7da55140fb..04ca1f7b642 100644
--- a/drivers/net/wan/hdlc_generic.c
+++ b/drivers/net/wan/hdlc_generic.c
@@ -34,10 +34,11 @@
#include <linux/inetdevice.h>
#include <linux/lapb.h>
#include <linux/rtnetlink.h>
+#include <linux/notifier.h>
#include <linux/hdlc.h>
-static const char* version = "HDLC support module revision 1.18";
+static const char* version = "HDLC support module revision 1.19";
#undef DEBUG_LINK
@@ -73,57 +74,51 @@ static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev,
-static void __hdlc_set_carrier_on(struct net_device *dev)
+static inline void hdlc_proto_start(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
if (hdlc->proto.start)
return hdlc->proto.start(dev);
-#if 0
-#ifdef DEBUG_LINK
- if (netif_carrier_ok(dev))
- printk(KERN_ERR "hdlc_set_carrier_on(): already on\n");
-#endif
- netif_carrier_on(dev);
-#endif
}
-static void __hdlc_set_carrier_off(struct net_device *dev)
+static inline void hdlc_proto_stop(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
if (hdlc->proto.stop)
return hdlc->proto.stop(dev);
-
-#if 0
-#ifdef DEBUG_LINK
- if (!netif_carrier_ok(dev))
- printk(KERN_ERR "hdlc_set_carrier_off(): already off\n");
-#endif
- netif_carrier_off(dev);
-#endif
}
-void hdlc_set_carrier(int on, struct net_device *dev)
+static int hdlc_device_event(struct notifier_block *this, unsigned long event,
+ void *ptr)
{
- hdlc_device *hdlc = dev_to_hdlc(dev);
+ struct net_device *dev = ptr;
+ hdlc_device *hdlc;
unsigned long flags;
- on = on ? 1 : 0;
+ int on;
+
+ if (dev->get_stats != hdlc_get_stats)
+ return NOTIFY_DONE; /* not an HDLC device */
+
+ if (event != NETDEV_CHANGE)
+ return NOTIFY_DONE; /* Only interrested in carrier changes */
+
+ on = netif_carrier_ok(dev);
#ifdef DEBUG_LINK
- printk(KERN_DEBUG "hdlc_set_carrier %i\n", on);
+ printk(KERN_DEBUG "%s: hdlc_device_event NETDEV_CHANGE, carrier %i\n",
+ dev->name, on);
#endif
+ hdlc = dev_to_hdlc(dev);
spin_lock_irqsave(&hdlc->state_lock, flags);
if (hdlc->carrier == on)
goto carrier_exit; /* no change in DCD line level */
-#ifdef DEBUG_LINK
- printk(KERN_INFO "%s: carrier %s\n", dev->name, on ? "ON" : "off");
-#endif
hdlc->carrier = on;
if (!hdlc->open)
@@ -131,14 +126,15 @@ void hdlc_set_carrier(int on, struct net_device *dev)
if (hdlc->carrier) {
printk(KERN_INFO "%s: Carrier detected\n", dev->name);
- __hdlc_set_carrier_on(dev);
+ hdlc_proto_start(dev);
} else {
printk(KERN_INFO "%s: Carrier lost\n", dev->name);
- __hdlc_set_carrier_off(dev);
+ hdlc_proto_stop(dev);
}
carrier_exit:
spin_unlock_irqrestore(&hdlc->state_lock, flags);
+ return NOTIFY_DONE;
}
@@ -165,7 +161,7 @@ int hdlc_open(struct net_device *dev)
if (hdlc->carrier) {
printk(KERN_INFO "%s: Carrier detected\n", dev->name);
- __hdlc_set_carrier_on(dev);
+ hdlc_proto_start(dev);
} else
printk(KERN_INFO "%s: No carrier\n", dev->name);
@@ -190,7 +186,7 @@ void hdlc_close(struct net_device *dev)
hdlc->open = 0;
if (hdlc->carrier)
- __hdlc_set_carrier_off(dev);
+ hdlc_proto_stop(dev);
spin_unlock_irq(&hdlc->state_lock);
@@ -303,7 +299,6 @@ MODULE_LICENSE("GPL v2");
EXPORT_SYMBOL(hdlc_open);
EXPORT_SYMBOL(hdlc_close);
-EXPORT_SYMBOL(hdlc_set_carrier);
EXPORT_SYMBOL(hdlc_ioctl);
EXPORT_SYMBOL(hdlc_setup);
EXPORT_SYMBOL(alloc_hdlcdev);
@@ -315,9 +310,18 @@ static struct packet_type hdlc_packet_type = {
};
+static struct notifier_block hdlc_notifier = {
+ .notifier_call = hdlc_device_event,
+};
+
+
static int __init hdlc_module_init(void)
{
+ int result;
+
printk(KERN_INFO "%s\n", version);
+ if ((result = register_netdevice_notifier(&hdlc_notifier)) != 0)
+ return result;
dev_add_pack(&hdlc_packet_type);
return 0;
}
@@ -327,6 +331,7 @@ static int __init hdlc_module_init(void)
static void __exit hdlc_module_exit(void)
{
dev_remove_pack(&hdlc_packet_type);
+ unregister_netdevice_notifier(&hdlc_notifier);
}
diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c
index b81263eaede..fbaab5bf71e 100644
--- a/drivers/net/wan/hdlc_ppp.c
+++ b/drivers/net/wan/hdlc_ppp.c
@@ -107,6 +107,7 @@ int hdlc_ppp_ioctl(struct net_device *dev, struct ifreq *ifr)
dev->hard_header = NULL;
dev->type = ARPHRD_PPP;
dev->addr_len = 0;
+ netif_dormant_off(dev);
return 0;
}
diff --git a/drivers/net/wan/hdlc_raw.c b/drivers/net/wan/hdlc_raw.c
index 9456d31cb1c..f15aa6ba77f 100644
--- a/drivers/net/wan/hdlc_raw.c
+++ b/drivers/net/wan/hdlc_raw.c
@@ -82,6 +82,7 @@ int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr)
dev->type = ARPHRD_RAWHDLC;
dev->flags = IFF_POINTOPOINT | IFF_NOARP;
dev->addr_len = 0;
+ netif_dormant_off(dev);
return 0;
}
diff --git a/drivers/net/wan/hdlc_raw_eth.c b/drivers/net/wan/hdlc_raw_eth.c
index b1285cc8fee..d1884987f94 100644
--- a/drivers/net/wan/hdlc_raw_eth.c
+++ b/drivers/net/wan/hdlc_raw_eth.c
@@ -100,6 +100,7 @@ int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr)
dev->tx_queue_len = old_qlen;
memcpy(dev->dev_addr, "\x00\x01", 2);
get_random_bytes(dev->dev_addr + 2, ETH_ALEN - 2);
+ netif_dormant_off(dev);
return 0;
}
diff --git a/drivers/net/wan/hdlc_x25.c b/drivers/net/wan/hdlc_x25.c
index 07e5eef1fe0..a867fb411f8 100644
--- a/drivers/net/wan/hdlc_x25.c
+++ b/drivers/net/wan/hdlc_x25.c
@@ -212,6 +212,7 @@ int hdlc_x25_ioctl(struct net_device *dev, struct ifreq *ifr)
dev->hard_header = NULL;
dev->type = ARPHRD_X25;
dev->addr_len = 0;
+ netif_dormant_off(dev);
return 0;
}
diff --git a/drivers/net/wan/n2.c b/drivers/net/wan/n2.c
index e013b817cab..dcf46add3ad 100644
--- a/drivers/net/wan/n2.c
+++ b/drivers/net/wan/n2.c
@@ -564,4 +564,5 @@ module_exit(n2_cleanup);
MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
MODULE_DESCRIPTION("RISCom/N2 serial port driver");
MODULE_LICENSE("GPL v2");
-module_param(hw, charp, 0444); /* hw=io,irq,ram,ports:io,irq,... */
+module_param(hw, charp, 0444);
+MODULE_PARM_DESC(hw, "io,irq,ram,ports:io,irq,...");
diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c
index d564224cdca..b2031dfc4bb 100644
--- a/drivers/net/wan/wanxl.c
+++ b/drivers/net/wan/wanxl.c
@@ -149,7 +149,10 @@ static inline void wanxl_cable_intr(port_t *port)
printk(KERN_INFO "%s: %s%s module, %s cable%s%s\n",
port->dev->name, pm, dte, cable, dsr, dcd);
- hdlc_set_carrier(value & STATUS_CABLE_DCD, port->dev);
+ if (value & STATUS_CABLE_DCD)
+ netif_carrier_on(port->dev);
+ else
+ netif_carrier_off(port->dev);
}
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 30ec235e693..2e8ac995d56 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -447,6 +447,7 @@ config AIRO_CS
tristate "Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards"
depends on NET_RADIO && PCMCIA && (BROKEN || !M32R)
select CRYPTO
+ select CRYPTO_AES
---help---
This is the standard Linux driver to support Cisco/Aironet PCMCIA
802.11 wireless cards. This driver is the same as the Aironet
@@ -550,6 +551,7 @@ config USB_ZD1201
source "drivers/net/wireless/hostap/Kconfig"
source "drivers/net/wireless/bcm43xx/Kconfig"
+source "drivers/net/wireless/zd1211rw/Kconfig"
# yes, this works even when no drivers are selected
config NET_WIRELESS
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 512603de309..c613af17a15 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -36,6 +36,7 @@ obj-$(CONFIG_PRISM54) += prism54/
obj-$(CONFIG_HOSTAP) += hostap/
obj-$(CONFIG_BCM43XX) += bcm43xx/
+obj-$(CONFIG_ZD1211RW) += zd1211rw/
# 16-bit wireless PCMCIA client drivers
obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index d8f5600578b..df317c1e12a 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -1547,7 +1547,7 @@ static void handle_irq_noise(struct bcm43xx_private *bcm)
goto generate_new;
/* Get the noise samples. */
- assert(bcm->noisecalc.nr_samples <= 8);
+ assert(bcm->noisecalc.nr_samples < 8);
i = bcm->noisecalc.nr_samples;
noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
@@ -1885,6 +1885,15 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re
spin_lock(&bcm->irq_lock);
+ /* Only accept IRQs, if we are initialized properly.
+ * This avoids an RX race while initializing.
+ * We should probably not enable IRQs before we are initialized
+ * completely, but some careful work is needed to fix this. I think it
+ * is best to stay with this cheap workaround for now... .
+ */
+ if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED))
+ goto out;
+
reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
if (reason == 0xffffffff) {
/* irq not for us (shared irq) */
@@ -1906,19 +1915,11 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re
bcm43xx_interrupt_ack(bcm, reason);
- /* Only accept IRQs, if we are initialized properly.
- * This avoids an RX race while initializing.
- * We should probably not enable IRQs before we are initialized
- * completely, but some careful work is needed to fix this. I think it
- * is best to stay with this cheap workaround for now... .
- */
- if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) {
- /* disable all IRQs. They are enabled again in the bottom half. */
- bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
- /* save the reason code and call our bottom half. */
- bcm->irq_reason = reason;
- tasklet_schedule(&bcm->isr_tasklet);
- }
+ /* disable all IRQs. They are enabled again in the bottom half. */
+ bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
+ /* save the reason code and call our bottom half. */
+ bcm->irq_reason = reason;
+ tasklet_schedule(&bcm->isr_tasklet);
out:
mmiowb();
@@ -3698,6 +3699,10 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
secinfo->encrypt = sec->encrypt;
dprintk(", .encrypt = %d", sec->encrypt);
}
+ if (sec->flags & SEC_AUTH_MODE) {
+ secinfo->auth_mode = sec->auth_mode;
+ dprintk(", .auth_mode = %d", sec->auth_mode);
+ }
dprintk("\n");
if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED &&
!bcm->ieee->host_encrypt) {
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
index 30a202b258b..116493671f8 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
@@ -112,30 +112,6 @@ int bcm43xx_channel_to_freq(struct bcm43xx_private *bcm,
return bcm43xx_channel_to_freq_bg(channel);
}
-/* Lightweight function to check if a channel number is valid.
- * Note that this does _NOT_ check for geographical restrictions!
- */
-static inline
-int bcm43xx_is_valid_channel_a(u8 channel)
-{
- return (channel >= IEEE80211_52GHZ_MIN_CHANNEL
- && channel <= IEEE80211_52GHZ_MAX_CHANNEL);
-}
-static inline
-int bcm43xx_is_valid_channel_bg(u8 channel)
-{
- return (channel >= IEEE80211_24GHZ_MIN_CHANNEL
- && channel <= IEEE80211_24GHZ_MAX_CHANNEL);
-}
-static inline
-int bcm43xx_is_valid_channel(struct bcm43xx_private *bcm,
- u8 channel)
-{
- if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A)
- return bcm43xx_is_valid_channel_a(channel);
- return bcm43xx_is_valid_channel_bg(channel);
-}
-
void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf);
void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
index af5c0bff169..bb9c484d7e1 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
@@ -1594,11 +1594,11 @@ int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm,
u16 r8, tmp;
u16 freq;
+ if (!ieee80211_is_valid_channel(bcm->ieee, channel))
+ return -EINVAL;
if ((radio->manufact == 0x17F) &&
(radio->version == 0x2060) &&
(radio->revision == 1)) {
- if (channel > 200)
- return -EINVAL;
freq = channel2freq_a(channel);
r8 = bcm43xx_radio_read16(bcm, 0x0008);
@@ -1651,9 +1651,6 @@ int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm,
TODO(); //TODO: TSSI2dbm workaround
bcm43xx_phy_xmitpower(bcm);//FIXME correct?
} else {
- if ((channel < 1) || (channel > 14))
- return -EINVAL;
-
if (synthetic_pu_workaround)
bcm43xx_synth_pu_workaround(bcm, channel);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
index c35cb3a0777..5c36e29efff 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
@@ -119,7 +119,7 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev,
channel = bcm43xx_freq_to_channel(bcm, data->freq.m);
freq = data->freq.m;
}
- if (!bcm43xx_is_valid_channel(bcm, channel))
+ if (!ieee80211_is_valid_channel(bcm->ieee, channel))
goto out_unlock;
if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
//ieee80211softmac_disassoc(softmac, $REASON);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
index d8ece28c079..6dbd855b364 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
@@ -296,11 +296,14 @@ void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm,
u16 control = 0;
u16 wsec_rate = 0;
u16 encrypt_frame;
+ const u16 ftype = WLAN_FC_GET_TYPE(le16_to_cpu(wireless_header->frame_ctl));
+ const int is_mgt = (ftype == IEEE80211_FTYPE_MGMT);
/* Now construct the TX header. */
memset(txhdr, 0, sizeof(*txhdr));
- bitrate = bcm->softmac->txrates.default_rate;
+ bitrate = ieee80211softmac_suggest_txrate(bcm->softmac,
+ is_multicast_ether_addr(wireless_header->addr1), is_mgt);
ofdm_modulation = !(ieee80211_is_cck_rate(bitrate));
fallback_bitrate = bcm43xx_calc_fallback_rate(bitrate);
fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate));
diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c
index 49860fa61c3..6dfa041be66 100644
--- a/drivers/net/wireless/hostap/hostap_plx.c
+++ b/drivers/net/wireless/hostap/hostap_plx.c
@@ -66,10 +66,12 @@ static struct pci_device_id prism2_plx_id_table[] __devinitdata = {
PLXDEV(0x10b7, 0x7770, "3Com AirConnect PCI 777A"),
PLXDEV(0x111a, 0x1023, "Siemens SpeedStream SS1023"),
PLXDEV(0x126c, 0x8030, "Nortel emobility"),
+ PLXDEV(0x1562, 0x0001, "Symbol LA-4123"),
PLXDEV(0x1385, 0x4100, "Netgear MA301"),
PLXDEV(0x15e8, 0x0130, "National Datacomm NCP130 (PLX9052)"),
PLXDEV(0x15e8, 0x0131, "National Datacomm NCP130 (TMD7160)"),
PLXDEV(0x1638, 0x1100, "Eumitcom WL11000"),
+ PLXDEV(0x16ab, 0x1100, "Global Sun Tech GL24110P"),
PLXDEV(0x16ab, 0x1101, "Global Sun Tech GL24110P (?)"),
PLXDEV(0x16ab, 0x1102, "Linksys WPC11 with WDT11"),
PLXDEV(0x16ab, 0x1103, "Longshine 8031"),
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
index d6ed5781b93..317ace7f9aa 100644
--- a/drivers/net/wireless/orinoco.c
+++ b/drivers/net/wireless/orinoco.c
@@ -2875,7 +2875,7 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev,
if (orinoco_lock(priv, &flags) != 0)
return -EBUSY;
- if (erq->pointer) {
+ if (erq->length > 0) {
if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
index = priv->tx_key;
@@ -2918,7 +2918,7 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev,
if (erq->flags & IW_ENCODE_RESTRICTED)
restricted = 1;
- if (erq->pointer) {
+ if (erq->pointer && erq->length > 0) {
priv->keys[index].len = cpu_to_le16(xlen);
memset(priv->keys[index].data, 0,
sizeof(priv->keys[index].data));
diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c
index 15465278c78..7f78b7801fb 100644
--- a/drivers/net/wireless/spectrum_cs.c
+++ b/drivers/net/wireless/spectrum_cs.c
@@ -34,8 +34,6 @@
#include "orinoco.h"
-static unsigned char *primsym;
-static unsigned char *secsym;
static const char primary_fw_name[] = "symbol_sp24t_prim_fw";
static const char secondary_fw_name[] = "symbol_sp24t_sec_fw";
@@ -440,7 +438,7 @@ spectrum_load_blocks(hermes_t *hw, const struct dblock *first_block)
*/
static int
spectrum_dl_image(hermes_t *hw, struct pcmcia_device *link,
- const unsigned char *image)
+ const unsigned char *image, int secondary)
{
int ret;
const unsigned char *ptr;
@@ -455,7 +453,7 @@ spectrum_dl_image(hermes_t *hw, struct pcmcia_device *link,
first_block = (const struct dblock *) ptr;
/* Read the PDA */
- if (image != primsym) {
+ if (secondary) {
ret = spectrum_read_pda(hw, pda, sizeof(pda));
if (ret)
return ret;
@@ -472,7 +470,7 @@ spectrum_dl_image(hermes_t *hw, struct pcmcia_device *link,
return ret;
/* Write the PDA to the adapter */
- if (image != primsym) {
+ if (secondary) {
ret = spectrum_apply_pda(hw, first_block, pda);
if (ret)
return ret;
@@ -487,7 +485,7 @@ spectrum_dl_image(hermes_t *hw, struct pcmcia_device *link,
ret = hermes_init(hw);
/* hermes_reset() should return 0 with the secondary firmware */
- if (image != primsym && ret != 0)
+ if (secondary && ret != 0)
return -ENODEV;
/* And this should work with any firmware */
@@ -509,33 +507,30 @@ spectrum_dl_firmware(hermes_t *hw, struct pcmcia_device *link)
const struct firmware *fw_entry;
if (request_firmware(&fw_entry, primary_fw_name,
- &handle_to_dev(link)) == 0) {
- primsym = fw_entry->data;
- } else {
+ &handle_to_dev(link)) != 0) {
printk(KERN_ERR PFX "Cannot find firmware: %s\n",
primary_fw_name);
return -ENOENT;
}
- if (request_firmware(&fw_entry, secondary_fw_name,
- &handle_to_dev(link)) == 0) {
- secsym = fw_entry->data;
- } else {
- printk(KERN_ERR PFX "Cannot find firmware: %s\n",
- secondary_fw_name);
- return -ENOENT;
- }
-
/* Load primary firmware */
- ret = spectrum_dl_image(hw, link, primsym);
+ ret = spectrum_dl_image(hw, link, fw_entry->data, 0);
+ release_firmware(fw_entry);
if (ret) {
printk(KERN_ERR PFX "Primary firmware download failed\n");
return ret;
}
- /* Load secondary firmware */
- ret = spectrum_dl_image(hw, link, secsym);
+ if (request_firmware(&fw_entry, secondary_fw_name,
+ &handle_to_dev(link)) != 0) {
+ printk(KERN_ERR PFX "Cannot find firmware: %s\n",
+ secondary_fw_name);
+ return -ENOENT;
+ }
+ /* Load secondary firmware */
+ ret = spectrum_dl_image(hw, link, fw_entry->data, 1);
+ release_firmware(fw_entry);
if (ret) {
printk(KERN_ERR PFX "Secondary firmware download failed\n");
}
diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c
index 662ecc8a33f..c52e9bcf8d0 100644
--- a/drivers/net/wireless/zd1201.c
+++ b/drivers/net/wireless/zd1201.c
@@ -1820,6 +1820,8 @@ static int zd1201_probe(struct usb_interface *interface,
zd->dev->name);
usb_set_intfdata(interface, zd);
+ zd1201_enable(zd); /* zd1201 likes to startup enabled, */
+ zd1201_disable(zd); /* interfering with all the wifis in range */
return 0;
err_net:
diff --git a/drivers/net/wireless/zd1211rw/Kconfig b/drivers/net/wireless/zd1211rw/Kconfig
new file mode 100644
index 00000000000..66ed55bc546
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/Kconfig
@@ -0,0 +1,19 @@
+config ZD1211RW
+ tristate "ZyDAS ZD1211/ZD1211B USB-wireless support"
+ depends on USB && IEEE80211 && IEEE80211_SOFTMAC && NET_RADIO && EXPERIMENTAL
+ select FW_LOADER
+ ---help---
+ This is an experimental driver for the ZyDAS ZD1211/ZD1211B wireless
+ chip, present in many USB-wireless adapters.
+
+ Device firmware is required alongside this driver. You can download the
+ firmware distribution from http://zd1211.ath.cx/get-firmware
+
+config ZD1211RW_DEBUG
+ bool "ZyDAS ZD1211 debugging"
+ depends on ZD1211RW
+ ---help---
+ ZD1211 debugging messages. Choosing Y will result in additional debug
+ messages being saved to your kernel logs, which may help debug any
+ problems.
+
diff --git a/drivers/net/wireless/zd1211rw/Makefile b/drivers/net/wireless/zd1211rw/Makefile
new file mode 100644
index 00000000000..500314fc74d
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/Makefile
@@ -0,0 +1,11 @@
+obj-$(CONFIG_ZD1211RW) += zd1211rw.o
+
+zd1211rw-objs := zd_chip.o zd_ieee80211.o \
+ zd_mac.o zd_netdev.o \
+ zd_rf_al2230.o zd_rf_rf2959.o \
+ zd_rf.o zd_usb.o zd_util.o
+
+ifeq ($(CONFIG_ZD1211RW_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
+
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
new file mode 100644
index 00000000000..da9d06bdb81
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -0,0 +1,1615 @@
+/* zd_chip.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* This file implements all the hardware specific functions for the ZD1211
+ * and ZD1211B chips. Support for the ZD1211B was possible after Timothy
+ * Legge sent me a ZD1211B device. Thank you Tim. -- Uli
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+#include "zd_def.h"
+#include "zd_chip.h"
+#include "zd_ieee80211.h"
+#include "zd_mac.h"
+#include "zd_rf.h"
+#include "zd_util.h"
+
+void zd_chip_init(struct zd_chip *chip,
+ struct net_device *netdev,
+ struct usb_interface *intf)
+{
+ memset(chip, 0, sizeof(*chip));
+ mutex_init(&chip->mutex);
+ zd_usb_init(&chip->usb, netdev, intf);
+ zd_rf_init(&chip->rf);
+}
+
+void zd_chip_clear(struct zd_chip *chip)
+{
+ mutex_lock(&chip->mutex);
+ zd_usb_clear(&chip->usb);
+ zd_rf_clear(&chip->rf);
+ mutex_unlock(&chip->mutex);
+ mutex_destroy(&chip->mutex);
+ memset(chip, 0, sizeof(*chip));
+}
+
+static int scnprint_mac_oui(const u8 *addr, char *buffer, size_t size)
+{
+ return scnprintf(buffer, size, "%02x-%02x-%02x",
+ addr[0], addr[1], addr[2]);
+}
+
+/* Prints an identifier line, which will support debugging. */
+static int scnprint_id(struct zd_chip *chip, char *buffer, size_t size)
+{
+ int i = 0;
+
+ i = scnprintf(buffer, size, "zd1211%s chip ",
+ chip->is_zd1211b ? "b" : "");
+ i += zd_usb_scnprint_id(&chip->usb, buffer+i, size-i);
+ i += scnprintf(buffer+i, size-i, " ");
+ i += scnprint_mac_oui(chip->e2p_mac, buffer+i, size-i);
+ i += scnprintf(buffer+i, size-i, " ");
+ i += zd_rf_scnprint_id(&chip->rf, buffer+i, size-i);
+ i += scnprintf(buffer+i, size-i, " pa%1x %c%c%c", chip->pa_type,
+ chip->patch_cck_gain ? 'g' : '-',
+ chip->patch_cr157 ? '7' : '-',
+ chip->patch_6m_band_edge ? '6' : '-');
+ return i;
+}
+
+static void print_id(struct zd_chip *chip)
+{
+ char buffer[80];
+
+ scnprint_id(chip, buffer, sizeof(buffer));
+ buffer[sizeof(buffer)-1] = 0;
+ dev_info(zd_chip_dev(chip), "%s\n", buffer);
+}
+
+/* Read a variable number of 32-bit values. Parameter count is not allowed to
+ * exceed USB_MAX_IOREAD32_COUNT.
+ */
+int zd_ioread32v_locked(struct zd_chip *chip, u32 *values, const zd_addr_t *addr,
+ unsigned int count)
+{
+ int r;
+ int i;
+ zd_addr_t *a16 = (zd_addr_t *)NULL;
+ u16 *v16;
+ unsigned int count16;
+
+ if (count > USB_MAX_IOREAD32_COUNT)
+ return -EINVAL;
+
+ /* Allocate a single memory block for values and addresses. */
+ count16 = 2*count;
+ a16 = (zd_addr_t *)kmalloc(count16 * (sizeof(zd_addr_t) + sizeof(u16)),
+ GFP_NOFS);
+ if (!a16) {
+ dev_dbg_f(zd_chip_dev(chip),
+ "error ENOMEM in allocation of a16\n");
+ r = -ENOMEM;
+ goto out;
+ }
+ v16 = (u16 *)(a16 + count16);
+
+ for (i = 0; i < count; i++) {
+ int j = 2*i;
+ /* We read the high word always first. */
+ a16[j] = zd_inc_word(addr[i]);
+ a16[j+1] = addr[i];
+ }
+
+ r = zd_ioread16v_locked(chip, v16, a16, count16);
+ if (r) {
+ dev_dbg_f(zd_chip_dev(chip),
+ "error: zd_ioread16v_locked. Error number %d\n", r);
+ goto out;
+ }
+
+ for (i = 0; i < count; i++) {
+ int j = 2*i;
+ values[i] = (v16[j] << 16) | v16[j+1];
+ }
+
+out:
+ kfree((void *)a16);
+ return r;
+}
+
+int _zd_iowrite32v_locked(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs,
+ unsigned int count)
+{
+ int i, j, r;
+ struct zd_ioreq16 *ioreqs16;
+ unsigned int count16;
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+
+ if (count == 0)
+ return 0;
+ if (count > USB_MAX_IOWRITE32_COUNT)
+ return -EINVAL;
+
+ /* Allocate a single memory block for values and addresses. */
+ count16 = 2*count;
+ ioreqs16 = kmalloc(count16 * sizeof(struct zd_ioreq16), GFP_NOFS);
+ if (!ioreqs16) {
+ r = -ENOMEM;
+ dev_dbg_f(zd_chip_dev(chip),
+ "error %d in ioreqs16 allocation\n", r);
+ goto out;
+ }
+
+ for (i = 0; i < count; i++) {
+ j = 2*i;
+ /* We write the high word always first. */
+ ioreqs16[j].value = ioreqs[i].value >> 16;
+ ioreqs16[j].addr = zd_inc_word(ioreqs[i].addr);
+ ioreqs16[j+1].value = ioreqs[i].value;
+ ioreqs16[j+1].addr = ioreqs[i].addr;
+ }
+
+ r = zd_usb_iowrite16v(&chip->usb, ioreqs16, count16);
+#ifdef DEBUG
+ if (r) {
+ dev_dbg_f(zd_chip_dev(chip),
+ "error %d in zd_usb_write16v\n", r);
+ }
+#endif /* DEBUG */
+out:
+ kfree(ioreqs16);
+ return r;
+}
+
+int zd_iowrite16a_locked(struct zd_chip *chip,
+ const struct zd_ioreq16 *ioreqs, unsigned int count)
+{
+ int r;
+ unsigned int i, j, t, max;
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ for (i = 0; i < count; i += j + t) {
+ t = 0;
+ max = count-i;
+ if (max > USB_MAX_IOWRITE16_COUNT)
+ max = USB_MAX_IOWRITE16_COUNT;
+ for (j = 0; j < max; j++) {
+ if (!ioreqs[i+j].addr) {
+ t = 1;
+ break;
+ }
+ }
+
+ r = zd_usb_iowrite16v(&chip->usb, &ioreqs[i], j);
+ if (r) {
+ dev_dbg_f(zd_chip_dev(chip),
+ "error zd_usb_iowrite16v. Error number %d\n",
+ r);
+ return r;
+ }
+ }
+
+ return 0;
+}
+
+/* Writes a variable number of 32 bit registers. The functions will split
+ * that in several USB requests. A split can be forced by inserting an IO
+ * request with an zero address field.
+ */
+int zd_iowrite32a_locked(struct zd_chip *chip,
+ const struct zd_ioreq32 *ioreqs, unsigned int count)
+{
+ int r;
+ unsigned int i, j, t, max;
+
+ for (i = 0; i < count; i += j + t) {
+ t = 0;
+ max = count-i;
+ if (max > USB_MAX_IOWRITE32_COUNT)
+ max = USB_MAX_IOWRITE32_COUNT;
+ for (j = 0; j < max; j++) {
+ if (!ioreqs[i+j].addr) {
+ t = 1;
+ break;
+ }
+ }
+
+ r = _zd_iowrite32v_locked(chip, &ioreqs[i], j);
+ if (r) {
+ dev_dbg_f(zd_chip_dev(chip),
+ "error _zd_iowrite32v_locked."
+ " Error number %d\n", r);
+ return r;
+ }
+ }
+
+ return 0;
+}
+
+int zd_ioread16(struct zd_chip *chip, zd_addr_t addr, u16 *value)
+{
+ int r;
+
+ ZD_ASSERT(!mutex_is_locked(&chip->mutex));
+ mutex_lock(&chip->mutex);
+ r = zd_ioread16_locked(chip, value, addr);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+int zd_ioread32(struct zd_chip *chip, zd_addr_t addr, u32 *value)
+{
+ int r;
+
+ ZD_ASSERT(!mutex_is_locked(&chip->mutex));
+ mutex_lock(&chip->mutex);
+ r = zd_ioread32_locked(chip, value, addr);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+int zd_iowrite16(struct zd_chip *chip, zd_addr_t addr, u16 value)
+{
+ int r;
+
+ ZD_ASSERT(!mutex_is_locked(&chip->mutex));
+ mutex_lock(&chip->mutex);
+ r = zd_iowrite16_locked(chip, value, addr);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+int zd_iowrite32(struct zd_chip *chip, zd_addr_t addr, u32 value)
+{
+ int r;
+
+ ZD_ASSERT(!mutex_is_locked(&chip->mutex));
+ mutex_lock(&chip->mutex);
+ r = zd_iowrite32_locked(chip, value, addr);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+int zd_ioread32v(struct zd_chip *chip, const zd_addr_t *addresses,
+ u32 *values, unsigned int count)
+{
+ int r;
+
+ ZD_ASSERT(!mutex_is_locked(&chip->mutex));
+ mutex_lock(&chip->mutex);
+ r = zd_ioread32v_locked(chip, values, addresses, count);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+int zd_iowrite32a(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs,
+ unsigned int count)
+{
+ int r;
+
+ ZD_ASSERT(!mutex_is_locked(&chip->mutex));
+ mutex_lock(&chip->mutex);
+ r = zd_iowrite32a_locked(chip, ioreqs, count);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+static int read_pod(struct zd_chip *chip, u8 *rf_type)
+{
+ int r;
+ u32 value;
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ r = zd_ioread32_locked(chip, &value, E2P_POD);
+ if (r)
+ goto error;
+ dev_dbg_f(zd_chip_dev(chip), "E2P_POD %#010x\n", value);
+
+ /* FIXME: AL2230 handling (Bit 7 in POD) */
+ *rf_type = value & 0x0f;
+ chip->pa_type = (value >> 16) & 0x0f;
+ chip->patch_cck_gain = (value >> 8) & 0x1;
+ chip->patch_cr157 = (value >> 13) & 0x1;
+ chip->patch_6m_band_edge = (value >> 21) & 0x1;
+
+ dev_dbg_f(zd_chip_dev(chip),
+ "RF %s %#01x PA type %#01x patch CCK %d patch CR157 %d "
+ "patch 6M %d\n",
+ zd_rf_name(*rf_type), *rf_type,
+ chip->pa_type, chip->patch_cck_gain,
+ chip->patch_cr157, chip->patch_6m_band_edge);
+ return 0;
+error:
+ *rf_type = 0;
+ chip->pa_type = 0;
+ chip->patch_cck_gain = 0;
+ chip->patch_cr157 = 0;
+ chip->patch_6m_band_edge = 0;
+ return r;
+}
+
+static int _read_mac_addr(struct zd_chip *chip, u8 *mac_addr,
+ const zd_addr_t *addr)
+{
+ int r;
+ u32 parts[2];
+
+ r = zd_ioread32v_locked(chip, parts, (const zd_addr_t *)addr, 2);
+ if (r) {
+ dev_dbg_f(zd_chip_dev(chip),
+ "error: couldn't read e2p macs. Error number %d\n", r);
+ return r;
+ }
+
+ mac_addr[0] = parts[0];
+ mac_addr[1] = parts[0] >> 8;
+ mac_addr[2] = parts[0] >> 16;
+ mac_addr[3] = parts[0] >> 24;
+ mac_addr[4] = parts[1];
+ mac_addr[5] = parts[1] >> 8;
+
+ return 0;
+}
+
+static int read_e2p_mac_addr(struct zd_chip *chip)
+{
+ static const zd_addr_t addr[2] = { E2P_MAC_ADDR_P1, E2P_MAC_ADDR_P2 };
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ return _read_mac_addr(chip, chip->e2p_mac, (const zd_addr_t *)addr);
+}
+
+/* MAC address: if custom mac addresses are to to be used CR_MAC_ADDR_P1 and
+ * CR_MAC_ADDR_P2 must be overwritten
+ */
+void zd_get_e2p_mac_addr(struct zd_chip *chip, u8 *mac_addr)
+{
+ mutex_lock(&chip->mutex);
+ memcpy(mac_addr, chip->e2p_mac, ETH_ALEN);
+ mutex_unlock(&chip->mutex);
+}
+
+static int read_mac_addr(struct zd_chip *chip, u8 *mac_addr)
+{
+ static const zd_addr_t addr[2] = { CR_MAC_ADDR_P1, CR_MAC_ADDR_P2 };
+ return _read_mac_addr(chip, mac_addr, (const zd_addr_t *)addr);
+}
+
+int zd_read_mac_addr(struct zd_chip *chip, u8 *mac_addr)
+{
+ int r;
+
+ dev_dbg_f(zd_chip_dev(chip), "\n");
+ mutex_lock(&chip->mutex);
+ r = read_mac_addr(chip, mac_addr);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr)
+{
+ int r;
+ struct zd_ioreq32 reqs[2] = {
+ [0] = { .addr = CR_MAC_ADDR_P1 },
+ [1] = { .addr = CR_MAC_ADDR_P2 },
+ };
+
+ reqs[0].value = (mac_addr[3] << 24)
+ | (mac_addr[2] << 16)
+ | (mac_addr[1] << 8)
+ | mac_addr[0];
+ reqs[1].value = (mac_addr[5] << 8)
+ | mac_addr[4];
+
+ dev_dbg_f(zd_chip_dev(chip),
+ "mac addr " MAC_FMT "\n", MAC_ARG(mac_addr));
+
+ mutex_lock(&chip->mutex);
+ r = zd_iowrite32a_locked(chip, reqs, ARRAY_SIZE(reqs));
+#ifdef DEBUG
+ {
+ u8 tmp[ETH_ALEN];
+ read_mac_addr(chip, tmp);
+ }
+#endif /* DEBUG */
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+int zd_read_regdomain(struct zd_chip *chip, u8 *regdomain)
+{
+ int r;
+ u32 value;
+
+ mutex_lock(&chip->mutex);
+ r = zd_ioread32_locked(chip, &value, E2P_SUBID);
+ mutex_unlock(&chip->mutex);
+ if (r)
+ return r;
+
+ *regdomain = value >> 16;
+ dev_dbg_f(zd_chip_dev(chip), "regdomain: %#04x\n", *regdomain);
+
+ return 0;
+}
+
+static int read_values(struct zd_chip *chip, u8 *values, size_t count,
+ zd_addr_t e2p_addr, u32 guard)
+{
+ int r;
+ int i;
+ u32 v;
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ for (i = 0;;) {
+ r = zd_ioread32_locked(chip, &v, e2p_addr+i/2);
+ if (r)
+ return r;
+ v -= guard;
+ if (i+4 < count) {
+ values[i++] = v;
+ values[i++] = v >> 8;
+ values[i++] = v >> 16;
+ values[i++] = v >> 24;
+ continue;
+ }
+ for (;i < count; i++)
+ values[i] = v >> (8*(i%3));
+ return 0;
+ }
+}
+
+static int read_pwr_cal_values(struct zd_chip *chip)
+{
+ return read_values(chip, chip->pwr_cal_values,
+ E2P_CHANNEL_COUNT, E2P_PWR_CAL_VALUE1,
+ 0);
+}
+
+static int read_pwr_int_values(struct zd_chip *chip)
+{
+ return read_values(chip, chip->pwr_int_values,
+ E2P_CHANNEL_COUNT, E2P_PWR_INT_VALUE1,
+ E2P_PWR_INT_GUARD);
+}
+
+static int read_ofdm_cal_values(struct zd_chip *chip)
+{
+ int r;
+ int i;
+ static const zd_addr_t addresses[] = {
+ E2P_36M_CAL_VALUE1,
+ E2P_48M_CAL_VALUE1,
+ E2P_54M_CAL_VALUE1,
+ };
+
+ for (i = 0; i < 3; i++) {
+ r = read_values(chip, chip->ofdm_cal_values[i],
+ E2P_CHANNEL_COUNT, addresses[i], 0);
+ if (r)
+ return r;
+ }
+ return 0;
+}
+
+static int read_cal_int_tables(struct zd_chip *chip)
+{
+ int r;
+
+ r = read_pwr_cal_values(chip);
+ if (r)
+ return r;
+ r = read_pwr_int_values(chip);
+ if (r)
+ return r;
+ r = read_ofdm_cal_values(chip);
+ if (r)
+ return r;
+ return 0;
+}
+
+/* phy means physical registers */
+int zd_chip_lock_phy_regs(struct zd_chip *chip)
+{
+ int r;
+ u32 tmp;
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ r = zd_ioread32_locked(chip, &tmp, CR_REG1);
+ if (r) {
+ dev_err(zd_chip_dev(chip), "error ioread32(CR_REG1): %d\n", r);
+ return r;
+ }
+
+ dev_dbg_f(zd_chip_dev(chip),
+ "CR_REG1: 0x%02x -> 0x%02x\n", tmp, tmp & ~UNLOCK_PHY_REGS);
+ tmp &= ~UNLOCK_PHY_REGS;
+
+ r = zd_iowrite32_locked(chip, tmp, CR_REG1);
+ if (r)
+ dev_err(zd_chip_dev(chip), "error iowrite32(CR_REG1): %d\n", r);
+ return r;
+}
+
+int zd_chip_unlock_phy_regs(struct zd_chip *chip)
+{
+ int r;
+ u32 tmp;
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ r = zd_ioread32_locked(chip, &tmp, CR_REG1);
+ if (r) {
+ dev_err(zd_chip_dev(chip),
+ "error ioread32(CR_REG1): %d\n", r);
+ return r;
+ }
+
+ dev_dbg_f(zd_chip_dev(chip),
+ "CR_REG1: 0x%02x -> 0x%02x\n", tmp, tmp | UNLOCK_PHY_REGS);
+ tmp |= UNLOCK_PHY_REGS;
+
+ r = zd_iowrite32_locked(chip, tmp, CR_REG1);
+ if (r)
+ dev_err(zd_chip_dev(chip), "error iowrite32(CR_REG1): %d\n", r);
+ return r;
+}
+
+/* CR157 can be optionally patched by the EEPROM */
+static int patch_cr157(struct zd_chip *chip)
+{
+ int r;
+ u32 value;
+
+ if (!chip->patch_cr157)
+ return 0;
+
+ r = zd_ioread32_locked(chip, &value, E2P_PHY_REG);
+ if (r)
+ return r;
+
+ dev_dbg_f(zd_chip_dev(chip), "patching value %x\n", value >> 8);
+ return zd_iowrite32_locked(chip, value >> 8, CR157);
+}
+
+/*
+ * 6M band edge can be optionally overwritten for certain RF's
+ * Vendor driver says: for FCC regulation, enabled per HWFeature 6M band edge
+ * bit (for AL2230, AL2230S)
+ */
+static int patch_6m_band_edge(struct zd_chip *chip, int channel)
+{
+ struct zd_ioreq16 ioreqs[] = {
+ { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
+ { CR47, 0x1e },
+ };
+
+ if (!chip->patch_6m_band_edge || !chip->rf.patch_6m_band_edge)
+ return 0;
+
+ /* FIXME: Channel 11 is not the edge for all regulatory domains. */
+ if (channel == 1 || channel == 11)
+ ioreqs[0].value = 0x12;
+
+ dev_dbg_f(zd_chip_dev(chip), "patching for channel %d\n", channel);
+ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static int zd1211_hw_reset_phy(struct zd_chip *chip)
+{
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR0, 0x0a }, { CR1, 0x06 }, { CR2, 0x26 },
+ { CR3, 0x38 }, { CR4, 0x80 }, { CR9, 0xa0 },
+ { CR10, 0x81 }, { CR11, 0x00 }, { CR12, 0x7f },
+ { CR13, 0x8c }, { CR14, 0x80 }, { CR15, 0x3d },
+ { CR16, 0x20 }, { CR17, 0x1e }, { CR18, 0x0a },
+ { CR19, 0x48 }, { CR20, 0x0c }, { CR21, 0x0c },
+ { CR22, 0x23 }, { CR23, 0x90 }, { CR24, 0x14 },
+ { CR25, 0x40 }, { CR26, 0x10 }, { CR27, 0x19 },
+ { CR28, 0x7f }, { CR29, 0x80 }, { CR30, 0x4b },
+ { CR31, 0x60 }, { CR32, 0x43 }, { CR33, 0x08 },
+ { CR34, 0x06 }, { CR35, 0x0a }, { CR36, 0x00 },
+ { CR37, 0x00 }, { CR38, 0x38 }, { CR39, 0x0c },
+ { CR40, 0x84 }, { CR41, 0x2a }, { CR42, 0x80 },
+ { CR43, 0x10 }, { CR44, 0x12 }, { CR46, 0xff },
+ { CR47, 0x1E }, { CR48, 0x26 }, { CR49, 0x5b },
+ { CR64, 0xd0 }, { CR65, 0x04 }, { CR66, 0x58 },
+ { CR67, 0xc9 }, { CR68, 0x88 }, { CR69, 0x41 },
+ { CR70, 0x23 }, { CR71, 0x10 }, { CR72, 0xff },
+ { CR73, 0x32 }, { CR74, 0x30 }, { CR75, 0x65 },
+ { CR76, 0x41 }, { CR77, 0x1b }, { CR78, 0x30 },
+ { CR79, 0x68 }, { CR80, 0x64 }, { CR81, 0x64 },
+ { CR82, 0x00 }, { CR83, 0x00 }, { CR84, 0x00 },
+ { CR85, 0x02 }, { CR86, 0x00 }, { CR87, 0x00 },
+ { CR88, 0xff }, { CR89, 0xfc }, { CR90, 0x00 },
+ { CR91, 0x00 }, { CR92, 0x00 }, { CR93, 0x08 },
+ { CR94, 0x00 }, { CR95, 0x00 }, { CR96, 0xff },
+ { CR97, 0xe7 }, { CR98, 0x00 }, { CR99, 0x00 },
+ { CR100, 0x00 }, { CR101, 0xae }, { CR102, 0x02 },
+ { CR103, 0x00 }, { CR104, 0x03 }, { CR105, 0x65 },
+ { CR106, 0x04 }, { CR107, 0x00 }, { CR108, 0x0a },
+ { CR109, 0xaa }, { CR110, 0xaa }, { CR111, 0x25 },
+ { CR112, 0x25 }, { CR113, 0x00 }, { CR119, 0x1e },
+ { CR125, 0x90 }, { CR126, 0x00 }, { CR127, 0x00 },
+ { },
+ { CR5, 0x00 }, { CR6, 0x00 }, { CR7, 0x00 },
+ { CR8, 0x00 }, { CR9, 0x20 }, { CR12, 0xf0 },
+ { CR20, 0x0e }, { CR21, 0x0e }, { CR27, 0x10 },
+ { CR44, 0x33 }, { CR47, 0x1E }, { CR83, 0x24 },
+ { CR84, 0x04 }, { CR85, 0x00 }, { CR86, 0x0C },
+ { CR87, 0x12 }, { CR88, 0x0C }, { CR89, 0x00 },
+ { CR90, 0x10 }, { CR91, 0x08 }, { CR93, 0x00 },
+ { CR94, 0x01 }, { CR95, 0x00 }, { CR96, 0x50 },
+ { CR97, 0x37 }, { CR98, 0x35 }, { CR101, 0x13 },
+ { CR102, 0x27 }, { CR103, 0x27 }, { CR104, 0x18 },
+ { CR105, 0x12 }, { CR109, 0x27 }, { CR110, 0x27 },
+ { CR111, 0x27 }, { CR112, 0x27 }, { CR113, 0x27 },
+ { CR114, 0x27 }, { CR115, 0x26 }, { CR116, 0x24 },
+ { CR117, 0xfc }, { CR118, 0xfa }, { CR120, 0x4f },
+ { CR123, 0x27 }, { CR125, 0xaa }, { CR127, 0x03 },
+ { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
+ { CR131, 0x0C }, { CR136, 0xdf }, { CR137, 0x40 },
+ { CR138, 0xa0 }, { CR139, 0xb0 }, { CR140, 0x99 },
+ { CR141, 0x82 }, { CR142, 0x54 }, { CR143, 0x1c },
+ { CR144, 0x6c }, { CR147, 0x07 }, { CR148, 0x4c },
+ { CR149, 0x50 }, { CR150, 0x0e }, { CR151, 0x18 },
+ { CR160, 0xfe }, { CR161, 0xee }, { CR162, 0xaa },
+ { CR163, 0xfa }, { CR164, 0xfa }, { CR165, 0xea },
+ { CR166, 0xbe }, { CR167, 0xbe }, { CR168, 0x6a },
+ { CR169, 0xba }, { CR170, 0xba }, { CR171, 0xba },
+ /* Note: CR204 must lead the CR203 */
+ { CR204, 0x7d },
+ { },
+ { CR203, 0x30 },
+ };
+
+ int r, t;
+
+ dev_dbg_f(zd_chip_dev(chip), "\n");
+
+ r = zd_chip_lock_phy_regs(chip);
+ if (r)
+ goto out;
+
+ r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+ if (r)
+ goto unlock;
+
+ r = patch_cr157(chip);
+unlock:
+ t = zd_chip_unlock_phy_regs(chip);
+ if (t && !r)
+ r = t;
+out:
+ return r;
+}
+
+static int zd1211b_hw_reset_phy(struct zd_chip *chip)
+{
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR0, 0x14 }, { CR1, 0x06 }, { CR2, 0x26 },
+ { CR3, 0x38 }, { CR4, 0x80 }, { CR9, 0xe0 },
+ { CR10, 0x81 },
+ /* power control { { CR11, 1 << 6 }, */
+ { CR11, 0x00 },
+ { CR12, 0xf0 }, { CR13, 0x8c }, { CR14, 0x80 },
+ { CR15, 0x3d }, { CR16, 0x20 }, { CR17, 0x1e },
+ { CR18, 0x0a }, { CR19, 0x48 },
+ { CR20, 0x10 }, /* Org:0x0E, ComTrend:RalLink AP */
+ { CR21, 0x0e }, { CR22, 0x23 }, { CR23, 0x90 },
+ { CR24, 0x14 }, { CR25, 0x40 }, { CR26, 0x10 },
+ { CR27, 0x10 }, { CR28, 0x7f }, { CR29, 0x80 },
+ { CR30, 0x49 }, /* jointly decoder, no ASIC */
+ { CR31, 0x60 }, { CR32, 0x43 }, { CR33, 0x08 },
+ { CR34, 0x06 }, { CR35, 0x0a }, { CR36, 0x00 },
+ { CR37, 0x00 }, { CR38, 0x38 }, { CR39, 0x0c },
+ { CR40, 0x84 }, { CR41, 0x2a }, { CR42, 0x80 },
+ { CR43, 0x10 }, { CR44, 0x33 }, { CR46, 0xff },
+ { CR47, 0x1E }, { CR48, 0x26 }, { CR49, 0x5b },
+ { CR64, 0xd0 }, { CR65, 0x04 }, { CR66, 0x58 },
+ { CR67, 0xc9 }, { CR68, 0x88 }, { CR69, 0x41 },
+ { CR70, 0x23 }, { CR71, 0x10 }, { CR72, 0xff },
+ { CR73, 0x32 }, { CR74, 0x30 }, { CR75, 0x65 },
+ { CR76, 0x41 }, { CR77, 0x1b }, { CR78, 0x30 },
+ { CR79, 0xf0 }, { CR80, 0x64 }, { CR81, 0x64 },
+ { CR82, 0x00 }, { CR83, 0x24 }, { CR84, 0x04 },
+ { CR85, 0x00 }, { CR86, 0x0c }, { CR87, 0x12 },
+ { CR88, 0x0c }, { CR89, 0x00 }, { CR90, 0x58 },
+ { CR91, 0x04 }, { CR92, 0x00 }, { CR93, 0x00 },
+ { CR94, 0x01 },
+ { CR95, 0x20 }, /* ZD1211B */
+ { CR96, 0x50 }, { CR97, 0x37 }, { CR98, 0x35 },
+ { CR99, 0x00 }, { CR100, 0x01 }, { CR101, 0x13 },
+ { CR102, 0x27 }, { CR103, 0x27 }, { CR104, 0x18 },
+ { CR105, 0x12 }, { CR106, 0x04 }, { CR107, 0x00 },
+ { CR108, 0x0a }, { CR109, 0x27 }, { CR110, 0x27 },
+ { CR111, 0x27 }, { CR112, 0x27 }, { CR113, 0x27 },
+ { CR114, 0x27 }, { CR115, 0x26 }, { CR116, 0x24 },
+ { CR117, 0xfc }, { CR118, 0xfa }, { CR119, 0x1e },
+ { CR125, 0x90 }, { CR126, 0x00 }, { CR127, 0x00 },
+ { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
+ { CR131, 0x0c }, { CR136, 0xdf }, { CR137, 0xa0 },
+ { CR138, 0xa8 }, { CR139, 0xb4 }, { CR140, 0x98 },
+ { CR141, 0x82 }, { CR142, 0x53 }, { CR143, 0x1c },
+ { CR144, 0x6c }, { CR147, 0x07 }, { CR148, 0x40 },
+ { CR149, 0x40 }, /* Org:0x50 ComTrend:RalLink AP */
+ { CR150, 0x14 }, /* Org:0x0E ComTrend:RalLink AP */
+ { CR151, 0x18 }, { CR159, 0x70 }, { CR160, 0xfe },
+ { CR161, 0xee }, { CR162, 0xaa }, { CR163, 0xfa },
+ { CR164, 0xfa }, { CR165, 0xea }, { CR166, 0xbe },
+ { CR167, 0xbe }, { CR168, 0x6a }, { CR169, 0xba },
+ { CR170, 0xba }, { CR171, 0xba },
+ /* Note: CR204 must lead the CR203 */
+ { CR204, 0x7d },
+ {},
+ { CR203, 0x30 },
+ };
+
+ int r, t;
+
+ dev_dbg_f(zd_chip_dev(chip), "\n");
+
+ r = zd_chip_lock_phy_regs(chip);
+ if (r)
+ goto out;
+
+ r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+ if (r)
+ goto unlock;
+
+ r = patch_cr157(chip);
+unlock:
+ t = zd_chip_unlock_phy_regs(chip);
+ if (t && !r)
+ r = t;
+out:
+ return r;
+}
+
+static int hw_reset_phy(struct zd_chip *chip)
+{
+ return chip->is_zd1211b ? zd1211b_hw_reset_phy(chip) :
+ zd1211_hw_reset_phy(chip);
+}
+
+static int zd1211_hw_init_hmac(struct zd_chip *chip)
+{
+ static const struct zd_ioreq32 ioreqs[] = {
+ { CR_ACK_TIMEOUT_EXT, 0x20 },
+ { CR_ADDA_MBIAS_WARMTIME, 0x30000808 },
+ { CR_ZD1211_RETRY_MAX, 0x2 },
+ { CR_SNIFFER_ON, 0 },
+ { CR_RX_FILTER, STA_RX_FILTER },
+ { CR_GROUP_HASH_P1, 0x00 },
+ { CR_GROUP_HASH_P2, 0x80000000 },
+ { CR_REG1, 0xa4 },
+ { CR_ADDA_PWR_DWN, 0x7f },
+ { CR_BCN_PLCP_CFG, 0x00f00401 },
+ { CR_PHY_DELAY, 0x00 },
+ { CR_ACK_TIMEOUT_EXT, 0x80 },
+ { CR_ADDA_PWR_DWN, 0x00 },
+ { CR_ACK_TIME_80211, 0x100 },
+ { CR_IFS_VALUE, 0x547c032 },
+ { CR_RX_PE_DELAY, 0x70 },
+ { CR_PS_CTRL, 0x10000000 },
+ { CR_RTS_CTS_RATE, 0x02030203 },
+ { CR_RX_THRESHOLD, 0x000c0640 },
+ { CR_AFTER_PNP, 0x1 },
+ { CR_WEP_PROTECT, 0x114 },
+ };
+
+ int r;
+
+ dev_dbg_f(zd_chip_dev(chip), "\n");
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ r = zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+#ifdef DEBUG
+ if (r) {
+ dev_err(zd_chip_dev(chip),
+ "error in zd_iowrite32a_locked. Error number %d\n", r);
+ }
+#endif /* DEBUG */
+ return r;
+}
+
+static int zd1211b_hw_init_hmac(struct zd_chip *chip)
+{
+ static const struct zd_ioreq32 ioreqs[] = {
+ { CR_ACK_TIMEOUT_EXT, 0x20 },
+ { CR_ADDA_MBIAS_WARMTIME, 0x30000808 },
+ { CR_ZD1211B_RETRY_MAX, 0x02020202 },
+ { CR_ZD1211B_TX_PWR_CTL4, 0x007f003f },
+ { CR_ZD1211B_TX_PWR_CTL3, 0x007f003f },
+ { CR_ZD1211B_TX_PWR_CTL2, 0x003f001f },
+ { CR_ZD1211B_TX_PWR_CTL1, 0x001f000f },
+ { CR_ZD1211B_AIFS_CTL1, 0x00280028 },
+ { CR_ZD1211B_AIFS_CTL2, 0x008C003C },
+ { CR_ZD1211B_TXOP, 0x01800824 },
+ { CR_SNIFFER_ON, 0 },
+ { CR_RX_FILTER, STA_RX_FILTER },
+ { CR_GROUP_HASH_P1, 0x00 },
+ { CR_GROUP_HASH_P2, 0x80000000 },
+ { CR_REG1, 0xa4 },
+ { CR_ADDA_PWR_DWN, 0x7f },
+ { CR_BCN_PLCP_CFG, 0x00f00401 },
+ { CR_PHY_DELAY, 0x00 },
+ { CR_ACK_TIMEOUT_EXT, 0x80 },
+ { CR_ADDA_PWR_DWN, 0x00 },
+ { CR_ACK_TIME_80211, 0x100 },
+ { CR_IFS_VALUE, 0x547c032 },
+ { CR_RX_PE_DELAY, 0x70 },
+ { CR_PS_CTRL, 0x10000000 },
+ { CR_RTS_CTS_RATE, 0x02030203 },
+ { CR_RX_THRESHOLD, 0x000c0640 },
+ { CR_AFTER_PNP, 0x1 },
+ { CR_WEP_PROTECT, 0x114 },
+ };
+
+ int r;
+
+ dev_dbg_f(zd_chip_dev(chip), "\n");
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ r = zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+ if (r) {
+ dev_dbg_f(zd_chip_dev(chip),
+ "error in zd_iowrite32a_locked. Error number %d\n", r);
+ }
+ return r;
+}
+
+static int hw_init_hmac(struct zd_chip *chip)
+{
+ return chip->is_zd1211b ?
+ zd1211b_hw_init_hmac(chip) : zd1211_hw_init_hmac(chip);
+}
+
+struct aw_pt_bi {
+ u32 atim_wnd_period;
+ u32 pre_tbtt;
+ u32 beacon_interval;
+};
+
+static int get_aw_pt_bi(struct zd_chip *chip, struct aw_pt_bi *s)
+{
+ int r;
+ static const zd_addr_t aw_pt_bi_addr[] =
+ { CR_ATIM_WND_PERIOD, CR_PRE_TBTT, CR_BCN_INTERVAL };
+ u32 values[3];
+
+ r = zd_ioread32v_locked(chip, values, (const zd_addr_t *)aw_pt_bi_addr,
+ ARRAY_SIZE(aw_pt_bi_addr));
+ if (r) {
+ memset(s, 0, sizeof(*s));
+ return r;
+ }
+
+ s->atim_wnd_period = values[0];
+ s->pre_tbtt = values[1];
+ s->beacon_interval = values[2];
+ dev_dbg_f(zd_chip_dev(chip), "aw %u pt %u bi %u\n",
+ s->atim_wnd_period, s->pre_tbtt, s->beacon_interval);
+ return 0;
+}
+
+static int set_aw_pt_bi(struct zd_chip *chip, struct aw_pt_bi *s)
+{
+ struct zd_ioreq32 reqs[3];
+
+ if (s->beacon_interval <= 5)
+ s->beacon_interval = 5;
+ if (s->pre_tbtt < 4 || s->pre_tbtt >= s->beacon_interval)
+ s->pre_tbtt = s->beacon_interval - 1;
+ if (s->atim_wnd_period >= s->pre_tbtt)
+ s->atim_wnd_period = s->pre_tbtt - 1;
+
+ reqs[0].addr = CR_ATIM_WND_PERIOD;
+ reqs[0].value = s->atim_wnd_period;
+ reqs[1].addr = CR_PRE_TBTT;
+ reqs[1].value = s->pre_tbtt;
+ reqs[2].addr = CR_BCN_INTERVAL;
+ reqs[2].value = s->beacon_interval;
+
+ dev_dbg_f(zd_chip_dev(chip),
+ "aw %u pt %u bi %u\n", s->atim_wnd_period, s->pre_tbtt,
+ s->beacon_interval);
+ return zd_iowrite32a_locked(chip, reqs, ARRAY_SIZE(reqs));
+}
+
+
+static int set_beacon_interval(struct zd_chip *chip, u32 interval)
+{
+ int r;
+ struct aw_pt_bi s;
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ r = get_aw_pt_bi(chip, &s);
+ if (r)
+ return r;
+ s.beacon_interval = interval;
+ return set_aw_pt_bi(chip, &s);
+}
+
+int zd_set_beacon_interval(struct zd_chip *chip, u32 interval)
+{
+ int r;
+
+ mutex_lock(&chip->mutex);
+ r = set_beacon_interval(chip, interval);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+static int hw_init(struct zd_chip *chip)
+{
+ int r;
+
+ dev_dbg_f(zd_chip_dev(chip), "\n");
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ r = hw_reset_phy(chip);
+ if (r)
+ return r;
+
+ r = hw_init_hmac(chip);
+ if (r)
+ return r;
+ r = set_beacon_interval(chip, 100);
+ if (r)
+ return r;
+ return 0;
+}
+
+#ifdef DEBUG
+static int dump_cr(struct zd_chip *chip, const zd_addr_t addr,
+ const char *addr_string)
+{
+ int r;
+ u32 value;
+
+ r = zd_ioread32_locked(chip, &value, addr);
+ if (r) {
+ dev_dbg_f(zd_chip_dev(chip),
+ "error reading %s. Error number %d\n", addr_string, r);
+ return r;
+ }
+
+ dev_dbg_f(zd_chip_dev(chip), "%s %#010x\n",
+ addr_string, (unsigned int)value);
+ return 0;
+}
+
+static int test_init(struct zd_chip *chip)
+{
+ int r;
+
+ r = dump_cr(chip, CR_AFTER_PNP, "CR_AFTER_PNP");
+ if (r)
+ return r;
+ r = dump_cr(chip, CR_GPI_EN, "CR_GPI_EN");
+ if (r)
+ return r;
+ return dump_cr(chip, CR_INTERRUPT, "CR_INTERRUPT");
+}
+
+static void dump_fw_registers(struct zd_chip *chip)
+{
+ static const zd_addr_t addr[4] = {
+ FW_FIRMWARE_VER, FW_USB_SPEED, FW_FIX_TX_RATE,
+ FW_LINK_STATUS
+ };
+
+ int r;
+ u16 values[4];
+
+ r = zd_ioread16v_locked(chip, values, (const zd_addr_t*)addr,
+ ARRAY_SIZE(addr));
+ if (r) {
+ dev_dbg_f(zd_chip_dev(chip), "error %d zd_ioread16v_locked\n",
+ r);
+ return;
+ }
+
+ dev_dbg_f(zd_chip_dev(chip), "FW_FIRMWARE_VER %#06hx\n", values[0]);
+ dev_dbg_f(zd_chip_dev(chip), "FW_USB_SPEED %#06hx\n", values[1]);
+ dev_dbg_f(zd_chip_dev(chip), "FW_FIX_TX_RATE %#06hx\n", values[2]);
+ dev_dbg_f(zd_chip_dev(chip), "FW_LINK_STATUS %#06hx\n", values[3]);
+}
+#endif /* DEBUG */
+
+static int print_fw_version(struct zd_chip *chip)
+{
+ int r;
+ u16 version;
+
+ r = zd_ioread16_locked(chip, &version, FW_FIRMWARE_VER);
+ if (r)
+ return r;
+
+ dev_info(zd_chip_dev(chip),"firmware version %04hx\n", version);
+ return 0;
+}
+
+static int set_mandatory_rates(struct zd_chip *chip, enum ieee80211_std std)
+{
+ u32 rates;
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ /* This sets the mandatory rates, which only depend from the standard
+ * that the device is supporting. Until further notice we should try
+ * to support 802.11g also for full speed USB.
+ */
+ switch (std) {
+ case IEEE80211B:
+ rates = CR_RATE_1M|CR_RATE_2M|CR_RATE_5_5M|CR_RATE_11M;
+ break;
+ case IEEE80211G:
+ rates = CR_RATE_1M|CR_RATE_2M|CR_RATE_5_5M|CR_RATE_11M|
+ CR_RATE_6M|CR_RATE_12M|CR_RATE_24M;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return zd_iowrite32_locked(chip, rates, CR_MANDATORY_RATE_TBL);
+}
+
+int zd_chip_enable_hwint(struct zd_chip *chip)
+{
+ int r;
+
+ mutex_lock(&chip->mutex);
+ r = zd_iowrite32_locked(chip, HWINT_ENABLED, CR_INTERRUPT);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+static int disable_hwint(struct zd_chip *chip)
+{
+ return zd_iowrite32_locked(chip, HWINT_DISABLED, CR_INTERRUPT);
+}
+
+int zd_chip_disable_hwint(struct zd_chip *chip)
+{
+ int r;
+
+ mutex_lock(&chip->mutex);
+ r = disable_hwint(chip);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+int zd_chip_init_hw(struct zd_chip *chip, u8 device_type)
+{
+ int r;
+ u8 rf_type;
+
+ dev_dbg_f(zd_chip_dev(chip), "\n");
+
+ mutex_lock(&chip->mutex);
+ chip->is_zd1211b = (device_type == DEVICE_ZD1211B) != 0;
+
+#ifdef DEBUG
+ r = test_init(chip);
+ if (r)
+ goto out;
+#endif
+ r = zd_iowrite32_locked(chip, 1, CR_AFTER_PNP);
+ if (r)
+ goto out;
+
+ r = zd_usb_init_hw(&chip->usb);
+ if (r)
+ goto out;
+
+ /* GPI is always disabled, also in the other driver.
+ */
+ r = zd_iowrite32_locked(chip, 0, CR_GPI_EN);
+ if (r)
+ goto out;
+ r = zd_iowrite32_locked(chip, CWIN_SIZE, CR_CWMIN_CWMAX);
+ if (r)
+ goto out;
+ /* Currently we support IEEE 802.11g for full and high speed USB.
+ * It might be discussed, whether we should suppport pure b mode for
+ * full speed USB.
+ */
+ r = set_mandatory_rates(chip, IEEE80211G);
+ if (r)
+ goto out;
+ /* Disabling interrupts is certainly a smart thing here.
+ */
+ r = disable_hwint(chip);
+ if (r)
+ goto out;
+ r = read_pod(chip, &rf_type);
+ if (r)
+ goto out;
+ r = hw_init(chip);
+ if (r)
+ goto out;
+ r = zd_rf_init_hw(&chip->rf, rf_type);
+ if (r)
+ goto out;
+
+ r = print_fw_version(chip);
+ if (r)
+ goto out;
+
+#ifdef DEBUG
+ dump_fw_registers(chip);
+ r = test_init(chip);
+ if (r)
+ goto out;
+#endif /* DEBUG */
+
+ r = read_e2p_mac_addr(chip);
+ if (r)
+ goto out;
+
+ r = read_cal_int_tables(chip);
+ if (r)
+ goto out;
+
+ print_id(chip);
+out:
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+static int update_pwr_int(struct zd_chip *chip, u8 channel)
+{
+ u8 value = chip->pwr_int_values[channel - 1];
+ dev_dbg_f(zd_chip_dev(chip), "channel %d pwr_int %#04x\n",
+ channel, value);
+ return zd_iowrite32_locked(chip, value, CR31);
+}
+
+static int update_pwr_cal(struct zd_chip *chip, u8 channel)
+{
+ u8 value = chip->pwr_cal_values[channel-1];
+ dev_dbg_f(zd_chip_dev(chip), "channel %d pwr_cal %#04x\n",
+ channel, value);
+ return zd_iowrite32_locked(chip, value, CR68);
+}
+
+static int update_ofdm_cal(struct zd_chip *chip, u8 channel)
+{
+ struct zd_ioreq32 ioreqs[3];
+
+ ioreqs[0].addr = CR67;
+ ioreqs[0].value = chip->ofdm_cal_values[OFDM_36M_INDEX][channel-1];
+ ioreqs[1].addr = CR66;
+ ioreqs[1].value = chip->ofdm_cal_values[OFDM_48M_INDEX][channel-1];
+ ioreqs[2].addr = CR65;
+ ioreqs[2].value = chip->ofdm_cal_values[OFDM_54M_INDEX][channel-1];
+
+ dev_dbg_f(zd_chip_dev(chip),
+ "channel %d ofdm_cal 36M %#04x 48M %#04x 54M %#04x\n",
+ channel, ioreqs[0].value, ioreqs[1].value, ioreqs[2].value);
+ return zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static int update_channel_integration_and_calibration(struct zd_chip *chip,
+ u8 channel)
+{
+ int r;
+
+ r = update_pwr_int(chip, channel);
+ if (r)
+ return r;
+ if (chip->is_zd1211b) {
+ static const struct zd_ioreq32 ioreqs[] = {
+ { CR69, 0x28 },
+ {},
+ { CR69, 0x2a },
+ };
+
+ r = update_ofdm_cal(chip, channel);
+ if (r)
+ return r;
+ r = update_pwr_cal(chip, channel);
+ if (r)
+ return r;
+ r = zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+ if (r)
+ return r;
+ }
+
+ return 0;
+}
+
+/* The CCK baseband gain can be optionally patched by the EEPROM */
+static int patch_cck_gain(struct zd_chip *chip)
+{
+ int r;
+ u32 value;
+
+ if (!chip->patch_cck_gain)
+ return 0;
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ r = zd_ioread32_locked(chip, &value, E2P_PHY_REG);
+ if (r)
+ return r;
+ dev_dbg_f(zd_chip_dev(chip), "patching value %x\n", value & 0xff);
+ return zd_iowrite32_locked(chip, value & 0xff, CR47);
+}
+
+int zd_chip_set_channel(struct zd_chip *chip, u8 channel)
+{
+ int r, t;
+
+ mutex_lock(&chip->mutex);
+ r = zd_chip_lock_phy_regs(chip);
+ if (r)
+ goto out;
+ r = zd_rf_set_channel(&chip->rf, channel);
+ if (r)
+ goto unlock;
+ r = update_channel_integration_and_calibration(chip, channel);
+ if (r)
+ goto unlock;
+ r = patch_cck_gain(chip);
+ if (r)
+ goto unlock;
+ r = patch_6m_band_edge(chip, channel);
+ if (r)
+ goto unlock;
+ r = zd_iowrite32_locked(chip, 0, CR_CONFIG_PHILIPS);
+unlock:
+ t = zd_chip_unlock_phy_regs(chip);
+ if (t && !r)
+ r = t;
+out:
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+u8 zd_chip_get_channel(struct zd_chip *chip)
+{
+ u8 channel;
+
+ mutex_lock(&chip->mutex);
+ channel = chip->rf.channel;
+ mutex_unlock(&chip->mutex);
+ return channel;
+}
+
+static u16 led_mask(int led)
+{
+ switch (led) {
+ case 1:
+ return LED1;
+ case 2:
+ return LED2;
+ default:
+ return 0;
+ }
+}
+
+static int read_led_reg(struct zd_chip *chip, u16 *status)
+{
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ return zd_ioread16_locked(chip, status, CR_LED);
+}
+
+static int write_led_reg(struct zd_chip *chip, u16 status)
+{
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ return zd_iowrite16_locked(chip, status, CR_LED);
+}
+
+int zd_chip_led_status(struct zd_chip *chip, int led, enum led_status status)
+{
+ int r, ret;
+ u16 mask = led_mask(led);
+ u16 reg;
+
+ if (!mask)
+ return -EINVAL;
+ mutex_lock(&chip->mutex);
+ r = read_led_reg(chip, &reg);
+ if (r)
+ return r;
+ switch (status) {
+ case LED_STATUS:
+ return (reg & mask) ? LED_ON : LED_OFF;
+ case LED_OFF:
+ reg &= ~mask;
+ ret = LED_OFF;
+ break;
+ case LED_FLIP:
+ reg ^= mask;
+ ret = (reg&mask) ? LED_ON : LED_OFF;
+ break;
+ case LED_ON:
+ reg |= mask;
+ ret = LED_ON;
+ break;
+ default:
+ return -EINVAL;
+ }
+ r = write_led_reg(chip, reg);
+ if (r) {
+ ret = r;
+ goto out;
+ }
+out:
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+int zd_chip_led_flip(struct zd_chip *chip, int led,
+ const unsigned int *phases_msecs, unsigned int count)
+{
+ int i, r;
+ enum led_status status;
+
+ r = zd_chip_led_status(chip, led, LED_STATUS);
+ if (r)
+ return r;
+ status = r;
+ for (i = 0; i < count; i++) {
+ r = zd_chip_led_status(chip, led, LED_FLIP);
+ if (r < 0)
+ goto out;
+ msleep(phases_msecs[i]);
+ }
+
+out:
+ zd_chip_led_status(chip, led, status);
+ return r;
+}
+
+int zd_chip_set_basic_rates(struct zd_chip *chip, u16 cr_rates)
+{
+ int r;
+
+ if (cr_rates & ~(CR_RATES_80211B|CR_RATES_80211G))
+ return -EINVAL;
+
+ mutex_lock(&chip->mutex);
+ r = zd_iowrite32_locked(chip, cr_rates, CR_BASIC_RATE_TBL);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+static int ofdm_qual_db(u8 status_quality, u8 rate, unsigned int size)
+{
+ static const u16 constants[] = {
+ 715, 655, 585, 540, 470, 410, 360, 315,
+ 270, 235, 205, 175, 150, 125, 105, 85,
+ 65, 50, 40, 25, 15
+ };
+
+ int i;
+ u32 x;
+
+ /* It seems that their quality parameter is somehow per signal
+ * and is now transferred per bit.
+ */
+ switch (rate) {
+ case ZD_OFDM_RATE_6M:
+ case ZD_OFDM_RATE_12M:
+ case ZD_OFDM_RATE_24M:
+ size *= 2;
+ break;
+ case ZD_OFDM_RATE_9M:
+ case ZD_OFDM_RATE_18M:
+ case ZD_OFDM_RATE_36M:
+ case ZD_OFDM_RATE_54M:
+ size *= 4;
+ size /= 3;
+ break;
+ case ZD_OFDM_RATE_48M:
+ size *= 3;
+ size /= 2;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ x = (10000 * status_quality)/size;
+ for (i = 0; i < ARRAY_SIZE(constants); i++) {
+ if (x > constants[i])
+ break;
+ }
+
+ return i;
+}
+
+static unsigned int log10times100(unsigned int x)
+{
+ static const u8 log10[] = {
+ 0,
+ 0, 30, 47, 60, 69, 77, 84, 90, 95, 100,
+ 104, 107, 111, 114, 117, 120, 123, 125, 127, 130,
+ 132, 134, 136, 138, 139, 141, 143, 144, 146, 147,
+ 149, 150, 151, 153, 154, 155, 156, 157, 159, 160,
+ 161, 162, 163, 164, 165, 166, 167, 168, 169, 169,
+ 170, 171, 172, 173, 174, 174, 175, 176, 177, 177,
+ 178, 179, 179, 180, 181, 181, 182, 183, 183, 184,
+ 185, 185, 186, 186, 187, 188, 188, 189, 189, 190,
+ 190, 191, 191, 192, 192, 193, 193, 194, 194, 195,
+ 195, 196, 196, 197, 197, 198, 198, 199, 199, 200,
+ 200, 200, 201, 201, 202, 202, 202, 203, 203, 204,
+ 204, 204, 205, 205, 206, 206, 206, 207, 207, 207,
+ 208, 208, 208, 209, 209, 210, 210, 210, 211, 211,
+ 211, 212, 212, 212, 213, 213, 213, 213, 214, 214,
+ 214, 215, 215, 215, 216, 216, 216, 217, 217, 217,
+ 217, 218, 218, 218, 219, 219, 219, 219, 220, 220,
+ 220, 220, 221, 221, 221, 222, 222, 222, 222, 223,
+ 223, 223, 223, 224, 224, 224, 224,
+ };
+
+ return x < ARRAY_SIZE(log10) ? log10[x] : 225;
+}
+
+enum {
+ MAX_CCK_EVM_DB = 45,
+};
+
+static int cck_evm_db(u8 status_quality)
+{
+ return (20 * log10times100(status_quality)) / 100;
+}
+
+static int cck_snr_db(u8 status_quality)
+{
+ int r = MAX_CCK_EVM_DB - cck_evm_db(status_quality);
+ ZD_ASSERT(r >= 0);
+ return r;
+}
+
+static int rx_qual_db(const void *rx_frame, unsigned int size,
+ const struct rx_status *status)
+{
+ return (status->frame_status&ZD_RX_OFDM) ?
+ ofdm_qual_db(status->signal_quality_ofdm,
+ zd_ofdm_plcp_header_rate(rx_frame),
+ size) :
+ cck_snr_db(status->signal_quality_cck);
+}
+
+u8 zd_rx_qual_percent(const void *rx_frame, unsigned int size,
+ const struct rx_status *status)
+{
+ int r = rx_qual_db(rx_frame, size, status);
+ if (r < 0)
+ r = 0;
+ r = (r * 100) / 14;
+ if (r > 100)
+ r = 100;
+ return r;
+}
+
+u8 zd_rx_strength_percent(u8 rssi)
+{
+ int r = (rssi*100) / 30;
+ if (r > 100)
+ r = 100;
+ return (u8) r;
+}
+
+u16 zd_rx_rate(const void *rx_frame, const struct rx_status *status)
+{
+ static const u16 ofdm_rates[] = {
+ [ZD_OFDM_RATE_6M] = 60,
+ [ZD_OFDM_RATE_9M] = 90,
+ [ZD_OFDM_RATE_12M] = 120,
+ [ZD_OFDM_RATE_18M] = 180,
+ [ZD_OFDM_RATE_24M] = 240,
+ [ZD_OFDM_RATE_36M] = 360,
+ [ZD_OFDM_RATE_48M] = 480,
+ [ZD_OFDM_RATE_54M] = 540,
+ };
+ u16 rate;
+ if (status->frame_status & ZD_RX_OFDM) {
+ u8 ofdm_rate = zd_ofdm_plcp_header_rate(rx_frame);
+ rate = ofdm_rates[ofdm_rate & 0xf];
+ } else {
+ u8 cck_rate = zd_cck_plcp_header_rate(rx_frame);
+ switch (cck_rate) {
+ case ZD_CCK_SIGNAL_1M:
+ rate = 10;
+ break;
+ case ZD_CCK_SIGNAL_2M:
+ rate = 20;
+ break;
+ case ZD_CCK_SIGNAL_5M5:
+ rate = 55;
+ break;
+ case ZD_CCK_SIGNAL_11M:
+ rate = 110;
+ break;
+ default:
+ rate = 0;
+ }
+ }
+
+ return rate;
+}
+
+int zd_chip_switch_radio_on(struct zd_chip *chip)
+{
+ int r;
+
+ mutex_lock(&chip->mutex);
+ r = zd_switch_radio_on(&chip->rf);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+int zd_chip_switch_radio_off(struct zd_chip *chip)
+{
+ int r;
+
+ mutex_lock(&chip->mutex);
+ r = zd_switch_radio_off(&chip->rf);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+int zd_chip_enable_int(struct zd_chip *chip)
+{
+ int r;
+
+ mutex_lock(&chip->mutex);
+ r = zd_usb_enable_int(&chip->usb);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+void zd_chip_disable_int(struct zd_chip *chip)
+{
+ mutex_lock(&chip->mutex);
+ zd_usb_disable_int(&chip->usb);
+ mutex_unlock(&chip->mutex);
+}
+
+int zd_chip_enable_rx(struct zd_chip *chip)
+{
+ int r;
+
+ mutex_lock(&chip->mutex);
+ r = zd_usb_enable_rx(&chip->usb);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+void zd_chip_disable_rx(struct zd_chip *chip)
+{
+ mutex_lock(&chip->mutex);
+ zd_usb_disable_rx(&chip->usb);
+ mutex_unlock(&chip->mutex);
+}
+
+int zd_rfwritev_locked(struct zd_chip *chip,
+ const u32* values, unsigned int count, u8 bits)
+{
+ int r;
+ unsigned int i;
+
+ for (i = 0; i < count; i++) {
+ r = zd_rfwrite_locked(chip, values[i], bits);
+ if (r)
+ return r;
+ }
+
+ return 0;
+}
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h
new file mode 100644
index 00000000000..069d2b46733
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_chip.h
@@ -0,0 +1,827 @@
+/* zd_chip.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _ZD_CHIP_H
+#define _ZD_CHIP_H
+
+#include "zd_types.h"
+#include "zd_rf.h"
+#include "zd_usb.h"
+
+/* Header for the Media Access Controller (MAC) and the Baseband Processor
+ * (BBP). It appears that the ZD1211 wraps the old ZD1205 with USB glue and
+ * adds a processor for handling the USB protocol.
+ */
+
+/* 8-bit hardware registers */
+#define CR0 CTL_REG(0x0000)
+#define CR1 CTL_REG(0x0004)
+#define CR2 CTL_REG(0x0008)
+#define CR3 CTL_REG(0x000C)
+
+#define CR5 CTL_REG(0x0010)
+/* bit 5: if set short preamble used
+ * bit 6: filter band - Japan channel 14 on, else off
+ */
+#define CR6 CTL_REG(0x0014)
+#define CR7 CTL_REG(0x0018)
+#define CR8 CTL_REG(0x001C)
+
+#define CR4 CTL_REG(0x0020)
+
+#define CR9 CTL_REG(0x0024)
+/* bit 2: antenna switch (together with CR10) */
+#define CR10 CTL_REG(0x0028)
+/* bit 1: antenna switch (together with CR9)
+ * RF2959 controls with CR11 radion on and off
+ */
+#define CR11 CTL_REG(0x002C)
+/* bit 6: TX power control for OFDM
+ * RF2959 controls with CR10 radio on and off
+ */
+#define CR12 CTL_REG(0x0030)
+#define CR13 CTL_REG(0x0034)
+#define CR14 CTL_REG(0x0038)
+#define CR15 CTL_REG(0x003C)
+#define CR16 CTL_REG(0x0040)
+#define CR17 CTL_REG(0x0044)
+#define CR18 CTL_REG(0x0048)
+#define CR19 CTL_REG(0x004C)
+#define CR20 CTL_REG(0x0050)
+#define CR21 CTL_REG(0x0054)
+#define CR22 CTL_REG(0x0058)
+#define CR23 CTL_REG(0x005C)
+#define CR24 CTL_REG(0x0060) /* CCA threshold */
+#define CR25 CTL_REG(0x0064)
+#define CR26 CTL_REG(0x0068)
+#define CR27 CTL_REG(0x006C)
+#define CR28 CTL_REG(0x0070)
+#define CR29 CTL_REG(0x0074)
+#define CR30 CTL_REG(0x0078)
+#define CR31 CTL_REG(0x007C) /* TX power control for RF in CCK mode */
+#define CR32 CTL_REG(0x0080)
+#define CR33 CTL_REG(0x0084)
+#define CR34 CTL_REG(0x0088)
+#define CR35 CTL_REG(0x008C)
+#define CR36 CTL_REG(0x0090)
+#define CR37 CTL_REG(0x0094)
+#define CR38 CTL_REG(0x0098)
+#define CR39 CTL_REG(0x009C)
+#define CR40 CTL_REG(0x00A0)
+#define CR41 CTL_REG(0x00A4)
+#define CR42 CTL_REG(0x00A8)
+#define CR43 CTL_REG(0x00AC)
+#define CR44 CTL_REG(0x00B0)
+#define CR45 CTL_REG(0x00B4)
+#define CR46 CTL_REG(0x00B8)
+#define CR47 CTL_REG(0x00BC) /* CCK baseband gain
+ * (patch value might be in EEPROM)
+ */
+#define CR48 CTL_REG(0x00C0)
+#define CR49 CTL_REG(0x00C4)
+#define CR50 CTL_REG(0x00C8)
+#define CR51 CTL_REG(0x00CC) /* TX power control for RF in 6-36M modes */
+#define CR52 CTL_REG(0x00D0) /* TX power control for RF in 48M mode */
+#define CR53 CTL_REG(0x00D4) /* TX power control for RF in 54M mode */
+#define CR54 CTL_REG(0x00D8)
+#define CR55 CTL_REG(0x00DC)
+#define CR56 CTL_REG(0x00E0)
+#define CR57 CTL_REG(0x00E4)
+#define CR58 CTL_REG(0x00E8)
+#define CR59 CTL_REG(0x00EC)
+#define CR60 CTL_REG(0x00F0)
+#define CR61 CTL_REG(0x00F4)
+#define CR62 CTL_REG(0x00F8)
+#define CR63 CTL_REG(0x00FC)
+#define CR64 CTL_REG(0x0100)
+#define CR65 CTL_REG(0x0104) /* OFDM 54M calibration */
+#define CR66 CTL_REG(0x0108) /* OFDM 48M calibration */
+#define CR67 CTL_REG(0x010C) /* OFDM 36M calibration */
+#define CR68 CTL_REG(0x0110) /* CCK calibration */
+#define CR69 CTL_REG(0x0114)
+#define CR70 CTL_REG(0x0118)
+#define CR71 CTL_REG(0x011C)
+#define CR72 CTL_REG(0x0120)
+#define CR73 CTL_REG(0x0124)
+#define CR74 CTL_REG(0x0128)
+#define CR75 CTL_REG(0x012C)
+#define CR76 CTL_REG(0x0130)
+#define CR77 CTL_REG(0x0134)
+#define CR78 CTL_REG(0x0138)
+#define CR79 CTL_REG(0x013C)
+#define CR80 CTL_REG(0x0140)
+#define CR81 CTL_REG(0x0144)
+#define CR82 CTL_REG(0x0148)
+#define CR83 CTL_REG(0x014C)
+#define CR84 CTL_REG(0x0150)
+#define CR85 CTL_REG(0x0154)
+#define CR86 CTL_REG(0x0158)
+#define CR87 CTL_REG(0x015C)
+#define CR88 CTL_REG(0x0160)
+#define CR89 CTL_REG(0x0164)
+#define CR90 CTL_REG(0x0168)
+#define CR91 CTL_REG(0x016C)
+#define CR92 CTL_REG(0x0170)
+#define CR93 CTL_REG(0x0174)
+#define CR94 CTL_REG(0x0178)
+#define CR95 CTL_REG(0x017C)
+#define CR96 CTL_REG(0x0180)
+#define CR97 CTL_REG(0x0184)
+#define CR98 CTL_REG(0x0188)
+#define CR99 CTL_REG(0x018C)
+#define CR100 CTL_REG(0x0190)
+#define CR101 CTL_REG(0x0194)
+#define CR102 CTL_REG(0x0198)
+#define CR103 CTL_REG(0x019C)
+#define CR104 CTL_REG(0x01A0)
+#define CR105 CTL_REG(0x01A4)
+#define CR106 CTL_REG(0x01A8)
+#define CR107 CTL_REG(0x01AC)
+#define CR108 CTL_REG(0x01B0)
+#define CR109 CTL_REG(0x01B4)
+#define CR110 CTL_REG(0x01B8)
+#define CR111 CTL_REG(0x01BC)
+#define CR112 CTL_REG(0x01C0)
+#define CR113 CTL_REG(0x01C4)
+#define CR114 CTL_REG(0x01C8)
+#define CR115 CTL_REG(0x01CC)
+#define CR116 CTL_REG(0x01D0)
+#define CR117 CTL_REG(0x01D4)
+#define CR118 CTL_REG(0x01D8)
+#define CR119 CTL_REG(0x01DC)
+#define CR120 CTL_REG(0x01E0)
+#define CR121 CTL_REG(0x01E4)
+#define CR122 CTL_REG(0x01E8)
+#define CR123 CTL_REG(0x01EC)
+#define CR124 CTL_REG(0x01F0)
+#define CR125 CTL_REG(0x01F4)
+#define CR126 CTL_REG(0x01F8)
+#define CR127 CTL_REG(0x01FC)
+#define CR128 CTL_REG(0x0200)
+#define CR129 CTL_REG(0x0204)
+#define CR130 CTL_REG(0x0208)
+#define CR131 CTL_REG(0x020C)
+#define CR132 CTL_REG(0x0210)
+#define CR133 CTL_REG(0x0214)
+#define CR134 CTL_REG(0x0218)
+#define CR135 CTL_REG(0x021C)
+#define CR136 CTL_REG(0x0220)
+#define CR137 CTL_REG(0x0224)
+#define CR138 CTL_REG(0x0228)
+#define CR139 CTL_REG(0x022C)
+#define CR140 CTL_REG(0x0230)
+#define CR141 CTL_REG(0x0234)
+#define CR142 CTL_REG(0x0238)
+#define CR143 CTL_REG(0x023C)
+#define CR144 CTL_REG(0x0240)
+#define CR145 CTL_REG(0x0244)
+#define CR146 CTL_REG(0x0248)
+#define CR147 CTL_REG(0x024C)
+#define CR148 CTL_REG(0x0250)
+#define CR149 CTL_REG(0x0254)
+#define CR150 CTL_REG(0x0258)
+#define CR151 CTL_REG(0x025C)
+#define CR152 CTL_REG(0x0260)
+#define CR153 CTL_REG(0x0264)
+#define CR154 CTL_REG(0x0268)
+#define CR155 CTL_REG(0x026C)
+#define CR156 CTL_REG(0x0270)
+#define CR157 CTL_REG(0x0274)
+#define CR158 CTL_REG(0x0278)
+#define CR159 CTL_REG(0x027C)
+#define CR160 CTL_REG(0x0280)
+#define CR161 CTL_REG(0x0284)
+#define CR162 CTL_REG(0x0288)
+#define CR163 CTL_REG(0x028C)
+#define CR164 CTL_REG(0x0290)
+#define CR165 CTL_REG(0x0294)
+#define CR166 CTL_REG(0x0298)
+#define CR167 CTL_REG(0x029C)
+#define CR168 CTL_REG(0x02A0)
+#define CR169 CTL_REG(0x02A4)
+#define CR170 CTL_REG(0x02A8)
+#define CR171 CTL_REG(0x02AC)
+#define CR172 CTL_REG(0x02B0)
+#define CR173 CTL_REG(0x02B4)
+#define CR174 CTL_REG(0x02B8)
+#define CR175 CTL_REG(0x02BC)
+#define CR176 CTL_REG(0x02C0)
+#define CR177 CTL_REG(0x02C4)
+#define CR178 CTL_REG(0x02C8)
+#define CR179 CTL_REG(0x02CC)
+#define CR180 CTL_REG(0x02D0)
+#define CR181 CTL_REG(0x02D4)
+#define CR182 CTL_REG(0x02D8)
+#define CR183 CTL_REG(0x02DC)
+#define CR184 CTL_REG(0x02E0)
+#define CR185 CTL_REG(0x02E4)
+#define CR186 CTL_REG(0x02E8)
+#define CR187 CTL_REG(0x02EC)
+#define CR188 CTL_REG(0x02F0)
+#define CR189 CTL_REG(0x02F4)
+#define CR190 CTL_REG(0x02F8)
+#define CR191 CTL_REG(0x02FC)
+#define CR192 CTL_REG(0x0300)
+#define CR193 CTL_REG(0x0304)
+#define CR194 CTL_REG(0x0308)
+#define CR195 CTL_REG(0x030C)
+#define CR196 CTL_REG(0x0310)
+#define CR197 CTL_REG(0x0314)
+#define CR198 CTL_REG(0x0318)
+#define CR199 CTL_REG(0x031C)
+#define CR200 CTL_REG(0x0320)
+#define CR201 CTL_REG(0x0324)
+#define CR202 CTL_REG(0x0328)
+#define CR203 CTL_REG(0x032C) /* I2C bus template value & flash control */
+#define CR204 CTL_REG(0x0330)
+#define CR205 CTL_REG(0x0334)
+#define CR206 CTL_REG(0x0338)
+#define CR207 CTL_REG(0x033C)
+#define CR208 CTL_REG(0x0340)
+#define CR209 CTL_REG(0x0344)
+#define CR210 CTL_REG(0x0348)
+#define CR211 CTL_REG(0x034C)
+#define CR212 CTL_REG(0x0350)
+#define CR213 CTL_REG(0x0354)
+#define CR214 CTL_REG(0x0358)
+#define CR215 CTL_REG(0x035C)
+#define CR216 CTL_REG(0x0360)
+#define CR217 CTL_REG(0x0364)
+#define CR218 CTL_REG(0x0368)
+#define CR219 CTL_REG(0x036C)
+#define CR220 CTL_REG(0x0370)
+#define CR221 CTL_REG(0x0374)
+#define CR222 CTL_REG(0x0378)
+#define CR223 CTL_REG(0x037C)
+#define CR224 CTL_REG(0x0380)
+#define CR225 CTL_REG(0x0384)
+#define CR226 CTL_REG(0x0388)
+#define CR227 CTL_REG(0x038C)
+#define CR228 CTL_REG(0x0390)
+#define CR229 CTL_REG(0x0394)
+#define CR230 CTL_REG(0x0398)
+#define CR231 CTL_REG(0x039C)
+#define CR232 CTL_REG(0x03A0)
+#define CR233 CTL_REG(0x03A4)
+#define CR234 CTL_REG(0x03A8)
+#define CR235 CTL_REG(0x03AC)
+#define CR236 CTL_REG(0x03B0)
+
+#define CR240 CTL_REG(0x03C0)
+/* bit 7: host-controlled RF register writes
+ * CR241-CR245: for hardware controlled writing of RF bits, not needed for
+ * USB
+ */
+#define CR241 CTL_REG(0x03C4)
+#define CR242 CTL_REG(0x03C8)
+#define CR243 CTL_REG(0x03CC)
+#define CR244 CTL_REG(0x03D0)
+#define CR245 CTL_REG(0x03D4)
+
+#define CR251 CTL_REG(0x03EC) /* only used for activation and deactivation of
+ * Airoha RFs AL2230 and AL7230B
+ */
+#define CR252 CTL_REG(0x03F0)
+#define CR253 CTL_REG(0x03F4)
+#define CR254 CTL_REG(0x03F8)
+#define CR255 CTL_REG(0x03FC)
+
+#define CR_MAX_PHY_REG 255
+
+/* Taken from the ZYDAS driver, not all of them are relevant for the ZSD1211
+ * driver.
+ */
+
+#define CR_RF_IF_CLK CTL_REG(0x0400)
+#define CR_RF_IF_DATA CTL_REG(0x0404)
+#define CR_PE1_PE2 CTL_REG(0x0408)
+#define CR_PE2_DLY CTL_REG(0x040C)
+#define CR_LE1 CTL_REG(0x0410)
+#define CR_LE2 CTL_REG(0x0414)
+/* Seems to enable/disable GPI (General Purpose IO?) */
+#define CR_GPI_EN CTL_REG(0x0418)
+#define CR_RADIO_PD CTL_REG(0x042C)
+#define CR_RF2948_PD CTL_REG(0x042C)
+#define CR_ENABLE_PS_MANUAL_AGC CTL_REG(0x043C)
+#define CR_CONFIG_PHILIPS CTL_REG(0x0440)
+#define CR_SA2400_SER_AP CTL_REG(0x0444)
+#define CR_I2C_WRITE CTL_REG(0x0444)
+#define CR_SA2400_SER_RP CTL_REG(0x0448)
+#define CR_RADIO_PE CTL_REG(0x0458)
+#define CR_RST_BUS_MASTER CTL_REG(0x045C)
+#define CR_RFCFG CTL_REG(0x0464)
+#define CR_HSTSCHG CTL_REG(0x046C)
+#define CR_PHY_ON CTL_REG(0x0474)
+#define CR_RX_DELAY CTL_REG(0x0478)
+#define CR_RX_PE_DELAY CTL_REG(0x047C)
+#define CR_GPIO_1 CTL_REG(0x0490)
+#define CR_GPIO_2 CTL_REG(0x0494)
+#define CR_EncryBufMux CTL_REG(0x04A8)
+#define CR_PS_CTRL CTL_REG(0x0500)
+#define CR_ADDA_PWR_DWN CTL_REG(0x0504)
+#define CR_ADDA_MBIAS_WARMTIME CTL_REG(0x0508)
+#define CR_MAC_PS_STATE CTL_REG(0x050C)
+
+#define CR_INTERRUPT CTL_REG(0x0510)
+#define INT_TX_COMPLETE 0x00000001
+#define INT_RX_COMPLETE 0x00000002
+#define INT_RETRY_FAIL 0x00000004
+#define INT_WAKEUP 0x00000008
+#define INT_DTIM_NOTIFY 0x00000020
+#define INT_CFG_NEXT_BCN 0x00000040
+#define INT_BUS_ABORT 0x00000080
+#define INT_TX_FIFO_READY 0x00000100
+#define INT_UART 0x00000200
+#define INT_TX_COMPLETE_EN 0x00010000
+#define INT_RX_COMPLETE_EN 0x00020000
+#define INT_RETRY_FAIL_EN 0x00040000
+#define INT_WAKEUP_EN 0x00080000
+#define INT_DTIM_NOTIFY_EN 0x00200000
+#define INT_CFG_NEXT_BCN_EN 0x00400000
+#define INT_BUS_ABORT_EN 0x00800000
+#define INT_TX_FIFO_READY_EN 0x01000000
+#define INT_UART_EN 0x02000000
+
+#define CR_TSF_LOW_PART CTL_REG(0x0514)
+#define CR_TSF_HIGH_PART CTL_REG(0x0518)
+
+/* Following three values are in time units (1024us)
+ * Following condition must be met:
+ * atim < tbtt < bcn
+ */
+#define CR_ATIM_WND_PERIOD CTL_REG(0x051C)
+#define CR_BCN_INTERVAL CTL_REG(0x0520)
+#define CR_PRE_TBTT CTL_REG(0x0524)
+/* in units of TU(1024us) */
+
+/* for UART support */
+#define CR_UART_RBR_THR_DLL CTL_REG(0x0540)
+#define CR_UART_DLM_IER CTL_REG(0x0544)
+#define CR_UART_IIR_FCR CTL_REG(0x0548)
+#define CR_UART_LCR CTL_REG(0x054c)
+#define CR_UART_MCR CTL_REG(0x0550)
+#define CR_UART_LSR CTL_REG(0x0554)
+#define CR_UART_MSR CTL_REG(0x0558)
+#define CR_UART_ECR CTL_REG(0x055c)
+#define CR_UART_STATUS CTL_REG(0x0560)
+
+#define CR_PCI_TX_ADDR_P1 CTL_REG(0x0600)
+#define CR_PCI_TX_AddR_P2 CTL_REG(0x0604)
+#define CR_PCI_RX_AddR_P1 CTL_REG(0x0608)
+#define CR_PCI_RX_AddR_P2 CTL_REG(0x060C)
+
+/* must be overwritten if custom MAC address will be used */
+#define CR_MAC_ADDR_P1 CTL_REG(0x0610)
+#define CR_MAC_ADDR_P2 CTL_REG(0x0614)
+#define CR_BSSID_P1 CTL_REG(0x0618)
+#define CR_BSSID_P2 CTL_REG(0x061C)
+#define CR_BCN_PLCP_CFG CTL_REG(0x0620)
+#define CR_GROUP_HASH_P1 CTL_REG(0x0624)
+#define CR_GROUP_HASH_P2 CTL_REG(0x0628)
+#define CR_RX_TIMEOUT CTL_REG(0x062C)
+
+/* Basic rates supported by the BSS. When producing ACK or CTS messages, the
+ * device will use a rate in this table that is less than or equal to the rate
+ * of the incoming frame which prompted the response */
+#define CR_BASIC_RATE_TBL CTL_REG(0x0630)
+#define CR_RATE_1M 0x0001 /* 802.11b */
+#define CR_RATE_2M 0x0002 /* 802.11b */
+#define CR_RATE_5_5M 0x0004 /* 802.11b */
+#define CR_RATE_11M 0x0008 /* 802.11b */
+#define CR_RATE_6M 0x0100 /* 802.11g */
+#define CR_RATE_9M 0x0200 /* 802.11g */
+#define CR_RATE_12M 0x0400 /* 802.11g */
+#define CR_RATE_18M 0x0800 /* 802.11g */
+#define CR_RATE_24M 0x1000 /* 802.11g */
+#define CR_RATE_36M 0x2000 /* 802.11g */
+#define CR_RATE_48M 0x4000 /* 802.11g */
+#define CR_RATE_54M 0x8000 /* 802.11g */
+#define CR_RATES_80211G 0xff00
+#define CR_RATES_80211B 0x000f
+
+/* Mandatory rates required in the BSS. When producing ACK or CTS messages, if
+ * the device could not find an appropriate rate in CR_BASIC_RATE_TBL, it will
+ * look for a rate in this table that is less than or equal to the rate of
+ * the incoming frame. */
+#define CR_MANDATORY_RATE_TBL CTL_REG(0x0634)
+#define CR_RTS_CTS_RATE CTL_REG(0x0638)
+
+#define CR_WEP_PROTECT CTL_REG(0x063C)
+#define CR_RX_THRESHOLD CTL_REG(0x0640)
+
+/* register for controlling the LEDS */
+#define CR_LED CTL_REG(0x0644)
+/* masks for controlling LEDs */
+#define LED1 0x0100
+#define LED2 0x0200
+
+/* Seems to indicate that the configuration is over.
+ */
+#define CR_AFTER_PNP CTL_REG(0x0648)
+#define CR_ACK_TIME_80211 CTL_REG(0x0658)
+
+#define CR_RX_OFFSET CTL_REG(0x065c)
+
+#define CR_PHY_DELAY CTL_REG(0x066C)
+#define CR_BCN_FIFO CTL_REG(0x0670)
+#define CR_SNIFFER_ON CTL_REG(0x0674)
+
+#define CR_ENCRYPTION_TYPE CTL_REG(0x0678)
+#define NO_WEP 0
+#define WEP64 1
+#define WEP128 5
+#define WEP256 6
+#define ENC_SNIFFER 8
+
+#define CR_ZD1211_RETRY_MAX CTL_REG(0x067C)
+
+#define CR_REG1 CTL_REG(0x0680)
+/* Setting the bit UNLOCK_PHY_REGS disallows the write access to physical
+ * registers, so one could argue it is a LOCK bit. But calling it
+ * LOCK_PHY_REGS makes it confusing.
+ */
+#define UNLOCK_PHY_REGS 0x0080
+
+#define CR_DEVICE_STATE CTL_REG(0x0684)
+#define CR_UNDERRUN_CNT CTL_REG(0x0688)
+
+#define CR_RX_FILTER CTL_REG(0x068c)
+#define RX_FILTER_ASSOC_RESPONSE 0x0002
+#define RX_FILTER_REASSOC_RESPONSE 0x0008
+#define RX_FILTER_PROBE_RESPONSE 0x0020
+#define RX_FILTER_BEACON 0x0100
+#define RX_FILTER_DISASSOC 0x0400
+#define RX_FILTER_AUTH 0x0800
+#define AP_RX_FILTER 0x0400feff
+#define STA_RX_FILTER 0x0000ffff
+
+/* Monitor mode sets filter to 0xfffff */
+
+#define CR_ACK_TIMEOUT_EXT CTL_REG(0x0690)
+#define CR_BCN_FIFO_SEMAPHORE CTL_REG(0x0694)
+#define CR_IFS_VALUE CTL_REG(0x0698)
+#define CR_RX_TIME_OUT CTL_REG(0x069C)
+#define CR_TOTAL_RX_FRM CTL_REG(0x06A0)
+#define CR_CRC32_CNT CTL_REG(0x06A4)
+#define CR_CRC16_CNT CTL_REG(0x06A8)
+#define CR_DECRYPTION_ERR_UNI CTL_REG(0x06AC)
+#define CR_RX_FIFO_OVERRUN CTL_REG(0x06B0)
+
+#define CR_DECRYPTION_ERR_MUL CTL_REG(0x06BC)
+
+#define CR_NAV_CNT CTL_REG(0x06C4)
+#define CR_NAV_CCA CTL_REG(0x06C8)
+#define CR_RETRY_CNT CTL_REG(0x06CC)
+
+#define CR_READ_TCB_ADDR CTL_REG(0x06E8)
+#define CR_READ_RFD_ADDR CTL_REG(0x06EC)
+#define CR_CWMIN_CWMAX CTL_REG(0x06F0)
+#define CR_TOTAL_TX_FRM CTL_REG(0x06F4)
+
+/* CAM: Continuous Access Mode (power management) */
+#define CR_CAM_MODE CTL_REG(0x0700)
+#define CR_CAM_ROLL_TB_LOW CTL_REG(0x0704)
+#define CR_CAM_ROLL_TB_HIGH CTL_REG(0x0708)
+#define CR_CAM_ADDRESS CTL_REG(0x070C)
+#define CR_CAM_DATA CTL_REG(0x0710)
+
+#define CR_ROMDIR CTL_REG(0x0714)
+
+#define CR_DECRY_ERR_FLG_LOW CTL_REG(0x0714)
+#define CR_DECRY_ERR_FLG_HIGH CTL_REG(0x0718)
+
+#define CR_WEPKEY0 CTL_REG(0x0720)
+#define CR_WEPKEY1 CTL_REG(0x0724)
+#define CR_WEPKEY2 CTL_REG(0x0728)
+#define CR_WEPKEY3 CTL_REG(0x072C)
+#define CR_WEPKEY4 CTL_REG(0x0730)
+#define CR_WEPKEY5 CTL_REG(0x0734)
+#define CR_WEPKEY6 CTL_REG(0x0738)
+#define CR_WEPKEY7 CTL_REG(0x073C)
+#define CR_WEPKEY8 CTL_REG(0x0740)
+#define CR_WEPKEY9 CTL_REG(0x0744)
+#define CR_WEPKEY10 CTL_REG(0x0748)
+#define CR_WEPKEY11 CTL_REG(0x074C)
+#define CR_WEPKEY12 CTL_REG(0x0750)
+#define CR_WEPKEY13 CTL_REG(0x0754)
+#define CR_WEPKEY14 CTL_REG(0x0758)
+#define CR_WEPKEY15 CTL_REG(0x075c)
+#define CR_TKIP_MODE CTL_REG(0x0760)
+
+#define CR_EEPROM_PROTECT0 CTL_REG(0x0758)
+#define CR_EEPROM_PROTECT1 CTL_REG(0x075C)
+
+#define CR_DBG_FIFO_RD CTL_REG(0x0800)
+#define CR_DBG_SELECT CTL_REG(0x0804)
+#define CR_FIFO_Length CTL_REG(0x0808)
+
+
+#define CR_RSSI_MGC CTL_REG(0x0810)
+
+#define CR_PON CTL_REG(0x0818)
+#define CR_RX_ON CTL_REG(0x081C)
+#define CR_TX_ON CTL_REG(0x0820)
+#define CR_CHIP_EN CTL_REG(0x0824)
+#define CR_LO_SW CTL_REG(0x0828)
+#define CR_TXRX_SW CTL_REG(0x082C)
+#define CR_S_MD CTL_REG(0x0830)
+
+#define CR_USB_DEBUG_PORT CTL_REG(0x0888)
+
+#define CR_ZD1211B_TX_PWR_CTL1 CTL_REG(0x0b00)
+#define CR_ZD1211B_TX_PWR_CTL2 CTL_REG(0x0b04)
+#define CR_ZD1211B_TX_PWR_CTL3 CTL_REG(0x0b08)
+#define CR_ZD1211B_TX_PWR_CTL4 CTL_REG(0x0b0c)
+#define CR_ZD1211B_AIFS_CTL1 CTL_REG(0x0b10)
+#define CR_ZD1211B_AIFS_CTL2 CTL_REG(0x0b14)
+#define CR_ZD1211B_TXOP CTL_REG(0x0b20)
+#define CR_ZD1211B_RETRY_MAX CTL_REG(0x0b28)
+
+#define CWIN_SIZE 0x007f043f
+
+
+#define HWINT_ENABLED 0x004f0000
+#define HWINT_DISABLED 0
+
+#define E2P_PWR_INT_GUARD 8
+#define E2P_CHANNEL_COUNT 14
+
+/* If you compare this addresses with the ZYDAS orignal driver, please notify
+ * that we use word mapping for the EEPROM.
+ */
+
+/*
+ * Upper 16 bit contains the regulatory domain.
+ */
+#define E2P_SUBID E2P_REG(0x00)
+#define E2P_POD E2P_REG(0x02)
+#define E2P_MAC_ADDR_P1 E2P_REG(0x04)
+#define E2P_MAC_ADDR_P2 E2P_REG(0x06)
+#define E2P_PWR_CAL_VALUE1 E2P_REG(0x08)
+#define E2P_PWR_CAL_VALUE2 E2P_REG(0x0a)
+#define E2P_PWR_CAL_VALUE3 E2P_REG(0x0c)
+#define E2P_PWR_CAL_VALUE4 E2P_REG(0x0e)
+#define E2P_PWR_INT_VALUE1 E2P_REG(0x10)
+#define E2P_PWR_INT_VALUE2 E2P_REG(0x12)
+#define E2P_PWR_INT_VALUE3 E2P_REG(0x14)
+#define E2P_PWR_INT_VALUE4 E2P_REG(0x16)
+
+/* Contains a bit for each allowed channel. It gives for Europe (ETSI 0x30)
+ * also only 11 channels. */
+#define E2P_ALLOWED_CHANNEL E2P_REG(0x18)
+
+#define E2P_PHY_REG E2P_REG(0x1a)
+#define E2P_DEVICE_VER E2P_REG(0x20)
+#define E2P_36M_CAL_VALUE1 E2P_REG(0x28)
+#define E2P_36M_CAL_VALUE2 E2P_REG(0x2a)
+#define E2P_36M_CAL_VALUE3 E2P_REG(0x2c)
+#define E2P_36M_CAL_VALUE4 E2P_REG(0x2e)
+#define E2P_11A_INT_VALUE1 E2P_REG(0x30)
+#define E2P_11A_INT_VALUE2 E2P_REG(0x32)
+#define E2P_11A_INT_VALUE3 E2P_REG(0x34)
+#define E2P_11A_INT_VALUE4 E2P_REG(0x36)
+#define E2P_48M_CAL_VALUE1 E2P_REG(0x38)
+#define E2P_48M_CAL_VALUE2 E2P_REG(0x3a)
+#define E2P_48M_CAL_VALUE3 E2P_REG(0x3c)
+#define E2P_48M_CAL_VALUE4 E2P_REG(0x3e)
+#define E2P_48M_INT_VALUE1 E2P_REG(0x40)
+#define E2P_48M_INT_VALUE2 E2P_REG(0x42)
+#define E2P_48M_INT_VALUE3 E2P_REG(0x44)
+#define E2P_48M_INT_VALUE4 E2P_REG(0x46)
+#define E2P_54M_CAL_VALUE1 E2P_REG(0x48) /* ??? */
+#define E2P_54M_CAL_VALUE2 E2P_REG(0x4a)
+#define E2P_54M_CAL_VALUE3 E2P_REG(0x4c)
+#define E2P_54M_CAL_VALUE4 E2P_REG(0x4e)
+#define E2P_54M_INT_VALUE1 E2P_REG(0x50)
+#define E2P_54M_INT_VALUE2 E2P_REG(0x52)
+#define E2P_54M_INT_VALUE3 E2P_REG(0x54)
+#define E2P_54M_INT_VALUE4 E2P_REG(0x56)
+
+/* All 16 bit values */
+#define FW_FIRMWARE_VER FW_REG(0)
+/* non-zero if USB high speed connection */
+#define FW_USB_SPEED FW_REG(1)
+#define FW_FIX_TX_RATE FW_REG(2)
+/* Seems to be able to control LEDs over the firmware */
+#define FW_LINK_STATUS FW_REG(3)
+#define FW_SOFT_RESET FW_REG(4)
+#define FW_FLASH_CHK FW_REG(5)
+
+enum {
+ CR_BASE_OFFSET = 0x9000,
+ FW_START_OFFSET = 0xee00,
+ FW_BASE_ADDR_OFFSET = FW_START_OFFSET + 0x1d,
+ EEPROM_START_OFFSET = 0xf800,
+ EEPROM_SIZE = 0x800, /* words */
+ LOAD_CODE_SIZE = 0xe, /* words */
+ LOAD_VECT_SIZE = 0x10000 - 0xfff7, /* words */
+ EEPROM_REGS_OFFSET = LOAD_CODE_SIZE + LOAD_VECT_SIZE,
+ E2P_BASE_OFFSET = EEPROM_START_OFFSET +
+ EEPROM_REGS_OFFSET,
+};
+
+#define FW_REG_TABLE_ADDR USB_ADDR(FW_START_OFFSET + 0x1d)
+
+enum {
+ /* indices for ofdm_cal_values */
+ OFDM_36M_INDEX = 0,
+ OFDM_48M_INDEX = 1,
+ OFDM_54M_INDEX = 2,
+};
+
+struct zd_chip {
+ struct zd_usb usb;
+ struct zd_rf rf;
+ struct mutex mutex;
+ u8 e2p_mac[ETH_ALEN];
+ /* EepSetPoint in the vendor driver */
+ u8 pwr_cal_values[E2P_CHANNEL_COUNT];
+ /* integration values in the vendor driver */
+ u8 pwr_int_values[E2P_CHANNEL_COUNT];
+ /* SetPointOFDM in the vendor driver */
+ u8 ofdm_cal_values[3][E2P_CHANNEL_COUNT];
+ u8 pa_type:4, patch_cck_gain:1, patch_cr157:1, patch_6m_band_edge:1,
+ is_zd1211b:1;
+};
+
+static inline struct zd_chip *zd_usb_to_chip(struct zd_usb *usb)
+{
+ return container_of(usb, struct zd_chip, usb);
+}
+
+static inline struct zd_chip *zd_rf_to_chip(struct zd_rf *rf)
+{
+ return container_of(rf, struct zd_chip, rf);
+}
+
+#define zd_chip_dev(chip) (&(chip)->usb.intf->dev)
+
+void zd_chip_init(struct zd_chip *chip,
+ struct net_device *netdev,
+ struct usb_interface *intf);
+void zd_chip_clear(struct zd_chip *chip);
+int zd_chip_init_hw(struct zd_chip *chip, u8 device_type);
+int zd_chip_reset(struct zd_chip *chip);
+
+static inline int zd_ioread16v_locked(struct zd_chip *chip, u16 *values,
+ const zd_addr_t *addresses,
+ unsigned int count)
+{
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ return zd_usb_ioread16v(&chip->usb, values, addresses, count);
+}
+
+static inline int zd_ioread16_locked(struct zd_chip *chip, u16 *value,
+ const zd_addr_t addr)
+{
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ return zd_usb_ioread16(&chip->usb, value, addr);
+}
+
+int zd_ioread32v_locked(struct zd_chip *chip, u32 *values,
+ const zd_addr_t *addresses, unsigned int count);
+
+static inline int zd_ioread32_locked(struct zd_chip *chip, u32 *value,
+ const zd_addr_t addr)
+{
+ return zd_ioread32v_locked(chip, value, (const zd_addr_t *)&addr, 1);
+}
+
+static inline int zd_iowrite16_locked(struct zd_chip *chip, u16 value,
+ zd_addr_t addr)
+{
+ struct zd_ioreq16 ioreq;
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ ioreq.addr = addr;
+ ioreq.value = value;
+
+ return zd_usb_iowrite16v(&chip->usb, &ioreq, 1);
+}
+
+int zd_iowrite16a_locked(struct zd_chip *chip,
+ const struct zd_ioreq16 *ioreqs, unsigned int count);
+
+int _zd_iowrite32v_locked(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs,
+ unsigned int count);
+
+static inline int zd_iowrite32_locked(struct zd_chip *chip, u32 value,
+ zd_addr_t addr)
+{
+ struct zd_ioreq32 ioreq;
+
+ ioreq.addr = addr;
+ ioreq.value = value;
+
+ return _zd_iowrite32v_locked(chip, &ioreq, 1);
+}
+
+int zd_iowrite32a_locked(struct zd_chip *chip,
+ const struct zd_ioreq32 *ioreqs, unsigned int count);
+
+static inline int zd_rfwrite_locked(struct zd_chip *chip, u32 value, u8 bits)
+{
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ return zd_usb_rfwrite(&chip->usb, value, bits);
+}
+
+int zd_rfwritev_locked(struct zd_chip *chip,
+ const u32* values, unsigned int count, u8 bits);
+
+/* Locking functions for reading and writing registers.
+ * The different parameters are intentional.
+ */
+int zd_ioread16(struct zd_chip *chip, zd_addr_t addr, u16 *value);
+int zd_iowrite16(struct zd_chip *chip, zd_addr_t addr, u16 value);
+int zd_ioread32(struct zd_chip *chip, zd_addr_t addr, u32 *value);
+int zd_iowrite32(struct zd_chip *chip, zd_addr_t addr, u32 value);
+int zd_ioread32v(struct zd_chip *chip, const zd_addr_t *addresses,
+ u32 *values, unsigned int count);
+int zd_iowrite32a(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs,
+ unsigned int count);
+
+int zd_chip_set_channel(struct zd_chip *chip, u8 channel);
+static inline u8 _zd_chip_get_channel(struct zd_chip *chip)
+{
+ return chip->rf.channel;
+}
+u8 zd_chip_get_channel(struct zd_chip *chip);
+int zd_read_regdomain(struct zd_chip *chip, u8 *regdomain);
+void zd_get_e2p_mac_addr(struct zd_chip *chip, u8 *mac_addr);
+int zd_read_mac_addr(struct zd_chip *chip, u8 *mac_addr);
+int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr);
+int zd_chip_switch_radio_on(struct zd_chip *chip);
+int zd_chip_switch_radio_off(struct zd_chip *chip);
+int zd_chip_enable_int(struct zd_chip *chip);
+void zd_chip_disable_int(struct zd_chip *chip);
+int zd_chip_enable_rx(struct zd_chip *chip);
+void zd_chip_disable_rx(struct zd_chip *chip);
+int zd_chip_enable_hwint(struct zd_chip *chip);
+int zd_chip_disable_hwint(struct zd_chip *chip);
+
+static inline int zd_get_encryption_type(struct zd_chip *chip, u32 *type)
+{
+ return zd_ioread32(chip, CR_ENCRYPTION_TYPE, type);
+}
+
+static inline int zd_set_encryption_type(struct zd_chip *chip, u32 type)
+{
+ return zd_iowrite32(chip, CR_ENCRYPTION_TYPE, type);
+}
+
+static inline int zd_chip_get_basic_rates(struct zd_chip *chip, u16 *cr_rates)
+{
+ return zd_ioread16(chip, CR_BASIC_RATE_TBL, cr_rates);
+}
+
+int zd_chip_set_basic_rates(struct zd_chip *chip, u16 cr_rates);
+
+static inline int zd_chip_set_rx_filter(struct zd_chip *chip, u32 filter)
+{
+ return zd_iowrite32(chip, CR_RX_FILTER, filter);
+}
+
+int zd_chip_lock_phy_regs(struct zd_chip *chip);
+int zd_chip_unlock_phy_regs(struct zd_chip *chip);
+
+enum led_status {
+ LED_OFF = 0,
+ LED_ON = 1,
+ LED_FLIP = 2,
+ LED_STATUS = 3,
+};
+
+int zd_chip_led_status(struct zd_chip *chip, int led, enum led_status status);
+int zd_chip_led_flip(struct zd_chip *chip, int led,
+ const unsigned int *phases_msecs, unsigned int count);
+
+int zd_set_beacon_interval(struct zd_chip *chip, u32 interval);
+
+static inline int zd_get_beacon_interval(struct zd_chip *chip, u32 *interval)
+{
+ return zd_ioread32(chip, CR_BCN_INTERVAL, interval);
+}
+
+struct rx_status;
+
+u8 zd_rx_qual_percent(const void *rx_frame, unsigned int size,
+ const struct rx_status *status);
+u8 zd_rx_strength_percent(u8 rssi);
+
+u16 zd_rx_rate(const void *rx_frame, const struct rx_status *status);
+
+#endif /* _ZD_CHIP_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_def.h b/drivers/net/wireless/zd1211rw/zd_def.h
new file mode 100644
index 00000000000..465906812fc
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_def.h
@@ -0,0 +1,48 @@
+/* zd_def.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _ZD_DEF_H
+#define _ZD_DEF_H
+
+#include <linux/kernel.h>
+#include <linux/stringify.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+
+#define dev_printk_f(level, dev, fmt, args...) \
+ dev_printk(level, dev, "%s() " fmt, __func__, ##args)
+
+#ifdef DEBUG
+# define dev_dbg_f(dev, fmt, args...) \
+ dev_printk_f(KERN_DEBUG, dev, fmt, ## args)
+#else
+# define dev_dbg_f(dev, fmt, args...) do { (void)(dev); } while (0)
+#endif /* DEBUG */
+
+#ifdef DEBUG
+# define ZD_ASSERT(x) \
+do { \
+ if (!(x)) { \
+ pr_debug("%s:%d ASSERT %s VIOLATED!\n", \
+ __FILE__, __LINE__, __stringify(x)); \
+ } \
+} while (0)
+#else
+# define ZD_ASSERT(x) do { } while (0)
+#endif
+
+#endif /* _ZD_DEF_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.c b/drivers/net/wireless/zd1211rw/zd_ieee80211.c
new file mode 100644
index 00000000000..66905f7b61f
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_ieee80211.c
@@ -0,0 +1,191 @@
+/* zd_ieee80211.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * A lot of this code is generic and should be moved into the upper layers
+ * at some point.
+ */
+
+#include <linux/errno.h>
+#include <linux/wireless.h>
+#include <linux/kernel.h>
+#include <net/ieee80211.h>
+
+#include "zd_def.h"
+#include "zd_ieee80211.h"
+#include "zd_mac.h"
+
+static const struct channel_range channel_ranges[] = {
+ [0] = { 0, 0},
+ [ZD_REGDOMAIN_FCC] = { 1, 12},
+ [ZD_REGDOMAIN_IC] = { 1, 12},
+ [ZD_REGDOMAIN_ETSI] = { 1, 14},
+ [ZD_REGDOMAIN_JAPAN] = { 1, 14},
+ [ZD_REGDOMAIN_SPAIN] = { 1, 14},
+ [ZD_REGDOMAIN_FRANCE] = { 1, 14},
+ [ZD_REGDOMAIN_JAPAN_ADD] = {14, 15},
+};
+
+const struct channel_range *zd_channel_range(u8 regdomain)
+{
+ if (regdomain >= ARRAY_SIZE(channel_ranges))
+ regdomain = 0;
+ return &channel_ranges[regdomain];
+}
+
+int zd_regdomain_supports_channel(u8 regdomain, u8 channel)
+{
+ const struct channel_range *range = zd_channel_range(regdomain);
+ return range->start <= channel && channel < range->end;
+}
+
+int zd_regdomain_supported(u8 regdomain)
+{
+ const struct channel_range *range = zd_channel_range(regdomain);
+ return range->start != 0;
+}
+
+/* Stores channel frequencies in MHz. */
+static const u16 channel_frequencies[] = {
+ 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447,
+ 2452, 2457, 2462, 2467, 2472, 2484,
+};
+
+#define NUM_CHANNELS ARRAY_SIZE(channel_frequencies)
+
+static int compute_freq(struct iw_freq *freq, u32 mhz, u32 hz)
+{
+ u32 factor;
+
+ freq->e = 0;
+ if (mhz >= 1000000000U) {
+ pr_debug("zd1211 mhz %u to large\n", mhz);
+ freq->m = 0;
+ return -EINVAL;
+ }
+
+ factor = 1000;
+ while (mhz >= factor) {
+
+ freq->e += 1;
+ factor *= 10;
+ }
+
+ factor /= 1000U;
+ freq->m = mhz * (1000000U/factor) + hz/factor;
+
+ return 0;
+}
+
+int zd_channel_to_freq(struct iw_freq *freq, u8 channel)
+{
+ if (channel > NUM_CHANNELS) {
+ freq->m = 0;
+ freq->e = 0;
+ return -EINVAL;
+ }
+ if (!channel) {
+ freq->m = 0;
+ freq->e = 0;
+ return -EINVAL;
+ }
+ return compute_freq(freq, channel_frequencies[channel-1], 0);
+}
+
+static int freq_to_mhz(const struct iw_freq *freq)
+{
+ u32 factor;
+ int e;
+
+ /* Such high frequencies are not supported. */
+ if (freq->e > 6)
+ return -EINVAL;
+
+ factor = 1;
+ for (e = freq->e; e > 0; --e) {
+ factor *= 10;
+ }
+ factor = 1000000U / factor;
+
+ if (freq->m % factor) {
+ return -EINVAL;
+ }
+
+ return freq->m / factor;
+}
+
+int zd_find_channel(u8 *channel, const struct iw_freq *freq)
+{
+ int i, r;
+ u32 mhz;
+
+ if (!(freq->flags & IW_FREQ_FIXED))
+ return 0;
+
+ if (freq->m < 1000) {
+ if (freq->m > NUM_CHANNELS || freq->m == 0)
+ return -EINVAL;
+ *channel = freq->m;
+ return 1;
+ }
+
+ r = freq_to_mhz(freq);
+ if (r < 0)
+ return r;
+ mhz = r;
+
+ for (i = 0; i < NUM_CHANNELS; i++) {
+ if (mhz == channel_frequencies[i]) {
+ *channel = i+1;
+ return 1;
+ }
+ }
+
+ return -EINVAL;
+}
+
+int zd_geo_init(struct ieee80211_device *ieee, u8 regdomain)
+{
+ struct ieee80211_geo geo;
+ const struct channel_range *range;
+ int i;
+ u8 channel;
+
+ dev_dbg(zd_mac_dev(zd_netdev_mac(ieee->dev)),
+ "regdomain %#04x\n", regdomain);
+
+ range = zd_channel_range(regdomain);
+ if (range->start == 0) {
+ dev_err(zd_mac_dev(zd_netdev_mac(ieee->dev)),
+ "zd1211 regdomain %#04x not supported\n",
+ regdomain);
+ return -EINVAL;
+ }
+
+ memset(&geo, 0, sizeof(geo));
+
+ for (i = 0, channel = range->start; channel < range->end; channel++) {
+ struct ieee80211_channel *chan = &geo.bg[i++];
+ chan->freq = channel_frequencies[channel - 1];
+ chan->channel = channel;
+ }
+
+ geo.bg_channels = i;
+ memcpy(geo.name, "XX ", 4);
+ ieee80211_set_geo(ieee, &geo);
+ return 0;
+}
diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.h b/drivers/net/wireless/zd1211rw/zd_ieee80211.h
new file mode 100644
index 00000000000..36329890dfe
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_ieee80211.h
@@ -0,0 +1,85 @@
+#ifndef _ZD_IEEE80211_H
+#define _ZD_IEEE80211_H
+
+#include <net/ieee80211.h>
+#include "zd_types.h"
+
+/* Additional definitions from the standards.
+ */
+
+#define ZD_REGDOMAIN_FCC 0x10
+#define ZD_REGDOMAIN_IC 0x20
+#define ZD_REGDOMAIN_ETSI 0x30
+#define ZD_REGDOMAIN_SPAIN 0x31
+#define ZD_REGDOMAIN_FRANCE 0x32
+#define ZD_REGDOMAIN_JAPAN_ADD 0x40
+#define ZD_REGDOMAIN_JAPAN 0x41
+
+enum {
+ MIN_CHANNEL24 = 1,
+ MAX_CHANNEL24 = 14,
+};
+
+struct channel_range {
+ u8 start;
+ u8 end; /* exclusive (channel must be less than end) */
+};
+
+struct iw_freq;
+
+int zd_geo_init(struct ieee80211_device *ieee, u8 regdomain);
+
+const struct channel_range *zd_channel_range(u8 regdomain);
+int zd_regdomain_supports_channel(u8 regdomain, u8 channel);
+int zd_regdomain_supported(u8 regdomain);
+
+/* for 2.4 GHz band */
+int zd_channel_to_freq(struct iw_freq *freq, u8 channel);
+int zd_find_channel(u8 *channel, const struct iw_freq *freq);
+
+#define ZD_PLCP_SERVICE_LENGTH_EXTENSION 0x80
+
+struct ofdm_plcp_header {
+ u8 prefix[3];
+ __le16 service;
+} __attribute__((packed));
+
+static inline u8 zd_ofdm_plcp_header_rate(
+ const struct ofdm_plcp_header *header)
+{
+ return header->prefix[0] & 0xf;
+}
+
+#define ZD_OFDM_RATE_6M 0xb
+#define ZD_OFDM_RATE_9M 0xf
+#define ZD_OFDM_RATE_12M 0xa
+#define ZD_OFDM_RATE_18M 0xe
+#define ZD_OFDM_RATE_24M 0x9
+#define ZD_OFDM_RATE_36M 0xd
+#define ZD_OFDM_RATE_48M 0x8
+#define ZD_OFDM_RATE_54M 0xc
+
+struct cck_plcp_header {
+ u8 signal;
+ u8 service;
+ __le16 length;
+ __le16 crc16;
+} __attribute__((packed));
+
+static inline u8 zd_cck_plcp_header_rate(const struct cck_plcp_header *header)
+{
+ return header->signal;
+}
+
+#define ZD_CCK_SIGNAL_1M 0x0a
+#define ZD_CCK_SIGNAL_2M 0x14
+#define ZD_CCK_SIGNAL_5M5 0x37
+#define ZD_CCK_SIGNAL_11M 0x6e
+
+enum ieee80211_std {
+ IEEE80211B = 0x01,
+ IEEE80211A = 0x02,
+ IEEE80211G = 0x04,
+};
+
+#endif /* _ZD_IEEE80211_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
new file mode 100644
index 00000000000..d6f3e02a0b5
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -0,0 +1,1057 @@
+/* zd_mac.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/wireless.h>
+#include <linux/usb.h>
+#include <linux/jiffies.h>
+#include <net/ieee80211_radiotap.h>
+
+#include "zd_def.h"
+#include "zd_chip.h"
+#include "zd_mac.h"
+#include "zd_ieee80211.h"
+#include "zd_netdev.h"
+#include "zd_rf.h"
+#include "zd_util.h"
+
+static void ieee_init(struct ieee80211_device *ieee);
+static void softmac_init(struct ieee80211softmac_device *sm);
+
+int zd_mac_init(struct zd_mac *mac,
+ struct net_device *netdev,
+ struct usb_interface *intf)
+{
+ struct ieee80211_device *ieee = zd_netdev_ieee80211(netdev);
+
+ memset(mac, 0, sizeof(*mac));
+ spin_lock_init(&mac->lock);
+ mac->netdev = netdev;
+
+ ieee_init(ieee);
+ softmac_init(ieee80211_priv(netdev));
+ zd_chip_init(&mac->chip, netdev, intf);
+ return 0;
+}
+
+static int reset_channel(struct zd_mac *mac)
+{
+ int r;
+ unsigned long flags;
+ const struct channel_range *range;
+
+ spin_lock_irqsave(&mac->lock, flags);
+ range = zd_channel_range(mac->regdomain);
+ if (!range->start) {
+ r = -EINVAL;
+ goto out;
+ }
+ mac->requested_channel = range->start;
+ r = 0;
+out:
+ spin_unlock_irqrestore(&mac->lock, flags);
+ return r;
+}
+
+int zd_mac_init_hw(struct zd_mac *mac, u8 device_type)
+{
+ int r;
+ struct zd_chip *chip = &mac->chip;
+ u8 addr[ETH_ALEN];
+ u8 default_regdomain;
+
+ r = zd_chip_enable_int(chip);
+ if (r)
+ goto out;
+ r = zd_chip_init_hw(chip, device_type);
+ if (r)
+ goto disable_int;
+
+ zd_get_e2p_mac_addr(chip, addr);
+ r = zd_write_mac_addr(chip, addr);
+ if (r)
+ goto disable_int;
+ ZD_ASSERT(!irqs_disabled());
+ spin_lock_irq(&mac->lock);
+ memcpy(mac->netdev->dev_addr, addr, ETH_ALEN);
+ spin_unlock_irq(&mac->lock);
+
+ r = zd_read_regdomain(chip, &default_regdomain);
+ if (r)
+ goto disable_int;
+ if (!zd_regdomain_supported(default_regdomain)) {
+ dev_dbg_f(zd_mac_dev(mac),
+ "Regulatory Domain %#04x is not supported.\n",
+ default_regdomain);
+ r = -EINVAL;
+ goto disable_int;
+ }
+ spin_lock_irq(&mac->lock);
+ mac->regdomain = mac->default_regdomain = default_regdomain;
+ spin_unlock_irq(&mac->lock);
+ r = reset_channel(mac);
+ if (r)
+ goto disable_int;
+
+ /* We must inform the device that we are doing encryption/decryption in
+ * software at the moment. */
+ r = zd_set_encryption_type(chip, ENC_SNIFFER);
+ if (r)
+ goto disable_int;
+
+ r = zd_geo_init(zd_mac_to_ieee80211(mac), mac->regdomain);
+ if (r)
+ goto disable_int;
+
+ r = 0;
+disable_int:
+ zd_chip_disable_int(chip);
+out:
+ return r;
+}
+
+void zd_mac_clear(struct zd_mac *mac)
+{
+ /* Aquire the lock. */
+ spin_lock(&mac->lock);
+ spin_unlock(&mac->lock);
+ zd_chip_clear(&mac->chip);
+ memset(mac, 0, sizeof(*mac));
+}
+
+static int reset_mode(struct zd_mac *mac)
+{
+ struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+ struct zd_ioreq32 ioreqs[3] = {
+ { CR_RX_FILTER, STA_RX_FILTER },
+ { CR_SNIFFER_ON, 0U },
+ };
+
+ if (ieee->iw_mode == IW_MODE_MONITOR) {
+ ioreqs[0].value = 0xffffffff;
+ ioreqs[1].value = 0x1;
+ ioreqs[2].value = ENC_SNIFFER;
+ }
+
+ return zd_iowrite32a(&mac->chip, ioreqs, 3);
+}
+
+int zd_mac_open(struct net_device *netdev)
+{
+ struct zd_mac *mac = zd_netdev_mac(netdev);
+ struct zd_chip *chip = &mac->chip;
+ int r;
+
+ r = zd_chip_enable_int(chip);
+ if (r < 0)
+ goto out;
+
+ r = zd_chip_set_basic_rates(chip, CR_RATES_80211B | CR_RATES_80211G);
+ if (r < 0)
+ goto disable_int;
+ r = reset_mode(mac);
+ if (r)
+ goto disable_int;
+ r = zd_chip_switch_radio_on(chip);
+ if (r < 0)
+ goto disable_int;
+ r = zd_chip_set_channel(chip, mac->requested_channel);
+ if (r < 0)
+ goto disable_radio;
+ r = zd_chip_enable_rx(chip);
+ if (r < 0)
+ goto disable_radio;
+ r = zd_chip_enable_hwint(chip);
+ if (r < 0)
+ goto disable_rx;
+
+ ieee80211softmac_start(netdev);
+ return 0;
+disable_rx:
+ zd_chip_disable_rx(chip);
+disable_radio:
+ zd_chip_switch_radio_off(chip);
+disable_int:
+ zd_chip_disable_int(chip);
+out:
+ return r;
+}
+
+int zd_mac_stop(struct net_device *netdev)
+{
+ struct zd_mac *mac = zd_netdev_mac(netdev);
+ struct zd_chip *chip = &mac->chip;
+
+ netif_stop_queue(netdev);
+
+ /*
+ * The order here deliberately is a little different from the open()
+ * method, since we need to make sure there is no opportunity for RX
+ * frames to be processed by softmac after we have stopped it.
+ */
+
+ zd_chip_disable_rx(chip);
+ ieee80211softmac_stop(netdev);
+
+ zd_chip_disable_hwint(chip);
+ zd_chip_switch_radio_off(chip);
+ zd_chip_disable_int(chip);
+
+ return 0;
+}
+
+int zd_mac_set_mac_address(struct net_device *netdev, void *p)
+{
+ int r;
+ unsigned long flags;
+ struct sockaddr *addr = p;
+ struct zd_mac *mac = zd_netdev_mac(netdev);
+ struct zd_chip *chip = &mac->chip;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ dev_dbg_f(zd_mac_dev(mac),
+ "Setting MAC to " MAC_FMT "\n", MAC_ARG(addr->sa_data));
+
+ r = zd_write_mac_addr(chip, addr->sa_data);
+ if (r)
+ return r;
+
+ spin_lock_irqsave(&mac->lock, flags);
+ memcpy(netdev->dev_addr, addr->sa_data, ETH_ALEN);
+ spin_unlock_irqrestore(&mac->lock, flags);
+
+ return 0;
+}
+
+int zd_mac_set_regdomain(struct zd_mac *mac, u8 regdomain)
+{
+ int r;
+ u8 channel;
+
+ ZD_ASSERT(!irqs_disabled());
+ spin_lock_irq(&mac->lock);
+ if (regdomain == 0) {
+ regdomain = mac->default_regdomain;
+ }
+ if (!zd_regdomain_supported(regdomain)) {
+ spin_unlock_irq(&mac->lock);
+ return -EINVAL;
+ }
+ mac->regdomain = regdomain;
+ channel = mac->requested_channel;
+ spin_unlock_irq(&mac->lock);
+
+ r = zd_geo_init(zd_mac_to_ieee80211(mac), regdomain);
+ if (r)
+ return r;
+ if (!zd_regdomain_supports_channel(regdomain, channel)) {
+ r = reset_channel(mac);
+ if (r)
+ return r;
+ }
+
+ return 0;
+}
+
+u8 zd_mac_get_regdomain(struct zd_mac *mac)
+{
+ unsigned long flags;
+ u8 regdomain;
+
+ spin_lock_irqsave(&mac->lock, flags);
+ regdomain = mac->regdomain;
+ spin_unlock_irqrestore(&mac->lock, flags);
+ return regdomain;
+}
+
+static void set_channel(struct net_device *netdev, u8 channel)
+{
+ struct zd_mac *mac = zd_netdev_mac(netdev);
+
+ dev_dbg_f(zd_mac_dev(mac), "channel %d\n", channel);
+
+ zd_chip_set_channel(&mac->chip, channel);
+}
+
+/* TODO: Should not work in Managed mode. */
+int zd_mac_request_channel(struct zd_mac *mac, u8 channel)
+{
+ unsigned long lock_flags;
+ struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+
+ if (ieee->iw_mode == IW_MODE_INFRA)
+ return -EPERM;
+
+ spin_lock_irqsave(&mac->lock, lock_flags);
+ if (!zd_regdomain_supports_channel(mac->regdomain, channel)) {
+ spin_unlock_irqrestore(&mac->lock, lock_flags);
+ return -EINVAL;
+ }
+ mac->requested_channel = channel;
+ spin_unlock_irqrestore(&mac->lock, lock_flags);
+ if (netif_running(mac->netdev))
+ return zd_chip_set_channel(&mac->chip, channel);
+ else
+ return 0;
+}
+
+int zd_mac_get_channel(struct zd_mac *mac, u8 *channel, u8 *flags)
+{
+ struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+
+ *channel = zd_chip_get_channel(&mac->chip);
+ if (ieee->iw_mode != IW_MODE_INFRA) {
+ spin_lock_irq(&mac->lock);
+ *flags = *channel == mac->requested_channel ?
+ MAC_FIXED_CHANNEL : 0;
+ spin_unlock(&mac->lock);
+ } else {
+ *flags = 0;
+ }
+ dev_dbg_f(zd_mac_dev(mac), "channel %u flags %u\n", *channel, *flags);
+ return 0;
+}
+
+/* If wrong rate is given, we are falling back to the slowest rate: 1MBit/s */
+static u8 cs_typed_rate(u8 cs_rate)
+{
+ static const u8 typed_rates[16] = {
+ [ZD_CS_CCK_RATE_1M] = ZD_CS_CCK|ZD_CS_CCK_RATE_1M,
+ [ZD_CS_CCK_RATE_2M] = ZD_CS_CCK|ZD_CS_CCK_RATE_2M,
+ [ZD_CS_CCK_RATE_5_5M] = ZD_CS_CCK|ZD_CS_CCK_RATE_5_5M,
+ [ZD_CS_CCK_RATE_11M] = ZD_CS_CCK|ZD_CS_CCK_RATE_11M,
+ [ZD_OFDM_RATE_6M] = ZD_CS_OFDM|ZD_OFDM_RATE_6M,
+ [ZD_OFDM_RATE_9M] = ZD_CS_OFDM|ZD_OFDM_RATE_9M,
+ [ZD_OFDM_RATE_12M] = ZD_CS_OFDM|ZD_OFDM_RATE_12M,
+ [ZD_OFDM_RATE_18M] = ZD_CS_OFDM|ZD_OFDM_RATE_18M,
+ [ZD_OFDM_RATE_24M] = ZD_CS_OFDM|ZD_OFDM_RATE_24M,
+ [ZD_OFDM_RATE_36M] = ZD_CS_OFDM|ZD_OFDM_RATE_36M,
+ [ZD_OFDM_RATE_48M] = ZD_CS_OFDM|ZD_OFDM_RATE_48M,
+ [ZD_OFDM_RATE_54M] = ZD_CS_OFDM|ZD_OFDM_RATE_54M,
+ };
+
+ ZD_ASSERT(ZD_CS_RATE_MASK == 0x0f);
+ return typed_rates[cs_rate & ZD_CS_RATE_MASK];
+}
+
+/* Fallback to lowest rate, if rate is unknown. */
+static u8 rate_to_cs_rate(u8 rate)
+{
+ switch (rate) {
+ case IEEE80211_CCK_RATE_2MB:
+ return ZD_CS_CCK_RATE_2M;
+ case IEEE80211_CCK_RATE_5MB:
+ return ZD_CS_CCK_RATE_5_5M;
+ case IEEE80211_CCK_RATE_11MB:
+ return ZD_CS_CCK_RATE_11M;
+ case IEEE80211_OFDM_RATE_6MB:
+ return ZD_OFDM_RATE_6M;
+ case IEEE80211_OFDM_RATE_9MB:
+ return ZD_OFDM_RATE_9M;
+ case IEEE80211_OFDM_RATE_12MB:
+ return ZD_OFDM_RATE_12M;
+ case IEEE80211_OFDM_RATE_18MB:
+ return ZD_OFDM_RATE_18M;
+ case IEEE80211_OFDM_RATE_24MB:
+ return ZD_OFDM_RATE_24M;
+ case IEEE80211_OFDM_RATE_36MB:
+ return ZD_OFDM_RATE_36M;
+ case IEEE80211_OFDM_RATE_48MB:
+ return ZD_OFDM_RATE_48M;
+ case IEEE80211_OFDM_RATE_54MB:
+ return ZD_OFDM_RATE_54M;
+ }
+ return ZD_CS_CCK_RATE_1M;
+}
+
+int zd_mac_set_mode(struct zd_mac *mac, u32 mode)
+{
+ struct ieee80211_device *ieee;
+
+ switch (mode) {
+ case IW_MODE_AUTO:
+ case IW_MODE_ADHOC:
+ case IW_MODE_INFRA:
+ mac->netdev->type = ARPHRD_ETHER;
+ break;
+ case IW_MODE_MONITOR:
+ mac->netdev->type = ARPHRD_IEEE80211_RADIOTAP;
+ break;
+ default:
+ dev_dbg_f(zd_mac_dev(mac), "wrong mode %u\n", mode);
+ return -EINVAL;
+ }
+
+ ieee = zd_mac_to_ieee80211(mac);
+ ZD_ASSERT(!irqs_disabled());
+ spin_lock_irq(&ieee->lock);
+ ieee->iw_mode = mode;
+ spin_unlock_irq(&ieee->lock);
+
+ if (netif_running(mac->netdev))
+ return reset_mode(mac);
+
+ return 0;
+}
+
+int zd_mac_get_mode(struct zd_mac *mac, u32 *mode)
+{
+ unsigned long flags;
+ struct ieee80211_device *ieee;
+
+ ieee = zd_mac_to_ieee80211(mac);
+ spin_lock_irqsave(&ieee->lock, flags);
+ *mode = ieee->iw_mode;
+ spin_unlock_irqrestore(&ieee->lock, flags);
+ return 0;
+}
+
+int zd_mac_get_range(struct zd_mac *mac, struct iw_range *range)
+{
+ int i;
+ const struct channel_range *channel_range;
+ u8 regdomain;
+
+ memset(range, 0, sizeof(*range));
+
+ /* FIXME: Not so important and depends on the mode. For 802.11g
+ * usually this value is used. It seems to be that Bit/s number is
+ * given here.
+ */
+ range->throughput = 27 * 1000 * 1000;
+
+ range->max_qual.qual = 100;
+ range->max_qual.level = 100;
+
+ /* FIXME: Needs still to be tuned. */
+ range->avg_qual.qual = 71;
+ range->avg_qual.level = 80;
+
+ /* FIXME: depends on standard? */
+ range->min_rts = 256;
+ range->max_rts = 2346;
+
+ range->min_frag = MIN_FRAG_THRESHOLD;
+ range->max_frag = MAX_FRAG_THRESHOLD;
+
+ range->max_encoding_tokens = WEP_KEYS;
+ range->num_encoding_sizes = 2;
+ range->encoding_size[0] = 5;
+ range->encoding_size[1] = WEP_KEY_LEN;
+
+ range->we_version_compiled = WIRELESS_EXT;
+ range->we_version_source = 20;
+
+ ZD_ASSERT(!irqs_disabled());
+ spin_lock_irq(&mac->lock);
+ regdomain = mac->regdomain;
+ spin_unlock_irq(&mac->lock);
+ channel_range = zd_channel_range(regdomain);
+
+ range->num_channels = channel_range->end - channel_range->start;
+ range->old_num_channels = range->num_channels;
+ range->num_frequency = range->num_channels;
+ range->old_num_frequency = range->num_frequency;
+
+ for (i = 0; i < range->num_frequency; i++) {
+ struct iw_freq *freq = &range->freq[i];
+ freq->i = channel_range->start + i;
+ zd_channel_to_freq(freq, freq->i);
+ }
+
+ return 0;
+}
+
+static int zd_calc_tx_length_us(u8 *service, u8 cs_rate, u16 tx_length)
+{
+ static const u8 rate_divisor[] = {
+ [ZD_CS_CCK_RATE_1M] = 1,
+ [ZD_CS_CCK_RATE_2M] = 2,
+ [ZD_CS_CCK_RATE_5_5M] = 11, /* bits must be doubled */
+ [ZD_CS_CCK_RATE_11M] = 11,
+ [ZD_OFDM_RATE_6M] = 6,
+ [ZD_OFDM_RATE_9M] = 9,
+ [ZD_OFDM_RATE_12M] = 12,
+ [ZD_OFDM_RATE_18M] = 18,
+ [ZD_OFDM_RATE_24M] = 24,
+ [ZD_OFDM_RATE_36M] = 36,
+ [ZD_OFDM_RATE_48M] = 48,
+ [ZD_OFDM_RATE_54M] = 54,
+ };
+
+ u32 bits = (u32)tx_length * 8;
+ u32 divisor;
+
+ divisor = rate_divisor[cs_rate];
+ if (divisor == 0)
+ return -EINVAL;
+
+ switch (cs_rate) {
+ case ZD_CS_CCK_RATE_5_5M:
+ bits = (2*bits) + 10; /* round up to the next integer */
+ break;
+ case ZD_CS_CCK_RATE_11M:
+ if (service) {
+ u32 t = bits % 11;
+ *service &= ~ZD_PLCP_SERVICE_LENGTH_EXTENSION;
+ if (0 < t && t <= 3) {
+ *service |= ZD_PLCP_SERVICE_LENGTH_EXTENSION;
+ }
+ }
+ bits += 10; /* round up to the next integer */
+ break;
+ }
+
+ return bits/divisor;
+}
+
+enum {
+ R2M_SHORT_PREAMBLE = 0x01,
+ R2M_11A = 0x02,
+};
+
+static u8 cs_rate_to_modulation(u8 cs_rate, int flags)
+{
+ u8 modulation;
+
+ modulation = cs_typed_rate(cs_rate);
+ if (flags & R2M_SHORT_PREAMBLE) {
+ switch (ZD_CS_RATE(modulation)) {
+ case ZD_CS_CCK_RATE_2M:
+ case ZD_CS_CCK_RATE_5_5M:
+ case ZD_CS_CCK_RATE_11M:
+ modulation |= ZD_CS_CCK_PREA_SHORT;
+ return modulation;
+ }
+ }
+ if (flags & R2M_11A) {
+ if (ZD_CS_TYPE(modulation) == ZD_CS_OFDM)
+ modulation |= ZD_CS_OFDM_MODE_11A;
+ }
+ return modulation;
+}
+
+static void cs_set_modulation(struct zd_mac *mac, struct zd_ctrlset *cs,
+ struct ieee80211_hdr_4addr *hdr)
+{
+ struct ieee80211softmac_device *softmac = ieee80211_priv(mac->netdev);
+ u16 ftype = WLAN_FC_GET_TYPE(le16_to_cpu(hdr->frame_ctl));
+ u8 rate, cs_rate;
+ int is_mgt = (ftype == IEEE80211_FTYPE_MGMT) != 0;
+
+ /* FIXME: 802.11a? short preamble? */
+ rate = ieee80211softmac_suggest_txrate(softmac,
+ is_multicast_ether_addr(hdr->addr1), is_mgt);
+
+ cs_rate = rate_to_cs_rate(rate);
+ cs->modulation = cs_rate_to_modulation(cs_rate, 0);
+}
+
+static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
+ struct ieee80211_hdr_4addr *header)
+{
+ unsigned int tx_length = le16_to_cpu(cs->tx_length);
+ u16 fctl = le16_to_cpu(header->frame_ctl);
+ u16 ftype = WLAN_FC_GET_TYPE(fctl);
+ u16 stype = WLAN_FC_GET_STYPE(fctl);
+
+ /*
+ * CONTROL:
+ * - start at 0x00
+ * - if fragment 0, enable bit 0
+ * - if backoff needed, enable bit 0
+ * - if burst (backoff not needed) disable bit 0
+ * - if multicast, enable bit 1
+ * - if PS-POLL frame, enable bit 2
+ * - if in INDEPENDENT_BSS mode and zd1205_DestPowerSave, then enable
+ * bit 4 (FIXME: wtf)
+ * - if frag_len > RTS threshold, set bit 5 as long if it isnt
+ * multicast or mgt
+ * - if bit 5 is set, and we are in OFDM mode, unset bit 5 and set bit
+ * 7
+ */
+
+ cs->control = 0;
+
+ /* First fragment */
+ if (WLAN_GET_SEQ_FRAG(le16_to_cpu(header->seq_ctl)) == 0)
+ cs->control |= ZD_CS_NEED_RANDOM_BACKOFF;
+
+ /* Multicast */
+ if (is_multicast_ether_addr(header->addr1))
+ cs->control |= ZD_CS_MULTICAST;
+
+ /* PS-POLL */
+ if (stype == IEEE80211_STYPE_PSPOLL)
+ cs->control |= ZD_CS_PS_POLL_FRAME;
+
+ if (!is_multicast_ether_addr(header->addr1) &&
+ ftype != IEEE80211_FTYPE_MGMT &&
+ tx_length > zd_netdev_ieee80211(mac->netdev)->rts)
+ {
+ /* FIXME: check the logic */
+ if (ZD_CS_TYPE(cs->modulation) == ZD_CS_OFDM) {
+ /* 802.11g */
+ cs->control |= ZD_CS_SELF_CTS;
+ } else { /* 802.11b */
+ cs->control |= ZD_CS_RTS;
+ }
+ }
+
+ /* FIXME: Management frame? */
+}
+
+static int fill_ctrlset(struct zd_mac *mac,
+ struct ieee80211_txb *txb,
+ int frag_num)
+{
+ int r;
+ struct sk_buff *skb = txb->fragments[frag_num];
+ struct ieee80211_hdr_4addr *hdr =
+ (struct ieee80211_hdr_4addr *) skb->data;
+ unsigned int frag_len = skb->len + IEEE80211_FCS_LEN;
+ unsigned int next_frag_len;
+ unsigned int packet_length;
+ struct zd_ctrlset *cs = (struct zd_ctrlset *)
+ skb_push(skb, sizeof(struct zd_ctrlset));
+
+ if (frag_num+1 < txb->nr_frags) {
+ next_frag_len = txb->fragments[frag_num+1]->len +
+ IEEE80211_FCS_LEN;
+ } else {
+ next_frag_len = 0;
+ }
+ ZD_ASSERT(frag_len <= 0xffff);
+ ZD_ASSERT(next_frag_len <= 0xffff);
+
+ cs_set_modulation(mac, cs, hdr);
+
+ cs->tx_length = cpu_to_le16(frag_len);
+
+ cs_set_control(mac, cs, hdr);
+
+ packet_length = frag_len + sizeof(struct zd_ctrlset) + 10;
+ ZD_ASSERT(packet_length <= 0xffff);
+ /* ZD1211B: Computing the length difference this way, gives us
+ * flexibility to compute the packet length.
+ */
+ cs->packet_length = cpu_to_le16(mac->chip.is_zd1211b ?
+ packet_length - frag_len : packet_length);
+
+ /*
+ * CURRENT LENGTH:
+ * - transmit frame length in microseconds
+ * - seems to be derived from frame length
+ * - see Cal_Us_Service() in zdinlinef.h
+ * - if macp->bTxBurstEnable is enabled, then multiply by 4
+ * - bTxBurstEnable is never set in the vendor driver
+ *
+ * SERVICE:
+ * - "for PLCP configuration"
+ * - always 0 except in some situations at 802.11b 11M
+ * - see line 53 of zdinlinef.h
+ */
+ cs->service = 0;
+ r = zd_calc_tx_length_us(&cs->service, ZD_CS_RATE(cs->modulation),
+ le16_to_cpu(cs->tx_length));
+ if (r < 0)
+ return r;
+ cs->current_length = cpu_to_le16(r);
+
+ if (next_frag_len == 0) {
+ cs->next_frame_length = 0;
+ } else {
+ r = zd_calc_tx_length_us(NULL, ZD_CS_RATE(cs->modulation),
+ next_frag_len);
+ if (r < 0)
+ return r;
+ cs->next_frame_length = cpu_to_le16(r);
+ }
+
+ return 0;
+}
+
+static int zd_mac_tx(struct zd_mac *mac, struct ieee80211_txb *txb, int pri)
+{
+ int i, r;
+
+ for (i = 0; i < txb->nr_frags; i++) {
+ struct sk_buff *skb = txb->fragments[i];
+
+ r = fill_ctrlset(mac, txb, i);
+ if (r)
+ return r;
+ r = zd_usb_tx(&mac->chip.usb, skb->data, skb->len);
+ if (r)
+ return r;
+ }
+
+ /* FIXME: shouldn't this be handled by the upper layers? */
+ mac->netdev->trans_start = jiffies;
+
+ ieee80211_txb_free(txb);
+ return 0;
+}
+
+struct zd_rt_hdr {
+ struct ieee80211_radiotap_header rt_hdr;
+ u8 rt_flags;
+ u8 rt_rate;
+ u16 rt_channel;
+ u16 rt_chbitmask;
+} __attribute__((packed));
+
+static void fill_rt_header(void *buffer, struct zd_mac *mac,
+ const struct ieee80211_rx_stats *stats,
+ const struct rx_status *status)
+{
+ struct zd_rt_hdr *hdr = buffer;
+
+ hdr->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
+ hdr->rt_hdr.it_pad = 0;
+ hdr->rt_hdr.it_len = cpu_to_le16(sizeof(struct zd_rt_hdr));
+ hdr->rt_hdr.it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
+ (1 << IEEE80211_RADIOTAP_CHANNEL) |
+ (1 << IEEE80211_RADIOTAP_RATE));
+
+ hdr->rt_flags = 0;
+ if (status->decryption_type & (ZD_RX_WEP64|ZD_RX_WEP128|ZD_RX_WEP256))
+ hdr->rt_flags |= IEEE80211_RADIOTAP_F_WEP;
+
+ hdr->rt_rate = stats->rate / 5;
+
+ /* FIXME: 802.11a */
+ hdr->rt_channel = cpu_to_le16(ieee80211chan2mhz(
+ _zd_chip_get_channel(&mac->chip)));
+ hdr->rt_chbitmask = cpu_to_le16(IEEE80211_CHAN_2GHZ |
+ ((status->frame_status & ZD_RX_FRAME_MODULATION_MASK) ==
+ ZD_RX_OFDM ? IEEE80211_CHAN_OFDM : IEEE80211_CHAN_CCK));
+}
+
+/* Returns 1 if the data packet is for us and 0 otherwise. */
+static int is_data_packet_for_us(struct ieee80211_device *ieee,
+ struct ieee80211_hdr_4addr *hdr)
+{
+ struct net_device *netdev = ieee->dev;
+ u16 fc = le16_to_cpu(hdr->frame_ctl);
+
+ ZD_ASSERT(WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA);
+
+ switch (ieee->iw_mode) {
+ case IW_MODE_ADHOC:
+ if ((fc & (IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS)) != 0 ||
+ memcmp(hdr->addr3, ieee->bssid, ETH_ALEN) != 0)
+ return 0;
+ break;
+ case IW_MODE_AUTO:
+ case IW_MODE_INFRA:
+ if ((fc & (IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS)) !=
+ IEEE80211_FCTL_FROMDS ||
+ memcmp(hdr->addr2, ieee->bssid, ETH_ALEN) != 0)
+ return 0;
+ break;
+ default:
+ ZD_ASSERT(ieee->iw_mode != IW_MODE_MONITOR);
+ return 0;
+ }
+
+ return memcmp(hdr->addr1, netdev->dev_addr, ETH_ALEN) == 0 ||
+ is_multicast_ether_addr(hdr->addr1) ||
+ (netdev->flags & IFF_PROMISC);
+}
+
+/* Filters receiving packets. If it returns 1 send it to ieee80211_rx, if 0
+ * return. If an error is detected -EINVAL is returned. ieee80211_rx_mgt() is
+ * called here.
+ *
+ * It has been based on ieee80211_rx_any.
+ */
+static int filter_rx(struct ieee80211_device *ieee,
+ const u8 *buffer, unsigned int length,
+ struct ieee80211_rx_stats *stats)
+{
+ struct ieee80211_hdr_4addr *hdr;
+ u16 fc;
+
+ if (ieee->iw_mode == IW_MODE_MONITOR)
+ return 1;
+
+ hdr = (struct ieee80211_hdr_4addr *)buffer;
+ fc = le16_to_cpu(hdr->frame_ctl);
+ if ((fc & IEEE80211_FCTL_VERS) != 0)
+ return -EINVAL;
+
+ switch (WLAN_FC_GET_TYPE(fc)) {
+ case IEEE80211_FTYPE_MGMT:
+ if (length < sizeof(struct ieee80211_hdr_3addr))
+ return -EINVAL;
+ ieee80211_rx_mgt(ieee, hdr, stats);
+ return 0;
+ case IEEE80211_FTYPE_CTL:
+ /* Ignore invalid short buffers */
+ return 0;
+ case IEEE80211_FTYPE_DATA:
+ if (length < sizeof(struct ieee80211_hdr_3addr))
+ return -EINVAL;
+ return is_data_packet_for_us(ieee, hdr);
+ }
+
+ return -EINVAL;
+}
+
+static void update_qual_rssi(struct zd_mac *mac, u8 qual_percent, u8 rssi)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mac->lock, flags);
+ mac->qual_average = (7 * mac->qual_average + qual_percent) / 8;
+ mac->rssi_average = (7 * mac->rssi_average + rssi) / 8;
+ spin_unlock_irqrestore(&mac->lock, flags);
+}
+
+static int fill_rx_stats(struct ieee80211_rx_stats *stats,
+ const struct rx_status **pstatus,
+ struct zd_mac *mac,
+ const u8 *buffer, unsigned int length)
+{
+ const struct rx_status *status;
+
+ *pstatus = status = zd_tail(buffer, length, sizeof(struct rx_status));
+ if (status->frame_status & ZD_RX_ERROR) {
+ /* FIXME: update? */
+ return -EINVAL;
+ }
+ memset(stats, 0, sizeof(struct ieee80211_rx_stats));
+ stats->len = length - (ZD_PLCP_HEADER_SIZE + IEEE80211_FCS_LEN +
+ + sizeof(struct rx_status));
+ /* FIXME: 802.11a */
+ stats->freq = IEEE80211_24GHZ_BAND;
+ stats->received_channel = _zd_chip_get_channel(&mac->chip);
+ stats->rssi = zd_rx_strength_percent(status->signal_strength);
+ stats->signal = zd_rx_qual_percent(buffer,
+ length - sizeof(struct rx_status),
+ status);
+ stats->mask = IEEE80211_STATMASK_RSSI | IEEE80211_STATMASK_SIGNAL;
+ stats->rate = zd_rx_rate(buffer, status);
+ if (stats->rate)
+ stats->mask |= IEEE80211_STATMASK_RATE;
+
+ update_qual_rssi(mac, stats->signal, stats->rssi);
+ return 0;
+}
+
+int zd_mac_rx(struct zd_mac *mac, const u8 *buffer, unsigned int length)
+{
+ int r;
+ struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+ struct ieee80211_rx_stats stats;
+ const struct rx_status *status;
+ struct sk_buff *skb;
+
+ if (length < ZD_PLCP_HEADER_SIZE + IEEE80211_1ADDR_LEN +
+ IEEE80211_FCS_LEN + sizeof(struct rx_status))
+ return -EINVAL;
+
+ r = fill_rx_stats(&stats, &status, mac, buffer, length);
+ if (r)
+ return r;
+
+ length -= ZD_PLCP_HEADER_SIZE+IEEE80211_FCS_LEN+
+ sizeof(struct rx_status);
+ buffer += ZD_PLCP_HEADER_SIZE;
+
+ r = filter_rx(ieee, buffer, length, &stats);
+ if (r <= 0)
+ return r;
+
+ skb = dev_alloc_skb(sizeof(struct zd_rt_hdr) + length);
+ if (!skb)
+ return -ENOMEM;
+ if (ieee->iw_mode == IW_MODE_MONITOR)
+ fill_rt_header(skb_put(skb, sizeof(struct zd_rt_hdr)), mac,
+ &stats, status);
+ memcpy(skb_put(skb, length), buffer, length);
+
+ r = ieee80211_rx(ieee, skb, &stats);
+ if (!r) {
+ ZD_ASSERT(in_irq());
+ dev_kfree_skb_irq(skb);
+ }
+ return 0;
+}
+
+static int netdev_tx(struct ieee80211_txb *txb, struct net_device *netdev,
+ int pri)
+{
+ return zd_mac_tx(zd_netdev_mac(netdev), txb, pri);
+}
+
+static void set_security(struct net_device *netdev,
+ struct ieee80211_security *sec)
+{
+ struct ieee80211_device *ieee = zd_netdev_ieee80211(netdev);
+ struct ieee80211_security *secinfo = &ieee->sec;
+ int keyidx;
+
+ dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)), "\n");
+
+ for (keyidx = 0; keyidx<WEP_KEYS; keyidx++)
+ if (sec->flags & (1<<keyidx)) {
+ secinfo->encode_alg[keyidx] = sec->encode_alg[keyidx];
+ secinfo->key_sizes[keyidx] = sec->key_sizes[keyidx];
+ memcpy(secinfo->keys[keyidx], sec->keys[keyidx],
+ SCM_KEY_LEN);
+ }
+
+ if (sec->flags & SEC_ACTIVE_KEY) {
+ secinfo->active_key = sec->active_key;
+ dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)),
+ " .active_key = %d\n", sec->active_key);
+ }
+ if (sec->flags & SEC_UNICAST_GROUP) {
+ secinfo->unicast_uses_group = sec->unicast_uses_group;
+ dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)),
+ " .unicast_uses_group = %d\n",
+ sec->unicast_uses_group);
+ }
+ if (sec->flags & SEC_LEVEL) {
+ secinfo->level = sec->level;
+ dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)),
+ " .level = %d\n", sec->level);
+ }
+ if (sec->flags & SEC_ENABLED) {
+ secinfo->enabled = sec->enabled;
+ dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)),
+ " .enabled = %d\n", sec->enabled);
+ }
+ if (sec->flags & SEC_ENCRYPT) {
+ secinfo->encrypt = sec->encrypt;
+ dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)),
+ " .encrypt = %d\n", sec->encrypt);
+ }
+ if (sec->flags & SEC_AUTH_MODE) {
+ secinfo->auth_mode = sec->auth_mode;
+ dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)),
+ " .auth_mode = %d\n", sec->auth_mode);
+ }
+}
+
+static void ieee_init(struct ieee80211_device *ieee)
+{
+ ieee->mode = IEEE_B | IEEE_G;
+ ieee->freq_band = IEEE80211_24GHZ_BAND;
+ ieee->modulation = IEEE80211_OFDM_MODULATION | IEEE80211_CCK_MODULATION;
+ ieee->tx_headroom = sizeof(struct zd_ctrlset);
+ ieee->set_security = set_security;
+ ieee->hard_start_xmit = netdev_tx;
+
+ /* Software encryption/decryption for now */
+ ieee->host_build_iv = 0;
+ ieee->host_encrypt = 1;
+ ieee->host_decrypt = 1;
+
+ /* FIXME: default to managed mode, until ieee80211 and zd1211rw can
+ * correctly support AUTO */
+ ieee->iw_mode = IW_MODE_INFRA;
+}
+
+static void softmac_init(struct ieee80211softmac_device *sm)
+{
+ sm->set_channel = set_channel;
+}
+
+struct iw_statistics *zd_mac_get_wireless_stats(struct net_device *ndev)
+{
+ struct zd_mac *mac = zd_netdev_mac(ndev);
+ struct iw_statistics *iw_stats = &mac->iw_stats;
+
+ memset(iw_stats, 0, sizeof(struct iw_statistics));
+ /* We are not setting the status, because ieee->state is not updated
+ * at all and this driver doesn't track authentication state.
+ */
+ spin_lock_irq(&mac->lock);
+ iw_stats->qual.qual = mac->qual_average;
+ iw_stats->qual.level = mac->rssi_average;
+ iw_stats->qual.updated = IW_QUAL_QUAL_UPDATED|IW_QUAL_LEVEL_UPDATED|
+ IW_QUAL_NOISE_INVALID;
+ spin_unlock_irq(&mac->lock);
+ /* TODO: update counter */
+ return iw_stats;
+}
+
+#ifdef DEBUG
+static const char* decryption_types[] = {
+ [ZD_RX_NO_WEP] = "none",
+ [ZD_RX_WEP64] = "WEP64",
+ [ZD_RX_TKIP] = "TKIP",
+ [ZD_RX_AES] = "AES",
+ [ZD_RX_WEP128] = "WEP128",
+ [ZD_RX_WEP256] = "WEP256",
+};
+
+static const char *decryption_type_string(u8 type)
+{
+ const char *s;
+
+ if (type < ARRAY_SIZE(decryption_types)) {
+ s = decryption_types[type];
+ } else {
+ s = NULL;
+ }
+ return s ? s : "unknown";
+}
+
+static int is_ofdm(u8 frame_status)
+{
+ return (frame_status & ZD_RX_OFDM);
+}
+
+void zd_dump_rx_status(const struct rx_status *status)
+{
+ const char* modulation;
+ u8 quality;
+
+ if (is_ofdm(status->frame_status)) {
+ modulation = "ofdm";
+ quality = status->signal_quality_ofdm;
+ } else {
+ modulation = "cck";
+ quality = status->signal_quality_cck;
+ }
+ pr_debug("rx status %s strength %#04x qual %#04x decryption %s\n",
+ modulation, status->signal_strength, quality,
+ decryption_type_string(status->decryption_type));
+ if (status->frame_status & ZD_RX_ERROR) {
+ pr_debug("rx error %s%s%s%s%s%s\n",
+ (status->frame_status & ZD_RX_TIMEOUT_ERROR) ?
+ "timeout " : "",
+ (status->frame_status & ZD_RX_FIFO_OVERRUN_ERROR) ?
+ "fifo " : "",
+ (status->frame_status & ZD_RX_DECRYPTION_ERROR) ?
+ "decryption " : "",
+ (status->frame_status & ZD_RX_CRC32_ERROR) ?
+ "crc32 " : "",
+ (status->frame_status & ZD_RX_NO_ADDR1_MATCH_ERROR) ?
+ "addr1 " : "",
+ (status->frame_status & ZD_RX_CRC16_ERROR) ?
+ "crc16" : "");
+ }
+}
+#endif /* DEBUG */
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h
new file mode 100644
index 00000000000..71e382c589e
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_mac.h
@@ -0,0 +1,190 @@
+/* zd_mac.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _ZD_MAC_H
+#define _ZD_MAC_H
+
+#include <linux/wireless.h>
+#include <linux/kernel.h>
+#include <net/ieee80211.h>
+#include <net/ieee80211softmac.h>
+
+#include "zd_chip.h"
+#include "zd_netdev.h"
+
+struct zd_ctrlset {
+ u8 modulation;
+ __le16 tx_length;
+ u8 control;
+ /* stores only the difference to tx_length on ZD1211B */
+ __le16 packet_length;
+ __le16 current_length;
+ u8 service;
+ __le16 next_frame_length;
+} __attribute__((packed));
+
+#define ZD_CS_RESERVED_SIZE 25
+
+/* zd_crtlset field modulation */
+#define ZD_CS_RATE_MASK 0x0f
+#define ZD_CS_TYPE_MASK 0x10
+#define ZD_CS_RATE(modulation) ((modulation) & ZD_CS_RATE_MASK)
+#define ZD_CS_TYPE(modulation) ((modulation) & ZD_CS_TYPE_MASK)
+
+#define ZD_CS_CCK 0x00
+#define ZD_CS_OFDM 0x10
+
+#define ZD_CS_CCK_RATE_1M 0x00
+#define ZD_CS_CCK_RATE_2M 0x01
+#define ZD_CS_CCK_RATE_5_5M 0x02
+#define ZD_CS_CCK_RATE_11M 0x03
+/* The rates for OFDM are encoded as in the PLCP header. Use ZD_OFDM_RATE_*.
+ */
+
+/* bit 5 is preamble (when in CCK mode), or a/g selection (when in OFDM mode) */
+#define ZD_CS_CCK_PREA_LONG 0x00
+#define ZD_CS_CCK_PREA_SHORT 0x20
+#define ZD_CS_OFDM_MODE_11G 0x00
+#define ZD_CS_OFDM_MODE_11A 0x20
+
+/* zd_ctrlset control field */
+#define ZD_CS_NEED_RANDOM_BACKOFF 0x01
+#define ZD_CS_MULTICAST 0x02
+
+#define ZD_CS_FRAME_TYPE_MASK 0x0c
+#define ZD_CS_DATA_FRAME 0x00
+#define ZD_CS_PS_POLL_FRAME 0x04
+#define ZD_CS_MANAGEMENT_FRAME 0x08
+#define ZD_CS_NO_SEQUENCE_CTL_FRAME 0x0c
+
+#define ZD_CS_WAKE_DESTINATION 0x10
+#define ZD_CS_RTS 0x20
+#define ZD_CS_ENCRYPT 0x40
+#define ZD_CS_SELF_CTS 0x80
+
+/* Incoming frames are prepended by a PLCP header */
+#define ZD_PLCP_HEADER_SIZE 5
+
+struct rx_length_info {
+ __le16 length[3];
+ __le16 tag;
+} __attribute__((packed));
+
+#define RX_LENGTH_INFO_TAG 0x697e
+
+struct rx_status {
+ /* rssi */
+ u8 signal_strength;
+ u8 signal_quality_cck;
+ u8 signal_quality_ofdm;
+ u8 decryption_type;
+ u8 frame_status;
+} __attribute__((packed));
+
+/* rx_status field decryption_type */
+#define ZD_RX_NO_WEP 0
+#define ZD_RX_WEP64 1
+#define ZD_RX_TKIP 2
+#define ZD_RX_AES 4
+#define ZD_RX_WEP128 5
+#define ZD_RX_WEP256 6
+
+/* rx_status field frame_status */
+#define ZD_RX_FRAME_MODULATION_MASK 0x01
+#define ZD_RX_CCK 0x00
+#define ZD_RX_OFDM 0x01
+
+#define ZD_RX_TIMEOUT_ERROR 0x02
+#define ZD_RX_FIFO_OVERRUN_ERROR 0x04
+#define ZD_RX_DECRYPTION_ERROR 0x08
+#define ZD_RX_CRC32_ERROR 0x10
+#define ZD_RX_NO_ADDR1_MATCH_ERROR 0x20
+#define ZD_RX_CRC16_ERROR 0x40
+#define ZD_RX_ERROR 0x80
+
+enum mac_flags {
+ MAC_FIXED_CHANNEL = 0x01,
+};
+
+struct zd_mac {
+ struct net_device *netdev;
+ struct zd_chip chip;
+ spinlock_t lock;
+ /* Unlocked reading possible */
+ struct iw_statistics iw_stats;
+ u8 qual_average;
+ u8 rssi_average;
+ u8 regdomain;
+ u8 default_regdomain;
+ u8 requested_channel;
+};
+
+static inline struct ieee80211_device *zd_mac_to_ieee80211(struct zd_mac *mac)
+{
+ return zd_netdev_ieee80211(mac->netdev);
+}
+
+static inline struct zd_mac *zd_netdev_mac(struct net_device *netdev)
+{
+ return ieee80211softmac_priv(netdev);
+}
+
+static inline struct zd_mac *zd_chip_to_mac(struct zd_chip *chip)
+{
+ return container_of(chip, struct zd_mac, chip);
+}
+
+static inline struct zd_mac *zd_usb_to_mac(struct zd_usb *usb)
+{
+ return zd_chip_to_mac(zd_usb_to_chip(usb));
+}
+
+#define zd_mac_dev(mac) (zd_chip_dev(&(mac)->chip))
+
+int zd_mac_init(struct zd_mac *mac,
+ struct net_device *netdev,
+ struct usb_interface *intf);
+void zd_mac_clear(struct zd_mac *mac);
+
+int zd_mac_init_hw(struct zd_mac *mac, u8 device_type);
+
+int zd_mac_open(struct net_device *netdev);
+int zd_mac_stop(struct net_device *netdev);
+int zd_mac_set_mac_address(struct net_device *dev, void *p);
+
+int zd_mac_rx(struct zd_mac *mac, const u8 *buffer, unsigned int length);
+
+int zd_mac_set_regdomain(struct zd_mac *zd_mac, u8 regdomain);
+u8 zd_mac_get_regdomain(struct zd_mac *zd_mac);
+
+int zd_mac_request_channel(struct zd_mac *mac, u8 channel);
+int zd_mac_get_channel(struct zd_mac *mac, u8 *channel, u8 *flags);
+
+int zd_mac_set_mode(struct zd_mac *mac, u32 mode);
+int zd_mac_get_mode(struct zd_mac *mac, u32 *mode);
+
+int zd_mac_get_range(struct zd_mac *mac, struct iw_range *range);
+
+struct iw_statistics *zd_mac_get_wireless_stats(struct net_device *ndev);
+
+#ifdef DEBUG
+void zd_dump_rx_status(const struct rx_status *status);
+#else
+#define zd_dump_rx_status(status)
+#endif /* DEBUG */
+
+#endif /* _ZD_MAC_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_netdev.c b/drivers/net/wireless/zd1211rw/zd_netdev.c
new file mode 100644
index 00000000000..9df232c2c86
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_netdev.c
@@ -0,0 +1,267 @@
+/* zd_netdev.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <net/ieee80211.h>
+#include <net/ieee80211softmac.h>
+#include <net/ieee80211softmac_wx.h>
+#include <net/iw_handler.h>
+
+#include "zd_def.h"
+#include "zd_netdev.h"
+#include "zd_mac.h"
+#include "zd_ieee80211.h"
+
+/* Region 0 means reset regdomain to default. */
+static int zd_set_regdomain(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *req, char *extra)
+{
+ const u8 *regdomain = (u8 *)req;
+ return zd_mac_set_regdomain(zd_netdev_mac(netdev), *regdomain);
+}
+
+static int zd_get_regdomain(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *req, char *extra)
+{
+ u8 *regdomain = (u8 *)req;
+ if (!regdomain)
+ return -EINVAL;
+ *regdomain = zd_mac_get_regdomain(zd_netdev_mac(netdev));
+ return 0;
+}
+
+static const struct iw_priv_args zd_priv_args[] = {
+ {
+ .cmd = ZD_PRIV_SET_REGDOMAIN,
+ .set_args = IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
+ .name = "set_regdomain",
+ },
+ {
+ .cmd = ZD_PRIV_GET_REGDOMAIN,
+ .get_args = IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
+ .name = "get_regdomain",
+ },
+};
+
+#define PRIV_OFFSET(x) [(x)-SIOCIWFIRSTPRIV]
+
+static const iw_handler zd_priv_handler[] = {
+ PRIV_OFFSET(ZD_PRIV_SET_REGDOMAIN) = zd_set_regdomain,
+ PRIV_OFFSET(ZD_PRIV_GET_REGDOMAIN) = zd_get_regdomain,
+};
+
+static int iw_get_name(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *req, char *extra)
+{
+ /* FIXME: check whether 802.11a will also supported, add also
+ * zd1211B, if we support it.
+ */
+ strlcpy(req->name, "802.11g zd1211", IFNAMSIZ);
+ return 0;
+}
+
+static int iw_set_freq(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *req, char *extra)
+{
+ int r;
+ struct zd_mac *mac = zd_netdev_mac(netdev);
+ struct iw_freq *freq = &req->freq;
+ u8 channel;
+
+ r = zd_find_channel(&channel, freq);
+ if (r < 0)
+ return r;
+ r = zd_mac_request_channel(mac, channel);
+ return r;
+}
+
+static int iw_get_freq(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *req, char *extra)
+{
+ int r;
+ struct zd_mac *mac = zd_netdev_mac(netdev);
+ struct iw_freq *freq = &req->freq;
+ u8 channel;
+ u8 flags;
+
+ r = zd_mac_get_channel(mac, &channel, &flags);
+ if (r)
+ return r;
+
+ freq->flags = (flags & MAC_FIXED_CHANNEL) ?
+ IW_FREQ_FIXED : IW_FREQ_AUTO;
+ dev_dbg_f(zd_mac_dev(mac), "channel %s\n",
+ (flags & MAC_FIXED_CHANNEL) ? "fixed" : "auto");
+ return zd_channel_to_freq(freq, channel);
+}
+
+static int iw_set_mode(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *req, char *extra)
+{
+ return zd_mac_set_mode(zd_netdev_mac(netdev), req->mode);
+}
+
+static int iw_get_mode(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *req, char *extra)
+{
+ return zd_mac_get_mode(zd_netdev_mac(netdev), &req->mode);
+}
+
+static int iw_get_range(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *req, char *extra)
+{
+ struct iw_range *range = (struct iw_range *)extra;
+
+ dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)), "\n");
+ req->data.length = sizeof(*range);
+ return zd_mac_get_range(zd_netdev_mac(netdev), range);
+}
+
+static int iw_set_encode(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *data,
+ char *extra)
+{
+ return ieee80211_wx_set_encode(zd_netdev_ieee80211(netdev), info,
+ data, extra);
+}
+
+static int iw_get_encode(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *data,
+ char *extra)
+{
+ return ieee80211_wx_get_encode(zd_netdev_ieee80211(netdev), info,
+ data, extra);
+}
+
+static int iw_set_encodeext(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *data,
+ char *extra)
+{
+ return ieee80211_wx_set_encodeext(zd_netdev_ieee80211(netdev), info,
+ data, extra);
+}
+
+static int iw_get_encodeext(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *data,
+ char *extra)
+{
+ return ieee80211_wx_get_encodeext(zd_netdev_ieee80211(netdev), info,
+ data, extra);
+}
+
+#define WX(x) [(x)-SIOCIWFIRST]
+
+static const iw_handler zd_standard_iw_handlers[] = {
+ WX(SIOCGIWNAME) = iw_get_name,
+ WX(SIOCSIWFREQ) = iw_set_freq,
+ WX(SIOCGIWFREQ) = iw_get_freq,
+ WX(SIOCSIWMODE) = iw_set_mode,
+ WX(SIOCGIWMODE) = iw_get_mode,
+ WX(SIOCGIWRANGE) = iw_get_range,
+ WX(SIOCSIWENCODE) = iw_set_encode,
+ WX(SIOCGIWENCODE) = iw_get_encode,
+ WX(SIOCSIWENCODEEXT) = iw_set_encodeext,
+ WX(SIOCGIWENCODEEXT) = iw_get_encodeext,
+ WX(SIOCSIWAUTH) = ieee80211_wx_set_auth,
+ WX(SIOCGIWAUTH) = ieee80211_wx_get_auth,
+ WX(SIOCSIWSCAN) = ieee80211softmac_wx_trigger_scan,
+ WX(SIOCGIWSCAN) = ieee80211softmac_wx_get_scan_results,
+ WX(SIOCSIWESSID) = ieee80211softmac_wx_set_essid,
+ WX(SIOCGIWESSID) = ieee80211softmac_wx_get_essid,
+ WX(SIOCSIWAP) = ieee80211softmac_wx_set_wap,
+ WX(SIOCGIWAP) = ieee80211softmac_wx_get_wap,
+ WX(SIOCSIWRATE) = ieee80211softmac_wx_set_rate,
+ WX(SIOCGIWRATE) = ieee80211softmac_wx_get_rate,
+ WX(SIOCSIWGENIE) = ieee80211softmac_wx_set_genie,
+ WX(SIOCGIWGENIE) = ieee80211softmac_wx_get_genie,
+ WX(SIOCSIWMLME) = ieee80211softmac_wx_set_mlme,
+};
+
+static const struct iw_handler_def iw_handler_def = {
+ .standard = zd_standard_iw_handlers,
+ .num_standard = ARRAY_SIZE(zd_standard_iw_handlers),
+ .private = zd_priv_handler,
+ .num_private = ARRAY_SIZE(zd_priv_handler),
+ .private_args = zd_priv_args,
+ .num_private_args = ARRAY_SIZE(zd_priv_args),
+ .get_wireless_stats = zd_mac_get_wireless_stats,
+};
+
+struct net_device *zd_netdev_alloc(struct usb_interface *intf)
+{
+ int r;
+ struct net_device *netdev;
+ struct zd_mac *mac;
+
+ netdev = alloc_ieee80211softmac(sizeof(struct zd_mac));
+ if (!netdev) {
+ dev_dbg_f(&intf->dev, "out of memory\n");
+ return NULL;
+ }
+
+ mac = zd_netdev_mac(netdev);
+ r = zd_mac_init(mac, netdev, intf);
+ if (r) {
+ usb_set_intfdata(intf, NULL);
+ free_ieee80211(netdev);
+ return NULL;
+ }
+
+ SET_MODULE_OWNER(netdev);
+ SET_NETDEV_DEV(netdev, &intf->dev);
+
+ dev_dbg_f(&intf->dev, "netdev->flags %#06hx\n", netdev->flags);
+ dev_dbg_f(&intf->dev, "netdev->features %#010lx\n", netdev->features);
+
+ netdev->open = zd_mac_open;
+ netdev->stop = zd_mac_stop;
+ /* netdev->get_stats = */
+ /* netdev->set_multicast_list = */
+ netdev->set_mac_address = zd_mac_set_mac_address;
+ netdev->wireless_handlers = &iw_handler_def;
+ /* netdev->ethtool_ops = */
+
+ return netdev;
+}
+
+void zd_netdev_free(struct net_device *netdev)
+{
+ if (!netdev)
+ return;
+
+ zd_mac_clear(zd_netdev_mac(netdev));
+ free_ieee80211(netdev);
+}
+
+void zd_netdev_disconnect(struct net_device *netdev)
+{
+ unregister_netdev(netdev);
+}
diff --git a/drivers/net/wireless/zd1211rw/zd_netdev.h b/drivers/net/wireless/zd1211rw/zd_netdev.h
new file mode 100644
index 00000000000..374a957073c
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_netdev.h
@@ -0,0 +1,45 @@
+/* zd_netdev.h: Header for net device related functions.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _ZD_NETDEV_H
+#define _ZD_NETDEV_H
+
+#include <linux/usb.h>
+#include <linux/netdevice.h>
+#include <net/ieee80211.h>
+
+#define ZD_PRIV_SET_REGDOMAIN (SIOCIWFIRSTPRIV)
+#define ZD_PRIV_GET_REGDOMAIN (SIOCIWFIRSTPRIV+1)
+
+static inline struct ieee80211_device *zd_netdev_ieee80211(
+ struct net_device *ndev)
+{
+ return netdev_priv(ndev);
+}
+
+static inline struct net_device *zd_ieee80211_to_netdev(
+ struct ieee80211_device *ieee)
+{
+ return ieee->dev;
+}
+
+struct net_device *zd_netdev_alloc(struct usb_interface *intf);
+void zd_netdev_free(struct net_device *netdev);
+
+void zd_netdev_disconnect(struct net_device *netdev);
+
+#endif /* _ZD_NETDEV_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.c b/drivers/net/wireless/zd1211rw/zd_rf.c
new file mode 100644
index 00000000000..d3770d2c61b
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_rf.c
@@ -0,0 +1,151 @@
+/* zd_rf.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/errno.h>
+#include <linux/string.h>
+
+#include "zd_def.h"
+#include "zd_rf.h"
+#include "zd_ieee80211.h"
+#include "zd_chip.h"
+
+static const char *rfs[] = {
+ [0] = "unknown RF0",
+ [1] = "unknown RF1",
+ [UW2451_RF] = "UW2451_RF",
+ [UCHIP_RF] = "UCHIP_RF",
+ [AL2230_RF] = "AL2230_RF",
+ [AL7230B_RF] = "AL7230B_RF",
+ [THETA_RF] = "THETA_RF",
+ [AL2210_RF] = "AL2210_RF",
+ [MAXIM_NEW_RF] = "MAXIM_NEW_RF",
+ [UW2453_RF] = "UW2453_RF",
+ [AL2230S_RF] = "AL2230S_RF",
+ [RALINK_RF] = "RALINK_RF",
+ [INTERSIL_RF] = "INTERSIL_RF",
+ [RF2959_RF] = "RF2959_RF",
+ [MAXIM_NEW2_RF] = "MAXIM_NEW2_RF",
+ [PHILIPS_RF] = "PHILIPS_RF",
+};
+
+const char *zd_rf_name(u8 type)
+{
+ if (type & 0xf0)
+ type = 0;
+ return rfs[type];
+}
+
+void zd_rf_init(struct zd_rf *rf)
+{
+ memset(rf, 0, sizeof(*rf));
+}
+
+void zd_rf_clear(struct zd_rf *rf)
+{
+ memset(rf, 0, sizeof(*rf));
+}
+
+int zd_rf_init_hw(struct zd_rf *rf, u8 type)
+{
+ int r, t;
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ switch (type) {
+ case RF2959_RF:
+ r = zd_rf_init_rf2959(rf);
+ if (r)
+ return r;
+ break;
+ case AL2230_RF:
+ r = zd_rf_init_al2230(rf);
+ if (r)
+ return r;
+ break;
+ default:
+ dev_err(zd_chip_dev(chip),
+ "RF %s %#x is not supported\n", zd_rf_name(type), type);
+ rf->type = 0;
+ return -ENODEV;
+ }
+
+ rf->type = type;
+
+ r = zd_chip_lock_phy_regs(chip);
+ if (r)
+ return r;
+ t = rf->init_hw(rf);
+ r = zd_chip_unlock_phy_regs(chip);
+ if (t)
+ r = t;
+ return r;
+}
+
+int zd_rf_scnprint_id(struct zd_rf *rf, char *buffer, size_t size)
+{
+ return scnprintf(buffer, size, "%s", zd_rf_name(rf->type));
+}
+
+int zd_rf_set_channel(struct zd_rf *rf, u8 channel)
+{
+ int r;
+
+ ZD_ASSERT(mutex_is_locked(&zd_rf_to_chip(rf)->mutex));
+ if (channel < MIN_CHANNEL24)
+ return -EINVAL;
+ if (channel > MAX_CHANNEL24)
+ return -EINVAL;
+ dev_dbg_f(zd_chip_dev(zd_rf_to_chip(rf)), "channel: %d\n", channel);
+
+ r = rf->set_channel(rf, channel);
+ if (r >= 0)
+ rf->channel = channel;
+ return r;
+}
+
+int zd_switch_radio_on(struct zd_rf *rf)
+{
+ int r, t;
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ r = zd_chip_lock_phy_regs(chip);
+ if (r)
+ return r;
+ t = rf->switch_radio_on(rf);
+ r = zd_chip_unlock_phy_regs(chip);
+ if (t)
+ r = t;
+ return r;
+}
+
+int zd_switch_radio_off(struct zd_rf *rf)
+{
+ int r, t;
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ /* TODO: move phy regs handling to zd_chip */
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ r = zd_chip_lock_phy_regs(chip);
+ if (r)
+ return r;
+ t = rf->switch_radio_off(rf);
+ r = zd_chip_unlock_phy_regs(chip);
+ if (t)
+ r = t;
+ return r;
+}
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.h b/drivers/net/wireless/zd1211rw/zd_rf.h
new file mode 100644
index 00000000000..ea30f693fcc
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_rf.h
@@ -0,0 +1,82 @@
+/* zd_rf.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _ZD_RF_H
+#define _ZD_RF_H
+
+#include "zd_types.h"
+
+#define UW2451_RF 0x2
+#define UCHIP_RF 0x3
+#define AL2230_RF 0x4
+#define AL7230B_RF 0x5 /* a,b,g */
+#define THETA_RF 0x6
+#define AL2210_RF 0x7
+#define MAXIM_NEW_RF 0x8
+#define UW2453_RF 0x9
+#define AL2230S_RF 0xa
+#define RALINK_RF 0xb
+#define INTERSIL_RF 0xc
+#define RF2959_RF 0xd
+#define MAXIM_NEW2_RF 0xe
+#define PHILIPS_RF 0xf
+
+#define RF_CHANNEL(ch) [(ch)-1]
+
+/* Provides functions of the RF transceiver. */
+
+enum {
+ RF_REG_BITS = 6,
+ RF_VALUE_BITS = 18,
+ RF_RV_BITS = RF_REG_BITS + RF_VALUE_BITS,
+};
+
+struct zd_rf {
+ u8 type;
+
+ u8 channel;
+ /*
+ * Whether this RF should patch the 6M band edge
+ * (assuming E2P_POD agrees)
+ */
+ u8 patch_6m_band_edge:1;
+
+ /* RF-specific functions */
+ int (*init_hw)(struct zd_rf *rf);
+ int (*set_channel)(struct zd_rf *rf, u8 channel);
+ int (*switch_radio_on)(struct zd_rf *rf);
+ int (*switch_radio_off)(struct zd_rf *rf);
+};
+
+const char *zd_rf_name(u8 type);
+void zd_rf_init(struct zd_rf *rf);
+void zd_rf_clear(struct zd_rf *rf);
+int zd_rf_init_hw(struct zd_rf *rf, u8 type);
+
+int zd_rf_scnprint_id(struct zd_rf *rf, char *buffer, size_t size);
+
+int zd_rf_set_channel(struct zd_rf *rf, u8 channel);
+
+int zd_switch_radio_on(struct zd_rf *rf);
+int zd_switch_radio_off(struct zd_rf *rf);
+
+/* Functions for individual RF chips */
+
+int zd_rf_init_rf2959(struct zd_rf *rf);
+int zd_rf_init_al2230(struct zd_rf *rf);
+
+#endif /* _ZD_RF_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
new file mode 100644
index 00000000000..0948b25f660
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
@@ -0,0 +1,308 @@
+/* zd_rf_al2230.c: Functions for the AL2230 RF controller
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+
+#include "zd_rf.h"
+#include "zd_usb.h"
+#include "zd_chip.h"
+
+static const u32 al2230_table[][3] = {
+ RF_CHANNEL( 1) = { 0x03f790, 0x033331, 0x00000d, },
+ RF_CHANNEL( 2) = { 0x03f790, 0x0b3331, 0x00000d, },
+ RF_CHANNEL( 3) = { 0x03e790, 0x033331, 0x00000d, },
+ RF_CHANNEL( 4) = { 0x03e790, 0x0b3331, 0x00000d, },
+ RF_CHANNEL( 5) = { 0x03f7a0, 0x033331, 0x00000d, },
+ RF_CHANNEL( 6) = { 0x03f7a0, 0x0b3331, 0x00000d, },
+ RF_CHANNEL( 7) = { 0x03e7a0, 0x033331, 0x00000d, },
+ RF_CHANNEL( 8) = { 0x03e7a0, 0x0b3331, 0x00000d, },
+ RF_CHANNEL( 9) = { 0x03f7b0, 0x033331, 0x00000d, },
+ RF_CHANNEL(10) = { 0x03f7b0, 0x0b3331, 0x00000d, },
+ RF_CHANNEL(11) = { 0x03e7b0, 0x033331, 0x00000d, },
+ RF_CHANNEL(12) = { 0x03e7b0, 0x0b3331, 0x00000d, },
+ RF_CHANNEL(13) = { 0x03f7c0, 0x033331, 0x00000d, },
+ RF_CHANNEL(14) = { 0x03e7c0, 0x066661, 0x00000d, },
+};
+
+static int zd1211_al2230_init_hw(struct zd_rf *rf)
+{
+ int r;
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR15, 0x20 }, { CR23, 0x40 }, { CR24, 0x20 },
+ { CR26, 0x11 }, { CR28, 0x3e }, { CR29, 0x00 },
+ { CR44, 0x33 }, { CR106, 0x2a }, { CR107, 0x1a },
+ { CR109, 0x09 }, { CR110, 0x27 }, { CR111, 0x2b },
+ { CR112, 0x2b }, { CR119, 0x0a }, { CR10, 0x89 },
+ /* for newest (3rd cut) AL2300 */
+ { CR17, 0x28 },
+ { CR26, 0x93 }, { CR34, 0x30 },
+ /* for newest (3rd cut) AL2300 */
+ { CR35, 0x3e },
+ { CR41, 0x24 }, { CR44, 0x32 },
+ /* for newest (3rd cut) AL2300 */
+ { CR46, 0x96 },
+ { CR47, 0x1e }, { CR79, 0x58 }, { CR80, 0x30 },
+ { CR81, 0x30 }, { CR87, 0x0a }, { CR89, 0x04 },
+ { CR92, 0x0a }, { CR99, 0x28 }, { CR100, 0x00 },
+ { CR101, 0x13 }, { CR102, 0x27 }, { CR106, 0x24 },
+ { CR107, 0x2a }, { CR109, 0x09 }, { CR110, 0x13 },
+ { CR111, 0x1f }, { CR112, 0x1f }, { CR113, 0x27 },
+ { CR114, 0x27 },
+ /* for newest (3rd cut) AL2300 */
+ { CR115, 0x24 },
+ { CR116, 0x24 }, { CR117, 0xf4 }, { CR118, 0xfc },
+ { CR119, 0x10 }, { CR120, 0x4f }, { CR121, 0x77 },
+ { CR122, 0xe0 }, { CR137, 0x88 }, { CR252, 0xff },
+ { CR253, 0xff },
+
+ /* These following happen separately in the vendor driver */
+ { },
+
+ /* shdnb(PLL_ON)=0 */
+ { CR251, 0x2f },
+ /* shdnb(PLL_ON)=1 */
+ { CR251, 0x3f },
+ { CR138, 0x28 }, { CR203, 0x06 },
+ };
+
+ static const u32 rv[] = {
+ /* Channel 1 */
+ 0x03f790,
+ 0x033331,
+ 0x00000d,
+
+ 0x0b3331,
+ 0x03b812,
+ 0x00fff3,
+ 0x000da4,
+ 0x0f4dc5, /* fix freq shift, 0x04edc5 */
+ 0x0805b6,
+ 0x011687,
+ 0x000688,
+ 0x0403b9, /* external control TX power (CR31) */
+ 0x00dbba,
+ 0x00099b,
+ 0x0bdffc,
+ 0x00000d,
+ 0x00500f,
+
+ /* These writes happen separately in the vendor driver */
+ 0x00d00f,
+ 0x004c0f,
+ 0x00540f,
+ 0x00700f,
+ 0x00500f,
+ };
+
+ r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+ if (r)
+ return r;
+
+ r = zd_rfwritev_locked(chip, rv, ARRAY_SIZE(rv), RF_RV_BITS);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+static int zd1211b_al2230_init_hw(struct zd_rf *rf)
+{
+ int r;
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ static const struct zd_ioreq16 ioreqs1[] = {
+ { CR10, 0x89 }, { CR15, 0x20 },
+ { CR17, 0x2B }, /* for newest(3rd cut) AL2230 */
+ { CR23, 0x40 }, { CR24, 0x20 }, { CR26, 0x93 },
+ { CR28, 0x3e }, { CR29, 0x00 },
+ { CR33, 0x28 }, /* 5621 */
+ { CR34, 0x30 },
+ { CR35, 0x3e }, /* for newest(3rd cut) AL2230 */
+ { CR41, 0x24 }, { CR44, 0x32 },
+ { CR46, 0x99 }, /* for newest(3rd cut) AL2230 */
+ { CR47, 0x1e },
+
+ /* ZD1211B 05.06.10 */
+ { CR48, 0x00 }, { CR49, 0x00 }, { CR51, 0x01 },
+ { CR52, 0x80 }, { CR53, 0x7e }, { CR65, 0x00 },
+ { CR66, 0x00 }, { CR67, 0x00 }, { CR68, 0x00 },
+ { CR69, 0x28 },
+
+ { CR79, 0x58 }, { CR80, 0x30 }, { CR81, 0x30 },
+ { CR87, 0x0a }, { CR89, 0x04 },
+ { CR91, 0x00 }, /* 5621 */
+ { CR92, 0x0a },
+ { CR98, 0x8d }, /* 4804, for 1212 new algorithm */
+ { CR99, 0x00 }, /* 5621 */
+ { CR101, 0x13 }, { CR102, 0x27 },
+ { CR106, 0x24 }, /* for newest(3rd cut) AL2230 */
+ { CR107, 0x2a },
+ { CR109, 0x13 }, /* 4804, for 1212 new algorithm */
+ { CR110, 0x1f }, /* 4804, for 1212 new algorithm */
+ { CR111, 0x1f }, { CR112, 0x1f }, { CR113, 0x27 },
+ { CR114, 0x27 },
+ { CR115, 0x26 }, /* 24->26 at 4902 for newest(3rd cut) AL2230 */
+ { CR116, 0x24 },
+ { CR117, 0xfa }, /* for 1211b */
+ { CR118, 0xfa }, /* for 1211b */
+ { CR119, 0x10 },
+ { CR120, 0x4f },
+ { CR121, 0x6c }, /* for 1211b */
+ { CR122, 0xfc }, /* E0->FC at 4902 */
+ { CR123, 0x57 }, /* 5623 */
+ { CR125, 0xad }, /* 4804, for 1212 new algorithm */
+ { CR126, 0x6c }, /* 5614 */
+ { CR127, 0x03 }, /* 4804, for 1212 new algorithm */
+ { CR137, 0x50 }, /* 5614 */
+ { CR138, 0xa8 },
+ { CR144, 0xac }, /* 5621 */
+ { CR150, 0x0d }, { CR252, 0x00 }, { CR253, 0x00 },
+ };
+
+ static const u32 rv1[] = {
+ /* channel 1 */
+ 0x03f790,
+ 0x033331,
+ 0x00000d,
+
+ 0x0b3331,
+ 0x03b812,
+ 0x00fff3,
+ 0x0005a4,
+ 0x0f4dc5, /* fix freq shift 0x044dc5 */
+ 0x0805b6,
+ 0x0146c7,
+ 0x000688,
+ 0x0403b9, /* External control TX power (CR31) */
+ 0x00dbba,
+ 0x00099b,
+ 0x0bdffc,
+ 0x00000d,
+ 0x00580f,
+ };
+
+ static const struct zd_ioreq16 ioreqs2[] = {
+ { CR47, 0x1e }, { CR_RFCFG, 0x03 },
+ };
+
+ static const u32 rv2[] = {
+ 0x00880f,
+ 0x00080f,
+ };
+
+ static const struct zd_ioreq16 ioreqs3[] = {
+ { CR_RFCFG, 0x00 }, { CR47, 0x1e }, { CR251, 0x7f },
+ };
+
+ static const u32 rv3[] = {
+ 0x00d80f,
+ 0x00780f,
+ 0x00580f,
+ };
+
+ static const struct zd_ioreq16 ioreqs4[] = {
+ { CR138, 0x28 }, { CR203, 0x06 },
+ };
+
+ r = zd_iowrite16a_locked(chip, ioreqs1, ARRAY_SIZE(ioreqs1));
+ if (r)
+ return r;
+ r = zd_rfwritev_locked(chip, rv1, ARRAY_SIZE(rv1), RF_RV_BITS);
+ if (r)
+ return r;
+ r = zd_iowrite16a_locked(chip, ioreqs2, ARRAY_SIZE(ioreqs2));
+ if (r)
+ return r;
+ r = zd_rfwritev_locked(chip, rv2, ARRAY_SIZE(rv2), RF_RV_BITS);
+ if (r)
+ return r;
+ r = zd_iowrite16a_locked(chip, ioreqs3, ARRAY_SIZE(ioreqs3));
+ if (r)
+ return r;
+ r = zd_rfwritev_locked(chip, rv3, ARRAY_SIZE(rv3), RF_RV_BITS);
+ if (r)
+ return r;
+ return zd_iowrite16a_locked(chip, ioreqs4, ARRAY_SIZE(ioreqs4));
+}
+
+static int al2230_set_channel(struct zd_rf *rf, u8 channel)
+{
+ int r;
+ const u32 *rv = al2230_table[channel-1];
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR138, 0x28 },
+ { CR203, 0x06 },
+ };
+
+ r = zd_rfwritev_locked(chip, rv, 3, RF_RV_BITS);
+ if (r)
+ return r;
+ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static int zd1211_al2230_switch_radio_on(struct zd_rf *rf)
+{
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR11, 0x00 },
+ { CR251, 0x3f },
+ };
+
+ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static int zd1211b_al2230_switch_radio_on(struct zd_rf *rf)
+{
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR11, 0x00 },
+ { CR251, 0x7f },
+ };
+
+ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static int al2230_switch_radio_off(struct zd_rf *rf)
+{
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR11, 0x04 },
+ { CR251, 0x2f },
+ };
+
+ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+int zd_rf_init_al2230(struct zd_rf *rf)
+{
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ rf->set_channel = al2230_set_channel;
+ rf->switch_radio_off = al2230_switch_radio_off;
+ if (chip->is_zd1211b) {
+ rf->init_hw = zd1211b_al2230_init_hw;
+ rf->switch_radio_on = zd1211b_al2230_switch_radio_on;
+ } else {
+ rf->init_hw = zd1211_al2230_init_hw;
+ rf->switch_radio_on = zd1211_al2230_switch_radio_on;
+ }
+ rf->patch_6m_band_edge = 1;
+ return 0;
+}
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c
new file mode 100644
index 00000000000..58247271cc2
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c
@@ -0,0 +1,279 @@
+/* zd_rf_rfmd.c: Functions for the RFMD RF controller
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+
+#include "zd_rf.h"
+#include "zd_usb.h"
+#include "zd_chip.h"
+
+static u32 rf2959_table[][2] = {
+ RF_CHANNEL( 1) = { 0x181979, 0x1e6666 },
+ RF_CHANNEL( 2) = { 0x181989, 0x1e6666 },
+ RF_CHANNEL( 3) = { 0x181999, 0x1e6666 },
+ RF_CHANNEL( 4) = { 0x1819a9, 0x1e6666 },
+ RF_CHANNEL( 5) = { 0x1819b9, 0x1e6666 },
+ RF_CHANNEL( 6) = { 0x1819c9, 0x1e6666 },
+ RF_CHANNEL( 7) = { 0x1819d9, 0x1e6666 },
+ RF_CHANNEL( 8) = { 0x1819e9, 0x1e6666 },
+ RF_CHANNEL( 9) = { 0x1819f9, 0x1e6666 },
+ RF_CHANNEL(10) = { 0x181a09, 0x1e6666 },
+ RF_CHANNEL(11) = { 0x181a19, 0x1e6666 },
+ RF_CHANNEL(12) = { 0x181a29, 0x1e6666 },
+ RF_CHANNEL(13) = { 0x181a39, 0x1e6666 },
+ RF_CHANNEL(14) = { 0x181a60, 0x1c0000 },
+};
+
+#if 0
+static int bits(u32 rw, int from, int to)
+{
+ rw &= ~(0xffffffffU << (to+1));
+ rw >>= from;
+ return rw;
+}
+
+static int bit(u32 rw, int bit)
+{
+ return bits(rw, bit, bit);
+}
+
+static void dump_regwrite(u32 rw)
+{
+ int reg = bits(rw, 18, 22);
+ int rw_flag = bits(rw, 23, 23);
+ PDEBUG("rf2959 %#010x reg %d rw %d", rw, reg, rw_flag);
+
+ switch (reg) {
+ case 0:
+ PDEBUG("reg0 CFG1 ref_sel %d hybernate %d rf_vco_reg_en %d"
+ " if_vco_reg_en %d if_vga_en %d",
+ bits(rw, 14, 15), bit(rw, 3), bit(rw, 2), bit(rw, 1),
+ bit(rw, 0));
+ break;
+ case 1:
+ PDEBUG("reg1 IFPLL1 pll_en1 %d kv_en1 %d vtc_en1 %d lpf1 %d"
+ " cpl1 %d pdp1 %d autocal_en1 %d ld_en1 %d ifloopr %d"
+ " ifloopc %d dac1 %d",
+ bit(rw, 17), bit(rw, 16), bit(rw, 15), bit(rw, 14),
+ bit(rw, 13), bit(rw, 12), bit(rw, 11), bit(rw, 10),
+ bits(rw, 7, 9), bits(rw, 4, 6), bits(rw, 0, 3));
+ break;
+ case 2:
+ PDEBUG("reg2 IFPLL2 n1 %d num1 %d",
+ bits(rw, 6, 17), bits(rw, 0, 5));
+ break;
+ case 3:
+ PDEBUG("reg3 IFPLL3 num %d", bits(rw, 0, 17));
+ break;
+ case 4:
+ PDEBUG("reg4 IFPLL4 dn1 %#04x ct_def1 %d kv_def1 %d",
+ bits(rw, 8, 16), bits(rw, 4, 7), bits(rw, 0, 3));
+ break;
+ case 5:
+ PDEBUG("reg5 RFPLL1 pll_en %d kv_en %d vtc_en %d lpf %d cpl %d"
+ " pdp %d autocal_en %d ld_en %d rfloopr %d rfloopc %d"
+ " dac %d",
+ bit(rw, 17), bit(rw, 16), bit(rw, 15), bit(rw, 14),
+ bit(rw, 13), bit(rw, 12), bit(rw, 11), bit(rw, 10),
+ bits(rw, 7, 9), bits(rw, 4, 6), bits(rw, 0,3));
+ break;
+ case 6:
+ PDEBUG("reg6 RFPLL2 n %d num %d",
+ bits(rw, 6, 17), bits(rw, 0, 5));
+ break;
+ case 7:
+ PDEBUG("reg7 RFPLL3 num2 %d", bits(rw, 0, 17));
+ break;
+ case 8:
+ PDEBUG("reg8 RFPLL4 dn %#06x ct_def %d kv_def %d",
+ bits(rw, 8, 16), bits(rw, 4, 7), bits(rw, 0, 3));
+ break;
+ case 9:
+ PDEBUG("reg9 CAL1 tvco %d tlock %d m_ct_value %d ld_window %d",
+ bits(rw, 13, 17), bits(rw, 8, 12), bits(rw, 3, 7),
+ bits(rw, 0, 2));
+ break;
+ case 10:
+ PDEBUG("reg10 TXRX1 rxdcfbbyps %d pcontrol %d txvgc %d"
+ " rxlpfbw %d txlpfbw %d txdiffmode %d txenmode %d"
+ " intbiasen %d tybypass %d",
+ bit(rw, 17), bits(rw, 15, 16), bits(rw, 10, 14),
+ bits(rw, 7, 9), bits(rw, 4, 6), bit(rw, 3), bit(rw, 2),
+ bit(rw, 1), bit(rw, 0));
+ break;
+ case 11:
+ PDEBUG("reg11 PCNT1 mid_bias %d p_desired %d pc_offset %d"
+ " tx_delay %d",
+ bits(rw, 15, 17), bits(rw, 9, 14), bits(rw, 3, 8),
+ bits(rw, 0, 2));
+ break;
+ case 12:
+ PDEBUG("reg12 PCNT2 max_power %d mid_power %d min_power %d",
+ bits(rw, 12, 17), bits(rw, 6, 11), bits(rw, 0, 5));
+ break;
+ case 13:
+ PDEBUG("reg13 VCOT1 rfpll vco comp %d ifpll vco comp %d"
+ " lobias %d if_biasbuf %d if_biasvco %d rf_biasbuf %d"
+ " rf_biasvco %d",
+ bit(rw, 17), bit(rw, 16), bit(rw, 15),
+ bits(rw, 8, 9), bits(rw, 5, 7), bits(rw, 3, 4),
+ bits(rw, 0, 2));
+ break;
+ case 14:
+ PDEBUG("reg14 IQCAL rx_acal %d rx_pcal %d"
+ " tx_acal %d tx_pcal %d",
+ bits(rw, 13, 17), bits(rw, 9, 12), bits(rw, 4, 8),
+ bits(rw, 0, 3));
+ break;
+ }
+}
+#endif /* 0 */
+
+static int rf2959_init_hw(struct zd_rf *rf)
+{
+ int r;
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR2, 0x1E }, { CR9, 0x20 }, { CR10, 0x89 },
+ { CR11, 0x00 }, { CR15, 0xD0 }, { CR17, 0x68 },
+ { CR19, 0x4a }, { CR20, 0x0c }, { CR21, 0x0E },
+ { CR23, 0x48 },
+ /* normal size for cca threshold */
+ { CR24, 0x14 },
+ /* { CR24, 0x20 }, */
+ { CR26, 0x90 }, { CR27, 0x30 }, { CR29, 0x20 },
+ { CR31, 0xb2 }, { CR32, 0x43 }, { CR33, 0x28 },
+ { CR38, 0x30 }, { CR34, 0x0f }, { CR35, 0xF0 },
+ { CR41, 0x2a }, { CR46, 0x7F }, { CR47, 0x1E },
+ { CR51, 0xc5 }, { CR52, 0xc5 }, { CR53, 0xc5 },
+ { CR79, 0x58 }, { CR80, 0x30 }, { CR81, 0x30 },
+ { CR82, 0x00 }, { CR83, 0x24 }, { CR84, 0x04 },
+ { CR85, 0x00 }, { CR86, 0x10 }, { CR87, 0x2A },
+ { CR88, 0x10 }, { CR89, 0x24 }, { CR90, 0x18 },
+ /* { CR91, 0x18 }, */
+ /* should solve continous CTS frame problems */
+ { CR91, 0x00 },
+ { CR92, 0x0a }, { CR93, 0x00 }, { CR94, 0x01 },
+ { CR95, 0x00 }, { CR96, 0x40 }, { CR97, 0x37 },
+ { CR98, 0x05 }, { CR99, 0x28 }, { CR100, 0x00 },
+ { CR101, 0x13 }, { CR102, 0x27 }, { CR103, 0x27 },
+ { CR104, 0x18 }, { CR105, 0x12 },
+ /* normal size */
+ { CR106, 0x1a },
+ /* { CR106, 0x22 }, */
+ { CR107, 0x24 }, { CR108, 0x0a }, { CR109, 0x13 },
+ { CR110, 0x2F }, { CR111, 0x27 }, { CR112, 0x27 },
+ { CR113, 0x27 }, { CR114, 0x27 }, { CR115, 0x40 },
+ { CR116, 0x40 }, { CR117, 0xF0 }, { CR118, 0xF0 },
+ { CR119, 0x16 },
+ /* no TX continuation */
+ { CR122, 0x00 },
+ /* { CR122, 0xff }, */
+ { CR127, 0x03 }, { CR131, 0x08 }, { CR138, 0x28 },
+ { CR148, 0x44 }, { CR150, 0x10 }, { CR169, 0xBB },
+ { CR170, 0xBB },
+ };
+
+ static const u32 rv[] = {
+ 0x000007, /* REG0(CFG1) */
+ 0x07dd43, /* REG1(IFPLL1) */
+ 0x080959, /* REG2(IFPLL2) */
+ 0x0e6666,
+ 0x116a57, /* REG4 */
+ 0x17dd43, /* REG5 */
+ 0x1819f9, /* REG6 */
+ 0x1e6666,
+ 0x214554,
+ 0x25e7fa,
+ 0x27fffa,
+ /* The Zydas driver somehow forgets to set this value. It's
+ * only set for Japan. We are using internal power control
+ * for now.
+ */
+ 0x294128, /* internal power */
+ /* 0x28252c, */ /* External control TX power */
+ /* CR31_CCK, CR51_6-36M, CR52_48M, CR53_54M */
+ 0x2c0000,
+ 0x300000,
+ 0x340000, /* REG13(0xD) */
+ 0x381e0f, /* REG14(0xE) */
+ /* Bogus, RF2959's data sheet doesn't know register 27, which is
+ * actually referenced here. The commented 0x11 is 17.
+ */
+ 0x6c180f, /* REG27(0x11) */
+ };
+
+ r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+ if (r)
+ return r;
+
+ return zd_rfwritev_locked(chip, rv, ARRAY_SIZE(rv), RF_RV_BITS);
+}
+
+static int rf2959_set_channel(struct zd_rf *rf, u8 channel)
+{
+ int i, r;
+ u32 *rv = rf2959_table[channel-1];
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ for (i = 0; i < 2; i++) {
+ r = zd_rfwrite_locked(chip, rv[i], RF_RV_BITS);
+ if (r)
+ return r;
+ }
+ return 0;
+}
+
+static int rf2959_switch_radio_on(struct zd_rf *rf)
+{
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR10, 0x89 },
+ { CR11, 0x00 },
+ };
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static int rf2959_switch_radio_off(struct zd_rf *rf)
+{
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR10, 0x15 },
+ { CR11, 0x81 },
+ };
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+int zd_rf_init_rf2959(struct zd_rf *rf)
+{
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ if (chip->is_zd1211b) {
+ dev_err(zd_chip_dev(chip),
+ "RF2959 is currently not supported for ZD1211B"
+ " devices\n");
+ return -ENODEV;
+ }
+ rf->init_hw = rf2959_init_hw;
+ rf->set_channel = rf2959_set_channel;
+ rf->switch_radio_on = rf2959_switch_radio_on;
+ rf->switch_radio_off = rf2959_switch_radio_off;
+ return 0;
+}
diff --git a/drivers/net/wireless/zd1211rw/zd_types.h b/drivers/net/wireless/zd1211rw/zd_types.h
new file mode 100644
index 00000000000..0155a1584ed
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_types.h
@@ -0,0 +1,71 @@
+/* zd_types.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _ZD_TYPES_H
+#define _ZD_TYPES_H
+
+#include <linux/types.h>
+
+/* We have three register spaces mapped into the overall USB address space of
+ * 64K words (16-bit values). There is the control register space of
+ * double-word registers, the eeprom register space and the firmware register
+ * space. The control register space is byte mapped, the others are word
+ * mapped.
+ *
+ * For that reason, we are using byte offsets for control registers and word
+ * offsets for everything else.
+ */
+
+typedef u32 __nocast zd_addr_t;
+
+enum {
+ ADDR_BASE_MASK = 0xff000000,
+ ADDR_OFFSET_MASK = 0x0000ffff,
+ ADDR_ZERO_MASK = 0x00ff0000,
+ NULL_BASE = 0x00000000,
+ USB_BASE = 0x01000000,
+ CR_BASE = 0x02000000,
+ CR_MAX_OFFSET = 0x0b30,
+ E2P_BASE = 0x03000000,
+ E2P_MAX_OFFSET = 0x007e,
+ FW_BASE = 0x04000000,
+ FW_MAX_OFFSET = 0x0005,
+};
+
+#define ZD_ADDR_BASE(addr) ((u32)(addr) & ADDR_BASE_MASK)
+#define ZD_OFFSET(addr) ((u32)(addr) & ADDR_OFFSET_MASK)
+
+#define ZD_ADDR(base, offset) \
+ ((zd_addr_t)(((base) & ADDR_BASE_MASK) | ((offset) & ADDR_OFFSET_MASK)))
+
+#define ZD_NULL_ADDR ((zd_addr_t)0)
+#define USB_REG(offset) ZD_ADDR(USB_BASE, offset) /* word addressing */
+#define CTL_REG(offset) ZD_ADDR(CR_BASE, offset) /* byte addressing */
+#define E2P_REG(offset) ZD_ADDR(E2P_BASE, offset) /* word addressing */
+#define FW_REG(offset) ZD_ADDR(FW_BASE, offset) /* word addressing */
+
+static inline zd_addr_t zd_inc_word(zd_addr_t addr)
+{
+ u32 base = ZD_ADDR_BASE(addr);
+ u32 offset = ZD_OFFSET(addr);
+
+ offset += base == CR_BASE ? 2 : 1;
+
+ return base | offset;
+}
+
+#endif /* _ZD_TYPES_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
new file mode 100644
index 00000000000..6320984126c
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -0,0 +1,1309 @@
+/* zd_usb.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <asm/unaligned.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/firmware.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/skbuff.h>
+#include <linux/usb.h>
+#include <net/ieee80211.h>
+
+#include "zd_def.h"
+#include "zd_netdev.h"
+#include "zd_mac.h"
+#include "zd_usb.h"
+#include "zd_util.h"
+
+static struct usb_device_id usb_ids[] = {
+ /* ZD1211 */
+ { USB_DEVICE(0x0ace, 0x1211), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x126f, 0xa006), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x0df6, 0x9071), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 },
+ /* ZD1211B */
+ { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
+ {}
+};
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("USB driver for devices with the ZD1211 chip.");
+MODULE_AUTHOR("Ulrich Kunitz");
+MODULE_AUTHOR("Daniel Drake");
+MODULE_VERSION("1.0");
+MODULE_DEVICE_TABLE(usb, usb_ids);
+
+#define FW_ZD1211_PREFIX "zd1211/zd1211_"
+#define FW_ZD1211B_PREFIX "zd1211/zd1211b_"
+
+/* register address handling */
+
+#ifdef DEBUG
+static int check_addr(struct zd_usb *usb, zd_addr_t addr)
+{
+ u32 base = ZD_ADDR_BASE(addr);
+ u32 offset = ZD_OFFSET(addr);
+
+ if ((u32)addr & ADDR_ZERO_MASK)
+ goto invalid_address;
+ switch (base) {
+ case USB_BASE:
+ break;
+ case CR_BASE:
+ if (offset > CR_MAX_OFFSET) {
+ dev_dbg(zd_usb_dev(usb),
+ "CR offset %#010x larger than"
+ " CR_MAX_OFFSET %#10x\n",
+ offset, CR_MAX_OFFSET);
+ goto invalid_address;
+ }
+ if (offset & 1) {
+ dev_dbg(zd_usb_dev(usb),
+ "CR offset %#010x is not a multiple of 2\n",
+ offset);
+ goto invalid_address;
+ }
+ break;
+ case E2P_BASE:
+ if (offset > E2P_MAX_OFFSET) {
+ dev_dbg(zd_usb_dev(usb),
+ "E2P offset %#010x larger than"
+ " E2P_MAX_OFFSET %#010x\n",
+ offset, E2P_MAX_OFFSET);
+ goto invalid_address;
+ }
+ break;
+ case FW_BASE:
+ if (!usb->fw_base_offset) {
+ dev_dbg(zd_usb_dev(usb),
+ "ERROR: fw base offset has not been set\n");
+ return -EAGAIN;
+ }
+ if (offset > FW_MAX_OFFSET) {
+ dev_dbg(zd_usb_dev(usb),
+ "FW offset %#10x is larger than"
+ " FW_MAX_OFFSET %#010x\n",
+ offset, FW_MAX_OFFSET);
+ goto invalid_address;
+ }
+ break;
+ default:
+ dev_dbg(zd_usb_dev(usb),
+ "address has unsupported base %#010x\n", addr);
+ goto invalid_address;
+ }
+
+ return 0;
+invalid_address:
+ dev_dbg(zd_usb_dev(usb),
+ "ERROR: invalid address: %#010x\n", addr);
+ return -EINVAL;
+}
+#endif /* DEBUG */
+
+static u16 usb_addr(struct zd_usb *usb, zd_addr_t addr)
+{
+ u32 base;
+ u16 offset;
+
+ base = ZD_ADDR_BASE(addr);
+ offset = ZD_OFFSET(addr);
+
+ ZD_ASSERT(check_addr(usb, addr) == 0);
+
+ switch (base) {
+ case CR_BASE:
+ offset += CR_BASE_OFFSET;
+ break;
+ case E2P_BASE:
+ offset += E2P_BASE_OFFSET;
+ break;
+ case FW_BASE:
+ offset += usb->fw_base_offset;
+ break;
+ }
+
+ return offset;
+}
+
+/* USB device initialization */
+
+static int request_fw_file(
+ const struct firmware **fw, const char *name, struct device *device)
+{
+ int r;
+
+ dev_dbg_f(device, "fw name %s\n", name);
+
+ r = request_firmware(fw, name, device);
+ if (r)
+ dev_err(device,
+ "Could not load firmware file %s. Error number %d\n",
+ name, r);
+ return r;
+}
+
+static inline u16 get_bcdDevice(const struct usb_device *udev)
+{
+ return le16_to_cpu(udev->descriptor.bcdDevice);
+}
+
+enum upload_code_flags {
+ REBOOT = 1,
+};
+
+/* Ensures that MAX_TRANSFER_SIZE is even. */
+#define MAX_TRANSFER_SIZE (USB_MAX_TRANSFER_SIZE & ~1)
+
+static int upload_code(struct usb_device *udev,
+ const u8 *data, size_t size, u16 code_offset, int flags)
+{
+ u8 *p;
+ int r;
+
+ /* USB request blocks need "kmalloced" buffers.
+ */
+ p = kmalloc(MAX_TRANSFER_SIZE, GFP_KERNEL);
+ if (!p) {
+ dev_err(&udev->dev, "out of memory\n");
+ r = -ENOMEM;
+ goto error;
+ }
+
+ size &= ~1;
+ while (size > 0) {
+ size_t transfer_size = size <= MAX_TRANSFER_SIZE ?
+ size : MAX_TRANSFER_SIZE;
+
+ dev_dbg_f(&udev->dev, "transfer size %zu\n", transfer_size);
+
+ memcpy(p, data, transfer_size);
+ r = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ USB_REQ_FIRMWARE_DOWNLOAD,
+ USB_DIR_OUT | USB_TYPE_VENDOR,
+ code_offset, 0, p, transfer_size, 1000 /* ms */);
+ if (r < 0) {
+ dev_err(&udev->dev,
+ "USB control request for firmware upload"
+ " failed. Error number %d\n", r);
+ goto error;
+ }
+ transfer_size = r & ~1;
+
+ size -= transfer_size;
+ data += transfer_size;
+ code_offset += transfer_size/sizeof(u16);
+ }
+
+ if (flags & REBOOT) {
+ u8 ret;
+
+ r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+ USB_REQ_FIRMWARE_CONFIRM,
+ USB_DIR_IN | USB_TYPE_VENDOR,
+ 0, 0, &ret, sizeof(ret), 5000 /* ms */);
+ if (r != sizeof(ret)) {
+ dev_err(&udev->dev,
+ "control request firmeware confirmation failed."
+ " Return value %d\n", r);
+ if (r >= 0)
+ r = -ENODEV;
+ goto error;
+ }
+ if (ret & 0x80) {
+ dev_err(&udev->dev,
+ "Internal error while downloading."
+ " Firmware confirm return value %#04x\n",
+ (unsigned int)ret);
+ r = -ENODEV;
+ goto error;
+ }
+ dev_dbg_f(&udev->dev, "firmware confirm return value %#04x\n",
+ (unsigned int)ret);
+ }
+
+ r = 0;
+error:
+ kfree(p);
+ return r;
+}
+
+static u16 get_word(const void *data, u16 offset)
+{
+ const __le16 *p = data;
+ return le16_to_cpu(p[offset]);
+}
+
+static char *get_fw_name(char *buffer, size_t size, u8 device_type,
+ const char* postfix)
+{
+ scnprintf(buffer, size, "%s%s",
+ device_type == DEVICE_ZD1211B ?
+ FW_ZD1211B_PREFIX : FW_ZD1211_PREFIX,
+ postfix);
+ return buffer;
+}
+
+static int upload_firmware(struct usb_device *udev, u8 device_type)
+{
+ int r;
+ u16 fw_bcdDevice;
+ u16 bcdDevice;
+ const struct firmware *ub_fw = NULL;
+ const struct firmware *uph_fw = NULL;
+ char fw_name[128];
+
+ bcdDevice = get_bcdDevice(udev);
+
+ r = request_fw_file(&ub_fw,
+ get_fw_name(fw_name, sizeof(fw_name), device_type, "ub"),
+ &udev->dev);
+ if (r)
+ goto error;
+
+ fw_bcdDevice = get_word(ub_fw->data, EEPROM_REGS_OFFSET);
+
+ /* FIXME: do we have any reason to perform the kludge that the vendor
+ * driver does when there is a version mismatch? (their driver uploads
+ * different firmwares and stuff)
+ */
+ if (fw_bcdDevice != bcdDevice) {
+ dev_info(&udev->dev,
+ "firmware device id %#06x and actual device id "
+ "%#06x differ, continuing anyway\n",
+ fw_bcdDevice, bcdDevice);
+ } else {
+ dev_dbg_f(&udev->dev,
+ "firmware device id %#06x is equal to the "
+ "actual device id\n", fw_bcdDevice);
+ }
+
+
+ r = request_fw_file(&uph_fw,
+ get_fw_name(fw_name, sizeof(fw_name), device_type, "uphr"),
+ &udev->dev);
+ if (r)
+ goto error;
+
+ r = upload_code(udev, uph_fw->data, uph_fw->size, FW_START_OFFSET,
+ REBOOT);
+ if (r) {
+ dev_err(&udev->dev,
+ "Could not upload firmware code uph. Error number %d\n",
+ r);
+ }
+
+ /* FALL-THROUGH */
+error:
+ release_firmware(ub_fw);
+ release_firmware(uph_fw);
+ return r;
+}
+
+static void disable_read_regs_int(struct zd_usb *usb)
+{
+ struct zd_usb_interrupt *intr = &usb->intr;
+
+ spin_lock(&intr->lock);
+ intr->read_regs_enabled = 0;
+ spin_unlock(&intr->lock);
+}
+
+#define urb_dev(urb) (&(urb)->dev->dev)
+
+static inline void handle_regs_int(struct urb *urb)
+{
+ struct zd_usb *usb = urb->context;
+ struct zd_usb_interrupt *intr = &usb->intr;
+ int len;
+
+ ZD_ASSERT(in_interrupt());
+ spin_lock(&intr->lock);
+
+ if (intr->read_regs_enabled) {
+ intr->read_regs.length = len = urb->actual_length;
+
+ if (len > sizeof(intr->read_regs.buffer))
+ len = sizeof(intr->read_regs.buffer);
+ memcpy(intr->read_regs.buffer, urb->transfer_buffer, len);
+ intr->read_regs_enabled = 0;
+ complete(&intr->read_regs.completion);
+ goto out;
+ }
+
+ dev_dbg_f(urb_dev(urb), "regs interrupt ignored\n");
+out:
+ spin_unlock(&intr->lock);
+}
+
+static inline void handle_retry_failed_int(struct urb *urb)
+{
+ dev_dbg_f(urb_dev(urb), "retry failed interrupt\n");
+}
+
+
+static void int_urb_complete(struct urb *urb, struct pt_regs *pt_regs)
+{
+ int r;
+ struct usb_int_header *hdr;
+
+ switch (urb->status) {
+ case 0:
+ break;
+ case -ESHUTDOWN:
+ case -EINVAL:
+ case -ENODEV:
+ case -ENOENT:
+ case -ECONNRESET:
+ case -EPIPE:
+ goto kfree;
+ default:
+ goto resubmit;
+ }
+
+ if (urb->actual_length < sizeof(hdr)) {
+ dev_dbg_f(urb_dev(urb), "error: urb %p to small\n", urb);
+ goto resubmit;
+ }
+
+ hdr = urb->transfer_buffer;
+ if (hdr->type != USB_INT_TYPE) {
+ dev_dbg_f(urb_dev(urb), "error: urb %p wrong type\n", urb);
+ goto resubmit;
+ }
+
+ switch (hdr->id) {
+ case USB_INT_ID_REGS:
+ handle_regs_int(urb);
+ break;
+ case USB_INT_ID_RETRY_FAILED:
+ handle_retry_failed_int(urb);
+ break;
+ default:
+ dev_dbg_f(urb_dev(urb), "error: urb %p unknown id %x\n", urb,
+ (unsigned int)hdr->id);
+ goto resubmit;
+ }
+
+resubmit:
+ r = usb_submit_urb(urb, GFP_ATOMIC);
+ if (r) {
+ dev_dbg_f(urb_dev(urb), "resubmit urb %p\n", urb);
+ goto kfree;
+ }
+ return;
+kfree:
+ kfree(urb->transfer_buffer);
+}
+
+static inline int int_urb_interval(struct usb_device *udev)
+{
+ switch (udev->speed) {
+ case USB_SPEED_HIGH:
+ return 4;
+ case USB_SPEED_LOW:
+ return 10;
+ case USB_SPEED_FULL:
+ default:
+ return 1;
+ }
+}
+
+static inline int usb_int_enabled(struct zd_usb *usb)
+{
+ unsigned long flags;
+ struct zd_usb_interrupt *intr = &usb->intr;
+ struct urb *urb;
+
+ spin_lock_irqsave(&intr->lock, flags);
+ urb = intr->urb;
+ spin_unlock_irqrestore(&intr->lock, flags);
+ return urb != NULL;
+}
+
+int zd_usb_enable_int(struct zd_usb *usb)
+{
+ int r;
+ struct usb_device *udev;
+ struct zd_usb_interrupt *intr = &usb->intr;
+ void *transfer_buffer = NULL;
+ struct urb *urb;
+
+ dev_dbg_f(zd_usb_dev(usb), "\n");
+
+ urb = usb_alloc_urb(0, GFP_NOFS);
+ if (!urb) {
+ r = -ENOMEM;
+ goto out;
+ }
+
+ ZD_ASSERT(!irqs_disabled());
+ spin_lock_irq(&intr->lock);
+ if (intr->urb) {
+ spin_unlock_irq(&intr->lock);
+ r = 0;
+ goto error_free_urb;
+ }
+ intr->urb = urb;
+ spin_unlock_irq(&intr->lock);
+
+ /* TODO: make it a DMA buffer */
+ r = -ENOMEM;
+ transfer_buffer = kmalloc(USB_MAX_EP_INT_BUFFER, GFP_NOFS);
+ if (!transfer_buffer) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "couldn't allocate transfer_buffer\n");
+ goto error_set_urb_null;
+ }
+
+ udev = zd_usb_to_usbdev(usb);
+ usb_fill_int_urb(urb, udev, usb_rcvintpipe(udev, EP_INT_IN),
+ transfer_buffer, USB_MAX_EP_INT_BUFFER,
+ int_urb_complete, usb,
+ intr->interval);
+
+ dev_dbg_f(zd_usb_dev(usb), "submit urb %p\n", intr->urb);
+ r = usb_submit_urb(urb, GFP_NOFS);
+ if (r) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "Couldn't submit urb. Error number %d\n", r);
+ goto error;
+ }
+
+ return 0;
+error:
+ kfree(transfer_buffer);
+error_set_urb_null:
+ spin_lock_irq(&intr->lock);
+ intr->urb = NULL;
+ spin_unlock_irq(&intr->lock);
+error_free_urb:
+ usb_free_urb(urb);
+out:
+ return r;
+}
+
+void zd_usb_disable_int(struct zd_usb *usb)
+{
+ unsigned long flags;
+ struct zd_usb_interrupt *intr = &usb->intr;
+ struct urb *urb;
+
+ spin_lock_irqsave(&intr->lock, flags);
+ urb = intr->urb;
+ if (!urb) {
+ spin_unlock_irqrestore(&intr->lock, flags);
+ return;
+ }
+ intr->urb = NULL;
+ spin_unlock_irqrestore(&intr->lock, flags);
+
+ usb_kill_urb(urb);
+ dev_dbg_f(zd_usb_dev(usb), "urb %p killed\n", urb);
+ usb_free_urb(urb);
+}
+
+static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer,
+ unsigned int length)
+{
+ int i;
+ struct zd_mac *mac = zd_usb_to_mac(usb);
+ const struct rx_length_info *length_info;
+
+ if (length < sizeof(struct rx_length_info)) {
+ /* It's not a complete packet anyhow. */
+ return;
+ }
+ length_info = (struct rx_length_info *)
+ (buffer + length - sizeof(struct rx_length_info));
+
+ /* It might be that three frames are merged into a single URB
+ * transaction. We have to check for the length info tag.
+ *
+ * While testing we discovered that length_info might be unaligned,
+ * because if USB transactions are merged, the last packet will not
+ * be padded. Unaligned access might also happen if the length_info
+ * structure is not present.
+ */
+ if (get_unaligned(&length_info->tag) == cpu_to_le16(RX_LENGTH_INFO_TAG))
+ {
+ unsigned int l, k, n;
+ for (i = 0, l = 0;; i++) {
+ k = le16_to_cpu(get_unaligned(&length_info->length[i]));
+ n = l+k;
+ if (n > length)
+ return;
+ zd_mac_rx(mac, buffer+l, k);
+ if (i >= 2)
+ return;
+ l = (n+3) & ~3;
+ }
+ } else {
+ zd_mac_rx(mac, buffer, length);
+ }
+}
+
+static void rx_urb_complete(struct urb *urb, struct pt_regs *pt_regs)
+{
+ struct zd_usb *usb;
+ struct zd_usb_rx *rx;
+ const u8 *buffer;
+ unsigned int length;
+
+ switch (urb->status) {
+ case 0:
+ break;
+ case -ESHUTDOWN:
+ case -EINVAL:
+ case -ENODEV:
+ case -ENOENT:
+ case -ECONNRESET:
+ case -EPIPE:
+ return;
+ default:
+ dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status);
+ goto resubmit;
+ }
+
+ buffer = urb->transfer_buffer;
+ length = urb->actual_length;
+ usb = urb->context;
+ rx = &usb->rx;
+
+ if (length%rx->usb_packet_size > rx->usb_packet_size-4) {
+ /* If there is an old first fragment, we don't care. */
+ dev_dbg_f(urb_dev(urb), "*** first fragment ***\n");
+ ZD_ASSERT(length <= ARRAY_SIZE(rx->fragment));
+ spin_lock(&rx->lock);
+ memcpy(rx->fragment, buffer, length);
+ rx->fragment_length = length;
+ spin_unlock(&rx->lock);
+ goto resubmit;
+ }
+
+ spin_lock(&rx->lock);
+ if (rx->fragment_length > 0) {
+ /* We are on a second fragment, we believe */
+ ZD_ASSERT(length + rx->fragment_length <=
+ ARRAY_SIZE(rx->fragment));
+ dev_dbg_f(urb_dev(urb), "*** second fragment ***\n");
+ memcpy(rx->fragment+rx->fragment_length, buffer, length);
+ handle_rx_packet(usb, rx->fragment,
+ rx->fragment_length + length);
+ rx->fragment_length = 0;
+ spin_unlock(&rx->lock);
+ } else {
+ spin_unlock(&rx->lock);
+ handle_rx_packet(usb, buffer, length);
+ }
+
+resubmit:
+ usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+struct urb *alloc_urb(struct zd_usb *usb)
+{
+ struct usb_device *udev = zd_usb_to_usbdev(usb);
+ struct urb *urb;
+ void *buffer;
+
+ urb = usb_alloc_urb(0, GFP_NOFS);
+ if (!urb)
+ return NULL;
+ buffer = usb_buffer_alloc(udev, USB_MAX_RX_SIZE, GFP_NOFS,
+ &urb->transfer_dma);
+ if (!buffer) {
+ usb_free_urb(urb);
+ return NULL;
+ }
+
+ usb_fill_bulk_urb(urb, udev, usb_rcvbulkpipe(udev, EP_DATA_IN),
+ buffer, USB_MAX_RX_SIZE,
+ rx_urb_complete, usb);
+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+ return urb;
+}
+
+void free_urb(struct urb *urb)
+{
+ if (!urb)
+ return;
+ usb_buffer_free(urb->dev, urb->transfer_buffer_length,
+ urb->transfer_buffer, urb->transfer_dma);
+ usb_free_urb(urb);
+}
+
+int zd_usb_enable_rx(struct zd_usb *usb)
+{
+ int i, r;
+ struct zd_usb_rx *rx = &usb->rx;
+ struct urb **urbs;
+
+ dev_dbg_f(zd_usb_dev(usb), "\n");
+
+ r = -ENOMEM;
+ urbs = kcalloc(URBS_COUNT, sizeof(struct urb *), GFP_NOFS);
+ if (!urbs)
+ goto error;
+ for (i = 0; i < URBS_COUNT; i++) {
+ urbs[i] = alloc_urb(usb);
+ if (!urbs[i])
+ goto error;
+ }
+
+ ZD_ASSERT(!irqs_disabled());
+ spin_lock_irq(&rx->lock);
+ if (rx->urbs) {
+ spin_unlock_irq(&rx->lock);
+ r = 0;
+ goto error;
+ }
+ rx->urbs = urbs;
+ rx->urbs_count = URBS_COUNT;
+ spin_unlock_irq(&rx->lock);
+
+ for (i = 0; i < URBS_COUNT; i++) {
+ r = usb_submit_urb(urbs[i], GFP_NOFS);
+ if (r)
+ goto error_submit;
+ }
+
+ return 0;
+error_submit:
+ for (i = 0; i < URBS_COUNT; i++) {
+ usb_kill_urb(urbs[i]);
+ }
+ spin_lock_irq(&rx->lock);
+ rx->urbs = NULL;
+ rx->urbs_count = 0;
+ spin_unlock_irq(&rx->lock);
+error:
+ if (urbs) {
+ for (i = 0; i < URBS_COUNT; i++)
+ free_urb(urbs[i]);
+ }
+ return r;
+}
+
+void zd_usb_disable_rx(struct zd_usb *usb)
+{
+ int i;
+ unsigned long flags;
+ struct urb **urbs;
+ unsigned int count;
+ struct zd_usb_rx *rx = &usb->rx;
+
+ spin_lock_irqsave(&rx->lock, flags);
+ urbs = rx->urbs;
+ count = rx->urbs_count;
+ spin_unlock_irqrestore(&rx->lock, flags);
+ if (!urbs)
+ return;
+
+ for (i = 0; i < count; i++) {
+ usb_kill_urb(urbs[i]);
+ free_urb(urbs[i]);
+ }
+ kfree(urbs);
+
+ spin_lock_irqsave(&rx->lock, flags);
+ rx->urbs = NULL;
+ rx->urbs_count = 0;
+ spin_unlock_irqrestore(&rx->lock, flags);
+}
+
+static void tx_urb_complete(struct urb *urb, struct pt_regs *pt_regs)
+{
+ int r;
+
+ switch (urb->status) {
+ case 0:
+ break;
+ case -ESHUTDOWN:
+ case -EINVAL:
+ case -ENODEV:
+ case -ENOENT:
+ case -ECONNRESET:
+ case -EPIPE:
+ dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status);
+ break;
+ default:
+ dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status);
+ goto resubmit;
+ }
+free_urb:
+ usb_buffer_free(urb->dev, urb->transfer_buffer_length,
+ urb->transfer_buffer, urb->transfer_dma);
+ usb_free_urb(urb);
+ return;
+resubmit:
+ r = usb_submit_urb(urb, GFP_ATOMIC);
+ if (r) {
+ dev_dbg_f(urb_dev(urb), "error resubmit urb %p %d\n", urb, r);
+ goto free_urb;
+ }
+}
+
+/* Puts the frame on the USB endpoint. It doesn't wait for
+ * completion. The frame must contain the control set.
+ */
+int zd_usb_tx(struct zd_usb *usb, const u8 *frame, unsigned int length)
+{
+ int r;
+ struct usb_device *udev = zd_usb_to_usbdev(usb);
+ struct urb *urb;
+ void *buffer;
+
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!urb) {
+ r = -ENOMEM;
+ goto out;
+ }
+
+ buffer = usb_buffer_alloc(zd_usb_to_usbdev(usb), length, GFP_ATOMIC,
+ &urb->transfer_dma);
+ if (!buffer) {
+ r = -ENOMEM;
+ goto error_free_urb;
+ }
+ memcpy(buffer, frame, length);
+
+ usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, EP_DATA_OUT),
+ buffer, length, tx_urb_complete, NULL);
+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+ r = usb_submit_urb(urb, GFP_ATOMIC);
+ if (r)
+ goto error;
+ return 0;
+error:
+ usb_buffer_free(zd_usb_to_usbdev(usb), length, buffer,
+ urb->transfer_dma);
+error_free_urb:
+ usb_free_urb(urb);
+out:
+ return r;
+}
+
+static inline void init_usb_interrupt(struct zd_usb *usb)
+{
+ struct zd_usb_interrupt *intr = &usb->intr;
+
+ spin_lock_init(&intr->lock);
+ intr->interval = int_urb_interval(zd_usb_to_usbdev(usb));
+ init_completion(&intr->read_regs.completion);
+ intr->read_regs.cr_int_addr = cpu_to_le16(usb_addr(usb, CR_INTERRUPT));
+}
+
+static inline void init_usb_rx(struct zd_usb *usb)
+{
+ struct zd_usb_rx *rx = &usb->rx;
+ spin_lock_init(&rx->lock);
+ if (interface_to_usbdev(usb->intf)->speed == USB_SPEED_HIGH) {
+ rx->usb_packet_size = 512;
+ } else {
+ rx->usb_packet_size = 64;
+ }
+ ZD_ASSERT(rx->fragment_length == 0);
+}
+
+static inline void init_usb_tx(struct zd_usb *usb)
+{
+ /* FIXME: at this point we will allocate a fixed number of urb's for
+ * use in a cyclic scheme */
+}
+
+void zd_usb_init(struct zd_usb *usb, struct net_device *netdev,
+ struct usb_interface *intf)
+{
+ memset(usb, 0, sizeof(*usb));
+ usb->intf = usb_get_intf(intf);
+ usb_set_intfdata(usb->intf, netdev);
+ init_usb_interrupt(usb);
+ init_usb_tx(usb);
+ init_usb_rx(usb);
+}
+
+int zd_usb_init_hw(struct zd_usb *usb)
+{
+ int r;
+ struct zd_chip *chip = zd_usb_to_chip(usb);
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ r = zd_ioread16_locked(chip, &usb->fw_base_offset,
+ USB_REG((u16)FW_BASE_ADDR_OFFSET));
+ if (r)
+ return r;
+ dev_dbg_f(zd_usb_dev(usb), "fw_base_offset: %#06hx\n",
+ usb->fw_base_offset);
+
+ return 0;
+}
+
+void zd_usb_clear(struct zd_usb *usb)
+{
+ usb_set_intfdata(usb->intf, NULL);
+ usb_put_intf(usb->intf);
+ memset(usb, 0, sizeof(*usb));
+ /* FIXME: usb_interrupt, usb_tx, usb_rx? */
+}
+
+static const char *speed(enum usb_device_speed speed)
+{
+ switch (speed) {
+ case USB_SPEED_LOW:
+ return "low";
+ case USB_SPEED_FULL:
+ return "full";
+ case USB_SPEED_HIGH:
+ return "high";
+ default:
+ return "unknown speed";
+ }
+}
+
+static int scnprint_id(struct usb_device *udev, char *buffer, size_t size)
+{
+ return scnprintf(buffer, size, "%04hx:%04hx v%04hx %s",
+ le16_to_cpu(udev->descriptor.idVendor),
+ le16_to_cpu(udev->descriptor.idProduct),
+ get_bcdDevice(udev),
+ speed(udev->speed));
+}
+
+int zd_usb_scnprint_id(struct zd_usb *usb, char *buffer, size_t size)
+{
+ struct usb_device *udev = interface_to_usbdev(usb->intf);
+ return scnprint_id(udev, buffer, size);
+}
+
+#ifdef DEBUG
+static void print_id(struct usb_device *udev)
+{
+ char buffer[40];
+
+ scnprint_id(udev, buffer, sizeof(buffer));
+ buffer[sizeof(buffer)-1] = 0;
+ dev_dbg_f(&udev->dev, "%s\n", buffer);
+}
+#else
+#define print_id(udev) do { } while (0)
+#endif
+
+static int probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+ int r;
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct net_device *netdev = NULL;
+
+ print_id(udev);
+
+ switch (udev->speed) {
+ case USB_SPEED_LOW:
+ case USB_SPEED_FULL:
+ case USB_SPEED_HIGH:
+ break;
+ default:
+ dev_dbg_f(&intf->dev, "Unknown USB speed\n");
+ r = -ENODEV;
+ goto error;
+ }
+
+ netdev = zd_netdev_alloc(intf);
+ if (netdev == NULL) {
+ r = -ENOMEM;
+ goto error;
+ }
+
+ r = upload_firmware(udev, id->driver_info);
+ if (r) {
+ dev_err(&intf->dev,
+ "couldn't load firmware. Error number %d\n", r);
+ goto error;
+ }
+
+ r = usb_reset_configuration(udev);
+ if (r) {
+ dev_dbg_f(&intf->dev,
+ "couldn't reset configuration. Error number %d\n", r);
+ goto error;
+ }
+
+ /* At this point the interrupt endpoint is not generally enabled. We
+ * save the USB bandwidth until the network device is opened. But
+ * notify that the initialization of the MAC will require the
+ * interrupts to be temporary enabled.
+ */
+ r = zd_mac_init_hw(zd_netdev_mac(netdev), id->driver_info);
+ if (r) {
+ dev_dbg_f(&intf->dev,
+ "couldn't initialize mac. Error number %d\n", r);
+ goto error;
+ }
+
+ r = register_netdev(netdev);
+ if (r) {
+ dev_dbg_f(&intf->dev,
+ "couldn't register netdev. Error number %d\n", r);
+ goto error;
+ }
+
+ dev_dbg_f(&intf->dev, "successful\n");
+ dev_info(&intf->dev,"%s\n", netdev->name);
+ return 0;
+error:
+ usb_reset_device(interface_to_usbdev(intf));
+ zd_netdev_free(netdev);
+ return r;
+}
+
+static void disconnect(struct usb_interface *intf)
+{
+ struct net_device *netdev = zd_intf_to_netdev(intf);
+ struct zd_mac *mac = zd_netdev_mac(netdev);
+ struct zd_usb *usb = &mac->chip.usb;
+
+ dev_dbg_f(zd_usb_dev(usb), "\n");
+
+ zd_netdev_disconnect(netdev);
+
+ /* Just in case something has gone wrong! */
+ zd_usb_disable_rx(usb);
+ zd_usb_disable_int(usb);
+
+ /* If the disconnect has been caused by a removal of the
+ * driver module, the reset allows reloading of the driver. If the
+ * reset will not be executed here, the upload of the firmware in the
+ * probe function caused by the reloading of the driver will fail.
+ */
+ usb_reset_device(interface_to_usbdev(intf));
+
+ /* If somebody still waits on this lock now, this is an error. */
+ zd_netdev_free(netdev);
+ dev_dbg(&intf->dev, "disconnected\n");
+}
+
+static struct usb_driver driver = {
+ .name = "zd1211rw",
+ .id_table = usb_ids,
+ .probe = probe,
+ .disconnect = disconnect,
+};
+
+static int __init usb_init(void)
+{
+ int r;
+
+ pr_debug("usb_init()\n");
+
+ r = usb_register(&driver);
+ if (r) {
+ printk(KERN_ERR "usb_register() failed. Error number %d\n", r);
+ return r;
+ }
+
+ pr_debug("zd1211rw initialized\n");
+ return 0;
+}
+
+static void __exit usb_exit(void)
+{
+ pr_debug("usb_exit()\n");
+ usb_deregister(&driver);
+}
+
+module_init(usb_init);
+module_exit(usb_exit);
+
+static int usb_int_regs_length(unsigned int count)
+{
+ return sizeof(struct usb_int_regs) + count * sizeof(struct reg_data);
+}
+
+static void prepare_read_regs_int(struct zd_usb *usb)
+{
+ struct zd_usb_interrupt *intr = &usb->intr;
+
+ spin_lock(&intr->lock);
+ intr->read_regs_enabled = 1;
+ INIT_COMPLETION(intr->read_regs.completion);
+ spin_unlock(&intr->lock);
+}
+
+static int get_results(struct zd_usb *usb, u16 *values,
+ struct usb_req_read_regs *req, unsigned int count)
+{
+ int r;
+ int i;
+ struct zd_usb_interrupt *intr = &usb->intr;
+ struct read_regs_int *rr = &intr->read_regs;
+ struct usb_int_regs *regs = (struct usb_int_regs *)rr->buffer;
+
+ spin_lock(&intr->lock);
+
+ r = -EIO;
+ /* The created block size seems to be larger than expected.
+ * However results appear to be correct.
+ */
+ if (rr->length < usb_int_regs_length(count)) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error: actual length %d less than expected %d\n",
+ rr->length, usb_int_regs_length(count));
+ goto error_unlock;
+ }
+ if (rr->length > sizeof(rr->buffer)) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error: actual length %d exceeds buffer size %zu\n",
+ rr->length, sizeof(rr->buffer));
+ goto error_unlock;
+ }
+
+ for (i = 0; i < count; i++) {
+ struct reg_data *rd = &regs->regs[i];
+ if (rd->addr != req->addr[i]) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "rd[%d] addr %#06hx expected %#06hx\n", i,
+ le16_to_cpu(rd->addr),
+ le16_to_cpu(req->addr[i]));
+ goto error_unlock;
+ }
+ values[i] = le16_to_cpu(rd->value);
+ }
+
+ r = 0;
+error_unlock:
+ spin_unlock(&intr->lock);
+ return r;
+}
+
+int zd_usb_ioread16v(struct zd_usb *usb, u16 *values,
+ const zd_addr_t *addresses, unsigned int count)
+{
+ int r;
+ int i, req_len, actual_req_len;
+ struct usb_device *udev;
+ struct usb_req_read_regs *req = NULL;
+ unsigned long timeout;
+
+ if (count < 1) {
+ dev_dbg_f(zd_usb_dev(usb), "error: count is zero\n");
+ return -EINVAL;
+ }
+ if (count > USB_MAX_IOREAD16_COUNT) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error: count %u exceeds possible max %u\n",
+ count, USB_MAX_IOREAD16_COUNT);
+ return -EINVAL;
+ }
+ if (in_atomic()) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error: io in atomic context not supported\n");
+ return -EWOULDBLOCK;
+ }
+ if (!usb_int_enabled(usb)) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error: usb interrupt not enabled\n");
+ return -EWOULDBLOCK;
+ }
+
+ req_len = sizeof(struct usb_req_read_regs) + count * sizeof(__le16);
+ req = kmalloc(req_len, GFP_NOFS);
+ if (!req)
+ return -ENOMEM;
+ req->id = cpu_to_le16(USB_REQ_READ_REGS);
+ for (i = 0; i < count; i++)
+ req->addr[i] = cpu_to_le16(usb_addr(usb, addresses[i]));
+
+ udev = zd_usb_to_usbdev(usb);
+ prepare_read_regs_int(usb);
+ r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, EP_REGS_OUT),
+ req, req_len, &actual_req_len, 1000 /* ms */);
+ if (r) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error in usb_bulk_msg(). Error number %d\n", r);
+ goto error;
+ }
+ if (req_len != actual_req_len) {
+ dev_dbg_f(zd_usb_dev(usb), "error in usb_bulk_msg()\n"
+ " req_len %d != actual_req_len %d\n",
+ req_len, actual_req_len);
+ r = -EIO;
+ goto error;
+ }
+
+ timeout = wait_for_completion_timeout(&usb->intr.read_regs.completion,
+ msecs_to_jiffies(1000));
+ if (!timeout) {
+ disable_read_regs_int(usb);
+ dev_dbg_f(zd_usb_dev(usb), "read timed out\n");
+ r = -ETIMEDOUT;
+ goto error;
+ }
+
+ r = get_results(usb, values, req, count);
+error:
+ kfree(req);
+ return r;
+}
+
+int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs,
+ unsigned int count)
+{
+ int r;
+ struct usb_device *udev;
+ struct usb_req_write_regs *req = NULL;
+ int i, req_len, actual_req_len;
+
+ if (count == 0)
+ return 0;
+ if (count > USB_MAX_IOWRITE16_COUNT) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error: count %u exceeds possible max %u\n",
+ count, USB_MAX_IOWRITE16_COUNT);
+ return -EINVAL;
+ }
+ if (in_atomic()) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error: io in atomic context not supported\n");
+ return -EWOULDBLOCK;
+ }
+
+ req_len = sizeof(struct usb_req_write_regs) +
+ count * sizeof(struct reg_data);
+ req = kmalloc(req_len, GFP_NOFS);
+ if (!req)
+ return -ENOMEM;
+
+ req->id = cpu_to_le16(USB_REQ_WRITE_REGS);
+ for (i = 0; i < count; i++) {
+ struct reg_data *rw = &req->reg_writes[i];
+ rw->addr = cpu_to_le16(usb_addr(usb, ioreqs[i].addr));
+ rw->value = cpu_to_le16(ioreqs[i].value);
+ }
+
+ udev = zd_usb_to_usbdev(usb);
+ r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, EP_REGS_OUT),
+ req, req_len, &actual_req_len, 1000 /* ms */);
+ if (r) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error in usb_bulk_msg(). Error number %d\n", r);
+ goto error;
+ }
+ if (req_len != actual_req_len) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error in usb_bulk_msg()"
+ " req_len %d != actual_req_len %d\n",
+ req_len, actual_req_len);
+ r = -EIO;
+ goto error;
+ }
+
+ /* FALL-THROUGH with r == 0 */
+error:
+ kfree(req);
+ return r;
+}
+
+int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits)
+{
+ int r;
+ struct usb_device *udev;
+ struct usb_req_rfwrite *req = NULL;
+ int i, req_len, actual_req_len;
+ u16 bit_value_template;
+
+ if (in_atomic()) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error: io in atomic context not supported\n");
+ return -EWOULDBLOCK;
+ }
+ if (bits < USB_MIN_RFWRITE_BIT_COUNT) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error: bits %d are smaller than"
+ " USB_MIN_RFWRITE_BIT_COUNT %d\n",
+ bits, USB_MIN_RFWRITE_BIT_COUNT);
+ return -EINVAL;
+ }
+ if (bits > USB_MAX_RFWRITE_BIT_COUNT) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error: bits %d exceed USB_MAX_RFWRITE_BIT_COUNT %d\n",
+ bits, USB_MAX_RFWRITE_BIT_COUNT);
+ return -EINVAL;
+ }
+#ifdef DEBUG
+ if (value & (~0UL << bits)) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error: value %#09x has bits >= %d set\n",
+ value, bits);
+ return -EINVAL;
+ }
+#endif /* DEBUG */
+
+ dev_dbg_f(zd_usb_dev(usb), "value %#09x bits %d\n", value, bits);
+
+ r = zd_usb_ioread16(usb, &bit_value_template, CR203);
+ if (r) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error %d: Couldn't read CR203\n", r);
+ goto out;
+ }
+ bit_value_template &= ~(RF_IF_LE|RF_CLK|RF_DATA);
+
+ req_len = sizeof(struct usb_req_rfwrite) + bits * sizeof(__le16);
+ req = kmalloc(req_len, GFP_NOFS);
+ if (!req)
+ return -ENOMEM;
+
+ req->id = cpu_to_le16(USB_REQ_WRITE_RF);
+ /* 1: 3683a, but not used in ZYDAS driver */
+ req->value = cpu_to_le16(2);
+ req->bits = cpu_to_le16(bits);
+
+ for (i = 0; i < bits; i++) {
+ u16 bv = bit_value_template;
+ if (value & (1 << (bits-1-i)))
+ bv |= RF_DATA;
+ req->bit_values[i] = cpu_to_le16(bv);
+ }
+
+ udev = zd_usb_to_usbdev(usb);
+ r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, EP_REGS_OUT),
+ req, req_len, &actual_req_len, 1000 /* ms */);
+ if (r) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error in usb_bulk_msg(). Error number %d\n", r);
+ goto out;
+ }
+ if (req_len != actual_req_len) {
+ dev_dbg_f(zd_usb_dev(usb), "error in usb_bulk_msg()"
+ " req_len %d != actual_req_len %d\n",
+ req_len, actual_req_len);
+ r = -EIO;
+ goto out;
+ }
+
+ /* FALL-THROUGH with r == 0 */
+out:
+ kfree(req);
+ return r;
+}
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h
new file mode 100644
index 00000000000..d6420283bd5
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_usb.h
@@ -0,0 +1,240 @@
+/* zd_usb.h: Header for USB interface implemented by ZD1211 chip
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _ZD_USB_H
+#define _ZD_USB_H
+
+#include <linux/completion.h>
+#include <linux/netdevice.h>
+#include <linux/spinlock.h>
+#include <linux/skbuff.h>
+#include <linux/usb.h>
+
+#include "zd_def.h"
+#include "zd_types.h"
+
+enum devicetype {
+ DEVICE_ZD1211 = 0,
+ DEVICE_ZD1211B = 1,
+};
+
+enum endpoints {
+ EP_CTRL = 0,
+ EP_DATA_OUT = 1,
+ EP_DATA_IN = 2,
+ EP_INT_IN = 3,
+ EP_REGS_OUT = 4,
+};
+
+enum {
+ USB_MAX_TRANSFER_SIZE = 4096, /* bytes */
+ /* FIXME: The original driver uses this value. We have to check,
+ * whether the MAX_TRANSFER_SIZE is sufficient and this needs only be
+ * used if one combined frame is split over two USB transactions.
+ */
+ USB_MAX_RX_SIZE = 4800, /* bytes */
+ USB_MAX_IOWRITE16_COUNT = 15,
+ USB_MAX_IOWRITE32_COUNT = USB_MAX_IOWRITE16_COUNT/2,
+ USB_MAX_IOREAD16_COUNT = 15,
+ USB_MAX_IOREAD32_COUNT = USB_MAX_IOREAD16_COUNT/2,
+ USB_MIN_RFWRITE_BIT_COUNT = 16,
+ USB_MAX_RFWRITE_BIT_COUNT = 28,
+ USB_MAX_EP_INT_BUFFER = 64,
+ USB_ZD1211B_BCD_DEVICE = 0x4810,
+};
+
+enum control_requests {
+ USB_REQ_WRITE_REGS = 0x21,
+ USB_REQ_READ_REGS = 0x22,
+ USB_REQ_WRITE_RF = 0x23,
+ USB_REQ_PROG_FLASH = 0x24,
+ USB_REQ_EEPROM_START = 0x0128, /* ? request is a byte */
+ USB_REQ_EEPROM_MID = 0x28,
+ USB_REQ_EEPROM_END = 0x0228, /* ? request is a byte */
+ USB_REQ_FIRMWARE_DOWNLOAD = 0x30,
+ USB_REQ_FIRMWARE_CONFIRM = 0x31,
+ USB_REQ_FIRMWARE_READ_DATA = 0x32,
+};
+
+struct usb_req_read_regs {
+ __le16 id;
+ __le16 addr[0];
+} __attribute__((packed));
+
+struct reg_data {
+ __le16 addr;
+ __le16 value;
+} __attribute__((packed));
+
+struct usb_req_write_regs {
+ __le16 id;
+ struct reg_data reg_writes[0];
+} __attribute__((packed));
+
+enum {
+ RF_IF_LE = 0x02,
+ RF_CLK = 0x04,
+ RF_DATA = 0x08,
+};
+
+struct usb_req_rfwrite {
+ __le16 id;
+ __le16 value;
+ /* 1: 3683a */
+ /* 2: other (default) */
+ __le16 bits;
+ /* RF2595: 24 */
+ __le16 bit_values[0];
+ /* (CR203 & ~(RF_IF_LE | RF_CLK | RF_DATA)) | (bit ? RF_DATA : 0) */
+} __attribute__((packed));
+
+/* USB interrupt */
+
+enum usb_int_id {
+ USB_INT_TYPE = 0x01,
+ USB_INT_ID_REGS = 0x90,
+ USB_INT_ID_RETRY_FAILED = 0xa0,
+};
+
+enum usb_int_flags {
+ USB_INT_READ_REGS_EN = 0x01,
+};
+
+struct usb_int_header {
+ u8 type; /* must always be 1 */
+ u8 id;
+} __attribute__((packed));
+
+struct usb_int_regs {
+ struct usb_int_header hdr;
+ struct reg_data regs[0];
+} __attribute__((packed));
+
+struct usb_int_retry_fail {
+ struct usb_int_header hdr;
+ u8 new_rate;
+ u8 _dummy;
+ u8 addr[ETH_ALEN];
+ u8 ibss_wakeup_dest;
+} __attribute__((packed));
+
+struct read_regs_int {
+ struct completion completion;
+ /* Stores the USB int structure and contains the USB address of the
+ * first requested register before request.
+ */
+ u8 buffer[USB_MAX_EP_INT_BUFFER];
+ int length;
+ __le16 cr_int_addr;
+};
+
+struct zd_ioreq16 {
+ zd_addr_t addr;
+ u16 value;
+};
+
+struct zd_ioreq32 {
+ zd_addr_t addr;
+ u32 value;
+};
+
+struct zd_usb_interrupt {
+ struct read_regs_int read_regs;
+ spinlock_t lock;
+ struct urb *urb;
+ int interval;
+ u8 read_regs_enabled:1;
+};
+
+static inline struct usb_int_regs *get_read_regs(struct zd_usb_interrupt *intr)
+{
+ return (struct usb_int_regs *)intr->read_regs.buffer;
+}
+
+#define URBS_COUNT 5
+
+struct zd_usb_rx {
+ spinlock_t lock;
+ u8 fragment[2*USB_MAX_RX_SIZE];
+ unsigned int fragment_length;
+ unsigned int usb_packet_size;
+ struct urb **urbs;
+ int urbs_count;
+};
+
+struct zd_usb_tx {
+ spinlock_t lock;
+};
+
+/* Contains the usb parts. The structure doesn't require a lock, because intf
+ * and fw_base_offset, will not be changed after initialization.
+ */
+struct zd_usb {
+ struct zd_usb_interrupt intr;
+ struct zd_usb_rx rx;
+ struct zd_usb_tx tx;
+ struct usb_interface *intf;
+ u16 fw_base_offset;
+};
+
+#define zd_usb_dev(usb) (&usb->intf->dev)
+
+static inline struct usb_device *zd_usb_to_usbdev(struct zd_usb *usb)
+{
+ return interface_to_usbdev(usb->intf);
+}
+
+static inline struct net_device *zd_intf_to_netdev(struct usb_interface *intf)
+{
+ return usb_get_intfdata(intf);
+}
+
+static inline struct net_device *zd_usb_to_netdev(struct zd_usb *usb)
+{
+ return zd_intf_to_netdev(usb->intf);
+}
+
+void zd_usb_init(struct zd_usb *usb, struct net_device *netdev,
+ struct usb_interface *intf);
+int zd_usb_init_hw(struct zd_usb *usb);
+void zd_usb_clear(struct zd_usb *usb);
+
+int zd_usb_scnprint_id(struct zd_usb *usb, char *buffer, size_t size);
+
+int zd_usb_enable_int(struct zd_usb *usb);
+void zd_usb_disable_int(struct zd_usb *usb);
+
+int zd_usb_enable_rx(struct zd_usb *usb);
+void zd_usb_disable_rx(struct zd_usb *usb);
+
+int zd_usb_tx(struct zd_usb *usb, const u8 *frame, unsigned int length);
+
+int zd_usb_ioread16v(struct zd_usb *usb, u16 *values,
+ const zd_addr_t *addresses, unsigned int count);
+
+static inline int zd_usb_ioread16(struct zd_usb *usb, u16 *value,
+ const zd_addr_t addr)
+{
+ return zd_usb_ioread16v(usb, value, (const zd_addr_t *)&addr, 1);
+}
+
+int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs,
+ unsigned int count);
+
+int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits);
+
+#endif /* _ZD_USB_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_util.c b/drivers/net/wireless/zd1211rw/zd_util.c
new file mode 100644
index 00000000000..d20036c15d1
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_util.c
@@ -0,0 +1,82 @@
+/* zd_util.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Utility program
+ */
+
+#include "zd_def.h"
+#include "zd_util.h"
+
+#ifdef DEBUG
+static char hex(u8 v)
+{
+ v &= 0xf;
+ return (v < 10 ? '0' : 'a' - 10) + v;
+}
+
+static char hex_print(u8 c)
+{
+ return (0x20 <= c && c < 0x7f) ? c : '.';
+}
+
+static void dump_line(const u8 *bytes, size_t size)
+{
+ char c;
+ size_t i;
+
+ size = size <= 8 ? size : 8;
+ printk(KERN_DEBUG "zd1211 %p ", bytes);
+ for (i = 0; i < 8; i++) {
+ switch (i) {
+ case 1:
+ case 5:
+ c = '.';
+ break;
+ case 3:
+ c = ':';
+ break;
+ default:
+ c = ' ';
+ }
+ if (i < size) {
+ printk("%c%c%c", hex(bytes[i] >> 4), hex(bytes[i]), c);
+ } else {
+ printk(" %c", c);
+ }
+ }
+
+ for (i = 0; i < size; i++)
+ printk("%c", hex_print(bytes[i]));
+ printk("\n");
+}
+
+void zd_hexdump(const void *bytes, size_t size)
+{
+ size_t i = 0;
+
+ do {
+ dump_line((u8 *)bytes + i, size-i);
+ i += 8;
+ } while (i < size);
+}
+#endif /* DEBUG */
+
+void *zd_tail(const void *buffer, size_t buffer_size, size_t tail_size)
+{
+ if (buffer_size < tail_size)
+ return NULL;
+ return (u8 *)buffer + (buffer_size - tail_size);
+}
diff --git a/drivers/w1/w1_io.h b/drivers/net/wireless/zd1211rw/zd_util.h
index 9a76d2ad69c..ce26f7adea9 100644
--- a/drivers/w1/w1_io.h
+++ b/drivers/net/wireless/zd1211rw/zd_util.h
@@ -1,8 +1,4 @@
-/*
- * w1_io.h
- *
- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
- *
+/* zd_util.h
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,18 +15,15 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#ifndef __W1_IO_H
-#define __W1_IO_H
+#ifndef _ZD_UTIL_H
+#define _ZD_UTIL_H
-#include "w1.h"
+void *zd_tail(const void *buffer, size_t buffer_size, size_t tail_size);
-u8 w1_triplet(struct w1_master *dev, int bdir);
-void w1_write_8(struct w1_master *, u8);
-int w1_reset_bus(struct w1_master *);
-u8 w1_calc_crc8(u8 *, int);
-void w1_write_block(struct w1_master *, const u8 *, int);
-u8 w1_read_block(struct w1_master *, u8 *, int);
-void w1_search_devices(struct w1_master *dev, w1_slave_found_callback cb);
-int w1_reset_select_slave(struct w1_slave *sl);
+#ifdef DEBUG
+void zd_hexdump(const void *bytes, size_t size);
+#else
+#define zd_hexdump(bytes, size)
+#endif /* DEBUG */
-#endif /* __W1_IO_H */
+#endif /* _ZD_UTIL_H */
diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
index bbbf7e274a2..8459a18254a 100644
--- a/drivers/net/yellowfin.c
+++ b/drivers/net/yellowfin.c
@@ -19,37 +19,13 @@
Support and updates available at
http://www.scyld.com/network/yellowfin.html
+ [link no longer provides useful info -jgarzik]
-
- Linux kernel changelog:
- -----------------------
-
- LK1.1.1 (jgarzik): Port to 2.4 kernel
-
- LK1.1.2 (jgarzik):
- * Merge in becker version 1.05
-
- LK1.1.3 (jgarzik):
- * Various cleanups
- * Update yellowfin_timer to correctly calculate duplex.
- (suggested by Manfred Spraul)
-
- LK1.1.4 (val@nmt.edu):
- * Fix three endian-ness bugs
- * Support dual function SYM53C885E ethernet chip
-
- LK1.1.5 (val@nmt.edu):
- * Fix forced full-duplex bug I introduced
-
- LK1.1.6 (val@nmt.edu):
- * Only print warning on truly "oversized" packets
- * Fix theoretical bug on gigabit cards - return to 1.1.3 behavior
-
*/
#define DRV_NAME "yellowfin"
-#define DRV_VERSION "1.05+LK1.1.6"
-#define DRV_RELDATE "Feb 11, 2002"
+#define DRV_VERSION "2.0"
+#define DRV_RELDATE "Jun 27, 2006"
#define PFX DRV_NAME ": "
@@ -239,8 +215,11 @@ enum capability_flags {
HasMACAddrBug=32, /* Only on early revs. */
DontUseEeprom=64, /* Don't read the MAC from the EEPROm. */
};
+
/* The PCI I/O space extent. */
-#define YELLOWFIN_SIZE 0x100
+enum {
+ YELLOWFIN_SIZE = 0x100,
+};
struct pci_id_info {
const char *name;
@@ -248,16 +227,14 @@ struct pci_id_info {
int pci, pci_mask, subsystem, subsystem_mask;
int revision, revision_mask; /* Only 8 bits. */
} id;
- int io_size; /* Needed for I/O region check or ioremap(). */
int drv_flags; /* Driver use, intended as capability flags. */
};
static const struct pci_id_info pci_id_tbl[] = {
{"Yellowfin G-NIC Gigabit Ethernet", { 0x07021000, 0xffffffff},
- YELLOWFIN_SIZE,
FullTxStatus | IsGigabit | HasMulticastBug | HasMACAddrBug | DontUseEeprom},
{"Symbios SYM83C885", { 0x07011000, 0xffffffff},
- YELLOWFIN_SIZE, HasMII | DontUseEeprom },
+ HasMII | DontUseEeprom },
{ }
};
diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig
index 222a1cc4aa2..3fae77ffb2f 100644
--- a/drivers/pci/hotplug/Kconfig
+++ b/drivers/pci/hotplug/Kconfig
@@ -6,8 +6,7 @@ menu "PCI Hotplug Support"
config HOTPLUG_PCI
tristate "Support for PCI Hotplug (EXPERIMENTAL)"
- depends on PCI && EXPERIMENTAL
- select HOTPLUG
+ depends on PCI && EXPERIMENTAL && HOTPLUG
---help---
Say Y here if you have a motherboard with a PCI Hotplug controller.
This allows you to add and remove PCI cards while the machine is
@@ -77,7 +76,7 @@ config HOTPLUG_PCI_IBM
config HOTPLUG_PCI_ACPI
tristate "ACPI PCI Hotplug driver"
- depends on ACPI && HOTPLUG_PCI
+ depends on ACPI_DOCK && HOTPLUG_PCI
help
Say Y here if you have a system that supports PCI Hotplug using
ACPI.
diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c
index 34de5697983..e2fef60c2d0 100644
--- a/drivers/pci/hotplug/acpiphp_core.c
+++ b/drivers/pci/hotplug/acpiphp_core.c
@@ -27,8 +27,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * Send feedback to <gregkh@us.ibm.com>,
- * <t-kochi@bq.jp.nec.com>
+ * Send feedback to <kristen.c.accardi@intel.com>
*
*/
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index ef95d12fb32..ae67a8f55ba 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -26,7 +26,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * Send feedback to <t-kochi@bq.jp.nec.com>
+ * Send feedback to <kristen.c.accardi@intel.com>
*
*/
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 36bc7c415af..a83c1f5735d 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -47,13 +47,13 @@ msi_register(struct msi_ops *ops)
static void msi_cache_ctor(void *p, kmem_cache_t *cache, unsigned long flags)
{
- memset(p, 0, NR_IRQS * sizeof(struct msi_desc));
+ memset(p, 0, sizeof(struct msi_desc));
}
static int msi_cache_init(void)
{
msi_cachep = kmem_cache_create("msi_cache",
- NR_IRQS * sizeof(struct msi_desc),
+ sizeof(struct msi_desc),
0, SLAB_HWCACHE_ALIGN, msi_cache_ctor, NULL);
if (!msi_cachep)
return -ENOMEM;
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index cf57d7de376..9f79dd6d51a 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -19,6 +19,7 @@
#include <asm/dma.h> /* isa_dma_bridge_buggy */
#include "pci.h"
+unsigned int pci_pm_d3_delay = 10;
/**
* pci_bus_max_busnr - returns maximum PCI bus number of given bus' children
@@ -313,6 +314,14 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state)
} else if (dev->current_state == state)
return 0; /* we're already there */
+ /*
+ * If the device or the parent bridge can't support PCI PM, ignore
+ * the request if we're doing anything besides putting it into D0
+ * (which would only happen on boot).
+ */
+ if ((state == PCI_D1 || state == PCI_D2) && pci_no_d1d2(dev))
+ return 0;
+
/* find PCI PM capability in list */
pm = pci_find_capability(dev, PCI_CAP_ID_PM);
@@ -363,7 +372,7 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state)
/* Mandatory power management transition delays */
/* see PCI PM 1.1 5.6.1 table 18 */
if (state == PCI_D3hot || dev->current_state == PCI_D3hot)
- msleep(10);
+ msleep(pci_pm_d3_delay);
else if (state == PCI_D2 || dev->current_state == PCI_D2)
udelay(200);
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 9cc842b666e..08d58fc78ee 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -47,7 +47,7 @@ extern int pci_msi_quirk;
#else
#define pci_msi_quirk 0
#endif
-
+extern unsigned int pci_pm_d3_delay;
#ifdef CONFIG_PCI_MSI
void disable_msi_mode(struct pci_dev *dev, int pos, int type);
void pci_no_msi(void);
@@ -66,7 +66,15 @@ static inline int pci_save_msix_state(struct pci_dev *dev) { return 0; }
static inline void pci_restore_msi_state(struct pci_dev *dev) {}
static inline void pci_restore_msix_state(struct pci_dev *dev) {}
#endif
+static inline int pci_no_d1d2(struct pci_dev *dev)
+{
+ unsigned int parent_dstates = 0;
+ if (dev->bus->self)
+ parent_dstates = dev->bus->self->no_d1d2;
+ return (dev->no_d1d2 || parent_dstates);
+
+}
extern int pcie_mch_quirk;
extern struct device_attribute pci_dev_attrs[];
extern struct class_device_attribute class_device_attr_cpuaffinity;
diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c
index 50bfc1b2f3b..478d0d28f7a 100644
--- a/drivers/pci/pcie/portdrv_pci.c
+++ b/drivers/pci/pcie/portdrv_pci.c
@@ -30,23 +30,6 @@ MODULE_LICENSE("GPL");
/* global data */
static const char device_name[] = "pcieport-driver";
-static int pcie_portdrv_save_config(struct pci_dev *dev)
-{
- return pci_save_state(dev);
-}
-
-static int pcie_portdrv_restore_config(struct pci_dev *dev)
-{
- int retval;
-
- pci_restore_state(dev);
- retval = pci_enable_device(dev);
- if (retval)
- return retval;
- pci_set_master(dev);
- return 0;
-}
-
/*
* pcie_portdrv_probe - Probe PCI-Express port devices
* @dev: PCI-Express port device being probed
@@ -73,8 +56,10 @@ static int __devinit pcie_portdrv_probe (struct pci_dev *dev,
"%s->Dev[%04x:%04x] has invalid IRQ. Check vendor BIOS\n",
__FUNCTION__, dev->device, dev->vendor);
}
- if (pcie_port_device_register(dev))
+ if (pcie_port_device_register(dev)) {
+ pci_disable_device(dev);
return -ENOMEM;
+ }
return 0;
}
@@ -86,6 +71,23 @@ static void pcie_portdrv_remove (struct pci_dev *dev)
}
#ifdef CONFIG_PM
+static int pcie_portdrv_save_config(struct pci_dev *dev)
+{
+ return pci_save_state(dev);
+}
+
+static int pcie_portdrv_restore_config(struct pci_dev *dev)
+{
+ int retval;
+
+ pci_restore_state(dev);
+ retval = pci_enable_device(dev);
+ if (retval)
+ return retval;
+ pci_set_master(dev);
+ return 0;
+}
+
static int pcie_portdrv_suspend (struct pci_dev *dev, pm_message_t state)
{
int ret = pcie_port_device_suspend(dev, state);
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index f89dbc3738b..c5a58d1c6c1 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -815,6 +815,7 @@ pci_scan_device(struct pci_bus *bus, int devfn)
dev->vendor = l & 0xffff;
dev->device = (l >> 16) & 0xffff;
dev->cfg_size = pci_cfg_space_size(dev);
+ dev->error_state = pci_channel_io_normal;
/* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer)
set this higher, assuming the system even supports it. */
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index d1d7333bb71..fb08bc951ac 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -400,6 +400,7 @@ static void __devinit quirk_piix4_acpi(struct pci_dev *dev)
piix4_io_quirk(dev, "PIIX4 devres J", 0x7c, 1 << 20);
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, quirk_piix4_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3, quirk_piix4_acpi );
/*
* ICH4, ICH4-M, ICH5, ICH5-M ACPI: Three IO regions pointed to by longwords at
@@ -682,6 +683,33 @@ static void __devinit quirk_vt82c598_id(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_vt82c598_id );
+#ifdef CONFIG_ACPI_SLEEP
+
+/*
+ * Some VIA systems boot with the abnormal status flag set. This can cause
+ * the BIOS to re-POST the system on resume rather than passing control
+ * back to the OS. Clear the flag on boot
+ */
+static void __devinit quirk_via_abnormal_poweroff(struct pci_dev *dev)
+{
+ u32 reg;
+
+ acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_STATUS,
+ &reg);
+
+ if (reg & 0x800) {
+ printk("Clearing abnormal poweroff flag\n");
+ acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
+ ACPI_REGISTER_PM1_STATUS,
+ (u16)0x800);
+ }
+}
+
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, quirk_via_abnormal_poweroff);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, quirk_via_abnormal_poweroff);
+
+#endif
+
/*
* CardBus controllers have a legacy base address that enables them
* to respond as i82365 pcmcia controllers. We don't want them to
@@ -962,6 +990,11 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev)
case 0x8070: /* P4G8X Deluxe */
asus_hides_smbus = 1;
}
+ if (dev->device == PCI_DEVICE_ID_INTEL_E7501_MCH)
+ switch (dev->subsystem_device) {
+ case 0x80c9: /* PU-DLS */
+ asus_hides_smbus = 1;
+ }
if (dev->device == PCI_DEVICE_ID_INTEL_82855GM_HB)
switch (dev->subsystem_device) {
case 0x1751: /* M2N notebook */
@@ -1030,6 +1063,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845G_HB, asu
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82850_HB, asus_hides_smbus_hostbridge );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82865_HB, asus_hides_smbus_hostbridge );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_7205_0, asus_hides_smbus_hostbridge );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7501_MCH, asus_hides_smbus_hostbridge );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855PM_HB, asus_hides_smbus_hostbridge );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855GM_HB, asus_hides_smbus_hostbridge );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82915GM_HB, asus_hides_smbus_hostbridge );
@@ -1053,6 +1087,7 @@ static void __init asus_hides_smbus_lpc(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, asus_hides_smbus_lpc );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, asus_hides_smbus_lpc );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, asus_hides_smbus_lpc );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, asus_hides_smbus_lpc );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, asus_hides_smbus_lpc );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, asus_hides_smbus_lpc );
@@ -1174,6 +1209,55 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus );
+#if defined(CONFIG_SCSI_SATA) || defined(CONFIG_SCSI_SATA_MODULE)
+
+/*
+ * If we are using libata we can drive this chip properly but must
+ * do this early on to make the additional device appear during
+ * the PCI scanning.
+ */
+
+static void __devinit quirk_jmicron_dualfn(struct pci_dev *pdev)
+{
+ u32 conf;
+ u8 hdr;
+
+ /* Only poke fn 0 */
+ if (PCI_FUNC(pdev->devfn))
+ return;
+
+ switch(pdev->device) {
+ case PCI_DEVICE_ID_JMICRON_JMB365:
+ case PCI_DEVICE_ID_JMICRON_JMB366:
+ /* Redirect IDE second PATA port to the right spot */
+ pci_read_config_dword(pdev, 0x80, &conf);
+ conf |= (1 << 24);
+ /* Fall through */
+ pci_write_config_dword(pdev, 0x80, conf);
+ case PCI_DEVICE_ID_JMICRON_JMB361:
+ case PCI_DEVICE_ID_JMICRON_JMB363:
+ pci_read_config_dword(pdev, 0x40, &conf);
+ /* Enable dual function mode, AHCI on fn 0, IDE fn1 */
+ /* Set the class codes correctly and then direct IDE 0 */
+ conf &= ~0x000F0200; /* Clear bit 9 and 16-19 */
+ conf |= 0x00C20002; /* Set bit 1, 17, 22, 23 */
+ pci_write_config_dword(pdev, 0x40, conf);
+
+ /* Reconfigure so that the PCI scanner discovers the
+ device is now multifunction */
+
+ pci_read_config_byte(pdev, PCI_HEADER_TYPE, &hdr);
+ pdev->hdr_type = hdr & 0x7f;
+ pdev->multifunction = !!(hdr & 0x80);
+
+ break;
+ }
+}
+
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, quirk_jmicron_dualfn);
+
+#endif
+
#ifdef CONFIG_X86_IO_APIC
static void __init quirk_alder_ioapic(struct pci_dev *pdev)
{
@@ -1341,6 +1425,37 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXH_0, quirk_pc
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXH_1, quirk_pcie_pxh);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXHV, quirk_pcie_pxh);
+/*
+ * Some Intel PCI Express chipsets have trouble with downstream
+ * device power management.
+ */
+static void quirk_intel_pcie_pm(struct pci_dev * dev)
+{
+ pci_pm_d3_delay = 120;
+ dev->no_d1d2 = 1;
+}
+
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x25e2, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x25e3, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x25e4, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x25e5, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x25e6, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x25e7, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x25f7, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x25f8, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x25f9, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x25fa, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2601, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2602, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2603, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2604, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2605, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2606, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2607, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2608, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2609, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x260a, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x260b, quirk_intel_pcie_pm);
/*
* Fixup the cardbus bridges on the IBM Dock II docking station
diff --git a/drivers/pci/search.c b/drivers/pci/search.c
index 622b3f8ba82..d529462d1b5 100644
--- a/drivers/pci/search.c
+++ b/drivers/pci/search.c
@@ -41,7 +41,7 @@ pci_do_find_bus(struct pci_bus* bus, unsigned char busnr)
* in the global list of PCI buses. If the bus is found, a pointer to its
* data structure is returned. If no bus is found, %NULL is returned.
*/
-struct pci_bus * __devinit pci_find_bus(int domain, int busnr)
+struct pci_bus * pci_find_bus(int domain, int busnr)
{
struct pci_bus *bus = NULL;
struct pci_bus *tmp_bus;
@@ -61,7 +61,7 @@ struct pci_bus * __devinit pci_find_bus(int domain, int busnr)
* @from: Previous PCI bus found, or %NULL for new search.
*
* Iterates through the list of known PCI busses. A new search is
- * initiated by passing %NULL to the @from argument. Otherwise if
+ * initiated by passing %NULL as the @from argument. Otherwise if
* @from is not %NULL, searches continue from next device on the
* global list.
*/
@@ -148,13 +148,14 @@ struct pci_dev * pci_get_slot(struct pci_bus *bus, unsigned int devfn)
* @from: Previous PCI device found in search, or %NULL for new search.
*
* Iterates through the list of known PCI devices. If a PCI device is
- * found with a matching @vendor, @device, @ss_vendor and @ss_device, a pointer to its
- * device structure is returned. Otherwise, %NULL is returned.
- * A new search is initiated by passing %NULL to the @from argument.
- * Otherwise if @from is not %NULL, searches continue from next device on the global list.
+ * found with a matching @vendor, @device, @ss_vendor and @ss_device, a
+ * pointer to its device structure is returned. Otherwise, %NULL is returned.
+ * A new search is initiated by passing %NULL as the @from argument.
+ * Otherwise if @from is not %NULL, searches continue from next device
+ * on the global list.
*
- * NOTE: Do not use this function anymore, use pci_get_subsys() instead, as
- * the pci device returned by this function can disappear at any moment in
+ * NOTE: Do not use this function any more; use pci_get_subsys() instead, as
+ * the PCI device returned by this function can disappear at any moment in
* time.
*/
static struct pci_dev * pci_find_subsys(unsigned int vendor,
@@ -191,14 +192,15 @@ exit:
* @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
* @from: Previous PCI device found in search, or %NULL for new search.
*
- * Iterates through the list of known PCI devices. If a PCI device is
- * found with a matching @vendor and @device, a pointer to its device structure is
+ * Iterates through the list of known PCI devices. If a PCI device is found
+ * with a matching @vendor and @device, a pointer to its device structure is
* returned. Otherwise, %NULL is returned.
- * A new search is initiated by passing %NULL to the @from argument.
- * Otherwise if @from is not %NULL, searches continue from next device on the global list.
+ * A new search is initiated by passing %NULL as the @from argument.
+ * Otherwise if @from is not %NULL, searches continue from next device
+ * on the global list.
*
- * NOTE: Do not use this function anymore, use pci_get_device() instead, as
- * the pci device returned by this function can disappear at any moment in
+ * NOTE: Do not use this function any more; use pci_get_device() instead, as
+ * the PCI device returned by this function can disappear at any moment in
* time.
*/
struct pci_dev *
@@ -215,11 +217,11 @@ pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev *
* @ss_device: PCI subsystem device id to match, or %PCI_ANY_ID to match all device ids
* @from: Previous PCI device found in search, or %NULL for new search.
*
- * Iterates through the list of known PCI devices. If a PCI device is
- * found with a matching @vendor, @device, @ss_vendor and @ss_device, a pointer to its
+ * Iterates through the list of known PCI devices. If a PCI device is found
+ * with a matching @vendor, @device, @ss_vendor and @ss_device, a pointer to its
* device structure is returned, and the reference count to the device is
* incremented. Otherwise, %NULL is returned. A new search is initiated by
- * passing %NULL to the @from argument. Otherwise if @from is not %NULL,
+ * passing %NULL as the @from argument. Otherwise if @from is not %NULL,
* searches continue from next device on the global list.
* The reference count for @from is always decremented if it is not %NULL.
*/
@@ -262,7 +264,7 @@ exit:
* found with a matching @vendor and @device, the reference count to the
* device is incremented and a pointer to its device structure is returned.
* Otherwise, %NULL is returned. A new search is initiated by passing %NULL
- * to the @from argument. Otherwise if @from is not %NULL, searches continue
+ * as the @from argument. Otherwise if @from is not %NULL, searches continue
* from next device on the global list. The reference count for @from is
* always decremented if it is not %NULL.
*/
@@ -279,11 +281,13 @@ pci_get_device(unsigned int vendor, unsigned int device, struct pci_dev *from)
* @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
* @from: Previous PCI device found in search, or %NULL for new search.
*
- * Iterates through the list of known PCI devices in the reverse order of pci_find_device().
+ * Iterates through the list of known PCI devices in the reverse order of
+ * pci_find_device().
* If a PCI device is found with a matching @vendor and @device, a pointer to
* its device structure is returned. Otherwise, %NULL is returned.
- * A new search is initiated by passing %NULL to the @from argument.
- * Otherwise if @from is not %NULL, searches continue from previous device on the global list.
+ * A new search is initiated by passing %NULL as the @from argument.
+ * Otherwise if @from is not %NULL, searches continue from previous device
+ * on the global list.
*/
struct pci_dev *
pci_find_device_reverse(unsigned int vendor, unsigned int device, const struct pci_dev *from)
@@ -317,7 +321,7 @@ exit:
* found with a matching @class, the reference count to the device is
* incremented and a pointer to its device structure is returned.
* Otherwise, %NULL is returned.
- * A new search is initiated by passing %NULL to the @from argument.
+ * A new search is initiated by passing %NULL as the @from argument.
* Otherwise if @from is not %NULL, searches continue from next device
* on the global list. The reference count for @from is always decremented
* if it is not %NULL.
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index 61cb4b29f55..35f88649d3b 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -6,7 +6,7 @@ menu "PCCARD (PCMCIA/CardBus) support"
config PCCARD
tristate "PCCard (PCMCIA/CardBus) support"
- select HOTPLUG
+ depends on HOTPLUG
---help---
Say Y here if you want to attach PCMCIA- or PC-cards to your Linux
computer. These are credit-card size devices such as network cards,
diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c
index 738b1ef595a..9ad18e62658 100644
--- a/drivers/pcmcia/pcmcia_ioctl.c
+++ b/drivers/pcmcia/pcmcia_ioctl.c
@@ -601,12 +601,8 @@ static int ds_ioctl(struct inode * inode, struct file * file,
ret = CS_BAD_ARGS;
else {
struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->config.Function);
- if (p_dev == NULL)
- ret = CS_BAD_ARGS;
- else {
- ret = pccard_get_configuration_info(s, p_dev, &buf->config);
- pcmcia_put_dev(p_dev);
- }
+ ret = pccard_get_configuration_info(s, p_dev, &buf->config);
+ pcmcia_put_dev(p_dev);
}
break;
case DS_GET_FIRST_TUPLE:
@@ -636,12 +632,8 @@ static int ds_ioctl(struct inode * inode, struct file * file,
ret = CS_BAD_ARGS;
else {
struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->status.Function);
- if (p_dev == NULL)
- ret = CS_BAD_ARGS;
- else {
- ret = pccard_get_status(s, p_dev, &buf->status);
- pcmcia_put_dev(p_dev);
- }
+ ret = pccard_get_status(s, p_dev, &buf->status);
+ pcmcia_put_dev(p_dev);
}
break;
case DS_VALIDATE_CIS:
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c
index 7bf25b88ea3..c8323399e9e 100644
--- a/drivers/pcmcia/pcmcia_resource.c
+++ b/drivers/pcmcia/pcmcia_resource.c
@@ -245,10 +245,17 @@ int pccard_get_configuration_info(struct pcmcia_socket *s,
return CS_SUCCESS;
}
- /* !!! This is a hack !!! */
- memcpy(&config->Attributes, &c->Attributes, sizeof(config_t));
- config->Attributes |= CONF_VALID_CLIENT;
- config->CardValues = c->CardValues;
+ config->Attributes = c->Attributes | CONF_VALID_CLIENT;
+ config->Vcc = s->socket.Vcc;
+ config->Vpp1 = config->Vpp2 = s->socket.Vpp;
+ config->IntType = c->IntType;
+ config->ConfigBase = c->ConfigBase;
+ config->Status = c->Status;
+ config->Pin = c->Pin;
+ config->Copy = c->Copy;
+ config->Option = c->Option;
+ config->ExtStatus = c->ExtStatus;
+ config->Present = config->CardValues = c->CardValues;
config->IRQAttributes = c->irq.Attributes;
config->AssignedIRQ = s->irq.AssignedIRQ;
config->BasePort1 = c->io.BasePort1;
diff --git a/drivers/pnp/interface.c b/drivers/pnp/interface.c
index 3163e3d73da..9d8b415eca7 100644
--- a/drivers/pnp/interface.c
+++ b/drivers/pnp/interface.c
@@ -265,8 +265,8 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, struct device_at
pnp_printf(buffer," disabled\n");
else
pnp_printf(buffer," 0x%llx-0x%llx\n",
- pnp_port_start(dev, i),
- pnp_port_end(dev, i));
+ (unsigned long long)pnp_port_start(dev, i),
+ (unsigned long long)pnp_port_end(dev, i));
}
}
for (i = 0; i < PNP_MAX_MEM; i++) {
@@ -276,8 +276,8 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, struct device_at
pnp_printf(buffer," disabled\n");
else
pnp_printf(buffer," 0x%llx-0x%llx\n",
- pnp_mem_start(dev, i),
- pnp_mem_end(dev, i));
+ (unsigned long long)pnp_mem_start(dev, i),
+ (unsigned long long)pnp_mem_end(dev, i));
}
}
for (i = 0; i < PNP_MAX_IRQ; i++) {
@@ -287,7 +287,7 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, struct device_at
pnp_printf(buffer," disabled\n");
else
pnp_printf(buffer," %lld\n",
- pnp_irq(dev, i));
+ (unsigned long long)pnp_irq(dev, i));
}
}
for (i = 0; i < PNP_MAX_DMA; i++) {
@@ -297,7 +297,7 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, struct device_at
pnp_printf(buffer," disabled\n");
else
pnp_printf(buffer," %lld\n",
- pnp_dma(dev, i));
+ (unsigned long long)pnp_dma(dev, i));
}
}
ret = (buffer->curr - buf);
diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c
index b154b3f52cb..551f58e2981 100644
--- a/drivers/pnp/pnpbios/core.c
+++ b/drivers/pnp/pnpbios/core.c
@@ -346,7 +346,7 @@ static int insert_device(struct pnp_dev *dev, struct pnp_bios_node * node)
dev->flags = node->flags;
if (!(dev->flags & PNPBIOS_NO_CONFIG))
dev->capabilities |= PNP_CONFIGURABLE;
- if (!(dev->flags & PNPBIOS_NO_DISABLE))
+ if (!(dev->flags & PNPBIOS_NO_DISABLE) && pnpbios_is_dynamic(dev))
dev->capabilities |= PNP_DISABLE;
dev->capabilities |= PNP_READ;
if (pnpbios_is_dynamic(dev))
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index f5b9f187a93..7ff1d88094b 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -121,6 +121,16 @@ config RTC_DRV_DS1553
This driver can also be built as a module. If so, the module
will be called rtc-ds1553.
+config RTC_DRV_ISL1208
+ tristate "Intersil 1208"
+ depends on RTC_CLASS && I2C
+ help
+ If you say yes here you get support for the
+ Intersil 1208 RTC chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-isl1208.
+
config RTC_DRV_DS1672
tristate "Dallas/Maxim DS1672"
depends on RTC_CLASS && I2C
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 54220714ff4..bbcfb09d81d 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_RTC_INTF_PROC) += rtc-proc.o
obj-$(CONFIG_RTC_INTF_DEV) += rtc-dev.o
obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o
+obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o
obj-$(CONFIG_RTC_DRV_DS1307) += rtc-ds1307.o
obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o
diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c
new file mode 100644
index 00000000000..f324d0a635d
--- /dev/null
+++ b/drivers/rtc/rtc-isl1208.c
@@ -0,0 +1,591 @@
+/*
+ * Intersil ISL1208 rtc class driver
+ *
+ * Copyright 2005,2006 Hebert Valerio Riedel <hvr@gnu.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/bcd.h>
+#include <linux/rtc.h>
+
+#define DRV_NAME "isl1208"
+#define DRV_VERSION "0.2"
+
+/* Register map */
+/* rtc section */
+#define ISL1208_REG_SC 0x00
+#define ISL1208_REG_MN 0x01
+#define ISL1208_REG_HR 0x02
+#define ISL1208_REG_HR_MIL (1<<7) /* 24h/12h mode */
+#define ISL1208_REG_HR_PM (1<<5) /* PM/AM bit in 12h mode */
+#define ISL1208_REG_DT 0x03
+#define ISL1208_REG_MO 0x04
+#define ISL1208_REG_YR 0x05
+#define ISL1208_REG_DW 0x06
+#define ISL1208_RTC_SECTION_LEN 7
+
+/* control/status section */
+#define ISL1208_REG_SR 0x07
+#define ISL1208_REG_SR_ARST (1<<7) /* auto reset */
+#define ISL1208_REG_SR_XTOSCB (1<<6) /* crystal oscillator */
+#define ISL1208_REG_SR_WRTC (1<<4) /* write rtc */
+#define ISL1208_REG_SR_ALM (1<<2) /* alarm */
+#define ISL1208_REG_SR_BAT (1<<1) /* battery */
+#define ISL1208_REG_SR_RTCF (1<<0) /* rtc fail */
+#define ISL1208_REG_INT 0x08
+#define ISL1208_REG_09 0x09 /* reserved */
+#define ISL1208_REG_ATR 0x0a
+#define ISL1208_REG_DTR 0x0b
+
+/* alarm section */
+#define ISL1208_REG_SCA 0x0c
+#define ISL1208_REG_MNA 0x0d
+#define ISL1208_REG_HRA 0x0e
+#define ISL1208_REG_DTA 0x0f
+#define ISL1208_REG_MOA 0x10
+#define ISL1208_REG_DWA 0x11
+#define ISL1208_ALARM_SECTION_LEN 6
+
+/* user section */
+#define ISL1208_REG_USR1 0x12
+#define ISL1208_REG_USR2 0x13
+#define ISL1208_USR_SECTION_LEN 2
+
+/* i2c configuration */
+#define ISL1208_I2C_ADDR 0xde
+
+static unsigned short normal_i2c[] = {
+ ISL1208_I2C_ADDR>>1, I2C_CLIENT_END
+};
+I2C_CLIENT_INSMOD; /* defines addr_data */
+
+static int isl1208_attach_adapter(struct i2c_adapter *adapter);
+static int isl1208_detach_client(struct i2c_client *client);
+
+static struct i2c_driver isl1208_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ },
+ .id = I2C_DRIVERID_ISL1208,
+ .attach_adapter = &isl1208_attach_adapter,
+ .detach_client = &isl1208_detach_client,
+};
+
+/* block read */
+static int
+isl1208_i2c_read_regs(struct i2c_client *client, u8 reg, u8 buf[],
+ unsigned len)
+{
+ u8 reg_addr[1] = { reg };
+ struct i2c_msg msgs[2] = {
+ { client->addr, client->flags, sizeof(reg_addr), reg_addr },
+ { client->addr, client->flags | I2C_M_RD, len, buf }
+ };
+ int ret;
+
+ BUG_ON(len == 0);
+ BUG_ON(reg > ISL1208_REG_USR2);
+ BUG_ON(reg + len > ISL1208_REG_USR2 + 1);
+
+ ret = i2c_transfer(client->adapter, msgs, 2);
+ if (ret > 0)
+ ret = 0;
+ return ret;
+}
+
+/* block write */
+static int
+isl1208_i2c_set_regs(struct i2c_client *client, u8 reg, u8 const buf[],
+ unsigned len)
+{
+ u8 i2c_buf[ISL1208_REG_USR2 + 2];
+ struct i2c_msg msgs[1] = {
+ { client->addr, client->flags, len + 1, i2c_buf }
+ };
+ int ret;
+
+ BUG_ON(len == 0);
+ BUG_ON(reg > ISL1208_REG_USR2);
+ BUG_ON(reg + len > ISL1208_REG_USR2 + 1);
+
+ i2c_buf[0] = reg;
+ memcpy(&i2c_buf[1], &buf[0], len);
+
+ ret = i2c_transfer(client->adapter, msgs, 1);
+ if (ret > 0)
+ ret = 0;
+ return ret;
+}
+
+/* simple check to see wether we have a isl1208 */
+static int isl1208_i2c_validate_client(struct i2c_client *client)
+{
+ u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, };
+ u8 zero_mask[ISL1208_RTC_SECTION_LEN] = {
+ 0x80, 0x80, 0x40, 0xc0, 0xe0, 0x00, 0xf8
+ };
+ int i;
+ int ret;
+
+ ret = isl1208_i2c_read_regs(client, 0, regs, ISL1208_RTC_SECTION_LEN);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < ISL1208_RTC_SECTION_LEN; ++i) {
+ if (regs[i] & zero_mask[i]) /* check if bits are cleared */
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int isl1208_i2c_get_sr(struct i2c_client *client)
+{
+ return i2c_smbus_read_byte_data(client, ISL1208_REG_SR) == -1 ? -EIO:0;
+}
+
+static int isl1208_i2c_get_atr(struct i2c_client *client)
+{
+ int atr = i2c_smbus_read_byte_data(client, ISL1208_REG_ATR);
+
+ if (atr < 0)
+ return -EIO;
+
+ /* The 6bit value in the ATR register controls the load
+ * capacitance C_load * in steps of 0.25pF
+ *
+ * bit (1<<5) of the ATR register is inverted
+ *
+ * C_load(ATR=0x20) = 4.50pF
+ * C_load(ATR=0x00) = 12.50pF
+ * C_load(ATR=0x1f) = 20.25pF
+ *
+ */
+
+ atr &= 0x3f; /* mask out lsb */
+ atr ^= 1<<5; /* invert 6th bit */
+ atr += 2*9; /* add offset of 4.5pF; unit[atr] = 0.25pF */
+
+ return atr;
+}
+
+static int isl1208_i2c_get_dtr(struct i2c_client *client)
+{
+ int dtr = i2c_smbus_read_byte_data(client, ISL1208_REG_DTR);
+
+ if (dtr < 0)
+ return -EIO;
+
+ /* dtr encodes adjustments of {-60,-40,-20,0,20,40,60} ppm */
+ dtr = ((dtr & 0x3) * 20) * (dtr & (1<<2) ? -1 : 1);
+
+ return dtr;
+}
+
+static int isl1208_i2c_get_usr(struct i2c_client *client)
+{
+ u8 buf[ISL1208_USR_SECTION_LEN] = { 0, };
+ int ret;
+
+ ret = isl1208_i2c_read_regs (client, ISL1208_REG_USR1, buf,
+ ISL1208_USR_SECTION_LEN);
+ if (ret < 0)
+ return ret;
+
+ return (buf[1] << 8) | buf[0];
+}
+
+static int isl1208_i2c_set_usr(struct i2c_client *client, u16 usr)
+{
+ u8 buf[ISL1208_USR_SECTION_LEN];
+
+ buf[0] = usr & 0xff;
+ buf[1] = (usr >> 8) & 0xff;
+
+ return isl1208_i2c_set_regs (client, ISL1208_REG_USR1, buf,
+ ISL1208_USR_SECTION_LEN);
+}
+
+static int isl1208_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+ struct i2c_client *const client = to_i2c_client(dev);
+ int sr, dtr, atr, usr;
+
+ sr = isl1208_i2c_get_sr(client);
+ if (sr < 0) {
+ dev_err(&client->dev, "%s: reading SR failed\n", __func__);
+ return sr;
+ }
+
+ seq_printf(seq, "status_reg\t:%s%s%s%s%s%s (0x%.2x)\n",
+ (sr & ISL1208_REG_SR_RTCF) ? " RTCF" : "",
+ (sr & ISL1208_REG_SR_BAT) ? " BAT" : "",
+ (sr & ISL1208_REG_SR_ALM) ? " ALM" : "",
+ (sr & ISL1208_REG_SR_WRTC) ? " WRTC" : "",
+ (sr & ISL1208_REG_SR_XTOSCB) ? " XTOSCB" : "",
+ (sr & ISL1208_REG_SR_ARST) ? " ARST" : "",
+ sr);
+
+ seq_printf(seq, "batt_status\t: %s\n",
+ (sr & ISL1208_REG_SR_RTCF) ? "bad" : "okay");
+
+ dtr = isl1208_i2c_get_dtr(client);
+ if (dtr >= 0 -1)
+ seq_printf(seq, "digital_trim\t: %d ppm\n", dtr);
+
+ atr = isl1208_i2c_get_atr(client);
+ if (atr >= 0)
+ seq_printf(seq, "analog_trim\t: %d.%.2d pF\n",
+ atr>>2, (atr&0x3)*25);
+
+ usr = isl1208_i2c_get_usr(client);
+ if (usr >= 0)
+ seq_printf(seq, "user_data\t: 0x%.4x\n", usr);
+
+ return 0;
+}
+
+
+static int isl1208_i2c_read_time(struct i2c_client *client,
+ struct rtc_time *tm)
+{
+ int sr;
+ u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, };
+
+ sr = isl1208_i2c_get_sr(client);
+ if (sr < 0) {
+ dev_err(&client->dev, "%s: reading SR failed\n", __func__);
+ return -EIO;
+ }
+
+ sr = isl1208_i2c_read_regs(client, 0, regs, ISL1208_RTC_SECTION_LEN);
+ if (sr < 0) {
+ dev_err(&client->dev, "%s: reading RTC section failed\n",
+ __func__);
+ return sr;
+ }
+
+ tm->tm_sec = BCD2BIN(regs[ISL1208_REG_SC]);
+ tm->tm_min = BCD2BIN(regs[ISL1208_REG_MN]);
+ { /* HR field has a more complex interpretation */
+ const u8 _hr = regs[ISL1208_REG_HR];
+ if (_hr & ISL1208_REG_HR_MIL) /* 24h format */
+ tm->tm_hour = BCD2BIN(_hr & 0x3f);
+ else { // 12h format
+ tm->tm_hour = BCD2BIN(_hr & 0x1f);
+ if (_hr & ISL1208_REG_HR_PM) /* PM flag set */
+ tm->tm_hour += 12;
+ }
+ }
+
+ tm->tm_mday = BCD2BIN(regs[ISL1208_REG_DT]);
+ tm->tm_mon = BCD2BIN(regs[ISL1208_REG_MO]) - 1; /* rtc starts at 1 */
+ tm->tm_year = BCD2BIN(regs[ISL1208_REG_YR]) + 100;
+ tm->tm_wday = BCD2BIN(regs[ISL1208_REG_DW]);
+
+ return 0;
+}
+
+static int isl1208_i2c_read_alarm(struct i2c_client *client,
+ struct rtc_wkalrm *alarm)
+{
+ struct rtc_time *const tm = &alarm->time;
+ u8 regs[ISL1208_ALARM_SECTION_LEN] = { 0, };
+ int sr;
+
+ sr = isl1208_i2c_get_sr(client);
+ if (sr < 0) {
+ dev_err(&client->dev, "%s: reading SR failed\n", __func__);
+ return sr;
+ }
+
+ sr = isl1208_i2c_read_regs(client, ISL1208_REG_SCA, regs,
+ ISL1208_ALARM_SECTION_LEN);
+ if (sr < 0) {
+ dev_err(&client->dev, "%s: reading alarm section failed\n",
+ __func__);
+ return sr;
+ }
+
+ /* MSB of each alarm register is an enable bit */
+ tm->tm_sec = BCD2BIN(regs[ISL1208_REG_SCA-ISL1208_REG_SCA] & 0x7f);
+ tm->tm_min = BCD2BIN(regs[ISL1208_REG_MNA-ISL1208_REG_SCA] & 0x7f);
+ tm->tm_hour = BCD2BIN(regs[ISL1208_REG_HRA-ISL1208_REG_SCA] & 0x3f);
+ tm->tm_mday = BCD2BIN(regs[ISL1208_REG_DTA-ISL1208_REG_SCA] & 0x3f);
+ tm->tm_mon = BCD2BIN(regs[ISL1208_REG_MOA-ISL1208_REG_SCA] & 0x1f)-1;
+ tm->tm_wday = BCD2BIN(regs[ISL1208_REG_DWA-ISL1208_REG_SCA] & 0x03);
+
+ return 0;
+}
+
+static int isl1208_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ return isl1208_i2c_read_time(to_i2c_client(dev), tm);
+}
+
+static int isl1208_i2c_set_time(struct i2c_client *client,
+ struct rtc_time const *tm)
+{
+ int sr;
+ u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, };
+
+ regs[ISL1208_REG_SC] = BIN2BCD(tm->tm_sec);
+ regs[ISL1208_REG_MN] = BIN2BCD(tm->tm_min);
+ regs[ISL1208_REG_HR] = BIN2BCD(tm->tm_hour) | ISL1208_REG_HR_MIL;
+
+ regs[ISL1208_REG_DT] = BIN2BCD(tm->tm_mday);
+ regs[ISL1208_REG_MO] = BIN2BCD(tm->tm_mon + 1);
+ regs[ISL1208_REG_YR] = BIN2BCD(tm->tm_year - 100);
+
+ regs[ISL1208_REG_DW] = BIN2BCD(tm->tm_wday & 7);
+
+ sr = isl1208_i2c_get_sr(client);
+ if (sr < 0) {
+ dev_err(&client->dev, "%s: reading SR failed\n", __func__);
+ return sr;
+ }
+
+ /* set WRTC */
+ sr = i2c_smbus_write_byte_data (client, ISL1208_REG_SR,
+ sr | ISL1208_REG_SR_WRTC);
+ if (sr < 0) {
+ dev_err(&client->dev, "%s: writing SR failed\n", __func__);
+ return sr;
+ }
+
+ /* write RTC registers */
+ sr = isl1208_i2c_set_regs(client, 0, regs, ISL1208_RTC_SECTION_LEN);
+ if (sr < 0) {
+ dev_err(&client->dev, "%s: writing RTC section failed\n",
+ __func__);
+ return sr;
+ }
+
+ /* clear WRTC again */
+ sr = i2c_smbus_write_byte_data (client, ISL1208_REG_SR,
+ sr & ~ISL1208_REG_SR_WRTC);
+ if (sr < 0) {
+ dev_err(&client->dev, "%s: writing SR failed\n", __func__);
+ return sr;
+ }
+
+ return 0;
+}
+
+
+static int isl1208_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ return isl1208_i2c_set_time(to_i2c_client(dev), tm);
+}
+
+static int isl1208_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ return isl1208_i2c_read_alarm(to_i2c_client(dev), alarm);
+}
+
+static struct rtc_class_ops isl1208_rtc_ops = {
+ .proc = isl1208_rtc_proc,
+ .read_time = isl1208_rtc_read_time,
+ .set_time = isl1208_rtc_set_time,
+ .read_alarm = isl1208_rtc_read_alarm,
+ //.set_alarm = isl1208_rtc_set_alarm,
+};
+
+/* sysfs interface */
+
+static ssize_t isl1208_sysfs_show_atrim(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int atr;
+
+ atr = isl1208_i2c_get_atr(to_i2c_client(dev));
+ if (atr < 0)
+ return atr;
+
+ return sprintf(buf, "%d.%.2d pF\n", atr>>2, (atr&0x3)*25);
+}
+static DEVICE_ATTR(atrim, S_IRUGO, isl1208_sysfs_show_atrim, NULL);
+
+static ssize_t isl1208_sysfs_show_dtrim(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int dtr;
+
+ dtr = isl1208_i2c_get_dtr(to_i2c_client(dev));
+ if (dtr < 0)
+ return dtr;
+
+ return sprintf(buf, "%d ppm\n", dtr);
+}
+static DEVICE_ATTR(dtrim, S_IRUGO, isl1208_sysfs_show_dtrim, NULL);
+
+static ssize_t isl1208_sysfs_show_usr(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int usr;
+
+ usr = isl1208_i2c_get_usr(to_i2c_client(dev));
+ if (usr < 0)
+ return usr;
+
+ return sprintf(buf, "0x%.4x\n", usr);
+}
+
+static ssize_t isl1208_sysfs_store_usr(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int usr = -1;
+
+ if (buf[0] == '0' && (buf[1] == 'x' || buf[1] == 'X')) {
+ if (sscanf(buf, "%x", &usr) != 1)
+ return -EINVAL;
+ } else {
+ if (sscanf(buf, "%d", &usr) != 1)
+ return -EINVAL;
+ }
+
+ if (usr < 0 || usr > 0xffff)
+ return -EINVAL;
+
+ return isl1208_i2c_set_usr(to_i2c_client(dev), usr) ? -EIO : count;
+}
+static DEVICE_ATTR(usr, S_IRUGO | S_IWUSR, isl1208_sysfs_show_usr,
+ isl1208_sysfs_store_usr);
+
+static int
+isl1208_probe(struct i2c_adapter *adapter, int addr, int kind)
+{
+ int rc = 0;
+ struct i2c_client *new_client = NULL;
+ struct rtc_device *rtc = NULL;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
+ rc = -ENODEV;
+ goto failout;
+ }
+
+ new_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (new_client == NULL) {
+ rc = -ENOMEM;
+ goto failout;
+ }
+
+ new_client->addr = addr;
+ new_client->adapter = adapter;
+ new_client->driver = &isl1208_driver;
+ new_client->flags = 0;
+ strcpy(new_client->name, DRV_NAME);
+
+ if (kind < 0) {
+ rc = isl1208_i2c_validate_client(new_client);
+ if (rc < 0)
+ goto failout;
+ }
+
+ rc = i2c_attach_client(new_client);
+ if (rc < 0)
+ goto failout;
+
+ dev_info(&new_client->dev,
+ "chip found, driver version " DRV_VERSION "\n");
+
+ rtc = rtc_device_register(isl1208_driver.driver.name,
+ &new_client->dev,
+ &isl1208_rtc_ops, THIS_MODULE);
+
+ if (IS_ERR(rtc)) {
+ rc = PTR_ERR(rtc);
+ goto failout_detach;
+ }
+
+ i2c_set_clientdata(new_client, rtc);
+
+ rc = isl1208_i2c_get_sr(new_client);
+ if (rc < 0) {
+ dev_err(&new_client->dev, "reading status failed\n");
+ goto failout_unregister;
+ }
+
+ if (rc & ISL1208_REG_SR_RTCF)
+ dev_warn(&new_client->dev, "rtc power failure detected, "
+ "please set clock.\n");
+
+ rc = device_create_file(&new_client->dev, &dev_attr_atrim);
+ if (rc < 0)
+ goto failout_unregister;
+ rc = device_create_file(&new_client->dev, &dev_attr_dtrim);
+ if (rc < 0)
+ goto failout_atrim;
+ rc = device_create_file(&new_client->dev, &dev_attr_usr);
+ if (rc < 0)
+ goto failout_dtrim;
+
+ return 0;
+
+ failout_dtrim:
+ device_remove_file(&new_client->dev, &dev_attr_dtrim);
+ failout_atrim:
+ device_remove_file(&new_client->dev, &dev_attr_atrim);
+ failout_unregister:
+ rtc_device_unregister(rtc);
+ failout_detach:
+ i2c_detach_client(new_client);
+ failout:
+ kfree(new_client);
+ return rc;
+}
+
+static int
+isl1208_attach_adapter (struct i2c_adapter *adapter)
+{
+ return i2c_probe(adapter, &addr_data, isl1208_probe);
+}
+
+static int
+isl1208_detach_client(struct i2c_client *client)
+{
+ int rc;
+ struct rtc_device *const rtc = i2c_get_clientdata(client);
+
+ if (rtc)
+ rtc_device_unregister(rtc); /* do we need to kfree? */
+
+ rc = i2c_detach_client(client);
+ if (rc)
+ return rc;
+
+ kfree(client);
+
+ return 0;
+}
+
+/* module management */
+
+static int __init isl1208_init(void)
+{
+ return i2c_add_driver(&isl1208_driver);
+}
+
+static void __exit isl1208_exit(void)
+{
+ i2c_del_driver(&isl1208_driver);
+}
+
+MODULE_AUTHOR("Herbert Valerio Riedel <hvr@gnu.org>");
+MODULE_DESCRIPTION("Intersil ISL1208 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_init(isl1208_init);
+module_exit(isl1208_exit);
diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c
index bb6d5ff24fd..596764fd29f 100644
--- a/drivers/rtc/rtc-vr41xx.c
+++ b/drivers/rtc/rtc-vr41xx.c
@@ -30,7 +30,7 @@
#include <asm/div64.h>
#include <asm/io.h>
#include <asm/uaccess.h>
-#include <asm/vr41xx/vr41xx.h>
+#include <asm/vr41xx/irq.h>
MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>");
MODULE_DESCRIPTION("NEC VR4100 series RTC driver");
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index d7295386821..7f6fdac7470 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -394,7 +394,7 @@ dasd_add_busid(char *bus_id, int features)
if (!new)
return ERR_PTR(-ENOMEM);
spin_lock(&dasd_devmap_lock);
- devmap = 0;
+ devmap = NULL;
hash = dasd_hash_busid(bus_id);
list_for_each_entry(tmp, &dasd_hashlists[hash], list)
if (strncmp(tmp->bus_id, bus_id, BUS_ID_SIZE) == 0) {
@@ -406,10 +406,10 @@ dasd_add_busid(char *bus_id, int features)
new->devindex = dasd_max_devindex++;
strncpy(new->bus_id, bus_id, BUS_ID_SIZE);
new->features = features;
- new->device = 0;
+ new->device = NULL;
list_add(&new->list, &dasd_hashlists[hash]);
devmap = new;
- new = 0;
+ new = NULL;
}
spin_unlock(&dasd_devmap_lock);
kfree(new);
@@ -479,7 +479,7 @@ dasd_device_from_devindex(int devindex)
int i;
spin_lock(&dasd_devmap_lock);
- devmap = 0;
+ devmap = NULL;
for (i = 0; (i < 256) && !devmap; i++)
list_for_each_entry(tmp, &dasd_hashlists[i], list)
if (tmp->devindex == devindex) {
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 2e655f46674..39c2281371b 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -65,16 +65,16 @@ struct dasd_eckd_private {
/* The ccw bus type uses this table to find devices that it sends to
* dasd_eckd_probe */
static struct ccw_device_id dasd_eckd_ids[] = {
- { CCW_DEVICE_DEVTYPE (0x3990, 0, 0x3390, 0), driver_info: 0x1},
- { CCW_DEVICE_DEVTYPE (0x2105, 0, 0x3390, 0), driver_info: 0x2},
- { CCW_DEVICE_DEVTYPE (0x3880, 0, 0x3390, 0), driver_info: 0x3},
- { CCW_DEVICE_DEVTYPE (0x3990, 0, 0x3380, 0), driver_info: 0x4},
- { CCW_DEVICE_DEVTYPE (0x2105, 0, 0x3380, 0), driver_info: 0x5},
- { CCW_DEVICE_DEVTYPE (0x9343, 0, 0x9345, 0), driver_info: 0x6},
- { CCW_DEVICE_DEVTYPE (0x2107, 0, 0x3390, 0), driver_info: 0x7},
- { CCW_DEVICE_DEVTYPE (0x2107, 0, 0x3380, 0), driver_info: 0x8},
- { CCW_DEVICE_DEVTYPE (0x1750, 0, 0x3390, 0), driver_info: 0x9},
- { CCW_DEVICE_DEVTYPE (0x1750, 0, 0x3380, 0), driver_info: 0xa},
+ { CCW_DEVICE_DEVTYPE (0x3990, 0, 0x3390, 0), .driver_info = 0x1},
+ { CCW_DEVICE_DEVTYPE (0x2105, 0, 0x3390, 0), .driver_info = 0x2},
+ { CCW_DEVICE_DEVTYPE (0x3880, 0, 0x3390, 0), .driver_info = 0x3},
+ { CCW_DEVICE_DEVTYPE (0x3990, 0, 0x3380, 0), .driver_info = 0x4},
+ { CCW_DEVICE_DEVTYPE (0x2105, 0, 0x3380, 0), .driver_info = 0x5},
+ { CCW_DEVICE_DEVTYPE (0x9343, 0, 0x9345, 0), .driver_info = 0x6},
+ { CCW_DEVICE_DEVTYPE (0x2107, 0, 0x3390, 0), .driver_info = 0x7},
+ { CCW_DEVICE_DEVTYPE (0x2107, 0, 0x3380, 0), .driver_info = 0x8},
+ { CCW_DEVICE_DEVTYPE (0x1750, 0, 0x3390, 0), .driver_info = 0x9},
+ { CCW_DEVICE_DEVTYPE (0x1750, 0, 0x3380, 0), .driver_info = 0xa},
{ /* end of list */ },
};
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c
index 808434d3852..e85015be109 100644
--- a/drivers/s390/block/dasd_fba.c
+++ b/drivers/s390/block/dasd_fba.c
@@ -44,8 +44,8 @@ struct dasd_fba_private {
};
static struct ccw_device_id dasd_fba_ids[] = {
- { CCW_DEVICE_DEVTYPE (0x6310, 0, 0x9336, 0), driver_info: 0x1},
- { CCW_DEVICE_DEVTYPE (0x3880, 0, 0x3370, 0), driver_info: 0x2},
+ { CCW_DEVICE_DEVTYPE (0x6310, 0, 0x9336, 0), .driver_info = 0x1},
+ { CCW_DEVICE_DEVTYPE (0x3880, 0, 0x3370, 0), .driver_info = 0x2},
{ /* end of list */ },
};
diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c
index 12c7d296eaa..4c272b70f41 100644
--- a/drivers/s390/block/dasd_genhd.c
+++ b/drivers/s390/block/dasd_genhd.c
@@ -84,9 +84,9 @@ void
dasd_gendisk_free(struct dasd_device *device)
{
del_gendisk(device->gdp);
- device->gdp->queue = 0;
+ device->gdp->queue = NULL;
put_disk(device->gdp);
- device->gdp = 0;
+ device->gdp = NULL;
}
/*
@@ -136,7 +136,7 @@ dasd_destroy_partitions(struct dasd_device * device)
* device->bdev to lower the offline open_count limit again.
*/
bdev = device->bdev;
- device->bdev = 0;
+ device->bdev = NULL;
/*
* See fs/partition/check.c:delete_partition
@@ -145,7 +145,7 @@ dasd_destroy_partitions(struct dasd_device * device)
*/
memset(&bpart, 0, sizeof(struct blkpg_partition));
memset(&barg, 0, sizeof(struct blkpg_ioctl_arg));
- barg.data = &bpart;
+ barg.data = (void __user *) &bpart;
barg.op = BLKPG_DEL_PARTITION;
for (bpart.pno = device->gdp->minors - 1; bpart.pno > 0; bpart.pno--)
ioctl_by_bdev(bdev, BLKPG, (unsigned long) &barg);
diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c
index e97f5316ad2..8fed3603e9e 100644
--- a/drivers/s390/block/dasd_ioctl.c
+++ b/drivers/s390/block/dasd_ioctl.c
@@ -345,7 +345,7 @@ dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp)
if (bdev != bdev->bd_contains)
// ro setting is not allowed for partitions
return -EINVAL;
- if (get_user(intval, (int *)argp))
+ if (get_user(intval, (int __user *)argp))
return -EFAULT;
set_disk_ro(bdev->bd_disk, intval);
diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c
index 4c1e56b9b98..1140302ff11 100644
--- a/drivers/s390/block/xpram.c
+++ b/drivers/s390/block/xpram.c
@@ -71,11 +71,11 @@ static int xpram_devs;
/*
* Parameter parsing functions.
*/
-static int devs = XPRAM_DEVS;
-static unsigned int sizes[XPRAM_MAX_DEVS];
+static int __initdata devs = XPRAM_DEVS;
+static char __initdata *sizes[XPRAM_MAX_DEVS];
module_param(devs, int, 0);
-module_param_array(sizes, int, NULL, 0);
+module_param_array(sizes, charp, NULL, 0);
MODULE_PARM_DESC(devs, "number of devices (\"partitions\"), " \
"the default is " __MODULE_STRING(XPRAM_DEVS) "\n");
@@ -86,59 +86,6 @@ MODULE_PARM_DESC(sizes, "list of device (partition) sizes " \
"claimed by explicit sizes\n");
MODULE_LICENSE("GPL");
-#ifndef MODULE
-/*
- * Parses the kernel parameters given in the kernel parameter line.
- * The expected format is
- * <number_of_partitions>[","<partition_size>]*
- * where
- * devices is a positive integer that initializes xpram_devs
- * each size is a non-negative integer possibly followed by a
- * magnitude (k,K,m,M,g,G), the list of sizes initialises
- * xpram_sizes
- *
- * Arguments
- * str: substring of kernel parameter line that contains xprams
- * kernel parameters.
- *
- * Result 0 on success, -EINVAL else -- only for Version > 2.3
- *
- * Side effects
- * the global variabls devs is set to the value of
- * <number_of_partitions> and sizes[i] is set to the i-th
- * partition size (if provided). A parsing error of a value
- * results in this value being set to -EINVAL.
- */
-static int __init xpram_setup (char *str)
-{
- char *cp;
- int i;
-
- devs = simple_strtoul(str, &cp, 10);
- if (cp <= str || devs > XPRAM_MAX_DEVS)
- return 0;
- for (i = 0; (i < devs) && (*cp++ == ','); i++) {
- sizes[i] = simple_strtoul(cp, &cp, 10);
- if (*cp == 'g' || *cp == 'G') {
- sizes[i] <<= 20;
- cp++;
- } else if (*cp == 'm' || *cp == 'M') {
- sizes[i] <<= 10;
- cp++;
- } else if (*cp == 'k' || *cp == 'K')
- cp++;
- while (isspace(*cp)) cp++;
- }
- if (*cp == ',' && i >= devs)
- PRINT_WARN("partition sizes list has too many entries.\n");
- else if (*cp != 0)
- PRINT_WARN("ignored '%s' at end of parameter string.\n", cp);
- return 1;
-}
-
-__setup("xpram_parts=", xpram_setup);
-#endif
-
/*
* Copy expanded memory page (4kB) into main memory
* Arguments
@@ -357,6 +304,7 @@ static int __init xpram_setup_sizes(unsigned long pages)
{
unsigned long mem_needed;
unsigned long mem_auto;
+ unsigned long long size;
int mem_auto_no;
int i;
@@ -374,7 +322,19 @@ static int __init xpram_setup_sizes(unsigned long pages)
mem_needed = 0;
mem_auto_no = 0;
for (i = 0; i < xpram_devs; i++) {
- xpram_sizes[i] = (sizes[i] + 3) & -4UL;
+ if (sizes[i]) {
+ size = simple_strtoull(sizes[i], &sizes[i], 0);
+ switch (sizes[i][0]) {
+ case 'g':
+ case 'G':
+ size <<= 20;
+ break;
+ case 'm':
+ case 'M':
+ size <<= 10;
+ }
+ xpram_sizes[i] = (size + 3) & -4UL;
+ }
if (xpram_sizes[i])
mem_needed += xpram_sizes[i];
else
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index f25c6d116f6..2fa566fa6da 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -693,7 +693,7 @@ raw3215_probe (struct ccw_device *cdev)
GFP_KERNEL|GFP_DMA);
if (raw->buffer == NULL) {
spin_lock(&raw3215_device_lock);
- raw3215[line] = 0;
+ raw3215[line] = NULL;
spin_unlock(&raw3215_device_lock);
kfree(raw);
return -ENOMEM;
diff --git a/drivers/s390/char/ctrlchar.c b/drivers/s390/char/ctrlchar.c
index 0ea6f36a252..d83eb6358ba 100644
--- a/drivers/s390/char/ctrlchar.c
+++ b/drivers/s390/char/ctrlchar.c
@@ -23,7 +23,7 @@ ctrlchar_handle_sysrq(void *tty)
handle_sysrq(ctrlchar_sysrq_key, NULL, (struct tty_struct *) tty);
}
-static DECLARE_WORK(ctrlchar_work, ctrlchar_handle_sysrq, 0);
+static DECLARE_WORK(ctrlchar_work, ctrlchar_handle_sysrq, NULL);
#endif
diff --git a/drivers/s390/char/defkeymap.c b/drivers/s390/char/defkeymap.c
index ca15adb140d..17027d918cf 100644
--- a/drivers/s390/char/defkeymap.c
+++ b/drivers/s390/char/defkeymap.c
@@ -83,8 +83,8 @@ static u_short shift_ctrl_map[NR_KEYS] = {
};
ushort *key_maps[MAX_NR_KEYMAPS] = {
- plain_map, shift_map, 0, 0,
- ctrl_map, shift_ctrl_map, 0
+ plain_map, shift_map, NULL, NULL,
+ ctrl_map, shift_ctrl_map, NULL,
};
unsigned int keymap_count = 4;
@@ -145,7 +145,7 @@ char *func_table[MAX_NR_FUNC] = {
func_buf + 97,
func_buf + 103,
func_buf + 109,
- 0,
+ NULL,
};
struct kbdiacr accent_table[MAX_DIACR] = {
diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c
index 6099c14de42..ef004d08971 100644
--- a/drivers/s390/char/fs3270.c
+++ b/drivers/s390/char/fs3270.c
@@ -236,7 +236,7 @@ fs3270_irq(struct fs3270 *fp, struct raw3270_request *rq, struct irb *irb)
* Process reads from fullscreen 3270.
*/
static ssize_t
-fs3270_read(struct file *filp, char *data, size_t count, loff_t *off)
+fs3270_read(struct file *filp, char __user *data, size_t count, loff_t *off)
{
struct fs3270 *fp;
struct raw3270_request *rq;
@@ -281,7 +281,7 @@ fs3270_read(struct file *filp, char *data, size_t count, loff_t *off)
* Process writes to fullscreen 3270.
*/
static ssize_t
-fs3270_write(struct file *filp, const char *data, size_t count, loff_t *off)
+fs3270_write(struct file *filp, const char __user *data, size_t count, loff_t *off)
{
struct fs3270 *fp;
struct raw3270_request *rq;
@@ -338,10 +338,10 @@ fs3270_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
fp->write_command = arg;
break;
case TUBGETI:
- rc = put_user(fp->read_command, (char *) arg);
+ rc = put_user(fp->read_command, (char __user *) arg);
break;
case TUBGETO:
- rc = put_user(fp->write_command,(char *) arg);
+ rc = put_user(fp->write_command,(char __user *) arg);
break;
case TUBGETMOD:
iocb.model = fp->view.model;
@@ -350,7 +350,7 @@ fs3270_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
iocb.pf_cnt = 24;
iocb.re_cnt = 20;
iocb.map = 0;
- if (copy_to_user((char *) arg, &iocb,
+ if (copy_to_user((char __user *) arg, &iocb,
sizeof(struct raw3270_iocb)))
rc = -EFAULT;
break;
@@ -479,7 +479,7 @@ fs3270_close(struct inode *inode, struct file *filp)
struct fs3270 *fp;
fp = filp->private_data;
- filp->private_data = 0;
+ filp->private_data = NULL;
if (fp) {
fp->fs_pid = 0;
raw3270_reset(&fp->view);
diff --git a/drivers/s390/char/keyboard.c b/drivers/s390/char/keyboard.c
index 547ef906ae2..3be06569180 100644
--- a/drivers/s390/char/keyboard.c
+++ b/drivers/s390/char/keyboard.c
@@ -103,7 +103,7 @@ out_maps:
out_kbd:
kfree(kbd);
out:
- return 0;
+ return NULL;
}
void
@@ -304,7 +304,7 @@ kbd_keycode(struct kbd_data *kbd, unsigned int keycode)
if (kbd->sysrq) {
if (kbd->sysrq == K(KT_LATIN, '-')) {
kbd->sysrq = 0;
- handle_sysrq(value, 0, kbd->tty);
+ handle_sysrq(value, NULL, kbd->tty);
return;
}
if (value == '-') {
@@ -363,7 +363,7 @@ do_kdsk_ioctl(struct kbd_data *kbd, struct kbentry __user *user_kbe,
/* disallocate map */
key_map = kbd->key_maps[tmp.kb_table];
if (key_map) {
- kbd->key_maps[tmp.kb_table] = 0;
+ kbd->key_maps[tmp.kb_table] = NULL;
kfree(key_map);
}
break;
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c
index e95b56f810d..7a84014f203 100644
--- a/drivers/s390/char/raw3270.c
+++ b/drivers/s390/char/raw3270.c
@@ -555,7 +555,7 @@ raw3270_start_init(struct raw3270 *rp, struct raw3270_view *view,
#ifdef CONFIG_TN3270_CONSOLE
if (raw3270_registered == 0) {
spin_lock_irqsave(get_ccwdev_lock(view->dev->cdev), flags);
- rq->callback = 0;
+ rq->callback = NULL;
rc = __raw3270_start(rp, view, rq);
if (rc == 0)
while (!raw3270_request_final(rq)) {
@@ -719,8 +719,8 @@ raw3270_size_device(struct raw3270 *rp)
rc = __raw3270_size_device_vm(rp);
else
rc = __raw3270_size_device(rp);
- raw3270_init_view.dev = 0;
- rp->view = 0;
+ raw3270_init_view.dev = NULL;
+ rp->view = NULL;
up(&raw3270_init_sem);
if (rc == 0) { /* Found something. */
/* Try to find a model. */
@@ -761,8 +761,8 @@ raw3270_reset_device(struct raw3270 *rp)
rp->view = &raw3270_init_view;
raw3270_init_view.dev = rp;
rc = raw3270_start_init(rp, &raw3270_init_view, &rp->init_request);
- raw3270_init_view.dev = 0;
- rp->view = 0;
+ raw3270_init_view.dev = NULL;
+ rp->view = NULL;
up(&raw3270_init_sem);
return rc;
}
@@ -934,7 +934,7 @@ raw3270_activate_view(struct raw3270_view *view)
else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags))
rc = -ENODEV;
else {
- oldview = 0;
+ oldview = NULL;
if (rp->view) {
oldview = rp->view;
oldview->fn->deactivate(oldview);
@@ -951,7 +951,7 @@ raw3270_activate_view(struct raw3270_view *view)
rp->view = nv;
if (nv->fn->activate(nv) == 0)
break;
- rp->view = 0;
+ rp->view = NULL;
}
}
}
@@ -975,7 +975,7 @@ raw3270_deactivate_view(struct raw3270_view *view)
spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
if (rp->view == view) {
view->fn->deactivate(view);
- rp->view = 0;
+ rp->view = NULL;
/* Move deactivated view to end of list. */
list_del_init(&view->list);
list_add_tail(&view->list, &rp->view_list);
@@ -985,7 +985,7 @@ raw3270_deactivate_view(struct raw3270_view *view)
rp->view = view;
if (view->fn->activate(view) == 0)
break;
- rp->view = 0;
+ rp->view = NULL;
}
}
}
@@ -1076,7 +1076,7 @@ raw3270_del_view(struct raw3270_view *view)
spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
if (rp->view == view) {
view->fn->deactivate(view);
- rp->view = 0;
+ rp->view = NULL;
}
list_del_init(&view->list);
if (!rp->view && test_bit(RAW3270_FLAGS_READY, &rp->flags)) {
@@ -1106,10 +1106,10 @@ raw3270_delete_device(struct raw3270 *rp)
/* Remove from device chain. */
mutex_lock(&raw3270_mutex);
- if (rp->clttydev)
+ if (rp->clttydev && !IS_ERR(rp->clttydev))
class_device_destroy(class3270,
MKDEV(IBM_TTY3270_MAJOR, rp->minor));
- if (rp->cltubdev)
+ if (rp->cltubdev && !IS_ERR(rp->cltubdev))
class_device_destroy(class3270,
MKDEV(IBM_FS3270_MAJOR, rp->minor));
list_del_init(&rp->list);
@@ -1117,9 +1117,9 @@ raw3270_delete_device(struct raw3270 *rp)
/* Disconnect from ccw_device. */
cdev = rp->cdev;
- rp->cdev = 0;
- cdev->dev.driver_data = 0;
- cdev->handler = 0;
+ rp->cdev = NULL;
+ cdev->dev.driver_data = NULL;
+ cdev->handler = NULL;
/* Put ccw_device structure. */
put_device(&cdev->dev);
@@ -1144,7 +1144,7 @@ raw3270_model_show(struct device *dev, struct device_attribute *attr, char *buf)
return snprintf(buf, PAGE_SIZE, "%i\n",
((struct raw3270 *) dev->driver_data)->model);
}
-static DEVICE_ATTR(model, 0444, raw3270_model_show, 0);
+static DEVICE_ATTR(model, 0444, raw3270_model_show, NULL);
static ssize_t
raw3270_rows_show(struct device *dev, struct device_attribute *attr, char *buf)
@@ -1152,7 +1152,7 @@ raw3270_rows_show(struct device *dev, struct device_attribute *attr, char *buf)
return snprintf(buf, PAGE_SIZE, "%i\n",
((struct raw3270 *) dev->driver_data)->rows);
}
-static DEVICE_ATTR(rows, 0444, raw3270_rows_show, 0);
+static DEVICE_ATTR(rows, 0444, raw3270_rows_show, NULL);
static ssize_t
raw3270_columns_show(struct device *dev, struct device_attribute *attr, char *buf)
@@ -1160,7 +1160,7 @@ raw3270_columns_show(struct device *dev, struct device_attribute *attr, char *bu
return snprintf(buf, PAGE_SIZE, "%i\n",
((struct raw3270 *) dev->driver_data)->cols);
}
-static DEVICE_ATTR(columns, 0444, raw3270_columns_show, 0);
+static DEVICE_ATTR(columns, 0444, raw3270_columns_show, NULL);
static struct attribute * raw3270_attrs[] = {
&dev_attr_model.attr,
@@ -1173,21 +1173,37 @@ static struct attribute_group raw3270_attr_group = {
.attrs = raw3270_attrs,
};
-static void
-raw3270_create_attributes(struct raw3270 *rp)
+static int raw3270_create_attributes(struct raw3270 *rp)
{
- //FIXME: check return code
- sysfs_create_group(&rp->cdev->dev.kobj, &raw3270_attr_group);
- rp->clttydev =
- class_device_create(class3270, NULL,
- MKDEV(IBM_TTY3270_MAJOR, rp->minor),
- &rp->cdev->dev, "tty%s",
- rp->cdev->dev.bus_id);
- rp->cltubdev =
- class_device_create(class3270, NULL,
- MKDEV(IBM_FS3270_MAJOR, rp->minor),
- &rp->cdev->dev, "tub%s",
- rp->cdev->dev.bus_id);
+ int rc;
+
+ rc = sysfs_create_group(&rp->cdev->dev.kobj, &raw3270_attr_group);
+ if (rc)
+ goto out;
+
+ rp->clttydev = class_device_create(class3270, NULL,
+ MKDEV(IBM_TTY3270_MAJOR, rp->minor),
+ &rp->cdev->dev, "tty%s",
+ rp->cdev->dev.bus_id);
+ if (IS_ERR(rp->clttydev)) {
+ rc = PTR_ERR(rp->clttydev);
+ goto out_ttydev;
+ }
+
+ rp->cltubdev = class_device_create(class3270, NULL,
+ MKDEV(IBM_FS3270_MAJOR, rp->minor),
+ &rp->cdev->dev, "tub%s",
+ rp->cdev->dev.bus_id);
+ if (!IS_ERR(rp->cltubdev))
+ goto out;
+
+ rc = PTR_ERR(rp->cltubdev);
+ class_device_destroy(class3270, MKDEV(IBM_TTY3270_MAJOR, rp->minor));
+
+out_ttydev:
+ sysfs_remove_group(&rp->cdev->dev.kobj, &raw3270_attr_group);
+out:
+ return rc;
}
/*
@@ -1255,7 +1271,9 @@ raw3270_set_online (struct ccw_device *cdev)
rc = raw3270_reset_device(rp);
if (rc)
goto failure;
- raw3270_create_attributes(rp);
+ rc = raw3270_create_attributes(rp);
+ if (rc)
+ goto failure;
set_bit(RAW3270_FLAGS_READY, &rp->flags);
mutex_lock(&raw3270_mutex);
list_for_each_entry(np, &raw3270_notifier, list)
@@ -1296,7 +1314,7 @@ raw3270_remove (struct ccw_device *cdev)
spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
if (rp->view) {
rp->view->fn->deactivate(rp->view);
- rp->view = 0;
+ rp->view = NULL;
}
while (!list_empty(&rp->view_list)) {
v = list_entry(rp->view_list.next, struct raw3270_view, list);
diff --git a/drivers/s390/char/raw3270.h b/drivers/s390/char/raw3270.h
index b635bf8e777..90beaa80a78 100644
--- a/drivers/s390/char/raw3270.h
+++ b/drivers/s390/char/raw3270.h
@@ -231,7 +231,7 @@ alloc_string(struct list_head *free_list, unsigned long len)
INIT_LIST_HEAD(&cs->update);
return cs;
}
- return 0;
+ return NULL;
}
static inline unsigned long
diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c
index 48b4d30a725..7b95dab913d 100644
--- a/drivers/s390/char/tape_34xx.c
+++ b/drivers/s390/char/tape_34xx.c
@@ -1309,9 +1309,9 @@ static struct tape_discipline tape_discipline_34xx = {
};
static struct ccw_device_id tape_34xx_ids[] = {
- { CCW_DEVICE_DEVTYPE(0x3480, 0, 0x3480, 0), driver_info: tape_3480},
- { CCW_DEVICE_DEVTYPE(0x3490, 0, 0x3490, 0), driver_info: tape_3490},
- { /* end of list */ }
+ { CCW_DEVICE_DEVTYPE(0x3480, 0, 0x3480, 0), .driver_info = tape_3480},
+ { CCW_DEVICE_DEVTYPE(0x3490, 0, 0x3490, 0), .driver_info = tape_3490},
+ { /* end of list */ },
};
static int
diff --git a/drivers/s390/char/tape_class.c b/drivers/s390/char/tape_class.c
index a5c68e60fcf..643b6d07856 100644
--- a/drivers/s390/char/tape_class.c
+++ b/drivers/s390/char/tape_class.c
@@ -76,14 +76,22 @@ struct tape_class_device *register_tape_dev(
device,
"%s", tcd->device_name
);
- sysfs_create_link(
+ rc = PTR_ERR(tcd->class_device);
+ if (rc)
+ goto fail_with_cdev;
+ rc = sysfs_create_link(
&device->kobj,
&tcd->class_device->kobj,
tcd->mode_name
);
+ if (rc)
+ goto fail_with_class_device;
return tcd;
+fail_with_class_device:
+ class_device_destroy(tape_class, tcd->char_device->dev);
+
fail_with_cdev:
cdev_del(tcd->char_device);
diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c
index 122b4d8965c..2826aed9104 100644
--- a/drivers/s390/char/tape_core.c
+++ b/drivers/s390/char/tape_core.c
@@ -543,20 +543,24 @@ int
tape_generic_probe(struct ccw_device *cdev)
{
struct tape_device *device;
+ int ret;
device = tape_alloc_device();
if (IS_ERR(device))
return -ENODEV;
- PRINT_INFO("tape device %s found\n", cdev->dev.bus_id);
+ ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP);
+ ret = sysfs_create_group(&cdev->dev.kobj, &tape_attr_group);
+ if (ret) {
+ tape_put_device(device);
+ PRINT_ERR("probe failed for tape device %s\n", cdev->dev.bus_id);
+ return ret;
+ }
cdev->dev.driver_data = device;
+ cdev->handler = __tape_do_irq;
device->cdev = cdev;
device->cdev_id = busid_to_int(cdev->dev.bus_id);
- cdev->handler = __tape_do_irq;
-
- ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP);
- sysfs_create_group(&cdev->dev.kobj, &tape_attr_group);
-
- return 0;
+ PRINT_INFO("tape device %s found\n", cdev->dev.bus_id);
+ return ret;
}
static inline void
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
index f496f236b9c..29718042c6c 100644
--- a/drivers/s390/char/tty3270.c
+++ b/drivers/s390/char/tty3270.c
@@ -437,7 +437,7 @@ tty3270_rcl_add(struct tty3270 *tp, char *input, int len)
{
struct string *s;
- tp->rcl_walk = 0;
+ tp->rcl_walk = NULL;
if (len <= 0)
return;
if (tp->rcl_nr >= tp->rcl_max) {
@@ -466,12 +466,12 @@ tty3270_rcl_backward(struct kbd_data *kbd)
else if (!list_empty(&tp->rcl_lines))
tp->rcl_walk = tp->rcl_lines.prev;
s = tp->rcl_walk ?
- list_entry(tp->rcl_walk, struct string, list) : 0;
+ list_entry(tp->rcl_walk, struct string, list) : NULL;
if (tp->rcl_walk) {
s = list_entry(tp->rcl_walk, struct string, list);
tty3270_update_prompt(tp, s->string, s->len);
} else
- tty3270_update_prompt(tp, 0, 0);
+ tty3270_update_prompt(tp, NULL, 0);
tty3270_set_timer(tp, 1);
}
spin_unlock_bh(&tp->view.lock);
@@ -553,7 +553,7 @@ tty3270_read_tasklet(struct raw3270_request *rrq)
* has to be emitted to the tty and for 0x6d the screen
* needs to be redrawn.
*/
- input = 0;
+ input = NULL;
len = 0;
if (tp->input->string[0] == 0x7d) {
/* Enter: write input to tty. */
@@ -567,7 +567,7 @@ tty3270_read_tasklet(struct raw3270_request *rrq)
tty3270_update_status(tp);
}
/* Clear input area. */
- tty3270_update_prompt(tp, 0, 0);
+ tty3270_update_prompt(tp, NULL, 0);
tty3270_set_timer(tp, 1);
} else if (tp->input->string[0] == 0x6d) {
/* Display has been cleared. Redraw. */
@@ -808,8 +808,8 @@ tty3270_release(struct raw3270_view *view)
tp = (struct tty3270 *) view;
tty = tp->tty;
if (tty) {
- tty->driver_data = 0;
- tp->tty = tp->kbd->tty = 0;
+ tty->driver_data = NULL;
+ tp->tty = tp->kbd->tty = NULL;
tty_hangup(tty);
raw3270_put_view(&tp->view);
}
@@ -948,8 +948,8 @@ tty3270_close(struct tty_struct *tty, struct file * filp)
return;
tp = (struct tty3270 *) tty->driver_data;
if (tp) {
- tty->driver_data = 0;
- tp->tty = tp->kbd->tty = 0;
+ tty->driver_data = NULL;
+ tp->tty = tp->kbd->tty = NULL;
raw3270_put_view(&tp->view);
}
}
@@ -1673,7 +1673,7 @@ tty3270_set_termios(struct tty_struct *tty, struct termios *old)
new = L_ECHO(tty) ? TF_INPUT: TF_INPUTN;
if (new != tp->inattr) {
tp->inattr = new;
- tty3270_update_prompt(tp, 0, 0);
+ tty3270_update_prompt(tp, NULL, 0);
tty3270_set_timer(tp, 1);
}
}
@@ -1759,7 +1759,7 @@ void
tty3270_notifier(int index, int active)
{
if (active)
- tty_register_device(tty3270_driver, index, 0);
+ tty_register_device(tty3270_driver, index, NULL);
else
tty_unregister_device(tty3270_driver, index);
}
@@ -1818,7 +1818,7 @@ tty3270_exit(void)
raw3270_unregister_notifier(tty3270_notifier);
driver = tty3270_driver;
- tty3270_driver = 0;
+ tty3270_driver = NULL;
tty_unregister_driver(driver);
tty3270_del_views();
}
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c
index c625b69ebd1..6cb23040954 100644
--- a/drivers/s390/char/vmlogrdr.c
+++ b/drivers/s390/char/vmlogrdr.c
@@ -86,8 +86,8 @@ struct vmlogrdr_priv_t {
*/
static int vmlogrdr_open(struct inode *, struct file *);
static int vmlogrdr_release(struct inode *, struct file *);
-static ssize_t vmlogrdr_read (struct file *filp, char *data, size_t count,
- loff_t * ppos);
+static ssize_t vmlogrdr_read (struct file *filp, char __user *data,
+ size_t count, loff_t * ppos);
static struct file_operations vmlogrdr_fops = {
.owner = THIS_MODULE,
@@ -515,7 +515,7 @@ vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) {
static ssize_t
-vmlogrdr_read (struct file *filp, char *data, size_t count, loff_t * ppos)
+vmlogrdr_read(struct file *filp, char __user *data, size_t count, loff_t * ppos)
{
int rc;
struct vmlogrdr_priv_t * priv = filp->private_data;
diff --git a/drivers/s390/char/vmwatchdog.c b/drivers/s390/char/vmwatchdog.c
index 5acc0ace3d7..807320a41fa 100644
--- a/drivers/s390/char/vmwatchdog.c
+++ b/drivers/s390/char/vmwatchdog.c
@@ -193,7 +193,7 @@ static int vmwdt_ioctl(struct inode *i, struct file *f,
return 0;
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
- return put_user(0, (int *)arg);
+ return put_user(0, (int __user *)arg);
case WDIOC_GETTEMP:
return -EINVAL;
case WDIOC_SETOPTIONS:
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index c7319a07ba3..3cba6c9fab1 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -152,7 +152,6 @@ ccwgroup_create(struct device *root,
struct ccwgroup_device *gdev;
int i;
int rc;
- int del_drvdata;
if (argc > 256) /* disallow dumb users */
return -EINVAL;
@@ -163,7 +162,6 @@ ccwgroup_create(struct device *root,
atomic_set(&gdev->onoff, 0);
- del_drvdata = 0;
for (i = 0; i < argc; i++) {
gdev->cdev[i] = get_ccwdev_by_busid(cdrv, argv[i]);
@@ -180,10 +178,8 @@ ccwgroup_create(struct device *root,
rc = -EINVAL;
goto free_dev;
}
- }
- for (i = 0; i < argc; i++)
gdev->cdev[i]->dev.driver_data = gdev;
- del_drvdata = 1;
+ }
gdev->creator_id = creator_id;
gdev->count = argc;
@@ -226,9 +222,9 @@ error:
free_dev:
for (i = 0; i < argc; i++)
if (gdev->cdev[i]) {
- put_device(&gdev->cdev[i]->dev);
- if (del_drvdata)
+ if (gdev->cdev[i]->dev.driver_data == gdev)
gdev->cdev[i]->dev.driver_data = NULL;
+ put_device(&gdev->cdev[i]->dev);
}
kfree(gdev);
return rc;
@@ -319,7 +315,7 @@ ccwgroup_online_store (struct device *dev, struct device_attribute *attr, const
if (!try_module_get(gdrv->owner))
return -EINVAL;
- value = simple_strtoul(buf, 0, 0);
+ value = simple_strtoul(buf, NULL, 0);
ret = count;
if (value == 1)
ccwgroup_set_online(gdev);
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index a01f3bba4a7..61ce3f1d522 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -1464,6 +1464,40 @@ chsc_get_chp_desc(struct subchannel *sch, int chp_no)
return desc;
}
+static int reset_channel_path(struct channel_path *chp)
+{
+ int cc;
+
+ cc = rchp(chp->id);
+ switch (cc) {
+ case 0:
+ return 0;
+ case 2:
+ return -EBUSY;
+ default:
+ return -ENODEV;
+ }
+}
+
+static void reset_channel_paths_css(struct channel_subsystem *css)
+{
+ int i;
+
+ for (i = 0; i <= __MAX_CHPID; i++) {
+ if (css->chps[i])
+ reset_channel_path(css->chps[i]);
+ }
+}
+
+void cio_reset_channel_paths(void)
+{
+ int i;
+
+ for (i = 0; i <= __MAX_CSSID; i++) {
+ if (css[i] && css[i]->valid)
+ reset_channel_paths_css(css[i]);
+ }
+}
static int __init
chsc_alloc_sei_area(void)
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 6fec90eab00..89320c1ad82 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -519,6 +519,7 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
memset(sch, 0, sizeof(struct subchannel));
spin_lock_init(&sch->lock);
+ mutex_init(&sch->reg_mutex);
/* Set a name for the subchannel */
snprintf (sch->dev.bus_id, BUS_ID_SIZE, "0.%x.%04x", schid.ssid,
@@ -797,7 +798,7 @@ struct subchannel *
cio_get_console_subchannel(void)
{
if (!console_subchannel_in_use)
- return 0;
+ return NULL;
return &console_subchannel;
}
@@ -875,5 +876,6 @@ void
reipl(unsigned long devno)
{
clear_all_subchannels();
+ cio_reset_channel_paths();
do_reipl(devno);
}
diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h
index 0ca987344e0..4541c1af4b6 100644
--- a/drivers/s390/cio/cio.h
+++ b/drivers/s390/cio/cio.h
@@ -2,6 +2,7 @@
#define S390_CIO_H
#include "schid.h"
+#include <linux/mutex.h>
/*
* where we put the ssd info
@@ -87,7 +88,7 @@ struct orb {
struct subchannel {
struct subchannel_id schid;
spinlock_t lock; /* subchannel lock */
-
+ struct mutex reg_mutex;
enum {
SUBCHANNEL_TYPE_IO = 0,
SUBCHANNEL_TYPE_CHSC = 1,
diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c
index 1c3e8e9012b..828b2d334f0 100644
--- a/drivers/s390/cio/cmf.c
+++ b/drivers/s390/cio/cmf.c
@@ -1068,6 +1068,7 @@ cmb_show_avg_sample_interval(struct device *dev, struct device_attribute *attr,
if (count) {
interval = cmb_data->last_update -
cdev->private->cmb_start_time;
+ interval = (interval * 1000) >> 12;
interval /= count;
} else
interval = -1;
@@ -1140,7 +1141,7 @@ static struct attribute *cmf_attributes[] = {
&dev_attr_avg_device_disconnect_time.attr,
&dev_attr_avg_control_unit_queuing_time.attr,
&dev_attr_avg_device_active_only_time.attr,
- 0,
+ NULL,
};
static struct attribute_group cmf_attr_group = {
@@ -1160,7 +1161,7 @@ static struct attribute *cmf_attributes_ext[] = {
&dev_attr_avg_device_active_only_time.attr,
&dev_attr_avg_device_busy_time.attr,
&dev_attr_avg_initial_command_response_time.attr,
- 0,
+ NULL,
};
static struct attribute_group cmf_attr_group_ext = {
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 1d3be80797f..13eeea3d547 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -108,6 +108,24 @@ css_subchannel_release(struct device *dev)
extern int css_get_ssd_info(struct subchannel *sch);
+
+int css_sch_device_register(struct subchannel *sch)
+{
+ int ret;
+
+ mutex_lock(&sch->reg_mutex);
+ ret = device_register(&sch->dev);
+ mutex_unlock(&sch->reg_mutex);
+ return ret;
+}
+
+void css_sch_device_unregister(struct subchannel *sch)
+{
+ mutex_lock(&sch->reg_mutex);
+ device_unregister(&sch->dev);
+ mutex_unlock(&sch->reg_mutex);
+}
+
static int
css_register_subchannel(struct subchannel *sch)
{
@@ -119,7 +137,7 @@ css_register_subchannel(struct subchannel *sch)
sch->dev.release = &css_subchannel_release;
/* make it known to the system */
- ret = device_register(&sch->dev);
+ ret = css_sch_device_register(sch);
if (ret)
printk (KERN_WARNING "%s: could not register %s\n",
__func__, sch->dev.bus_id);
@@ -250,7 +268,7 @@ css_evaluate_subchannel(struct subchannel_id schid, int slow)
* The device will be killed automatically.
*/
cio_disable_subchannel(sch);
- device_unregister(&sch->dev);
+ css_sch_device_unregister(sch);
/* Reset intparm to zeroes. */
sch->schib.pmcw.intparm = 0;
cio_modify(sch);
@@ -264,7 +282,7 @@ css_evaluate_subchannel(struct subchannel_id schid, int slow)
* away in any case.
*/
if (!disc) {
- device_unregister(&sch->dev);
+ css_sch_device_unregister(sch);
/* Reset intparm to zeroes. */
sch->schib.pmcw.intparm = 0;
cio_modify(sch);
@@ -605,9 +623,13 @@ init_channel_subsystem (void)
ret = device_register(&css[i]->device);
if (ret)
goto out_free;
- if (css_characteristics_avail && css_chsc_characteristics.secm)
- device_create_file(&css[i]->device,
- &dev_attr_cm_enable);
+ if (css_characteristics_avail &&
+ css_chsc_characteristics.secm) {
+ ret = device_create_file(&css[i]->device,
+ &dev_attr_cm_enable);
+ if (ret)
+ goto out_device;
+ }
}
css_init_done = 1;
@@ -615,6 +637,8 @@ init_channel_subsystem (void)
for_each_subchannel(__init_channel_subsystem, NULL);
return 0;
+out_device:
+ device_unregister(&css[i]->device);
out_free:
kfree(css[i]);
out_unregister:
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h
index e210f89a244..8aabb4adeb5 100644
--- a/drivers/s390/cio/css.h
+++ b/drivers/s390/cio/css.h
@@ -100,7 +100,7 @@ struct ccw_device_private {
struct qdio_irq *qdio_data;
struct irb irb; /* device status */
struct senseid senseid; /* SenseID info */
- struct pgid pgid; /* path group ID */
+ struct pgid pgid[8]; /* path group IDs per chpid*/
struct ccw1 iccws[2]; /* ccws for SNID/SID/SPGID commands */
struct work_struct kick_work;
wait_queue_head_t wait_q;
@@ -136,6 +136,8 @@ extern struct bus_type css_bus_type;
extern struct css_driver io_subchannel_driver;
extern int css_probe_device(struct subchannel_id);
+extern int css_sch_device_register(struct subchannel *);
+extern void css_sch_device_unregister(struct subchannel *);
extern struct subchannel * get_subchannel_by_schid(struct subchannel_id);
extern int css_init_done;
extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *);
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 67f0de6aed3..585fa04233c 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -100,7 +100,7 @@ ccw_uevent (struct device *dev, char **envp, int num_envp,
if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
- envp[i] = 0;
+ envp[i] = NULL;
return 0;
}
@@ -280,7 +280,7 @@ ccw_device_remove_disconnected(struct ccw_device *cdev)
* 'throw away device'.
*/
sch = to_subchannel(cdev->dev.parent);
- device_unregister(&sch->dev);
+ css_sch_device_unregister(sch);
/* Reset intparm to zeroes. */
sch->schib.pmcw.intparm = 0;
cio_modify(sch);
@@ -625,7 +625,7 @@ ccw_device_do_unreg_rereg(void *data)
other_sch->schib.pmcw.intparm = 0;
cio_modify(other_sch);
}
- device_unregister(&other_sch->dev);
+ css_sch_device_unregister(other_sch);
}
}
/* Update ssd info here. */
@@ -709,7 +709,7 @@ ccw_device_call_sch_unregister(void *data)
struct subchannel *sch;
sch = to_subchannel(cdev->dev.parent);
- device_unregister(&sch->dev);
+ css_sch_device_unregister(sch);
/* Reset intparm to zeroes. */
sch->schib.pmcw.intparm = 0;
cio_modify(sch);
@@ -1057,7 +1057,7 @@ get_ccwdev_by_busid(struct ccw_driver *cdrv, const char *bus_id)
__ccwdev_check_busid);
put_driver(drv);
- return dev ? to_ccwdev(dev) : 0;
+ return dev ? to_ccwdev(dev) : NULL;
}
/************************** device driver handling ************************/
@@ -1082,7 +1082,7 @@ ccw_device_probe (struct device *dev)
ret = cdrv->probe ? cdrv->probe(cdev) : -ENODEV;
if (ret) {
- cdev->drv = 0;
+ cdev->drv = NULL;
return ret;
}
@@ -1113,7 +1113,7 @@ ccw_device_remove (struct device *dev)
ret, cdev->dev.bus_id);
}
ccw_device_set_timeout(cdev, 0);
- cdev->drv = 0;
+ cdev->drv = NULL;
return 0;
}
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index cb1af0b6f03..7a39e0b0386 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -152,7 +152,8 @@ ccw_device_cancel_halt_clear(struct ccw_device *cdev)
if (cdev->private->iretry) {
cdev->private->iretry--;
ret = cio_halt(sch);
- return (ret == 0) ? -EBUSY : ret;
+ if (ret != -EBUSY)
+ return (ret == 0) ? -EBUSY : ret;
}
/* halt io unsuccessful. */
cdev->private->iretry = 255; /* 255 clear retries. */
@@ -378,6 +379,56 @@ ccw_device_done(struct ccw_device *cdev, int state)
put_device (&cdev->dev);
}
+static inline int cmp_pgid(struct pgid *p1, struct pgid *p2)
+{
+ char *c1;
+ char *c2;
+
+ c1 = (char *)p1;
+ c2 = (char *)p2;
+
+ return memcmp(c1 + 1, c2 + 1, sizeof(struct pgid) - 1);
+}
+
+static void __ccw_device_get_common_pgid(struct ccw_device *cdev)
+{
+ int i;
+ int last;
+
+ last = 0;
+ for (i = 0; i < 8; i++) {
+ if (cdev->private->pgid[i].inf.ps.state1 == SNID_STATE1_RESET)
+ /* No PGID yet */
+ continue;
+ if (cdev->private->pgid[last].inf.ps.state1 ==
+ SNID_STATE1_RESET) {
+ /* First non-zero PGID */
+ last = i;
+ continue;
+ }
+ if (cmp_pgid(&cdev->private->pgid[i],
+ &cdev->private->pgid[last]) == 0)
+ /* Non-conflicting PGIDs */
+ continue;
+
+ /* PGID mismatch, can't pathgroup. */
+ CIO_MSG_EVENT(0, "SNID - pgid mismatch for device "
+ "0.%x.%04x, can't pathgroup\n",
+ cdev->private->ssid, cdev->private->devno);
+ cdev->private->options.pgroup = 0;
+ return;
+ }
+ if (cdev->private->pgid[last].inf.ps.state1 ==
+ SNID_STATE1_RESET)
+ /* No previous pgid found */
+ memcpy(&cdev->private->pgid[0], &css[0]->global_pgid,
+ sizeof(struct pgid));
+ else
+ /* Use existing pgid */
+ memcpy(&cdev->private->pgid[0], &cdev->private->pgid[last],
+ sizeof(struct pgid));
+}
+
/*
* Function called from device_pgid.c after sense path ground has completed.
*/
@@ -388,24 +439,26 @@ ccw_device_sense_pgid_done(struct ccw_device *cdev, int err)
sch = to_subchannel(cdev->dev.parent);
switch (err) {
- case 0:
- /* Start Path Group verification. */
- sch->vpm = 0; /* Start with no path groups set. */
- cdev->private->state = DEV_STATE_VERIFY;
- ccw_device_verify_start(cdev);
+ case -EOPNOTSUPP: /* path grouping not supported, use nop instead. */
+ cdev->private->options.pgroup = 0;
+ break;
+ case 0: /* success */
+ case -EACCES: /* partial success, some paths not operational */
+ /* Check if all pgids are equal or 0. */
+ __ccw_device_get_common_pgid(cdev);
break;
case -ETIME: /* Sense path group id stopped by timeout. */
case -EUSERS: /* device is reserved for someone else. */
ccw_device_done(cdev, DEV_STATE_BOXED);
- break;
- case -EOPNOTSUPP: /* path grouping not supported, just set online. */
- cdev->private->options.pgroup = 0;
- ccw_device_done(cdev, DEV_STATE_ONLINE);
- break;
+ return;
default:
ccw_device_done(cdev, DEV_STATE_NOT_OPER);
- break;
+ return;
}
+ /* Start Path Group verification. */
+ sch->vpm = 0; /* Start with no path groups set. */
+ cdev->private->state = DEV_STATE_VERIFY;
+ ccw_device_verify_start(cdev);
}
/*
@@ -562,8 +615,9 @@ ccw_device_online(struct ccw_device *cdev)
}
/* Do we want to do path grouping? */
if (!cdev->private->options.pgroup) {
- /* No, set state online immediately. */
- ccw_device_done(cdev, DEV_STATE_ONLINE);
+ /* Start initial path verification. */
+ cdev->private->state = DEV_STATE_VERIFY;
+ ccw_device_verify_start(cdev);
return 0;
}
/* Do a SensePGID first. */
@@ -609,6 +663,7 @@ ccw_device_offline(struct ccw_device *cdev)
/* Are we doing path grouping? */
if (!cdev->private->options.pgroup) {
/* No, set state offline immediately. */
+ sch->vpm = 0;
ccw_device_done(cdev, DEV_STATE_OFFLINE);
return 0;
}
@@ -705,8 +760,6 @@ ccw_device_online_verify(struct ccw_device *cdev, enum dev_event dev_event)
{
struct subchannel *sch;
- if (!cdev->private->options.pgroup)
- return;
if (cdev->private->state == DEV_STATE_W4SENSE) {
cdev->private->flags.doverify = 1;
return;
@@ -995,8 +1048,7 @@ static void
ccw_device_wait4io_verify(struct ccw_device *cdev, enum dev_event dev_event)
{
/* When the I/O has terminated, we have to start verification. */
- if (cdev->private->options.pgroup)
- cdev->private->flags.doverify = 1;
+ cdev->private->flags.doverify = 1;
}
static void
diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c
index 54cb64ed078..32610fd8868 100644
--- a/drivers/s390/cio/device_pgid.c
+++ b/drivers/s390/cio/device_pgid.c
@@ -33,12 +33,17 @@ __ccw_device_sense_pgid_start(struct ccw_device *cdev)
struct subchannel *sch;
struct ccw1 *ccw;
int ret;
+ int i;
sch = to_subchannel(cdev->dev.parent);
+ /* Return if we already checked on all paths. */
+ if (cdev->private->imask == 0)
+ return (sch->lpm == 0) ? -ENODEV : -EACCES;
+ i = 8 - ffs(cdev->private->imask);
+
/* Setup sense path group id channel program. */
ccw = cdev->private->iccws;
ccw->cmd_code = CCW_CMD_SENSE_PGID;
- ccw->cda = (__u32) __pa (&cdev->private->pgid);
ccw->count = sizeof (struct pgid);
ccw->flags = CCW_FLAG_SLI;
@@ -48,6 +53,7 @@ __ccw_device_sense_pgid_start(struct ccw_device *cdev)
ret = -ENODEV;
while (cdev->private->imask != 0) {
/* Try every path multiple times. */
+ ccw->cda = (__u32) __pa (&cdev->private->pgid[i]);
if (cdev->private->iretry > 0) {
cdev->private->iretry--;
ret = cio_start (sch, cdev->private->iccws,
@@ -64,7 +70,9 @@ __ccw_device_sense_pgid_start(struct ccw_device *cdev)
}
cdev->private->imask >>= 1;
cdev->private->iretry = 5;
+ i++;
}
+
return ret;
}
@@ -76,7 +84,7 @@ ccw_device_sense_pgid_start(struct ccw_device *cdev)
cdev->private->state = DEV_STATE_SENSE_PGID;
cdev->private->imask = 0x80;
cdev->private->iretry = 5;
- memset (&cdev->private->pgid, 0, sizeof (struct pgid));
+ memset (&cdev->private->pgid, 0, sizeof (cdev->private->pgid));
ret = __ccw_device_sense_pgid_start(cdev);
if (ret && ret != -EBUSY)
ccw_device_sense_pgid_done(cdev, ret);
@@ -91,6 +99,7 @@ __ccw_device_check_sense_pgid(struct ccw_device *cdev)
{
struct subchannel *sch;
struct irb *irb;
+ int i;
sch = to_subchannel(cdev->dev.parent);
irb = &cdev->private->irb;
@@ -124,7 +133,8 @@ __ccw_device_check_sense_pgid(struct ccw_device *cdev)
sch->schid.sch_no, sch->orb.lpm);
return -EACCES;
}
- if (cdev->private->pgid.inf.ps.state2 == SNID_STATE2_RESVD_ELSE) {
+ i = 8 - ffs(cdev->private->imask);
+ if (cdev->private->pgid[i].inf.ps.state2 == SNID_STATE2_RESVD_ELSE) {
CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel 0.%x.%04x "
"is reserved by someone else\n",
cdev->private->devno, sch->schid.ssid,
@@ -162,12 +172,6 @@ ccw_device_sense_pgid_irq(struct ccw_device *cdev, enum dev_event dev_event)
memset(&cdev->private->irb, 0, sizeof(struct irb));
switch (ret) {
/* 0, -ETIME, -EOPNOTSUPP, -EAGAIN, -EACCES or -EUSERS */
- case 0: /* Sense Path Group ID successful. */
- if (cdev->private->pgid.inf.ps.state1 == SNID_STATE1_RESET)
- memcpy(&cdev->private->pgid, &css[0]->global_pgid,
- sizeof(struct pgid));
- ccw_device_sense_pgid_done(cdev, 0);
- break;
case -EOPNOTSUPP: /* Sense Path Group ID not supported */
ccw_device_sense_pgid_done(cdev, -EOPNOTSUPP);
break;
@@ -176,13 +180,15 @@ ccw_device_sense_pgid_irq(struct ccw_device *cdev, enum dev_event dev_event)
break;
case -EACCES: /* channel is not operational. */
sch->lpm &= ~cdev->private->imask;
+ /* Fall through. */
+ case 0: /* Sense Path Group ID successful. */
cdev->private->imask >>= 1;
cdev->private->iretry = 5;
/* Fall through. */
case -EAGAIN: /* Try again. */
ret = __ccw_device_sense_pgid_start(cdev);
if (ret != 0 && ret != -EBUSY)
- ccw_device_sense_pgid_done(cdev, -ENODEV);
+ ccw_device_sense_pgid_done(cdev, ret);
break;
case -EUSERS: /* device is reserved for someone else. */
ccw_device_sense_pgid_done(cdev, -EUSERS);
@@ -203,20 +209,20 @@ __ccw_device_do_pgid(struct ccw_device *cdev, __u8 func)
sch = to_subchannel(cdev->dev.parent);
/* Setup sense path group id channel program. */
- cdev->private->pgid.inf.fc = func;
+ cdev->private->pgid[0].inf.fc = func;
ccw = cdev->private->iccws;
if (!cdev->private->flags.pgid_single) {
- cdev->private->pgid.inf.fc |= SPID_FUNC_MULTI_PATH;
+ cdev->private->pgid[0].inf.fc |= SPID_FUNC_MULTI_PATH;
ccw->cmd_code = CCW_CMD_SUSPEND_RECONN;
ccw->cda = 0;
ccw->count = 0;
ccw->flags = CCW_FLAG_SLI | CCW_FLAG_CC;
ccw++;
} else
- cdev->private->pgid.inf.fc |= SPID_FUNC_SINGLE_PATH;
+ cdev->private->pgid[0].inf.fc |= SPID_FUNC_SINGLE_PATH;
ccw->cmd_code = CCW_CMD_SET_PGID;
- ccw->cda = (__u32) __pa (&cdev->private->pgid);
+ ccw->cda = (__u32) __pa (&cdev->private->pgid[0]);
ccw->count = sizeof (struct pgid);
ccw->flags = CCW_FLAG_SLI;
@@ -244,6 +250,48 @@ __ccw_device_do_pgid(struct ccw_device *cdev, __u8 func)
}
/*
+ * Helper function to send a nop ccw down a path.
+ */
+static int __ccw_device_do_nop(struct ccw_device *cdev)
+{
+ struct subchannel *sch;
+ struct ccw1 *ccw;
+ int ret;
+
+ sch = to_subchannel(cdev->dev.parent);
+
+ /* Setup nop channel program. */
+ ccw = cdev->private->iccws;
+ ccw->cmd_code = CCW_CMD_NOOP;
+ ccw->cda = 0;
+ ccw->count = 0;
+ ccw->flags = CCW_FLAG_SLI;
+
+ /* Reset device status. */
+ memset(&cdev->private->irb, 0, sizeof(struct irb));
+
+ /* Try multiple times. */
+ ret = -ENODEV;
+ if (cdev->private->iretry > 0) {
+ cdev->private->iretry--;
+ ret = cio_start (sch, cdev->private->iccws,
+ cdev->private->imask);
+ /* ret is 0, -EBUSY, -EACCES or -ENODEV */
+ if ((ret != -EACCES) && (ret != -ENODEV))
+ return ret;
+ }
+ /* nop command failed on this path. Switch it off. */
+ sch->lpm &= ~cdev->private->imask;
+ sch->vpm &= ~cdev->private->imask;
+ CIO_MSG_EVENT(2, "NOP - Device %04x on Subchannel "
+ "0.%x.%04x, lpm %02X, became 'not operational'\n",
+ cdev->private->devno, sch->schid.ssid,
+ sch->schid.sch_no, cdev->private->imask);
+ return ret;
+}
+
+
+/*
* Called from interrupt context to check if a valid answer
* to Set Path Group ID was received.
*/
@@ -282,6 +330,29 @@ __ccw_device_check_pgid(struct ccw_device *cdev)
return 0;
}
+/*
+ * Called from interrupt context to check the path status after a nop has
+ * been send.
+ */
+static int __ccw_device_check_nop(struct ccw_device *cdev)
+{
+ struct subchannel *sch;
+ struct irb *irb;
+
+ sch = to_subchannel(cdev->dev.parent);
+ irb = &cdev->private->irb;
+ if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC))
+ return -ETIME;
+ if (irb->scsw.cc == 3) {
+ CIO_MSG_EVENT(2, "NOP - Device %04x on Subchannel 0.%x.%04x,"
+ " lpm %02X, became 'not operational'\n",
+ cdev->private->devno, sch->schid.ssid,
+ sch->schid.sch_no, cdev->private->imask);
+ return -EACCES;
+ }
+ return 0;
+}
+
static void
__ccw_device_verify_start(struct ccw_device *cdev)
{
@@ -296,9 +367,12 @@ __ccw_device_verify_start(struct ccw_device *cdev)
if ((sch->vpm & imask) != (sch->lpm & imask))
break;
cdev->private->imask = imask;
- func = (sch->vpm & imask) ?
- SPID_FUNC_RESIGN : SPID_FUNC_ESTABLISH;
- ret = __ccw_device_do_pgid(cdev, func);
+ if (cdev->private->options.pgroup) {
+ func = (sch->vpm & imask) ?
+ SPID_FUNC_RESIGN : SPID_FUNC_ESTABLISH;
+ ret = __ccw_device_do_pgid(cdev, func);
+ } else
+ ret = __ccw_device_do_nop(cdev);
if (ret == 0 || ret == -EBUSY)
return;
cdev->private->iretry = 5;
@@ -327,7 +401,10 @@ ccw_device_verify_irq(struct ccw_device *cdev, enum dev_event dev_event)
if (ccw_device_accumulate_and_sense(cdev, irb) != 0)
return;
sch = to_subchannel(cdev->dev.parent);
- ret = __ccw_device_check_pgid(cdev);
+ if (cdev->private->options.pgroup)
+ ret = __ccw_device_check_pgid(cdev);
+ else
+ ret = __ccw_device_check_nop(cdev);
memset(&cdev->private->irb, 0, sizeof(struct irb));
switch (ret) {
/* 0, -ETIME, -EAGAIN, -EOPNOTSUPP or -EACCES */
@@ -345,11 +422,10 @@ ccw_device_verify_irq(struct ccw_device *cdev, enum dev_event dev_event)
* One of those strange devices which claim to be able
* to do multipathing but not for Set Path Group ID.
*/
- if (cdev->private->flags.pgid_single) {
- ccw_device_verify_done(cdev, -EOPNOTSUPP);
- break;
- }
- cdev->private->flags.pgid_single = 1;
+ if (cdev->private->flags.pgid_single)
+ cdev->private->options.pgroup = 0;
+ else
+ cdev->private->flags.pgid_single = 1;
/* fall through. */
case -EAGAIN: /* Try again. */
__ccw_device_verify_start(cdev);
diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c
index 14bef2c179b..caf148d5caa 100644
--- a/drivers/s390/cio/device_status.c
+++ b/drivers/s390/cio/device_status.c
@@ -67,8 +67,7 @@ ccw_device_path_notoper(struct ccw_device *cdev)
sch->schib.pmcw.pnom);
sch->lpm &= ~sch->schib.pmcw.pnom;
- if (cdev->private->options.pgroup)
- cdev->private->flags.doverify = 1;
+ cdev->private->flags.doverify = 1;
}
/*
@@ -180,7 +179,7 @@ ccw_device_accumulate_esw(struct ccw_device *cdev, struct irb *irb)
cdev_irb->esw.esw0.erw.auth = irb->esw.esw0.erw.auth;
/* Copy path verification required flag. */
cdev_irb->esw.esw0.erw.pvrf = irb->esw.esw0.erw.pvrf;
- if (irb->esw.esw0.erw.pvrf && cdev->private->options.pgroup)
+ if (irb->esw.esw0.erw.pvrf)
cdev->private->flags.doverify = 1;
/* Copy concurrent sense bit. */
cdev_irb->esw.esw0.erw.cons = irb->esw.esw0.erw.cons;
@@ -354,7 +353,7 @@ ccw_device_accumulate_basic_sense(struct ccw_device *cdev, struct irb *irb)
}
/* Check if path verification is required. */
if (ccw_device_accumulate_esw_valid(irb) &&
- irb->esw.esw0.erw.pvrf && cdev->private->options.pgroup)
+ irb->esw.esw0.erw.pvrf)
cdev->private->flags.doverify = 1;
}
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c
index b70039af70d..7c93a8798d2 100644
--- a/drivers/s390/cio/qdio.c
+++ b/drivers/s390/cio/qdio.c
@@ -2735,7 +2735,7 @@ qdio_free(struct ccw_device *cdev)
QDIO_DBF_TEXT1(0,trace,dbf_text);
QDIO_DBF_TEXT0(0,setup,dbf_text);
- cdev->private->qdio_data = 0;
+ cdev->private->qdio_data = NULL;
up(&irq_ptr->setting_up_sema);
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c
index 23d53bf9daf..95f4e105cb9 100644
--- a/drivers/s390/net/claw.c
+++ b/drivers/s390/net/claw.c
@@ -529,7 +529,7 @@ claw_open(struct net_device *dev)
printk(KERN_INFO "%s:%s Enter \n",dev->name,__FUNCTION__);
#endif
CLAW_DBF_TEXT(4,trace,"open");
- if (!dev | (dev->name[0] == 0x00)) {
+ if (!dev || (dev->name[0] == 0x00)) {
CLAW_DBF_TEXT(2,trace,"BadDev");
printk(KERN_WARNING "claw: Bad device at open failing \n");
return -ENODEV;
diff --git a/drivers/s390/net/ctcmain.c b/drivers/s390/net/ctcmain.c
index 20c8eb16f46..8a4b5812014 100644
--- a/drivers/s390/net/ctcmain.c
+++ b/drivers/s390/net/ctcmain.c
@@ -2686,9 +2686,17 @@ static struct attribute_group ctc_attr_group = {
static int
ctc_add_attributes(struct device *dev)
{
- device_create_file(dev, &dev_attr_loglevel);
- device_create_file(dev, &dev_attr_stats);
- return 0;
+ int rc;
+
+ rc = device_create_file(dev, &dev_attr_loglevel);
+ if (rc)
+ goto out;
+ rc = device_create_file(dev, &dev_attr_stats);
+ if (!rc)
+ goto out;
+ device_remove_file(dev, &dev_attr_loglevel);
+out:
+ return rc;
}
static void
@@ -2901,7 +2909,12 @@ ctc_new_device(struct ccwgroup_device *cgdev)
goto out;
}
- ctc_add_attributes(&cgdev->dev);
+ if (ctc_add_attributes(&cgdev->dev)) {
+ ctc_netdev_unregister(dev);
+ dev->priv = NULL;
+ ctc_free_netdevice(dev, 1);
+ goto out;
+ }
strlcpy(privptr->fsm->name, dev->name, sizeof (privptr->fsm->name));
diff --git a/drivers/s390/net/iucv.c b/drivers/s390/net/iucv.c
index 189a4927543..0e863df4027 100644
--- a/drivers/s390/net/iucv.c
+++ b/drivers/s390/net/iucv.c
@@ -692,7 +692,7 @@ iucv_retrieve_buffer (void)
iucv_debug(1, "entering");
if (iucv_cpuid != -1) {
smp_call_function_on(iucv_retrieve_buffer_cpuid,
- 0, 0, 1, iucv_cpuid);
+ NULL, 0, 1, iucv_cpuid);
/* Release the cpu reserved by iucv_declare_buffer. */
smp_put_cpu(iucv_cpuid);
iucv_cpuid = -1;
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c
index b452cc1afd5..5d6e6cbfa36 100644
--- a/drivers/s390/net/netiucv.c
+++ b/drivers/s390/net/netiucv.c
@@ -2029,7 +2029,7 @@ remove_write (struct device_driver *drv, const char *buf, size_t count)
count = IFNAMSIZ-1;
for (i=0, p=(char *)buf; i<count && *p; i++, p++) {
- if ((*p == '\n') | (*p == ' ')) {
+ if ((*p == '\n') || (*p == ' ')) {
/* trailing lf, grr */
break;
} else {
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
index 8e8963f1573..5fff1f93973 100644
--- a/drivers/s390/net/qeth_main.c
+++ b/drivers/s390/net/qeth_main.c
@@ -4420,8 +4420,10 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO;
struct qeth_eddp_context *ctx = NULL;
int tx_bytes = skb->len;
+#ifdef CONFIG_QETH_PERF_STATS
unsigned short nr_frags = skb_shinfo(skb)->nr_frags;
unsigned short tso_size = skb_shinfo(skb)->gso_size;
+#endif
int rc;
QETH_DBF_TEXT(trace, 6, "sendpkt");
@@ -4457,7 +4459,7 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
queue = card->qdio.out_qs
[qeth_get_priority_queue(card, skb, ipv, cast_type)];
- if (skb_shinfo(skb)->gso_size)
+ if (skb_is_gso(skb))
large_send = card->options.large_send;
/*are we able to do TSO ? If so ,prepare and send it from here */
@@ -4802,7 +4804,7 @@ static struct qeth_cmd_buffer *
qeth_get_setassparms_cmd(struct qeth_card *, enum qeth_ipa_funcs,
__u16, __u16, enum qeth_prot_versions);
static int
-qeth_arp_query(struct qeth_card *card, char *udata)
+qeth_arp_query(struct qeth_card *card, char __user *udata)
{
struct qeth_cmd_buffer *iob;
struct qeth_arp_query_info qinfo = {0, };
@@ -4935,7 +4937,7 @@ qeth_get_adapter_cmd(struct qeth_card *card, __u32 command, __u32 cmdlen)
* function to send SNMP commands to OSA-E card
*/
static int
-qeth_snmp_command(struct qeth_card *card, char *udata)
+qeth_snmp_command(struct qeth_card *card, char __user *udata)
{
struct qeth_cmd_buffer *iob;
struct qeth_ipa_cmd *cmd;
@@ -7907,9 +7909,9 @@ qeth_set_online(struct ccwgroup_device *gdev)
}
static struct ccw_device_id qeth_ids[] = {
- {CCW_DEVICE(0x1731, 0x01), driver_info:QETH_CARD_TYPE_OSAE},
- {CCW_DEVICE(0x1731, 0x05), driver_info:QETH_CARD_TYPE_IQD},
- {CCW_DEVICE(0x1731, 0x06), driver_info:QETH_CARD_TYPE_OSN},
+ {CCW_DEVICE(0x1731, 0x01), .driver_info = QETH_CARD_TYPE_OSAE},
+ {CCW_DEVICE(0x1731, 0x05), .driver_info = QETH_CARD_TYPE_IQD},
+ {CCW_DEVICE(0x1731, 0x06), .driver_info = QETH_CARD_TYPE_OSN},
{},
};
MODULE_DEVICE_TABLE(ccw, qeth_ids);
@@ -8378,7 +8380,7 @@ out:
static struct notifier_block qeth_ip_notifier = {
qeth_ip_event,
- 0
+ NULL,
};
#ifdef CONFIG_QETH_IPV6
@@ -8431,7 +8433,7 @@ out:
static struct notifier_block qeth_ip6_notifier = {
qeth_ip6_event,
- 0
+ NULL,
};
#endif
@@ -8449,16 +8451,17 @@ __qeth_reboot_event_card(struct device *dev, void *data)
static int
qeth_reboot_event(struct notifier_block *this, unsigned long event, void *ptr)
{
+ int ret;
- driver_for_each_device(&qeth_ccwgroup_driver.driver, NULL, NULL,
- __qeth_reboot_event_card);
- return NOTIFY_DONE;
+ ret = driver_for_each_device(&qeth_ccwgroup_driver.driver, NULL, NULL,
+ __qeth_reboot_event_card);
+ return ret ? NOTIFY_BAD : NOTIFY_DONE;
}
static struct notifier_block qeth_reboot_notifier = {
qeth_reboot_event,
- 0
+ NULL,
};
static int
diff --git a/drivers/s390/net/qeth_sys.c b/drivers/s390/net/qeth_sys.c
index 185a9cfbcbd..001497bbea1 100644
--- a/drivers/s390/net/qeth_sys.c
+++ b/drivers/s390/net/qeth_sys.c
@@ -1755,7 +1755,7 @@ qeth_driver_group_store(struct device_driver *ddrv, const char *buf,
}
-static DRIVER_ATTR(group, 0200, 0, qeth_driver_group_store);
+static DRIVER_ATTR(group, 0200, NULL, qeth_driver_group_store);
static ssize_t
qeth_driver_notifier_register_store(struct device_driver *ddrv, const char *buf,
@@ -1783,7 +1783,7 @@ qeth_driver_notifier_register_store(struct device_driver *ddrv, const char *buf,
return count;
}
-static DRIVER_ATTR(notifier_register, 0200, 0,
+static DRIVER_ATTR(notifier_register, 0200, NULL,
qeth_driver_notifier_register_store);
int
diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c
index 72118ee6895..b8179c27ceb 100644
--- a/drivers/s390/net/smsgiucv.c
+++ b/drivers/s390/net/smsgiucv.c
@@ -66,7 +66,7 @@ smsg_message_pending(iucv_MessagePending *eib, void *pgm_data)
return;
}
rc = iucv_receive(eib->ippathid, eib->ipmsgid, eib->iptrgcls,
- msg, len, 0, 0, 0);
+ msg, len, NULL, NULL, NULL);
if (rc == 0) {
msg[len] = 0;
EBCASC(msg, len);
@@ -122,7 +122,7 @@ smsg_unregister_callback(char *prefix, void (*callback)(char *from, char *str))
struct smsg_callback *cb, *tmp;
spin_lock(&smsg_list_lock);
- cb = 0;
+ cb = NULL;
list_for_each_entry(tmp, &smsg_list, list)
if (tmp->callback == callback &&
strcmp(tmp->prefix, prefix) == 0) {
@@ -139,7 +139,7 @@ smsg_exit(void)
{
if (smsg_handle > 0) {
cpcmd("SET SMSG OFF", NULL, 0, NULL);
- iucv_sever(smsg_pathid, 0);
+ iucv_sever(smsg_pathid, NULL);
iucv_unregister_program(smsg_handle);
driver_unregister(&smsg_driver);
}
@@ -162,19 +162,19 @@ smsg_init(void)
return rc;
}
smsg_handle = iucv_register_program("SMSGIUCV ", "*MSG ",
- pgmmask, &smsg_ops, 0);
+ pgmmask, &smsg_ops, NULL);
if (!smsg_handle) {
printk(KERN_ERR "SMSGIUCV: failed to register to iucv");
driver_unregister(&smsg_driver);
return -EIO; /* better errno ? */
}
- rc = iucv_connect (&smsg_pathid, 255, 0, "*MSG ", 0, 0, 0, 0,
- smsg_handle, 0);
+ rc = iucv_connect (&smsg_pathid, 255, NULL, "*MSG ", NULL, 0,
+ NULL, NULL, smsg_handle, NULL);
if (rc) {
printk(KERN_ERR "SMSGIUCV: failed to connect to *MSG");
iucv_unregister_program(smsg_handle);
driver_unregister(&smsg_driver);
- smsg_handle = 0;
+ smsg_handle = NULL;
return -EIO;
}
cpcmd("SET SMSG IUCV", NULL, 0, NULL);
diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c
index ffb3677e354..5399c5d99b8 100644
--- a/drivers/s390/s390mach.c
+++ b/drivers/s390/s390mach.c
@@ -111,6 +111,16 @@ repeat:
break;
case CRW_RSC_CPATH:
pr_debug("source is channel path %02X\n", crw[0].rsid);
+ /*
+ * Check for solicited machine checks. These are
+ * created by reset channel path and need not be
+ * reported to the common I/O layer.
+ */
+ if (crw[chain].slct) {
+ DBG(KERN_INFO"solicited machine check for "
+ "channel path %02X\n", crw[0].rsid);
+ break;
+ }
switch (crw[0].erc) {
case CRW_ERC_IPARM: /* Path has come. */
ret = chp_process_crw(crw[0].rsid, 1);
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 6335f922918..31db2b06fab 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -2227,7 +2227,7 @@ zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action,
/* setup new FSF request */
retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA,
erp_action ? ZFCP_REQ_AUTO_CLEANUP : 0,
- 0, &lock_flags, &fsf_req);
+ NULL, &lock_flags, &fsf_req);
if (retval < 0) {
ZFCP_LOG_INFO("error: Out of resources. Could not create an "
"exchange port data request for"
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index 46e14f22ec1..671f4a6a5d1 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -44,30 +44,29 @@ struct scsi_transport_template *zfcp_transport_template;
struct zfcp_data zfcp_data = {
.scsi_host_template = {
- name: ZFCP_NAME,
- proc_name: "zfcp",
- proc_info: NULL,
- detect: NULL,
- slave_alloc: zfcp_scsi_slave_alloc,
- slave_configure: zfcp_scsi_slave_configure,
- slave_destroy: zfcp_scsi_slave_destroy,
- queuecommand: zfcp_scsi_queuecommand,
- eh_abort_handler: zfcp_scsi_eh_abort_handler,
- eh_device_reset_handler: zfcp_scsi_eh_device_reset_handler,
- eh_bus_reset_handler: zfcp_scsi_eh_bus_reset_handler,
- eh_host_reset_handler: zfcp_scsi_eh_host_reset_handler,
- /* FIXME(openfcp): Tune */
- can_queue: 4096,
- this_id: -1,
- /*
- * FIXME:
- * one less? can zfcp_create_sbale cope with it?
- */
- sg_tablesize: ZFCP_MAX_SBALES_PER_REQ,
- cmd_per_lun: 1,
- unchecked_isa_dma: 0,
- use_clustering: 1,
- sdev_attrs: zfcp_sysfs_sdev_attrs,
+ .name = ZFCP_NAME,
+ .proc_name = "zfcp",
+ .proc_info = NULL,
+ .detect = NULL,
+ .slave_alloc = zfcp_scsi_slave_alloc,
+ .slave_configure = zfcp_scsi_slave_configure,
+ .slave_destroy = zfcp_scsi_slave_destroy,
+ .queuecommand = zfcp_scsi_queuecommand,
+ .eh_abort_handler = zfcp_scsi_eh_abort_handler,
+ .eh_device_reset_handler = zfcp_scsi_eh_device_reset_handler,
+ .eh_bus_reset_handler = zfcp_scsi_eh_bus_reset_handler,
+ .eh_host_reset_handler = zfcp_scsi_eh_host_reset_handler,
+ .can_queue = 4096,
+ .this_id = -1,
+ /*
+ * FIXME:
+ * one less? can zfcp_create_sbale cope with it?
+ */
+ .sg_tablesize = ZFCP_MAX_SBALES_PER_REQ,
+ .cmd_per_lun = 1,
+ .unchecked_isa_dma = 0,
+ .use_clustering = 1,
+ .sdev_attrs = zfcp_sysfs_sdev_attrs,
},
.driver_version = ZFCP_VERSION,
/* rest initialised with zeros */
diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c
index 16b59773c0b..935952ef88f 100644
--- a/drivers/sbus/sbus.c
+++ b/drivers/sbus/sbus.c
@@ -233,7 +233,7 @@ static void __init build_one_sbus(struct device_node *dp, int num_sbus)
sbus->ofdev.node = dp;
sbus->ofdev.dev.parent = NULL;
sbus->ofdev.dev.bus = &sbus_bus_type;
- strcpy(sbus->ofdev.dev.bus_id, dp->path_component_name);
+ sprintf(sbus->ofdev.dev.bus_id, "sbus%d", num_sbus);
if (of_device_register(&sbus->ofdev) != 0)
printk(KERN_DEBUG "sbus: device registration error for %s!\n",
diff --git a/drivers/scsi/53c7xx.c b/drivers/scsi/53c7xx.c
index c690c2b89e4..acf292736b4 100644
--- a/drivers/scsi/53c7xx.c
+++ b/drivers/scsi/53c7xx.c
@@ -3451,12 +3451,12 @@ create_cmd (Scsi_Cmnd *cmd) {
for (i = 0; cmd->use_sg ? (i < cmd->use_sg) : !i; cmd_datain += 4,
cmd_dataout += 4, ++i) {
u32 vbuf = cmd->use_sg
- ? (u32)page_address(((struct scatterlist *)cmd->buffer)[i].page)+
- ((struct scatterlist *)cmd->buffer)[i].offset
+ ? (u32)page_address(((struct scatterlist *)cmd->request_buffer)[i].page)+
+ ((struct scatterlist *)cmd->request_buffer)[i].offset
: (u32)(cmd->request_buffer);
u32 bbuf = virt_to_bus((void *)vbuf);
u32 count = cmd->use_sg ?
- ((struct scatterlist *)cmd->buffer)[i].length :
+ ((struct scatterlist *)cmd->request_buffer)[i].length :
cmd->request_bufflen;
/*
@@ -5417,7 +5417,7 @@ insn_to_offset (Scsi_Cmnd *cmd, u32 *insn) {
if ((buffers = cmd->use_sg)) {
for (offset = 0,
- segment = (struct scatterlist *) cmd->buffer;
+ segment = (struct scatterlist *) cmd->request_buffer;
buffers && !((found = ((ptr >= (char *)page_address(segment->page)+segment->offset) &&
(ptr < ((char *)page_address(segment->page)+segment->offset+segment->length)))));
--buffers, offset += segment->length, ++segment)
diff --git a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c
index 8a4659e9410..bdc6bb262bc 100644
--- a/drivers/scsi/NCR53C9x.c
+++ b/drivers/scsi/NCR53C9x.c
@@ -911,7 +911,7 @@ static void esp_get_dmabufs(struct NCR_ESP *esp, Scsi_Cmnd *sp)
sp->SCp.ptr =
(char *) virt_to_phys(sp->request_buffer);
} else {
- sp->SCp.buffer = (struct scatterlist *) sp->buffer;
+ sp->SCp.buffer = (struct scatterlist *) sp->request_buffer;
sp->SCp.buffers_residual = sp->use_sg - 1;
sp->SCp.this_residual = sp->SCp.buffer->length;
if (esp->dma_mmu_get_scsi_sgl)
@@ -2152,29 +2152,23 @@ static int esp_do_data_finale(struct NCR_ESP *esp,
*/
static int esp_should_clear_sync(Scsi_Cmnd *sp)
{
- unchar cmd1 = sp->cmnd[0];
- unchar cmd2 = sp->data_cmnd[0];
+ unchar cmd = sp->cmnd[0];
/* These cases are for spinning up a disk and
* waiting for that spinup to complete.
*/
- if(cmd1 == START_STOP ||
- cmd2 == START_STOP)
+ if(cmd == START_STOP)
return 0;
- if(cmd1 == TEST_UNIT_READY ||
- cmd2 == TEST_UNIT_READY)
+ if(cmd == TEST_UNIT_READY)
return 0;
/* One more special case for SCSI tape drives,
* this is what is used to probe the device for
* completion of a rewind or tape load operation.
*/
- if(sp->device->type == TYPE_TAPE) {
- if(cmd1 == MODE_SENSE ||
- cmd2 == MODE_SENSE)
- return 0;
- }
+ if(sp->device->type == TYPE_TAPE && cmd == MODE_SENSE)
+ return 0;
return 1;
}
diff --git a/drivers/scsi/NCR_D700.c b/drivers/scsi/NCR_D700.c
index a06f547e87f..d05681f9d81 100644
--- a/drivers/scsi/NCR_D700.c
+++ b/drivers/scsi/NCR_D700.c
@@ -114,7 +114,7 @@ MODULE_DESCRIPTION("NCR Dual700 SCSI Driver");
MODULE_LICENSE("GPL");
module_param(NCR_D700, charp, 0);
-static __u8 __initdata id_array[2*(MCA_MAX_SLOT_NR + 1)] =
+static __u8 __devinitdata id_array[2*(MCA_MAX_SLOT_NR + 1)] =
{ [0 ... 2*(MCA_MAX_SLOT_NR + 1)-1] = 7 };
#ifdef MODULE
@@ -173,7 +173,7 @@ struct NCR_D700_private {
char pad;
};
-static int
+static int __devinit
NCR_D700_probe_one(struct NCR_D700_private *p, int siop, int irq,
int slot, u32 region, int differential)
{
@@ -243,7 +243,7 @@ NCR_D700_intr(int irq, void *data, struct pt_regs *regs)
* essentially connectecd to the MCA bus independently, it is easier
* to set them up as two separate host adapters, rather than one
* adapter with two channels */
-static int
+static int __devinit
NCR_D700_probe(struct device *dev)
{
struct NCR_D700_private *p;
@@ -329,7 +329,7 @@ NCR_D700_probe(struct device *dev)
for (i = 0; i < 2; i++) {
int err;
- if ((err = NCR_D700_probe_one(p, i, slot, irq,
+ if ((err = NCR_D700_probe_one(p, i, irq, slot,
offset_addr + (0x80 * i),
differential)) != 0)
printk("D700: SIOP%d: probe failed, error = %d\n",
@@ -349,7 +349,7 @@ NCR_D700_probe(struct device *dev)
return 0;
}
-static void
+static void __devexit
NCR_D700_remove_one(struct Scsi_Host *host)
{
scsi_remove_host(host);
@@ -359,7 +359,7 @@ NCR_D700_remove_one(struct Scsi_Host *host)
release_region(host->base, 64);
}
-static int
+static int __devexit
NCR_D700_remove(struct device *dev)
{
struct NCR_D700_private *p = dev_get_drvdata(dev);
@@ -380,7 +380,7 @@ static struct mca_driver NCR_D700_driver = {
.name = "NCR_D700",
.bus = &mca_bus_type,
.probe = NCR_D700_probe,
- .remove = NCR_D700_remove,
+ .remove = __devexit_p(NCR_D700_remove),
},
};
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
index 36e63f82d9f..f974869ea32 100644
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -551,6 +551,11 @@ struct aha152x_hostdata {
struct aha152x_scdata {
Scsi_Cmnd *next; /* next sc in queue */
struct semaphore *sem; /* semaphore to block on */
+ unsigned char cmd_len;
+ unsigned char cmnd[MAX_COMMAND_SIZE];
+ unsigned short use_sg;
+ unsigned request_bufflen;
+ void *request_buffer;
};
@@ -1006,11 +1011,20 @@ static int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct semaphore *sem, int p
return FAILED;
}
} else {
+ struct aha152x_scdata *sc;
+
SCpnt->host_scribble = kmalloc(sizeof(struct aha152x_scdata), GFP_ATOMIC);
if(SCpnt->host_scribble==0) {
printk(ERR_LEAD "allocation failed\n", CMDINFO(SCpnt));
return FAILED;
}
+
+ sc = SCDATA(SCpnt);
+ memcpy(sc->cmnd, SCpnt->cmnd, sizeof(sc->cmnd));
+ sc->request_buffer = SCpnt->request_buffer;
+ sc->request_bufflen = SCpnt->request_bufflen;
+ sc->use_sg = SCpnt->use_sg;
+ sc->cmd_len = SCpnt->cmd_len;
}
SCNEXT(SCpnt) = NULL;
@@ -1165,6 +1179,10 @@ static int aha152x_device_reset(Scsi_Cmnd * SCpnt)
DECLARE_MUTEX_LOCKED(sem);
struct timer_list timer;
int ret, issued, disconnected;
+ unsigned char old_cmd_len = SCpnt->cmd_len;
+ unsigned short old_use_sg = SCpnt->use_sg;
+ void *old_buffer = SCpnt->request_buffer;
+ unsigned old_bufflen = SCpnt->request_bufflen;
unsigned long flags;
#if defined(AHA152X_DEBUG)
@@ -1198,11 +1216,11 @@ static int aha152x_device_reset(Scsi_Cmnd * SCpnt)
add_timer(&timer);
down(&sem);
del_timer(&timer);
-
- SCpnt->cmd_len = SCpnt->old_cmd_len;
- SCpnt->use_sg = SCpnt->old_use_sg;
- SCpnt->request_buffer = SCpnt->buffer;
- SCpnt->request_bufflen = SCpnt->bufflen;
+
+ SCpnt->cmd_len = old_cmd_len;
+ SCpnt->use_sg = old_use_sg;
+ SCpnt->request_buffer = old_buffer;
+ SCpnt->request_bufflen = old_bufflen;
DO_LOCK(flags);
@@ -1565,6 +1583,9 @@ static void busfree_run(struct Scsi_Host *shpnt)
#endif
if(DONE_SC->SCp.phase & check_condition) {
+ struct scsi_cmnd *cmd = HOSTDATA(shpnt)->done_SC;
+ struct aha152x_scdata *sc = SCDATA(cmd);
+
#if 0
if(HOSTDATA(shpnt)->debug & debug_eh) {
printk(ERR_LEAD "received sense: ", CMDINFO(DONE_SC));
@@ -1573,13 +1594,13 @@ static void busfree_run(struct Scsi_Host *shpnt)
#endif
/* restore old command */
- memcpy((void *) DONE_SC->cmnd, (void *) DONE_SC->data_cmnd, sizeof(DONE_SC->data_cmnd));
- DONE_SC->request_buffer = DONE_SC->buffer;
- DONE_SC->request_bufflen = DONE_SC->bufflen;
- DONE_SC->use_sg = DONE_SC->old_use_sg;
- DONE_SC->cmd_len = DONE_SC->old_cmd_len;
+ memcpy(cmd->cmnd, sc->cmnd, sizeof(sc->cmnd));
+ cmd->request_buffer = sc->request_buffer;
+ cmd->request_bufflen = sc->request_bufflen;
+ cmd->use_sg = sc->use_sg;
+ cmd->cmd_len = sc->cmd_len;
- DONE_SC->SCp.Status = 0x02;
+ cmd->SCp.Status = 0x02;
HOSTDATA(shpnt)->commands--;
if (!HOSTDATA(shpnt)->commands)
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index 15f6cd4279b..904c25fb4ba 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -940,14 +940,8 @@ static void ahci_host_intr(struct ata_port *ap)
return;
/* ignore interim PIO setup fis interrupts */
- if (ata_tag_valid(ap->active_tag)) {
- struct ata_queued_cmd *qc =
- ata_qc_from_tag(ap, ap->active_tag);
-
- if (qc && qc->tf.protocol == ATA_PROT_PIO &&
- (status & PORT_IRQ_PIOS_FIS))
- return;
- }
+ if (ata_tag_valid(ap->active_tag) && (status & PORT_IRQ_PIOS_FIS))
+ return;
if (ata_ratelimit())
ata_port_printk(ap, KERN_INFO, "spurious interrupt "
@@ -1052,7 +1046,7 @@ static void ahci_thaw(struct ata_port *ap)
static void ahci_error_handler(struct ata_port *ap)
{
- if (!(ap->flags & ATA_FLAG_FROZEN)) {
+ if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
/* restart engine */
ahci_stop_engine(ap);
ahci_start_engine(ap);
@@ -1323,6 +1317,17 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ /* JMicron-specific fixup: make sure we're in AHCI mode */
+ /* This is protected from races with ata_jmicron by the pci probe
+ locking */
+ if (pdev->vendor == PCI_VENDOR_ID_JMICRON) {
+ /* AHCI enable, AHCI on function 0 */
+ pci_write_config_byte(pdev, 0x41, 0xa1);
+ /* Function 1 is the PATA controller */
+ if (PCI_FUNC(pdev->devfn))
+ return -ENODEV;
+ }
+
rc = pci_enable_device(pdev);
if (rc)
return rc;
@@ -1378,10 +1383,6 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (have_msi)
hpriv->flags |= AHCI_FLAG_MSI;
- /* JMicron-specific fixup: make sure we're in AHCI mode */
- if (pdev->vendor == 0x197b)
- pci_write_config_byte(pdev, 0x41, 0xa1);
-
/* initialize adapter */
rc = ahci_host_init(probe_ent);
if (rc)
diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c
index a1e8ca75859..653818d2f80 100644
--- a/drivers/scsi/aic7xxx/aic79xx_core.c
+++ b/drivers/scsi/aic7xxx/aic79xx_core.c
@@ -7289,7 +7289,7 @@ ahd_reset_cmds_pending(struct ahd_softc *ahd)
ahd->flags &= ~AHD_UPDATE_PEND_CMDS;
}
-void
+static void
ahd_done_with_status(struct ahd_softc *ahd, struct scb *scb, uint32_t status)
{
cam_status ostat;
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index b244c712417..998999c0a97 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -243,25 +243,6 @@ ahd_print_path(struct ahd_softc *ahd, struct scb *scb)
static uint32_t aic79xx_no_reset;
/*
- * Certain PCI motherboards will scan PCI devices from highest to lowest,
- * others scan from lowest to highest, and they tend to do all kinds of
- * strange things when they come into contact with PCI bridge chips. The
- * net result of all this is that the PCI card that is actually used to boot
- * the machine is very hard to detect. Most motherboards go from lowest
- * PCI slot number to highest, and the first SCSI controller found is the
- * one you boot from. The only exceptions to this are when a controller
- * has its BIOS disabled. So, we by default sort all of our SCSI controllers
- * from lowest PCI slot number to highest PCI slot number. We also force
- * all controllers with their BIOS disabled to the end of the list. This
- * works on *almost* all computers. Where it doesn't work, we have this
- * option. Setting this option to non-0 will reverse the order of the sort
- * to highest first, then lowest, but will still leave cards with their BIOS
- * disabled at the very end. That should fix everyone up unless there are
- * really strange cirumstances.
- */
-static uint32_t aic79xx_reverse_scan;
-
-/*
* Should we force EXTENDED translation on a controller.
* 0 == Use whatever is in the SEEPROM or default to off
* 1 == Use whatever is in the SEEPROM or default to on
@@ -350,7 +331,6 @@ MODULE_PARM_DESC(aic79xx,
" periodically to prevent tag starvation.\n"
" This may be required by some older disk\n"
" or drives/RAID arrays.\n"
-" reverse_scan Sort PCI devices highest Bus/Slot to lowest\n"
" tag_info:<tag_str> Set per-target tag depth\n"
" global_tag_depth:<int> Global tag depth for all targets on all buses\n"
" slewrate:<slewrate_list>Set the signal slew rate (0-15).\n"
@@ -1031,7 +1011,6 @@ aic79xx_setup(char *s)
#ifdef AHD_DEBUG
{ "debug", &ahd_debug },
#endif
- { "reverse_scan", &aic79xx_reverse_scan },
{ "periodic_otag", &aic79xx_periodic_otag },
{ "pci_parity", &aic79xx_pci_parity },
{ "seltime", &aic79xx_seltime },
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h
index 9e871de2383..601340d8441 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.h
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.h
@@ -93,7 +93,6 @@
#endif
/********************************** Misc Macros *******************************/
-#define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
#define powerof2(x) ((((x)-1)&(x))==0)
/************************* Forward Declarations *******************************/
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
index debf3e2a079..aa4be8a3141 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -353,7 +353,6 @@ MODULE_PARM_DESC(aic7xxx,
" periodically to prevent tag starvation.\n"
" This may be required by some older disk\n"
" drives or RAID arrays.\n"
-" reverse_scan Sort PCI devices highest Bus/Slot to lowest\n"
" tag_info:<tag_str> Set per-target tag depth\n"
" global_tag_depth:<int> Global tag depth for every target\n"
" on every bus\n"
diff --git a/drivers/scsi/aic7xxx/aicasm/Makefile b/drivers/scsi/aic7xxx/aicasm/Makefile
index 8c91fda6482..b98c5c1056c 100644
--- a/drivers/scsi/aic7xxx/aicasm/Makefile
+++ b/drivers/scsi/aic7xxx/aicasm/Makefile
@@ -14,6 +14,8 @@ LIBS= -ldb
clean-files:= ${GENSRCS} ${GENHDRS} $(YSRCS:.y=.output) $(PROG)
# Override default kernel CFLAGS. This is a userland app.
AICASM_CFLAGS:= -I/usr/include -I.
+LEX= flex
+YACC= bison
YFLAGS= -d
NOMAN= noman
diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c
index 3e1053f111d..4cf7afc31cc 100644
--- a/drivers/scsi/arm/fas216.c
+++ b/drivers/scsi/arm/fas216.c
@@ -2427,7 +2427,7 @@ int fas216_eh_abort(Scsi_Cmnd *SCpnt)
info->stats.aborts += 1;
printk(KERN_WARNING "scsi%d: abort command ", info->host->host_no);
- __scsi_print_command(SCpnt->data_cmnd);
+ __scsi_print_command(SCpnt->cmnd);
print_debug_list();
fas216_dumpstate(info);
diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c
index 94b1261a259..19745a31072 100644
--- a/drivers/scsi/ata_piix.c
+++ b/drivers/scsi/ata_piix.c
@@ -105,9 +105,6 @@ enum {
PIIX_FLAG_SCR = (1 << 26), /* SCR available */
PIIX_FLAG_AHCI = (1 << 27), /* AHCI possible */
PIIX_FLAG_CHECKINTR = (1 << 28), /* make sure PCI INTx enabled */
- PIIX_FLAG_COMBINED = (1 << 29), /* combined mode possible */
- /* ICH6/7 use different scheme for map value */
- PIIX_FLAG_COMBINED_ICH6 = PIIX_FLAG_COMBINED | (1 << 30),
/* combined mode. if set, PATA is channel 0.
* if clear, PATA is channel 1.
@@ -126,6 +123,7 @@ enum {
ich6_sata = 4,
ich6_sata_ahci = 5,
ich6m_sata_ahci = 6,
+ ich8_sata_ahci = 7,
/* constants for mapping table */
P0 = 0, /* port 0 */
@@ -141,11 +139,19 @@ enum {
struct piix_map_db {
const u32 mask;
+ const u16 port_enable;
+ const int present_shift;
const int map[][4];
};
+struct piix_host_priv {
+ const int *map;
+ const struct piix_map_db *map_db;
+};
+
static int piix_init_one (struct pci_dev *pdev,
const struct pci_device_id *ent);
+static void piix_host_stop(struct ata_host_set *host_set);
static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev);
static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev);
static void piix_pata_error_handler(struct ata_port *ap);
@@ -186,11 +192,11 @@ static const struct pci_device_id piix_pci_tbl[] = {
/* Enterprise Southbridge 2 (where's the datasheet?) */
{ 0x8086, 0x2680, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
/* SATA Controller 1 IDE (ICH8, no datasheet yet) */
- { 0x8086, 0x2820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
+ { 0x8086, 0x2820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
/* SATA Controller 2 IDE (ICH8, ditto) */
- { 0x8086, 0x2825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
+ { 0x8086, 0x2825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
/* Mobile SATA Controller IDE (ICH8M, ditto) */
- { 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6m_sata_ahci },
+ { 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
{ } /* terminate list */
};
@@ -254,7 +260,7 @@ static const struct ata_port_operations piix_pata_ops = {
.port_start = ata_port_start,
.port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
+ .host_stop = piix_host_stop,
};
static const struct ata_port_operations piix_sata_ops = {
@@ -284,11 +290,13 @@ static const struct ata_port_operations piix_sata_ops = {
.port_start = ata_port_start,
.port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
+ .host_stop = piix_host_stop,
};
-static struct piix_map_db ich5_map_db = {
+static const struct piix_map_db ich5_map_db = {
.mask = 0x7,
+ .port_enable = 0x3,
+ .present_shift = 4,
.map = {
/* PM PS SM SS MAP */
{ P0, NA, P1, NA }, /* 000b */
@@ -302,8 +310,10 @@ static struct piix_map_db ich5_map_db = {
},
};
-static struct piix_map_db ich6_map_db = {
+static const struct piix_map_db ich6_map_db = {
.mask = 0x3,
+ .port_enable = 0xf,
+ .present_shift = 4,
.map = {
/* PM PS SM SS MAP */
{ P0, P2, P1, P3 }, /* 00b */
@@ -313,8 +323,10 @@ static struct piix_map_db ich6_map_db = {
},
};
-static struct piix_map_db ich6m_map_db = {
+static const struct piix_map_db ich6m_map_db = {
.mask = 0x3,
+ .port_enable = 0x5,
+ .present_shift = 4,
.map = {
/* PM PS SM SS MAP */
{ P0, P2, RV, RV }, /* 00b */
@@ -324,6 +336,28 @@ static struct piix_map_db ich6m_map_db = {
},
};
+static const struct piix_map_db ich8_map_db = {
+ .mask = 0x3,
+ .port_enable = 0x3,
+ .present_shift = 8,
+ .map = {
+ /* PM PS SM SS MAP */
+ { P0, NA, P1, NA }, /* 00b (hardwired) */
+ { RV, RV, RV, RV },
+ { RV, RV, RV, RV }, /* 10b (never) */
+ { RV, RV, RV, RV },
+ },
+};
+
+static const struct piix_map_db *piix_map_db_table[] = {
+ [ich5_sata] = &ich5_map_db,
+ [esb_sata] = &ich5_map_db,
+ [ich6_sata] = &ich6_map_db,
+ [ich6_sata_ahci] = &ich6_map_db,
+ [ich6m_sata_ahci] = &ich6m_map_db,
+ [ich8_sata_ahci] = &ich8_map_db,
+};
+
static struct ata_port_info piix_port_info[] = {
/* piix4_pata */
{
@@ -356,63 +390,69 @@ static struct ata_port_info piix_port_info[] = {
/* ich5_sata */
{
.sht = &piix_sht,
- .host_flags = ATA_FLAG_SATA | PIIX_FLAG_COMBINED |
- PIIX_FLAG_CHECKINTR,
+ .host_flags = ATA_FLAG_SATA | PIIX_FLAG_CHECKINTR,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 */
.port_ops = &piix_sata_ops,
- .private_data = &ich5_map_db,
},
/* i6300esb_sata */
{
.sht = &piix_sht,
- .host_flags = ATA_FLAG_SATA | PIIX_FLAG_COMBINED |
+ .host_flags = ATA_FLAG_SATA |
PIIX_FLAG_CHECKINTR | PIIX_FLAG_IGNORE_PCS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 */
.port_ops = &piix_sata_ops,
- .private_data = &ich5_map_db,
},
/* ich6_sata */
{
.sht = &piix_sht,
- .host_flags = ATA_FLAG_SATA | PIIX_FLAG_COMBINED_ICH6 |
+ .host_flags = ATA_FLAG_SATA |
PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 */
.port_ops = &piix_sata_ops,
- .private_data = &ich6_map_db,
},
/* ich6_sata_ahci */
{
.sht = &piix_sht,
- .host_flags = ATA_FLAG_SATA | PIIX_FLAG_COMBINED_ICH6 |
+ .host_flags = ATA_FLAG_SATA |
PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR |
PIIX_FLAG_AHCI,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 */
.port_ops = &piix_sata_ops,
- .private_data = &ich6_map_db,
},
/* ich6m_sata_ahci */
{
.sht = &piix_sht,
- .host_flags = ATA_FLAG_SATA | PIIX_FLAG_COMBINED_ICH6 |
+ .host_flags = ATA_FLAG_SATA |
+ PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR |
+ PIIX_FLAG_AHCI,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x7f, /* udma0-6 */
+ .port_ops = &piix_sata_ops,
+ },
+
+ /* ich8_sata_ahci */
+ {
+ .sht = &piix_sht,
+ .host_flags = ATA_FLAG_SATA |
PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR |
PIIX_FLAG_AHCI,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 */
.port_ops = &piix_sata_ops,
- .private_data = &ich6m_map_db,
},
};
@@ -508,46 +548,29 @@ static void piix_pata_error_handler(struct ata_port *ap)
static int piix_sata_prereset(struct ata_port *ap)
{
struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
- const unsigned int *map = ap->host_set->private_data;
+ struct piix_host_priv *hpriv = ap->host_set->private_data;
+ const unsigned int *map = hpriv->map;
int base = 2 * ap->hard_port_no;
- unsigned int present_mask = 0;
+ unsigned int present = 0;
int port, i;
- u8 pcs;
+ u16 pcs;
- pci_read_config_byte(pdev, ICH5_PCS, &pcs);
+ pci_read_config_word(pdev, ICH5_PCS, &pcs);
DPRINTK("ata%u: ENTER, pcs=0x%x base=%d\n", ap->id, pcs, base);
- /* enable all ports on this ap and wait for them to settle */
- for (i = 0; i < 2; i++) {
- port = map[base + i];
- if (port >= 0)
- pcs |= 1 << port;
- }
-
- pci_write_config_byte(pdev, ICH5_PCS, pcs);
- msleep(100);
-
- /* let's see which devices are present */
- pci_read_config_byte(pdev, ICH5_PCS, &pcs);
-
for (i = 0; i < 2; i++) {
port = map[base + i];
if (port < 0)
continue;
- if (ap->flags & PIIX_FLAG_IGNORE_PCS || pcs & 1 << (4 + port))
- present_mask |= 1 << i;
- else
- pcs &= ~(1 << port);
+ if ((ap->flags & PIIX_FLAG_IGNORE_PCS) ||
+ (pcs & 1 << (hpriv->map_db->present_shift + port)))
+ present = 1;
}
- /* disable offline ports on non-AHCI controllers */
- if (!(ap->flags & PIIX_FLAG_AHCI))
- pci_write_config_byte(pdev, ICH5_PCS, pcs);
-
DPRINTK("ata%u: LEAVE, pcs=0x%x present_mask=0x%x\n",
ap->id, pcs, present_mask);
- if (!present_mask) {
+ if (!present) {
ata_port_printk(ap, KERN_INFO, "SATA port has no device.\n");
ap->eh_context.i.action &= ~ATA_EH_RESET_MASK;
return 0;
@@ -761,10 +784,27 @@ static int __devinit piix_check_450nx_errata(struct pci_dev *ata_dev)
return no_piix_dma;
}
+static void __devinit piix_init_pcs(struct pci_dev *pdev,
+ const struct piix_map_db *map_db)
+{
+ u16 pcs, new_pcs;
+
+ pci_read_config_word(pdev, ICH5_PCS, &pcs);
+
+ new_pcs = pcs | map_db->port_enable;
+
+ if (new_pcs != pcs) {
+ DPRINTK("updating PCS from 0x%x to 0x%x\n", pcs, new_pcs);
+ pci_write_config_word(pdev, ICH5_PCS, new_pcs);
+ msleep(150);
+ }
+}
+
static void __devinit piix_init_sata_map(struct pci_dev *pdev,
- struct ata_port_info *pinfo)
+ struct ata_port_info *pinfo,
+ const struct piix_map_db *map_db)
{
- struct piix_map_db *map_db = pinfo[0].private_data;
+ struct piix_host_priv *hpriv = pinfo[0].private_data;
const unsigned int *map;
int i, invalid_map = 0;
u8 map_value;
@@ -805,8 +845,8 @@ static void __devinit piix_init_sata_map(struct pci_dev *pdev,
dev_printk(KERN_ERR, &pdev->dev,
"invalid MAP value %u\n", map_value);
- pinfo[0].private_data = (void *)map;
- pinfo[1].private_data = (void *)map;
+ hpriv->map = map;
+ hpriv->map_db = map_db;
}
/**
@@ -829,6 +869,7 @@ static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
static int printed_version;
struct ata_port_info port_info[2];
struct ata_port_info *ppinfo[2] = { &port_info[0], &port_info[1] };
+ struct piix_host_priv *hpriv;
unsigned long host_flags;
if (!printed_version++)
@@ -839,8 +880,14 @@ static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (!in_module_init)
return -ENODEV;
+ hpriv = kzalloc(sizeof(*hpriv), GFP_KERNEL);
+ if (!hpriv)
+ return -ENOMEM;
+
port_info[0] = piix_port_info[ent->driver_data];
port_info[1] = piix_port_info[ent->driver_data];
+ port_info[0].private_data = hpriv;
+ port_info[1].private_data = hpriv;
host_flags = port_info[0].host_flags;
@@ -855,8 +902,11 @@ static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
}
/* Initialize SATA map */
- if (host_flags & ATA_FLAG_SATA)
- piix_init_sata_map(pdev, port_info);
+ if (host_flags & ATA_FLAG_SATA) {
+ piix_init_sata_map(pdev, port_info,
+ piix_map_db_table[ent->driver_data]);
+ piix_init_pcs(pdev, piix_map_db_table[ent->driver_data]);
+ }
/* On ICH5, some BIOSen disable the interrupt using the
* PCI_COMMAND_INTX_DISABLE bit added in PCI 2.3.
@@ -879,6 +929,13 @@ static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
return ata_pci_init_one(pdev, ppinfo, 2);
}
+static void piix_host_stop(struct ata_host_set *host_set)
+{
+ if (host_set->next == NULL)
+ kfree(host_set->private_data);
+ ata_host_stop(host_set);
+}
+
static int __init piix_init(void)
{
int rc;
diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c
index 007a14e5c3f..e397129c90d 100644
--- a/drivers/scsi/atari_NCR5380.c
+++ b/drivers/scsi/atari_NCR5380.c
@@ -507,7 +507,7 @@ static __inline__ void initialize_SCp(Scsi_Cmnd *cmd)
*/
if (cmd->use_sg) {
- cmd->SCp.buffer = (struct scatterlist *) cmd->buffer;
+ cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
cmd->SCp.buffers_residual = cmd->use_sg - 1;
cmd->SCp.ptr = (char *)page_address(cmd->SCp.buffer->page)+
cmd->SCp.buffer->offset;
diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c
index dddd2acce76..61f6024b61b 100644
--- a/drivers/scsi/constants.c
+++ b/drivers/scsi/constants.c
@@ -5,6 +5,7 @@
* Additions for SCSI 3+ (SPC-3 T10/1416-D Rev 07 3 May 2002)
* by D. Gilbert and aeb (20020609)
* Additions for SPC-3 T10/1416-D Rev 21 22 Sept 2004, D. Gilbert 20041025
+ * Update to SPC-4 T10/1713-D Rev 5a, 14 June 2006, D. Gilbert 20060702
*/
#include <linux/blkdev.h>
@@ -36,55 +37,56 @@ static const char * cdb_byte0_names[] = {
/* 00-03 */ "Test Unit Ready", "Rezero Unit/Rewind", NULL, "Request Sense",
/* 04-07 */ "Format Unit/Medium", "Read Block Limits", NULL,
"Reasssign Blocks",
-/* 08-0d */ "Read (6)", NULL, "Write (6)", "Seek (6)", NULL, NULL,
+/* 08-0d */ "Read(6)", NULL, "Write(6)", "Seek(6)", NULL, NULL,
/* 0e-12 */ NULL, "Read Reverse", "Write Filemarks", "Space", "Inquiry",
-/* 13-16 */ "Verify (6)", "Recover Buffered Data", "Mode Select (6)",
- "Reserve (6)",
-/* 17-1a */ "Release (6)", "Copy", "Erase", "Mode Sense (6)",
+/* 13-16 */ "Verify(6)", "Recover Buffered Data", "Mode Select(6)",
+ "Reserve(6)",
+/* 17-1a */ "Release(6)", "Copy", "Erase", "Mode Sense(6)",
/* 1b-1d */ "Start/Stop Unit", "Receive Diagnostic", "Send Diagnostic",
/* 1e-1f */ "Prevent/Allow Medium Removal", NULL,
/* 20-22 */ NULL, NULL, NULL,
/* 23-28 */ "Read Format Capacities", "Set Window",
- "Read Capacity (10)", NULL, NULL, "Read (10)",
-/* 29-2d */ "Read Generation", "Write (10)", "Seek (10)", "Erase (10)",
- "Read updated block",
-/* 2e-31 */ "Write Verify (10)", "Verify (10)", "Search High", "Search Equal",
+ "Read Capacity(10)", NULL, NULL, "Read(10)",
+/* 29-2d */ "Read Generation", "Write(10)", "Seek(10)", "Erase(10)",
+ "Read updated block",
+/* 2e-31 */ "Write Verify(10)", "Verify(10)", "Search High", "Search Equal",
/* 32-34 */ "Search Low", "Set Limits", "Prefetch/Read Position",
-/* 35-37 */ "Synchronize Cache (10)", "Lock/Unlock Cache (10)",
+/* 35-37 */ "Synchronize Cache(10)", "Lock/Unlock Cache(10)",
"Read Defect Data(10)",
/* 38-3c */ "Medium Scan", "Compare", "Copy Verify", "Write Buffer",
"Read Buffer",
-/* 3d-3f */ "Update Block", "Read Long (10)", "Write Long (10)",
-/* 40-41 */ "Change Definition", "Write Same (10)",
+/* 3d-3f */ "Update Block", "Read Long(10)", "Write Long(10)",
+/* 40-41 */ "Change Definition", "Write Same(10)",
/* 42-48 */ "Read sub-channel", "Read TOC/PMA/ATIP", "Read density support",
- "Play audio (10)", "Get configuration", "Play audio msf",
+ "Play audio(10)", "Get configuration", "Play audio msf",
"Play audio track/index",
-/* 49-4f */ "Play track relative (10)", "Get event status notification",
+/* 49-4f */ "Play track relative(10)", "Get event status notification",
"Pause/resume", "Log Select", "Log Sense", "Stop play/scan",
NULL,
/* 50-55 */ "Xdwrite", "Xpwrite, Read disk info", "Xdread, Read track info",
- "Reserve track", "Send OPC info", "Mode Select (10)",
-/* 56-5b */ "Reserve (10)", "Release (10)", "Repair track", "Read master cue",
- "Mode Sense (10)", "Close track/session",
+ "Reserve track", "Send OPC info", "Mode Select(10)",
+/* 56-5b */ "Reserve(10)", "Release(10)", "Repair track", "Read master cue",
+ "Mode Sense(10)", "Close track/session",
/* 5c-5f */ "Read buffer capacity", "Send cue sheet", "Persistent reserve in",
"Persistent reserve out",
/* 60-67 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 68-6f */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 70-77 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 78-7f */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, "Variable length",
-/* 80-84 */ "Xdwrite (16)", "Rebuild (16)", "Regenerate (16)", "Extended copy",
+/* 80-84 */ "Xdwrite(16)", "Rebuild(16)", "Regenerate(16)", "Extended copy",
"Receive copy results",
-/* 85-89 */ "Memory Export In (16)", "Access control in", "Access control out",
- "Read (16)", "Memory Export Out (16)",
-/* 8a-8f */ "Write (16)", NULL, "Read attributes", "Write attributes",
- "Write and verify (16)", "Verify (16)",
-/* 90-94 */ "Pre-fetch (16)", "Synchronize cache (16)",
- "Lock/unlock cache (16)", "Write same (16)", NULL,
+/* 85-89 */ "ATA command pass through(16)", "Access control in",
+ "Access control out", "Read(16)", "Memory Export Out(16)",
+/* 8a-8f */ "Write(16)", NULL, "Read attributes", "Write attributes",
+ "Write and verify(16)", "Verify(16)",
+/* 90-94 */ "Pre-fetch(16)", "Synchronize cache(16)",
+ "Lock/unlock cache(16)", "Write same(16)", NULL,
/* 95-99 */ NULL, NULL, NULL, NULL, NULL,
-/* 9a-9f */ NULL, NULL, NULL, NULL, "Service action in (16)",
- "Service action out (16)",
-/* a0-a5 */ "Report luns", "Blank", "Send event", "Maintenance in",
- "Maintenance out", "Move medium/play audio(12)",
+/* 9a-9f */ NULL, NULL, NULL, NULL, "Service action in(16)",
+ "Service action out(16)",
+/* a0-a5 */ "Report luns", "ATA command pass through(12)/Blank",
+ "Security protocol in", "Maintenance in", "Maintenance out",
+ "Move medium/play audio(12)",
/* a6-a9 */ "Exchange medium", "Move medium attached", "Read(12)",
"Play track relative(12)",
/* aa-ae */ "Write(12)", NULL, "Erase(12), Get Performance",
@@ -92,12 +94,12 @@ static const char * cdb_byte0_names[] = {
/* af-b1 */ "Verify(12)", "Search data high(12)", "Search data equal(12)",
/* b2-b4 */ "Search data low(12)", "Set limits(12)",
"Read element status attached",
-/* b5-b6 */ "Request volume element address", "Send volume tag, set streaming",
+/* b5-b6 */ "Security protocol out", "Send volume tag, set streaming",
/* b7-b9 */ "Read defect data(12)", "Read element status", "Read CD msf",
/* ba-bc */ "Redundancy group (in), Scan",
- "Redundancy group (out), Set cd-rom speed", "Spare in, Play cd",
-/* bd-bf */ "Spare out, Mechanism status", "Volume set in, Read cd",
- "Volume set out, Send DVD structure",
+ "Redundancy group (out), Set cd-rom speed", "Spare (in), Play cd",
+/* bd-bf */ "Spare (out), Mechanism status", "Volume set (in), Read cd",
+ "Volume set (out), Send DVD structure",
};
struct value_name_pair {
@@ -112,6 +114,7 @@ static const struct value_name_pair maint_in_arr[] = {
{0xc, "Report supported operation codes"},
{0xd, "Report supported task management functions"},
{0xe, "Report priority"},
+ {0xf, "Report timestamp"},
};
#define MAINT_IN_SZ ARRAY_SIZE(maint_in_arr)
@@ -120,6 +123,7 @@ static const struct value_name_pair maint_out_arr[] = {
{0xa, "Set target port groups"},
{0xb, "Change aliases"},
{0xe, "Set priority"},
+ {0xe, "Set timestamp"},
};
#define MAINT_OUT_SZ ARRAY_SIZE(maint_out_arr)
@@ -427,6 +431,7 @@ static struct error_info additional[] =
{0x001A, "Rewind operation in progress"},
{0x001B, "Set capacity operation in progress"},
{0x001C, "Verify operation in progress"},
+ {0x001D, "ATA pass through information available"},
{0x0100, "No index/sector signal"},
@@ -438,7 +443,7 @@ static struct error_info additional[] =
{0x0400, "Logical unit not ready, cause not reportable"},
{0x0401, "Logical unit is in process of becoming ready"},
- {0x0402, "Logical unit not ready, initializing cmd. required"},
+ {0x0402, "Logical unit not ready, initializing command required"},
{0x0403, "Logical unit not ready, manual intervention required"},
{0x0404, "Logical unit not ready, format in progress"},
{0x0405, "Logical unit not ready, rebuild in progress"},
@@ -478,6 +483,9 @@ static struct error_info additional[] =
{0x0B00, "Warning"},
{0x0B01, "Warning - specified temperature exceeded"},
{0x0B02, "Warning - enclosure degraded"},
+ {0x0B03, "Warning - background self-test failed"},
+ {0x0B04, "Warning - background pre-scan detected medium error"},
+ {0x0B05, "Warning - background medium scan detected medium error"},
{0x0C00, "Write error"},
{0x0C01, "Write error - recovered with auto reallocation"},
@@ -493,6 +501,7 @@ static struct error_info additional[] =
{0x0C0B, "Auxiliary memory write error"},
{0x0C0C, "Write error - unexpected unsolicited data"},
{0x0C0D, "Write error - not enough unsolicited data"},
+ {0x0C0F, "Defects in error window"},
{0x0D00, "Error detected by third party temporary initiator"},
{0x0D01, "Third party device failure"},
@@ -504,11 +513,12 @@ static struct error_info additional[] =
{0x0E00, "Invalid information unit"},
{0x0E01, "Information unit too short"},
{0x0E02, "Information unit too long"},
+ {0x0E03, "Invalid field in command information unit"},
{0x1000, "Id CRC or ECC error"},
- {0x1001, "Data block guard check failed"},
- {0x1002, "Data block application tag check failed"},
- {0x1003, "Data block reference tag check failed"},
+ {0x1001, "Logical block guard check failed"},
+ {0x1002, "Logical block application tag check failed"},
+ {0x1003, "Logical block reference tag check failed"},
{0x1100, "Unrecovered read error"},
{0x1101, "Read retries exhausted"},
@@ -530,6 +540,7 @@ static struct error_info additional[] =
{0x1111, "Read error - loss of streaming"},
{0x1112, "Auxiliary memory read error"},
{0x1113, "Read error - failed retransmission request"},
+ {0x1114, "Read error - lba marked bad by application client"},
{0x1200, "Address mark not found for id field"},
@@ -610,11 +621,14 @@ static struct error_info additional[] =
{0x2100, "Logical block address out of range"},
{0x2101, "Invalid element address"},
{0x2102, "Invalid address for write"},
+ {0x2103, "Invalid write crossing layer jump"},
{0x2200, "Illegal function (use 20 00, 24 00, or 26 00)"},
{0x2400, "Invalid field in cdb"},
{0x2401, "CDB decryption error"},
+ {0x2402, "Obsolete"},
+ {0x2403, "Obsolete"},
{0x2404, "Security audit value frozen"},
{0x2405, "Security working key frozen"},
{0x2406, "Nonce not unique"},
@@ -637,7 +651,10 @@ static struct error_info additional[] =
{0x260C, "Invalid operation for copy source or destination"},
{0x260D, "Copy segment granularity violation"},
{0x260E, "Invalid parameter while port is enabled"},
- {0x260F, "Invalid data-out buffer integrity"},
+ {0x260F, "Invalid data-out buffer integrity check value"},
+ {0x2610, "Data decryption key fail limit reached"},
+ {0x2611, "Incomplete key-associated data set"},
+ {0x2612, "Vendor specific key reference not found"},
{0x2700, "Write protected"},
{0x2701, "Hardware write protected"},
@@ -649,6 +666,7 @@ static struct error_info additional[] =
{0x2800, "Not ready to ready change, medium may have changed"},
{0x2801, "Import or export element accessed"},
+ {0x2802, "Format-layer may have changed"},
{0x2900, "Power on, reset, or bus device reset occurred"},
{0x2901, "Power on occurred"},
@@ -669,6 +687,11 @@ static struct error_info additional[] =
{0x2A07, "Implicit asymmetric access state transition failed"},
{0x2A08, "Priority changed"},
{0x2A09, "Capacity data has changed"},
+ {0x2A10, "Timestamp changed"},
+ {0x2A11, "Data encryption parameters changed by another i_t nexus"},
+ {0x2A12, "Data encryption parameters changed by vendor specific "
+ "event"},
+ {0x2A13, "Data encryption key instance counter has changed"},
{0x2B00, "Copy cannot execute since host cannot disconnect"},
@@ -690,6 +713,7 @@ static struct error_info additional[] =
{0x2E00, "Insufficient time for operation"},
{0x2F00, "Commands cleared by another initiator"},
+ {0x2F01, "Commands cleared by power loss notification"},
{0x3000, "Incompatible medium installed"},
{0x3001, "Cannot read medium - unknown format"},
@@ -702,7 +726,8 @@ static struct error_info additional[] =
{0x3008, "Cannot write - application code mismatch"},
{0x3009, "Current session not fixated for append"},
{0x300A, "Cleaning request rejected"},
- {0x300C, "WORM medium, overwrite attempted"},
+ {0x300C, "WORM medium - overwrite attempted"},
+ {0x300D, "WORM medium - integrity check"},
{0x3010, "Medium not formatted"},
{0x3100, "Medium format corrupted"},
@@ -790,6 +815,9 @@ static struct error_info additional[] =
{0x3F0F, "Echo buffer overwritten"},
{0x3F10, "Medium loadable"},
{0x3F11, "Medium auxiliary memory accessible"},
+ {0x3F12, "iSCSI IP address added"},
+ {0x3F13, "iSCSI IP address removed"},
+ {0x3F14, "iSCSI IP address changed"},
/*
* {0x40NN, "Ram failure"},
* {0x40NN, "Diagnostic failure on component nn"},
@@ -799,6 +827,7 @@ static struct error_info additional[] =
{0x4300, "Message error"},
{0x4400, "Internal target failure"},
+ {0x4471, "ATA device failed set features"},
{0x4500, "Select or reselect failure"},
@@ -807,9 +836,10 @@ static struct error_info additional[] =
{0x4700, "Scsi parity error"},
{0x4701, "Data phase CRC error detected"},
{0x4702, "Scsi parity error detected during st data phase"},
- {0x4703, "Information unit CRC error detected"},
+ {0x4703, "Information unit iuCRC error detected"},
{0x4704, "Asynchronous information protection error detected"},
{0x4705, "Protocol service CRC error"},
+ {0x4706, "Phy test function in progress"},
{0x477f, "Some commands cleared by iSCSI Protocol event"},
{0x4800, "Initiator detected error message received"},
@@ -844,6 +874,8 @@ static struct error_info additional[] =
{0x5300, "Media load or eject failed"},
{0x5301, "Unload tape failure"},
{0x5302, "Medium removal prevented"},
+ {0x5303, "Medium removal prevented by data transfer element"},
+ {0x5304, "Medium thread or unthread failure"},
{0x5400, "Scsi to host system interface failure"},
@@ -855,6 +887,7 @@ static struct error_info additional[] =
{0x5505, "Insufficient access control resources"},
{0x5506, "Auxiliary memory out of space"},
{0x5507, "Quota error"},
+ {0x5508, "Maximum number of supplemental decryption keys exceeded"},
{0x5700, "Unable to recover table-of-contents"},
@@ -1004,6 +1037,7 @@ static struct error_info additional[] =
{0x6708, "Assign failure occurred"},
{0x6709, "Multiply assigned logical unit"},
{0x670A, "Set target port groups command failed"},
+ {0x670B, "ATA device feature not enabled"},
{0x6800, "Logical unit not configured"},
@@ -1030,6 +1064,8 @@ static struct error_info additional[] =
{0x6F03, "Read of scrambled sector without authentication"},
{0x6F04, "Media region code is mismatched to logical unit region"},
{0x6F05, "Drive region must be permanent/region reset count error"},
+ {0x6F06, "Insufficient block count for binding nonce recording"},
+ {0x6F07, "Conflict in binding nonce recording"},
/*
* {0x70NN, "Decompression exception short algorithm id of nn"},
*/
@@ -1041,6 +1077,8 @@ static struct error_info additional[] =
{0x7203, "Session fixation error - incomplete track in session"},
{0x7204, "Empty or partially written reserved track"},
{0x7205, "No more track reservations allowed"},
+ {0x7206, "RMZ extension is not allowed"},
+ {0x7207, "No more test zone extensions are allowed"},
{0x7300, "Cd control error"},
{0x7301, "Power calibration area almost full"},
@@ -1049,6 +1087,18 @@ static struct error_info additional[] =
{0x7304, "Program memory area update failure"},
{0x7305, "Program memory area is full"},
{0x7306, "RMA/PMA is almost full"},
+ {0x7310, "Current power calibration area almost full"},
+ {0x7311, "Current power calibration area is full"},
+ {0x7317, "RDZ is full"},
+
+ {0x7400, "Security error"},
+ {0x7401, "Unable to decrypt data"},
+ {0x7402, "Unencrypted data encountered while decrypting"},
+ {0x7403, "Incorrect data encryption key"},
+ {0x7404, "Cryptographic integrity validation failed"},
+ {0x7405, "Error decrypting data"},
+ {0x7471, "Logical unit access not authorized"},
+
{0, NULL}
};
diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c
index 10573c24a50..98bd22714d0 100644
--- a/drivers/scsi/esp.c
+++ b/drivers/scsi/esp.c
@@ -1397,7 +1397,7 @@ static void esp_get_dmabufs(struct esp *esp, struct scsi_cmnd *sp)
sp->SCp.ptr = NULL;
}
} else {
- sp->SCp.buffer = (struct scatterlist *) sp->buffer;
+ sp->SCp.buffer = (struct scatterlist *) sp->request_buffer;
sp->SCp.buffers_residual = sbus_map_sg(esp->sdev,
sp->SCp.buffer,
sp->use_sg,
@@ -1410,7 +1410,7 @@ static void esp_get_dmabufs(struct esp *esp, struct scsi_cmnd *sp)
static void esp_release_dmabufs(struct esp *esp, struct scsi_cmnd *sp)
{
if (sp->use_sg) {
- sbus_unmap_sg(esp->sdev, sp->buffer, sp->use_sg,
+ sbus_unmap_sg(esp->sdev, sp->request_buffer, sp->use_sg,
sp->sc_data_direction);
} else if (sp->request_bufflen) {
sbus_unmap_single(esp->sdev,
@@ -2754,18 +2754,15 @@ static int esp_do_data_finale(struct esp *esp)
*/
static int esp_should_clear_sync(struct scsi_cmnd *sp)
{
- u8 cmd1 = sp->cmnd[0];
- u8 cmd2 = sp->data_cmnd[0];
+ u8 cmd = sp->cmnd[0];
/* These cases are for spinning up a disk and
* waiting for that spinup to complete.
*/
- if (cmd1 == START_STOP ||
- cmd2 == START_STOP)
+ if (cmd == START_STOP)
return 0;
- if (cmd1 == TEST_UNIT_READY ||
- cmd2 == TEST_UNIT_READY)
+ if (cmd == TEST_UNIT_READY)
return 0;
/* One more special case for SCSI tape drives,
@@ -2773,8 +2770,7 @@ static int esp_should_clear_sync(struct scsi_cmnd *sp)
* completion of a rewind or tape load operation.
*/
if (sp->device->type == TYPE_TAPE) {
- if (cmd1 == MODE_SENSE ||
- cmd2 == MODE_SENSE)
+ if (cmd == MODE_SENSE)
return 0;
}
diff --git a/drivers/scsi/ibmvscsi/iseries_vscsi.c b/drivers/scsi/ibmvscsi/iseries_vscsi.c
index 7eed0b09817..6aeb5f003c3 100644
--- a/drivers/scsi/ibmvscsi/iseries_vscsi.c
+++ b/drivers/scsi/ibmvscsi/iseries_vscsi.c
@@ -81,7 +81,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
int rc;
single_host_data = hostdata;
- rc = viopath_open(viopath_hostLp, viomajorsubtype_scsi, 0);
+ rc = viopath_open(viopath_hostLp, viomajorsubtype_scsi, max_requests);
if (rc < 0) {
printk("viopath_open failed with rc %d in open_event_path\n",
rc);
diff --git a/drivers/scsi/ibmvscsi/rpa_vscsi.c b/drivers/scsi/ibmvscsi/rpa_vscsi.c
index 242b8873b33..ed22b96580c 100644
--- a/drivers/scsi/ibmvscsi/rpa_vscsi.c
+++ b/drivers/scsi/ibmvscsi/rpa_vscsi.c
@@ -238,6 +238,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
if (rc == 2) {
/* Adapter is good, but other end is not ready */
printk(KERN_WARNING "ibmvscsi: Partner adapter not ready\n");
+ retrc = 0;
} else if (rc != 0) {
printk(KERN_WARNING "ibmvscsi: Error %d opening adapter\n", rc);
goto reg_crq_failed;
diff --git a/drivers/scsi/jazz_esp.c b/drivers/scsi/jazz_esp.c
index 3fd8a96f2af..bfac4441d89 100644
--- a/drivers/scsi/jazz_esp.c
+++ b/drivers/scsi/jazz_esp.c
@@ -257,7 +257,7 @@ static void dma_mmu_release_scsi_one (struct NCR_ESP *esp, struct scsi_cmnd *sp)
static void dma_mmu_release_scsi_sgl (struct NCR_ESP *esp, struct scsi_cmnd *sp)
{
int sz = sp->use_sg - 1;
- struct scatterlist *sg = (struct scatterlist *)sp->buffer;
+ struct scatterlist *sg = (struct scatterlist *)sp->request_buffer;
while(sz >= 0) {
vdma_free(sg[sz].dma_address);
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 1c960ac1617..386e5f21e19 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -61,9 +61,9 @@
#include "libata.h"
/* debounce timing parameters in msecs { interval, duration, timeout } */
-const unsigned long sata_deb_timing_boot[] = { 5, 100, 2000 };
-const unsigned long sata_deb_timing_eh[] = { 25, 500, 2000 };
-const unsigned long sata_deb_timing_before_fsrst[] = { 100, 2000, 5000 };
+const unsigned long sata_deb_timing_normal[] = { 5, 100, 2000 };
+const unsigned long sata_deb_timing_hotplug[] = { 25, 500, 2000 };
+const unsigned long sata_deb_timing_long[] = { 100, 2000, 5000 };
static unsigned int ata_dev_init_params(struct ata_device *dev,
u16 heads, u16 sectors);
@@ -907,7 +907,7 @@ void ata_port_queue_task(struct ata_port *ap, void (*fn)(void *), void *data,
{
int rc;
- if (ap->flags & ATA_FLAG_FLUSH_PORT_TASK)
+ if (ap->pflags & ATA_PFLAG_FLUSH_PORT_TASK)
return;
PREPARE_WORK(&ap->port_task, fn, data);
@@ -938,7 +938,7 @@ void ata_port_flush_task(struct ata_port *ap)
DPRINTK("ENTER\n");
spin_lock_irqsave(ap->lock, flags);
- ap->flags |= ATA_FLAG_FLUSH_PORT_TASK;
+ ap->pflags |= ATA_PFLAG_FLUSH_PORT_TASK;
spin_unlock_irqrestore(ap->lock, flags);
DPRINTK("flush #1\n");
@@ -957,7 +957,7 @@ void ata_port_flush_task(struct ata_port *ap)
}
spin_lock_irqsave(ap->lock, flags);
- ap->flags &= ~ATA_FLAG_FLUSH_PORT_TASK;
+ ap->pflags &= ~ATA_PFLAG_FLUSH_PORT_TASK;
spin_unlock_irqrestore(ap->lock, flags);
if (ata_msg_ctl(ap))
@@ -1009,7 +1009,7 @@ unsigned ata_exec_internal(struct ata_device *dev,
spin_lock_irqsave(ap->lock, flags);
/* no internal command while frozen */
- if (ap->flags & ATA_FLAG_FROZEN) {
+ if (ap->pflags & ATA_PFLAG_FROZEN) {
spin_unlock_irqrestore(ap->lock, flags);
return AC_ERR_SYSTEM;
}
@@ -1325,6 +1325,19 @@ static void ata_dev_config_ncq(struct ata_device *dev,
snprintf(desc, desc_sz, "NCQ (depth %d/%d)", hdepth, ddepth);
}
+static void ata_set_port_max_cmd_len(struct ata_port *ap)
+{
+ int i;
+
+ if (ap->host) {
+ ap->host->max_cmd_len = 0;
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ ap->host->max_cmd_len = max_t(unsigned int,
+ ap->host->max_cmd_len,
+ ap->device[i].cdb_len);
+ }
+}
+
/**
* ata_dev_configure - Configure the specified ATA/ATAPI device
* @dev: Target device to configure
@@ -1344,7 +1357,7 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
struct ata_port *ap = dev->ap;
const u16 *id = dev->id;
unsigned int xfer_mask;
- int i, rc;
+ int rc;
if (!ata_dev_enabled(dev) && ata_msg_info(ap)) {
ata_dev_printk(dev, KERN_INFO,
@@ -1404,7 +1417,7 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc));
/* print device info to dmesg */
- if (ata_msg_info(ap))
+ if (ata_msg_drv(ap) && print_info)
ata_dev_printk(dev, KERN_INFO, "ATA-%d, "
"max %s, %Lu sectors: %s %s\n",
ata_id_major_version(id),
@@ -1427,7 +1440,7 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
}
/* print device info to dmesg */
- if (ata_msg_info(ap))
+ if (ata_msg_drv(ap) && print_info)
ata_dev_printk(dev, KERN_INFO, "ATA-%d, "
"max %s, %Lu sectors: CHS %u/%u/%u\n",
ata_id_major_version(id),
@@ -1439,7 +1452,7 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
if (dev->id[59] & 0x100) {
dev->multi_count = dev->id[59] & 0xff;
- if (ata_msg_info(ap))
+ if (ata_msg_drv(ap) && print_info)
ata_dev_printk(dev, KERN_INFO,
"ata%u: dev %u multi count %u\n",
ap->id, dev->devno, dev->multi_count);
@@ -1468,21 +1481,17 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
}
/* print device info to dmesg */
- if (ata_msg_info(ap))
+ if (ata_msg_drv(ap) && print_info)
ata_dev_printk(dev, KERN_INFO, "ATAPI, max %s%s\n",
ata_mode_string(xfer_mask),
cdb_intr_string);
}
- ap->host->max_cmd_len = 0;
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- ap->host->max_cmd_len = max_t(unsigned int,
- ap->host->max_cmd_len,
- ap->device[i].cdb_len);
+ ata_set_port_max_cmd_len(ap);
/* limit bridge transfers to udma5, 200 sectors */
if (ata_dev_knobble(dev)) {
- if (ata_msg_info(ap))
+ if (ata_msg_drv(ap) && print_info)
ata_dev_printk(dev, KERN_INFO,
"applying bridge limits\n");
dev->udma_mask &= ATA_UDMA5;
@@ -2137,7 +2146,7 @@ int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
* return error code and failing device on failure.
*/
for (i = 0; i < ATA_MAX_DEVICES; i++) {
- if (ata_dev_enabled(&ap->device[i])) {
+ if (ata_dev_ready(&ap->device[i])) {
ap->ops->set_mode(ap);
break;
}
@@ -2203,7 +2212,8 @@ int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
for (i = 0; i < ATA_MAX_DEVICES; i++) {
dev = &ap->device[i];
- if (!ata_dev_enabled(dev))
+ /* don't udpate suspended devices' xfer mode */
+ if (!ata_dev_ready(dev))
continue;
rc = ata_dev_set_mode(dev);
@@ -2579,7 +2589,7 @@ static void ata_wait_spinup(struct ata_port *ap)
/* first, debounce phy if SATA */
if (ap->cbl == ATA_CBL_SATA) {
- rc = sata_phy_debounce(ap, sata_deb_timing_eh);
+ rc = sata_phy_debounce(ap, sata_deb_timing_hotplug);
/* if debounced successfully and offline, no need to wait */
if ((rc == 0 || rc == -EOPNOTSUPP) && ata_port_offline(ap))
@@ -2615,16 +2625,17 @@ static void ata_wait_spinup(struct ata_port *ap)
int ata_std_prereset(struct ata_port *ap)
{
struct ata_eh_context *ehc = &ap->eh_context;
- const unsigned long *timing;
+ const unsigned long *timing = sata_ehc_deb_timing(ehc);
int rc;
- /* hotplug? */
- if (ehc->i.flags & ATA_EHI_HOTPLUGGED) {
- if (ap->flags & ATA_FLAG_HRST_TO_RESUME)
- ehc->i.action |= ATA_EH_HARDRESET;
- if (ap->flags & ATA_FLAG_SKIP_D2H_BSY)
- ata_wait_spinup(ap);
- }
+ /* handle link resume & hotplug spinup */
+ if ((ehc->i.flags & ATA_EHI_RESUME_LINK) &&
+ (ap->flags & ATA_FLAG_HRST_TO_RESUME))
+ ehc->i.action |= ATA_EH_HARDRESET;
+
+ if ((ehc->i.flags & ATA_EHI_HOTPLUGGED) &&
+ (ap->flags & ATA_FLAG_SKIP_D2H_BSY))
+ ata_wait_spinup(ap);
/* if we're about to do hardreset, nothing more to do */
if (ehc->i.action & ATA_EH_HARDRESET)
@@ -2632,11 +2643,6 @@ int ata_std_prereset(struct ata_port *ap)
/* if SATA, resume phy */
if (ap->cbl == ATA_CBL_SATA) {
- if (ap->flags & ATA_FLAG_LOADING)
- timing = sata_deb_timing_boot;
- else
- timing = sata_deb_timing_eh;
-
rc = sata_phy_resume(ap, timing);
if (rc && rc != -EOPNOTSUPP) {
/* phy resume failed */
@@ -2724,6 +2730,8 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes)
*/
int sata_std_hardreset(struct ata_port *ap, unsigned int *class)
{
+ struct ata_eh_context *ehc = &ap->eh_context;
+ const unsigned long *timing = sata_ehc_deb_timing(ehc);
u32 scontrol;
int rc;
@@ -2761,7 +2769,7 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class)
msleep(1);
/* bring phy back */
- sata_phy_resume(ap, sata_deb_timing_eh);
+ sata_phy_resume(ap, timing);
/* TODO: phy layer with polling, timeouts, etc. */
if (ata_port_offline(ap)) {
@@ -4285,7 +4293,7 @@ static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)
unsigned int i;
/* no command while frozen */
- if (unlikely(ap->flags & ATA_FLAG_FROZEN))
+ if (unlikely(ap->pflags & ATA_PFLAG_FROZEN))
return NULL;
/* the last tag is reserved for internal command. */
@@ -4407,7 +4415,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
* taken care of.
*/
if (ap->ops->error_handler) {
- WARN_ON(ap->flags & ATA_FLAG_FROZEN);
+ WARN_ON(ap->pflags & ATA_PFLAG_FROZEN);
if (unlikely(qc->err_mask))
qc->flags |= ATA_QCFLAG_FAILED;
@@ -5001,86 +5009,120 @@ int ata_flush_cache(struct ata_device *dev)
return 0;
}
-static int ata_standby_drive(struct ata_device *dev)
+static int ata_host_set_request_pm(struct ata_host_set *host_set,
+ pm_message_t mesg, unsigned int action,
+ unsigned int ehi_flags, int wait)
{
- unsigned int err_mask;
+ unsigned long flags;
+ int i, rc;
- err_mask = ata_do_simple_cmd(dev, ATA_CMD_STANDBYNOW1);
- if (err_mask) {
- ata_dev_printk(dev, KERN_ERR, "failed to standby drive "
- "(err_mask=0x%x)\n", err_mask);
- return -EIO;
- }
+ for (i = 0; i < host_set->n_ports; i++) {
+ struct ata_port *ap = host_set->ports[i];
- return 0;
-}
+ /* Previous resume operation might still be in
+ * progress. Wait for PM_PENDING to clear.
+ */
+ if (ap->pflags & ATA_PFLAG_PM_PENDING) {
+ ata_port_wait_eh(ap);
+ WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
+ }
-static int ata_start_drive(struct ata_device *dev)
-{
- unsigned int err_mask;
+ /* request PM ops to EH */
+ spin_lock_irqsave(ap->lock, flags);
- err_mask = ata_do_simple_cmd(dev, ATA_CMD_IDLEIMMEDIATE);
- if (err_mask) {
- ata_dev_printk(dev, KERN_ERR, "failed to start drive "
- "(err_mask=0x%x)\n", err_mask);
- return -EIO;
+ ap->pm_mesg = mesg;
+ if (wait) {
+ rc = 0;
+ ap->pm_result = &rc;
+ }
+
+ ap->pflags |= ATA_PFLAG_PM_PENDING;
+ ap->eh_info.action |= action;
+ ap->eh_info.flags |= ehi_flags;
+
+ ata_port_schedule_eh(ap);
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ /* wait and check result */
+ if (wait) {
+ ata_port_wait_eh(ap);
+ WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
+ if (rc)
+ return rc;
+ }
}
return 0;
}
/**
- * ata_device_resume - wakeup a previously suspended devices
- * @dev: the device to resume
+ * ata_host_set_suspend - suspend host_set
+ * @host_set: host_set to suspend
+ * @mesg: PM message
*
- * Kick the drive back into action, by sending it an idle immediate
- * command and making sure its transfer mode matches between drive
- * and host.
+ * Suspend @host_set. Actual operation is performed by EH. This
+ * function requests EH to perform PM operations and waits for EH
+ * to finish.
*
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
*/
-int ata_device_resume(struct ata_device *dev)
+int ata_host_set_suspend(struct ata_host_set *host_set, pm_message_t mesg)
{
- struct ata_port *ap = dev->ap;
+ int i, j, rc;
- if (ap->flags & ATA_FLAG_SUSPENDED) {
- struct ata_device *failed_dev;
+ rc = ata_host_set_request_pm(host_set, mesg, 0, ATA_EHI_QUIET, 1);
+ if (rc)
+ goto fail;
- ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
- ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 200000);
+ /* EH is quiescent now. Fail if we have any ready device.
+ * This happens if hotplug occurs between completion of device
+ * suspension and here.
+ */
+ for (i = 0; i < host_set->n_ports; i++) {
+ struct ata_port *ap = host_set->ports[i];
- ap->flags &= ~ATA_FLAG_SUSPENDED;
- while (ata_set_mode(ap, &failed_dev))
- ata_dev_disable(failed_dev);
+ for (j = 0; j < ATA_MAX_DEVICES; j++) {
+ struct ata_device *dev = &ap->device[j];
+
+ if (ata_dev_ready(dev)) {
+ ata_port_printk(ap, KERN_WARNING,
+ "suspend failed, device %d "
+ "still active\n", dev->devno);
+ rc = -EBUSY;
+ goto fail;
+ }
+ }
}
- if (!ata_dev_enabled(dev))
- return 0;
- if (dev->class == ATA_DEV_ATA)
- ata_start_drive(dev);
+ host_set->dev->power.power_state = mesg;
return 0;
+
+ fail:
+ ata_host_set_resume(host_set);
+ return rc;
}
/**
- * ata_device_suspend - prepare a device for suspend
- * @dev: the device to suspend
- * @state: target power management state
+ * ata_host_set_resume - resume host_set
+ * @host_set: host_set to resume
+ *
+ * Resume @host_set. Actual operation is performed by EH. This
+ * function requests EH to perform PM operations and returns.
+ * Note that all resume operations are performed parallely.
*
- * Flush the cache on the drive, if appropriate, then issue a
- * standbynow command.
+ * LOCKING:
+ * Kernel thread context (may sleep).
*/
-int ata_device_suspend(struct ata_device *dev, pm_message_t state)
+void ata_host_set_resume(struct ata_host_set *host_set)
{
- struct ata_port *ap = dev->ap;
-
- if (!ata_dev_enabled(dev))
- return 0;
- if (dev->class == ATA_DEV_ATA)
- ata_flush_cache(dev);
-
- if (state.event != PM_EVENT_FREEZE)
- ata_standby_drive(dev);
- ap->flags |= ATA_FLAG_SUSPENDED;
- return 0;
+ ata_host_set_request_pm(host_set, PMSG_ON, ATA_EH_SOFTRESET,
+ ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 0);
+ host_set->dev->power.power_state = PMSG_ON;
}
/**
@@ -5440,6 +5482,7 @@ int ata_device_add(const struct ata_probe_ent *ent)
}
if (ap->ops->error_handler) {
+ struct ata_eh_info *ehi = &ap->eh_info;
unsigned long flags;
ata_port_probe(ap);
@@ -5447,10 +5490,11 @@ int ata_device_add(const struct ata_probe_ent *ent)
/* kick EH for boot probing */
spin_lock_irqsave(ap->lock, flags);
- ap->eh_info.probe_mask = (1 << ATA_MAX_DEVICES) - 1;
- ap->eh_info.action |= ATA_EH_SOFTRESET;
+ ehi->probe_mask = (1 << ATA_MAX_DEVICES) - 1;
+ ehi->action |= ATA_EH_SOFTRESET;
+ ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
- ap->flags |= ATA_FLAG_LOADING;
+ ap->pflags |= ATA_PFLAG_LOADING;
ata_port_schedule_eh(ap);
spin_unlock_irqrestore(ap->lock, flags);
@@ -5518,7 +5562,7 @@ void ata_port_detach(struct ata_port *ap)
/* tell EH we're leaving & flush EH */
spin_lock_irqsave(ap->lock, flags);
- ap->flags |= ATA_FLAG_UNLOADING;
+ ap->pflags |= ATA_PFLAG_UNLOADING;
spin_unlock_irqrestore(ap->lock, flags);
ata_port_wait_eh(ap);
@@ -5723,20 +5767,55 @@ int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits)
return (tmp == bits->val) ? 1 : 0;
}
-int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t state)
+void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t state)
{
pci_save_state(pdev);
- pci_disable_device(pdev);
- pci_set_power_state(pdev, PCI_D3hot);
- return 0;
+
+ if (state.event == PM_EVENT_SUSPEND) {
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, PCI_D3hot);
+ }
}
-int ata_pci_device_resume(struct pci_dev *pdev)
+void ata_pci_device_do_resume(struct pci_dev *pdev)
{
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
pci_enable_device(pdev);
pci_set_master(pdev);
+}
+
+int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev);
+ int rc = 0;
+
+ rc = ata_host_set_suspend(host_set, state);
+ if (rc)
+ return rc;
+
+ if (host_set->next) {
+ rc = ata_host_set_suspend(host_set->next, state);
+ if (rc) {
+ ata_host_set_resume(host_set);
+ return rc;
+ }
+ }
+
+ ata_pci_device_do_suspend(pdev, state);
+
+ return 0;
+}
+
+int ata_pci_device_resume(struct pci_dev *pdev)
+{
+ struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev);
+
+ ata_pci_device_do_resume(pdev);
+ ata_host_set_resume(host_set);
+ if (host_set->next)
+ ata_host_set_resume(host_set->next);
+
return 0;
}
#endif /* CONFIG_PCI */
@@ -5842,9 +5921,9 @@ u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val,
* Do not depend on ABI/API stability.
*/
-EXPORT_SYMBOL_GPL(sata_deb_timing_boot);
-EXPORT_SYMBOL_GPL(sata_deb_timing_eh);
-EXPORT_SYMBOL_GPL(sata_deb_timing_before_fsrst);
+EXPORT_SYMBOL_GPL(sata_deb_timing_normal);
+EXPORT_SYMBOL_GPL(sata_deb_timing_hotplug);
+EXPORT_SYMBOL_GPL(sata_deb_timing_long);
EXPORT_SYMBOL_GPL(ata_std_bios_param);
EXPORT_SYMBOL_GPL(ata_std_ports);
EXPORT_SYMBOL_GPL(ata_device_add);
@@ -5916,6 +5995,8 @@ EXPORT_SYMBOL_GPL(sata_scr_write);
EXPORT_SYMBOL_GPL(sata_scr_write_flush);
EXPORT_SYMBOL_GPL(ata_port_online);
EXPORT_SYMBOL_GPL(ata_port_offline);
+EXPORT_SYMBOL_GPL(ata_host_set_suspend);
+EXPORT_SYMBOL_GPL(ata_host_set_resume);
EXPORT_SYMBOL_GPL(ata_id_string);
EXPORT_SYMBOL_GPL(ata_id_c_string);
EXPORT_SYMBOL_GPL(ata_scsi_simulate);
@@ -5930,14 +6011,14 @@ EXPORT_SYMBOL_GPL(ata_pci_host_stop);
EXPORT_SYMBOL_GPL(ata_pci_init_native_mode);
EXPORT_SYMBOL_GPL(ata_pci_init_one);
EXPORT_SYMBOL_GPL(ata_pci_remove_one);
+EXPORT_SYMBOL_GPL(ata_pci_device_do_suspend);
+EXPORT_SYMBOL_GPL(ata_pci_device_do_resume);
EXPORT_SYMBOL_GPL(ata_pci_device_suspend);
EXPORT_SYMBOL_GPL(ata_pci_device_resume);
EXPORT_SYMBOL_GPL(ata_pci_default_filter);
EXPORT_SYMBOL_GPL(ata_pci_clear_simplex);
#endif /* CONFIG_PCI */
-EXPORT_SYMBOL_GPL(ata_device_suspend);
-EXPORT_SYMBOL_GPL(ata_device_resume);
EXPORT_SYMBOL_GPL(ata_scsi_device_suspend);
EXPORT_SYMBOL_GPL(ata_scsi_device_resume);
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index bf5a72aca8a..29f59345305 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -47,6 +47,8 @@
static void __ata_port_freeze(struct ata_port *ap);
static void ata_eh_finish(struct ata_port *ap);
+static void ata_eh_handle_port_suspend(struct ata_port *ap);
+static void ata_eh_handle_port_resume(struct ata_port *ap);
static void ata_ering_record(struct ata_ering *ering, int is_io,
unsigned int err_mask)
@@ -190,7 +192,6 @@ enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
void ata_scsi_error(struct Scsi_Host *host)
{
struct ata_port *ap = ata_shost_to_port(host);
- spinlock_t *ap_lock = ap->lock;
int i, repeat_cnt = ATA_EH_MAX_REPEAT;
unsigned long flags;
@@ -217,7 +218,7 @@ void ata_scsi_error(struct Scsi_Host *host)
struct scsi_cmnd *scmd, *tmp;
int nr_timedout = 0;
- spin_lock_irqsave(ap_lock, flags);
+ spin_lock_irqsave(ap->lock, flags);
list_for_each_entry_safe(scmd, tmp, &host->eh_cmd_q, eh_entry) {
struct ata_queued_cmd *qc;
@@ -256,43 +257,49 @@ void ata_scsi_error(struct Scsi_Host *host)
if (nr_timedout)
__ata_port_freeze(ap);
- spin_unlock_irqrestore(ap_lock, flags);
+ spin_unlock_irqrestore(ap->lock, flags);
} else
- spin_unlock_wait(ap_lock);
+ spin_unlock_wait(ap->lock);
repeat:
/* invoke error handler */
if (ap->ops->error_handler) {
+ /* process port resume request */
+ ata_eh_handle_port_resume(ap);
+
/* fetch & clear EH info */
- spin_lock_irqsave(ap_lock, flags);
+ spin_lock_irqsave(ap->lock, flags);
memset(&ap->eh_context, 0, sizeof(ap->eh_context));
ap->eh_context.i = ap->eh_info;
memset(&ap->eh_info, 0, sizeof(ap->eh_info));
- ap->flags |= ATA_FLAG_EH_IN_PROGRESS;
- ap->flags &= ~ATA_FLAG_EH_PENDING;
+ ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS;
+ ap->pflags &= ~ATA_PFLAG_EH_PENDING;
- spin_unlock_irqrestore(ap_lock, flags);
+ spin_unlock_irqrestore(ap->lock, flags);
- /* invoke EH. if unloading, just finish failed qcs */
- if (!(ap->flags & ATA_FLAG_UNLOADING))
+ /* invoke EH, skip if unloading or suspended */
+ if (!(ap->pflags & (ATA_PFLAG_UNLOADING | ATA_PFLAG_SUSPENDED)))
ap->ops->error_handler(ap);
else
ata_eh_finish(ap);
+ /* process port suspend request */
+ ata_eh_handle_port_suspend(ap);
+
/* Exception might have happend after ->error_handler
* recovered the port but before this point. Repeat
* EH in such case.
*/
- spin_lock_irqsave(ap_lock, flags);
+ spin_lock_irqsave(ap->lock, flags);
- if (ap->flags & ATA_FLAG_EH_PENDING) {
+ if (ap->pflags & ATA_PFLAG_EH_PENDING) {
if (--repeat_cnt) {
ata_port_printk(ap, KERN_INFO,
"EH pending after completion, "
"repeating EH (cnt=%d)\n", repeat_cnt);
- spin_unlock_irqrestore(ap_lock, flags);
+ spin_unlock_irqrestore(ap->lock, flags);
goto repeat;
}
ata_port_printk(ap, KERN_ERR, "EH pending after %d "
@@ -302,14 +309,14 @@ void ata_scsi_error(struct Scsi_Host *host)
/* this run is complete, make sure EH info is clear */
memset(&ap->eh_info, 0, sizeof(ap->eh_info));
- /* Clear host_eh_scheduled while holding ap_lock such
+ /* Clear host_eh_scheduled while holding ap->lock such
* that if exception occurs after this point but
* before EH completion, SCSI midlayer will
* re-initiate EH.
*/
host->host_eh_scheduled = 0;
- spin_unlock_irqrestore(ap_lock, flags);
+ spin_unlock_irqrestore(ap->lock, flags);
} else {
WARN_ON(ata_qc_from_tag(ap, ap->active_tag) == NULL);
ap->ops->eng_timeout(ap);
@@ -321,24 +328,23 @@ void ata_scsi_error(struct Scsi_Host *host)
scsi_eh_flush_done_q(&ap->eh_done_q);
/* clean up */
- spin_lock_irqsave(ap_lock, flags);
+ spin_lock_irqsave(ap->lock, flags);
- if (ap->flags & ATA_FLAG_LOADING) {
- ap->flags &= ~ATA_FLAG_LOADING;
- } else {
- if (ap->flags & ATA_FLAG_SCSI_HOTPLUG)
- queue_work(ata_aux_wq, &ap->hotplug_task);
- if (ap->flags & ATA_FLAG_RECOVERED)
- ata_port_printk(ap, KERN_INFO, "EH complete\n");
- }
+ if (ap->pflags & ATA_PFLAG_LOADING)
+ ap->pflags &= ~ATA_PFLAG_LOADING;
+ else if (ap->pflags & ATA_PFLAG_SCSI_HOTPLUG)
+ queue_work(ata_aux_wq, &ap->hotplug_task);
- ap->flags &= ~(ATA_FLAG_SCSI_HOTPLUG | ATA_FLAG_RECOVERED);
+ if (ap->pflags & ATA_PFLAG_RECOVERED)
+ ata_port_printk(ap, KERN_INFO, "EH complete\n");
+
+ ap->pflags &= ~(ATA_PFLAG_SCSI_HOTPLUG | ATA_PFLAG_RECOVERED);
/* tell wait_eh that we're done */
- ap->flags &= ~ATA_FLAG_EH_IN_PROGRESS;
+ ap->pflags &= ~ATA_PFLAG_EH_IN_PROGRESS;
wake_up_all(&ap->eh_wait_q);
- spin_unlock_irqrestore(ap_lock, flags);
+ spin_unlock_irqrestore(ap->lock, flags);
DPRINTK("EXIT\n");
}
@@ -360,7 +366,7 @@ void ata_port_wait_eh(struct ata_port *ap)
retry:
spin_lock_irqsave(ap->lock, flags);
- while (ap->flags & (ATA_FLAG_EH_PENDING | ATA_FLAG_EH_IN_PROGRESS)) {
+ while (ap->pflags & (ATA_PFLAG_EH_PENDING | ATA_PFLAG_EH_IN_PROGRESS)) {
prepare_to_wait(&ap->eh_wait_q, &wait, TASK_UNINTERRUPTIBLE);
spin_unlock_irqrestore(ap->lock, flags);
schedule();
@@ -489,7 +495,7 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
WARN_ON(!ap->ops->error_handler);
qc->flags |= ATA_QCFLAG_FAILED;
- qc->ap->flags |= ATA_FLAG_EH_PENDING;
+ qc->ap->pflags |= ATA_PFLAG_EH_PENDING;
/* The following will fail if timeout has already expired.
* ata_scsi_error() takes care of such scmds on EH entry.
@@ -513,7 +519,7 @@ void ata_port_schedule_eh(struct ata_port *ap)
{
WARN_ON(!ap->ops->error_handler);
- ap->flags |= ATA_FLAG_EH_PENDING;
+ ap->pflags |= ATA_PFLAG_EH_PENDING;
scsi_schedule_eh(ap->host);
DPRINTK("port EH scheduled\n");
@@ -578,7 +584,7 @@ static void __ata_port_freeze(struct ata_port *ap)
if (ap->ops->freeze)
ap->ops->freeze(ap);
- ap->flags |= ATA_FLAG_FROZEN;
+ ap->pflags |= ATA_PFLAG_FROZEN;
DPRINTK("ata%u port frozen\n", ap->id);
}
@@ -646,7 +652,7 @@ void ata_eh_thaw_port(struct ata_port *ap)
spin_lock_irqsave(ap->lock, flags);
- ap->flags &= ~ATA_FLAG_FROZEN;
+ ap->pflags &= ~ATA_PFLAG_FROZEN;
if (ap->ops->thaw)
ap->ops->thaw(ap);
@@ -731,7 +737,7 @@ static void ata_eh_detach_dev(struct ata_device *dev)
if (ata_scsi_offline_dev(dev)) {
dev->flags |= ATA_DFLAG_DETACHED;
- ap->flags |= ATA_FLAG_SCSI_HOTPLUG;
+ ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG;
}
/* clear per-dev EH actions */
@@ -758,10 +764,29 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev,
unsigned int action)
{
unsigned long flags;
+ struct ata_eh_info *ehi = &ap->eh_info;
+ struct ata_eh_context *ehc = &ap->eh_context;
spin_lock_irqsave(ap->lock, flags);
- ata_eh_clear_action(dev, &ap->eh_info, action);
- ap->flags |= ATA_FLAG_RECOVERED;
+
+ /* Reset is represented by combination of actions and EHI
+ * flags. Suck in all related bits before clearing eh_info to
+ * avoid losing requested action.
+ */
+ if (action & ATA_EH_RESET_MASK) {
+ ehc->i.action |= ehi->action & ATA_EH_RESET_MASK;
+ ehc->i.flags |= ehi->flags & ATA_EHI_RESET_MODIFIER_MASK;
+
+ /* make sure all reset actions are cleared & clear EHI flags */
+ action |= ATA_EH_RESET_MASK;
+ ehi->flags &= ~ATA_EHI_RESET_MODIFIER_MASK;
+ }
+
+ ata_eh_clear_action(dev, ehi, action);
+
+ if (!(ehc->i.flags & ATA_EHI_QUIET))
+ ap->pflags |= ATA_PFLAG_RECOVERED;
+
spin_unlock_irqrestore(ap->lock, flags);
}
@@ -780,6 +805,12 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev,
static void ata_eh_done(struct ata_port *ap, struct ata_device *dev,
unsigned int action)
{
+ /* if reset is complete, clear all reset actions & reset modifier */
+ if (action & ATA_EH_RESET_MASK) {
+ action |= ATA_EH_RESET_MASK;
+ ap->eh_context.i.flags &= ~ATA_EHI_RESET_MODIFIER_MASK;
+ }
+
ata_eh_clear_action(dev, &ap->eh_context.i, action);
}
@@ -1027,7 +1058,7 @@ static void ata_eh_analyze_ncq_error(struct ata_port *ap)
int tag, rc;
/* if frozen, we can't do much */
- if (ap->flags & ATA_FLAG_FROZEN)
+ if (ap->pflags & ATA_PFLAG_FROZEN)
return;
/* is it NCQ device error? */
@@ -1266,8 +1297,6 @@ static int ata_eh_speed_down(struct ata_device *dev, int is_io,
static void ata_eh_autopsy(struct ata_port *ap)
{
struct ata_eh_context *ehc = &ap->eh_context;
- unsigned int action = ehc->i.action;
- struct ata_device *failed_dev = NULL;
unsigned int all_err_mask = 0;
int tag, is_io = 0;
u32 serror;
@@ -1275,13 +1304,16 @@ static void ata_eh_autopsy(struct ata_port *ap)
DPRINTK("ENTER\n");
+ if (ehc->i.flags & ATA_EHI_NO_AUTOPSY)
+ return;
+
/* obtain and analyze SError */
rc = sata_scr_read(ap, SCR_ERROR, &serror);
if (rc == 0) {
ehc->i.serror |= serror;
ata_eh_analyze_serror(ap);
} else if (rc != -EOPNOTSUPP)
- action |= ATA_EH_HARDRESET;
+ ehc->i.action |= ATA_EH_HARDRESET;
/* analyze NCQ failure */
ata_eh_analyze_ncq_error(ap);
@@ -1302,7 +1334,7 @@ static void ata_eh_autopsy(struct ata_port *ap)
qc->err_mask |= ehc->i.err_mask;
/* analyze TF */
- action |= ata_eh_analyze_tf(qc, &qc->result_tf);
+ ehc->i.action |= ata_eh_analyze_tf(qc, &qc->result_tf);
/* DEV errors are probably spurious in case of ATA_BUS error */
if (qc->err_mask & AC_ERR_ATA_BUS)
@@ -1316,38 +1348,35 @@ static void ata_eh_autopsy(struct ata_port *ap)
/* SENSE_VALID trumps dev/unknown error and revalidation */
if (qc->flags & ATA_QCFLAG_SENSE_VALID) {
qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_OTHER);
- action &= ~ATA_EH_REVALIDATE;
+ ehc->i.action &= ~ATA_EH_REVALIDATE;
}
/* accumulate error info */
- failed_dev = qc->dev;
+ ehc->i.dev = qc->dev;
all_err_mask |= qc->err_mask;
if (qc->flags & ATA_QCFLAG_IO)
is_io = 1;
}
/* enforce default EH actions */
- if (ap->flags & ATA_FLAG_FROZEN ||
+ if (ap->pflags & ATA_PFLAG_FROZEN ||
all_err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT))
- action |= ATA_EH_SOFTRESET;
+ ehc->i.action |= ATA_EH_SOFTRESET;
else if (all_err_mask)
- action |= ATA_EH_REVALIDATE;
+ ehc->i.action |= ATA_EH_REVALIDATE;
/* if we have offending qcs and the associated failed device */
- if (failed_dev) {
+ if (ehc->i.dev) {
/* speed down */
- action |= ata_eh_speed_down(failed_dev, is_io, all_err_mask);
+ ehc->i.action |= ata_eh_speed_down(ehc->i.dev, is_io,
+ all_err_mask);
/* perform per-dev EH action only on the offending device */
- ehc->i.dev_action[failed_dev->devno] |=
- action & ATA_EH_PERDEV_MASK;
- action &= ~ATA_EH_PERDEV_MASK;
+ ehc->i.dev_action[ehc->i.dev->devno] |=
+ ehc->i.action & ATA_EH_PERDEV_MASK;
+ ehc->i.action &= ~ATA_EH_PERDEV_MASK;
}
- /* record autopsy result */
- ehc->i.dev = failed_dev;
- ehc->i.action = action;
-
DPRINTK("EXIT\n");
}
@@ -1385,7 +1414,7 @@ static void ata_eh_report(struct ata_port *ap)
return;
frozen = "";
- if (ap->flags & ATA_FLAG_FROZEN)
+ if (ap->pflags & ATA_PFLAG_FROZEN)
frozen = " frozen";
if (ehc->i.dev) {
@@ -1465,11 +1494,14 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
struct ata_eh_context *ehc = &ap->eh_context;
unsigned int *classes = ehc->classes;
int tries = ATA_EH_RESET_TRIES;
- int verbose = !(ap->flags & ATA_FLAG_LOADING);
+ int verbose = !(ehc->i.flags & ATA_EHI_QUIET);
unsigned int action;
ata_reset_fn_t reset;
int i, did_followup_srst, rc;
+ /* about to reset */
+ ata_eh_about_to_do(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK);
+
/* Determine which reset to use and record in ehc->i.action.
* prereset() may examine and modify it.
*/
@@ -1518,8 +1550,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
ata_port_printk(ap, KERN_INFO, "%s resetting port\n",
reset == softreset ? "soft" : "hard");
- /* reset */
- ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK);
+ /* mark that this EH session started with reset */
ehc->i.flags |= ATA_EHI_DID_RESET;
rc = ata_do_reset(ap, reset, classes);
@@ -1582,7 +1613,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
postreset(ap, classes);
/* reset successful, schedule revalidation */
- ata_eh_done(ap, NULL, ATA_EH_RESET_MASK);
+ ata_eh_done(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK);
ehc->i.action |= ATA_EH_REVALIDATE;
}
@@ -1605,7 +1636,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
dev = &ap->device[i];
action = ata_eh_dev_action(dev);
- if (action & ATA_EH_REVALIDATE && ata_dev_enabled(dev)) {
+ if (action & ATA_EH_REVALIDATE && ata_dev_ready(dev)) {
if (ata_port_offline(ap)) {
rc = -EIO;
break;
@@ -1636,7 +1667,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
}
spin_lock_irqsave(ap->lock, flags);
- ap->flags |= ATA_FLAG_SCSI_HOTPLUG;
+ ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG;
spin_unlock_irqrestore(ap->lock, flags);
}
}
@@ -1648,6 +1679,164 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
return rc;
}
+/**
+ * ata_eh_suspend - handle suspend EH action
+ * @ap: target host port
+ * @r_failed_dev: result parameter to indicate failing device
+ *
+ * Handle suspend EH action. Disk devices are spinned down and
+ * other types of devices are just marked suspended. Once
+ * suspended, no EH action to the device is allowed until it is
+ * resumed.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise
+ */
+static int ata_eh_suspend(struct ata_port *ap, struct ata_device **r_failed_dev)
+{
+ struct ata_device *dev;
+ int i, rc = 0;
+
+ DPRINTK("ENTER\n");
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ unsigned long flags;
+ unsigned int action, err_mask;
+
+ dev = &ap->device[i];
+ action = ata_eh_dev_action(dev);
+
+ if (!ata_dev_enabled(dev) || !(action & ATA_EH_SUSPEND))
+ continue;
+
+ WARN_ON(dev->flags & ATA_DFLAG_SUSPENDED);
+
+ ata_eh_about_to_do(ap, dev, ATA_EH_SUSPEND);
+
+ if (dev->class == ATA_DEV_ATA && !(action & ATA_EH_PM_FREEZE)) {
+ /* flush cache */
+ rc = ata_flush_cache(dev);
+ if (rc)
+ break;
+
+ /* spin down */
+ err_mask = ata_do_simple_cmd(dev, ATA_CMD_STANDBYNOW1);
+ if (err_mask) {
+ ata_dev_printk(dev, KERN_ERR, "failed to "
+ "spin down (err_mask=0x%x)\n",
+ err_mask);
+ rc = -EIO;
+ break;
+ }
+ }
+
+ spin_lock_irqsave(ap->lock, flags);
+ dev->flags |= ATA_DFLAG_SUSPENDED;
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ ata_eh_done(ap, dev, ATA_EH_SUSPEND);
+ }
+
+ if (rc)
+ *r_failed_dev = dev;
+
+ DPRINTK("EXIT\n");
+ return 0;
+}
+
+/**
+ * ata_eh_prep_resume - prep for resume EH action
+ * @ap: target host port
+ *
+ * Clear SUSPENDED in preparation for scheduled resume actions.
+ * This allows other parts of EH to access the devices being
+ * resumed.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+static void ata_eh_prep_resume(struct ata_port *ap)
+{
+ struct ata_device *dev;
+ unsigned long flags;
+ int i;
+
+ DPRINTK("ENTER\n");
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ unsigned int action;
+
+ dev = &ap->device[i];
+ action = ata_eh_dev_action(dev);
+
+ if (!ata_dev_enabled(dev) || !(action & ATA_EH_RESUME))
+ continue;
+
+ spin_lock_irqsave(ap->lock, flags);
+ dev->flags &= ~ATA_DFLAG_SUSPENDED;
+ spin_unlock_irqrestore(ap->lock, flags);
+ }
+
+ DPRINTK("EXIT\n");
+}
+
+/**
+ * ata_eh_resume - handle resume EH action
+ * @ap: target host port
+ * @r_failed_dev: result parameter to indicate failing device
+ *
+ * Handle resume EH action. Target devices are already reset and
+ * revalidated. Spinning up is the only operation left.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise
+ */
+static int ata_eh_resume(struct ata_port *ap, struct ata_device **r_failed_dev)
+{
+ struct ata_device *dev;
+ int i, rc = 0;
+
+ DPRINTK("ENTER\n");
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ unsigned int action, err_mask;
+
+ dev = &ap->device[i];
+ action = ata_eh_dev_action(dev);
+
+ if (!ata_dev_enabled(dev) || !(action & ATA_EH_RESUME))
+ continue;
+
+ ata_eh_about_to_do(ap, dev, ATA_EH_RESUME);
+
+ if (dev->class == ATA_DEV_ATA && !(action & ATA_EH_PM_FREEZE)) {
+ err_mask = ata_do_simple_cmd(dev,
+ ATA_CMD_IDLEIMMEDIATE);
+ if (err_mask) {
+ ata_dev_printk(dev, KERN_ERR, "failed to "
+ "spin up (err_mask=0x%x)\n",
+ err_mask);
+ rc = -EIO;
+ break;
+ }
+ }
+
+ ata_eh_done(ap, dev, ATA_EH_RESUME);
+ }
+
+ if (rc)
+ *r_failed_dev = dev;
+
+ DPRINTK("EXIT\n");
+ return 0;
+}
+
static int ata_port_nr_enabled(struct ata_port *ap)
{
int i, cnt = 0;
@@ -1673,7 +1862,20 @@ static int ata_eh_skip_recovery(struct ata_port *ap)
struct ata_eh_context *ehc = &ap->eh_context;
int i;
- if (ap->flags & ATA_FLAG_FROZEN || ata_port_nr_enabled(ap))
+ /* skip if all possible devices are suspended */
+ for (i = 0; i < ata_port_max_devices(ap); i++) {
+ struct ata_device *dev = &ap->device[i];
+
+ if (!(dev->flags & ATA_DFLAG_SUSPENDED))
+ break;
+ }
+
+ if (i == ata_port_max_devices(ap))
+ return 1;
+
+ /* thaw frozen port, resume link and recover failed devices */
+ if ((ap->pflags & ATA_PFLAG_FROZEN) ||
+ (ehc->i.flags & ATA_EHI_RESUME_LINK) || ata_port_nr_enabled(ap))
return 0;
/* skip if class codes for all vacant slots are ATA_DEV_NONE */
@@ -1744,9 +1946,12 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
rc = 0;
/* if UNLOADING, finish immediately */
- if (ap->flags & ATA_FLAG_UNLOADING)
+ if (ap->pflags & ATA_PFLAG_UNLOADING)
goto out;
+ /* prep for resume */
+ ata_eh_prep_resume(ap);
+
/* skip EH if possible. */
if (ata_eh_skip_recovery(ap))
ehc->i.action = 0;
@@ -1774,6 +1979,11 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
if (rc)
goto dev_fail;
+ /* resume devices */
+ rc = ata_eh_resume(ap, &dev);
+ if (rc)
+ goto dev_fail;
+
/* configure transfer mode if the port has been reset */
if (ehc->i.flags & ATA_EHI_DID_RESET) {
rc = ata_set_mode(ap, &dev);
@@ -1783,6 +1993,11 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
}
}
+ /* suspend devices */
+ rc = ata_eh_suspend(ap, &dev);
+ if (rc)
+ goto dev_fail;
+
goto out;
dev_fail:
@@ -1908,11 +2123,124 @@ void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
ata_postreset_fn_t postreset)
{
- if (!(ap->flags & ATA_FLAG_LOADING)) {
- ata_eh_autopsy(ap);
- ata_eh_report(ap);
- }
-
+ ata_eh_autopsy(ap);
+ ata_eh_report(ap);
ata_eh_recover(ap, prereset, softreset, hardreset, postreset);
ata_eh_finish(ap);
}
+
+/**
+ * ata_eh_handle_port_suspend - perform port suspend operation
+ * @ap: port to suspend
+ *
+ * Suspend @ap.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+static void ata_eh_handle_port_suspend(struct ata_port *ap)
+{
+ unsigned long flags;
+ int rc = 0;
+
+ /* are we suspending? */
+ spin_lock_irqsave(ap->lock, flags);
+ if (!(ap->pflags & ATA_PFLAG_PM_PENDING) ||
+ ap->pm_mesg.event == PM_EVENT_ON) {
+ spin_unlock_irqrestore(ap->lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ WARN_ON(ap->pflags & ATA_PFLAG_SUSPENDED);
+
+ /* suspend */
+ ata_eh_freeze_port(ap);
+
+ if (ap->ops->port_suspend)
+ rc = ap->ops->port_suspend(ap, ap->pm_mesg);
+
+ /* report result */
+ spin_lock_irqsave(ap->lock, flags);
+
+ ap->pflags &= ~ATA_PFLAG_PM_PENDING;
+ if (rc == 0)
+ ap->pflags |= ATA_PFLAG_SUSPENDED;
+ else
+ ata_port_schedule_eh(ap);
+
+ if (ap->pm_result) {
+ *ap->pm_result = rc;
+ ap->pm_result = NULL;
+ }
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ return;
+}
+
+/**
+ * ata_eh_handle_port_resume - perform port resume operation
+ * @ap: port to resume
+ *
+ * Resume @ap.
+ *
+ * This function also waits upto one second until all devices
+ * hanging off this port requests resume EH action. This is to
+ * prevent invoking EH and thus reset multiple times on resume.
+ *
+ * On DPM resume, where some of devices might not be resumed
+ * together, this may delay port resume upto one second, but such
+ * DPM resumes are rare and 1 sec delay isn't too bad.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+static void ata_eh_handle_port_resume(struct ata_port *ap)
+{
+ unsigned long timeout;
+ unsigned long flags;
+ int i, rc = 0;
+
+ /* are we resuming? */
+ spin_lock_irqsave(ap->lock, flags);
+ if (!(ap->pflags & ATA_PFLAG_PM_PENDING) ||
+ ap->pm_mesg.event != PM_EVENT_ON) {
+ spin_unlock_irqrestore(ap->lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ /* spurious? */
+ if (!(ap->pflags & ATA_PFLAG_SUSPENDED))
+ goto done;
+
+ if (ap->ops->port_resume)
+ rc = ap->ops->port_resume(ap);
+
+ /* give devices time to request EH */
+ timeout = jiffies + HZ; /* 1s max */
+ while (1) {
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ struct ata_device *dev = &ap->device[i];
+ unsigned int action = ata_eh_dev_action(dev);
+
+ if ((dev->flags & ATA_DFLAG_SUSPENDED) &&
+ !(action & ATA_EH_RESUME))
+ break;
+ }
+
+ if (i == ATA_MAX_DEVICES || time_after(jiffies, timeout))
+ break;
+ msleep(10);
+ }
+
+ done:
+ spin_lock_irqsave(ap->lock, flags);
+ ap->pflags &= ~(ATA_PFLAG_PM_PENDING | ATA_PFLAG_SUSPENDED);
+ if (ap->pm_result) {
+ *ap->pm_result = rc;
+ ap->pm_result = NULL;
+ }
+ spin_unlock_irqrestore(ap->lock, flags);
+}
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index 2915bca691e..7ced41ecde8 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -397,20 +397,129 @@ void ata_dump_status(unsigned id, struct ata_taskfile *tf)
}
}
-int ata_scsi_device_resume(struct scsi_device *sdev)
+/**
+ * ata_scsi_device_suspend - suspend ATA device associated with sdev
+ * @sdev: the SCSI device to suspend
+ * @state: target power management state
+ *
+ * Request suspend EH action on the ATA device associated with
+ * @sdev and wait for the operation to complete.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state)
{
struct ata_port *ap = ata_shost_to_port(sdev->host);
- struct ata_device *dev = __ata_scsi_find_dev(ap, sdev);
+ struct ata_device *dev = ata_scsi_find_dev(ap, sdev);
+ unsigned long flags;
+ unsigned int action;
+ int rc = 0;
+
+ if (!dev)
+ goto out;
+
+ spin_lock_irqsave(ap->lock, flags);
+
+ /* wait for the previous resume to complete */
+ while (dev->flags & ATA_DFLAG_SUSPENDED) {
+ spin_unlock_irqrestore(ap->lock, flags);
+ ata_port_wait_eh(ap);
+ spin_lock_irqsave(ap->lock, flags);
+ }
+
+ /* if @sdev is already detached, nothing to do */
+ if (sdev->sdev_state == SDEV_OFFLINE ||
+ sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL)
+ goto out_unlock;
+
+ /* request suspend */
+ action = ATA_EH_SUSPEND;
+ if (state.event != PM_EVENT_SUSPEND)
+ action |= ATA_EH_PM_FREEZE;
+ ap->eh_info.dev_action[dev->devno] |= action;
+ ap->eh_info.flags |= ATA_EHI_QUIET;
+ ata_port_schedule_eh(ap);
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ /* wait for EH to do the job */
+ ata_port_wait_eh(ap);
+
+ spin_lock_irqsave(ap->lock, flags);
+
+ /* If @sdev is still attached but the associated ATA device
+ * isn't suspended, the operation failed.
+ */
+ if (sdev->sdev_state != SDEV_OFFLINE &&
+ sdev->sdev_state != SDEV_CANCEL && sdev->sdev_state != SDEV_DEL &&
+ !(dev->flags & ATA_DFLAG_SUSPENDED))
+ rc = -EIO;
- return ata_device_resume(dev);
+ out_unlock:
+ spin_unlock_irqrestore(ap->lock, flags);
+ out:
+ if (rc == 0)
+ sdev->sdev_gendev.power.power_state = state;
+ return rc;
}
-int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state)
+/**
+ * ata_scsi_device_resume - resume ATA device associated with sdev
+ * @sdev: the SCSI device to resume
+ *
+ * Request resume EH action on the ATA device associated with
+ * @sdev and return immediately. This enables parallel
+ * wakeup/spinup of devices.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0.
+ */
+int ata_scsi_device_resume(struct scsi_device *sdev)
{
struct ata_port *ap = ata_shost_to_port(sdev->host);
- struct ata_device *dev = __ata_scsi_find_dev(ap, sdev);
+ struct ata_device *dev = ata_scsi_find_dev(ap, sdev);
+ struct ata_eh_info *ehi = &ap->eh_info;
+ unsigned long flags;
+ unsigned int action;
+
+ if (!dev)
+ goto out;
+
+ spin_lock_irqsave(ap->lock, flags);
+
+ /* if @sdev is already detached, nothing to do */
+ if (sdev->sdev_state == SDEV_OFFLINE ||
+ sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL)
+ goto out_unlock;
- return ata_device_suspend(dev, state);
+ /* request resume */
+ action = ATA_EH_RESUME;
+ if (sdev->sdev_gendev.power.power_state.event == PM_EVENT_SUSPEND)
+ __ata_ehi_hotplugged(ehi);
+ else
+ action |= ATA_EH_PM_FREEZE | ATA_EH_SOFTRESET;
+ ehi->dev_action[dev->devno] |= action;
+
+ /* We don't want autopsy and verbose EH messages. Disable
+ * those if we're the only device on this link.
+ */
+ if (ata_port_max_devices(ap) == 1)
+ ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
+
+ ata_port_schedule_eh(ap);
+
+ out_unlock:
+ spin_unlock_irqrestore(ap->lock, flags);
+ out:
+ sdev->sdev_gendev.power.power_state = PMSG_ON;
+ return 0;
}
/**
@@ -2930,7 +3039,7 @@ void ata_scsi_hotplug(void *data)
struct ata_port *ap = data;
int i;
- if (ap->flags & ATA_FLAG_UNLOADING) {
+ if (ap->pflags & ATA_PFLAG_UNLOADING) {
DPRINTK("ENTER/EXIT - unloading\n");
return;
}
@@ -3011,6 +3120,7 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
if (dev) {
ap->eh_info.probe_mask |= 1 << dev->devno;
ap->eh_info.action |= ATA_EH_SOFTRESET;
+ ap->eh_info.flags |= ATA_EHI_RESUME_LINK;
} else
rc = -EINVAL;
}
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index f81691fcf17..d44f9aac6b8 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -21,10 +21,12 @@
struct lpfc_sli2_slim;
-#define LPFC_MAX_TARGET 256 /* max targets supported */
-#define LPFC_MAX_DISC_THREADS 64 /* max outstanding discovery els req */
-#define LPFC_MAX_NS_RETRY 3 /* max NameServer retries */
+#define LPFC_MAX_TARGET 256 /* max number of targets supported */
+#define LPFC_MAX_DISC_THREADS 64 /* max outstanding discovery els
+ requests */
+#define LPFC_MAX_NS_RETRY 3 /* Number of retry attempts to contact
+ the NameServer before giving up. */
#define LPFC_DFT_HBA_Q_DEPTH 2048 /* max cmds per hba */
#define LPFC_LC_HBA_Q_DEPTH 1024 /* max cmds per low cost hba */
#define LPFC_LP101_HBA_Q_DEPTH 128 /* max cmds per low cost hba */
@@ -41,7 +43,6 @@ struct lpfc_sli2_slim;
(( (u64)(high)<<16 ) << 16)|( (u64)(low))))
/* Provide maximum configuration definitions. */
#define LPFC_DRVR_TIMEOUT 16 /* driver iocb timeout value in sec */
-#define MAX_FCP_TARGET 256 /* max num of FCP targets supported */
#define FC_MAX_ADPTMSG 64
#define MAX_HBAEVT 32
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index b62a72dfab2..5c68cdd8736 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -219,9 +219,19 @@ lpfc_issue_lip(struct Scsi_Host *host)
return -ENOMEM;
memset((void *)pmboxq, 0, sizeof (LPFC_MBOXQ_t));
- lpfc_init_link(phba, pmboxq, phba->cfg_topology, phba->cfg_link_speed);
+ pmboxq->mb.mbxCommand = MBX_DOWN_LINK;
+ pmboxq->mb.mbxOwner = OWN_HOST;
+
mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
+ if ((mbxstatus == MBX_SUCCESS) && (pmboxq->mb.mbxStatus == 0)) {
+ memset((void *)pmboxq, 0, sizeof (LPFC_MBOXQ_t));
+ lpfc_init_link(phba, pmboxq, phba->cfg_topology,
+ phba->cfg_link_speed);
+ mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq,
+ phba->fc_ratov * 2);
+ }
+
if (mbxstatus == MBX_TIMEOUT)
pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
else
@@ -233,51 +243,53 @@ lpfc_issue_lip(struct Scsi_Host *host)
return 0;
}
-static ssize_t
-lpfc_nport_evt_cnt_show(struct class_device *cdev, char *buf)
+static int
+lpfc_selective_reset(struct lpfc_hba *phba)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
- return snprintf(buf, PAGE_SIZE, "%d\n", phba->nport_event_cnt);
+ struct completion online_compl;
+ int status = 0;
+
+ init_completion(&online_compl);
+ lpfc_workq_post_event(phba, &status, &online_compl,
+ LPFC_EVT_OFFLINE);
+ wait_for_completion(&online_compl);
+
+ if (status != 0)
+ return -EIO;
+
+ init_completion(&online_compl);
+ lpfc_workq_post_event(phba, &status, &online_compl,
+ LPFC_EVT_ONLINE);
+ wait_for_completion(&online_compl);
+
+ if (status != 0)
+ return -EIO;
+
+ return 0;
}
static ssize_t
-lpfc_board_online_show(struct class_device *cdev, char *buf)
+lpfc_issue_reset(struct class_device *cdev, const char *buf, size_t count)
{
struct Scsi_Host *host = class_to_shost(cdev);
struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ int status = -EINVAL;
- if (phba->fc_flag & FC_OFFLINE_MODE)
- return snprintf(buf, PAGE_SIZE, "0\n");
+ if (strncmp(buf, "selective", sizeof("selective") - 1) == 0)
+ status = lpfc_selective_reset(phba);
+
+ if (status == 0)
+ return strlen(buf);
else
- return snprintf(buf, PAGE_SIZE, "1\n");
+ return status;
}
static ssize_t
-lpfc_board_online_store(struct class_device *cdev, const char *buf,
- size_t count)
+lpfc_nport_evt_cnt_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
- struct completion online_compl;
- int val=0, status=0;
-
- if (sscanf(buf, "%d", &val) != 1)
- return -EINVAL;
-
- init_completion(&online_compl);
-
- if (val)
- lpfc_workq_post_event(phba, &status, &online_compl,
- LPFC_EVT_ONLINE);
- else
- lpfc_workq_post_event(phba, &status, &online_compl,
- LPFC_EVT_OFFLINE);
- wait_for_completion(&online_compl);
- if (!status)
- return strlen(buf);
- else
- return -EIO;
+ return snprintf(buf, PAGE_SIZE, "%d\n", phba->nport_event_cnt);
}
static ssize_t
@@ -532,10 +544,9 @@ static CLASS_DEVICE_ATTR(lpfc_drvr_version, S_IRUGO, lpfc_drvr_version_show,
NULL);
static CLASS_DEVICE_ATTR(management_version, S_IRUGO, management_version_show,
NULL);
-static CLASS_DEVICE_ATTR(board_online, S_IRUGO | S_IWUSR,
- lpfc_board_online_show, lpfc_board_online_store);
static CLASS_DEVICE_ATTR(board_mode, S_IRUGO | S_IWUSR,
lpfc_board_mode_show, lpfc_board_mode_store);
+static CLASS_DEVICE_ATTR(issue_reset, S_IWUSR, NULL, lpfc_issue_reset);
static int lpfc_poll = 0;
module_param(lpfc_poll, int, 0);
@@ -695,12 +706,12 @@ LPFC_ATTR(discovery_threads, 32, 1, 64, "Maximum number of ELS commands "
"during discovery");
/*
-# lpfc_max_luns: maximum number of LUNs per target driver will support
-# Value range is [1,32768]. Default value is 256.
-# NOTE: The SCSI layer will scan each target for this many luns
+# lpfc_max_luns: maximum allowed LUN.
+# Value range is [0,65535]. Default value is 255.
+# NOTE: The SCSI layer might probe all allowed LUN on some old targets.
*/
-LPFC_ATTR_R(max_luns, 256, 1, 32768,
- "Maximum number of LUNs per target driver will support");
+LPFC_ATTR_R(max_luns, 255, 0, 65535,
+ "Maximum allowed LUN");
/*
# lpfc_poll_tmo: .Milliseconds driver will wait between polling FCP ring.
@@ -739,8 +750,8 @@ struct class_device_attribute *lpfc_host_attrs[] = {
&class_device_attr_lpfc_max_luns,
&class_device_attr_nport_evt_cnt,
&class_device_attr_management_version,
- &class_device_attr_board_online,
&class_device_attr_board_mode,
+ &class_device_attr_issue_reset,
&class_device_attr_lpfc_poll,
&class_device_attr_lpfc_poll_tmo,
NULL,
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index ee22173fce4..517e9e4dd46 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -147,6 +147,7 @@ int lpfc_sli_hba_setup(struct lpfc_hba *);
int lpfc_sli_hba_down(struct lpfc_hba *);
int lpfc_sli_issue_mbox(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t);
int lpfc_sli_handle_mb_event(struct lpfc_hba *);
+int lpfc_sli_flush_mbox_queue(struct lpfc_hba *);
int lpfc_sli_handle_slow_ring_event(struct lpfc_hba *,
struct lpfc_sli_ring *, uint32_t);
void lpfc_sli_def_mbox_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *);
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 4126fd87956..b89f6cb641e 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -648,33 +648,32 @@ lpfc_more_plogi(struct lpfc_hba * phba)
}
static struct lpfc_nodelist *
-lpfc_plogi_confirm_nport(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
+lpfc_plogi_confirm_nport(struct lpfc_hba * phba, struct lpfc_dmabuf *prsp,
struct lpfc_nodelist *ndlp)
{
struct lpfc_nodelist *new_ndlp;
- struct lpfc_dmabuf *pcmd, *prsp;
uint32_t *lp;
struct serv_parm *sp;
uint8_t name[sizeof (struct lpfc_name)];
uint32_t rc;
- pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
- prsp = (struct lpfc_dmabuf *) pcmd->list.next;
lp = (uint32_t *) prsp->virt;
sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
+ memset(name, 0, sizeof (struct lpfc_name));
/* Now we to find out if the NPort we are logging into, matches the WWPN
* we have for that ndlp. If not, we have some work to do.
*/
new_ndlp = lpfc_findnode_wwpn(phba, NLP_SEARCH_ALL, &sp->portName);
- memset(name, 0, sizeof (struct lpfc_name));
- rc = memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name));
- if (!rc || (new_ndlp == ndlp)) {
+ if (new_ndlp == ndlp)
return ndlp;
- }
if (!new_ndlp) {
+ rc =
+ memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name));
+ if (!rc)
+ return ndlp;
new_ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_ATOMIC);
if (!new_ndlp)
return ndlp;
@@ -683,17 +682,21 @@ lpfc_plogi_confirm_nport(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
}
lpfc_unreg_rpi(phba, new_ndlp);
- new_ndlp->nlp_prev_state = ndlp->nlp_state;
new_ndlp->nlp_DID = ndlp->nlp_DID;
- new_ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
- lpfc_nlp_list(phba, new_ndlp, NLP_PLOGI_LIST);
+ new_ndlp->nlp_prev_state = ndlp->nlp_prev_state;
+ new_ndlp->nlp_state = ndlp->nlp_state;
+ lpfc_nlp_list(phba, new_ndlp, ndlp->nlp_flag & NLP_LIST_MASK);
/* Move this back to NPR list */
- lpfc_unreg_rpi(phba, ndlp);
- ndlp->nlp_DID = 0; /* Two ndlps cannot have the same did */
- ndlp->nlp_state = NLP_STE_NPR_NODE;
- lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
-
+ if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0) {
+ lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+ }
+ else {
+ lpfc_unreg_rpi(phba, ndlp);
+ ndlp->nlp_DID = 0; /* Two ndlps cannot have the same did */
+ ndlp->nlp_state = NLP_STE_NPR_NODE;
+ lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+ }
return new_ndlp;
}
@@ -703,6 +706,7 @@ lpfc_cmpl_els_plogi(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
{
IOCB_t *irsp;
struct lpfc_nodelist *ndlp;
+ struct lpfc_dmabuf *prsp;
int disc, rc, did, type;
@@ -769,7 +773,10 @@ lpfc_cmpl_els_plogi(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
}
} else {
/* Good status, call state machine */
- ndlp = lpfc_plogi_confirm_nport(phba, cmdiocb, ndlp);
+ prsp = list_entry(((struct lpfc_dmabuf *)
+ cmdiocb->context2)->list.next,
+ struct lpfc_dmabuf, list);
+ ndlp = lpfc_plogi_confirm_nport(phba, prsp, ndlp);
rc = lpfc_disc_state_machine(phba, ndlp, cmdiocb,
NLP_EVT_CMPL_PLOGI);
}
@@ -3282,10 +3289,9 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba)
} else
lpfc_sli_release_iocbq(phba, piocb);
}
- if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt) {
- phba->els_tmofunc.expires = jiffies + HZ * timeout;
- add_timer(&phba->els_tmofunc);
- }
+ if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt)
+ mod_timer(&phba->els_tmofunc, jiffies + HZ * timeout);
+
spin_unlock_irq(phba->host->host_lock);
}
@@ -3442,6 +3448,8 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) {
ndlp->nlp_type |= NLP_FABRIC;
}
+ ndlp->nlp_state = NLP_STE_UNUSED_NODE;
+ lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST);
}
phba->fc_stat.elsRcvFrame++;
@@ -3463,13 +3471,14 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
rjt_err = 1;
break;
}
+ ndlp = lpfc_plogi_confirm_nport(phba, mp, ndlp);
lpfc_disc_state_machine(phba, ndlp, elsiocb, NLP_EVT_RCV_PLOGI);
break;
case ELS_CMD_FLOGI:
phba->fc_stat.elsRcvFLOGI++;
lpfc_els_rcv_flogi(phba, elsiocb, ndlp, newnode);
if (newnode) {
- mempool_free( ndlp, phba->nlp_mem_pool);
+ lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
}
break;
case ELS_CMD_LOGO:
@@ -3492,7 +3501,7 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
phba->fc_stat.elsRcvRSCN++;
lpfc_els_rcv_rscn(phba, elsiocb, ndlp, newnode);
if (newnode) {
- mempool_free( ndlp, phba->nlp_mem_pool);
+ lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
}
break;
case ELS_CMD_ADISC:
@@ -3535,28 +3544,28 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
phba->fc_stat.elsRcvLIRR++;
lpfc_els_rcv_lirr(phba, elsiocb, ndlp);
if (newnode) {
- mempool_free( ndlp, phba->nlp_mem_pool);
+ lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
}
break;
case ELS_CMD_RPS:
phba->fc_stat.elsRcvRPS++;
lpfc_els_rcv_rps(phba, elsiocb, ndlp);
if (newnode) {
- mempool_free( ndlp, phba->nlp_mem_pool);
+ lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
}
break;
case ELS_CMD_RPL:
phba->fc_stat.elsRcvRPL++;
lpfc_els_rcv_rpl(phba, elsiocb, ndlp);
if (newnode) {
- mempool_free( ndlp, phba->nlp_mem_pool);
+ lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
}
break;
case ELS_CMD_RNID:
phba->fc_stat.elsRcvRNID++;
lpfc_els_rcv_rnid(phba, elsiocb, ndlp);
if (newnode) {
- mempool_free( ndlp, phba->nlp_mem_pool);
+ lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
}
break;
default:
@@ -3568,7 +3577,7 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
"%d:0115 Unknown ELS command x%x received from "
"NPORT x%x\n", phba->brd_no, cmd, did);
if (newnode) {
- mempool_free( ndlp, phba->nlp_mem_pool);
+ lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
}
break;
}
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index adb086009ae..4d6cf990c4f 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -1084,7 +1084,7 @@ lpfc_register_remote_port(struct lpfc_hba * phba,
fc_remote_port_rolechg(rport, rport_ids.roles);
if ((rport->scsi_target_id != -1) &&
- (rport->scsi_target_id < MAX_FCP_TARGET)) {
+ (rport->scsi_target_id < LPFC_MAX_TARGET)) {
ndlp->nlp_sid = rport->scsi_target_id;
}
@@ -1313,7 +1313,7 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list)
if ((rport_add == mapped) &&
((!nlp->rport) ||
(nlp->rport->scsi_target_id == -1) ||
- (nlp->rport->scsi_target_id >= MAX_FCP_TARGET))) {
+ (nlp->rport->scsi_target_id >= LPFC_MAX_TARGET))) {
nlp->nlp_state = NLP_STE_UNMAPPED_NODE;
spin_lock_irq(phba->host->host_lock);
nlp->nlp_flag |= NLP_TGT_NO_SCSIID;
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 81755a3f7c6..ef47b824cbe 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -71,6 +71,7 @@ lpfc_config_port_prep(struct lpfc_hba * phba)
uint16_t offset = 0;
static char licensed[56] =
"key unlock for use with gnu public licensed code only\0";
+ static int init_key = 1;
pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!pmb) {
@@ -82,10 +83,13 @@ lpfc_config_port_prep(struct lpfc_hba * phba)
phba->hba_state = LPFC_INIT_MBX_CMDS;
if (lpfc_is_LC_HBA(phba->pcidev->device)) {
- uint32_t *ptext = (uint32_t *) licensed;
+ if (init_key) {
+ uint32_t *ptext = (uint32_t *) licensed;
- for (i = 0; i < 56; i += sizeof (uint32_t), ptext++)
- *ptext = cpu_to_be32(*ptext);
+ for (i = 0; i < 56; i += sizeof (uint32_t), ptext++)
+ *ptext = cpu_to_be32(*ptext);
+ init_key = 0;
+ }
lpfc_read_nv(phba, pmb);
memset((char*)mb->un.varRDnvp.rsvd3, 0,
@@ -405,19 +409,26 @@ lpfc_config_port_post(struct lpfc_hba * phba)
}
/* MBOX buffer will be freed in mbox compl */
- i = 0;
+ return (0);
+}
+
+static int
+lpfc_discovery_wait(struct lpfc_hba *phba)
+{
+ int i = 0;
+
while ((phba->hba_state != LPFC_HBA_READY) ||
(phba->num_disc_nodes) || (phba->fc_prli_sent) ||
((phba->fc_map_cnt == 0) && (i<2)) ||
- (psli->sli_flag & LPFC_SLI_MBOX_ACTIVE)) {
+ (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE)) {
/* Check every second for 30 retries. */
i++;
if (i > 30) {
- break;
+ return -ETIMEDOUT;
}
if ((i >= 15) && (phba->hba_state <= LPFC_LINK_DOWN)) {
/* The link is down. Set linkdown timeout */
- break;
+ return -ETIMEDOUT;
}
/* Delay for 1 second to give discovery time to complete. */
@@ -425,12 +436,7 @@ lpfc_config_port_post(struct lpfc_hba * phba)
}
- /* Since num_disc_nodes keys off of PLOGI, delay a bit to let
- * any potential PRLIs to flush thru the SLI sub-system.
- */
- msleep(50);
-
- return (0);
+ return 0;
}
/************************************************************************/
@@ -1339,7 +1345,8 @@ lpfc_offline(struct lpfc_hba * phba)
struct lpfc_sli_ring *pring;
struct lpfc_sli *psli;
unsigned long iflag;
- int i = 0;
+ int i;
+ int cnt = 0;
if (!phba)
return 0;
@@ -1348,17 +1355,27 @@ lpfc_offline(struct lpfc_hba * phba)
return 0;
psli = &phba->sli;
- pring = &psli->ring[psli->fcp_ring];
lpfc_linkdown(phba);
+ lpfc_sli_flush_mbox_queue(phba);
- /* The linkdown event takes 30 seconds to timeout. */
- while (pring->txcmplq_cnt) {
- mdelay(10);
- if (i++ > 3000)
- break;
+ for (i = 0; i < psli->num_rings; i++) {
+ pring = &psli->ring[i];
+ /* The linkdown event takes 30 seconds to timeout. */
+ while (pring->txcmplq_cnt) {
+ mdelay(10);
+ if (cnt++ > 3000) {
+ lpfc_printf_log(phba,
+ KERN_WARNING, LOG_INIT,
+ "%d:0466 Outstanding IO when "
+ "bringing Adapter offline\n",
+ phba->brd_no);
+ break;
+ }
+ }
}
+
/* stop all timers associated with this hba */
lpfc_stop_timer(phba);
phba->work_hba_events = 0;
@@ -1639,6 +1656,8 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
goto out_free_irq;
}
+ lpfc_discovery_wait(phba);
+
if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
spin_lock_irq(phba->host->host_lock);
lpfc_poll_start_timer(phba);
diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c
index 07017658ac5..066292d3995 100644
--- a/drivers/scsi/lpfc/lpfc_mem.c
+++ b/drivers/scsi/lpfc/lpfc_mem.c
@@ -133,6 +133,11 @@ lpfc_mem_free(struct lpfc_hba * phba)
pci_pool_destroy(phba->lpfc_scsi_dma_buf_pool);
pci_pool_destroy(phba->lpfc_mbuf_pool);
+
+ /* Free the iocb lookup array */
+ kfree(psli->iocbq_lookup);
+ psli->iocbq_lookup = NULL;
+
}
void *
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index 27d60ad897c..bd0b0e293d6 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -1110,6 +1110,17 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_hba * phba,
phba->brd_no,
did, mb->mbxStatus, phba->hba_state);
+ /*
+ * If RegLogin failed due to lack of HBA resources do not
+ * retry discovery.
+ */
+ if (mb->mbxStatus == MBXERR_RPI_FULL) {
+ ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE;
+ ndlp->nlp_state = NLP_STE_UNUSED_NODE;
+ lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST);
+ return ndlp->nlp_state;
+ }
+
/* Put ndlp in npr list set plogi timer for 1 sec */
mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
spin_lock_irq(phba->host->host_lock);
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index aea1ee472f3..a760a44173d 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -153,22 +153,6 @@ static void
lpfc_release_scsi_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * psb)
{
unsigned long iflag = 0;
- /*
- * There are only two special cases to consider. (1) the scsi command
- * requested scatter-gather usage or (2) the scsi command allocated
- * a request buffer, but did not request use_sg. There is a third
- * case, but it does not require resource deallocation.
- */
- if ((psb->seg_cnt > 0) && (psb->pCmd->use_sg)) {
- dma_unmap_sg(&phba->pcidev->dev, psb->pCmd->request_buffer,
- psb->seg_cnt, psb->pCmd->sc_data_direction);
- } else {
- if ((psb->nonsg_phys) && (psb->pCmd->request_bufflen)) {
- dma_unmap_single(&phba->pcidev->dev, psb->nonsg_phys,
- psb->pCmd->request_bufflen,
- psb->pCmd->sc_data_direction);
- }
- }
spin_lock_irqsave(&phba->scsi_buf_list_lock, iflag);
psb->pCmd = NULL;
@@ -282,6 +266,27 @@ lpfc_scsi_prep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * lpfc_cmd)
}
static void
+lpfc_scsi_unprep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * psb)
+{
+ /*
+ * There are only two special cases to consider. (1) the scsi command
+ * requested scatter-gather usage or (2) the scsi command allocated
+ * a request buffer, but did not request use_sg. There is a third
+ * case, but it does not require resource deallocation.
+ */
+ if ((psb->seg_cnt > 0) && (psb->pCmd->use_sg)) {
+ dma_unmap_sg(&phba->pcidev->dev, psb->pCmd->request_buffer,
+ psb->seg_cnt, psb->pCmd->sc_data_direction);
+ } else {
+ if ((psb->nonsg_phys) && (psb->pCmd->request_bufflen)) {
+ dma_unmap_single(&phba->pcidev->dev, psb->nonsg_phys,
+ psb->pCmd->request_bufflen,
+ psb->pCmd->sc_data_direction);
+ }
+ }
+}
+
+static void
lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd)
{
struct scsi_cmnd *cmnd = lpfc_cmd->pCmd;
@@ -454,6 +459,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
cmd->scsi_done(cmd);
if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) {
+ lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd);
lpfc_release_scsi_buf(phba, lpfc_cmd);
return;
}
@@ -511,6 +517,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
}
}
+ lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd);
lpfc_release_scsi_buf(phba, lpfc_cmd);
}
@@ -609,6 +616,7 @@ lpfc_scsi_prep_cmnd(struct lpfc_hba * phba, struct lpfc_scsi_buf * lpfc_cmd,
static int
lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_hba *phba,
struct lpfc_scsi_buf *lpfc_cmd,
+ unsigned int lun,
uint8_t task_mgmt_cmd)
{
struct lpfc_sli *psli;
@@ -627,8 +635,7 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_hba *phba,
piocb = &piocbq->iocb;
fcp_cmnd = lpfc_cmd->fcp_cmnd;
- int_to_scsilun(lpfc_cmd->pCmd->device->lun,
- &lpfc_cmd->fcp_cmnd->fcp_lun);
+ int_to_scsilun(lun, &lpfc_cmd->fcp_cmnd->fcp_lun);
fcp_cmnd->fcpCntl2 = task_mgmt_cmd;
piocb->ulpCommand = CMD_FCP_ICMND64_CR;
@@ -655,14 +662,16 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_hba *phba,
static int
lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba,
- unsigned tgt_id, struct lpfc_rport_data *rdata)
+ unsigned tgt_id, unsigned int lun,
+ struct lpfc_rport_data *rdata)
{
struct lpfc_iocbq *iocbq;
struct lpfc_iocbq *iocbqrsp;
int ret;
lpfc_cmd->rdata = rdata;
- ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, FCP_TARGET_RESET);
+ ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, lun,
+ FCP_TARGET_RESET);
if (!ret)
return FAILED;
@@ -822,6 +831,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
return 0;
out_host_busy_free_buf:
+ lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd);
lpfc_release_scsi_buf(phba, lpfc_cmd);
out_host_busy:
return SCSI_MLQUEUE_HOST_BUSY;
@@ -969,12 +979,12 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
if (lpfc_cmd == NULL)
goto out;
- lpfc_cmd->pCmd = cmnd;
lpfc_cmd->timeout = 60;
lpfc_cmd->scsi_hba = phba;
lpfc_cmd->rdata = rdata;
- ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, FCP_LUN_RESET);
+ ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, cmnd->device->lun,
+ FCP_LUN_RESET);
if (!ret)
goto out_free_scsi_buf;
@@ -1001,7 +1011,6 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
cmd_status = iocbqrsp->iocb.ulpStatus;
lpfc_sli_release_iocbq(phba, iocbqrsp);
- lpfc_release_scsi_buf(phba, lpfc_cmd);
/*
* All outstanding txcmplq I/Os should have been aborted by the device.
@@ -1040,6 +1049,8 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
}
out_free_scsi_buf:
+ lpfc_release_scsi_buf(phba, lpfc_cmd);
+
lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
"%d:0713 SCSI layer issued LUN reset (%d, %d) "
"Data: x%x x%x x%x\n",
@@ -1070,7 +1081,6 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
/* The lpfc_cmd storage is reused. Set all loop invariants. */
lpfc_cmd->timeout = 60;
- lpfc_cmd->pCmd = cmnd;
lpfc_cmd->scsi_hba = phba;
/*
@@ -1078,7 +1088,7 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
* targets known to the driver. Should any target reset
* fail, this routine returns failure to the midlayer.
*/
- for (i = 0; i < MAX_FCP_TARGET; i++) {
+ for (i = 0; i < LPFC_MAX_TARGET; i++) {
/* Search the mapped list for this target ID */
match = 0;
list_for_each_entry(ndlp, &phba->fc_nlpmap_list, nlp_listp) {
@@ -1090,8 +1100,8 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
if (!match)
continue;
- ret = lpfc_scsi_tgt_reset(lpfc_cmd, phba,
- i, ndlp->rport->dd_data);
+ ret = lpfc_scsi_tgt_reset(lpfc_cmd, phba, i, cmnd->device->lun,
+ ndlp->rport->dd_data);
if (ret != SUCCESS) {
lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
"%d:0713 Bus Reset on target %d failed\n",
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index bb69a7a1ec5..350a625fa22 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -191,35 +191,12 @@ static int
lpfc_sli_ringtxcmpl_put(struct lpfc_hba * phba,
struct lpfc_sli_ring * pring, struct lpfc_iocbq * piocb)
{
- uint16_t iotag;
-
list_add_tail(&piocb->list, &pring->txcmplq);
pring->txcmplq_cnt++;
if (unlikely(pring->ringno == LPFC_ELS_RING))
mod_timer(&phba->els_tmofunc,
jiffies + HZ * (phba->fc_ratov << 1));
- if (pring->fast_lookup) {
- /* Setup fast lookup based on iotag for completion */
- iotag = piocb->iocb.ulpIoTag;
- if (iotag && (iotag < pring->fast_iotag))
- *(pring->fast_lookup + iotag) = piocb;
- else {
-
- /* Cmd ring <ringno> put: iotag <iotag> greater then
- configured max <fast_iotag> wd0 <icmd> */
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_SLI,
- "%d:0316 Cmd ring %d put: iotag x%x "
- "greater then configured max x%x "
- "wd0 x%x\n",
- phba->brd_no,
- pring->ringno, iotag,
- pring->fast_iotag,
- *(((uint32_t *)(&piocb->iocb)) + 7));
- }
- }
return (0);
}
@@ -601,7 +578,7 @@ lpfc_sli_handle_mb_event(struct lpfc_hba * phba)
/* Stray Mailbox Interrupt, mbxCommand <cmd> mbxStatus
<status> */
lpfc_printf_log(phba,
- KERN_ERR,
+ KERN_WARNING,
LOG_MBOX | LOG_SLI,
"%d:0304 Stray Mailbox Interrupt "
"mbxCommand x%x mbxStatus x%x\n",
@@ -1570,8 +1547,8 @@ lpfc_sli_brdready(struct lpfc_hba * phba, uint32_t mask)
void lpfc_reset_barrier(struct lpfc_hba * phba)
{
- uint32_t * resp_buf;
- uint32_t * mbox_buf;
+ uint32_t __iomem *resp_buf;
+ uint32_t __iomem *mbox_buf;
volatile uint32_t mbox;
uint32_t hc_copy;
int i;
@@ -1587,7 +1564,7 @@ void lpfc_reset_barrier(struct lpfc_hba * phba)
* Tell the other part of the chip to suspend temporarily all
* its DMA activity.
*/
- resp_buf = (uint32_t *)phba->MBslimaddr;
+ resp_buf = phba->MBslimaddr;
/* Disable the error attention */
hc_copy = readl(phba->HCregaddr);
@@ -1605,7 +1582,7 @@ void lpfc_reset_barrier(struct lpfc_hba * phba)
((MAILBOX_t *)&mbox)->mbxOwner = OWN_CHIP;
writel(BARRIER_TEST_PATTERN, (resp_buf + 1));
- mbox_buf = (uint32_t *)phba->MBslimaddr;
+ mbox_buf = phba->MBslimaddr;
writel(mbox, mbox_buf);
for (i = 0;
@@ -1805,7 +1782,7 @@ lpfc_sli_brdrestart(struct lpfc_hba * phba)
skip_post = 0;
word0 = 0; /* This is really setting up word1 */
}
- to_slim = (uint8_t *) phba->MBslimaddr + sizeof (uint32_t);
+ to_slim = phba->MBslimaddr + sizeof (uint32_t);
writel(*(uint32_t *) mb, to_slim);
readl(to_slim); /* flush */
@@ -2659,8 +2636,6 @@ lpfc_sli_hba_down(struct lpfc_hba * phba)
INIT_LIST_HEAD(&(pring->txq));
- kfree(pring->fast_lookup);
- pring->fast_lookup = NULL;
}
spin_unlock_irqrestore(phba->host->host_lock, flags);
@@ -3110,6 +3085,24 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq,
return retval;
}
+int
+lpfc_sli_flush_mbox_queue(struct lpfc_hba * phba)
+{
+ int i = 0;
+
+ while (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE && !phba->stopped) {
+ if (i++ > LPFC_MBOX_TMO * 1000)
+ return 1;
+
+ if (lpfc_sli_handle_mb_event(phba) == 0)
+ i = 0;
+
+ msleep(1);
+ }
+
+ return (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE) ? 1 : 0;
+}
+
irqreturn_t
lpfc_intr_handler(int irq, void *dev_id, struct pt_regs * regs)
{
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
index a52d6c6cf08..d8ef0d2894d 100644
--- a/drivers/scsi/lpfc/lpfc_sli.h
+++ b/drivers/scsi/lpfc/lpfc_sli.h
@@ -135,8 +135,6 @@ struct lpfc_sli_ring {
uint32_t fast_iotag; /* max fastlookup based iotag */
uint32_t iotag_ctr; /* keeps track of the next iotag to use */
uint32_t iotag_max; /* max iotag value to use */
- struct lpfc_iocbq ** fast_lookup; /* array of IOCB ptrs indexed by
- iotag */
struct list_head txq;
uint16_t txq_cnt; /* current length of queue */
uint16_t txq_max; /* max length */
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index 6b737568b83..10e89c6ae82 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -18,7 +18,7 @@
* included with this package. *
*******************************************************************/
-#define LPFC_DRIVER_VERSION "8.1.6"
+#define LPFC_DRIVER_VERSION "8.1.7"
#define LPFC_DRIVER_NAME "lpfc"
diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c
index 93edaa8696c..89ef34df5a1 100644
--- a/drivers/scsi/mac53c94.c
+++ b/drivers/scsi/mac53c94.c
@@ -378,7 +378,7 @@ static void set_dma_cmds(struct fsc_state *state, struct scsi_cmnd *cmd)
int nseg;
total = 0;
- scl = (struct scatterlist *) cmd->buffer;
+ scl = (struct scatterlist *) cmd->request_buffer;
nseg = pci_map_sg(state->pdev, scl, cmd->use_sg,
cmd->sc_data_direction);
for (i = 0; i < nseg; ++i) {
diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c
index c88717727be..5572981a9f9 100644
--- a/drivers/scsi/mesh.c
+++ b/drivers/scsi/mesh.c
@@ -1268,7 +1268,7 @@ static void set_dma_cmds(struct mesh_state *ms, struct scsi_cmnd *cmd)
if (cmd->use_sg > 0) {
int nseg;
total = 0;
- scl = (struct scatterlist *) cmd->buffer;
+ scl = (struct scatterlist *) cmd->request_buffer;
off = ms->data_ptr;
nseg = pci_map_sg(ms->pdev, scl, cmd->use_sg,
cmd->sc_data_direction);
diff --git a/drivers/scsi/pluto.c b/drivers/scsi/pluto.c
index 7abf64d1bfc..0bd9c60e645 100644
--- a/drivers/scsi/pluto.c
+++ b/drivers/scsi/pluto.c
@@ -169,8 +169,6 @@ int __init pluto_detect(struct scsi_host_template *tpnt)
SCpnt->request->rq_status = RQ_SCSI_BUSY;
SCpnt->done = pluto_detect_done;
- SCpnt->bufflen = 256;
- SCpnt->buffer = fcs[i].inquiry;
SCpnt->request_bufflen = 256;
SCpnt->request_buffer = fcs[i].inquiry;
PLD(("set up %d %08lx\n", i, (long)SCpnt))
diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
index 69e0551a81d..5b2f0741a55 100644
--- a/drivers/scsi/qlogicpti.c
+++ b/drivers/scsi/qlogicpti.c
@@ -874,7 +874,7 @@ static inline int load_cmd(struct scsi_cmnd *Cmnd, struct Command_Entry *cmd,
if (Cmnd->use_sg) {
int sg_count;
- sg = (struct scatterlist *) Cmnd->buffer;
+ sg = (struct scatterlist *) Cmnd->request_buffer;
sg_count = sbus_map_sg(qpti->sdev, sg, Cmnd->use_sg, Cmnd->sc_data_direction);
ds = cmd->dataseg;
@@ -1278,7 +1278,7 @@ static struct scsi_cmnd *qlogicpti_intr_handler(struct qlogicpti *qpti)
if (Cmnd->use_sg) {
sbus_unmap_sg(qpti->sdev,
- (struct scatterlist *)Cmnd->buffer,
+ (struct scatterlist *)Cmnd->request_buffer,
Cmnd->use_sg,
Cmnd->sc_data_direction);
} else {
diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c
index 64631bd3895..4776f4e5583 100644
--- a/drivers/scsi/sata_promise.c
+++ b/drivers/scsi/sata_promise.c
@@ -269,8 +269,15 @@ static const struct pci_device_id pdc_ata_pci_tbl[] = {
{ PCI_VENDOR_ID_PROMISE, 0x6629, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
board_20619 },
+/* TODO: remove all associated board_20771 code, as it completely
+ * duplicates board_2037x code, unless reason for separation can be
+ * divined.
+ */
+#if 0
{ PCI_VENDOR_ID_PROMISE, 0x3570, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
board_20771 },
+#endif
+
{ } /* terminate list */
};
diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c
index 7aabb45c35e..d0a85073ebf 100644
--- a/drivers/scsi/sata_sil.c
+++ b/drivers/scsi/sata_sil.c
@@ -109,6 +109,7 @@ enum {
};
static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static int sil_pci_device_resume(struct pci_dev *pdev);
static void sil_dev_config(struct ata_port *ap, struct ata_device *dev);
static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg);
static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
@@ -160,6 +161,8 @@ static struct pci_driver sil_pci_driver = {
.id_table = sil_pci_tbl,
.probe = sil_init_one,
.remove = ata_pci_remove_one,
+ .suspend = ata_pci_device_suspend,
+ .resume = sil_pci_device_resume,
};
static struct scsi_host_template sil_sht = {
@@ -178,6 +181,8 @@ static struct scsi_host_template sil_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+ .suspend = ata_scsi_device_suspend,
+ .resume = ata_scsi_device_resume,
};
static const struct ata_port_operations sil_ops = {
@@ -370,7 +375,7 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
* during hardreset makes controllers with broken SIEN
* repeat probing needlessly.
*/
- if (!(ap->flags & ATA_FLAG_FROZEN)) {
+ if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
ata_ehi_hotplugged(&ap->eh_info);
ap->eh_info.serror |= serror;
}
@@ -561,6 +566,52 @@ static void sil_dev_config(struct ata_port *ap, struct ata_device *dev)
}
}
+static void sil_init_controller(struct pci_dev *pdev,
+ int n_ports, unsigned long host_flags,
+ void __iomem *mmio_base)
+{
+ u8 cls;
+ u32 tmp;
+ int i;
+
+ /* Initialize FIFO PCI bus arbitration */
+ cls = sil_get_device_cache_line(pdev);
+ if (cls) {
+ cls >>= 3;
+ cls++; /* cls = (line_size/8)+1 */
+ for (i = 0; i < n_ports; i++)
+ writew(cls << 8 | cls,
+ mmio_base + sil_port[i].fifo_cfg);
+ } else
+ dev_printk(KERN_WARNING, &pdev->dev,
+ "cache line size not set. Driver may not function\n");
+
+ /* Apply R_ERR on DMA activate FIS errata workaround */
+ if (host_flags & SIL_FLAG_RERR_ON_DMA_ACT) {
+ int cnt;
+
+ for (i = 0, cnt = 0; i < n_ports; i++) {
+ tmp = readl(mmio_base + sil_port[i].sfis_cfg);
+ if ((tmp & 0x3) != 0x01)
+ continue;
+ if (!cnt)
+ dev_printk(KERN_INFO, &pdev->dev,
+ "Applying R_ERR on DMA activate "
+ "FIS errata fix\n");
+ writel(tmp & ~0x3, mmio_base + sil_port[i].sfis_cfg);
+ cnt++;
+ }
+ }
+
+ if (n_ports == 4) {
+ /* flip the magic "make 4 ports work" bit */
+ tmp = readl(mmio_base + sil_port[2].bmdma);
+ if ((tmp & SIL_INTR_STEERING) == 0)
+ writel(tmp | SIL_INTR_STEERING,
+ mmio_base + sil_port[2].bmdma);
+ }
+}
+
static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
@@ -570,8 +621,6 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
int rc;
unsigned int i;
int pci_dev_busy = 0;
- u32 tmp;
- u8 cls;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
@@ -630,42 +679,8 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
ata_std_ports(&probe_ent->port[i]);
}
- /* Initialize FIFO PCI bus arbitration */
- cls = sil_get_device_cache_line(pdev);
- if (cls) {
- cls >>= 3;
- cls++; /* cls = (line_size/8)+1 */
- for (i = 0; i < probe_ent->n_ports; i++)
- writew(cls << 8 | cls,
- mmio_base + sil_port[i].fifo_cfg);
- } else
- dev_printk(KERN_WARNING, &pdev->dev,
- "cache line size not set. Driver may not function\n");
-
- /* Apply R_ERR on DMA activate FIS errata workaround */
- if (probe_ent->host_flags & SIL_FLAG_RERR_ON_DMA_ACT) {
- int cnt;
-
- for (i = 0, cnt = 0; i < probe_ent->n_ports; i++) {
- tmp = readl(mmio_base + sil_port[i].sfis_cfg);
- if ((tmp & 0x3) != 0x01)
- continue;
- if (!cnt)
- dev_printk(KERN_INFO, &pdev->dev,
- "Applying R_ERR on DMA activate "
- "FIS errata fix\n");
- writel(tmp & ~0x3, mmio_base + sil_port[i].sfis_cfg);
- cnt++;
- }
- }
-
- if (ent->driver_data == sil_3114) {
- /* flip the magic "make 4 ports work" bit */
- tmp = readl(mmio_base + sil_port[2].bmdma);
- if ((tmp & SIL_INTR_STEERING) == 0)
- writel(tmp | SIL_INTR_STEERING,
- mmio_base + sil_port[2].bmdma);
- }
+ sil_init_controller(pdev, probe_ent->n_ports, probe_ent->host_flags,
+ mmio_base);
pci_set_master(pdev);
@@ -685,6 +700,18 @@ err_out:
return rc;
}
+static int sil_pci_device_resume(struct pci_dev *pdev)
+{
+ struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev);
+
+ ata_pci_device_do_resume(pdev);
+ sil_init_controller(pdev, host_set->n_ports, host_set->ports[0]->flags,
+ host_set->mmio_base);
+ ata_host_set_resume(host_set);
+
+ return 0;
+}
+
static int __init sil_init(void)
{
return pci_module_init(&sil_pci_driver);
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c
index 07a1c6a8a41..2e0f4a4076a 100644
--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/scsi/sata_sil24.c
@@ -92,6 +92,7 @@ enum {
HOST_CTRL_STOP = (1 << 18), /* latched PCI STOP */
HOST_CTRL_DEVSEL = (1 << 19), /* latched PCI DEVSEL */
HOST_CTRL_REQ64 = (1 << 20), /* latched PCI REQ64 */
+ HOST_CTRL_GLOBAL_RST = (1 << 31), /* global reset */
/*
* Port registers
@@ -338,6 +339,7 @@ static int sil24_port_start(struct ata_port *ap);
static void sil24_port_stop(struct ata_port *ap);
static void sil24_host_stop(struct ata_host_set *host_set);
static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
+static int sil24_pci_device_resume(struct pci_dev *pdev);
static const struct pci_device_id sil24_pci_tbl[] = {
{ 0x1095, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 },
@@ -353,6 +355,8 @@ static struct pci_driver sil24_pci_driver = {
.id_table = sil24_pci_tbl,
.probe = sil24_init_one,
.remove = ata_pci_remove_one, /* safe? */
+ .suspend = ata_pci_device_suspend,
+ .resume = sil24_pci_device_resume,
};
static struct scsi_host_template sil24_sht = {
@@ -372,6 +376,8 @@ static struct scsi_host_template sil24_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+ .suspend = ata_scsi_device_suspend,
+ .resume = ata_scsi_device_resume,
};
static const struct ata_port_operations sil24_ops = {
@@ -607,7 +613,7 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class)
/* SStatus oscillates between zero and valid status after
* DEV_RST, debounce it.
*/
- rc = sata_phy_debounce(ap, sata_deb_timing_before_fsrst);
+ rc = sata_phy_debounce(ap, sata_deb_timing_long);
if (rc) {
reason = "PHY debouncing failed";
goto err;
@@ -988,6 +994,64 @@ static void sil24_host_stop(struct ata_host_set *host_set)
kfree(hpriv);
}
+static void sil24_init_controller(struct pci_dev *pdev, int n_ports,
+ unsigned long host_flags,
+ void __iomem *host_base,
+ void __iomem *port_base)
+{
+ u32 tmp;
+ int i;
+
+ /* GPIO off */
+ writel(0, host_base + HOST_FLASH_CMD);
+
+ /* clear global reset & mask interrupts during initialization */
+ writel(0, host_base + HOST_CTRL);
+
+ /* init ports */
+ for (i = 0; i < n_ports; i++) {
+ void __iomem *port = port_base + i * PORT_REGS_SIZE;
+
+ /* Initial PHY setting */
+ writel(0x20c, port + PORT_PHY_CFG);
+
+ /* Clear port RST */
+ tmp = readl(port + PORT_CTRL_STAT);
+ if (tmp & PORT_CS_PORT_RST) {
+ writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
+ tmp = ata_wait_register(port + PORT_CTRL_STAT,
+ PORT_CS_PORT_RST,
+ PORT_CS_PORT_RST, 10, 100);
+ if (tmp & PORT_CS_PORT_RST)
+ dev_printk(KERN_ERR, &pdev->dev,
+ "failed to clear port RST\n");
+ }
+
+ /* Configure IRQ WoC */
+ if (host_flags & SIL24_FLAG_PCIX_IRQ_WOC)
+ writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
+ else
+ writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
+
+ /* Zero error counters. */
+ writel(0x8000, port + PORT_DECODE_ERR_THRESH);
+ writel(0x8000, port + PORT_CRC_ERR_THRESH);
+ writel(0x8000, port + PORT_HSHK_ERR_THRESH);
+ writel(0x0000, port + PORT_DECODE_ERR_CNT);
+ writel(0x0000, port + PORT_CRC_ERR_CNT);
+ writel(0x0000, port + PORT_HSHK_ERR_CNT);
+
+ /* Always use 64bit activation */
+ writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
+
+ /* Clear port multiplier enable and resume bits */
+ writel(PORT_CS_PM_EN | PORT_CS_RESUME, port + PORT_CTRL_CLR);
+ }
+
+ /* Turn on interrupts */
+ writel(IRQ_STAT_4PORTS, host_base + HOST_CTRL);
+}
+
static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version = 0;
@@ -1076,9 +1140,6 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
}
}
- /* GPIO off */
- writel(0, host_base + HOST_FLASH_CMD);
-
/* Apply workaround for completion IRQ loss on PCI-X errata */
if (probe_ent->host_flags & SIL24_FLAG_PCIX_IRQ_WOC) {
tmp = readl(host_base + HOST_CTRL);
@@ -1090,56 +1151,18 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
probe_ent->host_flags &= ~SIL24_FLAG_PCIX_IRQ_WOC;
}
- /* clear global reset & mask interrupts during initialization */
- writel(0, host_base + HOST_CTRL);
-
for (i = 0; i < probe_ent->n_ports; i++) {
- void __iomem *port = port_base + i * PORT_REGS_SIZE;
- unsigned long portu = (unsigned long)port;
+ unsigned long portu =
+ (unsigned long)port_base + i * PORT_REGS_SIZE;
probe_ent->port[i].cmd_addr = portu;
probe_ent->port[i].scr_addr = portu + PORT_SCONTROL;
ata_std_ports(&probe_ent->port[i]);
-
- /* Initial PHY setting */
- writel(0x20c, port + PORT_PHY_CFG);
-
- /* Clear port RST */
- tmp = readl(port + PORT_CTRL_STAT);
- if (tmp & PORT_CS_PORT_RST) {
- writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
- tmp = ata_wait_register(port + PORT_CTRL_STAT,
- PORT_CS_PORT_RST,
- PORT_CS_PORT_RST, 10, 100);
- if (tmp & PORT_CS_PORT_RST)
- dev_printk(KERN_ERR, &pdev->dev,
- "failed to clear port RST\n");
- }
-
- /* Configure IRQ WoC */
- if (probe_ent->host_flags & SIL24_FLAG_PCIX_IRQ_WOC)
- writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
- else
- writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
-
- /* Zero error counters. */
- writel(0x8000, port + PORT_DECODE_ERR_THRESH);
- writel(0x8000, port + PORT_CRC_ERR_THRESH);
- writel(0x8000, port + PORT_HSHK_ERR_THRESH);
- writel(0x0000, port + PORT_DECODE_ERR_CNT);
- writel(0x0000, port + PORT_CRC_ERR_CNT);
- writel(0x0000, port + PORT_HSHK_ERR_CNT);
-
- /* Always use 64bit activation */
- writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
-
- /* Clear port multiplier enable and resume bits */
- writel(PORT_CS_PM_EN | PORT_CS_RESUME, port + PORT_CTRL_CLR);
}
- /* Turn on interrupts */
- writel(IRQ_STAT_4PORTS, host_base + HOST_CTRL);
+ sil24_init_controller(pdev, probe_ent->n_ports, probe_ent->host_flags,
+ host_base, port_base);
pci_set_master(pdev);
@@ -1162,6 +1185,25 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
return rc;
}
+static int sil24_pci_device_resume(struct pci_dev *pdev)
+{
+ struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev);
+ struct sil24_host_priv *hpriv = host_set->private_data;
+
+ ata_pci_device_do_resume(pdev);
+
+ if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND)
+ writel(HOST_CTRL_GLOBAL_RST, hpriv->host_base + HOST_CTRL);
+
+ sil24_init_controller(pdev, host_set->n_ports,
+ host_set->ports[0]->flags,
+ hpriv->host_base, hpriv->port_base);
+
+ ata_host_set_resume(host_set);
+
+ return 0;
+}
+
static int __init sil24_init(void)
{
return pci_module_init(&sil24_pci_driver);
diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c
index 916fe6fba75..ad37871594f 100644
--- a/drivers/scsi/sata_vsc.c
+++ b/drivers/scsi/sata_vsc.c
@@ -297,7 +297,7 @@ static const struct ata_port_operations vsc_sata_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_mmio_data_xfer,
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 2ab7df0dcfe..b332caddd5b 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -346,7 +346,7 @@ void scsi_log_send(struct scsi_cmnd *cmd)
if (level > 3) {
printk(KERN_INFO "buffer = 0x%p, bufflen = %d,"
" done = 0x%p, queuecommand 0x%p\n",
- cmd->buffer, cmd->bufflen,
+ cmd->request_buffer, cmd->request_bufflen,
cmd->done,
sdev->host->hostt->queuecommand);
@@ -661,11 +661,6 @@ void __scsi_done(struct scsi_cmnd *cmd)
*/
int scsi_retry_command(struct scsi_cmnd *cmd)
{
- /*
- * Restore the SCSI command state.
- */
- scsi_setup_cmd_retry(cmd);
-
/*
* Zero the sense information from the last time we tried
* this command.
@@ -711,10 +706,6 @@ void scsi_finish_command(struct scsi_cmnd *cmd)
"Notifying upper driver of completion "
"(result %x)\n", cmd->result));
- /*
- * We can get here with use_sg=0, causing a panic in the upper level
- */
- cmd->use_sg = cmd->old_use_sg;
cmd->done(cmd);
}
EXPORT_SYMBOL(scsi_finish_command);
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 9c63b00773c..a80303c6b3f 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -286,7 +286,7 @@ static int inquiry_evpd_83(unsigned char * arr, int target_dev_id,
int dev_id_num, const char * dev_id_str,
int dev_id_str_len);
static int inquiry_evpd_88(unsigned char * arr, int target_dev_id);
-static void do_create_driverfs_files(void);
+static int do_create_driverfs_files(void);
static void do_remove_driverfs_files(void);
static int sdebug_add_adapter(void);
@@ -2487,19 +2487,22 @@ static ssize_t sdebug_add_host_store(struct device_driver * ddp,
DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
sdebug_add_host_store);
-static void do_create_driverfs_files(void)
+static int do_create_driverfs_files(void)
{
- driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
- driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
- driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
- driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
- driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
- driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
- driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
- driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
- driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
- driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
- driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
+ int ret;
+
+ ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
+ return ret;
}
static void do_remove_driverfs_files(void)
@@ -2522,6 +2525,7 @@ static int __init scsi_debug_init(void)
unsigned int sz;
int host_to_add;
int k;
+ int ret;
if (scsi_debug_dev_size_mb < 1)
scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
@@ -2560,12 +2564,32 @@ static int __init scsi_debug_init(void)
if (scsi_debug_num_parts > 0)
sdebug_build_parts(fake_storep);
- init_all_queued();
+ ret = device_register(&pseudo_primary);
+ if (ret < 0) {
+ printk(KERN_WARNING "scsi_debug: device_register error: %d\n",
+ ret);
+ goto free_vm;
+ }
+ ret = bus_register(&pseudo_lld_bus);
+ if (ret < 0) {
+ printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
+ ret);
+ goto dev_unreg;
+ }
+ ret = driver_register(&sdebug_driverfs_driver);
+ if (ret < 0) {
+ printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
+ ret);
+ goto bus_unreg;
+ }
+ ret = do_create_driverfs_files();
+ if (ret < 0) {
+ printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n",
+ ret);
+ goto del_files;
+ }
- device_register(&pseudo_primary);
- bus_register(&pseudo_lld_bus);
- driver_register(&sdebug_driverfs_driver);
- do_create_driverfs_files();
+ init_all_queued();
sdebug_driver_template.proc_name = (char *)sdebug_proc_name;
@@ -2585,6 +2609,18 @@ static int __init scsi_debug_init(void)
scsi_debug_add_host);
}
return 0;
+
+del_files:
+ do_remove_driverfs_files();
+ driver_unregister(&sdebug_driverfs_driver);
+bus_unreg:
+ bus_unregister(&pseudo_lld_bus);
+dev_unreg:
+ device_unregister(&pseudo_primary);
+free_vm:
+ vfree(fake_storep);
+
+ return ret;
}
static void __exit scsi_debug_exit(void)
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 6683d596234..6a5b731bd5b 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -460,19 +460,67 @@ static void scsi_eh_done(struct scsi_cmnd *scmd)
* Return value:
* SUCCESS or FAILED or NEEDS_RETRY
**/
-static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, int timeout)
+static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, int timeout, int copy_sense)
{
struct scsi_device *sdev = scmd->device;
struct Scsi_Host *shost = sdev->host;
+ int old_result = scmd->result;
DECLARE_COMPLETION(done);
unsigned long timeleft;
unsigned long flags;
+ unsigned char old_cmnd[MAX_COMMAND_SIZE];
+ enum dma_data_direction old_data_direction;
+ unsigned short old_use_sg;
+ unsigned char old_cmd_len;
+ unsigned old_bufflen;
+ void *old_buffer;
int rtn;
+ /*
+ * We need saved copies of a number of fields - this is because
+ * error handling may need to overwrite these with different values
+ * to run different commands, and once error handling is complete,
+ * we will need to restore these values prior to running the actual
+ * command.
+ */
+ old_buffer = scmd->request_buffer;
+ old_bufflen = scmd->request_bufflen;
+ memcpy(old_cmnd, scmd->cmnd, sizeof(scmd->cmnd));
+ old_data_direction = scmd->sc_data_direction;
+ old_cmd_len = scmd->cmd_len;
+ old_use_sg = scmd->use_sg;
+
+ if (copy_sense) {
+ int gfp_mask = GFP_ATOMIC;
+
+ if (shost->hostt->unchecked_isa_dma)
+ gfp_mask |= __GFP_DMA;
+
+ scmd->sc_data_direction = DMA_FROM_DEVICE;
+ scmd->request_bufflen = 252;
+ scmd->request_buffer = kzalloc(scmd->request_bufflen, gfp_mask);
+ if (!scmd->request_buffer)
+ return FAILED;
+ } else {
+ scmd->request_buffer = NULL;
+ scmd->request_bufflen = 0;
+ scmd->sc_data_direction = DMA_NONE;
+ }
+
+ scmd->underflow = 0;
+ scmd->use_sg = 0;
+ scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
+
if (sdev->scsi_level <= SCSI_2)
scmd->cmnd[1] = (scmd->cmnd[1] & 0x1f) |
(sdev->lun << 5 & 0xe0);
+ /*
+ * Zero the sense buffer. The scsi spec mandates that any
+ * untransferred sense data should be interpreted as being zero.
+ */
+ memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer));
+
shost->eh_action = &done;
spin_lock_irqsave(shost->host_lock, flags);
@@ -522,6 +570,29 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, int timeout)
rtn = FAILED;
}
+
+ /*
+ * Last chance to have valid sense data.
+ */
+ if (copy_sense) {
+ if (!SCSI_SENSE_VALID(scmd)) {
+ memcpy(scmd->sense_buffer, scmd->request_buffer,
+ sizeof(scmd->sense_buffer));
+ }
+ kfree(scmd->request_buffer);
+ }
+
+
+ /*
+ * Restore original data
+ */
+ scmd->request_buffer = old_buffer;
+ scmd->request_bufflen = old_bufflen;
+ memcpy(scmd->cmnd, old_cmnd, sizeof(scmd->cmnd));
+ scmd->sc_data_direction = old_data_direction;
+ scmd->cmd_len = old_cmd_len;
+ scmd->use_sg = old_use_sg;
+ scmd->result = old_result;
return rtn;
}
@@ -537,56 +608,10 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, int timeout)
static int scsi_request_sense(struct scsi_cmnd *scmd)
{
static unsigned char generic_sense[6] =
- {REQUEST_SENSE, 0, 0, 0, 252, 0};
- unsigned char *scsi_result;
- int saved_result;
- int rtn;
+ {REQUEST_SENSE, 0, 0, 0, 252, 0};
memcpy(scmd->cmnd, generic_sense, sizeof(generic_sense));
-
- scsi_result = kmalloc(252, GFP_ATOMIC | ((scmd->device->host->hostt->unchecked_isa_dma) ? __GFP_DMA : 0));
-
-
- if (unlikely(!scsi_result)) {
- printk(KERN_ERR "%s: cannot allocate scsi_result.\n",
- __FUNCTION__);
- return FAILED;
- }
-
- /*
- * zero the sense buffer. some host adapters automatically always
- * request sense, so it is not a good idea that
- * scmd->request_buffer and scmd->sense_buffer point to the same
- * address (db). 0 is not a valid sense code.
- */
- memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer));
- memset(scsi_result, 0, 252);
-
- saved_result = scmd->result;
- scmd->request_buffer = scsi_result;
- scmd->request_bufflen = 252;
- scmd->use_sg = 0;
- scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
- scmd->sc_data_direction = DMA_FROM_DEVICE;
- scmd->underflow = 0;
-
- rtn = scsi_send_eh_cmnd(scmd, SENSE_TIMEOUT);
-
- /* last chance to have valid sense data */
- if(!SCSI_SENSE_VALID(scmd)) {
- memcpy(scmd->sense_buffer, scmd->request_buffer,
- sizeof(scmd->sense_buffer));
- }
-
- kfree(scsi_result);
-
- /*
- * when we eventually call scsi_finish, we really wish to complete
- * the original request, so let's restore the original data. (db)
- */
- scsi_setup_cmd_retry(scmd);
- scmd->result = saved_result;
- return rtn;
+ return scsi_send_eh_cmnd(scmd, SENSE_TIMEOUT, 1);
}
/**
@@ -605,12 +630,6 @@ void scsi_eh_finish_cmd(struct scsi_cmnd *scmd, struct list_head *done_q)
{
scmd->device->host->host_failed--;
scmd->eh_eflags = 0;
-
- /*
- * set this back so that the upper level can correctly free up
- * things.
- */
- scsi_setup_cmd_retry(scmd);
list_move_tail(&scmd->eh_entry, done_q);
}
EXPORT_SYMBOL(scsi_eh_finish_cmd);
@@ -715,47 +734,26 @@ static int scsi_eh_tur(struct scsi_cmnd *scmd)
{
static unsigned char tur_command[6] = {TEST_UNIT_READY, 0, 0, 0, 0, 0};
int retry_cnt = 1, rtn;
- int saved_result;
retry_tur:
memcpy(scmd->cmnd, tur_command, sizeof(tur_command));
- /*
- * zero the sense buffer. the scsi spec mandates that any
- * untransferred sense data should be interpreted as being zero.
- */
- memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer));
-
- saved_result = scmd->result;
- scmd->request_buffer = NULL;
- scmd->request_bufflen = 0;
- scmd->use_sg = 0;
- scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
- scmd->underflow = 0;
- scmd->sc_data_direction = DMA_NONE;
- rtn = scsi_send_eh_cmnd(scmd, SENSE_TIMEOUT);
+ rtn = scsi_send_eh_cmnd(scmd, SENSE_TIMEOUT, 0);
- /*
- * when we eventually call scsi_finish, we really wish to complete
- * the original request, so let's restore the original data. (db)
- */
- scsi_setup_cmd_retry(scmd);
- scmd->result = saved_result;
-
- /*
- * hey, we are done. let's look to see what happened.
- */
SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd %p rtn %x\n",
__FUNCTION__, scmd, rtn));
- if (rtn == SUCCESS)
- return 0;
- else if (rtn == NEEDS_RETRY) {
+
+ switch (rtn) {
+ case NEEDS_RETRY:
if (retry_cnt--)
goto retry_tur;
+ /*FALLTHRU*/
+ case SUCCESS:
return 0;
+ default:
+ return 1;
}
- return 1;
}
/**
@@ -837,44 +835,16 @@ static int scsi_try_bus_device_reset(struct scsi_cmnd *scmd)
static int scsi_eh_try_stu(struct scsi_cmnd *scmd)
{
static unsigned char stu_command[6] = {START_STOP, 0, 0, 0, 1, 0};
- int rtn;
- int saved_result;
- if (!scmd->device->allow_restart)
- return 1;
-
- memcpy(scmd->cmnd, stu_command, sizeof(stu_command));
-
- /*
- * zero the sense buffer. the scsi spec mandates that any
- * untransferred sense data should be interpreted as being zero.
- */
- memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer));
-
- saved_result = scmd->result;
- scmd->request_buffer = NULL;
- scmd->request_bufflen = 0;
- scmd->use_sg = 0;
- scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
- scmd->underflow = 0;
- scmd->sc_data_direction = DMA_NONE;
+ if (scmd->device->allow_restart) {
+ int rtn;
- rtn = scsi_send_eh_cmnd(scmd, START_UNIT_TIMEOUT);
-
- /*
- * when we eventually call scsi_finish, we really wish to complete
- * the original request, so let's restore the original data. (db)
- */
- scsi_setup_cmd_retry(scmd);
- scmd->result = saved_result;
+ memcpy(scmd->cmnd, stu_command, sizeof(stu_command));
+ rtn = scsi_send_eh_cmnd(scmd, START_UNIT_TIMEOUT, 0);
+ if (rtn == SUCCESS)
+ return 0;
+ }
- /*
- * hey, we are done. let's look to see what happened.
- */
- SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd %p rtn %x\n",
- __FUNCTION__, scmd, rtn));
- if (rtn == SUCCESS)
- return 0;
return 1;
}
@@ -1684,8 +1654,6 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
scmd->scsi_done = scsi_reset_provider_done_command;
scmd->done = NULL;
- scmd->buffer = NULL;
- scmd->bufflen = 0;
scmd->request_buffer = NULL;
scmd->request_bufflen = 0;
diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c
index a89c4115cfb..32293f45166 100644
--- a/drivers/scsi/scsi_ioctl.c
+++ b/drivers/scsi/scsi_ioctl.c
@@ -110,11 +110,8 @@ static int ioctl_internal_command(struct scsi_device *sdev, char *cmd,
sshdr.asc, sshdr.ascq);
break;
case NOT_READY: /* This happens if there is no disc in drive */
- if (sdev->removable && (cmd[0] != TEST_UNIT_READY)) {
- printk(KERN_INFO "Device not ready. Make sure"
- " there is a disc in the drive.\n");
+ if (sdev->removable)
break;
- }
case UNIT_ATTENTION:
if (sdev->removable) {
sdev->changed = 1;
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 08af9aae7df..077c1c69121 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -436,60 +436,16 @@ EXPORT_SYMBOL_GPL(scsi_execute_async);
*
* Arguments: cmd - command that is ready to be queued.
*
- * Returns: Nothing
- *
* Notes: This function has the job of initializing a number of
* fields related to error handling. Typically this will
* be called once for each command, as required.
*/
-static int scsi_init_cmd_errh(struct scsi_cmnd *cmd)
+static void scsi_init_cmd_errh(struct scsi_cmnd *cmd)
{
cmd->serial_number = 0;
-
memset(cmd->sense_buffer, 0, sizeof cmd->sense_buffer);
-
if (cmd->cmd_len == 0)
cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
-
- /*
- * We need saved copies of a number of fields - this is because
- * error handling may need to overwrite these with different values
- * to run different commands, and once error handling is complete,
- * we will need to restore these values prior to running the actual
- * command.
- */
- cmd->old_use_sg = cmd->use_sg;
- cmd->old_cmd_len = cmd->cmd_len;
- cmd->sc_old_data_direction = cmd->sc_data_direction;
- cmd->old_underflow = cmd->underflow;
- memcpy(cmd->data_cmnd, cmd->cmnd, sizeof(cmd->cmnd));
- cmd->buffer = cmd->request_buffer;
- cmd->bufflen = cmd->request_bufflen;
-
- return 1;
-}
-
-/*
- * Function: scsi_setup_cmd_retry()
- *
- * Purpose: Restore the command state for a retry
- *
- * Arguments: cmd - command to be restored
- *
- * Returns: Nothing
- *
- * Notes: Immediately prior to retrying a command, we need
- * to restore certain fields that we saved above.
- */
-void scsi_setup_cmd_retry(struct scsi_cmnd *cmd)
-{
- memcpy(cmd->cmnd, cmd->data_cmnd, sizeof(cmd->data_cmnd));
- cmd->request_buffer = cmd->buffer;
- cmd->request_bufflen = cmd->bufflen;
- cmd->use_sg = cmd->old_use_sg;
- cmd->cmd_len = cmd->old_cmd_len;
- cmd->sc_data_direction = cmd->sc_old_data_direction;
- cmd->underflow = cmd->old_underflow;
}
void scsi_device_unbusy(struct scsi_device *sdev)
@@ -807,22 +763,13 @@ static void scsi_free_sgtable(struct scatterlist *sgl, int index)
*/
static void scsi_release_buffers(struct scsi_cmnd *cmd)
{
- struct request *req = cmd->request;
-
- /*
- * Free up any indirection buffers we allocated for DMA purposes.
- */
if (cmd->use_sg)
scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len);
- else if (cmd->request_buffer != req->buffer)
- kfree(cmd->request_buffer);
/*
* Zero these out. They now point to freed memory, and it is
* dangerous to hang onto the pointers.
*/
- cmd->buffer = NULL;
- cmd->bufflen = 0;
cmd->request_buffer = NULL;
cmd->request_bufflen = 0;
}
@@ -858,7 +805,7 @@ static void scsi_release_buffers(struct scsi_cmnd *cmd)
void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
{
int result = cmd->result;
- int this_count = cmd->bufflen;
+ int this_count = cmd->request_bufflen;
request_queue_t *q = cmd->device->request_queue;
struct request *req = cmd->request;
int clear_errors = 1;
@@ -866,28 +813,14 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
int sense_valid = 0;
int sense_deferred = 0;
- /*
- * Free up any indirection buffers we allocated for DMA purposes.
- * For the case of a READ, we need to copy the data out of the
- * bounce buffer and into the real buffer.
- */
- if (cmd->use_sg)
- scsi_free_sgtable(cmd->buffer, cmd->sglist_len);
- else if (cmd->buffer != req->buffer) {
- if (rq_data_dir(req) == READ) {
- unsigned long flags;
- char *to = bio_kmap_irq(req->bio, &flags);
- memcpy(to, cmd->buffer, cmd->bufflen);
- bio_kunmap_irq(to, &flags);
- }
- kfree(cmd->buffer);
- }
+ scsi_release_buffers(cmd);
if (result) {
sense_valid = scsi_command_normalize_sense(cmd, &sshdr);
if (sense_valid)
sense_deferred = scsi_sense_is_deferred(&sshdr);
}
+
if (blk_pc_request(req)) { /* SG_IO ioctl from block level */
req->errors = result;
if (result) {
@@ -908,15 +841,6 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
}
/*
- * Zero these out. They now point to freed memory, and it is
- * dangerous to hang onto the pointers.
- */
- cmd->buffer = NULL;
- cmd->bufflen = 0;
- cmd->request_buffer = NULL;
- cmd->request_bufflen = 0;
-
- /*
* Next deal with any sectors which we were able to correctly
* handle.
*/
@@ -1012,7 +936,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
if (!(req->flags & REQ_QUIET)) {
scmd_printk(KERN_INFO, cmd,
"Volume overflow, CDB: ");
- __scsi_print_command(cmd->data_cmnd);
+ __scsi_print_command(cmd->cmnd);
scsi_print_sense("", cmd);
}
/* See SSC3rXX or current. */
@@ -1143,7 +1067,7 @@ static void scsi_blk_pc_done(struct scsi_cmnd *cmd)
* successfully. Since this is a REQ_BLOCK_PC command the
* caller should check the request's errors value
*/
- scsi_io_completion(cmd, cmd->bufflen);
+ scsi_io_completion(cmd, cmd->request_bufflen);
}
static void scsi_setup_blk_pc_cmnd(struct scsi_cmnd *cmd)
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index e2fbe9a9d5a..ae24c85aaee 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -57,7 +57,6 @@ extern int scsi_eh_scmd_add(struct scsi_cmnd *, int);
/* scsi_lib.c */
extern int scsi_maybe_unblock_host(struct scsi_device *sdev);
-extern void scsi_setup_cmd_retry(struct scsi_cmnd *cmd);
extern void scsi_device_unbusy(struct scsi_device *sdev);
extern int scsi_queue_insert(struct scsi_cmnd *cmd, int reason);
extern void scsi_next_command(struct scsi_cmnd *cmd);
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index dd075627e60..5a625c3fdda 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -41,6 +41,7 @@ struct sas_host_attrs {
struct mutex lock;
u32 next_target_id;
u32 next_expander_id;
+ int next_port_id;
};
#define to_sas_host_attrs(host) ((struct sas_host_attrs *)(host)->shost_data)
@@ -146,6 +147,7 @@ static int sas_host_setup(struct transport_container *tc, struct device *dev,
mutex_init(&sas_host->lock);
sas_host->next_target_id = 0;
sas_host->next_expander_id = 0;
+ sas_host->next_port_id = 0;
return 0;
}
@@ -327,7 +329,7 @@ sas_phy_protocol_attr(identify.target_port_protocols,
sas_phy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n",
unsigned long long);
sas_phy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8);
-//sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", u8);
+//sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", int);
sas_phy_linkspeed_attr(negotiated_linkrate);
sas_phy_linkspeed_attr(minimum_linkrate_hw);
sas_phy_linkspeed_attr(minimum_linkrate);
@@ -590,6 +592,38 @@ struct sas_port *sas_port_alloc(struct device *parent, int port_id)
}
EXPORT_SYMBOL(sas_port_alloc);
+/** sas_port_alloc_num - allocate and initialize a SAS port structure
+ *
+ * @parent: parent device
+ *
+ * Allocates a SAS port structure and a number to go with it. This
+ * interface is really for adapters where the port number has no
+ * meansing, so the sas class should manage them. It will be added to
+ * the device tree below the device specified by @parent which must be
+ * either a Scsi_Host or a sas_expander_device.
+ *
+ * Returns %NULL on error
+ */
+struct sas_port *sas_port_alloc_num(struct device *parent)
+{
+ int index;
+ struct Scsi_Host *shost = dev_to_shost(parent);
+ struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
+
+ /* FIXME: use idr for this eventually */
+ mutex_lock(&sas_host->lock);
+ if (scsi_is_sas_expander_device(parent)) {
+ struct sas_rphy *rphy = dev_to_rphy(parent);
+ struct sas_expander_device *exp = rphy_to_expander_device(rphy);
+
+ index = exp->next_port_id++;
+ } else
+ index = sas_host->next_port_id++;
+ mutex_unlock(&sas_host->lock);
+ return sas_port_alloc(parent, index);
+}
+EXPORT_SYMBOL(sas_port_alloc_num);
+
/**
* sas_port_add - add a SAS port to the device hierarchy
*
@@ -658,6 +692,13 @@ void sas_port_delete(struct sas_port *port)
}
mutex_unlock(&port->phy_list_mutex);
+ if (port->is_backlink) {
+ struct device *parent = port->dev.parent;
+
+ sysfs_remove_link(&port->dev.kobj, parent->bus_id);
+ port->is_backlink = 0;
+ }
+
transport_remove_device(dev);
device_del(dev);
transport_destroy_device(dev);
@@ -733,6 +774,19 @@ void sas_port_delete_phy(struct sas_port *port, struct sas_phy *phy)
}
EXPORT_SYMBOL(sas_port_delete_phy);
+void sas_port_mark_backlink(struct sas_port *port)
+{
+ struct device *parent = port->dev.parent->parent->parent;
+
+ if (port->is_backlink)
+ return;
+ port->is_backlink = 1;
+ sysfs_create_link(&port->dev.kobj, &parent->kobj,
+ parent->bus_id);
+
+}
+EXPORT_SYMBOL(sas_port_mark_backlink);
+
/*
* SAS remote PHY attributes.
*/
@@ -1140,7 +1194,7 @@ int sas_rphy_add(struct sas_rphy *rphy)
if (identify->device_type == SAS_END_DEVICE &&
rphy->scsi_target_id != -1) {
- scsi_scan_target(&rphy->dev, parent->port_identifier,
+ scsi_scan_target(&rphy->dev, 0,
rphy->scsi_target_id, ~0, 0);
}
@@ -1242,15 +1296,13 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel,
mutex_lock(&sas_host->lock);
list_for_each_entry(rphy, &sas_host->rphy_list, list) {
- struct sas_port *parent = dev_to_sas_port(rphy->dev.parent);
-
if (rphy->identify.device_type != SAS_END_DEVICE ||
rphy->scsi_target_id == -1)
continue;
- if ((channel == SCAN_WILD_CARD || channel == parent->port_identifier) &&
+ if ((channel == SCAN_WILD_CARD || channel == 0) &&
(id == SCAN_WILD_CARD || id == rphy->scsi_target_id)) {
- scsi_scan_target(&rphy->dev, parent->port_identifier,
+ scsi_scan_target(&rphy->dev, 0,
rphy->scsi_target_id, lun, 1);
}
}
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 3225d31449e..98bd3aab973 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -502,8 +502,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
SCpnt->cmnd[4] = (unsigned char) this_count;
SCpnt->cmnd[5] = 0;
}
- SCpnt->request_bufflen = SCpnt->bufflen =
- this_count * sdp->sector_size;
+ SCpnt->request_bufflen = this_count * sdp->sector_size;
/*
* We shouldn't disconnect in the middle of a sector, so with a dumb
diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c
index 3f312a84c6a..2679ea8bff1 100644
--- a/drivers/scsi/seagate.c
+++ b/drivers/scsi/seagate.c
@@ -1002,7 +1002,7 @@ connect_loop:
}
#endif
- buffer = (struct scatterlist *) SCint->buffer;
+ buffer = (struct scatterlist *) SCint->request_buffer;
len = buffer->length;
data = page_address(buffer->page) + buffer->offset;
} else {
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index fd94408577e..fae6e95a629 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -360,7 +360,7 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
"mismatch count %d, bytes %d\n",
size, SCpnt->request_bufflen);
if (SCpnt->request_bufflen > size)
- SCpnt->request_bufflen = SCpnt->bufflen = size;
+ SCpnt->request_bufflen = size;
}
}
@@ -387,8 +387,7 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
if (this_count > 0xffff) {
this_count = 0xffff;
- SCpnt->request_bufflen = SCpnt->bufflen =
- this_count * s_size;
+ SCpnt->request_bufflen = this_count * s_size;
}
SCpnt->cmnd[2] = (unsigned char) (block >> 24) & 0xff;
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 756ceb93ddc..7f669b60067 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -368,7 +368,7 @@ static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt)
SRpnt->cmd[0], SRpnt->cmd[1], SRpnt->cmd[2],
SRpnt->cmd[3], SRpnt->cmd[4], SRpnt->cmd[5]);
if (cmdstatp->have_sense)
- __scsi_print_sense("st", SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
+ __scsi_print_sense(name, SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
} ) /* end DEB */
if (!debugging) { /* Abnormal conditions for tape */
if (!cmdstatp->have_sense)
@@ -384,9 +384,8 @@ static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt)
scode != VOLUME_OVERFLOW &&
SRpnt->cmd[0] != MODE_SENSE &&
SRpnt->cmd[0] != TEST_UNIT_READY) {
- printk(KERN_WARNING "%s: Error with sense data: ", name);
- __scsi_print_sense("st", SRpnt->sense,
- SCSI_SENSE_BUFFERSIZE);
+
+ __scsi_print_sense(name, SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
}
}
diff --git a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c
index 2ebe0d66389..2f8073b73bf 100644
--- a/drivers/scsi/sun3_NCR5380.c
+++ b/drivers/scsi/sun3_NCR5380.c
@@ -517,7 +517,7 @@ static __inline__ void initialize_SCp(Scsi_Cmnd *cmd)
*/
if (cmd->use_sg) {
- cmd->SCp.buffer = (struct scatterlist *) cmd->buffer;
+ cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
cmd->SCp.buffers_residual = cmd->use_sg - 1;
cmd->SCp.ptr = (char *) SGADDR(cmd->SCp.buffer);
cmd->SCp.this_residual = cmd->SCp.buffer->length;
diff --git a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c
index 1f328cae5c0..6b60536ac92 100644
--- a/drivers/scsi/sun3x_esp.c
+++ b/drivers/scsi/sun3x_esp.c
@@ -347,7 +347,7 @@ static void dma_mmu_release_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp)
static void dma_mmu_release_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp)
{
int sz = sp->use_sg - 1;
- struct scatterlist *sg = (struct scatterlist *)sp->buffer;
+ struct scatterlist *sg = (struct scatterlist *)sp->request_buffer;
while(sz >= 0) {
dvma_unmap((char *)sg[sz].dma_address);
diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c
index 680f38ab60d..2083454db51 100644
--- a/drivers/scsi/wd33c93.c
+++ b/drivers/scsi/wd33c93.c
@@ -373,7 +373,7 @@ wd33c93_queuecommand(struct scsi_cmnd *cmd,
*/
if (cmd->use_sg) {
- cmd->SCp.buffer = (struct scatterlist *) cmd->buffer;
+ cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
cmd->SCp.buffers_residual = cmd->use_sg - 1;
cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) +
cmd->SCp.buffer->offset;
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 0995430e4cf..0ae9ced00ed 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -299,6 +299,7 @@ static inline int map_8250_out_reg(struct uart_8250_port *up, int offset)
static unsigned int serial_in(struct uart_8250_port *up, int offset)
{
+ unsigned int tmp;
offset = map_8250_in_reg(up, offset) << up->port.regshift;
switch (up->port.iotype) {
@@ -317,6 +318,13 @@ static unsigned int serial_in(struct uart_8250_port *up, int offset)
return __raw_readl(up->port.membase + offset);
#endif
+ case UPIO_TSI:
+ if (offset == UART_IIR) {
+ tmp = readl((u32 *)(up->port.membase + UART_RX));
+ return (cpu_to_le32(tmp) >> 8) & 0xff;
+ } else
+ return readb(up->port.membase + offset);
+
default:
return inb(up->port.iobase + offset);
}
@@ -346,6 +354,10 @@ serial_out(struct uart_8250_port *up, int offset, int value)
__raw_writel(value, up->port.membase + offset);
break;
#endif
+ case UPIO_TSI:
+ if (!((offset == UART_IER) && (value & UART_IER_UUE)))
+ writeb(value, up->port.membase + offset);
+ break;
default:
outb(value, up->port.iobase + offset);
@@ -2240,10 +2252,14 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
touch_nmi_watchdog();
- if (oops_in_progress) {
- locked = spin_trylock_irqsave(&up->port.lock, flags);
+ local_irq_save(flags);
+ if (up->port.sysrq) {
+ /* serial8250_handle_port() already took the lock */
+ locked = 0;
+ } else if (oops_in_progress) {
+ locked = spin_trylock(&up->port.lock);
} else
- spin_lock_irqsave(&up->port.lock, flags);
+ spin_lock(&up->port.lock);
/*
* First save the IER then disable the interrupts
@@ -2265,7 +2281,8 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
serial_out(up, UART_IER, ier);
if (locked)
- spin_unlock_irqrestore(&up->port.lock, flags);
+ spin_unlock(&up->port.lock);
+ local_irq_restore(flags);
}
static int serial8250_console_setup(struct console *co, char *options)
diff --git a/drivers/serial/at91_serial.c b/drivers/serial/at91_serial.c
index a7d664383da..54c6b2adf7b 100644
--- a/drivers/serial/at91_serial.c
+++ b/drivers/serial/at91_serial.c
@@ -41,6 +41,7 @@
#include <asm/mach/serial_at91.h>
#include <asm/arch/board.h>
#include <asm/arch/system.h>
+#include <asm/arch/gpio.h>
#if defined(CONFIG_SERIAL_AT91_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
@@ -140,9 +141,9 @@ static void at91_set_mctrl(struct uart_port *port, u_int mctrl)
*/
if (port->mapbase == AT91_BASE_US0) {
if (mctrl & TIOCM_RTS)
- at91_sys_write(AT91_PIOA + PIO_CODR, AT91_PA21_RTS0);
+ at91_set_gpio_value(AT91_PIN_PA21, 0);
else
- at91_sys_write(AT91_PIOA + PIO_SODR, AT91_PA21_RTS0);
+ at91_set_gpio_value(AT91_PIN_PA21, 1);
}
}
diff --git a/drivers/serial/dz.c b/drivers/serial/dz.c
index d119c8296a7..8a98aae80e2 100644
--- a/drivers/serial/dz.c
+++ b/drivers/serial/dz.c
@@ -673,7 +673,7 @@ static void dz_reset(struct dz_port *dport)
}
#ifdef CONFIG_SERIAL_DZ_CONSOLE
-static void dz_console_putchar(struct uart_port *port, int ch)
+static void dz_console_putchar(struct uart_port *uport, int ch)
{
struct dz_port *dport = (struct dz_port *)uport;
unsigned long flags;
diff --git a/drivers/serial/ip22zilog.c b/drivers/serial/ip22zilog.c
index 342042889f6..5ff269fb604 100644
--- a/drivers/serial/ip22zilog.c
+++ b/drivers/serial/ip22zilog.c
@@ -1143,9 +1143,8 @@ static void __init ip22zilog_prepare(void)
up[(chip * 2) + 1].port.fifosize = 1;
up[(chip * 2) + 1].port.ops = &ip22zilog_pops;
up[(chip * 2) + 1].port.type = PORT_IP22ZILOG;
- up[(chip * 2) + 1].port.flags |= IP22ZILOG_FLAG_IS_CHANNEL_A;
up[(chip * 2) + 1].port.line = (chip * 2) + 1;
- up[(chip * 2) + 1].flags = 0;
+ up[(chip * 2) + 1].flags |= IP22ZILOG_FLAG_IS_CHANNEL_A;
}
}
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index d5f636fbf29..80ef7d48275 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -2036,6 +2036,7 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
case UPIO_MEM:
case UPIO_MEM32:
case UPIO_AU:
+ case UPIO_TSI:
snprintf(address, sizeof(address),
"MMIO 0x%lx", port->mapbase);
break;
diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c
index 0dbd4df44c0..dc673e1b6fd 100644
--- a/drivers/serial/sunsab.c
+++ b/drivers/serial/sunsab.c
@@ -1047,12 +1047,13 @@ static int __devinit sab_probe(struct of_device *op, const struct of_device_id *
up = &sunsab_ports[inst * 2];
err = sunsab_init_one(&up[0], op,
- sizeof(union sab82532_async_regs),
+ 0,
(inst * 2) + 0);
if (err)
return err;
- err = sunsab_init_one(&up[0], op, 0,
+ err = sunsab_init_one(&up[1], op,
+ sizeof(union sab82532_async_regs),
(inst * 2) + 1);
if (err) {
of_iounmap(up[0].port.membase,
@@ -1117,7 +1118,7 @@ static int __init sunsab_init(void)
int err;
num_channels = 0;
- for_each_node_by_name(dp, "su")
+ for_each_node_by_name(dp, "se")
num_channels += 2;
for_each_node_by_name(dp, "serial") {
if (of_device_is_compatible(dp, "sab82532"))
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
index f9013baba05..d3a5aeee73a 100644
--- a/drivers/serial/sunsu.c
+++ b/drivers/serial/sunsu.c
@@ -1200,6 +1200,11 @@ static int __init sunsu_kbd_ms_init(struct uart_sunsu_port *up)
if (up->port.type == PORT_UNKNOWN)
return -ENODEV;
+ printk("%s: %s port at %lx, irq %u\n",
+ to_of_device(up->port.dev)->node->full_name,
+ (up->su_type == SU_PORT_KBD) ? "Keyboard" : "Mouse",
+ up->port.mapbase, up->port.irq);
+
#ifdef CONFIG_SERIO
serio = &up->serio;
serio->port_data = up;
@@ -1406,25 +1411,35 @@ static int __devinit su_probe(struct of_device *op, const struct of_device_id *m
struct device_node *dp = op->node;
struct uart_sunsu_port *up;
struct resource *rp;
+ enum su_type type;
int err;
- if (inst >= UART_NR)
- return -EINVAL;
+ type = su_get_type(dp);
+ if (type == SU_PORT_PORT) {
+ if (inst >= UART_NR)
+ return -EINVAL;
+ up = &sunsu_ports[inst];
+ } else {
+ up = kzalloc(sizeof(*up), GFP_KERNEL);
+ if (!up)
+ return -ENOMEM;
+ }
- up = &sunsu_ports[inst];
up->port.line = inst;
spin_lock_init(&up->port.lock);
- up->su_type = su_get_type(dp);
+ up->su_type = type;
rp = &op->resource[0];
- up->port.mapbase = op->resource[0].start;
-
+ up->port.mapbase = rp->start;
up->reg_size = (rp->end - rp->start) + 1;
up->port.membase = of_ioremap(rp, 0, up->reg_size, "su");
- if (!up->port.membase)
+ if (!up->port.membase) {
+ if (type != SU_PORT_PORT)
+ kfree(up);
return -ENOMEM;
+ }
up->port.irq = op->irqs[0];
@@ -1436,8 +1451,11 @@ static int __devinit su_probe(struct of_device *op, const struct of_device_id *m
err = 0;
if (up->su_type == SU_PORT_KBD || up->su_type == SU_PORT_MS) {
err = sunsu_kbd_ms_init(up);
- if (err)
+ if (err) {
+ kfree(up);
goto out_unmap;
+ }
+ dev_set_drvdata(&op->dev, up);
return 0;
}
@@ -1476,8 +1494,12 @@ static int __devexit su_remove(struct of_device *dev)
#ifdef CONFIG_SERIO
serio_unregister_port(&up->serio);
#endif
- } else if (up->port.type != PORT_UNKNOWN)
+ kfree(up);
+ } else if (up->port.type != PORT_UNKNOWN) {
uart_remove_one_port(&sunsu_reg, &up->port);
+ }
+
+ dev_set_drvdata(&dev->dev, NULL);
return 0;
}
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c
index a1456d9352c..47bc3d57e01 100644
--- a/drivers/serial/sunzilog.c
+++ b/drivers/serial/sunzilog.c
@@ -68,9 +68,6 @@ static int num_sunzilog;
#define NUM_SUNZILOG num_sunzilog
#define NUM_CHANNELS (NUM_SUNZILOG * 2)
-#define KEYBOARD_LINE 0x2
-#define MOUSE_LINE 0x3
-
#define ZS_CLOCK 4915200 /* Zilog input clock rate. */
#define ZS_CLOCK_DIVISOR 16 /* Divisor this driver uses. */
@@ -1225,12 +1222,10 @@ static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channe
{
int baud, brg;
- if (channel == KEYBOARD_LINE) {
- up->flags |= SUNZILOG_FLAG_CONS_KEYB;
+ if (up->flags & SUNZILOG_FLAG_CONS_KEYB) {
up->cflag = B1200 | CS8 | CLOCAL | CREAD;
baud = 1200;
} else {
- up->flags |= SUNZILOG_FLAG_CONS_MOUSE;
up->cflag = B4800 | CS8 | CLOCAL | CREAD;
baud = 4800;
}
@@ -1243,14 +1238,14 @@ static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channe
}
#ifdef CONFIG_SERIO
-static void __init sunzilog_register_serio(struct uart_sunzilog_port *up, int channel)
+static void __init sunzilog_register_serio(struct uart_sunzilog_port *up)
{
struct serio *serio = &up->serio;
serio->port_data = up;
serio->id.type = SERIO_RS232;
- if (channel == KEYBOARD_LINE) {
+ if (up->flags & SUNZILOG_FLAG_CONS_KEYB) {
serio->id.proto = SERIO_SUNKBD;
strlcpy(serio->name, "zskbd", sizeof(serio->name));
} else {
@@ -1259,7 +1254,8 @@ static void __init sunzilog_register_serio(struct uart_sunzilog_port *up, int ch
strlcpy(serio->name, "zsms", sizeof(serio->name));
}
strlcpy(serio->phys,
- (channel == KEYBOARD_LINE ? "zs/serio0" : "zs/serio1"),
+ ((up->flags & SUNZILOG_FLAG_CONS_KEYB) ?
+ "zs/serio0" : "zs/serio1"),
sizeof(serio->phys));
serio->write = sunzilog_serio_write;
@@ -1286,8 +1282,8 @@ static void __init sunzilog_init_hw(struct uart_sunzilog_port *up)
(void) read_zsreg(channel, R0);
}
- if (up->port.line == KEYBOARD_LINE ||
- up->port.line == MOUSE_LINE) {
+ if (up->flags & (SUNZILOG_FLAG_CONS_KEYB |
+ SUNZILOG_FLAG_CONS_MOUSE)) {
sunzilog_init_kbdms(up, up->port.line);
up->curregs[R9] |= (NV | MIE);
write_zsreg(channel, R9, up->curregs[R9]);
@@ -1313,37 +1309,26 @@ static void __init sunzilog_init_hw(struct uart_sunzilog_port *up)
spin_unlock_irqrestore(&up->port.lock, flags);
#ifdef CONFIG_SERIO
- if (up->port.line == KEYBOARD_LINE || up->port.line == MOUSE_LINE)
- sunzilog_register_serio(up, up->port.line);
+ if (up->flags & (SUNZILOG_FLAG_CONS_KEYB |
+ SUNZILOG_FLAG_CONS_MOUSE))
+ sunzilog_register_serio(up);
#endif
}
-static int __devinit zs_get_instance(struct device_node *dp)
-{
- int ret;
-
- ret = of_getintprop_default(dp, "slave", -1);
- if (ret != -1)
- return ret;
-
- if (of_find_property(dp, "keyboard", NULL))
- ret = 1;
- else
- ret = 0;
-
- return ret;
-}
-
static int zilog_irq = -1;
-static int __devinit zs_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devinit zs_probe(struct of_device *op, const struct of_device_id *match)
{
- struct of_device *op = to_of_device(&dev->dev);
+ static int inst;
struct uart_sunzilog_port *up;
struct zilog_layout __iomem *rp;
- int inst = zs_get_instance(dev->node);
+ int keyboard_mouse;
int err;
+ keyboard_mouse = 0;
+ if (of_find_property(op->node, "keyboard", NULL))
+ keyboard_mouse = 1;
+
sunzilog_chip_regs[inst] = of_ioremap(&op->resource[0], 0,
sizeof(struct zilog_layout),
"zs");
@@ -1352,16 +1337,8 @@ static int __devinit zs_probe(struct of_device *dev, const struct of_device_id *
rp = sunzilog_chip_regs[inst];
- if (zilog_irq == -1) {
+ if (zilog_irq == -1)
zilog_irq = op->irqs[0];
- err = request_irq(zilog_irq, sunzilog_interrupt, IRQF_SHARED,
- "zs", sunzilog_irq_chain);
- if (err) {
- of_iounmap(rp, sizeof(struct zilog_layout));
-
- return err;
- }
- }
up = &sunzilog_port_table[inst * 2];
@@ -1378,7 +1355,7 @@ static int __devinit zs_probe(struct of_device *dev, const struct of_device_id *
up[0].port.line = (inst * 2) + 0;
up[0].port.dev = &op->dev;
up[0].flags |= SUNZILOG_FLAG_IS_CHANNEL_A;
- if (inst == 1)
+ if (keyboard_mouse)
up[0].flags |= SUNZILOG_FLAG_CONS_KEYB;
sunzilog_init_hw(&up[0]);
@@ -1395,11 +1372,11 @@ static int __devinit zs_probe(struct of_device *dev, const struct of_device_id *
up[1].port.line = (inst * 2) + 1;
up[1].port.dev = &op->dev;
up[1].flags |= 0;
- if (inst == 1)
+ if (keyboard_mouse)
up[1].flags |= SUNZILOG_FLAG_CONS_MOUSE;
sunzilog_init_hw(&up[1]);
- if (inst != 1) {
+ if (!keyboard_mouse) {
err = uart_add_one_port(&sunzilog_reg, &up[0].port);
if (err) {
of_iounmap(rp, sizeof(struct zilog_layout));
@@ -1411,9 +1388,18 @@ static int __devinit zs_probe(struct of_device *dev, const struct of_device_id *
of_iounmap(rp, sizeof(struct zilog_layout));
return err;
}
+ } else {
+ printk(KERN_INFO "%s: Keyboard at MMIO %lx (irq = %d) "
+ "is a zs\n",
+ op->dev.bus_id, up[0].port.mapbase, op->irqs[0]);
+ printk(KERN_INFO "%s: Mouse at MMIO %lx (irq = %d) "
+ "is a zs\n",
+ op->dev.bus_id, up[1].port.mapbase, op->irqs[0]);
}
- dev_set_drvdata(&dev->dev, &up[0]);
+ dev_set_drvdata(&op->dev, &up[0]);
+
+ inst++;
return 0;
}
@@ -1462,36 +1448,65 @@ static struct of_platform_driver zs_driver = {
static int __init sunzilog_init(void)
{
struct device_node *dp;
- int err;
+ int err, uart_count;
+ int num_keybms;
NUM_SUNZILOG = 0;
- for_each_node_by_name(dp, "zs")
+ num_keybms = 0;
+ for_each_node_by_name(dp, "zs") {
NUM_SUNZILOG++;
+ if (of_find_property(dp, "keyboard", NULL))
+ num_keybms++;
+ }
+ uart_count = 0;
if (NUM_SUNZILOG) {
int uart_count;
err = sunzilog_alloc_tables();
if (err)
- return err;
+ goto out;
- /* Subtract 1 for keyboard, 1 for mouse. */
- uart_count = (NUM_SUNZILOG * 2) - 2;
+ uart_count = (NUM_SUNZILOG * 2) - (2 * num_keybms);
sunzilog_reg.nr = uart_count;
sunzilog_reg.minor = sunserial_current_minor;
err = uart_register_driver(&sunzilog_reg);
- if (err) {
- sunzilog_free_tables();
- return err;
- }
+ if (err)
+ goto out_free_tables;
+
sunzilog_reg.tty_driver->name_base = sunzilog_reg.minor - 64;
sunzilog_reg.cons = SUNZILOG_CONSOLE();
sunserial_current_minor += uart_count;
}
- return of_register_driver(&zs_driver, &of_bus_type);
+ err = of_register_driver(&zs_driver, &of_bus_type);
+ if (err)
+ goto out_unregister_uart;
+
+ if (zilog_irq != -1) {
+ err = request_irq(zilog_irq, sunzilog_interrupt, IRQF_SHARED,
+ "zs", sunzilog_irq_chain);
+ if (err)
+ goto out_unregister_driver;
+ }
+
+out:
+ return err;
+
+out_unregister_driver:
+ of_unregister_driver(&zs_driver);
+
+out_unregister_uart:
+ if (NUM_SUNZILOG) {
+ uart_unregister_driver(&sunzilog_reg);
+ sunzilog_reg.cons = NULL;
+ }
+
+out_free_tables:
+ sunzilog_free_tables();
+ goto out;
}
static void __exit sunzilog_exit(void)
diff --git a/drivers/serial/vr41xx_siu.c b/drivers/serial/vr41xx_siu.c
index e93d0edc2e0..6c8b0ea83c3 100644
--- a/drivers/serial/vr41xx_siu.c
+++ b/drivers/serial/vr41xx_siu.c
@@ -38,6 +38,7 @@
#include <linux/tty_flip.h>
#include <asm/io.h>
+#include <asm/vr41xx/irq.h>
#include <asm/vr41xx/siu.h>
#include <asm/vr41xx/vr41xx.h>
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 7fdbc5dad5f..00504319752 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -23,7 +23,8 @@ config USB_ARCH_HAS_OHCI
default y if ARCH_LH7A404
default y if ARCH_S3C2410
default y if PXA27x
- default y if ARCH_AT91RM9200
+ default y if ARCH_EP93XX
+ default y if (ARCH_AT91RM9200 || ARCH_AT91SAM9261)
# PPC:
default y if STB03xxx
default y if PPC_MPC52xx
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index c7123bf71c5..4710eb02ed6 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -48,7 +48,7 @@ obj-$(CONFIG_USB_MICROTEK) += image/
obj-$(CONFIG_USB_SERIAL) += serial/
obj-$(CONFIG_USB_AUERSWALD) += misc/
-obj-$(CONFIG_USB_CY7C63) += misc/
+obj-$(CONFIG_USB_CYPRESS_CY7C63)+= misc/
obj-$(CONFIG_USB_CYTHERM) += misc/
obj-$(CONFIG_USB_EMI26) += misc/
obj-$(CONFIG_USB_EMI62) += misc/
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 3670d77e912..ca90326f2f5 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -291,13 +291,13 @@ static void acm_read_bulk(struct urb *urb, struct pt_regs *regs)
struct acm_ru *rcv = urb->context;
struct acm *acm = rcv->instance;
int status = urb->status;
- dbg("Entering acm_read_bulk with status %d\n", urb->status);
+ dbg("Entering acm_read_bulk with status %d", urb->status);
if (!ACM_READY(acm))
return;
if (status)
- dev_dbg(&acm->data->dev, "bulk rx status %d\n", status);
+ dev_dbg(&acm->data->dev, "bulk rx status %d", status);
buf = rcv->buffer;
buf->size = urb->actual_length;
@@ -343,7 +343,7 @@ next_buffer:
list_del(&buf->list);
spin_unlock(&acm->read_lock);
- dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d\n", buf, buf->size);
+ dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size);
tty_buffer_request_room(tty, buf->size);
if (!acm->throttle)
@@ -394,7 +394,7 @@ urbs:
rcv->urb->transfer_dma = buf->dma;
rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
- dbg("acm_rx_tasklet: sending urb 0x%p, rcv 0x%p, buf 0x%p\n", rcv->urb, rcv, buf);
+ dbg("acm_rx_tasklet: sending urb 0x%p, rcv 0x%p, buf 0x%p", rcv->urb, rcv, buf);
/* This shouldn't kill the driver as unsuccessful URBs are returned to the
free-urbs-pool and resubmited ASAP */
@@ -413,7 +413,7 @@ static void acm_write_bulk(struct urb *urb, struct pt_regs *regs)
{
struct acm *acm = (struct acm *)urb->context;
- dbg("Entering acm_write_bulk with status %d\n", urb->status);
+ dbg("Entering acm_write_bulk with status %d", urb->status);
acm_write_done(acm);
acm_write_start(acm);
@@ -424,7 +424,7 @@ static void acm_write_bulk(struct urb *urb, struct pt_regs *regs)
static void acm_softint(void *private)
{
struct acm *acm = private;
- dbg("Entering acm_softint.\n");
+ dbg("Entering acm_softint.");
if (!ACM_READY(acm))
return;
@@ -440,7 +440,7 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
struct acm *acm;
int rv = -EINVAL;
int i;
- dbg("Entering acm_tty_open.\n");
+ dbg("Entering acm_tty_open.");
mutex_lock(&open_mutex);
@@ -541,7 +541,7 @@ static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int c
int wbn;
struct acm_wb *wb;
- dbg("Entering acm_tty_write to write %d bytes,\n", count);
+ dbg("Entering acm_tty_write to write %d bytes,", count);
if (!ACM_READY(acm))
return -EINVAL;
@@ -793,7 +793,7 @@ static int acm_probe (struct usb_interface *intf,
if (!buflen) {
if (intf->cur_altsetting->endpoint->extralen && intf->cur_altsetting->endpoint->extra) {
- dev_dbg(&intf->dev,"Seeking extra descriptors on endpoint\n");
+ dev_dbg(&intf->dev,"Seeking extra descriptors on endpoint");
buflen = intf->cur_altsetting->endpoint->extralen;
buffer = intf->cur_altsetting->endpoint->extra;
} else {
@@ -842,24 +842,24 @@ next_desc:
if (!union_header) {
if (call_interface_num > 0) {
- dev_dbg(&intf->dev,"No union descriptor, using call management descriptor\n");
+ dev_dbg(&intf->dev,"No union descriptor, using call management descriptor");
data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num));
control_interface = intf;
} else {
- dev_dbg(&intf->dev,"No union descriptor, giving up\n");
+ dev_dbg(&intf->dev,"No union descriptor, giving up");
return -ENODEV;
}
} else {
control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);
data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0));
if (!control_interface || !data_interface) {
- dev_dbg(&intf->dev,"no interfaces\n");
+ dev_dbg(&intf->dev,"no interfaces");
return -ENODEV;
}
}
if (data_interface_num != call_interface_num)
- dev_dbg(&intf->dev,"Seperate call control interface. That is not fully supported.\n");
+ dev_dbg(&intf->dev,"Seperate call control interface. That is not fully supported.");
skip_normal_probe:
@@ -867,7 +867,7 @@ skip_normal_probe:
if (data_interface->cur_altsetting->desc.bInterfaceClass != CDC_DATA_INTERFACE_TYPE) {
if (control_interface->cur_altsetting->desc.bInterfaceClass == CDC_DATA_INTERFACE_TYPE) {
struct usb_interface *t;
- dev_dbg(&intf->dev,"Your device has switched interfaces.\n");
+ dev_dbg(&intf->dev,"Your device has switched interfaces.");
t = control_interface;
control_interface = data_interface;
@@ -878,7 +878,7 @@ skip_normal_probe:
}
if (usb_interface_claimed(data_interface)) { /* valid in this context */
- dev_dbg(&intf->dev,"The data interface isn't available\n");
+ dev_dbg(&intf->dev,"The data interface isn't available");
return -EBUSY;
}
@@ -895,7 +895,7 @@ skip_normal_probe:
if ((epread->bEndpointAddress & USB_DIR_IN) != USB_DIR_IN) {
/* descriptors are swapped */
struct usb_endpoint_descriptor *t;
- dev_dbg(&intf->dev,"The data interface has switched endpoints\n");
+ dev_dbg(&intf->dev,"The data interface has switched endpoints");
t = epread;
epread = epwrite;
@@ -910,7 +910,7 @@ skip_normal_probe:
}
if (!(acm = kzalloc(sizeof(struct acm), GFP_KERNEL))) {
- dev_dbg(&intf->dev, "out of memory (acm kzalloc)\n");
+ dev_dbg(&intf->dev, "out of memory (acm kzalloc)");
goto alloc_fail;
}
@@ -936,26 +936,26 @@ skip_normal_probe:
buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
if (!buf) {
- dev_dbg(&intf->dev, "out of memory (ctrl buffer alloc)\n");
+ dev_dbg(&intf->dev, "out of memory (ctrl buffer alloc)");
goto alloc_fail2;
}
acm->ctrl_buffer = buf;
if (acm_write_buffers_alloc(acm) < 0) {
- dev_dbg(&intf->dev, "out of memory (write buffer alloc)\n");
+ dev_dbg(&intf->dev, "out of memory (write buffer alloc)");
goto alloc_fail4;
}
acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
if (!acm->ctrlurb) {
- dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)\n");
+ dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)");
goto alloc_fail5;
}
for (i = 0; i < num_rx_buf; i++) {
struct acm_ru *rcv = &(acm->ru[i]);
if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) {
- dev_dbg(&intf->dev, "out of memory (read urbs usb_alloc_urb)\n");
+ dev_dbg(&intf->dev, "out of memory (read urbs usb_alloc_urb)");
goto alloc_fail7;
}
@@ -966,13 +966,13 @@ skip_normal_probe:
struct acm_rb *buf = &(acm->rb[i]);
if (!(buf->base = usb_buffer_alloc(acm->dev, readsize, GFP_KERNEL, &buf->dma))) {
- dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)\n");
+ dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)");
goto alloc_fail7;
}
}
acm->writeurb = usb_alloc_urb(0, GFP_KERNEL);
if (!acm->writeurb) {
- dev_dbg(&intf->dev, "out of memory (writeurb kmalloc)\n");
+ dev_dbg(&intf->dev, "out of memory (writeurb kmalloc)");
goto alloc_fail7;
}
@@ -1086,6 +1086,9 @@ static struct usb_device_id acm_ids[] = {
{ USB_DEVICE(0x0ace, 0x1608), /* ZyDAS 56K USB MODEM */
.driver_info = SINGLE_RX_URB, /* firmware bug */
},
+ { USB_DEVICE(0x0ace, 0x1611), /* ZyDAS 56K USB MODEM - new version */
+ .driver_info = SINGLE_RX_URB, /* firmware bug */
+ },
/* control interfaces with various AT-command sets */
{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
USB_CDC_ACM_PROTO_AT_V25TER) },
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index a08787e253a..6e3b5358a76 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -31,9 +31,6 @@ config USB_DEVICEFS
For the format of the various /proc/bus/usb/ files, please read
<file:Documentation/usb/proc_usb_info.txt>.
- Please note that this code is completely unrelated to devfs, the
- "/dev file system support".
-
Most users want to say Y here.
config USB_BANDWIDTH
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index f7bdd94b3aa..218621b9958 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -517,19 +517,19 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig
static struct usb_device *usbdev_lookup_minor(int minor)
{
- struct device *device;
- struct usb_device *udev = NULL;
+ struct class_device *class_dev;
+ struct usb_device *dev = NULL;
down(&usb_device_class->sem);
- list_for_each_entry(device, &usb_device_class->devices, node) {
- if (device->devt == MKDEV(USB_DEVICE_MAJOR, minor)) {
- udev = device->platform_data;
+ list_for_each_entry(class_dev, &usb_device_class->children, node) {
+ if (class_dev->devt == MKDEV(USB_DEVICE_MAJOR, minor)) {
+ dev = class_dev->class_data;
break;
}
}
up(&usb_device_class->sem);
- return udev;
+ return dev;
};
/*
@@ -1580,16 +1580,16 @@ static void usbdev_add(struct usb_device *dev)
{
int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1);
- dev->usbfs_dev = device_create(usb_device_class, &dev->dev,
- MKDEV(USB_DEVICE_MAJOR, minor),
+ dev->class_dev = class_device_create(usb_device_class, NULL,
+ MKDEV(USB_DEVICE_MAJOR, minor), &dev->dev,
"usbdev%d.%d", dev->bus->busnum, dev->devnum);
- dev->usbfs_dev->platform_data = dev;
+ dev->class_dev->class_data = dev;
}
static void usbdev_remove(struct usb_device *dev)
{
- device_unregister(dev->usbfs_dev);
+ class_device_unregister(dev->class_dev);
}
static int usbdev_notify(struct notifier_block *self, unsigned long action,
diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c
index abee0f5b6a6..8de4f8c99d6 100644
--- a/drivers/usb/core/file.c
+++ b/drivers/usb/core/file.c
@@ -194,13 +194,14 @@ int usb_register_dev(struct usb_interface *intf,
++temp;
else
temp = name;
- intf->usb_dev = device_create(usb_class->class, &intf->dev,
- MKDEV(USB_MAJOR, minor), "%s", temp);
- if (IS_ERR(intf->usb_dev)) {
+ intf->class_dev = class_device_create(usb_class->class, NULL,
+ MKDEV(USB_MAJOR, minor),
+ &intf->dev, "%s", temp);
+ if (IS_ERR(intf->class_dev)) {
spin_lock (&minor_lock);
usb_minors[intf->minor] = NULL;
spin_unlock (&minor_lock);
- retval = PTR_ERR(intf->usb_dev);
+ retval = PTR_ERR(intf->class_dev);
}
exit:
return retval;
@@ -241,8 +242,8 @@ void usb_deregister_dev(struct usb_interface *intf,
spin_unlock (&minor_lock);
snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base);
- device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
- intf->usb_dev = NULL;
+ class_device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
+ intf->class_dev = NULL;
intf->minor = -1;
destroy_usb_class();
}
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 875596e98e4..26c8cb5f3e6 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1790,7 +1790,10 @@ static int finish_device_resume(struct usb_device *udev)
* and device drivers will know about any resume quirks.
*/
status = usb_get_status(udev, USB_RECIP_DEVICE, 0, &devstatus);
- if (status < 2)
+ if (status >= 0)
+ status = (status == 2 ? 0 : -ENODEV);
+
+ if (status)
dev_dbg(&udev->dev,
"gone after usb resume? status %d\n",
status);
@@ -1879,7 +1882,12 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
dev_dbg(hub->intfdev,
"port %d status %04x.%04x after resume, %d\n",
port1, portchange, devstatus, status);
+ if (status >= 0)
+ status = -ENODEV;
} else {
+ if (portchange & USB_PORT_STAT_C_SUSPEND)
+ clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_SUSPEND);
/* TRSMRCY = 10 msec */
msleep(10);
if (udev)
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
index f48c3dbc367..3182c2224ba 100644
--- a/drivers/usb/core/inode.c
+++ b/drivers/usb/core/inode.c
@@ -695,7 +695,7 @@ static void usbfs_remove_device(struct usb_device *dev)
wake_up_all(&ds->wait);
list_del_init(&ds->list);
if (ds->discsignr) {
- sinfo.si_signo = SIGPIPE;
+ sinfo.si_signo = ds->discsignr;
sinfo.si_errno = EPIPE;
sinfo.si_code = SI_ASYNCIO;
sinfo.si_addr = ds->disccontext;
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 363b2ad74ae..1a32d96774b 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -207,7 +207,7 @@ config USB_AT91
config USB_GADGET_DUMMY_HCD
boolean "Dummy HCD (DEVELOPMENT)"
- depends on USB && EXPERIMENTAL
+ depends on (USB=y || (USB=m && USB_GADGET=m)) && EXPERIMENTAL
select USB_GADGET_DUALSPEED
help
This host controller driver emulates USB, looping all data transfer
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index 1c459ff037c..cfebca05ead 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -57,19 +57,23 @@
/*
* This controller is simple and PIO-only. It's used in many AT91-series
- * ARMv4T controllers, including the at91rm9200 (arm920T, with MMU),
- * at91sam9261 (arm926ejs, with MMU), and several no-mmu versions.
+ * full speed USB controllers, including the at91rm9200 (arm920T, with MMU),
+ * at91sam926x (arm926ejs, with MMU), and several no-mmu versions.
*
* This driver expects the board has been wired with two GPIOs suppporting
* a VBUS sensing IRQ, and a D+ pullup. (They may be omitted, but the
- * testing hasn't covered such cases.) The pullup is most important; it
+ * testing hasn't covered such cases.)
+ *
+ * The pullup is most important (so it's integrated on sam926x parts). It
* provides software control over whether the host enumerates the device.
+ *
* The VBUS sensing helps during enumeration, and allows both USB clocks
* (and the transceiver) to stay gated off until they're necessary, saving
- * power. During USB suspend, the 48 MHz clock is gated off.
+ * power. During USB suspend, the 48 MHz clock is gated off in hardware;
+ * it may also be gated off by software during some Linux sleep states.
*/
-#define DRIVER_VERSION "8 March 2005"
+#define DRIVER_VERSION "3 May 2006"
static const char driver_name [] = "at91_udc";
static const char ep0name[] = "ep0";
@@ -316,9 +320,15 @@ static void done(struct at91_ep *ep, struct at91_request *req, int status)
*
* There are also state bits like FORCESTALL, EPEDS, DIR, and EPTYPE
* that shouldn't normally be changed.
+ *
+ * NOTE at91sam9260 docs mention synch between UDPCK and MCK clock domains,
+ * implying a need to wait for one write to complete (test relevant bits)
+ * before starting the next write. This shouldn't be an issue given how
+ * infrequently we write, except maybe for write-then-read idioms.
*/
#define SET_FX (AT91_UDP_TXPKTRDY)
-#define CLR_FX (RX_DATA_READY | AT91_UDP_RXSETUP | AT91_UDP_STALLSENT | AT91_UDP_TXCOMP)
+#define CLR_FX (RX_DATA_READY | AT91_UDP_RXSETUP \
+ | AT91_UDP_STALLSENT | AT91_UDP_TXCOMP)
/* pull OUT packet data from the endpoint's fifo */
static int read_fifo (struct at91_ep *ep, struct at91_request *req)
@@ -472,7 +482,8 @@ static void nuke(struct at91_ep *ep, int status)
/*-------------------------------------------------------------------------*/
-static int at91_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
+static int at91_ep_enable(struct usb_ep *_ep,
+ const struct usb_endpoint_descriptor *desc)
{
struct at91_ep *ep = container_of(_ep, struct at91_ep, ep);
struct at91_udc *dev = ep->udc;
@@ -582,11 +593,12 @@ static int at91_ep_disable (struct usb_ep * _ep)
* interesting for request or buffer allocation.
*/
-static struct usb_request *at91_ep_alloc_request (struct usb_ep *_ep, unsigned int gfp_flags)
+static struct usb_request *
+at91_ep_alloc_request(struct usb_ep *_ep, unsigned int gfp_flags)
{
struct at91_request *req;
- req = kcalloc(1, sizeof (struct at91_request), SLAB_KERNEL);
+ req = kcalloc(1, sizeof (struct at91_request), gfp_flags);
if (!req)
return NULL;
@@ -862,6 +874,7 @@ static void stop_activity(struct at91_udc *udc)
if (udc->gadget.speed == USB_SPEED_UNKNOWN)
driver = NULL;
udc->gadget.speed = USB_SPEED_UNKNOWN;
+ udc->suspended = 0;
for (i = 0; i < NUM_ENDPOINTS; i++) {
struct at91_ep *ep = &udc->ep[i];
@@ -889,8 +902,8 @@ static void clk_off(struct at91_udc *udc)
return;
udc->clocked = 0;
udc->gadget.speed = USB_SPEED_UNKNOWN;
- clk_disable(udc->iclk);
clk_disable(udc->fclk);
+ clk_disable(udc->iclk);
}
/*
@@ -911,9 +924,6 @@ static void pullup(struct at91_udc *udc, int is_on)
at91_udp_write(AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
at91_set_gpio_value(udc->board.pullup_pin, 0);
clk_off(udc);
-
- // REVISIT: with transceiver disabled, will D- float
- // so that a host would falsely detect a device?
}
}
@@ -1290,7 +1300,8 @@ static void handle_ep0(struct at91_udc *udc)
if (udc->wait_for_addr_ack) {
u32 tmp;
- at91_udp_write(AT91_UDP_FADDR, AT91_UDP_FEN | udc->addr);
+ at91_udp_write(AT91_UDP_FADDR,
+ AT91_UDP_FEN | udc->addr);
tmp = at91_udp_read(AT91_UDP_GLB_STAT);
tmp &= ~AT91_UDP_FADDEN;
if (udc->addr)
@@ -1361,9 +1372,10 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc, struct pt_regs *r)
u32 rescans = 5;
while (rescans--) {
- u32 status = at91_udp_read(AT91_UDP_ISR);
+ u32 status;
- status &= at91_udp_read(AT91_UDP_IMR);
+ status = at91_udp_read(AT91_UDP_ISR)
+ & at91_udp_read(AT91_UDP_IMR);
if (!status)
break;
@@ -1379,18 +1391,17 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc, struct pt_regs *r)
stop_activity(udc);
/* enable ep0 */
- at91_udp_write(AT91_UDP_CSR(0), AT91_UDP_EPEDS | AT91_UDP_EPTYPE_CTRL);
+ at91_udp_write(AT91_UDP_CSR(0),
+ AT91_UDP_EPEDS | AT91_UDP_EPTYPE_CTRL);
udc->gadget.speed = USB_SPEED_FULL;
udc->suspended = 0;
at91_udp_write(AT91_UDP_IER, AT91_UDP_EP(0));
/*
* NOTE: this driver keeps clocks off unless the
- * USB host is present. That saves power, and also
- * eliminates IRQs (reset, resume, suspend) that can
- * otherwise flood from the controller. If your
- * board doesn't support VBUS detection, suspend and
- * resume irq logic may need more attention...
+ * USB host is present. That saves power, but for
+ * boards that don't support VBUS detection, both
+ * clocks need to be active most of the time.
*/
/* host initiated suspend (3+ms bus idle) */
@@ -1452,13 +1463,19 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc, struct pt_regs *r)
/*-------------------------------------------------------------------------*/
+static void nop_release(struct device *dev)
+{
+ /* nothing to free */
+}
+
static struct at91_udc controller = {
.gadget = {
- .ops = &at91_udc_ops,
- .ep0 = &controller.ep[0].ep,
- .name = driver_name,
- .dev = {
- .bus_id = "gadget"
+ .ops = &at91_udc_ops,
+ .ep0 = &controller.ep[0].ep,
+ .name = driver_name,
+ .dev = {
+ .bus_id = "gadget",
+ .release = nop_release,
}
},
.ep[0] = {
@@ -1468,7 +1485,8 @@ static struct at91_udc controller = {
},
.udc = &controller,
.maxpacket = 8,
- .creg = (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(0)),
+ .creg = (void __iomem *)(AT91_VA_BASE_UDP
+ + AT91_UDP_CSR(0)),
.int_mask = 1 << 0,
},
.ep[1] = {
@@ -1479,7 +1497,8 @@ static struct at91_udc controller = {
.udc = &controller,
.is_pingpong = 1,
.maxpacket = 64,
- .creg = (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(1)),
+ .creg = (void __iomem *)(AT91_VA_BASE_UDP
+ + AT91_UDP_CSR(1)),
.int_mask = 1 << 1,
},
.ep[2] = {
@@ -1490,7 +1509,8 @@ static struct at91_udc controller = {
.udc = &controller,
.is_pingpong = 1,
.maxpacket = 64,
- .creg = (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(2)),
+ .creg = (void __iomem *)(AT91_VA_BASE_UDP
+ + AT91_UDP_CSR(2)),
.int_mask = 1 << 2,
},
.ep[3] = {
@@ -1501,7 +1521,8 @@ static struct at91_udc controller = {
},
.udc = &controller,
.maxpacket = 8,
- .creg = (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(3)),
+ .creg = (void __iomem *)(AT91_VA_BASE_UDP
+ + AT91_UDP_CSR(3)),
.int_mask = 1 << 3,
},
.ep[4] = {
@@ -1512,7 +1533,8 @@ static struct at91_udc controller = {
.udc = &controller,
.is_pingpong = 1,
.maxpacket = 256,
- .creg = (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(4)),
+ .creg = (void __iomem *)(AT91_VA_BASE_UDP
+ + AT91_UDP_CSR(4)),
.int_mask = 1 << 4,
},
.ep[5] = {
@@ -1523,10 +1545,11 @@ static struct at91_udc controller = {
.udc = &controller,
.is_pingpong = 1,
.maxpacket = 256,
- .creg = (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(5)),
+ .creg = (void __iomem *)(AT91_VA_BASE_UDP
+ + AT91_UDP_CSR(5)),
.int_mask = 1 << 5,
},
- /* ep6 and ep7 are also reserved */
+ /* ep6 and ep7 are also reserved (custom silicon might use them) */
};
static irqreturn_t at91_vbus_irq(int irq, void *_udc, struct pt_regs *r)
@@ -1593,6 +1616,7 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
local_irq_disable();
udc->enabled = 0;
+ at91_udp_write(AT91_UDP_IDR, ~0);
pullup(udc, 0);
local_irq_enable();
@@ -1624,6 +1648,16 @@ static int __devinit at91udc_probe(struct platform_device *pdev)
return -ENODEV;
}
+ if (pdev->num_resources != 2) {
+ DBG("invalid num_resources");
+ return -ENODEV;
+ }
+ if ((pdev->resource[0].flags != IORESOURCE_MEM)
+ || (pdev->resource[1].flags != IORESOURCE_IRQ)) {
+ DBG("invalid resource type");
+ return -ENODEV;
+ }
+
if (!request_mem_region(AT91_BASE_UDP, SZ_16K, driver_name)) {
DBG("someone's using UDC memory\n");
return -EBUSY;
@@ -1649,19 +1683,26 @@ static int __devinit at91udc_probe(struct platform_device *pdev)
if (retval < 0)
goto fail0;
- /* disable everything until there's a gadget driver and vbus */
- pullup(udc, 0);
+ /* don't do anything until we have both gadget driver and VBUS */
+ clk_enable(udc->iclk);
+ at91_udp_write(AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
+ at91_udp_write(AT91_UDP_IDR, 0xffffffff);
+ clk_disable(udc->iclk);
/* request UDC and maybe VBUS irqs */
- if (request_irq(AT91_ID_UDP, at91_udc_irq, IRQF_DISABLED, driver_name, udc)) {
- DBG("request irq %d failed\n", AT91_ID_UDP);
+ udc->udp_irq = platform_get_irq(pdev, 0);
+ if (request_irq(udc->udp_irq, at91_udc_irq,
+ IRQF_DISABLED, driver_name, udc)) {
+ DBG("request irq %d failed\n", udc->udp_irq);
retval = -EBUSY;
goto fail1;
}
if (udc->board.vbus_pin > 0) {
- if (request_irq(udc->board.vbus_pin, at91_vbus_irq, IRQF_DISABLED, driver_name, udc)) {
- DBG("request vbus irq %d failed\n", udc->board.vbus_pin);
- free_irq(AT91_ID_UDP, udc);
+ if (request_irq(udc->board.vbus_pin, at91_vbus_irq,
+ IRQF_DISABLED, driver_name, udc)) {
+ DBG("request vbus irq %d failed\n",
+ udc->board.vbus_pin);
+ free_irq(udc->udp_irq, udc);
retval = -EBUSY;
goto fail1;
}
@@ -1670,6 +1711,7 @@ static int __devinit at91udc_probe(struct platform_device *pdev)
udc->vbus = 1;
}
dev_set_drvdata(dev, udc);
+ device_init_wakeup(dev, 1);
create_debug_file(udc);
INFO("%s version %s\n", driver_name, DRIVER_VERSION);
@@ -1678,14 +1720,14 @@ static int __devinit at91udc_probe(struct platform_device *pdev)
fail1:
device_unregister(&udc->gadget.dev);
fail0:
- release_mem_region(AT91_VA_BASE_UDP, SZ_16K);
+ release_mem_region(AT91_BASE_UDP, SZ_16K);
DBG("%s probe failed, %d\n", driver_name, retval);
return retval;
}
-static int __devexit at91udc_remove(struct platform_device *dev)
+static int __devexit at91udc_remove(struct platform_device *pdev)
{
- struct at91_udc *udc = platform_get_drvdata(dev);
+ struct at91_udc *udc = platform_get_drvdata(pdev);
DBG("remove\n");
@@ -1694,10 +1736,11 @@ static int __devexit at91udc_remove(struct platform_device *dev)
if (udc->driver != 0)
usb_gadget_unregister_driver(udc->driver);
+ device_init_wakeup(&pdev->dev, 0);
remove_debug_file(udc);
if (udc->board.vbus_pin > 0)
free_irq(udc->board.vbus_pin, udc);
- free_irq(AT91_ID_UDP, udc);
+ free_irq(udc->udp_irq, udc);
device_unregister(&udc->gadget.dev);
release_mem_region(AT91_BASE_UDP, SZ_16K);
@@ -1708,31 +1751,36 @@ static int __devexit at91udc_remove(struct platform_device *dev)
}
#ifdef CONFIG_PM
-static int at91udc_suspend(struct platform_device *dev, pm_message_t mesg)
+static int at91udc_suspend(struct platform_device *pdev, pm_message_t mesg)
{
- struct at91_udc *udc = platform_get_drvdata(dev);
+ struct at91_udc *udc = platform_get_drvdata(pdev);
+ int wake = udc->driver && device_may_wakeup(&pdev->dev);
- /*
- * The "safe" suspend transitions are opportunistic ... e.g. when
- * the USB link is suspended (48MHz clock autogated off), or when
- * it's disconnected (programmatically gated off, elsewhere).
- * Then we can suspend, and the chip can enter slow clock mode.
- *
- * The problem case is some component (user mode?) suspending this
- * device while it's active, with the 48 MHz clock in use. There
- * are two basic approaches: (a) veto suspend levels involving slow
- * clock mode, (b) disconnect, so 48 MHz will no longer be in use
- * and we can enter slow clock mode. This uses (b) for now, since
- * it's simplest until AT91 PM exists and supports the other option.
+ /* Unless we can act normally to the host (letting it wake us up
+ * whenever it has work for us) force disconnect. Wakeup requires
+ * PLLB for USB events (signaling for reset, wakeup, or incoming
+ * tokens) and VBUS irqs (on systems which support them).
*/
- if (udc->vbus && !udc->suspended)
+ if ((!udc->suspended && udc->addr)
+ || !wake
+ || at91_suspend_entering_slow_clock()) {
pullup(udc, 0);
+ disable_irq_wake(udc->udp_irq);
+ } else
+ enable_irq_wake(udc->udp_irq);
+
+ if (udc->board.vbus_pin > 0) {
+ if (wake)
+ enable_irq_wake(udc->board.vbus_pin);
+ else
+ disable_irq_wake(udc->board.vbus_pin);
+ }
return 0;
}
-static int at91udc_resume(struct platform_device *dev)
+static int at91udc_resume(struct platform_device *pdev)
{
- struct at91_udc *udc = platform_get_drvdata(dev);
+ struct at91_udc *udc = platform_get_drvdata(pdev);
/* maybe reconnect to host; if so, clocks on */
pullup(udc, 1);
@@ -1748,7 +1796,7 @@ static struct platform_driver at91_udc = {
.remove = __devexit_p(at91udc_remove),
.shutdown = at91udc_shutdown,
.suspend = at91udc_suspend,
- .resume = at91udc_resume,
+ .resume = at91udc_resume,
.driver = {
.name = (char *) driver_name,
.owner = THIS_MODULE,
@@ -1767,6 +1815,6 @@ static void __devexit udc_exit_module(void)
}
module_exit(udc_exit_module);
-MODULE_DESCRIPTION("AT91RM9200 udc driver");
+MODULE_DESCRIPTION("AT91 udc driver");
MODULE_AUTHOR("Thomas Rathbone, David Brownell");
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h
index 5a4799cedd1..882af42e86c 100644
--- a/drivers/usb/gadget/at91_udc.h
+++ b/drivers/usb/gadget/at91_udc.h
@@ -141,6 +141,7 @@ struct at91_udc {
struct clk *iclk, *fclk;
struct platform_device *pdev;
struct proc_dir_entry *pde;
+ int udp_irq;
};
static inline struct at91_udc *to_udc(struct usb_gadget *g)
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index 4be47195bd3..7d1c22c3495 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -609,7 +609,8 @@ static int dummy_dequeue (struct usb_ep *_ep, struct usb_request *_req)
if (!dum->driver)
return -ESHUTDOWN;
- spin_lock_irqsave (&dum->lock, flags);
+ local_irq_save (flags);
+ spin_lock (&dum->lock);
list_for_each_entry (req, &ep->queue, queue) {
if (&req->req == _req) {
list_del_init (&req->queue);
@@ -618,7 +619,7 @@ static int dummy_dequeue (struct usb_ep *_ep, struct usb_request *_req)
break;
}
}
- spin_unlock_irqrestore (&dum->lock, flags);
+ spin_unlock (&dum->lock);
if (retval == 0) {
dev_dbg (udc_dev(dum),
@@ -626,6 +627,7 @@ static int dummy_dequeue (struct usb_ep *_ep, struct usb_request *_req)
req, _ep->name, _req->length, _req->buf);
_req->complete (_ep, _req);
}
+ local_irq_restore (flags);
return retval;
}
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index f7c6d758e1b..53d584589c2 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -34,12 +34,12 @@
/* we must assign addresses for configurable endpoints (like net2280) */
-static __initdata unsigned epnum;
+static __devinitdata unsigned epnum;
// #define MANY_ENDPOINTS
#ifdef MANY_ENDPOINTS
/* more than 15 configurable endpoints */
-static __initdata unsigned in_epnum;
+static __devinitdata unsigned in_epnum;
#endif
@@ -59,7 +59,7 @@ static __initdata unsigned in_epnum;
* NOTE: each endpoint is unidirectional, as specified by its USB
* descriptor; and isn't specific to a configuration or altsetting.
*/
-static int __init
+static int __devinit
ep_matches (
struct usb_gadget *gadget,
struct usb_ep *ep,
@@ -73,7 +73,7 @@ ep_matches (
/* endpoint already claimed? */
if (0 != ep->driver_data)
return 0;
-
+
/* only support ep0 for portable CONTROL traffic */
type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
if (USB_ENDPOINT_XFER_CONTROL == type)
@@ -186,7 +186,7 @@ ep_matches (
return 1;
}
-static struct usb_ep * __init
+static struct usb_ep * __devinit
find_ep (struct usb_gadget *gadget, const char *name)
{
struct usb_ep *ep;
@@ -228,7 +228,7 @@ find_ep (struct usb_gadget *gadget, const char *name)
*
* On failure, this returns a null endpoint descriptor.
*/
-struct usb_ep * __init usb_ep_autoconfig (
+struct usb_ep * __devinit usb_ep_autoconfig (
struct usb_gadget *gadget,
struct usb_endpoint_descriptor *desc
)
@@ -276,7 +276,7 @@ struct usb_ep * __init usb_ep_autoconfig (
return ep;
}
- /* Second, look at endpoints until an unclaimed one looks usable */
+ /* Second, look at endpoints until an unclaimed one looks usable */
list_for_each_entry (ep, &gadget->ep_list, ep_list) {
if (ep_matches (gadget, ep, desc))
return ep;
@@ -295,7 +295,7 @@ struct usb_ep * __init usb_ep_autoconfig (
* state such as ep->driver_data and the record of assigned endpoints
* used by usb_ep_autoconfig().
*/
-void __init usb_ep_autoconfig_reset (struct usb_gadget *gadget)
+void __devinit usb_ep_autoconfig_reset (struct usb_gadget *gadget)
{
struct usb_ep *ep;
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index 8320fcef042..4fe1bec1c25 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -2131,7 +2131,7 @@ eth_req_free (struct usb_ep *ep, struct usb_request *req)
}
-static void __exit
+static void /* __init_or_exit */
eth_unbind (struct usb_gadget *gadget)
{
struct eth_dev *dev = get_gadget_data (gadget);
@@ -2158,7 +2158,7 @@ eth_unbind (struct usb_gadget *gadget)
set_gadget_data (gadget, NULL);
}
-static u8 __init nibble (unsigned char c)
+static u8 __devinit nibble (unsigned char c)
{
if (likely (isdigit (c)))
return c - '0';
@@ -2168,7 +2168,7 @@ static u8 __init nibble (unsigned char c)
return 0;
}
-static int __init get_ether_addr(const char *str, u8 *dev_addr)
+static int __devinit get_ether_addr(const char *str, u8 *dev_addr)
{
if (str) {
unsigned i;
@@ -2189,7 +2189,7 @@ static int __init get_ether_addr(const char *str, u8 *dev_addr)
return 1;
}
-static int __init
+static int __devinit
eth_bind (struct usb_gadget *gadget)
{
struct eth_dev *dev;
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index b1a9cf06f3e..8d7f1e84cd7 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -3691,7 +3691,7 @@ static void lun_release(struct device *dev)
kref_put(&fsg->ref, fsg_release);
}
-static void __exit fsg_unbind(struct usb_gadget *gadget)
+static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget)
{
struct fsg_dev *fsg = get_gadget_data(gadget);
int i;
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index 354670d1230..408c3380d60 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -1398,7 +1398,7 @@ static struct proc_dir_entry *rndis_connect_state [RNDIS_MAX_CONFIGS];
#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
-int __init rndis_init (void)
+int __devinit rndis_init (void)
{
u8 i;
diff --git a/drivers/usb/gadget/rndis.h b/drivers/usb/gadget/rndis.h
index 2956608be75..4c3c7259f01 100644
--- a/drivers/usb/gadget/rndis.h
+++ b/drivers/usb/gadget/rndis.h
@@ -264,7 +264,7 @@ int rndis_signal_disconnect (int configNr);
int rndis_state (int configNr);
extern void rndis_set_host_mac (int configNr, const u8 *addr);
-int __init rndis_init (void);
+int __devinit rndis_init (void);
void rndis_exit (void);
#endif /* _LINUX_RNDIS_H */
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index 30d7664d449..e762aa19ab0 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -1473,7 +1473,7 @@ autoconf_fail:
* Called on module unload. Frees the control request and device
* structure.
*/
-static void __exit gs_unbind(struct usb_gadget *gadget)
+static void /* __init_or_exit */ gs_unbind(struct usb_gadget *gadget)
{
struct gs_dev *dev = get_gadget_data(gadget);
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
index 3a08a7ab4ce..b7018ee487e 100644
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -1121,7 +1121,7 @@ zero_autoresume (unsigned long _dev)
/*-------------------------------------------------------------------------*/
-static void __exit
+static void /* __init_or_exit */
zero_unbind (struct usb_gadget *gadget)
{
struct zero_dev *dev = get_gadget_data (gadget);
diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c
index d66867aa527..26ed757d22a 100644
--- a/drivers/usb/host/ehci-au1xxx.c
+++ b/drivers/usb/host/ehci-au1xxx.c
@@ -41,8 +41,6 @@
#endif
#define USBH_DISABLE (USB_MCFG_EBMEN | USB_MCFG_EMEMEN)
-#endif /* Au1200 */
-
extern int usb_disabled(void);
/*-------------------------------------------------------------------------*/
@@ -107,9 +105,9 @@ int usb_ehci_au1xxx_probe(const struct hc_driver *driver,
/* Au1200 AB USB does not support coherent memory */
if (!(read_c0_prid() & 0xff)) {
- pr_info("%s: this is chip revision AB!\n", dev->dev.name);
+ pr_info("%s: this is chip revision AB!\n", dev->name);
pr_info("%s: update your board or re-configure the kernel\n",
- dev->dev.name);
+ dev->name);
return -ENODEV;
}
#endif
@@ -228,9 +226,8 @@ static const struct hc_driver ehci_au1xxx_hc_driver = {
/*-------------------------------------------------------------------------*/
-static int ehci_hcd_au1xxx_drv_probe(struct device *dev)
+static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
{
- struct platform_device *pdev = to_platform_device(dev);
struct usb_hcd *hcd = NULL;
int ret;
@@ -243,10 +240,9 @@ static int ehci_hcd_au1xxx_drv_probe(struct device *dev)
return ret;
}
-static int ehci_hcd_au1xxx_drv_remove(struct device *dev)
+static int ehci_hcd_au1xxx_drv_remove(struct platform_device *pdev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
usb_ehci_au1xxx_remove(hcd, pdev);
return 0;
@@ -269,12 +265,13 @@ static int ehci_hcd_au1xxx_drv_resume(struct device *dev)
}
*/
MODULE_ALIAS("au1xxx-ehci");
-/* FIXME use "struct platform_driver" */
-static struct device_driver ehci_hcd_au1xxx_driver = {
- .name = "au1xxx-ehci",
- .bus = &platform_bus_type,
+static struct platform_driver ehci_hcd_au1xxx_driver = {
.probe = ehci_hcd_au1xxx_drv_probe,
.remove = ehci_hcd_au1xxx_drv_remove,
/*.suspend = ehci_hcd_au1xxx_drv_suspend, */
/*.resume = ehci_hcd_au1xxx_drv_resume, */
+ .driver = {
+ .name = "au1xxx-ehci",
+ .bus = &platform_bus_type
+ }
};
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index cee6f538de0..d63177a8eae 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -625,10 +625,11 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs)
writel (status | CMD_RUN, &ehci->regs->command);
while (i--) {
- status = readl (&ehci->regs->port_status [i]);
- if (status & PORT_OWNER)
+ int pstatus = readl (&ehci->regs->port_status [i]);
+
+ if (pstatus & PORT_OWNER)
continue;
- if (!(status & PORT_RESUME)
+ if (!(pstatus & PORT_RESUME)
|| ehci->reset_done [i] != 0)
continue;
@@ -891,7 +892,7 @@ MODULE_LICENSE ("GPL");
#define PCI_DRIVER ehci_pci_driver
#endif
-#ifdef CONFIG_PPC_83xx
+#ifdef CONFIG_MPC834x
#include "ehci-fsl.c"
#define PLATFORM_DRIVER ehci_fsl_driver
#endif
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index cdbafb71000..85cc059705a 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -4,7 +4,7 @@
* Copyright (C) 2004 SAN People (Pty) Ltd.
* Copyright (C) 2005 Thibaut VARENE <varenet@parisc-linux.org>
*
- * AT91RM9200 Bus Glue
+ * AT91 Bus Glue
*
* Based on fragments of 2.4 driver by Rick Bronson.
* Based on ohci-omap.c
@@ -19,12 +19,13 @@
#include <asm/hardware.h>
#include <asm/arch/board.h>
-#ifndef CONFIG_ARCH_AT91RM9200
-#error "CONFIG_ARCH_AT91RM9200 must be defined."
+#ifndef CONFIG_ARCH_AT91
+#error "CONFIG_ARCH_AT91 must be defined."
#endif
/* interface and function clocks */
static struct clk *iclk, *fclk;
+static int clocked;
extern int usb_disabled(void);
@@ -35,13 +36,14 @@ static void at91_start_hc(struct platform_device *pdev)
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct ohci_regs __iomem *regs = hcd->regs;
- dev_dbg(&pdev->dev, "starting AT91RM9200 OHCI USB Controller\n");
+ dev_dbg(&pdev->dev, "start\n");
/*
* Start the USB clocks.
*/
clk_enable(iclk);
clk_enable(fclk);
+ clocked = 1;
/*
* The USB host controller must remain in reset.
@@ -54,7 +56,7 @@ static void at91_stop_hc(struct platform_device *pdev)
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct ohci_regs __iomem *regs = hcd->regs;
- dev_dbg(&pdev->dev, "stopping AT91RM9200 OHCI USB Controller\n");
+ dev_dbg(&pdev->dev, "stop\n");
/*
* Put the USB host controller into reset.
@@ -66,6 +68,7 @@ static void at91_stop_hc(struct platform_device *pdev)
*/
clk_disable(fclk);
clk_disable(iclk);
+ clocked = 0;
}
@@ -78,14 +81,15 @@ static int usb_hcd_at91_remove (struct usb_hcd *, struct platform_device *);
/**
- * usb_hcd_at91_probe - initialize AT91RM9200-based HCDs
+ * usb_hcd_at91_probe - initialize AT91-based HCDs
* Context: !in_interrupt()
*
* Allocates basic resources for this USB host controller, and
* then invokes the start() method for the HCD associated with it
* through the hotplug entry's driver_data.
*/
-int usb_hcd_at91_probe (const struct hc_driver *driver, struct platform_device *pdev)
+static int usb_hcd_at91_probe(const struct hc_driver *driver,
+ struct platform_device *pdev)
{
int retval;
struct usb_hcd *hcd = NULL;
@@ -95,12 +99,13 @@ int usb_hcd_at91_probe (const struct hc_driver *driver, struct platform_device *
return -ENODEV;
}
- if ((pdev->resource[0].flags != IORESOURCE_MEM) || (pdev->resource[1].flags != IORESOURCE_IRQ)) {
+ if ((pdev->resource[0].flags != IORESOURCE_MEM)
+ || (pdev->resource[1].flags != IORESOURCE_IRQ)) {
pr_debug("hcd probe: invalid resource type\n");
return -ENODEV;
}
- hcd = usb_create_hcd(driver, &pdev->dev, "at91rm9200");
+ hcd = usb_create_hcd(driver, &pdev->dev, "at91");
if (!hcd)
return -ENOMEM;
hcd->rsrc_start = pdev->resource[0].start;
@@ -149,21 +154,23 @@ int usb_hcd_at91_probe (const struct hc_driver *driver, struct platform_device *
/* may be called with controller, bus, and devices active */
/**
- * usb_hcd_at91_remove - shutdown processing for AT91RM9200-based HCDs
+ * usb_hcd_at91_remove - shutdown processing for AT91-based HCDs
* @dev: USB Host Controller being removed
* Context: !in_interrupt()
*
* Reverses the effect of usb_hcd_at91_probe(), first invoking
* the HCD's stop() method. It is always called from a thread
- * context, normally "rmmod", "apmd", or something similar.
+ * context, "rmmod" or something similar.
*
*/
-static int usb_hcd_at91_remove (struct usb_hcd *hcd, struct platform_device *pdev)
+static int usb_hcd_at91_remove(struct usb_hcd *hcd,
+ struct platform_device *pdev)
{
usb_remove_hcd(hcd);
at91_stop_hc(pdev);
iounmap(hcd->regs);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ disable_irq_wake(hcd->irq);
clk_put(fclk);
clk_put(iclk);
@@ -178,19 +185,21 @@ static int usb_hcd_at91_remove (struct usb_hcd *hcd, struct platform_device *pde
static int __devinit
ohci_at91_start (struct usb_hcd *hcd)
{
-// struct at91_ohci_data *board = hcd->self.controller->platform_data;
+ struct at91_usbh_data *board = hcd->self.controller->platform_data;
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+ struct usb_device *root = hcd->self.root_hub;
int ret;
if ((ret = ohci_init(ohci)) < 0)
return ret;
+ root->maxchild = board->ports;
+
if ((ret = ohci_run(ohci)) < 0) {
err("can't start %s", hcd->self.bus_name);
ohci_stop(hcd);
return ret;
}
-// hcd->self.root_hub->maxchild = board->ports;
return 0;
}
@@ -198,7 +207,7 @@ ohci_at91_start (struct usb_hcd *hcd)
static const struct hc_driver ohci_at91_hc_driver = {
.description = hcd_name,
- .product_desc = "AT91RM9200 OHCI",
+ .product_desc = "AT91 OHCI",
.hcd_priv_size = sizeof(struct ohci_hcd),
/*
@@ -240,33 +249,54 @@ static const struct hc_driver ohci_at91_hc_driver = {
/*-------------------------------------------------------------------------*/
-static int ohci_hcd_at91_drv_probe(struct platform_device *dev)
+static int ohci_hcd_at91_drv_probe(struct platform_device *pdev)
{
- return usb_hcd_at91_probe(&ohci_at91_hc_driver, dev);
+ device_init_wakeup(&pdev->dev, 1);
+ return usb_hcd_at91_probe(&ohci_at91_hc_driver, pdev);
}
-static int ohci_hcd_at91_drv_remove(struct platform_device *dev)
+static int ohci_hcd_at91_drv_remove(struct platform_device *pdev)
{
- return usb_hcd_at91_remove(platform_get_drvdata(dev), dev);
+ device_init_wakeup(&pdev->dev, 0);
+ return usb_hcd_at91_remove(platform_get_drvdata(pdev), pdev);
}
#ifdef CONFIG_PM
-/* REVISIT suspend/resume look "too" simple here */
-
static int
-ohci_hcd_at91_drv_suspend(struct platform_device *dev, pm_message_t mesg)
+ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg)
{
- clk_disable(fclk);
- clk_disable(iclk);
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+
+ if (device_may_wakeup(&pdev->dev))
+ enable_irq_wake(hcd->irq);
+ else
+ disable_irq_wake(hcd->irq);
+
+ /*
+ * The integrated transceivers seem unable to notice disconnect,
+ * reconnect, or wakeup without the 48 MHz clock active. so for
+ * correctness, always discard connection state (using reset).
+ *
+ * REVISIT: some boards will be able to turn VBUS off...
+ */
+ if (at91_suspend_entering_slow_clock()) {
+ ohci_usb_reset (ohci);
+ clk_disable(fclk);
+ clk_disable(iclk);
+ clocked = 0;
+ }
return 0;
}
-static int ohci_hcd_at91_drv_resume(struct platform_device *dev)
+static int ohci_hcd_at91_drv_resume(struct platform_device *pdev)
{
- clk_enable(iclk);
- clk_enable(fclk);
+ if (!clocked) {
+ clk_enable(iclk);
+ clk_enable(fclk);
+ }
return 0;
}
@@ -275,7 +305,7 @@ static int ohci_hcd_at91_drv_resume(struct platform_device *dev)
#define ohci_hcd_at91_drv_resume NULL
#endif
-MODULE_ALIAS("at91rm9200-ohci");
+MODULE_ALIAS("at91_ohci");
static struct platform_driver ohci_hcd_at91_driver = {
.probe = ohci_hcd_at91_drv_probe,
@@ -283,7 +313,7 @@ static struct platform_driver ohci_hcd_at91_driver = {
.suspend = ohci_hcd_at91_drv_suspend,
.resume = ohci_hcd_at91_drv_resume,
.driver = {
- .name = "at91rm9200-ohci",
+ .name = "at91_ohci",
.owner = THIS_MODULE,
},
};
diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c
index 689261e4401..822914e2f43 100644
--- a/drivers/usb/host/ohci-au1xxx.c
+++ b/drivers/usb/host/ohci-au1xxx.c
@@ -101,13 +101,16 @@ static void au1xxx_start_ohc(struct platform_device *dev)
#endif /* Au1200 */
+#ifndef CONFIG_SOC_AU1200
/* wait for reset complete (read register twice; see au1500 errata) */
while (au_readl(USB_HOST_CONFIG),
!(au_readl(USB_HOST_CONFIG) & USBH_ENABLE_RD))
+#endif
udelay(1000);
printk(KERN_DEBUG __FILE__
": Clock to USB host has been enabled \n");
+#endif
}
static void au1xxx_stop_ohc(struct platform_device *dev)
@@ -157,9 +160,9 @@ static int usb_ohci_au1xxx_probe(const struct hc_driver *driver,
/* Au1200 AB USB does not support coherent memory */
if (!(read_c0_prid() & 0xff)) {
pr_info("%s: this is chip revision AB !!\n",
- dev->dev.name);
+ dev->name);
pr_info("%s: update your board or re-configure the kernel\n",
- dev->dev.name);
+ dev->name);
return -ENODEV;
}
#endif
diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c
new file mode 100644
index 00000000000..6531c4d2652
--- /dev/null
+++ b/drivers/usb/host/ohci-ep93xx.c
@@ -0,0 +1,225 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2002 Hewlett-Packard Company
+ *
+ * Bus Glue for ep93xx.
+ *
+ * Written by Christopher Hoover <ch@hpl.hp.com>
+ * Based on fragments of previous driver by Russell King et al.
+ *
+ * Modified for LH7A404 from ohci-sa1111.c
+ * by Durgesh Pattamatta <pattamattad@sharpsec.com>
+ *
+ * Modified for pxa27x from ohci-lh7a404.c
+ * by Nick Bane <nick@cecomputing.co.uk> 26-8-2004
+ *
+ * Modified for ep93xx from ohci-pxa27x.c
+ * by Lennert Buytenhek <buytenh@wantstofly.org> 28-2-2006
+ * Based on an earlier driver by Ray Lehtiniemi
+ *
+ * This file is licenced under the GPL.
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/signal.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+
+static struct clk *usb_host_clock;
+
+static void ep93xx_start_hc(struct device *dev)
+{
+ clk_enable(usb_host_clock);
+}
+
+static void ep93xx_stop_hc(struct device *dev)
+{
+ clk_disable(usb_host_clock);
+}
+
+static int usb_hcd_ep93xx_probe(const struct hc_driver *driver,
+ struct platform_device *pdev)
+{
+ int retval;
+ struct usb_hcd *hcd;
+
+ if (pdev->resource[1].flags != IORESOURCE_IRQ) {
+ pr_debug("resource[1] is not IORESOURCE_IRQ");
+ return -ENOMEM;
+ }
+
+ hcd = usb_create_hcd(driver, &pdev->dev, "ep93xx");
+ if (hcd == NULL)
+ return -ENOMEM;
+
+ hcd->rsrc_start = pdev->resource[0].start;
+ hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+ usb_put_hcd(hcd);
+ retval = -EBUSY;
+ goto err1;
+ }
+
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (hcd->regs == NULL) {
+ pr_debug("ioremap failed");
+ retval = -ENOMEM;
+ goto err2;
+ }
+
+ usb_host_clock = clk_get(&pdev->dev, "usb_host");
+ ep93xx_start_hc(&pdev->dev);
+
+ ohci_hcd_init(hcd_to_ohci(hcd));
+
+ retval = usb_add_hcd(hcd, pdev->resource[1].start, SA_INTERRUPT);
+ if (retval == 0)
+ return retval;
+
+ ep93xx_stop_hc(&pdev->dev);
+ iounmap(hcd->regs);
+err2:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err1:
+ usb_put_hcd(hcd);
+
+ return retval;
+}
+
+static void usb_hcd_ep93xx_remove(struct usb_hcd *hcd,
+ struct platform_device *pdev)
+{
+ usb_remove_hcd(hcd);
+ ep93xx_stop_hc(&pdev->dev);
+ clk_put(usb_host_clock);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+}
+
+static int __devinit ohci_ep93xx_start(struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+ int ret;
+
+ if ((ret = ohci_init(ohci)) < 0)
+ return ret;
+
+ if ((ret = ohci_run(ohci)) < 0) {
+ err("can't start %s", hcd->self.bus_name);
+ ohci_stop(hcd);
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct hc_driver ohci_ep93xx_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "EP93xx OHCI",
+ .hcd_priv_size = sizeof(struct ohci_hcd),
+ .irq = ohci_irq,
+ .flags = HCD_USB11 | HCD_MEMORY,
+ .start = ohci_ep93xx_start,
+ .stop = ohci_stop,
+ .urb_enqueue = ohci_urb_enqueue,
+ .urb_dequeue = ohci_urb_dequeue,
+ .endpoint_disable = ohci_endpoint_disable,
+ .get_frame_number = ohci_get_frame,
+ .hub_status_data = ohci_hub_status_data,
+ .hub_control = ohci_hub_control,
+#ifdef CONFIG_PM
+ .bus_suspend = ohci_bus_suspend,
+ .bus_resume = ohci_bus_resume,
+#endif
+ .start_port_reset = ohci_start_port_reset,
+};
+
+extern int usb_disabled(void);
+
+static int ohci_hcd_ep93xx_drv_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ ret = -ENODEV;
+ if (!usb_disabled())
+ ret = usb_hcd_ep93xx_probe(&ohci_ep93xx_hc_driver, pdev);
+
+ return ret;
+}
+
+static int ohci_hcd_ep93xx_drv_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+ usb_hcd_ep93xx_remove(hcd, pdev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int ohci_hcd_ep93xx_drv_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct ochi_hcd *ohci = hcd_to_ohci(hcd);
+
+ if (time_before(jiffies, ohci->next_statechange))
+ msleep(5);
+ ohci->next_statechange = jiffies;
+
+ ep93xx_stop_hc(&pdev->dev);
+ hcd->state = HC_STATE_SUSPENDED;
+ pdev->dev.power.power_state = PMSG_SUSPEND;
+
+ return 0;
+}
+
+static int ohci_hcd_ep93xx_drv_resume(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+ int status;
+
+ if (time_before(jiffies, ohci->next_statechange))
+ msleep(5);
+ ohci->next_statechange = jiffies;
+
+ ep93xx_start_hc(&pdev->dev);
+ pdev->dev.power.power_state = PMSG_ON;
+ usb_hcd_resume_root_hub(hcd);
+
+ return 0;
+}
+#endif
+
+
+static struct platform_driver ohci_hcd_ep93xx_driver = {
+ .probe = ohci_hcd_ep93xx_drv_probe,
+ .remove = ohci_hcd_ep93xx_drv_remove,
+#ifdef CONFIG_PM
+ .suspend = ohci_hcd_ep93xx_drv_suspend,
+ .resume = ohci_hcd_ep93xx_drv_resume,
+#endif
+ .driver = {
+ .name = "ep93xx-ohci",
+ },
+};
+
+static int __init ohci_hcd_ep93xx_init(void)
+{
+ return platform_driver_register(&ohci_hcd_ep93xx_driver);
+}
+
+static void __exit ohci_hcd_ep93xx_cleanup(void)
+{
+ platform_driver_unregister(&ohci_hcd_ep93xx_driver);
+}
+
+module_init(ohci_hcd_ep93xx_init);
+module_exit(ohci_hcd_ep93xx_cleanup);
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 8fb842ed5f6..94d8cf4b36c 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -901,6 +901,10 @@ MODULE_LICENSE ("GPL");
#include "ohci-pxa27x.c"
#endif
+#ifdef CONFIG_ARCH_EP93XX
+#include "ohci-ep93xx.c"
+#endif
+
#ifdef CONFIG_SOC_AU1X00
#include "ohci-au1xxx.c"
#endif
@@ -909,7 +913,7 @@ MODULE_LICENSE ("GPL");
#include "ohci-ppc-soc.c"
#endif
-#ifdef CONFIG_ARCH_AT91RM9200
+#if defined(CONFIG_ARCH_AT91RM9200) || defined(CONFIG_ARCH_AT91SAM9261)
#include "ohci-at91.c"
#endif
@@ -919,9 +923,11 @@ MODULE_LICENSE ("GPL");
|| defined(CONFIG_ARCH_OMAP) \
|| defined (CONFIG_ARCH_LH7A404) \
|| defined (CONFIG_PXA27x) \
+ || defined (CONFIG_ARCH_EP93XX) \
|| defined (CONFIG_SOC_AU1X00) \
|| defined (CONFIG_USB_OHCI_HCD_PPC_SOC) \
|| defined (CONFIG_ARCH_AT91RM9200) \
+ || defined (CONFIG_ARCH_AT91SAM9261) \
)
#error "missing bus glue for ohci-hcd"
#endif
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index 0bb972b5833..5b0a23fd798 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -581,14 +581,14 @@ static int ohci_hub_control (
break;
case GetHubStatus:
temp = roothub_status (ohci) & ~(RH_HS_CRWE | RH_HS_DRWE);
- *(__le32 *) buf = cpu_to_le32 (temp);
+ put_unaligned(cpu_to_le32 (temp), (__le32 *) buf);
break;
case GetPortStatus:
if (!wIndex || wIndex > ports)
goto error;
wIndex--;
temp = roothub_portstatus (ohci, wIndex);
- *(__le32 *) buf = cpu_to_le32 (temp);
+ put_unaligned(cpu_to_le32 (temp), (__le32 *) buf);
#ifndef OHCI_VERBOSE_DEBUG
if (*(u16*)(buf+2)) /* only if wPortChange is interesting */
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index dff60568b4a..20861650905 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -167,8 +167,6 @@ static int __devinit mmio_resource_enabled(struct pci_dev *pdev, int idx)
static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
{
void __iomem *base;
- int wait_time;
- u32 control;
if (!mmio_resource_enabled(pdev, 0))
return;
@@ -179,9 +177,10 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
/* On PA-RISC, PDC can leave IR set incorrectly; ignore it there. */
#ifndef __hppa__
- control = readl(base + OHCI_CONTROL);
+{
+ u32 control = readl(base + OHCI_CONTROL);
if (control & OHCI_CTRL_IR) {
- wait_time = 500; /* arbitrary; 5 seconds */
+ int wait_time = 500; /* arbitrary; 5 seconds */
writel(OHCI_INTR_OC, base + OHCI_INTRENABLE);
writel(OHCI_OCR, base + OHCI_CMDSTATUS);
while (wait_time > 0 &&
@@ -198,6 +197,7 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
/* reset controller, preserving RWC */
writel(control & OHCI_CTRL_RWC, base + OHCI_CONTROL);
}
+}
#endif
/*
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index c9d72ac0a1d..66c3f61bc9d 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -943,7 +943,9 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
/* We received a short packet */
if (urb->transfer_flags & URB_SHORT_NOT_OK)
ret = -EREMOTEIO;
- else if (ctrlstat & TD_CTRL_SPD)
+
+ /* Fixup needed only if this isn't the URB's last TD */
+ else if (&td->list != urbp->td_list.prev)
ret = 1;
}
diff --git a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c
index 05d2d6012eb..df198cf76f5 100644
--- a/drivers/usb/input/ati_remote.c
+++ b/drivers/usb/input/ati_remote.c
@@ -152,9 +152,8 @@ static const char accel[] = { 1, 2, 4, 6, 9, 13, 20 };
* events. The hardware generates 5 events for the first keypress
* and we have to take this into account for an accurate repeat
* behaviour.
- * (HZ / 20) == 50 ms and works well for me.
*/
-#define FILTER_TIME (HZ / 20)
+#define FILTER_TIME 60 /* msec */
struct ati_remote {
struct input_dev *idev;
@@ -467,7 +466,7 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs)
/* Filter duplicate events which happen "too close" together. */
if ((ati_remote->old_data[0] == data[1]) &&
(ati_remote->old_data[1] == data[2]) &&
- time_before(jiffies, ati_remote->old_jiffies + FILTER_TIME)) {
+ time_before(jiffies, ati_remote->old_jiffies + msecs_to_jiffies(FILTER_TIME))) {
ati_remote->repeat_count++;
} else {
ati_remote->repeat_count = 0;
diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
index b9fb9687f92..8ea9c915fbf 100644
--- a/drivers/usb/input/hid-core.c
+++ b/drivers/usb/input/hid-core.c
@@ -1507,6 +1507,9 @@ void hid_init_reports(struct hid_device *hid)
#define USB_DEVICE_ID_4_PHIDGETSERVO_20 0x8104
#define USB_DEVICE_ID_DUAL_USB_JOYPAD 0x8866
+#define USB_VENDOR_ID_WISEGROUP_LTD 0x6677
+#define USB_DEVICE_ID_SMARTJOY_DUAL_PLUS 0x8802
+
#define USB_VENDOR_ID_CODEMERCS 0x07c0
#define USB_DEVICE_ID_CODEMERCS_IOW40 0x1500
#define USB_DEVICE_ID_CODEMERCS_IOW24 0x1501
@@ -1670,6 +1673,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE, HID_QUIRK_MIGHTYMOUSE | HID_QUIRK_INVERT_HWHEEL },
{ USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_7 },
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
index daa486dde8c..88928a4be80 100644
--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -88,19 +88,19 @@ config USB_LED
To compile this driver as a module, choose M here: the
module will be called usbled.
-config USB_CY7C63
+config USB_CYPRESS_CY7C63
tristate "Cypress CY7C63xxx USB driver support"
depends on USB
help
Say Y here if you want to connect a Cypress CY7C63xxx
- micro controller to your computer's USB port. This driver
- supports the pre-programmed devices (incl. firmware) by
- AK Modul-Bus Computer GmbH.
+ micro controller to your computer's USB port. Currently this
+ driver supports the pre-programmed devices (incl. firmware)
+ by AK Modul-Bus Computer GmbH.
Please see: http://www.ak-modul-bus.de/stat/mikrocontroller.html
To compile this driver as a module, choose M here: the
- module will be called cy7c63.
+ module will be called cypress_cy7c63.
config USB_CYTHERM
tristate "Cypress USB thermometer driver support"
diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile
index f25a9722729..2927260c581 100644
--- a/drivers/usb/misc/Makefile
+++ b/drivers/usb/misc/Makefile
@@ -4,7 +4,7 @@
#
obj-$(CONFIG_USB_AUERSWALD) += auerswald.o
-obj-$(CONFIG_USB_CY7C63) += cy7c63.o
+obj-$(CONFIG_USB_CYPRESS_CY7C63)+= cypress_cy7c63.o
obj-$(CONFIG_USB_CYTHERM) += cytherm.o
obj-$(CONFIG_USB_EMI26) += emi26.o
obj-$(CONFIG_USB_EMI62) += emi62.o
diff --git a/drivers/usb/misc/cy7c63.c b/drivers/usb/misc/cy7c63.c
deleted file mode 100644
index 8a1c10b89b7..00000000000
--- a/drivers/usb/misc/cy7c63.c
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
-* cy7c63.c
-*
-* Copyright (c) 2006 Oliver Bock (bock@fh-wolfenbuettel.de)
-*
-* This driver is based on the Cypress Thermometer USB Driver by
-* Marcus Maul and the 2.0 version of Greg Kroah-Hartman's
-* USB Skeleton driver.
-*
-* Is is a generic driver for the Cypress CY7C63000 family.
-* For the time being it enables you to toggle the single I/O ports
-* of the device.
-*
-* Supported vendors: AK Modul-Bus Computer GmbH
-* Supported devices: CY7C63001A-PC (to be continued...)
-* Supported functions: Read/Write Ports (to be continued...)
-*
-* Chipsets families: CY7C63000, CY7C63001, CY7C63100, CY7C63101
-*
-*
-* This program is free software; you can redistribute it and/or
-* modify it under the terms of the GNU General Public License as
-* published by the Free Software Foundation, version 2.
-*/
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/usb.h>
-
-#define DRIVER_AUTHOR "Oliver Bock (bock@fh-wolfenbuettel.de)"
-#define DRIVER_DESC "Cypress CY7C63xxx USB driver"
-
-#define CY7C63_VENDOR_ID 0xa2c
-#define CY7C63_PRODUCT_ID 0x8
-
-#define CY7C63_READ_PORT 0x4
-#define CY7C63_WRITE_PORT 0x5
-#define CY7C63_READ_RAM 0x2
-#define CY7C63_WRITE_RAM 0x3
-#define CY7C63_READ_ROM 0x1
-
-#define CY7C63_READ_PORT_ID0 0
-#define CY7C63_WRITE_PORT_ID0 0
-#define CY7C63_READ_PORT_ID1 0x2
-#define CY7C63_WRITE_PORT_ID1 1
-
-#define CY7C63_MAX_REQSIZE 8
-
-
-/* table of devices that work with this driver */
-static struct usb_device_id cy7c63_table [] = {
- { USB_DEVICE(CY7C63_VENDOR_ID, CY7C63_PRODUCT_ID) },
- { }
-};
-MODULE_DEVICE_TABLE(usb, cy7c63_table);
-
-/* structure to hold all of our device specific stuff */
-struct cy7c63 {
- struct usb_device * udev;
- char port0;
- char port1;
-};
-
-/* used to send usb control messages to device */
-int vendor_command(struct cy7c63 *dev, unsigned char request,
- unsigned char address, unsigned char data) {
-
- int retval = 0;
- unsigned int pipe;
- unsigned char *iobuf;
-
- /* allocate some memory for the i/o buffer*/
- iobuf = kzalloc(CY7C63_MAX_REQSIZE, GFP_KERNEL);
- if (!iobuf) {
- dev_err(&dev->udev->dev, "Out of memory!\n");
- retval = -ENOMEM;
- goto error;
- }
-
- dev_dbg(&dev->udev->dev, "Sending usb_control_msg (data: %d)\n", data);
-
- /* prepare usb control message and send it upstream */
- pipe = usb_rcvctrlpipe(dev->udev, 0);
- retval = usb_control_msg(dev->udev, pipe, request,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER,
- address, data, iobuf, CY7C63_MAX_REQSIZE,
- USB_CTRL_GET_TIMEOUT);
-
- /* store returned data (more READs to be added!) */
- switch (request) {
- case CY7C63_READ_PORT:
- if (address == CY7C63_READ_PORT_ID0) {
- dev->port0 = iobuf[1];
- dev_dbg(&dev->udev->dev,
- "READ_PORT0 returned: %d\n",dev->port0);
- }
- else if (address == CY7C63_READ_PORT_ID1) {
- dev->port1 = iobuf[1];
- dev_dbg(&dev->udev->dev,
- "READ_PORT1 returned: %d\n",dev->port1);
- }
- break;
- }
-
- kfree(iobuf);
-error:
- return retval;
-}
-
-#define get_set_port(num,read_id,write_id) \
-static ssize_t set_port##num(struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) { \
- \
- int value; \
- int result = 0; \
- \
- struct usb_interface *intf = to_usb_interface(dev); \
- struct cy7c63 *cyp = usb_get_intfdata(intf); \
- \
- dev_dbg(&cyp->udev->dev, "WRITE_PORT%d called\n", num); \
- \
- /* validate input data */ \
- if (sscanf(buf, "%d", &value) < 1) { \
- result = -EINVAL; \
- goto error; \
- } \
- if (value>255 || value<0) { \
- result = -EINVAL; \
- goto error; \
- } \
- \
- result = vendor_command(cyp, CY7C63_WRITE_PORT, write_id, \
- (unsigned char)value); \
- \
- dev_dbg(&cyp->udev->dev, "Result of vendor_command: %d\n\n",result); \
-error: \
- return result < 0 ? result : count; \
-} \
- \
-static ssize_t get_port##num(struct device *dev, \
- struct device_attribute *attr, char *buf) { \
- \
- int result = 0; \
- \
- struct usb_interface *intf = to_usb_interface(dev); \
- struct cy7c63 *cyp = usb_get_intfdata(intf); \
- \
- dev_dbg(&cyp->udev->dev, "READ_PORT%d called\n", num); \
- \
- result = vendor_command(cyp, CY7C63_READ_PORT, read_id, 0); \
- \
- dev_dbg(&cyp->udev->dev, "Result of vendor_command: %d\n\n", result); \
- \
- return sprintf(buf, "%d", cyp->port##num); \
-} \
-static DEVICE_ATTR(port##num, S_IWUGO | S_IRUGO, get_port##num, set_port##num);
-
-get_set_port(0, CY7C63_READ_PORT_ID0, CY7C63_WRITE_PORT_ID0);
-get_set_port(1, CY7C63_READ_PORT_ID1, CY7C63_WRITE_PORT_ID1);
-
-static int cy7c63_probe(struct usb_interface *interface,
- const struct usb_device_id *id) {
-
- struct cy7c63 *dev = NULL;
- int retval = -ENOMEM;
-
- /* allocate memory for our device state and initialize it */
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (dev == NULL) {
- dev_err(&dev->udev->dev, "Out of memory!\n");
- goto error;
- }
-
- dev->udev = usb_get_dev(interface_to_usbdev(interface));
-
- /* save our data pointer in this interface device */
- usb_set_intfdata(interface, dev);
-
- /* create device attribute files */
- device_create_file(&interface->dev, &dev_attr_port0);
- device_create_file(&interface->dev, &dev_attr_port1);
-
- /* let the user know what node this device is now attached to */
- dev_info(&interface->dev,
- "Cypress CY7C63xxx device now attached\n");
-
- retval = 0;
-error:
- return retval;
-}
-
-static void cy7c63_disconnect(struct usb_interface *interface) {
-
- struct cy7c63 *dev;
-
- dev = usb_get_intfdata(interface);
- usb_set_intfdata(interface, NULL);
-
- /* remove device attribute files */
- device_remove_file(&interface->dev, &dev_attr_port0);
- device_remove_file(&interface->dev, &dev_attr_port1);
-
- usb_put_dev(dev->udev);
-
- dev_info(&interface->dev,
- "Cypress CY7C63xxx device now disconnected\n");
-
- kfree(dev);
-}
-
-static struct usb_driver cy7c63_driver = {
- .name = "cy7c63",
- .probe = cy7c63_probe,
- .disconnect = cy7c63_disconnect,
- .id_table = cy7c63_table,
-};
-
-static int __init cy7c63_init(void) {
-
- int result;
-
- /* register this driver with the USB subsystem */
- result = usb_register(&cy7c63_driver);
- if (result) {
- err("Function usb_register failed! Error number: %d\n", result);
- }
-
- return result;
-}
-
-static void __exit cy7c63_exit(void) {
-
- /* deregister this driver with the USB subsystem */
- usb_deregister(&cy7c63_driver);
-}
-
-module_init(cy7c63_init);
-module_exit(cy7c63_exit);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/misc/cypress_cy7c63.c b/drivers/usb/misc/cypress_cy7c63.c
new file mode 100644
index 00000000000..a4062a6adbb
--- /dev/null
+++ b/drivers/usb/misc/cypress_cy7c63.c
@@ -0,0 +1,284 @@
+/*
+* cypress_cy7c63.c
+*
+* Copyright (c) 2006 Oliver Bock (o.bock@fh-wolfenbuettel.de)
+*
+* This driver is based on the Cypress USB Driver by Marcus Maul
+* (cyport) and the 2.0 version of Greg Kroah-Hartman's
+* USB Skeleton driver.
+*
+* This is a generic driver for the Cypress CY7C63xxx family.
+* For the time being it enables you to read from and write to
+* the single I/O ports of the device.
+*
+* Supported vendors: AK Modul-Bus Computer GmbH
+* (Firmware "Port-Chip")
+*
+* Supported devices: CY7C63001A-PC
+* CY7C63001C-PXC
+* CY7C63001C-SXC
+*
+* Supported functions: Read/Write Ports
+*
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License as
+* published by the Free Software Foundation, version 2.
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/usb.h>
+
+#define DRIVER_AUTHOR "Oliver Bock (o.bock@fh-wolfenbuettel.de)"
+#define DRIVER_DESC "Cypress CY7C63xxx USB driver"
+
+#define CYPRESS_VENDOR_ID 0xa2c
+#define CYPRESS_PRODUCT_ID 0x8
+
+#define CYPRESS_READ_PORT 0x4
+#define CYPRESS_WRITE_PORT 0x5
+
+#define CYPRESS_READ_RAM 0x2
+#define CYPRESS_WRITE_RAM 0x3
+#define CYPRESS_READ_ROM 0x1
+
+#define CYPRESS_READ_PORT_ID0 0
+#define CYPRESS_WRITE_PORT_ID0 0
+#define CYPRESS_READ_PORT_ID1 0x2
+#define CYPRESS_WRITE_PORT_ID1 1
+
+#define CYPRESS_MAX_REQSIZE 8
+
+
+/* table of devices that work with this driver */
+static struct usb_device_id cypress_table [] = {
+ { USB_DEVICE(CYPRESS_VENDOR_ID, CYPRESS_PRODUCT_ID) },
+ { }
+};
+MODULE_DEVICE_TABLE(usb, cypress_table);
+
+/* structure to hold all of our device specific stuff */
+struct cypress {
+ struct usb_device * udev;
+ unsigned char port[2];
+};
+
+/* used to send usb control messages to device */
+static int vendor_command(struct cypress *dev, unsigned char request,
+ unsigned char address, unsigned char data)
+{
+ int retval = 0;
+ unsigned int pipe;
+ unsigned char *iobuf;
+
+ /* allocate some memory for the i/o buffer*/
+ iobuf = kzalloc(CYPRESS_MAX_REQSIZE, GFP_KERNEL);
+ if (!iobuf) {
+ dev_err(&dev->udev->dev, "Out of memory!\n");
+ retval = -ENOMEM;
+ goto error;
+ }
+
+ dev_dbg(&dev->udev->dev, "Sending usb_control_msg (data: %d)\n", data);
+
+ /* prepare usb control message and send it upstream */
+ pipe = usb_rcvctrlpipe(dev->udev, 0);
+ retval = usb_control_msg(dev->udev, pipe, request,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER,
+ address, data, iobuf, CYPRESS_MAX_REQSIZE,
+ USB_CTRL_GET_TIMEOUT);
+
+ /* store returned data (more READs to be added) */
+ switch (request) {
+ case CYPRESS_READ_PORT:
+ if (address == CYPRESS_READ_PORT_ID0) {
+ dev->port[0] = iobuf[1];
+ dev_dbg(&dev->udev->dev,
+ "READ_PORT0 returned: %d\n",
+ dev->port[0]);
+ }
+ else if (address == CYPRESS_READ_PORT_ID1) {
+ dev->port[1] = iobuf[1];
+ dev_dbg(&dev->udev->dev,
+ "READ_PORT1 returned: %d\n",
+ dev->port[1]);
+ }
+ break;
+ }
+
+ kfree(iobuf);
+error:
+ return retval;
+}
+
+/* write port value */
+static ssize_t write_port(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count,
+ int port_num, int write_id)
+{
+ int value = -1;
+ int result = 0;
+
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct cypress *cyp = usb_get_intfdata(intf);
+
+ dev_dbg(&cyp->udev->dev, "WRITE_PORT%d called\n", port_num);
+
+ /* validate input data */
+ if (sscanf(buf, "%d", &value) < 1) {
+ result = -EINVAL;
+ goto error;
+ }
+ if (value < 0 || value > 255) {
+ result = -EINVAL;
+ goto error;
+ }
+
+ result = vendor_command(cyp, CYPRESS_WRITE_PORT, write_id,
+ (unsigned char)value);
+
+ dev_dbg(&cyp->udev->dev, "Result of vendor_command: %d\n\n", result);
+error:
+ return result < 0 ? result : count;
+}
+
+/* attribute callback handler (write) */
+static ssize_t set_port0_handler(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return write_port(dev, attr, buf, count, 0, CYPRESS_WRITE_PORT_ID0);
+}
+
+/* attribute callback handler (write) */
+static ssize_t set_port1_handler(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return write_port(dev, attr, buf, count, 1, CYPRESS_WRITE_PORT_ID1);
+}
+
+/* read port value */
+static ssize_t read_port(struct device *dev, struct device_attribute *attr,
+ char *buf, int port_num, int read_id)
+{
+ int result = 0;
+
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct cypress *cyp = usb_get_intfdata(intf);
+
+ dev_dbg(&cyp->udev->dev, "READ_PORT%d called\n", port_num);
+
+ result = vendor_command(cyp, CYPRESS_READ_PORT, read_id, 0);
+
+ dev_dbg(&cyp->udev->dev, "Result of vendor_command: %d\n\n", result);
+
+ return sprintf(buf, "%d", cyp->port[port_num]);
+}
+
+/* attribute callback handler (read) */
+static ssize_t get_port0_handler(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return read_port(dev, attr, buf, 0, CYPRESS_READ_PORT_ID0);
+}
+
+/* attribute callback handler (read) */
+static ssize_t get_port1_handler(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return read_port(dev, attr, buf, 1, CYPRESS_READ_PORT_ID1);
+}
+
+static DEVICE_ATTR(port0, S_IWUGO | S_IRUGO,
+ get_port0_handler, set_port0_handler);
+
+static DEVICE_ATTR(port1, S_IWUGO | S_IRUGO,
+ get_port1_handler, set_port1_handler);
+
+
+static int cypress_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct cypress *dev = NULL;
+ int retval = -ENOMEM;
+
+ /* allocate memory for our device state and initialize it */
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL) {
+ dev_err(&dev->udev->dev, "Out of memory!\n");
+ goto error;
+ }
+
+ dev->udev = usb_get_dev(interface_to_usbdev(interface));
+
+ /* save our data pointer in this interface device */
+ usb_set_intfdata(interface, dev);
+
+ /* create device attribute files */
+ device_create_file(&interface->dev, &dev_attr_port0);
+ device_create_file(&interface->dev, &dev_attr_port1);
+
+ /* let the user know that the device is now attached */
+ dev_info(&interface->dev,
+ "Cypress CY7C63xxx device now attached\n");
+
+ retval = 0;
+error:
+ return retval;
+}
+
+static void cypress_disconnect(struct usb_interface *interface)
+{
+ struct cypress *dev;
+
+ dev = usb_get_intfdata(interface);
+ usb_set_intfdata(interface, NULL);
+
+ /* remove device attribute files */
+ device_remove_file(&interface->dev, &dev_attr_port0);
+ device_remove_file(&interface->dev, &dev_attr_port1);
+
+ usb_put_dev(dev->udev);
+
+ dev_info(&interface->dev,
+ "Cypress CY7C63xxx device now disconnected\n");
+
+ kfree(dev);
+}
+
+static struct usb_driver cypress_driver = {
+ .name = "cypress_cy7c63",
+ .probe = cypress_probe,
+ .disconnect = cypress_disconnect,
+ .id_table = cypress_table,
+};
+
+static int __init cypress_init(void)
+{
+ int result;
+
+ /* register this driver with the USB subsystem */
+ result = usb_register(&cypress_driver);
+ if (result) {
+ err("Function usb_register failed! Error number: %d\n", result);
+ }
+
+ return result;
+}
+
+static void __exit cypress_exit(void)
+{
+ /* deregister this driver with the USB subsystem */
+ usb_deregister(&cypress_driver);
+}
+
+module_init(cypress_init);
+module_exit(cypress_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c
index c82c402285a..e095772dd8e 100644
--- a/drivers/usb/misc/usblcd.c
+++ b/drivers/usb/misc/usblcd.c
@@ -200,10 +200,8 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer, siz
/* create a urb, and a buffer for it, and copy the data to the urb */
urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!urb) {
- retval = -ENOMEM;
- goto error;
- }
+ if (!urb)
+ return -ENOMEM;
buf = usb_buffer_alloc(dev->udev, count, GFP_KERNEL, &urb->transfer_dma);
if (!buf) {
diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c
index e02c1a30c4c..f961a770cee 100644
--- a/drivers/usb/mon/mon_text.c
+++ b/drivers/usb/mon/mon_text.c
@@ -64,7 +64,6 @@ struct mon_reader_text {
};
static void mon_text_ctor(void *, kmem_cache_t *, unsigned long);
-static void mon_text_dtor(void *, kmem_cache_t *, unsigned long);
/*
* mon_text_submit
@@ -268,7 +267,7 @@ static int mon_text_open(struct inode *inode, struct file *file)
(long)rp);
rp->e_slab = kmem_cache_create(rp->slab_name,
sizeof(struct mon_event_text), sizeof(long), 0,
- mon_text_ctor, mon_text_dtor);
+ mon_text_ctor, NULL);
if (rp->e_slab == NULL) {
rc = -ENOMEM;
goto err_slab;
@@ -459,7 +458,3 @@ static void mon_text_ctor(void *mem, kmem_cache_t *slab, unsigned long sflags)
memset(mem, 0xe5, sizeof(struct mon_event_text));
}
-static void mon_text_dtor(void *mem, kmem_cache_t *slab, unsigned long sflags)
-{
- ;
-}
diff --git a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c
index 718f8e2b552..bd09232ce13 100644
--- a/drivers/usb/net/rtl8150.c
+++ b/drivers/usb/net/rtl8150.c
@@ -128,11 +128,13 @@
#define VENDOR_ID_MELCO 0x0411
#define VENDOR_ID_MICRONET 0x3980
#define VENDOR_ID_LONGSHINE 0x07b8
+#define VENDOR_ID_ZYXEL 0x0586
#define PRODUCT_ID_RTL8150 0x8150
#define PRODUCT_ID_LUAKTX 0x0012
#define PRODUCT_ID_LCS8138TX 0x401a
#define PRODUCT_ID_SP128AR 0x0003
+#define PRODUCT_ID_PRESTIGE 0x401a
#undef EEPROM_WRITE
@@ -142,6 +144,7 @@ static struct usb_device_id rtl8150_table[] = {
{USB_DEVICE(VENDOR_ID_MELCO, PRODUCT_ID_LUAKTX)},
{USB_DEVICE(VENDOR_ID_MICRONET, PRODUCT_ID_SP128AR)},
{USB_DEVICE(VENDOR_ID_LONGSHINE, PRODUCT_ID_LCS8138TX)},
+ {USB_DEVICE(VENDOR_ID_ZYXEL, PRODUCT_ID_PRESTIGE)},
{}
};
@@ -172,6 +175,8 @@ static inline struct sk_buff *pull_skb(rtl8150_t *);
static void rtl8150_disconnect(struct usb_interface *intf);
static int rtl8150_probe(struct usb_interface *intf,
const struct usb_device_id *id);
+static int rtl8150_suspend(struct usb_interface *intf, pm_message_t message);
+static int rtl8150_resume(struct usb_interface *intf);
static const char driver_name [] = "rtl8150";
@@ -180,6 +185,8 @@ static struct usb_driver rtl8150_driver = {
.probe = rtl8150_probe,
.disconnect = rtl8150_disconnect,
.id_table = rtl8150_table,
+ .suspend = rtl8150_suspend,
+ .resume = rtl8150_resume
};
/*
@@ -235,9 +242,11 @@ static int async_set_registers(rtl8150_t * dev, u16 indx, u16 size)
usb_fill_control_urb(dev->ctrl_urb, dev->udev,
usb_sndctrlpipe(dev->udev, 0), (char *) &dev->dr,
&dev->rx_creg, size, ctrl_callback, dev);
- if ((ret = usb_submit_urb(dev->ctrl_urb, GFP_ATOMIC)))
+ if ((ret = usb_submit_urb(dev->ctrl_urb, GFP_ATOMIC))) {
+ if (ret == -ENODEV)
+ netif_device_detach(dev->netdev);
err("control request submission failed: %d", ret);
- else
+ } else
set_bit(RX_REG_SET, &dev->flags);
return ret;
@@ -413,6 +422,7 @@ static void read_bulk_callback(struct urb *urb, struct pt_regs *regs)
struct sk_buff *skb;
struct net_device *netdev;
u16 rx_stat;
+ int status;
dev = urb->context;
if (!dev)
@@ -462,7 +472,10 @@ static void read_bulk_callback(struct urb *urb, struct pt_regs *regs)
goon:
usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev);
- if (usb_submit_urb(dev->rx_urb, GFP_ATOMIC)) {
+ status = usb_submit_urb(dev->rx_urb, GFP_ATOMIC);
+ if (status == -ENODEV)
+ netif_device_detach(dev->netdev);
+ else if (status) {
set_bit(RX_URB_FAIL, &dev->flags);
goto resched;
} else {
@@ -478,6 +491,7 @@ static void rx_fixup(unsigned long data)
{
rtl8150_t *dev;
struct sk_buff *skb;
+ int status;
dev = (rtl8150_t *)data;
@@ -496,10 +510,13 @@ static void rx_fixup(unsigned long data)
usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev);
try_again:
- if (usb_submit_urb(dev->rx_urb, GFP_ATOMIC)) {
+ status = usb_submit_urb(dev->rx_urb, GFP_ATOMIC);
+ if (status == -ENODEV) {
+ netif_device_detach(dev->netdev);
+ } else if (status) {
set_bit(RX_URB_FAIL, &dev->flags);
goto tlsched;
- } else {
+ } else {
clear_bit(RX_URB_FAIL, &dev->flags);
}
@@ -571,12 +588,43 @@ static void intr_callback(struct urb *urb, struct pt_regs *regs)
resubmit:
status = usb_submit_urb (urb, SLAB_ATOMIC);
- if (status)
+ if (status == -ENODEV)
+ netif_device_detach(dev->netdev);
+ else if (status)
err ("can't resubmit intr, %s-%s/input0, status %d",
dev->udev->bus->bus_name,
dev->udev->devpath, status);
}
+static int rtl8150_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ rtl8150_t *dev = usb_get_intfdata(intf);
+
+ netif_device_detach(dev->netdev);
+
+ if (netif_running(dev->netdev)) {
+ usb_kill_urb(dev->rx_urb);
+ usb_kill_urb(dev->intr_urb);
+ }
+ return 0;
+}
+
+static int rtl8150_resume(struct usb_interface *intf)
+{
+ rtl8150_t *dev = usb_get_intfdata(intf);
+
+ netif_device_attach(dev->netdev);
+ if (netif_running(dev->netdev)) {
+ dev->rx_urb->status = 0;
+ dev->rx_urb->actual_length = 0;
+ read_bulk_callback(dev->rx_urb, NULL);
+
+ dev->intr_urb->status = 0;
+ dev->intr_urb->actual_length = 0;
+ intr_callback(dev->intr_urb, NULL);
+ }
+ return 0;
+}
/*
**
@@ -687,9 +735,14 @@ static int rtl8150_start_xmit(struct sk_buff *skb, struct net_device *netdev)
usb_fill_bulk_urb(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev, 2),
skb->data, count, write_bulk_callback, dev);
if ((res = usb_submit_urb(dev->tx_urb, GFP_ATOMIC))) {
- warn("failed tx_urb %d\n", res);
- dev->stats.tx_errors++;
- netif_start_queue(netdev);
+ /* Can we get/handle EPIPE here? */
+ if (res == -ENODEV)
+ netif_device_detach(dev->netdev);
+ else {
+ warn("failed tx_urb %d\n", res);
+ dev->stats.tx_errors++;
+ netif_start_queue(netdev);
+ }
} else {
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
@@ -726,16 +779,25 @@ static int rtl8150_open(struct net_device *netdev)
usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev);
- if ((res = usb_submit_urb(dev->rx_urb, GFP_KERNEL)))
+ if ((res = usb_submit_urb(dev->rx_urb, GFP_KERNEL))) {
+ if (res == -ENODEV)
+ netif_device_detach(dev->netdev);
warn("%s: rx_urb submit failed: %d", __FUNCTION__, res);
+ return res;
+ }
usb_fill_int_urb(dev->intr_urb, dev->udev, usb_rcvintpipe(dev->udev, 3),
dev->intr_buff, INTBUFSIZE, intr_callback,
dev, dev->intr_interval);
- if ((res = usb_submit_urb(dev->intr_urb, GFP_KERNEL)))
+ if ((res = usb_submit_urb(dev->intr_urb, GFP_KERNEL))) {
+ if (res == -ENODEV)
+ netif_device_detach(dev->netdev);
warn("%s: intr_urb submit failed: %d", __FUNCTION__, res);
- netif_start_queue(netdev);
+ usb_kill_urb(dev->rx_urb);
+ return res;
+ }
enable_net_traffic(dev);
set_carrier(netdev);
+ netif_start_queue(netdev);
return res;
}
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 8bd44fda5ea..f5b9438c94f 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -62,15 +62,6 @@ config USB_SERIAL_AIRPRIME
To compile this driver as a module, choose M here: the
module will be called airprime.
-config USB_SERIAL_ANYDATA
- tristate "USB AnyData CDMA Wireless Driver"
- depends on USB_SERIAL
- help
- Say Y here if you want to use a AnyData CDMA device.
-
- To compile this driver as a module, choose M here: the
- module will be called anydata.
-
config USB_SERIAL_ARK3116
tristate "USB ARK Micro 3116 USB Serial Driver (EXPERIMENTAL)"
depends on USB_SERIAL && EXPERIMENTAL
@@ -456,6 +447,17 @@ config USB_SERIAL_SAFE_PADDED
bool "USB Secure Encapsulated Driver - Padded"
depends on USB_SERIAL_SAFE
+config USB_SERIAL_SIERRAWIRELESS
+ tristate "USB Sierra Wireless Driver"
+ depends on USB_SERIAL
+ help
+ Say M here if you want to use a Sierra Wireless device (if
+ using an PC 5220 or AC580 please use the Airprime driver
+ instead).
+
+ To compile this driver as a module, choose M here: the
+ module will be called sierra.
+
config USB_SERIAL_TI
tristate "USB TI 3410/5052 Serial Driver"
depends on USB_SERIAL
@@ -491,15 +493,18 @@ config USB_SERIAL_XIRCOM
module will be called keyspan_pda.
config USB_SERIAL_OPTION
- tristate "USB driver for GSM modems"
+ tristate "USB driver for GSM and CDMA modems"
depends on USB_SERIAL
help
- Say Y here if you have an "Option" GSM PCMCIA card
- (or an OEM version: branded Huawei, Audiovox, or Novatel).
+ Say Y here if you have a GSM or CDMA modem that's connected to USB.
+
+ This driver also supports several PCMCIA cards which have a
+ built-in OHCI-USB adapter and an internally-connected GSM modem.
+ The USB bus on these cards is not accessible externally.
- These cards feature a built-in OHCI-USB adapter and an
- internally-connected GSM modem. The USB bus is not
- accessible externally.
+ Supported devices include (some of?) those made by:
+ Option, Huawei, Audiovox, Sierra Wireless, Novatel Wireless, or
+ Anydata.
To compile this driver as a module, choose M here: the
module will be called option.
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 5a0960fc9d3..8efed2ce1ba 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -12,7 +12,6 @@ usbserial-obj-$(CONFIG_USB_EZUSB) += ezusb.o
usbserial-objs := usb-serial.o generic.o bus.o $(usbserial-obj-y)
obj-$(CONFIG_USB_SERIAL_AIRPRIME) += airprime.o
-obj-$(CONFIG_USB_SERIAL_ANYDATA) += anydata.o
obj-$(CONFIG_USB_SERIAL_ARK3116) += ark3116.o
obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o
obj-$(CONFIG_USB_SERIAL_CP2101) += cp2101.o
@@ -39,6 +38,7 @@ obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o
obj-$(CONFIG_USB_SERIAL_OPTION) += option.o
obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o
obj-$(CONFIG_USB_SERIAL_SAFE) += safe_serial.o
+obj-$(CONFIG_USB_SERIAL_SIERRAWIRELESS) += sierra.o
obj-$(CONFIG_USB_SERIAL_TI) += ti_usb_3410_5052.o
obj-$(CONFIG_USB_SERIAL_VISOR) += visor.o
obj-$(CONFIG_USB_SERIAL_WHITEHEAT) += whiteheat.o
diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c
index 94b9ba0ff87..62082532a8b 100644
--- a/drivers/usb/serial/airprime.c
+++ b/drivers/usb/serial/airprime.c
@@ -13,7 +13,7 @@
#include <linux/tty.h>
#include <linux/module.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x0c88, 0x17da) }, /* Kyocera Wireless KPC650/Passport */
diff --git a/drivers/usb/serial/anydata.c b/drivers/usb/serial/anydata.c
deleted file mode 100644
index 343f6f22822..00000000000
--- a/drivers/usb/serial/anydata.c
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * AnyData CDMA Serial USB driver
- *
- * Copyright (C) 2005 Greg Kroah-Hartman <gregkh@suse.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include "usb-serial.h"
-
-static struct usb_device_id id_table [] = {
- { USB_DEVICE(0x16d5, 0x6501) }, /* AirData CDMA device */
- { },
-};
-MODULE_DEVICE_TABLE(usb, id_table);
-
-/* if overridden by the user, then use their value for the size of the
- * read and write urbs */
-static int buffer_size;
-static int debug;
-
-static struct usb_driver anydata_driver = {
- .name = "anydata",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
- .no_dynamic_id = 1,
-};
-
-static int anydata_open(struct usb_serial_port *port, struct file *filp)
-{
- char *buffer;
- int result = 0;
-
- dbg("%s - port %d", __FUNCTION__, port->number);
-
- if (buffer_size) {
- /* override the default buffer sizes */
- buffer = kmalloc(buffer_size, GFP_KERNEL);
- if (!buffer) {
- dev_err(&port->dev, "%s - out of memory.\n",
- __FUNCTION__);
- return -ENOMEM;
- }
- kfree (port->read_urb->transfer_buffer);
- port->read_urb->transfer_buffer = buffer;
- port->read_urb->transfer_buffer_length = buffer_size;
-
- buffer = kmalloc(buffer_size, GFP_KERNEL);
- if (!buffer) {
- dev_err(&port->dev, "%s - out of memory.\n",
- __FUNCTION__);
- return -ENOMEM;
- }
- kfree (port->write_urb->transfer_buffer);
- port->write_urb->transfer_buffer = buffer;
- port->write_urb->transfer_buffer_length = buffer_size;
- port->bulk_out_size = buffer_size;
- }
-
- /* Start reading from the device */
- usb_fill_bulk_urb(port->read_urb, port->serial->dev,
- usb_rcvbulkpipe(port->serial->dev,
- port->bulk_in_endpointAddress),
- port->read_urb->transfer_buffer,
- port->read_urb->transfer_buffer_length,
- usb_serial_generic_write_bulk_callback, port);
- result = usb_submit_urb(port->read_urb, GFP_KERNEL);
- if (result)
- dev_err(&port->dev,
- "%s - failed submitting read urb, error %d\n",
- __FUNCTION__, result);
-
- return result;
-}
-
-static struct usb_serial_driver anydata_device = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "anydata",
- },
- .id_table = id_table,
- .num_interrupt_in = NUM_DONT_CARE,
- .num_bulk_in = NUM_DONT_CARE,
- .num_bulk_out = NUM_DONT_CARE,
- .num_ports = 1,
- .open = anydata_open,
-};
-
-static int __init anydata_init(void)
-{
- int retval;
-
- retval = usb_serial_register(&anydata_device);
- if (retval)
- return retval;
- retval = usb_register(&anydata_driver);
- if (retval)
- usb_serial_deregister(&anydata_device);
- return retval;
-}
-
-static void __exit anydata_exit(void)
-{
- usb_deregister(&anydata_driver);
- usb_serial_deregister(&anydata_device);
-}
-
-module_init(anydata_init);
-module_exit(anydata_exit);
-MODULE_LICENSE("GPL");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
-module_param(buffer_size, int, 0);
-MODULE_PARM_DESC(buffer_size, "Size of the transfer buffers");
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index 8dec796222a..970d9ef0a7a 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -21,7 +21,7 @@
#include <linux/tty.h>
#include <linux/module.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
static int debug;
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
index 3faa7aa0111..70ece9e01ce 100644
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -74,7 +74,7 @@
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
#include "belkin_sa.h"
static int debug;
diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c
index f2d993b70c1..6542f220468 100644
--- a/drivers/usb/serial/bus.c
+++ b/drivers/usb/serial/bus.c
@@ -13,7 +13,7 @@
#include <linux/tty.h>
#include <linux/module.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
static int usb_serial_device_match (struct device *dev, struct device_driver *drv)
{
diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c
index 3d456b32c31..3a9073dbfe6 100644
--- a/drivers/usb/serial/console.c
+++ b/drivers/usb/serial/console.c
@@ -17,11 +17,10 @@
#include <linux/tty.h>
#include <linux/console.h>
#include <linux/usb.h>
+#include <linux/usb/serial.h>
static int debug;
-#include "usb-serial.h"
-
struct usbcons_info {
int magic;
int break_flag;
diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c
index df0a4f98b4a..486c7411b9a 100644
--- a/drivers/usb/serial/cp2101.c
+++ b/drivers/usb/serial/cp2101.c
@@ -26,7 +26,7 @@
#include <linux/moduleparam.h>
#include <linux/usb.h>
#include <asm/uaccess.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
/*
* Version Information
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index 49b51ab0d4c..6286aba86fa 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -39,7 +39,7 @@
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
#define CYBERJACK_LOCAL_BUF_SIZE 32
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index 4ff2dfb299b..ee70fddcab6 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -59,11 +59,11 @@
#include <linux/moduleparam.h>
#include <linux/spinlock.h>
#include <linux/usb.h>
+#include <linux/usb/serial.h>
#include <linux/serial.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
-#include "usb-serial.h"
#include "cypress_m8.h"
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index 6953d3ef573..9b225183fc7 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -246,7 +246,7 @@
#include <asm/uaccess.h>
#include <linux/usb.h>
#include <linux/wait.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
/* Defines */
diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
index 1e2b31eeb49..daafe405d86 100644
--- a/drivers/usb/serial/empeg.c
+++ b/drivers/usb/serial/empeg.c
@@ -62,7 +62,7 @@
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
static int debug;
diff --git a/drivers/usb/serial/ezusb.c b/drivers/usb/serial/ezusb.c
index debc3b0f966..5169c2d154a 100644
--- a/drivers/usb/serial/ezusb.c
+++ b/drivers/usb/serial/ezusb.c
@@ -15,7 +15,7 @@
#include <linux/tty.h>
#include <linux/module.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
/* EZ-USB Control and Status Register. Bit 0 controls 8051 reset */
#define CPUCS_REG 0x7F92
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 8a74b19f128..a20da8528a5 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -257,7 +257,7 @@
#include <asm/uaccess.h>
#include <linux/usb.h>
#include <linux/serial.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
#include "ftdi_sio.h"
/*
@@ -313,6 +313,7 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_MICRO_CHAMELEON_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) },
{ USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) },
{ USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) },
@@ -336,6 +337,7 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_MTXORB_6_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_PIEGROUP_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_TNC_X_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2101_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2102_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2103_PID) },
@@ -500,6 +502,8 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_TMU_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ACG_HFDUAL_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_YEI_SERVOCENTER31_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_THORLABS_PID) },
+ { USB_DEVICE(TESTO_VID, TESTO_USB_INTERFACE_PID) },
{ }, /* Optional parameter entry */
{ } /* Terminating entry */
};
@@ -548,11 +552,17 @@ struct ftdi_private {
spinlock_t rx_lock; /* spinlock for receive state */
struct work_struct rx_work;
int rx_processed;
+ unsigned long rx_bytes;
__u16 interface; /* FT2232C port interface (0 for FT232/245) */
int force_baud; /* if non-zero, force the baud rate to this value */
int force_rtscts; /* if non-zero, force RTS-CTS to always be enabled */
+
+ spinlock_t tx_lock; /* spinlock for transmit state */
+ unsigned long tx_bytes;
+ unsigned long tx_outstanding_bytes;
+ unsigned long tx_outstanding_urbs;
};
/* Used for TIOCMIWAIT */
@@ -626,6 +636,9 @@ static struct usb_serial_driver ftdi_sio_device = {
#define HIGH 1
#define LOW 0
+/* number of outstanding urbs to prevent userspace DoS from happening */
+#define URB_UPPER_LIMIT 42
+
/*
* ***************************************************************************
* Utlity functions
@@ -1156,6 +1169,7 @@ static int ftdi_sio_attach (struct usb_serial *serial)
}
spin_lock_init(&priv->rx_lock);
+ spin_lock_init(&priv->tx_lock);
init_waitqueue_head(&priv->delta_msr_wait);
/* This will push the characters through immediately rather
than queue a task to deliver them */
@@ -1270,6 +1284,13 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp)
dbg("%s", __FUNCTION__);
+ spin_lock_irqsave(&priv->tx_lock, flags);
+ priv->tx_bytes = 0;
+ spin_unlock_irqrestore(&priv->tx_lock, flags);
+ spin_lock_irqsave(&priv->rx_lock, flags);
+ priv->rx_bytes = 0;
+ spin_unlock_irqrestore(&priv->rx_lock, flags);
+
if (port->tty)
port->tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
@@ -1372,6 +1393,7 @@ static int ftdi_write (struct usb_serial_port *port,
int data_offset ; /* will be 1 for the SIO and 0 otherwise */
int status;
int transfer_size;
+ unsigned long flags;
dbg("%s port %d, %d bytes", __FUNCTION__, port->number, count);
@@ -1379,6 +1401,13 @@ static int ftdi_write (struct usb_serial_port *port,
dbg("write request of 0 bytes");
return 0;
}
+ spin_lock_irqsave(&priv->tx_lock, flags);
+ if (priv->tx_outstanding_urbs > URB_UPPER_LIMIT) {
+ spin_unlock_irqrestore(&priv->tx_lock, flags);
+ dbg("%s - write limit hit\n", __FUNCTION__);
+ return 0;
+ }
+ spin_unlock_irqrestore(&priv->tx_lock, flags);
data_offset = priv->write_offset;
dbg("data_offset set to %d",data_offset);
@@ -1445,6 +1474,12 @@ static int ftdi_write (struct usb_serial_port *port,
err("%s - failed submitting write urb, error %d", __FUNCTION__, status);
count = status;
kfree (buffer);
+ } else {
+ spin_lock_irqsave(&priv->tx_lock, flags);
+ ++priv->tx_outstanding_urbs;
+ priv->tx_outstanding_bytes += count;
+ priv->tx_bytes += count;
+ spin_unlock_irqrestore(&priv->tx_lock, flags);
}
/* we are done with this urb, so let the host driver
@@ -1460,7 +1495,11 @@ static int ftdi_write (struct usb_serial_port *port,
static void ftdi_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
{
+ unsigned long flags;
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct ftdi_private *priv;
+ int data_offset; /* will be 1 for the SIO and 0 otherwise */
+ unsigned long countback;
/* free up the transfer buffer, as usb_free_urb() does not do this */
kfree (urb->transfer_buffer);
@@ -1472,34 +1511,67 @@ static void ftdi_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
return;
}
+ priv = usb_get_serial_port_data(port);
+ if (!priv) {
+ dbg("%s - bad port private data pointer - exiting", __FUNCTION__);
+ return;
+ }
+ /* account for transferred data */
+ countback = urb->actual_length;
+ data_offset = priv->write_offset;
+ if (data_offset > 0) {
+ /* Subtract the control bytes */
+ countback -= (data_offset * ((countback + (PKTSZ - 1)) / PKTSZ));
+ }
+ spin_lock_irqsave(&priv->tx_lock, flags);
+ --priv->tx_outstanding_urbs;
+ priv->tx_outstanding_bytes -= countback;
+ spin_unlock_irqrestore(&priv->tx_lock, flags);
+
usb_serial_port_softint(port);
} /* ftdi_write_bulk_callback */
static int ftdi_write_room( struct usb_serial_port *port )
{
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+ int room;
+ unsigned long flags;
+
dbg("%s - port %d", __FUNCTION__, port->number);
- /*
- * We really can take anything the user throws at us
- * but let's pick a nice big number to tell the tty
- * layer that we have lots of free space
- */
- return 2048;
+ spin_lock_irqsave(&priv->tx_lock, flags);
+ if (priv->tx_outstanding_urbs < URB_UPPER_LIMIT) {
+ /*
+ * We really can take anything the user throws at us
+ * but let's pick a nice big number to tell the tty
+ * layer that we have lots of free space
+ */
+ room = 2048;
+ } else {
+ room = 0;
+ }
+ spin_unlock_irqrestore(&priv->tx_lock, flags);
+ return room;
} /* ftdi_write_room */
static int ftdi_chars_in_buffer (struct usb_serial_port *port)
{ /* ftdi_chars_in_buffer */
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+ int buffered;
+ unsigned long flags;
+
dbg("%s - port %d", __FUNCTION__, port->number);
- /*
- * We can't really account for how much data we
- * have sent out, but hasn't made it through to the
- * device, so just tell the tty layer that everything
- * is flushed.
- */
- return 0;
+ spin_lock_irqsave(&priv->tx_lock, flags);
+ buffered = (int)priv->tx_outstanding_bytes;
+ spin_unlock_irqrestore(&priv->tx_lock, flags);
+ if (buffered < 0) {
+ err("%s outstanding tx bytes is negative!", __FUNCTION__);
+ buffered = 0;
+ }
+ return buffered;
} /* ftdi_chars_in_buffer */
@@ -1509,6 +1581,8 @@ static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct tty_struct *tty;
struct ftdi_private *priv;
+ unsigned long countread;
+ unsigned long flags;
if (urb->number_of_packets > 0) {
err("%s transfer_buffer_length %d actual_length %d number of packets %d",__FUNCTION__,
@@ -1543,6 +1617,13 @@ static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
return;
}
+ /* count data bytes, but not status bytes */
+ countread = urb->actual_length;
+ countread -= 2 * ((countread + (PKTSZ - 1)) / PKTSZ);
+ spin_lock_irqsave(&priv->rx_lock, flags);
+ priv->rx_bytes += countread;
+ spin_unlock_irqrestore(&priv->rx_lock, flags);
+
ftdi_process_read(port);
} /* ftdi_read_bulk_callback */
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index 6ab2ac845bd..9f7343a4542 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -36,6 +36,9 @@
#define FTDI_ACTZWAVE_PID 0xF2D0
+/* www.starting-point-systems.com µChameleon device */
+#define FTDI_MICRO_CHAMELEON_PID 0xCAA0 /* Product Id */
+
/* www.irtrans.de device */
#define FTDI_IRTRANS_PID 0xFC60 /* Product Id */
@@ -179,6 +182,10 @@
/* http://home.earthlink.net/~jrhees/USBUIRT/index.htm */
#define FTDI_USB_UIRT_PID 0xF850 /* Product Id */
+/* TNC-X USB-to-packet-radio adapter, versions prior to 3.0 (DLP module) */
+
+#define FTDI_TNC_X_PID 0xEBE0
+
/*
* ELV USB devices submitted by Christian Abt of ELV (www.elv.de).
* All of these devices use FTDI's vendor ID (0x0403).
@@ -442,6 +449,18 @@
*/
#define FTDI_YEI_SERVOCENTER31_PID 0xE050 /* YEI ServoCenter3.1 USB */
+/*
+ * ThorLabs USB motor drivers
+ */
+#define FTDI_THORLABS_PID 0xfaf0 /* ThorLabs USB motor drivers */
+
+/*
+ * Testo products (http://www.testo.com/)
+ * Submitted by Colin Leroy
+ */
+#define TESTO_VID 0x128D
+#define TESTO_USB_INTERFACE_PID 0x0001
+
/* Commands */
#define FTDI_SIO_RESET 0 /* Reset the port */
#define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */
diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c
index 803721b97e2..77b977206a8 100644
--- a/drivers/usb/serial/funsoft.c
+++ b/drivers/usb/serial/funsoft.c
@@ -13,7 +13,7 @@
#include <linux/tty.h>
#include <linux/module.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x1404, 0xcddc) },
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
index 1f5d1620baa..727852634be 100644
--- a/drivers/usb/serial/garmin_gps.c
+++ b/drivers/usb/serial/garmin_gps.c
@@ -35,6 +35,7 @@
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
+#include <linux/usb/serial.h>
/* the mode to be set when the port ist opened */
static int initial_mode = 1;
@@ -42,8 +43,6 @@ static int initial_mode = 1;
/* debug flag */
static int debug = 0;
-#include "usb-serial.h"
-
#define GARMIN_VENDOR_ID 0x091E
/*
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index 945b8bb38c9..17271355639 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -17,8 +17,8 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/usb.h>
+#include <linux/usb/serial.h>
#include <asm/uaccess.h>
-#include "usb-serial.h"
static int debug;
@@ -285,6 +285,7 @@ void usb_serial_generic_read_bulk_callback (struct urb *urb, struct pt_regs *reg
if (result)
dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
}
+EXPORT_SYMBOL_GPL(usb_serial_generic_read_bulk_callback);
void usb_serial_generic_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
{
diff --git a/drivers/usb/serial/hp4x.c b/drivers/usb/serial/hp4x.c
index 7e06358b031..ebcac701b06 100644
--- a/drivers/usb/serial/hp4x.c
+++ b/drivers/usb/serial/hp4x.c
@@ -17,7 +17,7 @@
#include <linux/tty.h>
#include <linux/module.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
/*
* Version Information
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index bd2c05dac2a..c49976c3ad5 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -44,7 +44,7 @@
#include <linux/wait.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
#include "io_edgeport.h"
#include "io_ionsp.h" /* info for the iosp messages */
#include "io_16654.h" /* 16654 UART defines */
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index 723a12ae87b..17c5b1d2311 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -39,8 +39,8 @@
#include <asm/uaccess.h>
#include <asm/semaphore.h>
#include <linux/usb.h>
+#include <linux/usb/serial.h>
-#include "usb-serial.h"
#include "io_16654.h"
#include "io_usbvend.h"
#include "io_ti.h"
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index dbcfe172a5c..7e1bd5d6dfa 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -55,7 +55,7 @@
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
#include "ipaq.h"
#define KP_RETRIES 100
@@ -70,6 +70,8 @@
static __u16 product, vendor;
static int debug;
+static int connect_retries = KP_RETRIES;
+static int initial_wait;
/* Function prototypes for an ipaq */
static int ipaq_open (struct usb_serial_port *port, struct file *filp);
@@ -248,6 +250,7 @@ static struct usb_device_id ipaq_id_table [] = {
{ USB_DEVICE(0x04C5, 0x1058) }, /* FUJITSU USB Sync */
{ USB_DEVICE(0x04C5, 0x1079) }, /* FUJITSU USB Sync */
{ USB_DEVICE(0x04DA, 0x2500) }, /* Panasonic USB Sync */
+ { USB_DEVICE(0x04DD, 0x9102) }, /* SHARP WS003SH USB Modem */
{ USB_DEVICE(0x04E8, 0x5F00) }, /* Samsung NEXiO USB Sync */
{ USB_DEVICE(0x04E8, 0x5F01) }, /* Samsung NEXiO USB Sync */
{ USB_DEVICE(0x04E8, 0x5F02) }, /* Samsung NEXiO USB Sync */
@@ -582,7 +585,7 @@ static int ipaq_open(struct usb_serial_port *port, struct file *filp)
struct ipaq_private *priv;
struct ipaq_packet *pkt;
int i, result = 0;
- int retries = KP_RETRIES;
+ int retries = connect_retries;
dbg("%s - port %d", __FUNCTION__, port->number);
@@ -646,16 +649,12 @@ static int ipaq_open(struct usb_serial_port *port, struct file *filp)
port->read_urb->transfer_buffer_length = URBDATA_SIZE;
port->bulk_out_size = port->write_urb->transfer_buffer_length = URBDATA_SIZE;
+ msleep(1000*initial_wait);
/* Start reading from the device */
usb_fill_bulk_urb(port->read_urb, serial->dev,
usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
ipaq_read_bulk_callback, port);
- result = usb_submit_urb(port->read_urb, GFP_KERNEL);
- if (result) {
- err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
- goto error;
- }
/*
* Send out control message observed in win98 sniffs. Not sure what
@@ -670,8 +669,14 @@ static int ipaq_open(struct usb_serial_port *port, struct file *filp)
usb_sndctrlpipe(serial->dev, 0), 0x22, 0x21,
0x1, 0, NULL, 0, 100);
if (result == 0) {
+ result = usb_submit_urb(port->read_urb, GFP_KERNEL);
+ if (result) {
+ err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
+ goto error;
+ }
return 0;
}
+ msleep(1000);
}
err("%s - failed doing control urb, error %d", __FUNCTION__, result);
goto error;
@@ -854,6 +859,7 @@ static void ipaq_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
if (urb->status) {
dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
+ return;
}
spin_lock_irqsave(&write_list_lock, flags);
@@ -966,3 +972,9 @@ MODULE_PARM_DESC(vendor, "User specified USB idVendor");
module_param(product, ushort, 0);
MODULE_PARM_DESC(product, "User specified USB idProduct");
+
+module_param(connect_retries, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(connect_retries, "Maximum number of connect retries (one second each)");
+
+module_param(initial_wait, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(initial_wait, "Time to wait before attempting a connection (in seconds)");
diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c
index a4a0bfeaab0..87306cb6f9f 100644
--- a/drivers/usb/serial/ipw.c
+++ b/drivers/usb/serial/ipw.c
@@ -46,8 +46,8 @@
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/usb.h>
+#include <linux/usb/serial.h>
#include <asm/uaccess.h>
-#include "usb-serial.h"
/*
* Version Information
@@ -373,6 +373,8 @@ static void ipw_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
dbg("%s", __FUNCTION__);
+ port->write_urb_busy = 0;
+
if (urb->status)
dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index 2cf1fed3de4..1738b0b6a37 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -57,7 +57,7 @@
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
/*
* Version Information
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index d7c58f1bc96..015ad6cc1bb 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -107,7 +107,7 @@
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
#include "keyspan.h"
static int debug;
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index 03ab3c0f3cc..49b8dc039d1 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -78,6 +78,7 @@
#include <linux/workqueue.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
+#include <linux/usb/serial.h>
static int debug;
@@ -107,8 +108,6 @@ struct ezusb_hex_record {
#include "xircom_pgs_fw.h"
#endif
-#include "usb-serial.h"
-
/*
* Version Information
*/
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index b45ff3e7ab4..2a2f3e2da05 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -55,7 +55,7 @@
#include <linux/module.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
#include "kl5kusb105.h"
static int debug;
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index 45773337477..d50dce03495 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -46,8 +46,8 @@
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
+#include <linux/usb/serial.h>
#include <linux/ioctl.h>
-#include "usb-serial.h"
#include "kobil_sct.h"
static int debug;
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index ca05d3275f3..f4d4305c2c0 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -75,7 +75,7 @@
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
#include "mct_u232.h"
/*
diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c
index 7f544081032..ac3f8b5d2c4 100644
--- a/drivers/usb/serial/navman.c
+++ b/drivers/usb/serial/navman.c
@@ -14,7 +14,7 @@
#include <linux/tty_flip.h>
#include <linux/module.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
static int debug;
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index cfb711a21a4..e49f40913c2 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -46,7 +46,7 @@
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
static int debug;
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 78ad4b3126a..c856e6f40e2 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -9,39 +9,14 @@
Portions copied from the Keyspan driver by Hugh Blemings <hugh@blemings.org>
- History:
-
- 2005-05-19 v0.1 Initial version, based on incomplete docs
- and analysis of misbehavior with the standard driver
- 2005-05-20 v0.2 Extended the input buffer to avoid losing
- random 64-byte chunks of data
- 2005-05-21 v0.3 implemented chars_in_buffer()
- turned on low_latency
- simplified the code somewhat
- 2005-05-24 v0.4 option_write() sometimes deadlocked under heavy load
- removed some dead code
- added sponsor notice
- coding style clean-up
- 2005-06-20 v0.4.1 add missing braces :-/
- killed end-of-line whitespace
- 2005-07-15 v0.4.2 rename WLAN product to FUSION, add FUSION2
- 2005-09-10 v0.4.3 added HUAWEI E600 card and Audiovox AirCard
- 2005-09-20 v0.4.4 increased recv buffer size: the card sometimes
- wants to send >2000 bytes.
- 2006-04-10 v0.5 fixed two array overrun errors :-/
- 2006-04-21 v0.5.1 added support for Sierra Wireless MC8755
- 2006-05-15 v0.6 re-enable multi-port support
- 2006-06-01 v0.6.1 add COBRA
- 2006-06-01 v0.6.2 add backwards-compatibility stuff
- 2006-06-01 v0.6.3 add Novatel Wireless
- 2006-06-01 v0.7 Option => GSM
+ History: see the git log.
Work sponsored by: Sigos GmbH, Germany <info@sigos.de>
This driver exists because the "normal" serial driver doesn't work too well
with GSM modems. Issues:
- data loss -- one single Receive URB is not nearly enough
- - nonstandard flow (Option devices) and multiplex (Sierra) control
+ - nonstandard flow (Option devices) control
- controlling the baud rate doesn't make sense
This driver is named "option" because the most common device it's
@@ -53,7 +28,7 @@
device features.
*/
-#define DRIVER_VERSION "v0.7.0"
+#define DRIVER_VERSION "v0.7.1"
#define DRIVER_AUTHOR "Matthias Urlichs <smurf@smurf.noris.de>"
#define DRIVER_DESC "USB Driver for GSM modems"
@@ -64,7 +39,7 @@
#include <linux/tty_flip.h>
#include <linux/module.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
/* Function prototypes */
static int option_open(struct usb_serial_port *port, struct file *filp);
@@ -95,27 +70,29 @@ static int option_send_setup(struct usb_serial_port *port);
#define OPTION_VENDOR_ID 0x0AF0
#define HUAWEI_VENDOR_ID 0x12D1
#define AUDIOVOX_VENDOR_ID 0x0F3D
-#define SIERRAWIRELESS_VENDOR_ID 0x1199
#define NOVATELWIRELESS_VENDOR_ID 0x1410
+#define ANYDATA_VENDOR_ID 0x16d5
#define OPTION_PRODUCT_OLD 0x5000
#define OPTION_PRODUCT_FUSION 0x6000
#define OPTION_PRODUCT_FUSION2 0x6300
#define OPTION_PRODUCT_COBRA 0x6500
+#define OPTION_PRODUCT_COBRA2 0x6600
#define HUAWEI_PRODUCT_E600 0x1001
#define AUDIOVOX_PRODUCT_AIRCARD 0x0112
-#define SIERRAWIRELESS_PRODUCT_MC8755 0x6802
#define NOVATELWIRELESS_PRODUCT_U740 0x1400
+#define ANYDATA_PRODUCT_ID 0x6501
static struct usb_device_id option_ids[] = {
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA2) },
{ USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },
{ USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) },
- { USB_DEVICE(SIERRAWIRELESS_VENDOR_ID, SIERRAWIRELESS_PRODUCT_MC8755) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) },
+ { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) },
{ } /* Terminating entry */
};
@@ -124,13 +101,11 @@ static struct usb_device_id option_ids1[] = {
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA2) },
{ USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },
{ USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) },
- { } /* Terminating entry */
-};
-static struct usb_device_id option_ids3[] = {
- { USB_DEVICE(SIERRAWIRELESS_VENDOR_ID, SIERRAWIRELESS_PRODUCT_MC8755) },
+ { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) },
{ } /* Terminating entry */
};
@@ -147,37 +122,11 @@ static struct usb_driver option_driver = {
/* The card has three separate interfaces, which the serial driver
* recognizes separately, thus num_port=1.
*/
-static struct usb_serial_driver option_3port_device = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "option",
- },
- .description = "GSM modem (3-port)",
- .id_table = option_ids3,
- .num_interrupt_in = NUM_DONT_CARE,
- .num_bulk_in = NUM_DONT_CARE,
- .num_bulk_out = NUM_DONT_CARE,
- .num_ports = 3,
- .open = option_open,
- .close = option_close,
- .write = option_write,
- .write_room = option_write_room,
- .chars_in_buffer = option_chars_in_buffer,
- .throttle = option_rx_throttle,
- .unthrottle = option_rx_unthrottle,
- .set_termios = option_set_termios,
- .break_ctl = option_break_ctl,
- .tiocmget = option_tiocmget,
- .tiocmset = option_tiocmset,
- .attach = option_startup,
- .shutdown = option_shutdown,
- .read_int_callback = option_instat_callback,
-};
static struct usb_serial_driver option_1port_device = {
.driver = {
.owner = THIS_MODULE,
- .name = "option",
+ .name = "option1",
},
.description = "GSM modem (1-port)",
.id_table = option_ids1,
@@ -241,9 +190,6 @@ static int __init option_init(void)
retval = usb_serial_register(&option_1port_device);
if (retval)
goto failed_1port_device_register;
- retval = usb_serial_register(&option_3port_device);
- if (retval)
- goto failed_3port_device_register;
retval = usb_register(&option_driver);
if (retval)
goto failed_driver_register;
@@ -253,8 +199,6 @@ static int __init option_init(void)
return 0;
failed_driver_register:
- usb_serial_deregister (&option_3port_device);
-failed_3port_device_register:
usb_serial_deregister (&option_1port_device);
failed_1port_device_register:
return retval;
@@ -263,7 +207,6 @@ failed_1port_device_register:
static void __exit option_exit(void)
{
usb_deregister (&option_driver);
- usb_serial_deregister (&option_3port_device);
usb_serial_deregister (&option_1port_device);
}
@@ -652,7 +595,6 @@ static void option_setup_urbs(struct usb_serial *serial)
dbg("%s", __FUNCTION__);
-
for (i = 0; i < serial->num_ports; i++) {
port = serial->port[i];
portdata = usb_get_serial_port_data(port);
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index de93a2b909e..efbbc0adb89 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -27,7 +27,7 @@
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
#include "pl2303.h"
/*
@@ -52,6 +52,7 @@ struct pl2303_buf {
static struct usb_device_id id_table [] = {
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
+ { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) },
{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
@@ -79,6 +80,8 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) },
{ USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) },
{ USB_DEVICE(OTI_VENDOR_ID, OTI_PRODUCT_ID) },
+ { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },
+ { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },
{ } /* Terminating entry */
};
diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h
index 7f29e81d3e3..a692ac66ca6 100644
--- a/drivers/usb/serial/pl2303.h
+++ b/drivers/usb/serial/pl2303.h
@@ -10,6 +10,7 @@
#define PL2303_VENDOR_ID 0x067b
#define PL2303_PRODUCT_ID 0x2303
#define PL2303_PRODUCT_ID_RSAQ2 0x04bb
+#define PL2303_PRODUCT_ID_DCU11 0x1234
#define PL2303_PRODUCT_ID_PHAROS 0xaaa0
#define PL2303_PRODUCT_ID_RSAQ3 0xaaa2
@@ -84,3 +85,11 @@
/* Ours Technology Inc DKU-5 clone, chipset: Prolific Technology Inc */
#define OTI_VENDOR_ID 0x0ea0
#define OTI_PRODUCT_ID 0x6858
+
+/* DATAPILOT Universal-2 Phone Cable */
+#define DATAPILOT_U2_VENDOR_ID 0x0731
+#define DATAPILOT_U2_PRODUCT_ID 0x2003
+
+/* Belkin "F5U257" Serial Adapter */
+#define BELKIN_VENDOR_ID 0x050d
+#define BELKIN_PRODUCT_ID 0x0257
diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
index 897d8447252..789771ecdb1 100644
--- a/drivers/usb/serial/safe_serial.c
+++ b/drivers/usb/serial/safe_serial.c
@@ -71,7 +71,7 @@
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
#ifndef CONFIG_USB_SAFE_PADDED
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
new file mode 100644
index 00000000000..d29638daa98
--- /dev/null
+++ b/drivers/usb/serial/sierra.c
@@ -0,0 +1,75 @@
+/*
+ * Sierra Wireless CDMA Wireless Serial USB driver
+ *
+ * Current Copy modified by: Kevin Lloyd <linux@sierrawireless.com>
+ * Original Copyright (C) 2005-2006 Greg Kroah-Hartman <gregkh@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+
+static struct usb_device_id id_table [] = {
+ { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
+ { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
+ { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
+ { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
+ { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
+ { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
+ { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */
+ { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
+ /* Following devices are supported in the airprime.c driver */
+ /* { USB_DEVICE(0x1199, 0x0112) }, */ /* Sierra Wireless AirCard 580 */
+ /* { USB_DEVICE(0x0F3D, 0x0112) }, */ /* AirPrime/Sierra PC 5220 */
+ { }
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+static struct usb_driver sierra_driver = {
+ .name = "sierra_wireless",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = id_table,
+};
+
+static struct usb_serial_driver sierra_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "Sierra_Wireless",
+ },
+ .id_table = id_table,
+ .num_interrupt_in = NUM_DONT_CARE,
+ .num_bulk_in = NUM_DONT_CARE,
+ .num_bulk_out = NUM_DONT_CARE,
+ .num_ports = 3,
+};
+
+static int __init sierra_init(void)
+{
+ int retval;
+
+ retval = usb_serial_register(&sierra_device);
+ if (retval)
+ return retval;
+ retval = usb_register(&sierra_driver);
+ if (retval)
+ usb_serial_deregister(&sierra_device);
+ return retval;
+}
+
+static void __exit sierra_exit(void)
+{
+ usb_deregister(&sierra_driver);
+ usb_serial_deregister(&sierra_device);
+}
+
+module_init(sierra_init);
+module_exit(sierra_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index a9afff31a92..ac9b8ee52d4 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -83,8 +83,8 @@
#include <asm/uaccess.h>
#include <asm/semaphore.h>
#include <linux/usb.h>
+#include <linux/usb/serial.h>
-#include "usb-serial.h"
#include "ti_usb_3410_5052.h"
#include "ti_fw_3410.h" /* firmware image for 3410 */
#include "ti_fw_5052.h" /* firmware image for 5052 */
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index b59a0536ea5..12c1694d322 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -31,7 +31,7 @@
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
#include "pl2303.h"
/*
@@ -40,6 +40,8 @@
#define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux/"
#define DRIVER_DESC "USB Serial Driver core"
+static void port_free(struct usb_serial_port *port);
+
/* Driver structure we register with the USB core */
static struct usb_driver usb_serial_driver = {
.name = "usbserial",
@@ -146,23 +148,10 @@ static void destroy_serial(struct kref *kref)
port = serial->port[i];
if (!port)
continue;
- usb_kill_urb(port->read_urb);
- usb_free_urb(port->read_urb);
- usb_kill_urb(port->write_urb);
- usb_free_urb(port->write_urb);
- usb_kill_urb(port->interrupt_in_urb);
- usb_free_urb(port->interrupt_in_urb);
- usb_kill_urb(port->interrupt_out_urb);
- usb_free_urb(port->interrupt_out_urb);
- kfree(port->bulk_in_buffer);
- kfree(port->bulk_out_buffer);
- kfree(port->interrupt_in_buffer);
- kfree(port->interrupt_out_buffer);
+ port_free(port);
}
}
- flush_scheduled_work(); /* port->work */
-
usb_put_dev(serial->dev);
/* free up any memory that we allocated */
@@ -564,6 +553,11 @@ static void port_release(struct device *dev)
struct usb_serial_port *port = to_usb_serial_port(dev);
dbg ("%s - %s", __FUNCTION__, dev->bus_id);
+ port_free(port);
+}
+
+static void port_free(struct usb_serial_port *port)
+{
usb_kill_urb(port->read_urb);
usb_free_urb(port->read_urb);
usb_kill_urb(port->write_urb);
@@ -576,6 +570,7 @@ static void port_release(struct device *dev)
kfree(port->bulk_out_buffer);
kfree(port->interrupt_in_buffer);
kfree(port->interrupt_out_buffer);
+ flush_scheduled_work(); /* port->work */
kfree(port);
}
diff --git a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h
deleted file mode 100644
index 0f2802a6019..00000000000
--- a/drivers/usb/serial/usb-serial.h
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- * USB Serial Converter driver
- *
- * Copyright (C) 1999 - 2005
- * Greg Kroah-Hartman (greg@kroah.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.
- *
- */
-
-
-#ifndef __LINUX_USB_SERIAL_H
-#define __LINUX_USB_SERIAL_H
-
-#include <linux/kref.h>
-#include <linux/mutex.h>
-
-#define SERIAL_TTY_MAJOR 188 /* Nice legal number now */
-#define SERIAL_TTY_MINORS 255 /* loads of devices :) */
-
-#define MAX_NUM_PORTS 8 /* The maximum number of ports one device can grab at once */
-
-/* parity check flag */
-#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-
-/**
- * usb_serial_port: structure for the specific ports of a device.
- * @serial: pointer back to the struct usb_serial owner of this port.
- * @tty: pointer to the corresponding tty for this port.
- * @lock: spinlock to grab when updating portions of this structure.
- * @mutex: mutex used to synchronize serial_open() and serial_close()
- * access for this port.
- * @number: the number of the port (the minor number).
- * @interrupt_in_buffer: pointer to the interrupt in buffer for this port.
- * @interrupt_in_urb: pointer to the interrupt in struct urb for this port.
- * @interrupt_in_endpointAddress: endpoint address for the interrupt in pipe
- * for this port.
- * @interrupt_out_buffer: pointer to the interrupt out buffer for this port.
- * @interrupt_out_size: the size of the interrupt_out_buffer, in bytes.
- * @interrupt_out_urb: pointer to the interrupt out struct urb for this port.
- * @interrupt_out_endpointAddress: endpoint address for the interrupt out pipe
- * for this port.
- * @bulk_in_buffer: pointer to the bulk in buffer for this port.
- * @read_urb: pointer to the bulk in struct urb for this port.
- * @bulk_in_endpointAddress: endpoint address for the bulk in pipe for this
- * port.
- * @bulk_out_buffer: pointer to the bulk out buffer for this port.
- * @bulk_out_size: the size of the bulk_out_buffer, in bytes.
- * @write_urb: pointer to the bulk out struct urb for this port.
- * @bulk_out_endpointAddress: endpoint address for the bulk out pipe for this
- * port.
- * @write_wait: a wait_queue_head_t used by the port.
- * @work: work queue entry for the line discipline waking up.
- * @open_count: number of times this port has been opened.
- *
- * This structure is used by the usb-serial core and drivers for the specific
- * ports of a device.
- */
-struct usb_serial_port {
- struct usb_serial * serial;
- struct tty_struct * tty;
- spinlock_t lock;
- struct mutex mutex;
- unsigned char number;
-
- unsigned char * interrupt_in_buffer;
- struct urb * interrupt_in_urb;
- __u8 interrupt_in_endpointAddress;
-
- unsigned char * interrupt_out_buffer;
- int interrupt_out_size;
- struct urb * interrupt_out_urb;
- __u8 interrupt_out_endpointAddress;
-
- unsigned char * bulk_in_buffer;
- int bulk_in_size;
- struct urb * read_urb;
- __u8 bulk_in_endpointAddress;
-
- unsigned char * bulk_out_buffer;
- int bulk_out_size;
- struct urb * write_urb;
- int write_urb_busy;
- __u8 bulk_out_endpointAddress;
-
- wait_queue_head_t write_wait;
- struct work_struct work;
- int open_count;
- struct device dev;
-};
-#define to_usb_serial_port(d) container_of(d, struct usb_serial_port, dev)
-
-/* get and set the port private data pointer helper functions */
-static inline void *usb_get_serial_port_data (struct usb_serial_port *port)
-{
- return dev_get_drvdata(&port->dev);
-}
-
-static inline void usb_set_serial_port_data (struct usb_serial_port *port, void *data)
-{
- dev_set_drvdata(&port->dev, data);
-}
-
-/**
- * usb_serial - structure used by the usb-serial core for a device
- * @dev: pointer to the struct usb_device for this device
- * @type: pointer to the struct usb_serial_driver for this device
- * @interface: pointer to the struct usb_interface for this device
- * @minor: the starting minor number for this device
- * @num_ports: the number of ports this device has
- * @num_interrupt_in: number of interrupt in endpoints we have
- * @num_interrupt_out: number of interrupt out endpoints we have
- * @num_bulk_in: number of bulk in endpoints we have
- * @num_bulk_out: number of bulk out endpoints we have
- * @port: array of struct usb_serial_port structures for the different ports.
- * @private: place to put any driver specific information that is needed. The
- * usb-serial driver is required to manage this data, the usb-serial core
- * will not touch this. Use usb_get_serial_data() and
- * usb_set_serial_data() to access this.
- */
-struct usb_serial {
- struct usb_device * dev;
- struct usb_serial_driver * type;
- struct usb_interface * interface;
- unsigned char minor;
- unsigned char num_ports;
- unsigned char num_port_pointers;
- char num_interrupt_in;
- char num_interrupt_out;
- char num_bulk_in;
- char num_bulk_out;
- struct usb_serial_port * port[MAX_NUM_PORTS];
- struct kref kref;
- void * private;
-};
-#define to_usb_serial(d) container_of(d, struct usb_serial, kref)
-
-#define NUM_DONT_CARE (-1)
-
-/* get and set the serial private data pointer helper functions */
-static inline void *usb_get_serial_data (struct usb_serial *serial)
-{
- return serial->private;
-}
-
-static inline void usb_set_serial_data (struct usb_serial *serial, void *data)
-{
- serial->private = data;
-}
-
-/**
- * usb_serial_driver - describes a usb serial driver
- * @description: pointer to a string that describes this driver. This string used
- * in the syslog messages when a device is inserted or removed.
- * @id_table: pointer to a list of usb_device_id structures that define all
- * of the devices this structure can support.
- * @num_interrupt_in: the number of interrupt in endpoints this device will
- * have.
- * @num_interrupt_out: the number of interrupt out endpoints this device will
- * have.
- * @num_bulk_in: the number of bulk in endpoints this device will have.
- * @num_bulk_out: the number of bulk out endpoints this device will have.
- * @num_ports: the number of different ports this device will have.
- * @calc_num_ports: pointer to a function to determine how many ports this
- * device has dynamically. It will be called after the probe()
- * callback is called, but before attach()
- * @probe: pointer to the driver's probe function.
- * This will be called when the device is inserted into the system,
- * but before the device has been fully initialized by the usb_serial
- * subsystem. Use this function to download any firmware to the device,
- * or any other early initialization that might be needed.
- * Return 0 to continue on with the initialization sequence. Anything
- * else will abort it.
- * @attach: pointer to the driver's attach function.
- * This will be called when the struct usb_serial structure is fully set
- * set up. Do any local initialization of the device, or any private
- * memory structure allocation at this point in time.
- * @shutdown: pointer to the driver's shutdown function. This will be
- * called when the device is removed from the system.
- *
- * This structure is defines a USB Serial driver. It provides all of
- * the information that the USB serial core code needs. If the function
- * pointers are defined, then the USB serial core code will call them when
- * the corresponding tty port functions are called. If they are not
- * called, the generic serial function will be used instead.
- *
- * The driver.owner field should be set to the module owner of this driver.
- * The driver.name field should be set to the name of this driver (remember
- * it will show up in sysfs, so it needs to be short and to the point.
- * Useing the module name is a good idea.)
- */
-struct usb_serial_driver {
- const char *description;
- const struct usb_device_id *id_table;
- char num_interrupt_in;
- char num_interrupt_out;
- char num_bulk_in;
- char num_bulk_out;
- char num_ports;
-
- struct list_head driver_list;
- struct device_driver driver;
-
- int (*probe) (struct usb_serial *serial, const struct usb_device_id *id);
- int (*attach) (struct usb_serial *serial);
- int (*calc_num_ports) (struct usb_serial *serial);
-
- void (*shutdown) (struct usb_serial *serial);
-
- int (*port_probe) (struct usb_serial_port *port);
- int (*port_remove) (struct usb_serial_port *port);
-
- /* serial function calls */
- int (*open) (struct usb_serial_port *port, struct file * filp);
- void (*close) (struct usb_serial_port *port, struct file * filp);
- int (*write) (struct usb_serial_port *port, const unsigned char *buf, int count);
- int (*write_room) (struct usb_serial_port *port);
- int (*ioctl) (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
- void (*set_termios) (struct usb_serial_port *port, struct termios * old);
- void (*break_ctl) (struct usb_serial_port *port, int break_state);
- int (*chars_in_buffer) (struct usb_serial_port *port);
- void (*throttle) (struct usb_serial_port *port);
- void (*unthrottle) (struct usb_serial_port *port);
- int (*tiocmget) (struct usb_serial_port *port, struct file *file);
- int (*tiocmset) (struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear);
-
- void (*read_int_callback)(struct urb *urb, struct pt_regs *regs);
- void (*write_int_callback)(struct urb *urb, struct pt_regs *regs);
- void (*read_bulk_callback)(struct urb *urb, struct pt_regs *regs);
- void (*write_bulk_callback)(struct urb *urb, struct pt_regs *regs);
-};
-#define to_usb_serial_driver(d) container_of(d, struct usb_serial_driver, driver)
-
-extern int usb_serial_register(struct usb_serial_driver *driver);
-extern void usb_serial_deregister(struct usb_serial_driver *driver);
-extern void usb_serial_port_softint(struct usb_serial_port *port);
-
-extern int usb_serial_probe(struct usb_interface *iface, const struct usb_device_id *id);
-extern void usb_serial_disconnect(struct usb_interface *iface);
-
-extern int ezusb_writememory (struct usb_serial *serial, int address, unsigned char *data, int length, __u8 bRequest);
-extern int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit);
-
-/* USB Serial console functions */
-#ifdef CONFIG_USB_SERIAL_CONSOLE
-extern void usb_serial_console_init (int debug, int minor);
-extern void usb_serial_console_exit (void);
-extern void usb_serial_console_disconnect(struct usb_serial *serial);
-#else
-static inline void usb_serial_console_init (int debug, int minor) { }
-static inline void usb_serial_console_exit (void) { }
-static inline void usb_serial_console_disconnect(struct usb_serial *serial) {}
-#endif
-
-/* Functions needed by other parts of the usbserial core */
-extern struct usb_serial *usb_serial_get_by_index (unsigned int minor);
-extern void usb_serial_put(struct usb_serial *serial);
-extern int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp);
-extern int usb_serial_generic_write (struct usb_serial_port *port, const unsigned char *buf, int count);
-extern void usb_serial_generic_close (struct usb_serial_port *port, struct file *filp);
-extern int usb_serial_generic_write_room (struct usb_serial_port *port);
-extern int usb_serial_generic_chars_in_buffer (struct usb_serial_port *port);
-extern void usb_serial_generic_read_bulk_callback (struct urb *urb, struct pt_regs *regs);
-extern void usb_serial_generic_write_bulk_callback (struct urb *urb, struct pt_regs *regs);
-extern void usb_serial_generic_shutdown (struct usb_serial *serial);
-extern int usb_serial_generic_register (int debug);
-extern void usb_serial_generic_deregister (void);
-
-extern int usb_serial_bus_register (struct usb_serial_driver *device);
-extern void usb_serial_bus_deregister (struct usb_serial_driver *device);
-
-extern struct usb_serial_driver usb_serial_generic_device;
-extern struct bus_type usb_serial_bus_type;
-extern struct tty_driver *usb_serial_tty_driver;
-
-static inline void usb_serial_debug_data(int debug,
- struct device *dev,
- const char *function, int size,
- const unsigned char *data)
-{
- int i;
-
- if (debug) {
- dev_printk(KERN_DEBUG, dev, "%s - length = %d, data = ", function, size);
- for (i = 0; i < size; ++i)
- printk ("%.2x ", data[i]);
- printk ("\n");
- }
-}
-
-/* Use our own dbg macro */
-#undef dbg
-#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG "%s: " format "\n" , __FILE__ , ## arg); } while (0)
-
-
-
-#endif /* ifdef __LINUX_USB_SERIAL_H */
-
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index 95a2936e902..88949f7884c 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -25,7 +25,7 @@
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
#include "visor.h"
/*
@@ -302,7 +302,6 @@ static int visor_open (struct usb_serial_port *port, struct file *filp)
spin_lock_irqsave(&priv->lock, flags);
priv->bytes_in = 0;
priv->bytes_out = 0;
- priv->outstanding_urbs = 0;
priv->throttled = 0;
spin_unlock_irqrestore(&priv->lock, flags);
@@ -435,13 +434,25 @@ static int visor_write (struct usb_serial_port *port, const unsigned char *buf,
static int visor_write_room (struct usb_serial_port *port)
{
+ struct visor_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+
dbg("%s - port %d", __FUNCTION__, port->number);
/*
* We really can take anything the user throws at us
* but let's pick a nice big number to tell the tty
- * layer that we have lots of free space
+ * layer that we have lots of free space, unless we don't.
*/
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (priv->outstanding_urbs > URB_UPPER_LIMIT * 2 / 3) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ dbg("%s - write limit hit\n", __FUNCTION__);
+ return 0;
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+
return 2048;
}
@@ -758,15 +769,22 @@ static int visor_calc_num_ports (struct usb_serial *serial)
static int generic_startup(struct usb_serial *serial)
{
+ struct usb_serial_port **ports = serial->port;
struct visor_private *priv;
int i;
for (i = 0; i < serial->num_ports; ++i) {
priv = kzalloc (sizeof(*priv), GFP_KERNEL);
- if (!priv)
+ if (!priv) {
+ while (i-- != 0) {
+ priv = usb_get_serial_port_data(ports[i]);
+ usb_set_serial_port_data(ports[i], NULL);
+ kfree(priv);
+ }
return -ENOMEM;
+ }
spin_lock_init(&priv->lock);
- usb_set_serial_port_data(serial->port[i], priv);
+ usb_set_serial_port_data(ports[i], priv);
}
return 0;
}
@@ -876,7 +894,18 @@ static int clie_5_attach (struct usb_serial *serial)
static void visor_shutdown (struct usb_serial *serial)
{
+ struct visor_private *priv;
+ int i;
+
dbg("%s", __FUNCTION__);
+
+ for (i = 0; i < serial->num_ports; i++) {
+ priv = usb_get_serial_port_data(serial->port[i]);
+ if (priv) {
+ usb_set_serial_port_data(serial->port[i], NULL);
+ kfree(priv);
+ }
+ }
}
static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index 540438c3f38..6e6c7934be3 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -79,7 +79,7 @@
#include <linux/usb.h>
#include <linux/serial_reg.h>
#include <linux/serial.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
#include "whiteheat_fw.h" /* firmware for the ConnectTech WhiteHEAT device */
#include "whiteheat.h" /* WhiteHEAT specific commands */
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index 5715291ba54..a4b7df9ff8c 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -112,13 +112,11 @@ static int slave_configure(struct scsi_device *sdev)
if (sdev->scsi_level < SCSI_2)
sdev->scsi_level = sdev->sdev_target->scsi_level = SCSI_2;
- /* According to the technical support people at Genesys Logic,
- * devices using their chips have problems transferring more than
- * 32 KB at a time. In practice people have found that 64 KB
- * works okay and that's what Windows does. But we'll be
- * conservative; people can always use the sysfs interface to
- * increase max_sectors. */
- if (le16_to_cpu(us->pusb_dev->descriptor.idVendor) == USB_VENDOR_ID_GENESYS &&
+ /* Many devices have trouble transfering more than 32KB at a time,
+ * while others have trouble with more than 64K. At this time we
+ * are limiting both to 32K (64 sectores).
+ */
+ if ((us->flags & US_FL_MAX_SECTORS_64) &&
sdev->request_queue->max_sectors > 64)
blk_queue_max_sectors(sdev->request_queue, 64);
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index eb7188b3565..d6acc92a4ae 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -180,7 +180,7 @@ static int usb_stor_msg_common(struct us_data *us, int timeout)
if (timeleft <= 0) {
US_DEBUGP("%s -- cancelling URB\n",
timeleft == 0 ? "Timeout" : "Signal");
- usb_unlink_urb(us->current_urb);
+ usb_kill_urb(us->current_urb);
}
/* return the URB status */
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index c7e84e653df..2793f9a912b 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -112,6 +112,19 @@ UNUSUAL_DEV( 0x0411, 0x001c, 0x0113, 0x0113,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_INQUIRY ),
+/* Submitted by Ernestas Vaiciukevicius <ernisv@gmail.com> */
+UNUSUAL_DEV( 0x0419, 0x0100, 0x0100, 0x0100,
+ "Samsung Info. Systems America, Inc.",
+ "MP3 Player",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE ),
+
+/* Reported by Orgad Shaneh <orgads@gmail.com> */
+UNUSUAL_DEV( 0x0419, 0xaace, 0x0100, 0x0100,
+ "Samsung", "MP3 Player",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE ),
+
/* Reported by Christian Leber <christian@leber.de> */
UNUSUAL_DEV( 0x0419, 0xaaf5, 0x0100, 0x0100,
"TrekStor",
@@ -132,6 +145,21 @@ UNUSUAL_DEV( 0x0420, 0x0001, 0x0100, 0x0100,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
+/* Reported by Mario Rettig <mariorettig@web.de> */
+UNUSUAL_DEV( 0x0421, 0x042e, 0x0100, 0x0100,
+ "Nokia",
+ "Nokia 3250",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ),
+
+/* Reported by Sumedha Swamy <sumedhaswamy@gmail.com> and
+ * Einar Th. Einarsson <einarthered@gmail.com> */
+UNUSUAL_DEV( 0x0421, 0x0444, 0x0100, 0x0100,
+ "Nokia",
+ "N91",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ),
+
/* Reported by Jiri Slaby <jirislaby@gmail.com> and
* Rene C. Castberg <Rene@Castberg.org> */
UNUSUAL_DEV( 0x0421, 0x0446, 0x0100, 0x0100,
@@ -140,6 +168,13 @@ UNUSUAL_DEV( 0x0421, 0x0446, 0x0100, 0x0100,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ),
+/* Reported by Matthew Bloch <matthew@bytemark.co.uk> */
+UNUSUAL_DEV( 0x0421, 0x044e, 0x0100, 0x0100,
+ "Nokia",
+ "E61",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ),
+
/* Reported by Olaf Hering <olh@suse.de> from novell bug #105878 */
UNUSUAL_DEV( 0x0424, 0x0fdc, 0x0210, 0x0210,
"SMSC",
@@ -473,10 +508,11 @@ UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0450,
US_SC_SCSI, US_PR_DEVICE, NULL,
US_FL_SINGLE_LUN | US_FL_NOT_LOCKABLE | US_FL_NO_WP_DETECT ),
-/* This entry is needed because the device reports Sub=ff */
-UNUSUAL_DEV( 0x054c, 0x0010, 0x0500, 0x0600,
+/* Submitted by Lars Jacob <jacob.lars@googlemail.com>
+ * This entry is needed because the device reports Sub=ff */
+UNUSUAL_DEV( 0x054c, 0x0010, 0x0500, 0x0610,
"Sony",
- "DSC-T1/T5",
+ "DSC-T1/T5/H5",
US_SC_8070, US_PR_DEVICE, NULL,
US_FL_SINGLE_LUN ),
@@ -598,18 +634,6 @@ UNUSUAL_DEV( 0x0595, 0x4343, 0x0000, 0x2210,
"Digital Camera EX-20 DSC",
US_SC_8070, US_PR_DEVICE, NULL, 0 ),
-/* The entry was here before I took over, and had US_SC_RBC. It turns
- * out that isn't needed. Additionally, Torsten Eriksson
- * <Torsten.Eriksson@bergianska.se> is able to use his device fine
- * without this entry at all - but I don't suspect that will be true
- * for all users (the protocol is likely needed), so is staying at
- * this time. - Phil Dibowitz <phil@ipom.com>
- */
-UNUSUAL_DEV( 0x059f, 0xa601, 0x0200, 0x0200,
- "LaCie",
- "USB Hard Disk",
- US_SC_DEVICE, US_PR_CB, NULL, 0 ),
-
/* Submitted by Joel Bourquard <numlock@freesurf.ch>
* Some versions of this device need the SubClass and Protocol overrides
* while others don't.
@@ -708,18 +732,22 @@ UNUSUAL_DEV( 0x05dc, 0xb002, 0x0000, 0x0113,
* They were originally reported by Alexander Oltu
* <alexander@all-2.com> and Peter Marks <peter.marks@turner.com>
* respectively.
+ *
+ * US_FL_GO_SLOW and US_FL_MAX_SECTORS_64 added by Phil Dibowitz
+ * <phil@ipom.com> as these flags were made and hard-coded
+ * special-cases were pulled from scsiglue.c.
*/
UNUSUAL_DEV( 0x05e3, 0x0701, 0x0000, 0xffff,
"Genesys Logic",
"USB to IDE Optical",
US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_GO_SLOW ),
+ US_FL_GO_SLOW | US_FL_MAX_SECTORS_64 ),
UNUSUAL_DEV( 0x05e3, 0x0702, 0x0000, 0xffff,
"Genesys Logic",
"USB to IDE Disk",
US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_GO_SLOW ),
+ US_FL_GO_SLOW | US_FL_MAX_SECTORS_64 ),
/* Reported by Hanno Boeck <hanno@gmx.de>
* Taken from the Lycoris Kernel */
@@ -1073,7 +1101,15 @@ UNUSUAL_DEV( 0x0a17, 0x006, 0x0000, 0xffff,
"Optio S/S4",
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_INQUIRY ),
-
+
+/* This is a virtual windows driver CD, which the zd1211rw driver automatically
+ * converts into a WLAN device. */
+UNUSUAL_DEV( 0x0ace, 0x2011, 0x0101, 0x0101,
+ "ZyXEL",
+ "G-220F USB-WLAN Install",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_DEVICE ),
+
#ifdef CONFIG_USB_STORAGE_ISD200
UNUSUAL_DEV( 0x0bf6, 0xa001, 0x0100, 0x0110,
"ATI",
@@ -1196,6 +1232,14 @@ UNUSUAL_DEV( 0x0ea0, 0x6828, 0x0110, 0x0110,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
+/* Reported by Benjamin Schiller <sbenni@gmx.de>
+ * It is also sold by Easylite as DJ 20 */
+UNUSUAL_DEV( 0x0ed1, 0x7636, 0x0103, 0x0103,
+ "Typhoon",
+ "My DJ 1820",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE | US_FL_GO_SLOW | US_FL_MAX_SECTORS_64),
+
/* Reported by Michael Stattmann <michael@stattmann.com> */
UNUSUAL_DEV( 0x0fce, 0xd008, 0x0000, 0x0000,
"Sony Ericsson",
@@ -1227,6 +1271,15 @@ UNUSUAL_DEV( 0x1370, 0x6828, 0x0110, 0x0110,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
+/* patch submitted by Davide Perini <perini.davide@dpsoftware.org>
+ * and Renato Perini <rperini@email.it>
+ */
+UNUSUAL_DEV( 0x22b8, 0x3010, 0x0001, 0x0001,
+ "Motorola",
+ "RAZR V3x",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY | US_FL_IGNORE_RESIDUE ),
+
/* Reported by Radovan Garabik <garabik@kassiopeia.juls.savba.sk> */
UNUSUAL_DEV( 0x2735, 0x100b, 0x0000, 0x9999,
"MPIO",
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 1185acac4b2..8d7bdcb5924 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -55,6 +55,7 @@
#include <linux/slab.h>
#include <linux/kthread.h>
#include <linux/mutex.h>
+#include <linux/utsrelease.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -373,8 +374,12 @@ static int usb_stor_control_thread(void * __us)
/* lock access to the state */
scsi_lock(host);
+ /* did the command already complete because of a disconnect? */
+ if (!us->srb)
+ ; /* nothing to do */
+
/* indicate that the command is done */
- if (us->srb->result != DID_ABORT << 16) {
+ else if (us->srb->result != DID_ABORT << 16) {
US_DEBUGP("scsi cmd done, result=0x%x\n",
us->srb->result);
us->srb->scsi_done(us->srb);
@@ -478,7 +483,7 @@ static struct us_unusual_dev *find_unusual(const struct usb_device_id *id)
}
/* Get the unusual_devs entries and the string descriptors */
-static void get_device_info(struct us_data *us, const struct usb_device_id *id)
+static int get_device_info(struct us_data *us, const struct usb_device_id *id)
{
struct usb_device *dev = us->pusb_dev;
struct usb_interface_descriptor *idesc =
@@ -495,6 +500,11 @@ static void get_device_info(struct us_data *us, const struct usb_device_id *id)
unusual_dev->useTransport;
us->flags = USB_US_ORIG_FLAGS(id->driver_info);
+ if (us->flags & US_FL_IGNORE_DEVICE) {
+ printk(KERN_INFO USB_STORAGE "device ignored\n");
+ return -ENODEV;
+ }
+
/*
* This flag is only needed when we're in high-speed, so let's
* disable it if we're in full-speed
@@ -524,7 +534,8 @@ static void get_device_info(struct us_data *us, const struct usb_device_id *id)
if (msg >= 0 && !(us->flags & US_FL_NEED_OVERRIDE))
printk(KERN_NOTICE USB_STORAGE "This device "
"(%04x,%04x,%04x S %02x P %02x)"
- " has %s in unusual_devs.h\n"
+ " has %s in unusual_devs.h (kernel"
+ " %s)\n"
" Please send a copy of this message to "
"<linux-usb-devel@lists.sourceforge.net>\n",
le16_to_cpu(ddesc->idVendor),
@@ -532,8 +543,11 @@ static void get_device_info(struct us_data *us, const struct usb_device_id *id)
le16_to_cpu(ddesc->bcdDevice),
idesc->bInterfaceSubClass,
idesc->bInterfaceProtocol,
- msgs[msg]);
+ msgs[msg],
+ UTS_RELEASE);
}
+
+ return 0;
}
/* Get the transport settings */
@@ -836,32 +850,34 @@ static void dissociate_dev(struct us_data *us)
* the host */
static void quiesce_and_remove_host(struct us_data *us)
{
+ struct Scsi_Host *host = us_to_host(us);
+
/* Prevent new USB transfers, stop the current command, and
* interrupt a SCSI-scan or device-reset delay */
+ scsi_lock(host);
set_bit(US_FLIDX_DISCONNECTING, &us->flags);
+ scsi_unlock(host);
usb_stor_stop_transport(us);
wake_up(&us->delay_wait);
/* It doesn't matter if the SCSI-scanning thread is still running.
* The thread will exit when it sees the DISCONNECTING flag. */
- /* Wait for the current command to finish, then remove the host */
- mutex_lock(&us->dev_mutex);
- mutex_unlock(&us->dev_mutex);
-
/* queuecommand won't accept any new commands and the control
* thread won't execute a previously-queued command. If there
* is such a command pending, complete it with an error. */
+ mutex_lock(&us->dev_mutex);
if (us->srb) {
us->srb->result = DID_NO_CONNECT << 16;
- scsi_lock(us_to_host(us));
+ scsi_lock(host);
us->srb->scsi_done(us->srb);
us->srb = NULL;
- scsi_unlock(us_to_host(us));
+ scsi_unlock(host);
}
+ mutex_unlock(&us->dev_mutex);
/* Now we own no commands so it's safe to remove the SCSI host */
- scsi_remove_host(us_to_host(us));
+ scsi_remove_host(host);
}
/* Second stage of disconnect processing: deallocate all resources */
@@ -960,7 +976,9 @@ static int storage_probe(struct usb_interface *intf,
* of the match from the usb_device_id table, so we can find the
* corresponding entry in the private table.
*/
- get_device_info(us, id);
+ result = get_device_info(us, id);
+ if (result)
+ goto BadDevice;
/* Get the transport, protocol, and pipe settings */
result = get_transport(us);
diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
index 5284abe1b5e..21f3ddbc908 100644
--- a/drivers/usb/storage/usb.h
+++ b/drivers/usb/storage/usb.h
@@ -176,8 +176,4 @@ extern void fill_inquiry_response(struct us_data *us,
#define scsi_unlock(host) spin_unlock_irq(host->host_lock)
#define scsi_lock(host) spin_lock_irq(host->host_lock)
-
-/* Vendor ID list for devices that require special handling */
-#define USB_VENDOR_ID_GENESYS 0x05e3 /* Genesys Logic */
-
#endif
diff --git a/drivers/video/68328fb.c b/drivers/video/68328fb.c
index 78488bb41ae..0dda73da862 100644
--- a/drivers/video/68328fb.c
+++ b/drivers/video/68328fb.c
@@ -32,7 +32,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 3badb48d662..c40b9b8b1e7 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -86,9 +86,11 @@ config FB_MACMODES
default n
config FB_BACKLIGHT
- bool
- depends on FB
- default n
+ bool
+ depends on FB
+ select BACKLIGHT_LCD_SUPPORT
+ select BACKLIGHT_CLASS_DEVICE
+ default n
config FB_MODE_HELPERS
bool "Enable Video Mode Handling Helpers"
@@ -420,7 +422,7 @@ config FB_OF
config FB_CONTROL
bool "Apple \"control\" display support"
- depends on (FB = y) && PPC_PMAC
+ depends on (FB = y) && PPC_PMAC && PPC32
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -431,7 +433,7 @@ config FB_CONTROL
config FB_PLATINUM
bool "Apple \"platinum\" display support"
- depends on (FB = y) && PPC_PMAC
+ depends on (FB = y) && PPC_PMAC && PPC32
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -442,7 +444,7 @@ config FB_PLATINUM
config FB_VALKYRIE
bool "Apple \"valkyrie\" display support"
- depends on (FB = y) && (MAC || PPC_PMAC)
+ depends on (FB = y) && (MAC || (PPC_PMAC && PPC32))
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -453,7 +455,7 @@ config FB_VALKYRIE
config FB_CT65550
bool "Chips 65550 display support"
- depends on (FB = y) && PPC
+ depends on (FB = y) && PPC32
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -721,10 +723,8 @@ config FB_NVIDIA_I2C
config FB_NVIDIA_BACKLIGHT
bool "Support for backlight control"
- depends on FB_NVIDIA && PPC_PMAC
+ depends on FB_NVIDIA && PMAC_BACKLIGHT
select FB_BACKLIGHT
- select BACKLIGHT_LCD_SUPPORT
- select BACKLIGHT_CLASS_DEVICE
default y
help
Say Y here if you want to control the backlight of your display.
@@ -769,10 +769,8 @@ config FB_RIVA_DEBUG
config FB_RIVA_BACKLIGHT
bool "Support for backlight control"
- depends on FB_RIVA && PPC_PMAC
+ depends on FB_RIVA && PMAC_BACKLIGHT
select FB_BACKLIGHT
- select BACKLIGHT_LCD_SUPPORT
- select BACKLIGHT_CLASS_DEVICE
default y
help
Say Y here if you want to control the backlight of your display.
@@ -1025,10 +1023,8 @@ config FB_RADEON_I2C
config FB_RADEON_BACKLIGHT
bool "Support for backlight control"
- depends on FB_RADEON && PPC_PMAC
+ depends on FB_RADEON && PMAC_BACKLIGHT
select FB_BACKLIGHT
- select BACKLIGHT_LCD_SUPPORT
- select BACKLIGHT_CLASS_DEVICE
default y
help
Say Y here if you want to control the backlight of your display.
@@ -1059,10 +1055,8 @@ config FB_ATY128
config FB_ATY128_BACKLIGHT
bool "Support for backlight control"
- depends on FB_ATY128 && PPC_PMAC
+ depends on FB_ATY128 && PMAC_BACKLIGHT
select FB_BACKLIGHT
- select BACKLIGHT_LCD_SUPPORT
- select BACKLIGHT_CLASS_DEVICE
default y
help
Say Y here if you want to control the backlight of your display.
@@ -1111,10 +1105,8 @@ config FB_ATY_GX
config FB_ATY_BACKLIGHT
bool "Support for backlight control"
- depends on FB_ATY && PPC_PMAC
+ depends on FB_ATY && PMAC_BACKLIGHT
select FB_BACKLIGHT
- select BACKLIGHT_LCD_SUPPORT
- select BACKLIGHT_CLASS_DEVICE
default y
help
Say Y here if you want to control the backlight of your display.
@@ -1518,6 +1510,26 @@ config FB_PXA_PARAMETERS
<file:Documentation/fb/pxafb.txt> describes the available parameters.
+config FB_MBX
+ tristate "2700G LCD framebuffer support"
+ depends on FB && ARCH_PXA
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ ---help---
+ Framebuffer driver for the Intel 2700G (Marathon) Graphics
+ Accelerator
+
+config FB_MBX_DEBUG
+ bool "Enable debugging info via debugfs"
+ depends on FB_MBX && DEBUG_FS
+ default n
+ ---help---
+ Enable this if you want debugging information using the debug
+ filesystem (debugfs)
+
+ If unsure, say N.
+
config FB_W100
tristate "W100 frame buffer support"
depends on FB && PXA_SHARPSL
@@ -1600,7 +1612,7 @@ if FB || SGI_NEWPORT_CONSOLE
source "drivers/video/logo/Kconfig"
endif
-if FB && SYSFS
+if SYSFS
source "drivers/video/backlight/Kconfig"
endif
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 6283d015f8f..481c6c9695f 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -4,6 +4,7 @@
# Each configuration option enables a list of files.
+obj-y += fb_notify.o
obj-$(CONFIG_FB) += fb.o
fb-y := fbmem.o fbmon.o fbcmap.o fbsysfs.o \
modedb.o fbcvt.o
@@ -38,6 +39,7 @@ obj-$(CONFIG_FB_SIS) += sis/
obj-$(CONFIG_FB_KYRO) += kyro/
obj-$(CONFIG_FB_SAVAGE) += savage/
obj-$(CONFIG_FB_GEODE) += geode/
+obj-$(CONFIG_FB_MBX) += mbx/
obj-$(CONFIG_FB_I810) += vgastate.o
obj-$(CONFIG_FB_NEOMAGIC) += neofb.o vgastate.o
obj-$(CONFIG_FB_VIRGE) += virgefb.o
diff --git a/drivers/video/S3triofb.c b/drivers/video/S3triofb.c
index e714e8449c1..afd146f5f68 100644
--- a/drivers/video/S3triofb.c
+++ b/drivers/video/S3triofb.c
@@ -28,7 +28,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c
index f9bc9f777e7..f1ba54f4fc3 100644
--- a/drivers/video/amifb.c
+++ b/drivers/video/amifb.c
@@ -45,7 +45,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
diff --git a/drivers/video/arcfb.c b/drivers/video/arcfb.c
index fd95c2dbd4f..70dd8115a4d 100644
--- a/drivers/video/arcfb.c
+++ b/drivers/video/arcfb.c
@@ -39,7 +39,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
diff --git a/drivers/video/asiliantfb.c b/drivers/video/asiliantfb.c
index eaeaf4d1a09..1fd22f460b0 100644
--- a/drivers/video/asiliantfb.c
+++ b/drivers/video/asiliantfb.c
@@ -34,7 +34,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c
index e69ab65f784..5831893bf7a 100644
--- a/drivers/video/atafb.c
+++ b/drivers/video/atafb.c
@@ -53,7 +53,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/init.h>
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
index 72c58910947..8b08121b390 100644
--- a/drivers/video/aty/aty128fb.c
+++ b/drivers/video/aty/aty128fb.c
@@ -52,7 +52,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
@@ -457,6 +456,10 @@ static void wait_for_fifo(u16 entries, struct aty128fb_par *par);
static void wait_for_idle(struct aty128fb_par *par);
static u32 depth_to_dst(u32 depth);
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
+static void aty128_bl_set_power(struct fb_info *info, int power);
+#endif
+
#define BIOS_IN8(v) (readb(bios + (v)))
#define BIOS_IN16(v) (readb(bios + (v)) | \
(readb(bios + (v) + 1) << 8))
@@ -1258,25 +1261,11 @@ static void aty128_set_lcd_enable(struct aty128fb_par *par, int on)
reg &= ~LVDS_DISPLAY_DIS;
aty_st_le32(LVDS_GEN_CNTL, reg);
#ifdef CONFIG_FB_ATY128_BACKLIGHT
- mutex_lock(&info->bl_mutex);
- if (info->bl_dev) {
- down(&info->bl_dev->sem);
- info->bl_dev->props->update_status(info->bl_dev);
- up(&info->bl_dev->sem);
- }
- mutex_unlock(&info->bl_mutex);
+ aty128_bl_set_power(info, FB_BLANK_UNBLANK);
#endif
} else {
#ifdef CONFIG_FB_ATY128_BACKLIGHT
- mutex_lock(&info->bl_mutex);
- if (info->bl_dev) {
- down(&info->bl_dev->sem);
- info->bl_dev->props->brightness = 0;
- info->bl_dev->props->power = FB_BLANK_POWERDOWN;
- info->bl_dev->props->update_status(info->bl_dev);
- up(&info->bl_dev->sem);
- }
- mutex_unlock(&info->bl_mutex);
+ aty128_bl_set_power(info, FB_BLANK_POWERDOWN);
#endif
reg = aty_ld_le32(LVDS_GEN_CNTL);
reg |= LVDS_DISPLAY_DIS;
@@ -1703,6 +1692,7 @@ static int __devinit aty128fb_setup(char *options)
static struct backlight_properties aty128_bl_data;
+/* Call with fb_info->bl_mutex held */
static int aty128_bl_get_level_brightness(struct aty128fb_par *par,
int level)
{
@@ -1710,10 +1700,8 @@ static int aty128_bl_get_level_brightness(struct aty128fb_par *par,
int atylevel;
/* Get and convert the value */
- mutex_lock(&info->bl_mutex);
atylevel = MAX_LEVEL -
(info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL);
- mutex_unlock(&info->bl_mutex);
if (atylevel < 0)
atylevel = 0;
@@ -1731,7 +1719,8 @@ static int aty128_bl_get_level_brightness(struct aty128fb_par *par,
/* That one prevents proper CRT output with LCD off */
#undef BACKLIGHT_DAC_OFF
-static int aty128_bl_update_status(struct backlight_device *bd)
+/* Call with fb_info->bl_mutex held */
+static int __aty128_bl_update_status(struct backlight_device *bd)
{
struct aty128fb_par *par = class_get_devdata(&bd->class_dev);
unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL);
@@ -1784,6 +1773,19 @@ static int aty128_bl_update_status(struct backlight_device *bd)
return 0;
}
+static int aty128_bl_update_status(struct backlight_device *bd)
+{
+ struct aty128fb_par *par = class_get_devdata(&bd->class_dev);
+ struct fb_info *info = pci_get_drvdata(par->pdev);
+ int ret;
+
+ mutex_lock(&info->bl_mutex);
+ ret = __aty128_bl_update_status(bd);
+ mutex_unlock(&info->bl_mutex);
+
+ return ret;
+}
+
static int aty128_bl_get_brightness(struct backlight_device *bd)
{
return bd->props->brightness;
@@ -1796,6 +1798,16 @@ static struct backlight_properties aty128_bl_data = {
.max_brightness = (FB_BACKLIGHT_LEVELS - 1),
};
+static void aty128_bl_set_power(struct fb_info *info, int power)
+{
+ mutex_lock(&info->bl_mutex);
+ up(&info->bl_dev->sem);
+ info->bl_dev->props->power = power;
+ __aty128_bl_update_status(info->bl_dev);
+ down(&info->bl_dev->sem);
+ mutex_unlock(&info->bl_mutex);
+}
+
static void aty128_bl_init(struct aty128fb_par *par)
{
struct fb_info *info = pci_get_drvdata(par->pdev);
@@ -2198,12 +2210,8 @@ static int aty128fb_blank(int blank, struct fb_info *fb)
return 0;
#ifdef CONFIG_FB_ATY128_BACKLIGHT
- if (machine_is(powermac) && blank) {
- down(&fb->bl_dev->sem);
- fb->bl_dev->props->power = FB_BLANK_POWERDOWN;
- fb->bl_dev->props->update_status(fb->bl_dev);
- up(&fb->bl_dev->sem);
- }
+ if (machine_is(powermac) && blank)
+ aty128_bl_set_power(fb, FB_BLANK_POWERDOWN);
#endif
if (blank & FB_BLANK_VSYNC_SUSPEND)
@@ -2219,14 +2227,12 @@ static int aty128fb_blank(int blank, struct fb_info *fb)
aty128_set_crt_enable(par, par->crt_on && !blank);
aty128_set_lcd_enable(par, par->lcd_on && !blank);
}
+
#ifdef CONFIG_FB_ATY128_BACKLIGHT
- if (machine_is(powermac) && !blank) {
- down(&fb->bl_dev->sem);
- fb->bl_dev->props->power = FB_BLANK_UNBLANK;
- fb->bl_dev->props->update_status(fb->bl_dev);
- up(&fb->bl_dev->sem);
- }
+ if (machine_is(powermac) && !blank)
+ aty128_bl_set_power(fb, FB_BLANK_UNBLANK);
#endif
+
return 0;
}
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index 0c9706746d7..053ff63365b 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -2129,15 +2129,14 @@ static int atyfb_pci_resume(struct pci_dev *pdev)
static struct backlight_properties aty_bl_data;
+/* Call with fb_info->bl_mutex held */
static int aty_bl_get_level_brightness(struct atyfb_par *par, int level)
{
struct fb_info *info = pci_get_drvdata(par->pdev);
int atylevel;
/* Get and convert the value */
- mutex_lock(&info->bl_mutex);
atylevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL;
- mutex_unlock(&info->bl_mutex);
if (atylevel < 0)
atylevel = 0;
@@ -2147,7 +2146,8 @@ static int aty_bl_get_level_brightness(struct atyfb_par *par, int level)
return atylevel;
}
-static int aty_bl_update_status(struct backlight_device *bd)
+/* Call with fb_info->bl_mutex held */
+static int __aty_bl_update_status(struct backlight_device *bd)
{
struct atyfb_par *par = class_get_devdata(&bd->class_dev);
unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, par);
@@ -2172,6 +2172,19 @@ static int aty_bl_update_status(struct backlight_device *bd)
return 0;
}
+static int aty_bl_update_status(struct backlight_device *bd)
+{
+ struct atyfb_par *par = class_get_devdata(&bd->class_dev);
+ struct fb_info *info = pci_get_drvdata(par->pdev);
+ int ret;
+
+ mutex_lock(&info->bl_mutex);
+ ret = __aty_bl_update_status(bd);
+ mutex_unlock(&info->bl_mutex);
+
+ return ret;
+}
+
static int aty_bl_get_brightness(struct backlight_device *bd)
{
return bd->props->brightness;
@@ -2184,6 +2197,16 @@ static struct backlight_properties aty_bl_data = {
.max_brightness = (FB_BACKLIGHT_LEVELS - 1),
};
+static void aty_bl_set_power(struct fb_info *info, int power)
+{
+ mutex_lock(&info->bl_mutex);
+ up(&info->bl_dev->sem);
+ info->bl_dev->props->power = power;
+ __aty_bl_update_status(info->bl_dev);
+ down(&info->bl_dev->sem);
+ mutex_unlock(&info->bl_mutex);
+}
+
static void aty_bl_init(struct atyfb_par *par)
{
struct fb_info *info = pci_get_drvdata(par->pdev);
@@ -2789,17 +2812,9 @@ static int atyfb_blank(int blank, struct fb_info *info)
if (par->lock_blank || par->asleep)
return 0;
-#ifdef CONFIG_PMAC_BACKLIGHT
- if (machine_is(powermac) && blank > FB_BLANK_NORMAL) {
- mutex_lock(&info->bl_mutex);
- if (info->bl_dev) {
- down(&info->bl_dev->sem);
- info->bl_dev->props->power = FB_BLANK_POWERDOWN;
- info->bl_dev->props->update_status(info->bl_dev);
- up(&info->bl_dev->sem);
- }
- mutex_unlock(&info->bl_mutex);
- }
+#ifdef CONFIG_FB_ATY_BACKLIGHT
+ if (machine_is(powermac) && blank > FB_BLANK_NORMAL)
+ aty_bl_set_power(info, FB_BLANK_POWERDOWN);
#elif defined(CONFIG_FB_ATY_GENERIC_LCD)
if (par->lcd_table && blank > FB_BLANK_NORMAL &&
(aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {
@@ -2829,17 +2844,9 @@ static int atyfb_blank(int blank, struct fb_info *info)
}
aty_st_le32(CRTC_GEN_CNTL, gen_cntl, par);
-#ifdef CONFIG_PMAC_BACKLIGHT
- if (machine_is(powermac) && blank <= FB_BLANK_NORMAL) {
- mutex_lock(&info->bl_mutex);
- if (info->bl_dev) {
- down(&info->bl_dev->sem);
- info->bl_dev->props->power = FB_BLANK_UNBLANK;
- info->bl_dev->props->update_status(info->bl_dev);
- up(&info->bl_dev->sem);
- }
- mutex_unlock(&info->bl_mutex);
- }
+#ifdef CONFIG_FB_ATY_BACKLIGHT
+ if (machine_is(powermac) && blank <= FB_BLANK_NORMAL)
+ aty_bl_set_power(info, FB_BLANK_UNBLANK);
#elif defined(CONFIG_FB_ATY_GENERIC_LCD)
if (par->lcd_table && blank <= FB_BLANK_NORMAL &&
(aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {
diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c
index 51b78f8de94..8e3400d5dd2 100644
--- a/drivers/video/aty/radeon_base.c
+++ b/drivers/video/aty/radeon_base.c
@@ -58,7 +58,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/time.h>
@@ -267,6 +266,8 @@ static int force_measure_pll = 0;
#ifdef CONFIG_MTRR
static int nomtrr = 0;
#endif
+static int force_sleep;
+static int ignore_devlist;
/*
* prototypes
@@ -2328,9 +2329,9 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev,
/* -2 is special: means ON on mobility chips and do not
* change on others
*/
- radeonfb_pm_init(rinfo, rinfo->is_mobility ? 1 : -1);
+ radeonfb_pm_init(rinfo, rinfo->is_mobility ? 1 : -1, ignore_devlist, force_sleep);
} else
- radeonfb_pm_init(rinfo, default_dynclk);
+ radeonfb_pm_init(rinfo, default_dynclk, ignore_devlist, force_sleep);
pci_set_drvdata(pdev, info);
@@ -2478,6 +2479,12 @@ static int __init radeonfb_setup (char *options)
force_measure_pll = 1;
} else if (!strncmp(this_opt, "ignore_edid", 11)) {
ignore_edid = 1;
+#if defined(CONFIG_PM) && defined(CONFIG_X86)
+ } else if (!strncmp(this_opt, "force_sleep", 11)) {
+ force_sleep = 1;
+ } else if (!strncmp(this_opt, "ignore_devlist", 14)) {
+ ignore_devlist = 1;
+#endif
} else
mode_option = this_opt;
}
@@ -2533,3 +2540,9 @@ module_param(panel_yres, int, 0);
MODULE_PARM_DESC(panel_yres, "int: set panel yres");
module_param(mode_option, charp, 0);
MODULE_PARM_DESC(mode_option, "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
+#if defined(CONFIG_PM) && defined(CONFIG_X86)
+module_param(force_sleep, bool, 0);
+MODULE_PARM_DESC(force_sleep, "bool: force D2 sleep mode on all hardware");
+module_param(ignore_devlist, bool, 0);
+MODULE_PARM_DESC(ignore_devlist, "bool: ignore workarounds for bugs in specific laptops");
+#endif
diff --git a/drivers/video/aty/radeon_pm.c b/drivers/video/aty/radeon_pm.c
index c7091761cef..f31e606a2de 100644
--- a/drivers/video/aty/radeon_pm.c
+++ b/drivers/video/aty/radeon_pm.c
@@ -27,6 +27,99 @@
#include "ati_ids.h"
+static void radeon_reinitialize_M10(struct radeonfb_info *rinfo);
+
+/*
+ * Workarounds for bugs in PC laptops:
+ * - enable D2 sleep in some IBM Thinkpads
+ * - special case for Samsung P35
+ *
+ * Whitelist by subsystem vendor/device because
+ * its the subsystem vendor's fault!
+ */
+
+#if defined(CONFIG_PM) && defined(CONFIG_X86)
+struct radeon_device_id {
+ const char *ident; /* (arbitrary) Name */
+ const unsigned short subsystem_vendor; /* Subsystem Vendor ID */
+ const unsigned short subsystem_device; /* Subsystem Device ID */
+ const enum radeon_pm_mode pm_mode_modifier; /* modify pm_mode */
+ const reinit_function_ptr new_reinit_func; /* changed reinit_func */
+};
+
+#define BUGFIX(model, sv, sd, pm, fn) { \
+ .ident = model, \
+ .subsystem_vendor = sv, \
+ .subsystem_device = sd, \
+ .pm_mode_modifier = pm, \
+ .new_reinit_func = fn \
+}
+
+static struct radeon_device_id radeon_workaround_list[] = {
+ BUGFIX("IBM Thinkpad R32",
+ PCI_VENDOR_ID_IBM, 0x1905,
+ radeon_pm_d2, NULL),
+ BUGFIX("IBM Thinkpad R40",
+ PCI_VENDOR_ID_IBM, 0x0526,
+ radeon_pm_d2, NULL),
+ BUGFIX("IBM Thinkpad R40",
+ PCI_VENDOR_ID_IBM, 0x0527,
+ radeon_pm_d2, NULL),
+ BUGFIX("IBM Thinkpad R50/R51/T40/T41",
+ PCI_VENDOR_ID_IBM, 0x0531,
+ radeon_pm_d2, NULL),
+ BUGFIX("IBM Thinkpad R51/T40/T41/T42",
+ PCI_VENDOR_ID_IBM, 0x0530,
+ radeon_pm_d2, NULL),
+ BUGFIX("IBM Thinkpad T30",
+ PCI_VENDOR_ID_IBM, 0x0517,
+ radeon_pm_d2, NULL),
+ BUGFIX("IBM Thinkpad T40p",
+ PCI_VENDOR_ID_IBM, 0x054d,
+ radeon_pm_d2, NULL),
+ BUGFIX("IBM Thinkpad T42",
+ PCI_VENDOR_ID_IBM, 0x0550,
+ radeon_pm_d2, NULL),
+ BUGFIX("IBM Thinkpad X31/X32",
+ PCI_VENDOR_ID_IBM, 0x052f,
+ radeon_pm_d2, NULL),
+ BUGFIX("Samsung P35",
+ PCI_VENDOR_ID_SAMSUNG, 0xc00c,
+ radeon_pm_off, radeon_reinitialize_M10),
+ { .ident = NULL }
+};
+
+static int radeon_apply_workarounds(struct radeonfb_info *rinfo)
+{
+ struct radeon_device_id *id;
+
+ for (id = radeon_workaround_list; id->ident != NULL; id++ )
+ if ((id->subsystem_vendor == rinfo->pdev->subsystem_vendor ) &&
+ (id->subsystem_device == rinfo->pdev->subsystem_device )) {
+
+ /* we found a device that requires workaround */
+ printk(KERN_DEBUG "radeonfb: %s detected"
+ ", enabling workaround\n", id->ident);
+
+ rinfo->pm_mode |= id->pm_mode_modifier;
+
+ if (id->new_reinit_func != NULL)
+ rinfo->reinit_func = id->new_reinit_func;
+
+ return 1;
+ }
+ return 0; /* not found */
+}
+
+#else /* defined(CONFIG_PM) && defined(CONFIG_X86) */
+static inline int radeon_apply_workarounds(struct radeonfb_info *rinfo)
+{
+ return 0;
+}
+#endif /* defined(CONFIG_PM) && defined(CONFIG_X86) */
+
+
+
static void radeon_pm_disable_dynamic_mode(struct radeonfb_info *rinfo)
{
u32 tmp;
@@ -852,18 +945,26 @@ static void radeon_pm_setup_for_suspend(struct radeonfb_info *rinfo)
/* because both INPLL and OUTPLL take the same lock, that's why. */
tmp = INPLL( pllMCLK_MISC) | MCLK_MISC__EN_MCLK_TRISTATE_IN_SUSPEND;
OUTPLL( pllMCLK_MISC, tmp);
-
- /* AGP PLL control */
- if (rinfo->family <= CHIP_FAMILY_RV280) {
- OUTREG(BUS_CNTL1, INREG(BUS_CNTL1) | BUS_CNTL1__AGPCLK_VALID);
- OUTREG(BUS_CNTL1,
- (INREG(BUS_CNTL1) & ~BUS_CNTL1__MOBILE_PLATFORM_SEL_MASK)
- | (2<<BUS_CNTL1__MOBILE_PLATFORM_SEL__SHIFT)); // 440BX
- } else {
- OUTREG(BUS_CNTL1, INREG(BUS_CNTL1));
- OUTREG(BUS_CNTL1, (INREG(BUS_CNTL1) & ~0x4000) | 0x8000);
+ /* BUS_CNTL1__MOBILE_PLATORM_SEL setting is northbridge chipset
+ * and radeon chip dependent. Thus we only enable it on Mac for
+ * now (until we get more info on how to compute the correct
+ * value for various X86 bridges).
+ */
+#ifdef CONFIG_PPC_PMAC
+ if (machine_is(powermac)) {
+ /* AGP PLL control */
+ if (rinfo->family <= CHIP_FAMILY_RV280) {
+ OUTREG(BUS_CNTL1, INREG(BUS_CNTL1) | BUS_CNTL1__AGPCLK_VALID);
+ OUTREG(BUS_CNTL1,
+ (INREG(BUS_CNTL1) & ~BUS_CNTL1__MOBILE_PLATFORM_SEL_MASK)
+ | (2<<BUS_CNTL1__MOBILE_PLATFORM_SEL__SHIFT)); // 440BX
+ } else {
+ OUTREG(BUS_CNTL1, INREG(BUS_CNTL1));
+ OUTREG(BUS_CNTL1, (INREG(BUS_CNTL1) & ~0x4000) | 0x8000);
+ }
}
+#endif
OUTREG(CRTC_OFFSET_CNTL, (INREG(CRTC_OFFSET_CNTL)
& ~CRTC_OFFSET_CNTL__CRTC_STEREO_SYNC_OUT_EN));
@@ -2713,7 +2814,7 @@ static void radeonfb_early_resume(void *data)
#endif /* CONFIG_PM */
-void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk)
+void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk, int ignore_devlist, int force_sleep)
{
/* Find PM registers in config space if any*/
rinfo->pm_reg = pci_find_capability(rinfo->pdev, PCI_CAP_ID_PM);
@@ -2729,22 +2830,13 @@ void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk)
}
#if defined(CONFIG_PM)
+#if defined(CONFIG_PPC_PMAC)
/* Check if we can power manage on suspend/resume. We can do
* D2 on M6, M7 and M9, and we can resume from D3 cold a few other
* "Mac" cards, but that's all. We need more infos about what the
* BIOS does tho. Right now, all this PM stuff is pmac-only for that
* reason. --BenH
*/
- /* Special case for Samsung P35 laptops
- */
- if ((rinfo->pdev->vendor == PCI_VENDOR_ID_ATI) &&
- (rinfo->pdev->device == PCI_CHIP_RV350_NP) &&
- (rinfo->pdev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG) &&
- (rinfo->pdev->subsystem_device == 0xc00c)) {
- rinfo->reinit_func = radeon_reinitialize_M10;
- rinfo->pm_mode |= radeon_pm_off;
- }
-#if defined(CONFIG_PPC_PMAC)
if (machine_is(powermac) && rinfo->of_node) {
if (rinfo->is_mobility && rinfo->pm_reg &&
rinfo->family <= CHIP_FAMILY_RV250)
@@ -2790,6 +2882,18 @@ void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk)
}
#endif /* defined(CONFIG_PPC_PMAC) */
#endif /* defined(CONFIG_PM) */
+
+ if (ignore_devlist)
+ printk(KERN_DEBUG
+ "radeonfb: skipping test for device workarounds\n");
+ else
+ radeon_apply_workarounds(rinfo);
+
+ if (force_sleep) {
+ printk(KERN_DEBUG
+ "radeonfb: forcefully enabling D2 sleep mode\n");
+ rinfo->pm_mode |= radeon_pm_d2;
+ }
}
void radeonfb_pm_exit(struct radeonfb_info *rinfo)
diff --git a/drivers/video/aty/radeonfb.h b/drivers/video/aty/radeonfb.h
index 38657b2d10e..d5ff224a625 100644
--- a/drivers/video/aty/radeonfb.h
+++ b/drivers/video/aty/radeonfb.h
@@ -273,6 +273,8 @@ enum radeon_pm_mode {
radeon_pm_off = 0x00000002, /* Can resume from D3 cold */
};
+typedef void (*reinit_function_ptr)(struct radeonfb_info *rinfo);
+
struct radeonfb_info {
struct fb_info *info;
@@ -338,7 +340,7 @@ struct radeonfb_info {
int dynclk;
int no_schedule;
enum radeon_pm_mode pm_mode;
- void (*reinit_func)(struct radeonfb_info *rinfo);
+ reinit_function_ptr reinit_func;
/* Lock on register access */
spinlock_t reg_lock;
@@ -600,7 +602,7 @@ extern int radeon_probe_i2c_connector(struct radeonfb_info *rinfo, int conn, u8
/* PM Functions */
extern int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t state);
extern int radeonfb_pci_resume(struct pci_dev *pdev);
-extern void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk);
+extern void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk, int ignore_devlist, int force_sleep);
extern void radeonfb_pm_exit(struct radeonfb_info *rinfo);
/* Monitor probe functions */
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 022f9d3473f..02f15297a02 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -10,7 +10,7 @@ menuconfig BACKLIGHT_LCD_SUPPORT
config BACKLIGHT_CLASS_DEVICE
tristate "Lowlevel Backlight controls"
- depends on BACKLIGHT_LCD_SUPPORT && FB
+ depends on BACKLIGHT_LCD_SUPPORT
default m
help
This framework adds support for low-level control of the LCD
@@ -26,7 +26,7 @@ config BACKLIGHT_DEVICE
config LCD_CLASS_DEVICE
tristate "Lowlevel LCD controls"
- depends on BACKLIGHT_LCD_SUPPORT && FB
+ depends on BACKLIGHT_LCD_SUPPORT
default m
help
This framework adds support for low-level control of LCD.
diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c
index 0e465c80ef2..73cb426bf2d 100644
--- a/drivers/video/chipsfb.c
+++ b/drivers/video/chipsfb.c
@@ -19,7 +19,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
@@ -150,12 +149,11 @@ static int chipsfb_blank(int blank, struct fb_info *info)
mutex_lock(&pmac_backlight_mutex);
if (pmac_backlight) {
- down(&pmac_backlight->sem);
-
/* used to disable backlight only for blank > 1, but it seems
* useful at blank = 1 too (saves battery, extends backlight
* life)
*/
+ down(&pmac_backlight->sem);
if (blank)
pmac_backlight->props->power = FB_BLANK_POWERDOWN;
else
diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c
index 7355da09c72..daf43f535a0 100644
--- a/drivers/video/cirrusfb.c
+++ b/drivers/video/cirrusfb.c
@@ -41,7 +41,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c
index 878707a0439..d9315d99445 100644
--- a/drivers/video/console/dummycon.c
+++ b/drivers/video/console/dummycon.c
@@ -7,9 +7,9 @@
#include <linux/types.h>
#include <linux/kdev_t.h>
-#include <linux/tty.h>
#include <linux/console.h>
#include <linux/vt_kern.h>
+#include <linux/screen_info.h>
#include <linux/init.h>
#include <linux/module.h>
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 94e9f7069be..390439b3d89 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -64,7 +64,6 @@
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/delay.h> /* MSch: for IRQ probe */
-#include <linux/tty.h>
#include <linux/console.h>
#include <linux/string.h>
#include <linux/kd.h>
diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c
index c89f90edf8a..eb4d03fa539 100644
--- a/drivers/video/console/mdacon.c
+++ b/drivers/video/console/mdacon.c
@@ -31,7 +31,6 @@
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/tty.h>
#include <linux/console.h>
#include <linux/string.h>
#include <linux/kd.h>
@@ -198,7 +197,7 @@ static int __init mdacon_setup(char *str)
__setup("mdacon=", mdacon_setup);
#endif
-static int __init mda_detect(void)
+static int mda_detect(void)
{
int count=0;
u16 *p, p_save;
@@ -283,7 +282,7 @@ static int __init mda_detect(void)
return 1;
}
-static void __init mda_initialize(void)
+static void mda_initialize(void)
{
write_mda_b(97, 0x00); /* horizontal total */
write_mda_b(80, 0x01); /* horizontal displayed */
diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c
index 03041311711..7fa1afeae8d 100644
--- a/drivers/video/console/newport_con.c
+++ b/drivers/video/console/newport_con.c
@@ -12,7 +12,6 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/tty.h>
#include <linux/kd.h>
#include <linux/selection.h>
#include <linux/console.h>
diff --git a/drivers/video/console/promcon.c b/drivers/video/console/promcon.c
index 5cd5e114d1e..b78eac63459 100644
--- a/drivers/video/console/promcon.c
+++ b/drivers/video/console/promcon.c
@@ -10,7 +10,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/console.h>
diff --git a/drivers/video/console/softcursor.c b/drivers/video/console/softcursor.c
index 3957fc7523e..557c563e4ae 100644
--- a/drivers/video/console/softcursor.c
+++ b/drivers/video/console/softcursor.c
@@ -10,7 +10,6 @@
#include <linux/module.h>
#include <linux/string.h>
-#include <linux/tty.h>
#include <linux/fb.h>
#include <linux/slab.h>
diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c
index 45c4f227e56..45586aaabd1 100644
--- a/drivers/video/console/sticon.c
+++ b/drivers/video/console/sticon.c
@@ -37,7 +37,6 @@
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/tty.h>
#include <linux/console.h>
#include <linux/errno.h>
#include <linux/vt_kern.h>
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
index 05735ff4e9c..0a2c10a1abf 100644
--- a/drivers/video/console/vgacon.c
+++ b/drivers/video/console/vgacon.c
@@ -38,7 +38,6 @@
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/kernel.h>
-#include <linux/tty.h>
#include <linux/console.h>
#include <linux/string.h>
#include <linux/kd.h>
@@ -48,6 +47,7 @@
#include <linux/spinlock.h>
#include <linux/ioport.h>
#include <linux/init.h>
+#include <linux/screen_info.h>
#include <linux/smp_lock.h>
#include <video/vga.h>
#include <asm/io.h>
diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c
index acdd6a103db..8cc6c0e2d27 100644
--- a/drivers/video/controlfb.c
+++ b/drivers/video/controlfb.c
@@ -36,7 +36,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c
index 2e2924957d8..aae6d9c26e8 100644
--- a/drivers/video/cyber2000fb.c
+++ b/drivers/video/cyber2000fb.c
@@ -41,7 +41,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
diff --git a/drivers/video/cyberfb.c b/drivers/video/cyberfb.c
index a3e189f90a7..c40e72dafb0 100644
--- a/drivers/video/cyberfb.c
+++ b/drivers/video/cyberfb.c
@@ -81,7 +81,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/zorro.h>
diff --git a/drivers/video/dnfb.c b/drivers/video/dnfb.c
index 5abd3cb0067..b083ea7e9c6 100644
--- a/drivers/video/dnfb.c
+++ b/drivers/video/dnfb.c
@@ -2,7 +2,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
diff --git a/drivers/video/epson1355fb.c b/drivers/video/epson1355fb.c
index f0a621ecc28..737257d278f 100644
--- a/drivers/video/epson1355fb.c
+++ b/drivers/video/epson1355fb.c
@@ -48,7 +48,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
diff --git a/drivers/video/fb_notify.c b/drivers/video/fb_notify.c
new file mode 100644
index 00000000000..8c020389e4f
--- /dev/null
+++ b/drivers/video/fb_notify.c
@@ -0,0 +1,46 @@
+/*
+ * linux/drivers/video/fb_notify.c
+ *
+ * Copyright (C) 2006 Antonino Daplas <adaplas@pol.net>
+ *
+ * 2001 - Documented with DocBook
+ * - Brad Douglas <brad@neruo.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+#include <linux/fb.h>
+#include <linux/notifier.h>
+
+static BLOCKING_NOTIFIER_HEAD(fb_notifier_list);
+
+/**
+ * fb_register_client - register a client notifier
+ * @nb: notifier block to callback on events
+ */
+int fb_register_client(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(&fb_notifier_list, nb);
+}
+EXPORT_SYMBOL(fb_register_client);
+
+/**
+ * fb_unregister_client - unregister a client notifier
+ * @nb: notifier block to callback on events
+ */
+int fb_unregister_client(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_unregister(&fb_notifier_list, nb);
+}
+EXPORT_SYMBOL(fb_unregister_client);
+
+/**
+ * fb_notifier_call_chain - notify clients of fb_events
+ *
+ */
+int fb_notifier_call_chain(unsigned long val, void *v)
+{
+ return blocking_notifier_call_chain(&fb_notifier_list, val, v);
+}
+EXPORT_SYMBOL_GPL(fb_notifier_call_chain);
diff --git a/drivers/video/fbcmap.c b/drivers/video/fbcmap.c
index 1f98392a43b..e8b135f3d80 100644
--- a/drivers/video/fbcmap.c
+++ b/drivers/video/fbcmap.c
@@ -13,7 +13,6 @@
#include <linux/string.h>
#include <linux/module.h>
-#include <linux/tty.h>
#include <linux/fb.h>
#include <linux/slab.h>
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 33034f81114..17961e3ecaa 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -23,7 +23,7 @@
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/mman.h>
-#include <linux/tty.h>
+#include <linux/vt.h>
#include <linux/init.h>
#include <linux/linux_logo.h>
#include <linux/proc_fs.h>
@@ -52,7 +52,6 @@
#define FBPIXMAPSIZE (1024 * 8)
-static BLOCKING_NOTIFIER_HEAD(fb_notifier_list);
struct fb_info *registered_fb[FB_MAX];
int num_registered_fb;
@@ -791,8 +790,7 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
event.info = info;
event.data = &mode1;
- ret = blocking_notifier_call_chain(&fb_notifier_list,
- FB_EVENT_MODE_DELETE, &event);
+ ret = fb_notifier_call_chain(FB_EVENT_MODE_DELETE, &event);
}
if (!ret)
@@ -837,8 +835,7 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
info->flags &= ~FBINFO_MISC_USEREVENT;
event.info = info;
- blocking_notifier_call_chain(&fb_notifier_list,
- evnt, &event);
+ fb_notifier_call_chain(evnt, &event);
}
}
}
@@ -861,8 +858,7 @@ fb_blank(struct fb_info *info, int blank)
event.info = info;
event.data = &blank;
- blocking_notifier_call_chain(&fb_notifier_list,
- FB_EVENT_BLANK, &event);
+ fb_notifier_call_chain(FB_EVENT_BLANK, &event);
}
return ret;
@@ -933,8 +929,7 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
con2fb.framebuffer = -1;
event.info = info;
event.data = &con2fb;
- blocking_notifier_call_chain(&fb_notifier_list,
- FB_EVENT_GET_CONSOLE_MAP, &event);
+ fb_notifier_call_chain(FB_EVENT_GET_CONSOLE_MAP, &event);
return copy_to_user(argp, &con2fb,
sizeof(con2fb)) ? -EFAULT : 0;
case FBIOPUT_CON2FBMAP:
@@ -952,9 +947,8 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
return -EINVAL;
event.info = info;
event.data = &con2fb;
- return blocking_notifier_call_chain(&fb_notifier_list,
- FB_EVENT_SET_CONSOLE_MAP,
- &event);
+ return fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP,
+ &event);
case FBIOBLANK:
acquire_console_sem();
info->flags |= FBINFO_MISC_USEREVENT;
@@ -1330,8 +1324,7 @@ register_framebuffer(struct fb_info *fb_info)
registered_fb[i] = fb_info;
event.info = fb_info;
- blocking_notifier_call_chain(&fb_notifier_list,
- FB_EVENT_FB_REGISTERED, &event);
+ fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
return 0;
}
@@ -1365,30 +1358,11 @@ unregister_framebuffer(struct fb_info *fb_info)
fb_cleanup_class_device(fb_info);
class_device_destroy(fb_class, MKDEV(FB_MAJOR, i));
event.info = fb_info;
- blocking_notifier_call_chain(&fb_notifier_list,
- FB_EVENT_FB_UNREGISTERED, &event);
+ fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event);
return 0;
}
/**
- * fb_register_client - register a client notifier
- * @nb: notifier block to callback on events
- */
-int fb_register_client(struct notifier_block *nb)
-{
- return blocking_notifier_chain_register(&fb_notifier_list, nb);
-}
-
-/**
- * fb_unregister_client - unregister a client notifier
- * @nb: notifier block to callback on events
- */
-int fb_unregister_client(struct notifier_block *nb)
-{
- return blocking_notifier_chain_unregister(&fb_notifier_list, nb);
-}
-
-/**
* fb_set_suspend - low level driver signals suspend
* @info: framebuffer affected
* @state: 0 = resuming, !=0 = suspending
@@ -1403,13 +1377,11 @@ void fb_set_suspend(struct fb_info *info, int state)
event.info = info;
if (state) {
- blocking_notifier_call_chain(&fb_notifier_list,
- FB_EVENT_SUSPEND, &event);
+ fb_notifier_call_chain(FB_EVENT_SUSPEND, &event);
info->state = FBINFO_STATE_SUSPENDED;
} else {
info->state = FBINFO_STATE_RUNNING;
- blocking_notifier_call_chain(&fb_notifier_list,
- FB_EVENT_RESUME, &event);
+ fb_notifier_call_chain(FB_EVENT_RESUME, &event);
}
}
@@ -1480,9 +1452,7 @@ int fb_new_modelist(struct fb_info *info)
if (!list_empty(&info->modelist)) {
event.info = info;
- err = blocking_notifier_call_chain(&fb_notifier_list,
- FB_EVENT_NEW_MODELIST,
- &event);
+ err = fb_notifier_call_chain(FB_EVENT_NEW_MODELIST, &event);
}
return err;
@@ -1594,8 +1564,6 @@ EXPORT_SYMBOL(fb_blank);
EXPORT_SYMBOL(fb_pan_display);
EXPORT_SYMBOL(fb_get_buffer_offset);
EXPORT_SYMBOL(fb_set_suspend);
-EXPORT_SYMBOL(fb_register_client);
-EXPORT_SYMBOL(fb_unregister_client);
EXPORT_SYMBOL(fb_get_options);
MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c
index 3ccfff715a5..de93139ccbb 100644
--- a/drivers/video/fbmon.c
+++ b/drivers/video/fbmon.c
@@ -26,7 +26,6 @@
* for more details.
*
*/
-#include <linux/tty.h>
#include <linux/fb.h>
#include <linux/module.h>
#include <linux/pci.h>
diff --git a/drivers/video/g364fb.c b/drivers/video/g364fb.c
index 605d1a13202..1b981b63567 100644
--- a/drivers/video/g364fb.c
+++ b/drivers/video/g364fb.c
@@ -21,7 +21,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
diff --git a/drivers/video/geode/gx1fb_core.c b/drivers/video/geode/gx1fb_core.c
index 4d3a8871d3d..bcf9cea54d8 100644
--- a/drivers/video/geode/gx1fb_core.c
+++ b/drivers/video/geode/gx1fb_core.c
@@ -15,7 +15,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
diff --git a/drivers/video/geode/gxfb_core.c b/drivers/video/geode/gxfb_core.c
index 5ef12a3dfa5..0d3643fc629 100644
--- a/drivers/video/geode/gxfb_core.c
+++ b/drivers/video/geode/gxfb_core.c
@@ -25,7 +25,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
diff --git a/drivers/video/hgafb.c b/drivers/video/hgafb.c
index 4e39035cf33..fb9e6722854 100644
--- a/drivers/video/hgafb.c
+++ b/drivers/video/hgafb.c
@@ -36,7 +36,6 @@
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
diff --git a/drivers/video/hitfb.c b/drivers/video/hitfb.c
index 01864767450..4cc6b454265 100644
--- a/drivers/video/hitfb.c
+++ b/drivers/video/hitfb.c
@@ -17,7 +17,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/init.h>
diff --git a/drivers/video/hpfb.c b/drivers/video/hpfb.c
index abd920a663a..91cf3b577d1 100644
--- a/drivers/video/hpfb.c
+++ b/drivers/video/hpfb.c
@@ -11,7 +11,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/init.h>
diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c
index fbe8a2c4b04..a6ca02f2156 100644
--- a/drivers/video/i810/i810_main.c
+++ b/drivers/video/i810/i810_main.c
@@ -33,7 +33,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/fb.h>
#include <linux/init.h>
diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c
index 8a0c2d3d380..67f384f8675 100644
--- a/drivers/video/igafb.c
+++ b/drivers/video/igafb.c
@@ -33,7 +33,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
diff --git a/drivers/video/imacfb.c b/drivers/video/imacfb.c
index cdbae173d69..ff233b84dec 100644
--- a/drivers/video/imacfb.c
+++ b/drivers/video/imacfb.c
@@ -15,9 +15,9 @@
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/screen_info.h>
#include <linux/slab.h>
#include <linux/string.h>
-#include <linux/tty.h>
#include <asm/io.h>
diff --git a/drivers/video/imsttfb.c b/drivers/video/imsttfb.c
index 5f393d985b1..5715b8ad0dd 100644
--- a/drivers/video/imsttfb.c
+++ b/drivers/video/imsttfb.c
@@ -21,7 +21,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c
index 3f39d84015f..06af89d44a0 100644
--- a/drivers/video/intelfb/intelfbdrv.c
+++ b/drivers/video/intelfb/intelfbdrv.c
@@ -113,7 +113,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
@@ -122,6 +121,7 @@
#include <linux/pci.h>
#include <linux/vmalloc.h>
#include <linux/pagemap.h>
+#include <linux/screen_info.h>
#include <asm/io.h>
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index 3b78a57924f..2a9322f9cfd 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -24,7 +24,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
diff --git a/drivers/video/kyro/fbdev.c b/drivers/video/kyro/fbdev.c
index 2fdbe9b2b04..f0d614a80f1 100644
--- a/drivers/video/kyro/fbdev.c
+++ b/drivers/video/kyro/fbdev.c
@@ -16,7 +16,6 @@
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/string.h>
-#include <linux/tty.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/ioctl.h>
diff --git a/drivers/video/macfb.c b/drivers/video/macfb.c
index e6cbd9de944..80a04380716 100644
--- a/drivers/video/macfb.c
+++ b/drivers/video/macfb.c
@@ -24,7 +24,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/nubus.h>
diff --git a/drivers/video/matrox/matroxfb_base.h b/drivers/video/matrox/matroxfb_base.h
index b95779b57c0..9c25c2f7966 100644
--- a/drivers/video/matrox/matroxfb_base.h
+++ b/drivers/video/matrox/matroxfb_base.h
@@ -30,7 +30,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
diff --git a/drivers/video/maxinefb.c b/drivers/video/maxinefb.c
index f85421bf7cb..38c8d38de4f 100644
--- a/drivers/video/maxinefb.c
+++ b/drivers/video/maxinefb.c
@@ -29,7 +29,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/init.h>
diff --git a/drivers/video/mbx/Makefile b/drivers/video/mbx/Makefile
new file mode 100644
index 00000000000..16c1165cf9c
--- /dev/null
+++ b/drivers/video/mbx/Makefile
@@ -0,0 +1,4 @@
+# Makefile for the 2700G controller driver.
+
+obj-$(CONFIG_FB_MBX) += mbxfb.o
+obj-$(CONFIG_FB_MBX_DEBUG) += mbxfbdebugfs.o
diff --git a/drivers/video/mbx/mbxdebugfs.c b/drivers/video/mbx/mbxdebugfs.c
new file mode 100644
index 00000000000..84aab3ad024
--- /dev/null
+++ b/drivers/video/mbx/mbxdebugfs.c
@@ -0,0 +1,188 @@
+#include <linux/debugfs.h>
+
+#define BIG_BUFFER_SIZE (1024)
+
+static char big_buffer[BIG_BUFFER_SIZE];
+
+struct mbxfb_debugfs_data {
+ struct dentry *dir;
+ struct dentry *sysconf;
+ struct dentry *clock;
+ struct dentry *display;
+ struct dentry *gsctl;
+};
+
+static int open_file_generic(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->u.generic_ip;
+ return 0;
+}
+
+static ssize_t write_file_dummy(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ return count;
+}
+
+static ssize_t sysconf_read_file(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ char * s = big_buffer;
+
+ s += sprintf(s, "SYSCFG = %08lx\n", SYSCFG);
+ s += sprintf(s, "PFBASE = %08lx\n", PFBASE);
+ s += sprintf(s, "PFCEIL = %08lx\n", PFCEIL);
+ s += sprintf(s, "POLLFLAG = %08lx\n", POLLFLAG);
+ s += sprintf(s, "SYSRST = %08lx\n", SYSRST);
+
+ return simple_read_from_buffer(userbuf, count, ppos,
+ big_buffer, s-big_buffer);
+}
+
+
+static ssize_t gsctl_read_file(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ char * s = big_buffer;
+
+ s += sprintf(s, "GSCTRL = %08lx\n", GSCTRL);
+ s += sprintf(s, "VSCTRL = %08lx\n", VSCTRL);
+ s += sprintf(s, "GBBASE = %08lx\n", GBBASE);
+ s += sprintf(s, "VBBASE = %08lx\n", VBBASE);
+ s += sprintf(s, "GDRCTRL = %08lx\n", GDRCTRL);
+ s += sprintf(s, "VCMSK = %08lx\n", VCMSK);
+ s += sprintf(s, "GSCADR = %08lx\n", GSCADR);
+ s += sprintf(s, "VSCADR = %08lx\n", VSCADR);
+ s += sprintf(s, "VUBASE = %08lx\n", VUBASE);
+ s += sprintf(s, "VVBASE = %08lx\n", VVBASE);
+ s += sprintf(s, "GSADR = %08lx\n", GSADR);
+ s += sprintf(s, "VSADR = %08lx\n", VSADR);
+ s += sprintf(s, "HCCTRL = %08lx\n", HCCTRL);
+ s += sprintf(s, "HCSIZE = %08lx\n", HCSIZE);
+ s += sprintf(s, "HCPOS = %08lx\n", HCPOS);
+ s += sprintf(s, "HCBADR = %08lx\n", HCBADR);
+ s += sprintf(s, "HCCKMSK = %08lx\n", HCCKMSK);
+ s += sprintf(s, "GPLUT = %08lx\n", GPLUT);
+
+ return simple_read_from_buffer(userbuf, count, ppos,
+ big_buffer, s-big_buffer);
+}
+
+static ssize_t display_read_file(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ char * s = big_buffer;
+
+ s += sprintf(s, "DSCTRL = %08lx\n", DSCTRL);
+ s += sprintf(s, "DHT01 = %08lx\n", DHT01);
+ s += sprintf(s, "DHT02 = %08lx\n", DHT02);
+ s += sprintf(s, "DHT03 = %08lx\n", DHT03);
+ s += sprintf(s, "DVT01 = %08lx\n", DVT01);
+ s += sprintf(s, "DVT02 = %08lx\n", DVT02);
+ s += sprintf(s, "DVT03 = %08lx\n", DVT03);
+ s += sprintf(s, "DBCOL = %08lx\n", DBCOL);
+ s += sprintf(s, "BGCOLOR = %08lx\n", BGCOLOR);
+ s += sprintf(s, "DINTRS = %08lx\n", DINTRS);
+ s += sprintf(s, "DINTRE = %08lx\n", DINTRE);
+ s += sprintf(s, "DINTRCNT = %08lx\n", DINTRCNT);
+ s += sprintf(s, "DSIG = %08lx\n", DSIG);
+ s += sprintf(s, "DMCTRL = %08lx\n", DMCTRL);
+ s += sprintf(s, "CLIPCTRL = %08lx\n", CLIPCTRL);
+ s += sprintf(s, "SPOCTRL = %08lx\n", SPOCTRL);
+ s += sprintf(s, "SVCTRL = %08lx\n", SVCTRL);
+ s += sprintf(s, "DLSTS = %08lx\n", DLSTS);
+ s += sprintf(s, "DLLCTRL = %08lx\n", DLLCTRL);
+ s += sprintf(s, "DVLNUM = %08lx\n", DVLNUM);
+ s += sprintf(s, "DUCTRL = %08lx\n", DUCTRL);
+ s += sprintf(s, "DVECTRL = %08lx\n", DVECTRL);
+ s += sprintf(s, "DHDET = %08lx\n", DHDET);
+ s += sprintf(s, "DVDET = %08lx\n", DVDET);
+ s += sprintf(s, "DODMSK = %08lx\n", DODMSK);
+ s += sprintf(s, "CSC01 = %08lx\n", CSC01);
+ s += sprintf(s, "CSC02 = %08lx\n", CSC02);
+ s += sprintf(s, "CSC03 = %08lx\n", CSC03);
+ s += sprintf(s, "CSC04 = %08lx\n", CSC04);
+ s += sprintf(s, "CSC05 = %08lx\n", CSC05);
+
+ return simple_read_from_buffer(userbuf, count, ppos,
+ big_buffer, s-big_buffer);
+}
+
+static ssize_t clock_read_file(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ char * s = big_buffer;
+
+ s += sprintf(s, "SYSCLKSRC = %08lx\n", SYSCLKSRC);
+ s += sprintf(s, "PIXCLKSRC = %08lx\n", PIXCLKSRC);
+ s += sprintf(s, "CLKSLEEP = %08lx\n", CLKSLEEP);
+ s += sprintf(s, "COREPLL = %08lx\n", COREPLL);
+ s += sprintf(s, "DISPPLL = %08lx\n", DISPPLL);
+ s += sprintf(s, "PLLSTAT = %08lx\n", PLLSTAT);
+ s += sprintf(s, "VOVRCLK = %08lx\n", VOVRCLK);
+ s += sprintf(s, "PIXCLK = %08lx\n", PIXCLK);
+ s += sprintf(s, "MEMCLK = %08lx\n", MEMCLK);
+ s += sprintf(s, "M24CLK = %08lx\n", M24CLK);
+ s += sprintf(s, "MBXCLK = %08lx\n", MBXCLK);
+ s += sprintf(s, "SDCLK = %08lx\n", SDCLK);
+ s += sprintf(s, "PIXCLKDIV = %08lx\n", PIXCLKDIV);
+
+ return simple_read_from_buffer(userbuf, count, ppos,
+ big_buffer, s-big_buffer);
+}
+
+static struct file_operations sysconf_fops = {
+ .read = sysconf_read_file,
+ .write = write_file_dummy,
+ .open = open_file_generic,
+};
+
+static struct file_operations clock_fops = {
+ .read = clock_read_file,
+ .write = write_file_dummy,
+ .open = open_file_generic,
+};
+
+static struct file_operations display_fops = {
+ .read = display_read_file,
+ .write = write_file_dummy,
+ .open = open_file_generic,
+};
+
+static struct file_operations gsctl_fops = {
+ .read = gsctl_read_file,
+ .write = write_file_dummy,
+ .open = open_file_generic,
+};
+
+
+static void __devinit mbxfb_debugfs_init(struct fb_info *fbi)
+{
+ struct mbxfb_info *mfbi = fbi->par;
+ struct mbxfb_debugfs_data *dbg;
+
+ dbg = kzalloc(sizeof(struct mbxfb_debugfs_data), GFP_KERNEL);
+ mfbi->debugfs_data = dbg;
+
+ dbg->dir = debugfs_create_dir("mbxfb", NULL);
+ dbg->sysconf = debugfs_create_file("sysconf", 0444, dbg->dir,
+ fbi, &sysconf_fops);
+ dbg->clock = debugfs_create_file("clock", 0444, dbg->dir,
+ fbi, &clock_fops);
+ dbg->display = debugfs_create_file("display", 0444, dbg->dir,
+ fbi, &display_fops);
+ dbg->gsctl = debugfs_create_file("gsctl", 0444, dbg->dir,
+ fbi, &gsctl_fops);
+}
+
+static void __devexit mbxfb_debugfs_remove(struct fb_info *fbi)
+{
+ struct mbxfb_info *mfbi = fbi->par;
+ struct mbxfb_debugfs_data *dbg = mfbi->debugfs_data;
+
+ debugfs_remove(dbg->gsctl);
+ debugfs_remove(dbg->display);
+ debugfs_remove(dbg->clock);
+ debugfs_remove(dbg->sysconf);
+ debugfs_remove(dbg->dir);
+}
diff --git a/drivers/video/mbx/mbxfb.c b/drivers/video/mbx/mbxfb.c
new file mode 100644
index 00000000000..6849ab75d40
--- /dev/null
+++ b/drivers/video/mbx/mbxfb.c
@@ -0,0 +1,683 @@
+/*
+ * linux/drivers/video/mbx/mbxfb.c
+ *
+ * Copyright (C) 2006 Compulab, Ltd.
+ * Mike Rapoport <mike@compulab.co.il>
+ *
+ * Based on pxafb.c
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ * Intel 2700G (Marathon) Graphics Accelerator Frame Buffer Driver
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+
+#include <video/mbxfb.h>
+
+#include "regs.h"
+#include "reg_bits.h"
+
+static unsigned long virt_base_2700;
+
+#define MIN_XRES 16
+#define MIN_YRES 16
+#define MAX_XRES 2048
+#define MAX_YRES 2048
+
+#define MAX_PALETTES 16
+
+/* FIXME: take care of different chip revisions with different sizes
+ of ODFB */
+#define MEMORY_OFFSET 0x60000
+
+struct mbxfb_info {
+ struct device *dev;
+
+ struct resource *fb_res;
+ struct resource *fb_req;
+
+ struct resource *reg_res;
+ struct resource *reg_req;
+
+ void __iomem *fb_virt_addr;
+ unsigned long fb_phys_addr;
+
+ void __iomem *reg_virt_addr;
+ unsigned long reg_phys_addr;
+
+ int (*platform_probe) (struct fb_info * fb);
+ int (*platform_remove) (struct fb_info * fb);
+
+ u32 pseudo_palette[MAX_PALETTES];
+#ifdef CONFIG_FB_MBX_DEBUG
+ void *debugfs_data;
+#endif
+
+};
+
+static struct fb_var_screeninfo mbxfb_default __devinitdata = {
+ .xres = 640,
+ .yres = 480,
+ .xres_virtual = 640,
+ .yres_virtual = 480,
+ .bits_per_pixel = 16,
+ .red = {11, 5, 0},
+ .green = {5, 6, 0},
+ .blue = {0, 5, 0},
+ .activate = FB_ACTIVATE_TEST,
+ .height = -1,
+ .width = -1,
+ .pixclock = 40000,
+ .left_margin = 48,
+ .right_margin = 16,
+ .upper_margin = 33,
+ .lower_margin = 10,
+ .hsync_len = 96,
+ .vsync_len = 2,
+ .vmode = FB_VMODE_NONINTERLACED,
+ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+};
+
+static struct fb_fix_screeninfo mbxfb_fix __devinitdata = {
+ .id = "MBX",
+ .type = FB_TYPE_PACKED_PIXELS,
+ .visual = FB_VISUAL_TRUECOLOR,
+ .xpanstep = 0,
+ .ypanstep = 0,
+ .ywrapstep = 0,
+ .accel = FB_ACCEL_NONE,
+};
+
+struct pixclock_div {
+ u8 m;
+ u8 n;
+ u8 p;
+};
+
+static unsigned int mbxfb_get_pixclock(unsigned int pixclock_ps,
+ struct pixclock_div *div)
+{
+ u8 m, n, p;
+ unsigned int err = 0;
+ unsigned int min_err = ~0x0;
+ unsigned int clk;
+ unsigned int best_clk = 0;
+ unsigned int ref_clk = 13000; /* FIXME: take from platform data */
+ unsigned int pixclock;
+
+ /* convert pixclock to KHz */
+ pixclock = PICOS2KHZ(pixclock_ps);
+
+ for (m = 1; m < 64; m++) {
+ for (n = 1; n < 8; n++) {
+ for (p = 0; p < 8; p++) {
+ clk = (ref_clk * m) / (n * (1 << p));
+ err = (clk > pixclock) ? (clk - pixclock) :
+ (pixclock - clk);
+ if (err < min_err) {
+ min_err = err;
+ best_clk = clk;
+ div->m = m;
+ div->n = n;
+ div->p = p;
+ }
+ }
+ }
+ }
+ return KHZ2PICOS(best_clk);
+}
+
+static int mbxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int trans, struct fb_info *info)
+{
+ u32 val, ret = 1;
+
+ if (regno < MAX_PALETTES) {
+ u32 *pal = info->pseudo_palette;
+
+ val = (red & 0xf800) | ((green & 0xfc00) >> 5) |
+ ((blue & 0xf800) >> 11);
+ pal[regno] = val;
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static int mbxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ struct pixclock_div div;
+
+ var->pixclock = mbxfb_get_pixclock(var->pixclock, &div);
+
+ if (var->xres < MIN_XRES)
+ var->xres = MIN_XRES;
+ if (var->yres < MIN_YRES)
+ var->yres = MIN_YRES;
+ if (var->xres > MAX_XRES)
+ return -EINVAL;
+ if (var->yres > MAX_YRES)
+ return -EINVAL;
+ var->xres_virtual = max(var->xres_virtual, var->xres);
+ var->yres_virtual = max(var->yres_virtual, var->yres);
+
+ switch (var->bits_per_pixel) {
+ /* 8 bits-per-pixel is not supported yet */
+ case 8:
+ return -EINVAL;
+ case 16:
+ var->green.length = (var->green.length == 5) ? 5 : 6;
+ var->red.length = 5;
+ var->blue.length = 5;
+ var->transp.length = 6 - var->green.length;
+ var->blue.offset = 0;
+ var->green.offset = 5;
+ var->red.offset = 5 + var->green.length;
+ var->transp.offset = (5 + var->red.offset) & 15;
+ break;
+ case 24: /* RGB 888 */
+ case 32: /* RGBA 8888 */
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.length = var->bits_per_pixel - 24;
+ var->transp.offset = (var->transp.length) ? 24 : 0;
+ break;
+ }
+ var->red.msb_right = 0;
+ var->green.msb_right = 0;
+ var->blue.msb_right = 0;
+ var->transp.msb_right = 0;
+
+ return 0;
+}
+
+static int mbxfb_set_par(struct fb_info *info)
+{
+ struct fb_var_screeninfo *var = &info->var;
+ struct pixclock_div div;
+ ushort hbps, ht, hfps, has;
+ ushort vbps, vt, vfps, vas;
+ u32 gsctrl = readl(GSCTRL);
+ u32 gsadr = readl(GSADR);
+
+ info->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
+
+ /* setup color mode */
+ gsctrl &= ~(FMsk(GSCTRL_GPIXFMT));
+ /* FIXME: add *WORKING* support for 8-bits per color */
+ if (info->var.bits_per_pixel == 8) {
+ return -EINVAL;
+ } else {
+ fb_dealloc_cmap(&info->cmap);
+ gsctrl &= ~GSCTRL_LUT_EN;
+
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+ switch (info->var.bits_per_pixel) {
+ case 16:
+ if (info->var.green.length == 5)
+ gsctrl |= GSCTRL_GPIXFMT_ARGB1555;
+ else
+ gsctrl |= GSCTRL_GPIXFMT_RGB565;
+ break;
+ case 24:
+ gsctrl |= GSCTRL_GPIXFMT_RGB888;
+ break;
+ case 32:
+ gsctrl |= GSCTRL_GPIXFMT_ARGB8888;
+ break;
+ }
+ }
+
+ /* setup resolution */
+ gsctrl &= ~(FMsk(GSCTRL_GSWIDTH) | FMsk(GSCTRL_GSHEIGHT));
+ gsctrl |= Gsctrl_Width(info->var.xres - 1) |
+ Gsctrl_Height(info->var.yres - 1);
+ writel(gsctrl, GSCTRL);
+ udelay(1000);
+
+ gsadr &= ~(FMsk(GSADR_SRCSTRIDE));
+ gsadr |= Gsadr_Srcstride(info->var.xres * info->var.bits_per_pixel /
+ (8 * 16) - 1);
+ writel(gsadr, GSADR);
+ udelay(1000);
+
+ /* setup timings */
+ var->pixclock = mbxfb_get_pixclock(info->var.pixclock, &div);
+
+ writel((Disp_Pll_M(div.m) | Disp_Pll_N(div.n) |
+ Disp_Pll_P(div.p) | DISP_PLL_EN), DISPPLL);
+
+ hbps = var->hsync_len;
+ has = hbps + var->left_margin;
+ hfps = has + var->xres;
+ ht = hfps + var->right_margin;
+
+ vbps = var->vsync_len;
+ vas = vbps + var->upper_margin;
+ vfps = vas + var->yres;
+ vt = vfps + var->lower_margin;
+
+ writel((Dht01_Hbps(hbps) | Dht01_Ht(ht)), DHT01);
+ writel((Dht02_Hlbs(has) | Dht02_Has(has)), DHT02);
+ writel((Dht03_Hfps(hfps) | Dht03_Hrbs(hfps)), DHT03);
+ writel((Dhdet_Hdes(has) | Dhdet_Hdef(hfps)), DHDET);
+
+ writel((Dvt01_Vbps(vbps) | Dvt01_Vt(vt)), DVT01);
+ writel((Dvt02_Vtbs(vas) | Dvt02_Vas(vas)), DVT02);
+ writel((Dvt03_Vfps(vfps) | Dvt03_Vbbs(vfps)), DVT03);
+ writel((Dvdet_Vdes(vas) | Dvdet_Vdef(vfps)), DVDET);
+ writel((Dvectrl_Vevent(vfps) | Dvectrl_Vfetch(vbps)), DVECTRL);
+
+ writel((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
+
+ return 0;
+}
+
+static int mbxfb_blank(int blank, struct fb_info *info)
+{
+ switch (blank) {
+ case FB_BLANK_POWERDOWN:
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_HSYNC_SUSPEND:
+ case FB_BLANK_NORMAL:
+ writel((readl(DSCTRL) & ~DSCTRL_SYNCGEN_EN), DSCTRL);
+ udelay(1000);
+ writel((readl(PIXCLK) & ~PIXCLK_EN), PIXCLK);
+ udelay(1000);
+ writel((readl(VOVRCLK) & ~VOVRCLK_EN), VOVRCLK);
+ udelay(1000);
+ break;
+ case FB_BLANK_UNBLANK:
+ writel((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
+ udelay(1000);
+ writel((readl(PIXCLK) | PIXCLK_EN), PIXCLK);
+ udelay(1000);
+ break;
+ }
+ return 0;
+}
+
+static struct fb_ops mbxfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = mbxfb_check_var,
+ .fb_set_par = mbxfb_set_par,
+ .fb_setcolreg = mbxfb_setcolreg,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_blank = mbxfb_blank,
+};
+
+/*
+ Enable external SDRAM controller. Assume that all clocks are active
+ by now.
+*/
+static void __devinit setup_memc(struct fb_info *fbi)
+{
+ struct mbxfb_info *mfbi = fbi->par;
+ unsigned long tmp;
+ int i;
+
+ /* FIXME: use platfrom specific parameters */
+ /* setup SDRAM controller */
+ writel((LMCFG_LMC_DS | LMCFG_LMC_TS | LMCFG_LMD_TS |
+ LMCFG_LMA_TS),
+ LMCFG);
+ udelay(1000);
+
+ writel(LMPWR_MC_PWR_ACT, LMPWR);
+ udelay(1000);
+
+ /* setup SDRAM timings */
+ writel((Lmtim_Tras(7) | Lmtim_Trp(3) | Lmtim_Trcd(3) |
+ Lmtim_Trc(9) | Lmtim_Tdpl(2)),
+ LMTIM);
+ udelay(1000);
+ /* setup SDRAM refresh rate */
+ writel(0xc2b, LMREFRESH);
+ udelay(1000);
+ /* setup SDRAM type parameters */
+ writel((LMTYPE_CASLAT_3 | LMTYPE_BKSZ_2 | LMTYPE_ROWSZ_11 |
+ LMTYPE_COLSZ_8),
+ LMTYPE);
+ udelay(1000);
+ /* enable memory controller */
+ writel(LMPWR_MC_PWR_ACT, LMPWR);
+ udelay(1000);
+
+ /* perform dummy reads */
+ for ( i = 0; i < 16; i++ ) {
+ tmp = readl(fbi->screen_base);
+ }
+}
+
+static void enable_clocks(struct fb_info *fbi)
+{
+ /* enable clocks */
+ writel(SYSCLKSRC_PLL_2, SYSCLKSRC);
+ udelay(1000);
+ writel(PIXCLKSRC_PLL_1, PIXCLKSRC);
+ udelay(1000);
+ writel(0x00000000, CLKSLEEP);
+ udelay(1000);
+ writel((Core_Pll_M(0x17) | Core_Pll_N(0x3) | Core_Pll_P(0x0) |
+ CORE_PLL_EN),
+ COREPLL);
+ udelay(1000);
+ writel((Disp_Pll_M(0x1b) | Disp_Pll_N(0x7) | Disp_Pll_P(0x1) |
+ DISP_PLL_EN),
+ DISPPLL);
+
+ writel(0x00000000, VOVRCLK);
+ udelay(1000);
+ writel(PIXCLK_EN, PIXCLK);
+ udelay(1000);
+ writel(MEMCLK_EN, MEMCLK);
+ udelay(1000);
+ writel(0x00000006, M24CLK);
+ udelay(1000);
+ writel(0x00000006, MBXCLK);
+ udelay(1000);
+ writel(SDCLK_EN, SDCLK);
+ udelay(1000);
+ writel(0x00000001, PIXCLKDIV);
+ udelay(1000);
+}
+
+static void __devinit setup_graphics(struct fb_info *fbi)
+{
+ unsigned long gsctrl;
+
+ gsctrl = GSCTRL_GAMMA_EN | Gsctrl_Width(fbi->var.xres - 1) |
+ Gsctrl_Height(fbi->var.yres - 1);
+ switch (fbi->var.bits_per_pixel) {
+ case 16:
+ if (fbi->var.green.length == 5)
+ gsctrl |= GSCTRL_GPIXFMT_ARGB1555;
+ else
+ gsctrl |= GSCTRL_GPIXFMT_RGB565;
+ break;
+ case 24:
+ gsctrl |= GSCTRL_GPIXFMT_RGB888;
+ break;
+ case 32:
+ gsctrl |= GSCTRL_GPIXFMT_ARGB8888;
+ break;
+ }
+
+ writel(gsctrl, GSCTRL);
+ udelay(1000);
+ writel(0x00000000, GBBASE);
+ udelay(1000);
+ writel(0x00ffffff, GDRCTRL);
+ udelay(1000);
+ writel((GSCADR_STR_EN | Gscadr_Gbase_Adr(0x6000)), GSCADR);
+ udelay(1000);
+ writel(0x00000000, GPLUT);
+ udelay(1000);
+}
+
+static void __devinit setup_display(struct fb_info *fbi)
+{
+ unsigned long dsctrl = 0;
+
+ dsctrl = DSCTRL_BLNK_POL;
+ if (fbi->var.sync & FB_SYNC_HOR_HIGH_ACT)
+ dsctrl |= DSCTRL_HS_POL;
+ if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT)
+ dsctrl |= DSCTRL_VS_POL;
+ writel(dsctrl, DSCTRL);
+ udelay(1000);
+ writel(0xd0303010, DMCTRL);
+ udelay(1000);
+ writel((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
+}
+
+static void __devinit enable_controller(struct fb_info *fbi)
+{
+ writel(SYSRST_RST, SYSRST);
+ udelay(1000);
+
+
+ enable_clocks(fbi);
+ setup_memc(fbi);
+ setup_graphics(fbi);
+ setup_display(fbi);
+}
+
+#ifdef CONFIG_PM
+/*
+ * Power management hooks. Note that we won't be called from IRQ context,
+ * unlike the blank functions above, so we may sleep.
+ */
+static int mbxfb_suspend(struct platform_device *dev, pm_message_t state)
+{
+ /* make frame buffer memory enter self-refresh mode */
+ writel(LMPWR_MC_PWR_SRM, LMPWR);
+ while (LMPWRSTAT != LMPWRSTAT_MC_PWR_SRM)
+ ; /* empty statement */
+
+ /* reset the device, since it's initial state is 'mostly sleeping' */
+ writel(SYSRST_RST, SYSRST);
+ return 0;
+}
+
+static int mbxfb_resume(struct platform_device *dev)
+{
+ struct fb_info *fbi = platform_get_drvdata(dev);
+
+ enable_clocks(fbi);
+/* setup_graphics(fbi); */
+/* setup_display(fbi); */
+
+ writel((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
+ return 0;
+}
+#else
+#define mbxfb_suspend NULL
+#define mbxfb_resume NULL
+#endif
+
+/* debugfs entries */
+#ifndef CONFIG_FB_MBX_DEBUG
+#define mbxfb_debugfs_init(x) do {} while(0)
+#define mbxfb_debugfs_remove(x) do {} while(0)
+#endif
+
+#define res_size(_r) (((_r)->end - (_r)->start) + 1)
+
+static int __devinit mbxfb_probe(struct platform_device *dev)
+{
+ int ret;
+ struct fb_info *fbi;
+ struct mbxfb_info *mfbi;
+ struct mbxfb_platform_data *pdata;
+
+ dev_dbg(dev, "mbxfb_probe\n");
+
+ fbi = framebuffer_alloc(sizeof(struct mbxfb_info), &dev->dev);
+ if (fbi == NULL) {
+ dev_err(&dev->dev, "framebuffer_alloc failed\n");
+ return -ENOMEM;
+ }
+
+ mfbi = fbi->par;
+ fbi->pseudo_palette = mfbi->pseudo_palette;
+ pdata = dev->dev.platform_data;
+ if (pdata->probe)
+ mfbi->platform_probe = pdata->probe;
+ if (pdata->remove)
+ mfbi->platform_remove = pdata->remove;
+
+ mfbi->fb_res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ mfbi->reg_res = platform_get_resource(dev, IORESOURCE_MEM, 1);
+
+ if (!mfbi->fb_res || !mfbi->reg_res) {
+ dev_err(&dev->dev, "no resources found\n");
+ ret = -ENODEV;
+ goto err1;
+ }
+
+ mfbi->fb_req = request_mem_region(mfbi->fb_res->start,
+ res_size(mfbi->fb_res), dev->name);
+ if (mfbi->fb_req == NULL) {
+ dev_err(&dev->dev, "failed to claim framebuffer memory\n");
+ ret = -EINVAL;
+ goto err1;
+ }
+ mfbi->fb_phys_addr = mfbi->fb_res->start;
+
+ mfbi->reg_req = request_mem_region(mfbi->reg_res->start,
+ res_size(mfbi->reg_res), dev->name);
+ if (mfbi->reg_req == NULL) {
+ dev_err(&dev->dev, "failed to claim Marathon registers\n");
+ ret = -EINVAL;
+ goto err2;
+ }
+ mfbi->reg_phys_addr = mfbi->reg_res->start;
+
+ mfbi->reg_virt_addr = ioremap_nocache(mfbi->reg_phys_addr,
+ res_size(mfbi->reg_req));
+ if (!mfbi->reg_virt_addr) {
+ dev_err(&dev->dev, "failed to ioremap Marathon registers\n");
+ ret = -EINVAL;
+ goto err3;
+ }
+ virt_base_2700 = (unsigned long)mfbi->reg_virt_addr;
+
+ mfbi->fb_virt_addr = ioremap_nocache(mfbi->fb_phys_addr,
+ res_size(mfbi->fb_req));
+ if (!mfbi->reg_virt_addr) {
+ dev_err(&dev->dev, "failed to ioremap frame buffer\n");
+ ret = -EINVAL;
+ goto err4;
+ }
+
+ /* FIXME: get from platform */
+ fbi->screen_base = (char __iomem *)(mfbi->fb_virt_addr + 0x60000);
+ fbi->screen_size = 8 * 1024 * 1024; /* 8 Megs */
+ fbi->fbops = &mbxfb_ops;
+
+ fbi->var = mbxfb_default;
+ fbi->fix = mbxfb_fix;
+ fbi->fix.smem_start = mfbi->fb_phys_addr + 0x60000;
+ fbi->fix.smem_len = 8 * 1024 * 1024;
+ fbi->fix.line_length = 640 * 2;
+
+ ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
+ if (ret < 0) {
+ dev_err(&dev->dev, "fb_alloc_cmap failed\n");
+ ret = -EINVAL;
+ goto err5;
+ }
+
+ platform_set_drvdata(dev, fbi);
+
+ printk(KERN_INFO "fb%d: mbx frame buffer device\n", fbi->node);
+
+ if (mfbi->platform_probe)
+ mfbi->platform_probe(fbi);
+
+ enable_controller(fbi);
+
+ mbxfb_debugfs_init(fbi);
+
+ ret = register_framebuffer(fbi);
+ if (ret < 0) {
+ dev_err(&dev->dev, "register_framebuffer failed\n");
+ ret = -EINVAL;
+ goto err6;
+ }
+
+ return 0;
+
+err6:
+ fb_dealloc_cmap(&fbi->cmap);
+err5:
+ iounmap(mfbi->fb_virt_addr);
+err4:
+ iounmap(mfbi->reg_virt_addr);
+err3:
+ release_mem_region(mfbi->reg_res->start, res_size(mfbi->reg_res));
+err2:
+ release_mem_region(mfbi->fb_res->start, res_size(mfbi->fb_res));
+err1:
+ framebuffer_release(fbi);
+
+ return ret;
+}
+
+static int __devexit mbxfb_remove(struct platform_device *dev)
+{
+ struct fb_info *fbi = platform_get_drvdata(dev);
+
+ writel(SYSRST_RST, SYSRST);
+ udelay(1000);
+
+ mbxfb_debugfs_remove(fbi);
+
+ if (fbi) {
+ struct mbxfb_info *mfbi = fbi->par;
+
+ unregister_framebuffer(fbi);
+ if (mfbi) {
+ if (mfbi->platform_remove)
+ mfbi->platform_remove(fbi);
+
+ if (mfbi->fb_virt_addr)
+ iounmap(mfbi->fb_virt_addr);
+ if (mfbi->reg_virt_addr)
+ iounmap(mfbi->reg_virt_addr);
+ if (mfbi->reg_req)
+ release_mem_region(mfbi->reg_req->start,
+ res_size(mfbi->reg_req));
+ if (mfbi->fb_req)
+ release_mem_region(mfbi->fb_req->start,
+ res_size(mfbi->fb_req));
+ }
+ framebuffer_release(fbi);
+ }
+
+ return 0;
+}
+
+static struct platform_driver mbxfb_driver = {
+ .probe = mbxfb_probe,
+ .remove = mbxfb_remove,
+ .suspend = mbxfb_suspend,
+ .resume = mbxfb_resume,
+ .driver = {
+ .name = "mbx-fb",
+ },
+};
+
+int __devinit mbxfb_init(void)
+{
+ return platform_driver_register(&mbxfb_driver);
+}
+
+static void __devexit mbxfb_exit(void)
+{
+ platform_driver_unregister(&mbxfb_driver);
+}
+
+module_init(mbxfb_init);
+module_exit(mbxfb_exit);
+
+MODULE_DESCRIPTION("loadable framebuffer driver for Marathon device");
+MODULE_AUTHOR("Mike Rapoport, Compulab");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/mbx/reg_bits.h b/drivers/video/mbx/reg_bits.h
new file mode 100644
index 00000000000..c226a8e4531
--- /dev/null
+++ b/drivers/video/mbx/reg_bits.h
@@ -0,0 +1,418 @@
+#ifndef __REG_BITS_2700G_
+#define __REG_BITS_2700G_
+
+/* use defines from asm-arm/arch-pxa/bitfields.h for bit fields access */
+#define UData(Data) ((unsigned long) (Data))
+#define Fld(Size, Shft) (((Size) << 16) + (Shft))
+#define FSize(Field) ((Field) >> 16)
+#define FShft(Field) ((Field) & 0x0000FFFF)
+#define FMsk(Field) (((UData (1) << FSize (Field)) - 1) << FShft (Field))
+#define FAlnMsk(Field) ((UData (1) << FSize (Field)) - 1)
+#define F1stBit(Field) (UData (1) << FShft (Field))
+
+#define SYSRST_RST (1 << 0)
+
+/* SYSCLKSRC - SYSCLK Source Control Register */
+#define SYSCLKSRC_SEL Fld(2,0)
+#define SYSCLKSRC_REF ((0x0) << FShft(SYSCLKSRC_SEL))
+#define SYSCLKSRC_PLL_1 ((0x1) << FShft(SYSCLKSRC_SEL))
+#define SYSCLKSRC_PLL_2 ((0x2) << FShft(SYSCLKSRC_SEL))
+
+/* PIXCLKSRC - PIXCLK Source Control Register */
+#define PIXCLKSRC_SEL Fld(2,0)
+#define PIXCLKSRC_REF ((0x0) << FShft(PIXCLKSRC_SEL))
+#define PIXCLKSRC_PLL_1 ((0x1) << FShft(PIXCLKSRC_SEL))
+#define PIXCLKSRC_PLL_2 ((0x2) << FShft(PIXCLKSRC_SEL))
+
+/* Clock Disable Register */
+#define CLKSLEEP_SLP (1 << 0)
+
+/* Core PLL Control Register */
+#define CORE_PLL_M Fld(6,7)
+#define Core_Pll_M(x) ((x) << FShft(CORE_PLL_M))
+#define CORE_PLL_N Fld(3,4)
+#define Core_Pll_N(x) ((x) << FShft(CORE_PLL_N))
+#define CORE_PLL_P Fld(3,1)
+#define Core_Pll_P(x) ((x) << FShft(CORE_PLL_P))
+#define CORE_PLL_EN (1 << 0)
+
+/* Display PLL Control Register */
+#define DISP_PLL_M Fld(6,7)
+#define Disp_Pll_M(x) ((x) << FShft(DISP_PLL_M))
+#define DISP_PLL_N Fld(3,4)
+#define Disp_Pll_N(x) ((x) << FShft(DISP_PLL_N))
+#define DISP_PLL_P Fld(3,1)
+#define Disp_Pll_P(x) ((x) << FShft(DISP_PLL_P))
+#define DISP_PLL_EN (1 << 0)
+
+/* PLL status register */
+#define PLLSTAT_CORE_PLL_LOST_L (1 << 3)
+#define PLLSTAT_CORE_PLL_LSTS (1 << 2)
+#define PLLSTAT_DISP_PLL_LOST_L (1 << 1)
+#define PLLSTAT_DISP_PLL_LSTS (1 << 0)
+
+/* Video and scale clock control register */
+#define VOVRCLK_EN (1 << 0)
+
+/* Pixel clock control register */
+#define PIXCLK_EN (1 << 0)
+
+/* Memory clock control register */
+#define MEMCLK_EN (1 << 0)
+
+/* MBX clock control register */
+#define MBXCLK_DIV Fld(2,2)
+#define MBXCLK_DIV_1 ((0x0) << FShft(MBXCLK_DIV))
+#define MBXCLK_DIV_2 ((0x1) << FShft(MBXCLK_DIV))
+#define MBXCLK_DIV_3 ((0x2) << FShft(MBXCLK_DIV))
+#define MBXCLK_DIV_4 ((0x3) << FShft(MBXCLK_DIV))
+#define MBXCLK_EN Fld(2,0)
+#define MBXCLK_EN_NONE ((0x0) << FShft(MBXCLK_EN))
+#define MBXCLK_EN_2D ((0x1) << FShft(MBXCLK_EN))
+#define MBXCLK_EN_BOTH ((0x2) << FShft(MBXCLK_EN))
+
+/* M24 clock control register */
+#define M24CLK_DIV Fld(2,1)
+#define M24CLK_DIV_1 ((0x0) << FShft(M24CLK_DIV))
+#define M24CLK_DIV_2 ((0x1) << FShft(M24CLK_DIV))
+#define M24CLK_DIV_3 ((0x2) << FShft(M24CLK_DIV))
+#define M24CLK_DIV_4 ((0x3) << FShft(M24CLK_DIV))
+#define M24CLK_EN (1 << 0)
+
+/* SDRAM clock control register */
+#define SDCLK_EN (1 << 0)
+
+/* PixClk Divisor Register */
+#define PIXCLKDIV_PD Fld(9,0)
+#define Pixclkdiv_Pd(x) ((x) << FShft(PIXCLKDIV_PD))
+
+/* LCD Config control register */
+#define LCDCFG_IN_FMT Fld(3,28)
+#define Lcdcfg_In_Fmt(x) ((x) << FShft(LCDCFG_IN_FMT))
+#define LCDCFG_LCD1DEN_POL (1 << 27)
+#define LCDCFG_LCD1FCLK_POL (1 << 26)
+#define LCDCFG_LCD1LCLK_POL (1 << 25)
+#define LCDCFG_LCD1D_POL (1 << 24)
+#define LCDCFG_LCD2DEN_POL (1 << 23)
+#define LCDCFG_LCD2FCLK_POL (1 << 22)
+#define LCDCFG_LCD2LCLK_POL (1 << 21)
+#define LCDCFG_LCD2D_POL (1 << 20)
+#define LCDCFG_LCD1_TS (1 << 19)
+#define LCDCFG_LCD1D_DS (1 << 18)
+#define LCDCFG_LCD1C_DS (1 << 17)
+#define LCDCFG_LCD1_IS_IN (1 << 16)
+#define LCDCFG_LCD2_TS (1 << 3)
+#define LCDCFG_LCD2D_DS (1 << 2)
+#define LCDCFG_LCD2C_DS (1 << 1)
+#define LCDCFG_LCD2_IS_IN (1 << 0)
+
+/* On-Die Frame Buffer Power Control Register */
+#define ODFBPWR_SLOW (1 << 2)
+#define ODFBPWR_MODE Fld(2,0)
+#define ODFBPWR_MODE_ACT ((0x0) << FShft(ODFBPWR_MODE))
+#define ODFBPWR_MODE_ACT_LP ((0x1) << FShft(ODFBPWR_MODE))
+#define ODFBPWR_MODE_SLEEP ((0x2) << FShft(ODFBPWR_MODE))
+#define ODFBPWR_MODE_SHUTD ((0x3) << FShft(ODFBPWR_MODE))
+
+/* On-Die Frame Buffer Power State Status Register */
+#define ODFBSTAT_ACT (1 << 2)
+#define ODFBSTAT_SLP (1 << 1)
+#define ODFBSTAT_SDN (1 << 0)
+
+/* LMRST - Local Memory (SDRAM) Reset */
+#define LMRST_MC_RST (1 << 0)
+
+/* LMCFG - Local Memory (SDRAM) Configuration Register */
+#define LMCFG_LMC_DS (1 << 5)
+#define LMCFG_LMD_DS (1 << 4)
+#define LMCFG_LMA_DS (1 << 3)
+#define LMCFG_LMC_TS (1 << 2)
+#define LMCFG_LMD_TS (1 << 1)
+#define LMCFG_LMA_TS (1 << 0)
+
+/* LMPWR - Local Memory (SDRAM) Power Control Register */
+#define LMPWR_MC_PWR_CNT Fld(2,0)
+#define LMPWR_MC_PWR_ACT ((0x0) << FShft(LMPWR_MC_PWR_CNT)) /* Active */
+#define LMPWR_MC_PWR_SRM ((0x1) << FShft(LMPWR_MC_PWR_CNT)) /* Self-refresh */
+#define LMPWR_MC_PWR_DPD ((0x3) << FShft(LMPWR_MC_PWR_CNT)) /* deep power down */
+
+/* LMPWRSTAT - Local Memory (SDRAM) Power Status Register */
+#define LMPWRSTAT_MC_PWR_CNT Fld(2,0)
+#define LMPWRSTAT_MC_PWR_ACT ((0x0) << FShft(LMPWRSTAT_MC_PWR_CNT)) /* Active */
+#define LMPWRSTAT_MC_PWR_SRM ((0x1) << FShft(LMPWRSTAT_MC_PWR_CNT)) /* Self-refresh */
+#define LMPWRSTAT_MC_PWR_DPD ((0x3) << FShft(LMPWRSTAT_MC_PWR_CNT)) /* deep power down */
+
+/* LMTYPE - Local Memory (SDRAM) Type Register */
+#define LMTYPE_CASLAT Fld(3,10)
+#define LMTYPE_CASLAT_1 ((0x1) << FShft(LMTYPE_CASLAT))
+#define LMTYPE_CASLAT_2 ((0x2) << FShft(LMTYPE_CASLAT))
+#define LMTYPE_CASLAT_3 ((0x3) << FShft(LMTYPE_CASLAT))
+#define LMTYPE_BKSZ Fld(2,8)
+#define LMTYPE_BKSZ_1 ((0x1) << FShft(LMTYPE_BKSZ))
+#define LMTYPE_BKSZ_2 ((0x2) << FShft(LMTYPE_BKSZ))
+#define LMTYPE_ROWSZ Fld(4,4)
+#define LMTYPE_ROWSZ_11 ((0xb) << FShft(LMTYPE_ROWSZ))
+#define LMTYPE_ROWSZ_12 ((0xc) << FShft(LMTYPE_ROWSZ))
+#define LMTYPE_ROWSZ_13 ((0xd) << FShft(LMTYPE_ROWSZ))
+#define LMTYPE_COLSZ Fld(4,0)
+#define LMTYPE_COLSZ_7 ((0x7) << FShft(LMTYPE_COLSZ))
+#define LMTYPE_COLSZ_8 ((0x8) << FShft(LMTYPE_COLSZ))
+#define LMTYPE_COLSZ_9 ((0x9) << FShft(LMTYPE_COLSZ))
+#define LMTYPE_COLSZ_10 ((0xa) << FShft(LMTYPE_COLSZ))
+#define LMTYPE_COLSZ_11 ((0xb) << FShft(LMTYPE_COLSZ))
+#define LMTYPE_COLSZ_12 ((0xc) << FShft(LMTYPE_COLSZ))
+
+/* LMTIM - Local Memory (SDRAM) Timing Register */
+#define LMTIM_TRAS Fld(4,16)
+#define Lmtim_Tras(x) ((x) << FShft(LMTIM_TRAS))
+#define LMTIM_TRP Fld(4,12)
+#define Lmtim_Trp(x) ((x) << FShft(LMTIM_TRP))
+#define LMTIM_TRCD Fld(4,8)
+#define Lmtim_Trcd(x) ((x) << FShft(LMTIM_TRCD))
+#define LMTIM_TRC Fld(4,4)
+#define Lmtim_Trc(x) ((x) << FShft(LMTIM_TRC))
+#define LMTIM_TDPL Fld(4,0)
+#define Lmtim_Tdpl(x) ((x) << FShft(LMTIM_TDPL))
+
+/* LMREFRESH - Local Memory (SDRAM) tREF Control Register */
+#define LMREFRESH_TREF Fld(2,0)
+#define Lmrefresh_Tref(x) ((x) << FShft(LMREFRESH_TREF))
+
+/* GSCTRL - Graphics surface control register */
+#define GSCTRL_LUT_EN (1 << 31)
+#define GSCTRL_GPIXFMT Fld(4,27)
+#define GSCTRL_GPIXFMT_INDEXED ((0x0) << FShft(GSCTRL_GPIXFMT))
+#define GSCTRL_GPIXFMT_ARGB4444 ((0x4) << FShft(GSCTRL_GPIXFMT))
+#define GSCTRL_GPIXFMT_ARGB1555 ((0x5) << FShft(GSCTRL_GPIXFMT))
+#define GSCTRL_GPIXFMT_RGB888 ((0x6) << FShft(GSCTRL_GPIXFMT))
+#define GSCTRL_GPIXFMT_RGB565 ((0x7) << FShft(GSCTRL_GPIXFMT))
+#define GSCTRL_GPIXFMT_ARGB8888 ((0x8) << FShft(GSCTRL_GPIXFMT))
+#define GSCTRL_GAMMA_EN (1 << 26)
+
+#define GSCTRL_GSWIDTH Fld(11,11)
+#define Gsctrl_Width(Pixel) /* Display Width [1..2048 pix.] */ \
+ (((Pixel) - 1) << FShft(GSCTRL_GSWIDTH))
+
+#define GSCTRL_GSHEIGHT Fld(11,0)
+#define Gsctrl_Height(Pixel) /* Display Height [1..2048 pix.] */ \
+ (((Pixel) - 1) << FShft(GSCTRL_GSHEIGHT))
+
+/* GBBASE fileds */
+#define GBBASE_GLALPHA Fld(8,24)
+#define Gbbase_Glalpha(x) ((x) << FShft(GBBASE_GLALPHA))
+
+#define GBBASE_COLKEY Fld(24,0)
+#define Gbbase_Colkey(x) ((x) << FShft(GBBASE_COLKEY))
+
+/* GDRCTRL fields */
+#define GDRCTRL_PIXDBL (1 << 31)
+#define GDRCTRL_PIXHLV (1 << 30)
+#define GDRCTRL_LNDBL (1 << 29)
+#define GDRCTRL_LNHLV (1 << 28)
+#define GDRCTRL_COLKEYM Fld(24,0)
+#define Gdrctrl_Colkeym(x) ((x) << FShft(GDRCTRL_COLKEYM))
+
+/* GSCADR graphics stream control address register fields */
+#define GSCADR_STR_EN (1 << 31)
+#define GSCADR_COLKEY_EN (1 << 30)
+#define GSCADR_COLKEYSCR (1 << 29)
+#define GSCADR_BLEND_M Fld(2,27)
+#define GSCADR_BLEND_NONE ((0x0) << FShft(GSCADR_BLEND_M))
+#define GSCADR_BLEND_INV ((0x1) << FShft(GSCADR_BLEND_M))
+#define GSCADR_BLEND_GLOB ((0x2) << FShft(GSCADR_BLEND_M))
+#define GSCADR_BLEND_PIX ((0x3) << FShft(GSCADR_BLEND_M))
+#define GSCADR_BLEND_POS Fld(2,24)
+#define GSCADR_BLEND_GFX ((0x0) << FShft(GSCADR_BLEND_POS))
+#define GSCADR_BLEND_VID ((0x1) << FShft(GSCADR_BLEND_POS))
+#define GSCADR_BLEND_CUR ((0x2) << FShft(GSCADR_BLEND_POS))
+#define GSCADR_GBASE_ADR Fld(23,0)
+#define Gscadr_Gbase_Adr(x) ((x) << FShft(GSCADR_GBASE_ADR))
+
+/* GSADR graphics stride address register fields */
+#define GSADR_SRCSTRIDE Fld(10,22)
+#define Gsadr_Srcstride(x) ((x) << FShft(GSADR_SRCSTRIDE))
+#define GSADR_XSTART Fld(11,11)
+#define Gsadr_Xstart(x) ((x) << FShft(GSADR_XSTART))
+#define GSADR_YSTART Fld(11,0)
+#define Gsadr_Ystart(y) ((y) << FShft(GSADR_YSTART))
+
+/* GPLUT graphics palette register fields */
+#define GPLUT_LUTADR Fld(8,24)
+#define Gplut_Lutadr(x) ((x) << FShft(GPLUT_LUTADR))
+#define GPLUT_LUTDATA Fld(24,0)
+#define Gplut_Lutdata(x) ((x) << FShft(GPLUT_LUTDATA))
+
+/* HCCTRL - Hardware Cursor Register fields */
+#define HCCTRL_CUR_EN (1 << 31)
+#define HCCTRL_COLKEY_EN (1 << 29)
+#define HCCTRL_COLKEYSRC (1 << 28)
+#define HCCTRL_BLEND_M Fld(2,26)
+#define HCCTRL_BLEND_NONE ((0x0) << FShft(HCCTRL_BLEND_M))
+#define HCCTRL_BLEND_INV ((0x1) << FShft(HCCTRL_BLEND_M))
+#define HCCTRL_BLEND_GLOB ((0x2) << FShft(HCCTRL_BLEND_M))
+#define HCCTRL_BLEND_PIX ((0x3) << FShft(HCCTRL_BLEND_M))
+#define HCCTRL_CPIXFMT Fld(3,23)
+#define HCCTRL_CPIXFMT_RGB332 ((0x3) << FShft(HCCTRL_CPIXFMT))
+#define HCCTRL_CPIXFMT_ARGB4444 ((0x4) << FShft(HCCTRL_CPIXFMT))
+#define HCCTRL_CPIXFMT_ARGB1555 ((0x5) << FShft(HCCTRL_CPIXFMT))
+#define HCCTRL_CBASE_ADR Fld(23,0)
+#define Hcctrl_Cbase_Adr(x) ((x) << FShft(HCCTRL_CBASE_ADR))
+
+/* HCSIZE Hardware Cursor Size Register fields */
+#define HCSIZE_BLEND_POS Fld(2,29)
+#define HCSIZE_BLEND_GFX ((0x0) << FShft(HCSIZE_BLEND_POS))
+#define HCSIZE_BLEND_VID ((0x1) << FShft(HCSIZE_BLEND_POS))
+#define HCSIZE_BLEND_CUR ((0x2) << FShft(HCSIZE_BLEND_POS))
+#define HCSIZE_CWIDTH Fld(3,16)
+#define Hcsize_Cwidth(x) ((x) << FShft(HCSIZE_CWIDTH))
+#define HCSIZE_CHEIGHT Fld(3,0)
+#define Hcsize_Cheight(x) ((x) << FShft(HCSIZE_CHEIGHT))
+
+/* HCPOS Hardware Cursor Position Register fields */
+#define HCPOS_SWITCHSRC (1 << 30)
+#define HCPOS_CURBLINK Fld(6,24)
+#define Hcpos_Curblink(x) ((x) << FShft(HCPOS_CURBLINK))
+#define HCPOS_XSTART Fld(12,12)
+#define Hcpos_Xstart(x) ((x) << FShft(HCPOS_XSTART))
+#define HCPOS_YSTART Fld(12,0)
+#define Hcpos_Ystart(y) ((y) << FShft(HCPOS_YSTART))
+
+/* HCBADR Hardware Cursor Blend Address Register */
+#define HCBADR_GLALPHA Fld(8,24)
+#define Hcbadr_Glalpha(x) ((x) << FShft(HCBADR_GLALPHA))
+#define HCBADR_COLKEY Fld(24,0)
+#define Hcbadr_Colkey(x) ((x) << FShft(HCBADR_COLKEY))
+
+/* HCCKMSK - Hardware Cursor Color Key Mask Register */
+#define HCCKMSK_COLKEY_M Fld(24,0)
+#define Hcckmsk_Colkey_M(x) ((x) << FShft(HCCKMSK_COLKEY_M))
+
+/* DSCTRL - Display sync control register */
+#define DSCTRL_SYNCGEN_EN (1 << 31)
+#define DSCTRL_DPL_RST (1 << 29)
+#define DSCTRL_PWRDN_M (1 << 28)
+#define DSCTRL_UPDSYNCCNT (1 << 26)
+#define DSCTRL_UPDINTCNT (1 << 25)
+#define DSCTRL_UPDCNT (1 << 24)
+#define DSCTRL_UPDWAIT Fld(4,16)
+#define Dsctrl_Updwait(x) ((x) << FShft(DSCTRL_UPDWAIT))
+#define DSCTRL_CLKPOL (1 << 11)
+#define DSCTRL_CSYNC_EN (1 << 10)
+#define DSCTRL_VS_SLAVE (1 << 7)
+#define DSCTRL_HS_SLAVE (1 << 6)
+#define DSCTRL_BLNK_POL (1 << 5)
+#define DSCTRL_BLNK_DIS (1 << 4)
+#define DSCTRL_VS_POL (1 << 3)
+#define DSCTRL_VS_DIS (1 << 2)
+#define DSCTRL_HS_POL (1 << 1)
+#define DSCTRL_HS_DIS (1 << 0)
+
+/* DHT01 - Display horizontal timing register 01 */
+#define DHT01_HBPS Fld(12,16)
+#define Dht01_Hbps(x) ((x) << FShft(DHT01_HBPS))
+#define DHT01_HT Fld(12,0)
+#define Dht01_Ht(x) ((x) << FShft(DHT01_HT))
+
+/* DHT02 - Display horizontal timing register 02 */
+#define DHT02_HAS Fld(12,16)
+#define Dht02_Has(x) ((x) << FShft(DHT02_HAS))
+#define DHT02_HLBS Fld(12,0)
+#define Dht02_Hlbs(x) ((x) << FShft(DHT02_HLBS))
+
+/* DHT03 - Display horizontal timing register 03 */
+#define DHT03_HFPS Fld(12,16)
+#define Dht03_Hfps(x) ((x) << FShft(DHT03_HFPS))
+#define DHT03_HRBS Fld(12,0)
+#define Dht03_Hrbs(x) ((x) << FShft(DHT03_HRBS))
+
+/* DVT01 - Display vertical timing register 01 */
+#define DVT01_VBPS Fld(12,16)
+#define Dvt01_Vbps(x) ((x) << FShft(DVT01_VBPS))
+#define DVT01_VT Fld(12,0)
+#define Dvt01_Vt(x) ((x) << FShft(DVT01_VT))
+
+/* DVT02 - Display vertical timing register 02 */
+#define DVT02_VAS Fld(12,16)
+#define Dvt02_Vas(x) ((x) << FShft(DVT02_VAS))
+#define DVT02_VTBS Fld(12,0)
+#define Dvt02_Vtbs(x) ((x) << FShft(DVT02_VTBS))
+
+/* DVT03 - Display vertical timing register 03 */
+#define DVT03_VFPS Fld(12,16)
+#define Dvt03_Vfps(x) ((x) << FShft(DVT03_VFPS))
+#define DVT03_VBBS Fld(12,0)
+#define Dvt03_Vbbs(x) ((x) << FShft(DVT03_VBBS))
+
+/* DVECTRL - display vertical event control register */
+#define DVECTRL_VEVENT Fld(12,16)
+#define Dvectrl_Vevent(x) ((x) << FShft(DVECTRL_VEVENT))
+#define DVECTRL_VFETCH Fld(12,0)
+#define Dvectrl_Vfetch(x) ((x) << FShft(DVECTRL_VFETCH))
+
+/* DHDET - display horizontal DE timing register */
+#define DHDET_HDES Fld(12,16)
+#define Dhdet_Hdes(x) ((x) << FShft(DHDET_HDES))
+#define DHDET_HDEF Fld(12,0)
+#define Dhdet_Hdef(x) ((x) << FShft(DHDET_HDEF))
+
+/* DVDET - display vertical DE timing register */
+#define DVDET_VDES Fld(12,16)
+#define Dvdet_Vdes(x) ((x) << FShft(DVDET_VDES))
+#define DVDET_VDEF Fld(12,0)
+#define Dvdet_Vdef(x) ((x) << FShft(DVDET_VDEF))
+
+/* DODMSK - display output data mask register */
+#define DODMSK_MASK_LVL (1 << 31)
+#define DODMSK_BLNK_LVL (1 << 30)
+#define DODMSK_MASK_B Fld(8,16)
+#define Dodmsk_Mask_B(x) ((x) << FShft(DODMSK_MASK_B))
+#define DODMSK_MASK_G Fld(8,8)
+#define Dodmsk_Mask_G(x) ((x) << FShft(DODMSK_MASK_G))
+#define DODMSK_MASK_R Fld(8,0)
+#define Dodmsk_Mask_R(x) ((x) << FShft(DODMSK_MASK_R))
+
+/* DBCOL - display border color control register */
+#define DBCOL_BORDCOL Fld(24,0)
+#define Dbcol_Bordcol(x) ((x) << FShft(DBCOL_BORDCOL))
+
+/* DVLNUM - display vertical line number register */
+#define DVLNUM_VLINE Fld(12,0)
+#define Dvlnum_Vline(x) ((x) << FShft(DVLNUM_VLINE))
+
+/* DMCTRL - Display Memory Control Register */
+#define DMCTRL_MEM_REF Fld(2,30)
+#define DMCTRL_MEM_REF_ACT ((0x0) << FShft(DMCTRL_MEM_REF))
+#define DMCTRL_MEM_REF_HB ((0x1) << FShft(DMCTRL_MEM_REF))
+#define DMCTRL_MEM_REF_VB ((0x2) << FShft(DMCTRL_MEM_REF))
+#define DMCTRL_MEM_REF_BOTH ((0x3) << FShft(DMCTRL_MEM_REF))
+#define DMCTRL_UV_THRHLD Fld(6,24)
+#define Dmctrl_Uv_Thrhld(x) ((x) << FShft(DMCTRL_UV_THRHLD))
+#define DMCTRL_V_THRHLD Fld(7,16)
+#define Dmctrl_V_Thrhld(x) ((x) << FShft(DMCTRL_V_THRHLD))
+#define DMCTRL_D_THRHLD Fld(7,8)
+#define Dmctrl_D_Thrhld(x) ((x) << FShft(DMCTRL_D_THRHLD))
+#define DMCTRL_BURSTLEN Fld(6,0)
+#define Dmctrl_Burstlen(x) ((x) << FShft(DMCTRL_BURSTLEN))
+
+
+/* DLSTS - display load status register */
+#define DLSTS_RLD_ADONE (1 << 23)
+/* #define DLSTS_RLD_ADOUT Fld(23,0) */
+
+/* DLLCTRL - display list load control register */
+#define DLLCTRL_RLD_ADRLN Fld(8,24)
+#define Dllctrl_Rld_Adrln(x) ((x) << FShft(DLLCTRL_RLD_ADRLN))
+
+/* SPOCTRL - Scale Pitch/Order Control Register */
+#define SPOCTRL_H_SC_BP (1 << 31)
+#define SPOCTRL_V_SC_BP (1 << 30)
+#define SPOCTRL_HV_SC_OR (1 << 29)
+#define SPOCTRL_VS_UR_C (1 << 27)
+#define SPOCTRL_VORDER Fld(2,16)
+#define SPOCTRL_VORDER_1TAP ((0x0) << FShft(SPOCTRL_VORDER))
+#define SPOCTRL_VORDER_2TAP ((0x1) << FShft(SPOCTRL_VORDER))
+#define SPOCTRL_VORDER_4TAP ((0x3) << FShft(SPOCTRL_VORDER))
+#define SPOCTRL_VPITCH Fld(16,0)
+#define Spoctrl_Vpitch(x) ((x) << FShft(SPOCTRL_VPITCH))
+
+#endif /* __REG_BITS_2700G_ */
diff --git a/drivers/video/mbx/regs.h b/drivers/video/mbx/regs.h
new file mode 100644
index 00000000000..ad20be07666
--- /dev/null
+++ b/drivers/video/mbx/regs.h
@@ -0,0 +1,195 @@
+#ifndef __REGS_2700G_
+#define __REGS_2700G_
+
+/* extern unsigned long virt_base_2700; */
+/* #define __REG_2700G(x) (*(volatile unsigned long*)((x)+virt_base_2700)) */
+#define __REG_2700G(x) ((x)+virt_base_2700)
+
+/* System Configuration Registers (0x0000_0000 0x0000_0010) */
+#define SYSCFG __REG_2700G(0x00000000)
+#define PFBASE __REG_2700G(0x00000004)
+#define PFCEIL __REG_2700G(0x00000008)
+#define POLLFLAG __REG_2700G(0x0000000c)
+#define SYSRST __REG_2700G(0x00000010)
+
+/* Interrupt Control Registers (0x0000_0014 0x0000_002F) */
+#define NINTPW __REG_2700G(0x00000014)
+#define MINTENABLE __REG_2700G(0x00000018)
+#define MINTSTAT __REG_2700G(0x0000001c)
+#define SINTENABLE __REG_2700G(0x00000020)
+#define SINTSTAT __REG_2700G(0x00000024)
+#define SINTCLR __REG_2700G(0x00000028)
+
+/* Clock Control Registers (0x0000_002C 0x0000_005F) */
+#define SYSCLKSRC __REG_2700G(0x0000002c)
+#define PIXCLKSRC __REG_2700G(0x00000030)
+#define CLKSLEEP __REG_2700G(0x00000034)
+#define COREPLL __REG_2700G(0x00000038)
+#define DISPPLL __REG_2700G(0x0000003c)
+#define PLLSTAT __REG_2700G(0x00000040)
+#define VOVRCLK __REG_2700G(0x00000044)
+#define PIXCLK __REG_2700G(0x00000048)
+#define MEMCLK __REG_2700G(0x0000004c)
+#define M24CLK __REG_2700G(0x00000054)
+#define MBXCLK __REG_2700G(0x00000054)
+#define SDCLK __REG_2700G(0x00000058)
+#define PIXCLKDIV __REG_2700G(0x0000005c)
+
+/* LCD Port Control Register (0x0000_0060 0x0000_006F) */
+#define LCD_CONFIG __REG_2700G(0x00000060)
+
+/* On-Die Frame Buffer Registers (0x0000_0064 0x0000_006B) */
+#define ODFBPWR __REG_2700G(0x00000064)
+#define ODFBSTAT __REG_2700G(0x00000068)
+
+/* GPIO Registers (0x0000_006C 0x0000_007F) */
+#define GPIOCGF __REG_2700G(0x0000006c)
+#define GPIOHI __REG_2700G(0x00000070)
+#define GPIOLO __REG_2700G(0x00000074)
+#define GPIOSTAT __REG_2700G(0x00000078)
+
+/* Pulse Width Modulator (PWM) Registers (0x0000_0200 0x0000_02FF) */
+#define PWMRST __REG_2700G(0x00000200)
+#define PWMCFG __REG_2700G(0x00000204)
+#define PWM0DIV __REG_2700G(0x00000210)
+#define PWM0DUTY __REG_2700G(0x00000214)
+#define PWM0PER __REG_2700G(0x00000218)
+#define PWM1DIV __REG_2700G(0x00000220)
+#define PWM1DUTY __REG_2700G(0x00000224)
+#define PWM1PER __REG_2700G(0x00000228)
+
+/* Identification (ID) Registers (0x0000_0300 0x0000_0FFF) */
+#define ID __REG_2700G(0x00000FF0)
+
+/* Local Memory (SDRAM) Interface Registers (0x0000_1000 0x0000_1FFF) */
+#define LMRST __REG_2700G(0x00001000)
+#define LMCFG __REG_2700G(0x00001004)
+#define LMPWR __REG_2700G(0x00001008)
+#define LMPWRSTAT __REG_2700G(0x0000100c)
+#define LMCEMR __REG_2700G(0x00001010)
+#define LMTYPE __REG_2700G(0x00001014)
+#define LMTIM __REG_2700G(0x00001018)
+#define LMREFRESH __REG_2700G(0x0000101c)
+#define LMPROTMIN __REG_2700G(0x00001020)
+#define LMPROTMAX __REG_2700G(0x00001024)
+#define LMPROTCFG __REG_2700G(0x00001028)
+#define LMPROTERR __REG_2700G(0x0000102c)
+
+/* Plane Controller Registers (0x0000_2000 0x0000_2FFF) */
+#define GSCTRL __REG_2700G(0x00002000)
+#define VSCTRL __REG_2700G(0x00002004)
+#define GBBASE __REG_2700G(0x00002020)
+#define VBBASE __REG_2700G(0x00002024)
+#define GDRCTRL __REG_2700G(0x00002040)
+#define VCMSK __REG_2700G(0x00002044)
+#define GSCADR __REG_2700G(0x00002060)
+#define VSCADR __REG_2700G(0x00002064)
+#define VUBASE __REG_2700G(0x00002084)
+#define VVBASE __REG_2700G(0x000020a4)
+#define GSADR __REG_2700G(0x000020c0)
+#define VSADR __REG_2700G(0x000020c4)
+#define HCCTRL __REG_2700G(0x00002100)
+#define HCSIZE __REG_2700G(0x00002110)
+#define HCPOS __REG_2700G(0x00002120)
+#define HCBADR __REG_2700G(0x00002130)
+#define HCCKMSK __REG_2700G(0x00002140)
+#define GPLUT __REG_2700G(0x00002150)
+#define DSCTRL __REG_2700G(0x00002154)
+#define DHT01 __REG_2700G(0x00002158)
+#define DHT02 __REG_2700G(0x0000215c)
+#define DHT03 __REG_2700G(0x00002160)
+#define DVT01 __REG_2700G(0x00002164)
+#define DVT02 __REG_2700G(0x00002168)
+#define DVT03 __REG_2700G(0x0000216c)
+#define DBCOL __REG_2700G(0x00002170)
+#define BGCOLOR __REG_2700G(0x00002174)
+#define DINTRS __REG_2700G(0x00002178)
+#define DINTRE __REG_2700G(0x0000217c)
+#define DINTRCNT __REG_2700G(0x00002180)
+#define DSIG __REG_2700G(0x00002184)
+#define DMCTRL __REG_2700G(0x00002188)
+#define CLIPCTRL __REG_2700G(0x0000218c)
+#define SPOCTRL __REG_2700G(0x00002190)
+#define SVCTRL __REG_2700G(0x00002194)
+
+/* 0x0000_2198 */
+/* 0x0000_21A8 VSCOEFF[0:4] Video Scalar Vertical Coefficient [0:4] 4.14.5 */
+#define VSCOEFF0 __REG_2700G(0x00002198)
+#define VSCOEFF1 __REG_2700G(0x0000219c)
+#define VSCOEFF2 __REG_2700G(0x000021a0)
+#define VSCOEFF3 __REG_2700G(0x000021a4)
+#define VSCOEFF4 __REG_2700G(0x000021a8)
+
+#define SHCTRL __REG_2700G(0x000021b0)
+
+/* 0x0000_21B4 */
+/* 0x0000_21D4 HSCOEFF[0:8] Video Scalar Horizontal Coefficient [0:8] 4.14.7 */
+#define HSCOEFF0 __REG_2700G(0x000021b4)
+#define HSCOEFF1 __REG_2700G(0x000021b8)
+#define HSCOEFF2 __REG_2700G(0x000021bc)
+#define HSCOEFF3 __REG_2700G(0x000021b0)
+#define HSCOEFF4 __REG_2700G(0x000021c4)
+#define HSCOEFF5 __REG_2700G(0x000021c8)
+#define HSCOEFF6 __REG_2700G(0x000021cc)
+#define HSCOEFF7 __REG_2700G(0x000021d0)
+#define HSCOEFF8 __REG_2700G(0x000021d4)
+
+#define SSSIZE __REG_2700G(0x000021D8)
+
+/* 0x0000_2200 */
+/* 0x0000_2240 VIDGAM[0:16] Video Gamma LUT Index [0:16] 4.15.2 */
+#define VIDGAM0 __REG_2700G(0x00002200)
+#define VIDGAM1 __REG_2700G(0x00002204)
+#define VIDGAM2 __REG_2700G(0x00002208)
+#define VIDGAM3 __REG_2700G(0x0000220c)
+#define VIDGAM4 __REG_2700G(0x00002210)
+#define VIDGAM5 __REG_2700G(0x00002214)
+#define VIDGAM6 __REG_2700G(0x00002218)
+#define VIDGAM7 __REG_2700G(0x0000221c)
+#define VIDGAM8 __REG_2700G(0x00002220)
+#define VIDGAM9 __REG_2700G(0x00002224)
+#define VIDGAM10 __REG_2700G(0x00002228)
+#define VIDGAM11 __REG_2700G(0x0000222c)
+#define VIDGAM12 __REG_2700G(0x00002230)
+#define VIDGAM13 __REG_2700G(0x00002234)
+#define VIDGAM14 __REG_2700G(0x00002238)
+#define VIDGAM15 __REG_2700G(0x0000223c)
+#define VIDGAM16 __REG_2700G(0x00002240)
+
+/* 0x0000_2250 */
+/* 0x0000_2290 GFXGAM[0:16] Graphics Gamma LUT Index [0:16] 4.15.3 */
+#define GFXGAM0 __REG_2700G(0x00002250)
+#define GFXGAM1 __REG_2700G(0x00002254)
+#define GFXGAM2 __REG_2700G(0x00002258)
+#define GFXGAM3 __REG_2700G(0x0000225c)
+#define GFXGAM4 __REG_2700G(0x00002260)
+#define GFXGAM5 __REG_2700G(0x00002264)
+#define GFXGAM6 __REG_2700G(0x00002268)
+#define GFXGAM7 __REG_2700G(0x0000226c)
+#define GFXGAM8 __REG_2700G(0x00002270)
+#define GFXGAM9 __REG_2700G(0x00002274)
+#define GFXGAM10 __REG_2700G(0x00002278)
+#define GFXGAM11 __REG_2700G(0x0000227c)
+#define GFXGAM12 __REG_2700G(0x00002280)
+#define GFXGAM13 __REG_2700G(0x00002284)
+#define GFXGAM14 __REG_2700G(0x00002288)
+#define GFXGAM15 __REG_2700G(0x0000228c)
+#define GFXGAM16 __REG_2700G(0x00002290)
+
+#define DLSTS __REG_2700G(0x00002300)
+#define DLLCTRL __REG_2700G(0x00002304)
+#define DVLNUM __REG_2700G(0x00002308)
+#define DUCTRL __REG_2700G(0x0000230c)
+#define DVECTRL __REG_2700G(0x00002310)
+#define DHDET __REG_2700G(0x00002314)
+#define DVDET __REG_2700G(0x00002318)
+#define DODMSK __REG_2700G(0x0000231c)
+#define CSC01 __REG_2700G(0x00002330)
+#define CSC02 __REG_2700G(0x00002334)
+#define CSC03 __REG_2700G(0x00002338)
+#define CSC04 __REG_2700G(0x0000233c)
+#define CSC05 __REG_2700G(0x00002340)
+
+#define FB_MEMORY_START __REG_2700G(0x00060000)
+
+#endif /* __REGS_2700G_ */
diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c
index ff5454601e2..d1267904c28 100644
--- a/drivers/video/modedb.c
+++ b/drivers/video/modedb.c
@@ -12,7 +12,6 @@
*/
#include <linux/module.h>
-#include <linux/tty.h>
#include <linux/fb.h>
#include <linux/sched.h>
diff --git a/drivers/video/neofb.c b/drivers/video/neofb.c
index 773855a311e..59a6f5fa5ae 100644
--- a/drivers/video/neofb.c
+++ b/drivers/video/neofb.c
@@ -59,7 +59,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
diff --git a/drivers/video/nvidia/nv_backlight.c b/drivers/video/nvidia/nv_backlight.c
index 1c1c10c699c..b45f577094a 100644
--- a/drivers/video/nvidia/nv_backlight.c
+++ b/drivers/video/nvidia/nv_backlight.c
@@ -26,9 +26,11 @@
*/
#define MIN_LEVEL 0x158
#define MAX_LEVEL 0x534
+#define LEVEL_STEP ((MAX_LEVEL - MIN_LEVEL) / FB_BACKLIGHT_MAX)
static struct backlight_properties nvidia_bl_data;
+/* Call with fb_info->bl_mutex held */
static int nvidia_bl_get_level_brightness(struct nvidia_par *par,
int level)
{
@@ -36,9 +38,7 @@ static int nvidia_bl_get_level_brightness(struct nvidia_par *par,
int nlevel;
/* Get and convert the value */
- mutex_lock(&info->bl_mutex);
- nlevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL;
- mutex_unlock(&info->bl_mutex);
+ nlevel = MIN_LEVEL + info->bl_curve[level] * LEVEL_STEP;
if (nlevel < 0)
nlevel = 0;
@@ -50,7 +50,8 @@ static int nvidia_bl_get_level_brightness(struct nvidia_par *par,
return nlevel;
}
-static int nvidia_bl_update_status(struct backlight_device *bd)
+/* Call with fb_info->bl_mutex held */
+static int __nvidia_bl_update_status(struct backlight_device *bd)
{
struct nvidia_par *par = class_get_devdata(&bd->class_dev);
u32 tmp_pcrt, tmp_pmc, fpcontrol;
@@ -84,6 +85,19 @@ static int nvidia_bl_update_status(struct backlight_device *bd)
return 0;
}
+static int nvidia_bl_update_status(struct backlight_device *bd)
+{
+ struct nvidia_par *par = class_get_devdata(&bd->class_dev);
+ struct fb_info *info = pci_get_drvdata(par->pci_dev);
+ int ret;
+
+ mutex_lock(&info->bl_mutex);
+ ret = __nvidia_bl_update_status(bd);
+ mutex_unlock(&info->bl_mutex);
+
+ return ret;
+}
+
static int nvidia_bl_get_brightness(struct backlight_device *bd)
{
return bd->props->brightness;
@@ -96,6 +110,16 @@ static struct backlight_properties nvidia_bl_data = {
.max_brightness = (FB_BACKLIGHT_LEVELS - 1),
};
+void nvidia_bl_set_power(struct fb_info *info, int power)
+{
+ mutex_lock(&info->bl_mutex);
+ up(&info->bl_dev->sem);
+ info->bl_dev->props->power = power;
+ __nvidia_bl_update_status(info->bl_dev);
+ down(&info->bl_dev->sem);
+ mutex_unlock(&info->bl_mutex);
+}
+
void nvidia_bl_init(struct nvidia_par *par)
{
struct fb_info *info = pci_get_drvdata(par->pci_dev);
diff --git a/drivers/video/nvidia/nv_proto.h b/drivers/video/nvidia/nv_proto.h
index 6fba656cd56..86127101765 100644
--- a/drivers/video/nvidia/nv_proto.h
+++ b/drivers/video/nvidia/nv_proto.h
@@ -68,9 +68,11 @@ extern u8 byte_rev[256];
#ifdef CONFIG_FB_NVIDIA_BACKLIGHT
extern void nvidia_bl_init(struct nvidia_par *par);
extern void nvidia_bl_exit(struct nvidia_par *par);
+extern void nvidia_bl_set_power(struct fb_info *info, int power);
#else
static inline void nvidia_bl_init(struct nvidia_par *par) {}
static inline void nvidia_bl_exit(struct nvidia_par *par) {}
+static inline void nvidia_bl_set_power(struct fb_info *info, int power) {}
#endif
#endif /* __NV_PROTO_H__ */
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c
index b02d6033cc0..d4f85011787 100644
--- a/drivers/video/nvidia/nvidia.c
+++ b/drivers/video/nvidia/nvidia.c
@@ -14,7 +14,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
@@ -35,10 +34,6 @@
#include "nv_proto.h"
#include "nv_dma.h"
-#ifndef CONFIG_PCI /* sanity check */
-#error This driver requires PCI support.
-#endif
-
#undef CONFIG_FB_NVIDIA_DEBUG
#ifdef CONFIG_FB_NVIDIA_DEBUG
#define NVTRACE printk
@@ -933,16 +928,7 @@ static int nvidiafb_blank(int blank, struct fb_info *info)
NVWriteSeq(par, 0x01, tmp);
NVWriteCrtc(par, 0x1a, vesa);
-#ifdef CONFIG_FB_NVIDIA_BACKLIGHT
- mutex_lock(&info->bl_mutex);
- if (info->bl_dev) {
- down(&info->bl_dev->sem);
- info->bl_dev->props->power = blank;
- info->bl_dev->props->update_status(info->bl_dev);
- up(&info->bl_dev->sem);
- }
- mutex_unlock(&info->bl_mutex);
-#endif
+ nvidia_bl_set_power(info, blank);
NVTRACE_LEAVE();
@@ -1313,20 +1299,19 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd,
nvidia_save_vga(par, &par->SavedReg);
+ pci_set_drvdata(pd, info);
+ nvidia_bl_init(par);
if (register_framebuffer(info) < 0) {
printk(KERN_ERR PFX "error registering nVidia framebuffer\n");
goto err_out_iounmap_fb;
}
- pci_set_drvdata(pd, info);
printk(KERN_INFO PFX
"PCI nVidia %s framebuffer (%dMB @ 0x%lX)\n",
info->fix.id,
par->FbMapSize / (1024 * 1024), info->fix.smem_start);
- nvidia_bl_init(par);
-
NVTRACE_LEAVE();
return 0;
diff --git a/drivers/video/offb.c b/drivers/video/offb.c
index 71ce1fa45cf..0013311e056 100644
--- a/drivers/video/offb.c
+++ b/drivers/video/offb.c
@@ -17,7 +17,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
@@ -63,8 +62,6 @@ struct offb_par default_par;
* Interface used by the world
*/
-int offb_init(void);
-
static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
u_int transp, struct fb_info *info);
static int offb_blank(int blank, struct fb_info *info);
@@ -73,11 +70,6 @@ static int offb_blank(int blank, struct fb_info *info);
extern boot_infos_t *boot_infos;
#endif
-static void offb_init_nodriver(struct device_node *);
-static void offb_init_fb(const char *name, const char *full_name,
- int width, int height, int depth, int pitch,
- unsigned long address, struct device_node *dp);
-
static struct fb_ops offb_ops = {
.owner = THIS_MODULE,
.fb_setcolreg = offb_setcolreg,
@@ -230,123 +222,17 @@ static int offb_blank(int blank, struct fb_info *info)
return 0;
}
- /*
- * Initialisation
- */
-int __init offb_init(void)
+static void __iomem *offb_map_reg(struct device_node *np, int index,
+ unsigned long offset, unsigned long size)
{
- struct device_node *dp = NULL, *boot_disp = NULL;
-
- if (fb_get_options("offb", NULL))
- return -ENODEV;
+ struct resource r;
- for (dp = NULL; (dp = of_find_node_by_type(dp, "display"));) {
- if (get_property(dp, "linux,opened", NULL) &&
- get_property(dp, "linux,boot-display", NULL)) {
- boot_disp = dp;
- offb_init_nodriver(dp);
- }
- }
- for (dp = NULL; (dp = of_find_node_by_type(dp, "display"));) {
- if (get_property(dp, "linux,opened", NULL) &&
- dp != boot_disp)
- offb_init_nodriver(dp);
- }
-
- return 0;
-}
-
-
-static void __init offb_init_nodriver(struct device_node *dp)
-{
- unsigned int len;
- int i, width = 640, height = 480, depth = 8, pitch = 640;
- unsigned int flags, rsize, addr_prop = 0;
- unsigned long max_size = 0;
- u64 rstart, address = OF_BAD_ADDR;
- u32 *pp, *addrp, *up;
- u64 asize;
-
- pp = (u32 *)get_property(dp, "linux,bootx-depth", &len);
- if (pp == NULL)
- pp = (u32 *)get_property(dp, "depth", &len);
- if (pp && len == sizeof(u32))
- depth = *pp;
-
- pp = (u32 *)get_property(dp, "linux,bootx-width", &len);
- if (pp == NULL)
- pp = (u32 *)get_property(dp, "width", &len);
- if (pp && len == sizeof(u32))
- width = *pp;
-
- pp = (u32 *)get_property(dp, "linux,bootx-height", &len);
- if (pp == NULL)
- pp = (u32 *)get_property(dp, "height", &len);
- if (pp && len == sizeof(u32))
- height = *pp;
-
- pp = (u32 *)get_property(dp, "linux,bootx-linebytes", &len);
- if (pp == NULL)
- pp = (u32 *)get_property(dp, "linebytes", &len);
- if (pp && len == sizeof(u32))
- pitch = *pp;
- else
- pitch = width * ((depth + 7) / 8);
-
- rsize = (unsigned long)pitch * (unsigned long)height;
-
- /* Ok, now we try to figure out the address of the framebuffer.
- *
- * Unfortunately, Open Firmware doesn't provide a standard way to do
- * so. All we can do is a dodgy heuristic that happens to work in
- * practice. On most machines, the "address" property contains what
- * we need, though not on Matrox cards found in IBM machines. What I've
- * found that appears to give good results is to go through the PCI
- * ranges and pick one that is both big enough and if possible encloses
- * the "address" property. If none match, we pick the biggest
- */
- up = (u32 *)get_property(dp, "linux,bootx-addr", &len);
- if (up == NULL)
- up = (u32 *)get_property(dp, "address", &len);
- if (up && len == sizeof(u32))
- addr_prop = *up;
-
- for (i = 0; (addrp = of_get_address(dp, i, &asize, &flags))
- != NULL; i++) {
- int match_addrp = 0;
-
- if (!(flags & IORESOURCE_MEM))
- continue;
- if (asize < rsize)
- continue;
- rstart = of_translate_address(dp, addrp);
- if (rstart == OF_BAD_ADDR)
- continue;
- if (addr_prop && (rstart <= addr_prop) &&
- ((rstart + asize) >= (addr_prop + rsize)))
- match_addrp = 1;
- if (match_addrp) {
- address = addr_prop;
- break;
- }
- if (rsize > max_size) {
- max_size = rsize;
- address = OF_BAD_ADDR;
- }
-
- if (address == OF_BAD_ADDR)
- address = rstart;
- }
- if (address == OF_BAD_ADDR && addr_prop)
- address = (u64)addr_prop;
- if (address != OF_BAD_ADDR) {
- /* kludge for valkyrie */
- if (strcmp(dp->name, "valkyrie") == 0)
- address += 0x1000;
- offb_init_fb(dp->name, dp->full_name, width, height, depth,
- pitch, address, dp);
- }
+ if (of_address_to_resource(np, index, &r))
+ return 0;
+ if ((r.start + offset + size) > r.end)
+ return 0;
+ return ioremap(r.start + offset, size);
}
static void __init offb_init_fb(const char *name, const char *full_name,
@@ -403,45 +289,39 @@ static void __init offb_init_fb(const char *name, const char *full_name,
par->cmap_type = cmap_unknown;
if (depth == 8) {
-
/* Palette hacks disabled for now */
-#if 0
if (dp && !strncmp(name, "ATY,Rage128", 11)) {
- unsigned long regbase = dp->addrs[2].address;
- par->cmap_adr = ioremap(regbase, 0x1FFF);
- par->cmap_type = cmap_r128;
+ par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff);
+ if (par->cmap_adr)
+ par->cmap_type = cmap_r128;
} else if (dp && (!strncmp(name, "ATY,RageM3pA", 12)
|| !strncmp(name, "ATY,RageM3p12A", 14))) {
- unsigned long regbase =
- dp->parent->addrs[2].address;
- par->cmap_adr = ioremap(regbase, 0x1FFF);
- par->cmap_type = cmap_M3A;
+ par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff);
+ if (par->cmap_adr)
+ par->cmap_type = cmap_M3A;
} else if (dp && !strncmp(name, "ATY,RageM3pB", 12)) {
- unsigned long regbase =
- dp->parent->addrs[2].address;
- par->cmap_adr = ioremap(regbase, 0x1FFF);
- par->cmap_type = cmap_M3B;
+ par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff);
+ if (par->cmap_adr)
+ par->cmap_type = cmap_M3B;
} else if (dp && !strncmp(name, "ATY,Rage6", 9)) {
- unsigned long regbase = dp->addrs[1].address;
- par->cmap_adr = ioremap(regbase, 0x1FFF);
- par->cmap_type = cmap_radeon;
+ par->cmap_adr = offb_map_reg(dp, 1, 0, 0x1fff);
+ if (par->cmap_adr)
+ par->cmap_type = cmap_radeon;
} else if (!strncmp(name, "ATY,", 4)) {
unsigned long base = address & 0xff000000UL;
par->cmap_adr =
ioremap(base + 0x7ff000, 0x1000) + 0xcc0;
par->cmap_data = par->cmap_adr + 1;
par->cmap_type = cmap_m64;
- } else if (device_is_compatible(dp, "pci1014,b7")) {
- unsigned long regbase = dp->addrs[0].address;
- par->cmap_adr = ioremap(regbase + 0x6000, 0x1000);
- par->cmap_type = cmap_gxt2000;
+ } else if (dp && device_is_compatible(dp, "pci1014,b7")) {
+ par->cmap_adr = offb_map_reg(dp, 0, 0x6000, 0x1000);
+ if (par->cmap_adr)
+ par->cmap_type = cmap_gxt2000;
}
-#endif
- fix->visual = par->cmap_adr ? FB_VISUAL_PSEUDOCOLOR
- : FB_VISUAL_STATIC_PSEUDOCOLOR;
+ fix->visual = (par->cmap_type != cmap_unknown) ?
+ FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_STATIC_PSEUDOCOLOR;
} else
- fix->visual = /* par->cmap_adr ? FB_VISUAL_DIRECTCOLOR
- : */ FB_VISUAL_TRUECOLOR;
+ fix->visual = FB_VISUAL_TRUECOLOR;
var->xoffset = var->yoffset = 0;
switch (depth) {
@@ -521,5 +401,139 @@ static void __init offb_init_fb(const char *name, const char *full_name,
info->node, full_name);
}
+
+static void __init offb_init_nodriver(struct device_node *dp, int no_real_node)
+{
+ unsigned int len;
+ int i, width = 640, height = 480, depth = 8, pitch = 640;
+ unsigned int flags, rsize, addr_prop = 0;
+ unsigned long max_size = 0;
+ u64 rstart, address = OF_BAD_ADDR;
+ u32 *pp, *addrp, *up;
+ u64 asize;
+
+ pp = (u32 *)get_property(dp, "linux,bootx-depth", &len);
+ if (pp == NULL)
+ pp = (u32 *)get_property(dp, "depth", &len);
+ if (pp && len == sizeof(u32))
+ depth = *pp;
+
+ pp = (u32 *)get_property(dp, "linux,bootx-width", &len);
+ if (pp == NULL)
+ pp = (u32 *)get_property(dp, "width", &len);
+ if (pp && len == sizeof(u32))
+ width = *pp;
+
+ pp = (u32 *)get_property(dp, "linux,bootx-height", &len);
+ if (pp == NULL)
+ pp = (u32 *)get_property(dp, "height", &len);
+ if (pp && len == sizeof(u32))
+ height = *pp;
+
+ pp = (u32 *)get_property(dp, "linux,bootx-linebytes", &len);
+ if (pp == NULL)
+ pp = (u32 *)get_property(dp, "linebytes", &len);
+ if (pp && len == sizeof(u32))
+ pitch = *pp;
+ else
+ pitch = width * ((depth + 7) / 8);
+
+ rsize = (unsigned long)pitch * (unsigned long)height;
+
+ /* Ok, now we try to figure out the address of the framebuffer.
+ *
+ * Unfortunately, Open Firmware doesn't provide a standard way to do
+ * so. All we can do is a dodgy heuristic that happens to work in
+ * practice. On most machines, the "address" property contains what
+ * we need, though not on Matrox cards found in IBM machines. What I've
+ * found that appears to give good results is to go through the PCI
+ * ranges and pick one that is both big enough and if possible encloses
+ * the "address" property. If none match, we pick the biggest
+ */
+ up = (u32 *)get_property(dp, "linux,bootx-addr", &len);
+ if (up == NULL)
+ up = (u32 *)get_property(dp, "address", &len);
+ if (up && len == sizeof(u32))
+ addr_prop = *up;
+
+ /* Hack for when BootX is passing us */
+ if (no_real_node)
+ goto skip_addr;
+
+ for (i = 0; (addrp = of_get_address(dp, i, &asize, &flags))
+ != NULL; i++) {
+ int match_addrp = 0;
+
+ if (!(flags & IORESOURCE_MEM))
+ continue;
+ if (asize < rsize)
+ continue;
+ rstart = of_translate_address(dp, addrp);
+ if (rstart == OF_BAD_ADDR)
+ continue;
+ if (addr_prop && (rstart <= addr_prop) &&
+ ((rstart + asize) >= (addr_prop + rsize)))
+ match_addrp = 1;
+ if (match_addrp) {
+ address = addr_prop;
+ break;
+ }
+ if (rsize > max_size) {
+ max_size = rsize;
+ address = OF_BAD_ADDR;
+ }
+
+ if (address == OF_BAD_ADDR)
+ address = rstart;
+ }
+ skip_addr:
+ if (address == OF_BAD_ADDR && addr_prop)
+ address = (u64)addr_prop;
+ if (address != OF_BAD_ADDR) {
+ /* kludge for valkyrie */
+ if (strcmp(dp->name, "valkyrie") == 0)
+ address += 0x1000;
+ offb_init_fb(no_real_node ? "bootx" : dp->name,
+ no_real_node ? "display" : dp->full_name,
+ width, height, depth, pitch, address,
+ no_real_node ? dp : NULL);
+ }
+}
+
+static int __init offb_init(void)
+{
+ struct device_node *dp = NULL, *boot_disp = NULL;
+
+ if (fb_get_options("offb", NULL))
+ return -ENODEV;
+
+ /* Check if we have a MacOS display without a node spec */
+ if (get_property(of_chosen, "linux,bootx-noscreen", NULL) != NULL) {
+ /* The old code tried to work out which node was the MacOS
+ * display based on the address. I'm dropping that since the
+ * lack of a node spec only happens with old BootX versions
+ * (users can update) and with this code, they'll still get
+ * a display (just not the palette hacks).
+ */
+ offb_init_nodriver(of_chosen, 1);
+ }
+
+ for (dp = NULL; (dp = of_find_node_by_type(dp, "display"));) {
+ if (get_property(dp, "linux,opened", NULL) &&
+ get_property(dp, "linux,boot-display", NULL)) {
+ boot_disp = dp;
+ offb_init_nodriver(dp, 0);
+ }
+ }
+ for (dp = NULL; (dp = of_find_node_by_type(dp, "display"));) {
+ if (get_property(dp, "linux,opened", NULL) &&
+ dp != boot_disp)
+ offb_init_nodriver(dp, 0);
+ }
+
+ return 0;
+}
+
+
module_init(offb_init);
MODULE_LICENSE("GPL");
diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c
index 450e802e0aa..983be3ec234 100644
--- a/drivers/video/platinumfb.c
+++ b/drivers/video/platinumfb.c
@@ -22,7 +22,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c
index 49a203e1591..a560a222382 100644
--- a/drivers/video/pm2fb.c
+++ b/drivers/video/pm2fb.c
@@ -33,7 +33,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c
index 0e0f977b05e..1d81ef47efd 100644
--- a/drivers/video/pm3fb.c
+++ b/drivers/video/pm3fb.c
@@ -57,7 +57,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
diff --git a/drivers/video/pmag-aa-fb.c b/drivers/video/pmag-aa-fb.c
index d92f352211e..68ca3cc4077 100644
--- a/drivers/video/pmag-aa-fb.c
+++ b/drivers/video/pmag-aa-fb.c
@@ -29,7 +29,6 @@
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/init.h>
diff --git a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c
index 4a1e0e85692..940ba2be55e 100644
--- a/drivers/video/pvr2fb.c
+++ b/drivers/video/pvr2fb.c
@@ -53,7 +53,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
diff --git a/drivers/video/q40fb.c b/drivers/video/q40fb.c
index fc91dbf896d..48536c3e58a 100644
--- a/drivers/video/q40fb.c
+++ b/drivers/video/q40fb.c
@@ -14,7 +14,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
diff --git a/drivers/video/retz3fb.c b/drivers/video/retz3fb.c
index 5e2c64f622c..cf41ff17764 100644
--- a/drivers/video/retz3fb.c
+++ b/drivers/video/retz3fb.c
@@ -25,7 +25,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
index 2788655e6e7..76fc9d355eb 100644
--- a/drivers/video/riva/fbdev.c
+++ b/drivers/video/riva/fbdev.c
@@ -34,7 +34,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
@@ -278,9 +277,11 @@ static const struct riva_regs reg_template = {
*/
#define MIN_LEVEL 0x158
#define MAX_LEVEL 0x534
+#define LEVEL_STEP ((MAX_LEVEL - MIN_LEVEL) / FB_BACKLIGHT_MAX)
static struct backlight_properties riva_bl_data;
+/* Call with fb_info->bl_mutex held */
static int riva_bl_get_level_brightness(struct riva_par *par,
int level)
{
@@ -288,9 +289,7 @@ static int riva_bl_get_level_brightness(struct riva_par *par,
int nlevel;
/* Get and convert the value */
- mutex_lock(&info->bl_mutex);
- nlevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL;
- mutex_unlock(&info->bl_mutex);
+ nlevel = MIN_LEVEL + info->bl_curve[level] * LEVEL_STEP;
if (nlevel < 0)
nlevel = 0;
@@ -302,7 +301,8 @@ static int riva_bl_get_level_brightness(struct riva_par *par,
return nlevel;
}
-static int riva_bl_update_status(struct backlight_device *bd)
+/* Call with fb_info->bl_mutex held */
+static int __riva_bl_update_status(struct backlight_device *bd)
{
struct riva_par *par = class_get_devdata(&bd->class_dev);
U032 tmp_pcrt, tmp_pmc;
@@ -327,6 +327,19 @@ static int riva_bl_update_status(struct backlight_device *bd)
return 0;
}
+static int riva_bl_update_status(struct backlight_device *bd)
+{
+ struct riva_par *par = class_get_devdata(&bd->class_dev);
+ struct fb_info *info = pci_get_drvdata(par->pdev);
+ int ret;
+
+ mutex_lock(&info->bl_mutex);
+ ret = __riva_bl_update_status(bd);
+ mutex_unlock(&info->bl_mutex);
+
+ return ret;
+}
+
static int riva_bl_get_brightness(struct backlight_device *bd)
{
return bd->props->brightness;
@@ -339,6 +352,16 @@ static struct backlight_properties riva_bl_data = {
.max_brightness = (FB_BACKLIGHT_LEVELS - 1),
};
+static void riva_bl_set_power(struct fb_info *info, int power)
+{
+ mutex_lock(&info->bl_mutex);
+ up(&info->bl_dev->sem);
+ info->bl_dev->props->power = power;
+ __riva_bl_update_status(info->bl_dev);
+ down(&info->bl_dev->sem);
+ mutex_unlock(&info->bl_mutex);
+}
+
static void riva_bl_init(struct riva_par *par)
{
struct fb_info *info = pci_get_drvdata(par->pdev);
@@ -419,6 +442,7 @@ static void riva_bl_exit(struct riva_par *par)
#else
static inline void riva_bl_init(struct riva_par *par) {}
static inline void riva_bl_exit(struct riva_par *par) {}
+static inline void riva_bl_set_power(struct fb_info *info, int power) {}
#endif /* CONFIG_FB_RIVA_BACKLIGHT */
/* ------------------------------------------------------------------------- *
@@ -1337,16 +1361,7 @@ static int rivafb_blank(int blank, struct fb_info *info)
SEQout(par, 0x01, tmp);
CRTCout(par, 0x1a, vesa);
-#ifdef CONFIG_FB_RIVA_BACKLIGHT
- mutex_lock(&info->bl_mutex);
- if (info->bl_dev) {
- down(&info->bl_dev->sem);
- info->bl_dev->props->power = blank;
- info->bl_dev->props->update_status(info->bl_dev);
- up(&info->bl_dev->sem);
- }
- mutex_unlock(&info->bl_mutex);
-#endif
+ riva_bl_set_power(info, blank);
NVTRACE_LEAVE();
@@ -2117,6 +2132,9 @@ static int __devinit rivafb_probe(struct pci_dev *pd,
fb_destroy_modedb(info->monspecs.modedb);
info->monspecs.modedb = NULL;
+
+ pci_set_drvdata(pd, info);
+ riva_bl_init(info->par);
ret = register_framebuffer(info);
if (ret < 0) {
printk(KERN_ERR PFX
@@ -2124,8 +2142,6 @@ static int __devinit rivafb_probe(struct pci_dev *pd,
goto err_iounmap_screen_base;
}
- pci_set_drvdata(pd, info);
-
printk(KERN_INFO PFX
"PCI nVidia %s framebuffer ver %s (%dMB @ 0x%lX)\n",
info->fix.id,
@@ -2133,8 +2149,6 @@ static int __devinit rivafb_probe(struct pci_dev *pd,
info->fix.smem_len / (1024 * 1024),
info->fix.smem_start);
- riva_bl_init(info->par);
-
NVTRACE_LEAVE();
return 0;
diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c
index f461eb10cc7..ad3bdd6f1ac 100644
--- a/drivers/video/s3c2410fb.c
+++ b/drivers/video/s3c2410fb.c
@@ -76,7 +76,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c
index 4729af477fb..461e094e7b4 100644
--- a/drivers/video/savage/savagefb_driver.c
+++ b/drivers/video/savage/savagefb_driver.c
@@ -46,7 +46,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c
index b848ca7db7f..895ebda7d9e 100644
--- a/drivers/video/sis/sis_main.c
+++ b/drivers/video/sis/sis_main.c
@@ -44,7 +44,13 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
#include <linux/tty.h>
+#else
+#include <linux/screen_info.h>
+#endif
+
#include <linux/slab.h>
#include <linux/fb.h>
#include <linux/selection.h>
diff --git a/drivers/video/skeletonfb.c b/drivers/video/skeletonfb.c
index 67f429e9318..bb96cb65fda 100644
--- a/drivers/video/skeletonfb.c
+++ b/drivers/video/skeletonfb.c
@@ -47,7 +47,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
diff --git a/drivers/video/sun3fb.c b/drivers/video/sun3fb.c
index e046e20f02b..f80356dfa8e 100644
--- a/drivers/video/sun3fb.c
+++ b/drivers/video/sun3fb.c
@@ -30,7 +30,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c
index 239b1496874..689ce0270b8 100644
--- a/drivers/video/tdfxfb.c
+++ b/drivers/video/tdfxfb.c
@@ -63,7 +63,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c
index 6c2c78ab982..94fde625a6c 100644
--- a/drivers/video/tgafb.c
+++ b/drivers/video/tgafb.c
@@ -17,7 +17,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/init.h>
diff --git a/drivers/video/tx3912fb.c b/drivers/video/tx3912fb.c
index d904da44e1a..07389ba01ef 100644
--- a/drivers/video/tx3912fb.c
+++ b/drivers/video/tx3912fb.c
@@ -14,7 +14,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
-#include <linux/tty.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
diff --git a/drivers/video/valkyriefb.c b/drivers/video/valkyriefb.c
index 1d76c035050..47f27924a7d 100644
--- a/drivers/video/valkyriefb.c
+++ b/drivers/video/valkyriefb.c
@@ -44,7 +44,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c
index 5718924b677..2196448396e 100644
--- a/drivers/video/vesafb.c
+++ b/drivers/video/vesafb.c
@@ -13,13 +13,13 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/platform_device.h>
+#include <linux/screen_info.h>
#include <video/vga.h>
#include <asm/io.h>
diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c
index d073ffb6e1f..a9b99b01bd8 100644
--- a/drivers/video/vfb.c
+++ b/drivers/video/vfb.c
@@ -15,7 +15,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c
index 3c404c9bd36..43d5a6d9c4a 100644
--- a/drivers/video/vga16fb.c
+++ b/drivers/video/vga16fb.c
@@ -15,13 +15,13 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/platform_device.h>
+#include <linux/screen_info.h>
#include <asm/io.h>
#include <video/vga.h>
diff --git a/drivers/video/virgefb.c b/drivers/video/virgefb.c
index 5ea2345dab9..64378959dd7 100644
--- a/drivers/video/virgefb.c
+++ b/drivers/video/virgefb.c
@@ -39,7 +39,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/zorro.h>
diff --git a/drivers/w1/masters/ds2482.c b/drivers/w1/masters/ds2482.c
index af492cc48db..d93eb626b2f 100644
--- a/drivers/w1/masters/ds2482.c
+++ b/drivers/w1/masters/ds2482.c
@@ -218,7 +218,7 @@ static int ds2482_wait_1wire_idle(struct ds2482_data *pdev)
do {
temp = i2c_smbus_read_byte(&pdev->client);
} while ((temp >= 0) && (temp & DS2482_REG_STS_1WB) &&
- (++retries > DS2482_WAIT_IDLE_TIMEOUT));
+ (++retries < DS2482_WAIT_IDLE_TIMEOUT));
}
if (retries > DS2482_WAIT_IDLE_TIMEOUT)