aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Makefile2
-rw-r--r--drivers/acpi/Kconfig37
-rw-r--r--drivers/acpi/Makefile5
-rw-r--r--drivers/acpi/asus_acpi.c9
-rw-r--r--drivers/acpi/battery.c4
-rw-r--r--drivers/acpi/bay.c490
-rw-r--r--drivers/acpi/blacklist.c29
-rw-r--r--drivers/acpi/bus.c44
-rw-r--r--drivers/acpi/button.c2
-rw-r--r--drivers/acpi/container.c6
-rw-r--r--drivers/acpi/debug.c62
-rw-r--r--drivers/acpi/dispatcher/dsfield.c32
-rw-r--r--drivers/acpi/dispatcher/dsinit.c25
-rw-r--r--drivers/acpi/dispatcher/dsmethod.c55
-rw-r--r--drivers/acpi/dispatcher/dsmthdat.c2
-rw-r--r--drivers/acpi/dispatcher/dsobject.c78
-rw-r--r--drivers/acpi/dispatcher/dsopcode.c6
-rw-r--r--drivers/acpi/dispatcher/dsutils.c2
-rw-r--r--drivers/acpi/dispatcher/dswexec.c12
-rw-r--r--drivers/acpi/dispatcher/dswload.c19
-rw-r--r--drivers/acpi/dispatcher/dswscope.c2
-rw-r--r--drivers/acpi/dispatcher/dswstate.c2
-rw-r--r--drivers/acpi/dock.c16
-rw-r--r--drivers/acpi/ec.c13
-rw-r--r--drivers/acpi/events/evevent.c17
-rw-r--r--drivers/acpi/events/evgpe.c91
-rw-r--r--drivers/acpi/events/evgpeblk.c64
-rw-r--r--drivers/acpi/events/evmisc.c201
-rw-r--r--drivers/acpi/events/evregion.c17
-rw-r--r--drivers/acpi/events/evrgnini.c168
-rw-r--r--drivers/acpi/events/evsci.c14
-rw-r--r--drivers/acpi/events/evxface.c8
-rw-r--r--drivers/acpi/events/evxfevnt.c27
-rw-r--r--drivers/acpi/events/evxfregn.c2
-rw-r--r--drivers/acpi/executer/exconfig.c235
-rw-r--r--drivers/acpi/executer/exconvrt.c2
-rw-r--r--drivers/acpi/executer/excreate.c21
-rw-r--r--drivers/acpi/executer/exdump.c29
-rw-r--r--drivers/acpi/executer/exfield.c2
-rw-r--r--drivers/acpi/executer/exfldio.c7
-rw-r--r--drivers/acpi/executer/exmisc.c2
-rw-r--r--drivers/acpi/executer/exmutex.c86
-rw-r--r--drivers/acpi/executer/exnames.c2
-rw-r--r--drivers/acpi/executer/exoparg1.c4
-rw-r--r--drivers/acpi/executer/exoparg2.c2
-rw-r--r--drivers/acpi/executer/exoparg3.c2
-rw-r--r--drivers/acpi/executer/exoparg6.c2
-rw-r--r--drivers/acpi/executer/exprep.c2
-rw-r--r--drivers/acpi/executer/exregion.c16
-rw-r--r--drivers/acpi/executer/exresnte.c2
-rw-r--r--drivers/acpi/executer/exresolv.c10
-rw-r--r--drivers/acpi/executer/exresop.c12
-rw-r--r--drivers/acpi/executer/exstore.c2
-rw-r--r--drivers/acpi/executer/exstoren.c2
-rw-r--r--drivers/acpi/executer/exstorob.c2
-rw-r--r--drivers/acpi/executer/exsystem.c110
-rw-r--r--drivers/acpi/executer/exutils.c106
-rw-r--r--drivers/acpi/fan.c8
-rw-r--r--drivers/acpi/glue.c123
-rw-r--r--drivers/acpi/hardware/hwacpi.c56
-rw-r--r--drivers/acpi/hardware/hwgpe.c15
-rw-r--r--drivers/acpi/hardware/hwregs.c98
-rw-r--r--drivers/acpi/hardware/hwsleep.c81
-rw-r--r--drivers/acpi/hardware/hwtimer.c9
-rw-r--r--drivers/acpi/motherboard.c191
-rw-r--r--drivers/acpi/namespace/nsaccess.c36
-rw-r--r--drivers/acpi/namespace/nsalloc.c14
-rw-r--r--drivers/acpi/namespace/nsdump.c13
-rw-r--r--drivers/acpi/namespace/nsdumpdv.c2
-rw-r--r--drivers/acpi/namespace/nseval.c13
-rw-r--r--drivers/acpi/namespace/nsinit.c9
-rw-r--r--drivers/acpi/namespace/nsload.c160
-rw-r--r--drivers/acpi/namespace/nsnames.c2
-rw-r--r--drivers/acpi/namespace/nsobject.c2
-rw-r--r--drivers/acpi/namespace/nsparse.c52
-rw-r--r--drivers/acpi/namespace/nssearch.c9
-rw-r--r--drivers/acpi/namespace/nsutils.c9
-rw-r--r--drivers/acpi/namespace/nswalk.c65
-rw-r--r--drivers/acpi/namespace/nsxfeval.c13
-rw-r--r--drivers/acpi/namespace/nsxfname.c47
-rw-r--r--drivers/acpi/namespace/nsxfobj.c2
-rw-r--r--drivers/acpi/numa.c77
-rw-r--r--drivers/acpi/osl.c97
-rw-r--r--drivers/acpi/parser/psargs.c2
-rw-r--r--drivers/acpi/parser/psloop.c1408
-rw-r--r--drivers/acpi/parser/psopcode.c2
-rw-r--r--drivers/acpi/parser/psparse.c7
-rw-r--r--drivers/acpi/parser/psscope.c2
-rw-r--r--drivers/acpi/parser/pstree.c2
-rw-r--r--drivers/acpi/parser/psutils.c2
-rw-r--r--drivers/acpi/parser/pswalk.c2
-rw-r--r--drivers/acpi/parser/psxface.c116
-rw-r--r--drivers/acpi/pci_link.c4
-rw-r--r--drivers/acpi/pci_root.c38
-rw-r--r--drivers/acpi/processor_core.c189
-rw-r--r--drivers/acpi/processor_idle.c52
-rw-r--r--drivers/acpi/processor_perflib.c27
-rw-r--r--drivers/acpi/processor_throttling.c4
-rw-r--r--drivers/acpi/resources/rsaddr.c2
-rw-r--r--drivers/acpi/resources/rscalc.c2
-rw-r--r--drivers/acpi/resources/rscreate.c2
-rw-r--r--drivers/acpi/resources/rsdump.c2
-rw-r--r--drivers/acpi/resources/rsinfo.c2
-rw-r--r--drivers/acpi/resources/rsio.c2
-rw-r--r--drivers/acpi/resources/rsirq.c2
-rw-r--r--drivers/acpi/resources/rslist.c2
-rw-r--r--drivers/acpi/resources/rsmemory.c2
-rw-r--r--drivers/acpi/resources/rsmisc.c2
-rw-r--r--drivers/acpi/resources/rsutils.c2
-rw-r--r--drivers/acpi/resources/rsxface.c2
-rw-r--r--drivers/acpi/scan.c1265
-rw-r--r--drivers/acpi/sleep/proc.c36
-rw-r--r--drivers/acpi/system.c39
-rw-r--r--drivers/acpi/tables.c508
-rw-r--r--drivers/acpi/tables/Makefile3
-rw-r--r--drivers/acpi/tables/tbconvrt.c622
-rw-r--r--drivers/acpi/tables/tbfadt.c434
-rw-r--r--drivers/acpi/tables/tbfind.c126
-rw-r--r--drivers/acpi/tables/tbget.c471
-rw-r--r--drivers/acpi/tables/tbgetall.c311
-rw-r--r--drivers/acpi/tables/tbinstal.c664
-rw-r--r--drivers/acpi/tables/tbrsdt.c307
-rw-r--r--drivers/acpi/tables/tbutils.c513
-rw-r--r--drivers/acpi/tables/tbxface.c671
-rw-r--r--drivers/acpi/tables/tbxfroot.c552
-rw-r--r--drivers/acpi/thermal.c4
-rw-r--r--drivers/acpi/utilities/utalloc.c11
-rw-r--r--drivers/acpi/utilities/utcache.c10
-rw-r--r--drivers/acpi/utilities/utcopy.c11
-rw-r--r--drivers/acpi/utilities/utdebug.c7
-rw-r--r--drivers/acpi/utilities/utdelete.c16
-rw-r--r--drivers/acpi/utilities/uteval.c2
-rw-r--r--drivers/acpi/utilities/utglobal.c199
-rw-r--r--drivers/acpi/utilities/utinit.c114
-rw-r--r--drivers/acpi/utilities/utmath.c2
-rw-r--r--drivers/acpi/utilities/utmisc.c102
-rw-r--r--drivers/acpi/utilities/utmutex.c2
-rw-r--r--drivers/acpi/utilities/utobject.c2
-rw-r--r--drivers/acpi/utilities/utresrc.c2
-rw-r--r--drivers/acpi/utilities/utstate.c2
-rw-r--r--drivers/acpi/utilities/utxface.c29
-rw-r--r--drivers/acpi/video.c166
-rw-r--r--drivers/ata/ahci.c2
-rw-r--r--drivers/ata/sata_svw.c6
-rw-r--r--drivers/base/class.c21
-rw-r--r--drivers/base/core.c203
-rw-r--r--drivers/base/dd.c21
-rw-r--r--drivers/base/firmware_class.c2
-rw-r--r--drivers/base/platform.c11
-rw-r--r--drivers/char/Kconfig7
-rw-r--r--drivers/char/Makefile3
-rw-r--r--drivers/char/apm-emulation.c672
-rw-r--r--drivers/char/drm/drmP.h36
-rw-r--r--drivers/char/drm/drm_bufs.c19
-rw-r--r--drivers/char/drm/drm_memory.c94
-rw-r--r--drivers/char/drm/drm_memory.h20
-rw-r--r--drivers/char/drm/drm_memory_debug.h70
-rw-r--r--drivers/char/drm/drm_mm.c183
-rw-r--r--drivers/char/drm/drm_pciids.h4
-rw-r--r--drivers/char/drm/drm_proc.c4
-rw-r--r--drivers/char/drm/drm_sman.c3
-rw-r--r--drivers/char/drm/drm_vm.c16
-rw-r--r--drivers/char/drm/i810_dma.c34
-rw-r--r--drivers/char/drm/i810_drv.h2
-rw-r--r--drivers/char/drm/i830_dma.c32
-rw-r--r--drivers/char/drm/i830_drv.h2
-rw-r--r--drivers/char/drm/via_dma.c9
-rw-r--r--drivers/char/drm/via_dmablit.c2
-rw-r--r--drivers/char/drm/via_drv.h11
-rw-r--r--drivers/char/drm/via_irq.c16
-rw-r--r--drivers/char/drm/via_map.c3
-rw-r--r--drivers/char/drm/via_verifier.c50
-rw-r--r--drivers/char/drm/via_verifier.h1
-rw-r--r--drivers/char/hvc_beat.c134
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c18
-rw-r--r--drivers/char/tpm/tpm_bios.c8
-rw-r--r--drivers/char/watchdog/booke_wdt.c20
-rw-r--r--drivers/char/watchdog/machzwd.c2
-rw-r--r--drivers/crypto/Kconfig2
-rw-r--r--drivers/crypto/geode-aes.c2
-rw-r--r--drivers/firmware/pcdp.c2
-rw-r--r--drivers/hid/Kconfig14
-rw-r--r--drivers/hid/Makefile11
-rw-r--r--drivers/hid/hid-core.c8
-rw-r--r--drivers/hid/hid-debug.c764
-rw-r--r--drivers/hid/hid-input.c35
-rw-r--r--drivers/hwmon/ams/ams-input.c2
-rw-r--r--drivers/i2c/chips/isp1301_omap.c2
-rw-r--r--drivers/ide/Kconfig24
-rw-r--r--drivers/ide/Makefile1
-rw-r--r--drivers/ide/ide-acpi.c697
-rw-r--r--drivers/ide/ide-probe.c3
-rw-r--r--drivers/ide/ide.c36
-rw-r--r--drivers/ide/pci/Makefile4
-rw-r--r--drivers/ide/pci/delkin_cb.c140
-rw-r--r--drivers/ide/pci/hpt366.c1583
-rw-r--r--drivers/ide/pci/it8213.c362
-rw-r--r--drivers/ide/pci/pdc202xx_new.c56
-rw-r--r--drivers/ide/pci/pdc202xx_old.c27
-rw-r--r--drivers/ide/pci/piix.c31
-rw-r--r--drivers/ide/pci/slc90e66.c55
-rw-r--r--drivers/ide/pci/tc86c001.c309
-rw-r--r--drivers/ide/setup-pci.c7
-rw-r--r--drivers/ieee1394/.gitignore1
-rw-r--r--drivers/ieee1394/Kconfig21
-rw-r--r--drivers/ieee1394/Makefile10
-rw-r--r--drivers/ieee1394/csr1212.c15
-rw-r--r--drivers/ieee1394/dv1394.c46
-rw-r--r--drivers/ieee1394/hosts.c13
-rw-r--r--drivers/ieee1394/hosts.h7
-rw-r--r--drivers/ieee1394/ieee1394_core.c23
-rw-r--r--drivers/ieee1394/nodemgr.c63
-rw-r--r--drivers/ieee1394/nodemgr.h3
-rw-r--r--drivers/ieee1394/ohci1394.c17
-rw-r--r--drivers/ieee1394/oui.db7048
-rw-r--r--drivers/ieee1394/oui2c.sh22
-rw-r--r--drivers/ieee1394/raw1394.c48
-rw-r--r--drivers/ieee1394/sbp2.c23
-rw-r--r--drivers/ieee1394/video1394.c8
-rw-r--r--drivers/infiniband/core/addr.c3
-rw-r--r--drivers/infiniband/core/mad.c11
-rw-r--r--drivers/infiniband/core/uverbs_cmd.c2
-rw-r--r--drivers/infiniband/hw/amso1100/c2_cq.c2
-rw-r--r--drivers/infiniband/hw/ehca/ehca_classes.h29
-rw-r--r--drivers/infiniband/hw/ehca/ehca_cq.c65
-rw-r--r--drivers/infiniband/hw/ehca/ehca_iverbs.h8
-rw-r--r--drivers/infiniband/hw/ehca/ehca_main.c6
-rw-r--r--drivers/infiniband/hw/ehca/ehca_qp.c78
-rw-r--r--drivers/infiniband/hw/ehca/ehca_reqs.c2
-rw-r--r--drivers/infiniband/hw/ehca/ehca_uverbs.c395
-rw-r--r--drivers/infiniband/hw/ipath/ipath_qp.c2
-rw-r--r--drivers/infiniband/hw/ipath/ipath_rc.c8
-rw-r--r--drivers/infiniband/hw/ipath/ipath_ruc.c8
-rw-r--r--drivers/infiniband/hw/ipath/ipath_uc.c4
-rw-r--r--drivers/infiniband/hw/ipath/ipath_ud.c8
-rw-r--r--drivers/infiniband/hw/mthca/mthca_cmd.c2
-rw-r--r--drivers/infiniband/hw/mthca/mthca_cq.c2
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c33
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_vlan.c11
-rw-r--r--drivers/infiniband/ulp/iser/iser_initiator.c4
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c7
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.h1
-rw-r--r--drivers/input/serio/serio.c6
-rw-r--r--drivers/input/touchscreen/ucb1400_ts.c2
-rw-r--r--drivers/kvm/kvm_main.c63
-rw-r--r--drivers/kvm/mmu.c2
-rw-r--r--drivers/kvm/svm.c8
-rw-r--r--drivers/kvm/vmx.c2
-rw-r--r--drivers/macintosh/Kconfig2
-rw-r--r--drivers/macintosh/rack-meter.c6
-rw-r--r--drivers/macintosh/windfarm_core.c6
-rw-r--r--drivers/md/bitmap.c22
-rw-r--r--drivers/md/raid5.c42
-rw-r--r--drivers/media/common/ir-keymaps.c1
-rw-r--r--drivers/media/video/usbvision/usbvision-video.c2
-rw-r--r--drivers/media/video/zc0301/zc0301_sensor.h1
-rw-r--r--drivers/misc/Kconfig21
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/asus-laptop.c1165
-rw-r--r--drivers/misc/lkdtm.c4
-rw-r--r--drivers/misc/tifm_7xx1.c402
-rw-r--r--drivers/misc/tifm_core.c65
-rw-r--r--drivers/mmc/Kconfig2
-rw-r--r--drivers/mmc/at91_mci.c3
-rw-r--r--drivers/mmc/au1xmmc.c13
-rw-r--r--drivers/mmc/imxmmc.c4
-rw-r--r--drivers/mmc/mmc.c182
-rw-r--r--drivers/mmc/mmc_block.c15
-rw-r--r--drivers/mmc/mmc_queue.c2
-rw-r--r--drivers/mmc/mmc_sysfs.c2
-rw-r--r--drivers/mmc/mmci.c15
-rw-r--r--drivers/mmc/omap.c6
-rw-r--r--drivers/mmc/pxamci.c10
-rw-r--r--drivers/mmc/sdhci.c91
-rw-r--r--drivers/mmc/sdhci.h2
-rw-r--r--drivers/mmc/tifm_sd.c487
-rw-r--r--drivers/mmc/wbsd.c102
-rw-r--r--drivers/mmc/wbsd.h1
-rw-r--r--drivers/net/3c503.c3
-rw-r--r--drivers/net/3c59x.c3
-rw-r--r--drivers/net/Kconfig108
-rw-r--r--drivers/net/Makefile7
-rw-r--r--drivers/net/Space.c4
-rw-r--r--drivers/net/ac3200.c3
-rw-r--r--drivers/net/amd8111e.c3
-rw-r--r--drivers/net/arm/at91_ether.c2
-rw-r--r--drivers/net/arm/etherh.c2
-rw-r--r--drivers/net/atl1/Makefile2
-rw-r--r--drivers/net/atl1/atl1.h283
-rw-r--r--drivers/net/atl1/atl1_ethtool.c508
-rw-r--r--drivers/net/atl1/atl1_hw.c718
-rw-r--r--drivers/net/atl1/atl1_hw.h951
-rw-r--r--drivers/net/atl1/atl1_main.c2468
-rw-r--r--drivers/net/atl1/atl1_param.c206
-rw-r--r--drivers/net/b44.c8
-rw-r--r--drivers/net/b44.h10
-rw-r--r--drivers/net/bmac.c20
-rw-r--r--drivers/net/bnx2.c16
-rw-r--r--drivers/net/bonding/bond_alb.c4
-rw-r--r--drivers/net/bonding/bond_main.c27
-rw-r--r--drivers/net/bonding/bond_sysfs.c302
-rw-r--r--drivers/net/bonding/bonding.h9
-rw-r--r--drivers/net/chelsio/common.h2
-rw-r--r--drivers/net/chelsio/cpl5_cmd.h18
-rw-r--r--drivers/net/chelsio/cxgb2.c149
-rw-r--r--drivers/net/chelsio/elmer0.h40
-rw-r--r--drivers/net/chelsio/espi.c44
-rw-r--r--drivers/net/chelsio/fpga_defs.h6
-rw-r--r--drivers/net/chelsio/gmac.h11
-rw-r--r--drivers/net/chelsio/ixf1010.c100
-rw-r--r--drivers/net/chelsio/mv88e1xxx.c27
-rw-r--r--drivers/net/chelsio/my3126.c16
-rw-r--r--drivers/net/chelsio/pm3393.c91
-rw-r--r--drivers/net/chelsio/sge.c328
-rw-r--r--drivers/net/chelsio/subr.c89
-rw-r--r--drivers/net/chelsio/tp.c62
-rw-r--r--drivers/net/chelsio/vsc7326.c139
-rw-r--r--drivers/net/chelsio/vsc7326_reg.h139
-rw-r--r--drivers/net/chelsio/vsc8244.c41
-rw-r--r--drivers/net/cxgb3/Makefile8
-rw-r--r--drivers/net/cxgb3/adapter.h279
-rw-r--r--drivers/net/cxgb3/ael1002.c251
-rw-r--r--drivers/net/cxgb3/common.h729
-rw-r--r--drivers/net/cxgb3/cxgb3_ctl_defs.h164
-rw-r--r--drivers/net/cxgb3/cxgb3_defs.h99
-rw-r--r--drivers/net/cxgb3/cxgb3_ioctl.h185
-rw-r--r--drivers/net/cxgb3/cxgb3_main.c2519
-rw-r--r--drivers/net/cxgb3/cxgb3_offload.c1222
-rw-r--r--drivers/net/cxgb3/cxgb3_offload.h193
-rw-r--r--drivers/net/cxgb3/firmware_exports.h177
-rw-r--r--drivers/net/cxgb3/l2t.c450
-rw-r--r--drivers/net/cxgb3/l2t.h143
-rw-r--r--drivers/net/cxgb3/mc5.c473
-rw-r--r--drivers/net/cxgb3/regs.h2195
-rw-r--r--drivers/net/cxgb3/sge.c2681
-rw-r--r--drivers/net/cxgb3/sge_defs.h251
-rw-r--r--drivers/net/cxgb3/t3_cpl.h1444
-rw-r--r--drivers/net/cxgb3/t3_hw.c3375
-rw-r--r--drivers/net/cxgb3/t3cdev.h73
-rw-r--r--drivers/net/cxgb3/version.h39
-rw-r--r--drivers/net/cxgb3/vsc8211.c228
-rw-r--r--drivers/net/cxgb3/xgmac.c409
-rw-r--r--drivers/net/declance.c164
-rw-r--r--drivers/net/defxx.c928
-rw-r--r--drivers/net/defxx.h58
-rw-r--r--drivers/net/e1000/e1000.h7
-rw-r--r--drivers/net/e1000/e1000_ethtool.c6
-rw-r--r--drivers/net/e1000/e1000_main.c130
-rw-r--r--drivers/net/e1000/e1000_osdep.h4
-rw-r--r--drivers/net/e1000/e1000_param.c15
-rw-r--r--drivers/net/e2100.c3
-rw-r--r--drivers/net/ehea/ehea.h2
-rw-r--r--drivers/net/ehea/ehea_main.c8
-rw-r--r--drivers/net/ehea/ehea_phyp.c10
-rw-r--r--drivers/net/ehea/ehea_phyp.h3
-rw-r--r--drivers/net/ehea/ehea_qmr.c42
-rw-r--r--drivers/net/ehea/ehea_qmr.h5
-rw-r--r--drivers/net/es3210.c2
-rw-r--r--drivers/net/forcedeth.c1342
-rw-r--r--drivers/net/fs_enet/fs_enet.h1
-rw-r--r--drivers/net/gianfar_ethtool.c2
-rw-r--r--drivers/net/hp100.c2
-rw-r--r--drivers/net/iseries_veth.c2
-rw-r--r--drivers/net/ixgb/ixgb.h2
-rw-r--r--drivers/net/ixgb/ixgb_ethtool.c6
-rw-r--r--drivers/net/ixgb/ixgb_main.c6
-rw-r--r--drivers/net/macb.c61
-rw-r--r--drivers/net/macb.h8
-rw-r--r--drivers/net/mace.c16
-rw-r--r--drivers/net/macmace.c18
-rw-r--r--drivers/net/macsonic.c7
-rw-r--r--drivers/net/mv643xx_eth.c1
-rw-r--r--drivers/net/myri10ge/myri10ge.c10
-rw-r--r--drivers/net/netxen/netxen_nic.h18
-rw-r--r--drivers/net/netxen/netxen_nic_ethtool.c105
-rw-r--r--drivers/net/netxen/netxen_nic_hw.c2
-rw-r--r--drivers/net/netxen/netxen_nic_init.c291
-rw-r--r--drivers/net/netxen/netxen_nic_main.c3
-rw-r--r--drivers/net/netxen/netxen_nic_niu.c2
-rw-r--r--drivers/net/oaknet.c666
-rw-r--r--drivers/net/pasemi_mac.c1019
-rw-r--r--drivers/net/pasemi_mac.h460
-rwxr-xr-x[-rw-r--r--]drivers/net/qla3xxx.c363
-rwxr-xr-x[-rw-r--r--]drivers/net/qla3xxx.h88
-rw-r--r--drivers/net/r8169.c4
-rw-r--r--drivers/net/s2io-regs.h7
-rw-r--r--drivers/net/s2io.c1180
-rw-r--r--drivers/net/s2io.h227
-rw-r--r--drivers/net/sc92031.c1620
-rw-r--r--drivers/net/sk_mca.c1216
-rw-r--r--drivers/net/sk_mca.h170
-rw-r--r--drivers/net/skfp/can.c83
-rw-r--r--drivers/net/skfp/drvfbi.c24
-rw-r--r--drivers/net/skfp/fplustm.c4
-rw-r--r--drivers/net/skfp/smt.c10
-rw-r--r--drivers/net/skge.c235
-rw-r--r--drivers/net/skge.h2
-rw-r--r--drivers/net/sky2.c543
-rw-r--r--drivers/net/sky2.h85
-rw-r--r--drivers/net/slip.c5
-rw-r--r--drivers/net/smc-mca.c3
-rw-r--r--drivers/net/smc-ultra.c3
-rw-r--r--drivers/net/smc-ultra32.c3
-rw-r--r--drivers/net/smc911x.c2
-rw-r--r--drivers/net/smc91x.c2
-rw-r--r--drivers/net/spider_net.c315
-rw-r--r--drivers/net/spider_net.h20
-rw-r--r--drivers/net/spider_net_ethtool.c4
-rw-r--r--drivers/net/tg3.c34
-rw-r--r--drivers/net/ucc_geth.c102
-rw-r--r--drivers/net/ucc_geth_phy.c2
-rw-r--r--drivers/net/wan/Kconfig24
-rw-r--r--drivers/net/wan/Makefile1
-rw-r--r--drivers/net/wan/hdlc.c3
-rw-r--r--drivers/net/wan/pc300too.c565
-rw-r--r--drivers/net/wan/z85230.c14
-rw-r--r--drivers/net/wd.c2
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx.h7
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_leds.c11
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.c36
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_radio.c2
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_radio.h16
-rw-r--r--drivers/net/wireless/hostap/hostap_main.c2
-rw-r--r--drivers/net/wireless/ipw2200.c4
-rw-r--r--drivers/net/wireless/orinoco.c6
-rw-r--r--drivers/net/wireless/orinoco_cs.c2
-rw-r--r--drivers/net/wireless/prism54/islpci_dev.c13
-rw-r--r--drivers/net/wireless/prism54/islpci_dev.h4
-rw-r--r--drivers/net/wireless/prism54/islpci_hotplug.c3
-rw-r--r--drivers/net/wireless/spectrum_cs.c2
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.c126
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.h158
-rw-r--r--drivers/net/wireless/zd1211rw/zd_def.h2
-rw-r--r--drivers/net/wireless/zd1211rw/zd_ieee80211.h1
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf.h2
-rw-r--r--drivers/net/wireless/zd1211rw/zd_types.h71
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c128
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.h6
-rw-r--r--drivers/pci/hotplug/Kconfig9
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c10
-rw-r--r--drivers/pci/hotplug/pciehp.h194
-rw-r--r--drivers/pci/hotplug/pciehp_core.c292
-rw-r--r--drivers/pci/hotplug/pciehp_ctrl.c223
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c827
-rw-r--r--drivers/pci/hotplug/sgi_hotplug.c155
-rw-r--r--drivers/pci/hotplug/shpchp.h4
-rw-r--r--drivers/pci/hotplug/shpchp_core.c4
-rw-r--r--drivers/pci/hotplug/shpchp_ctrl.c20
-rw-r--r--drivers/pci/hotplug/shpchp_hpc.c185
-rw-r--r--drivers/pci/msi.c325
-rw-r--r--drivers/pci/pci-driver.c7
-rw-r--r--drivers/pci/pci.c171
-rw-r--r--drivers/pci/pci.h14
-rw-r--r--drivers/pci/probe.c70
-rw-r--r--drivers/pci/quirks.c131
-rw-r--r--drivers/pci/search.c38
-rw-r--r--drivers/pcmcia/cs.c34
-rw-r--r--drivers/pcmcia/cs_internal.h4
-rw-r--r--drivers/pcmcia/ds.c14
-rw-r--r--drivers/pcmcia/i82092.c2
-rw-r--r--drivers/pcmcia/i82365.c2
-rw-r--r--drivers/pcmcia/m32r_pcc.c2
-rw-r--r--drivers/pcmcia/pcmcia_ioctl.c1
-rw-r--r--drivers/pcmcia/pcmcia_resource.c1
-rw-r--r--drivers/pcmcia/pd6729.c2
-rw-r--r--drivers/pcmcia/rsrc_nonstatic.c56
-rw-r--r--drivers/pcmcia/soc_common.c6
-rw-r--r--drivers/pcmcia/socket_sysfs.c104
-rw-r--r--drivers/pcmcia/tcic.c2
-rw-r--r--drivers/pcmcia/yenta_socket.c2
-rw-r--r--drivers/pnp/pnpacpi/Kconfig4
-rw-r--r--drivers/pnp/system.c52
-rw-r--r--drivers/ps3/Makefile1
-rw-r--r--drivers/ps3/system-bus.c362
-rw-r--r--drivers/ps3/vuart.c4
-rw-r--r--drivers/ps3/vuart.h38
-rw-r--r--drivers/rtc/rtc-dev.c2
-rw-r--r--drivers/rtc/rtc-pcf8563.c40
-rw-r--r--drivers/s390/Kconfig8
-rw-r--r--drivers/s390/Makefile2
-rw-r--r--drivers/s390/block/dasd.c33
-rw-r--r--drivers/s390/block/dasd_3990_erp.c5
-rw-r--r--drivers/s390/block/dasd_devmap.c6
-rw-r--r--drivers/s390/block/dasd_diag.c8
-rw-r--r--drivers/s390/block/dasd_eckd.c95
-rw-r--r--drivers/s390/block/dasd_eer.c24
-rw-r--r--drivers/s390/block/dasd_erp.c80
-rw-r--r--drivers/s390/block/dasd_fba.c4
-rw-r--r--drivers/s390/block/dasd_genhd.c2
-rw-r--r--drivers/s390/block/dasd_int.h1
-rw-r--r--drivers/s390/block/dasd_proc.c8
-rw-r--r--drivers/s390/block/dcssblk.c6
-rw-r--r--drivers/s390/char/Makefile4
-rw-r--r--drivers/s390/char/con3215.c2
-rw-r--r--drivers/s390/char/con3270.c3
-rw-r--r--drivers/s390/char/defkeymap.c2
-rw-r--r--drivers/s390/char/fs3270.c4
-rw-r--r--drivers/s390/char/keyboard.c2
-rw-r--r--drivers/s390/char/monreader.c218
-rw-r--r--drivers/s390/char/monwriter.c4
-rw-r--r--drivers/s390/char/raw3270.c4
-rw-r--r--drivers/s390/char/sclp.c93
-rw-r--r--drivers/s390/char/sclp.h18
-rw-r--r--drivers/s390/char/sclp_con.c2
-rw-r--r--drivers/s390/char/sclp_cpi.c2
-rw-r--r--drivers/s390/char/sclp_info.c57
-rw-r--r--drivers/s390/char/sclp_rw.c2
-rw-r--r--drivers/s390/char/sclp_tty.c2
-rw-r--r--drivers/s390/char/sclp_vt220.c4
-rw-r--r--drivers/s390/char/tape.h22
-rw-r--r--drivers/s390/char/tape_3590.c479
-rw-r--r--drivers/s390/char/tape_3590.h53
-rw-r--r--drivers/s390/char/tape_block.c4
-rw-r--r--drivers/s390/char/tape_char.c27
-rw-r--r--drivers/s390/char/tape_core.c69
-rw-r--r--drivers/s390/char/tty3270.c13
-rw-r--r--drivers/s390/char/vmlogrdr.c284
-rw-r--r--drivers/s390/cio/blacklist.c10
-rw-r--r--drivers/s390/cio/ccwgroup.c6
-rw-r--r--drivers/s390/cio/chsc.c270
-rw-r--r--drivers/s390/cio/chsc.h11
-rw-r--r--drivers/s390/cio/cio.c37
-rw-r--r--drivers/s390/cio/cmf.c4
-rw-r--r--drivers/s390/cio/css.c13
-rw-r--r--drivers/s390/cio/css.h2
-rw-r--r--drivers/s390/cio/device.c12
-rw-r--r--drivers/s390/cio/device.h2
-rw-r--r--drivers/s390/cio/device_fsm.c8
-rw-r--r--drivers/s390/cio/device_ops.c2
-rw-r--r--drivers/s390/cio/device_status.c8
-rw-r--r--drivers/s390/cio/qdio.c77
-rw-r--r--drivers/s390/crypto/ap_bus.c8
-rw-r--r--drivers/s390/crypto/zcrypt_api.c20
-rw-r--r--drivers/s390/crypto/zcrypt_pcica.c8
-rw-r--r--drivers/s390/crypto/zcrypt_pcixcc.c3
-rw-r--r--drivers/s390/net/Kconfig7
-rw-r--r--drivers/s390/net/Makefile1
-rw-r--r--drivers/s390/net/claw.c16
-rw-r--r--drivers/s390/net/ctcmain.c8
-rw-r--r--drivers/s390/net/cu3088.c2
-rw-r--r--drivers/s390/net/iucv.c2540
-rw-r--r--drivers/s390/net/iucv.h849
-rw-r--r--drivers/s390/net/lcs.c6
-rw-r--r--drivers/s390/net/netiucv.c1318
-rw-r--r--drivers/s390/net/qeth_eddp.c28
-rw-r--r--drivers/s390/net/qeth_main.c92
-rw-r--r--drivers/s390/net/qeth_sys.c30
-rw-r--r--drivers/s390/net/smsgiucv.c147
-rw-r--r--drivers/s390/s390mach.c37
-rw-r--r--drivers/s390/s390mach.h3
-rw-r--r--drivers/s390/scsi/zfcp_aux.c25
-rw-r--r--drivers/s390/scsi/zfcp_dbf.c44
-rw-r--r--drivers/s390/scsi/zfcp_erp.c7
-rw-r--r--drivers/s390/scsi/zfcp_ext.h4
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c2
-rw-r--r--drivers/s390/scsi/zfcp_qdio.c38
-rw-r--r--drivers/s390/scsi/zfcp_scsi.c18
-rw-r--r--drivers/s390/sysinfo.c63
-rw-r--r--drivers/scsi/NCR53C9x.c8
-rw-r--r--drivers/scsi/NCR53C9x.h2
-rw-r--r--drivers/scsi/blz1230.c3
-rw-r--r--drivers/scsi/blz2060.c2
-rw-r--r--drivers/scsi/cyberstorm.c2
-rw-r--r--drivers/scsi/cyberstormII.c2
-rw-r--r--drivers/scsi/dec_esp.c355
-rw-r--r--drivers/scsi/fastlane.c2
-rw-r--r--drivers/scsi/ipr.c3
-rw-r--r--drivers/scsi/iscsi_tcp.c2
-rw-r--r--drivers/scsi/jazz_esp.c2
-rw-r--r--drivers/scsi/libiscsi.c40
-rw-r--r--drivers/scsi/mac_esp.c2
-rw-r--r--drivers/scsi/mca_53c9x.c2
-rw-r--r--drivers/scsi/oktagon_esp.c2
-rw-r--r--drivers/scsi/osst.c8
-rw-r--r--drivers/scsi/osst.h68
-rw-r--r--drivers/scsi/sun3x_esp.c2
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_cpm1.c15
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_cpm1.h3
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_cpm2.h3
-rw-r--r--drivers/serial/uartlite.c6
-rw-r--r--drivers/tc/Makefile2
-rw-r--r--drivers/tc/tc-driver.c110
-rw-r--r--drivers/tc/tc.c339
-rw-r--r--drivers/usb/atm/speedtch.c2
-rw-r--r--drivers/usb/class/usblp.c16
-rw-r--r--drivers/usb/core/Kconfig13
-rw-r--r--drivers/usb/core/buffer.c36
-rw-r--r--drivers/usb/core/devices.c22
-rw-r--r--drivers/usb/core/devio.c25
-rw-r--r--drivers/usb/core/driver.c39
-rw-r--r--drivers/usb/core/file.c13
-rw-r--r--drivers/usb/core/generic.c28
-rw-r--r--drivers/usb/core/hcd.c137
-rw-r--r--drivers/usb/core/hcd.h6
-rw-r--r--drivers/usb/core/hub.c64
-rw-r--r--drivers/usb/core/message.c6
-rw-r--r--drivers/usb/core/sysfs.c98
-rw-r--r--drivers/usb/core/urb.c21
-rw-r--r--drivers/usb/core/usb.c96
-rw-r--r--drivers/usb/gadget/at91_udc.c21
-rw-r--r--drivers/usb/gadget/at91_udc.h1
-rw-r--r--drivers/usb/gadget/config.c2
-rw-r--r--drivers/usb/gadget/epautoconf.c2
-rw-r--r--drivers/usb/gadget/ether.c148
-rw-r--r--drivers/usb/gadget/file_storage.c33
-rw-r--r--drivers/usb/gadget/gadget_chips.h8
-rw-r--r--drivers/usb/gadget/gmidi.c2
-rw-r--r--drivers/usb/gadget/goku_udc.c2
-rw-r--r--drivers/usb/gadget/inode.c240
-rw-r--r--drivers/usb/gadget/lh7a40x_udc.h2
-rw-r--r--drivers/usb/gadget/net2280.c2
-rw-r--r--drivers/usb/gadget/omap_udc.c2
-rw-r--r--drivers/usb/gadget/pxa2xx_udc.c2
-rw-r--r--drivers/usb/gadget/serial.c2
-rw-r--r--drivers/usb/gadget/usbstring.c2
-rw-r--r--drivers/usb/gadget/zero.c2
-rw-r--r--drivers/usb/host/Kconfig38
-rw-r--r--drivers/usb/host/ehci-dbg.c24
-rw-r--r--drivers/usb/host/ehci-fsl.c8
-rw-r--r--drivers/usb/host/ehci-hcd.c127
-rw-r--r--drivers/usb/host/ehci-hub.c324
-rw-r--r--drivers/usb/host/ehci-pci.c38
-rw-r--r--drivers/usb/host/ehci-ps3.c193
-rw-r--r--drivers/usb/host/ehci-q.c16
-rw-r--r--drivers/usb/host/ehci-sched.c22
-rw-r--r--drivers/usb/host/ehci.h46
-rw-r--r--drivers/usb/host/ohci-at91.c23
-rw-r--r--drivers/usb/host/ohci-au1xxx.c16
-rw-r--r--drivers/usb/host/ohci-ep93xx.c12
-rw-r--r--drivers/usb/host/ohci-hcd.c128
-rw-r--r--drivers/usb/host/ohci-lh7a404.c16
-rw-r--r--drivers/usb/host/ohci-omap.c19
-rw-r--r--drivers/usb/host/ohci-pci.c219
-rw-r--r--drivers/usb/host/ohci-pnx4008.c12
-rw-r--r--drivers/usb/host/ohci-pnx8550.c16
-rw-r--r--drivers/usb/host/ohci-ppc-of.c232
-rw-r--r--drivers/usb/host/ohci-ppc-soc.c18
-rw-r--r--drivers/usb/host/ohci-ps3.c196
-rw-r--r--drivers/usb/host/ohci-pxa27x.c16
-rw-r--r--drivers/usb/host/ohci-s3c2410.c12
-rw-r--r--drivers/usb/host/ohci-sa1111.c16
-rw-r--r--drivers/usb/host/ohci.h155
-rw-r--r--drivers/usb/host/uhci-debug.c71
-rw-r--r--drivers/usb/host/uhci-hcd.c51
-rw-r--r--drivers/usb/host/uhci-hcd.h8
-rw-r--r--drivers/usb/host/uhci-q.c258
-rw-r--r--drivers/usb/image/mdc800.c4
-rw-r--r--drivers/usb/input/Kconfig20
-rw-r--r--drivers/usb/input/Makefile4
-rw-r--r--drivers/usb/input/gtco.c1104
-rw-r--r--drivers/usb/input/hid-core.c116
-rw-r--r--drivers/usb/input/hid-ff.c3
-rw-r--r--drivers/usb/input/hid-lgff.c4
-rw-r--r--drivers/usb/input/hid-plff.c129
-rw-r--r--drivers/usb/misc/idmouse.c10
-rw-r--r--drivers/usb/misc/rio500.c54
-rw-r--r--drivers/usb/mon/Makefile2
-rw-r--r--drivers/usb/mon/mon_bin.c1172
-rw-r--r--drivers/usb/mon/mon_dma.c39
-rw-r--r--drivers/usb/mon/mon_main.c97
-rw-r--r--drivers/usb/mon/mon_text.c67
-rw-r--r--drivers/usb/mon/usb_mon.h30
-rw-r--r--drivers/usb/net/Kconfig6
-rw-r--r--drivers/usb/net/asix.c4
-rw-r--r--drivers/usb/net/cdc_ether.c60
-rw-r--r--drivers/usb/net/gl620a.c26
-rw-r--r--drivers/usb/net/kaweth.c37
-rw-r--r--drivers/usb/net/pegasus.h4
-rw-r--r--drivers/usb/net/rndis_host.c81
-rw-r--r--drivers/usb/serial/aircable.c21
-rw-r--r--drivers/usb/serial/airprime.c1
-rw-r--r--drivers/usb/serial/ark3116.c2
-rw-r--r--drivers/usb/serial/belkin_sa.c1
-rw-r--r--drivers/usb/serial/bus.c45
-rw-r--r--drivers/usb/serial/cp2101.c9
-rw-r--r--drivers/usb/serial/cyberjack.c3
-rw-r--r--drivers/usb/serial/cypress_m8.c3
-rw-r--r--drivers/usb/serial/digi_acceleport.c2
-rw-r--r--drivers/usb/serial/empeg.c1
-rw-r--r--drivers/usb/serial/ftdi_sio.c2
-rw-r--r--drivers/usb/serial/ftdi_sio.h1
-rw-r--r--drivers/usb/serial/funsoft.c1
-rw-r--r--drivers/usb/serial/garmin_gps.c1
-rw-r--r--drivers/usb/serial/generic.c35
-rw-r--r--drivers/usb/serial/hp4x.c1
-rw-r--r--drivers/usb/serial/io_edgeport.c417
-rw-r--r--drivers/usb/serial/io_edgeport.h6
-rw-r--r--drivers/usb/serial/io_tables.h61
-rw-r--r--drivers/usb/serial/io_ti.c2
-rw-r--r--drivers/usb/serial/io_usbvend.h5
-rw-r--r--drivers/usb/serial/ipaq.c1
-rw-r--r--drivers/usb/serial/ipw.c1
-rw-r--r--drivers/usb/serial/ir-usb.c1
-rw-r--r--drivers/usb/serial/keyspan.c49
-rw-r--r--drivers/usb/serial/keyspan.h7
-rw-r--r--drivers/usb/serial/keyspan_pda.c3
-rw-r--r--drivers/usb/serial/kl5kusb105.c1
-rw-r--r--drivers/usb/serial/kobil_sct.c1
-rw-r--r--drivers/usb/serial/mct_u232.c1
-rw-r--r--drivers/usb/serial/mos7720.c16
-rw-r--r--drivers/usb/serial/mos7840.c16
-rw-r--r--drivers/usb/serial/navman.c1
-rw-r--r--drivers/usb/serial/omninet.c1
-rw-r--r--drivers/usb/serial/option.c1
-rw-r--r--drivers/usb/serial/pl2303.c1
-rw-r--r--drivers/usb/serial/safe_serial.c1
-rw-r--r--drivers/usb/serial/sierra.c29
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c2
-rw-r--r--drivers/usb/serial/usb-serial.c102
-rw-r--r--drivers/usb/serial/visor.c6
-rw-r--r--drivers/usb/serial/visor.h1
-rw-r--r--drivers/usb/serial/whiteheat.c2
-rw-r--r--drivers/usb/storage/onetouch.c1
-rw-r--r--drivers/usb/storage/scsiglue.c31
-rw-r--r--drivers/usb/storage/unusual_devs.h9
-rw-r--r--drivers/usb/storage/usb.c23
-rw-r--r--drivers/video/Kconfig8
-rw-r--r--drivers/video/output.c129
-rw-r--r--drivers/video/pmag-ba-fb.c95
-rw-r--r--drivers/video/pmagb-b-fb.c98
720 files changed, 54644 insertions, 31760 deletions
diff --git a/drivers/Makefile b/drivers/Makefile
index 0dd96d1afd3..f28dcb4ec8b 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -30,7 +30,7 @@ obj-$(CONFIG_PARPORT) += parport/
obj-y += base/ block/ misc/ mfd/ net/ media/
obj-$(CONFIG_NUBUS) += nubus/
obj-$(CONFIG_ATM) += atm/
-obj-$(CONFIG_PPC_PMAC) += macintosh/
+obj-y += macintosh/
obj-$(CONFIG_IDE) += ide/
obj-$(CONFIG_FC4) += fc4/
obj-$(CONFIG_SCSI) += scsi/
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index f4f000abc4e..20eacc2c9e0 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -3,6 +3,7 @@
#
menu "ACPI (Advanced Configuration and Power Interface) Support"
+ depends on !X86_NUMAQ
depends on !X86_VISWS
depends on !IA64_HP_SIM
depends on IA64 || X86
@@ -77,6 +78,20 @@ config ACPI_SLEEP_PROC_SLEEP
Create /proc/acpi/sleep
Deprecated by /sys/power/state
+config ACPI_PROCFS
+ bool "Procfs interface (deprecated)"
+ depends on ACPI
+ default y
+ ---help---
+ Procfs interface for ACPI is made optional for back-compatible.
+ As the same functions are duplicated in sysfs interface
+ and this proc interface will be removed some time later,
+ it's marked as deprecated.
+ ( /proc/acpi/debug_layer && debug_level are deprecated by
+ /sys/module/acpi/parameters/debug_layer && debug_level.
+ /proc/acpi/info is deprecated by
+ /sys/module/acpi/parameters/acpica_version )
+
config ACPI_AC
tristate "AC Adapter"
depends on X86
@@ -107,7 +122,7 @@ config ACPI_BUTTON
config ACPI_VIDEO
tristate "Video"
- depends on X86
+ depends on X86 && BACKLIGHT_CLASS_DEVICE
help
This driver implement the ACPI Extensions For Display Adapters
for integrated graphics devices on motherboard, as specified in
@@ -139,6 +154,13 @@ config ACPI_DOCK
help
This driver adds support for ACPI controlled docking stations
+config ACPI_BAY
+ tristate "Removable Drive Bay (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ help
+ This driver adds support for ACPI controlled removable drive
+ bays such as the IBM ultrabay or the Dell Module Bay.
+
config ACPI_PROCESSOR
tristate "Processor"
default y
@@ -186,19 +208,22 @@ config ACPI_ASUS
Note: display switching code is currently considered EXPERIMENTAL,
toying with these values may even lock your machine.
-
+
All settings are changed via /proc/acpi/asus directory entries. Owner
and group for these entries can be set with asus_uid and asus_gid
parameters.
-
+
More information and a userspace daemon for handling the extra buttons
at <http://sourceforge.net/projects/acpi4asus/>.
-
+
If you have an ACPI-compatible ASUS laptop, say Y or M here. This
driver is still under development, so if your laptop is unsupported or
something works not quite as expected, please use the mailing list
- available on the above page (acpi4asus-user@lists.sourceforge.net)
-
+ available on the above page (acpi4asus-user@lists.sourceforge.net).
+
+ NOTE: This driver is deprecated and will probably be removed soon,
+ use asus-laptop instead.
+
config ACPI_IBM
tristate "IBM ThinkPad Laptop Extras"
depends on X86
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index bce7ca27b42..856c32bccac 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -37,13 +37,15 @@ endif
obj-y += sleep/
obj-y += bus.o glue.o
+obj-y += scan.o
obj-$(CONFIG_ACPI_AC) += ac.o
obj-$(CONFIG_ACPI_BATTERY) += battery.o
obj-$(CONFIG_ACPI_BUTTON) += button.o
obj-$(CONFIG_ACPI_EC) += ec.o
obj-$(CONFIG_ACPI_FAN) += fan.o
obj-$(CONFIG_ACPI_DOCK) += dock.o
-obj-$(CONFIG_ACPI_VIDEO) += video.o
+obj-$(CONFIG_ACPI_BAY) += bay.o
+obj-$(CONFIG_ACPI_VIDEO) += video.o
obj-$(CONFIG_ACPI_HOTKEY) += hotkey.o
obj-y += pci_root.o pci_link.o pci_irq.o pci_bind.o
obj-$(CONFIG_ACPI_POWER) += power.o
@@ -56,7 +58,6 @@ obj-$(CONFIG_ACPI_NUMA) += numa.o
obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o
obj-$(CONFIG_ACPI_IBM) += ibm_acpi.o
obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
-obj-y += scan.o motherboard.o
obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o
obj-y += cm_sbs.o
obj-$(CONFIG_ACPI_SBS) += i2c_ec.o sbs.o
diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c
index 396140bbbe5..31ad70a6e22 100644
--- a/drivers/acpi/asus_acpi.c
+++ b/drivers/acpi/asus_acpi.c
@@ -26,7 +26,7 @@
* Pontus Fuchs - Helper functions, cleanup
* Johann Wiesner - Small compile fixes
* John Belmonte - ACPI code for Toshiba laptop was a good starting point.
- * Éric Burghard - LED display support for W1N
+ * �ic Burghard - LED display support for W1N
*
*/
@@ -1128,7 +1128,6 @@ static int asus_model_match(char *model)
static int asus_hotk_get_info(void)
{
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
- struct acpi_buffer dsdt = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *model = NULL;
int bsts_result;
char *string = NULL;
@@ -1142,11 +1141,9 @@ static int asus_hotk_get_info(void)
* HID), this bit will be moved. A global variable asus_info contains
* the DSDT header.
*/
- status = acpi_get_table(ACPI_TABLE_ID_DSDT, 1, &dsdt);
+ status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus_info);
if (ACPI_FAILURE(status))
printk(KERN_WARNING " Couldn't get the DSDT table header\n");
- else
- asus_info = dsdt.pointer;
/* We have to write 0 on init this far for all ASUS models */
if (!write_acpi_int(hotk->handle, "INIT", 0, &buffer)) {
@@ -1358,8 +1355,6 @@ static void __exit asus_acpi_exit(void)
acpi_bus_unregister_driver(&asus_hotk_driver);
remove_proc_entry(PROC_ASUS, acpi_root_dir);
- kfree(asus_info);
-
return;
}
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 5f43e0d1489..2f4521a48fe 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -64,7 +64,7 @@ extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
static int acpi_battery_add(struct acpi_device *device);
static int acpi_battery_remove(struct acpi_device *device, int type);
-static int acpi_battery_resume(struct acpi_device *device, int status);
+static int acpi_battery_resume(struct acpi_device *device);
static struct acpi_driver acpi_battery_driver = {
.name = ACPI_BATTERY_DRIVER_NAME,
@@ -753,7 +753,7 @@ static int acpi_battery_remove(struct acpi_device *device, int type)
}
/* this is needed to learn about changes made in suspended state */
-static int acpi_battery_resume(struct acpi_device *device, int state)
+static int acpi_battery_resume(struct acpi_device *device)
{
struct acpi_battery *battery;
diff --git a/drivers/acpi/bay.c b/drivers/acpi/bay.c
new file mode 100644
index 00000000000..91082ce6f5d
--- /dev/null
+++ b/drivers/acpi/bay.c
@@ -0,0 +1,490 @@
+/*
+ * bay.c - ACPI removable drive bay driver
+ *
+ * Copyright (C) 2006 Kristen Carlson Accardi <kristen.c.accardi@intel.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/notifier.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+#include <linux/seq_file.h>
+#include <asm/uaccess.h>
+#include <linux/platform_device.h>
+
+#define ACPI_BAY_DRIVER_NAME "ACPI Removable Drive Bay Driver"
+
+ACPI_MODULE_NAME("bay")
+MODULE_AUTHOR("Kristen Carlson Accardi");
+MODULE_DESCRIPTION(ACPI_BAY_DRIVER_NAME);
+MODULE_LICENSE("GPL");
+#define ACPI_BAY_CLASS "bay"
+#define ACPI_BAY_COMPONENT 0x10000000
+#define _COMPONENT ACPI_BAY_COMPONENT
+#define bay_dprintk(h,s) {\
+ char prefix[80] = {'\0'};\
+ struct acpi_buffer buffer = {sizeof(prefix), prefix};\
+ acpi_get_name(h, ACPI_FULL_PATHNAME, &buffer);\
+ printk(KERN_DEBUG PREFIX "%s: %s\n", prefix, s); }
+static void bay_notify(acpi_handle handle, u32 event, void *data);
+static int acpi_bay_add(struct acpi_device *device);
+static int acpi_bay_remove(struct acpi_device *device, int type);
+
+static struct acpi_driver acpi_bay_driver = {
+ .name = ACPI_BAY_DRIVER_NAME,
+ .class = ACPI_BAY_CLASS,
+ .ids = ACPI_BAY_HID,
+ .ops = {
+ .add = acpi_bay_add,
+ .remove = acpi_bay_remove,
+ },
+};
+
+struct bay {
+ acpi_handle handle;
+ char *name;
+ struct list_head list;
+ struct platform_device *pdev;
+};
+
+static LIST_HEAD(drive_bays);
+
+
+/*****************************************************************************
+ * Drive Bay functions *
+ *****************************************************************************/
+/**
+ * is_ejectable - see if a device is ejectable
+ * @handle: acpi handle of the device
+ *
+ * If an acpi object has a _EJ0 method, then it is ejectable
+ */
+static int is_ejectable(acpi_handle handle)
+{
+ acpi_status status;
+ acpi_handle tmp;
+
+ status = acpi_get_handle(handle, "_EJ0", &tmp);
+ if (ACPI_FAILURE(status))
+ return 0;
+ return 1;
+}
+
+/**
+ * bay_present - see if the bay device is present
+ * @bay: the drive bay
+ *
+ * execute the _STA method.
+ */
+static int bay_present(struct bay *bay)
+{
+ unsigned long sta;
+ acpi_status status;
+
+ if (bay) {
+ status = acpi_evaluate_integer(bay->handle, "_STA", NULL, &sta);
+ if (ACPI_SUCCESS(status) && sta)
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * eject_device - respond to an eject request
+ * @handle - the device to eject
+ *
+ * Call this devices _EJ0 method.
+ */
+static void eject_device(acpi_handle handle)
+{
+ struct acpi_object_list arg_list;
+ union acpi_object arg;
+
+ bay_dprintk(handle, "Ejecting device");
+
+ arg_list.count = 1;
+ arg_list.pointer = &arg;
+ arg.type = ACPI_TYPE_INTEGER;
+ arg.integer.value = 1;
+
+ if (ACPI_FAILURE(acpi_evaluate_object(handle, "_EJ0",
+ &arg_list, NULL)))
+ pr_debug("Failed to evaluate _EJ0!\n");
+}
+
+/*
+ * show_present - read method for "present" file in sysfs
+ */
+static ssize_t show_present(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct bay *bay = dev_get_drvdata(dev);
+ return snprintf(buf, PAGE_SIZE, "%d\n", bay_present(bay));
+
+}
+DEVICE_ATTR(present, S_IRUGO, show_present, NULL);
+
+/*
+ * write_eject - write method for "eject" file in sysfs
+ */
+static ssize_t write_eject(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct bay *bay = dev_get_drvdata(dev);
+
+ if (!count)
+ return -EINVAL;
+
+ eject_device(bay->handle);
+ return count;
+}
+DEVICE_ATTR(eject, S_IWUSR, NULL, write_eject);
+
+/**
+ * is_ata - see if a device is an ata device
+ * @handle: acpi handle of the device
+ *
+ * If an acpi object has one of 4 ATA ACPI methods defined,
+ * then it is an ATA device
+ */
+static int is_ata(acpi_handle handle)
+{
+ acpi_handle tmp;
+
+ if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) ||
+ (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) ||
+ (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) ||
+ (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp))))
+ return 1;
+
+ return 0;
+}
+
+/**
+ * parent_is_ata(acpi_handle handle)
+ *
+ */
+static int parent_is_ata(acpi_handle handle)
+{
+ acpi_handle phandle;
+
+ if (acpi_get_parent(handle, &phandle))
+ return 0;
+
+ return is_ata(phandle);
+}
+
+/**
+ * is_ejectable_bay - see if a device is an ejectable drive bay
+ * @handle: acpi handle of the device
+ *
+ * If an acpi object is ejectable and has one of the ACPI ATA
+ * methods defined, then we can safely call it an ejectable
+ * drive bay
+ */
+static int is_ejectable_bay(acpi_handle handle)
+{
+ if ((is_ata(handle) || parent_is_ata(handle)) && is_ejectable(handle))
+ return 1;
+ return 0;
+}
+
+/**
+ * eject_removable_drive - try to eject this drive
+ * @dev : the device structure of the drive
+ *
+ * If a device is a removable drive that requires an _EJ0 method
+ * to be executed in order to safely remove from the system, do
+ * it. ATM - always returns success
+ */
+int eject_removable_drive(struct device *dev)
+{
+ acpi_handle handle = DEVICE_ACPI_HANDLE(dev);
+
+ if (handle) {
+ bay_dprintk(handle, "Got device handle");
+ if (is_ejectable_bay(handle))
+ eject_device(handle);
+ } else {
+ printk("No acpi handle for device\n");
+ }
+
+ /* should I return an error code? */
+ return 0;
+}
+EXPORT_SYMBOL_GPL(eject_removable_drive);
+
+static int acpi_bay_add(struct acpi_device *device)
+{
+ bay_dprintk(device->handle, "adding bay device");
+ strcpy(acpi_device_name(device), "Dockable Bay");
+ strcpy(acpi_device_class(device), "bay");
+ return 0;
+}
+
+static int acpi_bay_add_fs(struct bay *bay)
+{
+ int ret;
+ struct device *dev = &bay->pdev->dev;
+
+ ret = device_create_file(dev, &dev_attr_present);
+ if (ret)
+ goto add_fs_err;
+ ret = device_create_file(dev, &dev_attr_eject);
+ if (ret) {
+ device_remove_file(dev, &dev_attr_present);
+ goto add_fs_err;
+ }
+ return 0;
+
+ add_fs_err:
+ bay_dprintk(bay->handle, "Error adding sysfs files\n");
+ return ret;
+}
+
+static void acpi_bay_remove_fs(struct bay *bay)
+{
+ struct device *dev = &bay->pdev->dev;
+
+ /* cleanup sysfs */
+ device_remove_file(dev, &dev_attr_present);
+ device_remove_file(dev, &dev_attr_eject);
+}
+
+static int bay_is_dock_device(acpi_handle handle)
+{
+ acpi_handle parent;
+
+ acpi_get_parent(handle, &parent);
+
+ /* if the device or it's parent is dependent on the
+ * dock, then we are a dock device
+ */
+ return (is_dock_device(handle) || is_dock_device(parent));
+}
+
+static int bay_add(acpi_handle handle, int id)
+{
+ acpi_status status;
+ struct bay *new_bay;
+ struct platform_device *pdev;
+ struct acpi_buffer nbuffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ acpi_get_name(handle, ACPI_FULL_PATHNAME, &nbuffer);
+
+ bay_dprintk(handle, "Adding notify handler");
+
+ /*
+ * Initialize bay device structure
+ */
+ new_bay = kzalloc(sizeof(*new_bay), GFP_ATOMIC);
+ INIT_LIST_HEAD(&new_bay->list);
+ new_bay->handle = handle;
+ new_bay->name = (char *)nbuffer.pointer;
+
+ /* initialize platform device stuff */
+ pdev = platform_device_register_simple(ACPI_BAY_CLASS, id, NULL, 0);
+ if (pdev == NULL) {
+ printk(KERN_ERR PREFIX "Error registering bay device\n");
+ goto bay_add_err;
+ }
+ new_bay->pdev = pdev;
+ platform_set_drvdata(pdev, new_bay);
+
+ if (acpi_bay_add_fs(new_bay)) {
+ platform_device_unregister(new_bay->pdev);
+ goto bay_add_err;
+ }
+
+ /* register for events on this device */
+ status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+ bay_notify, new_bay);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR PREFIX "Error installing bay notify handler\n");
+ }
+
+ /* if we are on a dock station, we should register for dock
+ * notifications.
+ */
+ if (bay_is_dock_device(handle)) {
+ bay_dprintk(handle, "Is dependent on dock\n");
+ register_hotplug_dock_device(handle, bay_notify, new_bay);
+ }
+ list_add(&new_bay->list, &drive_bays);
+ printk(KERN_INFO PREFIX "Bay [%s] Added\n", new_bay->name);
+ return 0;
+
+bay_add_err:
+ kfree(new_bay->name);
+ kfree(new_bay);
+ return -ENODEV;
+}
+
+static int acpi_bay_remove(struct acpi_device *device, int type)
+{
+ /*** FIXME: do something here */
+ return 0;
+}
+
+/**
+ * bay_create_acpi_device - add new devices to acpi
+ * @handle - handle of the device to add
+ *
+ * This function will create a new acpi_device for the given
+ * handle if one does not exist already. This should cause
+ * acpi to scan for drivers for the given devices, and call
+ * matching driver's add routine.
+ *
+ * Returns a pointer to the acpi_device corresponding to the handle.
+ */
+static struct acpi_device * bay_create_acpi_device(acpi_handle handle)
+{
+ struct acpi_device *device = NULL;
+ struct acpi_device *parent_device;
+ acpi_handle parent;
+ int ret;
+
+ bay_dprintk(handle, "Trying to get device");
+ if (acpi_bus_get_device(handle, &device)) {
+ /*
+ * no device created for this object,
+ * so we should create one.
+ */
+ bay_dprintk(handle, "No device for handle");
+ acpi_get_parent(handle, &parent);
+ if (acpi_bus_get_device(parent, &parent_device))
+ parent_device = NULL;
+
+ ret = acpi_bus_add(&device, parent_device, handle,
+ ACPI_BUS_TYPE_DEVICE);
+ if (ret) {
+ pr_debug("error adding bus, %x\n",
+ -ret);
+ return NULL;
+ }
+ }
+ return device;
+}
+
+/**
+ * bay_notify - act upon an acpi bay notification
+ * @handle: the bay handle
+ * @event: the acpi event
+ * @data: our driver data struct
+ *
+ */
+static void bay_notify(acpi_handle handle, u32 event, void *data)
+{
+ struct acpi_device *dev;
+
+ bay_dprintk(handle, "Bay event");
+
+ switch(event) {
+ case ACPI_NOTIFY_BUS_CHECK:
+ printk("Bus Check\n");
+ case ACPI_NOTIFY_DEVICE_CHECK:
+ printk("Device Check\n");
+ dev = bay_create_acpi_device(handle);
+ if (dev)
+ acpi_bus_generate_event(dev, event, 0);
+ else
+ printk("No device for generating event\n");
+ /* wouldn't it be a good idea to just rescan SATA
+ * right here?
+ */
+ break;
+ case ACPI_NOTIFY_EJECT_REQUEST:
+ printk("Eject request\n");
+ dev = bay_create_acpi_device(handle);
+ if (dev)
+ acpi_bus_generate_event(dev, event, 0);
+ else
+ printk("No device for generating eventn");
+
+ /* wouldn't it be a good idea to just call the
+ * eject_device here if we were a SATA device?
+ */
+ break;
+ default:
+ printk("unknown event %d\n", event);
+ }
+}
+
+static acpi_status
+find_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+ int *count = (int *)context;
+
+ /*
+ * there could be more than one ejectable bay.
+ * so, just return AE_OK always so that every object
+ * will be checked.
+ */
+ if (is_ejectable_bay(handle)) {
+ bay_dprintk(handle, "found ejectable bay");
+ if (!bay_add(handle, *count))
+ (*count)++;
+ }
+ return AE_OK;
+}
+
+static int __init bay_init(void)
+{
+ int bays = 0;
+
+ INIT_LIST_HEAD(&drive_bays);
+
+ /* look for dockable drive bays */
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX, find_bay, &bays, NULL);
+
+ if (bays)
+ if ((acpi_bus_register_driver(&acpi_bay_driver) < 0))
+ printk(KERN_ERR "Unable to register bay driver\n");
+
+ if (!bays)
+ return -ENODEV;
+
+ return 0;
+}
+
+static void __exit bay_exit(void)
+{
+ struct bay *bay, *tmp;
+
+ list_for_each_entry_safe(bay, tmp, &drive_bays, list) {
+ if (is_dock_device(bay->handle))
+ unregister_hotplug_dock_device(bay->handle);
+ acpi_bay_remove_fs(bay);
+ acpi_remove_notify_handler(bay->handle, ACPI_SYSTEM_NOTIFY,
+ bay_notify);
+ platform_device_unregister(bay->pdev);
+ kfree(bay->name);
+ kfree(bay);
+ }
+
+ acpi_bus_unregister_driver(&acpi_bay_driver);
+}
+
+postcore_initcall(bay_init);
+module_exit(bay_exit);
+
diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c
index f9c972b26f4..f289fd41e77 100644
--- a/drivers/acpi/blacklist.c
+++ b/drivers/acpi/blacklist.c
@@ -44,7 +44,7 @@ struct acpi_blacklist_item {
char oem_id[7];
char oem_table_id[9];
u32 oem_revision;
- acpi_table_type table;
+ char *table;
enum acpi_blacklist_predicates oem_revision_predicate;
char *reason;
u32 is_critical_error;
@@ -56,18 +56,18 @@ struct acpi_blacklist_item {
*/
static struct acpi_blacklist_item acpi_blacklist[] __initdata = {
/* Compaq Presario 1700 */
- {"PTLTD ", " DSDT ", 0x06040000, ACPI_DSDT, less_than_or_equal,
+ {"PTLTD ", " DSDT ", 0x06040000, ACPI_SIG_DSDT, less_than_or_equal,
"Multiple problems", 1},
/* Sony FX120, FX140, FX150? */
- {"SONY ", "U0 ", 0x20010313, ACPI_DSDT, less_than_or_equal,
+ {"SONY ", "U0 ", 0x20010313, ACPI_SIG_DSDT, less_than_or_equal,
"ACPI driver problem", 1},
/* Compaq Presario 800, Insyde BIOS */
- {"INT440", "SYSFexxx", 0x00001001, ACPI_DSDT, less_than_or_equal,
+ {"INT440", "SYSFexxx", 0x00001001, ACPI_SIG_DSDT, less_than_or_equal,
"Does not use _REG to protect EC OpRegions", 1},
/* IBM 600E - _ADR should return 7, but it returns 1 */
- {"IBM ", "TP600E ", 0x00000105, ACPI_DSDT, less_than_or_equal,
+ {"IBM ", "TP600E ", 0x00000105, ACPI_SIG_DSDT, less_than_or_equal,
"Incorrect _ADR", 1},
- {"ASUS\0\0", "P2B-S ", 0, ACPI_DSDT, all_versions,
+ {"ASUS\0\0", "P2B-S ", 0, ACPI_SIG_DSDT, all_versions,
"Bogus PCI routing", 1},
{""}
@@ -79,7 +79,7 @@ static int __init blacklist_by_year(void)
{
int year = dmi_get_year(DMI_BIOS_DATE);
/* Doesn't exist? Likely an old system */
- if (year == -1)
+ if (year == -1)
return 1;
/* 0? Likely a buggy new BIOS */
if (year == 0)
@@ -103,22 +103,21 @@ int __init acpi_blacklisted(void)
{
int i = 0;
int blacklisted = 0;
- struct acpi_table_header *table_header;
+ struct acpi_table_header table_header;
while (acpi_blacklist[i].oem_id[0] != '\0') {
- if (acpi_get_table_header_early
- (acpi_blacklist[i].table, &table_header)) {
+ if (acpi_get_table_header(acpi_blacklist[i].table, 0, &table_header)) {
i++;
continue;
}
- if (strncmp(acpi_blacklist[i].oem_id, table_header->oem_id, 6)) {
+ if (strncmp(acpi_blacklist[i].oem_id, table_header.oem_id, 6)) {
i++;
continue;
}
if (strncmp
- (acpi_blacklist[i].oem_table_id, table_header->oem_table_id,
+ (acpi_blacklist[i].oem_table_id, table_header.oem_table_id,
8)) {
i++;
continue;
@@ -127,14 +126,14 @@ int __init acpi_blacklisted(void)
if ((acpi_blacklist[i].oem_revision_predicate == all_versions)
|| (acpi_blacklist[i].oem_revision_predicate ==
less_than_or_equal
- && table_header->oem_revision <=
+ && table_header.oem_revision <=
acpi_blacklist[i].oem_revision)
|| (acpi_blacklist[i].oem_revision_predicate ==
greater_than_or_equal
- && table_header->oem_revision >=
+ && table_header.oem_revision >=
acpi_blacklist[i].oem_revision)
|| (acpi_blacklist[i].oem_revision_predicate == equal
- && table_header->oem_revision ==
+ && table_header.oem_revision ==
acpi_blacklist[i].oem_revision)) {
printk(KERN_ERR PREFIX
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 766332e4559..c26468da429 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -44,9 +44,6 @@ ACPI_MODULE_NAME("acpi_bus")
extern void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger);
#endif
-struct fadt_descriptor acpi_fadt;
-EXPORT_SYMBOL(acpi_fadt);
-
struct acpi_device *acpi_root;
struct proc_dir_entry *acpi_root_dir;
EXPORT_SYMBOL(acpi_root_dir);
@@ -195,7 +192,7 @@ int acpi_bus_set_power(acpi_handle handle, int state)
if (!device->flags.power_manageable) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable\n",
- device->kobj.name));
+ device->dev.kobj.name));
return -ENODEV;
}
/*
@@ -582,11 +579,12 @@ static int __init acpi_bus_init_irq(void)
return 0;
}
+acpi_native_uint acpi_gbl_permanent_mmap;
+
+
void __init acpi_early_init(void)
{
acpi_status status = AE_OK;
- struct acpi_buffer buffer = { sizeof(acpi_fadt), &acpi_fadt };
-
if (acpi_disabled)
return;
@@ -597,6 +595,15 @@ void __init acpi_early_init(void)
if (!acpi_strict)
acpi_gbl_enable_interpreter_slack = TRUE;
+ acpi_gbl_permanent_mmap = 1;
+
+ status = acpi_reallocate_root_table();
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR PREFIX
+ "Unable to reallocate ACPI tables\n");
+ goto error0;
+ }
+
status = acpi_initialize_subsystem();
if (ACPI_FAILURE(status)) {
printk(KERN_ERR PREFIX
@@ -611,32 +618,25 @@ void __init acpi_early_init(void)
goto error0;
}
- /*
- * Get a separate copy of the FADT for use by other drivers.
- */
- status = acpi_get_table(ACPI_TABLE_ID_FADT, 1, &buffer);
- if (ACPI_FAILURE(status)) {
- printk(KERN_ERR PREFIX "Unable to get the FADT\n");
- goto error0;
- }
#ifdef CONFIG_X86
if (!acpi_ioapic) {
- extern acpi_interrupt_flags acpi_sci_flags;
+ extern u8 acpi_sci_flags;
/* compatible (0) means level (3) */
- if (acpi_sci_flags.trigger == 0)
- acpi_sci_flags.trigger = 3;
-
+ if (!(acpi_sci_flags & ACPI_MADT_TRIGGER_MASK)) {
+ acpi_sci_flags &= ~ACPI_MADT_TRIGGER_MASK;
+ acpi_sci_flags |= ACPI_MADT_TRIGGER_LEVEL;
+ }
/* Set PIC-mode SCI trigger type */
- acpi_pic_sci_set_trigger(acpi_fadt.sci_int,
- acpi_sci_flags.trigger);
+ acpi_pic_sci_set_trigger(acpi_gbl_FADT.sci_interrupt,
+ (acpi_sci_flags & ACPI_MADT_TRIGGER_MASK) >> 2);
} else {
extern int acpi_sci_override_gsi;
/*
- * now that acpi_fadt is initialized,
+ * now that acpi_gbl_FADT is initialized,
* update it with result from INT_SRC_OVR parsing
*/
- acpi_fadt.sci_int = acpi_sci_override_gsi;
+ acpi_gbl_FADT.sci_interrupt = acpi_sci_override_gsi;
}
#endif
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index ac860583c20..c726612fafb 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -75,7 +75,7 @@ static int acpi_button_state_open_fs(struct inode *inode, struct file *file);
static struct acpi_driver acpi_button_driver = {
.name = ACPI_BUTTON_DRIVER_NAME,
.class = ACPI_BUTTON_CLASS,
- .ids = "ACPI_FPB,ACPI_FSB,PNP0C0D,PNP0C0C,PNP0C0E",
+ .ids = "button_power,button_sleep,PNP0C0D,PNP0C0C,PNP0C0E",
.ops = {
.add = acpi_button_add,
.remove = acpi_button_remove,
diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c
index 0a1863ec91f..69a68fd394c 100644
--- a/drivers/acpi/container.c
+++ b/drivers/acpi/container.c
@@ -167,7 +167,7 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context)
if (ACPI_FAILURE(status) || !device) {
result = container_device_add(&device, handle);
if (!result)
- kobject_uevent(&device->kobj,
+ kobject_uevent(&device->dev.kobj,
KOBJ_ONLINE);
else
printk("Failed to add container\n");
@@ -175,13 +175,13 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context)
} else {
if (ACPI_SUCCESS(status)) {
/* device exist and this is a remove request */
- kobject_uevent(&device->kobj, KOBJ_OFFLINE);
+ kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
}
}
break;
case ACPI_NOTIFY_EJECT_REQUEST:
if (!acpi_bus_get_device(handle, &device) && device) {
- kobject_uevent(&device->kobj, KOBJ_OFFLINE);
+ kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
}
break;
default:
diff --git a/drivers/acpi/debug.c b/drivers/acpi/debug.c
index 35c6af8a83c..d48f65a8f65 100644
--- a/drivers/acpi/debug.c
+++ b/drivers/acpi/debug.c
@@ -13,14 +13,11 @@
#define _COMPONENT ACPI_SYSTEM_COMPONENT
ACPI_MODULE_NAME("debug")
-#define ACPI_SYSTEM_FILE_DEBUG_LAYER "debug_layer"
-#define ACPI_SYSTEM_FILE_DEBUG_LEVEL "debug_level"
+
#ifdef MODULE_PARAM_PREFIX
#undef MODULE_PARAM_PREFIX
#endif
-#define MODULE_PARAM_PREFIX
- module_param(acpi_dbg_layer, uint, 0400);
-module_param(acpi_dbg_level, uint, 0400);
+#define MODULE_PARAM_PREFIX "acpi."
struct acpi_dlayer {
const char *name;
@@ -86,6 +83,60 @@ static const struct acpi_dlevel acpi_debug_levels[] = {
ACPI_DEBUG_INIT(ACPI_LV_EVENTS),
};
+/* --------------------------------------------------------------------------
+ FS Interface (/sys)
+ -------------------------------------------------------------------------- */
+static int param_get_debug_layer(char *buffer, struct kernel_param *kp) {
+ int result = 0;
+ int i;
+
+ result = sprintf(buffer, "%-25s\tHex SET\n", "Description");
+
+ for(i = 0; i <ARRAY_SIZE(acpi_debug_layers); i++) {
+ result += sprintf(buffer+result, "%-25s\t0x%08lX [%c]\n",
+ acpi_debug_layers[i].name,
+ acpi_debug_layers[i].value,
+ (acpi_dbg_layer & acpi_debug_layers[i].value) ? '*' : ' ');
+ }
+ result += sprintf(buffer+result, "%-25s\t0x%08X [%c]\n", "ACPI_ALL_DRIVERS",
+ ACPI_ALL_DRIVERS,
+ (acpi_dbg_layer & ACPI_ALL_DRIVERS) ==
+ ACPI_ALL_DRIVERS ? '*' : (acpi_dbg_layer &
+ ACPI_ALL_DRIVERS) == 0 ? ' ' : '-');
+ result += sprintf(buffer+result, "--\ndebug_layer = 0x%08X ( * = enabled)\n", acpi_dbg_layer);
+
+ return result;
+}
+
+static int param_get_debug_level(char *buffer, struct kernel_param *kp) {
+ int result = 0;
+ int i;
+
+ result = sprintf(buffer, "%-25s\tHex SET\n", "Description");
+
+ for (i = 0; i < ARRAY_SIZE(acpi_debug_levels); i++) {
+ result += sprintf(buffer+result, "%-25s\t0x%08lX [%c]\n",
+ acpi_debug_levels[i].name,
+ acpi_debug_levels[i].value,
+ (acpi_dbg_level & acpi_debug_levels[i].
+ value) ? '*' : ' ');
+ }
+ result += sprintf(buffer+result, "--\ndebug_level = 0x%08X (* = enabled)\n",
+ acpi_dbg_level);
+
+ return result;
+}
+
+module_param_call(debug_layer, param_set_uint, param_get_debug_layer, &acpi_dbg_layer, 0644);
+module_param_call(debug_level, param_set_uint, param_get_debug_level, &acpi_dbg_level, 0644);
+
+/* --------------------------------------------------------------------------
+ FS Interface (/proc)
+ -------------------------------------------------------------------------- */
+#ifdef CONFIG_ACPI_PROCFS
+#define ACPI_SYSTEM_FILE_DEBUG_LAYER "debug_layer"
+#define ACPI_SYSTEM_FILE_DEBUG_LEVEL "debug_level"
+
static int
acpi_system_read_debug(char *page,
char **start, off_t off, int count, int *eof, void *data)
@@ -221,3 +272,4 @@ static int __init acpi_debug_init(void)
}
subsys_initcall(acpi_debug_init);
+#endif
diff --git a/drivers/acpi/dispatcher/dsfield.c b/drivers/acpi/dispatcher/dsfield.c
index a6d77efb41a..f049639bac3 100644
--- a/drivers/acpi/dispatcher/dsfield.c
+++ b/drivers/acpi/dispatcher/dsfield.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -133,7 +133,8 @@ acpi_ds_create_buffer_field(union acpi_parse_object *op,
}
}
- /* We could put the returned object (Node) on the object stack for later,
+ /*
+ * We could put the returned object (Node) on the object stack for later,
* but for now, we will put it in the "op" object that the parser uses,
* so we can get it again at the end of this scope
*/
@@ -514,8 +515,33 @@ acpi_ds_create_bank_field(union acpi_parse_object *op,
/* Third arg is the bank_value */
+ /* TBD: This arg is a term_arg, not a constant, and must be evaluated */
+
arg = arg->common.next;
- info.bank_value = (u32) arg->common.value.integer;
+
+ /* Currently, only the following constants are supported */
+
+ switch (arg->common.aml_opcode) {
+ case AML_ZERO_OP:
+ info.bank_value = 0;
+ break;
+
+ case AML_ONE_OP:
+ info.bank_value = 1;
+ break;
+
+ case AML_BYTE_OP:
+ case AML_WORD_OP:
+ case AML_DWORD_OP:
+ case AML_QWORD_OP:
+ info.bank_value = (u32) arg->common.value.integer;
+ break;
+
+ default:
+ info.bank_value = 0;
+ ACPI_ERROR((AE_INFO,
+ "Non-constant BankValue for BankField is not implemented"));
+ }
/* Fourth arg is the field flags */
diff --git a/drivers/acpi/dispatcher/dsinit.c b/drivers/acpi/dispatcher/dsinit.c
index 1888c055d10..af923c38852 100644
--- a/drivers/acpi/dispatcher/dsinit.c
+++ b/drivers/acpi/dispatcher/dsinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -44,6 +44,7 @@
#include <acpi/acpi.h>
#include <acpi/acdispat.h>
#include <acpi/acnamesp.h>
+#include <acpi/actables.h>
#define _COMPONENT ACPI_DISPATCHER
ACPI_MODULE_NAME("dsinit")
@@ -90,7 +91,7 @@ acpi_ds_init_one_object(acpi_handle obj_handle,
* We are only interested in NS nodes owned by the table that
* was just loaded
*/
- if (node->owner_id != info->table_desc->owner_id) {
+ if (node->owner_id != info->owner_id) {
return (AE_OK);
}
@@ -150,14 +151,21 @@ acpi_ds_init_one_object(acpi_handle obj_handle,
******************************************************************************/
acpi_status
-acpi_ds_initialize_objects(struct acpi_table_desc * table_desc,
+acpi_ds_initialize_objects(acpi_native_uint table_index,
struct acpi_namespace_node * start_node)
{
acpi_status status;
struct acpi_init_walk_info info;
+ struct acpi_table_header *table;
+ acpi_owner_id owner_id;
ACPI_FUNCTION_TRACE(ds_initialize_objects);
+ status = acpi_tb_get_owner_id(table_index, &owner_id);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
"**** Starting initialization of namespace objects ****\n"));
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, "Parsing all Control Methods:"));
@@ -166,7 +174,8 @@ acpi_ds_initialize_objects(struct acpi_table_desc * table_desc,
info.op_region_count = 0;
info.object_count = 0;
info.device_count = 0;
- info.table_desc = table_desc;
+ info.table_index = table_index;
+ info.owner_id = owner_id;
/* Walk entire namespace from the supplied root */
@@ -176,10 +185,14 @@ acpi_ds_initialize_objects(struct acpi_table_desc * table_desc,
ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace"));
}
+ status = acpi_get_table_by_index(table_index, &table);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
"\nTable [%4.4s](id %4.4X) - %hd Objects with %hd Devices %hd Methods %hd Regions\n",
- table_desc->pointer->signature,
- table_desc->owner_id, info.object_count,
+ table->signature, owner_id, info.object_count,
info.device_count, info.method_count,
info.op_region_count));
diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c
index cf888add319..1cbe6190582 100644
--- a/drivers/acpi/dispatcher/dsmethod.c
+++ b/drivers/acpi/dispatcher/dsmethod.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -327,7 +327,7 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread,
ACPI_FUNCTION_TRACE_PTR(ds_call_control_method, this_walk_state);
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
- "Execute method %p, currentstate=%p\n",
+ "Calling method %p, currentstate=%p\n",
this_walk_state->prev_op, this_walk_state));
/*
@@ -351,49 +351,7 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread,
return_ACPI_STATUS(status);
}
- /*
- * 1) Parse the method. All "normal" methods are parsed for each execution.
- * Internal methods (_OSI, etc.) do not require parsing.
- */
- if (!(obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY)) {
-
- /* Create a new walk state for the parse */
-
- next_walk_state =
- acpi_ds_create_walk_state(obj_desc->method.owner_id, op,
- obj_desc, NULL);
- if (!next_walk_state) {
- status = AE_NO_MEMORY;
- goto cleanup;
- }
-
- /* Create and init a parse tree root */
-
- op = acpi_ps_create_scope_op();
- if (!op) {
- status = AE_NO_MEMORY;
- goto cleanup;
- }
-
- status = acpi_ds_init_aml_walk(next_walk_state, op, method_node,
- obj_desc->method.aml_start,
- obj_desc->method.aml_length,
- NULL, 1);
- if (ACPI_FAILURE(status)) {
- acpi_ps_delete_parse_tree(op);
- goto cleanup;
- }
-
- /* Begin AML parse (deletes next_walk_state) */
-
- status = acpi_ps_parse_aml(next_walk_state);
- acpi_ps_delete_parse_tree(op);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
- }
- }
-
- /* 2) Begin method execution. Create a new walk state */
+ /* Begin method parse/execution. Create a new walk state */
next_walk_state = acpi_ds_create_walk_state(obj_desc->method.owner_id,
NULL, obj_desc, thread);
@@ -424,7 +382,8 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread,
status = acpi_ds_init_aml_walk(next_walk_state, NULL, method_node,
obj_desc->method.aml_start,
- obj_desc->method.aml_length, info, 3);
+ obj_desc->method.aml_length, info,
+ ACPI_IMODE_EXECUTE);
ACPI_FREE(info);
if (ACPI_FAILURE(status)) {
@@ -445,8 +404,8 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread,
this_walk_state->num_operands = 0;
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
- "Starting nested execution, newstate=%p\n",
- next_walk_state));
+ "**** Begin nested execution of [%4.4s] **** WalkState=%p\n",
+ method_node->name.ascii, next_walk_state));
/* Invoke an internal method if necessary */
diff --git a/drivers/acpi/dispatcher/dsmthdat.c b/drivers/acpi/dispatcher/dsmthdat.c
index 459160ff905..ba4626e06a5 100644
--- a/drivers/acpi/dispatcher/dsmthdat.c
+++ b/drivers/acpi/dispatcher/dsmthdat.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/dispatcher/dsobject.c b/drivers/acpi/dispatcher/dsobject.c
index 72190abb1d5..a474ca2334d 100644
--- a/drivers/acpi/dispatcher/dsobject.c
+++ b/drivers/acpi/dispatcher/dsobject.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -260,7 +260,7 @@ acpi_ds_build_internal_buffer_obj(struct acpi_walk_state *walk_state,
}
obj_desc->buffer.flags |= AOPOBJ_DATA_VALID;
- op->common.node = (struct acpi_namespace_node *)obj_desc;
+ op->common.node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_desc);
return_ACPI_STATUS(AE_OK);
}
@@ -270,7 +270,8 @@ acpi_ds_build_internal_buffer_obj(struct acpi_walk_state *walk_state,
*
* PARAMETERS: walk_state - Current walk state
* Op - Parser object to be translated
- * package_length - Number of elements in the package
+ * element_count - Number of elements in the package - this is
+ * the num_elements argument to Package()
* obj_desc_ptr - Where the ACPI internal object is returned
*
* RETURN: Status
@@ -278,18 +279,29 @@ acpi_ds_build_internal_buffer_obj(struct acpi_walk_state *walk_state,
* DESCRIPTION: Translate a parser Op package object to the equivalent
* namespace object
*
+ * NOTE: The number of elements in the package will be always be the num_elements
+ * count, regardless of the number of elements in the package list. If
+ * num_elements is smaller, only that many package list elements are used.
+ * if num_elements is larger, the Package object is padded out with
+ * objects of type Uninitialized (as per ACPI spec.)
+ *
+ * Even though the ASL compilers do not allow num_elements to be smaller
+ * than the Package list length (for the fixed length package opcode), some
+ * BIOS code modifies the AML on the fly to adjust the num_elements, and
+ * this code compensates for that. This also provides compatibility with
+ * other AML interpreters.
+ *
******************************************************************************/
acpi_status
acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
union acpi_parse_object *op,
- u32 package_length,
+ u32 element_count,
union acpi_operand_object **obj_desc_ptr)
{
union acpi_parse_object *arg;
union acpi_parse_object *parent;
union acpi_operand_object *obj_desc = NULL;
- u32 package_list_length;
acpi_status status = AE_OK;
acpi_native_uint i;
@@ -318,32 +330,13 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
obj_desc->package.node = parent->common.node;
}
- obj_desc->package.count = package_length;
-
- /* Count the number of items in the package list */
-
- arg = op->common.value.arg;
- arg = arg->common.next;
- for (package_list_length = 0; arg; package_list_length++) {
- arg = arg->common.next;
- }
-
- /*
- * The package length (number of elements) will be the greater
- * of the specified length and the length of the initializer list
- */
- if (package_list_length > package_length) {
- obj_desc->package.count = package_list_length;
- }
-
/*
- * Allocate the pointer array (array of pointers to the
- * individual objects). Add an extra pointer slot so
- * that the list is always null terminated.
+ * Allocate the element array (array of pointers to the individual
+ * objects) based on the num_elements parameter. Add an extra pointer slot
+ * so that the list is always null terminated.
*/
obj_desc->package.elements = ACPI_ALLOCATE_ZEROED(((acpi_size)
- obj_desc->package.
- count +
+ element_count +
1) * sizeof(void *));
if (!obj_desc->package.elements) {
@@ -351,15 +344,20 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
return_ACPI_STATUS(AE_NO_MEMORY);
}
+ obj_desc->package.count = element_count;
+
/*
- * Initialize all elements of the package
+ * Initialize the elements of the package, up to the num_elements count.
+ * Package is automatically padded with uninitialized (NULL) elements
+ * if num_elements is greater than the package list length. Likewise,
+ * Package is truncated if num_elements is less than the list length.
*/
arg = op->common.value.arg;
arg = arg->common.next;
- for (i = 0; arg; i++) {
+ for (i = 0; arg && (i < element_count); i++) {
if (arg->common.aml_opcode == AML_INT_RETURN_VALUE_OP) {
- /* Object (package or buffer) is already built */
+ /* This package element is already built, just get it */
obj_desc->package.elements[i] =
ACPI_CAST_PTR(union acpi_operand_object,
@@ -373,8 +371,14 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
arg = arg->common.next;
}
+ if (!arg) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Package List length larger than NumElements count (%X), truncated\n",
+ element_count));
+ }
+
obj_desc->package.flags |= AOPOBJ_DATA_VALID;
- op->common.node = (struct acpi_namespace_node *)obj_desc;
+ op->common.node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_desc);
return_ACPI_STATUS(status);
}
@@ -488,8 +492,9 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state,
/*
* Defer evaluation of Buffer term_arg operand
*/
- obj_desc->buffer.node = (struct acpi_namespace_node *)
- walk_state->operands[0];
+ obj_desc->buffer.node =
+ ACPI_CAST_PTR(struct acpi_namespace_node,
+ walk_state->operands[0]);
obj_desc->buffer.aml_start = op->named.data;
obj_desc->buffer.aml_length = op->named.length;
break;
@@ -499,8 +504,9 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state,
/*
* Defer evaluation of Package term_arg operand
*/
- obj_desc->package.node = (struct acpi_namespace_node *)
- walk_state->operands[0];
+ obj_desc->package.node =
+ ACPI_CAST_PTR(struct acpi_namespace_node,
+ walk_state->operands[0]);
obj_desc->package.aml_start = op->named.data;
obj_desc->package.aml_length = op->named.length;
break;
diff --git a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/dispatcher/dsopcode.c
index 5b974a8fe61..6c6104a7a24 100644
--- a/drivers/acpi/dispatcher/dsopcode.c
+++ b/drivers/acpi/dispatcher/dsopcode.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -114,7 +114,7 @@ acpi_ds_execute_arguments(struct acpi_namespace_node *node,
}
status = acpi_ds_init_aml_walk(walk_state, op, NULL, aml_start,
- aml_length, NULL, 1);
+ aml_length, NULL, ACPI_IMODE_LOAD_PASS1);
if (ACPI_FAILURE(status)) {
acpi_ds_delete_walk_state(walk_state);
goto cleanup;
@@ -157,7 +157,7 @@ acpi_ds_execute_arguments(struct acpi_namespace_node *node,
/* Execute the opcode and arguments */
status = acpi_ds_init_aml_walk(walk_state, op, NULL, aml_start,
- aml_length, NULL, 3);
+ aml_length, NULL, ACPI_IMODE_EXECUTE);
if (ACPI_FAILURE(status)) {
acpi_ds_delete_walk_state(walk_state);
goto cleanup;
diff --git a/drivers/acpi/dispatcher/dsutils.c b/drivers/acpi/dispatcher/dsutils.c
index 05230baf5de..e4073e05a75 100644
--- a/drivers/acpi/dispatcher/dsutils.c
+++ b/drivers/acpi/dispatcher/dsutils.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/dispatcher/dswexec.c b/drivers/acpi/dispatcher/dswexec.c
index d7a616c3104..69693fa0722 100644
--- a/drivers/acpi/dispatcher/dswexec.c
+++ b/drivers/acpi/dispatcher/dswexec.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -219,7 +219,7 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state,
if (!op) {
status = acpi_ds_load2_begin_op(walk_state, out_op);
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ goto error_exit;
}
op = *out_op;
@@ -238,7 +238,7 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state,
status = acpi_ds_scope_stack_pop(walk_state);
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ goto error_exit;
}
}
}
@@ -287,7 +287,7 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state,
status = acpi_ds_result_stack_push(walk_state);
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ goto error_exit;
}
status = acpi_ds_exec_begin_control_op(walk_state, op);
@@ -328,6 +328,10 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state,
/* Nothing to do here during method execution */
return_ACPI_STATUS(status);
+
+ error_exit:
+ status = acpi_ds_method_error(status, walk_state);
+ return_ACPI_STATUS(status);
}
/*****************************************************************************
diff --git a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/dispatcher/dswload.c
index e3ca7f6539c..8ab9d1b29a4 100644
--- a/drivers/acpi/dispatcher/dswload.c
+++ b/drivers/acpi/dispatcher/dswload.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -196,6 +196,7 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state,
* one of the opcodes that actually opens a scope
*/
switch (node->type) {
+ case ACPI_TYPE_ANY:
case ACPI_TYPE_LOCAL_SCOPE: /* Scope */
case ACPI_TYPE_DEVICE:
case ACPI_TYPE_POWER:
@@ -546,6 +547,7 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
acpi_status status;
acpi_object_type object_type;
char *buffer_ptr;
+ u32 flags;
ACPI_FUNCTION_TRACE(ds_load2_begin_op);
@@ -669,6 +671,7 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
* one of the opcodes that actually opens a scope
*/
switch (node->type) {
+ case ACPI_TYPE_ANY:
case ACPI_TYPE_LOCAL_SCOPE: /* Scope */
case ACPI_TYPE_DEVICE:
case ACPI_TYPE_POWER:
@@ -750,12 +753,20 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
break;
}
- /* Add new entry into namespace */
+ flags = ACPI_NS_NO_UPSEARCH;
+ if (walk_state->pass_number == ACPI_IMODE_EXECUTE) {
+
+ /* Execution mode, node cannot already exist, node is temporary */
+
+ flags |= (ACPI_NS_ERROR_IF_FOUND | ACPI_NS_TEMPORARY);
+ }
+
+ /* Add new entry or lookup existing entry */
status =
acpi_ns_lookup(walk_state->scope_info, buffer_ptr,
- object_type, ACPI_IMODE_LOAD_PASS2,
- ACPI_NS_NO_UPSEARCH, walk_state, &(node));
+ object_type, ACPI_IMODE_LOAD_PASS2, flags,
+ walk_state, &node);
break;
}
diff --git a/drivers/acpi/dispatcher/dswscope.c b/drivers/acpi/dispatcher/dswscope.c
index c9228972f5f..3927c495e4b 100644
--- a/drivers/acpi/dispatcher/dswscope.c
+++ b/drivers/acpi/dispatcher/dswscope.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/dispatcher/dswstate.c b/drivers/acpi/dispatcher/dswstate.c
index 7817e552267..16c8e38b51e 100644
--- a/drivers/acpi/dispatcher/dswstate.c
+++ b/drivers/acpi/dispatcher/dswstate.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index 90990a4b652..688e83a1690 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -615,20 +615,28 @@ static acpi_status
find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv)
{
acpi_status status;
- acpi_handle tmp;
+ acpi_handle tmp, parent;
struct dock_station *ds = context;
struct dock_dependent_device *dd;
status = acpi_bus_get_ejd(handle, &tmp);
- if (ACPI_FAILURE(status))
- return AE_OK;
+ if (ACPI_FAILURE(status)) {
+ /* try the parent device as well */
+ status = acpi_get_parent(handle, &parent);
+ if (ACPI_FAILURE(status))
+ goto fdd_out;
+ /* see if parent is dependent on dock */
+ status = acpi_bus_get_ejd(parent, &tmp);
+ if (ACPI_FAILURE(status))
+ goto fdd_out;
+ }
if (tmp == ds->handle) {
dd = alloc_dock_dependent_device(handle);
if (dd)
add_dock_dependent_device(ds, dd);
}
-
+fdd_out:
return AE_OK;
}
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index cbdf031f3c0..743ce27fa0b 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -872,9 +872,8 @@ static int __init acpi_ec_get_real_ecdt(void)
acpi_status status;
struct acpi_table_ecdt *ecdt_ptr;
- status = acpi_get_firmware_table("ECDT", 1, ACPI_LOGICAL_ADDRESSING,
- (struct acpi_table_header **)
- &ecdt_ptr);
+ status = acpi_get_table(ACPI_SIG_ECDT, 1,
+ (struct acpi_table_header **)&ecdt_ptr);
if (ACPI_FAILURE(status))
return -ENODEV;
@@ -891,14 +890,14 @@ static int __init acpi_ec_get_real_ecdt(void)
if (acpi_ec_mode == EC_INTR) {
init_waitqueue_head(&ec_ecdt->wait);
}
- ec_ecdt->command_addr = ecdt_ptr->ec_control.address;
- ec_ecdt->data_addr = ecdt_ptr->ec_data.address;
- ec_ecdt->gpe = ecdt_ptr->gpe_bit;
+ ec_ecdt->command_addr = ecdt_ptr->control.address;
+ ec_ecdt->data_addr = ecdt_ptr->data.address;
+ ec_ecdt->gpe = ecdt_ptr->gpe;
/* use the GL just to be safe */
ec_ecdt->global_lock = TRUE;
ec_ecdt->uid = ecdt_ptr->uid;
- status = acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->handle);
+ status = acpi_get_handle(NULL, ecdt_ptr->id, &ec_ecdt->handle);
if (ACPI_FAILURE(status)) {
goto error;
}
diff --git a/drivers/acpi/events/evevent.c b/drivers/acpi/events/evevent.c
index 919037d6acf..a1f87b5def2 100644
--- a/drivers/acpi/events/evevent.c
+++ b/drivers/acpi/events/evevent.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -70,13 +70,6 @@ acpi_status acpi_ev_initialize_events(void)
ACPI_FUNCTION_TRACE(ev_initialize_events);
- /* Make sure we have ACPI tables */
-
- if (!acpi_gbl_DSDT) {
- ACPI_WARNING((AE_INFO, "No ACPI tables present!"));
- return_ACPI_STATUS(AE_NO_ACPI_TABLES);
- }
-
/*
* Initialize the Fixed and General Purpose Events. This is done prior to
* enabling SCIs to prevent interrupts from occurring before the handlers are
@@ -211,8 +204,7 @@ static acpi_status acpi_ev_fixed_event_initialize(void)
if (acpi_gbl_fixed_event_info[i].enable_register_id != 0xFF) {
status =
acpi_set_register(acpi_gbl_fixed_event_info[i].
- enable_register_id, 0,
- ACPI_MTX_LOCK);
+ enable_register_id, 0);
if (ACPI_FAILURE(status)) {
return (status);
}
@@ -298,7 +290,7 @@ static u32 acpi_ev_fixed_event_dispatch(u32 event)
/* Clear the status bit */
(void)acpi_set_register(acpi_gbl_fixed_event_info[event].
- status_register_id, 1, ACPI_MTX_DO_NOT_LOCK);
+ status_register_id, 1);
/*
* Make sure we've got a handler. If not, report an error.
@@ -306,8 +298,7 @@ static u32 acpi_ev_fixed_event_dispatch(u32 event)
*/
if (NULL == acpi_gbl_fixed_event_handlers[event].handler) {
(void)acpi_set_register(acpi_gbl_fixed_event_info[event].
- enable_register_id, 0,
- ACPI_MTX_DO_NOT_LOCK);
+ enable_register_id, 0);
ACPI_ERROR((AE_INFO,
"No installed handler for fixed event [%08X]",
diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c
index c76c0583ca6..dfac3ecc596 100644
--- a/drivers/acpi/events/evgpe.c
+++ b/drivers/acpi/events/evgpe.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -121,7 +121,9 @@ acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info,
if (!gpe_register_info) {
return_ACPI_STATUS(AE_NOT_EXIST);
}
- register_bit = gpe_event_info->register_bit;
+ register_bit = (u8)
+ (1 <<
+ (gpe_event_info->gpe_number - gpe_register_info->base_gpe_number));
/* 1) Disable case. Simply clear all enable bits */
@@ -458,8 +460,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
/* Examine one GPE bit */
- if (enabled_status_byte &
- acpi_gbl_decode_to8bit[j]) {
+ if (enabled_status_byte & (1 << j)) {
/*
* Found an active GPE. Dispatch the event to a handler
* or method.
@@ -570,7 +571,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
- "While evaluating GPE method [%4.4s]",
+ "while evaluating GPE method [%4.4s]",
acpi_ut_get_node_name
(local_gpe_event_info.dispatch.
method_node)));
@@ -618,6 +619,8 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
ACPI_FUNCTION_TRACE(ev_gpe_dispatch);
+ acpi_gpe_count++;
+
/*
* If edge-triggered, clear the GPE status bit now. Note that
* level-triggered events are cleared after the GPE is serviced.
@@ -633,20 +636,23 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
}
}
- /* Save current system state */
-
- if (acpi_gbl_system_awake_and_running) {
- ACPI_SET_BIT(gpe_event_info->flags, ACPI_GPE_SYSTEM_RUNNING);
- } else {
- ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_SYSTEM_RUNNING);
+ if (!acpi_gbl_system_awake_and_running) {
+ /*
+ * We just woke up because of a wake GPE. Disable any further GPEs
+ * until we are fully up and running (Only wake GPEs should be enabled
+ * at this time, but we just brute-force disable them all.)
+ * 1) We must disable this particular wake GPE so it won't fire again
+ * 2) We want to disable all wake GPEs, since we are now awake
+ */
+ (void)acpi_hw_disable_all_gpes();
}
/*
- * Dispatch the GPE to either an installed handler, or the control
- * method associated with this GPE (_Lxx or _Exx).
- * If a handler exists, we invoke it and do not attempt to run the method.
- * If there is neither a handler nor a method, we disable the level to
- * prevent further events from coming in here.
+ * Dispatch the GPE to either an installed handler, or the control method
+ * associated with this GPE (_Lxx or _Exx). If a handler exists, we invoke
+ * it and do not attempt to run the method. If there is neither a handler
+ * nor a method, we disable this GPE to prevent further such pointless
+ * events from firing.
*/
switch (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) {
case ACPI_GPE_DISPATCH_HANDLER:
@@ -677,8 +683,8 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
case ACPI_GPE_DISPATCH_METHOD:
/*
- * Disable GPE, so it doesn't keep firing before the method has a
- * chance to run.
+ * Disable the GPE, so it doesn't keep firing before the method has a
+ * chance to run (it runs asynchronously with interrupts enabled).
*/
status = acpi_ev_disable_gpe(gpe_event_info);
if (ACPI_FAILURE(status)) {
@@ -711,7 +717,7 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
gpe_number));
/*
- * Disable the GPE. The GPE will remain disabled until the ACPI
+ * Disable the GPE. The GPE will remain disabled until the ACPI
* Core Subsystem is restarted, or a handler is installed.
*/
status = acpi_ev_disable_gpe(gpe_event_info);
@@ -726,50 +732,3 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
return_UINT32(ACPI_INTERRUPT_HANDLED);
}
-
-#ifdef ACPI_GPE_NOTIFY_CHECK
-/*******************************************************************************
- * TBD: NOT USED, PROTOTYPE ONLY AND WILL PROBABLY BE REMOVED
- *
- * FUNCTION: acpi_ev_check_for_wake_only_gpe
- *
- * PARAMETERS: gpe_event_info - info for this GPE
- *
- * RETURN: Status
- *
- * DESCRIPTION: Determine if a a GPE is "wake-only".
- *
- * Called from Notify() code in interpreter when a "DeviceWake"
- * Notify comes in.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ev_check_for_wake_only_gpe(struct acpi_gpe_event_info *gpe_event_info)
-{
- acpi_status status;
-
- ACPI_FUNCTION_TRACE(ev_check_for_wake_only_gpe);
-
- if ((gpe_event_info) && /* Only >0 for _Lxx/_Exx */
- ((gpe_event_info->flags & ACPI_GPE_SYSTEM_MASK) == ACPI_GPE_SYSTEM_RUNNING)) { /* System state at GPE time */
- /* This must be a wake-only GPE, disable it */
-
- status = acpi_ev_disable_gpe(gpe_event_info);
-
- /* Set GPE to wake-only. Do not change wake disabled/enabled status */
-
- acpi_ev_set_gpe_type(gpe_event_info, ACPI_GPE_TYPE_WAKE);
-
- ACPI_INFO((AE_INFO,
- "GPE %p was updated from wake/run to wake-only",
- gpe_event_info));
-
- /* This was a wake-only GPE */
-
- return_ACPI_STATUS(AE_WAKE_ONLY_GPE);
- }
-
- return_ACPI_STATUS(AE_OK);
-}
-#endif
diff --git a/drivers/acpi/events/evgpeblk.c b/drivers/acpi/events/evgpeblk.c
index 95ddeb48bc0..ad5bc76edf4 100644
--- a/drivers/acpi/events/evgpeblk.c
+++ b/drivers/acpi/events/evgpeblk.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -529,7 +529,7 @@ static struct acpi_gpe_xrupt_info *acpi_ev_get_gpe_xrupt_block(u32
/* Install new interrupt handler if not SCI_INT */
- if (interrupt_number != acpi_gbl_FADT->sci_int) {
+ if (interrupt_number != acpi_gbl_FADT.sci_interrupt) {
status = acpi_os_install_interrupt_handler(interrupt_number,
acpi_ev_gpe_xrupt_handler,
gpe_xrupt);
@@ -567,7 +567,7 @@ acpi_ev_delete_gpe_xrupt(struct acpi_gpe_xrupt_info *gpe_xrupt)
/* We never want to remove the SCI interrupt handler */
- if (gpe_xrupt->interrupt_number == acpi_gbl_FADT->sci_int) {
+ if (gpe_xrupt->interrupt_number == acpi_gbl_FADT.sci_interrupt) {
gpe_xrupt->gpe_block_list_head = NULL;
return_ACPI_STATUS(AE_OK);
}
@@ -796,30 +796,31 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block)
(u8) (gpe_block->block_base_number +
(i * ACPI_GPE_REGISTER_WIDTH));
- ACPI_STORE_ADDRESS(this_register->status_address.address,
- (gpe_block->block_address.address + i));
+ this_register->status_address.address =
+ gpe_block->block_address.address + i;
- ACPI_STORE_ADDRESS(this_register->enable_address.address,
- (gpe_block->block_address.address
- + i + gpe_block->register_count));
+ this_register->enable_address.address =
+ gpe_block->block_address.address + i +
+ gpe_block->register_count;
- this_register->status_address.address_space_id =
- gpe_block->block_address.address_space_id;
- this_register->enable_address.address_space_id =
- gpe_block->block_address.address_space_id;
- this_register->status_address.register_bit_width =
+ this_register->status_address.space_id =
+ gpe_block->block_address.space_id;
+ this_register->enable_address.space_id =
+ gpe_block->block_address.space_id;
+ this_register->status_address.bit_width =
ACPI_GPE_REGISTER_WIDTH;
- this_register->enable_address.register_bit_width =
+ this_register->enable_address.bit_width =
ACPI_GPE_REGISTER_WIDTH;
- this_register->status_address.register_bit_offset =
+ this_register->status_address.bit_offset =
ACPI_GPE_REGISTER_WIDTH;
- this_register->enable_address.register_bit_offset =
+ this_register->enable_address.bit_offset =
ACPI_GPE_REGISTER_WIDTH;
/* Init the event_info for each GPE within this register */
for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
- this_event->register_bit = acpi_gbl_decode_to8bit[j];
+ this_event->gpe_number =
+ (u8) (this_register->base_gpe_number + j);
this_event->register_info = this_register;
this_event++;
}
@@ -1109,11 +1110,12 @@ acpi_status acpi_ev_gpe_initialize(void)
* If EITHER the register length OR the block address are zero, then that
* particular block is not supported.
*/
- if (acpi_gbl_FADT->gpe0_blk_len && acpi_gbl_FADT->xgpe0_blk.address) {
+ if (acpi_gbl_FADT.gpe0_block_length &&
+ acpi_gbl_FADT.xgpe0_block.address) {
/* GPE block 0 exists (has both length and address > 0) */
- register_count0 = (u16) (acpi_gbl_FADT->gpe0_blk_len / 2);
+ register_count0 = (u16) (acpi_gbl_FADT.gpe0_block_length / 2);
gpe_number_max =
(register_count0 * ACPI_GPE_REGISTER_WIDTH) - 1;
@@ -1121,9 +1123,9 @@ acpi_status acpi_ev_gpe_initialize(void)
/* Install GPE Block 0 */
status = acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device,
- &acpi_gbl_FADT->xgpe0_blk,
+ &acpi_gbl_FADT.xgpe0_block,
register_count0, 0,
- acpi_gbl_FADT->sci_int,
+ acpi_gbl_FADT.sci_interrupt,
&acpi_gbl_gpe_fadt_blocks[0]);
if (ACPI_FAILURE(status)) {
@@ -1132,20 +1134,21 @@ acpi_status acpi_ev_gpe_initialize(void)
}
}
- if (acpi_gbl_FADT->gpe1_blk_len && acpi_gbl_FADT->xgpe1_blk.address) {
+ if (acpi_gbl_FADT.gpe1_block_length &&
+ acpi_gbl_FADT.xgpe1_block.address) {
/* GPE block 1 exists (has both length and address > 0) */
- register_count1 = (u16) (acpi_gbl_FADT->gpe1_blk_len / 2);
+ register_count1 = (u16) (acpi_gbl_FADT.gpe1_block_length / 2);
/* Check for GPE0/GPE1 overlap (if both banks exist) */
if ((register_count0) &&
- (gpe_number_max >= acpi_gbl_FADT->gpe1_base)) {
+ (gpe_number_max >= acpi_gbl_FADT.gpe1_base)) {
ACPI_ERROR((AE_INFO,
"GPE0 block (GPE 0 to %d) overlaps the GPE1 block (GPE %d to %d) - Ignoring GPE1",
- gpe_number_max, acpi_gbl_FADT->gpe1_base,
- acpi_gbl_FADT->gpe1_base +
+ gpe_number_max, acpi_gbl_FADT.gpe1_base,
+ acpi_gbl_FADT.gpe1_base +
((register_count1 *
ACPI_GPE_REGISTER_WIDTH) - 1)));
@@ -1157,10 +1160,11 @@ acpi_status acpi_ev_gpe_initialize(void)
status =
acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device,
- &acpi_gbl_FADT->xgpe1_blk,
+ &acpi_gbl_FADT.xgpe1_block,
register_count1,
- acpi_gbl_FADT->gpe1_base,
- acpi_gbl_FADT->sci_int,
+ acpi_gbl_FADT.gpe1_base,
+ acpi_gbl_FADT.
+ sci_interrupt,
&acpi_gbl_gpe_fadt_blocks
[1]);
@@ -1173,7 +1177,7 @@ acpi_status acpi_ev_gpe_initialize(void)
* GPE0 and GPE1 do not have to be contiguous in the GPE number
* space. However, GPE0 always starts at GPE number zero.
*/
- gpe_number_max = acpi_gbl_FADT->gpe1_base +
+ gpe_number_max = acpi_gbl_FADT.gpe1_base +
((register_count1 * ACPI_GPE_REGISTER_WIDTH) - 1);
}
}
diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c
index bf63edc6608..1b784ffe54c 100644
--- a/drivers/acpi/events/evmisc.c
+++ b/drivers/acpi/events/evmisc.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -63,14 +63,18 @@ static const char *acpi_notify_value_names[] = {
};
#endif
+/* Pointer to FACS needed for the Global Lock */
+
+static struct acpi_table_facs *facs = NULL;
+
/* Local prototypes */
static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context);
-static void ACPI_SYSTEM_XFACE acpi_ev_global_lock_thread(void *context);
-
static u32 acpi_ev_global_lock_handler(void *context);
+static acpi_status acpi_ev_remove_global_lock_handler(void);
+
/*******************************************************************************
*
* FUNCTION: acpi_ev_is_notify_object
@@ -282,49 +286,19 @@ static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context)
/*******************************************************************************
*
- * FUNCTION: acpi_ev_global_lock_thread
- *
- * PARAMETERS: Context - From thread interface, not used
- *
- * RETURN: None
- *
- * DESCRIPTION: Invoked by SCI interrupt handler upon acquisition of the
- * Global Lock. Simply signal all threads that are waiting
- * for the lock.
- *
- ******************************************************************************/
-
-static void ACPI_SYSTEM_XFACE acpi_ev_global_lock_thread(void *context)
-{
- acpi_status status;
-
- /* Signal threads that are waiting for the lock */
-
- if (acpi_gbl_global_lock_thread_count) {
-
- /* Send sufficient units to the semaphore */
-
- status =
- acpi_os_signal_semaphore(acpi_gbl_global_lock_semaphore,
- acpi_gbl_global_lock_thread_count);
- if (ACPI_FAILURE(status)) {
- ACPI_ERROR((AE_INFO,
- "Could not signal Global Lock semaphore"));
- }
- }
-}
-
-/*******************************************************************************
- *
* FUNCTION: acpi_ev_global_lock_handler
*
* PARAMETERS: Context - From thread interface, not used
*
- * RETURN: ACPI_INTERRUPT_HANDLED or ACPI_INTERRUPT_NOT_HANDLED
+ * RETURN: ACPI_INTERRUPT_HANDLED
*
* DESCRIPTION: Invoked directly from the SCI handler when a global lock
- * release interrupt occurs. Grab the global lock and queue
- * the global lock thread for execution
+ * release interrupt occurs. Attempt to acquire the global lock,
+ * if successful, signal the thread waiting for the lock.
+ *
+ * NOTE: Assumes that the semaphore can be signaled from interrupt level. If
+ * this is not possible for some reason, a separate thread will have to be
+ * scheduled to do this.
*
******************************************************************************/
@@ -333,16 +307,24 @@ static u32 acpi_ev_global_lock_handler(void *context)
u8 acquired = FALSE;
/*
- * Attempt to get the lock
+ * Attempt to get the lock.
+ *
* If we don't get it now, it will be marked pending and we will
* take another interrupt when it becomes free.
*/
- ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_common_fACS.global_lock, acquired);
+ ACPI_ACQUIRE_GLOBAL_LOCK(facs, acquired);
if (acquired) {
/* Got the lock, now wake all threads waiting for it */
+
acpi_gbl_global_lock_acquired = TRUE;
- acpi_ev_global_lock_thread(context);
+ /* Send a unit to the semaphore */
+
+ if (ACPI_FAILURE(acpi_os_signal_semaphore(
+ acpi_gbl_global_lock_semaphore, 1))) {
+ ACPI_ERROR((AE_INFO,
+ "Could not signal Global Lock semaphore"));
+ }
}
return (ACPI_INTERRUPT_HANDLED);
@@ -366,6 +348,13 @@ acpi_status acpi_ev_init_global_lock_handler(void)
ACPI_FUNCTION_TRACE(ev_init_global_lock_handler);
+ status =
+ acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
+ (struct acpi_table_header **)&facs);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
acpi_gbl_global_lock_present = TRUE;
status = acpi_install_fixed_event_handler(ACPI_EVENT_GLOBAL,
acpi_ev_global_lock_handler,
@@ -389,6 +378,31 @@ acpi_status acpi_ev_init_global_lock_handler(void)
return_ACPI_STATUS(status);
}
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_remove_global_lock_handler
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Remove the handler for the Global Lock
+ *
+ ******************************************************************************/
+
+static acpi_status acpi_ev_remove_global_lock_handler(void)
+{
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(ev_remove_global_lock_handler);
+
+ acpi_gbl_global_lock_present = FALSE;
+ status = acpi_remove_fixed_event_handler(ACPI_EVENT_GLOBAL,
+ acpi_ev_global_lock_handler);
+
+ return_ACPI_STATUS(status);
+}
+
/******************************************************************************
*
* FUNCTION: acpi_ev_acquire_global_lock
@@ -399,6 +413,16 @@ acpi_status acpi_ev_init_global_lock_handler(void)
*
* DESCRIPTION: Attempt to gain ownership of the Global Lock.
*
+ * MUTEX: Interpreter must be locked
+ *
+ * Note: The original implementation allowed multiple threads to "acquire" the
+ * Global Lock, and the OS would hold the lock until the last thread had
+ * released it. However, this could potentially starve the BIOS out of the
+ * lock, especially in the case where there is a tight handshake between the
+ * Embedded Controller driver and the BIOS. Therefore, this implementation
+ * allows only one thread to acquire the HW Global Lock at a time, and makes
+ * the global lock appear as a standard mutex on the OS side.
+ *
*****************************************************************************/
acpi_status acpi_ev_acquire_global_lock(u16 timeout)
@@ -408,53 +432,51 @@ acpi_status acpi_ev_acquire_global_lock(u16 timeout)
ACPI_FUNCTION_TRACE(ev_acquire_global_lock);
-#ifndef ACPI_APPLICATION
- /* Make sure that we actually have a global lock */
-
- if (!acpi_gbl_global_lock_present) {
- return_ACPI_STATUS(AE_NO_GLOBAL_LOCK);
+ /*
+ * Only one thread can acquire the GL at a time, the global_lock_mutex
+ * enforces this. This interface releases the interpreter if we must wait.
+ */
+ status = acpi_ex_system_wait_mutex(acpi_gbl_global_lock_mutex, timeout);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
}
-#endif
-
- /* One more thread wants the global lock */
-
- acpi_gbl_global_lock_thread_count++;
/*
- * If we (OS side vs. BIOS side) have the hardware lock already,
- * we are done
+ * Make sure that a global lock actually exists. If not, just treat
+ * the lock as a standard mutex.
*/
- if (acpi_gbl_global_lock_acquired) {
+ if (!acpi_gbl_global_lock_present) {
+ acpi_gbl_global_lock_acquired = TRUE;
return_ACPI_STATUS(AE_OK);
}
- /* We must acquire the actual hardware lock */
+ /* Attempt to acquire the actual hardware lock */
- ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_common_fACS.global_lock, acquired);
+ ACPI_ACQUIRE_GLOBAL_LOCK(facs, acquired);
if (acquired) {
/* We got the lock */
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "Acquired the HW Global Lock\n"));
+ "Acquired hardware Global Lock\n"));
acpi_gbl_global_lock_acquired = TRUE;
return_ACPI_STATUS(AE_OK);
}
/*
- * Did not get the lock. The pending bit was set above, and we must now
+ * Did not get the lock. The pending bit was set above, and we must now
* wait until we get the global lock released interrupt.
*/
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Waiting for the HW Global Lock\n"));
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Waiting for hardware Global Lock\n"));
/*
- * Acquire the global lock semaphore first.
- * Since this wait will block, we must release the interpreter
+ * Wait for handshake with the global lock interrupt handler.
+ * This interface releases the interpreter if we must wait.
*/
- status =
- acpi_ex_system_wait_semaphore(acpi_gbl_global_lock_semaphore,
- timeout);
+ status = acpi_ex_system_wait_semaphore(acpi_gbl_global_lock_semaphore,
+ ACPI_WAIT_FOREVER);
+
return_ACPI_STATUS(status);
}
@@ -477,38 +499,39 @@ acpi_status acpi_ev_release_global_lock(void)
ACPI_FUNCTION_TRACE(ev_release_global_lock);
- if (!acpi_gbl_global_lock_thread_count) {
+ /* Lock must be already acquired */
+
+ if (!acpi_gbl_global_lock_acquired) {
ACPI_WARNING((AE_INFO,
- "Cannot release HW Global Lock, it has not been acquired"));
+ "Cannot release the ACPI Global Lock, it has not been acquired"));
return_ACPI_STATUS(AE_NOT_ACQUIRED);
}
- /* One fewer thread has the global lock */
+ if (acpi_gbl_global_lock_present) {
- acpi_gbl_global_lock_thread_count--;
- if (acpi_gbl_global_lock_thread_count) {
+ /* Allow any thread to release the lock */
- /* There are still some threads holding the lock, cannot release */
+ ACPI_RELEASE_GLOBAL_LOCK(facs, pending);
- return_ACPI_STATUS(AE_OK);
+ /*
+ * If the pending bit was set, we must write GBL_RLS to the control
+ * register
+ */
+ if (pending) {
+ status =
+ acpi_set_register(ACPI_BITREG_GLOBAL_LOCK_RELEASE,
+ 1);
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Released hardware Global Lock\n"));
}
- /*
- * No more threads holding lock, we can do the actual hardware
- * release
- */
- ACPI_RELEASE_GLOBAL_LOCK(acpi_gbl_common_fACS.global_lock, pending);
acpi_gbl_global_lock_acquired = FALSE;
- /*
- * If the pending bit was set, we must write GBL_RLS to the control
- * register
- */
- if (pending) {
- status = acpi_set_register(ACPI_BITREG_GLOBAL_LOCK_RELEASE,
- 1, ACPI_MTX_LOCK);
- }
+ /* Release the local GL mutex */
+ acpi_os_release_mutex(acpi_gbl_global_lock_mutex);
return_ACPI_STATUS(status);
}
@@ -558,6 +581,12 @@ void acpi_ev_terminate(void)
if (ACPI_FAILURE(status)) {
ACPI_ERROR((AE_INFO, "Could not remove SCI handler"));
}
+
+ status = acpi_ev_remove_global_lock_handler();
+ if (ACPI_FAILURE(status)) {
+ ACPI_ERROR((AE_INFO,
+ "Could not remove Global Lock handler"));
+ }
}
/* Deallocate all handler objects installed within GPE info structs */
diff --git a/drivers/acpi/events/evregion.c b/drivers/acpi/events/evregion.c
index 21caae04fe8..e99f0c435a4 100644
--- a/drivers/acpi/events/evregion.c
+++ b/drivers/acpi/events/evregion.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -291,7 +291,6 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
u32 bit_width, acpi_integer * value)
{
acpi_status status;
- acpi_status status2;
acpi_adr_space_handler handler;
acpi_adr_space_setup region_setup;
union acpi_operand_object *handler_desc;
@@ -345,7 +344,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
* setup will potentially execute control methods
* (e.g., _REG method for this region)
*/
- acpi_ex_exit_interpreter();
+ acpi_ex_relinquish_interpreter();
status = region_setup(region_obj, ACPI_REGION_ACTIVATE,
handler_desc->address_space.context,
@@ -353,10 +352,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
/* Re-enter the interpreter */
- status2 = acpi_ex_enter_interpreter();
- if (ACPI_FAILURE(status2)) {
- return_ACPI_STATUS(status2);
- }
+ acpi_ex_reacquire_interpreter();
/* Check for failure of the Region Setup */
@@ -409,7 +405,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
* exit the interpreter because the handler *might* block -- we don't
* know what it will do, so we can't hold the lock on the intepreter.
*/
- acpi_ex_exit_interpreter();
+ acpi_ex_relinquish_interpreter();
}
/* Call the handler */
@@ -430,10 +426,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
* We just returned from a non-default handler, we must re-enter the
* interpreter
*/
- status2 = acpi_ex_enter_interpreter();
- if (ACPI_FAILURE(status2)) {
- return_ACPI_STATUS(status2);
- }
+ acpi_ex_reacquire_interpreter();
}
return_ACPI_STATUS(status);
diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c
index 203d1359190..a4fa7e6822a 100644
--- a/drivers/acpi/events/evrgnini.c
+++ b/drivers/acpi/events/evrgnini.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -48,6 +48,11 @@
#define _COMPONENT ACPI_EVENTS
ACPI_MODULE_NAME("evrgnini")
+/* Local prototypes */
+static u8 acpi_ev_match_pci_root_bridge(char *id);
+
+static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node);
+
/*******************************************************************************
*
* FUNCTION: acpi_ev_system_memory_region_setup
@@ -62,6 +67,7 @@ ACPI_MODULE_NAME("evrgnini")
* DESCRIPTION: Setup a system_memory operation region
*
******************************************************************************/
+
acpi_status
acpi_ev_system_memory_region_setup(acpi_handle handle,
u32 function,
@@ -168,9 +174,9 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
union acpi_operand_object *handler_obj;
struct acpi_namespace_node *parent_node;
struct acpi_namespace_node *pci_root_node;
+ struct acpi_namespace_node *pci_device_node;
union acpi_operand_object *region_obj =
(union acpi_operand_object *)handle;
- struct acpi_device_id object_hID;
ACPI_FUNCTION_TRACE(ev_pci_config_region_setup);
@@ -215,45 +221,30 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
pci_root_node = parent_node;
while (pci_root_node != acpi_gbl_root_node) {
- status =
- acpi_ut_execute_HID(pci_root_node, &object_hID);
- if (ACPI_SUCCESS(status)) {
- /*
- * Got a valid _HID string, check if this is a PCI root.
- * New for ACPI 3.0: check for a PCI Express root also.
- */
- if (!
- (ACPI_STRNCMP
- (object_hID.value, PCI_ROOT_HID_STRING,
- sizeof(PCI_ROOT_HID_STRING)))
- ||
- !(ACPI_STRNCMP
- (object_hID.value,
- PCI_EXPRESS_ROOT_HID_STRING,
- sizeof(PCI_EXPRESS_ROOT_HID_STRING)))) {
-
- /* Install a handler for this PCI root bridge */
- status =
- acpi_install_address_space_handler((acpi_handle) pci_root_node, ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL);
- if (ACPI_FAILURE(status)) {
- if (status == AE_SAME_HANDLER) {
- /*
- * It is OK if the handler is already installed on the root
- * bridge. Still need to return a context object for the
- * new PCI_Config operation region, however.
- */
- status = AE_OK;
- } else {
- ACPI_EXCEPTION((AE_INFO,
- status,
- "Could not install PciConfig handler for Root Bridge %4.4s",
- acpi_ut_get_node_name
- (pci_root_node)));
- }
+ /* Get the _HID/_CID in order to detect a root_bridge */
+
+ if (acpi_ev_is_pci_root_bridge(pci_root_node)) {
+
+ /* Install a handler for this PCI root bridge */
+
+ status = acpi_install_address_space_handler((acpi_handle) pci_root_node, ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL);
+ if (ACPI_FAILURE(status)) {
+ if (status == AE_SAME_HANDLER) {
+ /*
+ * It is OK if the handler is already installed on the root
+ * bridge. Still need to return a context object for the
+ * new PCI_Config operation region, however.
+ */
+ status = AE_OK;
+ } else {
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Could not install PciConfig handler for Root Bridge %4.4s",
+ acpi_ut_get_node_name
+ (pci_root_node)));
}
- break;
}
+ break;
}
pci_root_node = acpi_ns_get_parent_node(pci_root_node);
@@ -282,14 +273,25 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
/*
* For PCI_Config space access, we need the segment, bus,
* device and function numbers. Acquire them here.
+ *
+ * Find the parent device object. (This allows the operation region to be
+ * within a subscope under the device, such as a control method.)
*/
+ pci_device_node = region_obj->region.node;
+ while (pci_device_node && (pci_device_node->type != ACPI_TYPE_DEVICE)) {
+ pci_device_node = acpi_ns_get_parent_node(pci_device_node);
+ }
+
+ if (!pci_device_node) {
+ return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
+ }
/*
* Get the PCI device and function numbers from the _ADR object
* contained in the parent's scope.
*/
status =
- acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, parent_node,
+ acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, pci_device_node,
&pci_value);
/*
@@ -329,6 +331,91 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
/*******************************************************************************
*
+ * FUNCTION: acpi_ev_match_pci_root_bridge
+ *
+ * PARAMETERS: Id - The HID/CID in string format
+ *
+ * RETURN: TRUE if the Id is a match for a PCI/PCI-Express Root Bridge
+ *
+ * DESCRIPTION: Determine if the input ID is a PCI Root Bridge ID.
+ *
+ ******************************************************************************/
+
+static u8 acpi_ev_match_pci_root_bridge(char *id)
+{
+
+ /*
+ * Check if this is a PCI root.
+ * ACPI 3.0+: check for a PCI Express root also.
+ */
+ if (!(ACPI_STRNCMP(id,
+ PCI_ROOT_HID_STRING,
+ sizeof(PCI_ROOT_HID_STRING))) ||
+ !(ACPI_STRNCMP(id,
+ PCI_EXPRESS_ROOT_HID_STRING,
+ sizeof(PCI_EXPRESS_ROOT_HID_STRING)))) {
+ return (TRUE);
+ }
+
+ return (FALSE);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_is_pci_root_bridge
+ *
+ * PARAMETERS: Node - Device node being examined
+ *
+ * RETURN: TRUE if device is a PCI/PCI-Express Root Bridge
+ *
+ * DESCRIPTION: Determine if the input device represents a PCI Root Bridge by
+ * examining the _HID and _CID for the device.
+ *
+ ******************************************************************************/
+
+static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node)
+{
+ acpi_status status;
+ struct acpi_device_id hid;
+ struct acpi_compatible_id_list *cid;
+ acpi_native_uint i;
+
+ /*
+ * Get the _HID and check for a PCI Root Bridge
+ */
+ status = acpi_ut_execute_HID(node, &hid);
+ if (ACPI_FAILURE(status)) {
+ return (FALSE);
+ }
+
+ if (acpi_ev_match_pci_root_bridge(hid.value)) {
+ return (TRUE);
+ }
+
+ /*
+ * The _HID did not match.
+ * Get the _CID and check for a PCI Root Bridge
+ */
+ status = acpi_ut_execute_CID(node, &cid);
+ if (ACPI_FAILURE(status)) {
+ return (FALSE);
+ }
+
+ /* Check all _CIDs in the returned list */
+
+ for (i = 0; i < cid->count; i++) {
+ if (acpi_ev_match_pci_root_bridge(cid->id[i].value)) {
+ ACPI_FREE(cid);
+ return (TRUE);
+ }
+ }
+
+ ACPI_FREE(cid);
+ return (FALSE);
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_ev_pci_bar_region_setup
*
* PARAMETERS: Handle - Region we are interested in
@@ -432,6 +519,9 @@ acpi_ev_default_region_setup(acpi_handle handle,
* a PCI address in the scope of the definition. This address is
* required to perform an access to PCI config space.
*
+ * MUTEX: Interpreter should be unlocked, because we may run the _REG
+ * method for this region.
+ *
******************************************************************************/
acpi_status
diff --git a/drivers/acpi/events/evsci.c b/drivers/acpi/events/evsci.c
index 8106215ad55..7e5d15ce239 100644
--- a/drivers/acpi/events/evsci.c
+++ b/drivers/acpi/events/evsci.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -142,9 +142,10 @@ u32 acpi_ev_install_sci_handler(void)
ACPI_FUNCTION_TRACE(ev_install_sci_handler);
- status = acpi_os_install_interrupt_handler((u32) acpi_gbl_FADT->sci_int,
- acpi_ev_sci_xrupt_handler,
- acpi_gbl_gpe_xrupt_list_head);
+ status =
+ acpi_os_install_interrupt_handler((u32) acpi_gbl_FADT.sci_interrupt,
+ acpi_ev_sci_xrupt_handler,
+ acpi_gbl_gpe_xrupt_list_head);
return_ACPI_STATUS(status);
}
@@ -175,8 +176,9 @@ acpi_status acpi_ev_remove_sci_handler(void)
/* Just let the OS remove the handler and disable the level */
- status = acpi_os_remove_interrupt_handler((u32) acpi_gbl_FADT->sci_int,
- acpi_ev_sci_xrupt_handler);
+ status =
+ acpi_os_remove_interrupt_handler((u32) acpi_gbl_FADT.sci_interrupt,
+ acpi_ev_sci_xrupt_handler);
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/events/evxface.c b/drivers/acpi/events/evxface.c
index 923fd2b4695..685a103a358 100644
--- a/drivers/acpi/events/evxface.c
+++ b/drivers/acpi/events/evxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -768,11 +768,9 @@ acpi_status acpi_acquire_global_lock(u16 timeout, u32 * handle)
return (AE_BAD_PARAMETER);
}
- status = acpi_ex_enter_interpreter();
- if (ACPI_FAILURE(status)) {
- return (status);
- }
+ /* Must lock interpreter to prevent race conditions */
+ acpi_ex_enter_interpreter();
status = acpi_ev_acquire_global_lock(timeout);
acpi_ex_exit_interpreter();
diff --git a/drivers/acpi/events/evxfevnt.c b/drivers/acpi/events/evxfevnt.c
index 7ebc2efac93..17065e98807 100644
--- a/drivers/acpi/events/evxfevnt.c
+++ b/drivers/acpi/events/evxfevnt.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -44,6 +44,7 @@
#include <acpi/acpi.h>
#include <acpi/acevents.h>
#include <acpi/acnamesp.h>
+#include <acpi/actables.h>
#define _COMPONENT ACPI_EVENTS
ACPI_MODULE_NAME("evxfevnt")
@@ -65,13 +66,14 @@ acpi_status acpi_enable(void)
ACPI_FUNCTION_TRACE(acpi_enable);
- /* Make sure we have the FADT */
+ /* ACPI tables must be present */
- if (!acpi_gbl_FADT) {
- ACPI_WARNING((AE_INFO, "No FADT information present!"));
+ if (!acpi_tb_tables_loaded()) {
return_ACPI_STATUS(AE_NO_ACPI_TABLES);
}
+ /* Check current mode */
+
if (acpi_hw_get_mode() == ACPI_SYS_MODE_ACPI) {
ACPI_DEBUG_PRINT((ACPI_DB_INIT,
"System is already in ACPI mode\n"));
@@ -111,11 +113,6 @@ acpi_status acpi_disable(void)
ACPI_FUNCTION_TRACE(acpi_disable);
- if (!acpi_gbl_FADT) {
- ACPI_WARNING((AE_INFO, "No FADT information present!"));
- return_ACPI_STATUS(AE_NO_ACPI_TABLES);
- }
-
if (acpi_hw_get_mode() == ACPI_SYS_MODE_LEGACY) {
ACPI_DEBUG_PRINT((ACPI_DB_INIT,
"System is already in legacy (non-ACPI) mode\n"));
@@ -169,7 +166,7 @@ acpi_status acpi_enable_event(u32 event, u32 flags)
*/
status =
acpi_set_register(acpi_gbl_fixed_event_info[event].
- enable_register_id, 1, ACPI_MTX_LOCK);
+ enable_register_id, 1);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -178,7 +175,7 @@ acpi_status acpi_enable_event(u32 event, u32 flags)
status =
acpi_get_register(acpi_gbl_fixed_event_info[event].
- enable_register_id, &value, ACPI_MTX_LOCK);
+ enable_register_id, &value);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -368,14 +365,14 @@ acpi_status acpi_disable_event(u32 event, u32 flags)
*/
status =
acpi_set_register(acpi_gbl_fixed_event_info[event].
- enable_register_id, 0, ACPI_MTX_LOCK);
+ enable_register_id, 0);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
status =
acpi_get_register(acpi_gbl_fixed_event_info[event].
- enable_register_id, &value, ACPI_MTX_LOCK);
+ enable_register_id, &value);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -421,7 +418,7 @@ acpi_status acpi_clear_event(u32 event)
*/
status =
acpi_set_register(acpi_gbl_fixed_event_info[event].
- status_register_id, 1, ACPI_MTX_LOCK);
+ status_register_id, 1);
return_ACPI_STATUS(status);
}
@@ -510,7 +507,7 @@ acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status)
status =
acpi_get_register(acpi_gbl_fixed_event_info[event].
- status_register_id, event_status, ACPI_MTX_LOCK);
+ status_register_id, event_status);
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/events/evxfregn.c b/drivers/acpi/events/evxfregn.c
index 83b12a9afa3..7bf09c5fb24 100644
--- a/drivers/acpi/events/evxfregn.c
+++ b/drivers/acpi/events/evxfregn.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exconfig.c b/drivers/acpi/executer/exconfig.c
index c8341fa5fe0..25802f302ff 100644
--- a/drivers/acpi/executer/exconfig.c
+++ b/drivers/acpi/executer/exconfig.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -54,7 +54,7 @@ ACPI_MODULE_NAME("exconfig")
/* Local prototypes */
static acpi_status
-acpi_ex_add_table(struct acpi_table_header *table,
+acpi_ex_add_table(acpi_native_uint table_index,
struct acpi_namespace_node *parent_node,
union acpi_operand_object **ddb_handle);
@@ -74,12 +74,11 @@ acpi_ex_add_table(struct acpi_table_header *table,
******************************************************************************/
static acpi_status
-acpi_ex_add_table(struct acpi_table_header *table,
+acpi_ex_add_table(acpi_native_uint table_index,
struct acpi_namespace_node *parent_node,
union acpi_operand_object **ddb_handle)
{
acpi_status status;
- struct acpi_table_desc table_info;
union acpi_operand_object *obj_desc;
ACPI_FUNCTION_TRACE(ex_add_table);
@@ -98,42 +97,16 @@ acpi_ex_add_table(struct acpi_table_header *table,
/* Install the new table into the local data structures */
- ACPI_MEMSET(&table_info, 0, sizeof(struct acpi_table_desc));
-
- table_info.type = ACPI_TABLE_ID_SSDT;
- table_info.pointer = table;
- table_info.length = (acpi_size) table->length;
- table_info.allocation = ACPI_MEM_ALLOCATED;
-
- status = acpi_tb_install_table(&table_info);
- obj_desc->reference.object = table_info.installed_desc;
-
- if (ACPI_FAILURE(status)) {
- if (status == AE_ALREADY_EXISTS) {
-
- /* Table already exists, just return the handle */
-
- return_ACPI_STATUS(AE_OK);
- }
- goto cleanup;
- }
+ obj_desc->reference.object = ACPI_CAST_PTR(void, table_index);
/* Add the table to the namespace */
- status = acpi_ns_load_table(table_info.installed_desc, parent_node);
+ status = acpi_ns_load_table(table_index, parent_node);
if (ACPI_FAILURE(status)) {
-
- /* Uninstall table on error */
-
- (void)acpi_tb_uninstall_table(table_info.installed_desc);
- goto cleanup;
+ acpi_ut_remove_reference(obj_desc);
+ *ddb_handle = NULL;
}
- return_ACPI_STATUS(AE_OK);
-
- cleanup:
- acpi_ut_remove_reference(obj_desc);
- *ddb_handle = NULL;
return_ACPI_STATUS(status);
}
@@ -146,7 +119,7 @@ acpi_ex_add_table(struct acpi_table_header *table,
*
* RETURN: Status
*
- * DESCRIPTION: Load an ACPI table
+ * DESCRIPTION: Load an ACPI table from the RSDT/XSDT
*
******************************************************************************/
@@ -156,33 +129,20 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
{
acpi_status status;
union acpi_operand_object **operand = &walk_state->operands[0];
- struct acpi_table_header *table;
+ acpi_native_uint table_index;
struct acpi_namespace_node *parent_node;
struct acpi_namespace_node *start_node;
struct acpi_namespace_node *parameter_node = NULL;
union acpi_operand_object *ddb_handle;
+ struct acpi_table_header *table;
ACPI_FUNCTION_TRACE(ex_load_table_op);
-#if 0
- /*
- * Make sure that the signature does not match one of the tables that
- * is already loaded.
- */
- status = acpi_tb_match_signature(operand[0]->string.pointer, NULL);
- if (status == AE_OK) {
-
- /* Signature matched -- don't allow override */
-
- return_ACPI_STATUS(AE_ALREADY_EXISTS);
- }
-#endif
-
- /* Find the ACPI table */
+ /* Find the ACPI table in the RSDT/XSDT */
status = acpi_tb_find_table(operand[0]->string.pointer,
operand[1]->string.pointer,
- operand[2]->string.pointer, &table);
+ operand[2]->string.pointer, &table_index);
if (ACPI_FAILURE(status)) {
if (status != AE_NOT_FOUND) {
return_ACPI_STATUS(status);
@@ -245,7 +205,7 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
/* Load the table into the namespace */
- status = acpi_ex_add_table(table, parent_node, &ddb_handle);
+ status = acpi_ex_add_table(table_index, parent_node, &ddb_handle);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -266,9 +226,13 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
}
}
- ACPI_INFO((AE_INFO,
- "Dynamic OEM Table Load - [%4.4s] OemId [%6.6s] OemTableId [%8.8s]",
- table->signature, table->oem_id, table->oem_table_id));
+ status = acpi_get_table_by_index(table_index, &table);
+ if (ACPI_SUCCESS(status)) {
+ ACPI_INFO((AE_INFO,
+ "Dynamic OEM Table Load - [%4.4s] OemId [%6.6s] OemTableId [%8.8s]",
+ table->signature, table->oem_id,
+ table->oem_table_id));
+ }
*return_desc = ddb_handle;
return_ACPI_STATUS(status);
@@ -278,7 +242,7 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
*
* FUNCTION: acpi_ex_load_op
*
- * PARAMETERS: obj_desc - Region or Field where the table will be
+ * PARAMETERS: obj_desc - Region or Buffer/Field where the table will be
* obtained
* Target - Where a handle to the table will be stored
* walk_state - Current state
@@ -287,6 +251,12 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
*
* DESCRIPTION: Load an ACPI table from a field or operation region
*
+ * NOTE: Region Fields (Field, bank_field, index_fields) are resolved to buffer
+ * objects before this code is reached.
+ *
+ * If source is an operation region, it must refer to system_memory, as
+ * per the ACPI specification.
+ *
******************************************************************************/
acpi_status
@@ -294,22 +264,26 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
union acpi_operand_object *target,
struct acpi_walk_state *walk_state)
{
- acpi_status status;
union acpi_operand_object *ddb_handle;
- union acpi_operand_object *buffer_desc = NULL;
- struct acpi_table_header *table_ptr = NULL;
- acpi_physical_address address;
- struct acpi_table_header table_header;
- acpi_integer temp;
- u32 i;
+ struct acpi_table_desc table_desc;
+ acpi_native_uint table_index;
+ acpi_status status;
ACPI_FUNCTION_TRACE(ex_load_op);
- /* Object can be either an op_region or a Field */
+ ACPI_MEMSET(&table_desc, 0, sizeof(struct acpi_table_desc));
+
+ /* Source Object can be either an op_region or a Buffer/Field */
switch (ACPI_GET_OBJECT_TYPE(obj_desc)) {
case ACPI_TYPE_REGION:
+ /* Region must be system_memory (from ACPI spec) */
+
+ if (obj_desc->region.space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) {
+ return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
+ }
+
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Load from Region %p %s\n",
obj_desc,
acpi_ut_get_object_type_name(obj_desc)));
@@ -325,113 +299,41 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
}
}
- /* Get the base physical address of the region */
-
- address = obj_desc->region.address;
-
- /* Get part of the table header to get the table length */
-
- table_header.length = 0;
- for (i = 0; i < 8; i++) {
- status =
- acpi_ev_address_space_dispatch(obj_desc, ACPI_READ,
- (acpi_physical_address)
- (i + address), 8,
- &temp);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Get the one valid byte of the returned 64-bit value */
-
- ACPI_CAST_PTR(u8, &table_header)[i] = (u8) temp;
- }
-
- /* Sanity check the table length */
-
- if (table_header.length < sizeof(struct acpi_table_header)) {
- return_ACPI_STATUS(AE_BAD_HEADER);
- }
-
- /* Allocate a buffer for the entire table */
-
- table_ptr = ACPI_ALLOCATE(table_header.length);
- if (!table_ptr) {
- return_ACPI_STATUS(AE_NO_MEMORY);
- }
-
- /* Get the entire table from the op region */
-
- for (i = 0; i < table_header.length; i++) {
- status =
- acpi_ev_address_space_dispatch(obj_desc, ACPI_READ,
- (acpi_physical_address)
- (i + address), 8,
- &temp);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
- }
-
- /* Get the one valid byte of the returned 64-bit value */
-
- ACPI_CAST_PTR(u8, table_ptr)[i] = (u8) temp;
- }
+ table_desc.address = obj_desc->region.address;
+ table_desc.length = obj_desc->region.length;
+ table_desc.flags = ACPI_TABLE_ORIGIN_MAPPED;
break;
- case ACPI_TYPE_LOCAL_REGION_FIELD:
- case ACPI_TYPE_LOCAL_BANK_FIELD:
- case ACPI_TYPE_LOCAL_INDEX_FIELD:
+ case ACPI_TYPE_BUFFER: /* Buffer or resolved region_field */
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Load from Field %p %s\n",
- obj_desc,
- acpi_ut_get_object_type_name(obj_desc)));
+ /* Simply extract the buffer from the buffer object */
- /*
- * The length of the field must be at least as large as the table.
- * Read the entire field and thus the entire table. Buffer is
- * allocated during the read.
- */
- status =
- acpi_ex_read_data_from_field(walk_state, obj_desc,
- &buffer_desc);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- table_ptr = ACPI_CAST_PTR(struct acpi_table_header,
- buffer_desc->buffer.pointer);
-
- /* All done with the buffer_desc, delete it */
-
- buffer_desc->buffer.pointer = NULL;
- acpi_ut_remove_reference(buffer_desc);
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Load from Buffer or Field %p %s\n", obj_desc,
+ acpi_ut_get_object_type_name(obj_desc)));
- /* Sanity check the table length */
+ table_desc.pointer = ACPI_CAST_PTR(struct acpi_table_header,
+ obj_desc->buffer.pointer);
+ table_desc.length = table_desc.pointer->length;
+ table_desc.flags = ACPI_TABLE_ORIGIN_ALLOCATED;
- if (table_ptr->length < sizeof(struct acpi_table_header)) {
- status = AE_BAD_HEADER;
- goto cleanup;
- }
+ obj_desc->buffer.pointer = NULL;
break;
default:
return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
}
- /* The table must be either an SSDT or a PSDT */
-
- if ((!ACPI_COMPARE_NAME(table_ptr->signature, PSDT_SIG)) &&
- (!ACPI_COMPARE_NAME(table_ptr->signature, SSDT_SIG))) {
- ACPI_ERROR((AE_INFO,
- "Table has invalid signature [%4.4s], must be SSDT or PSDT",
- table_ptr->signature));
- status = AE_BAD_SIGNATURE;
+ /*
+ * Install the new table into the local data structures
+ */
+ status = acpi_tb_add_table(&table_desc, &table_index);
+ if (ACPI_FAILURE(status)) {
goto cleanup;
}
- /* Install the new table into the local data structures */
-
- status = acpi_ex_add_table(table_ptr, acpi_gbl_root_node, &ddb_handle);
+ status =
+ acpi_ex_add_table(table_index, acpi_gbl_root_node, &ddb_handle);
if (ACPI_FAILURE(status)) {
/* On error, table_ptr was deallocated above */
@@ -450,13 +352,9 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
return_ACPI_STATUS(status);
}
- ACPI_INFO((AE_INFO,
- "Dynamic SSDT Load - OemId [%6.6s] OemTableId [%8.8s]",
- table_ptr->oem_id, table_ptr->oem_table_id));
-
cleanup:
if (ACPI_FAILURE(status)) {
- ACPI_FREE(table_ptr);
+ acpi_tb_delete_table(&table_desc);
}
return_ACPI_STATUS(status);
}
@@ -477,7 +375,7 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle)
{
acpi_status status = AE_OK;
union acpi_operand_object *table_desc = ddb_handle;
- struct acpi_table_desc *table_info;
+ acpi_native_uint table_index;
ACPI_FUNCTION_TRACE(ex_unload_table);
@@ -493,19 +391,18 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle)
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- /* Get the actual table descriptor from the ddb_handle */
+ /* Get the table index from the ddb_handle */
- table_info = (struct acpi_table_desc *)table_desc->reference.object;
+ table_index = (acpi_native_uint) table_desc->reference.object;
/*
* Delete the entire namespace under this table Node
* (Offset contains the table_id)
*/
- acpi_ns_delete_namespace_by_owner(table_info->owner_id);
-
- /* Delete the table itself */
+ acpi_tb_delete_namespace_by_owner(table_index);
+ acpi_tb_release_owner_id(table_index);
- (void)acpi_tb_uninstall_table(table_info->installed_desc);
+ acpi_tb_set_table_loaded_flag(table_index, FALSE);
/* Delete the table descriptor (ddb_handle) */
diff --git a/drivers/acpi/executer/exconvrt.c b/drivers/acpi/executer/exconvrt.c
index 544e81a6a43..d470e8b1f4e 100644
--- a/drivers/acpi/executer/exconvrt.c
+++ b/drivers/acpi/executer/exconvrt.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/excreate.c b/drivers/acpi/executer/excreate.c
index 34eec82c1b1..7c38528a7e8 100644
--- a/drivers/acpi/executer/excreate.c
+++ b/drivers/acpi/executer/excreate.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -359,8 +359,9 @@ acpi_status acpi_ex_create_table_region(struct acpi_walk_state *walk_state)
union acpi_operand_object **operand = &walk_state->operands[0];
union acpi_operand_object *obj_desc;
struct acpi_namespace_node *node;
- struct acpi_table_header *table;
union acpi_operand_object *region_obj2;
+ acpi_native_uint table_index;
+ struct acpi_table_header *table;
ACPI_FUNCTION_TRACE(ex_create_table_region);
@@ -380,7 +381,7 @@ acpi_status acpi_ex_create_table_region(struct acpi_walk_state *walk_state)
status = acpi_tb_find_table(operand[1]->string.pointer,
operand[2]->string.pointer,
- operand[3]->string.pointer, &table);
+ operand[3]->string.pointer, &table_index);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -395,6 +396,11 @@ acpi_status acpi_ex_create_table_region(struct acpi_walk_state *walk_state)
region_obj2 = obj_desc->common.next_object;
region_obj2->extra.region_context = NULL;
+ status = acpi_get_table_by_index(table_index, &table);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
/* Init the region from the operands */
obj_desc->region.space_id = REGION_DATA_TABLE;
@@ -553,7 +559,8 @@ acpi_ex_create_method(u8 * aml_start,
obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_METHOD);
if (!obj_desc) {
- return_ACPI_STATUS(AE_NO_MEMORY);
+ status = AE_NO_MEMORY;
+ goto exit;
}
/* Save the method's AML pointer and length */
@@ -576,10 +583,7 @@ acpi_ex_create_method(u8 * aml_start,
* Get the sync_level. If method is serialized, a mutex will be
* created for this method when it is parsed.
*/
- if (acpi_gbl_all_methods_serialized) {
- obj_desc->method.sync_level = 0;
- obj_desc->method.method_flags |= AML_METHOD_SERIALIZED;
- } else if (method_flags & AML_METHOD_SERIALIZED) {
+ if (method_flags & AML_METHOD_SERIALIZED) {
/*
* ACPI 1.0: sync_level = 0
* ACPI 2.0: sync_level = sync_level in method declaration
@@ -597,6 +601,7 @@ acpi_ex_create_method(u8 * aml_start,
acpi_ut_remove_reference(obj_desc);
+ exit:
/* Remove a reference to the operand */
acpi_ut_remove_reference(operand[1]);
diff --git a/drivers/acpi/executer/exdump.c b/drivers/acpi/executer/exdump.c
index 2450943add3..68d283fd60e 100644
--- a/drivers/acpi/executer/exdump.c
+++ b/drivers/acpi/executer/exdump.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -59,8 +59,6 @@ static void acpi_ex_out_string(char *title, char *value);
static void acpi_ex_out_pointer(char *title, void *value);
-static void acpi_ex_out_address(char *title, acpi_physical_address value);
-
static void
acpi_ex_dump_object(union acpi_operand_object *obj_desc,
struct acpi_exdump_info *info);
@@ -92,10 +90,11 @@ static struct acpi_exdump_info acpi_ex_dump_string[4] = {
{ACPI_EXD_STRING, 0, NULL}
};
-static struct acpi_exdump_info acpi_ex_dump_buffer[4] = {
+static struct acpi_exdump_info acpi_ex_dump_buffer[5] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_buffer), NULL},
{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(buffer.length), "Length"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(buffer.pointer), "Pointer"},
+ {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(buffer.node), "Parent Node"},
{ACPI_EXD_BUFFER, 0, NULL}
};
@@ -165,8 +164,8 @@ static struct acpi_exdump_info acpi_ex_dump_power[5] = {
static struct acpi_exdump_info acpi_ex_dump_processor[7] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_processor), NULL},
- {ACPI_EXD_UINT32, ACPI_EXD_OFFSET(processor.proc_id), "Processor ID"},
- {ACPI_EXD_UINT32, ACPI_EXD_OFFSET(processor.length), "Length"},
+ {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(processor.proc_id), "Processor ID"},
+ {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(processor.length), "Length"},
{ACPI_EXD_ADDRESS, ACPI_EXD_OFFSET(processor.address), "Address"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(processor.system_notify),
"System Notify"},
@@ -379,18 +378,12 @@ acpi_ex_dump_object(union acpi_operand_object *obj_desc,
break;
case ACPI_EXD_POINTER:
+ case ACPI_EXD_ADDRESS:
acpi_ex_out_pointer(name,
*ACPI_CAST_PTR(void *, target));
break;
- case ACPI_EXD_ADDRESS:
-
- acpi_ex_out_address(name,
- *ACPI_CAST_PTR
- (acpi_physical_address, target));
- break;
-
case ACPI_EXD_STRING:
acpi_ut_print_string(obj_desc->string.pointer,
@@ -834,16 +827,6 @@ static void acpi_ex_out_pointer(char *title, void *value)
acpi_os_printf("%20s : %p\n", title, value);
}
-static void acpi_ex_out_address(char *title, acpi_physical_address value)
-{
-
-#if ACPI_MACHINE_WIDTH == 16
- acpi_os_printf("%20s : %p\n", title, value);
-#else
- acpi_os_printf("%20s : %8.8X%8.8X\n", title, ACPI_FORMAT_UINT64(value));
-#endif
-}
-
/*******************************************************************************
*
* FUNCTION: acpi_ex_dump_namespace_node
diff --git a/drivers/acpi/executer/exfield.c b/drivers/acpi/executer/exfield.c
index 9ea9c3a67ca..2d88a3d8d1a 100644
--- a/drivers/acpi/executer/exfield.c
+++ b/drivers/acpi/executer/exfield.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exfldio.c b/drivers/acpi/executer/exfldio.c
index 40f0bee6faa..65a48b6170e 100644
--- a/drivers/acpi/executer/exfldio.c
+++ b/drivers/acpi/executer/exfldio.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -257,14 +257,13 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc,
}
ACPI_DEBUG_PRINT_RAW((ACPI_DB_BFIELD,
- " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %8.8X%8.8X\n",
+ " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %p\n",
acpi_ut_get_region_name(rgn_desc->region.
space_id),
rgn_desc->region.space_id,
obj_desc->common_field.access_byte_width,
obj_desc->common_field.base_byte_offset,
- field_datum_byte_offset,
- ACPI_FORMAT_UINT64(address)));
+ field_datum_byte_offset, (void *)address));
/* Invoke the appropriate address_space/op_region handler */
diff --git a/drivers/acpi/executer/exmisc.c b/drivers/acpi/executer/exmisc.c
index bd98aab017c..f13d1cec2d6 100644
--- a/drivers/acpi/executer/exmisc.c
+++ b/drivers/acpi/executer/exmisc.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exmutex.c b/drivers/acpi/executer/exmutex.c
index bf90f04f2c6..5101bad5baf 100644
--- a/drivers/acpi/executer/exmutex.c
+++ b/drivers/acpi/executer/exmutex.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -44,6 +44,7 @@
#include <acpi/acpi.h>
#include <acpi/acinterp.h>
+#include <acpi/acevents.h>
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exmutex")
@@ -150,7 +151,7 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc,
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- /* Sanity check -- we must have a valid thread ID */
+ /* Sanity check: we must have a valid thread ID */
if (!walk_state->thread) {
ACPI_ERROR((AE_INFO,
@@ -174,24 +175,28 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc,
/* Support for multiple acquires by the owning thread */
if (obj_desc->mutex.owner_thread) {
-
- /* Special case for Global Lock, allow all threads */
-
- if ((obj_desc->mutex.owner_thread->thread_id ==
- walk_state->thread->thread_id) ||
- (obj_desc->mutex.os_mutex == ACPI_GLOBAL_LOCK)) {
+ if (obj_desc->mutex.owner_thread->thread_id ==
+ walk_state->thread->thread_id) {
/*
- * The mutex is already owned by this thread,
- * just increment the acquisition depth
+ * The mutex is already owned by this thread, just increment the
+ * acquisition depth
*/
obj_desc->mutex.acquisition_depth++;
return_ACPI_STATUS(AE_OK);
}
}
- /* Acquire the mutex, wait if necessary */
+ /* Acquire the mutex, wait if necessary. Special case for Global Lock */
+
+ if (obj_desc->mutex.os_mutex == acpi_gbl_global_lock_mutex) {
+ status =
+ acpi_ev_acquire_global_lock((u16) time_desc->integer.value);
+ } else {
+ status = acpi_ex_system_wait_mutex(obj_desc->mutex.os_mutex,
+ (u16) time_desc->integer.
+ value);
+ }
- status = acpi_ex_system_acquire_mutex(time_desc, obj_desc);
if (ACPI_FAILURE(status)) {
/* Includes failure from a timeout on time_desc */
@@ -211,7 +216,6 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc,
/* Link the mutex to the current thread for force-unlock at method exit */
acpi_ex_link_mutex(obj_desc, walk_state->thread);
-
return_ACPI_STATUS(AE_OK);
}
@@ -232,7 +236,7 @@ acpi_status
acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
struct acpi_walk_state *walk_state)
{
- acpi_status status;
+ acpi_status status = AE_OK;
ACPI_FUNCTION_TRACE(ex_release_mutex);
@@ -249,7 +253,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
return_ACPI_STATUS(AE_AML_MUTEX_NOT_ACQUIRED);
}
- /* Sanity check -- we must have a valid thread ID */
+ /* Sanity check: we must have a valid thread ID */
if (!walk_state->thread) {
ACPI_ERROR((AE_INFO,
@@ -264,7 +268,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
*/
if ((obj_desc->mutex.owner_thread->thread_id !=
walk_state->thread->thread_id)
- && (obj_desc->mutex.os_mutex != ACPI_GLOBAL_LOCK)) {
+ && (obj_desc->mutex.os_mutex != acpi_gbl_global_lock_mutex)) {
ACPI_ERROR((AE_INFO,
"Thread %lX cannot release Mutex [%4.4s] acquired by thread %lX",
(unsigned long)walk_state->thread->thread_id,
@@ -274,8 +278,8 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
}
/*
- * The sync level of the mutex must be less than or
- * equal to the current sync level
+ * The sync level of the mutex must be less than or equal to the current
+ * sync level
*/
if (obj_desc->mutex.sync_level > walk_state->thread->current_sync_level) {
ACPI_ERROR((AE_INFO,
@@ -298,11 +302,15 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
acpi_ex_unlink_mutex(obj_desc);
- /* Release the mutex */
+ /* Release the mutex, special case for Global Lock */
- status = acpi_ex_system_release_mutex(obj_desc);
+ if (obj_desc->mutex.os_mutex == acpi_gbl_global_lock_mutex) {
+ status = acpi_ev_release_global_lock();
+ } else {
+ acpi_os_release_mutex(obj_desc->mutex.os_mutex);
+ }
- /* Update the mutex and walk state, restore sync_level before acquire */
+ /* Update the mutex and restore sync_level */
obj_desc->mutex.owner_thread = NULL;
walk_state->thread->current_sync_level =
@@ -321,39 +329,49 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
*
* DESCRIPTION: Release all mutexes held by this thread
*
+ * NOTE: This function is called as the thread is exiting the interpreter.
+ * Mutexes are not released when an individual control method is exited, but
+ * only when the parent thread actually exits the interpreter. This allows one
+ * method to acquire a mutex, and a different method to release it, as long as
+ * this is performed underneath a single parent control method.
+ *
******************************************************************************/
void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread)
{
union acpi_operand_object *next = thread->acquired_mutex_list;
- union acpi_operand_object *this;
- acpi_status status;
+ union acpi_operand_object *obj_desc;
ACPI_FUNCTION_ENTRY();
/* Traverse the list of owned mutexes, releasing each one */
while (next) {
- this = next;
- next = this->mutex.next;
+ obj_desc = next;
+ next = obj_desc->mutex.next;
+
+ obj_desc->mutex.prev = NULL;
+ obj_desc->mutex.next = NULL;
+ obj_desc->mutex.acquisition_depth = 0;
+
+ /* Release the mutex, special case for Global Lock */
- this->mutex.acquisition_depth = 1;
- this->mutex.prev = NULL;
- this->mutex.next = NULL;
+ if (obj_desc->mutex.os_mutex == acpi_gbl_global_lock_mutex) {
- /* Release the mutex */
+ /* Ignore errors */
- status = acpi_ex_system_release_mutex(this);
- if (ACPI_FAILURE(status)) {
- continue;
+ (void)acpi_ev_release_global_lock();
+ } else {
+ acpi_os_release_mutex(obj_desc->mutex.os_mutex);
}
/* Mark mutex unowned */
- this->mutex.owner_thread = NULL;
+ obj_desc->mutex.owner_thread = NULL;
/* Update Thread sync_level (Last mutex is the important one) */
- thread->current_sync_level = this->mutex.original_sync_level;
+ thread->current_sync_level =
+ obj_desc->mutex.original_sync_level;
}
}
diff --git a/drivers/acpi/executer/exnames.c b/drivers/acpi/executer/exnames.c
index d3d70364626..1ee4fb1175c 100644
--- a/drivers/acpi/executer/exnames.c
+++ b/drivers/acpi/executer/exnames.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exoparg1.c b/drivers/acpi/executer/exoparg1.c
index 6374d8be88e..252f10acbbc 100644
--- a/drivers/acpi/executer/exoparg1.c
+++ b/drivers/acpi/executer/exoparg1.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -104,9 +104,7 @@ acpi_status acpi_ex_opcode_0A_0T_1R(struct acpi_walk_state *walk_state)
status = AE_NO_MEMORY;
goto cleanup;
}
-#if ACPI_MACHINE_WIDTH != 16
return_desc->integer.value = acpi_os_get_timer();
-#endif
break;
default: /* Unknown opcode */
diff --git a/drivers/acpi/executer/exoparg2.c b/drivers/acpi/executer/exoparg2.c
index 7d2cbc11316..17e652e6537 100644
--- a/drivers/acpi/executer/exoparg2.c
+++ b/drivers/acpi/executer/exoparg2.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exoparg3.c b/drivers/acpi/executer/exoparg3.c
index e2d945dfd50..7fe67cf82ce 100644
--- a/drivers/acpi/executer/exoparg3.c
+++ b/drivers/acpi/executer/exoparg3.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exoparg6.c b/drivers/acpi/executer/exoparg6.c
index f0c0ba6eb40..bd80a9cb3d6 100644
--- a/drivers/acpi/executer/exoparg6.c
+++ b/drivers/acpi/executer/exoparg6.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exprep.c b/drivers/acpi/executer/exprep.c
index 44d064f427b..a6696621ff1 100644
--- a/drivers/acpi/executer/exprep.c
+++ b/drivers/acpi/executer/exprep.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exregion.c b/drivers/acpi/executer/exregion.c
index 3cc97ba48b3..2e9ce94798c 100644
--- a/drivers/acpi/executer/exregion.c
+++ b/drivers/acpi/executer/exregion.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -155,16 +155,15 @@ acpi_ex_system_memory_space_handler(u32 function,
/* Create a new mapping starting at the address given */
- status = acpi_os_map_memory(address, window_size,
- (void **)&mem_info->
- mapped_logical_address);
- if (ACPI_FAILURE(status)) {
+ mem_info->mapped_logical_address =
+ acpi_os_map_memory((acpi_native_uint) address, window_size);
+ if (!mem_info->mapped_logical_address) {
ACPI_ERROR((AE_INFO,
"Could not map memory at %8.8X%8.8X, size %X",
ACPI_FORMAT_UINT64(address),
(u32) window_size));
mem_info->mapped_length = 0;
- return_ACPI_STATUS(status);
+ return_ACPI_STATUS(AE_NO_MEMORY);
}
/* Save the physical address and mapping size */
@@ -210,11 +209,10 @@ acpi_ex_system_memory_space_handler(u32 function,
*value = (acpi_integer) ACPI_GET32(logical_addr_ptr);
break;
-#if ACPI_MACHINE_WIDTH != 16
case 64:
*value = (acpi_integer) ACPI_GET64(logical_addr_ptr);
break;
-#endif
+
default:
/* bit_width was already validated */
break;
@@ -236,11 +234,9 @@ acpi_ex_system_memory_space_handler(u32 function,
ACPI_SET32(logical_addr_ptr) = (u32) * value;
break;
-#if ACPI_MACHINE_WIDTH != 16
case 64:
ACPI_SET64(logical_addr_ptr) = (u64) * value;
break;
-#endif
default:
/* bit_width was already validated */
diff --git a/drivers/acpi/executer/exresnte.c b/drivers/acpi/executer/exresnte.c
index 3089b05a136..2b3a01cc492 100644
--- a/drivers/acpi/executer/exresnte.c
+++ b/drivers/acpi/executer/exresnte.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exresolv.c b/drivers/acpi/executer/exresolv.c
index 6499de87801..6c64e55dab0 100644
--- a/drivers/acpi/executer/exresolv.c
+++ b/drivers/acpi/executer/exresolv.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -141,7 +141,7 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
acpi_status status = AE_OK;
union acpi_operand_object *stack_desc;
void *temp_node;
- union acpi_operand_object *obj_desc;
+ union acpi_operand_object *obj_desc = NULL;
u16 opcode;
ACPI_FUNCTION_TRACE(ex_resolve_object_to_value);
@@ -299,8 +299,6 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
status = acpi_ds_get_package_arguments(stack_desc);
break;
- /* These cases may never happen here, but just in case.. */
-
case ACPI_TYPE_BUFFER_FIELD:
case ACPI_TYPE_LOCAL_REGION_FIELD:
case ACPI_TYPE_LOCAL_BANK_FIELD:
@@ -314,6 +312,10 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
status =
acpi_ex_read_data_from_field(walk_state, stack_desc,
&obj_desc);
+
+ /* Remove a reference to the original operand, then override */
+
+ acpi_ut_remove_reference(*stack_ptr);
*stack_ptr = (void *)obj_desc;
break;
diff --git a/drivers/acpi/executer/exresop.c b/drivers/acpi/executer/exresop.c
index 4c93d097233..ba761862a59 100644
--- a/drivers/acpi/executer/exresop.c
+++ b/drivers/acpi/executer/exresop.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -611,22 +611,20 @@ acpi_ex_resolve_operands(u16 opcode,
}
goto next_operand;
- case ARGI_REGION_OR_FIELD:
+ case ARGI_REGION_OR_BUFFER: /* Used by Load() only */
- /* Need an operand of type REGION or a FIELD in a region */
+ /* Need an operand of type REGION or a BUFFER (which could be a resolved region field) */
switch (ACPI_GET_OBJECT_TYPE(obj_desc)) {
+ case ACPI_TYPE_BUFFER:
case ACPI_TYPE_REGION:
- case ACPI_TYPE_LOCAL_REGION_FIELD:
- case ACPI_TYPE_LOCAL_BANK_FIELD:
- case ACPI_TYPE_LOCAL_INDEX_FIELD:
/* Valid operand */
break;
default:
ACPI_ERROR((AE_INFO,
- "Needed [Region/RegionField], found [%s] %p",
+ "Needed [Region/Buffer], found [%s] %p",
acpi_ut_get_object_type_name
(obj_desc), obj_desc));
diff --git a/drivers/acpi/executer/exstore.c b/drivers/acpi/executer/exstore.c
index 0456405ba01..f4b69a63782 100644
--- a/drivers/acpi/executer/exstore.c
+++ b/drivers/acpi/executer/exstore.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exstoren.c b/drivers/acpi/executer/exstoren.c
index 591aaf0e18b..1d622c625c6 100644
--- a/drivers/acpi/executer/exstoren.c
+++ b/drivers/acpi/executer/exstoren.c
@@ -7,7 +7,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exstorob.c b/drivers/acpi/executer/exstorob.c
index 99ebe5adfcd..8233d40178e 100644
--- a/drivers/acpi/executer/exstorob.c
+++ b/drivers/acpi/executer/exstorob.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exsystem.c b/drivers/acpi/executer/exsystem.c
index 28aef3e69ec..9460baff303 100644
--- a/drivers/acpi/executer/exsystem.c
+++ b/drivers/acpi/executer/exsystem.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -66,7 +66,6 @@ ACPI_MODULE_NAME("exsystem")
acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout)
{
acpi_status status;
- acpi_status status2;
ACPI_FUNCTION_TRACE(ex_system_wait_semaphore);
@@ -79,7 +78,7 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout)
/* We must wait, so unlock the interpreter */
- acpi_ex_exit_interpreter();
+ acpi_ex_relinquish_interpreter();
status = acpi_os_wait_semaphore(semaphore, 1, timeout);
@@ -89,13 +88,7 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout)
/* Reacquire the interpreter */
- status2 = acpi_ex_enter_interpreter();
- if (ACPI_FAILURE(status2)) {
-
- /* Report fatal error, could not acquire interpreter */
-
- return_ACPI_STATUS(status2);
- }
+ acpi_ex_reacquire_interpreter();
}
return_ACPI_STATUS(status);
@@ -119,7 +112,6 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout)
acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout)
{
acpi_status status;
- acpi_status status2;
ACPI_FUNCTION_TRACE(ex_system_wait_mutex);
@@ -132,7 +124,7 @@ acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout)
/* We must wait, so unlock the interpreter */
- acpi_ex_exit_interpreter();
+ acpi_ex_relinquish_interpreter();
status = acpi_os_acquire_mutex(mutex, timeout);
@@ -142,13 +134,7 @@ acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout)
/* Reacquire the interpreter */
- status2 = acpi_ex_enter_interpreter();
- if (ACPI_FAILURE(status2)) {
-
- /* Report fatal error, could not acquire interpreter */
-
- return_ACPI_STATUS(status2);
- }
+ acpi_ex_reacquire_interpreter();
}
return_ACPI_STATUS(status);
@@ -209,96 +195,18 @@ acpi_status acpi_ex_system_do_stall(u32 how_long)
acpi_status acpi_ex_system_do_suspend(acpi_integer how_long)
{
- acpi_status status;
-
ACPI_FUNCTION_ENTRY();
/* Since this thread will sleep, we must release the interpreter */
- acpi_ex_exit_interpreter();
+ acpi_ex_relinquish_interpreter();
acpi_os_sleep(how_long);
/* And now we must get the interpreter again */
- status = acpi_ex_enter_interpreter();
- return (status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ex_system_acquire_mutex
- *
- * PARAMETERS: time_desc - Maximum time to wait for the mutex
- * obj_desc - The object descriptor for this op
- *
- * RETURN: Status
- *
- * DESCRIPTION: Provides an access point to perform synchronization operations
- * within the AML. This function will cause a lock to be generated
- * for the Mutex pointed to by obj_desc.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ex_system_acquire_mutex(union acpi_operand_object * time_desc,
- union acpi_operand_object * obj_desc)
-{
- acpi_status status = AE_OK;
-
- ACPI_FUNCTION_TRACE_PTR(ex_system_acquire_mutex, obj_desc);
-
- if (!obj_desc) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- /* Support for the _GL_ Mutex object -- go get the global lock */
-
- if (obj_desc->mutex.os_mutex == ACPI_GLOBAL_LOCK) {
- status =
- acpi_ev_acquire_global_lock((u16) time_desc->integer.value);
- return_ACPI_STATUS(status);
- }
-
- status = acpi_ex_system_wait_mutex(obj_desc->mutex.os_mutex,
- (u16) time_desc->integer.value);
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ex_system_release_mutex
- *
- * PARAMETERS: obj_desc - The object descriptor for this op
- *
- * RETURN: Status
- *
- * DESCRIPTION: Provides an access point to perform synchronization operations
- * within the AML. This operation is a request to release a
- * previously acquired Mutex. If the Mutex variable is set then
- * it will be decremented.
- *
- ******************************************************************************/
-
-acpi_status acpi_ex_system_release_mutex(union acpi_operand_object *obj_desc)
-{
- acpi_status status = AE_OK;
-
- ACPI_FUNCTION_TRACE(ex_system_release_mutex);
-
- if (!obj_desc) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- /* Support for the _GL_ Mutex object -- release the global lock */
-
- if (obj_desc->mutex.os_mutex == ACPI_GLOBAL_LOCK) {
- status = acpi_ev_release_global_lock();
- return_ACPI_STATUS(status);
- }
-
- acpi_os_release_mutex(obj_desc->mutex.os_mutex);
- return_ACPI_STATUS(AE_OK);
+ acpi_ex_reacquire_interpreter();
+ return (AE_OK);
}
/*******************************************************************************
@@ -314,7 +222,7 @@ acpi_status acpi_ex_system_release_mutex(union acpi_operand_object *obj_desc)
*
******************************************************************************/
-acpi_status acpi_ex_system_signal_event(union acpi_operand_object *obj_desc)
+acpi_status acpi_ex_system_signal_event(union acpi_operand_object * obj_desc)
{
acpi_status status = AE_OK;
diff --git a/drivers/acpi/executer/exutils.c b/drivers/acpi/executer/exutils.c
index 982c8b65876..6b0aeccbb69 100644
--- a/drivers/acpi/executer/exutils.c
+++ b/drivers/acpi/executer/exutils.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -76,14 +76,15 @@ static u32 acpi_ex_digits_needed(acpi_integer value, u32 base);
*
* PARAMETERS: None
*
- * RETURN: Status
+ * RETURN: None
*
- * DESCRIPTION: Enter the interpreter execution region. Failure to enter
- * the interpreter region is a fatal system error
+ * DESCRIPTION: Enter the interpreter execution region. Failure to enter
+ * the interpreter region is a fatal system error. Used in
+ * conjunction with exit_interpreter.
*
******************************************************************************/
-acpi_status acpi_ex_enter_interpreter(void)
+void acpi_ex_enter_interpreter(void)
{
acpi_status status;
@@ -91,31 +92,55 @@ acpi_status acpi_ex_enter_interpreter(void)
status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER);
if (ACPI_FAILURE(status)) {
- ACPI_ERROR((AE_INFO, "Could not acquire interpreter mutex"));
+ ACPI_ERROR((AE_INFO,
+ "Could not acquire AML Interpreter mutex"));
}
- return_ACPI_STATUS(status);
+ return_VOID;
}
/*******************************************************************************
*
- * FUNCTION: acpi_ex_exit_interpreter
+ * FUNCTION: acpi_ex_reacquire_interpreter
*
* PARAMETERS: None
*
* RETURN: None
*
- * DESCRIPTION: Exit the interpreter execution region
+ * DESCRIPTION: Reacquire the interpreter execution region from within the
+ * interpreter code. Failure to enter the interpreter region is a
+ * fatal system error. Used in conjuction with
+ * relinquish_interpreter
+ *
+ ******************************************************************************/
+
+void acpi_ex_reacquire_interpreter(void)
+{
+ ACPI_FUNCTION_TRACE(ex_reacquire_interpreter);
+
+ /*
+ * If the global serialized flag is set, do not release the interpreter,
+ * since it was not actually released by acpi_ex_relinquish_interpreter.
+ * This forces the interpreter to be single threaded.
+ */
+ if (!acpi_gbl_all_methods_serialized) {
+ acpi_ex_enter_interpreter();
+ }
+
+ return_VOID;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_exit_interpreter
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: None
*
- * Cases where the interpreter is unlocked:
- * 1) Completion of the execution of a control method
- * 2) Method blocked on a Sleep() AML opcode
- * 3) Method blocked on an Acquire() AML opcode
- * 4) Method blocked on a Wait() AML opcode
- * 5) Method blocked to acquire the global lock
- * 6) Method blocked to execute a serialized control method that is
- * already executing
- * 7) About to invoke a user-installed opregion handler
+ * DESCRIPTION: Exit the interpreter execution region. This is the top level
+ * routine used to exit the interpreter when all processing has
+ * been completed.
*
******************************************************************************/
@@ -127,7 +152,46 @@ void acpi_ex_exit_interpreter(void)
status = acpi_ut_release_mutex(ACPI_MTX_INTERPRETER);
if (ACPI_FAILURE(status)) {
- ACPI_ERROR((AE_INFO, "Could not release interpreter mutex"));
+ ACPI_ERROR((AE_INFO,
+ "Could not release AML Interpreter mutex"));
+ }
+
+ return_VOID;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_relinquish_interpreter
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Exit the interpreter execution region, from within the
+ * interpreter - before attempting an operation that will possibly
+ * block the running thread.
+ *
+ * Cases where the interpreter is unlocked internally
+ * 1) Method to be blocked on a Sleep() AML opcode
+ * 2) Method to be blocked on an Acquire() AML opcode
+ * 3) Method to be blocked on a Wait() AML opcode
+ * 4) Method to be blocked to acquire the global lock
+ * 5) Method to be blocked waiting to execute a serialized control method
+ * that is currently executing
+ * 6) About to invoke a user-installed opregion handler
+ *
+ ******************************************************************************/
+
+void acpi_ex_relinquish_interpreter(void)
+{
+ ACPI_FUNCTION_TRACE(ex_relinquish_interpreter);
+
+ /*
+ * If the global serialized flag is set, do not release the interpreter.
+ * This forces the interpreter to be single threaded.
+ */
+ if (!acpi_gbl_all_methods_serialized) {
+ acpi_ex_exit_interpreter();
}
return_VOID;
@@ -141,8 +205,8 @@ void acpi_ex_exit_interpreter(void)
*
* RETURN: none
*
- * DESCRIPTION: Truncate a number to 32-bits if the currently executing method
- * belongs to a 32-bit ACPI table.
+ * DESCRIPTION: Truncate an ACPI Integer to 32 bits if the execution mode is
+ * 32-bit, as determined by the revision of the DSDT.
*
******************************************************************************/
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index f305a826ca2..af22fdf7341 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -48,8 +48,8 @@ MODULE_LICENSE("GPL");
static int acpi_fan_add(struct acpi_device *device);
static int acpi_fan_remove(struct acpi_device *device, int type);
-static int acpi_fan_suspend(struct acpi_device *device, int state);
-static int acpi_fan_resume(struct acpi_device *device, int state);
+static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state);
+static int acpi_fan_resume(struct acpi_device *device);
static struct acpi_driver acpi_fan_driver = {
.name = ACPI_FAN_DRIVER_NAME,
@@ -237,7 +237,7 @@ static int acpi_fan_remove(struct acpi_device *device, int type)
return 0;
}
-static int acpi_fan_suspend(struct acpi_device *device, int state)
+static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state)
{
if (!device)
return -EINVAL;
@@ -247,7 +247,7 @@ static int acpi_fan_suspend(struct acpi_device *device, int state)
return AE_OK;
}
-static int acpi_fan_resume(struct acpi_device *device, int state)
+static int acpi_fan_resume(struct acpi_device *device)
{
int result = 0;
int power_state = 0;
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 8a0324b43e5..7b6c9ff9beb 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -86,129 +86,6 @@ static int acpi_find_bridge_device(struct device *dev, acpi_handle * handle)
return ret;
}
-/* Get PCI root bridge's handle from its segment and bus number */
-struct acpi_find_pci_root {
- unsigned int seg;
- unsigned int bus;
- acpi_handle handle;
-};
-
-static acpi_status
-do_root_bridge_busnr_callback(struct acpi_resource *resource, void *data)
-{
- unsigned long *busnr = data;
- struct acpi_resource_address64 address;
-
- if (resource->type != ACPI_RESOURCE_TYPE_ADDRESS16 &&
- resource->type != ACPI_RESOURCE_TYPE_ADDRESS32 &&
- resource->type != ACPI_RESOURCE_TYPE_ADDRESS64)
- return AE_OK;
-
- acpi_resource_to_address64(resource, &address);
- if ((address.address_length > 0) &&
- (address.resource_type == ACPI_BUS_NUMBER_RANGE))
- *busnr = address.minimum;
-
- return AE_OK;
-}
-
-static int get_root_bridge_busnr(acpi_handle handle)
-{
- acpi_status status;
- unsigned long bus, bbn;
- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-
- acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
-
- status = acpi_evaluate_integer(handle, METHOD_NAME__BBN, NULL,
- &bbn);
- if (status == AE_NOT_FOUND) {
- /* Assume bus = 0 */
- printk(KERN_INFO PREFIX
- "Assume root bridge [%s] bus is 0\n",
- (char *)buffer.pointer);
- status = AE_OK;
- bbn = 0;
- }
- if (ACPI_FAILURE(status)) {
- bbn = -ENODEV;
- goto exit;
- }
- if (bbn > 0)
- goto exit;
-
- /* _BBN in some systems return 0 for all root bridges */
- bus = -1;
- status = acpi_walk_resources(handle, METHOD_NAME__CRS,
- do_root_bridge_busnr_callback, &bus);
- /* If _CRS failed, we just use _BBN */
- if (ACPI_FAILURE(status) || (bus == -1))
- goto exit;
- /* We select _CRS */
- if (bbn != bus) {
- printk(KERN_INFO PREFIX
- "_BBN and _CRS returns different value for %s. Select _CRS\n",
- (char *)buffer.pointer);
- bbn = bus;
- }
- exit:
- kfree(buffer.pointer);
- return (int)bbn;
-}
-
-static acpi_status
-find_pci_rootbridge(acpi_handle handle, u32 lvl, void *context, void **rv)
-{
- struct acpi_find_pci_root *find = (struct acpi_find_pci_root *)context;
- unsigned long seg, bus;
- acpi_status status;
- int tmp;
- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-
- acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
-
- status = acpi_evaluate_integer(handle, METHOD_NAME__SEG, NULL, &seg);
- if (status == AE_NOT_FOUND) {
- /* Assume seg = 0 */
- status = AE_OK;
- seg = 0;
- }
- if (ACPI_FAILURE(status)) {
- status = AE_CTRL_DEPTH;
- goto exit;
- }
-
- tmp = get_root_bridge_busnr(handle);
- if (tmp < 0) {
- printk(KERN_ERR PREFIX
- "Find root bridge failed for %s\n",
- (char *)buffer.pointer);
- status = AE_CTRL_DEPTH;
- goto exit;
- }
- bus = tmp;
-
- if (seg == find->seg && bus == find->bus)
- {
- find->handle = handle;
- status = AE_CTRL_TERMINATE;
- }
- else
- status = AE_OK;
- exit:
- kfree(buffer.pointer);
- return status;
-}
-
-acpi_handle acpi_get_pci_rootbridge_handle(unsigned int seg, unsigned int bus)
-{
- struct acpi_find_pci_root find = { seg, bus, NULL };
-
- acpi_get_devices(PCI_ROOT_HID_STRING, find_pci_rootbridge, &find, NULL);
- return find.handle;
-}
-EXPORT_SYMBOL_GPL(acpi_get_pci_rootbridge_handle);
-
/* Get device's handler per its address under its parent */
struct acpi_find_child {
acpi_handle handle;
diff --git a/drivers/acpi/hardware/hwacpi.c b/drivers/acpi/hardware/hwacpi.c
index de50fab2a91..6031ca13dd2 100644
--- a/drivers/acpi/hardware/hwacpi.c
+++ b/drivers/acpi/hardware/hwacpi.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -49,41 +49,6 @@ ACPI_MODULE_NAME("hwacpi")
/******************************************************************************
*
- * FUNCTION: acpi_hw_initialize
- *
- * PARAMETERS: None
- *
- * RETURN: Status
- *
- * DESCRIPTION: Initialize and validate the various ACPI registers defined in
- * the FADT.
- *
- ******************************************************************************/
-acpi_status acpi_hw_initialize(void)
-{
- acpi_status status;
-
- ACPI_FUNCTION_TRACE(hw_initialize);
-
- /* We must have the ACPI tables by the time we get here */
-
- if (!acpi_gbl_FADT) {
- ACPI_ERROR((AE_INFO, "No FADT is present"));
- return_ACPI_STATUS(AE_NO_ACPI_TABLES);
- }
-
- /* Sanity check the FADT for valid values */
-
- status = acpi_ut_validate_fadt();
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- return_ACPI_STATUS(AE_OK);
-}
-
-/******************************************************************************
- *
* FUNCTION: acpi_hw_set_mode
*
* PARAMETERS: Mode - SYS_MODE_ACPI or SYS_MODE_LEGACY
@@ -93,7 +58,6 @@ acpi_status acpi_hw_initialize(void)
* DESCRIPTION: Transitions the system into the requested mode.
*
******************************************************************************/
-
acpi_status acpi_hw_set_mode(u32 mode)
{
@@ -106,7 +70,7 @@ acpi_status acpi_hw_set_mode(u32 mode)
* ACPI 2.0 clarified that if SMI_CMD in FADT is zero,
* system does not support mode transition.
*/
- if (!acpi_gbl_FADT->smi_cmd) {
+ if (!acpi_gbl_FADT.smi_command) {
ACPI_ERROR((AE_INFO,
"No SMI_CMD in FADT, mode transition failed"));
return_ACPI_STATUS(AE_NO_HARDWARE_RESPONSE);
@@ -119,7 +83,7 @@ acpi_status acpi_hw_set_mode(u32 mode)
* we make sure both the numbers are zero to determine these
* transitions are not supported.
*/
- if (!acpi_gbl_FADT->acpi_enable && !acpi_gbl_FADT->acpi_disable) {
+ if (!acpi_gbl_FADT.acpi_enable && !acpi_gbl_FADT.acpi_disable) {
ACPI_ERROR((AE_INFO,
"No ACPI mode transition supported in this system (enable/disable both zero)"));
return_ACPI_STATUS(AE_OK);
@@ -130,9 +94,8 @@ acpi_status acpi_hw_set_mode(u32 mode)
/* BIOS should have disabled ALL fixed and GP events */
- status = acpi_os_write_port(acpi_gbl_FADT->smi_cmd,
- (u32) acpi_gbl_FADT->acpi_enable,
- 8);
+ status = acpi_os_write_port(acpi_gbl_FADT.smi_command,
+ (u32) acpi_gbl_FADT.acpi_enable, 8);
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Attempting to enable ACPI mode\n"));
break;
@@ -143,8 +106,8 @@ acpi_status acpi_hw_set_mode(u32 mode)
* BIOS should clear all fixed status bits and restore fixed event
* enable bits to default
*/
- status = acpi_os_write_port(acpi_gbl_FADT->smi_cmd,
- (u32) acpi_gbl_FADT->acpi_disable,
+ status = acpi_os_write_port(acpi_gbl_FADT.smi_command,
+ (u32) acpi_gbl_FADT.acpi_disable,
8);
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Attempting to enable Legacy (non-ACPI) mode\n"));
@@ -204,12 +167,11 @@ u32 acpi_hw_get_mode(void)
* ACPI 2.0 clarified that if SMI_CMD in FADT is zero,
* system does not support mode transition.
*/
- if (!acpi_gbl_FADT->smi_cmd) {
+ if (!acpi_gbl_FADT.smi_command) {
return_UINT32(ACPI_SYS_MODE_ACPI);
}
- status =
- acpi_get_register(ACPI_BITREG_SCI_ENABLE, &value, ACPI_MTX_LOCK);
+ status = acpi_get_register(ACPI_BITREG_SCI_ENABLE, &value);
if (ACPI_FAILURE(status)) {
return_UINT32(ACPI_SYS_MODE_LEGACY);
}
diff --git a/drivers/acpi/hardware/hwgpe.c b/drivers/acpi/hardware/hwgpe.c
index 608a3a60ee1..117a05cadaa 100644
--- a/drivers/acpi/hardware/hwgpe.c
+++ b/drivers/acpi/hardware/hwgpe.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -105,14 +105,20 @@ acpi_hw_write_gpe_enable_reg(struct acpi_gpe_event_info *gpe_event_info)
acpi_status acpi_hw_clear_gpe(struct acpi_gpe_event_info * gpe_event_info)
{
acpi_status status;
+ u8 register_bit;
ACPI_FUNCTION_ENTRY();
+ register_bit = (u8)
+ (1 <<
+ (gpe_event_info->gpe_number -
+ gpe_event_info->register_info->base_gpe_number));
+
/*
* Write a one to the appropriate bit in the status register to
* clear this GPE.
*/
- status = acpi_hw_low_level_write(8, gpe_event_info->register_bit,
+ status = acpi_hw_low_level_write(8, register_bit,
&gpe_event_info->register_info->
status_address);
@@ -155,7 +161,10 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info,
/* Get the register bitmask for this GPE */
- register_bit = gpe_event_info->register_bit;
+ register_bit = (u8)
+ (1 <<
+ (gpe_event_info->gpe_number -
+ gpe_event_info->register_info->base_gpe_number));
/* GPE currently enabled? (enabled for runtime?) */
diff --git a/drivers/acpi/hardware/hwregs.c b/drivers/acpi/hardware/hwregs.c
index fa58c1edce1..1d371fa663f 100644
--- a/drivers/acpi/hardware/hwregs.c
+++ b/drivers/acpi/hardware/hwregs.c
@@ -7,7 +7,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -54,17 +54,15 @@ ACPI_MODULE_NAME("hwregs")
*
* FUNCTION: acpi_hw_clear_acpi_status
*
- * PARAMETERS: Flags - Lock the hardware or not
+ * PARAMETERS: None
*
- * RETURN: none
+ * RETURN: None
*
* DESCRIPTION: Clears all fixed and general purpose status bits
* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
*
- * NOTE: TBD: Flags parameter is obsolete, to be removed
- *
******************************************************************************/
-acpi_status acpi_hw_clear_acpi_status(u32 flags)
+acpi_status acpi_hw_clear_acpi_status(void)
{
acpi_status status;
acpi_cpu_flags lock_flags = 0;
@@ -73,7 +71,7 @@ acpi_status acpi_hw_clear_acpi_status(u32 flags)
ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %04X\n",
ACPI_BITMASK_ALL_FIXED_STATUS,
- (u16) acpi_gbl_FADT->xpm1a_evt_blk.address));
+ (u16) acpi_gbl_FADT.xpm1a_event_block.address));
lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock);
@@ -86,10 +84,10 @@ acpi_status acpi_hw_clear_acpi_status(u32 flags)
/* Clear the fixed events */
- if (acpi_gbl_FADT->xpm1b_evt_blk.address) {
+ if (acpi_gbl_FADT.xpm1b_event_block.address) {
status =
acpi_hw_low_level_write(16, ACPI_BITMASK_ALL_FIXED_STATUS,
- &acpi_gbl_FADT->xpm1b_evt_blk);
+ &acpi_gbl_FADT.xpm1b_event_block);
if (ACPI_FAILURE(status)) {
goto unlock_and_exit;
}
@@ -253,18 +251,15 @@ struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id)
*
* PARAMETERS: register_id - ID of ACPI bit_register to access
* return_value - Value that was read from the register
- * Flags - Lock the hardware or not
*
* RETURN: Status and the value read from specified Register. Value
* returned is normalized to bit0 (is shifted all the way right)
*
* DESCRIPTION: ACPI bit_register read function.
*
- * NOTE: TBD: Flags parameter is obsolete, to be removed
- *
******************************************************************************/
-acpi_status acpi_get_register(u32 register_id, u32 * return_value, u32 flags)
+acpi_status acpi_get_register(u32 register_id, u32 * return_value)
{
u32 register_value = 0;
struct acpi_bit_register_info *bit_reg_info;
@@ -312,16 +307,13 @@ ACPI_EXPORT_SYMBOL(acpi_get_register)
* PARAMETERS: register_id - ID of ACPI bit_register to access
* Value - (only used on write) value to write to the
* Register, NOT pre-normalized to the bit pos
- * Flags - Lock the hardware or not
*
* RETURN: Status
*
* DESCRIPTION: ACPI Bit Register write function.
*
- * NOTE: TBD: Flags parameter is obsolete, to be removed
- *
******************************************************************************/
-acpi_status acpi_set_register(u32 register_id, u32 value, u32 flags)
+acpi_status acpi_set_register(u32 register_id, u32 value)
{
u32 register_value = 0;
struct acpi_bit_register_info *bit_reg_info;
@@ -422,8 +414,9 @@ acpi_status acpi_set_register(u32 register_id, u32 value, u32 flags)
ACPI_DEBUG_PRINT((ACPI_DB_IO,
"PM2 control: Read %X from %8.8X%8.8X\n",
register_value,
- ACPI_FORMAT_UINT64(acpi_gbl_FADT->
- xpm2_cnt_blk.address)));
+ ACPI_FORMAT_UINT64(acpi_gbl_FADT.
+ xpm2_control_block.
+ address)));
ACPI_REGISTER_INSERT_VALUE(register_value,
bit_reg_info->bit_position,
@@ -433,8 +426,9 @@ acpi_status acpi_set_register(u32 register_id, u32 value, u32 flags)
ACPI_DEBUG_PRINT((ACPI_DB_IO,
"About to write %4.4X to %8.8X%8.8X\n",
register_value,
- ACPI_FORMAT_UINT64(acpi_gbl_FADT->
- xpm2_cnt_blk.address)));
+ ACPI_FORMAT_UINT64(acpi_gbl_FADT.
+ xpm2_control_block.
+ address)));
status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
ACPI_REGISTER_PM2_CONTROL,
@@ -495,7 +489,7 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value)
status =
acpi_hw_low_level_read(16, &value1,
- &acpi_gbl_FADT->xpm1a_evt_blk);
+ &acpi_gbl_FADT.xpm1a_event_block);
if (ACPI_FAILURE(status)) {
goto unlock_and_exit;
}
@@ -504,7 +498,7 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value)
status =
acpi_hw_low_level_read(16, &value2,
- &acpi_gbl_FADT->xpm1b_evt_blk);
+ &acpi_gbl_FADT.xpm1b_event_block);
value1 |= value2;
break;
@@ -527,14 +521,14 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value)
status =
acpi_hw_low_level_read(16, &value1,
- &acpi_gbl_FADT->xpm1a_cnt_blk);
+ &acpi_gbl_FADT.xpm1a_control_block);
if (ACPI_FAILURE(status)) {
goto unlock_and_exit;
}
status =
acpi_hw_low_level_read(16, &value2,
- &acpi_gbl_FADT->xpm1b_cnt_blk);
+ &acpi_gbl_FADT.xpm1b_control_block);
value1 |= value2;
break;
@@ -542,19 +536,20 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value)
status =
acpi_hw_low_level_read(8, &value1,
- &acpi_gbl_FADT->xpm2_cnt_blk);
+ &acpi_gbl_FADT.xpm2_control_block);
break;
case ACPI_REGISTER_PM_TIMER: /* 32-bit access */
status =
acpi_hw_low_level_read(32, &value1,
- &acpi_gbl_FADT->xpm_tmr_blk);
+ &acpi_gbl_FADT.xpm_timer_block);
break;
case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */
- status = acpi_os_read_port(acpi_gbl_FADT->smi_cmd, &value1, 8);
+ status =
+ acpi_os_read_port(acpi_gbl_FADT.smi_command, &value1, 8);
break;
default:
@@ -635,7 +630,7 @@ acpi_status acpi_hw_register_write(u8 use_lock, u32 register_id, u32 value)
status =
acpi_hw_low_level_write(16, value,
- &acpi_gbl_FADT->xpm1a_evt_blk);
+ &acpi_gbl_FADT.xpm1a_event_block);
if (ACPI_FAILURE(status)) {
goto unlock_and_exit;
}
@@ -644,7 +639,7 @@ acpi_status acpi_hw_register_write(u8 use_lock, u32 register_id, u32 value)
status =
acpi_hw_low_level_write(16, value,
- &acpi_gbl_FADT->xpm1b_evt_blk);
+ &acpi_gbl_FADT.xpm1b_event_block);
break;
case ACPI_REGISTER_PM1_ENABLE: /* 16-bit access */
@@ -682,49 +677,50 @@ acpi_status acpi_hw_register_write(u8 use_lock, u32 register_id, u32 value)
status =
acpi_hw_low_level_write(16, value,
- &acpi_gbl_FADT->xpm1a_cnt_blk);
+ &acpi_gbl_FADT.xpm1a_control_block);
if (ACPI_FAILURE(status)) {
goto unlock_and_exit;
}
status =
acpi_hw_low_level_write(16, value,
- &acpi_gbl_FADT->xpm1b_cnt_blk);
+ &acpi_gbl_FADT.xpm1b_control_block);
break;
case ACPI_REGISTER_PM1A_CONTROL: /* 16-bit access */
status =
acpi_hw_low_level_write(16, value,
- &acpi_gbl_FADT->xpm1a_cnt_blk);
+ &acpi_gbl_FADT.xpm1a_control_block);
break;
case ACPI_REGISTER_PM1B_CONTROL: /* 16-bit access */
status =
acpi_hw_low_level_write(16, value,
- &acpi_gbl_FADT->xpm1b_cnt_blk);
+ &acpi_gbl_FADT.xpm1b_control_block);
break;
case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */
status =
acpi_hw_low_level_write(8, value,
- &acpi_gbl_FADT->xpm2_cnt_blk);
+ &acpi_gbl_FADT.xpm2_control_block);
break;
case ACPI_REGISTER_PM_TIMER: /* 32-bit access */
status =
acpi_hw_low_level_write(32, value,
- &acpi_gbl_FADT->xpm_tmr_blk);
+ &acpi_gbl_FADT.xpm_timer_block);
break;
case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */
/* SMI_CMD is currently always in IO space */
- status = acpi_os_write_port(acpi_gbl_FADT->smi_cmd, value, 8);
+ status =
+ acpi_os_write_port(acpi_gbl_FADT.smi_command, value, 8);
break;
default:
@@ -783,7 +779,7 @@ acpi_hw_low_level_read(u32 width, u32 * value, struct acpi_generic_address *reg)
* Two address spaces supported: Memory or IO.
* PCI_Config is not supported here because the GAS struct is insufficient
*/
- switch (reg->address_space_id) {
+ switch (reg->space_id) {
case ACPI_ADR_SPACE_SYSTEM_MEMORY:
status = acpi_os_read_memory((acpi_physical_address) address,
@@ -792,22 +788,20 @@ acpi_hw_low_level_read(u32 width, u32 * value, struct acpi_generic_address *reg)
case ACPI_ADR_SPACE_SYSTEM_IO:
- status = acpi_os_read_port((acpi_io_address) address,
- value, width);
+ status =
+ acpi_os_read_port((acpi_io_address) address, value, width);
break;
default:
ACPI_ERROR((AE_INFO,
- "Unsupported address space: %X",
- reg->address_space_id));
+ "Unsupported address space: %X", reg->space_id));
return (AE_BAD_PARAMETER);
}
ACPI_DEBUG_PRINT((ACPI_DB_IO,
"Read: %8.8X width %2d from %8.8X%8.8X (%s)\n",
- *value, width,
- ACPI_FORMAT_UINT64(address),
- acpi_ut_get_region_name(reg->address_space_id)));
+ *value, width, ACPI_FORMAT_UINT64(address),
+ acpi_ut_get_region_name(reg->space_id)));
return (status);
}
@@ -854,7 +848,7 @@ acpi_hw_low_level_write(u32 width, u32 value, struct acpi_generic_address * reg)
* Two address spaces supported: Memory or IO.
* PCI_Config is not supported here because the GAS struct is insufficient
*/
- switch (reg->address_space_id) {
+ switch (reg->space_id) {
case ACPI_ADR_SPACE_SYSTEM_MEMORY:
status = acpi_os_write_memory((acpi_physical_address) address,
@@ -863,22 +857,20 @@ acpi_hw_low_level_write(u32 width, u32 value, struct acpi_generic_address * reg)
case ACPI_ADR_SPACE_SYSTEM_IO:
- status = acpi_os_write_port((acpi_io_address) address,
- value, width);
+ status = acpi_os_write_port((acpi_io_address) address, value,
+ width);
break;
default:
ACPI_ERROR((AE_INFO,
- "Unsupported address space: %X",
- reg->address_space_id));
+ "Unsupported address space: %X", reg->space_id));
return (AE_BAD_PARAMETER);
}
ACPI_DEBUG_PRINT((ACPI_DB_IO,
"Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n",
- value, width,
- ACPI_FORMAT_UINT64(address),
- acpi_ut_get_region_name(reg->address_space_id)));
+ value, width, ACPI_FORMAT_UINT64(address),
+ acpi_ut_get_region_name(reg->space_id)));
return (status);
}
diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c
index 8bb43cae60c..57901ca3ade 100644
--- a/drivers/acpi/hardware/hwsleep.c
+++ b/drivers/acpi/hardware/hwsleep.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -43,6 +43,7 @@
*/
#include <acpi/acpi.h>
+#include <acpi/actables.h>
#define _COMPONENT ACPI_HARDWARE
ACPI_MODULE_NAME("hwsleep")
@@ -62,17 +63,32 @@ ACPI_MODULE_NAME("hwsleep")
acpi_status
acpi_set_firmware_waking_vector(acpi_physical_address physical_address)
{
+ struct acpi_table_facs *facs;
+ acpi_status status;
ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector);
+ /* Get the FACS */
+
+ status =
+ acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
+ (struct acpi_table_header **)&facs);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
/* Set the vector */
- if (acpi_gbl_common_fACS.vector_width == 32) {
- *(ACPI_CAST_PTR
- (u32, acpi_gbl_common_fACS.firmware_waking_vector))
- = (u32) physical_address;
+ if ((facs->length < 32) || (!(facs->xfirmware_waking_vector))) {
+ /*
+ * ACPI 1.0 FACS or short table or optional X_ field is zero
+ */
+ facs->firmware_waking_vector = (u32) physical_address;
} else {
- *acpi_gbl_common_fACS.firmware_waking_vector = physical_address;
+ /*
+ * ACPI 2.0 FACS with valid X_ field
+ */
+ facs->xfirmware_waking_vector = physical_address;
}
return_ACPI_STATUS(AE_OK);
@@ -97,6 +113,8 @@ ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector)
acpi_status
acpi_get_firmware_waking_vector(acpi_physical_address * physical_address)
{
+ struct acpi_table_facs *facs;
+ acpi_status status;
ACPI_FUNCTION_TRACE(acpi_get_firmware_waking_vector);
@@ -104,16 +122,29 @@ acpi_get_firmware_waking_vector(acpi_physical_address * physical_address)
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
+ /* Get the FACS */
+
+ status =
+ acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
+ (struct acpi_table_header **)&facs);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
/* Get the vector */
- if (acpi_gbl_common_fACS.vector_width == 32) {
- *physical_address = (acpi_physical_address)
- *
- (ACPI_CAST_PTR
- (u32, acpi_gbl_common_fACS.firmware_waking_vector));
+ if ((facs->length < 32) || (!(facs->xfirmware_waking_vector))) {
+ /*
+ * ACPI 1.0 FACS or short table or optional X_ field is zero
+ */
+ *physical_address =
+ (acpi_physical_address) facs->firmware_waking_vector;
} else {
+ /*
+ * ACPI 2.0 FACS with valid X_ field
+ */
*physical_address =
- *acpi_gbl_common_fACS.firmware_waking_vector;
+ (acpi_physical_address) facs->xfirmware_waking_vector;
}
return_ACPI_STATUS(AE_OK);
@@ -246,15 +277,14 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
/* Clear wake status */
- status =
- acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK);
+ status = acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
/* Clear all fixed and general purpose status bits */
- status = acpi_hw_clear_acpi_status(ACPI_MTX_DO_NOT_LOCK);
+ status = acpi_hw_clear_acpi_status();
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -367,8 +397,7 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
/* Wait until we enter sleep state */
do {
- status = acpi_get_register(ACPI_BITREG_WAKE_STATUS, &in_value,
- ACPI_MTX_DO_NOT_LOCK);
+ status = acpi_get_register(ACPI_BITREG_WAKE_STATUS, &in_value);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -401,13 +430,12 @@ acpi_status asmlinkage acpi_enter_sleep_state_s4bios(void)
ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_s4bios);
- status =
- acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK);
+ status = acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
- status = acpi_hw_clear_acpi_status(ACPI_MTX_DO_NOT_LOCK);
+ status = acpi_hw_clear_acpi_status();
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -429,13 +457,12 @@ acpi_status asmlinkage acpi_enter_sleep_state_s4bios(void)
ACPI_FLUSH_CPU_CACHE();
- status = acpi_os_write_port(acpi_gbl_FADT->smi_cmd,
- (u32) acpi_gbl_FADT->S4bios_req, 8);
+ status = acpi_os_write_port(acpi_gbl_FADT.smi_command,
+ (u32) acpi_gbl_FADT.S4bios_request, 8);
do {
acpi_os_stall(1000);
- status = acpi_get_register(ACPI_BITREG_WAKE_STATUS, &in_value,
- ACPI_MTX_DO_NOT_LOCK);
+ status = acpi_get_register(ACPI_BITREG_WAKE_STATUS, &in_value);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -568,13 +595,11 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state)
(void)
acpi_set_register(acpi_gbl_fixed_event_info
- [ACPI_EVENT_POWER_BUTTON].enable_register_id, 1,
- ACPI_MTX_DO_NOT_LOCK);
+ [ACPI_EVENT_POWER_BUTTON].enable_register_id, 1);
(void)
acpi_set_register(acpi_gbl_fixed_event_info
- [ACPI_EVENT_POWER_BUTTON].status_register_id, 1,
- ACPI_MTX_DO_NOT_LOCK);
+ [ACPI_EVENT_POWER_BUTTON].status_register_id, 1);
arg.integer.value = ACPI_SST_WORKING;
status = acpi_evaluate_object(NULL, METHOD_NAME__SST, &arg_list, NULL);
diff --git a/drivers/acpi/hardware/hwtimer.c b/drivers/acpi/hardware/hwtimer.c
index c4ec47c939f..c32eab696ac 100644
--- a/drivers/acpi/hardware/hwtimer.c
+++ b/drivers/acpi/hardware/hwtimer.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -66,7 +66,7 @@ acpi_status acpi_get_timer_resolution(u32 * resolution)
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- if (acpi_gbl_FADT->tmr_val_ext == 0) {
+ if ((acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER) == 0) {
*resolution = 24;
} else {
*resolution = 32;
@@ -98,7 +98,8 @@ acpi_status acpi_get_timer(u32 * ticks)
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- status = acpi_hw_low_level_read(32, ticks, &acpi_gbl_FADT->xpm_tmr_blk);
+ status =
+ acpi_hw_low_level_read(32, ticks, &acpi_gbl_FADT.xpm_timer_block);
return_ACPI_STATUS(status);
}
@@ -153,7 +154,7 @@ acpi_get_timer_duration(u32 start_ticks, u32 end_ticks, u32 * time_elapsed)
if (start_ticks < end_ticks) {
delta_ticks = end_ticks - start_ticks;
} else if (start_ticks > end_ticks) {
- if (acpi_gbl_FADT->tmr_val_ext == 0) {
+ if ((acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER) == 0) {
/* 24-bit Timer */
diff --git a/drivers/acpi/motherboard.c b/drivers/acpi/motherboard.c
deleted file mode 100644
index 2e17ec75af0..00000000000
--- a/drivers/acpi/motherboard.c
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- * This program is free software; you can redistribute it and/or 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.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-
-/* Purpose: Prevent PCMCIA cards from using motherboard resources. */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/ioport.h>
-#include <asm/io.h>
-
-#include <acpi/acpi_bus.h>
-#include <acpi/acpi_drivers.h>
-
-#define _COMPONENT ACPI_SYSTEM_COMPONENT
-ACPI_MODULE_NAME("acpi_motherboard")
-
-/* Dell use PNP0C01 instead of PNP0C02 */
-#define ACPI_MB_HID1 "PNP0C01"
-#define ACPI_MB_HID2 "PNP0C02"
-/**
- * Doesn't care about legacy IO ports, only IO ports beyond 0x1000 are reserved
- * Doesn't care about the failure of 'request_region', since other may reserve
- * the io ports as well
- */
-#define IS_RESERVED_ADDR(base, len) \
- (((len) > 0) && ((base) > 0) && ((base) + (len) < IO_SPACE_LIMIT) \
- && ((base) + (len) > PCIBIOS_MIN_IO))
-/*
- * Clearing the flag (IORESOURCE_BUSY) allows drivers to use
- * the io ports if they really know they can use it, while
- * still preventing hotplug PCI devices from using it.
- */
-
-/*
- * When CONFIG_PNP is enabled, pnp/system.c binds to PNP0C01
- * and PNP0C02, redundant with acpi_reserve_io_ranges().
- * But acpi_reserve_io_ranges() is necessary for !CONFIG_PNP.
- */
-static acpi_status acpi_reserve_io_ranges(struct acpi_resource *res, void *data)
-{
- struct resource *requested_res = NULL;
-
-
- if (res->type == ACPI_RESOURCE_TYPE_IO) {
- struct acpi_resource_io *io_res = &res->data.io;
-
- if (io_res->minimum != io_res->maximum)
- return AE_OK;
- if (IS_RESERVED_ADDR
- (io_res->minimum, io_res->address_length)) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Motherboard resources 0x%08x - 0x%08x\n",
- io_res->minimum,
- io_res->minimum +
- io_res->address_length));
- requested_res =
- request_region(io_res->minimum,
- io_res->address_length, "motherboard");
- }
- } else if (res->type == ACPI_RESOURCE_TYPE_FIXED_IO) {
- struct acpi_resource_fixed_io *fixed_io_res =
- &res->data.fixed_io;
-
- if (IS_RESERVED_ADDR
- (fixed_io_res->address, fixed_io_res->address_length)) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Motherboard resources 0x%08x - 0x%08x\n",
- fixed_io_res->address,
- fixed_io_res->address +
- fixed_io_res->address_length));
- requested_res =
- request_region(fixed_io_res->address,
- fixed_io_res->address_length,
- "motherboard");
- }
- } else {
- /* Memory mapped IO? */
- }
-
- if (requested_res)
- requested_res->flags &= ~IORESOURCE_BUSY;
- return AE_OK;
-}
-
-static int acpi_motherboard_add(struct acpi_device *device)
-{
- if (!device)
- return -EINVAL;
- acpi_walk_resources(device->handle, METHOD_NAME__CRS,
- acpi_reserve_io_ranges, NULL);
-
- return 0;
-}
-
-static struct acpi_driver acpi_motherboard_driver1 = {
- .name = "motherboard",
- .class = "",
- .ids = ACPI_MB_HID1,
- .ops = {
- .add = acpi_motherboard_add,
- },
-};
-
-static struct acpi_driver acpi_motherboard_driver2 = {
- .name = "motherboard",
- .class = "",
- .ids = ACPI_MB_HID2,
- .ops = {
- .add = acpi_motherboard_add,
- },
-};
-
-static void __init acpi_request_region (struct acpi_generic_address *addr,
- unsigned int length, char *desc)
-{
- if (!addr->address || !length)
- return;
-
- if (addr->address_space_id == ACPI_ADR_SPACE_SYSTEM_IO)
- request_region(addr->address, length, desc);
- else if (addr->address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
- request_mem_region(addr->address, length, desc);
-}
-
-static void __init acpi_reserve_resources(void)
-{
- acpi_request_region(&acpi_gbl_FADT->xpm1a_evt_blk,
- acpi_gbl_FADT->pm1_evt_len, "ACPI PM1a_EVT_BLK");
-
- acpi_request_region(&acpi_gbl_FADT->xpm1b_evt_blk,
- acpi_gbl_FADT->pm1_evt_len, "ACPI PM1b_EVT_BLK");
-
- acpi_request_region(&acpi_gbl_FADT->xpm1a_cnt_blk,
- acpi_gbl_FADT->pm1_cnt_len, "ACPI PM1a_CNT_BLK");
-
- acpi_request_region(&acpi_gbl_FADT->xpm1b_cnt_blk,
- acpi_gbl_FADT->pm1_cnt_len, "ACPI PM1b_CNT_BLK");
-
- if (acpi_gbl_FADT->pm_tm_len == 4)
- acpi_request_region(&acpi_gbl_FADT->xpm_tmr_blk, 4, "ACPI PM_TMR");
-
- acpi_request_region(&acpi_gbl_FADT->xpm2_cnt_blk,
- acpi_gbl_FADT->pm2_cnt_len, "ACPI PM2_CNT_BLK");
-
- /* Length of GPE blocks must be a non-negative multiple of 2 */
-
- if (!(acpi_gbl_FADT->gpe0_blk_len & 0x1))
- acpi_request_region(&acpi_gbl_FADT->xgpe0_blk,
- acpi_gbl_FADT->gpe0_blk_len, "ACPI GPE0_BLK");
-
- if (!(acpi_gbl_FADT->gpe1_blk_len & 0x1))
- acpi_request_region(&acpi_gbl_FADT->xgpe1_blk,
- acpi_gbl_FADT->gpe1_blk_len, "ACPI GPE1_BLK");
-}
-
-static int __init acpi_motherboard_init(void)
-{
- acpi_bus_register_driver(&acpi_motherboard_driver1);
- acpi_bus_register_driver(&acpi_motherboard_driver2);
- /*
- * Guarantee motherboard IO reservation first
- * This module must run after scan.c
- */
- if (!acpi_disabled)
- acpi_reserve_resources();
- return 0;
-}
-
-/**
- * Reserve motherboard resources after PCI claim BARs,
- * but before PCI assign resources for uninitialized PCI devices
- */
-fs_initcall(acpi_motherboard_init);
diff --git a/drivers/acpi/namespace/nsaccess.c b/drivers/acpi/namespace/nsaccess.c
index c1c6c236df9..57faf598bad 100644
--- a/drivers/acpi/namespace/nsaccess.c
+++ b/drivers/acpi/namespace/nsaccess.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -195,31 +195,27 @@ acpi_status acpi_ns_root_initialize(void)
obj_desc->mutex.sync_level =
(u8) (ACPI_TO_INTEGER(val) - 1);
- if (ACPI_STRCMP(init_val->name, "_GL_") == 0) {
+ /* Create a mutex */
- /* Create a counting semaphore for the global lock */
+ status =
+ acpi_os_create_mutex(&obj_desc->mutex.
+ os_mutex);
+ if (ACPI_FAILURE(status)) {
+ acpi_ut_remove_reference(obj_desc);
+ goto unlock_and_exit;
+ }
- status =
- acpi_os_create_semaphore
- (ACPI_NO_UNIT_LIMIT, 1,
- &acpi_gbl_global_lock_semaphore);
- if (ACPI_FAILURE(status)) {
- acpi_ut_remove_reference
- (obj_desc);
- goto unlock_and_exit;
- }
+ /* Special case for ACPI Global Lock */
- /* Mark this mutex as very special */
+ if (ACPI_STRCMP(init_val->name, "_GL_") == 0) {
+ acpi_gbl_global_lock_mutex =
+ obj_desc->mutex.os_mutex;
- obj_desc->mutex.os_mutex =
- ACPI_GLOBAL_LOCK;
- } else {
- /* Create a mutex */
+ /* Create additional counting semaphore for global lock */
status =
- acpi_os_create_mutex(&obj_desc->
- mutex.
- os_mutex);
+ acpi_os_create_semaphore(1, 0,
+ &acpi_gbl_global_lock_semaphore);
if (ACPI_FAILURE(status)) {
acpi_ut_remove_reference
(obj_desc);
diff --git a/drivers/acpi/namespace/nsalloc.c b/drivers/acpi/namespace/nsalloc.c
index 55b407aae26..1d693d8ad2d 100644
--- a/drivers/acpi/namespace/nsalloc.c
+++ b/drivers/acpi/namespace/nsalloc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -61,6 +61,9 @@ ACPI_MODULE_NAME("nsalloc")
struct acpi_namespace_node *acpi_ns_create_node(u32 name)
{
struct acpi_namespace_node *node;
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+ u32 temp;
+#endif
ACPI_FUNCTION_TRACE(ns_create_node);
@@ -71,6 +74,15 @@ struct acpi_namespace_node *acpi_ns_create_node(u32 name)
ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_allocated++);
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+ temp =
+ acpi_gbl_ns_node_list->total_allocated -
+ acpi_gbl_ns_node_list->total_freed;
+ if (temp > acpi_gbl_ns_node_list->max_occupied) {
+ acpi_gbl_ns_node_list->max_occupied = temp;
+ }
+#endif
+
node->name.integer = name;
ACPI_SET_DESCRIPTOR_TYPE(node, ACPI_DESC_TYPE_NAMED);
return_PTR(node);
diff --git a/drivers/acpi/namespace/nsdump.c b/drivers/acpi/namespace/nsdump.c
index d72df66aa96..1fc4f86676e 100644
--- a/drivers/acpi/namespace/nsdump.c
+++ b/drivers/acpi/namespace/nsdump.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -205,7 +205,7 @@ acpi_ns_dump_one_object(acpi_handle obj_handle,
if (!acpi_ut_valid_acpi_name(this_node->name.integer)) {
this_node->name.integer =
- acpi_ut_repair_name(this_node->name.integer);
+ acpi_ut_repair_name(this_node->name.ascii);
ACPI_WARNING((AE_INFO, "Invalid ACPI Name %08X",
this_node->name.integer));
@@ -226,6 +226,12 @@ acpi_ns_dump_one_object(acpi_handle obj_handle,
obj_desc = acpi_ns_get_attached_object(this_node);
acpi_dbg_level = dbg_level;
+ /* Temp nodes are those nodes created by a control method */
+
+ if (this_node->flags & ANOBJ_TEMPORARY) {
+ acpi_os_printf("(T) ");
+ }
+
switch (info->display_type & ACPI_DISPLAY_MASK) {
case ACPI_DISPLAY_SUMMARY:
@@ -623,7 +629,8 @@ acpi_ns_dump_objects(acpi_object_type type,
info.display_type = display_type;
(void)acpi_ns_walk_namespace(type, start_handle, max_depth,
- ACPI_NS_WALK_NO_UNLOCK,
+ ACPI_NS_WALK_NO_UNLOCK |
+ ACPI_NS_WALK_TEMP_NODES,
acpi_ns_dump_one_object, (void *)&info,
NULL);
}
diff --git a/drivers/acpi/namespace/nsdumpdv.c b/drivers/acpi/namespace/nsdumpdv.c
index c6bf5d30fca..5097e167939 100644
--- a/drivers/acpi/namespace/nsdumpdv.c
+++ b/drivers/acpi/namespace/nsdumpdv.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/namespace/nseval.c b/drivers/acpi/namespace/nseval.c
index 4b0a4a8c984..aa6370c67ec 100644
--- a/drivers/acpi/namespace/nseval.c
+++ b/drivers/acpi/namespace/nseval.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -154,11 +154,7 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info)
* Execute the method via the interpreter. The interpreter is locked
* here before calling into the AML parser
*/
- status = acpi_ex_enter_interpreter();
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
+ acpi_ex_enter_interpreter();
status = acpi_ps_execute_method(info);
acpi_ex_exit_interpreter();
} else {
@@ -182,10 +178,7 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info)
* resolution, we must lock it because we could access an opregion.
* The opregion access code assumes that the interpreter is locked.
*/
- status = acpi_ex_enter_interpreter();
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
+ acpi_ex_enter_interpreter();
/* Function has a strange interface */
diff --git a/drivers/acpi/namespace/nsinit.c b/drivers/acpi/namespace/nsinit.c
index aec8488c001..326af8fc0ce 100644
--- a/drivers/acpi/namespace/nsinit.c
+++ b/drivers/acpi/namespace/nsinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -213,7 +213,7 @@ acpi_ns_init_one_object(acpi_handle obj_handle,
u32 level, void *context, void **return_value)
{
acpi_object_type type;
- acpi_status status;
+ acpi_status status = AE_OK;
struct acpi_init_walk_info *info =
(struct acpi_init_walk_info *)context;
struct acpi_namespace_node *node =
@@ -267,10 +267,7 @@ acpi_ns_init_one_object(acpi_handle obj_handle,
/*
* Must lock the interpreter before executing AML code
*/
- status = acpi_ex_enter_interpreter();
- if (ACPI_FAILURE(status)) {
- return (status);
- }
+ acpi_ex_enter_interpreter();
/*
* Each of these types can contain executable AML code within the
diff --git a/drivers/acpi/namespace/nsload.c b/drivers/acpi/namespace/nsload.c
index fe75d888e18..d4f9654fd20 100644
--- a/drivers/acpi/namespace/nsload.c
+++ b/drivers/acpi/namespace/nsload.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -44,13 +44,12 @@
#include <acpi/acpi.h>
#include <acpi/acnamesp.h>
#include <acpi/acdispat.h>
+#include <acpi/actables.h>
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nsload")
/* Local prototypes */
-static acpi_status acpi_ns_load_table_by_type(acpi_table_type table_type);
-
#ifdef ACPI_FUTURE_IMPLEMENTATION
acpi_status acpi_ns_unload_namespace(acpi_handle handle);
@@ -62,7 +61,7 @@ static acpi_status acpi_ns_delete_subtree(acpi_handle start_handle);
*
* FUNCTION: acpi_ns_load_table
*
- * PARAMETERS: table_desc - Descriptor for table to be loaded
+ * PARAMETERS: table_index - Index for table to be loaded
* Node - Owning NS node
*
* RETURN: Status
@@ -72,42 +71,13 @@ static acpi_status acpi_ns_delete_subtree(acpi_handle start_handle);
******************************************************************************/
acpi_status
-acpi_ns_load_table(struct acpi_table_desc *table_desc,
+acpi_ns_load_table(acpi_native_uint table_index,
struct acpi_namespace_node *node)
{
acpi_status status;
ACPI_FUNCTION_TRACE(ns_load_table);
- /* Check if table contains valid AML (must be DSDT, PSDT, SSDT, etc.) */
-
- if (!
- (acpi_gbl_table_data[table_desc->type].
- flags & ACPI_TABLE_EXECUTABLE)) {
-
- /* Just ignore this table */
-
- return_ACPI_STATUS(AE_OK);
- }
-
- /* Check validity of the AML start and length */
-
- if (!table_desc->aml_start) {
- ACPI_ERROR((AE_INFO, "Null AML pointer"));
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "AML block at %p\n",
- table_desc->aml_start));
-
- /* Ignore table if there is no AML contained within */
-
- if (!table_desc->aml_length) {
- ACPI_WARNING((AE_INFO, "Zero-length AML block in table [%4.4s]",
- table_desc->pointer->signature));
- return_ACPI_STATUS(AE_OK);
- }
-
/*
* Parse the table and load the namespace with all named
* objects found within. Control methods are NOT parsed
@@ -117,15 +87,34 @@ acpi_ns_load_table(struct acpi_table_desc *table_desc,
* to another control method, we can't continue parsing
* because we don't know how many arguments to parse next!
*/
+ status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /* If table already loaded into namespace, just return */
+
+ if (acpi_tb_is_table_loaded(table_index)) {
+ status = AE_ALREADY_EXISTS;
+ goto unlock;
+ }
+
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"**** Loading table into namespace ****\n"));
- status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+ status = acpi_tb_allocate_owner_id(table_index);
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ goto unlock;
+ }
+
+ status = acpi_ns_parse_table(table_index, node->child);
+ if (ACPI_SUCCESS(status)) {
+ acpi_tb_set_table_loaded_flag(table_index, TRUE);
+ } else {
+ acpi_tb_release_owner_id(table_index);
}
- status = acpi_ns_parse_table(table_desc, node->child);
+ unlock:
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(status)) {
@@ -141,7 +130,7 @@ acpi_ns_load_table(struct acpi_table_desc *table_desc,
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"**** Begin Table Method Parsing and Object Initialization ****\n"));
- status = acpi_ds_initialize_objects(table_desc, node);
+ status = acpi_ds_initialize_objects(table_index, node);
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"**** Completed Table Method Parsing and Object Initialization ****\n"));
@@ -149,99 +138,7 @@ acpi_ns_load_table(struct acpi_table_desc *table_desc,
return_ACPI_STATUS(status);
}
-/*******************************************************************************
- *
- * FUNCTION: acpi_ns_load_table_by_type
- *
- * PARAMETERS: table_type - Id of the table type to load
- *
- * RETURN: Status
- *
- * DESCRIPTION: Load an ACPI table or tables into the namespace. All tables
- * of the given type are loaded. The mechanism allows this
- * routine to be called repeatedly.
- *
- ******************************************************************************/
-
-static acpi_status acpi_ns_load_table_by_type(acpi_table_type table_type)
-{
- u32 i;
- acpi_status status;
- struct acpi_table_desc *table_desc;
-
- ACPI_FUNCTION_TRACE(ns_load_table_by_type);
-
- status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /*
- * Table types supported are:
- * DSDT (one), SSDT/PSDT (multiple)
- */
- switch (table_type) {
- case ACPI_TABLE_ID_DSDT:
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Namespace load: DSDT\n"));
-
- table_desc = acpi_gbl_table_lists[ACPI_TABLE_ID_DSDT].next;
-
- /* If table already loaded into namespace, just return */
-
- if (table_desc->loaded_into_namespace) {
- goto unlock_and_exit;
- }
-
- /* Now load the single DSDT */
-
- status = acpi_ns_load_table(table_desc, acpi_gbl_root_node);
- if (ACPI_SUCCESS(status)) {
- table_desc->loaded_into_namespace = TRUE;
- }
- break;
-
- case ACPI_TABLE_ID_SSDT:
- case ACPI_TABLE_ID_PSDT:
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Namespace load: %d SSDT or PSDTs\n",
- acpi_gbl_table_lists[table_type].count));
-
- /*
- * Traverse list of SSDT or PSDT tables
- */
- table_desc = acpi_gbl_table_lists[table_type].next;
- for (i = 0; i < acpi_gbl_table_lists[table_type].count; i++) {
- /*
- * Only attempt to load table into namespace if it is not
- * already loaded!
- */
- if (!table_desc->loaded_into_namespace) {
- status =
- acpi_ns_load_table(table_desc,
- acpi_gbl_root_node);
- if (ACPI_FAILURE(status)) {
- break;
- }
-
- table_desc->loaded_into_namespace = TRUE;
- }
-
- table_desc = table_desc->next;
- }
- break;
-
- default:
- status = AE_SUPPORT;
- break;
- }
-
- unlock_and_exit:
- (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
- return_ACPI_STATUS(status);
-}
-
+#ifdef ACPI_OBSOLETE_FUNCTIONS
/*******************************************************************************
*
* FUNCTION: acpi_load_namespace
@@ -288,6 +185,7 @@ acpi_status acpi_ns_load_namespace(void)
return_ACPI_STATUS(status);
}
+#endif
#ifdef ACPI_FUTURE_IMPLEMENTATION
/*******************************************************************************
diff --git a/drivers/acpi/namespace/nsnames.c b/drivers/acpi/namespace/nsnames.c
index 97b8332c974..cbd94af08cc 100644
--- a/drivers/acpi/namespace/nsnames.c
+++ b/drivers/acpi/namespace/nsnames.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/namespace/nsobject.c b/drivers/acpi/namespace/nsobject.c
index aabe8794b90..d9d7377bc6e 100644
--- a/drivers/acpi/namespace/nsobject.c
+++ b/drivers/acpi/namespace/nsobject.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/namespace/nsparse.c b/drivers/acpi/namespace/nsparse.c
index 155505a4ef6..e696aa84799 100644
--- a/drivers/acpi/namespace/nsparse.c
+++ b/drivers/acpi/namespace/nsparse.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -45,6 +45,7 @@
#include <acpi/acnamesp.h>
#include <acpi/acparser.h>
#include <acpi/acdispat.h>
+#include <acpi/actables.h>
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nsparse")
@@ -62,14 +63,24 @@ ACPI_MODULE_NAME("nsparse")
*
******************************************************************************/
acpi_status
-acpi_ns_one_complete_parse(u8 pass_number, struct acpi_table_desc *table_desc)
+acpi_ns_one_complete_parse(acpi_native_uint pass_number,
+ acpi_native_uint table_index)
{
union acpi_parse_object *parse_root;
acpi_status status;
+ acpi_native_uint aml_length;
+ u8 *aml_start;
struct acpi_walk_state *walk_state;
+ struct acpi_table_header *table;
+ acpi_owner_id owner_id;
ACPI_FUNCTION_TRACE(ns_one_complete_parse);
+ status = acpi_tb_get_owner_id(table_index, &owner_id);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
/* Create and init a Root Node */
parse_root = acpi_ps_create_scope_op();
@@ -79,26 +90,41 @@ acpi_ns_one_complete_parse(u8 pass_number, struct acpi_table_desc *table_desc)
/* Create and initialize a new walk state */
- walk_state = acpi_ds_create_walk_state(table_desc->owner_id,
- NULL, NULL, NULL);
+ walk_state = acpi_ds_create_walk_state(owner_id, NULL, NULL, NULL);
if (!walk_state) {
acpi_ps_free_op(parse_root);
return_ACPI_STATUS(AE_NO_MEMORY);
}
- status = acpi_ds_init_aml_walk(walk_state, parse_root, NULL,
- table_desc->aml_start,
- table_desc->aml_length, NULL,
- pass_number);
+ status = acpi_get_table_by_index(table_index, &table);
+ if (ACPI_FAILURE(status)) {
+ acpi_ds_delete_walk_state(walk_state);
+ acpi_ps_free_op(parse_root);
+ return_ACPI_STATUS(status);
+ }
+
+ /* Table must consist of at least a complete header */
+
+ if (table->length < sizeof(struct acpi_table_header)) {
+ status = AE_BAD_HEADER;
+ } else {
+ aml_start = (u8 *) table + sizeof(struct acpi_table_header);
+ aml_length = table->length - sizeof(struct acpi_table_header);
+ status = acpi_ds_init_aml_walk(walk_state, parse_root, NULL,
+ aml_start, aml_length, NULL,
+ (u8) pass_number);
+ }
+
if (ACPI_FAILURE(status)) {
acpi_ds_delete_walk_state(walk_state);
+ acpi_ps_delete_parse_tree(parse_root);
return_ACPI_STATUS(status);
}
/* Parse the AML */
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "*PARSE* pass %d parse\n",
- pass_number));
+ (unsigned)pass_number));
status = acpi_ps_parse_aml(walk_state);
acpi_ps_delete_parse_tree(parse_root);
@@ -119,7 +145,7 @@ acpi_ns_one_complete_parse(u8 pass_number, struct acpi_table_desc *table_desc)
******************************************************************************/
acpi_status
-acpi_ns_parse_table(struct acpi_table_desc *table_desc,
+acpi_ns_parse_table(acpi_native_uint table_index,
struct acpi_namespace_node *start_node)
{
acpi_status status;
@@ -134,10 +160,10 @@ acpi_ns_parse_table(struct acpi_table_desc *table_desc,
* each Parser Op subtree is deleted when it is finished. This saves
* a great deal of memory, and allows a small cache of parse objects
* to service the entire parse. The second pass of the parse then
- * performs another complete parse of the AML..
+ * performs another complete parse of the AML.
*/
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "**** Start pass 1\n"));
- status = acpi_ns_one_complete_parse(1, table_desc);
+ status = acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS1, table_index);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -152,7 +178,7 @@ acpi_ns_parse_table(struct acpi_table_desc *table_desc,
* parse objects are all cached.
*/
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "**** Start pass 2\n"));
- status = acpi_ns_one_complete_parse(2, table_desc);
+ status = acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS2, table_index);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/namespace/nssearch.c b/drivers/acpi/namespace/nssearch.c
index 500e2bbcfaf..e863be665ce 100644
--- a/drivers/acpi/namespace/nssearch.c
+++ b/drivers/acpi/namespace/nssearch.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -321,7 +321,8 @@ acpi_ns_search_and_enter(u32 target_name,
* even though there are a few bad names.
*/
if (!acpi_ut_valid_acpi_name(target_name)) {
- target_name = acpi_ut_repair_name(target_name);
+ target_name =
+ acpi_ut_repair_name(ACPI_CAST_PTR(char, &target_name));
/* Report warning only if in strict mode or debug mode */
@@ -401,6 +402,10 @@ acpi_ns_search_and_enter(u32 target_name,
}
#endif
+ if (flags & ACPI_NS_TEMPORARY) {
+ new_node->flags |= ANOBJ_TEMPORARY;
+ }
+
/* Install the new object into the parent's list of children */
acpi_ns_install_node(walk_state, node, new_node, type);
diff --git a/drivers/acpi/namespace/nsutils.c b/drivers/acpi/namespace/nsutils.c
index aa4e799d9a8..90fd059615f 100644
--- a/drivers/acpi/namespace/nsutils.c
+++ b/drivers/acpi/namespace/nsutils.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -770,13 +770,6 @@ void acpi_ns_terminate(void)
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Namespace freed\n"));
-
- /*
- * 2) Now we can delete the ACPI tables
- */
- acpi_tb_delete_all_tables();
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "ACPI Tables freed\n"));
-
return_VOID;
}
diff --git a/drivers/acpi/namespace/nswalk.c b/drivers/acpi/namespace/nswalk.c
index c8f6bef16ed..94eb8f332d9 100644
--- a/drivers/acpi/namespace/nswalk.c
+++ b/drivers/acpi/namespace/nswalk.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -126,7 +126,7 @@ struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type,
* PARAMETERS: Type - acpi_object_type to search for
* start_node - Handle in namespace where search begins
* max_depth - Depth to which search is to reach
- * unlock_before_callback- Whether to unlock the NS before invoking
+ * Flags - Whether to unlock the NS before invoking
* the callback routine
* user_function - Called when an object of "Type" is found
* Context - Passed to user function
@@ -153,7 +153,7 @@ acpi_status
acpi_ns_walk_namespace(acpi_object_type type,
acpi_handle start_node,
u32 max_depth,
- u8 unlock_before_callback,
+ u32 flags,
acpi_walk_callback user_function,
void *context, void **return_value)
{
@@ -193,20 +193,34 @@ acpi_ns_walk_namespace(acpi_object_type type,
acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node,
child_node);
if (child_node) {
- /*
- * Found node, Get the type if we are not
- * searching for ANY
- */
+
+ /* Found next child, get the type if we are not searching for ANY */
+
if (type != ACPI_TYPE_ANY) {
child_type = child_node->type;
}
- if (child_type == type) {
+ /*
+ * Ignore all temporary namespace nodes (created during control
+ * method execution) unless told otherwise. These temporary nodes
+ * can cause a race condition because they can be deleted during the
+ * execution of the user function (if the namespace is unlocked before
+ * invocation of the user function.) Only the debugger namespace dump
+ * will examine the temporary nodes.
+ */
+ if ((child_node->flags & ANOBJ_TEMPORARY) &&
+ !(flags & ACPI_NS_WALK_TEMP_NODES)) {
+ status = AE_CTRL_DEPTH;
+ }
+
+ /* Type must match requested type */
+
+ else if (child_type == type) {
/*
- * Found a matching node, invoke the user
- * callback function
+ * Found a matching node, invoke the user callback function.
+ * Unlock the namespace if flag is set.
*/
- if (unlock_before_callback) {
+ if (flags & ACPI_NS_WALK_UNLOCK) {
mutex_status =
acpi_ut_release_mutex
(ACPI_MTX_NAMESPACE);
@@ -216,10 +230,11 @@ acpi_ns_walk_namespace(acpi_object_type type,
}
}
- status = user_function(child_node, level,
- context, return_value);
+ status =
+ user_function(child_node, level, context,
+ return_value);
- if (unlock_before_callback) {
+ if (flags & ACPI_NS_WALK_UNLOCK) {
mutex_status =
acpi_ut_acquire_mutex
(ACPI_MTX_NAMESPACE);
@@ -251,20 +266,17 @@ acpi_ns_walk_namespace(acpi_object_type type,
}
/*
- * Depth first search:
- * Attempt to go down another level in the namespace
- * if we are allowed to. Don't go any further if we
- * have reached the caller specified maximum depth
- * or if the user function has specified that the
- * maximum depth has been reached.
+ * Depth first search: Attempt to go down another level in the
+ * namespace if we are allowed to. Don't go any further if we have
+ * reached the caller specified maximum depth or if the user
+ * function has specified that the maximum depth has been reached.
*/
if ((level < max_depth) && (status != AE_CTRL_DEPTH)) {
if (acpi_ns_get_next_node
(ACPI_TYPE_ANY, child_node, NULL)) {
- /*
- * There is at least one child of this
- * node, visit the onde
- */
+
+ /* There is at least one child of this node, visit it */
+
level++;
parent_node = child_node;
child_node = NULL;
@@ -272,9 +284,8 @@ acpi_ns_walk_namespace(acpi_object_type type,
}
} else {
/*
- * No more children of this node (acpi_ns_get_next_node
- * failed), go back upwards in the namespace tree to
- * the node's parent.
+ * No more children of this node (acpi_ns_get_next_node failed), go
+ * back upwards in the namespace tree to the node's parent.
*/
level--;
child_node = parent_node;
diff --git a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/namespace/nsxfeval.c
index dca6799ac67..7ac6ace5005 100644
--- a/drivers/acpi/namespace/nsxfeval.c
+++ b/drivers/acpi/namespace/nsxfeval.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -170,7 +170,6 @@ acpi_evaluate_object(acpi_handle handle,
struct acpi_buffer *return_buffer)
{
acpi_status status;
- acpi_status status2;
struct acpi_evaluate_info *info;
acpi_size buffer_space_needed;
u32 i;
@@ -329,14 +328,12 @@ acpi_evaluate_object(acpi_handle handle,
* Delete the internal return object. NOTE: Interpreter must be
* locked to avoid race condition.
*/
- status2 = acpi_ex_enter_interpreter();
- if (ACPI_SUCCESS(status2)) {
+ acpi_ex_enter_interpreter();
- /* Remove one reference on the return object (should delete it) */
+ /* Remove one reference on the return object (should delete it) */
- acpi_ut_remove_reference(info->return_object);
- acpi_ex_exit_interpreter();
- }
+ acpi_ut_remove_reference(info->return_object);
+ acpi_ex_exit_interpreter();
}
cleanup:
diff --git a/drivers/acpi/namespace/nsxfname.c b/drivers/acpi/namespace/nsxfname.c
index 978213a6c19..b489781b22a 100644
--- a/drivers/acpi/namespace/nsxfname.c
+++ b/drivers/acpi/namespace/nsxfname.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -84,38 +84,41 @@ acpi_get_handle(acpi_handle parent,
/* Convert a parent handle to a prefix node */
if (parent) {
- status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
- if (ACPI_FAILURE(status)) {
- return (status);
- }
-
prefix_node = acpi_ns_map_handle_to_node(parent);
if (!prefix_node) {
- (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
return (AE_BAD_PARAMETER);
}
+ }
+
+ /*
+ * Valid cases are:
+ * 1) Fully qualified pathname
+ * 2) Parent + Relative pathname
+ *
+ * Error for <null Parent + relative path>
+ */
+ if (acpi_ns_valid_root_prefix(pathname[0])) {
- status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
- if (ACPI_FAILURE(status)) {
- return (status);
+ /* Pathname is fully qualified (starts with '\') */
+
+ /* Special case for root-only, since we can't search for it */
+
+ if (!ACPI_STRCMP(pathname, ACPI_NS_ROOT_PATH)) {
+ *ret_handle =
+ acpi_ns_convert_entry_to_handle(acpi_gbl_root_node);
+ return (AE_OK);
}
- }
+ } else if (!prefix_node) {
- /* Special case for root, since we can't search for it */
+ /* Relative path with null prefix is disallowed */
- if (ACPI_STRCMP(pathname, ACPI_NS_ROOT_PATH) == 0) {
- *ret_handle =
- acpi_ns_convert_entry_to_handle(acpi_gbl_root_node);
- return (AE_OK);
+ return (AE_BAD_PARAMETER);
}
- /*
- * Find the Node and convert to a handle
- */
- status = acpi_ns_get_node(prefix_node, pathname, ACPI_NS_NO_UPSEARCH,
- &node);
+ /* Find the Node and convert to a handle */
- *ret_handle = NULL;
+ status =
+ acpi_ns_get_node(prefix_node, pathname, ACPI_NS_NO_UPSEARCH, &node);
if (ACPI_SUCCESS(status)) {
*ret_handle = acpi_ns_convert_entry_to_handle(node);
}
diff --git a/drivers/acpi/namespace/nsxfobj.c b/drivers/acpi/namespace/nsxfobj.c
index a18b1c22312..faa37588720 100644
--- a/drivers/acpi/namespace/nsxfobj.c
+++ b/drivers/acpi/namespace/nsxfobj.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c
index bd96a704592..4a9faff4c01 100644
--- a/drivers/acpi/numa.c
+++ b/drivers/acpi/numa.c
@@ -45,7 +45,7 @@ int __cpuinitdata pxm_to_node_map[MAX_PXM_DOMAINS]
int __cpuinitdata node_to_pxm_map[MAX_NUMNODES]
= { [0 ... MAX_NUMNODES - 1] = PXM_INVAL };
-extern int __init acpi_table_parse_madt_family(enum acpi_table_id id,
+extern int __init acpi_table_parse_madt_family(char *id,
unsigned long madt_size,
int entry_id,
acpi_madt_entry_handler handler,
@@ -89,7 +89,7 @@ void __cpuinit acpi_unmap_pxm_to_node(int node)
node_clear(node, nodes_found_map);
}
-void __init acpi_table_print_srat_entry(acpi_table_entry_header * header)
+void __init acpi_table_print_srat_entry(struct acpi_subtable_header * header)
{
ACPI_FUNCTION_NAME("acpi_table_print_srat_entry");
@@ -99,36 +99,35 @@ void __init acpi_table_print_srat_entry(acpi_table_entry_header * header)
switch (header->type) {
- case ACPI_SRAT_PROCESSOR_AFFINITY:
+ case ACPI_SRAT_TYPE_CPU_AFFINITY:
#ifdef ACPI_DEBUG_OUTPUT
{
- struct acpi_table_processor_affinity *p =
- (struct acpi_table_processor_affinity *)header;
+ struct acpi_srat_cpu_affinity *p =
+ (struct acpi_srat_cpu_affinity *)header;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"SRAT Processor (id[0x%02x] eid[0x%02x]) in proximity domain %d %s\n",
- p->apic_id, p->lsapic_eid,
- p->proximity_domain,
- p->flags.
- enabled ? "enabled" : "disabled"));
+ p->apic_id, p->local_sapic_eid,
+ p->proximity_domain_lo,
+ (p->flags & ACPI_SRAT_CPU_ENABLED)?
+ "enabled" : "disabled"));
}
#endif /* ACPI_DEBUG_OUTPUT */
break;
- case ACPI_SRAT_MEMORY_AFFINITY:
+ case ACPI_SRAT_TYPE_MEMORY_AFFINITY:
#ifdef ACPI_DEBUG_OUTPUT
{
- struct acpi_table_memory_affinity *p =
- (struct acpi_table_memory_affinity *)header;
+ struct acpi_srat_mem_affinity *p =
+ (struct acpi_srat_mem_affinity *)header;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "SRAT Memory (0x%08x%08x length 0x%08x%08x type 0x%x) in proximity domain %d %s%s\n",
- p->base_addr_hi, p->base_addr_lo,
- p->length_hi, p->length_lo,
+ "SRAT Memory (0x%lx length 0x%lx type 0x%x) in proximity domain %d %s%s\n",
+ (unsigned long)p->base_address,
+ (unsigned long)p->length,
p->memory_type, p->proximity_domain,
- p->flags.
- enabled ? "enabled" : "disabled",
- p->flags.
- hot_pluggable ? " hot-pluggable" :
- ""));
+ (p->flags & ACPI_SRAT_MEM_ENABLED)?
+ "enabled" : "disabled",
+ (p->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE)?
+ " hot-pluggable" : ""));
}
#endif /* ACPI_DEBUG_OUTPUT */
break;
@@ -141,18 +140,18 @@ void __init acpi_table_print_srat_entry(acpi_table_entry_header * header)
}
}
-static int __init acpi_parse_slit(unsigned long phys_addr, unsigned long size)
+static int __init acpi_parse_slit(struct acpi_table_header *table)
{
struct acpi_table_slit *slit;
u32 localities;
- if (!phys_addr || !size)
+ if (!table)
return -EINVAL;
- slit = (struct acpi_table_slit *)__va(phys_addr);
+ slit = (struct acpi_table_slit *)table;
/* downcast just for %llu vs %lu for i386/ia64 */
- localities = (u32) slit->localities;
+ localities = (u32) slit->locality_count;
acpi_numa_slit_init(slit);
@@ -160,12 +159,12 @@ static int __init acpi_parse_slit(unsigned long phys_addr, unsigned long size)
}
static int __init
-acpi_parse_processor_affinity(acpi_table_entry_header * header,
+acpi_parse_processor_affinity(struct acpi_subtable_header * header,
const unsigned long end)
{
- struct acpi_table_processor_affinity *processor_affinity;
+ struct acpi_srat_cpu_affinity *processor_affinity;
- processor_affinity = (struct acpi_table_processor_affinity *)header;
+ processor_affinity = (struct acpi_srat_cpu_affinity *)header;
if (!processor_affinity)
return -EINVAL;
@@ -178,12 +177,12 @@ acpi_parse_processor_affinity(acpi_table_entry_header * header,
}
static int __init
-acpi_parse_memory_affinity(acpi_table_entry_header * header,
+acpi_parse_memory_affinity(struct acpi_subtable_header * header,
const unsigned long end)
{
- struct acpi_table_memory_affinity *memory_affinity;
+ struct acpi_srat_mem_affinity *memory_affinity;
- memory_affinity = (struct acpi_table_memory_affinity *)header;
+ memory_affinity = (struct acpi_srat_mem_affinity *)header;
if (!memory_affinity)
return -EINVAL;
@@ -195,23 +194,23 @@ acpi_parse_memory_affinity(acpi_table_entry_header * header,
return 0;
}
-static int __init acpi_parse_srat(unsigned long phys_addr, unsigned long size)
+static int __init acpi_parse_srat(struct acpi_table_header *table)
{
struct acpi_table_srat *srat;
- if (!phys_addr || !size)
+ if (!table)
return -EINVAL;
- srat = (struct acpi_table_srat *)__va(phys_addr);
+ srat = (struct acpi_table_srat *)table;
return 0;
}
int __init
-acpi_table_parse_srat(enum acpi_srat_entry_id id,
+acpi_table_parse_srat(enum acpi_srat_type id,
acpi_madt_entry_handler handler, unsigned int max_entries)
{
- return acpi_table_parse_madt_family(ACPI_SRAT,
+ return acpi_table_parse_madt_family(ACPI_SIG_SRAT,
sizeof(struct acpi_table_srat), id,
handler, max_entries);
}
@@ -221,17 +220,17 @@ int __init acpi_numa_init(void)
int result;
/* SRAT: Static Resource Affinity Table */
- result = acpi_table_parse(ACPI_SRAT, acpi_parse_srat);
+ result = acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat);
if (result > 0) {
- result = acpi_table_parse_srat(ACPI_SRAT_PROCESSOR_AFFINITY,
+ result = acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY,
acpi_parse_processor_affinity,
NR_CPUS);
- result = acpi_table_parse_srat(ACPI_SRAT_MEMORY_AFFINITY, acpi_parse_memory_affinity, NR_NODE_MEMBLKS); // IA64 specific
+ result = acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY, acpi_parse_memory_affinity, NR_NODE_MEMBLKS); // IA64 specific
}
/* SLIT: System Locality Information Table */
- result = acpi_table_parse(ACPI_SLIT, acpi_parse_slit);
+ result = acpi_table_parse(ACPI_SIG_SLIT, acpi_parse_slit);
acpi_numa_arch_fixup();
return 0;
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 57ae1e5cde0..0f6f3bcbc8e 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -36,6 +36,7 @@
#include <linux/delay.h>
#include <linux/workqueue.h>
#include <linux/nmi.h>
+#include <linux/acpi.h>
#include <acpi/acpi.h>
#include <asm/io.h>
#include <acpi/acpi_bus.h>
@@ -75,6 +76,54 @@ static acpi_osd_handler acpi_irq_handler;
static void *acpi_irq_context;
static struct workqueue_struct *kacpid_wq;
+static void __init acpi_request_region (struct acpi_generic_address *addr,
+ unsigned int length, char *desc)
+{
+ struct resource *res;
+
+ if (!addr->address || !length)
+ return;
+
+ if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_IO)
+ res = request_region(addr->address, length, desc);
+ else if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
+ res = request_mem_region(addr->address, length, desc);
+}
+
+static int __init acpi_reserve_resources(void)
+{
+ acpi_request_region(&acpi_gbl_FADT.xpm1a_event_block, acpi_gbl_FADT.pm1_event_length,
+ "ACPI PM1a_EVT_BLK");
+
+ acpi_request_region(&acpi_gbl_FADT.xpm1b_event_block, acpi_gbl_FADT.pm1_event_length,
+ "ACPI PM1b_EVT_BLK");
+
+ acpi_request_region(&acpi_gbl_FADT.xpm1a_control_block, acpi_gbl_FADT.pm1_control_length,
+ "ACPI PM1a_CNT_BLK");
+
+ acpi_request_region(&acpi_gbl_FADT.xpm1b_control_block, acpi_gbl_FADT.pm1_control_length,
+ "ACPI PM1b_CNT_BLK");
+
+ if (acpi_gbl_FADT.pm_timer_length == 4)
+ acpi_request_region(&acpi_gbl_FADT.xpm_timer_block, 4, "ACPI PM_TMR");
+
+ acpi_request_region(&acpi_gbl_FADT.xpm2_control_block, acpi_gbl_FADT.pm2_control_length,
+ "ACPI PM2_CNT_BLK");
+
+ /* Length of GPE blocks must be a non-negative multiple of 2 */
+
+ if (!(acpi_gbl_FADT.gpe0_block_length & 0x1))
+ acpi_request_region(&acpi_gbl_FADT.xgpe0_block,
+ acpi_gbl_FADT.gpe0_block_length, "ACPI GPE0_BLK");
+
+ if (!(acpi_gbl_FADT.gpe1_block_length & 0x1))
+ acpi_request_region(&acpi_gbl_FADT.xgpe1_block,
+ acpi_gbl_FADT.gpe1_block_length, "ACPI GPE1_BLK");
+
+ return 0;
+}
+device_initcall(acpi_reserve_resources);
+
acpi_status acpi_os_initialize(void)
{
return AE_OK;
@@ -136,53 +185,43 @@ void acpi_os_vprintf(const char *fmt, va_list args)
#endif
}
-acpi_status acpi_os_get_root_pointer(u32 flags, struct acpi_pointer *addr)
+acpi_physical_address __init acpi_os_get_root_pointer(void)
{
if (efi_enabled) {
- addr->pointer_type = ACPI_PHYSICAL_POINTER;
if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
- addr->pointer.physical = efi.acpi20;
+ return efi.acpi20;
else if (efi.acpi != EFI_INVALID_TABLE_ADDR)
- addr->pointer.physical = efi.acpi;
+ return efi.acpi;
else {
printk(KERN_ERR PREFIX
"System description tables not found\n");
- return AE_NOT_FOUND;
+ return 0;
}
- } else {
- if (ACPI_FAILURE(acpi_find_root_pointer(flags, addr))) {
- printk(KERN_ERR PREFIX
- "System description tables not found\n");
- return AE_NOT_FOUND;
- }
- }
-
- return AE_OK;
+ } else
+ return acpi_find_rsdp();
}
-acpi_status
-acpi_os_map_memory(acpi_physical_address phys, acpi_size size,
- void __iomem ** virt)
+void __iomem *acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
{
if (phys > ULONG_MAX) {
printk(KERN_ERR PREFIX "Cannot map memory that high\n");
- return AE_BAD_PARAMETER;
+ return 0;
}
- /*
- * ioremap checks to ensure this is in reserved space
- */
- *virt = ioremap((unsigned long)phys, size);
-
- if (!*virt)
- return AE_NO_MEMORY;
-
- return AE_OK;
+ if (acpi_gbl_permanent_mmap)
+ /*
+ * ioremap checks to ensure this is in reserved space
+ */
+ return ioremap((unsigned long)phys, size);
+ else
+ return __acpi_map_table((unsigned long)phys, size);
}
EXPORT_SYMBOL_GPL(acpi_os_map_memory);
void acpi_os_unmap_memory(void __iomem * virt, acpi_size size)
{
- iounmap(virt);
+ if (acpi_gbl_permanent_mmap) {
+ iounmap(virt);
+ }
}
EXPORT_SYMBOL_GPL(acpi_os_unmap_memory);
@@ -254,7 +293,7 @@ acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler,
* FADT. It may not be the same if an interrupt source override exists
* for the SCI.
*/
- gsi = acpi_fadt.sci_int;
+ gsi = acpi_gbl_FADT.sci_interrupt;
if (acpi_gsi_to_irq(gsi, &irq) < 0) {
printk(KERN_ERR PREFIX "SCI (ACPI GSI %d) not registered\n",
gsi);
diff --git a/drivers/acpi/parser/psargs.c b/drivers/acpi/parser/psargs.c
index bf88e076c3e..c2b9835c890 100644
--- a/drivers/acpi/parser/psargs.c
+++ b/drivers/acpi/parser/psargs.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/parser/psloop.c b/drivers/acpi/parser/psloop.c
index e1541db3753..773aee82fbb 100644
--- a/drivers/acpi/parser/psloop.c
+++ b/drivers/acpi/parser/psloop.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -42,12 +42,11 @@
*/
/*
- * Parse the AML and build an operation tree as most interpreters,
- * like Perl, do. Parsing is done by hand rather than with a YACC
- * generated parser to tightly constrain stack and dynamic memory
- * usage. At the same time, parsing is kept flexible and the code
- * fairly compact by parsing based on a list of AML opcode
- * templates in aml_op_info[]
+ * Parse the AML and build an operation tree as most interpreters, (such as
+ * Perl) do. Parsing is done by hand rather than with a YACC generated parser
+ * to tightly constrain stack and dynamic memory usage. Parsing is kept
+ * flexible and the code fairly compact by parsing based on a list of AML
+ * opcode templates in aml_op_info[].
*/
#include <acpi/acpi.h>
@@ -60,766 +59,679 @@ ACPI_MODULE_NAME("psloop")
static u32 acpi_gbl_depth = 0;
+/* Local prototypes */
+
+static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state);
+
+static acpi_status
+acpi_ps_build_named_op(struct acpi_walk_state *walk_state,
+ u8 * aml_op_start,
+ union acpi_parse_object *unnamed_op,
+ union acpi_parse_object **op);
+
+static acpi_status
+acpi_ps_create_op(struct acpi_walk_state *walk_state,
+ u8 * aml_op_start, union acpi_parse_object **new_op);
+
+static acpi_status
+acpi_ps_get_arguments(struct acpi_walk_state *walk_state,
+ u8 * aml_op_start, union acpi_parse_object *op);
+
+static acpi_status
+acpi_ps_complete_op(struct acpi_walk_state *walk_state,
+ union acpi_parse_object **op, acpi_status status);
+
+static acpi_status
+acpi_ps_complete_final_op(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op, acpi_status status);
+
/*******************************************************************************
*
- * FUNCTION: acpi_ps_parse_loop
+ * FUNCTION: acpi_ps_get_aml_opcode
*
* PARAMETERS: walk_state - Current state
*
* RETURN: Status
*
- * DESCRIPTION: Parse AML (pointed to by the current parser state) and return
- * a tree of ops.
+ * DESCRIPTION: Extract the next AML opcode from the input stream.
*
******************************************************************************/
-acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
+static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state)
{
- acpi_status status = AE_OK;
- acpi_status status2;
- union acpi_parse_object *op = NULL; /* current op */
- union acpi_parse_object *arg = NULL;
- union acpi_parse_object *pre_op = NULL;
- struct acpi_parse_state *parser_state;
- u8 *aml_op_start = NULL;
- ACPI_FUNCTION_TRACE_PTR(ps_parse_loop, walk_state);
+ ACPI_FUNCTION_TRACE_PTR(ps_get_aml_opcode, walk_state);
- if (walk_state->descending_callback == NULL) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
+ walk_state->aml_offset =
+ (u32) ACPI_PTR_DIFF(walk_state->parser_state.aml,
+ walk_state->parser_state.aml_start);
+ walk_state->opcode = acpi_ps_peek_opcode(&(walk_state->parser_state));
- parser_state = &walk_state->parser_state;
- walk_state->arg_types = 0;
+ /*
+ * First cut to determine what we have found:
+ * 1) A valid AML opcode
+ * 2) A name string
+ * 3) An unknown/invalid opcode
+ */
+ walk_state->op_info = acpi_ps_get_opcode_info(walk_state->opcode);
-#if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY))
+ switch (walk_state->op_info->class) {
+ case AML_CLASS_ASCII:
+ case AML_CLASS_PREFIX:
+ /*
+ * Starts with a valid prefix or ASCII char, this is a name
+ * string. Convert the bare name string to a namepath.
+ */
+ walk_state->opcode = AML_INT_NAMEPATH_OP;
+ walk_state->arg_types = ARGP_NAMESTRING;
+ break;
- if (walk_state->walk_type & ACPI_WALK_METHOD_RESTART) {
+ case AML_CLASS_UNKNOWN:
- /* We are restarting a preempted control method */
+ /* The opcode is unrecognized. Just skip unknown opcodes */
- if (acpi_ps_has_completed_scope(parser_state)) {
- /*
- * We must check if a predicate to an IF or WHILE statement
- * was just completed
- */
- if ((parser_state->scope->parse_scope.op) &&
- ((parser_state->scope->parse_scope.op->common.
- aml_opcode == AML_IF_OP)
- || (parser_state->scope->parse_scope.op->common.
- aml_opcode == AML_WHILE_OP))
- && (walk_state->control_state)
- && (walk_state->control_state->common.state ==
- ACPI_CONTROL_PREDICATE_EXECUTING)) {
- /*
- * A predicate was just completed, get the value of the
- * predicate and branch based on that value
- */
- walk_state->op = NULL;
- status =
- acpi_ds_get_predicate_value(walk_state,
- ACPI_TO_POINTER
- (TRUE));
- if (ACPI_FAILURE(status)
- && ((status & AE_CODE_MASK) !=
- AE_CODE_CONTROL)) {
- if (status == AE_AML_NO_RETURN_VALUE) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Invoked method did not return a value"));
+ ACPI_ERROR((AE_INFO,
+ "Found unknown opcode %X at AML address %p offset %X, ignoring",
+ walk_state->opcode, walk_state->parser_state.aml,
+ walk_state->aml_offset));
- }
- ACPI_EXCEPTION((AE_INFO, status,
- "GetPredicate Failed"));
- return_ACPI_STATUS(status);
- }
+ ACPI_DUMP_BUFFER(walk_state->parser_state.aml, 128);
- status =
- acpi_ps_next_parse_state(walk_state, op,
- status);
- }
+ /* Assume one-byte bad opcode */
- acpi_ps_pop_scope(parser_state, &op,
- &walk_state->arg_types,
- &walk_state->arg_count);
- ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
- "Popped scope, Op=%p\n", op));
- } else if (walk_state->prev_op) {
+ walk_state->parser_state.aml++;
+ return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE);
- /* We were in the middle of an op */
+ default:
- op = walk_state->prev_op;
- walk_state->arg_types = walk_state->prev_arg_types;
- }
+ /* Found opcode info, this is a normal opcode */
+
+ walk_state->parser_state.aml +=
+ acpi_ps_get_opcode_size(walk_state->opcode);
+ walk_state->arg_types = walk_state->op_info->parse_args;
+ break;
}
-#endif
- /* Iterative parsing loop, while there is more AML to process: */
+ return_ACPI_STATUS(AE_OK);
+}
- while ((parser_state->aml < parser_state->aml_end) || (op)) {
- aml_op_start = parser_state->aml;
- if (!op) {
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_build_named_op
+ *
+ * PARAMETERS: walk_state - Current state
+ * aml_op_start - Begin of named Op in AML
+ * unnamed_op - Early Op (not a named Op)
+ * Op - Returned Op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Parse a named Op
+ *
+ ******************************************************************************/
- /* Get the next opcode from the AML stream */
+static acpi_status
+acpi_ps_build_named_op(struct acpi_walk_state *walk_state,
+ u8 * aml_op_start,
+ union acpi_parse_object *unnamed_op,
+ union acpi_parse_object **op)
+{
+ acpi_status status = AE_OK;
+ union acpi_parse_object *arg = NULL;
- walk_state->aml_offset =
- (u32) ACPI_PTR_DIFF(parser_state->aml,
- parser_state->aml_start);
- walk_state->opcode = acpi_ps_peek_opcode(parser_state);
+ ACPI_FUNCTION_TRACE_PTR(ps_build_named_op, walk_state);
- /*
- * First cut to determine what we have found:
- * 1) A valid AML opcode
- * 2) A name string
- * 3) An unknown/invalid opcode
- */
- walk_state->op_info =
- acpi_ps_get_opcode_info(walk_state->opcode);
- switch (walk_state->op_info->class) {
- case AML_CLASS_ASCII:
- case AML_CLASS_PREFIX:
- /*
- * Starts with a valid prefix or ASCII char, this is a name
- * string. Convert the bare name string to a namepath.
- */
- walk_state->opcode = AML_INT_NAMEPATH_OP;
- walk_state->arg_types = ARGP_NAMESTRING;
- break;
+ unnamed_op->common.value.arg = NULL;
+ unnamed_op->common.aml_opcode = walk_state->opcode;
- case AML_CLASS_UNKNOWN:
+ /*
+ * Get and append arguments until we find the node that contains
+ * the name (the type ARGP_NAME).
+ */
+ while (GET_CURRENT_ARG_TYPE(walk_state->arg_types) &&
+ (GET_CURRENT_ARG_TYPE(walk_state->arg_types) != ARGP_NAME)) {
+ status =
+ acpi_ps_get_next_arg(walk_state,
+ &(walk_state->parser_state),
+ GET_CURRENT_ARG_TYPE(walk_state->
+ arg_types), &arg);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
- /* The opcode is unrecognized. Just skip unknown opcodes */
+ acpi_ps_append_arg(unnamed_op, arg);
+ INCREMENT_ARG_LIST(walk_state->arg_types);
+ }
- ACPI_ERROR((AE_INFO,
- "Found unknown opcode %X at AML address %p offset %X, ignoring",
- walk_state->opcode,
- parser_state->aml,
- walk_state->aml_offset));
+ /*
+ * Make sure that we found a NAME and didn't run out of arguments
+ */
+ if (!GET_CURRENT_ARG_TYPE(walk_state->arg_types)) {
+ return_ACPI_STATUS(AE_AML_NO_OPERAND);
+ }
- ACPI_DUMP_BUFFER(parser_state->aml, 128);
+ /* We know that this arg is a name, move to next arg */
- /* Assume one-byte bad opcode */
+ INCREMENT_ARG_LIST(walk_state->arg_types);
- parser_state->aml++;
- continue;
+ /*
+ * Find the object. This will either insert the object into
+ * the namespace or simply look it up
+ */
+ walk_state->op = NULL;
- default:
+ status = walk_state->descending_callback(walk_state, op);
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status, "During name lookup/catalog"));
+ return_ACPI_STATUS(status);
+ }
- /* Found opcode info, this is a normal opcode */
+ if (!*op) {
+ return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE);
+ }
- parser_state->aml +=
- acpi_ps_get_opcode_size(walk_state->opcode);
- walk_state->arg_types =
- walk_state->op_info->parse_args;
- break;
- }
+ status = acpi_ps_next_parse_state(walk_state, *op, status);
+ if (ACPI_FAILURE(status)) {
+ if (status == AE_CTRL_PENDING) {
+ return_ACPI_STATUS(AE_CTRL_PARSE_PENDING);
+ }
+ return_ACPI_STATUS(status);
+ }
- /* Create Op structure and append to parent's argument list */
+ acpi_ps_append_arg(*op, unnamed_op->common.value.arg);
+ acpi_gbl_depth++;
- if (walk_state->op_info->flags & AML_NAMED) {
+ if ((*op)->common.aml_opcode == AML_REGION_OP) {
+ /*
+ * Defer final parsing of an operation_region body, because we don't
+ * have enough info in the first pass to parse it correctly (i.e.,
+ * there may be method calls within the term_arg elements of the body.)
+ *
+ * However, we must continue parsing because the opregion is not a
+ * standalone package -- we don't know where the end is at this point.
+ *
+ * (Length is unknown until parse of the body complete)
+ */
+ (*op)->named.data = aml_op_start;
+ (*op)->named.length = 0;
+ }
- /* Allocate a new pre_op if necessary */
+ return_ACPI_STATUS(AE_OK);
+}
- if (!pre_op) {
- pre_op =
- acpi_ps_alloc_op(walk_state->
- opcode);
- if (!pre_op) {
- status = AE_NO_MEMORY;
- goto close_this_op;
- }
- }
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_create_op
+ *
+ * PARAMETERS: walk_state - Current state
+ * aml_op_start - Op start in AML
+ * new_op - Returned Op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get Op from AML
+ *
+ ******************************************************************************/
- pre_op->common.value.arg = NULL;
- pre_op->common.aml_opcode = walk_state->opcode;
+static acpi_status
+acpi_ps_create_op(struct acpi_walk_state *walk_state,
+ u8 * aml_op_start, union acpi_parse_object **new_op)
+{
+ acpi_status status = AE_OK;
+ union acpi_parse_object *op;
+ union acpi_parse_object *named_op = NULL;
- /*
- * Get and append arguments until we find the node that contains
- * the name (the type ARGP_NAME).
- */
- while (GET_CURRENT_ARG_TYPE
- (walk_state->arg_types)
- &&
- (GET_CURRENT_ARG_TYPE
- (walk_state->arg_types) != ARGP_NAME)) {
- status =
- acpi_ps_get_next_arg(walk_state,
- parser_state,
- GET_CURRENT_ARG_TYPE
- (walk_state->
- arg_types),
- &arg);
- if (ACPI_FAILURE(status)) {
- goto close_this_op;
- }
+ ACPI_FUNCTION_TRACE_PTR(ps_create_op, walk_state);
- acpi_ps_append_arg(pre_op, arg);
- INCREMENT_ARG_LIST(walk_state->
- arg_types);
- }
+ status = acpi_ps_get_aml_opcode(walk_state);
+ if (status == AE_CTRL_PARSE_CONTINUE) {
+ return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE);
+ }
- /*
- * Make sure that we found a NAME and didn't run out of
- * arguments
- */
- if (!GET_CURRENT_ARG_TYPE
- (walk_state->arg_types)) {
- status = AE_AML_NO_OPERAND;
- goto close_this_op;
- }
+ /* Create Op structure and append to parent's argument list */
- /* We know that this arg is a name, move to next arg */
+ walk_state->op_info = acpi_ps_get_opcode_info(walk_state->opcode);
+ op = acpi_ps_alloc_op(walk_state->opcode);
+ if (!op) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
- INCREMENT_ARG_LIST(walk_state->arg_types);
+ if (walk_state->op_info->flags & AML_NAMED) {
+ status =
+ acpi_ps_build_named_op(walk_state, aml_op_start, op,
+ &named_op);
+ acpi_ps_free_op(op);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
- /*
- * Find the object. This will either insert the object into
- * the namespace or simply look it up
- */
- walk_state->op = NULL;
+ *new_op = named_op;
+ return_ACPI_STATUS(AE_OK);
+ }
- status =
- walk_state->descending_callback(walk_state,
- &op);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "During name lookup/catalog"));
- goto close_this_op;
- }
+ /* Not a named opcode, just allocate Op and append to parent */
- if (!op) {
- continue;
- }
+ if (walk_state->op_info->flags & AML_CREATE) {
+ /*
+ * Backup to beginning of create_xXXfield declaration
+ * body_length is unknown until we parse the body
+ */
+ op->named.data = aml_op_start;
+ op->named.length = 0;
+ }
- status =
- acpi_ps_next_parse_state(walk_state, op,
- status);
- if (status == AE_CTRL_PENDING) {
- status = AE_OK;
- goto close_this_op;
- }
+ acpi_ps_append_arg(acpi_ps_get_parent_scope
+ (&(walk_state->parser_state)), op);
- if (ACPI_FAILURE(status)) {
- goto close_this_op;
- }
+ if (walk_state->descending_callback != NULL) {
+ /*
+ * Find the object. This will either insert the object into
+ * the namespace or simply look it up
+ */
+ walk_state->op = *new_op = op;
- acpi_ps_append_arg(op,
- pre_op->common.value.arg);
- acpi_gbl_depth++;
-
- if (op->common.aml_opcode == AML_REGION_OP) {
- /*
- * Defer final parsing of an operation_region body,
- * because we don't have enough info in the first pass
- * to parse it correctly (i.e., there may be method
- * calls within the term_arg elements of the body.)
- *
- * However, we must continue parsing because
- * the opregion is not a standalone package --
- * we don't know where the end is at this point.
- *
- * (Length is unknown until parse of the body complete)
- */
- op->named.data = aml_op_start;
- op->named.length = 0;
- }
- } else {
- /* Not a named opcode, just allocate Op and append to parent */
+ status = walk_state->descending_callback(walk_state, &op);
+ status = acpi_ps_next_parse_state(walk_state, op, status);
+ if (status == AE_CTRL_PENDING) {
+ status = AE_CTRL_PARSE_PENDING;
+ }
+ }
- walk_state->op_info =
- acpi_ps_get_opcode_info(walk_state->opcode);
- op = acpi_ps_alloc_op(walk_state->opcode);
- if (!op) {
- status = AE_NO_MEMORY;
- goto close_this_op;
- }
+ return_ACPI_STATUS(status);
+}
- if (walk_state->op_info->flags & AML_CREATE) {
- /*
- * Backup to beginning of create_xXXfield declaration
- * body_length is unknown until we parse the body
- */
- op->named.data = aml_op_start;
- op->named.length = 0;
- }
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_get_arguments
+ *
+ * PARAMETERS: walk_state - Current state
+ * aml_op_start - Op start in AML
+ * Op - Current Op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get arguments for passed Op.
+ *
+ ******************************************************************************/
- acpi_ps_append_arg(acpi_ps_get_parent_scope
- (parser_state), op);
+static acpi_status
+acpi_ps_get_arguments(struct acpi_walk_state *walk_state,
+ u8 * aml_op_start, union acpi_parse_object *op)
+{
+ acpi_status status = AE_OK;
+ union acpi_parse_object *arg = NULL;
- if ((walk_state->descending_callback != NULL)) {
- /*
- * Find the object. This will either insert the object into
- * the namespace or simply look it up
- */
- walk_state->op = op;
+ ACPI_FUNCTION_TRACE_PTR(ps_get_arguments, walk_state);
- status =
- walk_state->
- descending_callback(walk_state,
- &op);
- status =
- acpi_ps_next_parse_state(walk_state,
- op,
- status);
- if (status == AE_CTRL_PENDING) {
- status = AE_OK;
- goto close_this_op;
- }
+ switch (op->common.aml_opcode) {
+ case AML_BYTE_OP: /* AML_BYTEDATA_ARG */
+ case AML_WORD_OP: /* AML_WORDDATA_ARG */
+ case AML_DWORD_OP: /* AML_DWORDATA_ARG */
+ case AML_QWORD_OP: /* AML_QWORDATA_ARG */
+ case AML_STRING_OP: /* AML_ASCIICHARLIST_ARG */
- if (ACPI_FAILURE(status)) {
- goto close_this_op;
- }
- }
- }
+ /* Fill in constant or string argument directly */
- op->common.aml_offset = walk_state->aml_offset;
+ acpi_ps_get_next_simple_arg(&(walk_state->parser_state),
+ GET_CURRENT_ARG_TYPE(walk_state->
+ arg_types),
+ op);
+ break;
- if (walk_state->op_info) {
- ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
- "Opcode %4.4X [%s] Op %p Aml %p AmlOffset %5.5X\n",
- (u32) op->common.aml_opcode,
- walk_state->op_info->name, op,
- parser_state->aml,
- op->common.aml_offset));
- }
+ case AML_INT_NAMEPATH_OP: /* AML_NAMESTRING_ARG */
+
+ status =
+ acpi_ps_get_next_namepath(walk_state,
+ &(walk_state->parser_state), op,
+ 1);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
}
+ walk_state->arg_types = 0;
+ break;
+
+ default:
/*
- * Start arg_count at zero because we don't know if there are
- * any args yet
+ * Op is not a constant or string, append each argument to the Op
*/
- walk_state->arg_count = 0;
-
- /* Are there any arguments that must be processed? */
-
- if (walk_state->arg_types) {
-
- /* Get arguments */
-
- switch (op->common.aml_opcode) {
- case AML_BYTE_OP: /* AML_BYTEDATA_ARG */
- case AML_WORD_OP: /* AML_WORDDATA_ARG */
- case AML_DWORD_OP: /* AML_DWORDATA_ARG */
- case AML_QWORD_OP: /* AML_QWORDATA_ARG */
- case AML_STRING_OP: /* AML_ASCIICHARLIST_ARG */
-
- /* Fill in constant or string argument directly */
-
- acpi_ps_get_next_simple_arg(parser_state,
- GET_CURRENT_ARG_TYPE
- (walk_state->
- arg_types), op);
- break;
-
- case AML_INT_NAMEPATH_OP: /* AML_NAMESTRING_ARG */
-
- status =
- acpi_ps_get_next_namepath(walk_state,
- parser_state, op,
- 1);
- if (ACPI_FAILURE(status)) {
- goto close_this_op;
- }
-
- walk_state->arg_types = 0;
- break;
+ while (GET_CURRENT_ARG_TYPE(walk_state->arg_types)
+ && !walk_state->arg_count) {
+ walk_state->aml_offset =
+ (u32) ACPI_PTR_DIFF(walk_state->parser_state.aml,
+ walk_state->parser_state.
+ aml_start);
- default:
- /*
- * Op is not a constant or string, append each argument
- * to the Op
- */
- while (GET_CURRENT_ARG_TYPE
- (walk_state->arg_types)
- && !walk_state->arg_count) {
- walk_state->aml_offset = (u32)
- ACPI_PTR_DIFF(parser_state->aml,
- parser_state->
- aml_start);
+ status =
+ acpi_ps_get_next_arg(walk_state,
+ &(walk_state->parser_state),
+ GET_CURRENT_ARG_TYPE
+ (walk_state->arg_types), &arg);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
- status =
- acpi_ps_get_next_arg(walk_state,
- parser_state,
- GET_CURRENT_ARG_TYPE
- (walk_state->
- arg_types),
- &arg);
- if (ACPI_FAILURE(status)) {
- goto close_this_op;
- }
+ if (arg) {
+ arg->common.aml_offset = walk_state->aml_offset;
+ acpi_ps_append_arg(op, arg);
+ }
- if (arg) {
- arg->common.aml_offset =
- walk_state->aml_offset;
- acpi_ps_append_arg(op, arg);
- }
- INCREMENT_ARG_LIST(walk_state->
- arg_types);
- }
+ INCREMENT_ARG_LIST(walk_state->arg_types);
+ }
- /* Special processing for certain opcodes */
+ /* Special processing for certain opcodes */
- /* TBD (remove): Temporary mechanism to disable this code if needed */
+ /* TBD (remove): Temporary mechanism to disable this code if needed */
#ifdef ACPI_ENABLE_MODULE_LEVEL_CODE
- if ((walk_state->pass_number <=
- ACPI_IMODE_LOAD_PASS1)
- &&
- ((walk_state->
- parse_flags & ACPI_PARSE_DISASSEMBLE) ==
- 0)) {
- /*
- * We want to skip If/Else/While constructs during Pass1
- * because we want to actually conditionally execute the
- * code during Pass2.
- *
- * Except for disassembly, where we always want to
- * walk the If/Else/While packages
- */
- switch (op->common.aml_opcode) {
- case AML_IF_OP:
- case AML_ELSE_OP:
- case AML_WHILE_OP:
-
- ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
- "Pass1: Skipping an If/Else/While body\n"));
-
- /* Skip body of if/else/while in pass 1 */
-
- parser_state->aml =
- parser_state->pkg_end;
- walk_state->arg_count = 0;
- break;
-
- default:
- break;
- }
- }
-#endif
- switch (op->common.aml_opcode) {
- case AML_METHOD_OP:
-
- /*
- * Skip parsing of control method
- * because we don't have enough info in the first pass
- * to parse it correctly.
- *
- * Save the length and address of the body
- */
- op->named.data = parser_state->aml;
- op->named.length =
- (u32) (parser_state->pkg_end -
- parser_state->aml);
-
- /* Skip body of method */
-
- parser_state->aml =
- parser_state->pkg_end;
- walk_state->arg_count = 0;
- break;
-
- case AML_BUFFER_OP:
- case AML_PACKAGE_OP:
- case AML_VAR_PACKAGE_OP:
-
- if ((op->common.parent) &&
- (op->common.parent->common.
- aml_opcode == AML_NAME_OP)
- && (walk_state->pass_number <=
- ACPI_IMODE_LOAD_PASS2)) {
- /*
- * Skip parsing of Buffers and Packages
- * because we don't have enough info in the first pass
- * to parse them correctly.
- */
- op->named.data = aml_op_start;
- op->named.length =
- (u32) (parser_state->
- pkg_end -
- aml_op_start);
-
- /* Skip body */
-
- parser_state->aml =
- parser_state->pkg_end;
- walk_state->arg_count = 0;
- }
- break;
+ if ((walk_state->pass_number <= ACPI_IMODE_LOAD_PASS1) &&
+ ((walk_state->parse_flags & ACPI_PARSE_DISASSEMBLE) == 0)) {
+ /*
+ * We want to skip If/Else/While constructs during Pass1 because we
+ * want to actually conditionally execute the code during Pass2.
+ *
+ * Except for disassembly, where we always want to walk the
+ * If/Else/While packages
+ */
+ switch (op->common.aml_opcode) {
+ case AML_IF_OP:
+ case AML_ELSE_OP:
+ case AML_WHILE_OP:
- case AML_WHILE_OP:
+ ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
+ "Pass1: Skipping an If/Else/While body\n"));
- if (walk_state->control_state) {
- walk_state->control_state->
- control.package_end =
- parser_state->pkg_end;
- }
- break;
+ /* Skip body of if/else/while in pass 1 */
- default:
+ walk_state->parser_state.aml =
+ walk_state->parser_state.pkg_end;
+ walk_state->arg_count = 0;
+ break;
- /* No action for all other opcodes */
- break;
- }
+ default:
break;
}
}
+#endif
- /* Check for arguments that need to be processed */
-
- if (walk_state->arg_count) {
+ switch (op->common.aml_opcode) {
+ case AML_METHOD_OP:
/*
- * There are arguments (complex ones), push Op and
- * prepare for argument
+ * Skip parsing of control method because we don't have enough
+ * info in the first pass to parse it correctly.
+ *
+ * Save the length and address of the body
*/
- status = acpi_ps_push_scope(parser_state, op,
- walk_state->arg_types,
- walk_state->arg_count);
- if (ACPI_FAILURE(status)) {
- goto close_this_op;
- }
- op = NULL;
- continue;
- }
+ op->named.data = walk_state->parser_state.aml;
+ op->named.length = (u32)
+ (walk_state->parser_state.pkg_end -
+ walk_state->parser_state.aml);
- /*
- * All arguments have been processed -- Op is complete,
- * prepare for next
- */
- walk_state->op_info =
- acpi_ps_get_opcode_info(op->common.aml_opcode);
- if (walk_state->op_info->flags & AML_NAMED) {
- if (acpi_gbl_depth) {
- acpi_gbl_depth--;
- }
+ /* Skip body of method */
- if (op->common.aml_opcode == AML_REGION_OP) {
+ walk_state->parser_state.aml =
+ walk_state->parser_state.pkg_end;
+ walk_state->arg_count = 0;
+ break;
+
+ case AML_BUFFER_OP:
+ case AML_PACKAGE_OP:
+ case AML_VAR_PACKAGE_OP:
+
+ if ((op->common.parent) &&
+ (op->common.parent->common.aml_opcode ==
+ AML_NAME_OP)
+ && (walk_state->pass_number <=
+ ACPI_IMODE_LOAD_PASS2)) {
/*
- * Skip parsing of control method or opregion body,
- * because we don't have enough info in the first pass
- * to parse them correctly.
- *
- * Completed parsing an op_region declaration, we now
- * know the length.
+ * Skip parsing of Buffers and Packages because we don't have
+ * enough info in the first pass to parse them correctly.
*/
- op->named.length =
- (u32) (parser_state->aml - op->named.data);
- }
- }
+ op->named.data = aml_op_start;
+ op->named.length = (u32)
+ (walk_state->parser_state.pkg_end -
+ aml_op_start);
- if (walk_state->op_info->flags & AML_CREATE) {
- /*
- * Backup to beginning of create_xXXfield declaration (1 for
- * Opcode)
- *
- * body_length is unknown until we parse the body
- */
- op->named.length =
- (u32) (parser_state->aml - op->named.data);
- }
+ /* Skip body */
- /* This op complete, notify the dispatcher */
+ walk_state->parser_state.aml =
+ walk_state->parser_state.pkg_end;
+ walk_state->arg_count = 0;
+ }
+ break;
- if (walk_state->ascending_callback != NULL) {
- walk_state->op = op;
- walk_state->opcode = op->common.aml_opcode;
+ case AML_WHILE_OP:
- status = walk_state->ascending_callback(walk_state);
- status =
- acpi_ps_next_parse_state(walk_state, op, status);
- if (status == AE_CTRL_PENDING) {
- status = AE_OK;
- goto close_this_op;
+ if (walk_state->control_state) {
+ walk_state->control_state->control.package_end =
+ walk_state->parser_state.pkg_end;
}
- }
-
- close_this_op:
- /*
- * Finished one argument of the containing scope
- */
- parser_state->scope->parse_scope.arg_count--;
+ break;
- /* Finished with pre_op */
+ default:
- if (pre_op) {
- acpi_ps_free_op(pre_op);
- pre_op = NULL;
+ /* No action for all other opcodes */
+ break;
}
- /* Close this Op (will result in parse subtree deletion) */
+ break;
+ }
- status2 = acpi_ps_complete_this_op(walk_state, op);
- if (ACPI_FAILURE(status2)) {
- return_ACPI_STATUS(status2);
- }
- op = NULL;
+ return_ACPI_STATUS(AE_OK);
+}
- switch (status) {
- case AE_OK:
- break;
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_complete_op
+ *
+ * PARAMETERS: walk_state - Current state
+ * Op - Returned Op
+ * Status - Parse status before complete Op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Complete Op
+ *
+ ******************************************************************************/
- case AE_CTRL_TRANSFER:
+static acpi_status
+acpi_ps_complete_op(struct acpi_walk_state *walk_state,
+ union acpi_parse_object **op, acpi_status status)
+{
+ acpi_status status2;
- /* We are about to transfer to a called method. */
+ ACPI_FUNCTION_TRACE_PTR(ps_complete_op, walk_state);
- walk_state->prev_op = op;
- walk_state->prev_arg_types = walk_state->arg_types;
- return_ACPI_STATUS(status);
+ /*
+ * Finished one argument of the containing scope
+ */
+ walk_state->parser_state.scope->parse_scope.arg_count--;
- case AE_CTRL_END:
+ /* Close this Op (will result in parse subtree deletion) */
- acpi_ps_pop_scope(parser_state, &op,
- &walk_state->arg_types,
- &walk_state->arg_count);
+ status2 = acpi_ps_complete_this_op(walk_state, *op);
+ if (ACPI_FAILURE(status2)) {
+ return_ACPI_STATUS(status2);
+ }
- if (op) {
- walk_state->op = op;
- walk_state->op_info =
- acpi_ps_get_opcode_info(op->common.
- aml_opcode);
- walk_state->opcode = op->common.aml_opcode;
+ *op = NULL;
- status =
- walk_state->ascending_callback(walk_state);
- status =
- acpi_ps_next_parse_state(walk_state, op,
- status);
+ switch (status) {
+ case AE_OK:
+ break;
- status2 =
- acpi_ps_complete_this_op(walk_state, op);
- if (ACPI_FAILURE(status2)) {
- return_ACPI_STATUS(status2);
- }
- op = NULL;
- }
- status = AE_OK;
- break;
+ case AE_CTRL_TRANSFER:
- case AE_CTRL_BREAK:
- case AE_CTRL_CONTINUE:
+ /* We are about to transfer to a called method */
- /* Pop off scopes until we find the While */
+ walk_state->prev_op = NULL;
+ walk_state->prev_arg_types = walk_state->arg_types;
+ return_ACPI_STATUS(status);
- while (!op || (op->common.aml_opcode != AML_WHILE_OP)) {
- acpi_ps_pop_scope(parser_state, &op,
- &walk_state->arg_types,
- &walk_state->arg_count);
+ case AE_CTRL_END:
- if (op->common.aml_opcode != AML_WHILE_OP) {
- status2 =
- acpi_ds_result_stack_pop
- (walk_state);
- if (ACPI_FAILURE(status2)) {
- return_ACPI_STATUS(status2);
- }
- }
- }
-
- /* Close this iteration of the While loop */
+ acpi_ps_pop_scope(&(walk_state->parser_state), op,
+ &walk_state->arg_types,
+ &walk_state->arg_count);
- walk_state->op = op;
+ if (*op) {
+ walk_state->op = *op;
walk_state->op_info =
- acpi_ps_get_opcode_info(op->common.aml_opcode);
- walk_state->opcode = op->common.aml_opcode;
+ acpi_ps_get_opcode_info((*op)->common.aml_opcode);
+ walk_state->opcode = (*op)->common.aml_opcode;
status = walk_state->ascending_callback(walk_state);
status =
- acpi_ps_next_parse_state(walk_state, op, status);
+ acpi_ps_next_parse_state(walk_state, *op, status);
- status2 = acpi_ps_complete_this_op(walk_state, op);
+ status2 = acpi_ps_complete_this_op(walk_state, *op);
if (ACPI_FAILURE(status2)) {
return_ACPI_STATUS(status2);
}
- op = NULL;
-
- status = AE_OK;
- break;
+ }
- case AE_CTRL_TERMINATE:
+ status = AE_OK;
+ break;
- status = AE_OK;
+ case AE_CTRL_BREAK:
+ case AE_CTRL_CONTINUE:
- /* Clean up */
- do {
- if (op) {
- status2 =
- acpi_ps_complete_this_op(walk_state,
- op);
- if (ACPI_FAILURE(status2)) {
- return_ACPI_STATUS(status2);
- }
+ /* Pop off scopes until we find the While */
- status2 =
- acpi_ds_result_stack_pop
- (walk_state);
- if (ACPI_FAILURE(status2)) {
- return_ACPI_STATUS(status2);
- }
+ while (!(*op) || ((*op)->common.aml_opcode != AML_WHILE_OP)) {
+ acpi_ps_pop_scope(&(walk_state->parser_state), op,
+ &walk_state->arg_types,
+ &walk_state->arg_count);
- acpi_ut_delete_generic_state
- (acpi_ut_pop_generic_state
- (&walk_state->control_state));
+ if ((*op)->common.aml_opcode != AML_WHILE_OP) {
+ status2 = acpi_ds_result_stack_pop(walk_state);
+ if (ACPI_FAILURE(status2)) {
+ return_ACPI_STATUS(status2);
}
+ }
+ }
- acpi_ps_pop_scope(parser_state, &op,
- &walk_state->arg_types,
- &walk_state->arg_count);
+ /* Close this iteration of the While loop */
- } while (op);
+ walk_state->op = *op;
+ walk_state->op_info =
+ acpi_ps_get_opcode_info((*op)->common.aml_opcode);
+ walk_state->opcode = (*op)->common.aml_opcode;
- return_ACPI_STATUS(status);
+ status = walk_state->ascending_callback(walk_state);
+ status = acpi_ps_next_parse_state(walk_state, *op, status);
- default: /* All other non-AE_OK status */
+ status2 = acpi_ps_complete_this_op(walk_state, *op);
+ if (ACPI_FAILURE(status2)) {
+ return_ACPI_STATUS(status2);
+ }
- do {
- if (op) {
- status2 =
- acpi_ps_complete_this_op(walk_state,
- op);
- if (ACPI_FAILURE(status2)) {
- return_ACPI_STATUS(status2);
- }
+ status = AE_OK;
+ break;
+
+ case AE_CTRL_TERMINATE:
+
+ /* Clean up */
+ do {
+ if (*op) {
+ status2 =
+ acpi_ps_complete_this_op(walk_state, *op);
+ if (ACPI_FAILURE(status2)) {
+ return_ACPI_STATUS(status2);
+ }
+ status2 = acpi_ds_result_stack_pop(walk_state);
+ if (ACPI_FAILURE(status2)) {
+ return_ACPI_STATUS(status2);
}
- acpi_ps_pop_scope(parser_state, &op,
- &walk_state->arg_types,
- &walk_state->arg_count);
+ acpi_ut_delete_generic_state
+ (acpi_ut_pop_generic_state
+ (&walk_state->control_state));
+ }
- } while (op);
+ acpi_ps_pop_scope(&(walk_state->parser_state), op,
+ &walk_state->arg_types,
+ &walk_state->arg_count);
- /*
- * TBD: Cleanup parse ops on error
- */
-#if 0
- if (op == NULL) {
- acpi_ps_pop_scope(parser_state, &op,
- &walk_state->arg_types,
- &walk_state->arg_count);
+ } while (*op);
+
+ return_ACPI_STATUS(AE_OK);
+
+ default: /* All other non-AE_OK status */
+
+ do {
+ if (*op) {
+ status2 =
+ acpi_ps_complete_this_op(walk_state, *op);
+ if (ACPI_FAILURE(status2)) {
+ return_ACPI_STATUS(status2);
+ }
}
-#endif
- walk_state->prev_op = op;
- walk_state->prev_arg_types = walk_state->arg_types;
- return_ACPI_STATUS(status);
- }
- /* This scope complete? */
+ acpi_ps_pop_scope(&(walk_state->parser_state), op,
+ &walk_state->arg_types,
+ &walk_state->arg_count);
- if (acpi_ps_has_completed_scope(parser_state)) {
- acpi_ps_pop_scope(parser_state, &op,
+ } while (*op);
+
+#if 0
+ /*
+ * TBD: Cleanup parse ops on error
+ */
+ if (*op == NULL) {
+ acpi_ps_pop_scope(parser_state, op,
&walk_state->arg_types,
&walk_state->arg_count);
- ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
- "Popped scope, Op=%p\n", op));
- } else {
- op = NULL;
}
+#endif
+ walk_state->prev_op = NULL;
+ walk_state->prev_arg_types = walk_state->arg_types;
+ return_ACPI_STATUS(status);
+ }
- } /* while parser_state->Aml */
+ /* This scope complete? */
+
+ if (acpi_ps_has_completed_scope(&(walk_state->parser_state))) {
+ acpi_ps_pop_scope(&(walk_state->parser_state), op,
+ &walk_state->arg_types,
+ &walk_state->arg_count);
+ ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "Popped scope, Op=%p\n", *op));
+ } else {
+ *op = NULL;
+ }
+
+ return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_complete_final_op
+ *
+ * PARAMETERS: walk_state - Current state
+ * Op - Current Op
+ * Status - Current parse status before complete last
+ * Op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Complete last Op.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ps_complete_final_op(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op, acpi_status status)
+{
+ acpi_status status2;
+
+ ACPI_FUNCTION_TRACE_PTR(ps_complete_final_op, walk_state);
/*
* Complete the last Op (if not completed), and clear the scope stack.
* It is easily possible to end an AML "package" with an unbounded number
* of open scopes (such as when several ASL blocks are closed with
- * sequential closing braces). We want to terminate each one cleanly.
+ * sequential closing braces). We want to terminate each one cleanly.
*/
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "AML package complete at Op %p\n",
op));
@@ -838,8 +750,12 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
acpi_ps_next_parse_state(walk_state, op,
status);
if (status == AE_CTRL_PENDING) {
- status = AE_OK;
- goto close_this_op;
+ status =
+ acpi_ps_complete_op(walk_state, &op,
+ AE_OK);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
}
if (status == AE_CTRL_TERMINATE) {
@@ -858,7 +774,9 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
}
}
- acpi_ps_pop_scope(parser_state,
+ acpi_ps_pop_scope(&
+ (walk_state->
+ parser_state),
&op,
&walk_state->
arg_types,
@@ -887,10 +805,252 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
}
}
- acpi_ps_pop_scope(parser_state, &op, &walk_state->arg_types,
+ acpi_ps_pop_scope(&(walk_state->parser_state), &op,
+ &walk_state->arg_types,
&walk_state->arg_count);
} while (op);
return_ACPI_STATUS(status);
}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_parse_loop
+ *
+ * PARAMETERS: walk_state - Current state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Parse AML (pointed to by the current parser state) and return
+ * a tree of ops.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
+{
+ acpi_status status = AE_OK;
+ union acpi_parse_object *op = NULL; /* current op */
+ struct acpi_parse_state *parser_state;
+ u8 *aml_op_start = NULL;
+
+ ACPI_FUNCTION_TRACE_PTR(ps_parse_loop, walk_state);
+
+ if (walk_state->descending_callback == NULL) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ parser_state = &walk_state->parser_state;
+ walk_state->arg_types = 0;
+
+#if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY))
+
+ if (walk_state->walk_type & ACPI_WALK_METHOD_RESTART) {
+
+ /* We are restarting a preempted control method */
+
+ if (acpi_ps_has_completed_scope(parser_state)) {
+ /*
+ * We must check if a predicate to an IF or WHILE statement
+ * was just completed
+ */
+ if ((parser_state->scope->parse_scope.op) &&
+ ((parser_state->scope->parse_scope.op->common.
+ aml_opcode == AML_IF_OP)
+ || (parser_state->scope->parse_scope.op->common.
+ aml_opcode == AML_WHILE_OP))
+ && (walk_state->control_state)
+ && (walk_state->control_state->common.state ==
+ ACPI_CONTROL_PREDICATE_EXECUTING)) {
+ /*
+ * A predicate was just completed, get the value of the
+ * predicate and branch based on that value
+ */
+ walk_state->op = NULL;
+ status =
+ acpi_ds_get_predicate_value(walk_state,
+ ACPI_TO_POINTER
+ (TRUE));
+ if (ACPI_FAILURE(status)
+ && ((status & AE_CODE_MASK) !=
+ AE_CODE_CONTROL)) {
+ if (status == AE_AML_NO_RETURN_VALUE) {
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Invoked method did not return a value"));
+
+ }
+
+ ACPI_EXCEPTION((AE_INFO, status,
+ "GetPredicate Failed"));
+ return_ACPI_STATUS(status);
+ }
+
+ status =
+ acpi_ps_next_parse_state(walk_state, op,
+ status);
+ }
+
+ acpi_ps_pop_scope(parser_state, &op,
+ &walk_state->arg_types,
+ &walk_state->arg_count);
+ ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
+ "Popped scope, Op=%p\n", op));
+ } else if (walk_state->prev_op) {
+
+ /* We were in the middle of an op */
+
+ op = walk_state->prev_op;
+ walk_state->arg_types = walk_state->prev_arg_types;
+ }
+ }
+#endif
+
+ /* Iterative parsing loop, while there is more AML to process: */
+
+ while ((parser_state->aml < parser_state->aml_end) || (op)) {
+ aml_op_start = parser_state->aml;
+ if (!op) {
+ status =
+ acpi_ps_create_op(walk_state, aml_op_start, &op);
+ if (ACPI_FAILURE(status)) {
+ if (status == AE_CTRL_PARSE_CONTINUE) {
+ continue;
+ }
+
+ if (status == AE_CTRL_PARSE_PENDING) {
+ status = AE_OK;
+ }
+
+ status =
+ acpi_ps_complete_op(walk_state, &op,
+ status);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ continue;
+ }
+
+ op->common.aml_offset = walk_state->aml_offset;
+
+ if (walk_state->op_info) {
+ ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
+ "Opcode %4.4X [%s] Op %p Aml %p AmlOffset %5.5X\n",
+ (u32) op->common.aml_opcode,
+ walk_state->op_info->name, op,
+ parser_state->aml,
+ op->common.aml_offset));
+ }
+ }
+
+ /*
+ * Start arg_count at zero because we don't know if there are
+ * any args yet
+ */
+ walk_state->arg_count = 0;
+
+ /* Are there any arguments that must be processed? */
+
+ if (walk_state->arg_types) {
+
+ /* Get arguments */
+
+ status =
+ acpi_ps_get_arguments(walk_state, aml_op_start, op);
+ if (ACPI_FAILURE(status)) {
+ status =
+ acpi_ps_complete_op(walk_state, &op,
+ status);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ continue;
+ }
+ }
+
+ /* Check for arguments that need to be processed */
+
+ if (walk_state->arg_count) {
+ /*
+ * There are arguments (complex ones), push Op and
+ * prepare for argument
+ */
+ status = acpi_ps_push_scope(parser_state, op,
+ walk_state->arg_types,
+ walk_state->arg_count);
+ if (ACPI_FAILURE(status)) {
+ status =
+ acpi_ps_complete_op(walk_state, &op,
+ status);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ continue;
+ }
+
+ op = NULL;
+ continue;
+ }
+
+ /*
+ * All arguments have been processed -- Op is complete,
+ * prepare for next
+ */
+ walk_state->op_info =
+ acpi_ps_get_opcode_info(op->common.aml_opcode);
+ if (walk_state->op_info->flags & AML_NAMED) {
+ if (acpi_gbl_depth) {
+ acpi_gbl_depth--;
+ }
+
+ if (op->common.aml_opcode == AML_REGION_OP) {
+ /*
+ * Skip parsing of control method or opregion body,
+ * because we don't have enough info in the first pass
+ * to parse them correctly.
+ *
+ * Completed parsing an op_region declaration, we now
+ * know the length.
+ */
+ op->named.length =
+ (u32) (parser_state->aml - op->named.data);
+ }
+ }
+
+ if (walk_state->op_info->flags & AML_CREATE) {
+ /*
+ * Backup to beginning of create_xXXfield declaration (1 for
+ * Opcode)
+ *
+ * body_length is unknown until we parse the body
+ */
+ op->named.length =
+ (u32) (parser_state->aml - op->named.data);
+ }
+
+ /* This op complete, notify the dispatcher */
+
+ if (walk_state->ascending_callback != NULL) {
+ walk_state->op = op;
+ walk_state->opcode = op->common.aml_opcode;
+
+ status = walk_state->ascending_callback(walk_state);
+ status =
+ acpi_ps_next_parse_state(walk_state, op, status);
+ if (status == AE_CTRL_PENDING) {
+ status = AE_OK;
+ }
+ }
+
+ status = acpi_ps_complete_op(walk_state, &op, status);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ } /* while parser_state->Aml */
+
+ status = acpi_ps_complete_final_op(walk_state, op, status);
+ return_ACPI_STATUS(status);
+}
diff --git a/drivers/acpi/parser/psopcode.c b/drivers/acpi/parser/psopcode.c
index 4bd25e32769..16d8b6cc3c2 100644
--- a/drivers/acpi/parser/psopcode.c
+++ b/drivers/acpi/parser/psopcode.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/parser/psparse.c b/drivers/acpi/parser/psparse.c
index a02aa62fe1e..5d63f48e56b 100644
--- a/drivers/acpi/parser/psparse.c
+++ b/drivers/acpi/parser/psparse.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -540,6 +540,11 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state)
if ((status == AE_ALREADY_EXISTS) &&
(!walk_state->method_desc->method.mutex)) {
+ ACPI_INFO((AE_INFO,
+ "Marking method %4.4s as Serialized",
+ walk_state->method_node->name.
+ ascii));
+
/*
* Method tried to create an object twice. The probable cause is
* that the method cannot handle reentrancy.
diff --git a/drivers/acpi/parser/psscope.c b/drivers/acpi/parser/psscope.c
index a3e0314de24..77cfa4ed0cf 100644
--- a/drivers/acpi/parser/psscope.c
+++ b/drivers/acpi/parser/psscope.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/parser/pstree.c b/drivers/acpi/parser/pstree.c
index 0015717ef09..966e7ea2a0c 100644
--- a/drivers/acpi/parser/pstree.c
+++ b/drivers/acpi/parser/pstree.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/parser/psutils.c b/drivers/acpi/parser/psutils.c
index d405387b741..8ca52002db5 100644
--- a/drivers/acpi/parser/psutils.c
+++ b/drivers/acpi/parser/psutils.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/parser/pswalk.c b/drivers/acpi/parser/pswalk.c
index a84a547a0f1..49f9757434e 100644
--- a/drivers/acpi/parser/pswalk.c
+++ b/drivers/acpi/parser/pswalk.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/parser/psxface.c b/drivers/acpi/parser/psxface.c
index 5d996c1140a..94103bced75 100644
--- a/drivers/acpi/parser/psxface.c
+++ b/drivers/acpi/parser/psxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -54,8 +54,6 @@ static void acpi_ps_start_trace(struct acpi_evaluate_info *info);
static void acpi_ps_stop_trace(struct acpi_evaluate_info *info);
-static acpi_status acpi_ps_execute_pass(struct acpi_evaluate_info *info);
-
static void
acpi_ps_update_parameter_list(struct acpi_evaluate_info *info, u16 action);
@@ -215,6 +213,8 @@ static void acpi_ps_stop_trace(struct acpi_evaluate_info *info)
acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info)
{
acpi_status status;
+ union acpi_parse_object *op;
+ struct acpi_walk_state *walk_state;
ACPI_FUNCTION_TRACE(ps_execute_method);
@@ -234,8 +234,7 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info)
}
/*
- * The caller "owns" the parameters, so give each one an extra
- * reference
+ * The caller "owns" the parameters, so give each one an extra reference
*/
acpi_ps_update_parameter_list(info, REF_INCREMENT);
@@ -244,30 +243,50 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info)
acpi_ps_start_trace(info);
/*
- * 1) Perform the first pass parse of the method to enter any
- * named objects that it creates into the namespace
+ * Execute the method. Performs parse simultaneously
*/
ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
- "**** Begin Method Parse **** Entry=%p obj=%p\n",
- info->resolved_node, info->obj_desc));
+ "**** Begin Method Parse/Execute [%4.4s] **** Node=%p Obj=%p\n",
+ info->resolved_node->name.ascii, info->resolved_node,
+ info->obj_desc));
+
+ /* Create and init a Root Node */
+
+ op = acpi_ps_create_scope_op();
+ if (!op) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /* Create and initialize a new walk state */
+
+ info->pass_number = ACPI_IMODE_EXECUTE;
+ walk_state =
+ acpi_ds_create_walk_state(info->obj_desc->method.owner_id, NULL,
+ NULL, NULL);
+ if (!walk_state) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
- info->pass_number = 1;
- status = acpi_ps_execute_pass(info);
+ status = acpi_ds_init_aml_walk(walk_state, op, info->resolved_node,
+ info->obj_desc->method.aml_start,
+ info->obj_desc->method.aml_length, info,
+ info->pass_number);
if (ACPI_FAILURE(status)) {
+ acpi_ds_delete_walk_state(walk_state);
goto cleanup;
}
- /*
- * 2) Execute the method. Performs second pass parse simultaneously
- */
- ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
- "**** Begin Method Execution **** Entry=%p obj=%p\n",
- info->resolved_node, info->obj_desc));
+ /* Parse the AML */
- info->pass_number = 3;
- status = acpi_ps_execute_pass(info);
+ status = acpi_ps_parse_aml(walk_state);
+
+ /* walk_state was deleted by parse_aml */
cleanup:
+ acpi_ps_delete_parse_tree(op);
+
/* End optional tracing */
acpi_ps_stop_trace(info);
@@ -330,62 +349,3 @@ acpi_ps_update_parameter_list(struct acpi_evaluate_info *info, u16 action)
}
}
}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ps_execute_pass
- *
- * PARAMETERS: Info - See struct acpi_evaluate_info
- * (Used: pass_number, Node, and obj_desc)
- *
- * RETURN: Status
- *
- * DESCRIPTION: Single AML pass: Parse or Execute a control method
- *
- ******************************************************************************/
-
-static acpi_status acpi_ps_execute_pass(struct acpi_evaluate_info *info)
-{
- acpi_status status;
- union acpi_parse_object *op;
- struct acpi_walk_state *walk_state;
-
- ACPI_FUNCTION_TRACE(ps_execute_pass);
-
- /* Create and init a Root Node */
-
- op = acpi_ps_create_scope_op();
- if (!op) {
- return_ACPI_STATUS(AE_NO_MEMORY);
- }
-
- /* Create and initialize a new walk state */
-
- walk_state =
- acpi_ds_create_walk_state(info->obj_desc->method.owner_id, NULL,
- NULL, NULL);
- if (!walk_state) {
- status = AE_NO_MEMORY;
- goto cleanup;
- }
-
- status = acpi_ds_init_aml_walk(walk_state, op, info->resolved_node,
- info->obj_desc->method.aml_start,
- info->obj_desc->method.aml_length,
- info->pass_number == 1 ? NULL : info,
- info->pass_number);
- if (ACPI_FAILURE(status)) {
- acpi_ds_delete_walk_state(walk_state);
- goto cleanup;
- }
-
- /* Parse the AML */
-
- status = acpi_ps_parse_aml(walk_state);
-
- /* Walk state was deleted by parse_aml */
-
- cleanup:
- acpi_ps_delete_parse_tree(op);
- return_ACPI_STATUS(status);
-}
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index 481e633bbf4..0f683c8c6fb 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -513,7 +513,7 @@ int __init acpi_irq_penalty_init(void)
}
}
/* Add a penalty for the SCI */
- acpi_irq_penalty[acpi_fadt.sci_int] += PIRQ_PENALTY_PCI_USING;
+ acpi_irq_penalty[acpi_gbl_FADT.sci_interrupt] += PIRQ_PENALTY_PCI_USING;
return 0;
}
@@ -785,7 +785,7 @@ 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_set_register(ACPI_BITREG_SCI_ENABLE, 1);
list_for_each(node, &acpi_link.entries) {
link = list_entry(node, struct acpi_pci_link, node);
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index a860efa2c56..4ecf701687e 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -117,6 +117,19 @@ void acpi_pci_unregister_driver(struct acpi_pci_driver *driver)
EXPORT_SYMBOL(acpi_pci_unregister_driver);
+acpi_handle acpi_get_pci_rootbridge_handle(unsigned int seg, unsigned int bus)
+{
+ struct acpi_pci_root *tmp;
+
+ list_for_each_entry(tmp, &acpi_pci_roots, node) {
+ if ((tmp->id.segment == (u16) seg) && (tmp->id.bus == (u16) bus))
+ return tmp->device->handle;
+ }
+ return NULL;
+}
+
+EXPORT_SYMBOL_GPL(acpi_get_pci_rootbridge_handle);
+
static acpi_status
get_root_bridge_busnr_callback(struct acpi_resource *resource, void *data)
{
@@ -152,6 +165,21 @@ static acpi_status try_get_root_bridge_busnr(acpi_handle handle, int *busnum)
return AE_OK;
}
+static void acpi_pci_bridge_scan(struct acpi_device *device)
+{
+ int status;
+ struct acpi_device *child = NULL;
+
+ if (device->flags.bus_address)
+ if (device->parent && device->parent->ops.bind) {
+ status = device->parent->ops.bind(device);
+ if (!status) {
+ list_for_each_entry(child, &device->children, node)
+ acpi_pci_bridge_scan(child);
+ }
+ }
+}
+
static int acpi_pci_root_add(struct acpi_device *device)
{
int result = 0;
@@ -160,6 +188,7 @@ static int acpi_pci_root_add(struct acpi_device *device)
acpi_status status = AE_OK;
unsigned long value = 0;
acpi_handle handle = NULL;
+ struct acpi_device *child;
if (!device)
@@ -175,9 +204,6 @@ static int acpi_pci_root_add(struct acpi_device *device)
strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS);
acpi_driver_data(device) = root;
- /*
- * TBD: Doesn't the bus driver automatically set this?
- */
device->ops.bind = acpi_pci_bind;
/*
@@ -299,6 +325,12 @@ static int acpi_pci_root_add(struct acpi_device *device)
result = acpi_pci_irq_add_prt(device->handle, root->id.segment,
root->id.bus);
+ /*
+ * Scan and bind all _ADR-Based Devices
+ */
+ list_for_each_entry(child, &device->children, node)
+ acpi_pci_bridge_scan(child);
+
end:
if (result) {
if (!list_empty(&root->node))
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index 5f9496d59ed..0079bc51082 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -375,30 +375,126 @@ static int acpi_processor_remove_fs(struct acpi_device *device)
}
/* Use the acpiid in MADT to map cpus in case of SMP */
+
#ifndef CONFIG_SMP
-#define convert_acpiid_to_cpu(acpi_id) (-1)
+static int get_cpu_id(acpi_handle handle, u32 acpi_id) {return -1;}
#else
+static struct acpi_table_madt *madt;
+
+static int map_lapic_id(struct acpi_subtable_header *entry,
+ u32 acpi_id, int *apic_id)
+{
+ struct acpi_madt_local_apic *lapic =
+ (struct acpi_madt_local_apic *)entry;
+ if ((lapic->lapic_flags & ACPI_MADT_ENABLED) &&
+ lapic->processor_id == acpi_id) {
+ *apic_id = lapic->id;
+ return 1;
+ }
+ return 0;
+}
+
+static int map_lsapic_id(struct acpi_subtable_header *entry,
+ u32 acpi_id, int *apic_id)
+{
+ struct acpi_madt_local_sapic *lsapic =
+ (struct acpi_madt_local_sapic *)entry;
+ /* Only check enabled APICs*/
+ if (lsapic->lapic_flags & ACPI_MADT_ENABLED) {
+ /* First check against id */
+ if (lsapic->processor_id == acpi_id) {
+ *apic_id = lsapic->id;
+ return 1;
+ /* Check against optional uid */
+ } else if (entry->length >= 16 &&
+ lsapic->uid == acpi_id) {
+ *apic_id = lsapic->uid;
+ return 1;
+ }
+ }
+ return 0;
+}
+
#ifdef CONFIG_IA64
-#define arch_acpiid_to_apicid ia64_acpiid_to_sapicid
#define arch_cpu_to_apicid ia64_cpu_to_sapicid
-#define ARCH_BAD_APICID (0xffff)
#else
-#define arch_acpiid_to_apicid x86_acpiid_to_apicid
#define arch_cpu_to_apicid x86_cpu_to_apicid
-#define ARCH_BAD_APICID (0xff)
#endif
-static int convert_acpiid_to_cpu(u8 acpi_id)
+static int map_madt_entry(u32 acpi_id)
+{
+ unsigned long madt_end, entry;
+ int apic_id = -1;
+
+ if (!madt)
+ return apic_id;
+
+ entry = (unsigned long)madt;
+ madt_end = entry + madt->header.length;
+
+ /* Parse all entries looking for a match. */
+
+ entry += sizeof(struct acpi_table_madt);
+ while (entry + sizeof(struct acpi_subtable_header) < madt_end) {
+ struct acpi_subtable_header *header =
+ (struct acpi_subtable_header *)entry;
+ if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) {
+ if (map_lapic_id(header, acpi_id, &apic_id))
+ break;
+ } else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) {
+ if (map_lsapic_id(header, acpi_id, &apic_id))
+ break;
+ }
+ entry += header->length;
+ }
+ return apic_id;
+}
+
+static int map_mat_entry(acpi_handle handle, u32 acpi_id)
+{
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *obj;
+ struct acpi_subtable_header *header;
+ int apic_id = -1;
+
+ if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
+ goto exit;
+
+ if (!buffer.length || !buffer.pointer)
+ goto exit;
+
+ obj = buffer.pointer;
+ if (obj->type != ACPI_TYPE_BUFFER ||
+ obj->buffer.length < sizeof(struct acpi_subtable_header)) {
+ goto exit;
+ }
+
+ header = (struct acpi_subtable_header *)obj->buffer.pointer;
+ if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) {
+ map_lapic_id(header, acpi_id, &apic_id);
+ } else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) {
+ map_lsapic_id(header, acpi_id, &apic_id);
+ }
+
+exit:
+ if (buffer.pointer)
+ kfree(buffer.pointer);
+ return apic_id;
+}
+
+static int get_cpu_id(acpi_handle handle, u32 acpi_id)
{
- u16 apic_id;
int i;
+ int apic_id = -1;
- apic_id = arch_acpiid_to_apicid[acpi_id];
- if (apic_id == ARCH_BAD_APICID)
- return -1;
+ apic_id = map_mat_entry(handle, acpi_id);
+ if (apic_id == -1)
+ apic_id = map_madt_entry(acpi_id);
+ if (apic_id == -1)
+ return apic_id;
- for (i = 0; i < NR_CPUS; i++) {
+ for (i = 0; i < NR_CPUS; ++i) {
if (arch_cpu_to_apicid[i] == apic_id)
return i;
}
@@ -410,7 +506,7 @@ static int convert_acpiid_to_cpu(u8 acpi_id)
Driver Interface
-------------------------------------------------------------------------- */
-static int acpi_processor_get_info(struct acpi_processor *pr)
+static int acpi_processor_get_info(struct acpi_processor *pr, unsigned has_uid)
{
acpi_status status = 0;
union acpi_object object = { 0 };
@@ -431,7 +527,7 @@ static int acpi_processor_get_info(struct acpi_processor *pr)
* Check to see if we have bus mastering arbitration control. This
* is required for proper C3 usage (to maintain cache coherency).
*/
- if (acpi_fadt.V1_pm2_cnt_blk && acpi_fadt.pm2_cnt_len) {
+ if (acpi_gbl_FADT.pm2_control_block && acpi_gbl_FADT.pm2_control_length) {
pr->flags.bm_control = 1;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Bus mastering arbitration control present\n"));
@@ -439,24 +535,35 @@ static int acpi_processor_get_info(struct acpi_processor *pr)
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"No bus mastering arbitration control\n"));
- /*
- * Evalute the processor object. Note that it is common on SMP to
- * have the first (boot) processor with a valid PBLK address while
- * all others have a NULL address.
- */
- status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer);
- if (ACPI_FAILURE(status)) {
- printk(KERN_ERR PREFIX "Evaluating processor object\n");
- return -ENODEV;
- }
-
- /*
- * TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP.
- * >>> 'acpi_get_processor_id(acpi_id, &id)' in arch/xxx/acpi.c
- */
- pr->acpi_id = object.processor.proc_id;
+ /* Check if it is a Device with HID and UID */
+ if (has_uid) {
+ unsigned long value;
+ status = acpi_evaluate_integer(pr->handle, METHOD_NAME__UID,
+ NULL, &value);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR PREFIX "Evaluating processor _UID\n");
+ return -ENODEV;
+ }
+ pr->acpi_id = value;
+ } else {
+ /*
+ * Evalute the processor object. Note that it is common on SMP to
+ * have the first (boot) processor with a valid PBLK address while
+ * all others have a NULL address.
+ */
+ status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR PREFIX "Evaluating processor object\n");
+ return -ENODEV;
+ }
- cpu_index = convert_acpiid_to_cpu(pr->acpi_id);
+ /*
+ * TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP.
+ * >>> 'acpi_get_processor_id(acpi_id, &id)' in arch/xxx/acpi.c
+ */
+ pr->acpi_id = object.processor.proc_id;
+ }
+ cpu_index = get_cpu_id(pr->handle, pr->acpi_id);
/* Handle UP system running SMP kernel, with no LAPIC in MADT */
if (!cpu0_initialized && (cpu_index == -1) &&
@@ -473,7 +580,7 @@ static int acpi_processor_get_info(struct acpi_processor *pr)
* less than the max # of CPUs. They should be ignored _iff
* they are physically not present.
*/
- if (cpu_index == -1) {
+ if (pr->id == -1) {
if (ACPI_FAILURE
(acpi_processor_hotadd_init(pr->handle, &pr->id))) {
return -ENODEV;
@@ -490,8 +597,8 @@ static int acpi_processor_get_info(struct acpi_processor *pr)
object.processor.pblk_length);
else {
pr->throttling.address = object.processor.pblk_address;
- pr->throttling.duty_offset = acpi_fadt.duty_offset;
- pr->throttling.duty_width = acpi_fadt.duty_width;
+ pr->throttling.duty_offset = acpi_gbl_FADT.duty_offset;
+ pr->throttling.duty_width = acpi_gbl_FADT.duty_width;
pr->pblk = object.processor.pblk_address;
@@ -525,7 +632,7 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device)
pr = acpi_driver_data(device);
- result = acpi_processor_get_info(pr);
+ result = acpi_processor_get_info(pr, device->flags.unique_id);
if (result) {
/* Processor is physically not present */
return 0;
@@ -707,7 +814,7 @@ int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device)
return -ENODEV;
if ((pr->id >= 0) && (pr->id < NR_CPUS)) {
- kobject_uevent(&(*device)->kobj, KOBJ_ONLINE);
+ kobject_uevent(&(*device)->dev.kobj, KOBJ_ONLINE);
}
return 0;
}
@@ -745,13 +852,13 @@ acpi_processor_hotplug_notify(acpi_handle handle, u32 event, void *data)
}
if (pr->id >= 0 && (pr->id < NR_CPUS)) {
- kobject_uevent(&device->kobj, KOBJ_OFFLINE);
+ kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
break;
}
result = acpi_processor_start(device);
if ((!result) && ((pr->id >= 0) && (pr->id < NR_CPUS))) {
- kobject_uevent(&device->kobj, KOBJ_ONLINE);
+ kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
} else {
printk(KERN_ERR PREFIX "Device [%s] failed to start\n",
acpi_device_bid(device));
@@ -774,7 +881,7 @@ acpi_processor_hotplug_notify(acpi_handle handle, u32 event, void *data)
}
if ((pr->id < NR_CPUS) && (cpu_present(pr->id)))
- kobject_uevent(&device->kobj, KOBJ_OFFLINE);
+ kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
break;
default:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -895,6 +1002,12 @@ static int __init acpi_processor_init(void)
memset(&processors, 0, sizeof(processors));
memset(&errata, 0, sizeof(errata));
+#ifdef CONFIG_SMP
+ if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0,
+ (struct acpi_table_header **)&madt)))
+ madt = 0;
+#endif
+
acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir);
if (!acpi_processor_dir)
return -ENOMEM;
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 3f30af21574..6c6751b1405 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -160,7 +160,7 @@ static inline u32 ticks_elapsed(u32 t1, u32 t2)
{
if (t2 >= t1)
return (t2 - t1);
- else if (!acpi_fadt.tmr_val_ext)
+ else if (!(acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER))
return (((0x00FFFFFF - t1) + t2) & 0x00FFFFFF);
else
return ((0xFFFFFFFF - t1) + t2);
@@ -187,8 +187,7 @@ acpi_processor_power_activate(struct acpi_processor *pr,
case ACPI_STATE_C3:
/* Disable bus master reload */
if (new->type != ACPI_STATE_C3 && pr->flags.bm_check)
- acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0,
- ACPI_MTX_DO_NOT_LOCK);
+ acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0);
break;
}
}
@@ -198,8 +197,7 @@ acpi_processor_power_activate(struct acpi_processor *pr,
case ACPI_STATE_C3:
/* Enable bus master reload */
if (old->type != ACPI_STATE_C3 && pr->flags.bm_check)
- acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 1,
- ACPI_MTX_DO_NOT_LOCK);
+ acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 1);
break;
}
@@ -236,7 +234,7 @@ static void acpi_cstate_enter(struct acpi_processor_cx *cstate)
/* Dummy wait op - must do something useless after P_LVL2 read
because chipsets cannot guarantee that STPCLK# signal
gets asserted in time to freeze execution properly. */
- unused = inl(acpi_fadt.xpm_tmr_blk.address);
+ unused = inl(acpi_gbl_FADT.xpm_timer_block.address);
}
}
@@ -291,12 +289,10 @@ static void acpi_processor_idle(void)
pr->power.bm_activity <<= diff;
- acpi_get_register(ACPI_BITREG_BUS_MASTER_STATUS,
- &bm_status, ACPI_MTX_DO_NOT_LOCK);
+ acpi_get_register(ACPI_BITREG_BUS_MASTER_STATUS, &bm_status);
if (bm_status) {
pr->power.bm_activity |= 0x1;
- acpi_set_register(ACPI_BITREG_BUS_MASTER_STATUS,
- 1, ACPI_MTX_DO_NOT_LOCK);
+ acpi_set_register(ACPI_BITREG_BUS_MASTER_STATUS, 1);
}
/*
* PIIX4 Erratum #18: Note that BM_STS doesn't always reflect
@@ -338,7 +334,7 @@ static void acpi_processor_idle(void)
* detection phase, to work cleanly with logical CPU hotplug.
*/
if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) &&
- !pr->flags.has_cst && !acpi_fadt.plvl2_up)
+ !pr->flags.has_cst && !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))
cx = &pr->power.states[ACPI_STATE_C1];
#endif
@@ -384,11 +380,11 @@ static void acpi_processor_idle(void)
case ACPI_STATE_C2:
/* Get start time (ticks) */
- t1 = inl(acpi_fadt.xpm_tmr_blk.address);
+ t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
/* Invoke C2 */
acpi_cstate_enter(cx);
/* Get end time (ticks) */
- t2 = inl(acpi_fadt.xpm_tmr_blk.address);
+ t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
#ifdef CONFIG_GENERIC_TIME
/* TSC halts in C2, so notify users */
@@ -411,8 +407,7 @@ static void acpi_processor_idle(void)
* All CPUs are trying to go to C3
* Disable bus master arbitration
*/
- acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1,
- ACPI_MTX_DO_NOT_LOCK);
+ acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1);
}
} else {
/* SMP with no shared cache... Invalidate cache */
@@ -420,16 +415,15 @@ static void acpi_processor_idle(void)
}
/* Get start time (ticks) */
- t1 = inl(acpi_fadt.xpm_tmr_blk.address);
+ t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
/* Invoke C3 */
acpi_cstate_enter(cx);
/* Get end time (ticks) */
- t2 = inl(acpi_fadt.xpm_tmr_blk.address);
+ t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
if (pr->flags.bm_check) {
/* Enable bus master arbitration */
atomic_dec(&c3_cpu_count);
- acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0,
- ACPI_MTX_DO_NOT_LOCK);
+ acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0);
}
#ifdef CONFIG_GENERIC_TIME
@@ -457,7 +451,7 @@ static void acpi_processor_idle(void)
#ifdef CONFIG_HOTPLUG_CPU
/* Don't do promotion/demotion */
if ((cx->type == ACPI_STATE_C1) && (num_online_cpus() > 1) &&
- !pr->flags.has_cst && !acpi_fadt.plvl2_up) {
+ !pr->flags.has_cst && !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) {
next_state = cx;
goto end;
}
@@ -627,7 +621,8 @@ static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr)
* Check for P_LVL2_UP flag before entering C2 and above on
* an SMP system.
*/
- if ((num_online_cpus() > 1) && !acpi_fadt.plvl2_up)
+ if ((num_online_cpus() > 1) &&
+ !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))
return -ENODEV;
#endif
@@ -636,8 +631,8 @@ static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr)
pr->power.states[ACPI_STATE_C3].address = pr->pblk + 5;
/* determine latencies from FADT */
- pr->power.states[ACPI_STATE_C2].latency = acpi_fadt.plvl2_lat;
- pr->power.states[ACPI_STATE_C3].latency = acpi_fadt.plvl3_lat;
+ pr->power.states[ACPI_STATE_C2].latency = acpi_gbl_FADT.C2latency;
+ pr->power.states[ACPI_STATE_C3].latency = acpi_gbl_FADT.C3latency;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"lvl2[0x%08x] lvl3[0x%08x]\n",
@@ -883,14 +878,13 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr,
* WBINVD should be set in fadt, for C3 state to be
* supported on when bm_check is not required.
*/
- if (acpi_fadt.wb_invd != 1) {
+ if (!(acpi_gbl_FADT.flags & ACPI_FADT_WBINVD)) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Cache invalidation should work properly"
" for C3 to be enabled on SMP systems\n"));
return;
}
- acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD,
- 0, ACPI_MTX_DO_NOT_LOCK);
+ acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0);
}
/*
@@ -1096,7 +1090,7 @@ static int acpi_processor_power_seq_show(struct seq_file *seq, void *offset)
seq_printf(seq, "latency[%03d] usage[%08d] duration[%020llu]\n",
pr->power.states[i].latency,
pr->power.states[i].usage,
- pr->power.states[i].time);
+ (unsigned long long)pr->power.states[i].time);
}
end:
@@ -1164,9 +1158,9 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
if (!pr)
return -EINVAL;
- if (acpi_fadt.cst_cnt && !nocst) {
+ if (acpi_gbl_FADT.cst_control && !nocst) {
status =
- acpi_os_write_port(acpi_fadt.smi_cmd, acpi_fadt.cst_cnt, 8);
+ acpi_os_write_port(acpi_gbl_FADT.smi_command, acpi_gbl_FADT.cst_control, 8);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
"Notifying BIOS of _CST ability failed"));
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index cbb6f0814ce..058f13cf3b7 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -352,31 +352,24 @@ int acpi_processor_notify_smm(struct module *calling_module)
is_done = -EIO;
- /* Can't write pstate_cnt to smi_cmd if either value is zero */
- if ((!acpi_fadt.smi_cmd) || (!acpi_fadt.pstate_cnt)) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No SMI port or pstate_cnt\n"));
+ /* Can't write pstate_control to smi_command if either value is zero */
+ if ((!acpi_gbl_FADT.smi_command) || (!acpi_gbl_FADT.pstate_control)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No SMI port or pstate_control\n"));
module_put(calling_module);
return 0;
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Writing pstate_cnt [0x%x] to smi_cmd [0x%x]\n",
- acpi_fadt.pstate_cnt, acpi_fadt.smi_cmd));
+ "Writing pstate_control [0x%x] to smi_command [0x%x]\n",
+ acpi_gbl_FADT.pstate_control, acpi_gbl_FADT.smi_command));
- /* FADT v1 doesn't support pstate_cnt, many BIOS vendors use
- * it anyway, so we need to support it... */
- if (acpi_fadt_is_v1) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Using v1.0 FADT reserved value for pstate_cnt\n"));
- }
-
- status = acpi_os_write_port(acpi_fadt.smi_cmd,
- (u32) acpi_fadt.pstate_cnt, 8);
+ status = acpi_os_write_port(acpi_gbl_FADT.smi_command,
+ (u32) acpi_gbl_FADT.pstate_control, 8);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
- "Failed to write pstate_cnt [0x%x] to "
- "smi_cmd [0x%x]", acpi_fadt.pstate_cnt,
- acpi_fadt.smi_cmd));
+ "Failed to write pstate_control [0x%x] to "
+ "smi_command [0x%x]", acpi_gbl_FADT.pstate_control,
+ acpi_gbl_FADT.smi_command));
module_put(calling_module);
return status;
}
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c
index 0ec7dcde006..89dff3639ab 100644
--- a/drivers/acpi/processor_throttling.c
+++ b/drivers/acpi/processor_throttling.c
@@ -125,7 +125,7 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
/* Used to clear all duty_value bits */
duty_mask = pr->throttling.state_count - 1;
- duty_mask <<= acpi_fadt.duty_offset;
+ duty_mask <<= acpi_gbl_FADT.duty_offset;
duty_mask = ~duty_mask;
}
@@ -208,7 +208,7 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)
return 0;
}
- pr->throttling.state_count = 1 << acpi_fadt.duty_width;
+ pr->throttling.state_count = 1 << acpi_gbl_FADT.duty_width;
/*
* Compute state values. Note that throttling displays a linear power/
diff --git a/drivers/acpi/resources/rsaddr.c b/drivers/acpi/resources/rsaddr.c
index 8fa3213ce00..271e61509ee 100644
--- a/drivers/acpi/resources/rsaddr.c
+++ b/drivers/acpi/resources/rsaddr.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rscalc.c b/drivers/acpi/resources/rscalc.c
index cf87b023002..8c6d3fdec38 100644
--- a/drivers/acpi/resources/rscalc.c
+++ b/drivers/acpi/resources/rscalc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rscreate.c b/drivers/acpi/resources/rscreate.c
index 008058acdd3..1358c06a969 100644
--- a/drivers/acpi/resources/rscreate.c
+++ b/drivers/acpi/resources/rscreate.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsdump.c b/drivers/acpi/resources/rsdump.c
index 9c99a723a86..de20a5d6dec 100644
--- a/drivers/acpi/resources/rsdump.c
+++ b/drivers/acpi/resources/rsdump.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsinfo.c b/drivers/acpi/resources/rsinfo.c
index 9e7ae2f8a1d..7e3c335ab32 100644
--- a/drivers/acpi/resources/rsinfo.c
+++ b/drivers/acpi/resources/rsinfo.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsio.c b/drivers/acpi/resources/rsio.c
index ea567167c4f..b297bc3e441 100644
--- a/drivers/acpi/resources/rsio.c
+++ b/drivers/acpi/resources/rsio.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsirq.c b/drivers/acpi/resources/rsirq.c
index 1fa63bc2e36..5657f7b9503 100644
--- a/drivers/acpi/resources/rsirq.c
+++ b/drivers/acpi/resources/rsirq.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rslist.c b/drivers/acpi/resources/rslist.c
index 29423ce030c..a92755c8877 100644
--- a/drivers/acpi/resources/rslist.c
+++ b/drivers/acpi/resources/rslist.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsmemory.c b/drivers/acpi/resources/rsmemory.c
index a5131936d69..521eab7dd8d 100644
--- a/drivers/acpi/resources/rsmemory.c
+++ b/drivers/acpi/resources/rsmemory.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsmisc.c b/drivers/acpi/resources/rsmisc.c
index faf6e106b78..3b63b561b94 100644
--- a/drivers/acpi/resources/rsmisc.c
+++ b/drivers/acpi/resources/rsmisc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsutils.c b/drivers/acpi/resources/rsutils.c
index a9cbee8e8b4..2442a8f8df5 100644
--- a/drivers/acpi/resources/rsutils.c
+++ b/drivers/acpi/resources/rsutils.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsxface.c b/drivers/acpi/resources/rsxface.c
index 1999e2ab7da..991f8901498 100644
--- a/drivers/acpi/resources/rsxface.c
+++ b/drivers/acpi/resources/rsxface.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 283d87522c5..64f26db10c8 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -21,101 +21,305 @@ extern struct acpi_device *acpi_root;
#define ACPI_BUS_DEVICE_NAME "System Bus"
static LIST_HEAD(acpi_device_list);
+static LIST_HEAD(acpi_bus_id_list);
DEFINE_SPINLOCK(acpi_device_lock);
LIST_HEAD(acpi_wakeup_device_list);
+struct acpi_device_bus_id{
+ char bus_id[15];
+ unsigned int instance_no;
+ struct list_head node;
+};
+static int acpi_eject_operation(acpi_handle handle, int lockable)
+{
+ struct acpi_object_list arg_list;
+ union acpi_object arg;
+ acpi_status status = AE_OK;
+
+ /*
+ * TBD: evaluate _PS3?
+ */
+
+ if (lockable) {
+ arg_list.count = 1;
+ arg_list.pointer = &arg;
+ arg.type = ACPI_TYPE_INTEGER;
+ arg.integer.value = 0;
+ acpi_evaluate_object(handle, "_LCK", &arg_list, NULL);
+ }
+
+ arg_list.count = 1;
+ arg_list.pointer = &arg;
+ arg.type = ACPI_TYPE_INTEGER;
+ arg.integer.value = 1;
+
+ /*
+ * TBD: _EJD support.
+ */
+
+ status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
+ if (ACPI_FAILURE(status)) {
+ return (-ENODEV);
+ }
+
+ return (0);
+}
-static void acpi_device_release(struct kobject *kobj)
+static ssize_t
+acpi_eject_store(struct device *d, struct device_attribute *attr,
+ const char *buf, size_t count)
{
- struct acpi_device *dev = container_of(kobj, struct acpi_device, kobj);
- kfree(dev->pnp.cid_list);
- kfree(dev);
+ int result;
+ int ret = count;
+ int islockable;
+ acpi_status status;
+ acpi_handle handle;
+ acpi_object_type type = 0;
+ struct acpi_device *acpi_device = to_acpi_device(d);
+
+ if ((!count) || (buf[0] != '1')) {
+ return -EINVAL;
+ }
+#ifndef FORCE_EJECT
+ if (acpi_device->driver == NULL) {
+ ret = -ENODEV;
+ goto err;
+ }
+#endif
+ status = acpi_get_type(acpi_device->handle, &type);
+ if (ACPI_FAILURE(status) || (!acpi_device->flags.ejectable)) {
+ ret = -ENODEV;
+ goto err;
+ }
+
+ islockable = acpi_device->flags.lockable;
+ handle = acpi_device->handle;
+
+ result = acpi_bus_trim(acpi_device, 1);
+
+ if (!result)
+ result = acpi_eject_operation(handle, islockable);
+
+ if (result) {
+ ret = -EBUSY;
+ }
+ err:
+ return ret;
}
-struct acpi_device_attribute {
- struct attribute attr;
- ssize_t(*show) (struct acpi_device *, char *);
- ssize_t(*store) (struct acpi_device *, const char *, size_t);
-};
+static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store);
+
+static ssize_t
+acpi_device_hid_show(struct device *dev, struct device_attribute *attr, char *buf) {
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+
+ return sprintf(buf, "%s\n", acpi_dev->pnp.hardware_id);
+}
+static DEVICE_ATTR(hid, 0444, acpi_device_hid_show, NULL);
+
+static ssize_t
+acpi_device_path_show(struct device *dev, struct device_attribute *attr, char *buf) {
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+ struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL};
+ int result;
+
+ result = acpi_get_name(acpi_dev->handle, ACPI_FULL_PATHNAME, &path);
+ if(result)
+ goto end;
+
+ result = sprintf(buf, "%s\n", (char*)path.pointer);
+ kfree(path.pointer);
+ end:
+ return result;
+}
+static DEVICE_ATTR(path, 0444, acpi_device_path_show, NULL);
+
+static int acpi_device_setup_files(struct acpi_device *dev)
+{
+ acpi_status status;
+ acpi_handle temp;
+ int result = 0;
+
+ /*
+ * Devices gotten from FADT don't have a "path" attribute
+ */
+ if(dev->handle) {
+ result = device_create_file(&dev->dev, &dev_attr_path);
+ if(result)
+ goto end;
+ }
-typedef void acpi_device_sysfs_files(struct kobject *,
- const struct attribute *);
+ if(dev->flags.hardware_id) {
+ result = device_create_file(&dev->dev, &dev_attr_hid);
+ if(result)
+ goto end;
+ }
-static void setup_sys_fs_device_files(struct acpi_device *dev,
- acpi_device_sysfs_files * func);
+ /*
+ * If device has _EJ0, 'eject' file is created that is used to trigger
+ * hot-removal function from userland.
+ */
+ status = acpi_get_handle(dev->handle, "_EJ0", &temp);
+ if (ACPI_SUCCESS(status))
+ result = device_create_file(&dev->dev, &dev_attr_eject);
+ end:
+ return result;
+}
-#define create_sysfs_device_files(dev) \
- setup_sys_fs_device_files(dev, (acpi_device_sysfs_files *)&sysfs_create_file)
-#define remove_sysfs_device_files(dev) \
- setup_sys_fs_device_files(dev, (acpi_device_sysfs_files *)&sysfs_remove_file)
+static void acpi_device_remove_files(struct acpi_device *dev)
+{
+ acpi_status status;
+ acpi_handle temp;
-#define to_acpi_device(n) container_of(n, struct acpi_device, kobj)
-#define to_handle_attr(n) container_of(n, struct acpi_device_attribute, attr);
+ /*
+ * If device has _EJ0, 'eject' file is created that is used to trigger
+ * hot-removal function from userland.
+ */
+ status = acpi_get_handle(dev->handle, "_EJ0", &temp);
+ if (ACPI_SUCCESS(status))
+ device_remove_file(&dev->dev, &dev_attr_eject);
-static ssize_t acpi_device_attr_show(struct kobject *kobj,
- struct attribute *attr, char *buf)
+ if(dev->flags.hardware_id)
+ device_remove_file(&dev->dev, &dev_attr_hid);
+ if(dev->handle)
+ device_remove_file(&dev->dev, &dev_attr_path);
+}
+/* --------------------------------------------------------------------------
+ ACPI Bus operations
+ -------------------------------------------------------------------------- */
+static void acpi_device_release(struct device *dev)
{
- struct acpi_device *device = to_acpi_device(kobj);
- struct acpi_device_attribute *attribute = to_handle_attr(attr);
- return attribute->show ? attribute->show(device, buf) : -EIO;
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+
+ kfree(acpi_dev->pnp.cid_list);
+ kfree(acpi_dev);
}
-static ssize_t acpi_device_attr_store(struct kobject *kobj,
- struct attribute *attr, const char *buf,
- size_t len)
+
+static int acpi_device_suspend(struct device *dev, pm_message_t state)
{
- struct acpi_device *device = to_acpi_device(kobj);
- struct acpi_device_attribute *attribute = to_handle_attr(attr);
- return attribute->store ? attribute->store(device, buf, len) : -EIO;
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+ struct acpi_driver *acpi_drv = acpi_dev->driver;
+
+ if (acpi_drv && acpi_drv->ops.suspend)
+ return acpi_drv->ops.suspend(acpi_dev, state);
+ return 0;
}
-static struct sysfs_ops acpi_device_sysfs_ops = {
- .show = acpi_device_attr_show,
- .store = acpi_device_attr_store,
-};
+static int acpi_device_resume(struct device *dev)
+{
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+ struct acpi_driver *acpi_drv = acpi_dev->driver;
-static struct kobj_type ktype_acpi_ns = {
- .sysfs_ops = &acpi_device_sysfs_ops,
- .release = acpi_device_release,
-};
+ if (acpi_drv && acpi_drv->ops.resume)
+ return acpi_drv->ops.resume(acpi_dev);
+ return 0;
+}
-static int namespace_uevent(struct kset *kset, struct kobject *kobj,
- char **envp, int num_envp, char *buffer,
- int buffer_size)
+static int acpi_bus_match(struct device *dev, struct device_driver *drv)
{
- struct acpi_device *dev = to_acpi_device(kobj);
- int i = 0;
- int len = 0;
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+ struct acpi_driver *acpi_drv = to_acpi_driver(drv);
- if (!dev->driver)
- return 0;
+ return !acpi_match_ids(acpi_dev, acpi_drv->ids);
+}
- if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
- "PHYSDEVDRIVER=%s", dev->driver->name))
+static int acpi_device_uevent(struct device *dev, char **envp, int num_envp,
+ char *buffer, int buffer_size)
+{
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+ int i = 0, length = 0, ret = 0;
+
+ if (acpi_dev->flags.hardware_id)
+ ret = add_uevent_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "HWID=%s", acpi_dev->pnp.hardware_id);
+ if (ret)
return -ENOMEM;
+ if (acpi_dev->flags.compatible_ids) {
+ int j;
+ struct acpi_compatible_id_list *cid_list;
+
+ cid_list = acpi_dev->pnp.cid_list;
+
+ for (j = 0; j < cid_list->count; j++) {
+ ret = add_uevent_var(envp, num_envp, &i, buffer,
+ buffer_size, &length, "COMPTID=%s",
+ cid_list->id[j].value);
+ if (ret)
+ return -ENOMEM;
+ }
+ }
envp[i] = NULL;
+ return 0;
+}
+
+static int acpi_bus_driver_init(struct acpi_device *, struct acpi_driver *);
+static int acpi_start_single_object(struct acpi_device *);
+static int acpi_device_probe(struct device * dev)
+{
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+ struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver);
+ int ret;
+
+ ret = acpi_bus_driver_init(acpi_dev, acpi_drv);
+ if (!ret) {
+ if (acpi_dev->bus_ops.acpi_op_start)
+ acpi_start_single_object(acpi_dev);
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Found driver [%s] for device [%s]\n",
+ acpi_drv->name, acpi_dev->pnp.bus_id));
+ get_device(dev);
+ }
+ return ret;
+}
+static int acpi_device_remove(struct device * dev)
+{
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+ struct acpi_driver *acpi_drv = acpi_dev->driver;
+
+ if (acpi_drv) {
+ if (acpi_drv->ops.stop)
+ acpi_drv->ops.stop(acpi_dev, acpi_dev->removal_type);
+ if (acpi_drv->ops.remove)
+ acpi_drv->ops.remove(acpi_dev, acpi_dev->removal_type);
+ }
+ acpi_dev->driver = NULL;
+ acpi_driver_data(dev) = NULL;
+
+ put_device(dev);
return 0;
}
-static struct kset_uevent_ops namespace_uevent_ops = {
- .uevent = &namespace_uevent,
-};
+static void acpi_device_shutdown(struct device *dev)
+{
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+ struct acpi_driver *acpi_drv = acpi_dev->driver;
+
+ if (acpi_drv && acpi_drv->ops.shutdown)
+ acpi_drv->ops.shutdown(acpi_dev);
-static struct kset acpi_namespace_kset = {
- .kobj = {
- .name = "namespace",
- },
- .subsys = &acpi_subsys,
- .ktype = &ktype_acpi_ns,
- .uevent_ops = &namespace_uevent_ops,
+ return ;
+}
+
+static struct bus_type acpi_bus_type = {
+ .name = "acpi",
+ .suspend = acpi_device_suspend,
+ .resume = acpi_device_resume,
+ .shutdown = acpi_device_shutdown,
+ .match = acpi_bus_match,
+ .probe = acpi_device_probe,
+ .remove = acpi_device_remove,
+ .uevent = acpi_device_uevent,
};
-static void acpi_device_register(struct acpi_device *device,
+static int acpi_device_register(struct acpi_device *device,
struct acpi_device *parent)
{
- int err;
-
+ int result;
+ struct acpi_device_bus_id *acpi_device_bus_id, *new_bus_id;
+ int found = 0;
/*
* Linkage
* -------
@@ -126,7 +330,33 @@ static void acpi_device_register(struct acpi_device *device,
INIT_LIST_HEAD(&device->g_list);
INIT_LIST_HEAD(&device->wakeup_list);
+ new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL);
+ if (!new_bus_id) {
+ printk(KERN_ERR PREFIX "Memory allocation error\n");
+ return -ENOMEM;
+ }
+
spin_lock(&acpi_device_lock);
+ /*
+ * Find suitable bus_id and instance number in acpi_bus_id_list
+ * If failed, create one and link it into acpi_bus_id_list
+ */
+ list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node) {
+ if(!strcmp(acpi_device_bus_id->bus_id, device->flags.hardware_id? device->pnp.hardware_id : "device")) {
+ acpi_device_bus_id->instance_no ++;
+ found = 1;
+ kfree(new_bus_id);
+ break;
+ }
+ }
+ if(!found) {
+ acpi_device_bus_id = new_bus_id;
+ strcpy(acpi_device_bus_id->bus_id, device->flags.hardware_id ? device->pnp.hardware_id : "device");
+ acpi_device_bus_id->instance_no = 0;
+ list_add_tail(&acpi_device_bus_id->node, &acpi_bus_id_list);
+ }
+ sprintf(device->dev.bus_id, "%s:%02x", acpi_device_bus_id->bus_id, acpi_device_bus_id->instance_no);
+
if (device->parent) {
list_add_tail(&device->node, &device->parent->children);
list_add_tail(&device->g_list, &device->parent->g_list);
@@ -136,16 +366,33 @@ static void acpi_device_register(struct acpi_device *device,
list_add_tail(&device->wakeup_list, &acpi_wakeup_device_list);
spin_unlock(&acpi_device_lock);
- strlcpy(device->kobj.name, device->pnp.bus_id, KOBJ_NAME_LEN);
- if (parent)
- device->kobj.parent = &parent->kobj;
- device->kobj.ktype = &ktype_acpi_ns;
- device->kobj.kset = &acpi_namespace_kset;
- err = kobject_register(&device->kobj);
- if (err < 0)
- printk(KERN_WARNING "%s: kobject_register error: %d\n",
- __FUNCTION__, err);
- create_sysfs_device_files(device);
+ if (device->parent)
+ device->dev.parent = &parent->dev;
+ device->dev.bus = &acpi_bus_type;
+ device_initialize(&device->dev);
+ device->dev.release = &acpi_device_release;
+ result = device_add(&device->dev);
+ if(result) {
+ printk("Error adding device %s", device->dev.bus_id);
+ goto end;
+ }
+
+ result = acpi_device_setup_files(device);
+ if(result)
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error creating sysfs interface for device %s\n", device->dev.bus_id));
+
+ device->removal_type = ACPI_BUS_REMOVAL_NORMAL;
+ return 0;
+ end:
+ spin_lock(&acpi_device_lock);
+ if (device->parent) {
+ list_del(&device->node);
+ list_del(&device->g_list);
+ } else
+ list_del(&device->g_list);
+ list_del(&device->wakeup_list);
+ spin_unlock(&acpi_device_lock);
+ return result;
}
static void acpi_device_unregister(struct acpi_device *device, int type)
@@ -158,81 +405,143 @@ static void acpi_device_unregister(struct acpi_device *device, int type)
list_del(&device->g_list);
list_del(&device->wakeup_list);
-
spin_unlock(&acpi_device_lock);
acpi_detach_data(device->handle, acpi_bus_data_handler);
- remove_sysfs_device_files(device);
- kobject_unregister(&device->kobj);
+
+ acpi_device_remove_files(device);
+ device_unregister(&device->dev);
}
-void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context)
+/* --------------------------------------------------------------------------
+ Driver Management
+ -------------------------------------------------------------------------- */
+/**
+ * acpi_bus_driver_init - add a device to a driver
+ * @device: the device to add and initialize
+ * @driver: driver for the device
+ *
+ * Used to initialize a device via its device driver. Called whenever a
+ * driver is bound to a device. Invokes the driver's add() ops.
+ */
+static int
+acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver)
{
+ int result = 0;
- /* TBD */
- return;
-}
+ if (!device || !driver)
+ return -EINVAL;
-static int acpi_bus_get_power_flags(struct acpi_device *device)
-{
- acpi_status status = 0;
- acpi_handle handle = NULL;
- u32 i = 0;
+ if (!driver->ops.add)
+ return -ENOSYS;
+ result = driver->ops.add(device);
+ if (result) {
+ device->driver = NULL;
+ acpi_driver_data(device) = NULL;
+ return result;
+ }
- /*
- * Power Management Flags
- */
- status = acpi_get_handle(device->handle, "_PSC", &handle);
- if (ACPI_SUCCESS(status))
- device->power.flags.explicit_get = 1;
- status = acpi_get_handle(device->handle, "_IRC", &handle);
- if (ACPI_SUCCESS(status))
- device->power.flags.inrush_current = 1;
+ device->driver = driver;
/*
- * Enumerate supported power management states
+ * TBD - Configuration Management: Assign resources to device based
+ * upon possible configuration and currently allocated resources.
*/
- for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3; i++) {
- struct acpi_device_power_state *ps = &device->power.states[i];
- char object_name[5] = { '_', 'P', 'R', '0' + i, '\0' };
- /* Evaluate "_PRx" to se if power resources are referenced */
- acpi_evaluate_reference(device->handle, object_name, NULL,
- &ps->resources);
- if (ps->resources.count) {
- device->power.flags.power_resources = 1;
- ps->flags.valid = 1;
- }
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Driver successfully bound to device\n"));
+ return 0;
+}
- /* Evaluate "_PSx" to see if we can do explicit sets */
- object_name[2] = 'S';
- status = acpi_get_handle(device->handle, object_name, &handle);
- if (ACPI_SUCCESS(status)) {
- ps->flags.explicit_set = 1;
- ps->flags.valid = 1;
- }
+static int acpi_start_single_object(struct acpi_device *device)
+{
+ int result = 0;
+ struct acpi_driver *driver;
- /* State is valid if we have some power control */
- if (ps->resources.count || ps->flags.explicit_set)
- ps->flags.valid = 1;
- ps->power = -1; /* Unknown - driver assigned */
- ps->latency = -1; /* Unknown - driver assigned */
+ if (!(driver = device->driver))
+ return 0;
+
+ if (driver->ops.start) {
+ result = driver->ops.start(device);
+ if (result && driver->ops.remove)
+ driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL);
}
- /* Set defaults for D0 and D3 states (always valid) */
- device->power.states[ACPI_STATE_D0].flags.valid = 1;
- device->power.states[ACPI_STATE_D0].power = 100;
- device->power.states[ACPI_STATE_D3].flags.valid = 1;
- device->power.states[ACPI_STATE_D3].power = 0;
+ return result;
+}
- /* TBD: System wake support and resource requirements. */
+/**
+ * acpi_bus_register_driver - register a driver with the ACPI bus
+ * @driver: driver being registered
+ *
+ * Registers a driver with the ACPI bus. Searches the namespace for all
+ * devices that match the driver's criteria and binds. Returns zero for
+ * success or a negative error status for failure.
+ */
+int acpi_bus_register_driver(struct acpi_driver *driver)
+{
+ int ret;
- device->power.state = ACPI_STATE_UNKNOWN;
+ if (acpi_disabled)
+ return -ENODEV;
+ driver->drv.name = driver->name;
+ driver->drv.bus = &acpi_bus_type;
+ driver->drv.owner = driver->owner;
- return 0;
+ ret = driver_register(&driver->drv);
+ return ret;
+}
+
+EXPORT_SYMBOL(acpi_bus_register_driver);
+
+/**
+ * acpi_bus_unregister_driver - unregisters a driver with the APIC bus
+ * @driver: driver to unregister
+ *
+ * Unregisters a driver with the ACPI bus. Searches the namespace for all
+ * devices that match the driver's criteria and unbinds.
+ */
+void acpi_bus_unregister_driver(struct acpi_driver *driver)
+{
+ driver_unregister(&driver->drv);
+}
+
+EXPORT_SYMBOL(acpi_bus_unregister_driver);
+
+/* --------------------------------------------------------------------------
+ Device Enumeration
+ -------------------------------------------------------------------------- */
+acpi_status
+acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd)
+{
+ acpi_status status;
+ acpi_handle tmp;
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ union acpi_object *obj;
+
+ status = acpi_get_handle(handle, "_EJD", &tmp);
+ if (ACPI_FAILURE(status))
+ return status;
+
+ status = acpi_evaluate_object(handle, "_EJD", NULL, &buffer);
+ if (ACPI_SUCCESS(status)) {
+ obj = buffer.pointer;
+ status = acpi_get_handle(NULL, obj->string.pointer, ejd);
+ kfree(buffer.pointer);
+ }
+ return status;
+}
+EXPORT_SYMBOL_GPL(acpi_bus_get_ejd);
+
+void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context)
+{
+
+ /* TBD */
+
+ return;
}
int acpi_match_ids(struct acpi_device *device, char *ids)
@@ -254,6 +563,12 @@ int acpi_match_ids(struct acpi_device *device, char *ids)
return -ENOENT;
}
+static int acpi_bus_get_perf_flags(struct acpi_device *device)
+{
+ device->performance.state = ACPI_STATE_UNKNOWN;
+ return 0;
+}
+
static acpi_status
acpi_bus_extract_wakeup_device_power_package(struct acpi_device *device,
union acpi_object *package)
@@ -338,359 +653,66 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
return 0;
}
-/* --------------------------------------------------------------------------
- ACPI sysfs device file support
- -------------------------------------------------------------------------- */
-static ssize_t acpi_eject_store(struct acpi_device *device,
- const char *buf, size_t count);
-
-#define ACPI_DEVICE_ATTR(_name,_mode,_show,_store) \
-static struct acpi_device_attribute acpi_device_attr_##_name = \
- __ATTR(_name, _mode, _show, _store)
-
-ACPI_DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store);
-
-/**
- * setup_sys_fs_device_files - sets up the device files under device namespace
- * @dev: acpi_device object
- * @func: function pointer to create or destroy the device file
- */
-static void
-setup_sys_fs_device_files(struct acpi_device *dev,
- acpi_device_sysfs_files * func)
-{
- acpi_status status;
- acpi_handle temp = NULL;
-
- /*
- * If device has _EJ0, 'eject' file is created that is used to trigger
- * hot-removal function from userland.
- */
- status = acpi_get_handle(dev->handle, "_EJ0", &temp);
- if (ACPI_SUCCESS(status))
- (*(func)) (&dev->kobj, &acpi_device_attr_eject.attr);
-}
-
-static int acpi_eject_operation(acpi_handle handle, int lockable)
+static int acpi_bus_get_power_flags(struct acpi_device *device)
{
- struct acpi_object_list arg_list;
- union acpi_object arg;
- acpi_status status = AE_OK;
-
- /*
- * TBD: evaluate _PS3?
- */
-
- if (lockable) {
- arg_list.count = 1;
- arg_list.pointer = &arg;
- arg.type = ACPI_TYPE_INTEGER;
- arg.integer.value = 0;
- acpi_evaluate_object(handle, "_LCK", &arg_list, NULL);
- }
+ acpi_status status = 0;
+ acpi_handle handle = NULL;
+ u32 i = 0;
- arg_list.count = 1;
- arg_list.pointer = &arg;
- arg.type = ACPI_TYPE_INTEGER;
- arg.integer.value = 1;
/*
- * TBD: _EJD support.
+ * Power Management Flags
*/
-
- status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
- if (ACPI_FAILURE(status)) {
- return (-ENODEV);
- }
-
- return (0);
-}
-
-static ssize_t
-acpi_eject_store(struct acpi_device *device, const char *buf, size_t count)
-{
- int result;
- int ret = count;
- int islockable;
- acpi_status status;
- acpi_handle handle;
- acpi_object_type type = 0;
-
- if ((!count) || (buf[0] != '1')) {
- return -EINVAL;
- }
-#ifndef FORCE_EJECT
- if (device->driver == NULL) {
- ret = -ENODEV;
- goto err;
- }
-#endif
- status = acpi_get_type(device->handle, &type);
- if (ACPI_FAILURE(status) || (!device->flags.ejectable)) {
- ret = -ENODEV;
- goto err;
- }
-
- islockable = device->flags.lockable;
- handle = device->handle;
-
- result = acpi_bus_trim(device, 1);
-
- if (!result)
- result = acpi_eject_operation(handle, islockable);
-
- if (result) {
- ret = -EBUSY;
- }
- err:
- return ret;
-}
-
-/* --------------------------------------------------------------------------
- Performance Management
- -------------------------------------------------------------------------- */
-
-static int acpi_bus_get_perf_flags(struct acpi_device *device)
-{
- device->performance.state = ACPI_STATE_UNKNOWN;
- return 0;
-}
-
-/* --------------------------------------------------------------------------
- Driver Management
- -------------------------------------------------------------------------- */
-
-static LIST_HEAD(acpi_bus_drivers);
-
-/**
- * acpi_bus_match - match device IDs to driver's supported IDs
- * @device: the device that we are trying to match to a driver
- * @driver: driver whose device id table is being checked
- *
- * Checks the device's hardware (_HID) or compatible (_CID) ids to see if it
- * matches the specified driver's criteria.
- */
-static int
-acpi_bus_match(struct acpi_device *device, struct acpi_driver *driver)
-{
- if (driver && driver->ops.match)
- return driver->ops.match(device, driver);
- return acpi_match_ids(device, driver->ids);
-}
-
-/**
- * acpi_bus_driver_init - add a device to a driver
- * @device: the device to add and initialize
- * @driver: driver for the device
- *
- * Used to initialize a device via its device driver. Called whenever a
- * driver is bound to a device. Invokes the driver's add() and start() ops.
- */
-static int
-acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver)
-{
- int result = 0;
-
-
- if (!device || !driver)
- return -EINVAL;
-
- if (!driver->ops.add)
- return -ENOSYS;
-
- result = driver->ops.add(device);
- if (result) {
- device->driver = NULL;
- acpi_driver_data(device) = NULL;
- return result;
- }
-
- device->driver = driver;
+ status = acpi_get_handle(device->handle, "_PSC", &handle);
+ if (ACPI_SUCCESS(status))
+ device->power.flags.explicit_get = 1;
+ status = acpi_get_handle(device->handle, "_IRC", &handle);
+ if (ACPI_SUCCESS(status))
+ device->power.flags.inrush_current = 1;
/*
- * TBD - Configuration Management: Assign resources to device based
- * upon possible configuration and currently allocated resources.
+ * Enumerate supported power management states
*/
+ for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3; i++) {
+ struct acpi_device_power_state *ps = &device->power.states[i];
+ char object_name[5] = { '_', 'P', 'R', '0' + i, '\0' };
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Driver successfully bound to device\n"));
- return 0;
-}
-
-static int acpi_start_single_object(struct acpi_device *device)
-{
- int result = 0;
- struct acpi_driver *driver;
-
-
- if (!(driver = device->driver))
- return 0;
-
- if (driver->ops.start) {
- result = driver->ops.start(device);
- if (result && driver->ops.remove)
- driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL);
- }
-
- return result;
-}
-
-static void acpi_driver_attach(struct acpi_driver *drv)
-{
- struct list_head *node, *next;
-
-
- spin_lock(&acpi_device_lock);
- list_for_each_safe(node, next, &acpi_device_list) {
- struct acpi_device *dev =
- container_of(node, struct acpi_device, g_list);
-
- if (dev->driver || !dev->status.present)
- continue;
- spin_unlock(&acpi_device_lock);
-
- if (!acpi_bus_match(dev, drv)) {
- if (!acpi_bus_driver_init(dev, drv)) {
- acpi_start_single_object(dev);
- atomic_inc(&drv->references);
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Found driver [%s] for device [%s]\n",
- drv->name, dev->pnp.bus_id));
- }
+ /* Evaluate "_PRx" to se if power resources are referenced */
+ acpi_evaluate_reference(device->handle, object_name, NULL,
+ &ps->resources);
+ if (ps->resources.count) {
+ device->power.flags.power_resources = 1;
+ ps->flags.valid = 1;
}
- spin_lock(&acpi_device_lock);
- }
- spin_unlock(&acpi_device_lock);
-}
-
-static void acpi_driver_detach(struct acpi_driver *drv)
-{
- struct list_head *node, *next;
-
- spin_lock(&acpi_device_lock);
- list_for_each_safe(node, next, &acpi_device_list) {
- struct acpi_device *dev =
- container_of(node, struct acpi_device, g_list);
-
- if (dev->driver == drv) {
- spin_unlock(&acpi_device_lock);
- if (drv->ops.remove)
- drv->ops.remove(dev, ACPI_BUS_REMOVAL_NORMAL);
- spin_lock(&acpi_device_lock);
- dev->driver = NULL;
- dev->driver_data = NULL;
- atomic_dec(&drv->references);
+ /* Evaluate "_PSx" to see if we can do explicit sets */
+ object_name[2] = 'S';
+ status = acpi_get_handle(device->handle, object_name, &handle);
+ if (ACPI_SUCCESS(status)) {
+ ps->flags.explicit_set = 1;
+ ps->flags.valid = 1;
}
- }
- spin_unlock(&acpi_device_lock);
-}
-
-/**
- * acpi_bus_register_driver - register a driver with the ACPI bus
- * @driver: driver being registered
- *
- * Registers a driver with the ACPI bus. Searches the namespace for all
- * devices that match the driver's criteria and binds. Returns zero for
- * success or a negative error status for failure.
- */
-int acpi_bus_register_driver(struct acpi_driver *driver)
-{
-
- if (acpi_disabled)
- return -ENODEV;
-
- spin_lock(&acpi_device_lock);
- list_add_tail(&driver->node, &acpi_bus_drivers);
- spin_unlock(&acpi_device_lock);
- acpi_driver_attach(driver);
-
- return 0;
-}
-
-EXPORT_SYMBOL(acpi_bus_register_driver);
-
-/**
- * acpi_bus_unregister_driver - unregisters a driver with the APIC bus
- * @driver: driver to unregister
- *
- * Unregisters a driver with the ACPI bus. Searches the namespace for all
- * devices that match the driver's criteria and unbinds.
- */
-void acpi_bus_unregister_driver(struct acpi_driver *driver)
-{
- acpi_driver_detach(driver);
-
- if (!atomic_read(&driver->references)) {
- spin_lock(&acpi_device_lock);
- list_del_init(&driver->node);
- spin_unlock(&acpi_device_lock);
- }
- return;
-}
-
-EXPORT_SYMBOL(acpi_bus_unregister_driver);
-
-/**
- * acpi_bus_find_driver - check if there is a driver installed for the device
- * @device: device that we are trying to find a supporting driver for
- *
- * Parses the list of registered drivers looking for a driver applicable for
- * the specified device.
- */
-static int acpi_bus_find_driver(struct acpi_device *device)
-{
- int result = 0;
- struct list_head *node, *next;
+ /* State is valid if we have some power control */
+ if (ps->resources.count || ps->flags.explicit_set)
+ ps->flags.valid = 1;
- spin_lock(&acpi_device_lock);
- list_for_each_safe(node, next, &acpi_bus_drivers) {
- struct acpi_driver *driver =
- container_of(node, struct acpi_driver, node);
-
- atomic_inc(&driver->references);
- spin_unlock(&acpi_device_lock);
- if (!acpi_bus_match(device, driver)) {
- result = acpi_bus_driver_init(device, driver);
- if (!result)
- goto Done;
- }
- atomic_dec(&driver->references);
- spin_lock(&acpi_device_lock);
+ ps->power = -1; /* Unknown - driver assigned */
+ ps->latency = -1; /* Unknown - driver assigned */
}
- spin_unlock(&acpi_device_lock);
-
- Done:
- return result;
-}
-/* --------------------------------------------------------------------------
- Device Enumeration
- -------------------------------------------------------------------------- */
+ /* Set defaults for D0 and D3 states (always valid) */
+ device->power.states[ACPI_STATE_D0].flags.valid = 1;
+ device->power.states[ACPI_STATE_D0].power = 100;
+ device->power.states[ACPI_STATE_D3].flags.valid = 1;
+ device->power.states[ACPI_STATE_D3].power = 0;
-acpi_status
-acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd)
-{
- acpi_status status;
- acpi_handle tmp;
- struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
- union acpi_object *obj;
+ /* TBD: System wake support and resource requirements. */
- status = acpi_get_handle(handle, "_EJD", &tmp);
- if (ACPI_FAILURE(status))
- return status;
+ device->power.state = ACPI_STATE_UNKNOWN;
- status = acpi_evaluate_object(handle, "_EJD", NULL, &buffer);
- if (ACPI_SUCCESS(status)) {
- obj = buffer.pointer;
- status = acpi_get_handle(NULL, obj->string.pointer, ejd);
- kfree(buffer.pointer);
- }
- return status;
+ return 0;
}
-EXPORT_SYMBOL_GPL(acpi_bus_get_ejd);
-
static int acpi_bus_get_flags(struct acpi_device *device)
{
@@ -782,6 +804,75 @@ static void acpi_device_get_busid(struct acpi_device *device,
}
}
+static int
+acpi_video_bus_match(struct acpi_device *device)
+{
+ acpi_handle h_dummy1;
+ acpi_handle h_dummy2;
+ acpi_handle h_dummy3;
+
+
+ if (!device)
+ return -EINVAL;
+
+ /* Since there is no HID, CID for ACPI Video drivers, we have
+ * to check well known required nodes for each feature we support.
+ */
+
+ /* Does this device able to support video switching ? */
+ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy1)) &&
+ ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy2)))
+ return 0;
+
+ /* Does this device able to retrieve a video ROM ? */
+ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy1)))
+ return 0;
+
+ /* Does this device able to configure which video head to be POSTed ? */
+ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy1)) &&
+ ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy2)) &&
+ ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy3)))
+ return 0;
+
+ return -ENODEV;
+}
+
+/*
+ * acpi_bay_match - see if a device is an ejectable driver bay
+ *
+ * If an acpi object is ejectable and has one of the ACPI ATA methods defined,
+ * then we can safely call it an ejectable drive bay
+ */
+static int acpi_bay_match(struct acpi_device *device){
+ acpi_status status;
+ acpi_handle handle;
+ acpi_handle tmp;
+ acpi_handle phandle;
+
+ handle = device->handle;
+
+ status = acpi_get_handle(handle, "_EJ0", &tmp);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) ||
+ (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) ||
+ (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) ||
+ (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp))))
+ return 0;
+
+ if (acpi_get_parent(handle, &phandle))
+ return -ENODEV;
+
+ if ((ACPI_SUCCESS(acpi_get_handle(phandle, "_GTF", &tmp))) ||
+ (ACPI_SUCCESS(acpi_get_handle(phandle, "_GTM", &tmp))) ||
+ (ACPI_SUCCESS(acpi_get_handle(phandle, "_STM", &tmp))) ||
+ (ACPI_SUCCESS(acpi_get_handle(phandle, "_SDD", &tmp))))
+ return 0;
+
+ return -ENODEV;
+}
+
static void acpi_device_set_id(struct acpi_device *device,
struct acpi_device *parent, acpi_handle handle,
int type)
@@ -812,6 +903,16 @@ static void acpi_device_set_id(struct acpi_device *device,
device->pnp.bus_address = info->address;
device->flags.bus_address = 1;
}
+
+ if(!(info->valid & (ACPI_VALID_HID | ACPI_VALID_CID))){
+ status = acpi_video_bus_match(device);
+ if(ACPI_SUCCESS(status))
+ hid = ACPI_VIDEO_HID;
+
+ status = acpi_bay_match(device);
+ if (ACPI_SUCCESS(status))
+ hid = ACPI_BAY_HID;
+ }
break;
case ACPI_BUS_TYPE_POWER:
hid = ACPI_POWER_HID;
@@ -888,86 +989,24 @@ static int acpi_device_set_context(struct acpi_device *device, int type)
return result;
}
-static void acpi_device_get_debug_info(struct acpi_device *device,
- acpi_handle handle, int type)
-{
-#ifdef CONFIG_ACPI_DEBUG_OUTPUT
- char *type_string = NULL;
- char name[80] = { '?', '\0' };
- struct acpi_buffer buffer = { sizeof(name), name };
-
- switch (type) {
- case ACPI_BUS_TYPE_DEVICE:
- type_string = "Device";
- acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
- break;
- case ACPI_BUS_TYPE_POWER:
- type_string = "Power Resource";
- acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
- break;
- case ACPI_BUS_TYPE_PROCESSOR:
- type_string = "Processor";
- acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
- break;
- case ACPI_BUS_TYPE_SYSTEM:
- type_string = "System";
- acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
- break;
- case ACPI_BUS_TYPE_THERMAL:
- type_string = "Thermal Zone";
- acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
- break;
- case ACPI_BUS_TYPE_POWER_BUTTON:
- type_string = "Power Button";
- sprintf(name, "PWRB");
- break;
- case ACPI_BUS_TYPE_SLEEP_BUTTON:
- type_string = "Sleep Button";
- sprintf(name, "SLPB");
- break;
- }
-
- printk(KERN_DEBUG "Found %s %s [%p]\n", type_string, name, handle);
-#endif /*CONFIG_ACPI_DEBUG_OUTPUT */
-}
-
static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)
{
- int result = 0;
- struct acpi_driver *driver;
-
-
if (!dev)
return -EINVAL;
- driver = dev->driver;
-
- if ((driver) && (driver->ops.remove)) {
-
- if (driver->ops.stop) {
- result = driver->ops.stop(dev, ACPI_BUS_REMOVAL_EJECT);
- if (result)
- return result;
- }
-
- result = dev->driver->ops.remove(dev, ACPI_BUS_REMOVAL_EJECT);
- if (result) {
- return result;
- }
-
- atomic_dec(&dev->driver->references);
- dev->driver = NULL;
- acpi_driver_data(dev) = NULL;
- }
+ dev->removal_type = ACPI_BUS_REMOVAL_EJECT;
+ device_release_driver(&dev->dev);
if (!rmdevice)
return 0;
+ /*
+ * unbind _ADR-Based Devices when hot removal
+ */
if (dev->flags.bus_address) {
if ((dev->parent) && (dev->parent->ops.unbind))
dev->parent->ops.unbind(dev);
}
-
acpi_device_unregister(dev, ACPI_BUS_REMOVAL_EJECT);
return 0;
@@ -975,7 +1014,8 @@ static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)
static int
acpi_add_single_object(struct acpi_device **child,
- struct acpi_device *parent, acpi_handle handle, int type)
+ struct acpi_device *parent, acpi_handle handle, int type,
+ struct acpi_bus_ops *ops)
{
int result = 0;
struct acpi_device *device = NULL;
@@ -992,6 +1032,8 @@ acpi_add_single_object(struct acpi_device **child,
device->handle = handle;
device->parent = parent;
+ device->bus_ops = *ops; /* workround for not call .start */
+
acpi_device_get_busid(device, handle, type);
@@ -1076,33 +1118,16 @@ acpi_add_single_object(struct acpi_device **child,
if ((result = acpi_device_set_context(device, type)))
goto end;
- acpi_device_get_debug_info(device, handle, type);
-
- acpi_device_register(device, parent);
+ result = acpi_device_register(device, parent);
/*
- * Bind _ADR-Based Devices
- * -----------------------
- * If there's a a bus address (_ADR) then we utilize the parent's
- * 'bind' function (if exists) to bind the ACPI- and natively-
- * enumerated device representations.
+ * Bind _ADR-Based Devices when hot add
*/
if (device->flags.bus_address) {
if (device->parent && device->parent->ops.bind)
device->parent->ops.bind(device);
}
- /*
- * Locate & Attach Driver
- * ----------------------
- * If there's a hardware id (_HID) or compatible ids (_CID) we check
- * to see if there's a driver installed for this kind of device. Note
- * that drivers can install before or after a device is enumerated.
- *
- * TBD: Assumes LDM provides driver hot-plug capability.
- */
- acpi_bus_find_driver(device);
-
end:
if (!result)
*child = device;
@@ -1188,14 +1213,14 @@ static int acpi_bus_scan(struct acpi_device *start, struct acpi_bus_ops *ops)
if (ops->acpi_op_add)
status = acpi_add_single_object(&child, parent,
- chandle, type);
+ chandle, type, ops);
else
status = acpi_bus_get_device(chandle, &child);
if (ACPI_FAILURE(status))
continue;
- if (ops->acpi_op_start) {
+ if (ops->acpi_op_start && !(ops->acpi_op_add)) {
status = acpi_start_single_object(child);
if (ACPI_FAILURE(status))
continue;
@@ -1233,13 +1258,13 @@ acpi_bus_add(struct acpi_device **child,
int result;
struct acpi_bus_ops ops;
+ memset(&ops, 0, sizeof(ops));
+ ops.acpi_op_add = 1;
- result = acpi_add_single_object(child, parent, handle, type);
- if (!result) {
- memset(&ops, 0, sizeof(ops));
- ops.acpi_op_add = 1;
+ result = acpi_add_single_object(child, parent, handle, type, &ops);
+ if (!result)
result = acpi_bus_scan(*child, &ops);
- }
+
return result;
}
@@ -1325,127 +1350,35 @@ static int acpi_bus_scan_fixed(struct acpi_device *root)
{
int result = 0;
struct acpi_device *device = NULL;
-
+ struct acpi_bus_ops ops;
if (!root)
return -ENODEV;
+ memset(&ops, 0, sizeof(ops));
+ ops.acpi_op_add = 1;
+ ops.acpi_op_start = 1;
+
/*
* Enumerate all fixed-feature devices.
*/
- if (acpi_fadt.pwr_button == 0) {
+ if ((acpi_gbl_FADT.flags & ACPI_FADT_POWER_BUTTON) == 0) {
result = acpi_add_single_object(&device, acpi_root,
NULL,
- ACPI_BUS_TYPE_POWER_BUTTON);
- if (!result)
- result = acpi_start_single_object(device);
+ ACPI_BUS_TYPE_POWER_BUTTON,
+ &ops);
}
- if (acpi_fadt.sleep_button == 0) {
+ if ((acpi_gbl_FADT.flags & ACPI_FADT_SLEEP_BUTTON) == 0) {
result = acpi_add_single_object(&device, acpi_root,
NULL,
- ACPI_BUS_TYPE_SLEEP_BUTTON);
- if (!result)
- result = acpi_start_single_object(device);
+ ACPI_BUS_TYPE_SLEEP_BUTTON,
+ &ops);
}
return result;
}
-
-static inline struct acpi_device * to_acpi_dev(struct device * dev)
-{
- return container_of(dev, struct acpi_device, dev);
-}
-
-
-static int root_suspend(struct acpi_device * acpi_dev, pm_message_t state)
-{
- struct acpi_device * dev, * next;
- int result;
-
- spin_lock(&acpi_device_lock);
- list_for_each_entry_safe_reverse(dev, next, &acpi_device_list, g_list) {
- if (dev->driver && dev->driver->ops.suspend) {
- spin_unlock(&acpi_device_lock);
- result = dev->driver->ops.suspend(dev, 0);
- if (result) {
- printk(KERN_ERR PREFIX "[%s - %s] Suspend failed: %d\n",
- acpi_device_name(dev),
- acpi_device_bid(dev), result);
- }
- spin_lock(&acpi_device_lock);
- }
- }
- spin_unlock(&acpi_device_lock);
- return 0;
-}
-
-
-static int acpi_device_suspend(struct device * dev, pm_message_t state)
-{
- struct acpi_device * acpi_dev = to_acpi_dev(dev);
-
- /*
- * For now, we should only register 1 generic device -
- * the ACPI root device - and from there, we walk the
- * tree of ACPI devices to suspend each one using the
- * ACPI driver methods.
- */
- if (acpi_dev->handle == ACPI_ROOT_OBJECT)
- root_suspend(acpi_dev, state);
- return 0;
-}
-
-
-
-static int root_resume(struct acpi_device * acpi_dev)
-{
- struct acpi_device * dev, * next;
- int result;
-
- spin_lock(&acpi_device_lock);
- list_for_each_entry_safe(dev, next, &acpi_device_list, g_list) {
- if (dev->driver && dev->driver->ops.resume) {
- spin_unlock(&acpi_device_lock);
- result = dev->driver->ops.resume(dev, 0);
- if (result) {
- printk(KERN_ERR PREFIX "[%s - %s] resume failed: %d\n",
- acpi_device_name(dev),
- acpi_device_bid(dev), result);
- }
- spin_lock(&acpi_device_lock);
- }
- }
- spin_unlock(&acpi_device_lock);
- return 0;
-}
-
-
-static int acpi_device_resume(struct device * dev)
-{
- struct acpi_device * acpi_dev = to_acpi_dev(dev);
-
- /*
- * For now, we should only register 1 generic device -
- * the ACPI root device - and from there, we walk the
- * tree of ACPI devices to resume each one using the
- * ACPI driver methods.
- */
- if (acpi_dev->handle == ACPI_ROOT_OBJECT)
- root_resume(acpi_dev);
- return 0;
-}
-
-
-static struct bus_type acpi_bus_type = {
- .name = "acpi",
- .suspend = acpi_device_suspend,
- .resume = acpi_device_resume,
-};
-
-
-
static int __init acpi_scan_init(void)
{
int result;
@@ -1455,9 +1388,9 @@ static int __init acpi_scan_init(void)
if (acpi_disabled)
return 0;
- result = kset_register(&acpi_namespace_kset);
- if (result < 0)
- printk(KERN_ERR PREFIX "kset_register error: %d\n", result);
+ memset(&ops, 0, sizeof(ops));
+ ops.acpi_op_add = 1;
+ ops.acpi_op_start = 1;
result = bus_register(&acpi_bus_type);
if (result) {
@@ -1469,32 +1402,16 @@ static int __init acpi_scan_init(void)
* Create the root device in the bus's device tree
*/
result = acpi_add_single_object(&acpi_root, NULL, ACPI_ROOT_OBJECT,
- ACPI_BUS_TYPE_SYSTEM);
+ ACPI_BUS_TYPE_SYSTEM, &ops);
if (result)
goto Done;
- result = acpi_start_single_object(acpi_root);
- if (result)
- goto Done;
-
- acpi_root->dev.bus = &acpi_bus_type;
- snprintf(acpi_root->dev.bus_id, BUS_ID_SIZE, "%s", acpi_bus_type.name);
- result = device_register(&acpi_root->dev);
- if (result) {
- /* We don't want to quit even if we failed to add suspend/resume */
- printk(KERN_ERR PREFIX "Could not register device\n");
- }
-
/*
* Enumerate devices in the ACPI namespace.
*/
result = acpi_bus_scan_fixed(acpi_root);
- if (!result) {
- memset(&ops, 0, sizeof(ops));
- ops.acpi_op_add = 1;
- ops.acpi_op_start = 1;
+ if (!result)
result = acpi_bus_scan(acpi_root, &ops);
- }
if (result)
acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c
index 34962578039..ccc11b33d89 100644
--- a/drivers/acpi/sleep/proc.c
+++ b/drivers/acpi/sleep/proc.c
@@ -73,7 +73,7 @@ acpi_system_write_sleep(struct file *file,
static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset)
{
u32 sec, min, hr;
- u32 day, mo, yr;
+ u32 day, mo, yr, cent = 0;
unsigned char rtc_control = 0;
unsigned long flags;
@@ -87,20 +87,19 @@ static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset)
rtc_control = CMOS_READ(RTC_CONTROL);
/* If we ever get an FACP with proper values... */
- if (acpi_gbl_FADT->day_alrm)
+ if (acpi_gbl_FADT.day_alarm)
/* ACPI spec: only low 6 its should be cared */
- day = CMOS_READ(acpi_gbl_FADT->day_alrm) & 0x3F;
+ day = CMOS_READ(acpi_gbl_FADT.day_alarm) & 0x3F;
else
day = CMOS_READ(RTC_DAY_OF_MONTH);
- if (acpi_gbl_FADT->mon_alrm)
- mo = CMOS_READ(acpi_gbl_FADT->mon_alrm);
+ if (acpi_gbl_FADT.month_alarm)
+ mo = CMOS_READ(acpi_gbl_FADT.month_alarm);
else
mo = CMOS_READ(RTC_MONTH);
- if (acpi_gbl_FADT->century)
- yr = CMOS_READ(acpi_gbl_FADT->century) * 100 +
- CMOS_READ(RTC_YEAR);
- else
- yr = CMOS_READ(RTC_YEAR);
+ if (acpi_gbl_FADT.century)
+ cent = CMOS_READ(acpi_gbl_FADT.century);
+
+ yr = CMOS_READ(RTC_YEAR);
spin_unlock_irqrestore(&rtc_lock, flags);
@@ -111,10 +110,11 @@ static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset)
BCD_TO_BIN(day);
BCD_TO_BIN(mo);
BCD_TO_BIN(yr);
+ BCD_TO_BIN(cent);
}
/* we're trusting the FADT (see above) */
- if (!acpi_gbl_FADT->century)
+ if (!acpi_gbl_FADT.century)
/* If we're not trusting the FADT, we should at least make it
* right for _this_ century... ehm, what is _this_ century?
*
@@ -134,6 +134,8 @@ static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset)
*
*/
yr += 2000;
+ else
+ yr += cent * 100;
seq_printf(seq, "%4.4u-", yr);
(mo > 12) ? seq_puts(seq, "**-") : seq_printf(seq, "%2.2u-", mo);
@@ -317,12 +319,12 @@ acpi_system_write_alarm(struct file *file,
* offsets into the CMOS RAM here -- which for some reason are pointing
* to the RTC area of memory.
*/
- if (acpi_gbl_FADT->day_alrm)
- CMOS_WRITE(day, acpi_gbl_FADT->day_alrm);
- if (acpi_gbl_FADT->mon_alrm)
- CMOS_WRITE(mo, acpi_gbl_FADT->mon_alrm);
- if (acpi_gbl_FADT->century)
- CMOS_WRITE(yr / 100, acpi_gbl_FADT->century);
+ if (acpi_gbl_FADT.day_alarm)
+ CMOS_WRITE(day, acpi_gbl_FADT.day_alarm);
+ if (acpi_gbl_FADT.month_alarm)
+ CMOS_WRITE(mo, acpi_gbl_FADT.month_alarm);
+ if (acpi_gbl_FADT.century)
+ CMOS_WRITE(yr / 100, acpi_gbl_FADT.century);
/* enable the rtc alarm interrupt */
rtc_control |= RTC_AIE;
CMOS_WRITE(rtc_control, RTC_CONTROL);
diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c
index d86dcb3c236..7147b0bdab0 100644
--- a/drivers/acpi/system.c
+++ b/drivers/acpi/system.c
@@ -32,6 +32,11 @@
#define _COMPONENT ACPI_SYSTEM_COMPONENT
ACPI_MODULE_NAME("acpi_system")
+#ifdef MODULE_PARAM_PREFIX
+#undef MODULE_PARAM_PREFIX
+#endif
+#define MODULE_PARAM_PREFIX "acpi."
+
#define ACPI_SYSTEM_CLASS "system"
#define ACPI_SYSTEM_DRIVER_NAME "ACPI System Driver"
#define ACPI_SYSTEM_DEVICE_NAME "System"
@@ -39,11 +44,24 @@ ACPI_MODULE_NAME("acpi_system")
#define ACPI_SYSTEM_FILE_EVENT "event"
#define ACPI_SYSTEM_FILE_DSDT "dsdt"
#define ACPI_SYSTEM_FILE_FADT "fadt"
-extern struct fadt_descriptor acpi_fadt;
+
+/*
+ * Make ACPICA version work as module param
+ */
+static int param_get_acpica_version(char *buffer, struct kernel_param *kp) {
+ int result;
+
+ result = sprintf(buffer, "%x", ACPI_CA_VERSION);
+
+ return result;
+}
+
+module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444);
/* --------------------------------------------------------------------------
FS Interface (/proc)
-------------------------------------------------------------------------- */
+#ifdef CONFIG_ACPI_PROCFS
static int acpi_system_read_info(struct seq_file *seq, void *offset)
{
@@ -63,6 +81,7 @@ static const struct file_operations acpi_system_info_ops = {
.llseek = seq_lseek,
.release = single_release,
};
+#endif
static ssize_t acpi_system_read_dsdt(struct file *, char __user *, size_t,
loff_t *);
@@ -76,17 +95,16 @@ acpi_system_read_dsdt(struct file *file,
char __user * buffer, size_t count, loff_t * ppos)
{
acpi_status status = AE_OK;
- struct acpi_buffer dsdt = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct acpi_table_header *dsdt = NULL;
ssize_t res;
- status = acpi_get_table(ACPI_TABLE_ID_DSDT, 1, &dsdt);
+ status = acpi_get_table(ACPI_SIG_DSDT, 1, &dsdt);
if (ACPI_FAILURE(status))
return -ENODEV;
res = simple_read_from_buffer(buffer, count, ppos,
- dsdt.pointer, dsdt.length);
- kfree(dsdt.pointer);
+ dsdt, dsdt->length);
return res;
}
@@ -103,17 +121,16 @@ acpi_system_read_fadt(struct file *file,
char __user * buffer, size_t count, loff_t * ppos)
{
acpi_status status = AE_OK;
- struct acpi_buffer fadt = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct acpi_table_header *fadt = NULL;
ssize_t res;
- status = acpi_get_table(ACPI_TABLE_ID_FADT, 1, &fadt);
+ status = acpi_get_table(ACPI_SIG_FADT, 1, &fadt);
if (ACPI_FAILURE(status))
return -ENODEV;
res = simple_read_from_buffer(buffer, count, ppos,
- fadt.pointer, fadt.length);
- kfree(fadt.pointer);
+ fadt, fadt->length);
return res;
}
@@ -128,6 +145,7 @@ static int __init acpi_system_init(void)
if (acpi_disabled)
return 0;
+#ifdef CONFIG_ACPI_PROCFS
/* 'info' [R] */
name = ACPI_SYSTEM_FILE_INFO;
entry = create_proc_entry(name, S_IRUGO, acpi_root_dir);
@@ -136,6 +154,7 @@ static int __init acpi_system_init(void)
else {
entry->proc_fops = &acpi_system_info_ops;
}
+#endif
/* 'dsdt' [R] */
name = ACPI_SYSTEM_FILE_DSDT;
@@ -159,7 +178,9 @@ static int __init acpi_system_init(void)
Error:
remove_proc_entry(ACPI_SYSTEM_FILE_FADT, acpi_root_dir);
remove_proc_entry(ACPI_SYSTEM_FILE_DSDT, acpi_root_dir);
+#ifdef CONFIG_ACPI_PROCFS
remove_proc_entry(ACPI_SYSTEM_FILE_INFO, acpi_root_dir);
+#endif
error = -EFAULT;
goto Done;
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index ffa30c9fccb..ba4cb200314 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -38,154 +38,97 @@
#define ACPI_MAX_TABLES 128
-static char *acpi_table_signatures[ACPI_TABLE_COUNT] = {
- [ACPI_TABLE_UNKNOWN] = "????",
- [ACPI_APIC] = "APIC",
- [ACPI_BOOT] = "BOOT",
- [ACPI_DBGP] = "DBGP",
- [ACPI_DSDT] = "DSDT",
- [ACPI_ECDT] = "ECDT",
- [ACPI_ETDT] = "ETDT",
- [ACPI_FADT] = "FACP",
- [ACPI_FACS] = "FACS",
- [ACPI_OEMX] = "OEM",
- [ACPI_PSDT] = "PSDT",
- [ACPI_SBST] = "SBST",
- [ACPI_SLIT] = "SLIT",
- [ACPI_SPCR] = "SPCR",
- [ACPI_SRAT] = "SRAT",
- [ACPI_SSDT] = "SSDT",
- [ACPI_SPMI] = "SPMI",
- [ACPI_HPET] = "HPET",
- [ACPI_MCFG] = "MCFG",
-};
-
static char *mps_inti_flags_polarity[] = { "dfl", "high", "res", "low" };
static char *mps_inti_flags_trigger[] = { "dfl", "edge", "res", "level" };
-/* System Description Table (RSDT/XSDT) */
-struct acpi_table_sdt {
- unsigned long pa;
- enum acpi_table_id id;
- unsigned long size;
-} __attribute__ ((packed));
-
-static unsigned long sdt_pa; /* Physical Address */
-static unsigned long sdt_count; /* Table count */
+static struct acpi_table_desc initial_tables[ACPI_MAX_TABLES] __initdata;
-static struct acpi_table_sdt sdt_entry[ACPI_MAX_TABLES] __initdata;
-
-void acpi_table_print(struct acpi_table_header *header, unsigned long phys_addr)
-{
- char *name = NULL;
-
- if (!header)
- return;
-
- /* Some table signatures aren't good table names */
-
- if (!strncmp((char *)&header->signature,
- acpi_table_signatures[ACPI_APIC],
- sizeof(header->signature))) {
- name = "MADT";
- } else if (!strncmp((char *)&header->signature,
- acpi_table_signatures[ACPI_FADT],
- sizeof(header->signature))) {
- name = "FADT";
- } else
- name = header->signature;
-
- printk(KERN_DEBUG PREFIX
- "%.4s (v%3.3d %6.6s %8.8s 0x%08x %.4s 0x%08x) @ 0x%p\n", name,
- header->revision, header->oem_id, header->oem_table_id,
- header->oem_revision, header->asl_compiler_id,
- header->asl_compiler_revision, (void *)phys_addr);
-}
-
-void acpi_table_print_madt_entry(acpi_table_entry_header * header)
+void acpi_table_print_madt_entry(struct acpi_subtable_header * header)
{
if (!header)
return;
switch (header->type) {
- case ACPI_MADT_LAPIC:
+ case ACPI_MADT_TYPE_LOCAL_APIC:
{
- struct acpi_table_lapic *p =
- (struct acpi_table_lapic *)header;
+ struct acpi_madt_local_apic *p =
+ (struct acpi_madt_local_apic *)header;
printk(KERN_INFO PREFIX
"LAPIC (acpi_id[0x%02x] lapic_id[0x%02x] %s)\n",
- p->acpi_id, p->id,
- p->flags.enabled ? "enabled" : "disabled");
+ p->processor_id, p->id,
+ (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled");
}
break;
- case ACPI_MADT_IOAPIC:
+ case ACPI_MADT_TYPE_IO_APIC:
{
- struct acpi_table_ioapic *p =
- (struct acpi_table_ioapic *)header;
+ struct acpi_madt_io_apic *p =
+ (struct acpi_madt_io_apic *)header;
printk(KERN_INFO PREFIX
"IOAPIC (id[0x%02x] address[0x%08x] gsi_base[%d])\n",
p->id, p->address, p->global_irq_base);
}
break;
- case ACPI_MADT_INT_SRC_OVR:
+ case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE:
{
- struct acpi_table_int_src_ovr *p =
- (struct acpi_table_int_src_ovr *)header;
+ struct acpi_madt_interrupt_override *p =
+ (struct acpi_madt_interrupt_override *)header;
printk(KERN_INFO PREFIX
"INT_SRC_OVR (bus %d bus_irq %d global_irq %d %s %s)\n",
- p->bus, p->bus_irq, p->global_irq,
- mps_inti_flags_polarity[p->flags.polarity],
- mps_inti_flags_trigger[p->flags.trigger]);
- if (p->flags.reserved)
+ p->bus, p->source_irq, p->global_irq,
+ mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
+ mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2]);
+ if (p->inti_flags &
+ ~(ACPI_MADT_POLARITY_MASK | ACPI_MADT_TRIGGER_MASK))
printk(KERN_INFO PREFIX
"INT_SRC_OVR unexpected reserved flags: 0x%x\n",
- p->flags.reserved);
+ p->inti_flags &
+ ~(ACPI_MADT_POLARITY_MASK | ACPI_MADT_TRIGGER_MASK));
}
break;
- case ACPI_MADT_NMI_SRC:
+ case ACPI_MADT_TYPE_NMI_SOURCE:
{
- struct acpi_table_nmi_src *p =
- (struct acpi_table_nmi_src *)header;
+ struct acpi_madt_nmi_source *p =
+ (struct acpi_madt_nmi_source *)header;
printk(KERN_INFO PREFIX
"NMI_SRC (%s %s global_irq %d)\n",
- mps_inti_flags_polarity[p->flags.polarity],
- mps_inti_flags_trigger[p->flags.trigger],
+ mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
+ mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
p->global_irq);
}
break;
- case ACPI_MADT_LAPIC_NMI:
+ case ACPI_MADT_TYPE_LOCAL_APIC_NMI:
{
- struct acpi_table_lapic_nmi *p =
- (struct acpi_table_lapic_nmi *)header;
+ struct acpi_madt_local_apic_nmi *p =
+ (struct acpi_madt_local_apic_nmi *)header;
printk(KERN_INFO PREFIX
"LAPIC_NMI (acpi_id[0x%02x] %s %s lint[0x%x])\n",
- p->acpi_id,
- mps_inti_flags_polarity[p->flags.polarity],
- mps_inti_flags_trigger[p->flags.trigger],
+ p->processor_id,
+ mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK ],
+ mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
p->lint);
}
break;
- case ACPI_MADT_LAPIC_ADDR_OVR:
+ case ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE:
{
- struct acpi_table_lapic_addr_ovr *p =
- (struct acpi_table_lapic_addr_ovr *)header;
+ struct acpi_madt_local_apic_override *p =
+ (struct acpi_madt_local_apic_override *)header;
printk(KERN_INFO PREFIX
"LAPIC_ADDR_OVR (address[%p])\n",
(void *)(unsigned long)p->address);
}
break;
- case ACPI_MADT_IOSAPIC:
+ case ACPI_MADT_TYPE_IO_SAPIC:
{
- struct acpi_table_iosapic *p =
- (struct acpi_table_iosapic *)header;
+ struct acpi_madt_io_sapic *p =
+ (struct acpi_madt_io_sapic *)header;
printk(KERN_INFO PREFIX
"IOSAPIC (id[0x%x] address[%p] gsi_base[%d])\n",
p->id, (void *)(unsigned long)p->address,
@@ -193,26 +136,26 @@ void acpi_table_print_madt_entry(acpi_table_entry_header * header)
}
break;
- case ACPI_MADT_LSAPIC:
+ case ACPI_MADT_TYPE_LOCAL_SAPIC:
{
- struct acpi_table_lsapic *p =
- (struct acpi_table_lsapic *)header;
+ struct acpi_madt_local_sapic *p =
+ (struct acpi_madt_local_sapic *)header;
printk(KERN_INFO PREFIX
"LSAPIC (acpi_id[0x%02x] lsapic_id[0x%02x] lsapic_eid[0x%02x] %s)\n",
- p->acpi_id, p->id, p->eid,
- p->flags.enabled ? "enabled" : "disabled");
+ p->processor_id, p->id, p->eid,
+ (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled");
}
break;
- case ACPI_MADT_PLAT_INT_SRC:
+ case ACPI_MADT_TYPE_INTERRUPT_SOURCE:
{
- struct acpi_table_plat_int_src *p =
- (struct acpi_table_plat_int_src *)header;
+ struct acpi_madt_interrupt_source *p =
+ (struct acpi_madt_interrupt_source *)header;
printk(KERN_INFO PREFIX
"PLAT_INT_SRC (%s %s type[0x%x] id[0x%04x] eid[0x%x] iosapic_vector[0x%x] global_irq[0x%x]\n",
- mps_inti_flags_polarity[p->flags.polarity],
- mps_inti_flags_trigger[p->flags.trigger],
- p->type, p->id, p->eid, p->iosapic_vector,
+ mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
+ mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
+ p->type, p->id, p->eid, p->io_sapic_vector,
p->global_irq);
}
break;
@@ -225,342 +168,76 @@ void acpi_table_print_madt_entry(acpi_table_entry_header * header)
}
}
-static int
-acpi_table_compute_checksum(void *table_pointer, unsigned long length)
-{
- u8 *p = table_pointer;
- unsigned long remains = length;
- unsigned long sum = 0;
-
- if (!p || !length)
- return -EINVAL;
-
- while (remains--)
- sum += *p++;
-
- return (sum & 0xFF);
-}
-/*
- * acpi_get_table_header_early()
- * for acpi_blacklisted(), acpi_table_get_sdt()
- */
int __init
-acpi_get_table_header_early(enum acpi_table_id id,
- struct acpi_table_header **header)
-{
- unsigned int i;
- enum acpi_table_id temp_id;
-
- /* DSDT is different from the rest */
- if (id == ACPI_DSDT)
- temp_id = ACPI_FADT;
- else
- temp_id = id;
-
- /* Locate the table. */
-
- for (i = 0; i < sdt_count; i++) {
- if (sdt_entry[i].id != temp_id)
- continue;
- *header = (void *)
- __acpi_map_table(sdt_entry[i].pa, sdt_entry[i].size);
- if (!*header) {
- printk(KERN_WARNING PREFIX "Unable to map %s\n",
- acpi_table_signatures[temp_id]);
- return -ENODEV;
- }
- break;
- }
-
- if (!*header) {
- printk(KERN_WARNING PREFIX "%s not present\n",
- acpi_table_signatures[id]);
- return -ENODEV;
- }
-
- /* Map the DSDT header via the pointer in the FADT */
- if (id == ACPI_DSDT) {
- struct fadt_descriptor *fadt =
- (struct fadt_descriptor *)*header;
-
- if (fadt->revision == 3 && fadt->Xdsdt) {
- *header = (void *)__acpi_map_table(fadt->Xdsdt,
- sizeof(struct
- acpi_table_header));
- } else if (fadt->V1_dsdt) {
- *header = (void *)__acpi_map_table(fadt->V1_dsdt,
- sizeof(struct
- acpi_table_header));
- } else
- *header = NULL;
-
- if (!*header) {
- printk(KERN_WARNING PREFIX "Unable to map DSDT\n");
- return -ENODEV;
- }
- }
-
- return 0;
-}
-
-int __init
-acpi_table_parse_madt_family(enum acpi_table_id id,
+acpi_table_parse_madt_family(char *id,
unsigned long madt_size,
int entry_id,
acpi_madt_entry_handler handler,
unsigned int max_entries)
{
- void *madt = NULL;
- acpi_table_entry_header *entry;
+ struct acpi_table_header *madt = NULL;
+ struct acpi_subtable_header *entry;
unsigned int count = 0;
unsigned long madt_end;
- unsigned int i;
if (!handler)
return -EINVAL;
/* Locate the MADT (if exists). There should only be one. */
-
- for (i = 0; i < sdt_count; i++) {
- if (sdt_entry[i].id != id)
- continue;
- madt = (void *)
- __acpi_map_table(sdt_entry[i].pa, sdt_entry[i].size);
- if (!madt) {
- printk(KERN_WARNING PREFIX "Unable to map %s\n",
- acpi_table_signatures[id]);
- return -ENODEV;
- }
- break;
- }
+ acpi_get_table(id, 0, &madt);
if (!madt) {
- printk(KERN_WARNING PREFIX "%s not present\n",
- acpi_table_signatures[id]);
+ printk(KERN_WARNING PREFIX "%4.4s not present\n", id);
return -ENODEV;
}
- madt_end = (unsigned long)madt + sdt_entry[i].size;
+ madt_end = (unsigned long)madt + madt->length;
/* Parse all entries looking for a match. */
- entry = (acpi_table_entry_header *)
+ entry = (struct acpi_subtable_header *)
((unsigned long)madt + madt_size);
- while (((unsigned long)entry) + sizeof(acpi_table_entry_header) <
+ while (((unsigned long)entry) + sizeof(struct acpi_subtable_header) <
madt_end) {
if (entry->type == entry_id
&& (!max_entries || count++ < max_entries))
if (handler(entry, madt_end))
return -EINVAL;
- entry = (acpi_table_entry_header *)
+ entry = (struct acpi_subtable_header *)
((unsigned long)entry + entry->length);
}
if (max_entries && count > max_entries) {
- printk(KERN_WARNING PREFIX "[%s:0x%02x] ignored %i entries of "
- "%i found\n", acpi_table_signatures[id], entry_id,
- count - max_entries, count);
+ printk(KERN_WARNING PREFIX "[%4.4s:0x%02x] ignored %i entries of "
+ "%i found\n", id, entry_id, count - max_entries, count);
}
return count;
}
int __init
-acpi_table_parse_madt(enum acpi_madt_entry_id id,
+acpi_table_parse_madt(enum acpi_madt_type id,
acpi_madt_entry_handler handler, unsigned int max_entries)
{
- return acpi_table_parse_madt_family(ACPI_APIC,
+ return acpi_table_parse_madt_family(ACPI_SIG_MADT,
sizeof(struct acpi_table_madt), id,
handler, max_entries);
}
-int __init acpi_table_parse(enum acpi_table_id id, acpi_table_handler handler)
+int __init acpi_table_parse(char *id, acpi_table_handler handler)
{
- int count = 0;
- unsigned int i = 0;
-
+ struct acpi_table_header *table = NULL;
if (!handler)
return -EINVAL;
- for (i = 0; i < sdt_count; i++) {
- if (sdt_entry[i].id != id)
- continue;
- count++;
- if (count == 1)
- handler(sdt_entry[i].pa, sdt_entry[i].size);
-
- else
- printk(KERN_WARNING PREFIX
- "%d duplicate %s table ignored.\n", count,
- acpi_table_signatures[id]);
- }
-
- return count;
-}
-
-static int __init acpi_table_get_sdt(struct acpi_table_rsdp *rsdp)
-{
- struct acpi_table_header *header = NULL;
- unsigned int i, id = 0;
-
- if (!rsdp)
- return -EINVAL;
-
- /* First check XSDT (but only on ACPI 2.0-compatible systems) */
-
- if ((rsdp->revision >= 2) &&
- (((struct acpi20_table_rsdp *)rsdp)->xsdt_address)) {
-
- struct acpi_table_xsdt *mapped_xsdt = NULL;
-
- sdt_pa = ((struct acpi20_table_rsdp *)rsdp)->xsdt_address;
-
- /* map in just the header */
- header = (struct acpi_table_header *)
- __acpi_map_table(sdt_pa, sizeof(struct acpi_table_header));
-
- if (!header) {
- printk(KERN_WARNING PREFIX
- "Unable to map XSDT header\n");
- return -ENODEV;
- }
-
- /* remap in the entire table before processing */
- mapped_xsdt = (struct acpi_table_xsdt *)
- __acpi_map_table(sdt_pa, header->length);
- if (!mapped_xsdt) {
- printk(KERN_WARNING PREFIX "Unable to map XSDT\n");
- return -ENODEV;
- }
- header = &mapped_xsdt->header;
-
- if (strncmp(header->signature, "XSDT", 4)) {
- printk(KERN_WARNING PREFIX
- "XSDT signature incorrect\n");
- return -ENODEV;
- }
-
- if (acpi_table_compute_checksum(header, header->length)) {
- printk(KERN_WARNING PREFIX "Invalid XSDT checksum\n");
- return -ENODEV;
- }
-
- sdt_count =
- (header->length - sizeof(struct acpi_table_header)) >> 3;
- if (sdt_count > ACPI_MAX_TABLES) {
- printk(KERN_WARNING PREFIX
- "Truncated %lu XSDT entries\n",
- (sdt_count - ACPI_MAX_TABLES));
- sdt_count = ACPI_MAX_TABLES;
- }
-
- for (i = 0; i < sdt_count; i++)
- sdt_entry[i].pa = (unsigned long)mapped_xsdt->entry[i];
- }
-
- /* Then check RSDT */
-
- else if (rsdp->rsdt_address) {
-
- struct acpi_table_rsdt *mapped_rsdt = NULL;
-
- sdt_pa = rsdp->rsdt_address;
-
- /* map in just the header */
- header = (struct acpi_table_header *)
- __acpi_map_table(sdt_pa, sizeof(struct acpi_table_header));
- if (!header) {
- printk(KERN_WARNING PREFIX
- "Unable to map RSDT header\n");
- return -ENODEV;
- }
-
- /* remap in the entire table before processing */
- mapped_rsdt = (struct acpi_table_rsdt *)
- __acpi_map_table(sdt_pa, header->length);
- if (!mapped_rsdt) {
- printk(KERN_WARNING PREFIX "Unable to map RSDT\n");
- return -ENODEV;
- }
- header = &mapped_rsdt->header;
-
- if (strncmp(header->signature, "RSDT", 4)) {
- printk(KERN_WARNING PREFIX
- "RSDT signature incorrect\n");
- return -ENODEV;
- }
-
- if (acpi_table_compute_checksum(header, header->length)) {
- printk(KERN_WARNING PREFIX "Invalid RSDT checksum\n");
- return -ENODEV;
- }
-
- sdt_count =
- (header->length - sizeof(struct acpi_table_header)) >> 2;
- if (sdt_count > ACPI_MAX_TABLES) {
- printk(KERN_WARNING PREFIX
- "Truncated %lu RSDT entries\n",
- (sdt_count - ACPI_MAX_TABLES));
- sdt_count = ACPI_MAX_TABLES;
- }
-
- for (i = 0; i < sdt_count; i++)
- sdt_entry[i].pa = (unsigned long)mapped_rsdt->entry[i];
- }
-
- else {
- printk(KERN_WARNING PREFIX
- "No System Description Table (RSDT/XSDT) specified in RSDP\n");
- return -ENODEV;
- }
-
- acpi_table_print(header, sdt_pa);
-
- for (i = 0; i < sdt_count; i++) {
-
- /* map in just the header */
- header = (struct acpi_table_header *)
- __acpi_map_table(sdt_entry[i].pa,
- sizeof(struct acpi_table_header));
- if (!header)
- continue;
-
- /* remap in the entire table before processing */
- header = (struct acpi_table_header *)
- __acpi_map_table(sdt_entry[i].pa, header->length);
- if (!header)
- continue;
-
- acpi_table_print(header, sdt_entry[i].pa);
-
- if (acpi_table_compute_checksum(header, header->length)) {
- printk(KERN_WARNING " >>> ERROR: Invalid checksum\n");
- continue;
- }
-
- sdt_entry[i].size = header->length;
-
- for (id = 0; id < ACPI_TABLE_COUNT; id++) {
- if (!strncmp((char *)&header->signature,
- acpi_table_signatures[id],
- sizeof(header->signature))) {
- sdt_entry[i].id = id;
- }
- }
- }
-
- /*
- * The DSDT is *not* in the RSDT (why not? no idea.) but we want
- * to print its info, because this is what people usually blacklist
- * against. Unfortunately, we don't know the phys_addr, so just
- * print 0. Maybe no one will notice.
- */
- if (!acpi_get_table_header_early(ACPI_DSDT, &header))
- acpi_table_print(header, 0);
-
- return 0;
+ acpi_get_table(id, 0, &table);
+ if (table) {
+ handler(table);
+ return 1;
+ } else
+ return 0;
}
/*
@@ -568,54 +245,13 @@ static int __init acpi_table_get_sdt(struct acpi_table_rsdp *rsdp)
*
* find RSDP, find and checksum SDT/XSDT.
* checksum all tables, print SDT/XSDT
- *
+ *
* result: sdt_entry[] is initialized
*/
+
int __init acpi_table_init(void)
{
- struct acpi_table_rsdp *rsdp = NULL;
- unsigned long rsdp_phys = 0;
- int result = 0;
-
- /* Locate and map the Root System Description Table (RSDP) */
-
- rsdp_phys = acpi_find_rsdp();
- if (!rsdp_phys) {
- printk(KERN_ERR PREFIX "Unable to locate RSDP\n");
- return -ENODEV;
- }
-
- rsdp = (struct acpi_table_rsdp *)__acpi_map_table(rsdp_phys,
- sizeof(struct acpi_table_rsdp));
- if (!rsdp) {
- printk(KERN_WARNING PREFIX "Unable to map RSDP\n");
- return -ENODEV;
- }
-
- printk(KERN_DEBUG PREFIX
- "RSDP (v%3.3d %6.6s ) @ 0x%p\n",
- rsdp->revision, rsdp->oem_id, (void *)rsdp_phys);
-
- if (rsdp->revision < 2)
- result =
- acpi_table_compute_checksum(rsdp,
- sizeof(struct acpi_table_rsdp));
- else
- result =
- acpi_table_compute_checksum(rsdp,
- ((struct acpi20_table_rsdp *)
- rsdp)->length);
-
- if (result) {
- printk(KERN_WARNING " >>> ERROR: Invalid checksum\n");
- return -ENODEV;
- }
-
- /* Locate and map the System Description table (RSDT/XSDT) */
-
- if (acpi_table_get_sdt(rsdp))
- return -ENODEV;
-
+ acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0);
return 0;
}
diff --git a/drivers/acpi/tables/Makefile b/drivers/acpi/tables/Makefile
index aa4c69594d9..0a7d7afac25 100644
--- a/drivers/acpi/tables/Makefile
+++ b/drivers/acpi/tables/Makefile
@@ -2,7 +2,6 @@
# Makefile for all Linux ACPI interpreter subdirectories
#
-obj-y := tbconvrt.o tbget.o tbrsdt.o tbxface.o \
- tbgetall.o tbinstal.o tbutils.o tbxfroot.o
+obj-y := tbxface.o tbinstal.o tbutils.o tbfind.o tbfadt.o
EXTRA_CFLAGS += $(ACPI_CFLAGS)
diff --git a/drivers/acpi/tables/tbconvrt.c b/drivers/acpi/tables/tbconvrt.c
deleted file mode 100644
index d697fcb35d5..00000000000
--- a/drivers/acpi/tables/tbconvrt.c
+++ /dev/null
@@ -1,622 +0,0 @@
-/******************************************************************************
- *
- * Module Name: tbconvrt - ACPI Table conversion utilities
- *
- *****************************************************************************/
-
-/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- * substantially similar to the "NO WARRANTY" disclaimer below
- * ("Disclaimer") and any redistribution must be conditioned upon
- * including a substantially similar Disclaimer requirement for further
- * binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- * of any contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * NO WARRANTY
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- */
-
-#include <acpi/acpi.h>
-#include <acpi/actables.h>
-
-#define _COMPONENT ACPI_TABLES
-ACPI_MODULE_NAME("tbconvrt")
-
-/* Local prototypes */
-static void
-acpi_tb_init_generic_address(struct acpi_generic_address *new_gas_struct,
- u8 register_bit_width,
- acpi_physical_address address);
-
-static void
-acpi_tb_convert_fadt1(struct fadt_descriptor *local_fadt,
- struct fadt_descriptor_rev1 *original_fadt);
-
-static void
-acpi_tb_convert_fadt2(struct fadt_descriptor *local_fadt,
- struct fadt_descriptor *original_fadt);
-
-u8 acpi_fadt_is_v1;
-ACPI_EXPORT_SYMBOL(acpi_fadt_is_v1)
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_get_table_count
- *
- * PARAMETERS: RSDP - Pointer to the RSDP
- * RSDT - Pointer to the RSDT/XSDT
- *
- * RETURN: The number of tables pointed to by the RSDT or XSDT.
- *
- * DESCRIPTION: Calculate the number of tables. Automatically handles either
- * an RSDT or XSDT.
- *
- ******************************************************************************/
-
-u32
-acpi_tb_get_table_count(struct rsdp_descriptor *RSDP,
- struct acpi_table_header *RSDT)
-{
- u32 pointer_size;
-
- ACPI_FUNCTION_ENTRY();
-
- /* RSDT pointers are 32 bits, XSDT pointers are 64 bits */
-
- if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) {
- pointer_size = sizeof(u32);
- } else {
- pointer_size = sizeof(u64);
- }
-
- /*
- * Determine the number of tables pointed to by the RSDT/XSDT.
- * This is defined by the ACPI Specification to be the number of
- * pointers contained within the RSDT/XSDT. The size of the pointers
- * is architecture-dependent.
- */
- return ((RSDT->length -
- sizeof(struct acpi_table_header)) / pointer_size);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_convert_to_xsdt
- *
- * PARAMETERS: table_info - Info about the RSDT
- *
- * RETURN: Status
- *
- * DESCRIPTION: Convert an RSDT to an XSDT (internal common format)
- *
- ******************************************************************************/
-
-acpi_status acpi_tb_convert_to_xsdt(struct acpi_table_desc *table_info)
-{
- acpi_size table_size;
- u32 i;
- struct xsdt_descriptor *new_table;
-
- ACPI_FUNCTION_ENTRY();
-
- /* Compute size of the converted XSDT */
-
- table_size = ((acpi_size) acpi_gbl_rsdt_table_count * sizeof(u64)) +
- sizeof(struct acpi_table_header);
-
- /* Allocate an XSDT */
-
- new_table = ACPI_ALLOCATE_ZEROED(table_size);
- if (!new_table) {
- return (AE_NO_MEMORY);
- }
-
- /* Copy the header and set the length */
-
- ACPI_MEMCPY(new_table, table_info->pointer,
- sizeof(struct acpi_table_header));
- new_table->length = (u32) table_size;
-
- /* Copy the table pointers */
-
- for (i = 0; i < acpi_gbl_rsdt_table_count; i++) {
-
- /* RSDT pointers are 32 bits, XSDT pointers are 64 bits */
-
- if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) {
- ACPI_STORE_ADDRESS(new_table->table_offset_entry[i],
- (ACPI_CAST_PTR
- (struct rsdt_descriptor,
- table_info->pointer))->
- table_offset_entry[i]);
- } else {
- new_table->table_offset_entry[i] =
- (ACPI_CAST_PTR(struct xsdt_descriptor,
- table_info->pointer))->
- table_offset_entry[i];
- }
- }
-
- /* Delete the original table (either mapped or in a buffer) */
-
- acpi_tb_delete_single_table(table_info);
-
- /* Point the table descriptor to the new table */
-
- table_info->pointer =
- ACPI_CAST_PTR(struct acpi_table_header, new_table);
- table_info->length = table_size;
- table_info->allocation = ACPI_MEM_ALLOCATED;
-
- return (AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_init_generic_address
- *
- * PARAMETERS: new_gas_struct - GAS struct to be initialized
- * register_bit_width - Width of this register
- * Address - Address of the register
- *
- * RETURN: None
- *
- * DESCRIPTION: Initialize a GAS structure.
- *
- ******************************************************************************/
-
-static void
-acpi_tb_init_generic_address(struct acpi_generic_address *new_gas_struct,
- u8 register_bit_width,
- acpi_physical_address address)
-{
-
- ACPI_STORE_ADDRESS(new_gas_struct->address, address);
-
- new_gas_struct->address_space_id = ACPI_ADR_SPACE_SYSTEM_IO;
- new_gas_struct->register_bit_width = register_bit_width;
- new_gas_struct->register_bit_offset = 0;
- new_gas_struct->access_width = 0;
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_convert_fadt1
- *
- * PARAMETERS: local_fadt - Pointer to new FADT
- * original_fadt - Pointer to old FADT
- *
- * RETURN: None, populates local_fadt
- *
- * DESCRIPTION: Convert an ACPI 1.0 FADT to common internal format
- *
- ******************************************************************************/
-
-static void
-acpi_tb_convert_fadt1(struct fadt_descriptor *local_fadt,
- struct fadt_descriptor_rev1 *original_fadt)
-{
-
- /* ACPI 1.0 FACS */
- /* The BIOS stored FADT should agree with Revision 1.0 */
- acpi_fadt_is_v1 = 1;
-
- /*
- * Copy the table header and the common part of the tables.
- *
- * The 2.0 table is an extension of the 1.0 table, so the entire 1.0
- * table can be copied first, then expand some fields to 64 bits.
- */
- ACPI_MEMCPY(local_fadt, original_fadt,
- sizeof(struct fadt_descriptor_rev1));
-
- /* Convert table pointers to 64-bit fields */
-
- ACPI_STORE_ADDRESS(local_fadt->xfirmware_ctrl,
- local_fadt->V1_firmware_ctrl);
- ACPI_STORE_ADDRESS(local_fadt->Xdsdt, local_fadt->V1_dsdt);
-
- /*
- * System Interrupt Model isn't used in ACPI 2.0
- * (local_fadt->Reserved1 = 0;)
- */
-
- /*
- * This field is set by the OEM to convey the preferred power management
- * profile to OSPM. It doesn't have any 1.0 equivalence. Since we don't
- * know what kind of 32-bit system this is, we will use "unspecified".
- */
- local_fadt->prefer_PM_profile = PM_UNSPECIFIED;
-
- /*
- * Processor Performance State Control. This is the value OSPM writes to
- * the SMI_CMD register to assume processor performance state control
- * responsibility. There isn't any equivalence in 1.0, but as many 1.x
- * ACPI tables contain _PCT and _PSS we also keep this value, unless
- * acpi_strict is set.
- */
- if (acpi_strict)
- local_fadt->pstate_cnt = 0;
-
- /*
- * Support for the _CST object and C States change notification.
- * This data item hasn't any 1.0 equivalence so leave it zero.
- */
- local_fadt->cst_cnt = 0;
-
- /*
- * FADT Rev 2 was an interim FADT released between ACPI 1.0 and ACPI 2.0.
- * It primarily adds the FADT reset mechanism.
- */
- if ((original_fadt->revision == 2) &&
- (original_fadt->length ==
- sizeof(struct fadt_descriptor_rev2_minus))) {
- /*
- * Grab the entire generic address struct, plus the 1-byte reset value
- * that immediately follows.
- */
- ACPI_MEMCPY(&local_fadt->reset_register,
- &(ACPI_CAST_PTR(struct fadt_descriptor_rev2_minus,
- original_fadt))->reset_register,
- sizeof(struct acpi_generic_address) + 1);
- } else {
- /*
- * Since there isn't any equivalence in 1.0 and since it is highly
- * likely that a 1.0 system has legacy support.
- */
- local_fadt->iapc_boot_arch = BAF_LEGACY_DEVICES;
- }
-
- /*
- * Convert the V1.0 block addresses to V2.0 GAS structures
- */
- acpi_tb_init_generic_address(&local_fadt->xpm1a_evt_blk,
- local_fadt->pm1_evt_len,
- (acpi_physical_address) local_fadt->
- V1_pm1a_evt_blk);
- acpi_tb_init_generic_address(&local_fadt->xpm1b_evt_blk,
- local_fadt->pm1_evt_len,
- (acpi_physical_address) local_fadt->
- V1_pm1b_evt_blk);
- acpi_tb_init_generic_address(&local_fadt->xpm1a_cnt_blk,
- local_fadt->pm1_cnt_len,
- (acpi_physical_address) local_fadt->
- V1_pm1a_cnt_blk);
- acpi_tb_init_generic_address(&local_fadt->xpm1b_cnt_blk,
- local_fadt->pm1_cnt_len,
- (acpi_physical_address) local_fadt->
- V1_pm1b_cnt_blk);
- acpi_tb_init_generic_address(&local_fadt->xpm2_cnt_blk,
- local_fadt->pm2_cnt_len,
- (acpi_physical_address) local_fadt->
- V1_pm2_cnt_blk);
- acpi_tb_init_generic_address(&local_fadt->xpm_tmr_blk,
- local_fadt->pm_tm_len,
- (acpi_physical_address) local_fadt->
- V1_pm_tmr_blk);
- acpi_tb_init_generic_address(&local_fadt->xgpe0_blk, 0,
- (acpi_physical_address) local_fadt->
- V1_gpe0_blk);
- acpi_tb_init_generic_address(&local_fadt->xgpe1_blk, 0,
- (acpi_physical_address) local_fadt->
- V1_gpe1_blk);
-
- /* Create separate GAS structs for the PM1 Enable registers */
-
- acpi_tb_init_generic_address(&acpi_gbl_xpm1a_enable,
- (u8) ACPI_DIV_2(acpi_gbl_FADT->
- pm1_evt_len),
- (acpi_physical_address)
- (local_fadt->xpm1a_evt_blk.address +
- ACPI_DIV_2(acpi_gbl_FADT->pm1_evt_len)));
-
- /* PM1B is optional; leave null if not present */
-
- if (local_fadt->xpm1b_evt_blk.address) {
- acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable,
- (u8) ACPI_DIV_2(acpi_gbl_FADT->
- pm1_evt_len),
- (acpi_physical_address)
- (local_fadt->xpm1b_evt_blk.
- address +
- ACPI_DIV_2(acpi_gbl_FADT->
- pm1_evt_len)));
- }
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_convert_fadt2
- *
- * PARAMETERS: local_fadt - Pointer to new FADT
- * original_fadt - Pointer to old FADT
- *
- * RETURN: None, populates local_fadt
- *
- * DESCRIPTION: Convert an ACPI 2.0 FADT to common internal format.
- * Handles optional "X" fields.
- *
- ******************************************************************************/
-
-static void
-acpi_tb_convert_fadt2(struct fadt_descriptor *local_fadt,
- struct fadt_descriptor *original_fadt)
-{
-
- /* We have an ACPI 2.0 FADT but we must copy it to our local buffer */
-
- ACPI_MEMCPY(local_fadt, original_fadt, sizeof(struct fadt_descriptor));
-
- /*
- * "X" fields are optional extensions to the original V1.0 fields, so
- * we must selectively expand V1.0 fields if the corresponding X field
- * is zero.
- */
- if (!(local_fadt->xfirmware_ctrl)) {
- ACPI_STORE_ADDRESS(local_fadt->xfirmware_ctrl,
- local_fadt->V1_firmware_ctrl);
- }
-
- if (!(local_fadt->Xdsdt)) {
- ACPI_STORE_ADDRESS(local_fadt->Xdsdt, local_fadt->V1_dsdt);
- }
-
- if (!(local_fadt->xpm1a_evt_blk.address)) {
- acpi_tb_init_generic_address(&local_fadt->xpm1a_evt_blk,
- local_fadt->pm1_evt_len,
- (acpi_physical_address)
- local_fadt->V1_pm1a_evt_blk);
- }
-
- if (!(local_fadt->xpm1b_evt_blk.address)) {
- acpi_tb_init_generic_address(&local_fadt->xpm1b_evt_blk,
- local_fadt->pm1_evt_len,
- (acpi_physical_address)
- local_fadt->V1_pm1b_evt_blk);
- }
-
- if (!(local_fadt->xpm1a_cnt_blk.address)) {
- acpi_tb_init_generic_address(&local_fadt->xpm1a_cnt_blk,
- local_fadt->pm1_cnt_len,
- (acpi_physical_address)
- local_fadt->V1_pm1a_cnt_blk);
- }
-
- if (!(local_fadt->xpm1b_cnt_blk.address)) {
- acpi_tb_init_generic_address(&local_fadt->xpm1b_cnt_blk,
- local_fadt->pm1_cnt_len,
- (acpi_physical_address)
- local_fadt->V1_pm1b_cnt_blk);
- }
-
- if (!(local_fadt->xpm2_cnt_blk.address)) {
- acpi_tb_init_generic_address(&local_fadt->xpm2_cnt_blk,
- local_fadt->pm2_cnt_len,
- (acpi_physical_address)
- local_fadt->V1_pm2_cnt_blk);
- }
-
- if (!(local_fadt->xpm_tmr_blk.address)) {
- acpi_tb_init_generic_address(&local_fadt->xpm_tmr_blk,
- local_fadt->pm_tm_len,
- (acpi_physical_address)
- local_fadt->V1_pm_tmr_blk);
- }
-
- if (!(local_fadt->xgpe0_blk.address)) {
- acpi_tb_init_generic_address(&local_fadt->xgpe0_blk,
- 0,
- (acpi_physical_address)
- local_fadt->V1_gpe0_blk);
- }
-
- if (!(local_fadt->xgpe1_blk.address)) {
- acpi_tb_init_generic_address(&local_fadt->xgpe1_blk,
- 0,
- (acpi_physical_address)
- local_fadt->V1_gpe1_blk);
- }
-
- /* Create separate GAS structs for the PM1 Enable registers */
-
- acpi_tb_init_generic_address(&acpi_gbl_xpm1a_enable,
- (u8) ACPI_DIV_2(acpi_gbl_FADT->
- pm1_evt_len),
- (acpi_physical_address)
- (local_fadt->xpm1a_evt_blk.address +
- ACPI_DIV_2(acpi_gbl_FADT->pm1_evt_len)));
-
- acpi_gbl_xpm1a_enable.address_space_id =
- local_fadt->xpm1a_evt_blk.address_space_id;
-
- /* PM1B is optional; leave null if not present */
-
- if (local_fadt->xpm1b_evt_blk.address) {
- acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable,
- (u8) ACPI_DIV_2(acpi_gbl_FADT->
- pm1_evt_len),
- (acpi_physical_address)
- (local_fadt->xpm1b_evt_blk.
- address +
- ACPI_DIV_2(acpi_gbl_FADT->
- pm1_evt_len)));
-
- acpi_gbl_xpm1b_enable.address_space_id =
- local_fadt->xpm1b_evt_blk.address_space_id;
- }
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_convert_table_fadt
- *
- * PARAMETERS: None
- *
- * RETURN: Status
- *
- * DESCRIPTION: Converts a BIOS supplied ACPI 1.0 FADT to a local
- * ACPI 2.0 FADT. If the BIOS supplied a 2.0 FADT then it is simply
- * copied to the local FADT. The ACPI CA software uses this
- * local FADT. Thus a significant amount of special #ifdef
- * type codeing is saved.
- *
- ******************************************************************************/
-
-acpi_status acpi_tb_convert_table_fadt(void)
-{
- struct fadt_descriptor *local_fadt;
- struct acpi_table_desc *table_desc;
-
- ACPI_FUNCTION_TRACE(tb_convert_table_fadt);
-
- /*
- * acpi_gbl_FADT is valid. Validate the FADT length. The table must be
- * at least as long as the version 1.0 FADT
- */
- if (acpi_gbl_FADT->length < sizeof(struct fadt_descriptor_rev1)) {
- ACPI_ERROR((AE_INFO, "FADT is invalid, too short: 0x%X",
- acpi_gbl_FADT->length));
- return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
- }
-
- /* Allocate buffer for the ACPI 2.0(+) FADT */
-
- local_fadt = ACPI_ALLOCATE_ZEROED(sizeof(struct fadt_descriptor));
- if (!local_fadt) {
- return_ACPI_STATUS(AE_NO_MEMORY);
- }
-
- if (acpi_gbl_FADT->revision >= FADT2_REVISION_ID) {
- if (acpi_gbl_FADT->length < sizeof(struct fadt_descriptor)) {
-
- /* Length is too short to be a V2.0 table */
-
- ACPI_WARNING((AE_INFO,
- "Inconsistent FADT length (0x%X) and revision (0x%X), using FADT V1.0 portion of table",
- acpi_gbl_FADT->length,
- acpi_gbl_FADT->revision));
-
- acpi_tb_convert_fadt1(local_fadt,
- (void *)acpi_gbl_FADT);
- } else {
- /* Valid V2.0 table */
-
- acpi_tb_convert_fadt2(local_fadt, acpi_gbl_FADT);
- }
- } else {
- /* Valid V1.0 table */
-
- acpi_tb_convert_fadt1(local_fadt, (void *)acpi_gbl_FADT);
- }
-
- /* Global FADT pointer will point to the new common V2.0 FADT */
-
- acpi_gbl_FADT = local_fadt;
- acpi_gbl_FADT->length = sizeof(struct fadt_descriptor);
-
- /* Free the original table */
-
- table_desc = acpi_gbl_table_lists[ACPI_TABLE_ID_FADT].next;
- acpi_tb_delete_single_table(table_desc);
-
- /* Install the new table */
-
- table_desc->pointer =
- ACPI_CAST_PTR(struct acpi_table_header, acpi_gbl_FADT);
- table_desc->allocation = ACPI_MEM_ALLOCATED;
- table_desc->length = sizeof(struct fadt_descriptor);
-
- /* Dump the entire FADT */
-
- ACPI_DEBUG_PRINT((ACPI_DB_TABLES,
- "Hex dump of common internal FADT, size %d (%X)\n",
- acpi_gbl_FADT->length, acpi_gbl_FADT->length));
-
- ACPI_DUMP_BUFFER(ACPI_CAST_PTR(u8, acpi_gbl_FADT),
- acpi_gbl_FADT->length);
-
- return_ACPI_STATUS(AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_build_common_facs
- *
- * PARAMETERS: table_info - Info for currently installed FACS
- *
- * RETURN: Status
- *
- * DESCRIPTION: Convert ACPI 1.0 and ACPI 2.0 FACS to a common internal
- * table format.
- *
- ******************************************************************************/
-
-acpi_status acpi_tb_build_common_facs(struct acpi_table_desc *table_info)
-{
-
- ACPI_FUNCTION_TRACE(tb_build_common_facs);
-
- /* Absolute minimum length is 24, but the ACPI spec says 64 */
-
- if (acpi_gbl_FACS->length < 24) {
- ACPI_ERROR((AE_INFO, "Invalid FACS table length: 0x%X",
- acpi_gbl_FACS->length));
- return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
- }
-
- if (acpi_gbl_FACS->length < 64) {
- ACPI_WARNING((AE_INFO,
- "FACS is shorter than the ACPI specification allows: 0x%X, using anyway",
- acpi_gbl_FACS->length));
- }
-
- /* Copy fields to the new FACS */
-
- acpi_gbl_common_fACS.global_lock = &(acpi_gbl_FACS->global_lock);
-
- if ((acpi_gbl_RSDP->revision < 2) ||
- (acpi_gbl_FACS->length < 32) ||
- (!(acpi_gbl_FACS->xfirmware_waking_vector))) {
-
- /* ACPI 1.0 FACS or short table or optional X_ field is zero */
-
- acpi_gbl_common_fACS.firmware_waking_vector = ACPI_CAST_PTR(u64,
- &
- (acpi_gbl_FACS->
- firmware_waking_vector));
- acpi_gbl_common_fACS.vector_width = 32;
- } else {
- /* ACPI 2.0 FACS with valid X_ field */
-
- acpi_gbl_common_fACS.firmware_waking_vector =
- &acpi_gbl_FACS->xfirmware_waking_vector;
- acpi_gbl_common_fACS.vector_width = 64;
- }
-
- return_ACPI_STATUS(AE_OK);
-}
diff --git a/drivers/acpi/tables/tbfadt.c b/drivers/acpi/tables/tbfadt.c
new file mode 100644
index 00000000000..807c7116e94
--- /dev/null
+++ b/drivers/acpi/tables/tbfadt.c
@@ -0,0 +1,434 @@
+/******************************************************************************
+ *
+ * Module Name: tbfadt - FADT table utilities
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2007, R. Byron Moore
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include <acpi/actables.h>
+
+#define _COMPONENT ACPI_TABLES
+ACPI_MODULE_NAME("tbfadt")
+
+/* Local prototypes */
+static void inline
+acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
+ u8 bit_width, u64 address);
+
+static void acpi_tb_convert_fadt(void);
+
+static void acpi_tb_validate_fadt(void);
+
+/* Table for conversion of FADT to common internal format and FADT validation */
+
+typedef struct acpi_fadt_info {
+ char *name;
+ u8 target;
+ u8 source;
+ u8 length;
+ u8 type;
+
+} acpi_fadt_info;
+
+#define ACPI_FADT_REQUIRED 1
+#define ACPI_FADT_SEPARATE_LENGTH 2
+
+static struct acpi_fadt_info fadt_info_table[] = {
+ {"Pm1aEventBlock", ACPI_FADT_OFFSET(xpm1a_event_block),
+ ACPI_FADT_OFFSET(pm1a_event_block),
+ ACPI_FADT_OFFSET(pm1_event_length), ACPI_FADT_REQUIRED},
+
+ {"Pm1bEventBlock", ACPI_FADT_OFFSET(xpm1b_event_block),
+ ACPI_FADT_OFFSET(pm1b_event_block),
+ ACPI_FADT_OFFSET(pm1_event_length), 0},
+
+ {"Pm1aControlBlock", ACPI_FADT_OFFSET(xpm1a_control_block),
+ ACPI_FADT_OFFSET(pm1a_control_block),
+ ACPI_FADT_OFFSET(pm1_control_length), ACPI_FADT_REQUIRED},
+
+ {"Pm1bControlBlock", ACPI_FADT_OFFSET(xpm1b_control_block),
+ ACPI_FADT_OFFSET(pm1b_control_block),
+ ACPI_FADT_OFFSET(pm1_control_length), 0},
+
+ {"Pm2ControlBlock", ACPI_FADT_OFFSET(xpm2_control_block),
+ ACPI_FADT_OFFSET(pm2_control_block),
+ ACPI_FADT_OFFSET(pm2_control_length), ACPI_FADT_SEPARATE_LENGTH},
+
+ {"PmTimerBlock", ACPI_FADT_OFFSET(xpm_timer_block),
+ ACPI_FADT_OFFSET(pm_timer_block),
+ ACPI_FADT_OFFSET(pm_timer_length), ACPI_FADT_REQUIRED},
+
+ {"Gpe0Block", ACPI_FADT_OFFSET(xgpe0_block),
+ ACPI_FADT_OFFSET(gpe0_block),
+ ACPI_FADT_OFFSET(gpe0_block_length), ACPI_FADT_SEPARATE_LENGTH},
+
+ {"Gpe1Block", ACPI_FADT_OFFSET(xgpe1_block),
+ ACPI_FADT_OFFSET(gpe1_block),
+ ACPI_FADT_OFFSET(gpe1_block_length), ACPI_FADT_SEPARATE_LENGTH}
+};
+
+#define ACPI_FADT_INFO_ENTRIES (sizeof (fadt_info_table) / sizeof (struct acpi_fadt_info))
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_init_generic_address
+ *
+ * PARAMETERS: generic_address - GAS struct to be initialized
+ * bit_width - Width of this register
+ * Address - Address of the register
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Initialize a Generic Address Structure (GAS)
+ * See the ACPI specification for a full description and
+ * definition of this structure.
+ *
+ ******************************************************************************/
+
+static void inline
+acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
+ u8 bit_width, u64 address)
+{
+
+ /*
+ * The 64-bit Address field is non-aligned in the byte packed
+ * GAS struct.
+ */
+ ACPI_MOVE_64_TO_64(&generic_address->address, &address);
+
+ /* All other fields are byte-wide */
+
+ generic_address->space_id = ACPI_ADR_SPACE_SYSTEM_IO;
+ generic_address->bit_width = bit_width;
+ generic_address->bit_offset = 0;
+ generic_address->access_width = 0;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_parse_fadt
+ *
+ * PARAMETERS: table_index - Index for the FADT
+ * Flags - Flags
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Initialize the FADT, DSDT and FACS tables
+ * (FADT contains the addresses of the DSDT and FACS)
+ *
+ ******************************************************************************/
+
+void acpi_tb_parse_fadt(acpi_native_uint table_index, u8 flags)
+{
+ u32 length;
+ struct acpi_table_header *table;
+
+ /*
+ * The FADT has multiple versions with different lengths,
+ * and it contains pointers to both the DSDT and FACS tables.
+ *
+ * Get a local copy of the FADT and convert it to a common format
+ * Map entire FADT, assumed to be smaller than one page.
+ */
+ length = acpi_gbl_root_table_list.tables[table_index].length;
+
+ table =
+ acpi_os_map_memory(acpi_gbl_root_table_list.tables[table_index].
+ address, length);
+ if (!table) {
+ return;
+ }
+
+ /*
+ * Validate the FADT checksum before we copy the table. Ignore
+ * checksum error as we want to try to get the DSDT and FACS.
+ */
+ (void)acpi_tb_verify_checksum(table, length);
+
+ /* Obtain a local copy of the FADT in common ACPI 2.0+ format */
+
+ acpi_tb_create_local_fadt(table, length);
+
+ /* All done with the real FADT, unmap it */
+
+ acpi_os_unmap_memory(table, length);
+
+ /* Obtain the DSDT and FACS tables via their addresses within the FADT */
+
+ acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xdsdt,
+ flags, ACPI_SIG_DSDT, ACPI_TABLE_INDEX_DSDT);
+
+ acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xfacs,
+ flags, ACPI_SIG_FACS, ACPI_TABLE_INDEX_FACS);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_create_local_fadt
+ *
+ * PARAMETERS: Table - Pointer to BIOS FADT
+ * Length - Length of the table
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Get a local copy of the FADT and convert it to a common format.
+ * Performs validation on some important FADT fields.
+ *
+ ******************************************************************************/
+
+void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length)
+{
+
+ /*
+ * Check if the FADT is larger than what we know about (ACPI 2.0 version).
+ * Truncate the table, but make some noise.
+ */
+ if (length > sizeof(struct acpi_table_fadt)) {
+ ACPI_WARNING((AE_INFO,
+ "FADT (revision %u) is longer than ACPI 2.0 version, truncating length 0x%X to 0x%zX",
+ table->revision, (unsigned)length,
+ sizeof(struct acpi_table_fadt)));
+ }
+
+ /* Copy the entire FADT locally. Zero first for tb_convert_fadt */
+
+ ACPI_MEMSET(&acpi_gbl_FADT, 0, sizeof(struct acpi_table_fadt));
+
+ ACPI_MEMCPY(&acpi_gbl_FADT, table,
+ ACPI_MIN(length, sizeof(struct acpi_table_fadt)));
+
+ /*
+ * 1) Convert the local copy of the FADT to the common internal format
+ * 2) Validate some of the important values within the FADT
+ */
+ acpi_tb_convert_fadt();
+ acpi_tb_validate_fadt();
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_convert_fadt
+ *
+ * PARAMETERS: None, uses acpi_gbl_FADT
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Converts all versions of the FADT to a common internal format.
+ * -> Expand all 32-bit addresses to 64-bit.
+ *
+ * NOTE: acpi_gbl_FADT must be of size (struct acpi_table_fadt),
+ * and must contain a copy of the actual FADT.
+ *
+ * ACPICA will use the "X" fields of the FADT for all addresses.
+ *
+ * "X" fields are optional extensions to the original V1.0 fields. Even if
+ * they are present in the structure, they can be optionally not used by
+ * setting them to zero. Therefore, we must selectively expand V1.0 fields
+ * if the corresponding X field is zero.
+ *
+ * For ACPI 1.0 FADTs, all address fields are expanded to the corresponding
+ * "X" fields.
+ *
+ * For ACPI 2.0 FADTs, any "X" fields that are NULL are filled in by
+ * expanding the corresponding ACPI 1.0 field.
+ *
+ ******************************************************************************/
+
+static void acpi_tb_convert_fadt(void)
+{
+ u8 pm1_register_length;
+ struct acpi_generic_address *target;
+ acpi_native_uint i;
+
+ /* Update the local FADT table header length */
+
+ acpi_gbl_FADT.header.length = sizeof(struct acpi_table_fadt);
+
+ /* Expand the 32-bit FACS and DSDT addresses to 64-bit as necessary */
+
+ if (!acpi_gbl_FADT.Xfacs) {
+ acpi_gbl_FADT.Xfacs = (u64) acpi_gbl_FADT.facs;
+ }
+
+ if (!acpi_gbl_FADT.Xdsdt) {
+ acpi_gbl_FADT.Xdsdt = (u64) acpi_gbl_FADT.dsdt;
+ }
+
+ /*
+ * Expand the 32-bit V1.0 addresses to the 64-bit "X" generic address
+ * structures as necessary.
+ */
+ for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) {
+ target =
+ ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT,
+ fadt_info_table[i].target);
+
+ /* Expand only if the X target is null */
+
+ if (!target->address) {
+ acpi_tb_init_generic_address(target,
+ *ACPI_ADD_PTR(u8,
+ &acpi_gbl_FADT,
+ fadt_info_table
+ [i].length),
+ (u64) * ACPI_ADD_PTR(u32,
+ &acpi_gbl_FADT,
+ fadt_info_table
+ [i].
+ source));
+ }
+ }
+
+ /*
+ * Calculate separate GAS structs for the PM1 Enable registers.
+ * These addresses do not appear (directly) in the FADT, so it is
+ * useful to calculate them once, here.
+ *
+ * The PM event blocks are split into two register blocks, first is the
+ * PM Status Register block, followed immediately by the PM Enable Register
+ * block. Each is of length (pm1_event_length/2)
+ */
+ pm1_register_length = (u8) ACPI_DIV_2(acpi_gbl_FADT.pm1_event_length);
+
+ /* The PM1A register block is required */
+
+ acpi_tb_init_generic_address(&acpi_gbl_xpm1a_enable,
+ pm1_register_length,
+ (acpi_gbl_FADT.xpm1a_event_block.address +
+ pm1_register_length));
+ /* Don't forget to copy space_id of the GAS */
+ acpi_gbl_xpm1a_enable.space_id = acpi_gbl_FADT.xpm1a_event_block.space_id;
+
+ /* The PM1B register block is optional, ignore if not present */
+
+ if (acpi_gbl_FADT.xpm1b_event_block.address) {
+ acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable,
+ pm1_register_length,
+ (acpi_gbl_FADT.xpm1b_event_block.
+ address + pm1_register_length));
+ /* Don't forget to copy space_id of the GAS */
+ acpi_gbl_xpm1b_enable.space_id = acpi_gbl_FADT.xpm1a_event_block.space_id;
+
+ }
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_tb_validate_fadt
+ *
+ * PARAMETERS: Table - Pointer to the FADT to be validated
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Validate various important fields within the FADT. If a problem
+ * is found, issue a message, but no status is returned.
+ * Used by both the table manager and the disassembler.
+ *
+ * Possible additional checks:
+ * (acpi_gbl_FADT.pm1_event_length >= 4)
+ * (acpi_gbl_FADT.pm1_control_length >= 2)
+ * (acpi_gbl_FADT.pm_timer_length >= 4)
+ * Gpe block lengths must be multiple of 2
+ *
+ ******************************************************************************/
+
+static void acpi_tb_validate_fadt(void)
+{
+ u32 *address32;
+ struct acpi_generic_address *address64;
+ u8 length;
+ acpi_native_uint i;
+
+ /* Examine all of the 64-bit extended address fields (X fields) */
+
+ for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) {
+
+ /* Generate pointers to the 32-bit and 64-bit addresses and get the length */
+
+ address64 =
+ ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT,
+ fadt_info_table[i].target);
+ address32 =
+ ACPI_ADD_PTR(u32, &acpi_gbl_FADT,
+ fadt_info_table[i].source);
+ length =
+ *ACPI_ADD_PTR(u8, &acpi_gbl_FADT,
+ fadt_info_table[i].length);
+
+ if (fadt_info_table[i].type & ACPI_FADT_REQUIRED) {
+ /*
+ * Field is required (Pm1a_event, Pm1a_control, pm_timer).
+ * Both the address and length must be non-zero.
+ */
+ if (!address64->address || !length) {
+ ACPI_ERROR((AE_INFO,
+ "Required field \"%s\" has zero address and/or length: %8.8X%8.8X/%X",
+ fadt_info_table[i].name,
+ ACPI_FORMAT_UINT64(address64->
+ address),
+ length));
+ }
+ } else if (fadt_info_table[i].type & ACPI_FADT_SEPARATE_LENGTH) {
+ /*
+ * Field is optional (PM2Control, GPE0, GPE1) AND has its own
+ * length field. If present, both the address and length must be valid.
+ */
+ if ((address64->address && !length)
+ || (!address64->address && length)) {
+ ACPI_WARNING((AE_INFO,
+ "Optional field \"%s\" has zero address or length: %8.8X%8.8X/%X",
+ fadt_info_table[i].name,
+ ACPI_FORMAT_UINT64(address64->
+ address),
+ length));
+ }
+ }
+
+ /* If both 32- and 64-bit addresses are valid (non-zero), they must match */
+
+ if (address64->address && *address32 &&
+ (address64->address != (u64) * address32)) {
+ ACPI_ERROR((AE_INFO,
+ "32/64X address mismatch in \"%s\": [%8.8X] [%8.8X%8.8X], using 64X",
+ fadt_info_table[i].name, *address32,
+ ACPI_FORMAT_UINT64(address64->address)));
+ }
+ }
+}
diff --git a/drivers/acpi/tables/tbfind.c b/drivers/acpi/tables/tbfind.c
new file mode 100644
index 00000000000..058c064948e
--- /dev/null
+++ b/drivers/acpi/tables/tbfind.c
@@ -0,0 +1,126 @@
+/******************************************************************************
+ *
+ * Module Name: tbfind - find table
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2007, R. Byron Moore
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include <acpi/actables.h>
+
+#define _COMPONENT ACPI_TABLES
+ACPI_MODULE_NAME("tbfind")
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_find_table
+ *
+ * PARAMETERS: Signature - String with ACPI table signature
+ * oem_id - String with the table OEM ID
+ * oem_table_id - String with the OEM Table ID
+ * table_index - Where the table index is returned
+ *
+ * RETURN: Status and table index
+ *
+ * DESCRIPTION: Find an ACPI table (in the RSDT/XSDT) that matches the
+ * Signature, OEM ID and OEM Table ID. Returns an index that can
+ * be used to get the table header or entire table.
+ *
+ ******************************************************************************/
+acpi_status
+acpi_tb_find_table(char *signature,
+ char *oem_id,
+ char *oem_table_id, acpi_native_uint * table_index)
+{
+ acpi_native_uint i;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(tb_find_table);
+
+ for (i = 0; i < acpi_gbl_root_table_list.count; ++i) {
+ if (ACPI_MEMCMP(&(acpi_gbl_root_table_list.tables[i].signature),
+ signature, ACPI_NAME_SIZE)) {
+
+ /* Not the requested table */
+
+ continue;
+ }
+
+ /* Table with matching signature has been found */
+
+ if (!acpi_gbl_root_table_list.tables[i].pointer) {
+
+ /* Table is not currently mapped, map it */
+
+ status =
+ acpi_tb_verify_table(&acpi_gbl_root_table_list.
+ tables[i]);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ if (!acpi_gbl_root_table_list.tables[i].pointer) {
+ continue;
+ }
+ }
+
+ /* Check for table match on all IDs */
+
+ if (!ACPI_MEMCMP
+ (acpi_gbl_root_table_list.tables[i].pointer->signature,
+ signature, ACPI_NAME_SIZE) && (!oem_id[0]
+ ||
+ !ACPI_MEMCMP
+ (acpi_gbl_root_table_list.
+ tables[i].pointer->oem_id,
+ oem_id, ACPI_OEM_ID_SIZE))
+ && (!oem_table_id[0]
+ || !ACPI_MEMCMP(acpi_gbl_root_table_list.tables[i].
+ pointer->oem_table_id, oem_table_id,
+ ACPI_OEM_TABLE_ID_SIZE))) {
+ *table_index = i;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_TABLES,
+ "Found table [%4.4s]\n", signature));
+ return_ACPI_STATUS(AE_OK);
+ }
+ }
+
+ return_ACPI_STATUS(AE_NOT_FOUND);
+}
diff --git a/drivers/acpi/tables/tbget.c b/drivers/acpi/tables/tbget.c
deleted file mode 100644
index 11e2d4454e0..00000000000
--- a/drivers/acpi/tables/tbget.c
+++ /dev/null
@@ -1,471 +0,0 @@
-/******************************************************************************
- *
- * Module Name: tbget - ACPI Table get* routines
- *
- *****************************************************************************/
-
-/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- * substantially similar to the "NO WARRANTY" disclaimer below
- * ("Disclaimer") and any redistribution must be conditioned upon
- * including a substantially similar Disclaimer requirement for further
- * binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- * of any contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * NO WARRANTY
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- */
-
-#include <acpi/acpi.h>
-#include <acpi/actables.h>
-
-#define _COMPONENT ACPI_TABLES
-ACPI_MODULE_NAME("tbget")
-
-/* Local prototypes */
-static acpi_status
-acpi_tb_get_this_table(struct acpi_pointer *address,
- struct acpi_table_header *header,
- struct acpi_table_desc *table_info);
-
-static acpi_status
-acpi_tb_table_override(struct acpi_table_header *header,
- struct acpi_table_desc *table_info);
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_get_table
- *
- * PARAMETERS: Address - Address of table to retrieve. Can be
- * Logical or Physical
- * table_info - Where table info is returned
- *
- * RETURN: None
- *
- * DESCRIPTION: Get entire table of unknown size.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_tb_get_table(struct acpi_pointer *address,
- struct acpi_table_desc *table_info)
-{
- acpi_status status;
- struct acpi_table_header header;
-
- ACPI_FUNCTION_TRACE(tb_get_table);
-
- /* Get the header in order to get signature and table size */
-
- status = acpi_tb_get_table_header(address, &header);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Get the entire table */
-
- status = acpi_tb_get_table_body(address, &header, table_info);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Could not get ACPI table (size %X)",
- header.length));
- return_ACPI_STATUS(status);
- }
-
- return_ACPI_STATUS(AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_get_table_header
- *
- * PARAMETERS: Address - Address of table to retrieve. Can be
- * Logical or Physical
- * return_header - Where the table header is returned
- *
- * RETURN: Status
- *
- * DESCRIPTION: Get an ACPI table header. Works in both physical or virtual
- * addressing mode. Works with both physical or logical pointers.
- * Table is either copied or mapped, depending on the pointer
- * type and mode of the processor.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_tb_get_table_header(struct acpi_pointer *address,
- struct acpi_table_header *return_header)
-{
- acpi_status status = AE_OK;
- struct acpi_table_header *header = NULL;
-
- ACPI_FUNCTION_TRACE(tb_get_table_header);
-
- /*
- * Flags contains the current processor mode (Virtual or Physical
- * addressing) The pointer_type is either Logical or Physical
- */
- switch (address->pointer_type) {
- case ACPI_PHYSMODE_PHYSPTR:
- case ACPI_LOGMODE_LOGPTR:
-
- /* Pointer matches processor mode, copy the header */
-
- ACPI_MEMCPY(return_header, address->pointer.logical,
- sizeof(struct acpi_table_header));
- break;
-
- case ACPI_LOGMODE_PHYSPTR:
-
- /* Create a logical address for the physical pointer */
-
- status = acpi_os_map_memory(address->pointer.physical,
- sizeof(struct acpi_table_header),
- (void *)&header);
- if (ACPI_FAILURE(status)) {
- ACPI_ERROR((AE_INFO,
- "Could not map memory at %8.8X%8.8X for table header",
- ACPI_FORMAT_UINT64(address->pointer.
- physical)));
- return_ACPI_STATUS(status);
- }
-
- /* Copy header and delete mapping */
-
- ACPI_MEMCPY(return_header, header,
- sizeof(struct acpi_table_header));
- acpi_os_unmap_memory(header, sizeof(struct acpi_table_header));
- break;
-
- default:
-
- ACPI_ERROR((AE_INFO, "Invalid address flags %X",
- address->pointer_type));
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- ACPI_DEBUG_PRINT((ACPI_DB_TABLES, "Table Signature: [%4.4s]\n",
- return_header->signature));
-
- return_ACPI_STATUS(AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_get_table_body
- *
- * PARAMETERS: Address - Address of table to retrieve. Can be
- * Logical or Physical
- * Header - Header of the table to retrieve
- * table_info - Where the table info is returned
- *
- * RETURN: Status
- *
- * DESCRIPTION: Get an entire ACPI table with support to allow the host OS to
- * replace the table with a newer version (table override.)
- * Works in both physical or virtual
- * addressing mode. Works with both physical or logical pointers.
- * Table is either copied or mapped, depending on the pointer
- * type and mode of the processor.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_tb_get_table_body(struct acpi_pointer *address,
- struct acpi_table_header *header,
- struct acpi_table_desc *table_info)
-{
- acpi_status status;
-
- ACPI_FUNCTION_TRACE(tb_get_table_body);
-
- if (!table_info || !address) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- /* Attempt table override. */
-
- status = acpi_tb_table_override(header, table_info);
- if (ACPI_SUCCESS(status)) {
-
- /* Table was overridden by the host OS */
-
- return_ACPI_STATUS(status);
- }
-
- /* No override, get the original table */
-
- status = acpi_tb_get_this_table(address, header, table_info);
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_table_override
- *
- * PARAMETERS: Header - Pointer to table header
- * table_info - Return info if table is overridden
- *
- * RETURN: None
- *
- * DESCRIPTION: Attempts override of current table with a new one if provided
- * by the host OS.
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_tb_table_override(struct acpi_table_header *header,
- struct acpi_table_desc *table_info)
-{
- struct acpi_table_header *new_table;
- acpi_status status;
- struct acpi_pointer address;
-
- ACPI_FUNCTION_TRACE(tb_table_override);
-
- /*
- * The OSL will examine the header and decide whether to override this
- * table. If it decides to override, a table will be returned in new_table,
- * which we will then copy.
- */
- status = acpi_os_table_override(header, &new_table);
- if (ACPI_FAILURE(status)) {
-
- /* Some severe error from the OSL, but we basically ignore it */
-
- ACPI_EXCEPTION((AE_INFO, status,
- "Could not override ACPI table"));
- return_ACPI_STATUS(status);
- }
-
- if (!new_table) {
-
- /* No table override */
-
- return_ACPI_STATUS(AE_NO_ACPI_TABLES);
- }
-
- /*
- * We have a new table to override the old one. Get a copy of
- * the new one. We know that the new table has a logical pointer.
- */
- address.pointer_type = ACPI_LOGICAL_POINTER | ACPI_LOGICAL_ADDRESSING;
- address.pointer.logical = new_table;
-
- status = acpi_tb_get_this_table(&address, new_table, table_info);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "Could not copy ACPI table"));
- return_ACPI_STATUS(status);
- }
-
- /* Copy the table info */
-
- ACPI_INFO((AE_INFO, "Table [%4.4s] replaced by host OS",
- table_info->pointer->signature));
-
- return_ACPI_STATUS(AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_get_this_table
- *
- * PARAMETERS: Address - Address of table to retrieve. Can be
- * Logical or Physical
- * Header - Header of the table to retrieve
- * table_info - Where the table info is returned
- *
- * RETURN: Status
- *
- * DESCRIPTION: Get an entire ACPI table. Works in both physical or virtual
- * addressing mode. Works with both physical or logical pointers.
- * Table is either copied or mapped, depending on the pointer
- * type and mode of the processor.
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_tb_get_this_table(struct acpi_pointer *address,
- struct acpi_table_header *header,
- struct acpi_table_desc *table_info)
-{
- struct acpi_table_header *full_table = NULL;
- u8 allocation;
- acpi_status status = AE_OK;
-
- 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 (%zX)",
- 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
- */
- switch (address->pointer_type) {
- case ACPI_PHYSMODE_PHYSPTR:
- case ACPI_LOGMODE_LOGPTR:
-
- /* Pointer matches processor mode, copy the table to a new buffer */
-
- full_table = ACPI_ALLOCATE(header->length);
- if (!full_table) {
- ACPI_ERROR((AE_INFO,
- "Could not allocate table memory for [%4.4s] length %X",
- header->signature, header->length));
- return_ACPI_STATUS(AE_NO_MEMORY);
- }
-
- /* Copy the entire table (including header) to the local buffer */
-
- ACPI_MEMCPY(full_table, address->pointer.logical,
- header->length);
-
- /* Save allocation type */
-
- allocation = ACPI_MEM_ALLOCATED;
- break;
-
- case ACPI_LOGMODE_PHYSPTR:
-
- /*
- * Just map the table's physical memory
- * into our address space.
- */
- status = acpi_os_map_memory(address->pointer.physical,
- (acpi_size) header->length,
- 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",
- header->signature,
- ACPI_FORMAT_UINT64(address->pointer.
- physical),
- header->length));
- return (status);
- }
-
- /* Save allocation type */
-
- allocation = ACPI_MEM_MAPPED;
- break;
-
- default:
-
- ACPI_ERROR((AE_INFO, "Invalid address flags %X",
- address->pointer_type));
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- /*
- * Validate checksum for _most_ tables,
- * even the ones whose signature we don't recognize
- */
- if (table_info->type != ACPI_TABLE_ID_FACS) {
- status = acpi_tb_verify_table_checksum(full_table);
-
-#if (!ACPI_CHECKSUM_ABORT)
- if (ACPI_FAILURE(status)) {
-
- /* Ignore the error if configuration says so */
-
- status = AE_OK;
- }
-#endif
- }
-
- /* Return values */
-
- table_info->pointer = full_table;
- table_info->length = (acpi_size) header->length;
- table_info->allocation = allocation;
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Found table [%4.4s] at %8.8X%8.8X, mapped/copied to %p\n",
- full_table->signature,
- ACPI_FORMAT_UINT64(address->pointer.physical),
- full_table));
-
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_get_table_ptr
- *
- * PARAMETERS: table_type - one of the defined table types
- * Instance - Which table of this type
- * return_table - pointer to location to place the pointer for
- * return
- *
- * RETURN: Status
- *
- * DESCRIPTION: This function is called to get the pointer to an ACPI table.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_tb_get_table_ptr(acpi_table_type table_type,
- u32 instance, struct acpi_table_header **return_table)
-{
- struct acpi_table_desc *table_desc;
- u32 i;
-
- ACPI_FUNCTION_TRACE(tb_get_table_ptr);
-
- if (table_type > ACPI_TABLE_ID_MAX) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- /* Check for instance out of range of the current table count */
-
- if (instance > acpi_gbl_table_lists[table_type].count) {
- return_ACPI_STATUS(AE_NOT_EXIST);
- }
-
- /*
- * Walk the list to get the desired table
- * Note: Instance is one-based
- */
- table_desc = acpi_gbl_table_lists[table_type].next;
- for (i = 1; i < instance; i++) {
- table_desc = table_desc->next;
- }
-
- /* We are now pointing to the requested table's descriptor */
-
- *return_table = table_desc->pointer;
- return_ACPI_STATUS(AE_OK);
-}
diff --git a/drivers/acpi/tables/tbgetall.c b/drivers/acpi/tables/tbgetall.c
deleted file mode 100644
index ad982112e4c..00000000000
--- a/drivers/acpi/tables/tbgetall.c
+++ /dev/null
@@ -1,311 +0,0 @@
-/******************************************************************************
- *
- * Module Name: tbgetall - Get all required ACPI tables
- *
- *****************************************************************************/
-
-/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- * substantially similar to the "NO WARRANTY" disclaimer below
- * ("Disclaimer") and any redistribution must be conditioned upon
- * including a substantially similar Disclaimer requirement for further
- * binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- * of any contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * NO WARRANTY
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- */
-
-#include <acpi/acpi.h>
-#include <acpi/actables.h>
-
-#define _COMPONENT ACPI_TABLES
-ACPI_MODULE_NAME("tbgetall")
-
-/* Local prototypes */
-static acpi_status
-acpi_tb_get_primary_table(struct acpi_pointer *address,
- struct acpi_table_desc *table_info);
-
-static acpi_status
-acpi_tb_get_secondary_table(struct acpi_pointer *address,
- acpi_string signature,
- struct acpi_table_desc *table_info);
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_get_primary_table
- *
- * PARAMETERS: Address - Physical address of table to retrieve
- * *table_info - Where the table info is returned
- *
- * RETURN: Status
- *
- * DESCRIPTION: Maps the physical address of table into a logical address
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_tb_get_primary_table(struct acpi_pointer *address,
- struct acpi_table_desc *table_info)
-{
- acpi_status status;
- struct acpi_table_header header;
-
- ACPI_FUNCTION_TRACE(tb_get_primary_table);
-
- /* Ignore a NULL address in the RSDT */
-
- if (!address->pointer.value) {
- return_ACPI_STATUS(AE_OK);
- }
-
- /* Get the header in order to get signature and table size */
-
- status = acpi_tb_get_table_header(address, &header);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Clear the table_info */
-
- ACPI_MEMSET(table_info, 0, sizeof(struct acpi_table_desc));
-
- /*
- * Check the table signature and make sure it is recognized.
- * Also checks the header checksum
- */
- table_info->pointer = &header;
- status = acpi_tb_recognize_table(table_info, ACPI_TABLE_PRIMARY);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Get the entire table */
-
- status = acpi_tb_get_table_body(address, &header, table_info);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Install the table */
-
- status = acpi_tb_install_table(table_info);
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_get_secondary_table
- *
- * PARAMETERS: Address - Physical address of table to retrieve
- * *table_info - Where the table info is returned
- *
- * RETURN: Status
- *
- * DESCRIPTION: Maps the physical address of table into a logical address
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_tb_get_secondary_table(struct acpi_pointer *address,
- acpi_string signature,
- struct acpi_table_desc *table_info)
-{
- acpi_status status;
- struct acpi_table_header header;
-
- ACPI_FUNCTION_TRACE_STR(tb_get_secondary_table, signature);
-
- /* Get the header in order to match the signature */
-
- status = acpi_tb_get_table_header(address, &header);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Signature must match request */
-
- if (!ACPI_COMPARE_NAME(header.signature, signature)) {
- ACPI_ERROR((AE_INFO,
- "Incorrect table signature - wanted [%s] found [%4.4s]",
- signature, header.signature));
- return_ACPI_STATUS(AE_BAD_SIGNATURE);
- }
-
- /*
- * Check the table signature and make sure it is recognized.
- * Also checks the header checksum
- */
- table_info->pointer = &header;
- status = acpi_tb_recognize_table(table_info, ACPI_TABLE_SECONDARY);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Get the entire table */
-
- status = acpi_tb_get_table_body(address, &header, table_info);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Install the table */
-
- status = acpi_tb_install_table(table_info);
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_get_required_tables
- *
- * PARAMETERS: None
- *
- * RETURN: Status
- *
- * DESCRIPTION: Load and validate tables other than the RSDT. The RSDT must
- * already be loaded and validated.
- *
- * Get the minimum set of ACPI tables, namely:
- *
- * 1) FADT (via RSDT in loop below)
- * 2) FACS (via FADT)
- * 3) DSDT (via FADT)
- *
- ******************************************************************************/
-
-acpi_status acpi_tb_get_required_tables(void)
-{
- acpi_status status = AE_OK;
- u32 i;
- struct acpi_table_desc table_info;
- struct acpi_pointer address;
-
- ACPI_FUNCTION_TRACE(tb_get_required_tables);
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%d ACPI tables in RSDT\n",
- acpi_gbl_rsdt_table_count));
-
- address.pointer_type = acpi_gbl_table_flags | ACPI_LOGICAL_ADDRESSING;
-
- /*
- * Loop through all table pointers found in RSDT.
- * This will NOT include the FACS and DSDT - we must get
- * them after the loop.
- *
- * The only tables we are interested in getting here is the FADT and
- * any SSDTs.
- */
- for (i = 0; i < acpi_gbl_rsdt_table_count; i++) {
-
- /* Get the table address from the common internal XSDT */
-
- address.pointer.value = acpi_gbl_XSDT->table_offset_entry[i];
-
- /*
- * Get the tables needed by this subsystem (FADT and any SSDTs).
- * NOTE: All other tables are completely ignored at this time.
- */
- status = acpi_tb_get_primary_table(&address, &table_info);
- if ((status != AE_OK) && (status != AE_TABLE_NOT_SUPPORTED)) {
- ACPI_WARNING((AE_INFO,
- "%s, while getting table at %8.8X%8.8X",
- acpi_format_exception(status),
- ACPI_FORMAT_UINT64(address.pointer.
- value)));
- }
- }
-
- /* We must have a FADT to continue */
-
- if (!acpi_gbl_FADT) {
- ACPI_ERROR((AE_INFO, "No FADT present in RSDT/XSDT"));
- return_ACPI_STATUS(AE_NO_ACPI_TABLES);
- }
-
- /*
- * Convert the FADT to a common format. This allows earlier revisions of
- * the table to coexist with newer versions, using common access code.
- */
- status = acpi_tb_convert_table_fadt();
- if (ACPI_FAILURE(status)) {
- ACPI_ERROR((AE_INFO,
- "Could not convert FADT to internal common format"));
- return_ACPI_STATUS(status);
- }
-
- /* Get the FACS (Pointed to by the FADT) */
-
- address.pointer.value = acpi_gbl_FADT->xfirmware_ctrl;
-
- status = acpi_tb_get_secondary_table(&address, FACS_SIG, &table_info);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Could not get/install the FACS"));
- return_ACPI_STATUS(status);
- }
-
- /*
- * Create the common FACS pointer table
- * (Contains pointers to the original table)
- */
- status = acpi_tb_build_common_facs(&table_info);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Get/install the DSDT (Pointed to by the FADT) */
-
- address.pointer.value = acpi_gbl_FADT->Xdsdt;
-
- status = acpi_tb_get_secondary_table(&address, DSDT_SIG, &table_info);
- if (ACPI_FAILURE(status)) {
- ACPI_ERROR((AE_INFO, "Could not get/install the DSDT"));
- return_ACPI_STATUS(status);
- }
-
- /* Set Integer Width (32/64) based upon DSDT revision */
-
- acpi_ut_set_integer_width(acpi_gbl_DSDT->revision);
-
- /* Dump the entire DSDT */
-
- ACPI_DEBUG_PRINT((ACPI_DB_TABLES,
- "Hex dump of entire DSDT, size %d (0x%X), Integer width = %d\n",
- acpi_gbl_DSDT->length, acpi_gbl_DSDT->length,
- acpi_gbl_integer_bit_width));
-
- ACPI_DUMP_BUFFER(ACPI_CAST_PTR(u8, acpi_gbl_DSDT),
- acpi_gbl_DSDT->length);
-
- /* Always delete the RSDP mapping, we are done with it */
-
- acpi_tb_delete_tables_by_type(ACPI_TABLE_ID_RSDP);
- return_ACPI_STATUS(status);
-}
diff --git a/drivers/acpi/tables/tbinstal.c b/drivers/acpi/tables/tbinstal.c
index 1668a232fb6..0e7b121a99c 100644
--- a/drivers/acpi/tables/tbinstal.c
+++ b/drivers/acpi/tables/tbinstal.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -42,510 +42,498 @@
*/
#include <acpi/acpi.h>
+#include <acpi/acnamesp.h>
#include <acpi/actables.h>
#define _COMPONENT ACPI_TABLES
ACPI_MODULE_NAME("tbinstal")
-/* Local prototypes */
-static acpi_status
-acpi_tb_match_signature(char *signature,
- struct acpi_table_desc *table_info, u8 search_type);
-
-/*******************************************************************************
+/******************************************************************************
*
- * FUNCTION: acpi_tb_match_signature
+ * FUNCTION: acpi_tb_verify_table
*
- * PARAMETERS: Signature - Table signature to match
- * table_info - Return data
- * search_type - Table type to match (primary/secondary)
+ * PARAMETERS: table_desc - table
*
* RETURN: Status
*
- * DESCRIPTION: Compare signature against the list of "ACPI-subsystem-owned"
- * tables (DSDT/FADT/SSDT, etc.) Returns the table_type_iD on match.
+ * DESCRIPTION: this function is called to verify and map table
*
- ******************************************************************************/
-
-static acpi_status
-acpi_tb_match_signature(char *signature,
- struct acpi_table_desc *table_info, u8 search_type)
+ *****************************************************************************/
+acpi_status acpi_tb_verify_table(struct acpi_table_desc *table_desc)
{
- acpi_native_uint i;
+ acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE(tb_match_signature);
+ ACPI_FUNCTION_TRACE(tb_verify_table);
- /* Search for a signature match among the known table types */
+ /* Map the table if necessary */
- for (i = 0; i < (ACPI_TABLE_ID_MAX + 1); i++) {
- if (!(acpi_gbl_table_data[i].flags & search_type)) {
- continue;
+ if (!table_desc->pointer) {
+ if ((table_desc->flags & ACPI_TABLE_ORIGIN_MASK) ==
+ ACPI_TABLE_ORIGIN_MAPPED) {
+ table_desc->pointer =
+ acpi_os_map_memory(table_desc->address,
+ table_desc->length);
}
+ if (!table_desc->pointer) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+ }
- if (!ACPI_STRNCMP(signature, acpi_gbl_table_data[i].signature,
- acpi_gbl_table_data[i].sig_length)) {
-
- /* Found a signature match, return index if requested */
+ /* FACS is the odd table, has no standard ACPI header and no checksum */
- if (table_info) {
- table_info->type = (u8) i;
- }
+ if (!ACPI_COMPARE_NAME(&table_desc->signature, ACPI_SIG_FACS)) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Table [%4.4s] is an ACPI table consumed by the core subsystem\n",
- (char *)acpi_gbl_table_data[i].
- signature));
+ /* Always calculate checksum, ignore bad checksum if requested */
- return_ACPI_STATUS(AE_OK);
- }
+ status =
+ acpi_tb_verify_checksum(table_desc->pointer,
+ table_desc->length);
}
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Table [%4.4s] is not an ACPI table consumed by the core subsystem - ignored\n",
- (char *)signature));
-
- return_ACPI_STATUS(AE_TABLE_NOT_SUPPORTED);
+ return_ACPI_STATUS(status);
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_install_table
+ * FUNCTION: acpi_tb_add_table
*
- * PARAMETERS: table_info - Return value from acpi_tb_get_table_body
+ * PARAMETERS: table_desc - Table descriptor
+ * table_index - Where the table index is returned
*
* RETURN: Status
*
- * DESCRIPTION: Install the table into the global data structures.
+ * DESCRIPTION: This function is called to add the ACPI table
*
******************************************************************************/
-acpi_status acpi_tb_install_table(struct acpi_table_desc *table_info)
+acpi_status
+acpi_tb_add_table(struct acpi_table_desc *table_desc,
+ acpi_native_uint * table_index)
{
- acpi_status status;
-
- ACPI_FUNCTION_TRACE(tb_install_table);
+ acpi_native_uint i;
+ acpi_native_uint length;
+ acpi_status status = AE_OK;
- /* Lock tables while installing */
+ ACPI_FUNCTION_TRACE(tb_add_table);
- status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Could not acquire table mutex"));
- return_ACPI_STATUS(status);
+ if (!table_desc->pointer) {
+ status = acpi_tb_verify_table(table_desc);
+ if (ACPI_FAILURE(status) || !table_desc->pointer) {
+ return_ACPI_STATUS(status);
+ }
}
- /*
- * Ignore a table that is already installed. For example, some BIOS
- * ASL code will repeatedly attempt to load the same SSDT.
- */
- status = acpi_tb_is_table_installed(table_info);
- if (ACPI_FAILURE(status)) {
- goto unlock_and_exit;
+ /* The table must be either an SSDT or a PSDT */
+
+ if ((!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_PSDT))
+ &&
+ (!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_SSDT)))
+ {
+ ACPI_ERROR((AE_INFO,
+ "Table has invalid signature [%4.4s], must be SSDT or PSDT",
+ table_desc->pointer->signature));
+ return_ACPI_STATUS(AE_BAD_SIGNATURE);
}
- /* Install the table into the global data structure */
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+
+ /* Check if table is already registered */
+
+ for (i = 0; i < acpi_gbl_root_table_list.count; ++i) {
+ if (!acpi_gbl_root_table_list.tables[i].pointer) {
+ status =
+ acpi_tb_verify_table(&acpi_gbl_root_table_list.
+ tables[i]);
+ if (ACPI_FAILURE(status)
+ || !acpi_gbl_root_table_list.tables[i].pointer) {
+ continue;
+ }
+ }
+
+ length = ACPI_MIN(table_desc->length,
+ acpi_gbl_root_table_list.tables[i].length);
+ if (ACPI_MEMCMP(table_desc->pointer,
+ acpi_gbl_root_table_list.tables[i].pointer,
+ length)) {
+ continue;
+ }
+
+ /* Table is already registered */
+
+ acpi_tb_delete_table(table_desc);
+ *table_index = i;
+ goto release;
+ }
- status = acpi_tb_init_table_descriptor(table_info->type, table_info);
+ /*
+ * Add the table to the global table list
+ */
+ status = acpi_tb_store_table(table_desc->address, table_desc->pointer,
+ table_desc->length, table_desc->flags,
+ table_index);
if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Could not install table [%4.4s]",
- table_info->pointer->signature));
+ goto release;
}
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s located at %p\n",
- acpi_gbl_table_data[table_info->type].name,
- table_info->pointer));
+ acpi_tb_print_table_header(table_desc->address, table_desc->pointer);
- unlock_and_exit:
+ release:
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
return_ACPI_STATUS(status);
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_recognize_table
+ * FUNCTION: acpi_tb_resize_root_table_list
*
- * PARAMETERS: table_info - Return value from acpi_tb_get_table_body
- * search_type - Table type to match (primary/secondary)
+ * PARAMETERS: None
*
* RETURN: Status
*
- * DESCRIPTION: Check a table signature for a match against known table types
- *
- * NOTE: All table pointers are validated as follows:
- * 1) Table pointer must point to valid physical memory
- * 2) Signature must be 4 ASCII chars, even if we don't recognize the
- * name
- * 3) Table must be readable for length specified in the header
- * 4) Table checksum must be valid (with the exception of the FACS
- * which has no checksum for some odd reason)
+ * DESCRIPTION: Expand the size of global table array
*
******************************************************************************/
-acpi_status
-acpi_tb_recognize_table(struct acpi_table_desc *table_info, u8 search_type)
+acpi_status acpi_tb_resize_root_table_list(void)
{
- struct acpi_table_header *table_header;
- acpi_status status;
+ struct acpi_table_desc *tables;
- ACPI_FUNCTION_TRACE(tb_recognize_table);
+ ACPI_FUNCTION_TRACE(tb_resize_root_table_list);
- /* Ensure that we have a valid table pointer */
+ /* allow_resize flag is a parameter to acpi_initialize_tables */
- table_header = (struct acpi_table_header *)table_info->pointer;
- if (!table_header) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
+ if (!(acpi_gbl_root_table_list.flags & ACPI_ROOT_ALLOW_RESIZE)) {
+ ACPI_ERROR((AE_INFO,
+ "Resize of Root Table Array is not allowed"));
+ return_ACPI_STATUS(AE_SUPPORT);
}
- /*
- * We only "recognize" a limited number of ACPI tables -- namely, the
- * ones that are used by the subsystem (DSDT, FADT, etc.)
- *
- * An AE_TABLE_NOT_SUPPORTED means that the table was not recognized.
- * This can be any one of many valid ACPI tables, it just isn't one of
- * the tables that is consumed by the core subsystem
- */
- status = acpi_tb_match_signature(table_header->signature,
- table_info, search_type);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ /* Increase the Table Array size */
+
+ tables = ACPI_ALLOCATE_ZEROED((acpi_gbl_root_table_list.size +
+ ACPI_ROOT_TABLE_SIZE_INCREMENT)
+ * sizeof(struct acpi_table_desc));
+ if (!tables) {
+ ACPI_ERROR((AE_INFO,
+ "Could not allocate new root table array"));
+ return_ACPI_STATUS(AE_NO_MEMORY);
}
- status = acpi_tb_validate_table_header(table_header);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ /* Copy and free the previous table array */
+
+ if (acpi_gbl_root_table_list.tables) {
+ ACPI_MEMCPY(tables, acpi_gbl_root_table_list.tables,
+ acpi_gbl_root_table_list.size *
+ sizeof(struct acpi_table_desc));
+
+ if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) {
+ ACPI_FREE(acpi_gbl_root_table_list.tables);
+ }
}
- /* Return the table type and length via the info struct */
+ acpi_gbl_root_table_list.tables = tables;
+ acpi_gbl_root_table_list.size += ACPI_ROOT_TABLE_SIZE_INCREMENT;
+ acpi_gbl_root_table_list.flags |= (u8) ACPI_ROOT_ORIGIN_ALLOCATED;
- table_info->length = (acpi_size) table_header->length;
- return_ACPI_STATUS(status);
+ return_ACPI_STATUS(AE_OK);
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_init_table_descriptor
+ * FUNCTION: acpi_tb_store_table
*
- * PARAMETERS: table_type - The type of the table
- * table_info - A table info struct
+ * PARAMETERS: Address - Table address
+ * Table - Table header
+ * Length - Table length
+ * Flags - flags
*
- * RETURN: None.
+ * RETURN: Status and table index.
*
- * DESCRIPTION: Install a table into the global data structs.
+ * DESCRIPTION: Add an ACPI table to the global table list
*
******************************************************************************/
acpi_status
-acpi_tb_init_table_descriptor(acpi_table_type table_type,
- struct acpi_table_desc *table_info)
+acpi_tb_store_table(acpi_physical_address address,
+ struct acpi_table_header *table,
+ u32 length, u8 flags, acpi_native_uint * table_index)
{
- struct acpi_table_list *list_head;
- struct acpi_table_desc *table_desc;
- acpi_status status;
-
- ACPI_FUNCTION_TRACE_U32(tb_init_table_descriptor, table_type);
+ acpi_status status = AE_OK;
- /* Allocate a descriptor for this table */
+ /* Ensure that there is room for the table in the Root Table List */
- table_desc = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_table_desc));
- if (!table_desc) {
- return_ACPI_STATUS(AE_NO_MEMORY);
+ if (acpi_gbl_root_table_list.count >= acpi_gbl_root_table_list.size) {
+ status = acpi_tb_resize_root_table_list();
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
}
- /* Get a new owner ID for the table */
+ /* Initialize added table */
+
+ acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].
+ address = address;
+ acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].
+ pointer = table;
+ acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].length =
+ length;
+ acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].
+ owner_id = 0;
+ acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].flags =
+ flags;
+
+ ACPI_MOVE_32_TO_32(&
+ (acpi_gbl_root_table_list.
+ tables[acpi_gbl_root_table_list.count].signature),
+ table->signature);
+
+ *table_index = acpi_gbl_root_table_list.count;
+ acpi_gbl_root_table_list.count++;
+ return (status);
+}
- status = acpi_ut_allocate_owner_id(&table_desc->owner_id);
- if (ACPI_FAILURE(status)) {
- goto error_exit1;
- }
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_delete_table
+ *
+ * PARAMETERS: table_index - Table index
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Delete one internal ACPI table
+ *
+ ******************************************************************************/
- /* Install the table into the global data structure */
+void acpi_tb_delete_table(struct acpi_table_desc *table_desc)
+{
+ /* Table must be mapped or allocated */
+ if (!table_desc->pointer) {
+ return;
+ }
+ switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) {
+ case ACPI_TABLE_ORIGIN_MAPPED:
+ acpi_os_unmap_memory(table_desc->pointer, table_desc->length);
+ break;
+ case ACPI_TABLE_ORIGIN_ALLOCATED:
+ ACPI_FREE(table_desc->pointer);
+ break;
+ default:;
+ }
- list_head = &acpi_gbl_table_lists[table_type];
+ table_desc->pointer = NULL;
+}
- /*
- * Two major types of tables: 1) Only one instance is allowed. This
- * includes most ACPI tables such as the DSDT. 2) Multiple instances of
- * the table are allowed. This includes SSDT and PSDTs.
- */
- if (ACPI_IS_SINGLE_TABLE(acpi_gbl_table_data[table_type].flags)) {
- /*
- * Only one table allowed, and a table has alread been installed
- * at this location, so return an error.
- */
- if (list_head->next) {
- status = AE_ALREADY_EXISTS;
- goto error_exit2;
- }
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_terminate
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Delete all internal ACPI tables
+ *
+ ******************************************************************************/
- table_desc->next = list_head->next;
- list_head->next = table_desc;
+void acpi_tb_terminate(void)
+{
+ acpi_native_uint i;
- if (table_desc->next) {
- table_desc->next->prev = table_desc;
- }
+ ACPI_FUNCTION_TRACE(tb_terminate);
- list_head->count++;
- } else {
- /*
- * Link the new table in to the list of tables of this type.
- * Insert at the end of the list, order IS IMPORTANT.
- *
- * table_desc->Prev & Next are already NULL from calloc()
- */
- list_head->count++;
-
- if (!list_head->next) {
- list_head->next = table_desc;
- } else {
- table_desc->next = list_head->next;
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
- while (table_desc->next->next) {
- table_desc->next = table_desc->next->next;
- }
+ /* Delete the individual tables */
- table_desc->next->next = table_desc;
- table_desc->prev = table_desc->next;
- table_desc->next = NULL;
- }
+ for (i = 0; i < acpi_gbl_root_table_list.count; ++i) {
+ acpi_tb_delete_table(&acpi_gbl_root_table_list.tables[i]);
}
- /* Finish initialization of the table descriptor */
-
- table_desc->loaded_into_namespace = FALSE;
- table_desc->type = (u8) table_type;
- table_desc->pointer = table_info->pointer;
- table_desc->length = table_info->length;
- table_desc->allocation = table_info->allocation;
- table_desc->aml_start = (u8 *) (table_desc->pointer + 1),
- table_desc->aml_length = (u32)
- (table_desc->length - (u32) sizeof(struct acpi_table_header));
-
/*
- * Set the appropriate global pointer (if there is one) to point to the
- * newly installed table
+ * Delete the root table array if allocated locally. Array cannot be
+ * mapped, so we don't need to check for that flag.
*/
- if (acpi_gbl_table_data[table_type].global_ptr) {
- *(acpi_gbl_table_data[table_type].global_ptr) =
- table_info->pointer;
+ if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) {
+ ACPI_FREE(acpi_gbl_root_table_list.tables);
}
- /* Return Data */
-
- 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);
+ acpi_gbl_root_table_list.tables = NULL;
+ acpi_gbl_root_table_list.flags = 0;
+ acpi_gbl_root_table_list.count = 0;
- error_exit1:
-
- ACPI_FREE(table_desc);
- return_ACPI_STATUS(status);
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "ACPI Tables freed\n"));
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_delete_all_tables
+ * FUNCTION: acpi_tb_delete_namespace_by_owner
*
- * PARAMETERS: None.
+ * PARAMETERS: table_index - Table index
*
- * RETURN: None.
+ * RETURN: None
*
- * DESCRIPTION: Delete all internal ACPI tables
+ * DESCRIPTION: Delete all namespace objects created when this table was loaded.
*
******************************************************************************/
-void acpi_tb_delete_all_tables(void)
+void acpi_tb_delete_namespace_by_owner(acpi_native_uint table_index)
{
- acpi_table_type type;
+ acpi_owner_id owner_id;
- /*
- * Free memory allocated for ACPI tables
- * Memory can either be mapped or allocated
- */
- for (type = 0; type < (ACPI_TABLE_ID_MAX + 1); type++) {
- acpi_tb_delete_tables_by_type(type);
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+ if (table_index < acpi_gbl_root_table_list.count) {
+ owner_id =
+ acpi_gbl_root_table_list.tables[table_index].owner_id;
+ } else {
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ return;
}
+
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ acpi_ns_delete_namespace_by_owner(owner_id);
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_delete_tables_by_type
+ * FUNCTION: acpi_tb_allocate_owner_id
*
- * PARAMETERS: Type - The table type to be deleted
+ * PARAMETERS: table_index - Table index
*
- * RETURN: None.
+ * RETURN: Status
*
- * DESCRIPTION: Delete an internal ACPI table
- * Locks the ACPI table mutex
+ * DESCRIPTION: Allocates owner_id in table_desc
*
******************************************************************************/
-void acpi_tb_delete_tables_by_type(acpi_table_type type)
+acpi_status acpi_tb_allocate_owner_id(acpi_native_uint table_index)
{
- struct acpi_table_desc *table_desc;
- u32 count;
- u32 i;
+ acpi_status status = AE_BAD_PARAMETER;
- ACPI_FUNCTION_TRACE_U32(tb_delete_tables_by_type, type);
+ ACPI_FUNCTION_TRACE(tb_allocate_owner_id);
- if (type > ACPI_TABLE_ID_MAX) {
- return_VOID;
- }
-
- if (ACPI_FAILURE(acpi_ut_acquire_mutex(ACPI_MTX_TABLES))) {
- return;
- }
-
- /* Clear the appropriate "typed" global table pointer */
-
- switch (type) {
- case ACPI_TABLE_ID_RSDP:
- acpi_gbl_RSDP = NULL;
- break;
-
- case ACPI_TABLE_ID_DSDT:
- acpi_gbl_DSDT = NULL;
- break;
-
- case ACPI_TABLE_ID_FADT:
- acpi_gbl_FADT = NULL;
- break;
-
- case ACPI_TABLE_ID_FACS:
- acpi_gbl_FACS = NULL;
- break;
-
- case ACPI_TABLE_ID_XSDT:
- acpi_gbl_XSDT = NULL;
- break;
-
- case ACPI_TABLE_ID_SSDT:
- case ACPI_TABLE_ID_PSDT:
- default:
- break;
- }
-
- /*
- * Free the table
- * 1) Get the head of the list
- */
- table_desc = acpi_gbl_table_lists[type].next;
- count = acpi_gbl_table_lists[type].count;
-
- /*
- * 2) Walk the entire list, deleting both the allocated tables
- * and the table descriptors
- */
- for (i = 0; i < count; i++) {
- table_desc = acpi_tb_uninstall_table(table_desc);
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+ if (table_index < acpi_gbl_root_table_list.count) {
+ status = acpi_ut_allocate_owner_id
+ (&(acpi_gbl_root_table_list.tables[table_index].owner_id));
}
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
- return_VOID;
+ return_ACPI_STATUS(status);
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_delete_single_table
+ * FUNCTION: acpi_tb_release_owner_id
*
- * PARAMETERS: table_info - A table info struct
+ * PARAMETERS: table_index - Table index
*
- * RETURN: None.
+ * RETURN: Status
*
- * DESCRIPTION: Low-level free for a single ACPI table. Handles cases where
- * the table was allocated a buffer or was mapped.
+ * DESCRIPTION: Releases owner_id in table_desc
*
******************************************************************************/
-void acpi_tb_delete_single_table(struct acpi_table_desc *table_desc)
+acpi_status acpi_tb_release_owner_id(acpi_native_uint table_index)
{
+ acpi_status status = AE_BAD_PARAMETER;
- /* Must have a valid table descriptor and pointer */
+ ACPI_FUNCTION_TRACE(tb_release_owner_id);
- if ((!table_desc) || (!table_desc->pointer)) {
- return;
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+ if (table_index < acpi_gbl_root_table_list.count) {
+ acpi_ut_release_owner_id(&
+ (acpi_gbl_root_table_list.
+ tables[table_index].owner_id));
+ status = AE_OK;
}
- /* Valid table, determine type of memory allocation */
-
- switch (table_desc->allocation) {
- case ACPI_MEM_NOT_ALLOCATED:
- break;
-
- case ACPI_MEM_ALLOCATED:
-
- ACPI_FREE(table_desc->pointer);
- break;
-
- case ACPI_MEM_MAPPED:
-
- acpi_os_unmap_memory(table_desc->pointer, table_desc->length);
- break;
-
- default:
- break;
- }
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ return_ACPI_STATUS(status);
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_uninstall_table
+ * FUNCTION: acpi_tb_get_owner_id
*
- * PARAMETERS: table_info - A table info struct
+ * PARAMETERS: table_index - Table index
+ * owner_id - Where the table owner_id is returned
*
- * RETURN: Pointer to the next table in the list (of same type)
+ * RETURN: Status
*
- * DESCRIPTION: Free the memory associated with an internal ACPI table that
- * is either installed or has never been installed.
- * Table mutex should be locked.
+ * DESCRIPTION: returns owner_id for the ACPI table
*
******************************************************************************/
-struct acpi_table_desc *acpi_tb_uninstall_table(struct acpi_table_desc
- *table_desc)
+acpi_status
+acpi_tb_get_owner_id(acpi_native_uint table_index, acpi_owner_id * owner_id)
{
- struct acpi_table_desc *next_desc;
+ acpi_status status = AE_BAD_PARAMETER;
- ACPI_FUNCTION_TRACE_PTR(tb_uninstall_table, table_desc);
+ ACPI_FUNCTION_TRACE(tb_get_owner_id);
- if (!table_desc) {
- return_PTR(NULL);
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+ if (table_index < acpi_gbl_root_table_list.count) {
+ *owner_id =
+ acpi_gbl_root_table_list.tables[table_index].owner_id;
+ status = AE_OK;
}
- /* Unlink the descriptor from the doubly linked list */
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ return_ACPI_STATUS(status);
+}
- if (table_desc->prev) {
- table_desc->prev->next = table_desc->next;
- } else {
- /* Is first on list, update list head */
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_is_table_loaded
+ *
+ * PARAMETERS: table_index - Table index
+ *
+ * RETURN: Table Loaded Flag
+ *
+ ******************************************************************************/
- acpi_gbl_table_lists[table_desc->type].next = table_desc->next;
- }
+u8 acpi_tb_is_table_loaded(acpi_native_uint table_index)
+{
+ u8 is_loaded = FALSE;
- if (table_desc->next) {
- table_desc->next->prev = table_desc->prev;
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+ if (table_index < acpi_gbl_root_table_list.count) {
+ is_loaded = (u8)
+ (acpi_gbl_root_table_list.tables[table_index].
+ flags & ACPI_TABLE_IS_LOADED);
}
- /* Free the memory allocated for the table itself */
-
- acpi_tb_delete_single_table(table_desc);
-
- /* Free the owner ID associated with this table */
-
- acpi_ut_release_owner_id(&table_desc->owner_id);
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ return (is_loaded);
+}
- /* Free the table descriptor */
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_set_table_loaded_flag
+ *
+ * PARAMETERS: table_index - Table index
+ * is_loaded - TRUE if table is loaded, FALSE otherwise
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Sets the table loaded flag to either TRUE or FALSE.
+ *
+ ******************************************************************************/
- next_desc = table_desc->next;
- ACPI_FREE(table_desc);
+void acpi_tb_set_table_loaded_flag(acpi_native_uint table_index, u8 is_loaded)
+{
- /* Return pointer to the next descriptor */
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+ if (table_index < acpi_gbl_root_table_list.count) {
+ if (is_loaded) {
+ acpi_gbl_root_table_list.tables[table_index].flags |=
+ ACPI_TABLE_IS_LOADED;
+ } else {
+ acpi_gbl_root_table_list.tables[table_index].flags &=
+ ~ACPI_TABLE_IS_LOADED;
+ }
+ }
- return_PTR(next_desc);
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
}
diff --git a/drivers/acpi/tables/tbrsdt.c b/drivers/acpi/tables/tbrsdt.c
deleted file mode 100644
index 86a5fca9b73..00000000000
--- a/drivers/acpi/tables/tbrsdt.c
+++ /dev/null
@@ -1,307 +0,0 @@
-/******************************************************************************
- *
- * Module Name: tbrsdt - ACPI RSDT table utilities
- *
- *****************************************************************************/
-
-/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- * substantially similar to the "NO WARRANTY" disclaimer below
- * ("Disclaimer") and any redistribution must be conditioned upon
- * including a substantially similar Disclaimer requirement for further
- * binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- * of any contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * NO WARRANTY
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- */
-
-#include <acpi/acpi.h>
-#include <acpi/actables.h>
-
-#define _COMPONENT ACPI_TABLES
-ACPI_MODULE_NAME("tbrsdt")
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_verify_rsdp
- *
- * PARAMETERS: Address - RSDP (Pointer to RSDT)
- *
- * RETURN: Status
- *
- * DESCRIPTION: Load and validate the RSDP (ptr) and RSDT (table)
- *
- ******************************************************************************/
-acpi_status acpi_tb_verify_rsdp(struct acpi_pointer *address)
-{
- struct acpi_table_desc table_info;
- acpi_status status;
- struct rsdp_descriptor *rsdp;
-
- ACPI_FUNCTION_TRACE(tb_verify_rsdp);
-
- switch (address->pointer_type) {
- case ACPI_LOGICAL_POINTER:
-
- rsdp = address->pointer.logical;
- break;
-
- case ACPI_PHYSICAL_POINTER:
- /*
- * Obtain access to the RSDP structure
- */
- status = acpi_os_map_memory(address->pointer.physical,
- sizeof(struct rsdp_descriptor),
- ACPI_CAST_PTR(void, &rsdp));
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
- break;
-
- default:
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- /* Verify RSDP signature and checksum */
-
- status = acpi_tb_validate_rsdp(rsdp);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
- }
-
- /* RSDP is ok. Init the table info */
-
- table_info.pointer = ACPI_CAST_PTR(struct acpi_table_header, rsdp);
- table_info.length = sizeof(struct rsdp_descriptor);
-
- if (address->pointer_type == ACPI_PHYSICAL_POINTER) {
- table_info.allocation = ACPI_MEM_MAPPED;
- } else {
- table_info.allocation = ACPI_MEM_NOT_ALLOCATED;
- }
-
- /* Save the table pointers and allocation info */
-
- status = acpi_tb_init_table_descriptor(ACPI_TABLE_ID_RSDP, &table_info);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
- }
-
- /* Save the RSDP in a global for easy access */
-
- acpi_gbl_RSDP =
- ACPI_CAST_PTR(struct rsdp_descriptor, table_info.pointer);
- return_ACPI_STATUS(status);
-
- /* Error exit */
- cleanup:
-
- if (acpi_gbl_table_flags & ACPI_PHYSICAL_POINTER) {
- acpi_os_unmap_memory(rsdp, sizeof(struct rsdp_descriptor));
- }
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_get_rsdt_address
- *
- * PARAMETERS: out_address - Where the address is returned
- *
- * RETURN: None, Address
- *
- * DESCRIPTION: Extract the address of either the RSDT or XSDT, depending on the
- * version of the RSDP and whether the XSDT pointer is valid
- *
- ******************************************************************************/
-
-void acpi_tb_get_rsdt_address(struct acpi_pointer *out_address)
-{
-
- ACPI_FUNCTION_ENTRY();
-
- out_address->pointer_type =
- acpi_gbl_table_flags | ACPI_LOGICAL_ADDRESSING;
-
- /* Use XSDT if it is present */
-
- if ((acpi_gbl_RSDP->revision >= 2) &&
- acpi_gbl_RSDP->xsdt_physical_address) {
- out_address->pointer.value =
- acpi_gbl_RSDP->xsdt_physical_address;
- acpi_gbl_root_table_type = ACPI_TABLE_TYPE_XSDT;
- } else {
- /* No XSDT, use the RSDT */
-
- out_address->pointer.value =
- acpi_gbl_RSDP->rsdt_physical_address;
- acpi_gbl_root_table_type = ACPI_TABLE_TYPE_RSDT;
- }
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_validate_rsdt
- *
- * PARAMETERS: table_ptr - Addressable pointer to the RSDT.
- *
- * RETURN: Status
- *
- * DESCRIPTION: Validate signature for the RSDT or XSDT
- *
- ******************************************************************************/
-
-acpi_status acpi_tb_validate_rsdt(struct acpi_table_header *table_ptr)
-{
- char *signature;
-
- 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 (%zX)",
- 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) {
- signature = RSDT_SIG;
- } else {
- signature = XSDT_SIG;
- }
-
- if (!ACPI_COMPARE_NAME(table_ptr->signature, signature)) {
-
- /* Invalid RSDT or XSDT signature */
-
- ACPI_ERROR((AE_INFO,
- "Invalid signature where RSDP indicates RSDT/XSDT should be located. RSDP:"));
-
- ACPI_DUMP_BUFFER(acpi_gbl_RSDP, 20);
-
- ACPI_ERROR((AE_INFO,
- "RSDT/XSDT signature at %X is invalid",
- acpi_gbl_RSDP->rsdt_physical_address));
-
- if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) {
- ACPI_ERROR((AE_INFO, "Looking for RSDT"));
- } else {
- ACPI_ERROR((AE_INFO, "Looking for XSDT"));
- }
-
- ACPI_DUMP_BUFFER(ACPI_CAST_PTR(char, table_ptr), 48);
- return (AE_BAD_SIGNATURE);
- }
-
- return (AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_get_table_rsdt
- *
- * PARAMETERS: None
- *
- * RETURN: Status
- *
- * DESCRIPTION: Load and validate the RSDP (ptr) and RSDT (table)
- *
- ******************************************************************************/
-
-acpi_status acpi_tb_get_table_rsdt(void)
-{
- struct acpi_table_desc table_info;
- acpi_status status;
- struct acpi_pointer address;
-
- ACPI_FUNCTION_TRACE(tb_get_table_rsdt);
-
- /* Get the RSDT/XSDT via the RSDP */
-
- acpi_tb_get_rsdt_address(&address);
-
- table_info.type = ACPI_TABLE_ID_XSDT;
- status = acpi_tb_get_table(&address, &table_info);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Could not get the RSDT/XSDT"));
- return_ACPI_STATUS(status);
- }
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "RSDP located at %p, points to RSDT physical=%8.8X%8.8X\n",
- acpi_gbl_RSDP,
- ACPI_FORMAT_UINT64(address.pointer.value)));
-
- /* Check the RSDT or XSDT signature */
-
- status = acpi_tb_validate_rsdt(table_info.pointer);
- if (ACPI_FAILURE(status)) {
- goto error_cleanup;
- }
-
- /* Get the number of tables defined in the RSDT or XSDT */
-
- acpi_gbl_rsdt_table_count = acpi_tb_get_table_count(acpi_gbl_RSDP,
- table_info.pointer);
-
- /* Convert and/or copy to an XSDT structure */
-
- status = acpi_tb_convert_to_xsdt(&table_info);
- if (ACPI_FAILURE(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)) {
- goto error_cleanup;
- }
-
- acpi_gbl_XSDT =
- ACPI_CAST_PTR(struct xsdt_descriptor, table_info.pointer);
-
- 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/tbutils.c b/drivers/acpi/tables/tbutils.c
index 209a401801e..1da64b4518c 100644
--- a/drivers/acpi/tables/tbutils.c
+++ b/drivers/acpi/tables/tbutils.c
@@ -1,11 +1,11 @@
/******************************************************************************
*
- * Module Name: tbutils - Table manipulation utilities
+ * Module Name: tbutils - table utilities
*
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -48,137 +48,119 @@
ACPI_MODULE_NAME("tbutils")
/* Local prototypes */
-#ifdef ACPI_OBSOLETE_FUNCTIONS
-acpi_status
-acpi_tb_handle_to_object(u16 table_id, struct acpi_table_desc **table_desc);
-#endif
+static acpi_physical_address
+acpi_tb_get_root_table_entry(u8 * table_entry,
+ acpi_native_uint table_entry_size);
/*******************************************************************************
*
- * FUNCTION: acpi_tb_is_table_installed
- *
- * PARAMETERS: new_table_desc - Descriptor for new table being installed
+ * FUNCTION: acpi_tb_tables_loaded
*
- * RETURN: Status - AE_ALREADY_EXISTS if the table is already installed
+ * PARAMETERS: None
*
- * DESCRIPTION: Determine if an ACPI table is already installed
+ * RETURN: TRUE if required ACPI tables are loaded
*
- * MUTEX: Table data structures should be locked
+ * DESCRIPTION: Determine if the minimum required ACPI tables are present
+ * (FADT, FACS, DSDT)
*
******************************************************************************/
-acpi_status acpi_tb_is_table_installed(struct acpi_table_desc *new_table_desc)
+u8 acpi_tb_tables_loaded(void)
{
- struct acpi_table_desc *table_desc;
-
- ACPI_FUNCTION_TRACE(tb_is_table_installed);
- /* Get the list descriptor and first table descriptor */
-
- table_desc = acpi_gbl_table_lists[new_table_desc->type].next;
+ if (acpi_gbl_root_table_list.count >= 3) {
+ return (TRUE);
+ }
- /* Examine all installed tables of this type */
+ return (FALSE);
+}
- while (table_desc) {
- /*
- * If the table lengths match, perform a full bytewise compare. This
- * means that we will allow tables with duplicate oem_table_id(s), as
- * long as the tables are different in some way.
- *
- * Checking if the table has been loaded into the namespace means that
- * we don't check for duplicate tables during the initial installation
- * of tables within the RSDT/XSDT.
- */
- if ((table_desc->loaded_into_namespace) &&
- (table_desc->pointer->length ==
- new_table_desc->pointer->length)
- &&
- (!ACPI_MEMCMP
- (table_desc->pointer, new_table_desc->pointer,
- new_table_desc->pointer->length))) {
-
- /* Match: this table is already installed */
-
- ACPI_DEBUG_PRINT((ACPI_DB_TABLES,
- "Table [%4.4s] already installed: Rev %X OemTableId [%8.8s]\n",
- new_table_desc->pointer->signature,
- new_table_desc->pointer->revision,
- new_table_desc->pointer->
- oem_table_id));
-
- new_table_desc->owner_id = table_desc->owner_id;
- new_table_desc->installed_desc = table_desc;
-
- return_ACPI_STATUS(AE_ALREADY_EXISTS);
- }
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_print_table_header
+ *
+ * PARAMETERS: Address - Table physical address
+ * Header - Table header
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Print an ACPI table header. Special cases for FACS and RSDP.
+ *
+ ******************************************************************************/
- /* Get next table on the list */
+void
+acpi_tb_print_table_header(acpi_physical_address address,
+ struct acpi_table_header *header)
+{
- table_desc = table_desc->next;
+ if (ACPI_COMPARE_NAME(header->signature, ACPI_SIG_FACS)) {
+
+ /* FACS only has signature and length fields of common table header */
+
+ ACPI_INFO((AE_INFO, "%4.4s %08lX, %04X",
+ header->signature, (unsigned long)address,
+ header->length));
+ } else if (ACPI_COMPARE_NAME(header->signature, ACPI_SIG_RSDP)) {
+
+ /* RSDP has no common fields */
+
+ ACPI_INFO((AE_INFO, "RSDP %08lX, %04X (r%d %6.6s)",
+ (unsigned long)address,
+ (ACPI_CAST_PTR(struct acpi_table_rsdp, header)->
+ revision >
+ 0) ? ACPI_CAST_PTR(struct acpi_table_rsdp,
+ header)->length : 20,
+ ACPI_CAST_PTR(struct acpi_table_rsdp,
+ header)->revision,
+ ACPI_CAST_PTR(struct acpi_table_rsdp,
+ header)->oem_id));
+ } else {
+ /* Standard ACPI table with full common header */
+
+ ACPI_INFO((AE_INFO,
+ "%4.4s %08lX, %04X (r%d %6.6s %8.8s %8X %4.4s %8X)",
+ header->signature, (unsigned long)address,
+ header->length, header->revision, header->oem_id,
+ header->oem_table_id, header->oem_revision,
+ header->asl_compiler_id,
+ header->asl_compiler_revision));
}
-
- return_ACPI_STATUS(AE_OK);
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_validate_table_header
+ * FUNCTION: acpi_tb_validate_checksum
*
- * PARAMETERS: table_header - Logical pointer to the table
+ * PARAMETERS: Table - ACPI table to verify
+ * Length - Length of entire table
*
* RETURN: Status
*
- * DESCRIPTION: Check an ACPI table header for validity
- *
- * NOTE: Table pointers are validated as follows:
- * 1) Table pointer must point to valid physical memory
- * 2) Signature must be 4 ASCII chars, even if we don't recognize the
- * name
- * 3) Table must be readable for length specified in the header
- * 4) Table checksum must be valid (with the exception of the FACS
- * which has no checksum because it contains variable fields)
+ * DESCRIPTION: Verifies that the table checksums to zero. Optionally returns
+ * exception on bad checksum.
*
******************************************************************************/
-acpi_status
-acpi_tb_validate_table_header(struct acpi_table_header *table_header)
+acpi_status acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length)
{
- acpi_name signature;
-
- ACPI_FUNCTION_ENTRY();
-
- /* Verify that this is a valid address */
-
- if (!acpi_os_readable(table_header, sizeof(struct acpi_table_header))) {
- ACPI_ERROR((AE_INFO,
- "Cannot read table header at %p", table_header));
-
- return (AE_BAD_ADDRESS);
- }
+ u8 checksum;
- /* Ensure that the signature is 4 ASCII characters */
+ /* Compute the checksum on the table */
- ACPI_MOVE_32_TO_32(&signature, table_header->signature);
- if (!acpi_ut_valid_acpi_name(signature)) {
- ACPI_ERROR((AE_INFO, "Invalid table signature 0x%8.8X",
- signature));
+ checksum = acpi_tb_checksum(ACPI_CAST_PTR(u8, table), length);
- ACPI_DUMP_BUFFER(table_header,
- sizeof(struct acpi_table_header));
- return (AE_BAD_SIGNATURE);
- }
+ /* Checksum ok? (should be zero) */
- /* Validate the table length */
+ if (checksum) {
+ ACPI_WARNING((AE_INFO,
+ "Incorrect checksum in table [%4.4s] - %2.2X, should be %2.2X",
+ table->signature, table->checksum,
+ (u8) (table->checksum - checksum)));
- if (table_header->length < sizeof(struct acpi_table_header)) {
- ACPI_ERROR((AE_INFO,
- "Invalid length 0x%X in table with signature %4.4s",
- (u32) table_header->length,
- ACPI_CAST_PTR(char, &signature)));
+#if (ACPI_CHECKSUM_ABORT)
- ACPI_DUMP_BUFFER(table_header,
- sizeof(struct acpi_table_header));
- return (AE_BAD_HEADER);
+ return (AE_BAD_CHECKSUM);
+#endif
}
return (AE_OK);
@@ -186,157 +168,320 @@ acpi_tb_validate_table_header(struct acpi_table_header *table_header)
/*******************************************************************************
*
- * FUNCTION: acpi_tb_sum_table
+ * FUNCTION: acpi_tb_checksum
*
- * PARAMETERS: Buffer - Buffer to sum
- * Length - Size of the buffer
+ * PARAMETERS: Buffer - Pointer to memory region to be checked
+ * Length - Length of this memory region
*
- * RETURN: 8 bit sum of buffer
+ * RETURN: Checksum (u8)
*
- * DESCRIPTION: Computes an 8 bit sum of the buffer(length) and returns it.
+ * DESCRIPTION: Calculates circular checksum of memory region.
*
******************************************************************************/
-u8 acpi_tb_sum_table(void *buffer, u32 length)
+u8 acpi_tb_checksum(u8 * buffer, acpi_native_uint length)
{
- acpi_native_uint i;
u8 sum = 0;
+ u8 *end = buffer + length;
- if (!buffer || !length) {
- return (0);
+ while (buffer < end) {
+ sum = (u8) (sum + *(buffer++));
}
- for (i = 0; i < length; i++) {
- sum = (u8) (sum + ((u8 *) buffer)[i]);
- }
- return (sum);
+ return sum;
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_generate_checksum
+ * FUNCTION: acpi_tb_install_table
*
- * PARAMETERS: Table - Pointer to a valid ACPI table (with a
- * standard ACPI header)
+ * PARAMETERS: Address - Physical address of DSDT or FACS
+ * Flags - Flags
+ * Signature - Table signature, NULL if no need to
+ * match
+ * table_index - Index into root table array
*
- * RETURN: 8 bit checksum of buffer
+ * RETURN: None
*
- * DESCRIPTION: Computes an 8 bit checksum of the table.
+ * DESCRIPTION: Install an ACPI table into the global data structure.
*
******************************************************************************/
-u8 acpi_tb_generate_checksum(struct acpi_table_header * table)
+void
+acpi_tb_install_table(acpi_physical_address address,
+ u8 flags, char *signature, acpi_native_uint table_index)
{
- u8 checksum;
+ struct acpi_table_header *table;
+
+ if (!address) {
+ ACPI_ERROR((AE_INFO,
+ "Null physical address for ACPI table [%s]",
+ signature));
+ return;
+ }
+
+ /* Map just the table header */
+
+ table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
+ if (!table) {
+ return;
+ }
+
+ /* If a particular signature is expected, signature must match */
+
+ if (signature && !ACPI_COMPARE_NAME(table->signature, signature)) {
+ ACPI_ERROR((AE_INFO,
+ "Invalid signature 0x%X for ACPI table [%s]",
+ *ACPI_CAST_PTR(u32, table->signature), signature));
+ goto unmap_and_exit;
+ }
- /* Sum the entire table as-is */
+ /* Initialize the table entry */
- checksum = acpi_tb_sum_table(table, table->length);
+ acpi_gbl_root_table_list.tables[table_index].address = address;
+ acpi_gbl_root_table_list.tables[table_index].length = table->length;
+ acpi_gbl_root_table_list.tables[table_index].flags = flags;
- /* Subtract off the existing checksum value in the table */
+ ACPI_MOVE_32_TO_32(&
+ (acpi_gbl_root_table_list.tables[table_index].
+ signature), table->signature);
- checksum = (u8) (checksum - table->checksum);
+ acpi_tb_print_table_header(address, table);
- /* Compute the final checksum */
+ if (table_index == ACPI_TABLE_INDEX_DSDT) {
- checksum = (u8) (0 - checksum);
- return (checksum);
+ /* Global integer width is based upon revision of the DSDT */
+
+ acpi_ut_set_integer_width(table->revision);
+ }
+
+ unmap_and_exit:
+ acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_set_checksum
+ * FUNCTION: acpi_tb_get_root_table_entry
*
- * PARAMETERS: Table - Pointer to a valid ACPI table (with a
- * standard ACPI header)
+ * PARAMETERS: table_entry - Pointer to the RSDT/XSDT table entry
+ * table_entry_size - sizeof 32 or 64 (RSDT or XSDT)
*
- * RETURN: None. Sets the table checksum field
+ * RETURN: Physical address extracted from the root table
*
- * DESCRIPTION: Computes an 8 bit checksum of the table and inserts the
- * checksum into the table header.
+ * DESCRIPTION: Get one root table entry. Handles 32-bit and 64-bit cases on
+ * both 32-bit and 64-bit platforms
+ *
+ * NOTE: acpi_physical_address is 32-bit on 32-bit platforms, 64-bit on
+ * 64-bit platforms.
*
******************************************************************************/
-void acpi_tb_set_checksum(struct acpi_table_header *table)
+static acpi_physical_address
+acpi_tb_get_root_table_entry(u8 * table_entry,
+ acpi_native_uint table_entry_size)
{
+ u64 address64;
+
+ /*
+ * Get the table physical address (32-bit for RSDT, 64-bit for XSDT):
+ * Note: Addresses are 32-bit aligned (not 64) in both RSDT and XSDT
+ */
+ if (table_entry_size == sizeof(u32)) {
+ /*
+ * 32-bit platform, RSDT: Return 32-bit table entry
+ * 64-bit platform, RSDT: Expand 32-bit to 64-bit and return
+ */
+ return ((acpi_physical_address)
+ (*ACPI_CAST_PTR(u32, table_entry)));
+ } else {
+ /*
+ * 32-bit platform, XSDT: Truncate 64-bit to 32-bit and return
+ * 64-bit platform, XSDT: Move (unaligned) 64-bit to local, return 64-bit
+ */
+ ACPI_MOVE_64_TO_64(&address64, table_entry);
- table->checksum = acpi_tb_generate_checksum(table);
+#if ACPI_MACHINE_WIDTH == 32
+ if (address64 > ACPI_UINT32_MAX) {
+
+ /* Will truncate 64-bit address to 32 bits, issue warning */
+
+ ACPI_WARNING((AE_INFO,
+ "64-bit Physical Address in XSDT is too large (%8.8X%8.8X), truncating",
+ ACPI_FORMAT_UINT64(address64)));
+ }
+#endif
+ return ((acpi_physical_address) (address64));
+ }
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_verify_table_checksum
+ * FUNCTION: acpi_tb_parse_root_table
+ *
+ * PARAMETERS: Rsdp - Pointer to the RSDP
+ * Flags - Flags
*
- * PARAMETERS: *table_header - ACPI table to verify
+ * RETURN: Status
*
- * RETURN: 8 bit checksum of table
+ * DESCRIPTION: This function is called to parse the Root System Description
+ * Table (RSDT or XSDT)
*
- * DESCRIPTION: Generates an 8 bit checksum of table and returns and compares
- * it to the existing checksum value.
+ * NOTE: Tables are mapped (not copied) for efficiency. The FACS must
+ * be mapped and cannot be copied because it contains the actual
+ * memory location of the ACPI Global Lock.
*
******************************************************************************/
-acpi_status
-acpi_tb_verify_table_checksum(struct acpi_table_header *table_header)
+acpi_status __init
+acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags)
{
- u8 checksum;
+ struct acpi_table_rsdp *rsdp;
+ acpi_native_uint table_entry_size;
+ acpi_native_uint i;
+ u32 table_count;
+ struct acpi_table_header *table;
+ acpi_physical_address address;
+ u32 length;
+ u8 *table_entry;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(tb_parse_root_table);
+
+ /*
+ * Map the entire RSDP and extract the address of the RSDT or XSDT
+ */
+ rsdp = acpi_os_map_memory(rsdp_address, sizeof(struct acpi_table_rsdp));
+ if (!rsdp) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
- ACPI_FUNCTION_TRACE(tb_verify_table_checksum);
+ acpi_tb_print_table_header(rsdp_address,
+ ACPI_CAST_PTR(struct acpi_table_header,
+ rsdp));
- /* Compute the checksum on the table */
+ /* Differentiate between RSDT and XSDT root tables */
- checksum = acpi_tb_generate_checksum(table_header);
+ if (rsdp->revision > 1 && rsdp->xsdt_physical_address) {
+ /*
+ * Root table is an XSDT (64-bit physical addresses). We must use the
+ * XSDT if the revision is > 1 and the XSDT pointer is present, as per
+ * the ACPI specification.
+ */
+ address = (acpi_physical_address) rsdp->xsdt_physical_address;
+ table_entry_size = sizeof(u64);
+ } else {
+ /* Root table is an RSDT (32-bit physical addresses) */
- /* Checksum ok? */
+ address = (acpi_physical_address) rsdp->rsdt_physical_address;
+ table_entry_size = sizeof(u32);
+ }
- if (checksum == table_header->checksum) {
- return_ACPI_STATUS(AE_OK);
+ /*
+ * It is not possible to map more than one entry in some environments,
+ * so unmap the RSDP here before mapping other tables
+ */
+ acpi_os_unmap_memory(rsdp, sizeof(struct acpi_table_rsdp));
+
+ /* Map the RSDT/XSDT table header to get the full table length */
+
+ table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
+ if (!table) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
}
- ACPI_WARNING((AE_INFO,
- "Incorrect checksum in table [%4.4s] - is %2.2X, should be %2.2X",
- table_header->signature, table_header->checksum,
- checksum));
+ acpi_tb_print_table_header(address, table);
- return_ACPI_STATUS(AE_BAD_CHECKSUM);
-}
+ /* Get the length of the full table, verify length and map entire table */
-#ifdef ACPI_OBSOLETE_FUNCTIONS
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_handle_to_object
- *
- * PARAMETERS: table_id - Id for which the function is searching
- * table_desc - Pointer to return the matching table
- * descriptor.
- *
- * RETURN: Search the tables to find one with a matching table_id and
- * return a pointer to that table descriptor.
- *
- ******************************************************************************/
+ length = table->length;
+ acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
-acpi_status
-acpi_tb_handle_to_object(u16 table_id,
- struct acpi_table_desc **return_table_desc)
-{
- u32 i;
- struct acpi_table_desc *table_desc;
+ if (length < sizeof(struct acpi_table_header)) {
+ ACPI_ERROR((AE_INFO, "Invalid length 0x%X in RSDT/XSDT",
+ length));
+ return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
+ }
- ACPI_FUNCTION_NAME(tb_handle_to_object);
+ table = acpi_os_map_memory(address, length);
+ if (!table) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ /* Validate the root table checksum */
+
+ status = acpi_tb_verify_checksum(table, length);
+ if (ACPI_FAILURE(status)) {
+ acpi_os_unmap_memory(table, length);
+ return_ACPI_STATUS(status);
+ }
- for (i = 0; i < ACPI_TABLE_MAX; i++) {
- table_desc = acpi_gbl_table_lists[i].next;
- while (table_desc) {
- if (table_desc->table_id == table_id) {
- *return_table_desc = table_desc;
- return (AE_OK);
+ /* Calculate the number of tables described in the root table */
+
+ table_count =
+ (u32) ((table->length -
+ sizeof(struct acpi_table_header)) / table_entry_size);
+
+ /*
+ * First two entries in the table array are reserved for the DSDT and FACS,
+ * which are not actually present in the RSDT/XSDT - they come from the FADT
+ */
+ table_entry =
+ ACPI_CAST_PTR(u8, table) + sizeof(struct acpi_table_header);
+ acpi_gbl_root_table_list.count = 2;
+
+ /*
+ * Initialize the root table array from the RSDT/XSDT
+ */
+ for (i = 0; i < table_count; i++) {
+ if (acpi_gbl_root_table_list.count >=
+ acpi_gbl_root_table_list.size) {
+
+ /* There is no more room in the root table array, attempt resize */
+
+ status = acpi_tb_resize_root_table_list();
+ if (ACPI_FAILURE(status)) {
+ ACPI_WARNING((AE_INFO,
+ "Truncating %u table entries!",
+ (unsigned)
+ (acpi_gbl_root_table_list.size -
+ acpi_gbl_root_table_list.
+ count)));
+ break;
}
+ }
+
+ /* Get the table physical address (32-bit for RSDT, 64-bit for XSDT) */
- table_desc = table_desc->next;
+ acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].
+ address =
+ acpi_tb_get_root_table_entry(table_entry, table_entry_size);
+
+ table_entry += table_entry_size;
+ acpi_gbl_root_table_list.count++;
+ }
+
+ /*
+ * It is not possible to map more than one entry in some environments,
+ * so unmap the root table here before mapping other tables
+ */
+ acpi_os_unmap_memory(table, length);
+
+ /*
+ * Complete the initialization of the root table array by examining
+ * the header of each table
+ */
+ for (i = 2; i < acpi_gbl_root_table_list.count; i++) {
+ acpi_tb_install_table(acpi_gbl_root_table_list.tables[i].
+ address, flags, NULL, i);
+
+ /* Special case for FADT - get the DSDT and FACS */
+
+ if (ACPI_COMPARE_NAME
+ (&acpi_gbl_root_table_list.tables[i].signature,
+ ACPI_SIG_FADT)) {
+ acpi_tb_parse_fadt(i, flags);
}
}
- ACPI_ERROR((AE_INFO, "TableId=%X does not exist", table_id));
- return (AE_BAD_PARAMETER);
+ return_ACPI_STATUS(AE_OK);
}
-#endif
diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c
index 5ba9303293a..807978d5381 100644
--- a/drivers/acpi/tables/tbxface.c
+++ b/drivers/acpi/tables/tbxface.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -49,80 +49,158 @@
#define _COMPONENT ACPI_TABLES
ACPI_MODULE_NAME("tbxface")
+/* Local prototypes */
+static acpi_status acpi_tb_load_namespace(void);
+
/*******************************************************************************
*
- * FUNCTION: acpi_load_tables
+ * FUNCTION: acpi_allocate_root_table
*
- * PARAMETERS: None
+ * PARAMETERS: initial_table_count - Size of initial_table_array, in number of
+ * struct acpi_table_desc structures
*
* RETURN: Status
*
- * DESCRIPTION: This function is called to load the ACPI tables from the
- * provided RSDT
+ * DESCRIPTION: Allocate a root table array. Used by i_aSL compiler and
+ * acpi_initialize_tables.
*
******************************************************************************/
-acpi_status acpi_load_tables(void)
+
+acpi_status acpi_allocate_root_table(u32 initial_table_count)
{
- struct acpi_pointer rsdp_address;
- acpi_status status;
- ACPI_FUNCTION_TRACE(acpi_load_tables);
+ acpi_gbl_root_table_list.size = initial_table_count;
+ acpi_gbl_root_table_list.flags = ACPI_ROOT_ALLOW_RESIZE;
- /* Get the RSDP */
+ return (acpi_tb_resize_root_table_list());
+}
- status = acpi_os_get_root_pointer(ACPI_LOGICAL_ADDRESSING,
- &rsdp_address);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "Could not get the RSDP"));
- goto error_exit;
- }
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_initialize_tables
+ *
+ * PARAMETERS: initial_table_array - Pointer to an array of pre-allocated
+ * struct acpi_table_desc structures. If NULL, the
+ * array is dynamically allocated.
+ * initial_table_count - Size of initial_table_array, in number of
+ * struct acpi_table_desc structures
+ * allow_realloc - Flag to tell Table Manager if resize of
+ * pre-allocated array is allowed. Ignored
+ * if initial_table_array is NULL.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Initialize the table manager, get the RSDP and RSDT/XSDT.
+ *
+ * NOTE: Allows static allocation of the initial table array in order
+ * to avoid the use of dynamic memory in confined environments
+ * such as the kernel boot sequence where it may not be available.
+ *
+ * If the host OS memory managers are initialized, use NULL for
+ * initial_table_array, and the table will be dynamically allocated.
+ *
+ ******************************************************************************/
- /* Map and validate the RSDP */
+acpi_status __init
+acpi_initialize_tables(struct acpi_table_desc * initial_table_array,
+ u32 initial_table_count, u8 allow_resize)
+{
+ acpi_physical_address rsdp_address;
+ acpi_status status;
- acpi_gbl_table_flags = rsdp_address.pointer_type;
+ ACPI_FUNCTION_TRACE(acpi_initialize_tables);
- status = acpi_tb_verify_rsdp(&rsdp_address);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "During RSDP validation"));
- goto error_exit;
+ /*
+ * Set up the Root Table Array
+ * Allocate the table array if requested
+ */
+ if (!initial_table_array) {
+ status = acpi_allocate_root_table(initial_table_count);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+ } else {
+ /* Root Table Array has been statically allocated by the host */
+
+ ACPI_MEMSET(initial_table_array, 0,
+ initial_table_count *
+ sizeof(struct acpi_table_desc));
+
+ acpi_gbl_root_table_list.tables = initial_table_array;
+ acpi_gbl_root_table_list.size = initial_table_count;
+ acpi_gbl_root_table_list.flags = ACPI_ROOT_ORIGIN_UNKNOWN;
+ if (allow_resize) {
+ acpi_gbl_root_table_list.flags |=
+ ACPI_ROOT_ALLOW_RESIZE;
+ }
}
- /* Get the RSDT via the RSDP */
+ /* Get the address of the RSDP */
- status = acpi_tb_get_table_rsdt();
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "Could not load RSDT"));
- goto error_exit;
+ rsdp_address = acpi_os_get_root_pointer();
+ if (!rsdp_address) {
+ return_ACPI_STATUS(AE_NOT_FOUND);
}
- /* Now get the tables needed by this subsystem (FADT, DSDT, etc.) */
+ /*
+ * Get the root table (RSDT or XSDT) and extract all entries to the local
+ * Root Table Array. This array contains the information of the RSDT/XSDT
+ * in a common, more useable format.
+ */
+ status =
+ acpi_tb_parse_root_table(rsdp_address, ACPI_TABLE_ORIGIN_MAPPED);
+ return_ACPI_STATUS(status);
+}
- status = acpi_tb_get_required_tables();
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Could not get all required tables (DSDT/FADT/FACS)"));
- goto error_exit;
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_reallocate_root_table
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Reallocate Root Table List into dynamic memory. Copies the
+ * root list from the previously provided scratch area. Should
+ * be called once dynamic memory allocation is available in the
+ * kernel
+ *
+ ******************************************************************************/
+acpi_status acpi_reallocate_root_table(void)
+{
+ struct acpi_table_desc *tables;
+ acpi_size new_size;
+
+ ACPI_FUNCTION_TRACE(acpi_reallocate_root_table);
+
+ /*
+ * Only reallocate the root table if the host provided a static buffer
+ * for the table array in the call to acpi_initialize_tables.
+ */
+ if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) {
+ return_ACPI_STATUS(AE_SUPPORT);
}
- ACPI_DEBUG_PRINT((ACPI_DB_INIT, "ACPI Tables successfully acquired\n"));
+ new_size =
+ (acpi_gbl_root_table_list.count +
+ ACPI_ROOT_TABLE_SIZE_INCREMENT) * sizeof(struct acpi_table_desc);
- /* Load the namespace from the tables */
+ /* Create new array and copy the old array */
- status = acpi_ns_load_namespace();
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "Could not load namespace"));
- goto error_exit;
+ tables = ACPI_ALLOCATE_ZEROED(new_size);
+ if (!tables) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
}
- return_ACPI_STATUS(AE_OK);
+ ACPI_MEMCPY(tables, acpi_gbl_root_table_list.tables, new_size);
- error_exit:
- ACPI_EXCEPTION((AE_INFO, status, "Could not load tables"));
- return_ACPI_STATUS(status);
-}
-
-ACPI_EXPORT_SYMBOL(acpi_load_tables)
+ acpi_gbl_root_table_list.size = acpi_gbl_root_table_list.count;
+ acpi_gbl_root_table_list.tables = tables;
+ acpi_gbl_root_table_list.flags =
+ ACPI_ROOT_ORIGIN_ALLOCATED | ACPI_ROOT_ALLOW_RESIZE;
+ return_ACPI_STATUS(AE_OK);
+}
/*******************************************************************************
*
* FUNCTION: acpi_load_table
@@ -141,342 +219,405 @@ ACPI_EXPORT_SYMBOL(acpi_load_tables)
acpi_status acpi_load_table(struct acpi_table_header *table_ptr)
{
acpi_status status;
- struct acpi_table_desc table_info;
- struct acpi_pointer address;
-
- ACPI_FUNCTION_TRACE(acpi_load_table);
-
- if (!table_ptr) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- /* Copy the table to a local buffer */
+ acpi_native_uint table_index;
+ struct acpi_table_desc table_desc;
- address.pointer_type = ACPI_LOGICAL_POINTER | ACPI_LOGICAL_ADDRESSING;
- address.pointer.logical = table_ptr;
-
- status = acpi_tb_get_table_body(&address, table_ptr, &table_info);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Check signature for a valid table type */
-
- status = acpi_tb_recognize_table(&table_info, ACPI_TABLE_ALL);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
+ if (!table_ptr)
+ return AE_BAD_PARAMETER;
- /* Install the new table into the local data structures */
+ ACPI_MEMSET(&table_desc, 0, sizeof(struct acpi_table_desc));
+ table_desc.pointer = table_ptr;
+ table_desc.length = table_ptr->length;
+ table_desc.flags = ACPI_TABLE_ORIGIN_UNKNOWN;
- status = acpi_tb_install_table(&table_info);
+ /*
+ * Install the new table into the local data structures
+ */
+ status = acpi_tb_add_table(&table_desc, &table_index);
if (ACPI_FAILURE(status)) {
- if (status == AE_ALREADY_EXISTS) {
-
- /* Table already exists, no error */
-
- status = AE_OK;
- }
-
- /* Free table allocated by acpi_tb_get_table_body */
-
- acpi_tb_delete_single_table(&table_info);
- return_ACPI_STATUS(status);
+ return status;
}
+ status = acpi_ns_load_table(table_index, acpi_gbl_root_node);
+ return status;
+}
- /* Convert the table to common format if necessary */
-
- switch (table_info.type) {
- case ACPI_TABLE_ID_FADT:
-
- status = acpi_tb_convert_table_fadt();
- break;
-
- case ACPI_TABLE_ID_FACS:
+ACPI_EXPORT_SYMBOL(acpi_load_table)
- status = acpi_tb_build_common_facs(&table_info);
- break;
+/******************************************************************************
+ *
+ * FUNCTION: acpi_get_table_header
+ *
+ * PARAMETERS: Signature - ACPI signature of needed table
+ * Instance - Which instance (for SSDTs)
+ * out_table_header - The pointer to the table header to fill
+ *
+ * RETURN: Status and pointer to mapped table header
+ *
+ * DESCRIPTION: Finds an ACPI table header.
+ *
+ * NOTE: Caller is responsible in unmapping the header with
+ * acpi_os_unmap_memory
+ *
+ *****************************************************************************/
+acpi_status
+acpi_get_table_header(char *signature,
+ acpi_native_uint instance,
+ struct acpi_table_header *out_table_header)
+{
+ acpi_native_uint i;
+ acpi_native_uint j;
+ struct acpi_table_header *header;
- default:
- /* Load table into namespace if it contains executable AML */
+ /* Parameter validation */
- status =
- acpi_ns_load_table(table_info.installed_desc,
- acpi_gbl_root_node);
- break;
+ if (!signature || !out_table_header) {
+ return (AE_BAD_PARAMETER);
}
- if (ACPI_FAILURE(status)) {
+ /*
+ * Walk the root table list
+ */
+ for (i = 0, j = 0; i < acpi_gbl_root_table_list.count; i++) {
+ if (!ACPI_COMPARE_NAME
+ (&(acpi_gbl_root_table_list.tables[i].signature),
+ signature)) {
+ continue;
+ }
- /* Uninstall table and free the buffer */
+ if (++j < instance) {
+ continue;
+ }
- (void)acpi_tb_uninstall_table(table_info.installed_desc);
+ if (!acpi_gbl_root_table_list.tables[i].pointer) {
+ if ((acpi_gbl_root_table_list.tables[i].
+ flags & ACPI_TABLE_ORIGIN_MASK) ==
+ ACPI_TABLE_ORIGIN_MAPPED) {
+ header =
+ acpi_os_map_memory(acpi_gbl_root_table_list.
+ tables[i].address,
+ sizeof(struct
+ acpi_table_header));
+ if (!header) {
+ return AE_NO_MEMORY;
+ }
+ ACPI_MEMCPY(out_table_header, header,
+ sizeof(struct acpi_table_header));
+ acpi_os_unmap_memory(header,
+ sizeof(struct
+ acpi_table_header));
+ } else {
+ return AE_NOT_FOUND;
+ }
+ } else {
+ ACPI_MEMCPY(out_table_header,
+ acpi_gbl_root_table_list.tables[i].pointer,
+ sizeof(struct acpi_table_header));
+ }
+ return (AE_OK);
}
- return_ACPI_STATUS(status);
+ return (AE_NOT_FOUND);
}
-ACPI_EXPORT_SYMBOL(acpi_load_table)
+ACPI_EXPORT_SYMBOL(acpi_get_table_header)
-/*******************************************************************************
+
+/******************************************************************************
*
* FUNCTION: acpi_unload_table_id
*
- * PARAMETERS: table_type - Type of table to be unloaded
- * id - Owner ID of the table to be removed.
+ * PARAMETERS: id - Owner ID of the table to be removed.
*
* RETURN: Status
*
* DESCRIPTION: This routine is used to force the unload of a table (by id)
*
******************************************************************************/
-acpi_status acpi_unload_table_id(acpi_table_type table_type, acpi_owner_id id)
+acpi_status acpi_unload_table_id(acpi_owner_id id)
{
- struct acpi_table_desc *table_desc;
- acpi_status status;
+ int i;
+ acpi_status status = AE_NOT_EXIST;
ACPI_FUNCTION_TRACE(acpi_unload_table);
- /* Parameter validation */
- if (table_type > ACPI_TABLE_ID_MAX)
- return_ACPI_STATUS(AE_BAD_PARAMETER);
-
/* Find table from the requested type list */
- table_desc = acpi_gbl_table_lists[table_type].next;
- while (table_desc && table_desc->owner_id != id)
- table_desc = table_desc->next;
-
- if (!table_desc)
- return_ACPI_STATUS(AE_NOT_EXIST);
-
- /*
- * 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);
-
- status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
- if (ACPI_FAILURE(status))
- return_ACPI_STATUS(status);
-
- (void)acpi_tb_uninstall_table(table_desc);
-
- (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
-
- return_ACPI_STATUS(AE_OK);
+ for (i = 0; i < acpi_gbl_root_table_list.count; ++i) {
+ if (id != acpi_gbl_root_table_list.tables[i].owner_id) {
+ continue;
+ }
+ /*
+ * 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_tb_delete_namespace_by_owner(i);
+ acpi_tb_release_owner_id(i);
+ acpi_tb_set_table_loaded_flag(i, FALSE);
+ }
+ return_ACPI_STATUS(status);
}
ACPI_EXPORT_SYMBOL(acpi_unload_table_id)
-#ifdef ACPI_FUTURE_USAGE
/*******************************************************************************
*
- * FUNCTION: acpi_unload_table
+ * FUNCTION: acpi_get_table
*
- * PARAMETERS: table_type - Type of table to be unloaded
+ * PARAMETERS: Signature - ACPI signature of needed table
+ * Instance - Which instance (for SSDTs)
+ * out_table - Where the pointer to the table is returned
*
- * RETURN: Status
+ * RETURN: Status and pointer to table
*
- * DESCRIPTION: This routine is used to force the unload of a table
+ * DESCRIPTION: Finds and verifies an ACPI table.
*
- ******************************************************************************/
-acpi_status acpi_unload_table(acpi_table_type table_type)
+ *****************************************************************************/
+acpi_status
+acpi_get_table(char *signature,
+ acpi_native_uint instance, struct acpi_table_header ** out_table)
{
- struct acpi_table_desc *table_desc;
-
- ACPI_FUNCTION_TRACE(acpi_unload_table);
+ acpi_native_uint i;
+ acpi_native_uint j;
+ acpi_status status;
/* Parameter validation */
- if (table_type > ACPI_TABLE_ID_MAX) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
+ if (!signature || !out_table) {
+ return (AE_BAD_PARAMETER);
}
- /* Find all tables of the requested type */
+ /*
+ * Walk the root table list
+ */
+ for (i = 0, j = 0; i < acpi_gbl_root_table_list.count; i++) {
+ if (!ACPI_COMPARE_NAME
+ (&(acpi_gbl_root_table_list.tables[i].signature),
+ signature)) {
+ continue;
+ }
- table_desc = acpi_gbl_table_lists[table_type].next;
- if (!table_desc) {
- return_ACPI_STATUS(AE_NOT_EXIST);
- }
+ if (++j < instance) {
+ continue;
+ }
- while (table_desc) {
- /*
- * 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);
- table_desc = table_desc->next;
- }
+ status =
+ acpi_tb_verify_table(&acpi_gbl_root_table_list.tables[i]);
+ if (ACPI_SUCCESS(status)) {
+ *out_table = acpi_gbl_root_table_list.tables[i].pointer;
+ }
- /* Delete (or unmap) all tables of this type */
+ if (!acpi_gbl_permanent_mmap) {
+ acpi_gbl_root_table_list.tables[i].pointer = 0;
+ }
- acpi_tb_delete_tables_by_type(table_type);
- return_ACPI_STATUS(AE_OK);
+ return (status);
+ }
+
+ return (AE_NOT_FOUND);
}
-ACPI_EXPORT_SYMBOL(acpi_unload_table)
+ACPI_EXPORT_SYMBOL(acpi_get_table)
/*******************************************************************************
*
- * FUNCTION: acpi_get_table_header
+ * FUNCTION: acpi_get_table_by_index
*
- * PARAMETERS: table_type - one of the defined table types
- * Instance - the non zero instance of the table, allows
- * support for multiple tables of the same type
- * see acpi_gbl_acpi_table_flag
- * out_table_header - pointer to the struct acpi_table_header if successful
+ * PARAMETERS: table_index - Table index
+ * Table - Where the pointer to the table is returned
*
- * 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.
+ * RETURN: Status and pointer to the table
*
- * The header contains a length field that can be used to determine
- * 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.
+ * DESCRIPTION: Obtain a table by an index into the global table list.
*
******************************************************************************/
acpi_status
-acpi_get_table_header(acpi_table_type table_type,
- u32 instance, struct acpi_table_header *out_table_header)
+acpi_get_table_by_index(acpi_native_uint table_index,
+ struct acpi_table_header ** table)
{
- struct acpi_table_header *tbl_ptr;
acpi_status status;
- ACPI_FUNCTION_TRACE(acpi_get_table_header);
+ ACPI_FUNCTION_TRACE(acpi_get_table_by_index);
+
+ /* Parameter validation */
- if ((instance == 0) ||
- (table_type == ACPI_TABLE_ID_RSDP) || (!out_table_header)) {
+ if (!table) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- /* Check the table type and instance */
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+
+ /* Validate index */
- if ((table_type > ACPI_TABLE_ID_MAX) ||
- (ACPI_IS_SINGLE_TABLE(acpi_gbl_table_data[table_type].flags) &&
- instance > 1)) {
+ if (table_index >= acpi_gbl_root_table_list.count) {
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- /* Get a pointer to the entire table */
+ if (!acpi_gbl_root_table_list.tables[table_index].pointer) {
- status = acpi_tb_get_table_ptr(table_type, instance, &tbl_ptr);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
+ /* Table is not mapped, map it */
- /* The function will return a NULL pointer if the table is not loaded */
-
- if (tbl_ptr == NULL) {
- return_ACPI_STATUS(AE_NOT_EXIST);
+ status =
+ acpi_tb_verify_table(&acpi_gbl_root_table_list.
+ tables[table_index]);
+ if (ACPI_FAILURE(status)) {
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ return_ACPI_STATUS(status);
+ }
}
- /* Copy the header to the caller's buffer */
-
- ACPI_MEMCPY(ACPI_CAST_PTR(void, out_table_header),
- ACPI_CAST_PTR(void, tbl_ptr),
- sizeof(struct acpi_table_header));
-
- return_ACPI_STATUS(status);
+ *table = acpi_gbl_root_table_list.tables[table_index].pointer;
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ return_ACPI_STATUS(AE_OK);
}
-ACPI_EXPORT_SYMBOL(acpi_get_table_header)
-#endif /* ACPI_FUTURE_USAGE */
+ACPI_EXPORT_SYMBOL(acpi_get_table_by_index)
/*******************************************************************************
*
- * FUNCTION: acpi_get_table
+ * FUNCTION: acpi_tb_load_namespace
*
- * PARAMETERS: table_type - one of the defined table types
- * Instance - the non zero instance of the table, allows
- * support for multiple tables of the same type
- * see acpi_gbl_acpi_table_flag
- * ret_buffer - pointer to a structure containing a buffer to
- * receive the table
+ * PARAMETERS: None
*
* RETURN: Status
*
- * 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
- * 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.
+ * DESCRIPTION: Load the namespace from the DSDT and all SSDTs/PSDTs found in
+ * the RSDT/XSDT.
*
******************************************************************************/
-acpi_status
-acpi_get_table(acpi_table_type table_type,
- u32 instance, struct acpi_buffer *ret_buffer)
+static acpi_status acpi_tb_load_namespace(void)
{
- struct acpi_table_header *tbl_ptr;
acpi_status status;
- acpi_size table_length;
+ struct acpi_table_header *table;
+ acpi_native_uint i;
- ACPI_FUNCTION_TRACE(acpi_get_table);
+ ACPI_FUNCTION_TRACE(tb_load_namespace);
- /* Parameter validation */
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
- if (instance == 0) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
+ /*
+ * Load the namespace. The DSDT is required, but any SSDT and PSDT tables
+ * are optional.
+ */
+ if (!acpi_gbl_root_table_list.count ||
+ !ACPI_COMPARE_NAME(&
+ (acpi_gbl_root_table_list.
+ tables[ACPI_TABLE_INDEX_DSDT].signature),
+ ACPI_SIG_DSDT)
+ ||
+ ACPI_FAILURE(acpi_tb_verify_table
+ (&acpi_gbl_root_table_list.
+ tables[ACPI_TABLE_INDEX_DSDT]))) {
+ status = AE_NO_ACPI_TABLES;
+ goto unlock_and_exit;
}
- status = acpi_ut_validate_buffer(ret_buffer);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ /*
+ * Find DSDT table
+ */
+ status =
+ acpi_os_table_override(acpi_gbl_root_table_list.
+ tables[ACPI_TABLE_INDEX_DSDT].pointer,
+ &table);
+ if (ACPI_SUCCESS(status) && table) {
+ /*
+ * DSDT table has been found
+ */
+ acpi_tb_delete_table(&acpi_gbl_root_table_list.
+ tables[ACPI_TABLE_INDEX_DSDT]);
+ acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].pointer =
+ table;
+ acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].length =
+ table->length;
+ acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].flags =
+ ACPI_TABLE_ORIGIN_UNKNOWN;
+
+ ACPI_INFO((AE_INFO, "Table DSDT replaced by host OS"));
+ acpi_tb_print_table_header(0, table);
}
- /* Check the table type and instance */
+ status =
+ acpi_tb_verify_table(&acpi_gbl_root_table_list.
+ tables[ACPI_TABLE_INDEX_DSDT]);
+ if (ACPI_FAILURE(status)) {
- if ((table_type > ACPI_TABLE_ID_MAX) ||
- (ACPI_IS_SINGLE_TABLE(acpi_gbl_table_data[table_type].flags) &&
- instance > 1)) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
+ /* A valid DSDT is required */
+
+ status = AE_NO_ACPI_TABLES;
+ goto unlock_and_exit;
}
- /* Get a pointer to the entire table */
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
- status = acpi_tb_get_table_ptr(table_type, instance, &tbl_ptr);
+ /*
+ * Load and parse tables.
+ */
+ status = acpi_ns_load_table(ACPI_TABLE_INDEX_DSDT, acpi_gbl_root_node);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
/*
- * acpi_tb_get_table_ptr will return a NULL pointer if the
- * table is not loaded.
+ * Load any SSDT or PSDT tables. Note: Loop leaves tables locked
*/
- if (tbl_ptr == NULL) {
- return_ACPI_STATUS(AE_NOT_EXIST);
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+ for (i = 0; i < acpi_gbl_root_table_list.count; ++i) {
+ if ((!ACPI_COMPARE_NAME
+ (&(acpi_gbl_root_table_list.tables[i].signature),
+ ACPI_SIG_SSDT)
+ &&
+ !ACPI_COMPARE_NAME(&
+ (acpi_gbl_root_table_list.tables[i].
+ signature), ACPI_SIG_PSDT))
+ ||
+ ACPI_FAILURE(acpi_tb_verify_table
+ (&acpi_gbl_root_table_list.tables[i]))) {
+ continue;
+ }
+
+ /* Ignore errors while loading tables, get as many as possible */
+
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ (void)acpi_ns_load_table(i, acpi_gbl_root_node);
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
}
- /* Get the table length */
+ ACPI_DEBUG_PRINT((ACPI_DB_INIT, "ACPI Tables successfully acquired\n"));
- if (table_type == ACPI_TABLE_ID_RSDP) {
+ unlock_and_exit:
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ return_ACPI_STATUS(status);
+}
- /* RSD PTR is the only "table" without a header */
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_load_tables
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Load the ACPI tables from the RSDT/XSDT
+ *
+ ******************************************************************************/
- table_length = sizeof(struct rsdp_descriptor);
- } else {
- table_length = (acpi_size) tbl_ptr->length;
- }
+acpi_status acpi_load_tables(void)
+{
+ acpi_status status;
- /* Validate/Allocate/Clear caller buffer */
+ ACPI_FUNCTION_TRACE(acpi_load_tables);
- status = acpi_ut_initialize_buffer(ret_buffer, table_length);
+ /*
+ * Load the namespace from the tables
+ */
+ status = acpi_tb_load_namespace();
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ ACPI_EXCEPTION((AE_INFO, status,
+ "While loading namespace from ACPI tables"));
}
- /* Copy the table to the buffer */
-
- ACPI_MEMCPY(ACPI_CAST_PTR(void, ret_buffer->pointer),
- ACPI_CAST_PTR(void, tbl_ptr), table_length);
-
- return_ACPI_STATUS(AE_OK);
+ return_ACPI_STATUS(status);
}
-ACPI_EXPORT_SYMBOL(acpi_get_table)
+ACPI_EXPORT_SYMBOL(acpi_load_tables)
diff --git a/drivers/acpi/tables/tbxfroot.c b/drivers/acpi/tables/tbxfroot.c
index da2648bbdbc..cf8fa514189 100644
--- a/drivers/acpi/tables/tbxfroot.c
+++ b/drivers/acpi/tables/tbxfroot.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -48,16 +48,15 @@
ACPI_MODULE_NAME("tbxfroot")
/* Local prototypes */
-static acpi_status
-acpi_tb_find_rsdp(struct acpi_table_desc *table_info, u32 flags);
-
static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length);
+static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp);
+
/*******************************************************************************
*
* FUNCTION: acpi_tb_validate_rsdp
*
- * PARAMETERS: Rsdp - Pointer to unvalidated RSDP
+ * PARAMETERS: Rsdp - Pointer to unvalidated RSDP
*
* RETURN: Status
*
@@ -65,14 +64,18 @@ static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length);
*
******************************************************************************/
-acpi_status acpi_tb_validate_rsdp(struct rsdp_descriptor *rsdp)
+static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp)
{
ACPI_FUNCTION_ENTRY();
/*
- * The signature and checksum must both be correct
+ * The signature and checksum must both be correct
+ *
+ * Note: Sometimes there exists more than one RSDP in memory; the valid
+ * RSDP has a valid checksum, all others have an invalid checksum.
*/
- if (ACPI_STRNCMP((char *)rsdp, RSDP_SIG, sizeof(RSDP_SIG) - 1) != 0) {
+ if (ACPI_STRNCMP((char *)rsdp, ACPI_SIG_RSDP, sizeof(ACPI_SIG_RSDP) - 1)
+ != 0) {
/* Nope, BAD Signature */
@@ -81,14 +84,14 @@ acpi_status acpi_tb_validate_rsdp(struct rsdp_descriptor *rsdp)
/* Check the standard checksum */
- if (acpi_tb_sum_table(rsdp, ACPI_RSDP_CHECKSUM_LENGTH) != 0) {
+ if (acpi_tb_checksum((u8 *) rsdp, ACPI_RSDP_CHECKSUM_LENGTH) != 0) {
return (AE_BAD_CHECKSUM);
}
/* Check extended checksum if table version >= 2 */
if ((rsdp->revision >= 2) &&
- (acpi_tb_sum_table(rsdp, ACPI_RSDP_XCHECKSUM_LENGTH) != 0)) {
+ (acpi_tb_checksum((u8 *) rsdp, ACPI_RSDP_XCHECKSUM_LENGTH) != 0)) {
return (AE_BAD_CHECKSUM);
}
@@ -97,314 +100,123 @@ acpi_status acpi_tb_validate_rsdp(struct rsdp_descriptor *rsdp)
/*******************************************************************************
*
- * FUNCTION: acpi_tb_find_table
- *
- * PARAMETERS: Signature - String with ACPI table signature
- * oem_id - String with the table OEM ID
- * oem_table_id - String with the OEM Table ID
- * table_ptr - Where the table pointer is returned
- *
- * RETURN: Status
+ * FUNCTION: acpi_tb_find_rsdp
*
- * DESCRIPTION: Find an ACPI table (in the RSDT/XSDT) that matches the
- * Signature, OEM ID and OEM Table ID.
+ * PARAMETERS: table_address - Where the table pointer is returned
*
- ******************************************************************************/
-
-acpi_status
-acpi_tb_find_table(char *signature,
- char *oem_id,
- char *oem_table_id, struct acpi_table_header ** table_ptr)
-{
- acpi_status status;
- struct acpi_table_header *table;
-
- ACPI_FUNCTION_TRACE(tb_find_table);
-
- /* Validate string lengths */
-
- if ((ACPI_STRLEN(signature) > ACPI_NAME_SIZE) ||
- (ACPI_STRLEN(oem_id) > sizeof(table->oem_id)) ||
- (ACPI_STRLEN(oem_table_id) > sizeof(table->oem_table_id))) {
- return_ACPI_STATUS(AE_AML_STRING_LIMIT);
- }
-
- if (ACPI_COMPARE_NAME(signature, DSDT_SIG)) {
- /*
- * The DSDT pointer is contained in the FADT, not the RSDT.
- * This code should suffice, because the only code that would perform
- * a "find" on the DSDT is the data_table_region() AML opcode -- in
- * which case, the DSDT is guaranteed to be already loaded.
- * If this becomes insufficient, the FADT will have to be found first.
- */
- if (!acpi_gbl_DSDT) {
- return_ACPI_STATUS(AE_NO_ACPI_TABLES);
- }
- table = acpi_gbl_DSDT;
- } else {
- /* Find the table */
-
- status = acpi_get_firmware_table(signature, 1,
- ACPI_LOGICAL_ADDRESSING,
- &table);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
- }
-
- /* Check oem_id and oem_table_id */
-
- if ((oem_id[0] &&
- ACPI_STRNCMP(oem_id, table->oem_id,
- sizeof(table->oem_id))) ||
- (oem_table_id[0] &&
- ACPI_STRNCMP(oem_table_id, table->oem_table_id,
- sizeof(table->oem_table_id)))) {
- return_ACPI_STATUS(AE_AML_NAME_NOT_FOUND);
- }
-
- ACPI_DEBUG_PRINT((ACPI_DB_TABLES, "Found table [%4.4s]\n",
- table->signature));
-
- *table_ptr = table;
- return_ACPI_STATUS(AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_get_firmware_table
+ * RETURN: Status, RSDP physical address
*
- * PARAMETERS: Signature - Any ACPI table signature
- * Instance - the non zero instance of the table, allows
- * support for multiple tables of the same type
- * Flags - Physical/Virtual support
- * table_pointer - Where a buffer containing the table is
- * returned
+ * DESCRIPTION: Search lower 1_mbyte of memory for the root system descriptor
+ * pointer structure. If it is found, set *RSDP to point to it.
*
- * RETURN: Status
+ * NOTE1: The RSDP must be either in the first 1_k of the Extended
+ * BIOS Data Area or between E0000 and FFFFF (From ACPI Spec.)
+ * Only a 32-bit physical address is necessary.
*
- * DESCRIPTION: This function is called to get an ACPI table. A buffer is
- * allocated for the table and returned in table_pointer.
- * This table will be a complete table including the header.
+ * NOTE2: This function is always available, regardless of the
+ * initialization state of the rest of ACPI.
*
******************************************************************************/
-acpi_status
-acpi_get_firmware_table(acpi_string signature,
- u32 instance,
- u32 flags, struct acpi_table_header **table_pointer)
+acpi_status acpi_find_root_pointer(acpi_native_uint * table_address)
{
- acpi_status status;
- struct acpi_pointer address;
- struct acpi_table_header *header = NULL;
- struct acpi_table_desc *table_info = NULL;
- struct acpi_table_desc *rsdt_info;
- u32 table_count;
- u32 i;
- u32 j;
-
- ACPI_FUNCTION_TRACE(acpi_get_firmware_table);
-
- /*
- * Ensure that at least the table manager is initialized. We don't
- * require that the entire ACPI subsystem is up for this interface.
- * If we have a buffer, we must have a length too
- */
- if ((instance == 0) || (!signature) || (!table_pointer)) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- /* Ensure that we have a RSDP */
-
- if (!acpi_gbl_RSDP) {
-
- /* Get the RSDP */
-
- status = acpi_os_get_root_pointer(flags, &address);
- if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "RSDP not found\n"));
- return_ACPI_STATUS(AE_NO_ACPI_TABLES);
- }
-
- /* Map and validate the RSDP */
-
- if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) {
- status = acpi_os_map_memory(address.pointer.physical,
- sizeof(struct
- rsdp_descriptor),
- (void *)&acpi_gbl_RSDP);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
- } else {
- acpi_gbl_RSDP = address.pointer.logical;
- }
-
- /* The RDSP signature and checksum must both be correct */
-
- status = acpi_tb_validate_rsdp(acpi_gbl_RSDP);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
- }
-
- /* Get the RSDT address via the RSDP */
-
- acpi_tb_get_rsdt_address(&address);
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "RSDP located at %p, RSDT physical=%8.8X%8.8X\n",
- acpi_gbl_RSDP,
- ACPI_FORMAT_UINT64(address.pointer.value)));
+ u8 *table_ptr;
+ u8 *mem_rover;
+ u32 physical_address;
- /* Insert processor_mode flags */
+ ACPI_FUNCTION_TRACE(acpi_find_root_pointer);
- address.pointer_type |= flags;
+ /* 1a) Get the location of the Extended BIOS Data Area (EBDA) */
- /* Get and validate the RSDT */
+ table_ptr = acpi_os_map_memory((acpi_physical_address)
+ ACPI_EBDA_PTR_LOCATION,
+ ACPI_EBDA_PTR_LENGTH);
+ if (!table_ptr) {
+ ACPI_ERROR((AE_INFO,
+ "Could not map memory at %8.8X for length %X",
+ ACPI_EBDA_PTR_LOCATION, ACPI_EBDA_PTR_LENGTH));
- rsdt_info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_table_desc));
- if (!rsdt_info) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
- status = acpi_tb_get_table(&address, rsdt_info);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
- }
-
- status = acpi_tb_validate_rsdt(rsdt_info->pointer);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
- }
+ ACPI_MOVE_16_TO_32(&physical_address, table_ptr);
- /* Allocate a scratch table header and table descriptor */
+ /* Convert segment part to physical address */
- header = ACPI_ALLOCATE(sizeof(struct acpi_table_header));
- if (!header) {
- status = AE_NO_MEMORY;
- goto cleanup;
- }
+ physical_address <<= 4;
+ acpi_os_unmap_memory(table_ptr, ACPI_EBDA_PTR_LENGTH);
- table_info = ACPI_ALLOCATE(sizeof(struct acpi_table_desc));
- if (!table_info) {
- status = AE_NO_MEMORY;
- goto cleanup;
- }
+ /* EBDA present? */
- /* Get the number of table pointers within the RSDT */
-
- table_count =
- acpi_tb_get_table_count(acpi_gbl_RSDP, rsdt_info->pointer);
- address.pointer_type = acpi_gbl_table_flags | flags;
-
- /*
- * Search the RSDT/XSDT for the correct instance of the
- * requested table
- */
- for (i = 0, j = 0; i < table_count; i++) {
+ if (physical_address > 0x400) {
/*
- * Get the next table pointer, handle RSDT vs. XSDT
- * RSDT pointers are 32 bits, XSDT pointers are 64 bits
+ * 1b) Search EBDA paragraphs (EBDA is required to be a
+ * minimum of 1_k length)
*/
- if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) {
- address.pointer.value =
- (ACPI_CAST_PTR
- (struct rsdt_descriptor,
- rsdt_info->pointer))->table_offset_entry[i];
- } else {
- address.pointer.value =
- (ACPI_CAST_PTR
- (struct xsdt_descriptor,
- rsdt_info->pointer))->table_offset_entry[i];
- }
-
- /* Get the table header */
+ table_ptr = acpi_os_map_memory((acpi_native_uint)
+ physical_address,
+ ACPI_EBDA_WINDOW_SIZE);
+ if (!table_ptr) {
+ ACPI_ERROR((AE_INFO,
+ "Could not map memory at %8.8X for length %X",
+ physical_address, ACPI_EBDA_WINDOW_SIZE));
- status = acpi_tb_get_table_header(&address, header);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
+ return_ACPI_STATUS(AE_NO_MEMORY);
}
- /* Compare table signatures and table instance */
-
- if (ACPI_COMPARE_NAME(header->signature, signature)) {
-
- /* An instance of the table was found */
+ mem_rover =
+ acpi_tb_scan_memory_for_rsdp(table_ptr,
+ ACPI_EBDA_WINDOW_SIZE);
+ acpi_os_unmap_memory(table_ptr, ACPI_EBDA_WINDOW_SIZE);
- j++;
- if (j >= instance) {
+ if (mem_rover) {
- /* Found the correct instance, get the entire table */
+ /* Return the physical address */
- status =
- acpi_tb_get_table_body(&address, header,
- table_info);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
- }
+ physical_address +=
+ (u32) ACPI_PTR_DIFF(mem_rover, table_ptr);
- *table_pointer = table_info->pointer;
- goto cleanup;
- }
+ *table_address = physical_address;
+ return_ACPI_STATUS(AE_OK);
}
}
- /* Did not find the table */
+ /*
+ * 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh
+ */
+ table_ptr = acpi_os_map_memory((acpi_physical_address)
+ ACPI_HI_RSDP_WINDOW_BASE,
+ ACPI_HI_RSDP_WINDOW_SIZE);
- status = AE_NOT_EXIST;
+ if (!table_ptr) {
+ ACPI_ERROR((AE_INFO,
+ "Could not map memory at %8.8X for length %X",
+ ACPI_HI_RSDP_WINDOW_BASE,
+ ACPI_HI_RSDP_WINDOW_SIZE));
- cleanup:
- if (rsdt_info->pointer) {
- acpi_os_unmap_memory(rsdt_info->pointer,
- (acpi_size) rsdt_info->pointer->length);
+ return_ACPI_STATUS(AE_NO_MEMORY);
}
- ACPI_FREE(rsdt_info);
- if (header) {
- ACPI_FREE(header);
- }
- if (table_info) {
- ACPI_FREE(table_info);
- }
- return_ACPI_STATUS(status);
-}
+ mem_rover =
+ acpi_tb_scan_memory_for_rsdp(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE);
+ acpi_os_unmap_memory(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE);
-ACPI_EXPORT_SYMBOL(acpi_get_firmware_table)
+ if (mem_rover) {
-/* TBD: Move to a new file */
-#if ACPI_MACHINE_WIDTH != 16
-/*******************************************************************************
- *
- * FUNCTION: acpi_find_root_pointer
- *
- * PARAMETERS: Flags - Logical/Physical addressing
- * rsdp_address - Where to place the RSDP address
- *
- * RETURN: Status, Physical address of the RSDP
- *
- * DESCRIPTION: Find the RSDP
- *
- ******************************************************************************/
-acpi_status acpi_find_root_pointer(u32 flags, struct acpi_pointer *rsdp_address)
-{
- struct acpi_table_desc table_info;
- acpi_status status;
-
- ACPI_FUNCTION_TRACE(acpi_find_root_pointer);
-
- /* Get the RSDP */
+ /* Return the physical address */
- status = acpi_tb_find_rsdp(&table_info, flags);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "RSDP structure not found - Flags=%X", flags));
+ physical_address = (u32)
+ (ACPI_HI_RSDP_WINDOW_BASE +
+ ACPI_PTR_DIFF(mem_rover, table_ptr));
- return_ACPI_STATUS(AE_NO_ACPI_TABLES);
+ *table_address = physical_address;
+ return_ACPI_STATUS(AE_OK);
}
- rsdp_address->pointer_type = ACPI_PHYSICAL_POINTER;
- rsdp_address->pointer.physical = table_info.physical_address;
- return_ACPI_STATUS(AE_OK);
+ /* A valid RSDP was not found */
+
+ ACPI_ERROR((AE_INFO, "A valid RSDP was not found"));
+ return_ACPI_STATUS(AE_NOT_FOUND);
}
ACPI_EXPORT_SYMBOL(acpi_find_root_pointer)
@@ -440,7 +252,7 @@ static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length)
status =
acpi_tb_validate_rsdp(ACPI_CAST_PTR
- (struct rsdp_descriptor, mem_rover));
+ (struct acpi_table_rsdp, mem_rover));
if (ACPI_SUCCESS(status)) {
/* Sig and checksum valid, we have found a real RSDP */
@@ -461,189 +273,3 @@ static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length)
start_address));
return_PTR(NULL);
}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_find_rsdp
- *
- * PARAMETERS: table_info - Where the table info is returned
- * Flags - Current memory mode (logical vs.
- * physical addressing)
- *
- * RETURN: Status, RSDP physical address
- *
- * DESCRIPTION: Search lower 1_mbyte of memory for the root system descriptor
- * pointer structure. If it is found, set *RSDP to point to it.
- *
- * NOTE1: The RSDP must be either in the first 1_k of the Extended
- * BIOS Data Area or between E0000 and FFFFF (From ACPI Spec.)
- * Only a 32-bit physical address is necessary.
- *
- * NOTE2: This function is always available, regardless of the
- * initialization state of the rest of ACPI.
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_tb_find_rsdp(struct acpi_table_desc *table_info, u32 flags)
-{
- u8 *table_ptr;
- u8 *mem_rover;
- u32 physical_address;
- acpi_status status;
-
- ACPI_FUNCTION_TRACE(tb_find_rsdp);
-
- /*
- * Scan supports either logical addressing or physical addressing
- */
- if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) {
-
- /* 1a) Get the location of the Extended BIOS Data Area (EBDA) */
-
- status = acpi_os_map_memory((acpi_physical_address)
- ACPI_EBDA_PTR_LOCATION,
- ACPI_EBDA_PTR_LENGTH,
- (void *)&table_ptr);
- if (ACPI_FAILURE(status)) {
- ACPI_ERROR((AE_INFO,
- "Could not map memory at %8.8X for length %X",
- ACPI_EBDA_PTR_LOCATION,
- ACPI_EBDA_PTR_LENGTH));
-
- return_ACPI_STATUS(status);
- }
-
- ACPI_MOVE_16_TO_32(&physical_address, table_ptr);
-
- /* Convert segment part to physical address */
-
- physical_address <<= 4;
- acpi_os_unmap_memory(table_ptr, ACPI_EBDA_PTR_LENGTH);
-
- /* EBDA present? */
-
- if (physical_address > 0x400) {
- /*
- * 1b) Search EBDA paragraphs (EBDA is required to be a
- * minimum of 1_k length)
- */
- status = acpi_os_map_memory((acpi_physical_address)
- physical_address,
- ACPI_EBDA_WINDOW_SIZE,
- (void *)&table_ptr);
- if (ACPI_FAILURE(status)) {
- ACPI_ERROR((AE_INFO,
- "Could not map memory at %8.8X for length %X",
- physical_address,
- ACPI_EBDA_WINDOW_SIZE));
-
- return_ACPI_STATUS(status);
- }
-
- mem_rover = acpi_tb_scan_memory_for_rsdp(table_ptr,
- ACPI_EBDA_WINDOW_SIZE);
- acpi_os_unmap_memory(table_ptr, ACPI_EBDA_WINDOW_SIZE);
-
- if (mem_rover) {
-
- /* Return the physical address */
-
- physical_address +=
- (u32) ACPI_PTR_DIFF(mem_rover, table_ptr);
-
- table_info->physical_address =
- (acpi_physical_address) physical_address;
- return_ACPI_STATUS(AE_OK);
- }
- }
-
- /*
- * 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh
- */
- status = acpi_os_map_memory((acpi_physical_address)
- ACPI_HI_RSDP_WINDOW_BASE,
- ACPI_HI_RSDP_WINDOW_SIZE,
- (void *)&table_ptr);
-
- if (ACPI_FAILURE(status)) {
- ACPI_ERROR((AE_INFO,
- "Could not map memory at %8.8X for length %X",
- ACPI_HI_RSDP_WINDOW_BASE,
- ACPI_HI_RSDP_WINDOW_SIZE));
-
- return_ACPI_STATUS(status);
- }
-
- mem_rover =
- acpi_tb_scan_memory_for_rsdp(table_ptr,
- ACPI_HI_RSDP_WINDOW_SIZE);
- acpi_os_unmap_memory(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE);
-
- if (mem_rover) {
-
- /* Return the physical address */
-
- physical_address = (u32)
- (ACPI_HI_RSDP_WINDOW_BASE +
- ACPI_PTR_DIFF(mem_rover, table_ptr));
-
- table_info->physical_address =
- (acpi_physical_address) physical_address;
- return_ACPI_STATUS(AE_OK);
- }
- }
-
- /*
- * Physical addressing
- */
- else {
- /* 1a) Get the location of the EBDA */
-
- ACPI_MOVE_16_TO_32(&physical_address, ACPI_EBDA_PTR_LOCATION);
- physical_address <<= 4; /* Convert segment to physical address */
-
- /* EBDA present? */
-
- if (physical_address > 0x400) {
- /*
- * 1b) Search EBDA paragraphs (EBDA is required to be a minimum of
- * 1_k length)
- */
- mem_rover =
- acpi_tb_scan_memory_for_rsdp(ACPI_PHYSADDR_TO_PTR
- (physical_address),
- ACPI_EBDA_WINDOW_SIZE);
- if (mem_rover) {
-
- /* Return the physical address */
-
- table_info->physical_address =
- ACPI_TO_INTEGER(mem_rover);
- return_ACPI_STATUS(AE_OK);
- }
- }
-
- /* 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh */
-
- mem_rover =
- acpi_tb_scan_memory_for_rsdp(ACPI_PHYSADDR_TO_PTR
- (ACPI_HI_RSDP_WINDOW_BASE),
- ACPI_HI_RSDP_WINDOW_SIZE);
- if (mem_rover) {
-
- /* Found it, return the physical address */
-
- table_info->physical_address =
- ACPI_TO_INTEGER(mem_rover);
- return_ACPI_STATUS(AE_OK);
- }
- }
-
- /* A valid RSDP was not found */
-
- ACPI_ERROR((AE_INFO, "No valid RSDP was found"));
- return_ACPI_STATUS(AE_NOT_FOUND);
-}
-
-#endif
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 40ddb4dd963..f76d3168c2b 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -82,7 +82,7 @@ MODULE_PARM_DESC(tzp, "Thermal zone polling frequency, in 1/10 seconds.\n");
static int acpi_thermal_add(struct acpi_device *device);
static int acpi_thermal_remove(struct acpi_device *device, int type);
-static int acpi_thermal_resume(struct acpi_device *device, int state);
+static int acpi_thermal_resume(struct acpi_device *device);
static int acpi_thermal_state_open_fs(struct inode *inode, struct file *file);
static int acpi_thermal_temp_open_fs(struct inode *inode, struct file *file);
static int acpi_thermal_trip_open_fs(struct inode *inode, struct file *file);
@@ -1353,7 +1353,7 @@ static int acpi_thermal_remove(struct acpi_device *device, int type)
return 0;
}
-static int acpi_thermal_resume(struct acpi_device *device, int state)
+static int acpi_thermal_resume(struct acpi_device *device)
{
struct acpi_thermal *tz = NULL;
int i;
diff --git a/drivers/acpi/utilities/utalloc.c b/drivers/acpi/utilities/utalloc.c
index f6cbc0b1bfd..55a76480749 100644
--- a/drivers/acpi/utilities/utalloc.c
+++ b/drivers/acpi/utilities/utalloc.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -42,6 +42,7 @@
*/
#include <acpi/acpi.h>
+#include <acpi/acdebug.h>
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utalloc")
@@ -142,6 +143,14 @@ acpi_status acpi_ut_create_caches(void)
acpi_status acpi_ut_delete_caches(void)
{
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+ char buffer[7];
+
+ if (acpi_gbl_display_final_mem_stats) {
+ ACPI_STRCPY(buffer, "MEMORY");
+ acpi_db_display_statistics(buffer);
+ }
+#endif
(void)acpi_os_delete_cache(acpi_gbl_namespace_cache);
acpi_gbl_namespace_cache = NULL;
diff --git a/drivers/acpi/utilities/utcache.c b/drivers/acpi/utilities/utcache.c
index 1a1f8109159..870f6edeb5f 100644
--- a/drivers/acpi/utilities/utcache.c
+++ b/drivers/acpi/utilities/utcache.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -289,6 +289,14 @@ void *acpi_os_acquire_object(struct acpi_memory_list *cache)
ACPI_MEM_TRACKING(cache->total_allocated++);
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+ if ((cache->total_allocated - cache->total_freed) >
+ cache->max_occupied) {
+ cache->max_occupied =
+ cache->total_allocated - cache->total_freed;
+ }
+#endif
+
/* Avoid deadlock with ACPI_ALLOCATE_ZEROED */
status = acpi_ut_release_mutex(ACPI_MTX_CACHES);
diff --git a/drivers/acpi/utilities/utcopy.c b/drivers/acpi/utilities/utcopy.c
index 5e1a80d1bc3..84d529db0a6 100644
--- a/drivers/acpi/utilities/utcopy.c
+++ b/drivers/acpi/utilities/utcopy.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -719,6 +719,15 @@ acpi_ut_copy_simple_object(union acpi_operand_object *source_desc,
acpi_ut_add_reference(source_desc->reference.object);
break;
+ case ACPI_TYPE_REGION:
+ /*
+ * We copied the Region Handler, so we now must add a reference
+ */
+ if (dest_desc->region.handler) {
+ acpi_ut_add_reference(dest_desc->region.handler);
+ }
+ break;
+
default:
/* Nothing to do for other simple objects */
break;
diff --git a/drivers/acpi/utilities/utdebug.c b/drivers/acpi/utilities/utdebug.c
index 9e9054e155c..61ad4f2daee 100644
--- a/drivers/acpi/utilities/utdebug.c
+++ b/drivers/acpi/utilities/utdebug.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -181,8 +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 %lX to TID %lX ****\n\n",
- (unsigned long) acpi_gbl_prev_thread_id,
- (unsigned long) thread_id);
+ (unsigned long)acpi_gbl_prev_thread_id, (unsigned long)thread_id);
}
acpi_gbl_prev_thread_id = thread_id;
@@ -195,7 +194,7 @@ acpi_ut_debug_print(u32 requested_debug_level,
acpi_os_printf("%8s-%04ld ", module_name, line_number);
if (ACPI_LV_THREADS & acpi_dbg_level) {
- acpi_os_printf("[%04lX] ", thread_id);
+ acpi_os_printf("[%04lX] ", (unsigned long)thread_id);
}
acpi_os_printf("[%02ld] %-22.22s: ",
diff --git a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/utilities/utdelete.c
index 9d3f1149ba2..f777cebdc46 100644
--- a/drivers/acpi/utilities/utdelete.c
+++ b/drivers/acpi/utilities/utdelete.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -158,16 +158,20 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
"***** Mutex %p, OS Mutex %p\n",
object, object->mutex.os_mutex));
- if (object->mutex.os_mutex != ACPI_GLOBAL_LOCK) {
- acpi_ex_unlink_mutex(object);
- acpi_os_delete_mutex(object->mutex.os_mutex);
- } else {
- /* Global Lock "mutex" is actually a counting semaphore */
+ if (object->mutex.os_mutex == acpi_gbl_global_lock_mutex) {
+
+ /* Global Lock has extra semaphore */
(void)
acpi_os_delete_semaphore
(acpi_gbl_global_lock_semaphore);
acpi_gbl_global_lock_semaphore = NULL;
+
+ acpi_os_delete_mutex(object->mutex.os_mutex);
+ acpi_gbl_global_lock_mutex = NULL;
+ } else {
+ acpi_ex_unlink_mutex(object);
+ acpi_os_delete_mutex(object->mutex.os_mutex);
}
break;
diff --git a/drivers/acpi/utilities/uteval.c b/drivers/acpi/utilities/uteval.c
index d6d7121583c..13d5879cd98 100644
--- a/drivers/acpi/utilities/uteval.c
+++ b/drivers/acpi/utilities/uteval.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c
index 014030af8b5..af33358a964 100644
--- a/drivers/acpi/utilities/utglobal.c
+++ b/drivers/acpi/utilities/utglobal.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -46,89 +46,9 @@
#include <acpi/acpi.h>
#include <acpi/acnamesp.h>
+ACPI_EXPORT_SYMBOL(acpi_gbl_FADT)
#define _COMPONENT ACPI_UTILITIES
-ACPI_MODULE_NAME("utglobal")
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_format_exception
- *
- * PARAMETERS: Status - The acpi_status code to be formatted
- *
- * RETURN: A string containing the exception text. A valid pointer is
- * always returned.
- *
- * DESCRIPTION: This function translates an ACPI exception into an ASCII string.
- *
- ******************************************************************************/
-const char *acpi_format_exception(acpi_status status)
-{
- acpi_status sub_status;
- const char *exception = NULL;
-
- ACPI_FUNCTION_ENTRY();
-
- /*
- * Status is composed of two parts, a "type" and an actual code
- */
- sub_status = (status & ~AE_CODE_MASK);
-
- switch (status & AE_CODE_MASK) {
- case AE_CODE_ENVIRONMENTAL:
-
- if (sub_status <= AE_CODE_ENV_MAX) {
- exception = acpi_gbl_exception_names_env[sub_status];
- }
- break;
-
- case AE_CODE_PROGRAMMER:
-
- if (sub_status <= AE_CODE_PGM_MAX) {
- exception =
- acpi_gbl_exception_names_pgm[sub_status - 1];
- }
- break;
-
- case AE_CODE_ACPI_TABLES:
-
- if (sub_status <= AE_CODE_TBL_MAX) {
- exception =
- acpi_gbl_exception_names_tbl[sub_status - 1];
- }
- break;
-
- case AE_CODE_AML:
-
- if (sub_status <= AE_CODE_AML_MAX) {
- exception =
- acpi_gbl_exception_names_aml[sub_status - 1];
- }
- break;
-
- case AE_CODE_CONTROL:
-
- if (sub_status <= AE_CODE_CTRL_MAX) {
- exception =
- acpi_gbl_exception_names_ctrl[sub_status - 1];
- }
- break;
-
- default:
- break;
- }
-
- if (!exception) {
-
- /* Exception code was not recognized */
-
- ACPI_ERROR((AE_INFO,
- "Unknown exception code: 0x%8.8X", status));
-
- exception = "UNKNOWN_STATUS_CODE";
- }
-
- return (ACPI_CAST_PTR(const char, exception));
-}
+ ACPI_MODULE_NAME("utglobal")
/*******************************************************************************
*
@@ -163,8 +83,6 @@ u32 acpi_gbl_startup_flags = 0;
u8 acpi_gbl_shutdown = TRUE;
-const u8 acpi_gbl_decode_to8bit[8] = { 1, 2, 4, 8, 16, 32, 64, 128 };
-
const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT] = {
"\\_S0_",
"\\_S1_",
@@ -183,10 +101,45 @@ const char *acpi_gbl_highest_dstate_names[4] = {
/*******************************************************************************
*
- * Namespace globals
+ * FUNCTION: acpi_format_exception
+ *
+ * PARAMETERS: Status - The acpi_status code to be formatted
+ *
+ * RETURN: A string containing the exception text. A valid pointer is
+ * always returned.
+ *
+ * DESCRIPTION: This function translates an ACPI exception into an ASCII string
+ * It is here instead of utxface.c so it is always present.
*
******************************************************************************/
+const char *acpi_format_exception(acpi_status status)
+{
+ const char *exception = NULL;
+
+ ACPI_FUNCTION_ENTRY();
+
+ exception = acpi_ut_validate_exception(status);
+ if (!exception) {
+
+ /* Exception code was not recognized */
+
+ ACPI_ERROR((AE_INFO,
+ "Unknown exception code: 0x%8.8X", status));
+
+ exception = "UNKNOWN_STATUS_CODE";
+ }
+
+ return (ACPI_CAST_PTR(const char, exception));
+}
+
+ACPI_EXPORT_SYMBOL(acpi_format_exception)
+
+/*******************************************************************************
+ *
+ * Namespace globals
+ *
+ ******************************************************************************/
/*
* Predefined ACPI Names (Built-in to the Interpreter)
*
@@ -280,53 +233,6 @@ char acpi_ut_hex_to_ascii_char(acpi_integer integer, u32 position)
return (acpi_gbl_hex_to_ascii[(integer >> position) & 0xF]);
}
-/*******************************************************************************
- *
- * Table name globals
- *
- * NOTE: This table includes ONLY the ACPI tables that the subsystem consumes.
- * it is NOT an exhaustive list of all possible ACPI tables. All ACPI tables
- * that are not used by the subsystem are simply ignored.
- *
- * Do NOT add any table to this list that is not consumed directly by this
- * subsystem (No MADT, ECDT, SBST, etc.)
- *
- ******************************************************************************/
-
-struct acpi_table_list acpi_gbl_table_lists[ACPI_TABLE_ID_MAX + 1];
-
-struct acpi_table_support acpi_gbl_table_data[ACPI_TABLE_ID_MAX + 1] = {
- /*********** Name, Signature, Global typed pointer Signature size, Type How many allowed?, Contains valid AML? */
-
- /* RSDP 0 */ {RSDP_NAME, RSDP_SIG, NULL, sizeof(RSDP_SIG) - 1,
- ACPI_TABLE_ROOT | ACPI_TABLE_SINGLE}
- ,
- /* DSDT 1 */ {DSDT_SIG, DSDT_SIG, (void *)&acpi_gbl_DSDT,
- sizeof(DSDT_SIG) - 1,
- ACPI_TABLE_SECONDARY | ACPI_TABLE_SINGLE |
- ACPI_TABLE_EXECUTABLE}
- ,
- /* FADT 2 */ {FADT_SIG, FADT_SIG, (void *)&acpi_gbl_FADT,
- sizeof(FADT_SIG) - 1,
- ACPI_TABLE_PRIMARY | ACPI_TABLE_SINGLE}
- ,
- /* FACS 3 */ {FACS_SIG, FACS_SIG, (void *)&acpi_gbl_FACS,
- sizeof(FACS_SIG) - 1,
- ACPI_TABLE_SECONDARY | ACPI_TABLE_SINGLE}
- ,
- /* PSDT 4 */ {PSDT_SIG, PSDT_SIG, NULL, sizeof(PSDT_SIG) - 1,
- ACPI_TABLE_PRIMARY | ACPI_TABLE_MULTIPLE |
- ACPI_TABLE_EXECUTABLE}
- ,
- /* SSDT 5 */ {SSDT_SIG, SSDT_SIG, NULL, sizeof(SSDT_SIG) - 1,
- ACPI_TABLE_PRIMARY | ACPI_TABLE_MULTIPLE |
- ACPI_TABLE_EXECUTABLE}
- ,
- /* XSDT 6 */ {XSDT_SIG, XSDT_SIG, NULL, sizeof(RSDT_SIG) - 1,
- ACPI_TABLE_ROOT | ACPI_TABLE_SINGLE}
- ,
-};
-
/******************************************************************************
*
* Event and Hardware globals
@@ -612,7 +518,7 @@ char *acpi_ut_get_node_name(void *object)
/* Name must be a valid ACPI name */
if (!acpi_ut_valid_acpi_name(node->name.integer)) {
- node->name.integer = acpi_ut_repair_name(node->name.integer);
+ node->name.integer = acpi_ut_repair_name(node->name.ascii);
}
/* Return the name */
@@ -751,13 +657,6 @@ void acpi_ut_init_globals(void)
return;
}
- /* ACPI table structure */
-
- for (i = 0; i < (ACPI_TABLE_ID_MAX + 1); i++) {
- acpi_gbl_table_lists[i].next = NULL;
- acpi_gbl_table_lists[i].count = 0;
- }
-
/* Mutex locked flags */
for (i = 0; i < ACPI_NUM_MUTEX; i++) {
@@ -773,6 +672,7 @@ void acpi_ut_init_globals(void)
/* GPE support */
+ acpi_gpe_count = 0;
acpi_gbl_gpe_xrupt_list_head = NULL;
acpi_gbl_gpe_fadt_blocks[0] = NULL;
acpi_gbl_gpe_fadt_blocks[1] = NULL;
@@ -784,25 +684,15 @@ void acpi_ut_init_globals(void)
acpi_gbl_exception_handler = NULL;
acpi_gbl_init_handler = NULL;
- /* Global "typed" ACPI table pointers */
-
- acpi_gbl_RSDP = NULL;
- acpi_gbl_XSDT = NULL;
- acpi_gbl_FACS = NULL;
- acpi_gbl_FADT = NULL;
- acpi_gbl_DSDT = NULL;
-
/* Global Lock support */
acpi_gbl_global_lock_semaphore = NULL;
+ acpi_gbl_global_lock_mutex = NULL;
acpi_gbl_global_lock_acquired = FALSE;
- acpi_gbl_global_lock_thread_count = 0;
acpi_gbl_global_lock_handle = 0;
/* Miscellaneous variables */
- acpi_gbl_table_flags = ACPI_PHYSICAL_POINTER;
- acpi_gbl_rsdp_original_location = 0;
acpi_gbl_cm_single_step = FALSE;
acpi_gbl_db_terminate_threads = FALSE;
acpi_gbl_shutdown = FALSE;
@@ -837,8 +727,13 @@ void acpi_ut_init_globals(void)
acpi_gbl_lowest_stack_pointer = ACPI_SIZE_MAX;
#endif
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+ acpi_gbl_display_final_mem_stats = FALSE;
+#endif
+
return_VOID;
}
ACPI_EXPORT_SYMBOL(acpi_dbg_level)
ACPI_EXPORT_SYMBOL(acpi_dbg_layer)
+ACPI_EXPORT_SYMBOL(acpi_gpe_count)
diff --git a/drivers/acpi/utilities/utinit.c b/drivers/acpi/utilities/utinit.c
index ff76055eb7d..ad3c0d0a5cf 100644
--- a/drivers/acpi/utilities/utinit.c
+++ b/drivers/acpi/utilities/utinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -44,119 +44,14 @@
#include <acpi/acpi.h>
#include <acpi/acnamesp.h>
#include <acpi/acevents.h>
+#include <acpi/actables.h>
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utinit")
/* Local prototypes */
-static void
-acpi_ut_fadt_register_error(char *register_name, u32 value, u8 offset);
-
static void acpi_ut_terminate(void);
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_fadt_register_error
- *
- * PARAMETERS: register_name - Pointer to string identifying register
- * Value - Actual register contents value
- * Offset - Byte offset in the FADT
- *
- * RETURN: AE_BAD_VALUE
- *
- * DESCRIPTION: Display failure message
- *
- ******************************************************************************/
-
-static void
-acpi_ut_fadt_register_error(char *register_name, u32 value, u8 offset)
-{
-
- ACPI_WARNING((AE_INFO,
- "Invalid FADT value %s=%X at offset %X FADT=%p",
- register_name, value, offset, acpi_gbl_FADT));
-}
-
-/******************************************************************************
- *
- * FUNCTION: acpi_ut_validate_fadt
- *
- * PARAMETERS: None
- *
- * RETURN: Status
- *
- * DESCRIPTION: Validate various ACPI registers in the FADT
- *
- ******************************************************************************/
-
-acpi_status acpi_ut_validate_fadt(void)
-{
-
- /*
- * Verify Fixed ACPI Description Table fields,
- * but don't abort on any problems, just display error
- */
- if (acpi_gbl_FADT->pm1_evt_len < 4) {
- acpi_ut_fadt_register_error("PM1_EVT_LEN",
- (u32) acpi_gbl_FADT->pm1_evt_len,
- ACPI_FADT_OFFSET(pm1_evt_len));
- }
-
- if (!acpi_gbl_FADT->pm1_cnt_len) {
- acpi_ut_fadt_register_error("PM1_CNT_LEN", 0,
- ACPI_FADT_OFFSET(pm1_cnt_len));
- }
-
- if (!acpi_gbl_FADT->xpm1a_evt_blk.address) {
- acpi_ut_fadt_register_error("X_PM1a_EVT_BLK", 0,
- ACPI_FADT_OFFSET(xpm1a_evt_blk.
- address));
- }
-
- if (!acpi_gbl_FADT->xpm1a_cnt_blk.address) {
- acpi_ut_fadt_register_error("X_PM1a_CNT_BLK", 0,
- ACPI_FADT_OFFSET(xpm1a_cnt_blk.
- address));
- }
-
- if (!acpi_gbl_FADT->xpm_tmr_blk.address) {
- acpi_ut_fadt_register_error("X_PM_TMR_BLK", 0,
- ACPI_FADT_OFFSET(xpm_tmr_blk.
- address));
- }
-
- if ((acpi_gbl_FADT->xpm2_cnt_blk.address &&
- !acpi_gbl_FADT->pm2_cnt_len)) {
- acpi_ut_fadt_register_error("PM2_CNT_LEN",
- (u32) acpi_gbl_FADT->pm2_cnt_len,
- ACPI_FADT_OFFSET(pm2_cnt_len));
- }
-
- if (acpi_gbl_FADT->pm_tm_len < 4) {
- acpi_ut_fadt_register_error("PM_TM_LEN",
- (u32) acpi_gbl_FADT->pm_tm_len,
- ACPI_FADT_OFFSET(pm_tm_len));
- }
-
- /* Length of GPE blocks must be a multiple of 2 */
-
- if (acpi_gbl_FADT->xgpe0_blk.address &&
- (acpi_gbl_FADT->gpe0_blk_len & 1)) {
- acpi_ut_fadt_register_error("(x)GPE0_BLK_LEN",
- (u32) acpi_gbl_FADT->gpe0_blk_len,
- ACPI_FADT_OFFSET(gpe0_blk_len));
- }
-
- if (acpi_gbl_FADT->xgpe1_blk.address &&
- (acpi_gbl_FADT->gpe1_blk_len & 1)) {
- acpi_ut_fadt_register_error("(x)GPE1_BLK_LEN",
- (u32) acpi_gbl_FADT->gpe1_blk_len,
- ACPI_FADT_OFFSET(gpe1_blk_len));
- }
-
- return (AE_OK);
-}
-
/******************************************************************************
*
* FUNCTION: acpi_ut_terminate
@@ -178,7 +73,6 @@ static void acpi_ut_terminate(void)
ACPI_FUNCTION_TRACE(ut_terminate);
- /* Free global tables, etc. */
/* Free global GPE blocks and related info structures */
gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head;
@@ -239,6 +133,10 @@ void acpi_ut_subsystem_shutdown(void)
acpi_ns_terminate();
+ /* Delete the ACPI tables */
+
+ acpi_tb_terminate();
+
/* Close the globals */
acpi_ut_terminate();
diff --git a/drivers/acpi/utilities/utmath.c b/drivers/acpi/utilities/utmath.c
index 19d74bedce2..0c56a0d20b2 100644
--- a/drivers/acpi/utilities/utmath.c
+++ b/drivers/acpi/utilities/utmath.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c
index 6d8a8211be9..50133fffe42 100644
--- a/drivers/acpi/utilities/utmisc.c
+++ b/drivers/acpi/utilities/utmisc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -51,6 +51,78 @@ ACPI_MODULE_NAME("utmisc")
/*******************************************************************************
*
+ * FUNCTION: acpi_ut_validate_exception
+ *
+ * PARAMETERS: Status - The acpi_status code to be formatted
+ *
+ * RETURN: A string containing the exception text. NULL if exception is
+ * not valid.
+ *
+ * DESCRIPTION: This function validates and translates an ACPI exception into
+ * an ASCII string.
+ *
+ ******************************************************************************/
+const char *acpi_ut_validate_exception(acpi_status status)
+{
+ acpi_status sub_status;
+ const char *exception = NULL;
+
+ ACPI_FUNCTION_ENTRY();
+
+ /*
+ * Status is composed of two parts, a "type" and an actual code
+ */
+ sub_status = (status & ~AE_CODE_MASK);
+
+ switch (status & AE_CODE_MASK) {
+ case AE_CODE_ENVIRONMENTAL:
+
+ if (sub_status <= AE_CODE_ENV_MAX) {
+ exception = acpi_gbl_exception_names_env[sub_status];
+ }
+ break;
+
+ case AE_CODE_PROGRAMMER:
+
+ if (sub_status <= AE_CODE_PGM_MAX) {
+ exception =
+ acpi_gbl_exception_names_pgm[sub_status - 1];
+ }
+ break;
+
+ case AE_CODE_ACPI_TABLES:
+
+ if (sub_status <= AE_CODE_TBL_MAX) {
+ exception =
+ acpi_gbl_exception_names_tbl[sub_status - 1];
+ }
+ break;
+
+ case AE_CODE_AML:
+
+ if (sub_status <= AE_CODE_AML_MAX) {
+ exception =
+ acpi_gbl_exception_names_aml[sub_status - 1];
+ }
+ break;
+
+ case AE_CODE_CONTROL:
+
+ if (sub_status <= AE_CODE_CTRL_MAX) {
+ exception =
+ acpi_gbl_exception_names_ctrl[sub_status - 1];
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return (ACPI_CAST_PTR(const char, exception));
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_ut_is_aml_table
*
* PARAMETERS: Table - An ACPI table
@@ -62,14 +134,15 @@ ACPI_MODULE_NAME("utmisc")
* data tables that do not contain AML code.
*
******************************************************************************/
+
u8 acpi_ut_is_aml_table(struct acpi_table_header *table)
{
/* These are the only tables that contain executable AML */
- if (ACPI_COMPARE_NAME(table->signature, DSDT_SIG) ||
- ACPI_COMPARE_NAME(table->signature, PSDT_SIG) ||
- ACPI_COMPARE_NAME(table->signature, SSDT_SIG)) {
+ if (ACPI_COMPARE_NAME(table->signature, ACPI_SIG_DSDT) ||
+ ACPI_COMPARE_NAME(table->signature, ACPI_SIG_PSDT) ||
+ ACPI_COMPARE_NAME(table->signature, ACPI_SIG_SSDT)) {
return (TRUE);
}
@@ -418,7 +491,7 @@ u32 acpi_ut_dword_byte_swap(u32 value)
void acpi_ut_set_integer_width(u8 revision)
{
- if (revision <= 1) {
+ if (revision < 2) {
/* 32-bit case */
@@ -582,26 +655,25 @@ u8 acpi_ut_valid_acpi_name(u32 name)
*
******************************************************************************/
-acpi_name acpi_ut_repair_name(acpi_name name)
+acpi_name acpi_ut_repair_name(char *name)
{
- char *name_ptr = ACPI_CAST_PTR(char, &name);
- char new_name[ACPI_NAME_SIZE];
acpi_native_uint i;
+ char new_name[ACPI_NAME_SIZE];
for (i = 0; i < ACPI_NAME_SIZE; i++) {
- new_name[i] = name_ptr[i];
+ new_name[i] = name[i];
/*
* Replace a bad character with something printable, yet technically
* still invalid. This prevents any collisions with existing "good"
* names in the namespace.
*/
- if (!acpi_ut_valid_acpi_char(name_ptr[i], i)) {
+ if (!acpi_ut_valid_acpi_char(name[i], i)) {
new_name[i] = '*';
}
}
- return (*ACPI_CAST_PTR(u32, new_name));
+ return (*(u32 *) new_name);
}
/*******************************************************************************
@@ -996,9 +1068,13 @@ acpi_ut_info(char *module_name, u32 line_number, char *format, ...)
{
va_list args;
- acpi_os_printf("ACPI (%s-%04d): ", module_name, line_number);
+ /*
+ * Removed module_name, line_number, and acpica version, not needed
+ * for info output
+ */
+ acpi_os_printf("ACPI: ");
va_start(args, format);
acpi_os_vprintf(format, args);
- acpi_os_printf(" [%X]\n", ACPI_CA_VERSION);
+ acpi_os_printf("\n");
}
diff --git a/drivers/acpi/utilities/utmutex.c b/drivers/acpi/utilities/utmutex.c
index 180e73ceb6e..cbad2ef5987 100644
--- a/drivers/acpi/utilities/utmutex.c
+++ b/drivers/acpi/utilities/utmutex.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/utilities/utobject.c b/drivers/acpi/utilities/utobject.c
index ba7d8ac702d..4696124759e 100644
--- a/drivers/acpi/utilities/utobject.c
+++ b/drivers/acpi/utilities/utobject.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/utilities/utresrc.c b/drivers/acpi/utilities/utresrc.c
index 5a2de92831d..e8fe1ba6cc2 100644
--- a/drivers/acpi/utilities/utresrc.c
+++ b/drivers/acpi/utilities/utresrc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/utilities/utstate.c b/drivers/acpi/utilities/utstate.c
index eaa13d05c85..edcaafad0a3 100644
--- a/drivers/acpi/utilities/utstate.c
+++ b/drivers/acpi/utilities/utstate.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/utilities/utxface.c b/drivers/acpi/utilities/utxface.c
index 3538f69c82a..de3276f4f46 100644
--- a/drivers/acpi/utilities/utxface.c
+++ b/drivers/acpi/utilities/utxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -67,6 +67,7 @@ acpi_status acpi_initialize_subsystem(void)
ACPI_FUNCTION_TRACE(acpi_initialize_subsystem);
+ acpi_gbl_startup_flags = ACPI_SUBSYSTEM_INITIALIZE;
ACPI_DEBUG_EXEC(acpi_ut_init_stack_ptr_trace());
/* Initialize the OS-Dependent layer */
@@ -127,20 +128,6 @@ acpi_status acpi_enable_subsystem(u32 flags)
ACPI_FUNCTION_TRACE(acpi_enable_subsystem);
- /*
- * We must initialize the hardware before we can enable ACPI.
- * The values from the FADT are validated here.
- */
- if (!(flags & ACPI_NO_HARDWARE_INIT)) {
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "[Init] Initializing ACPI hardware\n"));
-
- status = acpi_hw_initialize();
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
- }
-
/* Enable ACPI mode */
if (!(flags & ACPI_NO_ACPI_ENABLE)) {
@@ -398,7 +385,6 @@ acpi_status acpi_get_system_info(struct acpi_buffer * out_buffer)
{
struct acpi_system_info *info_ptr;
acpi_status status;
- u32 i;
ACPI_FUNCTION_TRACE(acpi_get_system_info);
@@ -431,9 +417,7 @@ acpi_status acpi_get_system_info(struct acpi_buffer * out_buffer)
/* Timer resolution - 24 or 32 bits */
- if (!acpi_gbl_FADT) {
- info_ptr->timer_resolution = 0;
- } else if (acpi_gbl_FADT->tmr_val_ext == 0) {
+ if (acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER) {
info_ptr->timer_resolution = 24;
} else {
info_ptr->timer_resolution = 32;
@@ -449,13 +433,6 @@ acpi_status acpi_get_system_info(struct acpi_buffer * out_buffer)
info_ptr->debug_layer = acpi_dbg_layer;
info_ptr->debug_level = acpi_dbg_level;
- /* Current status of the ACPI tables, per table type */
-
- info_ptr->num_table_types = ACPI_TABLE_ID_MAX + 1;
- for (i = 0; i < (ACPI_TABLE_ID_MAX + 1); i++) {
- info_ptr->table_info[i].count = acpi_gbl_table_lists[i].count;
- }
-
return_ACPI_STATUS(AE_OK);
}
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index 3d54680d033..e0b97add8c6 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -32,6 +32,7 @@
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#include <linux/backlight.h>
#include <asm/uaccess.h>
#include <acpi/acpi_bus.h>
@@ -56,6 +57,12 @@
#define ACPI_VIDEO_HEAD_INVALID (~0u - 1)
#define ACPI_VIDEO_HEAD_END (~0u)
+#define MAX_NAME_LEN 20
+
+#define ACPI_VIDEO_DISPLAY_CRT 1
+#define ACPI_VIDEO_DISPLAY_TV 2
+#define ACPI_VIDEO_DISPLAY_DVI 3
+#define ACPI_VIDEO_DISPLAY_LCD 4
#define _COMPONENT ACPI_VIDEO_COMPONENT
ACPI_MODULE_NAME("acpi_video")
@@ -66,16 +73,14 @@ MODULE_LICENSE("GPL");
static int acpi_video_bus_add(struct acpi_device *device);
static int acpi_video_bus_remove(struct acpi_device *device, int type);
-static int acpi_video_bus_match(struct acpi_device *device,
- struct acpi_driver *driver);
static struct acpi_driver acpi_video_bus = {
.name = ACPI_VIDEO_DRIVER_NAME,
.class = ACPI_VIDEO_CLASS,
+ .ids = ACPI_VIDEO_HID,
.ops = {
.add = acpi_video_bus_add,
.remove = acpi_video_bus_remove,
- .match = acpi_video_bus_match,
},
};
@@ -133,20 +138,21 @@ struct acpi_video_device_flags {
u8 crt:1;
u8 lcd:1;
u8 tvout:1;
+ u8 dvi:1;
u8 bios:1;
u8 unknown:1;
- u8 reserved:3;
+ u8 reserved:2;
};
struct acpi_video_device_cap {
u8 _ADR:1; /*Return the unique ID */
u8 _BCL:1; /*Query list of brightness control levels supported */
u8 _BCM:1; /*Set the brightness level */
+ u8 _BQC:1; /* Get current brightness level */
u8 _DDC:1; /*Return the EDID for this device */
u8 _DCS:1; /*Return status of output device */
u8 _DGS:1; /*Query graphics state */
u8 _DSS:1; /*Device state set */
- u8 _reserved:1;
};
struct acpi_video_device_brightness {
@@ -163,6 +169,8 @@ struct acpi_video_device {
struct acpi_video_bus *video;
struct acpi_device *dev;
struct acpi_video_device_brightness *brightness;
+ struct backlight_device *backlight;
+ struct backlight_properties *data;
};
/* bus */
@@ -257,11 +265,35 @@ static void acpi_video_device_bind(struct acpi_video_bus *video,
struct acpi_video_device *device);
static int acpi_video_device_enumerate(struct acpi_video_bus *video);
static int acpi_video_switch_output(struct acpi_video_bus *video, int event);
+static int acpi_video_device_lcd_set_level(struct acpi_video_device *device,
+ int level);
+static int acpi_video_device_lcd_get_level_current(
+ struct acpi_video_device *device,
+ unsigned long *level);
static int acpi_video_get_next_level(struct acpi_video_device *device,
u32 level_current, u32 event);
static void acpi_video_switch_brightness(struct acpi_video_device *device,
int event);
+/*backlight device sysfs support*/
+static int acpi_video_get_brightness(struct backlight_device *bd)
+{
+ unsigned long cur_level;
+ struct acpi_video_device *vd =
+ (struct acpi_video_device *)class_get_devdata(&bd->class_dev);
+ acpi_video_device_lcd_get_level_current(vd, &cur_level);
+ return (int) cur_level;
+}
+
+static int acpi_video_set_brightness(struct backlight_device *bd)
+{
+ int request_level = bd->props->brightness;
+ struct acpi_video_device *vd =
+ (struct acpi_video_device *)class_get_devdata(&bd->class_dev);
+ acpi_video_device_lcd_set_level(vd, request_level);
+ return 0;
+}
+
/* --------------------------------------------------------------------------
Video Management
-------------------------------------------------------------------------- */
@@ -499,6 +531,7 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
acpi_integer status;
acpi_handle h_dummy1;
int i;
+ u32 max_level = 0;
union acpi_object *obj = NULL;
struct acpi_video_device_brightness *br = NULL;
@@ -514,6 +547,8 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCM", &h_dummy1))) {
device->cap._BCM = 1;
}
+ if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle,"_BQC",&h_dummy1)))
+ device->cap._BQC = 1;
if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DDC", &h_dummy1))) {
device->cap._DDC = 1;
}
@@ -550,6 +585,8 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
continue;
}
br->levels[count] = (u32) o->integer.value;
+ if (br->levels[count] > max_level)
+ max_level = br->levels[count];
count++;
}
out:
@@ -568,6 +605,37 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
kfree(obj);
+ if (device->cap._BCL && device->cap._BCM && device->cap._BQC){
+ unsigned long tmp;
+ static int count = 0;
+ char *name;
+ struct backlight_properties *acpi_video_data;
+
+ name = kzalloc(MAX_NAME_LEN, GFP_KERNEL);
+ if (!name)
+ return;
+
+ acpi_video_data = kzalloc(
+ sizeof(struct backlight_properties),
+ GFP_KERNEL);
+ if (!acpi_video_data){
+ kfree(name);
+ return;
+ }
+ acpi_video_data->owner = THIS_MODULE;
+ acpi_video_data->get_brightness =
+ acpi_video_get_brightness;
+ acpi_video_data->update_status =
+ acpi_video_set_brightness;
+ sprintf(name, "acpi_video%d", count++);
+ device->data = acpi_video_data;
+ acpi_video_data->max_brightness = max_level;
+ acpi_video_device_lcd_get_level_current(device, &tmp);
+ acpi_video_data->brightness = (int)tmp;
+ device->backlight = backlight_device_register(name,
+ NULL, device, acpi_video_data);
+ kfree(name);
+ }
return;
}
@@ -668,6 +736,8 @@ static int acpi_video_device_info_seq_show(struct seq_file *seq, void *offset)
seq_printf(seq, "LCD\n");
else if (dev->flags.tvout)
seq_printf(seq, "TVOUT\n");
+ else if (dev->flags.dvi)
+ seq_printf(seq, "DVI\n");
else
seq_printf(seq, "UNKNOWN\n");
@@ -1242,6 +1312,16 @@ static int acpi_video_bus_remove_fs(struct acpi_device *device)
-------------------------------------------------------------------------- */
/* device interface */
+static struct acpi_video_device_attrib*
+acpi_video_get_device_attr(struct acpi_video_bus *video, unsigned long device_id)
+{
+ int count;
+
+ for(count = 0; count < video->attached_count; count++)
+ if((video->attached_array[count].value.int_val & 0xffff) == device_id)
+ return &(video->attached_array[count].value.attrib);
+ return NULL;
+}
static int
acpi_video_bus_get_one_device(struct acpi_device *device,
@@ -1250,7 +1330,7 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
unsigned long device_id;
int status;
struct acpi_video_device *data;
-
+ struct acpi_video_device_attrib* attribute;
if (!device || !video)
return -EINVAL;
@@ -1271,20 +1351,30 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
data->video = video;
data->dev = device;
- switch (device_id & 0xffff) {
- case 0x0100:
- data->flags.crt = 1;
- break;
- case 0x0400:
- data->flags.lcd = 1;
- break;
- case 0x0200:
- data->flags.tvout = 1;
- break;
- default:
+ attribute = acpi_video_get_device_attr(video, device_id);
+
+ if((attribute != NULL) && attribute->device_id_scheme) {
+ switch (attribute->display_type) {
+ case ACPI_VIDEO_DISPLAY_CRT:
+ data->flags.crt = 1;
+ break;
+ case ACPI_VIDEO_DISPLAY_TV:
+ data->flags.tvout = 1;
+ break;
+ case ACPI_VIDEO_DISPLAY_DVI:
+ data->flags.dvi = 1;
+ break;
+ case ACPI_VIDEO_DISPLAY_LCD:
+ data->flags.lcd = 1;
+ break;
+ default:
+ data->flags.unknown = 1;
+ break;
+ }
+ if(attribute->bios_can_detect)
+ data->flags.bios = 1;
+ } else
data->flags.unknown = 1;
- break;
- }
acpi_video_device_bind(video, data);
acpi_video_device_find_cap(data);
@@ -1588,7 +1678,10 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device)
status = acpi_remove_notify_handler(device->dev->handle,
ACPI_DEVICE_NOTIFY,
acpi_video_device_notify);
-
+ if (device->backlight){
+ backlight_device_unregister(device->backlight);
+ kfree(device->data);
+ }
return 0;
}
@@ -1790,39 +1883,6 @@ static int acpi_video_bus_remove(struct acpi_device *device, int type)
return 0;
}
-static int
-acpi_video_bus_match(struct acpi_device *device, struct acpi_driver *driver)
-{
- acpi_handle h_dummy1;
- acpi_handle h_dummy2;
- acpi_handle h_dummy3;
-
-
- if (!device || !driver)
- return -EINVAL;
-
- /* Since there is no HID, CID for ACPI Video drivers, we have
- * to check well known required nodes for each feature we support.
- */
-
- /* Does this device able to support video switching ? */
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy1)) &&
- ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy2)))
- return 0;
-
- /* Does this device able to retrieve a video ROM ? */
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy1)))
- return 0;
-
- /* Does this device able to configure which video head to be POSTed ? */
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy1)) &&
- ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy2)) &&
- ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy3)))
- return 0;
-
- return -ENODEV;
-}
-
static int __init acpi_video_init(void)
{
int result = 0;
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 48616c6fee9..e2796fb40eb 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -1173,7 +1173,7 @@ static void ahci_host_intr(struct ata_port *ap)
* dangerous, we need to know more about them. Print
* more of it.
*/
- const u32 *f = pp->rx_fis + RX_FIS_SDB;
+ const __le32 *f = pp->rx_fis + RX_FIS_SDB;
ata_port_printk(ap, KERN_INFO, "Spurious SDB FIS during NCQ "
"issue=0x%x SAct=0x%x FIS=%08x:%08x%s\n",
diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c
index 46d8a94669b..5f4e82ade6c 100644
--- a/drivers/ata/sata_svw.c
+++ b/drivers/ata/sata_svw.c
@@ -116,7 +116,7 @@ static u32 k2_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
{
if (sc_reg > SCR_CONTROL)
return 0xffffffffU;
- return readl((void *) ap->ioaddr.scr_addr + (sc_reg * 4));
+ return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
}
@@ -125,7 +125,7 @@ static void k2_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
{
if (sc_reg > SCR_CONTROL)
return;
- writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4));
+ writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
}
@@ -262,7 +262,7 @@ static void k2_bmdma_start_mmio (struct ata_queued_cmd *qc)
static u8 k2_stat_check_status(struct ata_port *ap)
{
- return readl((void *) ap->ioaddr.status_addr);
+ return readl((void __iomem *) ap->ioaddr.status_addr);
}
#ifdef CONFIG_PPC_OF
diff --git a/drivers/base/class.c b/drivers/base/class.c
index 8bf2ca2e56b..96def1ddba1 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -364,7 +364,7 @@ char *make_class_name(const char *name, struct kobject *kobj)
class_name = kmalloc(size, GFP_KERNEL);
if (!class_name)
- return ERR_PTR(-ENOMEM);
+ return NULL;
strcpy(class_name, name);
strcat(class_name, ":");
@@ -411,8 +411,11 @@ static int make_deprecated_class_device_links(struct class_device *class_dev)
return 0;
class_name = make_class_name(class_dev->class->name, &class_dev->kobj);
- error = sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj,
- class_name);
+ if (class_name)
+ error = sysfs_create_link(&class_dev->dev->kobj,
+ &class_dev->kobj, class_name);
+ else
+ error = -ENOMEM;
kfree(class_name);
return error;
}
@@ -425,7 +428,8 @@ static void remove_deprecated_class_device_links(struct class_device *class_dev)
return;
class_name = make_class_name(class_dev->class->name, &class_dev->kobj);
- sysfs_remove_link(&class_dev->dev->kobj, class_name);
+ if (class_name)
+ sysfs_remove_link(&class_dev->dev->kobj, class_name);
kfree(class_name);
}
#else
@@ -863,9 +867,12 @@ int class_device_rename(struct class_device *class_dev, char *new_name)
if (class_dev->dev) {
new_class_name = make_class_name(class_dev->class->name,
&class_dev->kobj);
- sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj,
- new_class_name);
- sysfs_remove_link(&class_dev->dev->kobj, old_class_name);
+ if (new_class_name)
+ sysfs_create_link(&class_dev->dev->kobj,
+ &class_dev->kobj, new_class_name);
+ if (old_class_name)
+ sysfs_remove_link(&class_dev->dev->kobj,
+ old_class_name);
}
#endif
class_device_put(class_dev);
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 67b79a7592a..e13614241c9 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -95,6 +95,8 @@ static void device_release(struct kobject * kobj)
if (dev->release)
dev->release(dev);
+ else if (dev->type && dev->type->release)
+ dev->type->release(dev);
else if (dev->class && dev->class->dev_release)
dev->class->dev_release(dev);
else {
@@ -154,25 +156,47 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp,
"MINOR=%u", MINOR(dev->devt));
}
-#ifdef CONFIG_SYSFS_DEPRECATED
- /* add bus name (same as SUBSYSTEM, deprecated) */
- if (dev->bus)
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PHYSDEVBUS=%s", dev->bus->name);
-#endif
-
- /* add driver name (PHYSDEV* values are deprecated)*/
- if (dev->driver) {
+ if (dev->driver)
add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length,
"DRIVER=%s", dev->driver->name);
+
#ifdef CONFIG_SYSFS_DEPRECATED
+ if (dev->class) {
+ struct device *parent = dev->parent;
+
+ /* find first bus device in parent chain */
+ while (parent && !parent->bus)
+ parent = parent->parent;
+ if (parent && parent->bus) {
+ const char *path;
+
+ path = kobject_get_path(&parent->kobj, GFP_KERNEL);
+ add_uevent_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "PHYSDEVPATH=%s", path);
+ kfree(path);
+
+ add_uevent_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "PHYSDEVBUS=%s", parent->bus->name);
+
+ if (parent->driver)
+ add_uevent_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "PHYSDEVDRIVER=%s", parent->driver->name);
+ }
+ } else if (dev->bus) {
add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length,
- "PHYSDEVDRIVER=%s", dev->driver->name);
-#endif
+ "PHYSDEVBUS=%s", dev->bus->name);
+
+ if (dev->driver)
+ add_uevent_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "PHYSDEVDRIVER=%s", dev->driver->name);
}
+#endif
/* terminate, set to next free slot, shrink available space */
envp[i] = NULL;
@@ -184,19 +208,25 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp,
if (dev->bus && dev->bus->uevent) {
/* have the bus specific function add its stuff */
retval = dev->bus->uevent(dev, envp, num_envp, buffer, buffer_size);
- if (retval) {
- pr_debug ("%s - uevent() returned %d\n",
+ if (retval)
+ pr_debug ("%s: bus uevent() returned %d\n",
__FUNCTION__, retval);
- }
}
if (dev->class && dev->class->dev_uevent) {
/* have the class specific function add its stuff */
retval = dev->class->dev_uevent(dev, envp, num_envp, buffer, buffer_size);
- if (retval) {
- pr_debug("%s - dev_uevent() returned %d\n",
- __FUNCTION__, retval);
- }
+ if (retval)
+ pr_debug("%s: class uevent() returned %d\n",
+ __FUNCTION__, retval);
+ }
+
+ if (dev->type && dev->type->uevent) {
+ /* have the device type specific fuction add its stuff */
+ retval = dev->type->uevent(dev, envp, num_envp, buffer, buffer_size);
+ if (retval)
+ pr_debug("%s: dev_type uevent() returned %d\n",
+ __FUNCTION__, retval);
}
return retval;
@@ -247,37 +277,50 @@ static void device_remove_groups(struct device *dev)
static int device_add_attrs(struct device *dev)
{
struct class *class = dev->class;
+ struct device_type *type = dev->type;
int error = 0;
int i;
- if (!class)
- return 0;
-
- if (class->dev_attrs) {
+ if (class && class->dev_attrs) {
for (i = 0; attr_name(class->dev_attrs[i]); i++) {
error = device_create_file(dev, &class->dev_attrs[i]);
if (error)
break;
}
+ if (error)
+ while (--i >= 0)
+ device_remove_file(dev, &class->dev_attrs[i]);
}
- if (error)
- while (--i >= 0)
- device_remove_file(dev, &class->dev_attrs[i]);
+
+ if (type && type->attrs) {
+ for (i = 0; attr_name(type->attrs[i]); i++) {
+ error = device_create_file(dev, &type->attrs[i]);
+ if (error)
+ break;
+ }
+ if (error)
+ while (--i >= 0)
+ device_remove_file(dev, &type->attrs[i]);
+ }
+
return error;
}
static void device_remove_attrs(struct device *dev)
{
struct class *class = dev->class;
+ struct device_type *type = dev->type;
int i;
- if (!class)
- return;
-
- if (class->dev_attrs) {
+ if (class && class->dev_attrs) {
for (i = 0; attr_name(class->dev_attrs[i]); i++)
device_remove_file(dev, &class->dev_attrs[i]);
}
+
+ if (type && type->attrs) {
+ for (i = 0; attr_name(type->attrs[i]); i++)
+ device_remove_file(dev, &type->attrs[i]);
+ }
}
@@ -390,22 +433,23 @@ void device_initialize(struct device *dev)
}
#ifdef CONFIG_SYSFS_DEPRECATED
-static int setup_parent(struct device *dev, struct device *parent)
+static struct kobject * get_device_parent(struct device *dev,
+ struct device *parent)
{
/* Set the parent to the class, not the parent device */
/* this keeps sysfs from having a symlink to make old udevs happy */
if (dev->class)
- dev->kobj.parent = &dev->class->subsys.kset.kobj;
+ return &dev->class->subsys.kset.kobj;
else if (parent)
- dev->kobj.parent = &parent->kobj;
+ return &parent->kobj;
- return 0;
+ return NULL;
}
#else
-static int virtual_device_parent(struct device *dev)
+static struct kobject * virtual_device_parent(struct device *dev)
{
if (!dev->class)
- return -ENODEV;
+ return ERR_PTR(-ENODEV);
if (!dev->class->virtual_dir) {
static struct kobject *virtual_dir = NULL;
@@ -415,25 +459,31 @@ static int virtual_device_parent(struct device *dev)
dev->class->virtual_dir = kobject_add_dir(virtual_dir, dev->class->name);
}
- dev->kobj.parent = dev->class->virtual_dir;
- return 0;
+ return dev->class->virtual_dir;
}
-static int setup_parent(struct device *dev, struct device *parent)
+static struct kobject * get_device_parent(struct device *dev,
+ struct device *parent)
{
- int error;
-
/* if this is a class device, and has no parent, create one */
if ((dev->class) && (parent == NULL)) {
- error = virtual_device_parent(dev);
- if (error)
- return error;
+ return virtual_device_parent(dev);
} else if (parent)
- dev->kobj.parent = &parent->kobj;
+ return &parent->kobj;
+ return NULL;
+}
+#endif
+static int setup_parent(struct device *dev, struct device *parent)
+{
+ struct kobject *kobj;
+ kobj = get_device_parent(dev, parent);
+ if (IS_ERR(kobj))
+ return PTR_ERR(kobj);
+ if (kobj)
+ dev->kobj.parent = kobj;
return 0;
}
-#endif
/**
* device_add - add device to device hierarchy.
@@ -520,9 +570,13 @@ int device_add(struct device *dev)
&dev->kobj, dev->bus_id);
#ifdef CONFIG_SYSFS_DEPRECATED
if (parent) {
- sysfs_create_link(&dev->kobj, &dev->parent->kobj, "device");
- class_name = make_class_name(dev->class->name, &dev->kobj);
- sysfs_create_link(&dev->parent->kobj, &dev->kobj, class_name);
+ sysfs_create_link(&dev->kobj, &dev->parent->kobj,
+ "device");
+ class_name = make_class_name(dev->class->name,
+ &dev->kobj);
+ if (class_name)
+ sysfs_create_link(&dev->parent->kobj,
+ &dev->kobj, class_name);
}
#endif
}
@@ -535,7 +589,8 @@ int device_add(struct device *dev)
goto PMError;
if ((error = bus_add_device(dev)))
goto BusError;
- kobject_uevent(&dev->kobj, KOBJ_ADD);
+ if (!dev->uevent_suppress)
+ kobject_uevent(&dev->kobj, KOBJ_ADD);
if ((error = bus_attach_device(dev)))
goto AttachError;
if (parent)
@@ -665,7 +720,9 @@ void device_del(struct device * dev)
if (parent) {
char *class_name = make_class_name(dev->class->name,
&dev->kobj);
- sysfs_remove_link(&dev->parent->kobj, class_name);
+ if (class_name)
+ sysfs_remove_link(&dev->parent->kobj,
+ class_name);
kfree(class_name);
sysfs_remove_link(&dev->kobj, "device");
}
@@ -968,20 +1025,25 @@ static int device_move_class_links(struct device *dev,
class_name = make_class_name(dev->class->name, &dev->kobj);
if (!class_name) {
- error = PTR_ERR(class_name);
- class_name = NULL;
+ error = -ENOMEM;
goto out;
}
if (old_parent) {
sysfs_remove_link(&dev->kobj, "device");
sysfs_remove_link(&old_parent->kobj, class_name);
}
- error = sysfs_create_link(&dev->kobj, &new_parent->kobj, "device");
- if (error)
- goto out;
- error = sysfs_create_link(&new_parent->kobj, &dev->kobj, class_name);
- if (error)
- sysfs_remove_link(&dev->kobj, "device");
+ if (new_parent) {
+ error = sysfs_create_link(&dev->kobj, &new_parent->kobj,
+ "device");
+ if (error)
+ goto out;
+ error = sysfs_create_link(&new_parent->kobj, &dev->kobj,
+ class_name);
+ if (error)
+ sysfs_remove_link(&dev->kobj, "device");
+ }
+ else
+ error = 0;
out:
kfree(class_name);
return error;
@@ -993,29 +1055,28 @@ out:
/**
* device_move - moves a device to a new parent
* @dev: the pointer to the struct device to be moved
- * @new_parent: the new parent of the device
+ * @new_parent: the new parent of the device (can by NULL)
*/
int device_move(struct device *dev, struct device *new_parent)
{
int error;
struct device *old_parent;
+ struct kobject *new_parent_kobj;
dev = get_device(dev);
if (!dev)
return -EINVAL;
- if (!device_is_registered(dev)) {
- error = -EINVAL;
- goto out;
- }
new_parent = get_device(new_parent);
- if (!new_parent) {
- error = -EINVAL;
+ new_parent_kobj = get_device_parent (dev, new_parent);
+ if (IS_ERR(new_parent_kobj)) {
+ error = PTR_ERR(new_parent_kobj);
+ put_device(new_parent);
goto out;
}
pr_debug("DEVICE: moving '%s' to '%s'\n", dev->bus_id,
- new_parent->bus_id);
- error = kobject_move(&dev->kobj, &new_parent->kobj);
+ new_parent ? new_parent->bus_id : "<NULL>");
+ error = kobject_move(&dev->kobj, new_parent_kobj);
if (error) {
put_device(new_parent);
goto out;
@@ -1024,7 +1085,8 @@ int device_move(struct device *dev, struct device *new_parent)
dev->parent = new_parent;
if (old_parent)
klist_remove(&dev->knode_parent);
- klist_add_tail(&dev->knode_parent, &new_parent->klist_children);
+ if (new_parent)
+ klist_add_tail(&dev->knode_parent, &new_parent->klist_children);
if (!dev->class)
goto out_put;
error = device_move_class_links(dev, old_parent, new_parent);
@@ -1032,7 +1094,8 @@ int device_move(struct device *dev, struct device *new_parent)
/* We ignore errors on cleanup since we're hosed anyway... */
device_move_class_links(dev, new_parent, old_parent);
if (!kobject_move(&dev->kobj, &old_parent->kobj)) {
- klist_remove(&dev->knode_parent);
+ if (new_parent)
+ klist_remove(&dev->knode_parent);
if (old_parent)
klist_add_tail(&dev->knode_parent,
&old_parent->klist_children);
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 510e7884975..b5bf243d9cd 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -86,8 +86,12 @@ static void driver_sysfs_remove(struct device *dev)
*/
int device_bind_driver(struct device *dev)
{
- driver_bound(dev);
- return driver_sysfs_add(dev);
+ int ret;
+
+ ret = driver_sysfs_add(dev);
+ if (!ret)
+ driver_bound(dev);
+ return ret;
}
struct stupid_thread_structure {
@@ -136,18 +140,17 @@ probe_failed:
driver_sysfs_remove(dev);
dev->driver = NULL;
- if (ret == -ENODEV || ret == -ENXIO) {
- /* Driver matched, but didn't support device
- * or device not found.
- * Not an error; keep going.
- */
- ret = 0;
- } else {
+ if (ret != -ENODEV && ret != -ENXIO) {
/* driver matched but the probe failed */
printk(KERN_WARNING
"%s: probe of %s failed with error %d\n",
drv->name, dev->bus_id, ret);
}
+ /*
+ * Ignore errors returned by ->probe so that the next driver can try
+ * its luck.
+ */
+ ret = 0;
done:
kfree(data);
atomic_dec(&probe_count);
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 64558f45e6b..c0a979a5074 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -35,7 +35,7 @@ enum {
FW_STATUS_READY_NOHOTPLUG,
};
-static int loading_timeout = 10; /* In seconds */
+static int loading_timeout = 60; /* In seconds */
/* fw_lock could be moved to 'struct firmware_priv' but since it is just
* guarding for corner cases a global lock should be OK */
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index f9c903ba9fc..30480f6f2af 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -611,8 +611,15 @@ EXPORT_SYMBOL_GPL(platform_bus_type);
int __init platform_bus_init(void)
{
- device_register(&platform_bus);
- return bus_register(&platform_bus_type);
+ int error;
+
+ error = device_register(&platform_bus);
+ if (error)
+ return error;
+ error = bus_register(&platform_bus_type);
+ if (error)
+ device_unregister(&platform_bus);
+ return error;
}
#ifndef ARCH_HAS_DMA_GET_REQUIRED_MASK
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 9e43e39dc35..d08bb4ee130 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -610,6 +610,13 @@ config HVC_RTAS
help
IBM Console device driver which makes use of RTAS
+config HVC_BEAT
+ bool "Toshiba's Beat Hypervisor Console support"
+ depends on PPC_CELLEB
+ select HVC_DRIVER
+ help
+ Toshiba's Cell Reference Set Beat Console device driver
+
config HVCS
tristate "IBM Hypervisor Virtual Console Server support"
depends on PPC_PSERIES
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index fc110637ced..ae8567cc529 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -45,6 +45,7 @@ obj-$(CONFIG_RIO) += rio/ generic_serial.o
obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi.o
obj-$(CONFIG_HVC_ISERIES) += hvc_iseries.o
obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o
+obj-$(CONFIG_HVC_BEAT) += hvc_beat.o
obj-$(CONFIG_HVC_DRIVER) += hvc_console.o
obj-$(CONFIG_RAW_DRIVER) += raw.o
obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o
@@ -59,6 +60,8 @@ obj-$(CONFIG_BRIQ_PANEL) += briq_panel.o
obj-$(CONFIG_PRINTER) += lp.o
obj-$(CONFIG_TIPAR) += tipar.o
+obj-$(CONFIG_APM_EMULATION) += apm-emulation.o
+
obj-$(CONFIG_DTLK) += dtlk.o
obj-$(CONFIG_R3964) += n_r3964.o
obj-$(CONFIG_APPLICOM) += applicom.o
diff --git a/drivers/char/apm-emulation.c b/drivers/char/apm-emulation.c
new file mode 100644
index 00000000000..179c7a3b6e7
--- /dev/null
+++ b/drivers/char/apm-emulation.c
@@ -0,0 +1,672 @@
+/*
+ * bios-less APM driver for ARM Linux
+ * Jamey Hicks <jamey@crl.dec.com>
+ * adapted from the APM BIOS driver for Linux by Stephen Rothwell (sfr@linuxcare.com)
+ *
+ * APM 1.2 Reference:
+ * Intel Corporation, Microsoft Corporation. Advanced Power Management
+ * (APM) BIOS Interface Specification, Revision 1.2, February 1996.
+ *
+ * [This document is available from Microsoft at:
+ * http://www.microsoft.com/hwdev/busbios/amp_12.htm]
+ */
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/miscdevice.h>
+#include <linux/apm_bios.h>
+#include <linux/capability.h>
+#include <linux/sched.h>
+#include <linux/pm.h>
+#include <linux/apm-emulation.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/init.h>
+#include <linux/completion.h>
+#include <linux/kthread.h>
+#include <linux/delay.h>
+
+#include <asm/system.h>
+
+/*
+ * The apm_bios device is one of the misc char devices.
+ * This is its minor number.
+ */
+#define APM_MINOR_DEV 134
+
+/*
+ * See Documentation/Config.help for the configuration options.
+ *
+ * Various options can be changed at boot time as follows:
+ * (We allow underscores for compatibility with the modules code)
+ * apm=on/off enable/disable APM
+ */
+
+/*
+ * Maximum number of events stored
+ */
+#define APM_MAX_EVENTS 16
+
+struct apm_queue {
+ unsigned int event_head;
+ unsigned int event_tail;
+ apm_event_t events[APM_MAX_EVENTS];
+};
+
+/*
+ * The per-file APM data
+ */
+struct apm_user {
+ struct list_head list;
+
+ unsigned int suser: 1;
+ unsigned int writer: 1;
+ unsigned int reader: 1;
+
+ int suspend_result;
+ unsigned int suspend_state;
+#define SUSPEND_NONE 0 /* no suspend pending */
+#define SUSPEND_PENDING 1 /* suspend pending read */
+#define SUSPEND_READ 2 /* suspend read, pending ack */
+#define SUSPEND_ACKED 3 /* suspend acked */
+#define SUSPEND_WAIT 4 /* waiting for suspend */
+#define SUSPEND_DONE 5 /* suspend completed */
+
+ struct apm_queue queue;
+};
+
+/*
+ * Local variables
+ */
+static int suspends_pending;
+static int apm_disabled;
+static struct task_struct *kapmd_tsk;
+
+static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
+static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
+
+/*
+ * This is a list of everyone who has opened /dev/apm_bios
+ */
+static DECLARE_RWSEM(user_list_lock);
+static LIST_HEAD(apm_user_list);
+
+/*
+ * kapmd info. kapmd provides us a process context to handle
+ * "APM" events within - specifically necessary if we're going
+ * to be suspending the system.
+ */
+static DECLARE_WAIT_QUEUE_HEAD(kapmd_wait);
+static DEFINE_SPINLOCK(kapmd_queue_lock);
+static struct apm_queue kapmd_queue;
+
+static DEFINE_MUTEX(state_lock);
+
+static const char driver_version[] = "1.13"; /* no spaces */
+
+
+
+/*
+ * Compatibility cruft until the IPAQ people move over to the new
+ * interface.
+ */
+static void __apm_get_power_status(struct apm_power_info *info)
+{
+}
+
+/*
+ * This allows machines to provide their own "apm get power status" function.
+ */
+void (*apm_get_power_status)(struct apm_power_info *) = __apm_get_power_status;
+EXPORT_SYMBOL(apm_get_power_status);
+
+
+/*
+ * APM event queue management.
+ */
+static inline int queue_empty(struct apm_queue *q)
+{
+ return q->event_head == q->event_tail;
+}
+
+static inline apm_event_t queue_get_event(struct apm_queue *q)
+{
+ q->event_tail = (q->event_tail + 1) % APM_MAX_EVENTS;
+ return q->events[q->event_tail];
+}
+
+static void queue_add_event(struct apm_queue *q, apm_event_t event)
+{
+ q->event_head = (q->event_head + 1) % APM_MAX_EVENTS;
+ if (q->event_head == q->event_tail) {
+ static int notified;
+
+ if (notified++ == 0)
+ printk(KERN_ERR "apm: an event queue overflowed\n");
+ q->event_tail = (q->event_tail + 1) % APM_MAX_EVENTS;
+ }
+ q->events[q->event_head] = event;
+}
+
+static void queue_event(apm_event_t event)
+{
+ struct apm_user *as;
+
+ down_read(&user_list_lock);
+ list_for_each_entry(as, &apm_user_list, list) {
+ if (as->reader)
+ queue_add_event(&as->queue, event);
+ }
+ up_read(&user_list_lock);
+ wake_up_interruptible(&apm_waitqueue);
+}
+
+/*
+ * queue_suspend_event - queue an APM suspend event.
+ *
+ * Check that we're in a state where we can suspend. If not,
+ * return -EBUSY. Otherwise, queue an event to all "writer"
+ * users. If there are no "writer" users, return '1' to
+ * indicate that we can immediately suspend.
+ */
+static int queue_suspend_event(apm_event_t event, struct apm_user *sender)
+{
+ struct apm_user *as;
+ int ret = 1;
+
+ mutex_lock(&state_lock);
+ down_read(&user_list_lock);
+
+ /*
+ * If a thread is still processing, we can't suspend, so reject
+ * the request.
+ */
+ list_for_each_entry(as, &apm_user_list, list) {
+ if (as != sender && as->reader && as->writer && as->suser &&
+ as->suspend_state != SUSPEND_NONE) {
+ ret = -EBUSY;
+ goto out;
+ }
+ }
+
+ list_for_each_entry(as, &apm_user_list, list) {
+ if (as != sender && as->reader && as->writer && as->suser) {
+ as->suspend_state = SUSPEND_PENDING;
+ suspends_pending++;
+ queue_add_event(&as->queue, event);
+ ret = 0;
+ }
+ }
+ out:
+ up_read(&user_list_lock);
+ mutex_unlock(&state_lock);
+ wake_up_interruptible(&apm_waitqueue);
+ return ret;
+}
+
+static void apm_suspend(void)
+{
+ struct apm_user *as;
+ int err = pm_suspend(PM_SUSPEND_MEM);
+
+ /*
+ * Anyone on the APM queues will think we're still suspended.
+ * Send a message so everyone knows we're now awake again.
+ */
+ queue_event(APM_NORMAL_RESUME);
+
+ /*
+ * Finally, wake up anyone who is sleeping on the suspend.
+ */
+ mutex_lock(&state_lock);
+ down_read(&user_list_lock);
+ list_for_each_entry(as, &apm_user_list, list) {
+ if (as->suspend_state == SUSPEND_WAIT ||
+ as->suspend_state == SUSPEND_ACKED) {
+ as->suspend_result = err;
+ as->suspend_state = SUSPEND_DONE;
+ }
+ }
+ up_read(&user_list_lock);
+ mutex_unlock(&state_lock);
+
+ wake_up(&apm_suspend_waitqueue);
+}
+
+static ssize_t apm_read(struct file *fp, char __user *buf, size_t count, loff_t *ppos)
+{
+ struct apm_user *as = fp->private_data;
+ apm_event_t event;
+ int i = count, ret = 0;
+
+ if (count < sizeof(apm_event_t))
+ return -EINVAL;
+
+ if (queue_empty(&as->queue) && fp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ wait_event_interruptible(apm_waitqueue, !queue_empty(&as->queue));
+
+ while ((i >= sizeof(event)) && !queue_empty(&as->queue)) {
+ event = queue_get_event(&as->queue);
+
+ ret = -EFAULT;
+ if (copy_to_user(buf, &event, sizeof(event)))
+ break;
+
+ mutex_lock(&state_lock);
+ if (as->suspend_state == SUSPEND_PENDING &&
+ (event == APM_SYS_SUSPEND || event == APM_USER_SUSPEND))
+ as->suspend_state = SUSPEND_READ;
+ mutex_unlock(&state_lock);
+
+ buf += sizeof(event);
+ i -= sizeof(event);
+ }
+
+ if (i < count)
+ ret = count - i;
+
+ return ret;
+}
+
+static unsigned int apm_poll(struct file *fp, poll_table * wait)
+{
+ struct apm_user *as = fp->private_data;
+
+ poll_wait(fp, &apm_waitqueue, wait);
+ return queue_empty(&as->queue) ? 0 : POLLIN | POLLRDNORM;
+}
+
+/*
+ * apm_ioctl - handle APM ioctl
+ *
+ * APM_IOC_SUSPEND
+ * This IOCTL is overloaded, and performs two functions. It is used to:
+ * - initiate a suspend
+ * - acknowledge a suspend read from /dev/apm_bios.
+ * Only when everyone who has opened /dev/apm_bios with write permission
+ * has acknowledge does the actual suspend happen.
+ */
+static int
+apm_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg)
+{
+ struct apm_user *as = filp->private_data;
+ unsigned long flags;
+ int err = -EINVAL;
+
+ if (!as->suser || !as->writer)
+ return -EPERM;
+
+ switch (cmd) {
+ case APM_IOC_SUSPEND:
+ mutex_lock(&state_lock);
+
+ as->suspend_result = -EINTR;
+
+ if (as->suspend_state == SUSPEND_READ) {
+ int pending;
+
+ /*
+ * If we read a suspend command from /dev/apm_bios,
+ * then the corresponding APM_IOC_SUSPEND ioctl is
+ * interpreted as an acknowledge.
+ */
+ as->suspend_state = SUSPEND_ACKED;
+ suspends_pending--;
+ pending = suspends_pending == 0;
+ mutex_unlock(&state_lock);
+
+ /*
+ * If there are no further acknowledges required,
+ * suspend the system.
+ */
+ if (pending)
+ apm_suspend();
+
+ /*
+ * Wait for the suspend/resume to complete. If there
+ * are pending acknowledges, we wait here for them.
+ *
+ * Note: we need to ensure that the PM subsystem does
+ * not kick us out of the wait when it suspends the
+ * threads.
+ */
+ flags = current->flags;
+ current->flags |= PF_NOFREEZE;
+
+ wait_event(apm_suspend_waitqueue,
+ as->suspend_state == SUSPEND_DONE);
+ } else {
+ as->suspend_state = SUSPEND_WAIT;
+ mutex_unlock(&state_lock);
+
+ /*
+ * Otherwise it is a request to suspend the system.
+ * Queue an event for all readers, and expect an
+ * acknowledge from all writers who haven't already
+ * acknowledged.
+ */
+ err = queue_suspend_event(APM_USER_SUSPEND, as);
+ if (err < 0) {
+ /*
+ * Avoid taking the lock here - this
+ * should be fine.
+ */
+ as->suspend_state = SUSPEND_NONE;
+ break;
+ }
+
+ if (err > 0)
+ apm_suspend();
+
+ /*
+ * Wait for the suspend/resume to complete. If there
+ * are pending acknowledges, we wait here for them.
+ *
+ * Note: we need to ensure that the PM subsystem does
+ * not kick us out of the wait when it suspends the
+ * threads.
+ */
+ flags = current->flags;
+ current->flags |= PF_NOFREEZE;
+
+ wait_event_interruptible(apm_suspend_waitqueue,
+ as->suspend_state == SUSPEND_DONE);
+ }
+
+ current->flags = flags;
+
+ mutex_lock(&state_lock);
+ err = as->suspend_result;
+ as->suspend_state = SUSPEND_NONE;
+ mutex_unlock(&state_lock);
+ break;
+ }
+
+ return err;
+}
+
+static int apm_release(struct inode * inode, struct file * filp)
+{
+ struct apm_user *as = filp->private_data;
+ int pending = 0;
+
+ filp->private_data = NULL;
+
+ down_write(&user_list_lock);
+ list_del(&as->list);
+ up_write(&user_list_lock);
+
+ /*
+ * We are now unhooked from the chain. As far as new
+ * events are concerned, we no longer exist. However, we
+ * need to balance suspends_pending, which means the
+ * possibility of sleeping.
+ */
+ mutex_lock(&state_lock);
+ if (as->suspend_state != SUSPEND_NONE) {
+ suspends_pending -= 1;
+ pending = suspends_pending == 0;
+ }
+ mutex_unlock(&state_lock);
+ if (pending)
+ apm_suspend();
+
+ kfree(as);
+ return 0;
+}
+
+static int apm_open(struct inode * inode, struct file * filp)
+{
+ struct apm_user *as;
+
+ as = kzalloc(sizeof(*as), GFP_KERNEL);
+ if (as) {
+ /*
+ * XXX - this is a tiny bit broken, when we consider BSD
+ * process accounting. If the device is opened by root, we
+ * instantly flag that we used superuser privs. Who knows,
+ * we might close the device immediately without doing a
+ * privileged operation -- cevans
+ */
+ as->suser = capable(CAP_SYS_ADMIN);
+ as->writer = (filp->f_mode & FMODE_WRITE) == FMODE_WRITE;
+ as->reader = (filp->f_mode & FMODE_READ) == FMODE_READ;
+
+ down_write(&user_list_lock);
+ list_add(&as->list, &apm_user_list);
+ up_write(&user_list_lock);
+
+ filp->private_data = as;
+ }
+
+ return as ? 0 : -ENOMEM;
+}
+
+static struct file_operations apm_bios_fops = {
+ .owner = THIS_MODULE,
+ .read = apm_read,
+ .poll = apm_poll,
+ .ioctl = apm_ioctl,
+ .open = apm_open,
+ .release = apm_release,
+};
+
+static struct miscdevice apm_device = {
+ .minor = APM_MINOR_DEV,
+ .name = "apm_bios",
+ .fops = &apm_bios_fops
+};
+
+
+#ifdef CONFIG_PROC_FS
+/*
+ * Arguments, with symbols from linux/apm_bios.h.
+ *
+ * 0) Linux driver version (this will change if format changes)
+ * 1) APM BIOS Version. Usually 1.0, 1.1 or 1.2.
+ * 2) APM flags from APM Installation Check (0x00):
+ * bit 0: APM_16_BIT_SUPPORT
+ * bit 1: APM_32_BIT_SUPPORT
+ * bit 2: APM_IDLE_SLOWS_CLOCK
+ * bit 3: APM_BIOS_DISABLED
+ * bit 4: APM_BIOS_DISENGAGED
+ * 3) AC line status
+ * 0x00: Off-line
+ * 0x01: On-line
+ * 0x02: On backup power (BIOS >= 1.1 only)
+ * 0xff: Unknown
+ * 4) Battery status
+ * 0x00: High
+ * 0x01: Low
+ * 0x02: Critical
+ * 0x03: Charging
+ * 0x04: Selected battery not present (BIOS >= 1.2 only)
+ * 0xff: Unknown
+ * 5) Battery flag
+ * bit 0: High
+ * bit 1: Low
+ * bit 2: Critical
+ * bit 3: Charging
+ * bit 7: No system battery
+ * 0xff: Unknown
+ * 6) Remaining battery life (percentage of charge):
+ * 0-100: valid
+ * -1: Unknown
+ * 7) Remaining battery life (time units):
+ * Number of remaining minutes or seconds
+ * -1: Unknown
+ * 8) min = minutes; sec = seconds
+ */
+static int apm_get_info(char *buf, char **start, off_t fpos, int length)
+{
+ struct apm_power_info info;
+ char *units;
+ int ret;
+
+ info.ac_line_status = 0xff;
+ info.battery_status = 0xff;
+ info.battery_flag = 0xff;
+ info.battery_life = -1;
+ info.time = -1;
+ info.units = -1;
+
+ if (apm_get_power_status)
+ apm_get_power_status(&info);
+
+ switch (info.units) {
+ default: units = "?"; break;
+ case 0: units = "min"; break;
+ case 1: units = "sec"; break;
+ }
+
+ ret = sprintf(buf, "%s 1.2 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
+ driver_version, APM_32_BIT_SUPPORT,
+ info.ac_line_status, info.battery_status,
+ info.battery_flag, info.battery_life,
+ info.time, units);
+
+ return ret;
+}
+#endif
+
+static int kapmd(void *arg)
+{
+ do {
+ apm_event_t event;
+ int ret;
+
+ wait_event_interruptible(kapmd_wait,
+ !queue_empty(&kapmd_queue) || kthread_should_stop());
+
+ if (kthread_should_stop())
+ break;
+
+ spin_lock_irq(&kapmd_queue_lock);
+ event = 0;
+ if (!queue_empty(&kapmd_queue))
+ event = queue_get_event(&kapmd_queue);
+ spin_unlock_irq(&kapmd_queue_lock);
+
+ switch (event) {
+ case 0:
+ break;
+
+ case APM_LOW_BATTERY:
+ case APM_POWER_STATUS_CHANGE:
+ queue_event(event);
+ break;
+
+ case APM_USER_SUSPEND:
+ case APM_SYS_SUSPEND:
+ ret = queue_suspend_event(event, NULL);
+ if (ret < 0) {
+ /*
+ * We were busy. Try again in 50ms.
+ */
+ queue_add_event(&kapmd_queue, event);
+ msleep(50);
+ }
+ if (ret > 0)
+ apm_suspend();
+ break;
+
+ case APM_CRITICAL_SUSPEND:
+ apm_suspend();
+ break;
+ }
+ } while (1);
+
+ return 0;
+}
+
+static int __init apm_init(void)
+{
+ int ret;
+
+ if (apm_disabled) {
+ printk(KERN_NOTICE "apm: disabled on user request.\n");
+ return -ENODEV;
+ }
+
+ kapmd_tsk = kthread_create(kapmd, NULL, "kapmd");
+ if (IS_ERR(kapmd_tsk)) {
+ ret = PTR_ERR(kapmd_tsk);
+ kapmd_tsk = NULL;
+ return ret;
+ }
+ kapmd_tsk->flags |= PF_NOFREEZE;
+ wake_up_process(kapmd_tsk);
+
+#ifdef CONFIG_PROC_FS
+ create_proc_info_entry("apm", 0, NULL, apm_get_info);
+#endif
+
+ ret = misc_register(&apm_device);
+ if (ret != 0) {
+ remove_proc_entry("apm", NULL);
+ kthread_stop(kapmd_tsk);
+ }
+
+ return ret;
+}
+
+static void __exit apm_exit(void)
+{
+ misc_deregister(&apm_device);
+ remove_proc_entry("apm", NULL);
+
+ kthread_stop(kapmd_tsk);
+}
+
+module_init(apm_init);
+module_exit(apm_exit);
+
+MODULE_AUTHOR("Stephen Rothwell");
+MODULE_DESCRIPTION("Advanced Power Management");
+MODULE_LICENSE("GPL");
+
+#ifndef MODULE
+static int __init apm_setup(char *str)
+{
+ while ((str != NULL) && (*str != '\0')) {
+ if (strncmp(str, "off", 3) == 0)
+ apm_disabled = 1;
+ if (strncmp(str, "on", 2) == 0)
+ apm_disabled = 0;
+ str = strchr(str, ',');
+ if (str != NULL)
+ str += strspn(str, ", \t");
+ }
+ return 1;
+}
+
+__setup("apm=", apm_setup);
+#endif
+
+/**
+ * apm_queue_event - queue an APM event for kapmd
+ * @event: APM event
+ *
+ * Queue an APM event for kapmd to process and ultimately take the
+ * appropriate action. Only a subset of events are handled:
+ * %APM_LOW_BATTERY
+ * %APM_POWER_STATUS_CHANGE
+ * %APM_USER_SUSPEND
+ * %APM_SYS_SUSPEND
+ * %APM_CRITICAL_SUSPEND
+ */
+void apm_queue_event(apm_event_t event)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&kapmd_queue_lock, flags);
+ queue_add_event(&kapmd_queue, event);
+ spin_unlock_irqrestore(&kapmd_queue_lock, flags);
+
+ wake_up_interruptible(&kapmd_wait);
+}
+EXPORT_SYMBOL(apm_queue_event);
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
index 6dcdceb8120..85d99e21e18 100644
--- a/drivers/char/drm/drmP.h
+++ b/drivers/char/drm/drmP.h
@@ -532,11 +532,13 @@ typedef struct drm_mm_node {
int free;
unsigned long start;
unsigned long size;
+ struct drm_mm *mm;
void *private;
} drm_mm_node_t;
typedef struct drm_mm {
- drm_mm_node_t root_node;
+ struct list_head fl_entry;
+ struct list_head ml_entry;
} drm_mm_t;
/**
@@ -843,9 +845,6 @@ extern void drm_mem_init(void);
extern int drm_mem_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data);
extern void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area);
-extern void *drm_ioremap(unsigned long offset, unsigned long size,
- drm_device_t * dev);
-extern void drm_ioremapfree(void *pt, unsigned long size, drm_device_t * dev);
extern DRM_AGP_MEM *drm_alloc_agp(drm_device_t * dev, int pages, u32 type);
extern int drm_free_agp(DRM_AGP_MEM * handle, int pages);
@@ -1053,33 +1052,18 @@ extern void drm_sysfs_device_remove(struct class_device *class_dev);
extern drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent,
unsigned long size,
unsigned alignment);
-extern void drm_mm_put_block(drm_mm_t *mm, drm_mm_node_t *cur);
+void drm_mm_put_block(drm_mm_node_t * cur);
extern drm_mm_node_t *drm_mm_search_free(const drm_mm_t *mm, unsigned long size,
unsigned alignment, int best_match);
extern int drm_mm_init(drm_mm_t *mm, unsigned long start, unsigned long size);
extern void drm_mm_takedown(drm_mm_t *mm);
+extern int drm_mm_clean(drm_mm_t *mm);
+extern unsigned long drm_mm_tail_space(drm_mm_t *mm);
+extern int drm_mm_remove_space_from_tail(drm_mm_t *mm, unsigned long size);
+extern int drm_mm_add_space_to_tail(drm_mm_t *mm, unsigned long size);
-/* Inline replacements for DRM_IOREMAP macros */
-static __inline__ void drm_core_ioremap(struct drm_map *map,
- struct drm_device *dev)
-{
- map->handle = drm_ioremap(map->offset, map->size, dev);
-}
-
-#if 0
-static __inline__ void drm_core_ioremap_nocache(struct drm_map *map,
- struct drm_device *dev)
-{
- map->handle = drm_ioremap_nocache(map->offset, map->size, dev);
-}
-#endif /* 0 */
-
-static __inline__ void drm_core_ioremapfree(struct drm_map *map,
- struct drm_device *dev)
-{
- if (map->handle && map->size)
- drm_ioremapfree(map->handle, map->size, dev);
-}
+extern void drm_core_ioremap(struct drm_map *map, struct drm_device *dev);
+extern void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev);
static __inline__ struct drm_map *drm_core_findmap(struct drm_device *dev,
unsigned int token)
diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c
index 9f65f5697ba..a6828cc14e5 100644
--- a/drivers/char/drm/drm_bufs.c
+++ b/drivers/char/drm/drm_bufs.c
@@ -79,14 +79,14 @@ static int drm_map_handle(drm_device_t *dev, drm_hash_item_t *hash,
if (!use_hashed_handle) {
int ret;
- hash->key = user_token;
+ hash->key = user_token >> PAGE_SHIFT;
ret = drm_ht_insert_item(&dev->map_hash, hash);
if (ret != -EINVAL)
return ret;
}
return drm_ht_just_insert_please(&dev->map_hash, hash,
user_token, 32 - PAGE_SHIFT - 3,
- PAGE_SHIFT, DRM_MAP_HASH_OFFSET);
+ 0, DRM_MAP_HASH_OFFSET >> PAGE_SHIFT);
}
/**
@@ -178,11 +178,11 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
}
}
if (map->type == _DRM_REGISTERS)
- map->handle = drm_ioremap(map->offset, map->size, dev);
+ map->handle = ioremap(map->offset, map->size);
break;
case _DRM_SHM:
- map->handle = vmalloc_32(map->size);
+ map->handle = vmalloc_user(map->size);
DRM_DEBUG("%lu %d %p\n",
map->size, drm_order(map->size), map->handle);
if (!map->handle) {
@@ -238,7 +238,7 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
list = drm_alloc(sizeof(*list), DRM_MEM_MAPS);
if (!list) {
if (map->type == _DRM_REGISTERS)
- drm_ioremapfree(map->handle, map->size, dev);
+ iounmap(map->handle);
drm_free(map, sizeof(*map), DRM_MEM_MAPS);
return -EINVAL;
}
@@ -255,14 +255,14 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
ret = drm_map_handle(dev, &list->hash, user_token, 0);
if (ret) {
if (map->type == _DRM_REGISTERS)
- drm_ioremapfree(map->handle, map->size, dev);
+ iounmap(map->handle);
drm_free(map, sizeof(*map), DRM_MEM_MAPS);
drm_free(list, sizeof(*list), DRM_MEM_MAPS);
mutex_unlock(&dev->struct_mutex);
return ret;
}
- list->user_token = list->hash.key;
+ list->user_token = list->hash.key << PAGE_SHIFT;
mutex_unlock(&dev->struct_mutex);
*maplist = list;
@@ -347,7 +347,8 @@ int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map)
if (r_list->map == map) {
list_del(list);
- drm_ht_remove_key(&dev->map_hash, r_list->user_token);
+ drm_ht_remove_key(&dev->map_hash,
+ r_list->user_token >> PAGE_SHIFT);
drm_free(list, sizeof(*list), DRM_MEM_MAPS);
break;
}
@@ -362,7 +363,7 @@ int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map)
switch (map->type) {
case _DRM_REGISTERS:
- drm_ioremapfree(map->handle, map->size, dev);
+ iounmap(map->handle);
/* FALLTHROUGH */
case _DRM_FRAME_BUFFER:
if (drm_core_has_MTRR(dev) && map->mtrr >= 0) {
diff --git a/drivers/char/drm/drm_memory.c b/drivers/char/drm/drm_memory.c
index 5681cae1d40..92a86708237 100644
--- a/drivers/char/drm/drm_memory.c
+++ b/drivers/char/drm/drm_memory.c
@@ -79,28 +79,6 @@ void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area)
}
#if __OS_HAS_AGP
-/*
- * Find the drm_map that covers the range [offset, offset+size).
- */
-static drm_map_t *drm_lookup_map(unsigned long offset,
- unsigned long size, drm_device_t * dev)
-{
- struct list_head *list;
- drm_map_list_t *r_list;
- drm_map_t *map;
-
- list_for_each(list, &dev->maplist->head) {
- r_list = (drm_map_list_t *) list;
- map = r_list->map;
- if (!map)
- continue;
- if (map->offset <= offset
- && (offset + size) <= (map->offset + map->size))
- return map;
- }
- return NULL;
-}
-
static void *agp_remap(unsigned long offset, unsigned long size,
drm_device_t * dev)
{
@@ -169,13 +147,6 @@ int drm_unbind_agp(DRM_AGP_MEM * handle)
}
#else /* __OS_HAS_AGP */
-
-static inline drm_map_t *drm_lookup_map(unsigned long offset,
- unsigned long size, drm_device_t * dev)
-{
- return NULL;
-}
-
static inline void *agp_remap(unsigned long offset, unsigned long size,
drm_device_t * dev)
{
@@ -184,57 +155,28 @@ static inline void *agp_remap(unsigned long offset, unsigned long size,
#endif /* agp */
-void *drm_ioremap(unsigned long offset, unsigned long size,
- drm_device_t * dev)
-{
- if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture) {
- drm_map_t *map = drm_lookup_map(offset, size, dev);
-
- if (map && map->type == _DRM_AGP)
- return agp_remap(offset, size, dev);
- }
- return ioremap(offset, size);
-}
-EXPORT_SYMBOL(drm_ioremap);
+#endif /* debug_memory */
-#if 0
-void *drm_ioremap_nocache(unsigned long offset,
- unsigned long size, drm_device_t * dev)
+void drm_core_ioremap(struct drm_map *map, struct drm_device *dev)
{
- if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture) {
- drm_map_t *map = drm_lookup_map(offset, size, dev);
-
- if (map && map->type == _DRM_AGP)
- return agp_remap(offset, size, dev);
- }
- return ioremap_nocache(offset, size);
+ if (drm_core_has_AGP(dev) &&
+ dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP)
+ map->handle = agp_remap(map->offset, map->size, dev);
+ else
+ map->handle = ioremap(map->offset, map->size);
}
-#endif /* 0 */
+EXPORT_SYMBOL(drm_core_ioremap);
-void drm_ioremapfree(void *pt, unsigned long size,
- drm_device_t * dev)
+void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev)
{
- /*
- * This is a bit ugly. It would be much cleaner if the DRM API would use separate
- * routines for handling mappings in the AGP space. Hopefully this can be done in
- * a future revision of the interface...
- */
- if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture
- && ((unsigned long)pt >= VMALLOC_START
- && (unsigned long)pt < VMALLOC_END)) {
- unsigned long offset;
- drm_map_t *map;
-
- offset = drm_follow_page(pt) | ((unsigned long)pt & ~PAGE_MASK);
- map = drm_lookup_map(offset, size, dev);
- if (map && map->type == _DRM_AGP) {
- vunmap(pt);
- return;
- }
- }
-
- iounmap(pt);
+ if (!map->handle || !map->size)
+ return;
+
+ if (drm_core_has_AGP(dev) &&
+ dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP)
+ vunmap(map->handle);
+ else
+ iounmap(map->handle);
}
-EXPORT_SYMBOL(drm_ioremapfree);
+EXPORT_SYMBOL(drm_core_ioremapfree);
-#endif /* debug_memory */
diff --git a/drivers/char/drm/drm_memory.h b/drivers/char/drm/drm_memory.h
index f1b97aff10c..63e425b5ea8 100644
--- a/drivers/char/drm/drm_memory.h
+++ b/drivers/char/drm/drm_memory.h
@@ -56,26 +56,6 @@
# endif
#endif
-static inline unsigned long drm_follow_page(void *vaddr)
-{
- pgd_t *pgd = pgd_offset_k((unsigned long)vaddr);
- pud_t *pud = pud_offset(pgd, (unsigned long)vaddr);
- pmd_t *pmd = pmd_offset(pud, (unsigned long)vaddr);
- pte_t *ptep = pte_offset_kernel(pmd, (unsigned long)vaddr);
- return pte_pfn(*ptep) << PAGE_SHIFT;
-}
-
#else /* __OS_HAS_AGP */
-static inline unsigned long drm_follow_page(void *vaddr)
-{
- return 0;
-}
-
#endif
-
-void *drm_ioremap(unsigned long offset, unsigned long size,
- drm_device_t * dev);
-
-void drm_ioremapfree(void *pt, unsigned long size,
- drm_device_t * dev);
diff --git a/drivers/char/drm/drm_memory_debug.h b/drivers/char/drm/drm_memory_debug.h
index 74581af806e..6463271deea 100644
--- a/drivers/char/drm/drm_memory_debug.h
+++ b/drivers/char/drm/drm_memory_debug.h
@@ -205,76 +205,6 @@ void drm_free (void *pt, size_t size, int area) {
}
}
-void *drm_ioremap (unsigned long offset, unsigned long size,
- drm_device_t * dev) {
- void *pt;
-
- if (!size) {
- DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
- "Mapping 0 bytes at 0x%08lx\n", offset);
- return NULL;
- }
-
- if (!(pt = drm_ioremap(offset, size, dev))) {
- spin_lock(&drm_mem_lock);
- ++drm_mem_stats[DRM_MEM_MAPPINGS].fail_count;
- spin_unlock(&drm_mem_lock);
- return NULL;
- }
- spin_lock(&drm_mem_lock);
- ++drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count;
- drm_mem_stats[DRM_MEM_MAPPINGS].bytes_allocated += size;
- spin_unlock(&drm_mem_lock);
- return pt;
-}
-
-#if 0
-void *drm_ioremap_nocache (unsigned long offset, unsigned long size,
- drm_device_t * dev) {
- void *pt;
-
- if (!size) {
- DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
- "Mapping 0 bytes at 0x%08lx\n", offset);
- return NULL;
- }
-
- if (!(pt = drm_ioremap_nocache(offset, size, dev))) {
- spin_lock(&drm_mem_lock);
- ++drm_mem_stats[DRM_MEM_MAPPINGS].fail_count;
- spin_unlock(&drm_mem_lock);
- return NULL;
- }
- spin_lock(&drm_mem_lock);
- ++drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count;
- drm_mem_stats[DRM_MEM_MAPPINGS].bytes_allocated += size;
- spin_unlock(&drm_mem_lock);
- return pt;
-}
-#endif /* 0 */
-
-void drm_ioremapfree (void *pt, unsigned long size, drm_device_t * dev) {
- int alloc_count;
- int free_count;
-
- if (!pt)
- DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
- "Attempt to free NULL pointer\n");
- else
- drm_ioremapfree(pt, size, dev);
-
- spin_lock(&drm_mem_lock);
- drm_mem_stats[DRM_MEM_MAPPINGS].bytes_freed += size;
- free_count = ++drm_mem_stats[DRM_MEM_MAPPINGS].free_count;
- alloc_count = drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count;
- spin_unlock(&drm_mem_lock);
- if (free_count > alloc_count) {
- DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
- "Excess frees: %d frees, %d allocs\n",
- free_count, alloc_count);
- }
-}
-
#if __OS_HAS_AGP
DRM_AGP_MEM *drm_alloc_agp (drm_device_t *dev, int pages, u32 type) {
diff --git a/drivers/char/drm/drm_mm.c b/drivers/char/drm/drm_mm.c
index 617526bd5b0..9b46b85027d 100644
--- a/drivers/char/drm/drm_mm.c
+++ b/drivers/char/drm/drm_mm.c
@@ -42,36 +42,131 @@
*/
#include "drmP.h"
+#include <linux/slab.h>
+
+unsigned long drm_mm_tail_space(drm_mm_t *mm)
+{
+ struct list_head *tail_node;
+ drm_mm_node_t *entry;
+
+ tail_node = mm->ml_entry.prev;
+ entry = list_entry(tail_node, drm_mm_node_t, ml_entry);
+ if (!entry->free)
+ return 0;
+
+ return entry->size;
+}
+
+int drm_mm_remove_space_from_tail(drm_mm_t *mm, unsigned long size)
+{
+ struct list_head *tail_node;
+ drm_mm_node_t *entry;
+
+ tail_node = mm->ml_entry.prev;
+ entry = list_entry(tail_node, drm_mm_node_t, ml_entry);
+ if (!entry->free)
+ return -ENOMEM;
+
+ if (entry->size <= size)
+ return -ENOMEM;
+
+ entry->size -= size;
+ return 0;
+}
+
+
+static int drm_mm_create_tail_node(drm_mm_t *mm,
+ unsigned long start,
+ unsigned long size)
+{
+ drm_mm_node_t *child;
+
+ child = (drm_mm_node_t *)
+ drm_alloc(sizeof(*child), DRM_MEM_MM);
+ if (!child)
+ return -ENOMEM;
+
+ child->free = 1;
+ child->size = size;
+ child->start = start;
+ child->mm = mm;
+
+ list_add_tail(&child->ml_entry, &mm->ml_entry);
+ list_add_tail(&child->fl_entry, &mm->fl_entry);
+
+ return 0;
+}
+
+
+int drm_mm_add_space_to_tail(drm_mm_t *mm, unsigned long size)
+{
+ struct list_head *tail_node;
+ drm_mm_node_t *entry;
+
+ tail_node = mm->ml_entry.prev;
+ entry = list_entry(tail_node, drm_mm_node_t, ml_entry);
+ if (!entry->free) {
+ return drm_mm_create_tail_node(mm, entry->start + entry->size, size);
+ }
+ entry->size += size;
+ return 0;
+}
+
+static drm_mm_node_t *drm_mm_split_at_start(drm_mm_node_t *parent,
+ unsigned long size)
+{
+ drm_mm_node_t *child;
+
+ child = (drm_mm_node_t *)
+ drm_alloc(sizeof(*child), DRM_MEM_MM);
+ if (!child)
+ return NULL;
+
+ INIT_LIST_HEAD(&child->fl_entry);
+
+ child->free = 0;
+ child->size = size;
+ child->start = parent->start;
+ child->mm = parent->mm;
+
+ list_add_tail(&child->ml_entry, &parent->ml_entry);
+ INIT_LIST_HEAD(&child->fl_entry);
+
+ parent->size -= size;
+ parent->start += size;
+ return child;
+}
+
+
drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent,
unsigned long size, unsigned alignment)
{
+ drm_mm_node_t *align_splitoff = NULL;
drm_mm_node_t *child;
+ unsigned tmp = 0;
if (alignment)
- size += alignment - 1;
+ tmp = parent->start % alignment;
+
+ if (tmp) {
+ align_splitoff = drm_mm_split_at_start(parent, alignment - tmp);
+ if (!align_splitoff)
+ return NULL;
+ }
if (parent->size == size) {
list_del_init(&parent->fl_entry);
parent->free = 0;
return parent;
} else {
- child = (drm_mm_node_t *) drm_alloc(sizeof(*child), DRM_MEM_MM);
- if (!child)
- return NULL;
-
- INIT_LIST_HEAD(&child->ml_entry);
- INIT_LIST_HEAD(&child->fl_entry);
+ child = drm_mm_split_at_start(parent, size);
+ }
- child->free = 0;
- child->size = size;
- child->start = parent->start;
+ if (align_splitoff)
+ drm_mm_put_block(align_splitoff);
- list_add_tail(&child->ml_entry, &parent->ml_entry);
- parent->size -= size;
- parent->start += size;
- }
return child;
}
@@ -80,12 +175,12 @@ drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent,
* Otherwise add to the free stack.
*/
-void drm_mm_put_block(drm_mm_t * mm, drm_mm_node_t * cur)
+void drm_mm_put_block(drm_mm_node_t * cur)
{
- drm_mm_node_t *list_root = &mm->root_node;
+ drm_mm_t *mm = cur->mm;
struct list_head *cur_head = &cur->ml_entry;
- struct list_head *root_head = &list_root->ml_entry;
+ struct list_head *root_head = &mm->ml_entry;
drm_mm_node_t *prev_node = NULL;
drm_mm_node_t *next_node;
@@ -116,7 +211,7 @@ void drm_mm_put_block(drm_mm_t * mm, drm_mm_node_t * cur)
}
if (!merged) {
cur->free = 1;
- list_add(&cur->fl_entry, &list_root->fl_entry);
+ list_add(&cur->fl_entry, &mm->fl_entry);
} else {
list_del(&cur->ml_entry);
drm_free(cur, sizeof(*cur), DRM_MEM_MM);
@@ -128,20 +223,30 @@ drm_mm_node_t *drm_mm_search_free(const drm_mm_t * mm,
unsigned alignment, int best_match)
{
struct list_head *list;
- const struct list_head *free_stack = &mm->root_node.fl_entry;
+ const struct list_head *free_stack = &mm->fl_entry;
drm_mm_node_t *entry;
drm_mm_node_t *best;
unsigned long best_size;
+ unsigned wasted;
best = NULL;
best_size = ~0UL;
- if (alignment)
- size += alignment - 1;
-
list_for_each(list, free_stack) {
entry = list_entry(list, drm_mm_node_t, fl_entry);
- if (entry->size >= size) {
+ wasted = 0;
+
+ if (entry->size < size)
+ continue;
+
+ if (alignment) {
+ register unsigned tmp = entry->start % alignment;
+ if (tmp)
+ wasted += alignment - tmp;
+ }
+
+
+ if (entry->size >= size + wasted) {
if (!best_match)
return entry;
if (size < best_size) {
@@ -154,40 +259,32 @@ drm_mm_node_t *drm_mm_search_free(const drm_mm_t * mm,
return best;
}
-int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size)
+int drm_mm_clean(drm_mm_t * mm)
{
- drm_mm_node_t *child;
-
- INIT_LIST_HEAD(&mm->root_node.ml_entry);
- INIT_LIST_HEAD(&mm->root_node.fl_entry);
- child = (drm_mm_node_t *) drm_alloc(sizeof(*child), DRM_MEM_MM);
- if (!child)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&child->ml_entry);
- INIT_LIST_HEAD(&child->fl_entry);
+ struct list_head *head = &mm->ml_entry;
- child->start = start;
- child->size = size;
- child->free = 1;
+ return (head->next->next == head);
+}
- list_add(&child->fl_entry, &mm->root_node.fl_entry);
- list_add(&child->ml_entry, &mm->root_node.ml_entry);
+int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size)
+{
+ INIT_LIST_HEAD(&mm->ml_entry);
+ INIT_LIST_HEAD(&mm->fl_entry);
- return 0;
+ return drm_mm_create_tail_node(mm, start, size);
}
EXPORT_SYMBOL(drm_mm_init);
void drm_mm_takedown(drm_mm_t * mm)
{
- struct list_head *bnode = mm->root_node.fl_entry.next;
+ struct list_head *bnode = mm->fl_entry.next;
drm_mm_node_t *entry;
entry = list_entry(bnode, drm_mm_node_t, fl_entry);
- if (entry->ml_entry.next != &mm->root_node.ml_entry ||
- entry->fl_entry.next != &mm->root_node.fl_entry) {
+ if (entry->ml_entry.next != &mm->ml_entry ||
+ entry->fl_entry.next != &mm->fl_entry) {
DRM_ERROR("Memory manager not clean. Delaying takedown\n");
return;
}
diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h
index 09398d5fbd3..ad54b845978 100644
--- a/drivers/char/drm/drm_pciids.h
+++ b/drivers/char/drm/drm_pciids.h
@@ -226,12 +226,14 @@
{0x1106, 0x3022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3118, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_PRO_GROUP_A}, \
{0x1106, 0x3122, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0x1106, 0x7204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x7205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3304, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3344, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
- {0x1106, 0x7204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0x1106, 0x3343, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0x1106, 0x3230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_DX9_0}, \
{0, 0, 0}
#define i810_PCI_IDS \
diff --git a/drivers/char/drm/drm_proc.c b/drivers/char/drm/drm_proc.c
index 62d5fe15f04..7fd0da71214 100644
--- a/drivers/char/drm/drm_proc.c
+++ b/drivers/char/drm/drm_proc.c
@@ -500,7 +500,7 @@ static int drm__vma_info(char *buf, char **start, off_t offset, int request,
for (pt = dev->vmalist; pt; pt = pt->next) {
if (!(vma = pt->vma))
continue;
- DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx",
+ DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx000",
pt->pid,
vma->vm_start,
vma->vm_end,
@@ -510,7 +510,7 @@ static int drm__vma_info(char *buf, char **start, off_t offset, int request,
vma->vm_flags & VM_MAYSHARE ? 's' : 'p',
vma->vm_flags & VM_LOCKED ? 'l' : '-',
vma->vm_flags & VM_IO ? 'i' : '-',
- vma->vm_pgoff << PAGE_SHIFT);
+ vma->vm_pgoff);
#if defined(__i386__)
pgprot = pgprot_val(vma->vm_page_prot);
diff --git a/drivers/char/drm/drm_sman.c b/drivers/char/drm/drm_sman.c
index 19c81d2e13d..e15db6d6bea 100644
--- a/drivers/char/drm/drm_sman.c
+++ b/drivers/char/drm/drm_sman.c
@@ -101,10 +101,9 @@ static void *drm_sman_mm_allocate(void *private, unsigned long size,
static void drm_sman_mm_free(void *private, void *ref)
{
- drm_mm_t *mm = (drm_mm_t *) private;
drm_mm_node_t *node = (drm_mm_node_t *) ref;
- drm_mm_put_block(mm, node);
+ drm_mm_put_block(node);
}
static void drm_sman_mm_destroy(void *private)
diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c
index b9cfc077f6b..54a63284895 100644
--- a/drivers/char/drm/drm_vm.c
+++ b/drivers/char/drm/drm_vm.c
@@ -70,7 +70,7 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma,
if (!dev->agp || !dev->agp->cant_use_aperture)
goto vm_nopage_error;
- if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff << PAGE_SHIFT, &hash))
+ if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff, &hash))
goto vm_nopage_error;
r_list = drm_hash_entry(hash, drm_map_list_t, hash);
@@ -227,7 +227,7 @@ static void drm_vm_shm_close(struct vm_area_struct *vma)
map->size);
DRM_DEBUG("mtrr_del = %d\n", retcode);
}
- drm_ioremapfree(map->handle, map->size, dev);
+ iounmap(map->handle);
break;
case _DRM_SHM:
vfree(map->handle);
@@ -463,8 +463,8 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
lock_kernel();
dev = priv->head->dev;
dma = dev->dma;
- DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
- vma->vm_start, vma->vm_end, vma->vm_pgoff << PAGE_SHIFT);
+ DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n",
+ vma->vm_start, vma->vm_end, vma->vm_pgoff);
/* Length must match exact page count */
if (!dma || (length >> PAGE_SHIFT) != dma->page_count) {
@@ -537,8 +537,8 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
unsigned long offset = 0;
drm_hash_item_t *hash;
- DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
- vma->vm_start, vma->vm_end, vma->vm_pgoff << PAGE_SHIFT);
+ DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n",
+ vma->vm_start, vma->vm_end, vma->vm_pgoff);
if (!priv->authenticated)
return -EACCES;
@@ -547,7 +547,7 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
* the AGP mapped at physical address 0
* --BenH.
*/
- if (!(vma->vm_pgoff << PAGE_SHIFT)
+ if (!vma->vm_pgoff
#if __OS_HAS_AGP
&& (!dev->agp
|| dev->agp->agp_info.device->vendor != PCI_VENDOR_ID_APPLE)
@@ -555,7 +555,7 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
)
return drm_mmap_dma(filp, vma);
- if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff << PAGE_SHIFT, &hash)) {
+ if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff, &hash)) {
DRM_ERROR("Could not find map\n");
return -EINVAL;
}
diff --git a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c
index fa2de70f740..60cb4e45a75 100644
--- a/drivers/char/drm/i810_dma.c
+++ b/drivers/char/drm/i810_dma.c
@@ -219,8 +219,7 @@ static int i810_dma_cleanup(drm_device_t * dev)
(drm_i810_private_t *) dev->dev_private;
if (dev_priv->ring.virtual_start) {
- drm_ioremapfree((void *)dev_priv->ring.virtual_start,
- dev_priv->ring.Size, dev);
+ drm_core_ioremapfree(&dev_priv->ring.map, dev);
}
if (dev_priv->hw_status_page) {
pci_free_consistent(dev->pdev, PAGE_SIZE,
@@ -236,9 +235,9 @@ static int i810_dma_cleanup(drm_device_t * dev)
for (i = 0; i < dma->buf_count; i++) {
drm_buf_t *buf = dma->buflist[i];
drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+
if (buf_priv->kernel_virtual && buf->total)
- drm_ioremapfree(buf_priv->kernel_virtual,
- buf->total, dev);
+ drm_core_ioremapfree(&buf_priv->map, dev);
}
}
return 0;
@@ -311,8 +310,15 @@ static int i810_freelist_init(drm_device_t * dev, drm_i810_private_t * dev_priv)
*buf_priv->in_use = I810_BUF_FREE;
- buf_priv->kernel_virtual = drm_ioremap(buf->bus_address,
- buf->total, dev);
+ buf_priv->map.offset = buf->bus_address;
+ buf_priv->map.size = buf->total;
+ buf_priv->map.type = _DRM_AGP;
+ buf_priv->map.flags = 0;
+ buf_priv->map.mtrr = 0;
+
+ drm_core_ioremap(&buf_priv->map, dev);
+ buf_priv->kernel_virtual = buf_priv->map.handle;
+
}
return 0;
}
@@ -363,18 +369,24 @@ static int i810_dma_initialize(drm_device_t * dev,
dev_priv->ring.End = init->ring_end;
dev_priv->ring.Size = init->ring_size;
- dev_priv->ring.virtual_start = drm_ioremap(dev->agp->base +
- init->ring_start,
- init->ring_size, dev);
+ dev_priv->ring.map.offset = dev->agp->base + init->ring_start;
+ dev_priv->ring.map.size = init->ring_size;
+ dev_priv->ring.map.type = _DRM_AGP;
+ dev_priv->ring.map.flags = 0;
+ dev_priv->ring.map.mtrr = 0;
- if (dev_priv->ring.virtual_start == NULL) {
+ drm_core_ioremap(&dev_priv->ring.map, dev);
+
+ if (dev_priv->ring.map.handle == NULL) {
dev->dev_private = (void *)dev_priv;
i810_dma_cleanup(dev);
DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
- return -ENOMEM;
+ return DRM_ERR(ENOMEM);
}
+ dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
+
dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
dev_priv->w = init->w;
diff --git a/drivers/char/drm/i810_drv.h b/drivers/char/drm/i810_drv.h
index e8cf3ff606f..e6df49f4928 100644
--- a/drivers/char/drm/i810_drv.h
+++ b/drivers/char/drm/i810_drv.h
@@ -61,6 +61,7 @@ typedef struct drm_i810_buf_priv {
int currently_mapped;
void *virtual;
void *kernel_virtual;
+ drm_local_map_t map;
} drm_i810_buf_priv_t;
typedef struct _drm_i810_ring_buffer {
@@ -72,6 +73,7 @@ typedef struct _drm_i810_ring_buffer {
int head;
int tail;
int space;
+ drm_local_map_t map;
} drm_i810_ring_buffer_t;
typedef struct drm_i810_private {
diff --git a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c
index 4f0e5746ab3..95224455ec0 100644
--- a/drivers/char/drm/i830_dma.c
+++ b/drivers/char/drm/i830_dma.c
@@ -223,8 +223,7 @@ static int i830_dma_cleanup(drm_device_t * dev)
(drm_i830_private_t *) dev->dev_private;
if (dev_priv->ring.virtual_start) {
- drm_ioremapfree((void *)dev_priv->ring.virtual_start,
- dev_priv->ring.Size, dev);
+ drm_core_ioremapfree(&dev_priv->ring.map, dev);
}
if (dev_priv->hw_status_page) {
pci_free_consistent(dev->pdev, PAGE_SIZE,
@@ -242,8 +241,7 @@ static int i830_dma_cleanup(drm_device_t * dev)
drm_buf_t *buf = dma->buflist[i];
drm_i830_buf_priv_t *buf_priv = buf->dev_private;
if (buf_priv->kernel_virtual && buf->total)
- drm_ioremapfree(buf_priv->kernel_virtual,
- buf->total, dev);
+ drm_core_ioremapfree(&buf_priv->map, dev);
}
}
return 0;
@@ -320,8 +318,14 @@ static int i830_freelist_init(drm_device_t * dev, drm_i830_private_t * dev_priv)
*buf_priv->in_use = I830_BUF_FREE;
- buf_priv->kernel_virtual = drm_ioremap(buf->bus_address,
- buf->total, dev);
+ buf_priv->map.offset = buf->bus_address;
+ buf_priv->map.size = buf->total;
+ buf_priv->map.type = _DRM_AGP;
+ buf_priv->map.flags = 0;
+ buf_priv->map.mtrr = 0;
+
+ drm_core_ioremap(&buf_priv->map, dev);
+ buf_priv->kernel_virtual = buf_priv->map.handle;
}
return 0;
}
@@ -373,18 +377,24 @@ static int i830_dma_initialize(drm_device_t * dev,
dev_priv->ring.End = init->ring_end;
dev_priv->ring.Size = init->ring_size;
- dev_priv->ring.virtual_start = drm_ioremap(dev->agp->base +
- init->ring_start,
- init->ring_size, dev);
+ dev_priv->ring.map.offset = dev->agp->base + init->ring_start;
+ dev_priv->ring.map.size = init->ring_size;
+ dev_priv->ring.map.type = _DRM_AGP;
+ dev_priv->ring.map.flags = 0;
+ dev_priv->ring.map.mtrr = 0;
+
+ drm_core_ioremap(&dev_priv->ring.map, dev);
- if (dev_priv->ring.virtual_start == NULL) {
+ if (dev_priv->ring.map.handle == NULL) {
dev->dev_private = (void *)dev_priv;
i830_dma_cleanup(dev);
DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
- return -ENOMEM;
+ return DRM_ERR(ENOMEM);
}
+ dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
+
dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
dev_priv->w = init->w;
diff --git a/drivers/char/drm/i830_drv.h b/drivers/char/drm/i830_drv.h
index 85bc5be6f91..e91f94afb4b 100644
--- a/drivers/char/drm/i830_drv.h
+++ b/drivers/char/drm/i830_drv.h
@@ -68,6 +68,7 @@ typedef struct drm_i830_buf_priv {
int currently_mapped;
void __user *virtual;
void *kernel_virtual;
+ drm_local_map_t map;
} drm_i830_buf_priv_t;
typedef struct _drm_i830_ring_buffer {
@@ -79,6 +80,7 @@ typedef struct _drm_i830_ring_buffer {
int head;
int tail;
int space;
+ drm_local_map_t map;
} drm_i830_ring_buffer_t;
typedef struct drm_i830_private {
diff --git a/drivers/char/drm/via_dma.c b/drivers/char/drm/via_dma.c
index a691ae74129..c0539c6299c 100644
--- a/drivers/char/drm/via_dma.c
+++ b/drivers/char/drm/via_dma.c
@@ -190,6 +190,11 @@ static int via_initialize(drm_device_t * dev,
return DRM_ERR(EFAULT);
}
+ if (dev_priv->chipset == VIA_DX9_0) {
+ DRM_ERROR("AGP DMA is not supported on this chip\n");
+ return DRM_ERR(EINVAL);
+ }
+
dev_priv->ring.map.offset = dev->agp->base + init->offset;
dev_priv->ring.map.size = init->size;
dev_priv->ring.map.type = 0;
@@ -480,6 +485,7 @@ static int via_hook_segment(drm_via_private_t * dev_priv,
VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16));
VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi);
VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo);
+ VIA_READ(VIA_REG_TRANSPACE);
}
}
return paused;
@@ -557,8 +563,9 @@ static void via_cmdbuf_start(drm_via_private_t * dev_priv)
VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi);
VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo);
-
+ DRM_WRITEMEMORYBARRIER();
VIA_WRITE(VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK);
+ VIA_READ(VIA_REG_TRANSPACE);
}
static void via_pad_cache(drm_via_private_t * dev_priv, int qwords)
diff --git a/drivers/char/drm/via_dmablit.c b/drivers/char/drm/via_dmablit.c
index 806f9ce5f47..2054d577371 100644
--- a/drivers/char/drm/via_dmablit.c
+++ b/drivers/char/drm/via_dmablit.c
@@ -218,7 +218,9 @@ via_fire_dmablit(drm_device_t *dev, drm_via_sg_info_t *vsg, int engine)
VIA_WRITE(VIA_PCI_DMA_MR0 + engine*0x04, VIA_DMA_MR_CM | VIA_DMA_MR_TDIE);
VIA_WRITE(VIA_PCI_DMA_BCR0 + engine*0x10, 0);
VIA_WRITE(VIA_PCI_DMA_DPR0 + engine*0x10, vsg->chain_start);
+ DRM_WRITEMEMORYBARRIER();
VIA_WRITE(VIA_PCI_DMA_CSR0 + engine*0x04, VIA_DMA_CSR_DE | VIA_DMA_CSR_TS);
+ VIA_READ(VIA_PCI_DMA_CSR0 + engine*0x04);
}
/*
diff --git a/drivers/char/drm/via_drv.h b/drivers/char/drm/via_drv.h
index d21b5b75da0..8b8778d4a42 100644
--- a/drivers/char/drm/via_drv.h
+++ b/drivers/char/drm/via_drv.h
@@ -29,10 +29,10 @@
#define DRIVER_NAME "via"
#define DRIVER_DESC "VIA Unichrome / Pro"
-#define DRIVER_DATE "20060529"
+#define DRIVER_DATE "20061227"
#define DRIVER_MAJOR 2
-#define DRIVER_MINOR 10
+#define DRIVER_MINOR 11
#define DRIVER_PATCHLEVEL 0
#include "via_verifier.h"
@@ -79,7 +79,7 @@ typedef struct drm_via_private {
char pci_buf[VIA_PCI_BUF_SIZE];
const uint32_t *fire_offsets[VIA_FIRE_BUF_SIZE];
uint32_t num_fire_offsets;
- int pro_group_a;
+ int chipset;
drm_via_irq_t via_irqs[VIA_NUM_IRQS];
unsigned num_irqs;
maskarray_t *irq_masks;
@@ -96,8 +96,9 @@ typedef struct drm_via_private {
} drm_via_private_t;
enum via_family {
- VIA_OTHER = 0,
- VIA_PRO_GROUP_A,
+ VIA_OTHER = 0, /* Baseline */
+ VIA_PRO_GROUP_A, /* Another video engine and DMA commands */
+ VIA_DX9_0 /* Same video as pro_group_a, but 3D is unsupported */
};
/* VIA MMIO register access */
diff --git a/drivers/char/drm/via_irq.c b/drivers/char/drm/via_irq.c
index c33d068cde1..1ac5941ad23 100644
--- a/drivers/char/drm/via_irq.c
+++ b/drivers/char/drm/via_irq.c
@@ -258,12 +258,16 @@ void via_driver_irq_preinstall(drm_device_t * dev)
dev_priv->irq_enable_mask = VIA_IRQ_VBLANK_ENABLE;
dev_priv->irq_pending_mask = VIA_IRQ_VBLANK_PENDING;
- dev_priv->irq_masks = (dev_priv->pro_group_a) ?
- via_pro_group_a_irqs : via_unichrome_irqs;
- dev_priv->num_irqs = (dev_priv->pro_group_a) ?
- via_num_pro_group_a : via_num_unichrome;
- dev_priv->irq_map = (dev_priv->pro_group_a) ?
- via_irqmap_pro_group_a : via_irqmap_unichrome;
+ if (dev_priv->chipset == VIA_PRO_GROUP_A ||
+ dev_priv->chipset == VIA_DX9_0) {
+ dev_priv->irq_masks = via_pro_group_a_irqs;
+ dev_priv->num_irqs = via_num_pro_group_a;
+ dev_priv->irq_map = via_irqmap_pro_group_a;
+ } else {
+ dev_priv->irq_masks = via_unichrome_irqs;
+ dev_priv->num_irqs = via_num_unichrome;
+ dev_priv->irq_map = via_irqmap_unichrome;
+ }
for (i = 0; i < dev_priv->num_irqs; ++i) {
atomic_set(&cur_irq->irq_received, 0);
diff --git a/drivers/char/drm/via_map.c b/drivers/char/drm/via_map.c
index 782011e0a58..4e3fc072aa3 100644
--- a/drivers/char/drm/via_map.c
+++ b/drivers/char/drm/via_map.c
@@ -106,8 +106,7 @@ int via_driver_load(drm_device_t *dev, unsigned long chipset)
dev->dev_private = (void *)dev_priv;
- if (chipset == VIA_PRO_GROUP_A)
- dev_priv->pro_group_a = 1;
+ dev_priv->chipset = chipset;
ret = drm_sman_init(&dev_priv->sman, 2, 12, 8);
if (ret) {
diff --git a/drivers/char/drm/via_verifier.c b/drivers/char/drm/via_verifier.c
index 70c897c8876..2e7e0807828 100644
--- a/drivers/char/drm/via_verifier.c
+++ b/drivers/char/drm/via_verifier.c
@@ -306,6 +306,7 @@ static __inline__ int finish_current_sequence(drm_via_state_t * cur_seq)
unsigned long lo = ~0, hi = 0, tmp;
uint32_t *addr, *pitch, *height, tex;
unsigned i;
+ int npot;
if (end > 9)
end = 9;
@@ -316,12 +317,15 @@ static __inline__ int finish_current_sequence(drm_via_state_t * cur_seq)
&(cur_seq->t_addr[tex = cur_seq->texture][start]);
pitch = &(cur_seq->pitch[tex][start]);
height = &(cur_seq->height[tex][start]);
-
+ npot = cur_seq->tex_npot[tex];
for (i = start; i <= end; ++i) {
tmp = *addr++;
if (tmp < lo)
lo = tmp;
- tmp += (*height++ << *pitch++);
+ if (i == 0 && npot)
+ tmp += (*height++ * *pitch++);
+ else
+ tmp += (*height++ << *pitch++);
if (tmp > hi)
hi = tmp;
}
@@ -443,13 +447,21 @@ investigate_hazard(uint32_t cmd, hazard_t hz, drm_via_state_t * cur_seq)
return 0;
case check_texture_addr3:
cur_seq->unfinished = tex_address;
- tmp = ((cmd >> 24) - 0x2B);
- cur_seq->pitch[cur_seq->texture][tmp] =
- (cmd & 0x00F00000) >> 20;
- if (!tmp && (cmd & 0x000FFFFF)) {
- DRM_ERROR
- ("Unimplemented texture level 0 pitch mode.\n");
- return 2;
+ tmp = ((cmd >> 24) - HC_SubA_HTXnL0Pit);
+ if (tmp == 0 &&
+ (cmd & HC_HTXnEnPit_MASK)) {
+ cur_seq->pitch[cur_seq->texture][tmp] =
+ (cmd & HC_HTXnLnPit_MASK);
+ cur_seq->tex_npot[cur_seq->texture] = 1;
+ } else {
+ cur_seq->pitch[cur_seq->texture][tmp] =
+ (cmd & HC_HTXnLnPitE_MASK) >> HC_HTXnLnPitE_SHIFT;
+ cur_seq->tex_npot[cur_seq->texture] = 0;
+ if (cmd & 0x000FFFFF) {
+ DRM_ERROR
+ ("Unimplemented texture level 0 pitch mode.\n");
+ return 2;
+ }
}
return 0;
case check_texture_addr4:
@@ -961,7 +973,13 @@ via_verify_command_stream(const uint32_t * buf, unsigned int size,
uint32_t cmd;
const uint32_t *buf_end = buf + (size >> 2);
verifier_state_t state = state_command;
- int pro_group_a = dev_priv->pro_group_a;
+ int cme_video;
+ int supported_3d;
+
+ cme_video = (dev_priv->chipset == VIA_PRO_GROUP_A ||
+ dev_priv->chipset == VIA_DX9_0);
+
+ supported_3d = dev_priv->chipset != VIA_DX9_0;
hc_state->dev = dev;
hc_state->unfinished = no_sequence;
@@ -986,17 +1004,21 @@ via_verify_command_stream(const uint32_t * buf, unsigned int size,
state = via_check_vheader6(&buf, buf_end);
break;
case state_command:
- if (HALCYON_HEADER2 == (cmd = *buf))
+ if ((HALCYON_HEADER2 == (cmd = *buf)) &&
+ supported_3d)
state = state_header2;
else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1)
state = state_header1;
- else if (pro_group_a
+ else if (cme_video
&& (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5)
state = state_vheader5;
- else if (pro_group_a
+ else if (cme_video
&& (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6)
state = state_vheader6;
- else {
+ else if ((cmd == HALCYON_HEADER2) && !supported_3d) {
+ DRM_ERROR("Accelerated 3D is not supported on this chipset yet.\n");
+ state = state_error;
+ } else {
DRM_ERROR
("Invalid / Unimplemented DMA HEADER command. 0x%x\n",
cmd);
diff --git a/drivers/char/drm/via_verifier.h b/drivers/char/drm/via_verifier.h
index 256590fcc22..b77f59df027 100644
--- a/drivers/char/drm/via_verifier.h
+++ b/drivers/char/drm/via_verifier.h
@@ -43,6 +43,7 @@ typedef struct {
uint32_t tex_level_lo[2];
uint32_t tex_level_hi[2];
uint32_t tex_palette_size[2];
+ uint32_t tex_npot[2];
drm_via_sequence_t unfinished;
int agp_texture;
int multitex;
diff --git a/drivers/char/hvc_beat.c b/drivers/char/hvc_beat.c
new file mode 100644
index 00000000000..6f019f19be7
--- /dev/null
+++ b/drivers/char/hvc_beat.c
@@ -0,0 +1,134 @@
+/*
+ * Beat hypervisor console driver
+ *
+ * (C) Copyright 2006 TOSHIBA CORPORATION
+ *
+ * This code is based on drivers/char/hvc_rtas.c:
+ * (C) Copyright IBM Corporation 2001-2005
+ * (C) Copyright Red Hat, Inc. 2005
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/console.h>
+#include <asm/prom.h>
+#include <asm/hvconsole.h>
+#include <asm/firmware.h>
+
+#include "hvc_console.h"
+
+extern int64_t beat_get_term_char(uint64_t, uint64_t *, uint64_t *, uint64_t *);
+extern int64_t beat_put_term_char(uint64_t, uint64_t, uint64_t, uint64_t);
+
+struct hvc_struct *hvc_beat_dev = NULL;
+
+/* bug: only one queue is available regardless of vtermno */
+static int hvc_beat_get_chars(uint32_t vtermno, char *buf, int cnt)
+{
+ static unsigned char q[sizeof(unsigned long) * 2]
+ __attribute__((aligned(sizeof(unsigned long))));
+ static int qlen = 0;
+ unsigned long got;
+
+again:
+ if (qlen) {
+ if (qlen > cnt) {
+ memcpy(buf, q, cnt);
+ qlen -= cnt;
+ memmove(q + cnt, q, qlen);
+ return cnt;
+ } else { /* qlen <= cnt */
+ int r;
+
+ memcpy(buf, q, qlen);
+ r = qlen;
+ qlen = 0;
+ return r;
+ }
+ }
+ if (beat_get_term_char(vtermno, &got,
+ ((unsigned long *)q), ((unsigned long *)q) + 1) == 0) {
+ qlen = got;
+ goto again;
+ }
+ return 0;
+}
+
+static int hvc_beat_put_chars(uint32_t vtermno, const char *buf, int cnt)
+{
+ unsigned long kb[2];
+ int rest, nlen;
+
+ for (rest = cnt; rest > 0; rest -= nlen) {
+ nlen = (rest > 16) ? 16 : rest;
+ memcpy(kb, buf, nlen);
+ beat_put_term_char(vtermno, rest, kb[0], kb[1]);
+ rest -= nlen;
+ }
+ return cnt;
+}
+
+static struct hv_ops hvc_beat_get_put_ops = {
+ .get_chars = hvc_beat_get_chars,
+ .put_chars = hvc_beat_put_chars,
+};
+
+static int hvc_beat_useit = 1;
+
+static int hvc_beat_config(char *p)
+{
+ hvc_beat_useit = simple_strtoul(p, NULL, 0);
+ return 0;
+}
+
+static int hvc_beat_console_init(void)
+{
+ if (hvc_beat_useit && machine_is_compatible("Beat")) {
+ hvc_instantiate(0, 0, &hvc_beat_get_put_ops);
+ }
+ return 0;
+}
+
+/* temp */
+static int hvc_beat_init(void)
+{
+ struct hvc_struct *hp;
+
+ if (!firmware_has_feature(FW_FEATURE_BEAT))
+ return -ENODEV;
+
+ hp = hvc_alloc(0, NO_IRQ, &hvc_beat_get_put_ops, 16);
+ if (IS_ERR(hp))
+ return PTR_ERR(hp);
+ hvc_beat_dev = hp;
+ return 0;
+}
+
+static void __exit hvc_beat_exit(void)
+{
+ if (hvc_beat_dev)
+ hvc_remove(hvc_beat_dev);
+}
+
+module_init(hvc_beat_init);
+module_exit(hvc_beat_exit);
+
+__setup("hvc_beat=", hvc_beat_config);
+
+console_initcall(hvc_beat_console_init);
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index f1afd26a509..a7b33d2f599 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -1802,7 +1802,7 @@ static __devinit int try_init_acpi(struct SPMITable *spmi)
return -ENODEV;
}
- if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
+ if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
addr_space = IPMI_MEM_ADDR_SPACE;
else
addr_space = IPMI_IO_ADDR_SPACE;
@@ -1848,19 +1848,19 @@ static __devinit int try_init_acpi(struct SPMITable *spmi)
info->irq_setup = NULL;
}
- if (spmi->addr.register_bit_width) {
+ if (spmi->addr.bit_width) {
/* A (hopefully) properly formed register bit width. */
- info->io.regspacing = spmi->addr.register_bit_width / 8;
+ info->io.regspacing = spmi->addr.bit_width / 8;
} else {
info->io.regspacing = DEFAULT_REGSPACING;
}
info->io.regsize = info->io.regspacing;
- info->io.regshift = spmi->addr.register_bit_offset;
+ info->io.regshift = spmi->addr.bit_offset;
- if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
+ if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
info->io_setup = mem_setup;
info->io.addr_type = IPMI_IO_ADDR_SPACE;
- } else if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
+ } else if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
info->io_setup = port_setup;
info->io.addr_type = IPMI_MEM_ADDR_SPACE;
} else {
@@ -1888,10 +1888,8 @@ static __devinit void acpi_find_bmc(void)
return;
for (i = 0; ; i++) {
- status = acpi_get_firmware_table("SPMI", i+1,
- ACPI_LOGICAL_ADDRESSING,
- (struct acpi_table_header **)
- &spmi);
+ status = acpi_get_table(ACPI_SIG_SPMI, i+1,
+ (struct acpi_table_header **)&spmi);
if (status != AE_OK)
return;
diff --git a/drivers/char/tpm/tpm_bios.c b/drivers/char/tpm/tpm_bios.c
index a611972024e..7fca5f470be 100644
--- a/drivers/char/tpm/tpm_bios.c
+++ b/drivers/char/tpm/tpm_bios.c
@@ -372,10 +372,8 @@ static int read_log(struct tpm_bios_log *log)
}
/* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */
- status = acpi_get_firmware_table(ACPI_TCPA_SIG, 1,
- ACPI_LOGICAL_ADDRESSING,
- (struct acpi_table_header **)
- &buff);
+ status = acpi_get_table(ACPI_SIG_TCPA, 1,
+ (struct acpi_table_header **)&buff);
if (ACPI_FAILURE(status)) {
printk(KERN_ERR "%s: ERROR - Could not get TCPA table\n",
@@ -409,7 +407,7 @@ static int read_log(struct tpm_bios_log *log)
log->bios_event_log_end = log->bios_event_log + len;
- acpi_os_map_memory(start, len, (void *) &virt);
+ virt = acpi_os_map_memory(start, len);
memcpy(log->bios_event_log, virt, len);
diff --git a/drivers/char/watchdog/booke_wdt.c b/drivers/char/watchdog/booke_wdt.c
index 488902231cc..0e23f29f71a 100644
--- a/drivers/char/watchdog/booke_wdt.c
+++ b/drivers/char/watchdog/booke_wdt.c
@@ -35,7 +35,7 @@
#ifdef CONFIG_FSL_BOOKE
#define WDT_PERIOD_DEFAULT 63 /* Ex. wdt_period=28 bus=333Mhz , reset=~40sec */
#else
-#define WDT_PERIOD_DEFAULT 4 /* Refer to the PPC40x and PPC4xx manuals */
+#define WDT_PERIOD_DEFAULT 3 /* Refer to the PPC40x and PPC4xx manuals */
#endif /* for timing information */
u32 booke_wdt_enabled = 0;
@@ -48,12 +48,22 @@ u32 booke_wdt_period = WDT_PERIOD_DEFAULT;
#endif
/*
+ * booke_wdt_ping:
+ */
+static __inline__ void booke_wdt_ping(void)
+{
+ mtspr(SPRN_TSR, TSR_ENW|TSR_WIS);
+}
+
+/*
* booke_wdt_enable:
*/
static __inline__ void booke_wdt_enable(void)
{
u32 val;
+ /* clear status before enabling watchdog */
+ booke_wdt_ping();
val = mfspr(SPRN_TCR);
val |= (TCR_WIE|TCR_WRC(WRC_CHIP)|WDTP(booke_wdt_period));
@@ -61,14 +71,6 @@ static __inline__ void booke_wdt_enable(void)
}
/*
- * booke_wdt_ping:
- */
-static __inline__ void booke_wdt_ping(void)
-{
- mtspr(SPRN_TSR, TSR_ENW|TSR_WIS);
-}
-
-/*
* booke_wdt_write:
*/
static ssize_t booke_wdt_write (struct file *file, const char __user *buf,
diff --git a/drivers/char/watchdog/machzwd.c b/drivers/char/watchdog/machzwd.c
index 276577d08fb..4d730fdbd52 100644
--- a/drivers/char/watchdog/machzwd.c
+++ b/drivers/char/watchdog/machzwd.c
@@ -325,7 +325,7 @@ static int zf_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
return put_user(0, p);
case WDIOC_KEEPALIVE:
- zf_ping(0);
+ zf_ping(NULL);
break;
default:
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 879250d3d06..ff8c4beaace 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -51,6 +51,8 @@ config CRYPTO_DEV_PADLOCK_SHA
If unsure say M. The compiled module will be
called padlock-sha.ko
+source "arch/s390/crypto/Kconfig"
+
config CRYPTO_DEV_GEODE
tristate "Support for the Geode LX AES engine"
depends on CRYPTO && X86_32 && PCI
diff --git a/drivers/crypto/geode-aes.c b/drivers/crypto/geode-aes.c
index 43a68398656..31ea405f2ee 100644
--- a/drivers/crypto/geode-aes.c
+++ b/drivers/crypto/geode-aes.c
@@ -457,7 +457,7 @@ static struct pci_driver geode_aes_driver = {
static int __init
geode_aes_init(void)
{
- return pci_module_init(&geode_aes_driver);
+ return pci_register_driver(&geode_aes_driver);
}
static void __exit
diff --git a/drivers/firmware/pcdp.c b/drivers/firmware/pcdp.c
index c2ad72fefd9..2b4b76e8bd7 100644
--- a/drivers/firmware/pcdp.c
+++ b/drivers/firmware/pcdp.c
@@ -26,7 +26,7 @@ setup_serial_console(struct pcdp_uart *uart)
static char options[64], *p = options;
char parity;
- mmio = (uart->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY);
+ mmio = (uart->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY);
p += sprintf(p, "console=uart,%s,0x%lx",
mmio ? "mmio" : "io", uart->addr.address);
if (uart->baud) {
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index ec796ad087d..850788f4dd2 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -22,5 +22,19 @@ config HID
If unsure, say Y
+config HID_DEBUG
+ bool "HID debugging support"
+ depends on HID
+ ---help---
+ This option lets the HID layer output diagnostics about its internal
+ state, resolve HID usages, dump HID fields, etc. Individual HID drivers
+ use this debugging facility to output information about individual HID
+ devices, etc.
+
+ This feature is useful for those who are either debugging the HID parser
+ or any HID hardware device.
+
+ If unsure, say N
+
endmenu
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 6432392110b..52e97d8f3c9 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -1,15 +1,8 @@
#
# Makefile for the HID driver
#
-
-# Multipart objects.
-hid-objs := hid-core.o hid-input.o
-
-# Optional parts of multipart objects.
+hid-objs := hid-core.o hid-input.o
obj-$(CONFIG_HID) += hid.o
-
-ifeq ($(CONFIG_INPUT_DEBUG),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
+hid-$(CONFIG_HID_DEBUG) += hid-debug.o
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 49f18f5b251..8c7d48eff7b 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -28,11 +28,9 @@
#include <linux/input.h>
#include <linux/wait.h>
-#undef DEBUG
-#undef DEBUG_DATA
-
#include <linux/hid.h>
#include <linux/hiddev.h>
+#include <linux/hid-debug.h>
/*
* Version Information
@@ -951,7 +949,7 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
return -1;
}
-#ifdef DEBUG_DATA
+#ifdef CONFIG_HID_DEBUG
printk(KERN_DEBUG __FILE__ ": report (size %u) (%snumbered)\n", size, report_enum->numbered ? "" : "un");
#endif
@@ -961,7 +959,7 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
size--;
}
-#ifdef DEBUG_DATA
+#ifdef CONFIG_HID_DEBUG
{
int i;
printk(KERN_DEBUG __FILE__ ": report %d (size %u) = ", n, size);
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c
new file mode 100644
index 00000000000..89241be4ec9
--- /dev/null
+++ b/drivers/hid/hid-debug.c
@@ -0,0 +1,764 @@
+/*
+ * $Id: hid-debug.h,v 1.8 2001/09/25 09:37:57 vojtech Exp $
+ *
+ * (c) 1999 Andreas Gal <gal@cs.uni-magdeburg.de>
+ * (c) 2000-2001 Vojtech Pavlik <vojtech@ucw.cz>
+ * (c) 2007 Jiri Kosina
+ *
+ * Some debug stuff for the HID parser.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/hid.h>
+
+struct hid_usage_entry {
+ unsigned page;
+ unsigned usage;
+ char *description;
+};
+
+static const struct hid_usage_entry hid_usage_table[] = {
+ { 0, 0, "Undefined" },
+ { 1, 0, "GenericDesktop" },
+ {0, 0x01, "Pointer"},
+ {0, 0x02, "Mouse"},
+ {0, 0x04, "Joystick"},
+ {0, 0x05, "GamePad"},
+ {0, 0x06, "Keyboard"},
+ {0, 0x07, "Keypad"},
+ {0, 0x08, "MultiAxis"},
+ {0, 0x30, "X"},
+ {0, 0x31, "Y"},
+ {0, 0x32, "Z"},
+ {0, 0x33, "Rx"},
+ {0, 0x34, "Ry"},
+ {0, 0x35, "Rz"},
+ {0, 0x36, "Slider"},
+ {0, 0x37, "Dial"},
+ {0, 0x38, "Wheel"},
+ {0, 0x39, "HatSwitch"},
+ {0, 0x3a, "CountedBuffer"},
+ {0, 0x3b, "ByteCount"},
+ {0, 0x3c, "MotionWakeup"},
+ {0, 0x3d, "Start"},
+ {0, 0x3e, "Select"},
+ {0, 0x40, "Vx"},
+ {0, 0x41, "Vy"},
+ {0, 0x42, "Vz"},
+ {0, 0x43, "Vbrx"},
+ {0, 0x44, "Vbry"},
+ {0, 0x45, "Vbrz"},
+ {0, 0x46, "Vno"},
+ {0, 0x80, "SystemControl"},
+ {0, 0x81, "SystemPowerDown"},
+ {0, 0x82, "SystemSleep"},
+ {0, 0x83, "SystemWakeUp"},
+ {0, 0x84, "SystemContextMenu"},
+ {0, 0x85, "SystemMainMenu"},
+ {0, 0x86, "SystemAppMenu"},
+ {0, 0x87, "SystemMenuHelp"},
+ {0, 0x88, "SystemMenuExit"},
+ {0, 0x89, "SystemMenuSelect"},
+ {0, 0x8a, "SystemMenuRight"},
+ {0, 0x8b, "SystemMenuLeft"},
+ {0, 0x8c, "SystemMenuUp"},
+ {0, 0x8d, "SystemMenuDown"},
+ {0, 0x90, "D-PadUp"},
+ {0, 0x91, "D-PadDown"},
+ {0, 0x92, "D-PadRight"},
+ {0, 0x93, "D-PadLeft"},
+ { 2, 0, "Simulation" },
+ {0, 0xb0, "Aileron"},
+ {0, 0xb1, "AileronTrim"},
+ {0, 0xb2, "Anti-Torque"},
+ {0, 0xb3, "Autopilot"},
+ {0, 0xb4, "Chaff"},
+ {0, 0xb5, "Collective"},
+ {0, 0xb6, "DiveBrake"},
+ {0, 0xb7, "ElectronicCountermeasures"},
+ {0, 0xb8, "Elevator"},
+ {0, 0xb9, "ElevatorTrim"},
+ {0, 0xba, "Rudder"},
+ {0, 0xbb, "Throttle"},
+ {0, 0xbc, "FlightCommunications"},
+ {0, 0xbd, "FlareRelease"},
+ {0, 0xbe, "LandingGear"},
+ {0, 0xbf, "ToeBrake"},
+ { 7, 0, "Keyboard" },
+ { 8, 0, "LED" },
+ {0, 0x01, "NumLock"},
+ {0, 0x02, "CapsLock"},
+ {0, 0x03, "ScrollLock"},
+ {0, 0x04, "Compose"},
+ {0, 0x05, "Kana"},
+ {0, 0x4b, "GenericIndicator"},
+ { 9, 0, "Button" },
+ { 10, 0, "Ordinal" },
+ { 12, 0, "Consumer" },
+ {0, 0x238, "HorizontalWheel"},
+ { 13, 0, "Digitizers" },
+ {0, 0x01, "Digitizer"},
+ {0, 0x02, "Pen"},
+ {0, 0x03, "LightPen"},
+ {0, 0x04, "TouchScreen"},
+ {0, 0x05, "TouchPad"},
+ {0, 0x20, "Stylus"},
+ {0, 0x21, "Puck"},
+ {0, 0x22, "Finger"},
+ {0, 0x30, "TipPressure"},
+ {0, 0x31, "BarrelPressure"},
+ {0, 0x32, "InRange"},
+ {0, 0x33, "Touch"},
+ {0, 0x34, "UnTouch"},
+ {0, 0x35, "Tap"},
+ {0, 0x39, "TabletFunctionKey"},
+ {0, 0x3a, "ProgramChangeKey"},
+ {0, 0x3c, "Invert"},
+ {0, 0x42, "TipSwitch"},
+ {0, 0x43, "SecondaryTipSwitch"},
+ {0, 0x44, "BarrelSwitch"},
+ {0, 0x45, "Eraser"},
+ {0, 0x46, "TabletPick"},
+ { 15, 0, "PhysicalInterfaceDevice" },
+ {0, 0x00, "Undefined"},
+ {0, 0x01, "Physical_Interface_Device"},
+ {0, 0x20, "Normal"},
+ {0, 0x21, "Set_Effect_Report"},
+ {0, 0x22, "Effect_Block_Index"},
+ {0, 0x23, "Parameter_Block_Offset"},
+ {0, 0x24, "ROM_Flag"},
+ {0, 0x25, "Effect_Type"},
+ {0, 0x26, "ET_Constant_Force"},
+ {0, 0x27, "ET_Ramp"},
+ {0, 0x28, "ET_Custom_Force_Data"},
+ {0, 0x30, "ET_Square"},
+ {0, 0x31, "ET_Sine"},
+ {0, 0x32, "ET_Triangle"},
+ {0, 0x33, "ET_Sawtooth_Up"},
+ {0, 0x34, "ET_Sawtooth_Down"},
+ {0, 0x40, "ET_Spring"},
+ {0, 0x41, "ET_Damper"},
+ {0, 0x42, "ET_Inertia"},
+ {0, 0x43, "ET_Friction"},
+ {0, 0x50, "Duration"},
+ {0, 0x51, "Sample_Period"},
+ {0, 0x52, "Gain"},
+ {0, 0x53, "Trigger_Button"},
+ {0, 0x54, "Trigger_Repeat_Interval"},
+ {0, 0x55, "Axes_Enable"},
+ {0, 0x56, "Direction_Enable"},
+ {0, 0x57, "Direction"},
+ {0, 0x58, "Type_Specific_Block_Offset"},
+ {0, 0x59, "Block_Type"},
+ {0, 0x5A, "Set_Envelope_Report"},
+ {0, 0x5B, "Attack_Level"},
+ {0, 0x5C, "Attack_Time"},
+ {0, 0x5D, "Fade_Level"},
+ {0, 0x5E, "Fade_Time"},
+ {0, 0x5F, "Set_Condition_Report"},
+ {0, 0x60, "CP_Offset"},
+ {0, 0x61, "Positive_Coefficient"},
+ {0, 0x62, "Negative_Coefficient"},
+ {0, 0x63, "Positive_Saturation"},
+ {0, 0x64, "Negative_Saturation"},
+ {0, 0x65, "Dead_Band"},
+ {0, 0x66, "Download_Force_Sample"},
+ {0, 0x67, "Isoch_Custom_Force_Enable"},
+ {0, 0x68, "Custom_Force_Data_Report"},
+ {0, 0x69, "Custom_Force_Data"},
+ {0, 0x6A, "Custom_Force_Vendor_Defined_Data"},
+ {0, 0x6B, "Set_Custom_Force_Report"},
+ {0, 0x6C, "Custom_Force_Data_Offset"},
+ {0, 0x6D, "Sample_Count"},
+ {0, 0x6E, "Set_Periodic_Report"},
+ {0, 0x6F, "Offset"},
+ {0, 0x70, "Magnitude"},
+ {0, 0x71, "Phase"},
+ {0, 0x72, "Period"},
+ {0, 0x73, "Set_Constant_Force_Report"},
+ {0, 0x74, "Set_Ramp_Force_Report"},
+ {0, 0x75, "Ramp_Start"},
+ {0, 0x76, "Ramp_End"},
+ {0, 0x77, "Effect_Operation_Report"},
+ {0, 0x78, "Effect_Operation"},
+ {0, 0x79, "Op_Effect_Start"},
+ {0, 0x7A, "Op_Effect_Start_Solo"},
+ {0, 0x7B, "Op_Effect_Stop"},
+ {0, 0x7C, "Loop_Count"},
+ {0, 0x7D, "Device_Gain_Report"},
+ {0, 0x7E, "Device_Gain"},
+ {0, 0x7F, "PID_Pool_Report"},
+ {0, 0x80, "RAM_Pool_Size"},
+ {0, 0x81, "ROM_Pool_Size"},
+ {0, 0x82, "ROM_Effect_Block_Count"},
+ {0, 0x83, "Simultaneous_Effects_Max"},
+ {0, 0x84, "Pool_Alignment"},
+ {0, 0x85, "PID_Pool_Move_Report"},
+ {0, 0x86, "Move_Source"},
+ {0, 0x87, "Move_Destination"},
+ {0, 0x88, "Move_Length"},
+ {0, 0x89, "PID_Block_Load_Report"},
+ {0, 0x8B, "Block_Load_Status"},
+ {0, 0x8C, "Block_Load_Success"},
+ {0, 0x8D, "Block_Load_Full"},
+ {0, 0x8E, "Block_Load_Error"},
+ {0, 0x8F, "Block_Handle"},
+ {0, 0x90, "PID_Block_Free_Report"},
+ {0, 0x91, "Type_Specific_Block_Handle"},
+ {0, 0x92, "PID_State_Report"},
+ {0, 0x94, "Effect_Playing"},
+ {0, 0x95, "PID_Device_Control_Report"},
+ {0, 0x96, "PID_Device_Control"},
+ {0, 0x97, "DC_Enable_Actuators"},
+ {0, 0x98, "DC_Disable_Actuators"},
+ {0, 0x99, "DC_Stop_All_Effects"},
+ {0, 0x9A, "DC_Device_Reset"},
+ {0, 0x9B, "DC_Device_Pause"},
+ {0, 0x9C, "DC_Device_Continue"},
+ {0, 0x9F, "Device_Paused"},
+ {0, 0xA0, "Actuators_Enabled"},
+ {0, 0xA4, "Safety_Switch"},
+ {0, 0xA5, "Actuator_Override_Switch"},
+ {0, 0xA6, "Actuator_Power"},
+ {0, 0xA7, "Start_Delay"},
+ {0, 0xA8, "Parameter_Block_Size"},
+ {0, 0xA9, "Device_Managed_Pool"},
+ {0, 0xAA, "Shared_Parameter_Blocks"},
+ {0, 0xAB, "Create_New_Effect_Report"},
+ {0, 0xAC, "RAM_Pool_Available"},
+ { 0x84, 0, "Power Device" },
+ { 0x84, 0x02, "PresentStatus" },
+ { 0x84, 0x03, "ChangeStatus" },
+ { 0x84, 0x04, "UPS" },
+ { 0x84, 0x05, "PowerSupply" },
+ { 0x84, 0x10, "BatterySystem" },
+ { 0x84, 0x11, "BatterySystemID" },
+ { 0x84, 0x12, "Battery" },
+ { 0x84, 0x13, "BatteryID" },
+ { 0x84, 0x14, "Charger" },
+ { 0x84, 0x15, "ChargerID" },
+ { 0x84, 0x16, "PowerConverter" },
+ { 0x84, 0x17, "PowerConverterID" },
+ { 0x84, 0x18, "OutletSystem" },
+ { 0x84, 0x19, "OutletSystemID" },
+ { 0x84, 0x1a, "Input" },
+ { 0x84, 0x1b, "InputID" },
+ { 0x84, 0x1c, "Output" },
+ { 0x84, 0x1d, "OutputID" },
+ { 0x84, 0x1e, "Flow" },
+ { 0x84, 0x1f, "FlowID" },
+ { 0x84, 0x20, "Outlet" },
+ { 0x84, 0x21, "OutletID" },
+ { 0x84, 0x22, "Gang" },
+ { 0x84, 0x24, "PowerSummary" },
+ { 0x84, 0x25, "PowerSummaryID" },
+ { 0x84, 0x30, "Voltage" },
+ { 0x84, 0x31, "Current" },
+ { 0x84, 0x32, "Frequency" },
+ { 0x84, 0x33, "ApparentPower" },
+ { 0x84, 0x35, "PercentLoad" },
+ { 0x84, 0x40, "ConfigVoltage" },
+ { 0x84, 0x41, "ConfigCurrent" },
+ { 0x84, 0x43, "ConfigApparentPower" },
+ { 0x84, 0x53, "LowVoltageTransfer" },
+ { 0x84, 0x54, "HighVoltageTransfer" },
+ { 0x84, 0x56, "DelayBeforeStartup" },
+ { 0x84, 0x57, "DelayBeforeShutdown" },
+ { 0x84, 0x58, "Test" },
+ { 0x84, 0x5a, "AudibleAlarmControl" },
+ { 0x84, 0x60, "Present" },
+ { 0x84, 0x61, "Good" },
+ { 0x84, 0x62, "InternalFailure" },
+ { 0x84, 0x65, "Overload" },
+ { 0x84, 0x66, "OverCharged" },
+ { 0x84, 0x67, "OverTemperature" },
+ { 0x84, 0x68, "ShutdownRequested" },
+ { 0x84, 0x69, "ShutdownImminent" },
+ { 0x84, 0x6b, "SwitchOn/Off" },
+ { 0x84, 0x6c, "Switchable" },
+ { 0x84, 0x6d, "Used" },
+ { 0x84, 0x6e, "Boost" },
+ { 0x84, 0x73, "CommunicationLost" },
+ { 0x84, 0xfd, "iManufacturer" },
+ { 0x84, 0xfe, "iProduct" },
+ { 0x84, 0xff, "iSerialNumber" },
+ { 0x85, 0, "Battery System" },
+ { 0x85, 0x01, "SMBBatteryMode" },
+ { 0x85, 0x02, "SMBBatteryStatus" },
+ { 0x85, 0x03, "SMBAlarmWarning" },
+ { 0x85, 0x04, "SMBChargerMode" },
+ { 0x85, 0x05, "SMBChargerStatus" },
+ { 0x85, 0x06, "SMBChargerSpecInfo" },
+ { 0x85, 0x07, "SMBSelectorState" },
+ { 0x85, 0x08, "SMBSelectorPresets" },
+ { 0x85, 0x09, "SMBSelectorInfo" },
+ { 0x85, 0x29, "RemainingCapacityLimit" },
+ { 0x85, 0x2c, "CapacityMode" },
+ { 0x85, 0x42, "BelowRemainingCapacityLimit" },
+ { 0x85, 0x44, "Charging" },
+ { 0x85, 0x45, "Discharging" },
+ { 0x85, 0x4b, "NeedReplacement" },
+ { 0x85, 0x66, "RemainingCapacity" },
+ { 0x85, 0x68, "RunTimeToEmpty" },
+ { 0x85, 0x6a, "AverageTimeToFull" },
+ { 0x85, 0x83, "DesignCapacity" },
+ { 0x85, 0x85, "ManufacturerDate" },
+ { 0x85, 0x89, "iDeviceChemistry" },
+ { 0x85, 0x8b, "Rechargable" },
+ { 0x85, 0x8f, "iOEMInformation" },
+ { 0x85, 0x8d, "CapacityGranularity1" },
+ { 0x85, 0xd0, "ACPresent" },
+ /* pages 0xff00 to 0xffff are vendor-specific */
+ { 0xffff, 0, "Vendor-specific-FF" },
+ { 0, 0, NULL }
+};
+
+static void resolv_usage_page(unsigned page) {
+ const struct hid_usage_entry *p;
+
+ for (p = hid_usage_table; p->description; p++)
+ if (p->page == page) {
+ printk("%s", p->description);
+ return;
+ }
+ printk("%04x", page);
+}
+
+void hid_resolv_usage(unsigned usage) {
+ const struct hid_usage_entry *p;
+
+ resolv_usage_page(usage >> 16);
+ printk(".");
+ for (p = hid_usage_table; p->description; p++)
+ if (p->page == (usage >> 16)) {
+ for(++p; p->description && p->usage != 0; p++)
+ if (p->usage == (usage & 0xffff)) {
+ printk("%s", p->description);
+ return;
+ }
+ break;
+ }
+ printk("%04x", usage & 0xffff);
+}
+EXPORT_SYMBOL_GPL(hid_resolv_usage);
+
+__inline__ static void tab(int n) {
+ while (n--) printk(" ");
+}
+
+void hid_dump_field(struct hid_field *field, int n) {
+ int j;
+
+ if (field->physical) {
+ tab(n);
+ printk("Physical(");
+ hid_resolv_usage(field->physical); printk(")\n");
+ }
+ if (field->logical) {
+ tab(n);
+ printk("Logical(");
+ hid_resolv_usage(field->logical); printk(")\n");
+ }
+ tab(n); printk("Usage(%d)\n", field->maxusage);
+ for (j = 0; j < field->maxusage; j++) {
+ tab(n+2); hid_resolv_usage(field->usage[j].hid); printk("\n");
+ }
+ if (field->logical_minimum != field->logical_maximum) {
+ tab(n); printk("Logical Minimum(%d)\n", field->logical_minimum);
+ tab(n); printk("Logical Maximum(%d)\n", field->logical_maximum);
+ }
+ if (field->physical_minimum != field->physical_maximum) {
+ tab(n); printk("Physical Minimum(%d)\n", field->physical_minimum);
+ tab(n); printk("Physical Maximum(%d)\n", field->physical_maximum);
+ }
+ if (field->unit_exponent) {
+ tab(n); printk("Unit Exponent(%d)\n", field->unit_exponent);
+ }
+ if (field->unit) {
+ char *systems[5] = { "None", "SI Linear", "SI Rotation", "English Linear", "English Rotation" };
+ char *units[5][8] = {
+ { "None", "None", "None", "None", "None", "None", "None", "None" },
+ { "None", "Centimeter", "Gram", "Seconds", "Kelvin", "Ampere", "Candela", "None" },
+ { "None", "Radians", "Gram", "Seconds", "Kelvin", "Ampere", "Candela", "None" },
+ { "None", "Inch", "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" },
+ { "None", "Degrees", "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" }
+ };
+
+ int i;
+ int sys;
+ __u32 data = field->unit;
+
+ /* First nibble tells us which system we're in. */
+ sys = data & 0xf;
+ data >>= 4;
+
+ if(sys > 4) {
+ tab(n); printk("Unit(Invalid)\n");
+ }
+ else {
+ int earlier_unit = 0;
+
+ tab(n); printk("Unit(%s : ", systems[sys]);
+
+ for (i=1 ; i<sizeof(__u32)*2 ; i++) {
+ char nibble = data & 0xf;
+ data >>= 4;
+ if (nibble != 0) {
+ if(earlier_unit++ > 0)
+ printk("*");
+ printk("%s", units[sys][i]);
+ if(nibble != 1) {
+ /* This is a _signed_ nibble(!) */
+
+ int val = nibble & 0x7;
+ if(nibble & 0x08)
+ val = -((0x7 & ~val) +1);
+ printk("^%d", val);
+ }
+ }
+ }
+ printk(")\n");
+ }
+ }
+ tab(n); printk("Report Size(%u)\n", field->report_size);
+ tab(n); printk("Report Count(%u)\n", field->report_count);
+ tab(n); printk("Report Offset(%u)\n", field->report_offset);
+
+ tab(n); printk("Flags( ");
+ j = field->flags;
+ printk("%s", HID_MAIN_ITEM_CONSTANT & j ? "Constant " : "");
+ printk("%s", HID_MAIN_ITEM_VARIABLE & j ? "Variable " : "Array ");
+ printk("%s", HID_MAIN_ITEM_RELATIVE & j ? "Relative " : "Absolute ");
+ printk("%s", HID_MAIN_ITEM_WRAP & j ? "Wrap " : "");
+ printk("%s", HID_MAIN_ITEM_NONLINEAR & j ? "NonLinear " : "");
+ printk("%s", HID_MAIN_ITEM_NO_PREFERRED & j ? "NoPrefferedState " : "");
+ printk("%s", HID_MAIN_ITEM_NULL_STATE & j ? "NullState " : "");
+ printk("%s", HID_MAIN_ITEM_VOLATILE & j ? "Volatile " : "");
+ printk("%s", HID_MAIN_ITEM_BUFFERED_BYTE & j ? "BufferedByte " : "");
+ printk(")\n");
+}
+EXPORT_SYMBOL_GPL(hid_dump_field);
+
+void hid_dump_device(struct hid_device *device) {
+ struct hid_report_enum *report_enum;
+ struct hid_report *report;
+ struct list_head *list;
+ unsigned i,k;
+ static char *table[] = {"INPUT", "OUTPUT", "FEATURE"};
+
+ for (i = 0; i < HID_REPORT_TYPES; i++) {
+ report_enum = device->report_enum + i;
+ list = report_enum->report_list.next;
+ while (list != &report_enum->report_list) {
+ report = (struct hid_report *) list;
+ tab(2);
+ printk("%s", table[i]);
+ if (report->id)
+ printk("(%d)", report->id);
+ printk("[%s]", table[report->type]);
+ printk("\n");
+ for (k = 0; k < report->maxfield; k++) {
+ tab(4);
+ printk("Field(%d)\n", k);
+ hid_dump_field(report->field[k], 6);
+ }
+ list = list->next;
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(hid_dump_device);
+
+void hid_dump_input(struct hid_usage *usage, __s32 value) {
+ printk("hid-debug: input ");
+ hid_resolv_usage(usage->hid);
+ printk(" = %d\n", value);
+}
+EXPORT_SYMBOL_GPL(hid_dump_input);
+
+static char *events[EV_MAX + 1] = {
+ [EV_SYN] = "Sync", [EV_KEY] = "Key",
+ [EV_REL] = "Relative", [EV_ABS] = "Absolute",
+ [EV_MSC] = "Misc", [EV_LED] = "LED",
+ [EV_SND] = "Sound", [EV_REP] = "Repeat",
+ [EV_FF] = "ForceFeedback", [EV_PWR] = "Power",
+ [EV_FF_STATUS] = "ForceFeedbackStatus",
+};
+
+static char *syncs[2] = {
+ [SYN_REPORT] = "Report", [SYN_CONFIG] = "Config",
+};
+static char *keys[KEY_MAX + 1] = {
+ [KEY_RESERVED] = "Reserved", [KEY_ESC] = "Esc",
+ [KEY_1] = "1", [KEY_2] = "2",
+ [KEY_3] = "3", [KEY_4] = "4",
+ [KEY_5] = "5", [KEY_6] = "6",
+ [KEY_7] = "7", [KEY_8] = "8",
+ [KEY_9] = "9", [KEY_0] = "0",
+ [KEY_MINUS] = "Minus", [KEY_EQUAL] = "Equal",
+ [KEY_BACKSPACE] = "Backspace", [KEY_TAB] = "Tab",
+ [KEY_Q] = "Q", [KEY_W] = "W",
+ [KEY_E] = "E", [KEY_R] = "R",
+ [KEY_T] = "T", [KEY_Y] = "Y",
+ [KEY_U] = "U", [KEY_I] = "I",
+ [KEY_O] = "O", [KEY_P] = "P",
+ [KEY_LEFTBRACE] = "LeftBrace", [KEY_RIGHTBRACE] = "RightBrace",
+ [KEY_ENTER] = "Enter", [KEY_LEFTCTRL] = "LeftControl",
+ [KEY_A] = "A", [KEY_S] = "S",
+ [KEY_D] = "D", [KEY_F] = "F",
+ [KEY_G] = "G", [KEY_H] = "H",
+ [KEY_J] = "J", [KEY_K] = "K",
+ [KEY_L] = "L", [KEY_SEMICOLON] = "Semicolon",
+ [KEY_APOSTROPHE] = "Apostrophe", [KEY_GRAVE] = "Grave",
+ [KEY_LEFTSHIFT] = "LeftShift", [KEY_BACKSLASH] = "BackSlash",
+ [KEY_Z] = "Z", [KEY_X] = "X",
+ [KEY_C] = "C", [KEY_V] = "V",
+ [KEY_B] = "B", [KEY_N] = "N",
+ [KEY_M] = "M", [KEY_COMMA] = "Comma",
+ [KEY_DOT] = "Dot", [KEY_SLASH] = "Slash",
+ [KEY_RIGHTSHIFT] = "RightShift", [KEY_KPASTERISK] = "KPAsterisk",
+ [KEY_LEFTALT] = "LeftAlt", [KEY_SPACE] = "Space",
+ [KEY_CAPSLOCK] = "CapsLock", [KEY_F1] = "F1",
+ [KEY_F2] = "F2", [KEY_F3] = "F3",
+ [KEY_F4] = "F4", [KEY_F5] = "F5",
+ [KEY_F6] = "F6", [KEY_F7] = "F7",
+ [KEY_F8] = "F8", [KEY_F9] = "F9",
+ [KEY_F10] = "F10", [KEY_NUMLOCK] = "NumLock",
+ [KEY_SCROLLLOCK] = "ScrollLock", [KEY_KP7] = "KP7",
+ [KEY_KP8] = "KP8", [KEY_KP9] = "KP9",
+ [KEY_KPMINUS] = "KPMinus", [KEY_KP4] = "KP4",
+ [KEY_KP5] = "KP5", [KEY_KP6] = "KP6",
+ [KEY_KPPLUS] = "KPPlus", [KEY_KP1] = "KP1",
+ [KEY_KP2] = "KP2", [KEY_KP3] = "KP3",
+ [KEY_KP0] = "KP0", [KEY_KPDOT] = "KPDot",
+ [KEY_ZENKAKUHANKAKU] = "Zenkaku/Hankaku", [KEY_102ND] = "102nd",
+ [KEY_F11] = "F11", [KEY_F12] = "F12",
+ [KEY_RO] = "RO", [KEY_KATAKANA] = "Katakana",
+ [KEY_HIRAGANA] = "HIRAGANA", [KEY_HENKAN] = "Henkan",
+ [KEY_KATAKANAHIRAGANA] = "Katakana/Hiragana", [KEY_MUHENKAN] = "Muhenkan",
+ [KEY_KPJPCOMMA] = "KPJpComma", [KEY_KPENTER] = "KPEnter",
+ [KEY_RIGHTCTRL] = "RightCtrl", [KEY_KPSLASH] = "KPSlash",
+ [KEY_SYSRQ] = "SysRq", [KEY_RIGHTALT] = "RightAlt",
+ [KEY_LINEFEED] = "LineFeed", [KEY_HOME] = "Home",
+ [KEY_UP] = "Up", [KEY_PAGEUP] = "PageUp",
+ [KEY_LEFT] = "Left", [KEY_RIGHT] = "Right",
+ [KEY_END] = "End", [KEY_DOWN] = "Down",
+ [KEY_PAGEDOWN] = "PageDown", [KEY_INSERT] = "Insert",
+ [KEY_DELETE] = "Delete", [KEY_MACRO] = "Macro",
+ [KEY_MUTE] = "Mute", [KEY_VOLUMEDOWN] = "VolumeDown",
+ [KEY_VOLUMEUP] = "VolumeUp", [KEY_POWER] = "Power",
+ [KEY_KPEQUAL] = "KPEqual", [KEY_KPPLUSMINUS] = "KPPlusMinus",
+ [KEY_PAUSE] = "Pause", [KEY_KPCOMMA] = "KPComma",
+ [KEY_HANGUEL] = "Hangeul", [KEY_HANJA] = "Hanja",
+ [KEY_YEN] = "Yen", [KEY_LEFTMETA] = "LeftMeta",
+ [KEY_RIGHTMETA] = "RightMeta", [KEY_COMPOSE] = "Compose",
+ [KEY_STOP] = "Stop", [KEY_AGAIN] = "Again",
+ [KEY_PROPS] = "Props", [KEY_UNDO] = "Undo",
+ [KEY_FRONT] = "Front", [KEY_COPY] = "Copy",
+ [KEY_OPEN] = "Open", [KEY_PASTE] = "Paste",
+ [KEY_FIND] = "Find", [KEY_CUT] = "Cut",
+ [KEY_HELP] = "Help", [KEY_MENU] = "Menu",
+ [KEY_CALC] = "Calc", [KEY_SETUP] = "Setup",
+ [KEY_SLEEP] = "Sleep", [KEY_WAKEUP] = "WakeUp",
+ [KEY_FILE] = "File", [KEY_SENDFILE] = "SendFile",
+ [KEY_DELETEFILE] = "DeleteFile", [KEY_XFER] = "X-fer",
+ [KEY_PROG1] = "Prog1", [KEY_PROG2] = "Prog2",
+ [KEY_WWW] = "WWW", [KEY_MSDOS] = "MSDOS",
+ [KEY_COFFEE] = "Coffee", [KEY_DIRECTION] = "Direction",
+ [KEY_CYCLEWINDOWS] = "CycleWindows", [KEY_MAIL] = "Mail",
+ [KEY_BOOKMARKS] = "Bookmarks", [KEY_COMPUTER] = "Computer",
+ [KEY_BACK] = "Back", [KEY_FORWARD] = "Forward",
+ [KEY_CLOSECD] = "CloseCD", [KEY_EJECTCD] = "EjectCD",
+ [KEY_EJECTCLOSECD] = "EjectCloseCD", [KEY_NEXTSONG] = "NextSong",
+ [KEY_PLAYPAUSE] = "PlayPause", [KEY_PREVIOUSSONG] = "PreviousSong",
+ [KEY_STOPCD] = "StopCD", [KEY_RECORD] = "Record",
+ [KEY_REWIND] = "Rewind", [KEY_PHONE] = "Phone",
+ [KEY_ISO] = "ISOKey", [KEY_CONFIG] = "Config",
+ [KEY_HOMEPAGE] = "HomePage", [KEY_REFRESH] = "Refresh",
+ [KEY_EXIT] = "Exit", [KEY_MOVE] = "Move",
+ [KEY_EDIT] = "Edit", [KEY_SCROLLUP] = "ScrollUp",
+ [KEY_SCROLLDOWN] = "ScrollDown", [KEY_KPLEFTPAREN] = "KPLeftParenthesis",
+ [KEY_KPRIGHTPAREN] = "KPRightParenthesis", [KEY_NEW] = "New",
+ [KEY_REDO] = "Redo", [KEY_F13] = "F13",
+ [KEY_F14] = "F14", [KEY_F15] = "F15",
+ [KEY_F16] = "F16", [KEY_F17] = "F17",
+ [KEY_F18] = "F18", [KEY_F19] = "F19",
+ [KEY_F20] = "F20", [KEY_F21] = "F21",
+ [KEY_F22] = "F22", [KEY_F23] = "F23",
+ [KEY_F24] = "F24", [KEY_PLAYCD] = "PlayCD",
+ [KEY_PAUSECD] = "PauseCD", [KEY_PROG3] = "Prog3",
+ [KEY_PROG4] = "Prog4", [KEY_SUSPEND] = "Suspend",
+ [KEY_CLOSE] = "Close", [KEY_PLAY] = "Play",
+ [KEY_FASTFORWARD] = "FastForward", [KEY_BASSBOOST] = "BassBoost",
+ [KEY_PRINT] = "Print", [KEY_HP] = "HP",
+ [KEY_CAMERA] = "Camera", [KEY_SOUND] = "Sound",
+ [KEY_QUESTION] = "Question", [KEY_EMAIL] = "Email",
+ [KEY_CHAT] = "Chat", [KEY_SEARCH] = "Search",
+ [KEY_CONNECT] = "Connect", [KEY_FINANCE] = "Finance",
+ [KEY_SPORT] = "Sport", [KEY_SHOP] = "Shop",
+ [KEY_ALTERASE] = "AlternateErase", [KEY_CANCEL] = "Cancel",
+ [KEY_BRIGHTNESSDOWN] = "BrightnessDown", [KEY_BRIGHTNESSUP] = "BrightnessUp",
+ [KEY_MEDIA] = "Media", [KEY_UNKNOWN] = "Unknown",
+ [BTN_0] = "Btn0", [BTN_1] = "Btn1",
+ [BTN_2] = "Btn2", [BTN_3] = "Btn3",
+ [BTN_4] = "Btn4", [BTN_5] = "Btn5",
+ [BTN_6] = "Btn6", [BTN_7] = "Btn7",
+ [BTN_8] = "Btn8", [BTN_9] = "Btn9",
+ [BTN_LEFT] = "LeftBtn", [BTN_RIGHT] = "RightBtn",
+ [BTN_MIDDLE] = "MiddleBtn", [BTN_SIDE] = "SideBtn",
+ [BTN_EXTRA] = "ExtraBtn", [BTN_FORWARD] = "ForwardBtn",
+ [BTN_BACK] = "BackBtn", [BTN_TASK] = "TaskBtn",
+ [BTN_TRIGGER] = "Trigger", [BTN_THUMB] = "ThumbBtn",
+ [BTN_THUMB2] = "ThumbBtn2", [BTN_TOP] = "TopBtn",
+ [BTN_TOP2] = "TopBtn2", [BTN_PINKIE] = "PinkieBtn",
+ [BTN_BASE] = "BaseBtn", [BTN_BASE2] = "BaseBtn2",
+ [BTN_BASE3] = "BaseBtn3", [BTN_BASE4] = "BaseBtn4",
+ [BTN_BASE5] = "BaseBtn5", [BTN_BASE6] = "BaseBtn6",
+ [BTN_DEAD] = "BtnDead", [BTN_A] = "BtnA",
+ [BTN_B] = "BtnB", [BTN_C] = "BtnC",
+ [BTN_X] = "BtnX", [BTN_Y] = "BtnY",
+ [BTN_Z] = "BtnZ", [BTN_TL] = "BtnTL",
+ [BTN_TR] = "BtnTR", [BTN_TL2] = "BtnTL2",
+ [BTN_TR2] = "BtnTR2", [BTN_SELECT] = "BtnSelect",
+ [BTN_START] = "BtnStart", [BTN_MODE] = "BtnMode",
+ [BTN_THUMBL] = "BtnThumbL", [BTN_THUMBR] = "BtnThumbR",
+ [BTN_TOOL_PEN] = "ToolPen", [BTN_TOOL_RUBBER] = "ToolRubber",
+ [BTN_TOOL_BRUSH] = "ToolBrush", [BTN_TOOL_PENCIL] = "ToolPencil",
+ [BTN_TOOL_AIRBRUSH] = "ToolAirbrush", [BTN_TOOL_FINGER] = "ToolFinger",
+ [BTN_TOOL_MOUSE] = "ToolMouse", [BTN_TOOL_LENS] = "ToolLens",
+ [BTN_TOUCH] = "Touch", [BTN_STYLUS] = "Stylus",
+ [BTN_STYLUS2] = "Stylus2", [BTN_TOOL_DOUBLETAP] = "ToolDoubleTap",
+ [BTN_TOOL_TRIPLETAP] = "ToolTripleTap", [BTN_GEAR_DOWN] = "WheelBtn",
+ [BTN_GEAR_UP] = "Gear up", [KEY_OK] = "Ok",
+ [KEY_SELECT] = "Select", [KEY_GOTO] = "Goto",
+ [KEY_CLEAR] = "Clear", [KEY_POWER2] = "Power2",
+ [KEY_OPTION] = "Option", [KEY_INFO] = "Info",
+ [KEY_TIME] = "Time", [KEY_VENDOR] = "Vendor",
+ [KEY_ARCHIVE] = "Archive", [KEY_PROGRAM] = "Program",
+ [KEY_CHANNEL] = "Channel", [KEY_FAVORITES] = "Favorites",
+ [KEY_EPG] = "EPG", [KEY_PVR] = "PVR",
+ [KEY_MHP] = "MHP", [KEY_LANGUAGE] = "Language",
+ [KEY_TITLE] = "Title", [KEY_SUBTITLE] = "Subtitle",
+ [KEY_ANGLE] = "Angle", [KEY_ZOOM] = "Zoom",
+ [KEY_MODE] = "Mode", [KEY_KEYBOARD] = "Keyboard",
+ [KEY_SCREEN] = "Screen", [KEY_PC] = "PC",
+ [KEY_TV] = "TV", [KEY_TV2] = "TV2",
+ [KEY_VCR] = "VCR", [KEY_VCR2] = "VCR2",
+ [KEY_SAT] = "Sat", [KEY_SAT2] = "Sat2",
+ [KEY_CD] = "CD", [KEY_TAPE] = "Tape",
+ [KEY_RADIO] = "Radio", [KEY_TUNER] = "Tuner",
+ [KEY_PLAYER] = "Player", [KEY_TEXT] = "Text",
+ [KEY_DVD] = "DVD", [KEY_AUX] = "Aux",
+ [KEY_MP3] = "MP3", [KEY_AUDIO] = "Audio",
+ [KEY_VIDEO] = "Video", [KEY_DIRECTORY] = "Directory",
+ [KEY_LIST] = "List", [KEY_MEMO] = "Memo",
+ [KEY_CALENDAR] = "Calendar", [KEY_RED] = "Red",
+ [KEY_GREEN] = "Green", [KEY_YELLOW] = "Yellow",
+ [KEY_BLUE] = "Blue", [KEY_CHANNELUP] = "ChannelUp",
+ [KEY_CHANNELDOWN] = "ChannelDown", [KEY_FIRST] = "First",
+ [KEY_LAST] = "Last", [KEY_AB] = "AB",
+ [KEY_NEXT] = "Next", [KEY_RESTART] = "Restart",
+ [KEY_SLOW] = "Slow", [KEY_SHUFFLE] = "Shuffle",
+ [KEY_BREAK] = "Break", [KEY_PREVIOUS] = "Previous",
+ [KEY_DIGITS] = "Digits", [KEY_TEEN] = "TEEN",
+ [KEY_TWEN] = "TWEN", [KEY_DEL_EOL] = "DeleteEOL",
+ [KEY_DEL_EOS] = "DeleteEOS", [KEY_INS_LINE] = "InsertLine",
+ [KEY_DEL_LINE] = "DeleteLine",
+ [KEY_SEND] = "Send", [KEY_REPLY] = "Reply",
+ [KEY_FORWARDMAIL] = "ForwardMail", [KEY_SAVE] = "Save",
+ [KEY_DOCUMENTS] = "Documents",
+ [KEY_FN] = "Fn", [KEY_FN_ESC] = "Fn+ESC",
+ [KEY_FN_1] = "Fn+1", [KEY_FN_2] = "Fn+2",
+ [KEY_FN_B] = "Fn+B", [KEY_FN_D] = "Fn+D",
+ [KEY_FN_E] = "Fn+E", [KEY_FN_F] = "Fn+F",
+ [KEY_FN_S] = "Fn+S",
+ [KEY_FN_F1] = "Fn+F1", [KEY_FN_F2] = "Fn+F2",
+ [KEY_FN_F3] = "Fn+F3", [KEY_FN_F4] = "Fn+F4",
+ [KEY_FN_F5] = "Fn+F5", [KEY_FN_F6] = "Fn+F6",
+ [KEY_FN_F7] = "Fn+F7", [KEY_FN_F8] = "Fn+F8",
+ [KEY_FN_F9] = "Fn+F9", [KEY_FN_F10] = "Fn+F10",
+ [KEY_FN_F11] = "Fn+F11", [KEY_FN_F12] = "Fn+F12",
+ [KEY_KBDILLUMTOGGLE] = "KbdIlluminationToggle",
+ [KEY_KBDILLUMDOWN] = "KbdIlluminationDown",
+ [KEY_KBDILLUMUP] = "KbdIlluminationUp",
+ [KEY_SWITCHVIDEOMODE] = "SwitchVideoMode",
+};
+
+static char *relatives[REL_MAX + 1] = {
+ [REL_X] = "X", [REL_Y] = "Y",
+ [REL_Z] = "Z", [REL_RX] = "Rx",
+ [REL_RY] = "Ry", [REL_RZ] = "Rz",
+ [REL_HWHEEL] = "HWheel", [REL_DIAL] = "Dial",
+ [REL_WHEEL] = "Wheel", [REL_MISC] = "Misc",
+};
+
+static char *absolutes[ABS_MAX + 1] = {
+ [ABS_X] = "X", [ABS_Y] = "Y",
+ [ABS_Z] = "Z", [ABS_RX] = "Rx",
+ [ABS_RY] = "Ry", [ABS_RZ] = "Rz",
+ [ABS_THROTTLE] = "Throttle", [ABS_RUDDER] = "Rudder",
+ [ABS_WHEEL] = "Wheel", [ABS_GAS] = "Gas",
+ [ABS_BRAKE] = "Brake", [ABS_HAT0X] = "Hat0X",
+ [ABS_HAT0Y] = "Hat0Y", [ABS_HAT1X] = "Hat1X",
+ [ABS_HAT1Y] = "Hat1Y", [ABS_HAT2X] = "Hat2X",
+ [ABS_HAT2Y] = "Hat2Y", [ABS_HAT3X] = "Hat3X",
+ [ABS_HAT3Y] = "Hat 3Y", [ABS_PRESSURE] = "Pressure",
+ [ABS_DISTANCE] = "Distance", [ABS_TILT_X] = "XTilt",
+ [ABS_TILT_Y] = "YTilt", [ABS_TOOL_WIDTH] = "Tool Width",
+ [ABS_VOLUME] = "Volume", [ABS_MISC] = "Misc",
+};
+
+static char *misc[MSC_MAX + 1] = {
+ [MSC_SERIAL] = "Serial", [MSC_PULSELED] = "Pulseled",
+ [MSC_GESTURE] = "Gesture", [MSC_RAW] = "RawData"
+};
+
+static char *leds[LED_MAX + 1] = {
+ [LED_NUML] = "NumLock", [LED_CAPSL] = "CapsLock",
+ [LED_SCROLLL] = "ScrollLock", [LED_COMPOSE] = "Compose",
+ [LED_KANA] = "Kana", [LED_SLEEP] = "Sleep",
+ [LED_SUSPEND] = "Suspend", [LED_MUTE] = "Mute",
+ [LED_MISC] = "Misc",
+};
+
+static char *repeats[REP_MAX + 1] = {
+ [REP_DELAY] = "Delay", [REP_PERIOD] = "Period"
+};
+
+static char *sounds[SND_MAX + 1] = {
+ [SND_CLICK] = "Click", [SND_BELL] = "Bell",
+ [SND_TONE] = "Tone"
+};
+
+static char **names[EV_MAX + 1] = {
+ [EV_SYN] = syncs, [EV_KEY] = keys,
+ [EV_REL] = relatives, [EV_ABS] = absolutes,
+ [EV_MSC] = misc, [EV_LED] = leds,
+ [EV_SND] = sounds, [EV_REP] = repeats,
+};
+
+void hid_resolv_event(__u8 type, __u16 code) {
+
+ printk("%s.%s", events[type] ? events[type] : "?",
+ names[type] ? (names[type][code] ? names[type][code] : "?") : "?");
+}
+EXPORT_SYMBOL_GPL(hid_resolv_event);
+
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index c7a6833f682..25d180a24fc 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -31,9 +31,8 @@
#include <linux/slab.h>
#include <linux/kernel.h>
-#undef DEBUG
-
#include <linux/hid.h>
+#include <linux/hid-debug.h>
static int hid_pb_fnmode = 1;
module_param_named(pb_fnmode, hid_pb_fnmode, int, 0644);
@@ -252,9 +251,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
field->hidinput = hidinput;
-#ifdef DEBUG
+#ifdef CONFIG_HID_DEBUG
printk(KERN_DEBUG "Mapping: ");
- resolv_usage(usage->hid);
+ hid_resolv_usage(usage->hid);
printk(" ---> ");
#endif
@@ -682,14 +681,14 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
field->dpad = usage->code;
}
-#ifdef DEBUG
- resolv_event(usage->type, usage->code);
+ hid_resolv_event(usage->type, usage->code);
+#ifdef CONFIG_HID_DEBUG
printk("\n");
#endif
return;
ignore:
-#ifdef DEBUG
+#ifdef CONFIG_HID_DEBUG
printk("IGNORED\n");
#endif
return;
@@ -804,6 +803,18 @@ int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int
}
EXPORT_SYMBOL_GPL(hidinput_find_field);
+static int hidinput_open(struct input_dev *dev)
+{
+ struct hid_device *hid = dev->private;
+ return hid->hid_open(hid);
+}
+
+static void hidinput_close(struct input_dev *dev)
+{
+ struct hid_device *hid = dev->private;
+ hid->hid_close(hid);
+}
+
/*
* Register the input device; print a message.
* Configure the input layer interface
@@ -816,6 +827,7 @@ int hidinput_connect(struct hid_device *hid)
struct hid_input *hidinput = NULL;
struct input_dev *input_dev;
int i, j, k;
+ int max_report_type = HID_OUTPUT_REPORT;
INIT_LIST_HEAD(&hid->inputs);
@@ -828,7 +840,10 @@ int hidinput_connect(struct hid_device *hid)
if (i == hid->maxcollection)
return -1;
- for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++)
+ if (hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS)
+ max_report_type = HID_INPUT_REPORT;
+
+ for (k = HID_INPUT_REPORT; k <= max_report_type; k++)
list_for_each_entry(report, &hid->report_enum[k].report_list, list) {
if (!report->maxfield)
@@ -846,8 +861,8 @@ int hidinput_connect(struct hid_device *hid)
input_dev->private = hid;
input_dev->event = hid->hidinput_input_event;
- input_dev->open = hid->hidinput_open;
- input_dev->close = hid->hidinput_close;
+ input_dev->open = hidinput_open;
+ input_dev->close = hidinput_close;
input_dev->name = hid->name;
input_dev->phys = hid->phys;
diff --git a/drivers/hwmon/ams/ams-input.c b/drivers/hwmon/ams/ams-input.c
index f126aa48513..18210164e30 100644
--- a/drivers/hwmon/ams/ams-input.c
+++ b/drivers/hwmon/ams/ams-input.c
@@ -153,7 +153,7 @@ int ams_input_init(void)
}
/* Call with ams_info.lock held! */
-void ams_input_exit()
+void ams_input_exit(void)
{
ams_input_disable();
device_remove_file(&ams_info.of_dev->dev, &dev_attr_joystick);
diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c
index ccdf3e90862..9fafadb9251 100644
--- a/drivers/i2c/chips/isp1301_omap.c
+++ b/drivers/i2c/chips/isp1301_omap.c
@@ -27,7 +27,7 @@
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <linux/usb.h>
#include <linux/usb/otg.h>
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index 3f828052f8d..ec03341d2bd 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -167,6 +167,13 @@ config BLK_DEV_IDECS
Support for Compact Flash cards, outboard IDE disks, tape drives,
and CD-ROM drives connected through a PCMCIA card.
+config BLK_DEV_DELKIN
+ tristate "Cardbus IDE support (Delkin/ASKA/Workbit)"
+ depends on CARDBUS && PCI
+ help
+ Support for Delkin, ASKA, and Workbit Cardbus CompactFlash
+ Adapters. This may also work for similar SD and XD adapters.
+
config BLK_DEV_IDECD
tristate "Include IDE/ATAPI CDROM support"
---help---
@@ -264,6 +271,13 @@ config BLK_DEV_IDESCSI
If both this SCSI emulation and native ATAPI support are compiled
into the kernel, the native support will be used.
+config BLK_DEV_IDEACPI
+ bool "IDE ACPI support"
+ depends on ACPI
+ ---help---
+ Implement ACPI support for generic IDE devices. On modern
+ machines ACPI support is required to properly handle ACPI S3 states.
+
config IDE_TASK_IOCTL
bool "IDE Taskfile Access"
help
@@ -606,6 +620,11 @@ config BLK_DEV_PIIX
the kernel to change PIO, DMA and UDMA speeds and to configure
the chip to optimum performance.
+config BLK_DEV_IT8213
+ tristate "IT8213 IDE support"
+ help
+ This driver adds support for the ITE 8213 IDE controller.
+
config BLK_DEV_IT821X
tristate "IT821X IDE support"
help
@@ -742,6 +761,11 @@ config BLK_DEV_VIA82CXXX
This allows the kernel to change PIO, DMA and UDMA speeds and to
configure the chip to optimum performance.
+config BLK_DEV_TC86C001
+ tristate "Toshiba TC86C001 support"
+ help
+ This driver adds support for Toshiba TC86C001 GOKU-S chip.
+
endif
config BLK_DEV_IDE_PMAC
diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile
index 569fae71750..d9f029e8ff7 100644
--- a/drivers/ide/Makefile
+++ b/drivers/ide/Makefile
@@ -22,6 +22,7 @@ ide-core-$(CONFIG_BLK_DEV_IDEPCI) += setup-pci.o
ide-core-$(CONFIG_BLK_DEV_IDEDMA) += ide-dma.o
ide-core-$(CONFIG_PROC_FS) += ide-proc.o
ide-core-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o
+ide-core-$(CONFIG_BLK_DEV_IDEACPI) += ide-acpi.o
# built-in only drivers from arm/
ide-core-$(CONFIG_IDE_ARM) += arm/ide_arm.o
diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c
new file mode 100644
index 00000000000..17aea65d7dd
--- /dev/null
+++ b/drivers/ide/ide-acpi.c
@@ -0,0 +1,697 @@
+/*
+ * ide-acpi.c
+ * Provides ACPI support for IDE drives.
+ *
+ * Copyright (C) 2005 Intel Corp.
+ * Copyright (C) 2005 Randy Dunlap
+ * Copyright (C) 2006 SUSE Linux Products GmbH
+ * Copyright (C) 2006 Hannes Reinecke
+ */
+
+#include <linux/ata.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <acpi/acpi.h>
+#include <linux/ide.h>
+#include <linux/pci.h>
+
+#include <acpi/acpi_bus.h>
+#include <acpi/acnames.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acparser.h>
+#include <acpi/acexcep.h>
+#include <acpi/acmacros.h>
+#include <acpi/actypes.h>
+
+#define REGS_PER_GTF 7
+struct taskfile_array {
+ u8 tfa[REGS_PER_GTF]; /* regs. 0x1f1 - 0x1f7 */
+};
+
+struct GTM_buffer {
+ u32 PIO_speed0;
+ u32 DMA_speed0;
+ u32 PIO_speed1;
+ u32 DMA_speed1;
+ u32 GTM_flags;
+};
+
+struct ide_acpi_drive_link {
+ ide_drive_t *drive;
+ acpi_handle obj_handle;
+ u8 idbuff[512];
+};
+
+struct ide_acpi_hwif_link {
+ ide_hwif_t *hwif;
+ acpi_handle obj_handle;
+ struct GTM_buffer gtm;
+ struct ide_acpi_drive_link master;
+ struct ide_acpi_drive_link slave;
+};
+
+#undef DEBUGGING
+/* note: adds function name and KERN_DEBUG */
+#ifdef DEBUGGING
+#define DEBPRINT(fmt, args...) \
+ printk(KERN_DEBUG "%s: " fmt, __FUNCTION__, ## args)
+#else
+#define DEBPRINT(fmt, args...) do {} while (0)
+#endif /* DEBUGGING */
+
+extern int ide_noacpi;
+extern int ide_noacpitfs;
+extern int ide_noacpionboot;
+
+/**
+ * ide_get_dev_handle - finds acpi_handle and PCI device.function
+ * @dev: device to locate
+ * @handle: returned acpi_handle for @dev
+ * @pcidevfn: return PCI device.func for @dev
+ *
+ * Returns the ACPI object handle to the corresponding PCI device.
+ *
+ * Returns 0 on success, <0 on error.
+ */
+static int ide_get_dev_handle(struct device *dev, acpi_handle *handle,
+ acpi_integer *pcidevfn)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ unsigned int bus, devnum, func;
+ acpi_integer addr;
+ acpi_handle dev_handle;
+ struct acpi_buffer buffer = {.length = ACPI_ALLOCATE_BUFFER,
+ .pointer = NULL};
+ acpi_status status;
+ struct acpi_device_info *dinfo = NULL;
+ int ret = -ENODEV;
+
+ bus = pdev->bus->number;
+ devnum = PCI_SLOT(pdev->devfn);
+ func = PCI_FUNC(pdev->devfn);
+ /* ACPI _ADR encoding for PCI bus: */
+ addr = (acpi_integer)(devnum << 16 | func);
+
+ DEBPRINT("ENTER: pci %02x:%02x.%01x\n", bus, devnum, func);
+
+ dev_handle = DEVICE_ACPI_HANDLE(dev);
+ if (!dev_handle) {
+ DEBPRINT("no acpi handle for device\n");
+ goto err;
+ }
+
+ status = acpi_get_object_info(dev_handle, &buffer);
+ if (ACPI_FAILURE(status)) {
+ DEBPRINT("get_object_info for device failed\n");
+ goto err;
+ }
+ dinfo = buffer.pointer;
+ if (dinfo && (dinfo->valid & ACPI_VALID_ADR) &&
+ dinfo->address == addr) {
+ *pcidevfn = addr;
+ *handle = dev_handle;
+ } else {
+ DEBPRINT("get_object_info for device has wrong "
+ " address: %llu, should be %u\n",
+ dinfo ? (unsigned long long)dinfo->address : -1ULL,
+ (unsigned int)addr);
+ goto err;
+ }
+
+ DEBPRINT("for dev=0x%x.%x, addr=0x%llx, *handle=0x%p\n",
+ devnum, func, (unsigned long long)addr, *handle);
+ ret = 0;
+err:
+ kfree(dinfo);
+ return ret;
+}
+
+/**
+ * ide_acpi_hwif_get_handle - Get ACPI object handle for a given hwif
+ * @hwif: device to locate
+ *
+ * Retrieves the object handle for a given hwif.
+ *
+ * Returns handle on success, 0 on error.
+ */
+static acpi_handle ide_acpi_hwif_get_handle(ide_hwif_t *hwif)
+{
+ struct device *dev = hwif->gendev.parent;
+ acpi_handle dev_handle;
+ acpi_integer pcidevfn;
+ acpi_handle chan_handle;
+ int err;
+
+ DEBPRINT("ENTER: device %s\n", hwif->name);
+
+ if (!dev) {
+ DEBPRINT("no PCI device for %s\n", hwif->name);
+ return NULL;
+ }
+
+ err = ide_get_dev_handle(dev, &dev_handle, &pcidevfn);
+ if (err < 0) {
+ DEBPRINT("ide_get_dev_handle failed (%d)\n", err);
+ return NULL;
+ }
+
+ /* get child objects of dev_handle == channel objects,
+ * + _their_ children == drive objects */
+ /* channel is hwif->channel */
+ chan_handle = acpi_get_child(dev_handle, hwif->channel);
+ DEBPRINT("chan adr=%d: handle=0x%p\n",
+ hwif->channel, chan_handle);
+
+ return chan_handle;
+}
+
+/**
+ * ide_acpi_drive_get_handle - Get ACPI object handle for a given drive
+ * @drive: device to locate
+ *
+ * Retrieves the object handle of a given drive. According to the ACPI
+ * spec the drive is a child of the hwif.
+ *
+ * Returns handle on success, 0 on error.
+ */
+static acpi_handle ide_acpi_drive_get_handle(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ int port;
+ acpi_handle drive_handle;
+
+ if (!hwif->acpidata)
+ return NULL;
+
+ if (!hwif->acpidata->obj_handle)
+ return NULL;
+
+ port = hwif->channel ? drive->dn - 2: drive->dn;
+
+ DEBPRINT("ENTER: %s at channel#: %d port#: %d\n",
+ drive->name, hwif->channel, port);
+
+
+ /* TBD: could also check ACPI object VALID bits */
+ drive_handle = acpi_get_child(hwif->acpidata->obj_handle, port);
+ DEBPRINT("drive %s handle 0x%p\n", drive->name, drive_handle);
+
+ return drive_handle;
+}
+
+/**
+ * do_drive_get_GTF - get the drive bootup default taskfile settings
+ * @drive: the drive for which the taskfile settings should be retrieved
+ * @gtf_length: number of bytes of _GTF data returned at @gtf_address
+ * @gtf_address: buffer containing _GTF taskfile arrays
+ *
+ * The _GTF method has no input parameters.
+ * It returns a variable number of register set values (registers
+ * hex 1F1..1F7, taskfiles).
+ * The <variable number> is not known in advance, so have ACPI-CA
+ * allocate the buffer as needed and return it, then free it later.
+ *
+ * The returned @gtf_length and @gtf_address are only valid if the
+ * function return value is 0.
+ */
+static int do_drive_get_GTF(ide_drive_t *drive,
+ unsigned int *gtf_length, unsigned long *gtf_address,
+ unsigned long *obj_loc)
+{
+ acpi_status status;
+ struct acpi_buffer output;
+ union acpi_object *out_obj;
+ ide_hwif_t *hwif = HWIF(drive);
+ struct device *dev = hwif->gendev.parent;
+ int err = -ENODEV;
+ int port;
+
+ *gtf_length = 0;
+ *gtf_address = 0UL;
+ *obj_loc = 0UL;
+
+ if (ide_noacpi)
+ return 0;
+
+ if (!dev) {
+ DEBPRINT("no PCI device for %s\n", hwif->name);
+ goto out;
+ }
+
+ if (!hwif->acpidata) {
+ DEBPRINT("no ACPI data for %s\n", hwif->name);
+ goto out;
+ }
+
+ port = hwif->channel ? drive->dn - 2: drive->dn;
+
+ if (!drive->acpidata) {
+ if (port == 0) {
+ drive->acpidata = &hwif->acpidata->master;
+ hwif->acpidata->master.drive = drive;
+ } else {
+ drive->acpidata = &hwif->acpidata->slave;
+ hwif->acpidata->slave.drive = drive;
+ }
+ }
+
+ DEBPRINT("ENTER: %s at %s, port#: %d, hard_port#: %d\n",
+ hwif->name, dev->bus_id, port, hwif->channel);
+
+ if (!drive->present) {
+ DEBPRINT("%s drive %d:%d not present\n",
+ hwif->name, hwif->channel, port);
+ goto out;
+ }
+
+ /* Get this drive's _ADR info. if not already known. */
+ if (!drive->acpidata->obj_handle) {
+ drive->acpidata->obj_handle = ide_acpi_drive_get_handle(drive);
+ if (!drive->acpidata->obj_handle) {
+ DEBPRINT("No ACPI object found for %s\n",
+ drive->name);
+ goto out;
+ }
+ }
+
+ /* Setting up output buffer */
+ output.length = ACPI_ALLOCATE_BUFFER;
+ output.pointer = NULL; /* ACPI-CA sets this; save/free it later */
+
+ /* _GTF has no input parameters */
+ err = -EIO;
+ status = acpi_evaluate_object(drive->acpidata->obj_handle, "_GTF",
+ NULL, &output);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_DEBUG
+ "%s: Run _GTF error: status = 0x%x\n",
+ __FUNCTION__, status);
+ goto out;
+ }
+
+ if (!output.length || !output.pointer) {
+ DEBPRINT("Run _GTF: "
+ "length or ptr is NULL (0x%llx, 0x%p)\n",
+ (unsigned long long)output.length,
+ output.pointer);
+ goto out;
+ }
+
+ out_obj = output.pointer;
+ if (out_obj->type != ACPI_TYPE_BUFFER) {
+ DEBPRINT("Run _GTF: error: "
+ "expected object type of ACPI_TYPE_BUFFER, "
+ "got 0x%x\n", out_obj->type);
+ err = -ENOENT;
+ kfree(output.pointer);
+ goto out;
+ }
+
+ if (!out_obj->buffer.length || !out_obj->buffer.pointer ||
+ out_obj->buffer.length % REGS_PER_GTF) {
+ printk(KERN_ERR
+ "%s: unexpected GTF length (%d) or addr (0x%p)\n",
+ __FUNCTION__, out_obj->buffer.length,
+ out_obj->buffer.pointer);
+ err = -ENOENT;
+ kfree(output.pointer);
+ goto out;
+ }
+
+ *gtf_length = out_obj->buffer.length;
+ *gtf_address = (unsigned long)out_obj->buffer.pointer;
+ *obj_loc = (unsigned long)out_obj;
+ DEBPRINT("returning gtf_length=%d, gtf_address=0x%lx, obj_loc=0x%lx\n",
+ *gtf_length, *gtf_address, *obj_loc);
+ err = 0;
+out:
+ return err;
+}
+
+/**
+ * taskfile_load_raw - send taskfile registers to drive
+ * @drive: drive to which output is sent
+ * @gtf: raw ATA taskfile register set (0x1f1 - 0x1f7)
+ *
+ * Outputs IDE taskfile to the drive.
+ */
+static int taskfile_load_raw(ide_drive_t *drive,
+ const struct taskfile_array *gtf)
+{
+ ide_task_t args;
+ int err = 0;
+
+ DEBPRINT("(0x1f1-1f7): hex: "
+ "%02x %02x %02x %02x %02x %02x %02x\n",
+ gtf->tfa[0], gtf->tfa[1], gtf->tfa[2],
+ gtf->tfa[3], gtf->tfa[4], gtf->tfa[5], gtf->tfa[6]);
+
+ memset(&args, 0, sizeof(ide_task_t));
+ args.command_type = IDE_DRIVE_TASK_NO_DATA;
+ args.data_phase = TASKFILE_IN;
+ args.handler = &task_no_data_intr;
+
+ /* convert gtf to IDE Taskfile */
+ args.tfRegister[1] = gtf->tfa[0]; /* 0x1f1 */
+ args.tfRegister[2] = gtf->tfa[1]; /* 0x1f2 */
+ args.tfRegister[3] = gtf->tfa[2]; /* 0x1f3 */
+ args.tfRegister[4] = gtf->tfa[3]; /* 0x1f4 */
+ args.tfRegister[5] = gtf->tfa[4]; /* 0x1f5 */
+ args.tfRegister[6] = gtf->tfa[5]; /* 0x1f6 */
+ args.tfRegister[7] = gtf->tfa[6]; /* 0x1f7 */
+
+ if (ide_noacpitfs) {
+ DEBPRINT("_GTF execution disabled\n");
+ return err;
+ }
+
+ err = ide_raw_taskfile(drive, &args, NULL);
+ if (err)
+ printk(KERN_ERR "%s: ide_raw_taskfile failed: %u\n",
+ __FUNCTION__, err);
+
+ return err;
+}
+
+/**
+ * do_drive_set_taskfiles - write the drive taskfile settings from _GTF
+ * @drive: the drive to which the taskfile command should be sent
+ * @gtf_length: total number of bytes of _GTF taskfiles
+ * @gtf_address: location of _GTF taskfile arrays
+ *
+ * Write {gtf_address, length gtf_length} in groups of
+ * REGS_PER_GTF bytes.
+ */
+static int do_drive_set_taskfiles(ide_drive_t *drive,
+ unsigned int gtf_length,
+ unsigned long gtf_address)
+{
+ int rc = -ENODEV, err;
+ int gtf_count = gtf_length / REGS_PER_GTF;
+ int ix;
+ struct taskfile_array *gtf;
+
+ if (ide_noacpi)
+ return 0;
+
+ DEBPRINT("ENTER: %s, hard_port#: %d\n", drive->name, drive->dn);
+
+ if (!drive->present)
+ goto out;
+ if (!gtf_count) /* shouldn't be here */
+ goto out;
+
+ DEBPRINT("total GTF bytes=%u (0x%x), gtf_count=%d, addr=0x%lx\n",
+ gtf_length, gtf_length, gtf_count, gtf_address);
+
+ if (gtf_length % REGS_PER_GTF) {
+ printk(KERN_ERR "%s: unexpected GTF length (%d)\n",
+ __FUNCTION__, gtf_length);
+ goto out;
+ }
+
+ rc = 0;
+ for (ix = 0; ix < gtf_count; ix++) {
+ gtf = (struct taskfile_array *)
+ (gtf_address + ix * REGS_PER_GTF);
+
+ /* send all TaskFile registers (0x1f1-0x1f7) *in*that*order* */
+ err = taskfile_load_raw(drive, gtf);
+ if (err)
+ rc = err;
+ }
+
+out:
+ return rc;
+}
+
+/**
+ * ide_acpi_exec_tfs - get then write drive taskfile settings
+ * @drive: the drive for which the taskfile settings should be
+ * written.
+ *
+ * According to the ACPI spec this should be called after _STM
+ * has been evaluated for the interface. Some ACPI vendors interpret
+ * that as a hard requirement and modify the taskfile according
+ * to the Identify Drive information passed down with _STM.
+ * So one should really make sure to call this only after _STM has
+ * been executed.
+ */
+int ide_acpi_exec_tfs(ide_drive_t *drive)
+{
+ int ret;
+ unsigned int gtf_length;
+ unsigned long gtf_address;
+ unsigned long obj_loc;
+
+ if (ide_noacpi)
+ return 0;
+
+ DEBPRINT("call get_GTF, drive=%s port=%d\n", drive->name, drive->dn);
+
+ ret = do_drive_get_GTF(drive, &gtf_length, &gtf_address, &obj_loc);
+ if (ret < 0) {
+ DEBPRINT("get_GTF error (%d)\n", ret);
+ return ret;
+ }
+
+ DEBPRINT("call set_taskfiles, drive=%s\n", drive->name);
+
+ ret = do_drive_set_taskfiles(drive, gtf_length, gtf_address);
+ kfree((void *)obj_loc);
+ if (ret < 0) {
+ DEBPRINT("set_taskfiles error (%d)\n", ret);
+ }
+
+ DEBPRINT("ret=%d\n", ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ide_acpi_exec_tfs);
+
+/**
+ * ide_acpi_get_timing - get the channel (controller) timings
+ * @hwif: target IDE interface (channel)
+ *
+ * This function executes the _GTM ACPI method for the target channel.
+ *
+ */
+void ide_acpi_get_timing(ide_hwif_t *hwif)
+{
+ acpi_status status;
+ struct acpi_buffer output;
+ union acpi_object *out_obj;
+
+ if (ide_noacpi)
+ return;
+
+ DEBPRINT("ENTER:\n");
+
+ if (!hwif->acpidata) {
+ DEBPRINT("no ACPI data for %s\n", hwif->name);
+ return;
+ }
+
+ /* Setting up output buffer for _GTM */
+ output.length = ACPI_ALLOCATE_BUFFER;
+ output.pointer = NULL; /* ACPI-CA sets this; save/free it later */
+
+ /* _GTM has no input parameters */
+ status = acpi_evaluate_object(hwif->acpidata->obj_handle, "_GTM",
+ NULL, &output);
+
+ DEBPRINT("_GTM status: %d, outptr: 0x%p, outlen: 0x%llx\n",
+ status, output.pointer,
+ (unsigned long long)output.length);
+
+ if (ACPI_FAILURE(status)) {
+ DEBPRINT("Run _GTM error: status = 0x%x\n", status);
+ return;
+ }
+
+ if (!output.length || !output.pointer) {
+ DEBPRINT("Run _GTM: length or ptr is NULL (0x%llx, 0x%p)\n",
+ (unsigned long long)output.length,
+ output.pointer);
+ kfree(output.pointer);
+ return;
+ }
+
+ out_obj = output.pointer;
+ if (out_obj->type != ACPI_TYPE_BUFFER) {
+ kfree(output.pointer);
+ DEBPRINT("Run _GTM: error: "
+ "expected object type of ACPI_TYPE_BUFFER, "
+ "got 0x%x\n", out_obj->type);
+ return;
+ }
+
+ if (!out_obj->buffer.length || !out_obj->buffer.pointer ||
+ out_obj->buffer.length != sizeof(struct GTM_buffer)) {
+ kfree(output.pointer);
+ printk(KERN_ERR
+ "%s: unexpected _GTM length (0x%x)[should be 0x%zx] or "
+ "addr (0x%p)\n",
+ __FUNCTION__, out_obj->buffer.length,
+ sizeof(struct GTM_buffer), out_obj->buffer.pointer);
+ return;
+ }
+
+ memcpy(&hwif->acpidata->gtm, out_obj->buffer.pointer,
+ sizeof(struct GTM_buffer));
+
+ DEBPRINT("_GTM info: ptr: 0x%p, len: 0x%x, exp.len: 0x%Zx\n",
+ out_obj->buffer.pointer, out_obj->buffer.length,
+ sizeof(struct GTM_buffer));
+
+ DEBPRINT("_GTM fields: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
+ hwif->acpidata->gtm.PIO_speed0,
+ hwif->acpidata->gtm.DMA_speed0,
+ hwif->acpidata->gtm.PIO_speed1,
+ hwif->acpidata->gtm.DMA_speed1,
+ hwif->acpidata->gtm.GTM_flags);
+
+ kfree(output.pointer);
+}
+EXPORT_SYMBOL_GPL(ide_acpi_get_timing);
+
+/**
+ * ide_acpi_push_timing - set the channel (controller) timings
+ * @hwif: target IDE interface (channel)
+ *
+ * This function executes the _STM ACPI method for the target channel.
+ *
+ * _STM requires Identify Drive data, which has to passed as an argument.
+ * Unfortunately hd_driveid is a mangled version which we can't readily
+ * use; hence we'll get the information afresh.
+ */
+void ide_acpi_push_timing(ide_hwif_t *hwif)
+{
+ acpi_status status;
+ struct acpi_object_list input;
+ union acpi_object in_params[3];
+ struct ide_acpi_drive_link *master = &hwif->acpidata->master;
+ struct ide_acpi_drive_link *slave = &hwif->acpidata->slave;
+
+ if (ide_noacpi)
+ return;
+
+ DEBPRINT("ENTER:\n");
+
+ if (!hwif->acpidata) {
+ DEBPRINT("no ACPI data for %s\n", hwif->name);
+ return;
+ }
+
+ /* Give the GTM buffer + drive Identify data to the channel via the
+ * _STM method: */
+ /* setup input parameters buffer for _STM */
+ input.count = 3;
+ input.pointer = in_params;
+ in_params[0].type = ACPI_TYPE_BUFFER;
+ in_params[0].buffer.length = sizeof(struct GTM_buffer);
+ in_params[0].buffer.pointer = (u8 *)&hwif->acpidata->gtm;
+ in_params[1].type = ACPI_TYPE_BUFFER;
+ in_params[1].buffer.length = sizeof(struct hd_driveid);
+ in_params[1].buffer.pointer = (u8 *)&master->idbuff;
+ in_params[2].type = ACPI_TYPE_BUFFER;
+ in_params[2].buffer.length = sizeof(struct hd_driveid);
+ in_params[2].buffer.pointer = (u8 *)&slave->idbuff;
+ /* Output buffer: _STM has no output */
+
+ status = acpi_evaluate_object(hwif->acpidata->obj_handle, "_STM",
+ &input, NULL);
+
+ if (ACPI_FAILURE(status)) {
+ DEBPRINT("Run _STM error: status = 0x%x\n", status);
+ }
+ DEBPRINT("_STM status: %d\n", status);
+}
+EXPORT_SYMBOL_GPL(ide_acpi_push_timing);
+
+/**
+ * ide_acpi_init - initialize the ACPI link for an IDE interface
+ * @hwif: target IDE interface (channel)
+ *
+ * The ACPI spec is not quite clear when the drive identify buffer
+ * should be obtained. Calling IDENTIFY DEVICE during shutdown
+ * is not the best of ideas as the drive might already being put to
+ * sleep. And obviously we can't call it during resume.
+ * So we get the information during startup; but this means that
+ * any changes during run-time will be lost after resume.
+ */
+void ide_acpi_init(ide_hwif_t *hwif)
+{
+ int unit;
+ int err;
+ struct ide_acpi_drive_link *master;
+ struct ide_acpi_drive_link *slave;
+
+ hwif->acpidata = kzalloc(sizeof(struct ide_acpi_hwif_link), GFP_KERNEL);
+ if (!hwif->acpidata)
+ return;
+
+ hwif->acpidata->obj_handle = ide_acpi_hwif_get_handle(hwif);
+ if (!hwif->acpidata->obj_handle) {
+ DEBPRINT("no ACPI object for %s found\n", hwif->name);
+ kfree(hwif->acpidata);
+ hwif->acpidata = NULL;
+ return;
+ }
+
+ /*
+ * The ACPI spec mandates that we send information
+ * for both drives, regardless whether they are connected
+ * or not.
+ */
+ hwif->acpidata->master.drive = &hwif->drives[0];
+ hwif->drives[0].acpidata = &hwif->acpidata->master;
+ master = &hwif->acpidata->master;
+
+ hwif->acpidata->slave.drive = &hwif->drives[1];
+ hwif->drives[1].acpidata = &hwif->acpidata->slave;
+ slave = &hwif->acpidata->slave;
+
+
+ /*
+ * Send IDENTIFY for each drive
+ */
+ if (master->drive->present) {
+ err = taskfile_lib_get_identify(master->drive, master->idbuff);
+ if (err) {
+ DEBPRINT("identify device %s failed (%d)\n",
+ master->drive->name, err);
+ }
+ }
+
+ if (slave->drive->present) {
+ err = taskfile_lib_get_identify(slave->drive, slave->idbuff);
+ if (err) {
+ DEBPRINT("identify device %s failed (%d)\n",
+ slave->drive->name, err);
+ }
+ }
+
+ if (ide_noacpionboot) {
+ DEBPRINT("ACPI methods disabled on boot\n");
+ return;
+ }
+
+ /*
+ * ACPI requires us to call _STM on startup
+ */
+ ide_acpi_get_timing(hwif);
+ ide_acpi_push_timing(hwif);
+
+ for (unit = 0; unit < MAX_DRIVES; ++unit) {
+ ide_drive_t *drive = &hwif->drives[unit];
+
+ if (drive->present) {
+ /* Execute ACPI startup code */
+ ide_acpi_exec_tfs(drive);
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(ide_acpi_init);
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 5a5c565a32a..176bbc850d6 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -1384,6 +1384,9 @@ static int hwif_init(ide_hwif_t *hwif)
done:
init_gendisk(hwif);
+
+ ide_acpi_init(hwif);
+
hwif->present = 1; /* success */
return 1;
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index 6c9bd5165bd..c750f6ce770 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -187,6 +187,12 @@ int noautodma = 1;
EXPORT_SYMBOL(noautodma);
+#ifdef CONFIG_BLK_DEV_IDEACPI
+int ide_noacpi = 0;
+int ide_noacpitfs = 1;
+int ide_noacpionboot = 1;
+#endif
+
/*
* This is declared extern in ide.h, for access by other IDE modules:
*/
@@ -1214,10 +1220,15 @@ EXPORT_SYMBOL(system_bus_clock);
static int generic_ide_suspend(struct device *dev, pm_message_t mesg)
{
ide_drive_t *drive = dev->driver_data;
+ ide_hwif_t *hwif = HWIF(drive);
struct request rq;
struct request_pm_state rqpm;
ide_task_t args;
+ /* Call ACPI _GTM only once */
+ if (!(drive->dn % 2))
+ ide_acpi_get_timing(hwif);
+
memset(&rq, 0, sizeof(rq));
memset(&rqpm, 0, sizeof(rqpm));
memset(&args, 0, sizeof(args));
@@ -1235,10 +1246,17 @@ static int generic_ide_suspend(struct device *dev, pm_message_t mesg)
static int generic_ide_resume(struct device *dev)
{
ide_drive_t *drive = dev->driver_data;
+ ide_hwif_t *hwif = HWIF(drive);
struct request rq;
struct request_pm_state rqpm;
ide_task_t args;
+ /* Call ACPI _STM only once */
+ if (!(drive->dn % 2))
+ ide_acpi_push_timing(hwif);
+
+ ide_acpi_exec_tfs(drive);
+
memset(&rq, 0, sizeof(rq));
memset(&rqpm, 0, sizeof(rqpm));
memset(&args, 0, sizeof(args));
@@ -1543,6 +1561,24 @@ static int __init ide_setup(char *s)
}
#endif /* CONFIG_BLK_DEV_IDEPCI */
+#ifdef CONFIG_BLK_DEV_IDEACPI
+ if (!strcmp(s, "ide=noacpi")) {
+ //printk(" : Disable IDE ACPI support.\n");
+ ide_noacpi = 1;
+ return 1;
+ }
+ if (!strcmp(s, "ide=acpigtf")) {
+ //printk(" : Enable IDE ACPI _GTF support.\n");
+ ide_noacpitfs = 0;
+ return 1;
+ }
+ if (!strcmp(s, "ide=acpionboot")) {
+ //printk(" : Call IDE ACPI methods on boot.\n");
+ ide_noacpionboot = 0;
+ return 1;
+ }
+#endif /* CONFIG_BLK_DEV_IDEACPI */
+
/*
* Look for drive options: "hdx="
*/
diff --git a/drivers/ide/pci/Makefile b/drivers/ide/pci/Makefile
index fef08960aa4..6591ff4753c 100644
--- a/drivers/ide/pci/Makefile
+++ b/drivers/ide/pci/Makefile
@@ -9,9 +9,10 @@ obj-$(CONFIG_BLK_DEV_CS5530) += cs5530.o
obj-$(CONFIG_BLK_DEV_CS5535) += cs5535.o
obj-$(CONFIG_BLK_DEV_SC1200) += sc1200.o
obj-$(CONFIG_BLK_DEV_CY82C693) += cy82c693.o
+obj-$(CONFIG_BLK_DEV_DELKIN) += delkin_cb.o
obj-$(CONFIG_BLK_DEV_HPT34X) += hpt34x.o
obj-$(CONFIG_BLK_DEV_HPT366) += hpt366.o
-#obj-$(CONFIG_BLK_DEV_HPT37X) += hpt37x.o
+obj-$(CONFIG_BLK_DEV_IT8213) += it8213.o
obj-$(CONFIG_BLK_DEV_IT821X) += it821x.o
obj-$(CONFIG_BLK_DEV_JMICRON) += jmicron.o
obj-$(CONFIG_BLK_DEV_NS87415) += ns87415.o
@@ -26,6 +27,7 @@ obj-$(CONFIG_BLK_DEV_SIIMAGE) += siimage.o
obj-$(CONFIG_BLK_DEV_SIS5513) += sis5513.o
obj-$(CONFIG_BLK_DEV_SL82C105) += sl82c105.o
obj-$(CONFIG_BLK_DEV_SLC90E66) += slc90e66.o
+obj-$(CONFIG_BLK_DEV_TC86C001) += tc86c001.o
obj-$(CONFIG_BLK_DEV_TRIFLEX) += triflex.o
obj-$(CONFIG_BLK_DEV_TRM290) += trm290.o
obj-$(CONFIG_BLK_DEV_VIA82CXXX) += via82cxxx.o
diff --git a/drivers/ide/pci/delkin_cb.c b/drivers/ide/pci/delkin_cb.c
new file mode 100644
index 00000000000..e2672fc65d3
--- /dev/null
+++ b/drivers/ide/pci/delkin_cb.c
@@ -0,0 +1,140 @@
+/*
+ * linux/drivers/ide/pci/delkin_cb.c
+ *
+ * Created 20 Oct 2004 by Mark Lord
+ *
+ * Basic support for Delkin/ASKA/Workbit Cardbus CompactFlash adapter
+ *
+ * Modeled after the 16-bit PCMCIA driver: ide-cs.c
+ *
+ * This is slightly peculiar, in that it is a PCI driver,
+ * but is NOT an IDE PCI driver -- the IDE layer does not directly
+ * support hot insertion/removal of PCI interfaces, so this driver
+ * is unable to use the IDE PCI interfaces. Instead, it uses the
+ * same interfaces as the ide-cs (PCMCIA) driver uses.
+ * On the plus side, the driver is also smaller/simpler this way.
+ *
+ * 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/autoconf.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+/*
+ * No chip documentation has yet been found,
+ * so these configuration values were pulled from
+ * a running Win98 system using "debug".
+ * This gives around 3MByte/second read performance,
+ * which is about 2/3 of what the chip is capable of.
+ *
+ * There is also a 4KByte mmio region on the card,
+ * but its purpose has yet to be reverse-engineered.
+ */
+static const u8 setup[] = {
+ 0x00, 0x05, 0xbe, 0x01, 0x20, 0x8f, 0x00, 0x00,
+ 0xa4, 0x1f, 0xb3, 0x1b, 0x00, 0x00, 0x00, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xa4, 0x83, 0x02, 0x13,
+};
+
+static int __devinit
+delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id)
+{
+ unsigned long base;
+ hw_regs_t hw;
+ ide_hwif_t *hwif = NULL;
+ ide_drive_t *drive;
+ int i, rc;
+
+ rc = pci_enable_device(dev);
+ if (rc) {
+ printk(KERN_ERR "delkin_cb: pci_enable_device failed (%d)\n", rc);
+ return rc;
+ }
+ rc = pci_request_regions(dev, "delkin_cb");
+ if (rc) {
+ printk(KERN_ERR "delkin_cb: pci_request_regions failed (%d)\n", rc);
+ pci_disable_device(dev);
+ return rc;
+ }
+ base = pci_resource_start(dev, 0);
+ outb(0x02, base + 0x1e); /* set nIEN to block interrupts */
+ inb(base + 0x17); /* read status to clear interrupts */
+ for (i = 0; i < sizeof(setup); ++i) {
+ if (setup[i])
+ outb(setup[i], base + i);
+ }
+ pci_release_regions(dev); /* IDE layer handles regions itself */
+
+ memset(&hw, 0, sizeof(hw));
+ ide_std_init_ports(&hw, base + 0x10, base + 0x1e);
+ hw.irq = dev->irq;
+ hw.chipset = ide_pci; /* this enables IRQ sharing */
+
+ rc = ide_register_hw_with_fixup(&hw, &hwif, ide_undecoded_slave);
+ if (rc < 0) {
+ printk(KERN_ERR "delkin_cb: ide_register_hw failed (%d)\n", rc);
+ pci_disable_device(dev);
+ return -ENODEV;
+ }
+ pci_set_drvdata(dev, hwif);
+ hwif->pci_dev = dev;
+ drive = &hwif->drives[0];
+ if (drive->present) {
+ drive->io_32bit = 1;
+ drive->unmask = 1;
+ }
+ return 0;
+}
+
+static void
+delkin_cb_remove (struct pci_dev *dev)
+{
+ ide_hwif_t *hwif = pci_get_drvdata(dev);
+
+ if (hwif)
+ ide_unregister(hwif->index);
+ pci_disable_device(dev);
+}
+
+static struct pci_device_id delkin_cb_pci_tbl[] __devinitdata = {
+ { 0x1145, 0xf021, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, delkin_cb_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "Delkin-ASKA-Workbit Cardbus IDE",
+ .id_table = delkin_cb_pci_tbl,
+ .probe = delkin_cb_probe,
+ .remove = delkin_cb_remove,
+};
+
+static int
+delkin_cb_init (void)
+{
+ return pci_module_init(&driver);
+}
+
+static void
+delkin_cb_exit (void)
+{
+ pci_unregister_driver(&driver);
+}
+
+module_init(delkin_cb_init);
+module_exit(delkin_cb_exit);
+
+MODULE_AUTHOR("Mark Lord");
+MODULE_DESCRIPTION("Basic support for Delkin/ASKA/Workbit Cardbus IDE");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c
index b486442dd5d..05be8fadda7 100644
--- a/drivers/ide/pci/hpt366.c
+++ b/drivers/ide/pci/hpt366.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/ide/pci/hpt366.c Version 0.36 April 25, 2003
+ * linux/drivers/ide/pci/hpt366.c Version 1.01 Dec 23, 2006
*
* Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org>
* Portions Copyright (C) 2001 Sun Microsystems, Inc.
@@ -60,13 +60,10 @@
* channel caused the cached register value to get out of sync with the
* actual one, the channels weren't serialized, the turnaround shouldn't
* be done on 66 MHz PCI bus
- * - avoid calibrating PLL twice as the second time results in a wrong PCI
- * frequency and thus in the wrong timings for the secondary channel
- * - disable UltraATA/133 for HPT372 by default (50 MHz DPLL clock do not
- * allow for this speed anyway)
- * - add support for HPT302N and HPT371N clocking (the same as for HPT372N)
- * - HPT371/N are single channel chips, so avoid touching the primary channel
- * which exists only virtually (there's no pins for it)
+ * - disable UltraATA/100 for HPT370 by default as the 33 MHz clock being used
+ * does not allow for this speed anyway
+ * - avoid touching disabled channels (e.g. HPT371/N are single channel chips,
+ * their primary channel is kind of virtual, it isn't tied to any pins)
* - fix/remove bad/unused timing tables and use one set of tables for the whole
* HPT37x chip family; save space by introducing the separate transfer mode
* table in which the mode lookup is done
@@ -76,11 +73,47 @@
* and for HPT36x the obsolete HDIO_TRISTATE_HWIF handler was called instead
* - pass to init_chipset() handlers a copy of the IDE PCI device structure as
* they tamper with its fields
- * <source@mvista.com>
- *
+ * - pass to the init_setup handlers a copy of the ide_pci_device_t structure
+ * since they may tamper with its fields
+ * - prefix the driver startup messages with the real chip name
+ * - claim the extra 240 bytes of I/O space for all chips
+ * - optimize the rate masking/filtering and the drive list lookup code
+ * - use pci_get_slot() to get to the function 1 of HPT36x/374
+ * - cache offset of the channel's misc. control registers (MCRs) being used
+ * throughout the driver
+ * - only touch the relevant MCR when detecting the cable type on HPT374's
+ * function 1
+ * - rename all the register related variables consistently
+ * - move all the interrupt twiddling code from the speedproc handlers into
+ * init_hwif_hpt366(), also grouping all the DMA related code together there
+ * - merge two HPT37x speedproc handlers, fix the PIO timing register mask and
+ * separate the UltraDMA and MWDMA masks there to avoid changing PIO timings
+ * when setting an UltraDMA mode
+ * - fix hpt3xx_tune_drive() to set the PIO mode requested, not always select
+ * the best possible one
+ * - clean up DMA timeout handling for HPT370
+ * - switch to using the enumeration type to differ between the numerous chip
+ * variants, matching PCI device/revision ID with the chip type early, at the
+ * init_setup stage
+ * - extend the hpt_info structure to hold the DPLL and PCI clock frequencies,
+ * stop duplicating it for each channel by storing the pointer in the pci_dev
+ * structure: first, at the init_setup stage, point it to a static "template"
+ * with only the chip type and its specific base DPLL frequency, the highest
+ * supported DMA mode, and the chip settings table pointer filled, then, at
+ * the init_chipset stage, allocate per-chip instance and fill it with the
+ * rest of the necessary information
+ * - get rid of the constant thresholds in the HPT37x PCI clock detection code,
+ * switch to calculating PCI clock frequency based on the chip's base DPLL
+ * frequency
+ * - switch to using the DPLL clock and enable UltraATA/133 mode by default on
+ * anything newer than HPT370/A
+ * - fold PCI clock detection and DPLL setup code into init_chipset_hpt366(),
+ * also fixing the interchanged 25/40 MHz PCI clock cases for HPT36x chips;
+ * unify HPT36x/37x timing setup code and the speedproc handlers by joining
+ * the register setting lists into the table indexed by the clock selected
+ * Sergei Shtylyov, <sshtylyov@ru.mvista.com> or <source@mvista.com>
*/
-
#include <linux/types.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -332,93 +365,159 @@ static u32 sixty_six_base_hpt37x[] = {
};
#define HPT366_DEBUG_DRIVE_INFO 0
-#define HPT374_ALLOW_ATA133_6 0
-#define HPT371_ALLOW_ATA133_6 0
-#define HPT302_ALLOW_ATA133_6 0
-#define HPT372_ALLOW_ATA133_6 0
-#define HPT370_ALLOW_ATA100_5 1
+#define HPT374_ALLOW_ATA133_6 1
+#define HPT371_ALLOW_ATA133_6 1
+#define HPT302_ALLOW_ATA133_6 1
+#define HPT372_ALLOW_ATA133_6 1
+#define HPT370_ALLOW_ATA100_5 0
#define HPT366_ALLOW_ATA66_4 1
#define HPT366_ALLOW_ATA66_3 1
#define HPT366_MAX_DEVS 8
-#define F_LOW_PCI_33 0x23
-#define F_LOW_PCI_40 0x29
-#define F_LOW_PCI_50 0x2d
-#define F_LOW_PCI_66 0x42
+/* Supported ATA clock frequencies */
+enum ata_clock {
+ ATA_CLOCK_25MHZ,
+ ATA_CLOCK_33MHZ,
+ ATA_CLOCK_40MHZ,
+ ATA_CLOCK_50MHZ,
+ ATA_CLOCK_66MHZ,
+ NUM_ATA_CLOCKS
+};
/*
- * Hold all the highpoint quirks and revision information in one
- * place.
+ * Hold all the HighPoint chip information in one place.
*/
-struct hpt_info
-{
+struct hpt_info {
+ u8 chip_type; /* Chip type */
u8 max_mode; /* Speeds allowed */
- int revision; /* Chipset revision */
- int flags; /* Chipset properties */
-#define PLL_MODE 1
-#define IS_3xxN 2
-#define PCI_66MHZ 4
- /* Speed table */
- u32 *speed;
+ u8 dpll_clk; /* DPLL clock in MHz */
+ u8 pci_clk; /* PCI clock in MHz */
+ u32 **settings; /* Chipset settings table */
};
-/*
- * This wants fixing so that we do everything not by classrev
- * (which breaks on the newest chips) but by creating an
- * enumeration of chip variants and using that
- */
+/* Supported HighPoint chips */
+enum {
+ HPT36x,
+ HPT370,
+ HPT370A,
+ HPT374,
+ HPT372,
+ HPT372A,
+ HPT302,
+ HPT371,
+ HPT372N,
+ HPT302N,
+ HPT371N
+};
+
+static u32 *hpt36x_settings[NUM_ATA_CLOCKS] = {
+ twenty_five_base_hpt36x,
+ thirty_three_base_hpt36x,
+ forty_base_hpt36x,
+ NULL,
+ NULL
+};
+
+static u32 *hpt37x_settings[NUM_ATA_CLOCKS] = {
+ NULL,
+ thirty_three_base_hpt37x,
+ NULL,
+ fifty_base_hpt37x,
+ sixty_six_base_hpt37x
+};
+
+static struct hpt_info hpt36x __devinitdata = {
+ .chip_type = HPT36x,
+ .max_mode = (HPT366_ALLOW_ATA66_4 || HPT366_ALLOW_ATA66_3) ? 2 : 1,
+ .dpll_clk = 0, /* no DPLL */
+ .settings = hpt36x_settings
+};
+
+static struct hpt_info hpt370 __devinitdata = {
+ .chip_type = HPT370,
+ .max_mode = HPT370_ALLOW_ATA100_5 ? 3 : 2,
+ .dpll_clk = 48,
+ .settings = hpt37x_settings
+};
+
+static struct hpt_info hpt370a __devinitdata = {
+ .chip_type = HPT370A,
+ .max_mode = HPT370_ALLOW_ATA100_5 ? 3 : 2,
+ .dpll_clk = 48,
+ .settings = hpt37x_settings
+};
+
+static struct hpt_info hpt374 __devinitdata = {
+ .chip_type = HPT374,
+ .max_mode = HPT374_ALLOW_ATA133_6 ? 4 : 3,
+ .dpll_clk = 48,
+ .settings = hpt37x_settings
+};
+
+static struct hpt_info hpt372 __devinitdata = {
+ .chip_type = HPT372,
+ .max_mode = HPT372_ALLOW_ATA133_6 ? 4 : 3,
+ .dpll_clk = 55,
+ .settings = hpt37x_settings
+};
+
+static struct hpt_info hpt372a __devinitdata = {
+ .chip_type = HPT372A,
+ .max_mode = HPT372_ALLOW_ATA133_6 ? 4 : 3,
+ .dpll_clk = 66,
+ .settings = hpt37x_settings
+};
+
+static struct hpt_info hpt302 __devinitdata = {
+ .chip_type = HPT302,
+ .max_mode = HPT302_ALLOW_ATA133_6 ? 4 : 3,
+ .dpll_clk = 66,
+ .settings = hpt37x_settings
+};
+
+static struct hpt_info hpt371 __devinitdata = {
+ .chip_type = HPT371,
+ .max_mode = HPT371_ALLOW_ATA133_6 ? 4 : 3,
+ .dpll_clk = 66,
+ .settings = hpt37x_settings
+};
+
+static struct hpt_info hpt372n __devinitdata = {
+ .chip_type = HPT372N,
+ .max_mode = HPT372_ALLOW_ATA133_6 ? 4 : 3,
+ .dpll_clk = 77,
+ .settings = hpt37x_settings
+};
+
+static struct hpt_info hpt302n __devinitdata = {
+ .chip_type = HPT302N,
+ .max_mode = HPT302_ALLOW_ATA133_6 ? 4 : 3,
+ .dpll_clk = 77,
+};
-static __devinit u32 hpt_revision (struct pci_dev *dev)
+static struct hpt_info hpt371n __devinitdata = {
+ .chip_type = HPT371N,
+ .max_mode = HPT371_ALLOW_ATA133_6 ? 4 : 3,
+ .dpll_clk = 77,
+ .settings = hpt37x_settings
+};
+
+static int check_in_drive_list(ide_drive_t *drive, const char **list)
{
- u32 class_rev;
- pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
- class_rev &= 0xff;
-
- switch(dev->device) {
- /* Remap new 372N onto 372 */
- case PCI_DEVICE_ID_TTI_HPT372N:
- class_rev = PCI_DEVICE_ID_TTI_HPT372; break;
- case PCI_DEVICE_ID_TTI_HPT374:
- class_rev = PCI_DEVICE_ID_TTI_HPT374; break;
- case PCI_DEVICE_ID_TTI_HPT371:
- class_rev = PCI_DEVICE_ID_TTI_HPT371; break;
- case PCI_DEVICE_ID_TTI_HPT302:
- class_rev = PCI_DEVICE_ID_TTI_HPT302; break;
- case PCI_DEVICE_ID_TTI_HPT372:
- class_rev = PCI_DEVICE_ID_TTI_HPT372; break;
- default:
- break;
- }
- return class_rev;
-}
+ struct hd_driveid *id = drive->id;
-static int check_in_drive_lists(ide_drive_t *drive, const char **list);
+ while (*list)
+ if (!strcmp(*list++,id->model))
+ return 1;
+ return 0;
+}
-static u8 hpt3xx_ratemask (ide_drive_t *drive)
+static u8 hpt3xx_ratemask(ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
- struct hpt_info *info = ide_get_hwifdata(hwif);
- u8 mode = 0;
-
- /* FIXME: TODO - move this to set info->mode once at boot */
-
- if (info->revision >= 8) { /* HPT374 */
- mode = (HPT374_ALLOW_ATA133_6) ? 4 : 3;
- } else if (info->revision >= 7) { /* HPT371 */
- mode = (HPT371_ALLOW_ATA133_6) ? 4 : 3;
- } else if (info->revision >= 6) { /* HPT302 */
- mode = (HPT302_ALLOW_ATA133_6) ? 4 : 3;
- } else if (info->revision >= 5) { /* HPT372 */
- mode = (HPT372_ALLOW_ATA133_6) ? 4 : 3;
- } else if (info->revision >= 4) { /* HPT370A */
- mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2;
- } else if (info->revision >= 3) { /* HPT370 */
- mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2;
- mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : mode;
- } else { /* HPT366 and HPT368 */
- mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : 2;
- }
+ struct hpt_info *info = pci_get_drvdata(HWIF(drive)->pci_dev);
+ u8 mode = info->max_mode;
+
if (!eighty_ninty_three(drive) && mode)
mode = min(mode, (u8)1);
return mode;
@@ -429,75 +528,61 @@ static u8 hpt3xx_ratemask (ide_drive_t *drive)
* either PIO or UDMA modes 0,4,5
*/
-static u8 hpt3xx_ratefilter (ide_drive_t *drive, u8 speed)
+static u8 hpt3xx_ratefilter(ide_drive_t *drive, u8 speed)
{
- ide_hwif_t *hwif = drive->hwif;
- struct hpt_info *info = ide_get_hwifdata(hwif);
+ struct hpt_info *info = pci_get_drvdata(HWIF(drive)->pci_dev);
+ u8 chip_type = info->chip_type;
u8 mode = hpt3xx_ratemask(drive);
if (drive->media != ide_disk)
return min(speed, (u8)XFER_PIO_4);
- switch(mode) {
+ switch (mode) {
case 0x04:
- speed = min(speed, (u8)XFER_UDMA_6);
+ speed = min_t(u8, speed, XFER_UDMA_6);
break;
case 0x03:
- speed = min(speed, (u8)XFER_UDMA_5);
- if (info->revision >= 5)
+ speed = min_t(u8, speed, XFER_UDMA_5);
+ if (chip_type >= HPT374)
break;
- if (check_in_drive_lists(drive, bad_ata100_5))
- speed = min(speed, (u8)XFER_UDMA_4);
- break;
+ if (!check_in_drive_list(drive, bad_ata100_5))
+ goto check_bad_ata33;
+ /* fall thru */
case 0x02:
- speed = min(speed, (u8)XFER_UDMA_4);
- /*
- * CHECK ME, Does this need to be set to 5 ??
- */
- if (info->revision >= 3)
- break;
- if ((check_in_drive_lists(drive, bad_ata66_4)) ||
- (!(HPT366_ALLOW_ATA66_4)))
- speed = min(speed, (u8)XFER_UDMA_3);
- if ((check_in_drive_lists(drive, bad_ata66_3)) ||
- (!(HPT366_ALLOW_ATA66_3)))
- speed = min(speed, (u8)XFER_UDMA_2);
- break;
+ speed = min_t(u8, speed, XFER_UDMA_4);
+
+ /*
+ * CHECK ME, Does this need to be changed to HPT374 ??
+ */
+ if (chip_type >= HPT370)
+ goto check_bad_ata33;
+ if (HPT366_ALLOW_ATA66_4 &&
+ !check_in_drive_list(drive, bad_ata66_4))
+ goto check_bad_ata33;
+
+ speed = min_t(u8, speed, XFER_UDMA_3);
+ if (HPT366_ALLOW_ATA66_3 &&
+ !check_in_drive_list(drive, bad_ata66_3))
+ goto check_bad_ata33;
+ /* fall thru */
case 0x01:
- speed = min(speed, (u8)XFER_UDMA_2);
- /*
- * CHECK ME, Does this need to be set to 5 ??
- */
- if (info->revision >= 3)
+ speed = min_t(u8, speed, XFER_UDMA_2);
+
+ check_bad_ata33:
+ if (chip_type >= HPT370A)
break;
- if (check_in_drive_lists(drive, bad_ata33))
- speed = min(speed, (u8)XFER_MW_DMA_2);
- break;
+ if (!check_in_drive_list(drive, bad_ata33))
+ break;
+ /* fall thru */
case 0x00:
default:
- speed = min(speed, (u8)XFER_MW_DMA_2);
+ speed = min_t(u8, speed, XFER_MW_DMA_2);
break;
}
return speed;
}
-static int check_in_drive_lists (ide_drive_t *drive, const char **list)
-{
- struct hd_driveid *id = drive->id;
-
- if (quirk_drives == list) {
- while (*list)
- if (strstr(id->model, *list++))
- return 1;
- } else {
- while (*list)
- if (!strcmp(*list++,id->model))
- return 1;
- }
- return 0;
-}
-
-static u32 pci_bus_clock_list(u8 speed, u32 *chipset_table)
+static u32 get_speed_setting(u8 speed, struct hpt_info *info)
{
int i;
@@ -510,228 +595,161 @@ static u32 pci_bus_clock_list(u8 speed, u32 *chipset_table)
for (i = 0; i < ARRAY_SIZE(xfer_speeds) - 1; i++)
if (xfer_speeds[i] == speed)
break;
- return chipset_table[i];
+ /*
+ * NOTE: info->settings only points to the pointer
+ * to the list of the actual register values
+ */
+ return (*info->settings)[i];
}
static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
{
- ide_hwif_t *hwif = drive->hwif;
- struct pci_dev *dev = hwif->pci_dev;
- struct hpt_info *info = ide_get_hwifdata(hwif);
- u8 speed = hpt3xx_ratefilter(drive, xferspeed);
- u8 regtime = (drive->select.b.unit & 0x01) ? 0x44 : 0x40;
- u8 regfast = (hwif->channel) ? 0x55 : 0x51;
- u8 drive_fast = 0;
- u32 reg1 = 0, reg2 = 0;
-
- /*
- * Disable the "fast interrupt" prediction.
- */
- pci_read_config_byte(dev, regfast, &drive_fast);
- if (drive_fast & 0x80)
- pci_write_config_byte(dev, regfast, drive_fast & ~0x80);
-
- reg2 = pci_bus_clock_list(speed, info->speed);
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ struct hpt_info *info = pci_get_drvdata(dev);
+ u8 speed = hpt3xx_ratefilter(drive, xferspeed);
+ u8 itr_addr = drive->dn ? 0x44 : 0x40;
+ u32 itr_mask = speed < XFER_MW_DMA_0 ? 0x30070000 :
+ (speed < XFER_UDMA_0 ? 0xc0070000 : 0xc03800ff);
+ u32 new_itr = get_speed_setting(speed, info);
+ u32 old_itr = 0;
/*
- * Disable on-chip PIO FIFO/buffer
- * (to avoid problems handling I/O errors later)
+ * Disable on-chip PIO FIFO/buffer (and PIO MST mode as well)
+ * to avoid problems handling I/O errors later
*/
- pci_read_config_dword(dev, regtime, &reg1);
- if (speed >= XFER_MW_DMA_0) {
- reg2 = (reg2 & ~0xc0000000) | (reg1 & 0xc0000000);
- } else {
- reg2 = (reg2 & ~0x30070000) | (reg1 & 0x30070000);
- }
- reg2 &= ~0x80000000;
+ pci_read_config_dword(dev, itr_addr, &old_itr);
+ new_itr = (new_itr & ~itr_mask) | (old_itr & itr_mask);
+ new_itr &= ~0xc0000000;
- pci_write_config_dword(dev, regtime, reg2);
+ pci_write_config_dword(dev, itr_addr, new_itr);
return ide_config_drive_speed(drive, speed);
}
-static int hpt370_tune_chipset(ide_drive_t *drive, u8 xferspeed)
+static int hpt37x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
{
- ide_hwif_t *hwif = drive->hwif;
- struct pci_dev *dev = hwif->pci_dev;
- struct hpt_info *info = ide_get_hwifdata(hwif);
- u8 speed = hpt3xx_ratefilter(drive, xferspeed);
- u8 regfast = (drive->hwif->channel) ? 0x55 : 0x51;
- u8 drive_pci = 0x40 + (drive->dn * 4);
- u8 new_fast = 0, drive_fast = 0;
- u32 list_conf = 0, drive_conf = 0;
- u32 conf_mask = (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
-
- /*
- * Disable the "fast interrupt" prediction.
- * don't holdoff on interrupts. (== 0x01 despite what the docs say)
- */
- pci_read_config_byte(dev, regfast, &drive_fast);
- new_fast = drive_fast;
- if (new_fast & 0x02)
- new_fast &= ~0x02;
-
-#ifdef HPT_DELAY_INTERRUPT
- if (new_fast & 0x01)
- new_fast &= ~0x01;
-#else
- if ((new_fast & 0x01) == 0)
- new_fast |= 0x01;
-#endif
- if (new_fast != drive_fast)
- pci_write_config_byte(dev, regfast, new_fast);
-
- list_conf = pci_bus_clock_list(speed, info->speed);
-
- pci_read_config_dword(dev, drive_pci, &drive_conf);
- list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ struct hpt_info *info = pci_get_drvdata(dev);
+ u8 speed = hpt3xx_ratefilter(drive, xferspeed);
+ u8 itr_addr = 0x40 + (drive->dn * 4);
+ u32 itr_mask = speed < XFER_MW_DMA_0 ? 0x303c0000 :
+ (speed < XFER_UDMA_0 ? 0xc03c0000 : 0xc1c001ff);
+ u32 new_itr = get_speed_setting(speed, info);
+ u32 old_itr = 0;
+
+ pci_read_config_dword(dev, itr_addr, &old_itr);
+ new_itr = (new_itr & ~itr_mask) | (old_itr & itr_mask);
if (speed < XFER_MW_DMA_0)
- list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
- pci_write_config_dword(dev, drive_pci, list_conf);
+ new_itr &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
+ pci_write_config_dword(dev, itr_addr, new_itr);
return ide_config_drive_speed(drive, speed);
}
-static int hpt372_tune_chipset(ide_drive_t *drive, u8 xferspeed)
+static int hpt3xx_tune_chipset(ide_drive_t *drive, u8 speed)
{
- ide_hwif_t *hwif = drive->hwif;
- struct pci_dev *dev = hwif->pci_dev;
- struct hpt_info *info = ide_get_hwifdata(hwif);
- u8 speed = hpt3xx_ratefilter(drive, xferspeed);
- u8 regfast = (drive->hwif->channel) ? 0x55 : 0x51;
- u8 drive_fast = 0, drive_pci = 0x40 + (drive->dn * 4);
- u32 list_conf = 0, drive_conf = 0;
- u32 conf_mask = (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
-
- /*
- * Disable the "fast interrupt" prediction.
- * don't holdoff on interrupts. (== 0x01 despite what the docs say)
- */
- pci_read_config_byte(dev, regfast, &drive_fast);
- drive_fast &= ~0x07;
- pci_write_config_byte(dev, regfast, drive_fast);
-
- list_conf = pci_bus_clock_list(speed, info->speed);
- pci_read_config_dword(dev, drive_pci, &drive_conf);
- list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
- if (speed < XFER_MW_DMA_0)
- list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
- pci_write_config_dword(dev, drive_pci, list_conf);
-
- return ide_config_drive_speed(drive, speed);
-}
+ ide_hwif_t *hwif = HWIF(drive);
+ struct hpt_info *info = pci_get_drvdata(hwif->pci_dev);
-static int hpt3xx_tune_chipset (ide_drive_t *drive, u8 speed)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct hpt_info *info = ide_get_hwifdata(hwif);
-
- if (info->revision >= 8)
- return hpt372_tune_chipset(drive, speed); /* not a typo */
- else if (info->revision >= 5)
- return hpt372_tune_chipset(drive, speed);
- else if (info->revision >= 3)
- return hpt370_tune_chipset(drive, speed);
+ if (info->chip_type >= HPT370)
+ return hpt37x_tune_chipset(drive, speed);
else /* hpt368: hpt_minimum_revision(dev, 2) */
return hpt36x_tune_chipset(drive, speed);
}
-static void hpt3xx_tune_drive (ide_drive_t *drive, u8 pio)
+static void hpt3xx_tune_drive(ide_drive_t *drive, u8 pio)
{
- pio = ide_get_best_pio_mode(drive, 255, pio, NULL);
- (void) hpt3xx_tune_chipset(drive, (XFER_PIO_0 + pio));
+ pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+ (void) hpt3xx_tune_chipset (drive, XFER_PIO_0 + pio);
}
/*
* This allows the configuration of ide_pci chipset registers
* for cards that learn about the drive's UDMA, DMA, PIO capabilities
- * after the drive is reported by the OS. Initially for designed for
+ * after the drive is reported by the OS. Initially designed for
* HPT366 UDMA chipset by HighPoint|Triones Technologies, Inc.
*
- * check_in_drive_lists(drive, bad_ata66_4)
- * check_in_drive_lists(drive, bad_ata66_3)
- * check_in_drive_lists(drive, bad_ata33)
- *
*/
-static int config_chipset_for_dma (ide_drive_t *drive)
+static int config_chipset_for_dma(ide_drive_t *drive)
{
u8 speed = ide_dma_speed(drive, hpt3xx_ratemask(drive));
- ide_hwif_t *hwif = drive->hwif;
- struct hpt_info *info = ide_get_hwifdata(hwif);
if (!speed)
return 0;
- /* If we don't have any timings we can't do a lot */
- if (info->speed == NULL)
- return 0;
-
(void) hpt3xx_tune_chipset(drive, speed);
return ide_dma_enable(drive);
}
-static int hpt3xx_quirkproc (ide_drive_t *drive)
+static int hpt3xx_quirkproc(ide_drive_t *drive)
{
- return ((int) check_in_drive_lists(drive, quirk_drives));
+ struct hd_driveid *id = drive->id;
+ const char **list = quirk_drives;
+
+ while (*list)
+ if (strstr(id->model, *list++))
+ return 1;
+ return 0;
}
-static void hpt3xx_intrproc (ide_drive_t *drive)
+static void hpt3xx_intrproc(ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
+ ide_hwif_t *hwif = HWIF(drive);
if (drive->quirk_list)
return;
/* drives in the quirk_list may not like intr setups/cleanups */
- hwif->OUTB(drive->ctl|2, IDE_CONTROL_REG);
+ hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG);
}
-static void hpt3xx_maskproc (ide_drive_t *drive, int mask)
+static void hpt3xx_maskproc(ide_drive_t *drive, int mask)
{
- ide_hwif_t *hwif = drive->hwif;
- struct hpt_info *info = ide_get_hwifdata(hwif);
- struct pci_dev *dev = hwif->pci_dev;
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ struct hpt_info *info = pci_get_drvdata(dev);
if (drive->quirk_list) {
- if (info->revision >= 3) {
- u8 reg5a = 0;
- pci_read_config_byte(dev, 0x5a, &reg5a);
- if (((reg5a & 0x10) >> 4) != mask)
- pci_write_config_byte(dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10));
+ if (info->chip_type >= HPT370) {
+ u8 scr1 = 0;
+
+ pci_read_config_byte(dev, 0x5a, &scr1);
+ if (((scr1 & 0x10) >> 4) != mask) {
+ if (mask)
+ scr1 |= 0x10;
+ else
+ scr1 &= ~0x10;
+ pci_write_config_byte(dev, 0x5a, scr1);
+ }
} else {
- if (mask) {
+ if (mask)
disable_irq(hwif->irq);
- } else {
- enable_irq(hwif->irq);
- }
+ else
+ enable_irq (hwif->irq);
}
- } else {
- if (IDE_CONTROL_REG)
- hwif->OUTB(mask ? (drive->ctl | 2) :
- (drive->ctl & ~2),
- IDE_CONTROL_REG);
- }
+ } else
+ hwif->OUTB(mask ? (drive->ctl | 2) : (drive->ctl & ~2),
+ IDE_CONTROL_REG);
}
-static int hpt366_config_drive_xfer_rate (ide_drive_t *drive)
+static int hpt366_config_drive_xfer_rate(ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
+ ide_hwif_t *hwif = HWIF(drive);
struct hd_driveid *id = drive->id;
drive->init_speed = 0;
if ((id->capability & 1) && drive->autodma) {
-
- if (ide_use_dma(drive)) {
- if (config_chipset_for_dma(drive))
- return hwif->ide_dma_on(drive);
- }
+ if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+ return hwif->ide_dma_on(drive);
goto fast_ata_pio;
} else if ((id->capability & 8) || (id->field_valid & 2)) {
fast_ata_pio:
- hpt3xx_tune_drive(drive, 5);
+ hpt3xx_tune_drive(drive, 255);
return hwif->ide_dma_off_quietly(drive);
}
/* IORDY not supported */
@@ -739,31 +757,48 @@ fast_ata_pio:
}
/*
- * This is specific to the HPT366 UDMA bios chipset
+ * This is specific to the HPT366 UDMA chipset
* by HighPoint|Triones Technologies, Inc.
*/
-static int hpt366_ide_dma_lostirq (ide_drive_t *drive)
+static int hpt366_ide_dma_lostirq(ide_drive_t *drive)
{
- struct pci_dev *dev = HWIF(drive)->pci_dev;
- u8 reg50h = 0, reg52h = 0, reg5ah = 0;
-
- pci_read_config_byte(dev, 0x50, &reg50h);
- pci_read_config_byte(dev, 0x52, &reg52h);
- pci_read_config_byte(dev, 0x5a, &reg5ah);
- printk("%s: (%s) reg50h=0x%02x, reg52h=0x%02x, reg5ah=0x%02x\n",
- drive->name, __FUNCTION__, reg50h, reg52h, reg5ah);
- if (reg5ah & 0x10)
- pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10);
+ struct pci_dev *dev = HWIF(drive)->pci_dev;
+ u8 mcr1 = 0, mcr3 = 0, scr1 = 0;
+
+ pci_read_config_byte(dev, 0x50, &mcr1);
+ pci_read_config_byte(dev, 0x52, &mcr3);
+ pci_read_config_byte(dev, 0x5a, &scr1);
+ printk("%s: (%s) mcr1=0x%02x, mcr3=0x%02x, scr1=0x%02x\n",
+ drive->name, __FUNCTION__, mcr1, mcr3, scr1);
+ if (scr1 & 0x10)
+ pci_write_config_byte(dev, 0x5a, scr1 & ~0x10);
return __ide_dma_lostirq(drive);
}
-static void hpt370_clear_engine (ide_drive_t *drive)
+static void hpt370_clear_engine(ide_drive_t *drive)
{
- u8 regstate = HWIF(drive)->channel ? 0x54 : 0x50;
- pci_write_config_byte(HWIF(drive)->pci_dev, regstate, 0x37);
+ ide_hwif_t *hwif = HWIF(drive);
+
+ pci_write_config_byte(hwif->pci_dev, hwif->select_data, 0x37);
udelay(10);
}
+static void hpt370_irq_timeout(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ u16 bfifo = 0;
+ u8 dma_cmd;
+
+ pci_read_config_word(hwif->pci_dev, hwif->select_data + 2, &bfifo);
+ printk(KERN_DEBUG "%s: %d bytes in FIFO\n", drive->name, bfifo & 0x1ff);
+
+ /* get DMA command mode */
+ dma_cmd = hwif->INB(hwif->dma_command);
+ /* stop DMA */
+ hwif->OUTB(dma_cmd & ~0x1, hwif->dma_command);
+ hpt370_clear_engine(drive);
+}
+
static void hpt370_ide_dma_start(ide_drive_t *drive)
{
#ifdef HPT_RESET_STATE_ENGINE
@@ -772,64 +807,35 @@ static void hpt370_ide_dma_start(ide_drive_t *drive)
ide_dma_start(drive);
}
-static int hpt370_ide_dma_end (ide_drive_t *drive)
+static int hpt370_ide_dma_end(ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
- u8 dma_stat = hwif->INB(hwif->dma_status);
+ u8 dma_stat = hwif->INB(hwif->dma_status);
if (dma_stat & 0x01) {
/* wait a little */
udelay(20);
dma_stat = hwif->INB(hwif->dma_status);
+ if (dma_stat & 0x01)
+ hpt370_irq_timeout(drive);
}
- if ((dma_stat & 0x01) != 0)
- /* fallthrough */
- (void) HWIF(drive)->ide_dma_timeout(drive);
-
return __ide_dma_end(drive);
}
-static void hpt370_lostirq_timeout (ide_drive_t *drive)
+static int hpt370_ide_dma_timeout(ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
- u8 bfifo = 0, reginfo = hwif->channel ? 0x56 : 0x52;
- u8 dma_stat = 0, dma_cmd = 0;
-
- pci_read_config_byte(HWIF(drive)->pci_dev, reginfo, &bfifo);
- printk(KERN_DEBUG "%s: %d bytes in FIFO\n", drive->name, bfifo);
- hpt370_clear_engine(drive);
- /* get dma command mode */
- dma_cmd = hwif->INB(hwif->dma_command);
- /* stop dma */
- hwif->OUTB(dma_cmd & ~0x1, hwif->dma_command);
- dma_stat = hwif->INB(hwif->dma_status);
- /* clear errors */
- hwif->OUTB(dma_stat | 0x6, hwif->dma_status);
-}
-
-static int hpt370_ide_dma_timeout (ide_drive_t *drive)
-{
- hpt370_lostirq_timeout(drive);
- hpt370_clear_engine(drive);
+ hpt370_irq_timeout(drive);
return __ide_dma_timeout(drive);
}
-static int hpt370_ide_dma_lostirq (ide_drive_t *drive)
-{
- hpt370_lostirq_timeout(drive);
- hpt370_clear_engine(drive);
- return __ide_dma_lostirq(drive);
-}
-
/* returns 1 if DMA IRQ issued, 0 otherwise */
static int hpt374_ide_dma_test_irq(ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
u16 bfifo = 0;
- u8 reginfo = hwif->channel ? 0x56 : 0x52;
- u8 dma_stat;
+ u8 dma_stat;
- pci_read_config_word(hwif->pci_dev, reginfo, &bfifo);
+ pci_read_config_word(hwif->pci_dev, hwif->select_data + 2, &bfifo);
if (bfifo & 0x1FF) {
// printk("%s: %d bytes in FIFO\n", drive->name, bfifo);
return 0;
@@ -837,7 +843,7 @@ static int hpt374_ide_dma_test_irq(ide_drive_t *drive)
dma_stat = hwif->INB(hwif->dma_status);
/* return 1 if INTR asserted */
- if ((dma_stat & 4) == 4)
+ if (dma_stat & 4)
return 1;
if (!drive->waiting_for_dma)
@@ -846,17 +852,17 @@ static int hpt374_ide_dma_test_irq(ide_drive_t *drive)
return 0;
}
-static int hpt374_ide_dma_end (ide_drive_t *drive)
+static int hpt374_ide_dma_end(ide_drive_t *drive)
{
- struct pci_dev *dev = HWIF(drive)->pci_dev;
ide_hwif_t *hwif = HWIF(drive);
- u8 msc_stat = 0, mscreg = hwif->channel ? 0x54 : 0x50;
- u8 bwsr_stat = 0, bwsr_mask = hwif->channel ? 0x02 : 0x01;
-
- pci_read_config_byte(dev, 0x6a, &bwsr_stat);
- pci_read_config_byte(dev, mscreg, &msc_stat);
- if ((bwsr_stat & bwsr_mask) == bwsr_mask)
- pci_write_config_byte(dev, mscreg, msc_stat|0x30);
+ struct pci_dev *dev = hwif->pci_dev;
+ u8 mcr = 0, mcr_addr = hwif->select_data;
+ u8 bwsr = 0, mask = hwif->channel ? 0x02 : 0x01;
+
+ pci_read_config_byte(dev, 0x6a, &bwsr);
+ pci_read_config_byte(dev, mcr_addr, &mcr);
+ if (bwsr & mask)
+ pci_write_config_byte(dev, mcr_addr, mcr | 0x30);
return __ide_dma_end(drive);
}
@@ -866,40 +872,37 @@ static int hpt374_ide_dma_end (ide_drive_t *drive)
* @mode: clocking mode (0x21 for write, 0x23 otherwise)
*
* Switch the DPLL clock on the HPT3xxN devices. This is a right mess.
- * NOTE: avoid touching the disabled primary channel on HPT371N -- it
- * doesn't physically exist anyway...
*/
static void hpt3xxn_set_clock(ide_hwif_t *hwif, u8 mode)
{
- u8 mcr1, scr2 = hwif->INB(hwif->dma_master + 0x7b);
+ u8 scr2 = hwif->INB(hwif->dma_master + 0x7b);
if ((scr2 & 0x7f) == mode)
return;
- /* MISC. control register 1 has the channel enable bit... */
- mcr1 = hwif->INB(hwif->dma_master + 0x70);
-
/* Tristate the bus */
- if (mcr1 & 0x04)
- hwif->OUTB(0x80, hwif->dma_master + 0x73);
+ hwif->OUTB(0x80, hwif->dma_master + 0x73);
hwif->OUTB(0x80, hwif->dma_master + 0x77);
/* Switch clock and reset channels */
hwif->OUTB(mode, hwif->dma_master + 0x7b);
hwif->OUTB(0xc0, hwif->dma_master + 0x79);
- /* Reset state machines */
- if (mcr1 & 0x04)
- hwif->OUTB(0x37, hwif->dma_master + 0x70);
- hwif->OUTB(0x37, hwif->dma_master + 0x74);
+ /*
+ * Reset the state machines.
+ * NOTE: avoid accidentally enabling the disabled channels.
+ */
+ hwif->OUTB(hwif->INB(hwif->dma_master + 0x70) | 0x32,
+ hwif->dma_master + 0x70);
+ hwif->OUTB(hwif->INB(hwif->dma_master + 0x74) | 0x32,
+ hwif->dma_master + 0x74);
/* Complete reset */
hwif->OUTB(0x00, hwif->dma_master + 0x79);
/* Reconnect channels to bus */
- if (mcr1 & 0x04)
- hwif->OUTB(0x00, hwif->dma_master + 0x73);
+ hwif->OUTB(0x00, hwif->dma_master + 0x73);
hwif->OUTB(0x00, hwif->dma_master + 0x77);
}
@@ -914,14 +917,12 @@ static void hpt3xxn_set_clock(ide_hwif_t *hwif, u8 mode)
static void hpt3xxn_rw_disk(ide_drive_t *drive, struct request *rq)
{
- ide_hwif_t *hwif = HWIF(drive);
- u8 wantclock = rq_data_dir(rq) ? 0x23 : 0x21;
-
- hpt3xxn_set_clock(hwif, wantclock);
+ hpt3xxn_set_clock(HWIF(drive), rq_data_dir(rq) ? 0x23 : 0x21);
}
/*
* Set/get power state for a drive.
+ * NOTE: affects both drives on each channel.
*
* When we turn the power back on, we need to re-initialize things.
*/
@@ -929,26 +930,18 @@ static void hpt3xxn_rw_disk(ide_drive_t *drive, struct request *rq)
static int hpt3xx_busproc(ide_drive_t *drive, int state)
{
- ide_hwif_t *hwif = drive->hwif;
+ ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
- u8 tristate, resetmask, bus_reg = 0;
- u16 tri_reg = 0;
+ u8 mcr_addr = hwif->select_data + 2;
+ u8 resetmask = hwif->channel ? 0x80 : 0x40;
+ u8 bsr2 = 0;
+ u16 mcr = 0;
hwif->bus_state = state;
- if (hwif->channel) {
- /* secondary channel */
- tristate = 0x56;
- resetmask = 0x80;
- } else {
- /* primary channel */
- tristate = 0x52;
- resetmask = 0x40;
- }
-
/* Grab the status. */
- pci_read_config_word(dev, tristate, &tri_reg);
- pci_read_config_byte(dev, 0x59, &bus_reg);
+ pci_read_config_word(dev, mcr_addr, &mcr);
+ pci_read_config_byte(dev, 0x59, &bsr2);
/*
* Set the state. We don't set it if we don't need to do so.
@@ -956,22 +949,22 @@ static int hpt3xx_busproc(ide_drive_t *drive, int state)
*/
switch (state) {
case BUSSTATE_ON:
- if (!(bus_reg & resetmask))
+ if (!(bsr2 & resetmask))
return 0;
hwif->drives[0].failures = hwif->drives[1].failures = 0;
- pci_write_config_byte(dev, 0x59, bus_reg & ~resetmask);
- pci_write_config_word(dev, tristate, tri_reg & ~TRISTATE_BIT);
+ pci_write_config_byte(dev, 0x59, bsr2 & ~resetmask);
+ pci_write_config_word(dev, mcr_addr, mcr & ~TRISTATE_BIT);
return 0;
case BUSSTATE_OFF:
- if ((bus_reg & resetmask) && !(tri_reg & TRISTATE_BIT))
+ if ((bsr2 & resetmask) && !(mcr & TRISTATE_BIT))
return 0;
- tri_reg &= ~TRISTATE_BIT;
+ mcr &= ~TRISTATE_BIT;
break;
case BUSSTATE_TRISTATE:
- if ((bus_reg & resetmask) && (tri_reg & TRISTATE_BIT))
+ if ((bsr2 & resetmask) && (mcr & TRISTATE_BIT))
return 0;
- tri_reg |= TRISTATE_BIT;
+ mcr |= TRISTATE_BIT;
break;
default:
return -EINVAL;
@@ -980,268 +973,320 @@ static int hpt3xx_busproc(ide_drive_t *drive, int state)
hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
- pci_write_config_word(dev, tristate, tri_reg);
- pci_write_config_byte(dev, 0x59, bus_reg | resetmask);
+ pci_write_config_word(dev, mcr_addr, mcr);
+ pci_write_config_byte(dev, 0x59, bsr2 | resetmask);
return 0;
}
-static void __devinit hpt366_clocking(ide_hwif_t *hwif)
+/**
+ * hpt37x_calibrate_dpll - calibrate the DPLL
+ * @dev: PCI device
+ *
+ * Perform a calibration cycle on the DPLL.
+ * Returns 1 if this succeeds
+ */
+static int __devinit hpt37x_calibrate_dpll(struct pci_dev *dev, u16 f_low, u16 f_high)
{
- u32 reg1 = 0;
- struct hpt_info *info = ide_get_hwifdata(hwif);
+ u32 dpll = (f_high << 16) | f_low | 0x100;
+ u8 scr2;
+ int i;
- pci_read_config_dword(hwif->pci_dev, 0x40, &reg1);
+ pci_write_config_dword(dev, 0x5c, dpll);
- /* detect bus speed by looking at control reg timing: */
- switch((reg1 >> 8) & 7) {
- case 5:
- info->speed = forty_base_hpt36x;
- break;
- case 9:
- info->speed = twenty_five_base_hpt36x;
- break;
- case 7:
- default:
- info->speed = thirty_three_base_hpt36x;
+ /* Wait for oscillator ready */
+ for(i = 0; i < 0x5000; ++i) {
+ udelay(50);
+ pci_read_config_byte(dev, 0x5b, &scr2);
+ if (scr2 & 0x80)
break;
}
+ /* See if it stays ready (we'll just bail out if it's not yet) */
+ for(i = 0; i < 0x1000; ++i) {
+ pci_read_config_byte(dev, 0x5b, &scr2);
+ /* DPLL destabilized? */
+ if(!(scr2 & 0x80))
+ return 0;
+ }
+ /* Turn off tuning, we have the DPLL set */
+ pci_read_config_dword (dev, 0x5c, &dpll);
+ pci_write_config_dword(dev, 0x5c, (dpll & ~0x100));
+ return 1;
}
-static void __devinit hpt37x_clocking(ide_hwif_t *hwif)
+static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const char *name)
{
- struct hpt_info *info = ide_get_hwifdata(hwif);
- struct pci_dev *dev = hwif->pci_dev;
- int adjust, i;
- u16 freq = 0;
- u32 pll, temp = 0;
- u8 reg5bh = 0, mcr1 = 0;
-
+ struct hpt_info *info = kmalloc(sizeof(struct hpt_info), GFP_KERNEL);
+ unsigned long io_base = pci_resource_start(dev, 4);
+ u8 pci_clk, dpll_clk = 0; /* PCI and DPLL clock in MHz */
+ enum ata_clock clock;
+
+ if (info == NULL) {
+ printk(KERN_ERR "%s: out of memory!\n", name);
+ return -ENOMEM;
+ }
+
/*
- * default to pci clock. make sure MA15/16 are set to output
- * to prevent drives having problems with 40-pin cables. Needed
- * for some drives such as IBM-DTLA which will not enter ready
- * state on reset when PDIAG is a input.
- *
- * ToDo: should we set 0x21 when using PLL mode ?
+ * Copy everything from a static "template" structure
+ * to just allocated per-chip hpt_info structure.
*/
- pci_write_config_byte(dev, 0x5b, 0x23);
+ *info = *(struct hpt_info *)pci_get_drvdata(dev);
/*
- * We'll have to read f_CNT value in order to determine
- * the PCI clock frequency according to the following ratio:
- *
- * f_CNT = Fpci * 192 / Fdpll
- *
- * First try reading the register in which the HighPoint BIOS
- * saves f_CNT value before reprogramming the DPLL from its
- * default setting (which differs for the various chips).
- * NOTE: This register is only accessible via I/O space.
- *
- * In case the signature check fails, we'll have to resort to
- * reading the f_CNT register itself in hopes that nobody has
- * touched the DPLL yet...
+ * FIXME: Not portable. Also, why do we enable the ROM in the first place?
+ * We don't seem to be using it.
*/
- temp = inl(pci_resource_start(dev, 4) + 0x90);
- if ((temp & 0xFFFFF000) != 0xABCDE000) {
- printk(KERN_WARNING "HPT37X: no clock data saved by BIOS\n");
-
- /* Calculate the average value of f_CNT */
- for (temp = i = 0; i < 128; i++) {
- pci_read_config_word(dev, 0x78, &freq);
- temp += freq & 0x1ff;
- mdelay(1);
- }
- freq = temp / 128;
- } else
- freq = temp & 0x1ff;
+ if (dev->resource[PCI_ROM_RESOURCE].start)
+ pci_write_config_dword(dev, PCI_ROM_ADDRESS,
+ dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+
+ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
+ pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
+ pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
/*
- * HPT3xxN chips use different PCI clock information.
- * Currently we always set up the PLL for them.
+ * First, try to estimate the PCI clock frequency...
*/
+ if (info->chip_type >= HPT370) {
+ u8 scr1 = 0;
+ u16 f_cnt = 0;
+ u32 temp = 0;
- if (info->flags & IS_3xxN) {
- if(freq < 0x55)
- pll = F_LOW_PCI_33;
- else if(freq < 0x70)
- pll = F_LOW_PCI_40;
- else if(freq < 0x7F)
- pll = F_LOW_PCI_50;
- else
- pll = F_LOW_PCI_66;
+ /* Interrupt force enable. */
+ pci_read_config_byte(dev, 0x5a, &scr1);
+ if (scr1 & 0x10)
+ pci_write_config_byte(dev, 0x5a, scr1 & ~0x10);
- printk(KERN_INFO "HPT3xxN detected, FREQ: %d, PLL: %d\n", freq, pll);
- }
- else
- {
- if(freq < 0x9C)
- pll = F_LOW_PCI_33;
- else if(freq < 0xb0)
- pll = F_LOW_PCI_40;
- else if(freq <0xc8)
- pll = F_LOW_PCI_50;
+ /*
+ * HighPoint does this for HPT372A.
+ * NOTE: This register is only writeable via I/O space.
+ */
+ if (info->chip_type == HPT372A)
+ outb(0x0e, io_base + 0x9c);
+
+ /*
+ * Default to PCI clock. Make sure MA15/16 are set to output
+ * to prevent drives having problems with 40-pin cables.
+ */
+ pci_write_config_byte(dev, 0x5b, 0x23);
+
+ /*
+ * We'll have to read f_CNT value in order to determine
+ * the PCI clock frequency according to the following ratio:
+ *
+ * f_CNT = Fpci * 192 / Fdpll
+ *
+ * First try reading the register in which the HighPoint BIOS
+ * saves f_CNT value before reprogramming the DPLL from its
+ * default setting (which differs for the various chips).
+ * NOTE: This register is only accessible via I/O space.
+ *
+ * In case the signature check fails, we'll have to resort to
+ * reading the f_CNT register itself in hopes that nobody has
+ * touched the DPLL yet...
+ */
+ temp = inl(io_base + 0x90);
+ if ((temp & 0xFFFFF000) != 0xABCDE000) {
+ int i;
+
+ printk(KERN_WARNING "%s: no clock data saved by BIOS\n",
+ name);
+
+ /* Calculate the average value of f_CNT. */
+ for (temp = i = 0; i < 128; i++) {
+ pci_read_config_word(dev, 0x78, &f_cnt);
+ temp += f_cnt & 0x1ff;
+ mdelay(1);
+ }
+ f_cnt = temp / 128;
+ } else
+ f_cnt = temp & 0x1ff;
+
+ dpll_clk = info->dpll_clk;
+ pci_clk = (f_cnt * dpll_clk) / 192;
+
+ /* Clamp PCI clock to bands. */
+ if (pci_clk < 40)
+ pci_clk = 33;
+ else if(pci_clk < 45)
+ pci_clk = 40;
+ else if(pci_clk < 55)
+ pci_clk = 50;
else
- pll = F_LOW_PCI_66;
-
- if (pll == F_LOW_PCI_33) {
- info->speed = thirty_three_base_hpt37x;
- printk(KERN_DEBUG "HPT37X: using 33MHz PCI clock\n");
- } else if (pll == F_LOW_PCI_40) {
- /* Unsupported */
- } else if (pll == F_LOW_PCI_50) {
- info->speed = fifty_base_hpt37x;
- printk(KERN_DEBUG "HPT37X: using 50MHz PCI clock\n");
- } else {
- info->speed = sixty_six_base_hpt37x;
- printk(KERN_DEBUG "HPT37X: using 66MHz PCI clock\n");
+ pci_clk = 66;
+
+ printk(KERN_INFO "%s: DPLL base: %d MHz, f_CNT: %d, "
+ "assuming %d MHz PCI\n", name, dpll_clk, f_cnt, pci_clk);
+ } else {
+ u32 itr1 = 0;
+
+ pci_read_config_dword(dev, 0x40, &itr1);
+
+ /* Detect PCI clock by looking at cmd_high_time. */
+ switch((itr1 >> 8) & 0x07) {
+ case 0x09:
+ pci_clk = 40;
+ break;
+ case 0x05:
+ pci_clk = 25;
+ break;
+ case 0x07:
+ default:
+ pci_clk = 33;
+ break;
}
}
- if (pll == F_LOW_PCI_66)
- info->flags |= PCI_66MHZ;
+ /* Let's assume we'll use PCI clock for the ATA clock... */
+ switch (pci_clk) {
+ case 25:
+ clock = ATA_CLOCK_25MHZ;
+ break;
+ case 33:
+ default:
+ clock = ATA_CLOCK_33MHZ;
+ break;
+ case 40:
+ clock = ATA_CLOCK_40MHZ;
+ break;
+ case 50:
+ clock = ATA_CLOCK_50MHZ;
+ break;
+ case 66:
+ clock = ATA_CLOCK_66MHZ;
+ break;
+ }
/*
- * only try the pll if we don't have a table for the clock
- * speed that we're running at. NOTE: the internal PLL will
- * result in slow reads when using a 33MHz PCI clock. we also
- * don't like to use the PLL because it will cause glitches
- * on PRST/SRST when the HPT state engine gets reset.
+ * Only try the DPLL if we don't have a table for the PCI clock that
+ * we are running at for HPT370/A, always use it for anything newer...
*
- * ToDo: Use 66MHz PLL when ATA133 devices are present on a
- * 372 device so we can get ATA133 support
+ * NOTE: Using the internal DPLL results in slow reads on 33 MHz PCI.
+ * We also don't like using the DPLL because this causes glitches
+ * on PRST-/SRST- when the state engine gets reset...
*/
- if (info->speed)
- goto init_hpt37X_done;
+ if (info->chip_type >= HPT374 || info->settings[clock] == NULL) {
+ u16 f_low, delta = pci_clk < 50 ? 2 : 4;
+ int adjust;
+
+ /*
+ * Select 66 MHz DPLL clock only if UltraATA/133 mode is
+ * supported/enabled, use 50 MHz DPLL clock otherwise...
+ */
+ if (info->max_mode == 0x04) {
+ dpll_clk = 66;
+ clock = ATA_CLOCK_66MHZ;
+ } else if (dpll_clk) { /* HPT36x chips don't have DPLL */
+ dpll_clk = 50;
+ clock = ATA_CLOCK_50MHZ;
+ }
- info->flags |= PLL_MODE;
-
- /*
- * Adjust the PLL based upon the PCI clock, enable it, and
- * wait for stabilization...
- */
- adjust = 0;
- freq = (pll < F_LOW_PCI_50) ? 2 : 4;
- while (adjust++ < 6) {
- pci_write_config_dword(dev, 0x5c, (freq + pll) << 16 |
- pll | 0x100);
-
- /* wait for clock stabilization */
- for (i = 0; i < 0x50000; i++) {
- pci_read_config_byte(dev, 0x5b, &reg5bh);
- if (reg5bh & 0x80) {
- /* spin looking for the clock to destabilize */
- for (i = 0; i < 0x1000; ++i) {
- pci_read_config_byte(dev, 0x5b,
- &reg5bh);
- if ((reg5bh & 0x80) == 0)
- goto pll_recal;
- }
- pci_read_config_dword(dev, 0x5c, &pll);
- pci_write_config_dword(dev, 0x5c,
- pll & ~0x100);
- pci_write_config_byte(dev, 0x5b, 0x21);
-
- info->speed = fifty_base_hpt37x;
- printk("HPT37X: using 50MHz internal PLL\n");
- goto init_hpt37X_done;
- }
+ if (info->settings[clock] == NULL) {
+ printk(KERN_ERR "%s: unknown bus timing!\n", name);
+ kfree(info);
+ return -EIO;
}
-pll_recal:
- if (adjust & 1)
- pll -= (adjust >> 1);
- else
- pll += (adjust >> 1);
- }
-init_hpt37X_done:
- if (!info->speed)
- printk(KERN_ERR "HPT37x%s: unknown bus timing [%d %d].\n",
- (info->flags & IS_3xxN) ? "N" : "", pll, freq);
- /*
- * Reset the state engines.
- * NOTE: avoid accidentally enabling the primary channel on HPT371N.
- */
- pci_read_config_byte(dev, 0x50, &mcr1);
- if (mcr1 & 0x04)
- pci_write_config_byte(dev, 0x50, 0x37);
- pci_write_config_byte(dev, 0x54, 0x37);
- udelay(100);
-}
+ /* Select the DPLL clock. */
+ pci_write_config_byte(dev, 0x5b, 0x21);
-static int __devinit init_hpt37x(struct pci_dev *dev)
-{
- u8 reg5ah;
+ /*
+ * Adjust the DPLL based upon PCI clock, enable it,
+ * and wait for stabilization...
+ */
+ f_low = (pci_clk * 48) / dpll_clk;
- pci_read_config_byte(dev, 0x5a, &reg5ah);
- /* interrupt force enable */
- pci_write_config_byte(dev, 0x5a, (reg5ah & ~0x10));
- return 0;
-}
+ for (adjust = 0; adjust < 8; adjust++) {
+ if(hpt37x_calibrate_dpll(dev, f_low, f_low + delta))
+ break;
-static int __devinit init_hpt366(struct pci_dev *dev)
-{
- u32 reg1 = 0;
- u8 drive_fast = 0;
+ /*
+ * See if it'll settle at a fractionally different clock
+ */
+ if (adjust & 1)
+ f_low -= adjust >> 1;
+ else
+ f_low += adjust >> 1;
+ }
+ if (adjust == 8) {
+ printk(KERN_ERR "%s: DPLL did not stabilize!\n", name);
+ kfree(info);
+ return -EIO;
+ }
- /*
- * Disable the "fast interrupt" prediction.
- */
- pci_read_config_byte(dev, 0x51, &drive_fast);
- if (drive_fast & 0x80)
- pci_write_config_byte(dev, 0x51, drive_fast & ~0x80);
- pci_read_config_dword(dev, 0x40, &reg1);
-
- return 0;
-}
+ printk("%s: using %d MHz DPLL clock\n", name, dpll_clk);
+ } else {
+ /* Mark the fact that we're not using the DPLL. */
+ dpll_clk = 0;
-static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const char *name)
-{
- int ret = 0;
+ printk("%s: using %d MHz PCI clock\n", name, pci_clk);
+ }
/*
- * FIXME: Not portable. Also, why do we enable the ROM in the first place?
- * We don't seem to be using it.
+ * Advance the table pointer to a slot which points to the list
+ * of the register values settings matching the clock being used.
*/
- if (dev->resource[PCI_ROM_RESOURCE].start)
- pci_write_config_dword(dev, PCI_ROM_ADDRESS,
- dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+ info->settings += clock;
- pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
- pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
- pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
- pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
+ /* Store the clock frequencies. */
+ info->dpll_clk = dpll_clk;
+ info->pci_clk = pci_clk;
- if (hpt_revision(dev) >= 3)
- ret = init_hpt37x(dev);
- else
- ret = init_hpt366(dev);
+ /* Point to this chip's own instance of the hpt_info structure. */
+ pci_set_drvdata(dev, info);
- if (ret)
- return ret;
+ if (info->chip_type >= HPT370) {
+ u8 mcr1, mcr4;
+
+ /*
+ * Reset the state engines.
+ * NOTE: Avoid accidentally enabling the disabled channels.
+ */
+ pci_read_config_byte (dev, 0x50, &mcr1);
+ pci_read_config_byte (dev, 0x54, &mcr4);
+ pci_write_config_byte(dev, 0x50, (mcr1 | 0x32));
+ pci_write_config_byte(dev, 0x54, (mcr4 | 0x32));
+ udelay(100);
+ }
+
+ /*
+ * On HPT371N, if ATA clock is 66 MHz we must set bit 2 in
+ * the MISC. register to stretch the UltraDMA Tss timing.
+ * NOTE: This register is only writeable via I/O space.
+ */
+ if (info->chip_type == HPT371N && clock == ATA_CLOCK_66MHZ)
+
+ outb(inb(io_base + 0x9c) | 0x04, io_base + 0x9c);
return dev->irq;
}
static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
{
- struct pci_dev *dev = hwif->pci_dev;
- struct hpt_info *info = ide_get_hwifdata(hwif);
- u8 ata66 = 0, regmask = (hwif->channel) ? 0x01 : 0x02;
+ struct pci_dev *dev = hwif->pci_dev;
+ struct hpt_info *info = pci_get_drvdata(dev);
int serialize = HPT_SERIALIZE_IO;
-
+ u8 scr1 = 0, ata66 = (hwif->channel) ? 0x01 : 0x02;
+ u8 chip_type = info->chip_type;
+ u8 new_mcr, old_mcr = 0;
+
+ /* Cache the channel's MISC. control registers' offset */
+ hwif->select_data = hwif->channel ? 0x54 : 0x50;
+
hwif->tuneproc = &hpt3xx_tune_drive;
hwif->speedproc = &hpt3xx_tune_chipset;
hwif->quirkproc = &hpt3xx_quirkproc;
hwif->intrproc = &hpt3xx_intrproc;
hwif->maskproc = &hpt3xx_maskproc;
-
+ hwif->busproc = &hpt3xx_busproc;
+
/*
* HPT3xxN chips have some complications:
*
* - on 33 MHz PCI we must clock switch
* - on 66 MHz PCI we must NOT use the PCI clock
*/
- if ((info->flags & (IS_3xxN | PCI_66MHZ)) == IS_3xxN) {
+ if (chip_type >= HPT372N && info->dpll_clk && info->pci_clk < 66) {
/*
* Clock is shared between the channels,
* so we'll have to serialize them... :-(
@@ -1250,200 +1295,171 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
hwif->rw_disk = &hpt3xxn_rw_disk;
}
+ /* Serialize access to this device if needed */
+ if (serialize && hwif->mate)
+ hwif->serialized = hwif->mate->serialized = 1;
+
+ /*
+ * Disable the "fast interrupt" prediction. Don't hold off
+ * on interrupts. (== 0x01 despite what the docs say)
+ */
+ pci_read_config_byte(dev, hwif->select_data + 1, &old_mcr);
+
+ if (info->chip_type >= HPT374)
+ new_mcr = old_mcr & ~0x07;
+ else if (info->chip_type >= HPT370) {
+ new_mcr = old_mcr;
+ new_mcr &= ~0x02;
+
+#ifdef HPT_DELAY_INTERRUPT
+ new_mcr &= ~0x01;
+#else
+ new_mcr |= 0x01;
+#endif
+ } else /* HPT366 and HPT368 */
+ new_mcr = old_mcr & ~0x80;
+
+ if (new_mcr != old_mcr)
+ pci_write_config_byte(dev, hwif->select_data + 1, new_mcr);
+
+ if (!hwif->dma_base) {
+ hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+ return;
+ }
+
+ hwif->ultra_mask = 0x7f;
+ hwif->mwdma_mask = 0x07;
+
/*
* The HPT37x uses the CBLID pins as outputs for MA15/MA16
- * address lines to access an external eeprom. To read valid
+ * address lines to access an external EEPROM. To read valid
* cable detect state the pins must be enabled as inputs.
*/
- if (info->revision >= 8 && (PCI_FUNC(dev->devfn) & 1)) {
+ if (chip_type == HPT374 && (PCI_FUNC(dev->devfn) & 1)) {
/*
* HPT374 PCI function 1
* - set bit 15 of reg 0x52 to enable TCBLID as input
* - set bit 15 of reg 0x56 to enable FCBLID as input
*/
- u16 mcr3, mcr6;
- pci_read_config_word(dev, 0x52, &mcr3);
- pci_read_config_word(dev, 0x56, &mcr6);
- pci_write_config_word(dev, 0x52, mcr3 | 0x8000);
- pci_write_config_word(dev, 0x56, mcr6 | 0x8000);
+ u8 mcr_addr = hwif->select_data + 2;
+ u16 mcr;
+
+ pci_read_config_word (dev, mcr_addr, &mcr);
+ pci_write_config_word(dev, mcr_addr, (mcr | 0x8000));
/* now read cable id register */
- pci_read_config_byte(dev, 0x5a, &ata66);
- pci_write_config_word(dev, 0x52, mcr3);
- pci_write_config_word(dev, 0x56, mcr6);
- } else if (info->revision >= 3) {
+ pci_read_config_byte (dev, 0x5a, &scr1);
+ pci_write_config_word(dev, mcr_addr, mcr);
+ } else if (chip_type >= HPT370) {
/*
* HPT370/372 and 374 pcifn 0
- * - clear bit 0 of 0x5b to enable P/SCBLID as inputs
+ * - clear bit 0 of reg 0x5b to enable P/SCBLID as inputs
*/
- u8 scr2;
- pci_read_config_byte(dev, 0x5b, &scr2);
- pci_write_config_byte(dev, 0x5b, scr2 & ~1);
- /* now read cable id register */
- pci_read_config_byte(dev, 0x5a, &ata66);
- pci_write_config_byte(dev, 0x5b, scr2);
- } else {
- pci_read_config_byte(dev, 0x5a, &ata66);
- }
+ u8 scr2 = 0;
-#ifdef DEBUG
- printk("HPT366: reg5ah=0x%02x ATA-%s Cable Port%d\n",
- ata66, (ata66 & regmask) ? "33" : "66",
- PCI_FUNC(hwif->pci_dev->devfn));
-#endif /* DEBUG */
-
- /* Serialize access to this device */
- if (serialize && hwif->mate)
- hwif->serialized = hwif->mate->serialized = 1;
+ pci_read_config_byte (dev, 0x5b, &scr2);
+ pci_write_config_byte(dev, 0x5b, (scr2 & ~1));
+ /* now read cable id register */
+ pci_read_config_byte (dev, 0x5a, &scr1);
+ pci_write_config_byte(dev, 0x5b, scr2);
+ } else
+ pci_read_config_byte (dev, 0x5a, &scr1);
- /*
- * Set up ioctl for power status.
- * NOTE: power affects both drives on each channel.
- */
- hwif->busproc = &hpt3xx_busproc;
+ if (!hwif->udma_four)
+ hwif->udma_four = (scr1 & ata66) ? 0 : 1;
- if (!hwif->dma_base) {
- hwif->drives[0].autotune = 1;
- hwif->drives[1].autotune = 1;
- return;
- }
+ hwif->ide_dma_check = &hpt366_config_drive_xfer_rate;
- hwif->ultra_mask = 0x7f;
- hwif->mwdma_mask = 0x07;
-
- if (!(hwif->udma_four))
- hwif->udma_four = ((ata66 & regmask) ? 0 : 1);
- hwif->ide_dma_check = &hpt366_config_drive_xfer_rate;
-
- if (info->revision >= 8) {
- hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq;
- hwif->ide_dma_end = &hpt374_ide_dma_end;
- } else if (info->revision >= 5) {
- hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq;
- hwif->ide_dma_end = &hpt374_ide_dma_end;
- } else if (info->revision >= 3) {
- hwif->dma_start = &hpt370_ide_dma_start;
- hwif->ide_dma_end = &hpt370_ide_dma_end;
- hwif->ide_dma_timeout = &hpt370_ide_dma_timeout;
- hwif->ide_dma_lostirq = &hpt370_ide_dma_lostirq;
- } else if (info->revision >= 2)
- hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq;
- else
- hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq;
+ if (chip_type >= HPT374) {
+ hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq;
+ hwif->ide_dma_end = &hpt374_ide_dma_end;
+ } else if (chip_type >= HPT370) {
+ hwif->dma_start = &hpt370_ide_dma_start;
+ hwif->ide_dma_end = &hpt370_ide_dma_end;
+ hwif->ide_dma_timeout = &hpt370_ide_dma_timeout;
+ } else
+ hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq;
if (!noautodma)
hwif->autodma = 1;
- hwif->drives[0].autodma = hwif->autodma;
- hwif->drives[1].autodma = hwif->autodma;
+ hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
}
static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase)
{
- struct hpt_info *info = ide_get_hwifdata(hwif);
- u8 masterdma = 0, slavedma = 0;
- u8 dma_new = 0, dma_old = 0;
- u8 primary = hwif->channel ? 0x4b : 0x43;
- u8 secondary = hwif->channel ? 0x4f : 0x47;
+ struct pci_dev *dev = hwif->pci_dev;
+ u8 masterdma = 0, slavedma = 0;
+ u8 dma_new = 0, dma_old = 0;
unsigned long flags;
if (!dmabase)
return;
- if(info->speed == NULL) {
- printk(KERN_WARNING "hpt366: no known IDE timings, disabling DMA.\n");
- return;
- }
-
- dma_old = hwif->INB(dmabase+2);
+ dma_old = hwif->INB(dmabase + 2);
local_irq_save(flags);
dma_new = dma_old;
- pci_read_config_byte(hwif->pci_dev, primary, &masterdma);
- pci_read_config_byte(hwif->pci_dev, secondary, &slavedma);
+ pci_read_config_byte(dev, hwif->channel ? 0x4b : 0x43, &masterdma);
+ pci_read_config_byte(dev, hwif->channel ? 0x4f : 0x47, &slavedma);
if (masterdma & 0x30) dma_new |= 0x20;
- if (slavedma & 0x30) dma_new |= 0x40;
+ if ( slavedma & 0x30) dma_new |= 0x40;
if (dma_new != dma_old)
- hwif->OUTB(dma_new, dmabase+2);
+ hwif->OUTB(dma_new, dmabase + 2);
local_irq_restore(flags);
ide_setup_dma(hwif, dmabase, 8);
}
-/*
- * We "borrow" this hook in order to set the data structures
- * up early enough before dma or init_hwif calls are made.
- */
-
-static void __devinit init_iops_hpt366(ide_hwif_t *hwif)
-{
- struct hpt_info *info = kzalloc(sizeof(struct hpt_info), GFP_KERNEL);
- struct pci_dev *dev = hwif->pci_dev;
- u16 did = dev->device;
- u8 rid = 0;
-
- if(info == NULL) {
- printk(KERN_WARNING "hpt366: out of memory.\n");
- return;
- }
- ide_set_hwifdata(hwif, info);
-
- /* Avoid doing the same thing twice. */
- if (hwif->channel && hwif->mate) {
- memcpy(info, ide_get_hwifdata(hwif->mate), sizeof(struct hpt_info));
- return;
- }
-
- pci_read_config_byte(dev, PCI_CLASS_REVISION, &rid);
-
- if (( did == PCI_DEVICE_ID_TTI_HPT366 && rid == 6) ||
- ((did == PCI_DEVICE_ID_TTI_HPT372 ||
- did == PCI_DEVICE_ID_TTI_HPT302 ||
- did == PCI_DEVICE_ID_TTI_HPT371) && rid > 1) ||
- did == PCI_DEVICE_ID_TTI_HPT372N)
- info->flags |= IS_3xxN;
-
- info->revision = hpt_revision(dev);
-
- if (info->revision >= 3)
- hpt37x_clocking(hwif);
- else
- hpt366_clocking(hwif);
-}
-
static int __devinit init_setup_hpt374(struct pci_dev *dev, ide_pci_device_t *d)
{
- struct pci_dev *findev = NULL;
+ struct pci_dev *dev2;
if (PCI_FUNC(dev->devfn) & 1)
return -ENODEV;
- while ((findev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) {
- if ((findev->vendor == dev->vendor) &&
- (findev->device == dev->device) &&
- ((findev->devfn - dev->devfn) == 1) &&
- (PCI_FUNC(findev->devfn) & 1)) {
- if (findev->irq != dev->irq) {
- /* FIXME: we need a core pci_set_interrupt() */
- findev->irq = dev->irq;
- printk(KERN_WARNING "%s: pci-config space interrupt "
- "fixed.\n", d->name);
- }
- return ide_setup_pci_devices(dev, findev, d);
+ pci_set_drvdata(dev, &hpt374);
+
+ if ((dev2 = pci_get_slot(dev->bus, dev->devfn + 1)) != NULL) {
+ int ret;
+
+ pci_set_drvdata(dev2, &hpt374);
+
+ if (dev2->irq != dev->irq) {
+ /* FIXME: we need a core pci_set_interrupt() */
+ dev2->irq = dev->irq;
+ printk(KERN_WARNING "%s: PCI config space interrupt "
+ "fixed.\n", d->name);
}
+ ret = ide_setup_pci_devices(dev, dev2, d);
+ if (ret < 0)
+ pci_dev_put(dev2);
+ return ret;
}
return ide_setup_pci_device(dev, d);
}
-static int __devinit init_setup_hpt37x(struct pci_dev *dev, ide_pci_device_t *d)
+static int __devinit init_setup_hpt372n(struct pci_dev *dev, ide_pci_device_t *d)
{
+ pci_set_drvdata(dev, &hpt372n);
+
return ide_setup_pci_device(dev, d);
}
static int __devinit init_setup_hpt371(struct pci_dev *dev, ide_pci_device_t *d)
{
- u8 mcr1 = 0;
+ struct hpt_info *info;
+ u8 rev = 0, mcr1 = 0;
+
+ pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
+
+ if (rev > 1) {
+ d->name = "HPT371N";
+
+ info = &hpt371n;
+ } else
+ info = &hpt371;
/*
* HPT371 chips physically have only one channel, the secondary one,
@@ -1453,59 +1469,94 @@ static int __devinit init_setup_hpt371(struct pci_dev *dev, ide_pci_device_t *d)
*/
pci_read_config_byte(dev, 0x50, &mcr1);
if (mcr1 & 0x04)
- pci_write_config_byte(dev, 0x50, (mcr1 & ~0x04));
+ pci_write_config_byte(dev, 0x50, mcr1 & ~0x04);
+
+ pci_set_drvdata(dev, info);
+
+ return ide_setup_pci_device(dev, d);
+}
+
+static int __devinit init_setup_hpt372a(struct pci_dev *dev, ide_pci_device_t *d)
+{
+ struct hpt_info *info;
+ u8 rev = 0;
+
+ pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
+
+ if (rev > 1) {
+ d->name = "HPT372N";
+
+ info = &hpt372n;
+ } else
+ info = &hpt372a;
+ pci_set_drvdata(dev, info);
+
+ return ide_setup_pci_device(dev, d);
+}
+
+static int __devinit init_setup_hpt302(struct pci_dev *dev, ide_pci_device_t *d)
+{
+ struct hpt_info *info;
+ u8 rev = 0;
+
+ pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
+
+ if (rev > 1) {
+ d->name = "HPT302N";
+
+ info = &hpt302n;
+ } else
+ info = &hpt302;
+ pci_set_drvdata(dev, info);
return ide_setup_pci_device(dev, d);
}
static int __devinit init_setup_hpt366(struct pci_dev *dev, ide_pci_device_t *d)
{
- struct pci_dev *findev = NULL;
- u8 pin1 = 0, pin2 = 0;
- unsigned int class_rev;
- char *chipset_names[] = {"HPT366", "HPT366", "HPT368",
- "HPT370", "HPT370A", "HPT372",
- "HPT372N" };
+ struct pci_dev *dev2;
+ u8 rev = 0;
+ static char *chipset_names[] = { "HPT366", "HPT366", "HPT368",
+ "HPT370", "HPT370A", "HPT372",
+ "HPT372N" };
+ static struct hpt_info *info[] = { &hpt36x, &hpt36x, &hpt36x,
+ &hpt370, &hpt370a, &hpt372,
+ &hpt372n };
if (PCI_FUNC(dev->devfn) & 1)
return -ENODEV;
- pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
- class_rev &= 0xff;
+ pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
- if(dev->device == PCI_DEVICE_ID_TTI_HPT372N)
- class_rev = 6;
+ if (rev > 6)
+ rev = 6;
- if(class_rev <= 6)
- d->name = chipset_names[class_rev];
-
- switch(class_rev) {
- case 6:
- case 5:
- case 4:
- case 3:
- goto init_single;
- default:
- break;
- }
+ d->name = chipset_names[rev];
+
+ pci_set_drvdata(dev, info[rev]);
+
+ if (rev > 2)
+ goto init_single;
d->channels = 1;
- pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1);
- while ((findev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) {
- if ((findev->vendor == dev->vendor) &&
- (findev->device == dev->device) &&
- ((findev->devfn - dev->devfn) == 1) &&
- (PCI_FUNC(findev->devfn) & 1)) {
- pci_read_config_byte(findev, PCI_INTERRUPT_PIN, &pin2);
- if ((pin1 != pin2) && (dev->irq == findev->irq)) {
- d->bootable = ON_BOARD;
- printk("%s: onboard version of chipset, "
- "pin1=%d pin2=%d\n", d->name,
- pin1, pin2);
- }
- return ide_setup_pci_devices(dev, findev, d);
+ if ((dev2 = pci_get_slot(dev->bus, dev->devfn + 1)) != NULL) {
+ u8 pin1 = 0, pin2 = 0;
+ int ret;
+
+ pci_set_drvdata(dev2, info[rev]);
+
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1);
+ pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2);
+ if (pin1 != pin2 && dev->irq == dev2->irq) {
+ d->bootable = ON_BOARD;
+ printk("%s: onboard version of chipset, pin1=%d pin2=%d\n",
+ d->name, pin1, pin2);
}
+ ret = ide_setup_pci_devices(dev, dev2, d);
+ if (ret < 0)
+ pci_dev_put(dev2);
+ return ret;
}
init_single:
return ide_setup_pci_device(dev, d);
@@ -1516,64 +1567,68 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
.name = "HPT366",
.init_setup = init_setup_hpt366,
.init_chipset = init_chipset_hpt366,
- .init_iops = init_iops_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
.channels = 2,
.autodma = AUTODMA,
+ .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
.bootable = OFF_BOARD,
.extra = 240
},{ /* 1 */
.name = "HPT372A",
- .init_setup = init_setup_hpt37x,
+ .init_setup = init_setup_hpt372a,
.init_chipset = init_chipset_hpt366,
- .init_iops = init_iops_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
.channels = 2,
.autodma = AUTODMA,
+ .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
.bootable = OFF_BOARD,
+ .extra = 240
},{ /* 2 */
.name = "HPT302",
- .init_setup = init_setup_hpt37x,
+ .init_setup = init_setup_hpt302,
.init_chipset = init_chipset_hpt366,
- .init_iops = init_iops_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
.channels = 2,
.autodma = AUTODMA,
+ .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
.bootable = OFF_BOARD,
+ .extra = 240
},{ /* 3 */
.name = "HPT371",
.init_setup = init_setup_hpt371,
.init_chipset = init_chipset_hpt366,
- .init_iops = init_iops_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
.channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
.bootable = OFF_BOARD,
+ .extra = 240
},{ /* 4 */
.name = "HPT374",
.init_setup = init_setup_hpt374,
.init_chipset = init_chipset_hpt366,
- .init_iops = init_iops_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
.channels = 2, /* 4 */
.autodma = AUTODMA,
+ .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
.bootable = OFF_BOARD,
+ .extra = 240
},{ /* 5 */
.name = "HPT372N",
- .init_setup = init_setup_hpt37x,
+ .init_setup = init_setup_hpt372n,
.init_chipset = init_chipset_hpt366,
- .init_iops = init_iops_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
.channels = 2, /* 4 */
.autodma = AUTODMA,
+ .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
.bootable = OFF_BOARD,
+ .extra = 240
}
};
diff --git a/drivers/ide/pci/it8213.c b/drivers/ide/pci/it8213.c
new file mode 100644
index 00000000000..63248b6909f
--- /dev/null
+++ b/drivers/ide/pci/it8213.c
@@ -0,0 +1,362 @@
+/*
+ * ITE 8213 IDE driver
+ *
+ * Copyright (C) 2006 Jack Lee
+ * Copyright (C) 2006 Alan Cox
+ * Copyright (C) 2007 Bartlomiej Zolnierkiewicz
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+/*
+ * it8213_ratemask - Compute available modes
+ * @drive: IDE drive
+ *
+ * Compute the available speeds for the devices on the interface. This
+ * is all modes to ATA133 clipped by drive cable setup.
+ */
+
+static u8 it8213_ratemask (ide_drive_t *drive)
+{
+ u8 mode = 4;
+ if (!eighty_ninty_three(drive))
+ mode = min_t(u8, mode, 1);
+ return mode;
+}
+
+/**
+ * it8213_dma_2_pio - return the PIO mode matching DMA
+ * @xfer_rate: transfer speed
+ *
+ * Returns the nearest equivalent PIO timing for the PIO or DMA
+ * mode requested by the controller.
+ */
+
+static u8 it8213_dma_2_pio (u8 xfer_rate) {
+ switch(xfer_rate) {
+ case XFER_UDMA_6:
+ case XFER_UDMA_5:
+ case XFER_UDMA_4:
+ case XFER_UDMA_3:
+ case XFER_UDMA_2:
+ case XFER_UDMA_1:
+ case XFER_UDMA_0:
+ case XFER_MW_DMA_2:
+ case XFER_PIO_4:
+ return 4;
+ case XFER_MW_DMA_1:
+ case XFER_PIO_3:
+ return 3;
+ case XFER_SW_DMA_2:
+ case XFER_PIO_2:
+ return 2;
+ case XFER_MW_DMA_0:
+ case XFER_SW_DMA_1:
+ case XFER_SW_DMA_0:
+ case XFER_PIO_1:
+ case XFER_PIO_0:
+ case XFER_PIO_SLOW:
+ default:
+ return 0;
+ }
+}
+
+/*
+ * it8213_tuneproc - tune a drive
+ * @drive: drive to tune
+ * @pio: desired PIO mode
+ *
+ * Set the interface PIO mode.
+ */
+
+static void it8213_tuneproc (ide_drive_t *drive, u8 pio)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ int is_slave = drive->dn & 1;
+ int master_port = 0x40;
+ int slave_port = 0x44;
+ unsigned long flags;
+ u16 master_data;
+ u8 slave_data;
+ static DEFINE_SPINLOCK(tune_lock);
+ int control = 0;
+
+ static const u8 timings[][2]= {
+ { 0, 0 },
+ { 0, 0 },
+ { 1, 0 },
+ { 2, 1 },
+ { 2, 3 }, };
+
+ pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+
+ spin_lock_irqsave(&tune_lock, flags);
+ pci_read_config_word(dev, master_port, &master_data);
+
+ if (pio > 1)
+ control |= 1; /* Programmable timing on */
+ if (drive->media != ide_disk)
+ control |= 4; /* ATAPI */
+ if (pio > 2)
+ control |= 2; /* IORDY */
+ if (is_slave) {
+ master_data |= 0x4000;
+ master_data &= ~0x0070;
+ if (pio > 1)
+ master_data = master_data | (control << 4);
+ pci_read_config_byte(dev, slave_port, &slave_data);
+ slave_data = slave_data & 0xf0;
+ slave_data = slave_data | (timings[pio][0] << 2) | timings[pio][1];
+ } else {
+ master_data &= ~0x3307;
+ if (pio > 1)
+ master_data = master_data | control;
+ master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8);
+ }
+ pci_write_config_word(dev, master_port, master_data);
+ if (is_slave)
+ pci_write_config_byte(dev, slave_port, slave_data);
+ spin_unlock_irqrestore(&tune_lock, flags);
+}
+
+/**
+ * it8213_tune_chipset - set controller timings
+ * @drive: Drive to set up
+ * @xferspeed: speed we want to achieve
+ *
+ * Tune the ITE chipset for the desired mode. If we can't achieve
+ * the desired mode then tune for a lower one, but ultimately
+ * make the thing work.
+ */
+
+static int it8213_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ u8 maslave = 0x40;
+ u8 speed = ide_rate_filter(it8213_ratemask(drive), xferspeed);
+ int a_speed = 3 << (drive->dn * 4);
+ int u_flag = 1 << drive->dn;
+ int v_flag = 0x01 << drive->dn;
+ int w_flag = 0x10 << drive->dn;
+ int u_speed = 0;
+ u16 reg4042, reg4a;
+ u8 reg48, reg54, reg55;
+
+ pci_read_config_word(dev, maslave, &reg4042);
+ pci_read_config_byte(dev, 0x48, &reg48);
+ pci_read_config_word(dev, 0x4a, &reg4a);
+ pci_read_config_byte(dev, 0x54, &reg54);
+ pci_read_config_byte(dev, 0x55, &reg55);
+
+ switch(speed) {
+ case XFER_UDMA_6:
+ case XFER_UDMA_4:
+ case XFER_UDMA_2: u_speed = 2 << (drive->dn * 4); break;
+ case XFER_UDMA_5:
+ case XFER_UDMA_3:
+ case XFER_UDMA_1: u_speed = 1 << (drive->dn * 4); break;
+ case XFER_UDMA_0: u_speed = 0 << (drive->dn * 4); break;
+ break;
+ case XFER_MW_DMA_2:
+ case XFER_MW_DMA_1:
+ case XFER_SW_DMA_2:
+ break;
+ case XFER_PIO_4:
+ case XFER_PIO_3:
+ case XFER_PIO_2:
+ case XFER_PIO_1:
+ case XFER_PIO_0:
+ break;
+ default:
+ return -1;
+ }
+
+ if (speed >= XFER_UDMA_0) {
+ if (!(reg48 & u_flag))
+ pci_write_config_byte(dev, 0x48, reg48 | u_flag);
+ if (speed >= XFER_UDMA_5) {
+ pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag);
+ } else {
+ pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
+ }
+
+ if ((reg4a & a_speed) != u_speed)
+ pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed);
+ if (speed > XFER_UDMA_2) {
+ if (!(reg54 & v_flag))
+ pci_write_config_byte(dev, 0x54, reg54 | v_flag);
+ } else
+ pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
+ } else {
+ if (reg48 & u_flag)
+ pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
+ if (reg4a & a_speed)
+ pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+ if (reg54 & v_flag)
+ pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
+ if (reg55 & w_flag)
+ pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
+ }
+ it8213_tuneproc(drive, it8213_dma_2_pio(speed));
+ return ide_config_drive_speed(drive, speed);
+}
+
+/*
+ * config_chipset_for_dma - configure for DMA
+ * @drive: drive to configure
+ *
+ * Called by the IDE layer when it wants the timings set up.
+ */
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+ u8 speed = ide_dma_speed(drive, it8213_ratemask(drive));
+
+ if (!speed)
+ return 0;
+
+ it8213_tune_chipset(drive, speed);
+
+ return ide_dma_enable(drive);
+}
+
+/**
+ * it8213_configure_drive_for_dma - set up for DMA transfers
+ * @drive: drive we are going to set up
+ *
+ * Set up the drive for DMA, tune the controller and drive as
+ * required. If the drive isn't suitable for DMA or we hit
+ * other problems then we will drop down to PIO and set up
+ * PIO appropriately
+ */
+
+static int it8213_config_drive_for_dma (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+
+ if (ide_use_dma(drive)) {
+ if (config_chipset_for_dma(drive))
+ return hwif->ide_dma_on(drive);
+ }
+
+ hwif->speedproc(drive, XFER_PIO_0
+ + ide_get_best_pio_mode(drive, 255, 4, NULL));
+
+ return hwif->ide_dma_off_quietly(drive);
+}
+
+/**
+ * init_hwif_it8213 - set up hwif structs
+ * @hwif: interface to set up
+ *
+ * We do the basic set up of the interface structure. The IT8212
+ * requires several custom handlers so we override the default
+ * ide DMA handlers appropriately
+ */
+
+static void __devinit init_hwif_it8213(ide_hwif_t *hwif)
+{
+ u8 reg42h = 0, ata66 = 0;
+
+ hwif->speedproc = &it8213_tune_chipset;
+ hwif->tuneproc = &it8213_tuneproc;
+
+ hwif->autodma = 0;
+
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+
+ if (!hwif->dma_base)
+ return;
+
+ hwif->atapi_dma = 1;
+ hwif->ultra_mask = 0x7f;
+ hwif->mwdma_mask = 0x06;
+ hwif->swdma_mask = 0x04;
+
+ pci_read_config_byte(hwif->pci_dev, 0x42, &reg42h);
+ ata66 = (reg42h & 0x02) ? 0 : 1;
+
+ hwif->ide_dma_check = &it8213_config_drive_for_dma;
+ if (!(hwif->udma_four))
+ hwif->udma_four = ata66;
+
+ /*
+ * The BIOS often doesn't set up DMA on this controller
+ * so we always do it.
+ */
+ if (!noautodma)
+ hwif->autodma = 1;
+
+ hwif->drives[0].autodma = hwif->autodma;
+ hwif->drives[1].autodma = hwif->autodma;
+}
+
+
+#define DECLARE_ITE_DEV(name_str) \
+ { \
+ .name = name_str, \
+ .init_hwif = init_hwif_it8213, \
+ .channels = 1, \
+ .autodma = AUTODMA, \
+ .enablebits = {{0x41,0x80,0x80}}, \
+ .bootable = ON_BOARD, \
+ }
+
+static ide_pci_device_t it8213_chipsets[] __devinitdata = {
+ /* 0 */ DECLARE_ITE_DEV("IT8213"),
+};
+
+
+/**
+ * it8213_init_one - pci layer discovery entry
+ * @dev: PCI device
+ * @id: ident table entry
+ *
+ * Called by the PCI code when it finds an ITE8213 controller. As
+ * this device follows the standard interfaces we can use the
+ * standard helper functions to do almost all the work for us.
+ */
+
+static int __devinit it8213_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ ide_setup_pci_device(dev, &it8213_chipsets[id->driver_data]);
+ return 0;
+}
+
+
+static struct pci_device_id it8213_pci_tbl[] = {
+ { PCI_VENDOR_ID_ITE, 0x8213, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { 0, },
+};
+
+MODULE_DEVICE_TABLE(pci, it8213_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "ITE8213_IDE",
+ .id_table = it8213_pci_tbl,
+ .probe = it8213_init_one,
+};
+
+static int __init it8213_ide_init(void)
+{
+ return ide_pci_register_driver(&driver);
+}
+
+module_init(it8213_ide_init);
+
+MODULE_AUTHOR("Jack Lee, Alan Cox");
+MODULE_DESCRIPTION("PCI driver module for the ITE 8213");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c
index 77a9aaa7dab..236a03144a2 100644
--- a/drivers/ide/pci/pdc202xx_new.c
+++ b/drivers/ide/pci/pdc202xx_new.c
@@ -92,26 +92,6 @@ static u8 pdcnew_ratemask(ide_drive_t *drive)
return mode;
}
-static int check_in_drive_lists(ide_drive_t *drive, const char **list)
-{
- struct hd_driveid *id = drive->id;
-
- if (pdc_quirk_drives == list) {
- while (*list) {
- if (strstr(id->model, *list++)) {
- return 2;
- }
- }
- } else {
- while (*list) {
- if (!strcmp(*list++,id->model)) {
- return 1;
- }
- }
- }
- return 0;
-}
-
/**
* get_indexed_reg - Get indexed register
* @hwif: for the port address
@@ -249,13 +229,6 @@ static int pdcnew_tune_chipset(ide_drive_t *drive, u8 speed)
return err;
}
-/* 0 1 2 3 4 5 6 7 8
- * 960, 480, 390, 300, 240, 180, 120, 90, 60
- * 180, 150, 120, 90, 60
- * DMA_Speed
- * 180, 120, 90, 90, 90, 60, 30
- * 11, 5, 4, 3, 2, 1, 0
- */
static void pdcnew_tune_drive(ide_drive_t *drive, u8 pio)
{
pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
@@ -313,12 +286,10 @@ static int pdcnew_config_drive_xfer_rate(ide_drive_t *drive)
drive->init_speed = 0;
- if (id && (id->capability & 1) && drive->autodma) {
+ if ((id->capability & 1) && drive->autodma) {
- if (ide_use_dma(drive)) {
- if (config_chipset_for_dma(drive))
- return hwif->ide_dma_on(drive);
- }
+ if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+ return hwif->ide_dma_on(drive);
goto fast_ata_pio;
@@ -333,21 +304,12 @@ fast_ata_pio:
static int pdcnew_quirkproc(ide_drive_t *drive)
{
- return check_in_drive_lists(drive, pdc_quirk_drives);
-}
+ const char **list, *model = drive->id->model;
-static int pdcnew_ide_dma_lostirq(ide_drive_t *drive)
-{
- if (HWIF(drive)->resetproc != NULL)
- HWIF(drive)->resetproc(drive);
- return __ide_dma_lostirq(drive);
-}
-
-static int pdcnew_ide_dma_timeout(ide_drive_t *drive)
-{
- if (HWIF(drive)->resetproc != NULL)
- HWIF(drive)->resetproc(drive);
- return __ide_dma_timeout(drive);
+ for (list = pdc_quirk_drives; *list != NULL; list++)
+ if (strstr(model, *list) != NULL)
+ return 2;
+ return 0;
}
static void pdcnew_reset(ide_drive_t *drive)
@@ -599,8 +561,6 @@ static void __devinit init_hwif_pdc202new(ide_hwif_t *hwif)
hwif->err_stops_fifo = 1;
hwif->ide_dma_check = &pdcnew_config_drive_xfer_rate;
- hwif->ide_dma_lostirq = &pdcnew_ide_dma_lostirq;
- hwif->ide_dma_timeout = &pdcnew_ide_dma_timeout;
if (!hwif->udma_four)
hwif->udma_four = pdcnew_cable_detect(hwif) ? 0 : 1;
diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c
index 143239c093d..730e8d1ec2f 100644
--- a/drivers/ide/pci/pdc202xx_old.c
+++ b/drivers/ide/pci/pdc202xx_old.c
@@ -123,26 +123,6 @@ static u8 pdc202xx_ratemask (ide_drive_t *drive)
return mode;
}
-static int check_in_drive_lists (ide_drive_t *drive, const char **list)
-{
- struct hd_driveid *id = drive->id;
-
- if (pdc_quirk_drives == list) {
- while (*list) {
- if (strstr(id->model, *list++)) {
- return 2;
- }
- }
- } else {
- while (*list) {
- if (!strcmp(*list++,id->model)) {
- return 1;
- }
- }
- }
- return 0;
-}
-
static int pdc202xx_tune_chipset (ide_drive_t *drive, u8 xferspeed)
{
ide_hwif_t *hwif = HWIF(drive);
@@ -377,7 +357,12 @@ fast_ata_pio:
static int pdc202xx_quirkproc (ide_drive_t *drive)
{
- return ((int) check_in_drive_lists(drive, pdc_quirk_drives));
+ const char **list, *model = drive->id->model;
+
+ for (list = pdc_quirk_drives; *list != NULL; list++)
+ if (strstr(model, *list) != NULL)
+ return 2;
+ return 0;
}
static void pdc202xx_old_ide_dma_start(ide_drive_t *drive)
diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c
index edb37f3d558..52cfc2ac22c 100644
--- a/drivers/ide/pci/piix.c
+++ b/drivers/ide/pci/piix.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/ide/pci/piix.c Version 0.45 May 12, 2006
+ * linux/drivers/ide/pci/piix.c Version 0.46 December 3, 2006
*
* Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
* Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
@@ -163,7 +163,7 @@ static u8 piix_ratemask (ide_drive_t *drive)
* if the drive cannot see an 80pin cable.
*/
if (!eighty_ninty_three(drive))
- mode = min(mode, (u8)1);
+ mode = min_t(u8, mode, 1);
return mode;
}
@@ -216,7 +216,7 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
- int is_slave = (&hwif->drives[1] == drive);
+ int is_slave = drive->dn & 1;
int master_port = hwif->channel ? 0x42 : 0x40;
int slave_port = 0x44;
unsigned long flags;
@@ -225,7 +225,7 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio)
static DEFINE_SPINLOCK(tune_lock);
int control = 0;
- /* ISP RTC */
+ /* ISP RTC */
static const u8 timings[][2]= {
{ 0, 0 },
{ 0, 0 },
@@ -233,7 +233,7 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio)
{ 2, 1 },
{ 2, 3 }, };
- pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+ pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
/*
* Master vs slave is synchronized above us but the slave register is
@@ -243,25 +243,24 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio)
spin_lock_irqsave(&tune_lock, flags);
pci_read_config_word(dev, master_port, &master_data);
- if (pio >= 2)
+ if (pio > 1)
control |= 1; /* Programmable timing on */
if (drive->media == ide_disk)
control |= 4; /* Prefetch, post write */
- if (pio >= 3)
+ if (pio > 2)
control |= 2; /* IORDY */
if (is_slave) {
- master_data = master_data | 0x4000;
+ master_data |= 0x4000;
+ master_data &= ~0x0070;
if (pio > 1) {
/* enable PPE, IE and TIME */
master_data = master_data | (control << 4);
- } else {
- master_data &= ~0x0070;
}
pci_read_config_byte(dev, slave_port, &slave_data);
slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0);
slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0));
} else {
- master_data = master_data & 0xccf8;
+ master_data &= ~0x3307;
if (pio > 1) {
/* enable PPE, IE and TIME */
master_data = master_data | control;
@@ -539,13 +538,19 @@ static ide_pci_device_t piix_pci_info[] __devinitdata = {
/* 0 */ DECLARE_PIIX_DEV("PIIXa"),
/* 1 */ DECLARE_PIIX_DEV("PIIXb"),
- { /* 2 */
+ /* 2 */
+ { /*
+ * MPIIX actually has only a single IDE channel mapped to
+ * the primary or secondary ports depending on the value
+ * of the bit 14 of the IDETIM register at offset 0x6c
+ */
.name = "MPIIX",
.init_hwif = init_hwif_piix,
.channels = 2,
.autodma = NODMA,
- .enablebits = {{0x6D,0x80,0x80}, {0x6F,0x80,0x80}},
+ .enablebits = {{0x6d,0xc0,0x80}, {0x6d,0xc0,0xc0}},
.bootable = ON_BOARD,
+ .flags = IDEPCI_FLAG_ISA_PORTS
},
/* 3 */ DECLARE_PIIX_DEV("PIIX3"),
diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c
index 90e79c0844d..2663ddbd9b6 100644
--- a/drivers/ide/pci/slc90e66.c
+++ b/drivers/ide/pci/slc90e66.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/ide/pci/slc90e66.c Version 0.12 May 12, 2006
+ * linux/drivers/ide/pci/slc90e66.c Version 0.13 December 30, 2006
*
* Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org>
* Copyright (C) 2006 MontaVista Software, Inc. <source@mvista.com>
@@ -26,7 +26,7 @@ static u8 slc90e66_ratemask (ide_drive_t *drive)
u8 mode = 2;
if (!eighty_ninty_three(drive))
- mode = min(mode, (u8)1);
+ mode = min_t(u8, mode, 1);
return mode;
}
@@ -65,36 +65,47 @@ static void slc90e66_tune_drive (ide_drive_t *drive, u8 pio)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
- int is_slave = (&hwif->drives[1] == drive);
+ int is_slave = drive->dn & 1;
int master_port = hwif->channel ? 0x42 : 0x40;
int slave_port = 0x44;
unsigned long flags;
u16 master_data;
u8 slave_data;
- /* ISP RTC */
+ int control = 0;
+ /* ISP RTC */
static const u8 timings[][2]= {
- { 0, 0 },
- { 0, 0 },
- { 1, 0 },
- { 2, 1 },
- { 2, 3 }, };
+ { 0, 0 },
+ { 0, 0 },
+ { 1, 0 },
+ { 2, 1 },
+ { 2, 3 }, };
- pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+ pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
spin_lock_irqsave(&ide_lock, flags);
pci_read_config_word(dev, master_port, &master_data);
+
+ if (pio > 1)
+ control |= 1; /* Programmable timing on */
+ if (drive->media == ide_disk)
+ control |= 4; /* Prefetch, post write */
+ if (pio > 2)
+ control |= 2; /* IORDY */
if (is_slave) {
- master_data = master_data | 0x4000;
- if (pio > 1)
+ master_data |= 0x4000;
+ master_data &= ~0x0070;
+ if (pio > 1) {
/* enable PPE, IE and TIME */
- master_data = master_data | 0x0070;
+ master_data = master_data | (control << 4);
+ }
pci_read_config_byte(dev, slave_port, &slave_data);
slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0);
slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0));
} else {
- master_data = master_data & 0xccf8;
- if (pio > 1)
+ master_data &= ~0x3307;
+ if (pio > 1) {
/* enable PPE, IE and TIME */
- master_data = master_data | 0x0007;
+ master_data = master_data | control;
+ }
master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8);
}
pci_write_config_word(dev, master_port, master_data);
@@ -173,7 +184,7 @@ static int slc90e66_config_drive_xfer_rate (ide_drive_t *drive)
drive->init_speed = 0;
- if (id && (id->capability & 1) && drive->autodma) {
+ if ((id->capability & 1) && drive->autodma) {
if (ide_use_dma(drive) && slc90e66_config_drive_for_dma(drive))
return hwif->ide_dma_on(drive);
@@ -201,7 +212,7 @@ static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif)
hwif->irq = hwif->channel ? 15 : 14;
hwif->speedproc = &slc90e66_tune_chipset;
- hwif->tuneproc = &slc90e66_tune_drive;
+ hwif->tuneproc = &slc90e66_tune_drive;
pci_read_config_byte(hwif->pci_dev, 0x47, &reg47);
@@ -213,14 +224,16 @@ static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif)
hwif->atapi_dma = 1;
hwif->ultra_mask = 0x1f;
- hwif->mwdma_mask = 0x07;
- hwif->swdma_mask = 0x07;
+ hwif->mwdma_mask = 0x06;
+ hwif->swdma_mask = 0x04;
- if (!(hwif->udma_four))
+ if (!hwif->udma_four) {
/* bit[0(1)]: 0:80, 1:40 */
hwif->udma_four = (reg47 & mask) ? 0 : 1;
+ }
hwif->ide_dma_check = &slc90e66_config_drive_xfer_rate;
+
if (!noautodma)
hwif->autodma = 1;
hwif->drives[0].autodma = hwif->autodma;
diff --git a/drivers/ide/pci/tc86c001.c b/drivers/ide/pci/tc86c001.c
new file mode 100644
index 00000000000..2ad72bbda34
--- /dev/null
+++ b/drivers/ide/pci/tc86c001.c
@@ -0,0 +1,309 @@
+/*
+ * drivers/ide/pci/tc86c001.c Version 1.00 Dec 12, 2006
+ *
+ * Copyright (C) 2002 Toshiba Corporation
+ * Copyright (C) 2005-2006 MontaVista Software, Inc. <source@mvista.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+static inline u8 tc86c001_ratemask(ide_drive_t *drive)
+{
+ return eighty_ninty_three(drive) ? 2 : 1;
+}
+
+static int tc86c001_tune_chipset(ide_drive_t *drive, u8 speed)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned long scr_port = hwif->config_data + (drive->dn ? 0x02 : 0x00);
+ u16 mode, scr = hwif->INW(scr_port);
+
+ speed = ide_rate_filter(tc86c001_ratemask(drive), speed);
+
+ switch (speed) {
+ case XFER_UDMA_4: mode = 0x00c0; break;
+ case XFER_UDMA_3: mode = 0x00b0; break;
+ case XFER_UDMA_2: mode = 0x00a0; break;
+ case XFER_UDMA_1: mode = 0x0090; break;
+ case XFER_UDMA_0: mode = 0x0080; break;
+ case XFER_MW_DMA_2: mode = 0x0070; break;
+ case XFER_MW_DMA_1: mode = 0x0060; break;
+ case XFER_MW_DMA_0: mode = 0x0050; break;
+ case XFER_PIO_4: mode = 0x0400; break;
+ case XFER_PIO_3: mode = 0x0300; break;
+ case XFER_PIO_2: mode = 0x0200; break;
+ case XFER_PIO_1: mode = 0x0100; break;
+ case XFER_PIO_0:
+ default: mode = 0x0000; break;
+ }
+
+ scr &= (speed < XFER_MW_DMA_0) ? 0xf8ff : 0xff0f;
+ scr |= mode;
+ hwif->OUTW(scr, scr_port);
+
+ return ide_config_drive_speed(drive, speed);
+}
+
+static void tc86c001_tune_drive(ide_drive_t *drive, u8 pio)
+{
+ pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+ (void) tc86c001_tune_chipset(drive, XFER_PIO_0 + pio);
+}
+
+/*
+ * HACKITY HACK
+ *
+ * This is a workaround for the limitation 5 of the TC86C001 IDE controller:
+ * if a DMA transfer terminates prematurely, the controller leaves the device's
+ * interrupt request (INTRQ) pending and does not generate a PCI interrupt (or
+ * set the interrupt bit in the DMA status register), thus no PCI interrupt
+ * will occur until a DMA transfer has been successfully completed.
+ *
+ * We work around this by initiating dummy, zero-length DMA transfer on
+ * a DMA timeout expiration. I found no better way to do this with the current
+ * IDE core than to temporarily replace a higher level driver's timer expiry
+ * handler with our own backing up to that handler in case our recovery fails.
+ */
+static int tc86c001_timer_expiry(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ ide_expiry_t *expiry = ide_get_hwifdata(hwif);
+ ide_hwgroup_t *hwgroup = HWGROUP(drive);
+ u8 dma_stat = hwif->INB(hwif->dma_status);
+
+ /* Restore a higher level driver's expiry handler first. */
+ hwgroup->expiry = expiry;
+
+ if ((dma_stat & 5) == 1) { /* DMA active and no interrupt */
+ unsigned long sc_base = hwif->config_data;
+ unsigned long twcr_port = sc_base + (drive->dn ? 0x06 : 0x04);
+ u8 dma_cmd = hwif->INB(hwif->dma_command);
+
+ printk(KERN_WARNING "%s: DMA interrupt possibly stuck, "
+ "attempting recovery...\n", drive->name);
+
+ /* Stop DMA */
+ hwif->OUTB(dma_cmd & ~0x01, hwif->dma_command);
+
+ /* Setup the dummy DMA transfer */
+ hwif->OUTW(0, sc_base + 0x0a); /* Sector Count */
+ hwif->OUTW(0, twcr_port); /* Transfer Word Count 1 or 2 */
+
+ /* Start the dummy DMA transfer */
+ hwif->OUTB(0x00, hwif->dma_command); /* clear R_OR_WCTR for write */
+ hwif->OUTB(0x01, hwif->dma_command); /* set START_STOPBM */
+
+ /*
+ * If an interrupt was pending, it should come thru shortly.
+ * If not, a higher level driver's expiry handler should
+ * eventually cause some kind of recovery from the DMA stall.
+ */
+ return WAIT_MIN_SLEEP;
+ }
+
+ /* Chain to the restored expiry handler if DMA wasn't active. */
+ if (likely(expiry != NULL))
+ return expiry(drive);
+
+ /* If there was no handler, "emulate" that for ide_timer_expiry()... */
+ return -1;
+}
+
+static void tc86c001_dma_start(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ ide_hwgroup_t *hwgroup = HWGROUP(drive);
+ unsigned long sc_base = hwif->config_data;
+ unsigned long twcr_port = sc_base + (drive->dn ? 0x06 : 0x04);
+ unsigned long nsectors = hwgroup->rq->nr_sectors;
+
+ /*
+ * We have to manually load the sector count and size into
+ * the appropriate system control registers for DMA to work
+ * with LBA48 and ATAPI devices...
+ */
+ hwif->OUTW(nsectors, sc_base + 0x0a); /* Sector Count */
+ hwif->OUTW(SECTOR_SIZE / 2, twcr_port); /* Transfer Word Count 1/2 */
+
+ /* Install our timeout expiry hook, saving the current handler... */
+ ide_set_hwifdata(hwif, hwgroup->expiry);
+ hwgroup->expiry = &tc86c001_timer_expiry;
+
+ ide_dma_start(drive);
+}
+
+static int tc86c001_busproc(ide_drive_t *drive, int state)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned long sc_base = hwif->config_data;
+ u16 scr1;
+
+ /* System Control 1 Register bit 11 (ATA Hard Reset) read */
+ scr1 = hwif->INW(sc_base + 0x00);
+
+ switch (state) {
+ case BUSSTATE_ON:
+ if (!(scr1 & 0x0800))
+ return 0;
+ scr1 &= ~0x0800;
+
+ hwif->drives[0].failures = hwif->drives[1].failures = 0;
+ break;
+ case BUSSTATE_OFF:
+ if (scr1 & 0x0800)
+ return 0;
+ scr1 |= 0x0800;
+
+ hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+ hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* System Control 1 Register bit 11 (ATA Hard Reset) write */
+ hwif->OUTW(scr1, sc_base + 0x00);
+ return 0;
+}
+
+static int config_chipset_for_dma(ide_drive_t *drive)
+{
+ u8 speed = ide_dma_speed(drive, tc86c001_ratemask(drive));
+
+ if (!speed)
+ return 0;
+
+ (void) tc86c001_tune_chipset(drive, speed);
+ return ide_dma_enable(drive);
+}
+
+static int tc86c001_config_drive_xfer_rate(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct hd_driveid *id = drive->id;
+
+ if ((id->capability & 1) && drive->autodma) {
+
+ if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+ return hwif->ide_dma_on(drive);
+
+ goto fast_ata_pio;
+
+ } else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+ tc86c001_tune_drive(drive, 255);
+ return hwif->ide_dma_off_quietly(drive);
+ }
+ /* IORDY not supported */
+ return 0;
+}
+
+static void __devinit init_hwif_tc86c001(ide_hwif_t *hwif)
+{
+ unsigned long sc_base = pci_resource_start(hwif->pci_dev, 5);
+ u16 scr1 = hwif->INW(sc_base + 0x00);;
+
+ /* System Control 1 Register bit 15 (Soft Reset) set */
+ hwif->OUTW(scr1 | 0x8000, sc_base + 0x00);
+
+ /* System Control 1 Register bit 14 (FIFO Reset) set */
+ hwif->OUTW(scr1 | 0x4000, sc_base + 0x00);
+
+ /* System Control 1 Register: reset clear */
+ hwif->OUTW(scr1 & ~0xc000, sc_base + 0x00);
+
+ /* Store the system control register base for convenience... */
+ hwif->config_data = sc_base;
+
+ hwif->tuneproc = &tc86c001_tune_drive;
+ hwif->speedproc = &tc86c001_tune_chipset;
+ hwif->busproc = &tc86c001_busproc;
+
+ hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+
+ if (!hwif->dma_base)
+ return;
+
+ /*
+ * Sector Count Control Register bits 0 and 1 set:
+ * software sets Sector Count Register for master and slave device
+ */
+ hwif->OUTW(0x0003, sc_base + 0x0c);
+
+ /* Sector Count Register limit */
+ hwif->rqsize = 0xffff;
+
+ hwif->atapi_dma = 1;
+ hwif->ultra_mask = 0x1f;
+ hwif->mwdma_mask = 0x07;
+
+ hwif->ide_dma_check = &tc86c001_config_drive_xfer_rate;
+ hwif->dma_start = &tc86c001_dma_start;
+
+ if (!hwif->udma_four) {
+ /*
+ * System Control 1 Register bit 13 (PDIAGN):
+ * 0=80-pin cable, 1=40-pin cable
+ */
+ scr1 = hwif->INW(sc_base + 0x00);
+ hwif->udma_four = (scr1 & 0x2000) ? 0 : 1;
+ }
+
+ if (!noautodma)
+ hwif->autodma = 1;
+ hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
+}
+
+static unsigned int __devinit init_chipset_tc86c001(struct pci_dev *dev,
+ const char *name)
+{
+ int err = pci_request_region(dev, 5, name);
+
+ if (err)
+ printk(KERN_ERR "%s: system control regs already in use", name);
+ return err;
+}
+
+static ide_pci_device_t tc86c001_chipset __devinitdata = {
+ .name = "TC86C001",
+ .init_chipset = init_chipset_tc86c001,
+ .init_hwif = init_hwif_tc86c001,
+ .channels = 1,
+ .autodma = AUTODMA,
+ .bootable = OFF_BOARD
+};
+
+static int __devinit tc86c001_init_one(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ return ide_setup_pci_device(dev, &tc86c001_chipset);
+}
+
+static struct pci_device_id tc86c001_pci_tbl[] = {
+ { PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, tc86c001_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "TC86C001",
+ .id_table = tc86c001_pci_tbl,
+ .probe = tc86c001_init_one
+};
+
+static int __init tc86c001_ide_init(void)
+{
+ return ide_pci_register_driver(&driver);
+}
+module_init(tc86c001_ide_init);
+
+MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
+MODULE_DESCRIPTION("PCI driver module for TC86C001 IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c
index 695e23904d3..a52c80fe7d3 100644
--- a/drivers/ide/setup-pci.c
+++ b/drivers/ide/setup-pci.c
@@ -783,10 +783,11 @@ static LIST_HEAD(ide_pci_drivers);
* Returns are the same as for pci_register_driver
*/
-int __ide_pci_register_driver(struct pci_driver *driver, struct module *module)
+int __ide_pci_register_driver(struct pci_driver *driver, struct module *module,
+ const char *mod_name)
{
if(!pre_init)
- return __pci_register_driver(driver, module);
+ return __pci_register_driver(driver, module, mod_name);
driver->driver.owner = module;
list_add_tail(&driver->node, &ide_pci_drivers);
return 0;
@@ -862,6 +863,6 @@ void __init ide_scan_pcibus (int scan_direction)
{
list_del(l);
d = list_entry(l, struct pci_driver, node);
- __pci_register_driver(d, d->driver.owner);
+ __pci_register_driver(d, d->driver.owner, d->driver.mod_name);
}
}
diff --git a/drivers/ieee1394/.gitignore b/drivers/ieee1394/.gitignore
deleted file mode 100644
index 33da10a2532..00000000000
--- a/drivers/ieee1394/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-oui.c
diff --git a/drivers/ieee1394/Kconfig b/drivers/ieee1394/Kconfig
index e7d56573fe5..b8a47342cd2 100644
--- a/drivers/ieee1394/Kconfig
+++ b/drivers/ieee1394/Kconfig
@@ -35,20 +35,6 @@ config IEEE1394_VERBOSEDEBUG
Say Y if you really want or need the debugging output, everyone
else says N.
-config IEEE1394_OUI_DB
- bool "OUI Database built-in (deprecated)"
- depends on IEEE1394
- help
- If you say Y here, then an OUI list (vendor unique ID's) will be
- compiled into the ieee1394 module. This doesn't really do much
- except being able to display the vendor of a hardware node. The
- downside is that it adds about 300k to the size of the module,
- or kernel (depending on whether you compile ieee1394 as a
- module, or static in the kernel).
-
- This option is not needed for userspace programs like gscanbus
- to show this information.
-
config IEEE1394_EXTRA_CONFIG_ROMS
bool "Build in extra config rom entries for certain functionality"
depends on IEEE1394
@@ -66,13 +52,6 @@ config IEEE1394_CONFIG_ROM_IP1394
with MacOSX and WinXP IP-over-1394), enable this option and the
eth1394 option below.
-config IEEE1394_EXPORT_FULL_API
- bool "Export all symbols of ieee1394's API (deprecated)"
- depends on IEEE1394
- default n
- help
- This option will be removed soon. Don't worry, say N.
-
comment "Device Drivers"
depends on IEEE1394
diff --git a/drivers/ieee1394/Makefile b/drivers/ieee1394/Makefile
index d9650d3d77a..489c133664d 100644
--- a/drivers/ieee1394/Makefile
+++ b/drivers/ieee1394/Makefile
@@ -5,9 +5,6 @@
ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \
highlevel.o csr.o nodemgr.o dma.o iso.o \
csr1212.o config_roms.o
-ifdef CONFIG_IEEE1394_OUI_DB
-ieee1394-objs += oui.o
-endif
obj-$(CONFIG_IEEE1394) += ieee1394.o
obj-$(CONFIG_IEEE1394_PCILYNX) += pcilynx.o
@@ -18,10 +15,3 @@ obj-$(CONFIG_IEEE1394_SBP2) += sbp2.o
obj-$(CONFIG_IEEE1394_DV1394) += dv1394.o
obj-$(CONFIG_IEEE1394_ETH1394) += eth1394.o
-quiet_cmd_oui2c = OUI2C $@
- cmd_oui2c = $(CONFIG_SHELL) $(srctree)/$(src)/oui2c.sh < $< > $@
-
-targets := oui.c
-$(obj)/oui.o: $(obj)/oui.c
-$(obj)/oui.c: $(src)/oui.db $(src)/oui2c.sh FORCE
- $(call if_changed,oui2c)
diff --git a/drivers/ieee1394/csr1212.c b/drivers/ieee1394/csr1212.c
index 586f71e7346..c28f639823d 100644
--- a/drivers/ieee1394/csr1212.c
+++ b/drivers/ieee1394/csr1212.c
@@ -47,14 +47,14 @@
#define __D (1 << CSR1212_KV_TYPE_DIRECTORY)
#define __L (1 << CSR1212_KV_TYPE_LEAF)
static const u_int8_t csr1212_key_id_type_map[0x30] = {
- 0, /* Reserved */
+ __C, /* used by Apple iSight */
__D | __L, /* Descriptor */
__I | __D | __L, /* Bus_Dependent_Info */
__I | __D | __L, /* Vendor */
__I, /* Hardware_Version */
0, 0, /* Reserved */
- __D | __L, /* Module */
- 0, 0, 0, 0, /* Reserved */
+ __D | __L | __I, /* Module */
+ __I, 0, 0, 0, /* used by Apple iSight, Reserved */
__I, /* Node_Capabilities */
__L, /* EUI_64 */
0, 0, 0, /* Reserved */
@@ -1234,6 +1234,12 @@ static int csr1212_parse_bus_info_block(struct csr1212_csr *csr)
csr->private);
if (ret != CSR1212_SUCCESS)
return ret;
+
+ /* check ROM header's info_length */
+ if (i == 0 &&
+ CSR1212_BE32_TO_CPU(csr->cache_head->data[0]) >> 24 !=
+ bytes_to_quads(csr->bus_info_len) - 1)
+ return CSR1212_EINVAL;
}
bi = (struct csr1212_bus_info_block_img*)csr->cache_head->data;
@@ -1250,9 +1256,6 @@ static int csr1212_parse_bus_info_block(struct csr1212_csr *csr)
return ret;
}
- if (bytes_to_quads(csr->bus_info_len - sizeof(csr1212_quad_t)) != bi->length)
- return CSR1212_EINVAL;
-
#if 0
/* Apparently there are too many differnt wrong implementations of the
* CRC algorithm that verifying them is moot. */
diff --git a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c
index 1084da4d88a..55d6ae664fd 100644
--- a/drivers/ieee1394/dv1394.c
+++ b/drivers/ieee1394/dv1394.c
@@ -2255,49 +2255,37 @@ static int dv1394_init(struct ti_ohci *ohci, enum pal_or_ntsc format, enum modes
return 0;
}
-static void dv1394_un_init(struct video_card *video)
+static void dv1394_remove_host(struct hpsb_host *host)
{
- /* obviously nobody has the driver open at this point */
- do_dv1394_shutdown(video, 1);
- kfree(video);
-}
-
-
-static void dv1394_remove_host (struct hpsb_host *host)
-{
- struct video_card *video;
+ struct video_card *video, *tmp_video;
unsigned long flags;
- int id = host->id;
+ int found_ohci_card = 0;
- /* We only work with the OHCI-1394 driver */
- if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
- return;
-
- /* find the corresponding video_cards */
do {
- struct video_card *tmp_vid;
-
video = NULL;
-
spin_lock_irqsave(&dv1394_cards_lock, flags);
- list_for_each_entry(tmp_vid, &dv1394_cards, list) {
- if ((tmp_vid->id >> 2) == id) {
- list_del(&tmp_vid->list);
- video = tmp_vid;
+ list_for_each_entry(tmp_video, &dv1394_cards, list) {
+ if ((tmp_video->id >> 2) == host->id) {
+ list_del(&tmp_video->list);
+ video = tmp_video;
+ found_ohci_card = 1;
break;
}
}
spin_unlock_irqrestore(&dv1394_cards_lock, flags);
- if (video)
- dv1394_un_init(video);
- } while (video != NULL);
+ if (video) {
+ do_dv1394_shutdown(video, 1);
+ kfree(video);
+ }
+ } while (video);
- class_device_destroy(hpsb_protocol_class,
- MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_DV1394 * 16 + (id<<2)));
+ if (found_ohci_card)
+ class_device_destroy(hpsb_protocol_class, MKDEV(IEEE1394_MAJOR,
+ IEEE1394_MINOR_BLOCK_DV1394 * 16 + (host->id << 2)));
}
-static void dv1394_add_host (struct hpsb_host *host)
+static void dv1394_add_host(struct hpsb_host *host)
{
struct ti_ohci *ohci;
int id = host->id;
diff --git a/drivers/ieee1394/hosts.c b/drivers/ieee1394/hosts.c
index ee82a5320bf..32a13092193 100644
--- a/drivers/ieee1394/hosts.c
+++ b/drivers/ieee1394/hosts.c
@@ -190,14 +190,19 @@ int hpsb_add_host(struct hpsb_host *host)
{
if (hpsb_default_host_entry(host))
return -ENOMEM;
-
hpsb_add_extra_config_roms(host);
-
highlevel_add_host(host);
-
return 0;
}
+void hpsb_resume_host(struct hpsb_host *host)
+{
+ if (host->driver->set_hw_config_rom)
+ host->driver->set_hw_config_rom(host,
+ host->csr.rom->bus_info_data);
+ host->driver->devctl(host, RESET_BUS, SHORT_RESET);
+}
+
void hpsb_remove_host(struct hpsb_host *host)
{
host->is_shutdown = 1;
@@ -206,9 +211,7 @@ void hpsb_remove_host(struct hpsb_host *host)
flush_scheduled_work();
host->driver = &dummy_driver;
-
highlevel_remove_host(host);
-
hpsb_remove_extra_config_roms(host);
class_device_unregister(&host->class_dev);
diff --git a/drivers/ieee1394/hosts.h b/drivers/ieee1394/hosts.h
index d553e38c954..4bf4fb7f67b 100644
--- a/drivers/ieee1394/hosts.h
+++ b/drivers/ieee1394/hosts.h
@@ -61,9 +61,9 @@ struct hpsb_host {
struct device device;
struct class_device class_dev;
- int update_config_rom;
struct delayed_work delayed_reset;
- unsigned int config_roms;
+ unsigned config_roms:31;
+ unsigned update_config_rom:1;
struct list_head addr_space;
u64 low_addr_space; /* upper bound of physical DMA area */
@@ -200,7 +200,8 @@ struct hpsb_host_driver {
struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra,
struct device *dev);
int hpsb_add_host(struct hpsb_host *host);
-void hpsb_remove_host(struct hpsb_host *h);
+void hpsb_resume_host(struct hpsb_host *host);
+void hpsb_remove_host(struct hpsb_host *host);
/* Updates the configuration rom image of a host. rom_version must be the
* current version, otherwise it will fail with return value -1. If this
diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c
index 9a48ca20d1f..1521e57e124 100644
--- a/drivers/ieee1394/ieee1394_core.c
+++ b/drivers/ieee1394/ieee1394_core.c
@@ -1178,6 +1178,7 @@ module_exit(ieee1394_cleanup);
/** hosts.c **/
EXPORT_SYMBOL(hpsb_alloc_host);
EXPORT_SYMBOL(hpsb_add_host);
+EXPORT_SYMBOL(hpsb_resume_host);
EXPORT_SYMBOL(hpsb_remove_host);
EXPORT_SYMBOL(hpsb_update_config_rom_image);
@@ -1195,10 +1196,6 @@ EXPORT_SYMBOL(hpsb_selfid_complete);
EXPORT_SYMBOL(hpsb_packet_sent);
EXPORT_SYMBOL(hpsb_packet_received);
EXPORT_SYMBOL_GPL(hpsb_disable_irm);
-#ifdef CONFIG_IEEE1394_EXPORT_FULL_API
-EXPORT_SYMBOL(hpsb_send_phy_config);
-EXPORT_SYMBOL(hpsb_send_packet_and_wait);
-#endif
/** ieee1394_transactions.c **/
EXPORT_SYMBOL(hpsb_get_tlabel);
@@ -1229,20 +1226,12 @@ EXPORT_SYMBOL(hpsb_set_hostinfo_key);
EXPORT_SYMBOL(hpsb_get_hostinfo_bykey);
EXPORT_SYMBOL(hpsb_set_hostinfo);
EXPORT_SYMBOL(highlevel_host_reset);
-#ifdef CONFIG_IEEE1394_EXPORT_FULL_API
-EXPORT_SYMBOL(highlevel_add_host);
-EXPORT_SYMBOL(highlevel_remove_host);
-#endif
/** nodemgr.c **/
EXPORT_SYMBOL(hpsb_node_fill_packet);
EXPORT_SYMBOL(hpsb_node_write);
EXPORT_SYMBOL(__hpsb_register_protocol);
EXPORT_SYMBOL(hpsb_unregister_protocol);
-#ifdef CONFIG_IEEE1394_EXPORT_FULL_API
-EXPORT_SYMBOL(ieee1394_bus_type);
-EXPORT_SYMBOL(nodemgr_for_each_host);
-#endif
/** csr.c **/
EXPORT_SYMBOL(hpsb_update_config_rom);
@@ -1287,13 +1276,3 @@ EXPORT_SYMBOL(csr1212_read);
EXPORT_SYMBOL(csr1212_parse_keyval);
EXPORT_SYMBOL(_csr1212_read_keyval);
EXPORT_SYMBOL(_csr1212_destroy_keyval);
-#ifdef CONFIG_IEEE1394_EXPORT_FULL_API
-EXPORT_SYMBOL(csr1212_create_csr);
-EXPORT_SYMBOL(csr1212_init_local_csr);
-EXPORT_SYMBOL(csr1212_new_immediate);
-EXPORT_SYMBOL(csr1212_associate_keyval);
-EXPORT_SYMBOL(csr1212_new_string_descriptor_leaf);
-EXPORT_SYMBOL(csr1212_destroy_csr);
-EXPORT_SYMBOL(csr1212_generate_csr_image);
-EXPORT_SYMBOL(csr1212_parse_csr);
-#endif
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
index 61307ca296a..ba9faeff479 100644
--- a/drivers/ieee1394/nodemgr.c
+++ b/drivers/ieee1394/nodemgr.c
@@ -41,22 +41,6 @@ struct nodemgr_csr_info {
};
-static char *nodemgr_find_oui_name(int oui)
-{
-#ifdef CONFIG_IEEE1394_OUI_DB
- extern struct oui_list_struct {
- int oui;
- char *name;
- } oui_list[];
- int i;
-
- for (i = 0; oui_list[i].name; i++)
- if (oui_list[i].oui == oui)
- return oui_list[i].name;
-#endif
- return NULL;
-}
-
/*
* Correct the speed map entry. This is necessary
* - for nodes with link speed < phy speed,
@@ -274,7 +258,6 @@ static struct device_driver nodemgr_mid_layer_driver = {
struct device nodemgr_dev_template_host = {
.bus = &ieee1394_bus_type,
.release = nodemgr_release_host,
- .driver = &nodemgr_mid_layer_driver,
};
@@ -473,11 +456,9 @@ fw_attr(ne, struct node_entry, nodeid, unsigned int, "0x%04x\n")
fw_attr(ne, struct node_entry, vendor_id, unsigned int, "0x%06x\n")
fw_attr_td(ne, struct node_entry, vendor_name_kv)
-fw_attr(ne, struct node_entry, vendor_oui, const char *, "%s\n")
fw_attr(ne, struct node_entry, guid, unsigned long long, "0x%016Lx\n")
fw_attr(ne, struct node_entry, guid_vendor_id, unsigned int, "0x%06x\n")
-fw_attr(ne, struct node_entry, guid_vendor_oui, const char *, "%s\n")
fw_attr(ne, struct node_entry, in_limbo, int, "%d\n");
static struct device_attribute *const fw_ne_attrs[] = {
@@ -503,7 +484,6 @@ fw_attr(ud, struct unit_directory, model_id, unsigned int, "0x%06x\n")
fw_attr(ud, struct unit_directory, specifier_id, unsigned int, "0x%06x\n")
fw_attr(ud, struct unit_directory, version, unsigned int, "0x%06x\n")
fw_attr_td(ud, struct unit_directory, vendor_name_kv)
-fw_attr(ud, struct unit_directory, vendor_oui, const char *, "%s\n")
fw_attr_td(ud, struct unit_directory, model_name_kv)
static struct device_attribute *const fw_ud_attrs[] = {
@@ -865,7 +845,6 @@ static struct node_entry *nodemgr_create_node(octlet_t guid, struct csr1212_csr
ne->guid = guid;
ne->guid_vendor_id = (guid >> 40) & 0xffffff;
- ne->guid_vendor_oui = nodemgr_find_oui_name(ne->guid_vendor_id);
ne->csr = csr;
memcpy(&ne->device, &nodemgr_dev_template_ne,
@@ -885,9 +864,6 @@ static struct node_entry *nodemgr_create_node(octlet_t guid, struct csr1212_csr
goto fail_classdevreg;
get_device(&ne->device);
- if (ne->guid_vendor_oui &&
- device_create_file(&ne->device, &dev_attr_ne_guid_vendor_oui))
- goto fail_addoiu;
nodemgr_create_ne_dev_files(ne);
nodemgr_update_bus_options(ne);
@@ -898,8 +874,6 @@ static struct node_entry *nodemgr_create_node(octlet_t guid, struct csr1212_csr
return ne;
-fail_addoiu:
- put_device(&ne->device);
fail_classdevreg:
device_unregister(&ne->device);
fail_devreg:
@@ -975,15 +949,10 @@ static void nodemgr_register_device(struct node_entry *ne,
goto fail_classdevreg;
get_device(&ud->device);
- if (ud->vendor_oui &&
- device_create_file(&ud->device, &dev_attr_ud_vendor_oui))
- goto fail_addoui;
nodemgr_create_ud_dev_files(ud);
return;
-fail_addoui:
- put_device(&ud->device);
fail_classdevreg:
device_unregister(&ud->device);
fail_devreg:
@@ -1020,9 +989,6 @@ static struct unit_directory *nodemgr_process_unit_directory
if (kv->key.type == CSR1212_KV_TYPE_IMMEDIATE) {
ud->vendor_id = kv->value.immediate;
ud->flags |= UNIT_DIRECTORY_VENDOR_ID;
-
- if (ud->vendor_id)
- ud->vendor_oui = nodemgr_find_oui_name(ud->vendor_id);
}
break;
@@ -1153,9 +1119,6 @@ static void nodemgr_process_root_directory(struct host_info *hi, struct node_ent
switch (kv->key.id) {
case CSR1212_KV_ID_VENDOR:
ne->vendor_id = kv->value.immediate;
-
- if (ne->vendor_id)
- ne->vendor_oui = nodemgr_find_oui_name(ne->vendor_id);
break;
case CSR1212_KV_ID_NODE_CAPABILITIES:
@@ -1183,9 +1146,6 @@ static void nodemgr_process_root_directory(struct host_info *hi, struct node_ent
last_key_id = kv->key.id;
}
- if (ne->vendor_oui &&
- device_create_file(&ne->device, &dev_attr_ne_vendor_oui))
- goto fail;
if (ne->vendor_name_kv &&
device_create_file(&ne->device, &dev_attr_ne_vendor_name_kv))
goto fail;
@@ -1889,22 +1849,31 @@ int init_ieee1394_nodemgr(void)
error = class_register(&nodemgr_ne_class);
if (error)
- return error;
-
+ goto fail_ne;
error = class_register(&nodemgr_ud_class);
- if (error) {
- class_unregister(&nodemgr_ne_class);
- return error;
- }
+ if (error)
+ goto fail_ud;
error = driver_register(&nodemgr_mid_layer_driver);
+ if (error)
+ goto fail_ml;
+ /* This driver is not used if nodemgr is off (disable_nodemgr=1). */
+ nodemgr_dev_template_host.driver = &nodemgr_mid_layer_driver;
+
hpsb_register_highlevel(&nodemgr_highlevel);
return 0;
+
+fail_ml:
+ class_unregister(&nodemgr_ud_class);
+fail_ud:
+ class_unregister(&nodemgr_ne_class);
+fail_ne:
+ return error;
}
void cleanup_ieee1394_nodemgr(void)
{
hpsb_unregister_highlevel(&nodemgr_highlevel);
-
+ driver_unregister(&nodemgr_mid_layer_driver);
class_unregister(&nodemgr_ud_class);
class_unregister(&nodemgr_ne_class);
}
diff --git a/drivers/ieee1394/nodemgr.h b/drivers/ieee1394/nodemgr.h
index e25cbadb8be..4147303ad44 100644
--- a/drivers/ieee1394/nodemgr.h
+++ b/drivers/ieee1394/nodemgr.h
@@ -70,7 +70,6 @@ struct unit_directory {
quadlet_t vendor_id;
struct csr1212_keyval *vendor_name_kv;
- const char *vendor_oui;
quadlet_t model_id;
struct csr1212_keyval *model_name_kv;
@@ -93,7 +92,6 @@ struct unit_directory {
struct node_entry {
u64 guid; /* GUID of this node */
u32 guid_vendor_id; /* Top 24bits of guid */
- const char *guid_vendor_oui; /* OUI name of guid vendor id */
struct hpsb_host *host; /* Host this node is attached to */
nodeid_t nodeid; /* NodeID */
@@ -104,7 +102,6 @@ struct node_entry {
/* The following is read from the config rom */
u32 vendor_id;
struct csr1212_keyval *vendor_name_kv;
- const char *vendor_oui;
u32 capabilities;
diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c
index 628130a58af..5729e412cc4 100644
--- a/drivers/ieee1394/ohci1394.c
+++ b/drivers/ieee1394/ohci1394.c
@@ -3281,14 +3281,11 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev,
PRINT(KERN_WARNING, "PCI resource length of 0x%llx too small!",
(unsigned long long)pci_resource_len(dev, 0));
- /* Seems PCMCIA handles this internally. Not sure why. Seems
- * pretty bogus to force a driver to special case this. */
-#ifndef PCMCIA
- if (!request_mem_region (ohci_base, OHCI1394_REGISTER_SIZE, OHCI1394_DRIVER_NAME))
+ if (!request_mem_region(ohci_base, OHCI1394_REGISTER_SIZE,
+ OHCI1394_DRIVER_NAME))
FAIL(-ENOMEM, "MMIO resource (0x%llx - 0x%llx) unavailable",
(unsigned long long)ohci_base,
(unsigned long long)ohci_base + OHCI1394_REGISTER_SIZE);
-#endif
ohci->init_state = OHCI_INIT_HAVE_MEM_REGION;
ohci->registers = ioremap(ohci_base, OHCI1394_REGISTER_SIZE);
@@ -3509,10 +3506,8 @@ static void ohci1394_pci_remove(struct pci_dev *pdev)
iounmap(ohci->registers);
case OHCI_INIT_HAVE_MEM_REGION:
-#ifndef PCMCIA
release_mem_region(pci_resource_start(ohci->dev, 0),
OHCI1394_REGISTER_SIZE);
-#endif
#ifdef CONFIG_PPC_PMAC
/* On UniNorth, power down the cable and turn off the chip clock
@@ -3541,9 +3536,6 @@ static int ohci1394_pci_suspend(struct pci_dev *pdev, pm_message_t state)
int err;
struct ti_ohci *ohci = pci_get_drvdata(pdev);
- printk(KERN_INFO "%s does not fully support suspend and resume yet\n",
- OHCI1394_DRIVER_NAME);
-
if (!ohci) {
printk(KERN_ERR "%s: tried to suspend nonexisting host\n",
OHCI1394_DRIVER_NAME);
@@ -3630,15 +3622,14 @@ static int ohci1394_pci_resume(struct pci_dev *pdev)
mdelay(50);
ohci_initialize(ohci);
+ hpsb_resume_host(ohci->host);
return 0;
}
#endif /* CONFIG_PM */
-#define PCI_CLASS_FIREWIRE_OHCI ((PCI_CLASS_SERIAL_FIREWIRE << 8) | 0x10)
-
static struct pci_device_id ohci1394_pci_tbl[] = {
{
- .class = PCI_CLASS_FIREWIRE_OHCI,
+ .class = PCI_CLASS_SERIAL_FIREWIRE_OHCI,
.class_mask = PCI_ANY_ID,
.vendor = PCI_ANY_ID,
.device = PCI_ANY_ID,
diff --git a/drivers/ieee1394/oui.db b/drivers/ieee1394/oui.db
deleted file mode 100644
index 592c8a60d01..00000000000
--- a/drivers/ieee1394/oui.db
+++ /dev/null
@@ -1,7048 +0,0 @@
-000000 XEROX CORPORATION
-000001 XEROX CORPORATION
-000002 XEROX CORPORATION
-000003 XEROX CORPORATION
-000004 XEROX CORPORATION
-000005 XEROX CORPORATION
-000006 XEROX CORPORATION
-000007 XEROX CORPORATION
-000008 XEROX CORPORATION
-000009 XEROX CORPORATION
-00000A OMRON TATEISI ELECTRONICS CO.
-00000B MATRIX CORPORATION
-00000C CISCO SYSTEMS, INC.
-00000D FIBRONICS LTD.
-00000E FUJITSU LIMITED
-00000F NEXT, INC.
-000010 SYTEK INC.
-000011 NORMEREL SYSTEMES
-000012 INFORMATION TECHNOLOGY LIMITED
-000013 CAMEX
-000014 NETRONIX
-000015 DATAPOINT CORPORATION
-000016 DU PONT PIXEL SYSTEMS .
-000017 TEKELEC
-000018 WEBSTER COMPUTER CORPORATION
-000019 APPLIED DYNAMICS INTERNATIONAL
-00001A ADVANCED MICRO DEVICES
-00001B NOVELL INC.
-00001C BELL TECHNOLOGIES
-00001D CABLETRON SYSTEMS, INC.
-00001E TELSIST INDUSTRIA ELECTRONICA
-00001F Telco Systems, Inc.
-000020 DATAINDUSTRIER DIAB AB
-000021 SUREMAN COMP. & COMMUN. CORP.
-000022 VISUAL TECHNOLOGY INC.
-000023 ABB INDUSTRIAL SYSTEMS AB
-000024 CONNECT AS
-000025 RAMTEK CORP.
-000026 SHA-KEN CO., LTD.
-000027 JAPAN RADIO COMPANY
-000028 PRODIGY SYSTEMS CORPORATION
-000029 IMC NETWORKS CORP.
-00002A TRW - SEDD/INP
-00002B CRISP AUTOMATION, INC
-00002C AUTOTOTE LIMITED
-00002D CHROMATICS INC
-00002E SOCIETE EVIRA
-00002F TIMEPLEX INC.
-000030 VG LABORATORY SYSTEMS LTD
-000031 QPSX COMMUNICATIONS PTY LTD
-000032 Marconi plc
-000033 EGAN MACHINERY COMPANY
-000034 NETWORK RESOURCES CORPORATION
-000035 SPECTRAGRAPHICS CORPORATION
-000036 ATARI CORPORATION
-000037 OXFORD METRICS LIMITED
-000038 CSS LABS
-000039 TOSHIBA CORPORATION
-00003A CHYRON CORPORATION
-00003B i Controls, Inc.
-00003C AUSPEX SYSTEMS INC.
-00003D UNISYS
-00003E SIMPACT
-00003F SYNTREX, INC.
-000040 APPLICON, INC.
-000041 ICE CORPORATION
-000042 METIER MANAGEMENT SYSTEMS LTD.
-000043 MICRO TECHNOLOGY
-000044 CASTELLE CORPORATION
-000045 FORD AEROSPACE & COMM. CORP.
-000046 OLIVETTI NORTH AMERICA
-000047 NICOLET INSTRUMENTS CORP.
-000048 SEIKO EPSON CORPORATION
-000049 APRICOT COMPUTERS, LTD
-00004A ADC CODENOLL TECHNOLOGY CORP.
-00004B ICL DATA OY
-00004C NEC CORPORATION
-00004D DCI CORPORATION
-00004E AMPEX CORPORATION
-00004F LOGICRAFT, INC.
-000050 RADISYS CORPORATION
-000051 HOB ELECTRONIC GMBH & CO. KG
-000052 Intrusion.com, Inc.
-000053 COMPUCORP
-000054 MODICON, INC.
-000055 COMMISSARIAT A L`ENERGIE ATOM.
-000056 DR. B. STRUCK
-000057 SCITEX CORPORATION LTD.
-000058 RACORE COMPUTER PRODUCTS INC.
-000059 HELLIGE GMBH
-00005A SysKonnect GmbH
-00005B ELTEC ELEKTRONIK AG
-00005C TELEMATICS INTERNATIONAL INC.
-00005D CS TELECOM
-00005E USC INFORMATION SCIENCES INST
-00005F SUMITOMO ELECTRIC IND., LTD.
-000060 KONTRON ELEKTRONIK GMBH
-000061 GATEWAY COMMUNICATIONS
-000062 BULL HN INFORMATION SYSTEMS
-000063 DR.ING.SEUFERT GMBH
-000064 YOKOGAWA DIGITAL COMPUTER CORP
-000065 NETWORK ASSOCIATES, INC.
-000066 TALARIS SYSTEMS, INC.
-000067 SOFT * RITE, INC.
-000068 ROSEMOUNT CONTROLS
-000069 CONCORD COMMUNICATIONS INC
-00006A COMPUTER CONSOLES INC.
-00006B SILICON GRAPHICS INC./MIPS
-00006D CRAY COMMUNICATIONS, LTD.
-00006E ARTISOFT, INC.
-00006F Madge Ltd.
-000070 HCL LIMITED
-000071 ADRA SYSTEMS INC.
-000072 MINIWARE TECHNOLOGY
-000073 SIECOR CORPORATION
-000074 RICOH COMPANY LTD.
-000075 Nortel Networks
-000076 ABEKAS VIDEO SYSTEM
-000077 INTERPHASE CORPORATION
-000078 LABTAM LIMITED
-000079 NETWORTH INCORPORATED
-00007A DANA COMPUTER INC.
-00007B RESEARCH MACHINES
-00007C AMPERE INCORPORATED
-00007D SUN MICROSYSTEMS, INC.
-00007E CLUSTRIX CORPORATION
-00007F LINOTYPE-HELL AG
-000080 CRAY COMMUNICATIONS A/S
-000081 BAY NETWORKS
-000082 LECTRA SYSTEMES SA
-000083 TADPOLE TECHNOLOGY PLC
-000084 SUPERNET
-000085 CANON INC.
-000086 MEGAHERTZ CORPORATION
-000087 HITACHI, LTD.
-000088 COMPUTER NETWORK TECH. CORP.
-000089 CAYMAN SYSTEMS INC.
-00008A DATAHOUSE INFORMATION SYSTEMS
-00008B INFOTRON
-00008C Alloy Computer Products (Australia) Pty Ltd
-00008D VERDIX CORPORATION
-00008E SOLBOURNE COMPUTER, INC.
-00008F RAYTHEON COMPANY
-000090 MICROCOM
-000091 ANRITSU CORPORATION
-000092 COGENT DATA TECHNOLOGIES
-000093 PROTEON INC.
-000094 ASANTE TECHNOLOGIES
-000095 SONY TEKTRONIX CORP.
-000096 MARCONI ELECTRONICS LTD.
-000097 EPOCH SYSTEMS
-000098 CROSSCOMM CORPORATION
-000099 MTX, INC.
-00009A RC COMPUTER A/S
-00009B INFORMATION INTERNATIONAL, INC
-00009C ROLM MIL-SPEC COMPUTERS
-00009D LOCUS COMPUTING CORPORATION
-00009E MARLI S.A.
-00009F AMERISTAR TECHNOLOGIES INC.
-0000A0 TOKYO SANYO ELECTRIC CO. LTD.
-0000A1 MARQUETTE ELECTRIC CO.
-0000A2 BAY NETWORKS
-0000A3 NETWORK APPLICATION TECHNOLOGY
-0000A4 ACORN COMPUTERS LIMITED
-0000A5 COMPATIBLE SYSTEMS CORP.
-0000A6 NETWORK GENERAL CORPORATION
-0000A7 NETWORK COMPUTING DEVICES INC.
-0000A8 STRATUS COMPUTER INC.
-0000A9 NETWORK SYSTEMS CORP.
-0000AA XEROX CORPORATION
-0000AB LOGIC MODELING CORPORATION
-0000AC CONWARE COMPUTER CONSULTING
-0000AD BRUKER INSTRUMENTS INC.
-0000AE DASSAULT ELECTRONIQUE
-0000AF NUCLEAR DATA INSTRUMENTATION
-0000B0 RND-RAD NETWORK DEVICES
-0000B1 ALPHA MICROSYSTEMS INC.
-0000B2 TELEVIDEO SYSTEMS, INC.
-0000B3 CIMLINC INCORPORATED
-0000B4 EDIMAX COMPUTER COMPANY
-0000B5 DATABILITY SOFTWARE SYS. INC.
-0000B6 MICRO-MATIC RESEARCH
-0000B7 DOVE COMPUTER CORPORATION
-0000B8 SEIKOSHA CO., LTD.
-0000B9 MCDONNELL DOUGLAS COMPUTER SYS
-0000BA SIIG, INC.
-0000BB TRI-DATA
-0000BC ALLEN-BRADLEY CO. INC.
-0000BD MITSUBISHI CABLE COMPANY
-0000BE THE NTI GROUP
-0000BF SYMMETRIC COMPUTER SYSTEMS
-0000C0 WESTERN DIGITAL CORPORATION
-0000C1 Madge Ltd.
-0000C2 INFORMATION PRESENTATION TECH.
-0000C3 HARRIS CORP COMPUTER SYS DIV
-0000C4 WATERS DIV. OF MILLIPORE
-0000C5 FARALLON COMPUTING/NETOPIA
-0000C6 EON SYSTEMS
-0000C7 ARIX CORPORATION
-0000C8 ALTOS COMPUTER SYSTEMS
-0000C9 EMULEX CORPORATION
-0000CA APPLITEK
-0000CB COMPU-SHACK ELECTRONIC GMBH
-0000CC DENSAN CO., LTD.
-0000CD Allied Telesyn Research Ltd.
-0000CE MEGADATA CORP.
-0000CF HAYES MICROCOMPUTER PRODUCTS
-0000D0 DEVELCON ELECTRONICS LTD.
-0000D1 ADAPTEC INCORPORATED
-0000D2 SBE, INC.
-0000D3 WANG LABORATORIES INC.
-0000D4 PURE DATA LTD.
-0000D5 MICROGNOSIS INTERNATIONAL
-0000D6 PUNCH LINE HOLDING
-0000D7 DARTMOUTH COLLEGE
-0000D8 NOVELL, INC.
-0000D9 NIPPON TELEGRAPH & TELEPHONE
-0000DA ATEX
-0000DB BRITISH TELECOMMUNICATIONS PLC
-0000DC HAYES MICROCOMPUTER PRODUCTS
-0000DD TCL INCORPORATED
-0000DE CETIA
-0000DF BELL & HOWELL PUB SYS DIV
-0000E0 QUADRAM CORP.
-0000E1 GRID SYSTEMS
-0000E2 ACER TECHNOLOGIES CORP.
-0000E3 INTEGRATED MICRO PRODUCTS LTD
-0000E4 IN2 GROUPE INTERTECHNIQUE
-0000E5 SIGMEX LTD.
-0000E6 APTOR PRODUITS DE COMM INDUST
-0000E7 STAR GATE TECHNOLOGIES
-0000E8 ACCTON TECHNOLOGY CORP.
-0000E9 ISICAD, INC.
-0000EA UPNOD AB
-0000EB MATSUSHITA COMM. IND. CO. LTD.
-0000EC MICROPROCESS
-0000ED APRIL
-0000EE NETWORK DESIGNERS, LTD.
-0000EF KTI
-0000F0 SAMSUNG ELECTRONICS CO., LTD.
-0000F1 MAGNA COMPUTER CORPORATION
-0000F2 SPIDER COMMUNICATIONS
-0000F3 GANDALF DATA LIMITED
-0000F4 ALLIED TELESYN INTERNATIONAL
-0000F5 DIAMOND SALES LIMITED
-0000F6 APPLIED MICROSYSTEMS CORP.
-0000F7 YOUTH KEEP ENTERPRISE CO LTD
-0000F8 DIGITAL EQUIPMENT CORPORATION
-0000F9 QUOTRON SYSTEMS INC.
-0000FA MICROSAGE COMPUTER SYSTEMS INC
-0000FB RECHNER ZUR KOMMUNIKATION
-0000FC MEIKO
-0000FD HIGH LEVEL HARDWARE
-0000FE ANNAPOLIS MICRO SYSTEMS
-0000FF CAMTEC ELECTRONICS LTD.
-000100 EQUIP'TRANS
-000102 3COM CORPORATION
-000103 3COM CORPORATION
-000104 DVICO Co., Ltd.
-000105 BECKHOFF GmbH
-000106 Tews Datentechnik GmbH
-000107 Leiser GmbH
-000108 AVLAB Technology, Inc.
-000109 Nagano Japan Radio Co., Ltd.
-00010A CIS TECHNOLOGY INC.
-00010B Space CyberLink, Inc.
-00010C System Talks Inc.
-00010D CORECO, INC.
-00010E Bri-Link Technologies Co., Ltd
-00010F Nishan Systems, Inc.
-000110 Gotham Networks
-000111 iDigm Inc.
-000112 Shark Multimedia Inc.
-000113 OLYMPUS CORPORATION
-000114 KANDA TSUSHIN KOGYO CO., LTD.
-000115 EXTRATECH CORPORATION
-000116 Netspect Technologies, Inc.
-000117 CANAL +
-000118 EZ Digital Co., Ltd.
-000119 Action Controls Pty. Ltd.
-00011A EEH DataLink GmbH
-00011B Unizone Technologies, Inc.
-00011C Universal Talkware Corporation
-00011D Centillium Communications
-00011E Precidia Technologies, Inc.
-00011F RC Networks, Inc.
-000120 OSCILLOQUARTZ S.A.
-000121 RapidStream Inc.
-000122 Trend Communications, Ltd.
-000123 DIGITAL ELECTRONICS CORP.
-000124 Acer Incorporated
-000125 YAESU MUSEN CO., LTD.
-000126 PAC Labs
-000127 The OPEN Group Limited
-000128 EnjoyWeb, Inc.
-000129 DFI Inc.
-00012A Telematica Sistems Inteligente
-00012B TELENET Co., Ltd.
-00012C Aravox Technologies, Inc.
-00012D Komodo Technology
-00012E PC Partner Ltd.
-00012F Twinhead International Corp
-000130 Extreme Networks
-000131 Detection Systems, Inc.
-000132 Dranetz - BMI
-000133 KYOWA Electronic Instruments C
-000134 SIG Positec Systems AG
-000135 KDC Corp.
-000136 CyberTAN Technology, Inc.
-000137 IT Farm Corporation
-000138 XAVi Technologies Corp.
-000139 Point Multimedia Systems
-00013A SHELCAD COMMUNICATIONS, LTD.
-00013B BNA SYSTEMS
-00013C TIW SYSTEMS
-00013D RiscStation Ltd.
-00013E Ascom Tateco AB
-00013F Neighbor World Co., Ltd.
-000140 Sendtek Corporation
-000141 CABLE PRINT
-000142 Cisco Systems, Inc.
-000143 Cisco Systems, Inc.
-000144 Cereva Networks, Inc.
-000145 WINSYSTEMS, INC.
-000146 Tesco Controls, Inc.
-000147 Zhone Technologies
-000148 X-traWeb Inc.
-000149 T.D.T. Transfer Data Test GmbH
-00014A SONY COMPUTER SCIENCE LABS., I
-00014B Ennovate Networks, Inc.
-00014C Berkeley Process Control
-00014D Shin Kin Enterprises Co., Ltd
-00014E WIN Enterprises, Inc.
-00014F LUMINOUS Networks, Inc.
-000150 GILAT COMMUNICATIONS, LTD.
-000151 Ensemble Communications
-000152 CHROMATEK INC.
-000153 ARCHTEK TELECOM CORPORATION
-000154 G3M Corporation
-000155 Promise Technology, Inc.
-000156 FIREWIREDIRECT.COM, INC.
-000157 SYSWAVE CO., LTD
-000158 Electro Industries/Gauge Tech
-000159 S1 Corporation
-00015A Digital Video Broadcasting
-00015B ITALTEL S.p.A/RF-UP-I
-00015C CADANT INC.
-00015D Sun Microsystems, Inc
-00015E BEST TECHNOLOGY CO., LTD.
-00015F DIGITAL DESIGN GmbH
-000160 ELMEX Co., LTD.
-000161 Meta Machine Technology
-000162 Cygnet Technologies, Inc.
-000163 Cisco Systems, Inc.
-000164 Cisco Systems, Inc.
-000165 AirSwitch Corporation
-000166 TC GROUP A/S
-000167 HIOKI E.E. CORPORATION
-000168 VITANA CORPORATION
-000169 Celestix Networks Pte Ltd.
-00016A ALITEC
-00016B LightChip, Inc.
-00016C FOXCONN
-00016D CarrierComm Inc.
-00016E Conklin Corporation
-00016F HAITAI ELECTRONICS CO., LTD.
-000170 ESE Embedded System Engineer'g
-000171 Allied Data Technologies
-000172 TechnoLand Co., LTD.
-000173 JNI Corporation
-000174 CyberOptics Corporation
-000175 Radiant Communications Corp.
-000176 Orient Silver Enterprises
-000177 EDSL
-000178 MARGI Systems, Inc.
-000179 WIRELESS TECHNOLOGY, INC.
-00017A Chengdu Maipu Electric Industrial Co., Ltd.
-00017B Heidelberger Druckmaschinen AG
-00017C AG-E GmbH
-00017D ThermoQuest
-00017E ADTEK System Science Co., Ltd.
-00017F Experience Music Project
-000180 AOpen, Inc.
-000181 Nortel Networks
-000182 DICA TECHNOLOGIES AG
-000183 ANITE TELECOMS
-000184 SIEB & MEYER AG
-000185 Aloka Co., Ltd.
-000186 DISCH GmbH
-000187 i2SE GmbH
-000188 LXCO Technologies ag
-000189 Refraction Technology, Inc.
-00018A ROI COMPUTER AG
-00018B NetLinks Co., Ltd.
-00018C Mega Vision
-00018D AudeSi Technologies
-00018E Logitec Corporation
-00018F Kenetec, Inc.
-000190 SMK-M
-000191 SYRED Data Systems
-000192 Texas Digital Systems
-000193 Hanbyul Telecom Co., Ltd.
-000194 Capital Equipment Corporation
-000195 Sena Technologies, Inc.
-000196 Cisco Systems, Inc.
-000197 Cisco Systems, Inc.
-000198 Darim Vision
-000199 HeiSei Electronics
-00019A LEUNIG GmbH
-00019B Kyoto Microcomputer Co., Ltd.
-00019C JDS Uniphase Inc.
-00019D E-Control Systems, Inc.
-00019E ESS Technology, Inc.
-00019F Phonex Broadband
-0001A0 Infinilink Corporation
-0001A1 Mag-Tek, Inc.
-0001A2 Logical Co., Ltd.
-0001A3 GENESYS LOGIC, INC.
-0001A4 Microlink Corporation
-0001A5 Nextcomm, Inc.
-0001A6 Scientific-Atlanta Arcodan A/S
-0001A7 UNEX TECHNOLOGY CORPORATION
-0001A8 Welltech Computer Co., Ltd.
-0001A9 BMW AG
-0001AA Airspan Communications, Ltd.
-0001AB Main Street Networks
-0001AC Sitara Networks, Inc.
-0001AD Coach Master International d.b.a. CMI Worldwide, Inc.
-0001AE Trex Enterprises
-0001AF Motorola Computer Group
-0001B0 Fulltek Technology Co., Ltd.
-0001B1 General Bandwidth
-0001B2 Digital Processing Systems, Inc.
-0001B3 Precision Electronic Manufacturing
-0001B4 Wayport, Inc.
-0001B5 Turin Networks, Inc.
-0001B6 SAEJIN T&M Co., Ltd.
-0001B7 Centos, Inc.
-0001B8 Netsensity, Inc.
-0001B9 SKF Condition Monitoring
-0001BA IC-Net, Inc.
-0001BB Frequentis
-0001BC Brains Corporation
-0001BD Peterson Electro-Musical Products, Inc.
-0001BE Gigalink Co., Ltd.
-0001BF Teleforce Co., Ltd.
-0001C0 CompuLab, Ltd.
-0001C1 Vitesse Semiconductor Corporation
-0001C2 ARK Research Corp.
-0001C3 Acromag, Inc.
-0001C4 NeoWave, Inc.
-0001C5 Simpler Networks
-0001C6 Quarry Technologies
-0001C7 Cisco Systems, Inc.
-0001C8 THOMAS CONRAD CORP.
-0001C8 CONRAD CORP.
-0001C9 Cisco Systems, Inc.
-0001CA Geocast Network Systems, Inc.
-0001CB NetGame, Ltd.
-0001CC Japan Total Design Communication Co., Ltd.
-0001CD ARtem
-0001CE Custom Micro Products, Ltd.
-0001CF Alpha Data Parallel Systems, Ltd.
-0001D0 VitalPoint, Inc.
-0001D1 CoNet Communications, Inc.
-0001D2 MacPower Peripherals, Ltd.
-0001D3 PAXCOMM, Inc.
-0001D4 Leisure Time, Inc.
-0001D5 HAEDONG INFO & COMM CO., LTD
-0001D6 MAN Roland Druckmaschinen AG
-0001D7 F5 Networks, Inc.
-0001D8 Teltronics, Inc.
-0001D9 Sigma, Inc.
-0001DA WINCOMM Corporation
-0001DB Freecom Technologies GmbH
-0001DC Activetelco
-0001DD Avail Networks
-0001DE Trango Systems, Inc.
-0001DF ISDN Communications, Ltd.
-0001E0 Fast Systems, Inc.
-0001E1 Kinpo Electronics, Inc.
-0001E2 Ando Electric Corporation
-0001E3 Siemens AG
-0001E4 Sitera, Inc.
-0001E5 Supernet, Inc.
-0001E6 Hewlett-Packard Company
-0001E7 Hewlett-Packard Company
-0001E8 Force10 Networks, Inc.
-0001E9 Litton Marine Systems B.V.
-0001EA Cirilium Corp.
-0001EB C-COM Corporation
-0001EC Ericsson Group
-0001ED SETA Corp.
-0001EE Comtrol Europe, Ltd.
-0001EF Camtel Technology Corp.
-0001F0 Tridium, Inc.
-0001F1 Innovative Concepts, Inc.
-0001F2 Mark of the Unicorn, Inc.
-0001F3 QPS, Inc.
-0001F4 Enterasys Networks
-0001F5 ERIM S.A.
-0001F6 Association of Musical Electronics Industry
-0001F7 Image Display Systems, Inc.
-0001F8 Adherent Systems, Ltd.
-0001F9 TeraGlobal Communications Corp.
-0001FA HOROSCAS
-0001FB DoTop Technology, Inc.
-0001FC Keyence Corporation
-0001FD Digital Voice Systems, Inc.
-0001FE DIGITAL EQUIPMENT CORPORATION
-0001FF Data Direct Networks, Inc.
-000200 Net & Sys Co., Ltd.
-000201 IFM Electronic gmbh
-000202 Amino Communications, Ltd.
-000203 Woonsang Telecom, Inc.
-000204 Bodmann Industries Elektronik GmbH
-000205 Hitachi Denshi, Ltd.
-000206 Telital R&D Denmark A/S
-000207 VisionGlobal Network Corp.
-000208 Unify Networks, Inc.
-000209 Shenzhen SED Information Technology Co., Ltd.
-00020A Gefran Spa
-00020B Native Networks, Inc.
-00020C Metro-Optix
-00020D Micronpc.com
-00020E Laurel Networks, Inc.
-00020F AATR
-000210 Fenecom
-000211 Nature Worldwide Technology Corp.
-000212 SierraCom
-000213 S.D.E.L.
-000214 DTVRO
-000215 Cotas Computer Technology A/B
-000216 Cisco Systems, Inc.
-000217 Cisco Systems, Inc.
-000218 Advanced Scientific Corp
-000219 Paralon Technologies
-00021A Zuma Networks
-00021B Kollmorgen-Servotronix
-00021C Network Elements, Inc.
-00021D Data General Communication Ltd.
-00021E SIMTEL S.R.L.
-00021F Aculab PLC
-000220 Canon Aptex, Inc.
-000221 DSP Application, Ltd.
-000222 Chromisys, Inc.
-000223 ClickTV
-000224 Lantern Communications, Inc.
-000225 Certus Technology, Inc.
-000226 XESystems, Inc.
-000227 ESD GmbH
-000228 Necsom, Ltd.
-000229 Adtec Corporation
-00022A Asound Electronic
-00022B Tamura Electric Works, Ltd.
-00022C ABB Bomem, Inc.
-00022D Agere Systems
-00022E TEAC Corp. R& D
-00022F P-Cube, Ltd.
-000230 Intersoft Electronics
-000231 Ingersoll-Rand
-000232 Avision, Inc.
-000233 Mantra Communications, Inc.
-000234 Imperial Technology, Inc.
-000235 Paragon Networks International
-000236 INIT GmbH
-000237 Cosmo Research Corp.
-000238 Serome Technology, Inc.
-000239 Visicom
-00023A ZSK Stickmaschinen GmbH
-00023B Redback Networks
-00023C Creative Technology, Ltd.
-00023D NuSpeed, Inc.
-00023E Selta Telematica S.p.a
-00023F Compal Electronics, Inc.
-000240 Seedek Co., Ltd.
-000241 Amer.com
-000242 Videoframe Systems
-000243 Raysis Co., Ltd.
-000244 SURECOM Technology Co.
-000245 Lampus Co, Ltd.
-000246 All-Win Tech Co., Ltd.
-000247 Great Dragon Information Technology (Group) Co., Ltd.
-000248 Pilz GmbH & Co.
-000249 Aviv Infocom Co, Ltd.
-00024A Cisco Systems, Inc.
-00024B Cisco Systems, Inc.
-00024C SiByte, Inc.
-00024D Mannesman Dematic Colby Pty. Ltd.
-00024E Datacard Group
-00024F IPM Datacom S.R.L.
-000250 Geyser Networks, Inc.
-000251 Soma Networks
-000252 Carrier Corporation
-000253 Televideo, Inc.
-000254 WorldGate
-000255 IBM Corporation
-000256 Alpha Processor, Inc.
-000257 Microcom Corp.
-000258 Flying Packets Communications
-000259 Tsann Kuen China (Shanghai)Enterprise Co., Ltd. IT Group
-00025A Catena Networks
-00025B Cambridge Silicon Radio
-00025C SCI Systems (Kunshan) Co., Ltd.
-00025D Calix Networks
-00025E High Technology Ltd
-00025F Nortel Networks
-000260 Accordion Networks, Inc.
-000261 i3 Micro Technology AB
-000262 Soyo Group Soyo Com Tech Co., Ltd
-000263 UPS Manufacturing SRL
-000264 AudioRamp.com
-000265 Virditech Co. Ltd.
-000266 Thermalogic Corporation
-000267 NODE RUNNER, INC.
-000268 Harris Government Communications
-000269 Nadatel Co., Ltd
-00026A Cocess Telecom Co., Ltd.
-00026B BCM Computers Co., Ltd.
-00026C Philips CFT
-00026D Adept Telecom
-00026E NeGeN Access, Inc.
-00026F Senao International Co., Ltd.
-000270 Crewave Co., Ltd.
-000271 Vpacket Communications
-000272 CC&C Technologies, Inc.
-000273 Coriolis Networks
-000274 Tommy Technologies Corp.
-000275 SMART Technologies, Inc.
-000276 Primax Electronics Ltd.
-000277 Cash Systemes Industrie
-000278 Samsung Electro-Mechanics Co., Ltd.
-000279 Control Applications, Ltd.
-00027A IOI Technology Corporation
-00027B Amplify Net, Inc.
-00027C Trilithic, Inc.
-00027D Cisco Systems, Inc.
-00027E Cisco Systems, Inc.
-00027F ask-technologies.com
-000280 Mu Net, Inc.
-000281 Madge Ltd.
-000282 ViaClix, Inc.
-000283 Spectrum Controls, Inc.
-000284 Alstom T&D P&C
-000285 Riverstone Networks
-000286 Occam Networks
-000287 Adapcom
-000288 GLOBAL VILLAGE COMMUNICATION
-000289 DNE Technologies
-00028A Ambit Microsystems Corporation
-00028B VDSL Systems OY
-00028C Micrel-Synergy Semiconductor
-00028D Movita Technologies, Inc.
-00028E Rapid 5 Networks, Inc.
-00028F Globetek, Inc.
-000290 Woorigisool, Inc.
-000291 Open Network Co., Ltd.
-000292 Logic Innovations, Inc.
-000293 Solid Data Systems
-000294 Tokyo Sokushin Co., Ltd.
-000295 IP.Access Limited
-000296 Lectron Co,. Ltd.
-000297 C-COR.net
-000298 Broadframe Corporation
-000299 Apex, Inc.
-00029A Storage Apps
-00029B Kreatel Communications AB
-00029C 3COM
-00029D Merix Corp.
-00029E Information Equipment Co., Ltd.
-00029F L-3 Communication Aviation Recorders
-0002A0 Flatstack Ltd.
-0002A1 World Wide Packets
-0002A2 Hilscher GmbH
-0002A3 ABB Power Automation
-0002A4 AddPac Technology Co., Ltd.
-0002A5 Compaq Computer Corporation
-0002A6 Effinet Systems Co., Ltd.
-0002A7 Vivace Networks
-0002A8 Air Link Technology
-0002A9 RACOM, s.r.o.
-0002AA PLcom Co., Ltd.
-0002AB CTC Union Technologies Co., Ltd.
-0002AC 3PAR data
-0002AD Pentax Corpotation
-0002AE Scannex Electronics Ltd.
-0002AF TeleCruz Technology, Inc.
-0002B0 Hokubu Communication & Industrial Co., Ltd.
-0002B1 Anritsu, Ltd.
-0002B2 Cablevision
-0002B3 Intel Corporation
-0002B4 DAPHNE
-0002B5 Avnet, Inc.
-0002B6 Acrosser Technology Co., Ltd.
-0002B7 Watanabe Electric Industry Co., Ltd.
-0002B8 WHI KONSULT AB
-0002B9 Cisco Systems, Inc.
-0002BA Cisco Systems, Inc.
-0002BB Continuous Computing
-0002BC LVL 7 Systems, Inc.
-0002BD Bionet Co., Ltd.
-0002BE Totsu Engineering, Inc.
-0002BF dotRocket, Inc.
-0002C0 Bencent Tzeng Industry Co., Ltd.
-0002C1 Innovative Electronic Designs, Inc.
-0002C2 Net Vision Telecom
-0002C3 Arelnet Ltd.
-0002C4 Vector International BUBA
-0002C5 Evertz Microsystems Ltd.
-0002C6 Data Track Technology PLC
-0002C7 ALPS ELECTRIC Co., Ltd.
-0002C8 Technocom Communications Technology (pte) Ltd
-0002C9 Mellanox Technologies
-0002CA EndPoints, Inc.
-0002CB TriState Ltd.
-0002CC M.C.C.I
-0002CD TeleDream, Inc.
-0002CE FoxJet, Inc.
-0002CF ZyGate Communications, Inc.
-0002D0 Comdial Corporation
-0002D1 Vivotek, Inc.
-0002D2 Workstation AG
-0002D3 NetBotz, Inc.
-0002D4 PDA Peripherals, Inc.
-0002D5 ACR
-0002D6 NICE Systems
-0002D7 EMPEG Ltd
-0002D8 BRECIS Communications Corporation
-0002D9 Reliable Controls
-0002DA ExiO Communications, Inc.
-0002DB NETSEC
-0002DC Fujitsu General Limited
-0002DD Bromax Communications, Ltd.
-0002DE Astrodesign, Inc.
-0002DF Net Com Systems, Inc.
-0002E0 ETAS GmbH
-0002E1 Integrated Network Corporation
-0002E2 NDC Infared Engineering
-0002E3 LITE-ON Communications, Inc.
-0002E4 JC HYUN Systems, Inc.
-0002E5 Timeware Ltd.
-0002E6 Gould Instrument Systems, Inc.
-0002E7 CAB GmbH & Co KG
-0002E8 E.D.&A.
-0002E9 CS Systemes De Securite - C3S
-0002EA Videonics, Inc.
-0002EB Pico Communications
-0002EC Maschoff Design Engineering
-0002ED DXO Telecom Co., Ltd.
-0002EE Nokia Danmark A/S
-0002EF CCC Network Systems Group Ltd.
-0002F0 AME Optimedia Technology Co., Ltd.
-0002F1 Pinetron Co., Ltd.
-0002F2 eDevice, Inc.
-0002F3 Media Serve Co., Ltd.
-0002F4 PCTEL, Inc.
-0002F5 VIVE Synergies, Inc.
-0002F6 Equipe Communications
-0002F7 ARM
-0002F8 SEAKR Engineering, Inc.
-0002F9 Mimos Semiconductor SDN BHD
-0002FA DX Antenna Co., Ltd.
-0002FB Baumuller Aulugen-Systemtechnik GmbH
-0002FC Cisco Systems, Inc.
-0002FD Cisco Systems, Inc.
-0002FE Viditec, Inc.
-0002FF Handan BroadInfoCom
-000300 NetContinuum, Inc.
-000301 Avantas Networks Corporation
-000302 Oasys Telecom, Inc.
-000303 JAMA Electronics Co., Ltd.
-000304 Pacific Broadband Communications
-000305 Smart Network Devices GmbH
-000306 Fusion In Tech Co., Ltd.
-000307 Secure Works, Inc.
-000308 AM Communications, Inc.
-000309 Texcel Technology PLC
-00030A Argus Technologies
-00030B Hunter Technology, Inc.
-00030C Telesoft Technologies Ltd.
-00030D Uniwill Computer Corp.
-00030E Core Communications Co., Ltd.
-00030F Digital China (Shanghai) Networks Ltd.
-000310 Link Evolution Corp.
-000311 Micro Technology Co., Ltd.
-000312 TR-Systemtechnik GmbH
-000313 Access Media SPA
-000314 Teleware Network Systems
-000315 Cidco Incorporated
-000316 Nobell Communications, Inc.
-000317 Merlin Systems, Inc.
-000318 Cyras Systems, Inc.
-000319 Infineon AG
-00031A Beijing Broad Telecom Ltd., China
-00031B Cellvision Systems, Inc.
-00031C Svenska Hardvarufabriken AB
-00031D Taiwan Commate Computer, Inc.
-00031E Optranet, Inc.
-00031F Condev Ltd.
-000320 Xpeed, Inc.
-000321 Reco Research Co., Ltd.
-000322 IDIS Co., Ltd.
-000323 Cornet Technology, Inc.
-000324 SANYO Multimedia Tottori Co., Ltd.
-000325 Arima Computer Corp.
-000326 Iwasaki Information Systems Co., Ltd.
-000327 ACT'L
-000328 Mace Group, Inc.
-000329 F3, Inc.
-00032A UniData Communication Systems, Inc.
-00032B GAI Datenfunksysteme GmbH
-00032C ABB Industrie AG
-00032D IBASE Technology, Inc.
-00032E Scope Information Management, Ltd.
-00032F Global Sun Technology, Inc.
-000330 Imagenics, Co., Ltd.
-000331 Cisco Systems, Inc.
-000332 Cisco Systems, Inc.
-000333 Digitel Co., Ltd.
-000334 Newport Electronics
-000335 Mirae Technology
-000336 Zetes Technologies
-000337 Vaone, Inc.
-000338 Oak Technology
-000339 Eurologic Systems, Ltd.
-00033A Silicon Wave, Inc.
-00033B TAMI Tech Co., Ltd.
-00033C Daiden Co., Ltd.
-00033D ILSHin Lab
-00033E Tateyama System Laboratory Co., Ltd.
-00033F BigBand Networks, Ltd.
-000340 Floware Wireless Systems, Ltd.
-000341 Axon Digital Design
-000342 Nortel Networks
-000343 Martin Professional A/S
-000344 Tietech.Co., Ltd.
-000345 Routrek Networks Corporation
-000346 Hitachi Kokusai Electric, Inc.
-000347 Intel Corporation
-000348 Norscan Instruments, Ltd.
-000349 Vidicode Datacommunicatie B.V.
-00034A RIAS Corporation
-00034B Nortel Networks
-00034C Shanghai DigiVision Technology Co., Ltd.
-00034D Chiaro Networks, Ltd.
-00034E Pos Data Company, Ltd.
-00034F Sur-Gard Security
-000350 BTICINO SPA
-000351 Diebold, Inc.
-000352 Colubris Networks
-000353 Mitac, Inc.
-000354 Fiber Logic Communications
-000355 TeraBeam Internet Systems
-000356 Wincor Nixdorf GmbH & Co KG
-000357 Intervoice-Brite, Inc.
-000358 iCable System Co., Ltd.
-000359 DigitalSis
-00035A Photron Limited
-00035B BridgeWave Communications
-00035C Saint Song Corp.
-00035D Bosung Hi-Net Co., Ltd.
-00035E Metropolitan Area Networks, Inc.
-00035F Prueftechnik Condition Monitoring GmbH & Co. KG
-000360 PAC Interactive Technology, Inc.
-000361 Widcomm, Inc.
-000362 Vodtel Communications, Inc.
-000363 Miraesys Co., Ltd.
-000364 Scenix Semiconductor, Inc.
-000365 Kira Information & Communications, Ltd.
-000366 ASM Pacific Technology
-000367 Jasmine Networks, Inc.
-000368 Embedone Co., Ltd.
-000369 Nippon Antenna Co., Ltd.
-00036A Mainnet, Ltd.
-00036B Cisco Systems, Inc.
-00036C Cisco Systems, Inc.
-00036D Runtop, Inc.
-00036E Nicon Systems (Pty) Limited
-00036F Telsey SPA
-000370 NXTV, Inc.
-000371 Acomz Networks Corp.
-000372 ULAN
-000373 Aselsan A.S
-000374 Hunter Watertech
-000375 NetMedia, Inc.
-000376 Graphtec Technology, Inc.
-000377 Gigabit Wireless
-000378 HUMAX Co., Ltd.
-000379 Proscend Communications, Inc.
-00037A Taiyo Yuden Co., Ltd.
-00037B IDEC IZUMI Corporation
-00037C Coax Media
-00037D Stellcom
-00037E PORTech Communications, Inc.
-00037F Atheros Communications, Inc.
-000380 SSH Communications Security Corp.
-000381 Ingenico International
-000382 A-One Co., Ltd.
-000383 Metera Networks, Inc.
-000384 AETA
-000385 Actelis Networks, Inc.
-000386 Ho Net, Inc.
-000387 Blaze Network Products
-000388 Fastfame Technology Co., Ltd.
-000389 Plantronics
-00038A America Online, Inc.
-00038B PLUS-ONE I&T, Inc.
-00038C Total Impact
-00038D PCS Revenue Control Systems, Inc.
-00038E Atoga Systems, Inc.
-00038F Weinschel Corporation
-000390 Digital Video Communications, Inc.
-000392 Hyundai Teletek Co., Ltd.
-000393 Apple Computer, Inc.
-000394 Connect One
-000395 California Amplifier
-000396 EZ Cast Co., Ltd.
-000397 Watchfront Electronics
-000398 WISI
-000399 Dongju Informations & Communications Co., Ltd.
-00039A nSine, Ltd.
-00039B NetChip Technology, Inc.
-00039C OptiMight Communications, Inc.
-00039D BENQ CORPORATION
-00039E Tera System Co., Ltd.
-00039F Cisco Systems, Inc.
-0003A0 Cisco Systems, Inc.
-0003A1 HIPER Information & Communication, Inc.
-0003A2 Catapult Communications
-0003A3 MAVIX, Ltd.
-0003A4 Data Storage and Information Management
-0003A5 Medea Corporation
-0003A7 Unixtar Technology, Inc.
-0003A8 IDOT Computers, Inc.
-0003A9 AXCENT Media AG
-0003AA Watlow
-0003AB Bridge Information Systems
-0003AC Fronius Schweissmaschinen
-0003AD Emerson Energy Systems AB
-0003AE Allied Advanced Manufacturing Pte, Ltd.
-0003AF Paragea Communications
-0003B0 Xsense Technology Corp.
-0003B1 Abbott Laboratories HPD
-0003B2 Radware
-0003B3 IA Link Systems Co., Ltd.
-0003B4 Macrotek International Corp.
-0003B5 Entra Technology Co.
-0003B6 QSI Corporation
-0003B7 ZACCESS Systems
-0003B8 NetKit Solutions, LLC
-0003B9 Hualong Telecom Co., Ltd.
-0003BA Sun Microsystems
-0003BB Signal Communications Limited
-0003BC COT GmbH
-0003BD OmniCluster Technologies, Inc.
-0003BE Netility
-0003BF Centerpoint Broadband Technologies, Inc.
-0003C0 RFTNC Co., Ltd.
-0003C1 Packet Dynamics Ltd
-0003C2 Solphone K.K.
-0003C3 Micronik Multimedia
-0003C4 Tomra Systems ASA
-0003C5 Mobotix AG
-0003C6 ICUE Systems, Inc.
-0003C7 hopf Elektronik GmbH
-0003C8 CML Emergency Services
-0003C9 TECOM Co., Ltd.
-0003CA MTS Systems Corp.
-0003CB Nippon Systems Development Co., Ltd.
-0003CC Momentum Computer, Inc.
-0003CD Clovertech, Inc.
-0003CE ETEN Technologies, Inc.
-0003CF Muxcom, Inc.
-0003D0 KOANKEISO Co., Ltd.
-0003D1 Takaya Corporation
-0003D2 Crossbeam Systems, Inc.
-0003D3 Internet Energy Systems, Inc.
-0003D4 Alloptic, Inc.
-0003D5 Advanced Communications Co., Ltd.
-0003D6 RADVision, Ltd.
-0003D7 NextNet Wireless, Inc.
-0003D8 iMPath Networks, Inc.
-0003D9 Secheron SA
-0003DA Takamisawa Cybernetics Co., Ltd.
-0003DB Apogee Electronics Corp.
-0003DC Lexar Media, Inc.
-0003DD Comark Corp.
-0003DE OTC Wireless
-0003DF Desana Systems
-0003E0 RadioFrame Networks, Inc.
-0003E1 Winmate Communication, Inc.
-0003E2 Comspace Corporation
-0003E3 Cisco Systems, Inc.
-0003E4 Cisco Systems, Inc.
-0003E5 Hermstedt SG
-0003E6 Entone Technologies, Inc.
-0003E7 Logostek Co. Ltd.
-0003E8 Wavelength Digital Limited
-0003E9 Akara Canada, Inc.
-0003EA Mega System Technologies, Inc.
-0003EB Atrica
-0003EC ICG Research, Inc.
-0003ED Shinkawa Electric Co., Ltd.
-0003EE MKNet Corporation
-0003EF Oneline AG
-0003F0 Redfern Broadband Networks
-0003F1 Cicada Semiconductor, Inc.
-0003F2 Seneca Networks
-0003F3 Dazzle Multimedia, Inc.
-0003F4 NetBurner
-0003F5 Chip2Chip
-0003F6 Allegro Networks, Inc.
-0003F7 Plast-Control GmbH
-0003F8 SanCastle Technologies, Inc.
-0003F9 Pleiades Communications, Inc.
-0003FA TiMetra Networks
-0003FB Toko Seiki Company, Ltd.
-0003FC Intertex Data AB
-0003FD Cisco Systems, Inc.
-0003FE Cisco Systems, Inc.
-0003FF Connectix
-000400 LEXMARK INTERNATIONAL, INC.
-000401 Osaki Electric Co., Ltd.
-000402 Nexsan Technologies, Ltd.
-000403 Nexsi Corporation
-000404 Makino Milling Machine Co., Ltd.
-000405 ACN Technologies
-000406 Fa. Metabox AG
-000407 Topcon Positioning Systems, Inc.
-000408 Sanko Electronics Co., Ltd.
-000409 Cratos Networks
-00040A Sage Systems
-00040B 3com Europe Ltd.
-00040C KANNO Work's Ltd.
-00040D Avaya, Inc.
-00040E AVM GmbH
-00040F Asus Network Technologies, Inc.
-000410 Spinnaker Networks, Inc.
-000411 Inkra Networks, Inc.
-000412 WaveSmith Networks, Inc.
-000413 SNOM Technology AG
-000414 Umezawa Musen Denki Co., Ltd.
-000415 Rasteme Systems Co., Ltd.
-000416 Parks S/A Comunicacoes Digitais
-000417 ELAU AG
-000418 Teltronic S.A.U.
-000419 Fibercycle Networks, Inc.
-00041A ines GmbH
-00041B Digital Interfaces Ltd.
-00041C ipDialog, Inc.
-00041D Corega of America
-00041E Shikoku Instrumentation Co., Ltd.
-00041F Sony Computer Entertainment, Inc.
-000420 Slim Devices, Inc.
-000421 Ocular Networks
-000422 Gordon Kapes, Inc.
-000423 Intel Corporation
-000424 TMC s.r.l.
-000425 Atmel Corporation
-000426 Autosys
-000427 Cisco Systems, Inc.
-000428 Cisco Systems, Inc.
-000429 Pixord Corporation
-00042A Wireless Networks, Inc.
-00042B IT Access Co., Ltd.
-00042C Minet, Inc.
-00042D Sarian Systems, Ltd.
-00042E Netous Technologies, Ltd.
-00042F International Communications Products, Inc.
-000430 Netgem
-000431 GlobalStreams, Inc.
-000432 Voyetra Turtle Beach, Inc.
-000433 Cyberboard A/S
-000434 Accelent Systems, Inc.
-000435 Comptek International, Inc.
-000436 ELANsat Technologies, Inc.
-000437 Powin Information Technology, Inc.
-000438 Nortel Networks
-000439 Rosco Entertainment Technology, Inc.
-00043A Intelligent Telecommunications, Inc.
-00043B Lava Computer Mfg., Inc.
-00043C SONOS Co., Ltd.
-00043D INDEL AG
-00043E Telencomm
-00043F Electronic Systems Technology, Inc.
-000440 cyberPIXIE, Inc.
-000441 Half Dome Systems, Inc.
-000442 NACT
-000443 Agilent Technologies, Inc.
-000444 Western Multiplex Corporation
-000445 LMS Skalar Instruments GmbH
-000446 CYZENTECH Co., Ltd.
-000447 Acrowave Systems Co., Ltd.
-000448 Polaroid Professional Imaging
-000449 Mapletree Networks
-00044A iPolicy Networks, Inc.
-00044B NVIDIA
-00044C JENOPTIK
-00044D Cisco Systems, Inc.
-00044E Cisco Systems, Inc.
-00044F Leukhardt Systemelektronik GmbH
-000450 DMD Computers SRL
-000451 Medrad, Inc.
-000452 RocketLogix, Inc.
-000453 YottaYotta, Inc.
-000454 Quadriga UK
-000455 ANTARA.net
-000456 PipingHot Networks
-000457 Universal Access Technology, Inc.
-000458 Fusion X Co., Ltd.
-000459 Veristar Corporation
-00045A The Linksys Group, Inc.
-00045B Techsan Electronics Co., Ltd.
-00045C Mobiwave Pte Ltd
-00045D BEKA Elektronik
-00045E PolyTrax Information Technology AG
-00045F Evalue Technology, Inc.
-000460 Knilink Technology, Inc.
-000461 EPOX Computer Co., Ltd.
-000462 DAKOS Data & Communication Co., Ltd.
-000463 Bosch Security Systems
-000464 Fantasma Networks, Inc.
-000465 i.s.t isdn-support technik GmbH
-000466 ARMITEL Co.
-000467 Wuhan Research Institute of MII
-000468 Vivity, Inc.
-000469 Innocom, Inc.
-00046A Navini Networks
-00046B Palm Wireless, Inc.
-00046C Cyber Technology Co., Ltd.
-00046D Cisco Systems, Inc.
-00046E Cisco Systems, Inc.
-00046F Digitel S/A Industria Eletronica
-000470 ipUnplugged AB
-000471 IPrad
-000472 Telelynx, Inc.
-000473 Photonex Corporation
-000474 LEGRAND
-000475 3 Com Corporation
-000476 3 Com Corporation
-000477 Scalant Systems, Inc.
-000478 G. Star Technology Corporation
-000479 Radius Co., Ltd.
-00047A AXXESSIT ASA
-00047B Schlumberger
-00047C Skidata AG
-00047D Pelco
-00047E NKF Electronics
-00047F Chr. Mayr GmbH & Co. KG
-000480 Foundry Networks, Inc.
-000481 Econolite Control Products, Inc.
-000482 Medialogic Corp.
-000483 Deltron Technology, Inc.
-000484 Amann GmbH
-000485 PicoLight
-000486 ITTC, University of Kansas
-000487 Cogency Semiconductor, Inc.
-000488 Eurotherm Action Incorporated.
-000489 YAFO Networks, Inc.
-00048A Temia Vertriebs GmbH
-00048B Poscon Corporation
-00048C Nayna Networks, Inc.
-00048D Tone Commander Systems, Inc.
-00048E Ohm Tech Labs, Inc.
-00048F TD Systems Corp.
-000490 Optical Access
-000491 Technovision, Inc.
-000492 Hive Internet, Ltd.
-000493 Tsinghua Unisplendour Co., Ltd.
-000494 Breezecom, Ltd.
-000495 Tejas Networks
-000496 Extreme Networks
-000497 MacroSystem Digital Video AG
-000499 Chino Corporation
-00049A Cisco Systems, Inc.
-00049B Cisco Systems, Inc.
-00049C Surgient Networks, Inc.
-00049D Ipanema Technologies
-00049E Wirelink Co., Ltd.
-00049F Metrowerks
-0004A0 Verity Instruments, Inc.
-0004A1 Pathway Connectivity
-0004A2 L.S.I. Japan Co., Ltd.
-0004A3 Microchip Technology, Inc.
-0004A4 NetEnabled, Inc.
-0004A5 Barco Projection Systems NV
-0004A6 SAF Tehnika Ltd.
-0004A7 FabiaTech Corporation
-0004A8 Broadmax Technologies, Inc.
-0004A9 SandStream Technologies, Inc.
-0004AA Jetstream Communications
-0004AB Comverse Network Systems, Inc.
-0004AC IBM CORP.
-0004AD Malibu Networks
-0004AE Liquid Metronics
-0004AF Digital Fountain, Inc.
-0004B0 ELESIGN Co., Ltd.
-0004B1 Signal Technology, Inc.
-0004B2 ESSEGI SRL
-0004B3 Videotek, Inc.
-0004B4 CIAC
-0004B5 Equitrac Corporation
-0004B6 Stratex Networks, Inc.
-0004B7 AMB i.t. Holding
-0004B8 Kumahira Co., Ltd.
-0004B9 S.I. Soubou, Inc.
-0004BA KDD Media Will Corporation
-0004BB Bardac Corporation
-0004BC Giantec, Inc.
-0004BD Motorola BCS
-0004BE OptXCon, Inc.
-0004BF VersaLogic Corp.
-0004C0 Cisco Systems, Inc.
-0004C1 Cisco Systems, Inc.
-0004C2 Magnipix, Inc.
-0004C3 CASTOR Informatique
-0004C4 Allen & Heath Limited
-0004C5 ASE Technologies, USA
-0004C6 Yamaha Motor Co., Ltd.
-0004C7 NetMount
-0004C8 LIBA Maschinenfabrik GmbH
-0004C9 Micro Electron Co., Ltd.
-0004CA FreeMs Corp.
-0004CB Tdsoft Communication, Ltd.
-0004CC Peek Traffic B.V.
-0004CD Informedia Research Group
-0004CE Patria Ailon
-0004CF Seagate Technology
-0004D0 Softlink s.r.o.
-0004D1 Drew Technologies, Inc.
-0004D2 Adcon Telemetry AG
-0004D3 Toyokeiki Co., Ltd.
-0004D4 Proview Electronics Co., Ltd.
-0004D5 Hitachi Communication Systems, Inc.
-0004D6 Takagi Industrial Co., Ltd.
-0004D7 Omitec Instrumentation Ltd.
-0004D8 IPWireless, Inc.
-0004D9 Titan Electronics, Inc.
-0004DA Relax Technology, Inc.
-0004DB Tellus Group Corp.
-0004DC Nortel Networks
-0004DD Cisco Systems, Inc.
-0004DE Cisco Systems, Inc.
-0004DF Teracom Telematica Ltda.
-0004E0 Procket Networks
-0004E1 Infinior Microsystems
-0004E2 SMC Networks, Inc.
-0004E3 Accton Technology Corp.
-0004E4 Daeryung Ind., Inc.
-0004E5 Glonet Systems, Inc.
-0004E6 Banyan Network Private Limited
-0004E7 Lightpointe Communications, Inc
-0004E8 IER, Inc.
-0004E9 Infiniswitch Corporation
-0004EA Hewlett-Packard Company
-0004EB Paxonet Communications, Inc.
-0004EC Memobox SA
-0004ED Billion Electric Co., Ltd.
-0004EE Lincoln Electric Company
-0004EF Polestar Corp.
-0004F0 International Computers, Ltd
-0004F1 WhereNet
-0004F2 Circa Communications, Ltd.
-0004F3 FS FORTH-SYSTEME GmbH
-0004F4 Infinite Electronics Inc.
-0004F5 SnowShore Networks, Inc.
-0004F6 Amphus
-0004F7 Omega Band, Inc.
-0004F8 QUALICABLE TV Industria E Com., Ltda
-0004F9 Xtera Communications, Inc.
-0004FA MIST Inc.
-0004FB Commtech, Inc.
-0004FC Stratus Computer (DE), Inc.
-0004FD Japan Control Engineering Co., Ltd.
-0004FE Pelago Networks
-0004FF Acronet Co., Ltd.
-000500 Cisco Systems, Inc.
-000501 Cisco Systems, Inc.
-000502 APPLE COMPUTER
-000503 ICONAG
-000504 Naray Information & Communication Enterprise
-000505 Systems Integration Solutions, Inc.
-000506 Reddo Networks AB
-000507 Fine Appliance Corp.
-000508 Inetcam, Inc.
-000509 AVOC Nishimura Ltd.
-00050A ICS Spa
-00050B SICOM Systems, Inc.
-00050C Network Photonics, Inc.
-00050D Midstream Technologies, Inc.
-00050E 3ware, Inc.
-00050F Tanaka S/S Ltd.
-000510 Infinite Shanghai Communication Terminals Ltd.
-000511 Complementary Technologies Ltd
-000512 MeshNetworks, Inc.
-000513 VTLinx Multimedia Systems, Inc.
-000514 KDT Systems Co., Ltd.
-000515 Nuark Co., Ltd.
-000516 SMART Modular Technologies
-000517 Shellcomm, Inc.
-000518 Jupiters Technology
-000519 Siemens Building Technologies AG,
-00051A 3Com Europe Ltd.
-00051B Magic Control Technology Corporation
-00051C Xnet Technology Corp.
-00051D Airocon, Inc.
-00051E Brocade Communications Systems, Inc.
-00051F Taijin Media Co., Ltd.
-000520 Smartronix, Inc.
-000521 Control Microsystems
-000522 LEA*D Corporation, Inc.
-000523 AVL List GmbH
-000524 BTL System (HK) Limited
-000525 Puretek Industrial Co., Ltd.
-000526 IPAS GmbH
-000527 SJ Tek Co. Ltd
-000528 New Focus, Inc.
-000529 Shanghai Broadan Communication Technology Co., Ltd
-00052A Ikegami Tsushinki Co., Ltd.
-00052B HORIBA, Ltd.
-00052C Supreme Magic Corporation
-00052D Zoltrix International Limited
-00052E Cinta Networks
-00052F Leviton Voice and Data
-000530 Andiamo Systems, Inc.
-000531 Cisco Systems, Inc.
-000532 Cisco Systems, Inc.
-000533 Sanera Systems, Inc.
-000534 Northstar Engineering Ltd.
-000535 Chip PC Ltd.
-000536 Danam Communications, Inc.
-000537 Nets Technology Co., Ltd.
-000538 Merilus, Inc.
-000539 A Brand New World in Sweden AB
-00053A Willowglen Services Pte Ltd
-00053B Harbour Networks Ltd., Co. Beijing
-00053C Xircom
-00053D Agere Systems
-00053E KID Systeme GmbH
-00053F VisionTek, Inc.
-000540 FAST Corporation
-000541 Advanced Systems Co., Ltd.
-000542 Otari, Inc.
-000543 IQ Wireless GmbH
-000544 Valley Technologies, Inc.
-000545 Internet Photonics
-000546 K-Solutions Inc.
-000547 Starent Networks
-000548 Disco Corporation
-000549 Salira Optical Network Systems
-00054A Ario Data Networks, Inc.
-00054B Micro Innovation AG
-00054C RF Innovations Pty Ltd
-00054D Brans Technologies, Inc.
-00054E Philips Components
-000550 Digi-Tech Communications Limited
-000551 F & S Elektronik Systeme GmbH
-000552 Xycotec Computer GmbH
-000553 DVC Company, Inc.
-000554 Rangestar Wireless
-000555 Japan Cash Machine Co., Ltd.
-000556 360 Systems
-000557 Agile TV Corporation
-000558 Synchronous, Inc.
-000559 Intracom S.A.
-00055A Power Dsine Ltd.
-00055B Charles Industries, Ltd.
-00055C Kowa Company, Ltd.
-00055D D-Link Systems, Inc.
-00055E Cisco Systems, Inc.
-00055F Cisco Systems, Inc.
-000560 LEADER COMM.CO., LTD
-000561 nac Image Technology, Inc.
-000562 Digital View Limited
-000563 J-Works, Inc.
-000564 Tsinghua Bitway Co., Ltd.
-000565 Tailyn Communication Company Ltd.
-000566 Secui.com Corporation
-000567 Etymonic Design, Inc.
-000568 Piltofish Networks AB
-000569 VMWARE, Inc.
-00056A Heuft Systemtechnik GmbH
-00056B C.P. Technology Co., Ltd.
-00056C Hung Chang Co., Ltd.
-00056D Pacific Corporation
-00056E National Enhance Technology, Inc.
-00056F Innomedia Technologies Pvt. Ltd.
-000570 Baydel Ltd.
-000571 Seiwa Electronics Co.
-000572 Deonet Co., Ltd.
-000573 Cisco Systems, Inc.
-000574 Cisco Systems, Inc.
-000575 CDS-Electronics BV
-000576 NSM Technology Ltd.
-000577 SM Information & Communication
-000579 Universal Control Solution Corp.
-00057A Hatteras Networks
-00057B Chung Nam Electronic Co., Ltd.
-00057C RCO Security AB
-00057D Sun Communications, Inc.
-00057E Eckelmann Steuerungstechnik GmbH
-00057F Acqis Technology
-000580 Fibrolan Ltd.
-000581 Snell & Wilcox Ltd.
-000582 ClearCube Technology
-000583 ImageCom Limited
-000584 AbsoluteValue Systems, Inc.
-000585 Juniper Networks, Inc.
-000586 Lucent Technologies
-000587 Locus, Incorporated
-000588 Sensoria Corp.
-000589 National Datacomputer
-00058A Netcom Co., Ltd.
-00058B IPmental, Inc.
-00058C Opentech Inc.
-00058D Lynx Photonic Networks, Inc.
-00058E Flextronics International GmbH & Co. Nfg. KG
-00058F CLCsoft co.
-000590 Swissvoice Ltd.
-000591 Active Silicon Ltd.
-000592 Pultek Corp.
-000593 Grammar Engine Inc.
-000594 IXXAT Automation GmbH
-000595 Alesis Corporation
-000596 Genotech Co., Ltd.
-000597 Eagle Traffic Control Systems
-000598 CRONOS S.r.l.
-000599 DRS Test and Energy Management or DRS-TEM
-00059A Cisco Systems, Inc.
-00059B Cisco Systems, Inc.
-00059C Kleinknecht GmbH, Ing. Buero
-00059D Daniel Computing Systems, Inc.
-00059E Zinwell Corporation
-00059F Yotta Networks, Inc.
-0005A0 MOBILINE Kft.
-0005A1 Zenocom
-0005A2 CELOX Networks
-0005A3 QEI, Inc.
-0005A4 Lucid Voice Ltd.
-0005A5 KOTT
-0005A6 Extron Electronics
-0005A7 Hyperchip, Inc.
-0005A8 WYLE ELECTRONICS
-0005A9 Princeton Networks, Inc.
-0005AA Moore Industries International Inc.
-0005AB Cyber Fone, Inc.
-0005AC Northern Digital, Inc.
-0005AD Topspin Communications, Inc.
-0005AE Mediaport USA
-0005AF InnoScan Computing A/S
-0005B0 Korea Computer Technology Co., Ltd.
-0005B1 ASB Technology BV
-0005B2 Medison Co., Ltd.
-0005B3 Asahi-Engineering Co., Ltd.
-0005B4 Aceex Corporation
-0005B5 Broadcom Technologies
-0005B6 INSYS Microelectronics GmbH
-0005B7 Arbor Technology Corp.
-0005B8 Electronic Design Associates, Inc.
-0005B9 Airvana, Inc.
-0005BA Area Netwoeks, Inc.
-0005BB Myspace AB
-0005BC Resorsys Ltd.
-0005BD ROAX BV
-0005BE Kongsberg Seatex AS
-0005BF JustEzy Technology, Inc.
-0005C0 Digital Network Alacarte Co., Ltd.
-0005C1 A-Kyung Motion, Inc.
-0005C2 Soronti, Inc.
-0005C3 Pacific Instruments, Inc.
-0005C4 Telect, Inc.
-0005C5 Flaga HF
-0005C6 Triz Communications
-0005C7 I/F-COM A/S
-0005C8 VERYTECH
-0005C9 LG Innotek
-0005CA Hitron Technology, Inc.
-0005CB ROIS Technologies, Inc.
-0005CC Sumtel Communications, Inc.
-0005CD Denon, Ltd.
-0005CE Prolink Microsystems Corporation
-0005CF Thunder River Technologies, Inc.
-0005D0 Solinet Systems
-0005D1 Metavector Technologies
-0005D2 DAP Technologies
-0005D3 eProduction Solutions, Inc.
-0005D4 FutureSmart Networks, Inc.
-0005D5 Speedcom Wireless
-0005D6 Titan Wireless
-0005D7 Vista Imaging, Inc.
-0005D8 Arescom, Inc.
-0005D9 Techno Valley, Inc.
-0005DA Apex Automationstechnik
-0005DB Nentec GmbH
-0005DC Cisco Systems, Inc.
-0005DD Cisco Systems, Inc.
-0005DE Gi Fone Korea, Inc.
-0005DF Electronic Innovation, Inc.
-0005E0 Empirix Corp.
-0005E1 Trellis Photonics, Ltd.
-0005E2 Creativ Network Technologies
-0005E3 LightSand Communications, Inc.
-0005E4 Red Lion Controls L.P.
-0005E5 Renishaw PLC
-0005E6 Egenera, Inc.
-0005E7 Netrake Corp.
-0005E8 TurboWave, Inc.
-0005E9 Unicess Network, Inc.
-0005EA Rednix
-0005EB Blue Ridge Networks, Inc.
-0005EC Mosaic Systems Inc.
-0005ED Technikum Joanneum GmbH
-0005EE BEWATOR Group
-0005EF ADOIR Digital Technology
-0005F0 SATEC
-0005F1 Vrcom, Inc.
-0005F2 Power R, Inc.
-0005F3 Weboyn
-0005F4 System Base Co., Ltd.
-0005F5 OYO Geospace Corp.
-0005F6 Young Chang Co. Ltd.
-0005F7 Analog Devices, Inc.
-0005F8 Real Time Access, Inc.
-0005F9 TOA Corporation
-0005FA IPOptical, Inc.
-0005FB ShareGate, Inc.
-0005FC Schenck Pegasus Corp.
-0005FD PacketLight Networks Ltd.
-0005FE Traficon N.V.
-0005FF SNS Solutions, Inc.
-000600 Tokyo Electronic Industry Co., Ltd.
-000601 Otanikeiki Co., Ltd.
-000602 Cirkitech Electronics Co.
-000603 Baker Hughes Inc.
-000604 @Track Communications, Inc.
-000605 Inncom International, Inc.
-000606 RapidWAN, Inc.
-000607 Omni Directional Control Technology Inc.
-000608 At-Sky SAS
-000609 Crossport Systems
-00060A Blue2space
-00060B Paceline Systems Corporation
-00060C Melco Industries, Inc.
-00060D Wave7 Optics
-00060E IGYS Systems, Inc.
-00060F Narad Networks Inc
-000610 Abeona Networks Inc
-000611 Zeus Wireless, Inc.
-000612 Accusys, Inc.
-000613 Kawasaki Microelectronics Incorporated
-000614 Prism Holdings
-000615 Kimoto Electric Co., Ltd.
-000616 Tel Net Co., Ltd.
-000617 Redswitch Inc.
-000618 DigiPower Manufacturing Inc.
-000619 Connection Technology Systems
-00061A Zetari Inc.
-00061B Portable Systems, IBM Japan Co, Ltd
-00061C Hoshino Metal Industries, Ltd.
-00061D MIP Telecom, Inc.
-00061E Maxan Systems
-00061F Vision Components GmbH
-000620 Serial System Ltd.
-000621 Hinox, Co., Ltd.
-000622 Chung Fu Chen Yeh Enterprise Corp.
-000623 MGE UPS Systems France
-000624 Gentner Communications Corp.
-000625 The Linksys Group, Inc.
-000626 MWE GmbH
-000627 Uniwide Technologies, Inc.
-000628 Cisco Systems, Inc.
-000629 IBM CORPORATION
-00062A Cisco Systems, Inc.
-00062B INTRASERVER TECHNOLOGY
-00062C Network Robots, Inc.
-00062D TouchStar Technologies, L.L.C.
-00062E Aristos Logic Corp.
-00062F Pivotech Systems Inc.
-000630 Adtranz Sweden
-000631 Optical Solutions, Inc.
-000632 Mesco Engineering GmbH
-000633 Heimann Biometric Systems GmbH
-000634 GTE Airfone Inc.
-000635 PacketAir Networks, Inc.
-000636 Jedai Broadband Networks
-000637 Toptrend-Meta Information (ShenZhen) Inc.
-000638 Sungjin C&C Co., Ltd.
-000639 Newtec
-00063A Dura Micro, Inc.
-00063B Arcturus Networks, Inc.
-00063C NMI Electronics Ltd
-00063D Microwave Data Systems Inc.
-00063E Opthos Inc.
-00063F Everex Communications Inc.
-000640 White Rock Networks
-000641 ITCN
-000642 Genetel Systems Inc.
-000643 SONO Computer Co., Ltd.
-000644 NEIX Inc.
-000645 Meisei Electric Co. Ltd.
-000646 ShenZhen XunBao Network Technology Co Ltd
-000647 Etrali S.A.
-000648 Seedsware, Inc.
-000649 Quante
-00064A Honeywell Co., Ltd. (KOREA)
-00064B Alexon Co., Ltd.
-00064C Invicta Networks, Inc.
-00064D Sencore
-00064E Broad Net Technology Inc.
-00064F PRO-NETS Technology Corporation
-000650 Tiburon Networks, Inc.
-000651 Aspen Networks Inc.
-000652 Cisco Systems, Inc.
-000653 Cisco Systems, Inc.
-000654 Maxxio Technologies
-000655 Yipee, Inc.
-000656 Tactel AB
-000657 Market Central, Inc.
-000658 Helmut Fischer GmbH & Co. KG
-000659 EAL (Apeldoorn) B.V.
-00065A Strix Systems
-00065B Dell Computer Corp.
-00065C Malachite Technologies, Inc.
-00065D Heidelberg Web Systems
-00065E Photuris, Inc.
-00065F ECI Telecom - NGTS Ltd.
-000660 NADEX Co., Ltd.
-000661 NIA Home Technologies Corp.
-000662 MBM Technology Ltd.
-000663 Human Technology Co., Ltd.
-000664 Fostex Corporation
-000665 Sunny Giken, Inc.
-000666 Roving Networks
-000667 Tripp Lite
-000668 Vicon Industries Inc.
-000669 Datasound Laboratories Ltd
-00066A InfiniCon Systems, Inc.
-00066B Sysmex Corporation
-00066C Robinson Corporation
-00066D Compuprint S.P.A.
-00066E Delta Electronics, Inc.
-00066F Korea Data Systems
-000670 Upponetti Oy
-000671 Softing AG
-000672 Netezza
-000673 Optelecom, Inc.
-000674 Spectrum Control, Inc.
-000675 Banderacom, Inc.
-000676 Novra Technologies Inc.
-000677 SICK AG
-000678 Marantz Japan, Inc.
-000679 Konami Corporation
-00067A JMP Systems
-00067B Toplink C&C Corporation
-00067C CISCO SYSTEMS, INC.
-00067D Takasago Ltd.
-00067E WinCom Systems, Inc.
-00067F Rearden Steel Technologies
-000680 Card Access, Inc.
-000681 Goepel Electronic GmbH
-000682 Convedia
-000683 Bravara Communications, Inc.
-000684 Biacore AB
-000685 NetNearU Corporation
-000686 ZARDCOM Co., Ltd.
-000687 Omnitron Systems Technology, Inc.
-000688 Telways Communication Co., Ltd.
-000689 yLez Technologies Pte Ltd
-00068A NeuronNet Co. Ltd. R&D Center
-00068B AirRunner Technologies, Inc.
-00068C 3Com Corporation
-00068D SANgate Systems
-00068E HID Corporation
-00068F Telemonitor, Inc.
-000690 Euracom Communication GmbH
-000691 PT Inovacao
-000692 Intruvert Networks, Inc.
-000693 Flexus Computer Technology, Inc.
-000694 Mobillian Corporation
-000695 Ensure Technologies, Inc.
-000696 Advent Networks
-000697 R & D Center
-000698 egnite Software GmbH
-000699 Vida Design Co.
-00069A e & Tel
-00069B AVT Audio Video Technologies GmbH
-00069C Transmode Systems AB
-00069D Petards Mobile Intelligence
-00069E UNIQA, Inc.
-00069F Kuokoa Networks
-0006A0 Mx Imaging
-0006A1 Celsian Technologies, Inc.
-0006A2 Microtune, Inc.
-0006A3 Bitran Corporation
-0006A4 INNOWELL Corp.
-0006A5 PINON Corp.
-0006A6 Artistic Licence (UK) Ltd
-0006A7 Primarion
-0006A8 KC Technology, Inc.
-0006A9 Universal Instruments Corp.
-0006AA Miltope Corporation
-0006AB W-Link Systems, Inc.
-0006AC Intersoft Co.
-0006AD KB Electronics Ltd.
-0006AE Himachal Futuristic Communications Ltd
-0006B0 Comtech EF Data Corp.
-0006B1 Sonicwall
-0006B2 Linxtek Co.
-0006B3 Diagraph Corporation
-0006B4 Vorne Industries, Inc.
-0006B5 Luminent, Inc.
-0006B6 Nir-Or Israel Ltd.
-0006B7 TELEM GmbH
-0006B8 Bandspeed Pty Ltd
-0006B9 A5TEK Corp.
-0006BA Westwave Communications
-0006BB ATI Technologies Inc.
-0006BC Macrolink, Inc.
-0006BD BNTECHNOLOGY Co., Ltd.
-0006BE Baumer Optronic GmbH
-0006BF Accella Technologies Co., Ltd.
-0006C0 United Internetworks, Inc.
-0006C1 CISCO SYSTEMS, INC.
-0006C2 Smartmatic Corporation
-0006C3 Schindler Elevators Ltd.
-0006C4 Piolink Inc.
-0006C5 INNOVI Technologies Limited
-0006C6 lesswire AG
-0006C7 RFNET Technologies Pte Ltd (S)
-0006C8 Sumitomo Metal Micro Devices, Inc.
-0006C9 Technical Marketing Research, Inc.
-0006CA American Computer & Digital Components, Inc. (ACDC)
-0006CB Jotron Electronics A/S
-0006CC JMI Electronics Co., Ltd.
-0006CD CreoScitex Corporation Ltd.
-0006CE DATENO
-0006CF Thales Avionics In-Flight Systems, LLC
-0006D0 Elgar Electronics Corp.
-0006D1 Tahoe Networks, Inc.
-0006D2 Tundra Semiconductor Corp.
-0006D3 Alpha Telecom, Inc. U.S.A.
-0006D4 Interactive Objects, Inc.
-0006D5 Diamond Systems Corp.
-0006D6 Cisco Systems, Inc.
-0006D7 Cisco Systems, Inc.
-0006D8 Maple Optical Systems
-0006D9 IPM-Net S.p.A.
-0006DA ITRAN Communications Ltd.
-0006DB ICHIPS Co., Ltd.
-0006DC Syabas Technology (Amquest)
-0006DD AT & T Laboratories - Cambridge Ltd
-0006DE Flash Technology
-0006DF AIDONIC Corporation
-0006E0 MAT Co., Ltd.
-0006E1 Techno Trade s.a
-0006E2 Ceemax Technology Co., Ltd.
-0006E3 Quantitative Imaging Corporation
-0006E4 Citel Technologies Ltd.
-0006E5 Fujian Newland Computer Ltd. Co.
-0006E6 DongYang Telecom Co., Ltd.
-0006E7 Bit Blitz Communications Inc.
-0006E8 Optical Network Testing, Inc.
-0006E9 Intime Corp.
-0006EA ELZET80 Mikrocomputer GmbH&Co. KG
-0006EB Global Data
-0006EC M/A COM Private Radio System Inc.
-0006ED Inara Networks
-0006EE Shenyang Neu-era Information & Technology Stock Co., Ltd
-0006EF Maxxan Systems, Inc.
-0006F0 Digeo, Inc.
-0006F1 Optillion
-0006F2 Platys Communications
-0006F3 AcceLight Networks
-0006F4 Prime Electronics & Satellitics Inc.
-0006F9 Mitsui Zosen Systems Research Inc.
-0006FA IP SQUARE Co, Ltd.
-0006FB Hitachi Printing Solutions, Ltd.
-0006FC Fnet Co., Ltd.
-0006FD Comjet Information Systems Corp.
-0006FE Celion Networks, Inc.
-0006FF Sheba Systems Co., Ltd.
-000700 Zettamedia Korea
-000701 RACAL-DATACOM
-000702 Varian Medical Systems
-000703 CSEE Transport
-000705 Endress & Hauser GmbH & Co
-000706 Sanritz Corporation
-000707 Interalia Inc.
-000708 Bitrage Inc.
-000709 Westerstrand Urfabrik AB
-00070A Unicom Automation Co., Ltd.
-00070B Octal, SA
-00070C SVA-Intrusion.com Co. Ltd.
-00070D Cisco Systems Inc.
-00070E Cisco Systems Inc.
-00070F Fujant, Inc.
-000710 Adax, Inc.
-000711 Acterna
-000712 JAL Information Technology
-000713 IP One, Inc.
-000714 Brightcom
-000715 General Research of Electronics, Inc.
-000716 J & S Marine Ltd.
-000717 Wieland Electric GmbH
-000718 iCanTek Co., Ltd.
-000719 Mobiis Co., Ltd.
-00071A Finedigital Inc.
-00071B Position Technology Inc.
-00071C AT&T Fixed Wireless Services
-00071D Satelsa Sistemas Y Aplicaciones De Telecomunicaciones, S.A.
-00071E Tri-M Engineering / Nupak Dev. Corp.
-00071F European Systems Integration
-000720 Trutzschler GmbH & Co. KG
-000721 Formac Elektronik GmbH
-000722 Nielsen Media Research
-000723 ELCON Systemtechnik GmbH
-000724 Telemax Co., Ltd.
-000725 Bematech International Corp.
-000727 Zi Corporation (HK) Ltd.
-000728 Neo Telecom
-000729 Kistler Instrumente AG
-00072A Innovance Networks
-00072B Jung Myung Telecom Co., Ltd.
-00072C Fabricom
-00072D CNSystems
-00072E North Node AB
-00072F Instransa, Inc.
-000730 Hutchison OPTEL Telecom Technology Co., Ltd.
-000731 Spiricon, Inc.
-000732 AAEON Technology Inc.
-000733 DANCONTROL Engineering
-000734 ONStor, Inc.
-000735 Flarion Technologies, Inc.
-000736 Data Video Technologies Co., Ltd.
-000737 Soriya Co. Ltd.
-000738 Young Technology Co., Ltd.
-000739 Motion Media Technology Ltd.
-00073A Inventel Systemes
-00073B Tenovis GmbH & Co KG
-00073C Telecom Design
-00073D Nanjing Postel Telecommunications Co., Ltd.
-00073E China Great-Wall Computer Shenzhen Co., Ltd.
-00073F Woojyun Systec Co., Ltd.
-000740 Melco Inc.
-000741 Sierra Automated Systems
-000742 Current Technologies
-000743 Chelsio Communications
-000744 Unico, Inc.
-000745 Radlan Computer Communications Ltd.
-000746 Interlink BT, LLC
-000747 Mecalc
-000748 The Imaging Source Europe
-000749 CENiX Inc.
-00074A Carl Valentin GmbH
-00074B Daihen Corporation
-00074C Beicom Inc.
-00074D Zebra Technologies Corp.
-00074E Naughty boy co., Ltd.
-00074F Cisco Systems, Inc.
-000750 Cisco Systems, Inc.
-000751 m.u.t. - GmbH
-000752 Rhythm Watch Co., Ltd.
-000753 Beijing Qxcomm Technology Co., Ltd.
-000754 Xyterra Computing, Inc.
-000755 Lafon SA
-000756 Juyoung Telecom
-000757 Topcall International AG
-000758 Dragonwave
-000759 Boris Manufacturing Corp.
-00075A Air Products and Chemicals, Inc.
-00075B Gibson Guitars
-00075C ENCAD, Inc.
-00075D Celleritas Inc.
-00075E Pulsar Technologies, Inc.
-00075F VCS Video Communication Systems AG
-000760 TOMIS Information & Telecom Corp.
-000761 Logitech SA
-000762 Group Sense Limited
-000763 Sunniwell Cyber Tech. Co., Ltd.
-000764 YoungWoo Telecom Co. Ltd.
-000765 Jade Quantum Technologies, Inc.
-000766 Chou Chin Industrial Co., Ltd.
-000767 Yuxing Electronics Company Limited
-000768 Danfoss A/S
-000769 Italiana Macchi SpA
-00076A NEXTEYE Co., Ltd.
-00076B Stralfors AB
-00076C Daehanet, Inc.
-00076D Flexlight Networks
-00076E Sinetica Corporation Ltd.
-00076F Synoptics Limited
-000770 Locusnetworks Corporation
-000771 Embedded System Corporation
-000772 Alcatel Shanghai Bell Co., Ltd.
-000773 Ascom Powerline Communications Ltd.
-000774 GuangZhou Thinker Technology Co. Ltd.
-000775 Valence Semiconductor, Inc.
-000776 Federal APD
-000777 Motah Ltd.
-000778 GERSTEL GmbH & Co. KG
-000779 Sungil Telecom Co., Ltd.
-00077A Infoware System Co., Ltd.
-00077B Millimetrix Broadband Networks
-00077C OnTime Networks
-00077E Elrest GmbH
-00077F J Communications Co., Ltd.
-000780 Bluegiga Technologies OY
-000781 Itron Inc.
-000782 Nauticus Networks, Inc.
-000783 SynCom Network, Inc.
-000784 Cisco Systems Inc.
-000785 Cisco Systems Inc.
-000786 Wireless Networks Inc.
-000787 Idea System Co., Ltd.
-000788 Clipcomm, Inc.
-000789 Eastel Systems Corporation
-00078A Mentor Data System Inc.
-00078B Wegener Communications, Inc.
-00078C Elektronikspecialisten i Borlange AB
-00078D NetEngines Ltd.
-00078E Garz & Friche GmbH
-00078F Emkay Innovative Products
-000790 Tri-M Technologies (s) Limited
-000791 International Data Communications, Inc.
-000792 Suetron Electronic GmbH
-000794 Simple Devices, Inc.
-000795 Elitegroup Computer System Co. (ECS)
-000796 LSI Systems, Inc.
-000797 Netpower Co., Ltd.
-000798 Selea SRL
-000799 Tipping Point Technologies, Inc.
-00079A SmartSight Networks Inc.
-00079B Aurora Networks
-00079C Golden Electronics Technology Co., Ltd.
-00079D Musashi Co., Ltd.
-00079E Ilinx Co., Ltd.
-00079F Action Digital Inc.
-0007A0 e-Watch Inc.
-0007A1 VIASYS Healthcare GmbH
-0007A2 Opteon Corporation
-0007A3 Ositis Software, Inc.
-0007A4 GN Netcom Ltd.
-0007A5 Y.D.K Co. Ltd.
-0007A6 Home Automation, Inc.
-0007A7 A-Z Inc.
-0007A8 Haier Group Technologies Ltd.
-0007A9 Novasonics
-0007AA Quantum Data Inc.
-0007AC Eolring
-0007AD Pentacon GmbH Foto-und Feinwerktechnik
-0007AE Layer N Networks
-0007AF N-Tron Corp.
-0007B0 Office Details, Inc.
-0007B1 Equator Technologies
-0007B2 Transaccess S.A.
-0007B3 Cisco Systems Inc.
-0007B4 Cisco Systems Inc.
-0007B5 Any One Wireless Ltd.
-0007B6 Telecom Technology Ltd.
-0007B7 Samurai Ind. Prods Eletronicos Ltda
-0007B8 American Predator Corp.
-0007B9 Ginganet Corporation
-0007BA Xebeo Communications, Inc.
-0007BB Candera Inc.
-0007BC Identix Inc.
-0007BD Radionet Ltd.
-0007BE DataLogic SpA
-0007BF Armillaire Technologies, Inc.
-0007C0 NetZerver Inc.
-0007C1 Overture Networks, Inc.
-0007C2 Netsys Telecom
-0007C3 Cirpack
-0007C4 JEAN Co. Ltd.
-0007C5 Gcom, Inc.
-0007C6 VDS Vosskuhler GmbH
-0007C7 Synectics Systems Limited
-0007C8 Brain21, Inc.
-0007C9 Technol Seven Co., Ltd.
-0007CA Creatix Polymedia Ges Fur Kommunikaitonssysteme
-0007CB Freebox SA
-0007CC Kaba Benzing GmbH
-0007CD NMTEL Co., Ltd.
-0007CE Cabletime Limited
-0007CF Anoto AB
-0007D0 Automat Engenharia de Automaoa Ltda.
-0007D1 Spectrum Signal Processing Inc.
-0007D2 Logopak Systeme
-0007D3 Stork Digital Imaging B.V.
-0007D4 Zhejiang Yutong Network Communication Co Ltd.
-0007D5 3e Technologies Int;., Inc.
-0007D6 Commil Ltd.
-0007D7 Caporis Networks AG
-0007D8 Hitron Systems Inc.
-0007D9 Splicecom
-0007DA Neuro Telecom Co., Ltd.
-0007DB Kirana Networks, Inc.
-0007DC Atek Co, Ltd.
-0007DD Cradle Technologies
-0007DE eCopilt AB
-0007DF Vbrick Systems Inc.
-0007E0 Palm Inc.
-0007E1 WIS Communications Co. Ltd.
-0007E2 Bitworks, Inc.
-0007E3 Navcom Technology, Inc.
-0007E4 SoftRadio Co., Ltd.
-0007E5 Coup Corporation
-0007E6 edgeflow Canada Inc.
-0007E7 FreeWave Technologies
-0007E8 St. Bernard Software
-0007E9 Intel Corporation
-0007EA Massana, Inc.
-0007EB Cisco Systems Inc.
-0007EC Cisco Systems Inc.
-0007ED Altera Corporation
-0007EE telco Informationssysteme GmbH
-0007EF Lockheed Martin Tactical Systems
-0007F0 LogiSync Corporation
-0007F1 TeraBurst Networks Inc.
-0007F2 IOA Corporation
-0007F3 Think Engine Networks
-0007F4 Eletex Co., Ltd.
-0007F5 Bridgeco Co AG
-0007F6 Qqest Software Systems
-0007F7 Galtronics
-0007F8 ITDevices, Inc.
-0007F9 Phonetics, Inc.
-0007FA ITT Co., Ltd.
-0007FB Giga Stream UMTS Technologies GmbH
-0007FC Adept Systems Inc.
-0007FD LANergy Ltd.
-0007FE Rigaku Corporation
-0007FF Gluon Networks
-000800 MULTITECH SYSTEMS, INC.
-000801 HighSpeed Surfing Inc.
-000802 Compaq Computer Corporation
-000803 Cos Tron
-000804 ICA Inc.
-000805 Techno-Holon Corporation
-000806 Raonet Systems, Inc.
-000807 Access Devices Limited
-000808 PPT Vision, Inc.
-000809 Systemonic AG
-00080A Espera-Werke GmbH
-00080B Birka BPA Informationssystem AB
-00080C VDA elettronica SrL
-00080D Toshiba
-00080E Motorola, BCS
-00080F Proximion Fiber Optics AB
-000810 Key Technology, Inc.
-000811 VOIX Corporation
-000812 GM-2 Corporation
-000813 Diskbank, Inc.
-000814 TIL Technologies
-000815 CATS Co., Ltd.
-000816 Bluetags A/S
-000817 EmergeCore Networks LLC
-000818 Pixelworks, Inc.
-000819 Banksys
-00081A Sanrad Intelligence Storage Communications (2000) Ltd.
-00081B Windigo Systems
-00081C @pos.com
-00081D Ipsil, Incorporated
-00081E Repeatit AB
-00081F Pou Yuen Tech Corp. Ltd.
-000820 Cisco Systems Inc.
-000821 Cisco Systems Inc.
-000822 InPro Comm
-000823 Texa Corp.
-000824 Promatek Industries Ltd.
-000825 Acme Packet
-000826 Colorado Med Tech
-000827 Pirelli Cables & Systems
-000828 Koei Engineering Ltd.
-000829 Aval Nagasaki Corporation
-00082A Powerwallz Network Security
-00082B Wooksung Electronics, Inc.
-00082C Homag AG
-00082D Indus Teqsite Private Limited
-00082E Multitone Electronics PLC
-00084E DivergeNet, Inc.
-00084F Qualstar Corporation
-000850 Arizona Instrument Corp.
-000851 Canadian Bank Note Company, Ltd.
-000852 Davolink Co. Inc.
-000853 Schleicher GmbH & Co. Relaiswerke KG
-000854 Netronix, Inc.
-000855 NASA-Goddard Space Flight Center
-000856 Gamatronic Electronic Industries Ltd.
-000857 Polaris Networks, Inc.
-000858 Novatechnology Inc.
-000859 ShenZhen Unitone Electronics Co., Ltd.
-00085A IntiGate Inc.
-00085B Hanbit Electronics Co., Ltd.
-00085C Shanghai Dare Technologies Co. Ltd.
-00085D Aastra
-00085E PCO AG
-00085F Picanol N.V.
-000860 LodgeNet Entertainment Corp.
-000861 SoftEnergy Co., Ltd.
-000862 NEC Eluminant Technologies, Inc.
-000863 Entrisphere Inc.
-000864 Fasy S.p.A.
-000865 JASCOM CO., LTD
-000866 DSX Access Systems, Inc.
-000867 Uptime Devices
-000868 PurOptix
-000869 Command-e Technology Co.,Ltd.
-00086A Industrie Technik IPS GmbH
-00086B MIPSYS
-00086C Plasmon LMS
-00086D Missouri FreeNet
-00086E Hyglo AB
-00086F Resources Computer Network Ltd.
-000870 Rasvia Systems, Inc.
-000871 NORTHDATA Co., Ltd.
-000872 Sorenson Technologies, Inc.
-000873 DAP Design B.V.
-000874 Dell Computer Corp.
-000875 Acorp Electronics Corp.
-000876 SDSystem
-000877 Liebert HIROSS S.p.A.
-000878 Benchmark Storage Innovations
-000879 CEM Corporation
-00087A Wipotec GmbH
-00087B RTX Telecom A/S
-00087C Cisco Systems, Inc.
-00087D Cisco Systems Inc.
-00087E Bon Electro-Telecom Inc.
-00087F SPAUN electronic GmbH & Co. KG
-000880 BroadTel Canada Communications inc.
-000881 DIGITAL HANDS CO.,LTD.
-000882 SIGMA CORPORATION
-000883 Hewlett-Packard Company
-000884 Index Braille AB
-000885 EMS Dr. Thomas Wuensche
-000886 Hansung Teliann, Inc.
-000887 Maschinenfabrik Reinhausen GmbH
-000888 OULLIM Information Technology Inc,.
-000889 Echostar Technologies Corp
-00088A Minds@Work
-00088B Tropic Networks Inc.
-00088C Quanta Network Systems Inc.
-00088D Sigma-Links Inc.
-00088E Nihon Computer Co., Ltd.
-00088F ADVANCED DIGITAL TECHNOLOGY
-000890 AVILINKS SA
-000891 Lyan Inc.
-000892 EM Solutions
-000894 InnoVISION Multimedia Ltd.
-000895 DIRC Technologie GmbH & Co.KG
-000896 Printronix, Inc.
-000897 Quake Technologies
-000898 Gigabit Optics Corporation
-000899 Netbind, Inc.
-00089A Alcatel Microelectronics
-00089B ICP Electronics Inc.
-00089C Elecs Industry Co., Ltd.
-00089D UHD-Elektronik
-00089E Beijing Enter-Net co.LTD
-00089F EFM Networks
-0008A0 Stotz Feinmesstechnik GmbH
-0008A1 CNet Technology Inc.
-0008A2 ADI Engineering, Inc.
-0008A3 Cisco Systems
-0008A4 Cisco Systems
-0008A5 Peninsula Systems Inc.
-0008A6 Multiware & Image Co., Ltd.
-0008A7 iLogic Inc.
-0008A8 Systec Co., Ltd.
-0008A9 SangSang Technology, Inc.
-0008AA KARAM
-0008AB EnerLinx.com, Inc.
-0008AD Toyo-Linx Co., Ltd.
-0008AE Packetfront
-0008AF Novatec Corporation
-0008B0 BKtel communications GmbH
-0008B1 ProQuent Systems
-0008B2 SHENZHEN COMPASS TECHNOLOGY DEVELOPMENT CO.,LTD
-0008B3 Fastwel
-0008B4 SYSPOL
-0008B5 TAI GUEN ENTERPRISE CO., LTD
-0008B6 RouteFree, Inc.
-0008B7 HIT Incorporated
-0008B8 E.F. Johnson
-0008B9 KAON MEDIA Co., Ltd.
-0008BA Erskine Systems Ltd
-0008BB NetExcell
-0008BC Ilevo AB
-0008BD TEPG-US
-0008BE XENPAK MSA Group
-0008BF Aptus Elektronik AB
-0008C0 ASA SYSTEMS
-0008C1 Avistar Communications Corporation
-0008C2 Cisco Systems
-0008C3 Contex A/S
-0008C4 Hikari Co.,Ltd.
-0008C5 Liontech Co., Ltd.
-0008C6 Philips Consumer Communications
-0008C7 COMPAQ COMPUTER CORPORATION
-0008C8 Soneticom, Inc.
-0008C9 TechniSat Digital GmbH
-0008CA TwinHan Technology Co.,Ltd
-0008CB Zeta Broadband Inc.
-0008CC Remotec, Inc.
-0008CD With-Net Inc
-0008CF Nippon Koei Power Systems Co., Ltd.
-0008D0 Musashi Engineering Co., LTD.
-0008D1 KAREL INC.
-0008D2 ZOOM Networks Inc.
-0008D3 Hercules Technologies S.A.
-0008D4 IneoQuest Technologies, Inc
-0008D5 Vanguard Managed Solutions
-0008D6 HASSNET Inc.
-0008D7 HOW CORPORATION
-0008D8 Dowkey Microwave
-0008D9 Mitadenshi Co.,LTD
-0008DA SofaWare Technologies Ltd.
-0008DB Corrigent Systems
-0008DC Wiznet
-0008DD Telena Communications, Inc.
-0008DE 3UP Systems
-0008DF Alistel Inc.
-0008E0 ATO Technology Ltd.
-0008E1 Barix AG
-0008E2 Cisco Systems
-0008E3 Cisco Systems
-0008E4 Envenergy Inc
-0008E5 IDK Corporation
-0008E6 Littlefeet
-0008E7 SHI ControlSystems,Ltd.
-0008E8 Excel Master Ltd.
-0008E9 NextGig
-0008EA Motion Control Engineering, Inc
-0008EB ROMWin Co.,Ltd.
-0008EC Zonu, Inc.
-0008ED ST&T Instrument Corp.
-0008EE Logic Product Development
-0008EF DIBAL,S.A.
-0008F0 Next Generation Systems, Inc.
-0008F1 Voltaire
-0008F2 C&S Technology
-0008F3 WANY
-0008F4 Bluetake Technology Co., Ltd.
-0008F5 YESTECHNOLOGY Co.,Ltd.
-0008F6 SUMITOMO ELECTRIC HIGHTECHS.co.,ltd.
-0008F7 Hitachi Ltd, Semiconductor &amp; Integrated Circuits Gr
-0008F8 Guardall Ltd
-0008F9 Padcom, Inc.
-0008FA Karl E.Brinkmann GmbH
-0008FB SonoSite, Inc.
-0008FC Gigaphoton Inc.
-0008FD BlueKorea Co., Ltd.
-0008FE UNIK C&C Co.,Ltd.
-0008FF Trilogy Broadcast (Holdings) Ltd
-000900 TMT
-000901 Shenzhen Shixuntong Information & Technoligy Co
-000902 Redline Communications Inc.
-000903 Panasas, Inc
-000904 MONDIAL electronic
-000905 iTEC Technologies Ltd.
-000906 Esteem Networks
-000907 Chrysalis Development
-000908 VTech Technology Corp.
-000909 Telenor Connect A/S
-00090A SnedFar Technology Co., Ltd.
-00090B MTL Instruments PLC
-00090C Mayekawa Mfg. Co. Ltd.
-00090D LEADER ELECTRONICS CORP.
-00090E Helix Technology Inc.
-00090F Fortinet Inc.
-000910 Simple Access Inc.
-000911 Cisco Systems
-000912 Cisco Systems
-000914 COMPUTROLS INC.
-000915 CAS Corp.
-000916 Listman Home Technologies, Inc.
-000917 WEM Technology Inc
-000918 SAMSUNG TECHWIN CO.,LTD
-000919 MDS Gateways
-00091A Macat Optics & Electronics Co., Ltd.
-00091B Digital Generation Inc.
-00091C CacheVision, Inc
-00091D Proteam Computer Corporation
-00091E Firstech Technology Corp.
-00091F A&amp;D Co., Ltd.
-000920 EpoX COMPUTER CO.,LTD.
-000921 Planmeca Oy
-000922 Touchless Sensor Technology AG
-000923 Heaman System Co., Ltd
-000924 Telebau GmbH
-000925 VSN Systemen BV
-000926 YODA COMMUNICATIONS, INC.
-000927 TOYOKEIKI CO.,LTD.
-000928 Telecore Inc
-000929 Sanyo Industries (UK) Limited
-00092A MYTECS Co.,Ltd.
-00092B iQstor Networks, Inc.
-00092C Hitpoint Inc.
-00092D High Tech Computer, Corp.
-00092E B&Tech System Inc.
-00092F Akom Technology Corporation
-000930 AeroConcierge Inc.
-000931 Future Internet, Inc.
-000932 Omnilux
-000933 OPTOVALLEY Co. Ltd.
-000934 Dream-Multimedia-Tv GmbH
-000935 Sandvine Incorporated
-000936 Ipetronik GmbH & Co.KG
-000937 Inventec Appliance Corp
-000938 Allot Communications
-000939 ShibaSoku Co.,Ltd.
-00093A Molex Fiber Optics
-00093B HYUNDAI NETWORKS INC.
-00093C Jacques Technologies P/L
-00093D Newisys,Inc.
-00093E C&I Technologies
-00093F Double-Win Enterpirse CO., LTD
-000940 AGFEO GmbH & Co. KG
-000941 Allied Telesis K.K.
-000942 CRESCO, LTD.
-000943 Cisco Systems
-000944 Cisco Systems
-000945 Palmmicro Communications Inc
-000946 Cluster Labs GmbH
-000947 Aztek, Inc.
-000948 Vista Control Systems, Corp.
-000949 Glyph Technologies Inc.
-00094A Homenet Communications
-00094B FillFactory NV
-00094C Communication Weaver Co.,Ltd.
-00094D Braintree Communications Pty Ltd
-00094E BARTECH SYSTEMS INTERNATIONAL, INC
-00094F elmegt GmbH & Co. KG
-000950 Independent Storage Corporation
-000951 Apogee Instruments, Inc
-000952 Auerswald GmbH & Co. KG
-000953 Linkage System Integration Co.Ltd.
-000954 AMiT spol. s. r. o.
-000955 Young Generation International Corp.
-000956 Network Systems Group, Ltd. (NSG)
-000957 Supercaller, Inc.
-000958 INTELNET S.A.
-000959 Sitecsoft
-00095A RACEWOOD TECHNOLOGY
-00095B Netgear, Inc.
-00095C Philips Medical Systems - Cardiac and Monitoring Systems (CM
-00095D Dialogue Technology Corp.
-00095E Masstech Group Inc.
-00095F Telebyte, Inc.
-000960 YOZAN Inc.
-000961 Switchgear and Instrumentation Ltd
-000962 Filetrac AS
-000963 Dominion Lasercom Inc.
-000964 Hi-Techniques
-000966 Thales Navigation
-000967 Tachyon, Inc
-000968 TECHNOVENTURE, INC.
-000969 Meret Optical Communications
-00096A Cloverleaf Communications Inc.
-00096B IBM Corporation
-00096C Imedia Semiconductor Corp.
-00096D Powernet Technologies Corp.
-00096E GIANT ELECTRONICS LTD.
-00096F Beijing Zhongqing Elegant Tech. Corp.,Limited
-000970 Vibration Research Corporation
-000971 Time Management, Inc.
-000972 Securebase,Inc
-000973 Lenten Technology Co., Ltd.
-000974 Innopia Technologies, Inc.
-000975 fSONA Communications Corporation
-000976 Datasoft ISDN Systems GmbH
-000977 Brunner Elektronik AG
-000978 AIJI System Co., Ltd.
-000979 Advanced Television Systems Committee, Inc.
-00097A Louis Design Labs.
-00097B Cisco Systems
-00097C Cisco Systems
-00097D SecWell Networks Oy
-00097E IMI TECHNOLOGY CO., LTD
-00097F Vsecure 2000 LTD.
-000980 Power Zenith Inc.
-000981 Newport Networks
-000982 Loewe Opta GmbH
-000983 Gvision Incorporated
-000984 MyCasa Network Inc.
-000985 Auto Telecom Company
-000986 Metalink LTD.
-000987 NISHI NIPPON ELECTRIC WIRE & CABLE CO.,LTD.
-000988 Nudian Electron Co., Ltd.
-000989 VividLogic Inc.
-00098A EqualLogic Inc
-00098B Entropic Communications, Inc.
-00098C Possio AB
-00098D DCT Ltd (Digital Communication Technologies Ltd)
-00098E ipcas GmbH
-00098F Cetacean Networks
-000990 ACKSYS Communications & systems
-000991 GE Fanuc Automation Manufacturing, Inc.
-000992 InterEpoch Technology,INC.
-000993 Visteon Corporation
-000994 Cronyx Engineering
-000995 Castle Technology Ltd
-000996 RDI
-000997 Nortel Networks
-000998 Capinfo Company Limited
-000999 CP GEORGES RENAULT
-00099A ELMO COMPANY, LIMITED
-00099B Western Telematic Inc.
-00099C Naval Research Laboratory
-00099D Haliplex Communications
-00099E Testech, Inc.
-00099F VIDEX INC.
-0009A0 Microtechno Corporation
-0009A1 Telewise Communications, Inc.
-0009A2 Interface Co., Ltd.
-0009A3 Leadfly Techologies Corp. Ltd.
-0009A4 HARTEC Corporation
-0009A5 HANSUNG ELETRONIC INDUSTRIES DEVELOPMENT CO., LTD
-0009A6 Ignis Optics, Inc.
-0009A7 Bang & Olufsen A/S
-0009A8 Eastmode Pte Ltd
-0009A9 Ikanos Communications
-0009AA Data Comm for Business, Inc.
-0009AB Netcontrol Oy
-0009AC LANVOICE
-0009AD HYUNDAI SYSCOMM, INC.
-0009AE OKANO ELECTRIC CO.,LTD
-0009AF e-generis
-0009B0 Onkyo Corporation
-0009B1 Kanematsu Electronics, Ltd.
-0009B2 L&F Inc.
-0009B3 MCM Systems Ltd
-0009B4 KISAN TELECOM CO., LTD.
-0009B5 3J Tech. Co., Ltd.
-0009B6 Cisco Systems
-0009B7 Cisco Systems
-0009B8 Entise Systems
-0009B9 Action Imaging Solutions
-0009BA MAKU Informationstechik GmbH
-0009BB MathStar, Inc.
-0009BC Digital Safety Technologies Inc.
-0009BD Epygi Technologies, Ltd.
-0009BE Mamiya-OP Co.,Ltd.
-0009BF Nintendo Co.,Ltd.
-0009C0 6WIND
-0009C1 PROCES-DATA A/S
-0009C3 NETAS
-0009C4 Medicore Co., Ltd
-0009C5 KINGENE Technology Corporation
-0009C6 Visionics Corporation
-0009C7 Movistec
-0009C8 SINAGAWA TSUSHIN KEISOU SERVICE
-0009C9 BlueWINC Co., Ltd.
-0009CA iMaxNetworks(Shenzhen)Limited.
-0009CB HBrain
-0009CC Moog GmbH
-0009CD HUDSON SOFT CO.,LTD.
-0009CE SpaceBridge Semiconductor Corp.
-0009CF iAd GmbH
-0009D0 Versatel Networks
-0009D1 SERANOA NETWORKS INC
-0009D2 Mai Logic Inc.
-0009D3 Western DataCom Co., Inc.
-0009D4 Transtech Networks
-0009D5 Signal Communication, Inc.
-0009D6 KNC One GmbH
-0009D7 DC Security Products
-0009D9 Neoscale Systems, Inc
-0009DA Control Module Inc.
-0009DB eSpace
-0009DC Galaxis Technology AG
-0009DD Mavin Technology Inc.
-0009DE Samjin Information & Communications Co., Ltd.
-0009DF Vestel Komunikasyon Sanayi ve Ticaret A.S.
-0009E0 XEMICS S.A.
-0009E1 Gemtek Technology Co., Ltd.
-0009E2 Sinbon Electronics Co., Ltd.
-0009E3 Angel Iglesias S.A.
-0009E4 K Tech Infosystem Inc.
-0009E5 Hottinger Baldwin Messtechnik GmbH
-0009E6 Cyber Switching Inc.
-0009E7 ADC Techonology
-0009E8 Cisco Systems
-0009E9 Cisco Systems
-0009EA YEM Inc.
-0009EB HuMANDATA LTD.
-0009EC Daktronics, Inc.
-0009ED CipherOptics
-0009EE MEIKYO ELECTRIC CO.,LTD
-0009EF Vocera Communications
-0009F0 Shimizu Technology Inc.
-0009F1 Yamaki Electric Corporation
-0009F2 Cohu, Inc., Electronics Division
-0009F3 WELL Communication Corp.
-0009F4 Alcon Laboratories, Inc.
-0009F5 Emerson Network Power Co.,Ltd
-0009F6 Shenzhen Eastern Digital Tech Ltd.
-0009F7 SED, a division of Calian
-0009F8 UNIMO TECHNOLOGY CO., LTD.
-0009F9 ART JAPAN CO., LTD.
-0009FB Philips Medizinsysteme Boeblingen GmbH
-0009FC IPFLEX Inc.
-0009FD Ubinetics Limited
-0009FE Daisy Technologies, Inc.
-0009FF X.net 2000 GmbH
-000A00 Mediatek Corp.
-000A01 SOHOware, Inc.
-000A02 ANNSO CO., LTD.
-000A03 ENDESA SERVICIOS, S.L.
-000A04 3Com Europe Ltd
-000A05 Widax Corp.
-000A06 Teledex LLC
-000A07 WebWayOne Ltd
-000A08 ALPINE ELECTRONICS, INC.
-000A09 TaraCom Integrated Products, Inc.
-000A0A SUNIX Co., Ltd.
-000A0B Sealevel Systems, Inc.
-000A0C Scientific Research Corporation
-000A0D MergeOptics GmbH
-000A0E Invivo Research Inc.
-000A0F Ilryung Telesys, Inc
-000A10 FAST media integrations AG
-000A11 ExPet Technologies, Inc
-000A12 Azylex Technology, Inc
-000A13 Silent Witness
-000A14 TECO a.s.
-000A15 Silicon Data, Inc
-000A16 Lassen Research
-000A17 NESTAR COMMUNICATIONS, INC
-000A18 Vichel Inc.
-000A19 Valere Power, Inc.
-000A1A Imerge Ltd
-000A1B Stream Labs
-000A1C Bridge Information Co., Ltd.
-000A1D Optical Communications Products Inc.
-000A1E Red-M (Communications) Limited
-000A1F ART WARE Telecommunication Co., Ltd.
-000A20 SVA Networks, Inc.
-000A21 Integra Telecom Co. Ltd
-000A22 Amperion Inc
-000A23 Parama Networks Inc
-000A24 Octave Communications
-000A25 CERAGON NETWORKS
-000A26 CEIA S.p.A.
-000A27 Apple Computer, Inc.
-000A28 Motorola
-000A29 Pan Dacom Networking AG
-000A2A QSI Systems Inc.
-000A2B Etherstuff
-000A2C Active Tchnology Corporation
-000A2E MAPLE NETWORKS CO., LTD
-000A2F Artnix Inc.
-000A30 Johnson Controls-ASG
-000A31 HCV Wireless
-000A32 Xsido Corporation
-000A33 Sierra Logic, Inc.
-000A34 Identicard Systems Incorporated
-000A35 Xilinx
-000A36 Synelec Telecom Multimedia
-000A37 Procera Networks, Inc.
-000A38 Netlock Technologies, Inc.
-000A39 LoPA Information Technology
-000A3A J-THREE INTERNATIONAL Holding Co., Ltd.
-000A3B GCT Semiconductor, Inc
-000A3C Enerpoint Ltd.
-000A3D Elo Sistemas Eletronicos S.A.
-000A3E EADS Telecom
-000A3F Data East Corporation
-000A40 Crown Audio
-000A41 Cisco Systems
-000A42 Cisco Systems
-000A43 Chunghwa Telecom Co., Ltd.
-000A44 Avery Dennison Deutschland GmbH
-000A45 Audio-Technica Corp.
-000A46 ARO Controls SAS
-000A47 Allied Vision Technologies
-000A48 Albatron Technology
-000A49 Acopia Networks
-000A4A Targa Systems Ltd.
-000A4B DataPower Technology, Inc.
-000A4C Molecular Devices Corporation
-000A4D Noritz Corporation
-000A4E UNITEK Electronics INC.
-000A4F Brain Boxes Limited
-000A50 REMOTEK CORPORATION
-000A51 GyroSignal Technology Co., Ltd.
-000A52 Venitek Co. Ltd.
-000A53 Intronics, Incorporated
-000A54 Laguna Hills, Inc.
-000A55 MARKEM Corporation
-000A56 HITACHI Maxell Ltd.
-000A57 Hewlett-Packard Company - Standards
-000A58 Ingenieur-Buero Freyer & Siegel
-000A59 HW server
-000A5A GreenNET Technologies Co.,Ltd.
-000A5B Power-One as
-000A5C Carel s.p.a.
-000A5D PUC Founder (MSC) Berhad
-000A5E 3COM Corporation
-000A5F almedio inc.
-000A60 Autostar Technology Pte Ltd
-000A61 Cellinx Systems Inc.
-000A62 Crinis Networks, Inc.
-000A63 DHD GmbH
-000A64 Eracom Technologies
-000A65 GentechMedia.co.,ltd.
-000A66 MITSUBISHI ELECTRIC SYSTEM & SERVICE CO.,LTD.
-000A67 OngCorp
-000A68 SolarFlare Communications, Inc.
-000A69 SUNNY bell Technology Co., Ltd.
-000A6A SVM Microwaves s.r.o.
-000A6B Tadiran Telecom Business Systems LTD
-000A6C Walchem Corporation
-000A6D EKS Elektronikservice GmbH
-000A6E Broadcast Technology Limited
-000A6F ZyTera Technologies Inc.
-000A70 MPLS Forum
-000A71 Avrio Technologies, Inc
-000A72 SimpleTech, Inc.
-000A73 Scientific Atlanta
-000A74 Manticom Networks Inc.
-000A75 Cat Electronics
-000A76 Beida Jade Bird Huaguang Technology Co.,Ltd
-000A77 Bluewire Technologies LLC
-000A78 OLITEC
-000A79 corega K.K.
-000A7A Kyoritsu Electric Co., Ltd.
-000A7B Cornelius Consult
-000A7C Tecton Ltd
-000A7D Valo, Inc.
-000A7E The Advantage Group
-000A7F Teradon Industries, Inc
-000A80 Telkonet Inc.
-000A81 TEIMA Audiotex S.L.
-000A82 TATSUTA SYSTEM ELECTRONICS CO.,LTD.
-000A83 SALTO SYSTEMS S.L.
-000A84 Rainsun Enterprise Co., Ltd.
-000A85 PLAT'C2,Inc
-000A86 Lenze
-000A87 Integrated Micromachines Inc.
-000A88 InCypher S.A.
-000A89 Creval Systems, Inc.
-000A8A Cisco Systems
-000A8B Cisco Systems
-000A8C Guardware Systems Ltd.
-000A8D EUROTHERM LIMITED
-000A8E Invacom Ltd
-000A8F Aska International Inc.
-000A90 Bayside Interactive, Inc.
-000A91 HemoCue AB
-000A92 Presonus Corporation
-000A93 W2 Networks, Inc.
-000A94 ShangHai cellink CO., LTD
-000A95 Apple Computer, Inc.
-000A96 MEWTEL TECHNOLOGY INC.
-000A97 SONICblue, Inc.
-000A98 M+F Gwinner GmbH & Co
-000A99 Dataradio Inc.
-000A9A Aiptek International Inc
-000A9B Towa Meccs Corporation
-000A9C Server Technology, Inc.
-000A9D King Young Technology Co. Ltd.
-000A9E BroadWeb Corportation
-000A9F Pannaway Technologies, Inc.
-000AA0 Cedar Point Communications
-000AA1 V V S Limited
-000AA2 SYSTEK INC.
-000AA3 SHIMAFUJI ELECTRIC CO.,LTD.
-000AA4 SHANGHAI SURVEILLANCE TECHNOLOGY CO,LTD
-000AA5 MAXLINK INDUSTRIES LIMITED
-000AA6 Hochiki Corporation
-000AA7 FEI Company
-000AA8 ePipe Pty. Ltd.
-000AA9 Brooks Automation GmbH
-000AAA AltiGen Communications Inc.
-000AAB TOYOTA MACS, INC.
-000AAC TerraTec Electronic GmbH
-000AAD Stargames Corporation
-000AAE Rosemount Process Analytical
-000AAF Pipal Systems
-000AB0 LOYTEC electronics GmbH
-000AB1 GENETEC Corporation
-000AB2 Fresnel Wireless Systems
-000AB3 Fa. GIRA
-000AB4 ETIC Telecommunications
-000AB5 Digital Electronic Network
-000AB6 COMPUNETIX, INC
-000AB7 Cisco Systems
-000AB8 Cisco Systems
-000AB9 Astera Technologies Corp.
-000ABA Arcon Technology Limited
-000ABB Taiwan Secom Co,. Ltd
-000ABC Seabridge Ltd.
-000ABD Rupprecht & Patashnick Co.
-000ABE OPNET Technologies CO., LTD.
-000ABF HIROTA SS
-000AC0 Fuyoh Video Industry CO., LTD.
-000AC1 Futuretel
-000AC2 FiberHome Telecommunication Technologies CO.,LTD
-000AC3 eM Technics Co., Ltd.
-000AC4 Daewoo Teletech Co., Ltd
-000AC5 Color Kinetics
-000AC7 Unication Group
-000AC8 ZPSYS CO.,LTD. (Planning&Management)
-000AC9 Zambeel Inc
-000ACA YOKOYAMA SHOKAI CO.,Ltd.
-000ACB XPAK MSA Group
-000ACC Winnow Networks, Inc.
-000ACD Sunrich Technology Limited
-000ACE RADIANTECH, INC.
-000ACF PROVIDEO Multimedia Co. Ltd.
-000AD0 Niigata Develoment Center, F.I.T. Co., Ltd.
-000AD1 MWS
-000AD2 JEPICO Corporation
-000AD3 INITECH Co., Ltd
-000AD4 CoreBell Systems Inc.
-000AD5 Brainchild Electronic Co., Ltd.
-000AD6 BeamReach Networks
-000AD8 IPCserv Technology Corp.
-000AD9 Sony Ericsson Mobile Communications AB
-000ADB SkyPilot Network, Inc
-000ADC RuggedCom Inc.
-000ADD InSciTek Microsystems, Inc.
-000ADE Happy Communication Co., Ltd.
-000ADF Gennum Corporation
-000AE0 Fujitsu Softek
-000AE1 EG Technology
-000AE2 Binatone Electronics International, Ltd
-000AE3 YANG MEI TECHNOLOGY CO., LTD
-000AE4 Wistron Corp.
-000AE5 ScottCare Corporation
-000AE6 Elitegroup Computer System Co. (ECS)
-000AE7 ELIOP S.A.
-000AE8 Cathay Roxus Information Technology Co. LTD
-000AE9 AirVast Technology Inc.
-000AEA ADAM ELEKTRONIK LTD.STI.
-000AEB Shenzhen Tp-link Technology Co; Ltd.
-000AEC Koatsu Gas Kogyo Co., Ltd.
-000AED HARTING Vending G.m.b.H. & CO KG
-000AEE GCD Hard- & Software GmbH
-000AEF OTRUM ASA
-000AF0 SHIN-OH ELECTRONICS CO., LTD. R&D
-000AF1 Clarity Design, Inc.
-000AF2 NeoAxiom Corp.
-000AF3 Cisco Systems
-000AF4 Cisco Systems
-000AF5 Airgo Networks, Inc.
-000AF6 Computer Process Controls
-000AF7 Broadcom Corp.
-000AF8 American Telecare Inc.
-000AFA Traverse Technologies Australia
-000AFB Ambri Limited
-000AFC Core Tec Communications, LLC
-000AFD Viking Electronic Services
-000AFE NovaPal Ltd
-000AFF Kilchherr Elektronik AG
-000B00 FUJIAN START COMPUTER EQUIPMENT CO.,LTD
-000B01 DAIICHI ELECTRONICS CO., LTD.
-000B02 Dallmeier electronic
-000B03 Taekwang Industrial Co., Ltd
-000B04 Volktek Corporation
-000B05 Pacific Broadband Networks
-000B06 Motorola BCS
-000B07 Voxpath Networks
-000B08 Pillar Data Systems
-000B09 Ifoundry Systems Singapore
-000B0A dBm Optics
-000B0B Corrent Corporation
-000B0C Agile Systems Inc.
-000B0D Air2U, Inc.
-000B0E Trapeze Networks
-000B0F Nyquist Industrial Control BV
-000B10 11wave Technonlogy Co.,Ltd
-000B11 HIMEJI ABC TRADING CO.,LTD.
-000B13 ZETRON INC
-000B14 ViewSonic Corporation
-000B15 Platypus Technology
-000B16 Communication Machinery Corporation
-000B17 MKS Instruments
-000B19 Vernier Networks, Inc.
-000B1A Teltone Corporation
-000B1B Systronix, Inc.
-000B1D LayerZero Power Systems, Inc.
-000B1E KAPPA opto-electronics GmbH
-000B1F I CON Computer Co.
-000B20 Hirata corporation
-000B21 G-Star Communications Inc.
-000B22 Environmental Systems and Services
-000B23 Efficient Networks, Inc.
-000B24 AirLogic
-000B25 Aeluros
-000B26 Wetek Corporation
-000B27 Scion Corporation
-000B28 Quatech Inc.
-000B29 LG Industrial Systems Co.,Ltd.
-000B2A HOWTEL Co., Ltd.
-000B2B HOSTNET CORPORATION
-000B2C Eiki Industrial Co. Ltd.
-000B2D Danfoss Inc.
-000B2E Cal-Comp Electronics (Thailand) Public Company Limited Taipe
-000B2F bplan GmbH
-000B30 Beijing Gongye Science & Technology Co.,Ltd
-000B31 Yantai ZhiYang Scientific and technology industry CO., LTD
-000B32 VORMETRIC, INC.
-000B33 Vivato
-000B34 ShangHai Broadband Technologies CO.LTD
-000B35 Quad Bit System co., Ltd.
-000B36 Productivity Systems, Inc.
-000B37 MANUFACTURE DES MONTRES ROLEX SA
-000B38 Knuerr AG
-000B39 Keisoku Giken Co.,Ltd.
-000B3A Fortel DTV, Inc.
-000B3B devolo AG
-000B3C Cygnal Integrated Products, Inc.
-000B3D CONTAL OK Ltd.
-000B3E BittWare, Inc
-000B3F Anthology Solutions Inc.
-000B40 OpNext Inc.
-000B41 Ing. Buero Dr. Beutlhauser
-000B42 commax Co., Ltd.
-000B43 Microscan Systems, Inc.
-000B44 Concord IDea Corp.
-000B45 Cisco
-000B46 Cisco
-000B47 Advanced Energy
-000B48 sofrel
-000B49 RF-Link System Inc.
-000B4A Visimetrics (UK) Ltd
-000B4B VISIOWAVE SA
-000B4C Clarion (M) Sdn Bhd
-000B4D Emuzed
-000B4E VertexRSI Antenna Products Division
-000B4F Verifone, INC.
-000B50 Oxygnet
-000B51 Micetek International Inc.
-000B52 JOYMAX ELECTRONICS CORP.
-000B53 INITIUM Co., Ltd.
-000B54 BiTMICRO Networks, Inc.
-000B55 ADInstruments
-000B56 Cybernetics
-000B57 Silicon Laboratories
-000B58 Astronautics C.A LTD
-000B59 ScriptPro, LLC
-000B5A HyperEdge
-000B5B Rincon Research Corporation
-000B5C Newtech Co.,Ltd
-000B5D FUJITSU LIMITED
-000B5E ATMAVA Ltd
-000B5F Cisco Systems
-000B60 Cisco Systems
-000B61 Friedrich Lütze GmbH &Co.
-000B62 Ingenieurbüro Ingo Mohnen
-000B64 Kieback & Peter GmbH & Co KG
-000B65 Sy.A.C. srl
-000B66 Teralink Communications
-000B67 Topview Technology Corporation
-000B68 Addvalue Communications Pte Ltd
-000B69 Franke Finland Oy
-000B6A Asiarock Incorporation
-000B6B Wistron Neweb Corp.
-000B6C Sychip Inc.
-000B6D SOLECTRON JAPAN NAKANIIDA
-000B6E Neff Instrument Corp.
-000B6F Media Streaming Networks Inc
-000B70 Load Technology, Inc.
-000B71 Litchfield Communications Inc.
-000B72 Lawo AG
-000B73 Kodeos Communications
-000B74 Kingwave Technology Co., Ltd.
-000B75 Iosoft Ltd.
-000B76 ET&T Co. Ltd.
-000B77 Cogent Systems, Inc.
-000B78 TAIFATECH INC.
-000B79 X-COM, Inc.
-000B7B Test-Um Inc.
-000B7C Telex Communications
-000B7D SOLOMON EXTREME INTERNATIONAL LTD.
-000B7E SAGINOMIYA Seisakusho Inc.
-000B7F OmniWerks
-000B81 Kaparel Corporation
-000B82 Grandstream Networks, Inc.
-000B83 DATAWATT B.V.
-000B84 BODET
-000B85 Airespace, Inc.
-000B86 Aruba Networks
-000B87 American Reliance Inc.
-000B88 Vidisco ltd.
-000B89 Top Global Technology, Ltd.
-000B8A MITEQ Inc.
-000B8B KERAJET, S.A.
-000B8C flextronics israel
-000B8D Avvio Networks
-000B8E Ascent Corporation
-000B8F AKITA ELECTRONICS SYSTEMS CO.,LTD.
-000B90 Covaro Networks, Inc.
-000B91 Aglaia Gesellschaft für Bildverarbeitung und Kommunikation m
-000B92 Ascom Danmark A/S
-000B93 Barmag Electronic
-000B94 Digital Monitoring Products, Inc.
-000B95 eBet Gaming Systems Pty Ltd
-000B96 Innotrac Diagnostics Oy
-000B97 Matsushita Electric Industrial Co.,Ltd.
-000B98 NiceTechVision
-000B99 SensAble Technologies, Inc.
-000B9A Shanghai Ulink Telecom Equipment Co. Ltd.
-000B9B Sirius System Co, Ltd.
-000B9C TriBeam Technologies, Inc.
-000B9D TwinMOS Technologies Inc.
-000B9E Yasing Technology Corp.
-000B9F Neue ELSA GmbH
-000BA0 T&L Information Inc.
-000BA1 SYSCOM Ltd.
-000BA2 Sumitomo Electric Networks, Inc
-000BA3 Siemens AG, I&S
-000BA4 Shiron Satellite Communications Ltd. (1996)
-000BA5 Quasar Cipta Mandiri, PT
-000BA6 Miyakawa Electric Works Ltd.
-000BA7 Maranti Networks
-000BA8 HANBACK ELECTRONICS CO., LTD.
-000BAA Aiphone co.,Ltd
-000BAB Advantech Technology (CHINA) Co., Ltd.
-000BAC 3Com Europe Ltd.
-000BAD PC-PoS Inc.
-000BAE Vitals System Inc.
-000BB0 Sysnet Telematica srl
-000BB1 Super Star Technology Co., Ltd.
-000BB2 SMALLBIG TECHNOLOGY
-000BB3 RiT technologies Ltd.
-000BB4 RDC Semiconductor Inc.,
-000BB5 nStor Technologies, Inc.
-000BB6 Mototech Inc.
-000BB7 Micro Systems Co.,Ltd.
-000BB8 Kihoku Electronic Co.
-000BB9 Imsys AB
-000BBA Harmonic Broadband Access Networks
-000BBB Etin Systems Co., Ltd
-000BBC En Garde Systems, Inc.
-000BBD Connexionz Limited
-000BBE Cisco Systems
-000BBF Cisco Systems
-000BC0 China IWNComm Co., Ltd.
-000BC1 Bay Microsystems, Inc.
-000BC2 Corinex Communication Corp.
-000BC3 Multiplex, Inc.
-000BC4 BIOTRONIK GmbH & Co
-000BC5 SMC Networks, Inc.
-000BC6 ISAC, Inc.
-000BC7 ICET S.p.A.
-000BC8 AirFlow Networks
-000BC9 Electroline Equipment
-000BCA DATAVAN International Corporation
-000BCB Fagor Automation , S. Coop
-000BCC JUSAN, S.A.
-000BCD Compaq (HP)
-000BCE Free2move AB
-000BCF AGFA NDT INC.
-000BD0 XiMeta Technology Americas Inc.
-000BD1 Aeronix, Inc.
-000BD2 Remopro Technology Inc.
-000BD3 cd3o
-000BD4 Beijing Wise Technology & Science Development Co.Ltd
-000BD5 Nvergence, Inc.
-000BD6 Paxton Access Ltd
-000BD7 MBB Gelma GmbH
-000BD8 Industrial Scientific Corp.
-000BD9 General Hydrogen
-000BDA EyeCross Co.,Inc.
-000BDB Dell ESG PCBA Test
-000BDC AKCP
-000BDD TOHOKU RICOH Co., LTD.
-000BDF Shenzhen RouterD Networks Limited
-000BE0 SercoNet Ltd.
-000BE2 Lumenera Corporation
-000BE3 Key Stream Co., Ltd.
-000BE4 Hosiden Corporation
-000BE5 HIMS Korea Co., Ltd.
-000BE6 Datel Electronics
-000BE7 COMFLUX TECHNOLOGY INC.
-000BE8 AOIP
-000BEA Zultys Technologies
-000BEB Systegra AG
-000BEC NIPPON ELECTRIC INSTRUMENT, INC.
-000BED ELM Inc.
-000BEE inc.jet, Incorporated
-000BEF Code Corporation
-000BF0 MoTEX Products Co., Ltd.
-000BF1 LAP Laser Applikations
-000BF2 Chih-Kan Technology Co., Ltd.
-000BF3 BAE SYSTEMS
-000BF5 Shanghai Sibo Telecom Technology Co.,Ltd
-000BF6 Nitgen Co., Ltd
-000BF7 NIDEK CO.,LTD
-000BF8 Infinera
-000BF9 Gemstone communications, Inc.
-000BFB D-NET International Corporation
-000BFC Cisco Systems
-000BFD Cisco Systems
-000BFE CASTEL Broadband Limited
-000BFF Berkeley Camera Engineering
-000C00 BEB Industrie-Elektronik AG
-000C01 Abatron AG
-000C02 ABB Oy
-000C03 HDMI Licensing, LLC
-000C04 Tecnova
-000C05 RPA Reserch Co., Ltd.
-000C06 Nixvue Systems Pte Ltd
-000C07 Iftest AG
-000C08 HUMEX Technologies Corp.
-000C09 Hitachi IE Systems Co., Ltd
-000C0A Guangdong Province Electronic Technology Research Institute
-000C0B Broadbus Technologies
-000C0C APPRO TECHNOLOGY INC.
-000C0D Communications & Power Industries / Satcom Division
-000C0E XtremeSpectrum, Inc.
-000C0F Techno-One Co., Ltd
-000C10 PNI Corporation
-000C11 NIPPON DEMPA CO.,LTD.
-000C12 Micro-Optronic-Messtechnik GmbH
-000C13 MediaQ
-000C14 Diagnostic Instruments, Inc.
-000C15 CyberPower Systems, Inc.
-000C16 Concorde Microsystems Inc.
-000C17 AJA Video Systems Inc
-000C18 Zenisu Keisoku Inc.
-000C19 Telio Communications GmbH
-000C1A Quest Technical Solutions Inc.
-000C1B ORACOM Co, Ltd.
-000C1C MicroWeb Co., Ltd.
-000C1D Mettler & Fuchs AG
-000C1E Global Cache
-000C1F Glimmerglass Networks
-000C20 Fi WIn, Inc.
-000C21 Faculty of Science and Technology, Keio University
-000C22 Double D Electronics Ltd
-000C23 Beijing Lanchuan Tech. Co., Ltd.
-000C25 Allied Telesyn Networks
-000C26 Weintek Labs. Inc.
-000C27 Sammy Corporation
-000C28 RIFATRON
-000C29 VMware, Inc.
-000C2A OCTTEL Communication Co., Ltd.
-000C2B ELIAS Technology, Inc.
-000C2C Enwiser Inc.
-000C2D FullWave Technology Co., Ltd.
-000C2E Openet information technology(shenzhen) Co., Ltd.
-000C2F SeorimTechnology Co.,Ltd.
-000C30 Cisco
-000C31 Cisco
-000C32 Avionic Design Development GmbH
-000C33 Compucase Enterprise Co. Ltd.
-000C34 Vixen Co., Ltd.
-000C35 KaVo Dental GmbH & Co. KG
-000C36 SHARP TAKAYA ELECTRONICS INDUSTRY CO.,LTD.
-000C37 Geomation, Inc.
-000C38 TelcoBridges Inc.
-000C39 Sentinel Wireless Inc.
-000C3A Oxance
-000C3B Orion Electric Co., Ltd.
-000C3C MediaChorus, Inc.
-000C3D Glsystech Co., Ltd.
-000C3E Crest Audio
-000C3F Cogent Defence & Security Networks,
-000C40 Altech Controls
-000C41 The Linksys Group, Inc.
-000C42 Routerboard.com
-000C43 Ralink Technology, Corp.
-000C44 Automated Interfaces, Inc.
-000C45 Animation Technologies Inc.
-000C46 Allied Telesyn Inc.
-000C47 SK Teletech(R&D Planning Team)
-000C48 QoStek Corporation
-000C49 Dangaard Telecom RTC Division A/S
-000C4A Cygnus Microsystems Private Limited
-000C4B Cheops Elektronik
-000C4C Arcor AG&Co.
-000C4D ACRA CONTROL
-000C4E Winbest Technology CO,LT
-000C4F UDTech Japan Corporation
-000C50 Seagate Technology
-000C51 Scientific Technologies Inc.
-000C52 Roll Systems Inc.
-000C54 Pedestal Networks, Inc
-000C55 Microlink Communications Inc.
-000C56 Megatel Computer (1986) Corp.
-000C57 MACKIE Engineering Services Belgium BVBA
-000C58 M&S Systems
-000C59 Indyme Electronics, Inc.
-000C5A IBSmm Industrieelektronik Multimedia
-000C5B HANWANG TECHNOLOGY CO.,LTD
-000C5C GTN Systems B.V.
-000C5D CHIC TECHNOLOGY (CHINA) CORP.
-000C5F Avtec, Inc.
-000C60 ACM Systems
-000C61 AC Tech corporation DBA Advanced Digital
-000C62 ABB Automation Technology Products AB, Control
-000C63 Zenith Electronics Corporation
-000C64 X2 MSA Group
-000C65 Sunin Telecom
-000C66 Pronto Networks Inc
-000C67 OYO ELECTRIC CO.,LTD
-000C68 Oasis Semiconductor, Inc.
-000C69 National Radio Astronomy Observatory
-000C6A MBARI
-000C6B Kurz Industrie-Elektronik GmbH
-000C6C Elgato Systems LLC
-000C6D BOC Edwards
-000C6E ASUSTEK COMPUTER INC.
-000C6F Amtek system co.,LTD.
-000C70 ACC GmbH
-000C71 Wybron, Inc
-000C72 Tempearl Industrial Co., Ltd.
-000C73 TELSON ELECTRONICS CO., LTD
-000C74 RIVERTEC CORPORATION
-000C75 Oriental integrated electronics. LTD
-000C76 MICRO-STAR INTERNATIONAL CO., LTD.
-000C77 Life Racing Ltd
-000C78 In-Tech Electronics Limited
-000C79 Extel Communications P/L
-000C7A DaTARIUS Technologies GmbH
-000C7B ALPHA PROJECT Co.,Ltd.
-000C7C Internet Information Image Inc.
-000C7D TEIKOKU ELECTRIC MFG. CO., LTD
-000C7E Tellium Incorporated
-000C7F synertronixx GmbH
-000C80 Opelcomm Inc.
-000C81 Nulec Industries Pty Ltd
-000C82 NETWORK TECHNOLOGIES INC
-000C83 Logical Solutions
-000C84 Eazix, Inc.
-000C85 Cisco Systems
-000C86 Cisco Systems
-000C87 ATI
-000C88 Apache Micro Peripherals, Inc.
-000C89 AC Electric Vehicles, Ltd.
-000C8A Bose Corporation
-000C8B Connect Tech Inc
-000C8C KODICOM CO.,LTD.
-000C8D MATRIX VISION GmbH
-000C8E Mentor Engineering Inc
-000C8F Nergal s.r.l.
-000C90 Octasic Inc.
-000C91 Riverhead Networks Inc.
-000C92 WolfVision Gmbh
-000C93 Xeline Co., Ltd.
-000C94 United Electronic Industries, Inc.
-000C95 PrimeNet
-000C96 OQO, Inc.
-000C97 NV ADB TTV Technologies SA
-000C98 LETEK Communications Inc.
-000C99 HITEL LINK Co.,Ltd
-000C9A Hitech Electronics Corp.
-000C9B EE Solutions, Inc
-000C9C Chongho information & communications
-000C9D AirWalk Communications, Inc.
-000C9E MemoryLink Corp.
-000C9F NKE Corporation
-000CA0 StorCase Technology, Inc.
-000CA1 SIGMACOM Co., LTD.
-000CA2 Scopus Network Technologies Ltd
-000CA3 Rancho Technology, Inc.
-000CA4 Prompttec Product Management GmbH
-000CA6 Mintera Corporation
-000CA7 Metro (Suzhou) Technologies Co., Ltd.
-000CA8 Garuda Networks Corporation
-000CA9 Ebtron Inc.
-000CAA Cubic Transportation Systems Inc
-000CAB COMMEND International
-000CAC Citizen Watch Co., Ltd.
-000CAD BTU International
-000CAE Ailocom Oy
-000CAF TRI TERM CO.,LTD.
-000CB0 Star Semiconductor Corporation
-000CB1 Salland Engineering (Europe) BV
-000CB2 safei Co., Ltd.
-000CB3 ROUND Co.,Ltd.
-000CB4 Propagate Networks, Inc
-000CB5 Premier Technolgies, Inc
-000CB6 NANJING SEU MOBILE & INTERNET TECHNOLOGY CO.,LTD
-000CB7 Nanjing Huazhuo Electronics Co., Ltd.
-000CB8 MEDION AG
-000CB9 LEA
-000CBA Jamex
-000CBB ISKRAEMECO
-000CBC Iscutum
-000CBD Interface Masters, Inc
-000CBF Holy Stone Ent. Co., Ltd.
-000CC0 Genera Oy
-000CC1 Cooper Industries Inc.
-000CC3 BeWAN systems
-000CC4 Tiptel AG
-000CC5 Nextlink Co., Ltd.
-000CC6 Ka-Ro electronics GmbH
-000CC7 Intelligent Computer Solutions Inc.
-000CC8 Integrated Digital Systems, Inc.
-000CC9 ILWOO DATA & TECHNOLOGY CO.,LTD
-000CCA Hitachi Global Storage Technologies
-000CCB Design Combus Ltd
-000CCC Bluesoft Ltd.
-000CCD IEC - TC57
-000CCE Cisco Systems
-000CCF Cisco Systems
-000CD0 Symetrix
-000CD1 SFOM Technology Corp.
-000CD2 Schaffner EMV AG
-000CD3 Prettl Elektronik Radeberg GmbH
-000CD4 Positron Public Safety Systems inc.
-000CD5 Passave Inc.
-000CD6 PARTNER TECH
-000CD7 Nallatech Ltd
-000CD8 M. K. Juchheim GmbH & Co
-000CD9 Itcare Co., Ltd
-000CDA FreeHand Systems, Inc.
-000CDB Foundry Networks
-000CDC BECS Technology, Inc
-000CDD AOS Technologies AG
-000CDE ABB STOTZ-KONTAKT GmbH
-000CDF PULNiX America, Inc
-000CE0 Trek Diagnostics Inc.
-000CE1 The Open Group
-000CE2 Rolls-Royce
-000CE3 Option International N.V.
-000CE4 NeuroCom International, Inc.
-000CE5 Motorola BCS
-000CE6 Meru Networks Inc
-000CE7 MediaTek Inc.
-000CE8 GuangZhou AnJuBao Co., Ltd
-000CE9 BLOOMBERG L.P.
-000CEA aphona Kommunikationssysteme
-000CEB CNMP Networks, Inc.
-000CEC Spectracom Corp.
-000CED Real Digital Media
-000CEE Q-Networks
-000CEF Open Networks Engineering Ltd
-000CF0 M & N GmbH
-000CF1 Intel Corporation
-000CF2 GAMESA EÓLICA
-000CF3 CALL IMAGE SA
-000CF4 AKATSUKI ELECTRIC MFG.CO.,LTD.
-000CF5 InfoExpress
-000CF6 Sitecom Europe BV
-000CF7 Nortel Networks
-000CF8 Nortel Networks
-000CF9 ITT Flygt AB
-000CFA Digital Systems Corp
-000CFB Korea Network Systems
-000CFC S2io Technologies Corp
-000CFE Grand Electronic Co., Ltd
-000CFF MRO-TEK LIMITED
-000D00 Seaway Networks Inc.
-000D01 P&E Microcomputer Systems, Inc.
-000D02 NEC Access Technica,Ltd
-000D03 Matrics, Inc.
-000D04 Foxboro Eckardt Development GmbH
-000D05 cybernet manufacturing inc.
-000D06 Compulogic Limited
-000D07 Calrec Audio Ltd
-000D08 AboveCable, Inc.
-000D09 Yuehua(Zhuhai) Electronic CO. LTD
-000D0A Projectiondesign as
-000D0B Melco Inc.
-000D0C MDI Security Systems
-000D0D ITSupported, LLC
-000D0E Inqnet Systems, Inc.
-000D0F Finlux Ltd
-000D10 Embedtronics Oy
-000D11 DENTSPLY - Gendex
-000D12 AXELL Corporation
-000D13 Wilhelm Rutenbeck GmbH&Co.
-000D14 Vtech Innovation LP dba Advanced American Telephones
-000D15 Voipac s.r.o.
-000D16 UHS Systems Pty Ltd
-000D17 Turbo Networks Co.Ltd
-000D18 Sunitec Enterprise Co., Ltd.
-000D19 ROBE Show lighting
-000D1A Mustek System Inc.
-000D1B Kyoto Electronics Manufacturing Co., Ltd.
-000D1C I2E TELECOM
-000D1D HIGH-TEK HARNESS ENT. CO., LTD.
-000D1E Control Techniques
-000D1F AV Digital
-000D20 ASAHIKASEI TECHNOSYSTEM CO.,LTD.
-000D21 WISCORE Inc.
-000D22 Unitronics
-000D23 Smart Solution, Inc
-000D24 SENTEC E&E CO., LTD.
-000D25 SANDEN CORPORATION
-000D26 Primagraphics Limited
-000D27 MICROPLEX Printware AG
-000D28 Cisco
-000D29 Cisco
-000D2A Scanmatic AS
-000D2B Racal Instruments
-000D2C Patapsco Designs Ltd
-000D2D NCT Deutschland GmbH
-000D2E Matsushita Avionics Systems Corporation
-000D2F AIN Comm.Tech.Co., LTD
-000D30 IceFyre Semiconductor
-000D31 Compellent Technologies, Inc.
-000D32 DispenseSource, Inc.
-000D33 Prediwave Corp.
-000D34 Shell International Exploration and Production, Inc.
-000D35 PAC International Ltd
-000D36 Wu Han Routon Electronic Co., Ltd
-000D37 WIPLUG
-000D38 NISSIN INC.
-000D39 Network Electronics
-000D3A Microsoft Corp.
-000D3B Microelectronics Technology Inc.
-000D3C i.Tech Dynamic Ltd
-000D3E APLUX Communications Ltd.
-000D3F VXI Technology
-000D40 Verint Loronix Video Solutions
-000D41 Siemens AG ICM MP UC RD IT KLF1
-000D42 Newbest Development Limited
-000D43 DRS Tactical Systems Inc.
-000D45 Tottori SANYO Electric Co., Ltd.
-000D46 Eurotherm Drives, Ltd.
-000D47 Collex
-000D48 AEWIN Technologies Co., Ltd.
-000D49 Triton Systems of Delaware, Inc.
-000D4A Steag ETA-Optik
-000D4B Roku, LLC
-000D4C Outline Electronics Ltd.
-000D4D Ninelanes
-000D4E NDR Co.,LTD.
-000D4F Kenwood Corporation
-000D50 Galazar Networks
-000D51 DIVR Systems, Inc.
-000D52 Comart system
-000D53 Beijing 5w Communication Corp.
-000D54 3Com Europe Ltd
-000D55 SANYCOM Technology Co.,Ltd
-000D56 Dell PCBA Test
-000D57 Fujitsu I-Network Systems Limited.
-000D59 Amity Systems, Inc.
-000D5A Tiesse SpA
-000D5B Smart Empire Investments Limited
-000D5C Robert Bosch GmbH, VT-ATMO
-000D5D Raritan Computer, Inc
-000D5E NEC CustomTechnica, Ltd.
-000D5F Minds Inc
-000D60 IBM Corporation
-000D61 Giga-Byte Technology Co., Ltd.
-000D62 Funkwerk Dabendorf GmbH
-000D63 DENT Instruments, Inc.
-000D64 COMAG Handels AG
-000D65 Cisco Systems
-000D66 Cisco Systems
-000D67 BelAir Networks Inc.
-000D68 Vinci Systems, Inc.
-000D69 TMT&D Corporation
-000D6A Redwood Technologies LTD
-000D6B Mita-Teknik A/S
-000D6C M-Audio
-000D6D K-Tech Devices Corp.
-000D6E K-Patents Oy
-000D6F Ember Corporation
-000D70 Datamax Corporation
-000D71 boca systems
-000D72 2Wire, Inc
-000D73 Technical Support, Inc.
-000D74 Sand Network Systems, Inc.
-000D75 Kobian Pte Ltd - Taiwan Branch
-000D76 Hokuto Denshi Co,. Ltd.
-000D77 FalconStor Software
-000D78 Engineering & Security
-000D79 Dynamic Solutions Co,.Ltd.
-000D7A DiGATTO Asia Pacific Pte Ltd
-000D7B Consensys Computers Inc.
-000D7C Codian Ltd
-000D7D Afco Systems
-000D7E Axiowave Networks, Inc.
-000D7F MIDAS COMMUNICATION TECHNOLOGIES PTE LTD ( Foreign Branch)
-000D80 Online Development Inc
-000D81 Pepperl+Fuchs GmbH
-000D82 PHS srl
-000D83 Sanmina-SCI Hungary Ltd.
-000D84 Seodu Inchip, Inc.
-000D85 Tapwave, Inc.
-000D86 Huber + Suhner AG
-000D87 Elitegroup Computer System Co. (ECS)
-000D88 D-Link Corporation
-000D89 Bils Technology Inc
-000D8A Winners Electronics Co., Ltd.
-000D8B T&D Corporation
-000D8C Shanghai Wedone Digital Ltd. CO.
-000D8D ProLinx Communication Gateways, Inc.
-000D8E Koden Electronics Co., Ltd.
-000D8F King Tsushin Kogyo Co., LTD.
-000D90 Factum Electronics AB
-000D91 Eclipse (HQ Espana) S.L.
-000D92 Arima Communication Corporation
-000D93 Apple Computer
-000D94 AFAR Communications,Inc
-000D96 Vtera Technology Inc.
-000D97 Tropos Networks, Inc.
-000D98 S.W.A.C. Schmitt-Walter Automation Consult GmbH
-000D99 Orbital Sciences Corp.; Launch Systems Group
-000D9A INFOTEC LTD
-000D9C Elan GmbH & Co KG
-000D9D Hewlett Packard
-000D9E TOKUDEN OHIZUMI SEISAKUSYO Co.,Ltd.
-000D9F RF Micro Devices
-000DA0 NEDAP N.V.
-000DA1 MIRAE ITS Co.,LTD.
-000DA2 Infrant Technologies, Inc.
-000DA3 Emerging Technologies Limited
-000DA4 DOSCH & AMAND SYSTEMS AG
-000DA5 Fabric7 Systems, Inc
-000DA6 Universal Switching Corporation
-000DA8 Teletronics Technology Corporation
-000DA9 T.E.A.M. S.L.
-000DAA S.A.Tehnology co.,Ltd.
-000DAB Parker Hannifin GmbH Electromechanical Division Europe
-000DAC Japan CBM Corporation
-000DAD Dataprobe Inc
-000DAE SAMSUNG HEAVY INDUSTRIES CO., LTD.
-000DAF Plexus Corp (UK) Ltd
-000DB0 Olym-tech Co.,Ltd.
-000DB1 Japan Network Service Co., Ltd.
-000DB2 Ammasso, Inc.
-000DB3 SDO Communication Corperation
-000DB4 NETASQ
-000DB5 GLOBALSAT TECHNOLOGY CORPORATION
-000DB6 Teknovus, Inc.
-000DB7 SANKO ELECTRIC CO,.LTD
-000DB8 SCHILLER AG
-000DB9 PC Engines GmbH
-000DBA Océ Document Technologies GmbH
-000DBB Nippon Dentsu Co.,Ltd.
-000DBC Cisco Systems
-000DBD Cisco Systems
-000DBE Bel Fuse Europe Ltd.,UK
-000DBF TekTone Sound & Signal Mfg., Inc.
-000DC0 Spagat AS
-000DC1 SafeWeb Inc
-000DC3 First Communication, Inc.
-000DC4 Emcore Corporation
-000DC5 EchoStar International Corporation
-000DC6 DigiRose Technology Co., Ltd.
-000DC7 COSMIC ENGINEERING INC.
-000DC8 AirMagnet, Inc
-000DC9 THALES Elektronik Systeme GmbH
-000DCA Tait Electronics
-000DCB Petcomkorea Co., Ltd.
-000DCC NEOSMART Corp.
-000DCD GROUPE TXCOM
-000DCE Dynavac Technology Pte Ltd
-000DCF Cidra Corp.
-000DD0 TetraTec Instruments GmbH
-000DD1 Stryker Corporation
-000DD2 Simrad Optronics ASA
-000DD3 SAMWOO Telecommunication Co.,Ltd.
-000DD4 Revivio Inc.
-000DD5 O'RITE TECHNOLOGY CO.,LTD
-000DD7 Bright
-000DD8 BBN
-000DD9 Anton Paar GmbH
-000DDA ALLIED TELESIS K.K.
-000DDB AIRWAVE TECHNOLOGIES INC.
-000DDC VAC
-000DDD PROFÝLO TELRA ELEKTRONÝK SANAYÝ VE TÝCARET A.Þ.
-000DDE Joyteck Co., Ltd.
-000DDF Japan Image & Network Inc.
-000DE0 ICPDAS Co.,LTD
-000DE1 Control Products, Inc.
-000DE2 CMZ Sistemi Elettronici
-000DE3 AT Sweden AB
-000DE4 DIGINICS, Inc.
-000DE5 Samsung Thales
-000DE6 YOUNGBO ENGINEERING CO.,LTD
-000DE7 Snap-on OEM Group
-000DE8 Nasaco Electronics Pte. Ltd
-000DE9 Napatech Aps
-000DEA Kingtel Telecommunication Corp.
-000DEB CompXs Limited
-000DEC Cisco Systems
-000DED Cisco Systems
-000DEF Soc. Coop. Bilanciai
-000DF0 QCOM TECHNOLOGY INC.
-000DF1 IONIX INC.
-000DF3 Asmax Solutions
-000DF4 Watertek Co.
-000DF5 Teletronics International Inc.
-000DF6 Technology Thesaurus Corp.
-000DF7 Space Dynamics Lab
-000DF8 ORGA Kartensysteme GmbH
-000DF9 NDS Limited
-000DFA Micro Control Systems Ltd.
-000DFB Komax AG
-000DFC ITFOR Inc. resarch and development
-000DFD Huges Hi-Tech Inc.,
-000DFE Hauppauge Computer Works, Inc.
-000DFF CHENMING MOLD INDUSTRY CORP.
-000E01 ASIP Technologies Inc.
-000E02 Advantech AMT Inc.
-000E03 Aarohi Communications, Inc.
-000E05 WIRELESS MATRIX CORP.
-000E06 Team Simoco Ltd
-000E07 Sony Ericsson Mobile Communications AB
-000E08 Sipura Technology, Inc.
-000E09 Shenzhen Coship Software Co.,LTD.
-000E0B Netac Technology Co., Ltd.
-000E0C Intel Corporation
-000E0D HESCH Schröder GmbH
-000E0E ESA elettronica S.P.A.
-000E0F ERMME
-000E11 BDT Büro- und Datentechnik GmbH & Co. KG
-000E12 Adaptive Micro Systems Inc.
-000E13 Accu-Sort Systems inc.
-000E14 Visionary Solutions, Inc.
-000E15 Tadlys LTD
-000E16 SouthWing
-000E18 MyA Technology
-000E19 LogicaCMG Pty Ltd
-000E1B IAV GmbH
-000E1C Hach Company
-000E1F TCL Networks Equipment Co., Ltd.
-000E20 PalmSource, Inc.
-000E21 MTU Friedrichshafen GmbH
-000E23 Incipient, Inc.
-000E25 Hannae Technology Co., Ltd
-000E26 Gincom Technology Corp.
-000E27 Crere Networks, Inc.
-000E28 Dynamic Ratings P/L
-000E29 Shester Communications Inc
-000E2B Safari Technologies
-000E2C Netcodec co.
-000E2D Hyundai Digital Technology Co.,Ltd.
-000E2E Edimax Technology Co., Ltd.
-000E2F Disetronic Medical Systems AG
-000E30 AERAS Networks, Inc.
-000E31 Olympus BioSystems GmbH
-000E32 Kontron Medical
-000E33 Shuko Electronics Co.,Ltd
-000E34 NexxGenCity
-000E35 Intel Corp
-000E36 HEINESYS, Inc.
-000E37 Harms & Wende GmbH & Co.KG
-000E38 Cisco Systems
-000E39 Cisco Systems
-000E3A Cirrus Logic
-000E3B Hawking Technologies, Inc.
-000E3C TransAct Technoloiges Inc.
-000E3D Televic N.V.
-000E3E Sun Optronics Inc
-000E3F Soronti, Inc.
-000E40 Nortel Networks
-000E41 NIHON MECHATRONICS CO.,LTD.
-000E42 Motic Incoporation Ltd.
-000E43 G-Tek Electronics Sdn. Bhd.
-000E44 Digital 5, Inc.
-000E45 Beijing Newtry Electronic Technology Ltd
-000E46 Niigata Seimitsu Co.,Ltd.
-000E47 NCI System Co.,Ltd.
-000E48 Lipman TransAction Solutions
-000E49 Forsway Scandinavia AB
-000E4A Changchun Huayu WEBPAD Co.,LTD
-000E4B atrium c and i
-000E4C Bermai Inc.
-000E4D Numesa Inc.
-000E4E Waveplus Technology Co., Ltd.
-000E4F Trajet GmbH
-000E50 Thomson Multi Media
-000E51 tecna elettronica srl
-000E52 Optium Corporation
-000E53 AV TECH CORPORATION
-000E54 AlphaCell Wireless Ltd.
-000E55 AUVITRAN
-000E56 4G Systems GmbH
-000E57 Iworld Networking, Inc.
-000E58 Rincon Networks
-000E5A TELEFIELD inc.
-000E5B ParkerVision - Direct2Data
-000E5C Motorola BCS
-000E5D Com-X Networks
-000E5E Beijing Raisecom Science & Technology Development Co.,Ltd
-000E5F activ-net GmbH & Co. KG
-000E60 360SUN Digital Broadband Corporation
-000E61 MICROTROL LIMITED
-000E62 Nortel Networks
-000E63 Lemke Diagnostics GmbH
-000E64 Elphel, Inc
-000E65 TransCore
-000E66 Hitachi Advanced Digital, Inc.
-000E67 Eltis Microelectronics Ltd.
-000E68 E-TOP Network Technology Inc.
-000E69 China Electric Power Research Institute
-000E6A 3COM EUROPE LTD
-000E6B Janitza electronics GmbH
-000E6C Device Drivers Limited
-000E6D Murata Manufacturing Co., Ltd.
-000E6E MICRELEC ELECTRONICS S.A
-000E6F IRIS Corporation Berhad
-000E70 in2 Networks
-000E71 Gemstar Technology Development Ltd.
-000E72 CTS electronics
-000E73 Tpack A/S
-000E74 Solar Telecom. Tech
-000E75 New York Air Brake Corp.
-000E76 GEMSOC INNOVISION INC.
-000E77 Decru, Inc.
-000E78 Amtelco
-000E79 Ample Communications Inc.
-000E7B Toshiba
-000E7D Electronics Line 3000 Ltd.
-000E7E Comprog Oy
-000E7F Hewlett Packard
-000E81 Instant802 Networks Inc.
-000E82 Commtech Wireless
-000E83 Cisco Systems
-000E84 Cisco Systems
-000E85 Catalyst Enterprises, Inc.
-000E86 Alcatel North America
-000E87 adp Gauselmann GmbH
-000E88 VIDEOTRON CORP.
-000E89 CLEMATIC
-000E8A Avara Technologies Pty. Ltd.
-000E8B Astarte Technology Co, Ltd.
-000E8C Siemens AG A&D ET
-000E8D Systems in Progress Holding GmbH
-000E8E SparkLAN Communications, Inc.
-000E8F Sercomm Corp.
-000E90 PONICO CORP.
-000E92 Millinet Co., Ltd.
-000E93 Milénio 3 Sistemas Electrónicos, Lda.
-000E94 Maas International BV
-000E95 Fujiya Denki Seisakusho Co.,Ltd.
-000E96 Cubic Defense Applications, Inc.
-000E97 Ultracker Technology CO., Inc
-000E98 Vitec CC, INC.
-000E99 Spectrum Digital, Inc
-000E9A BOE TECHNOLOGY GROUP CO.,LTD
-000E9C Pemstar
-000E9D Video Networks Ltd
-000E9E Topfield Co., Ltd
-000E9F TEMIC SDS GmbH
-000EA0 NetKlass Technology Inc.
-000EA1 Formosa Teletek Corporation
-000EA2 CyberGuard Corporation
-000EA3 CNCR-IT CO.,LTD,HangZhou P.R.CHINA
-000EA4 Certance Inc.
-000EA5 BLIP Systems
-000EA6 ASUSTEK COMPUTER INC.
-000EA7 Endace Inc Ltd.
-000EA8 United Technologists Europe Limited
-000EA9 Shanghai Xun Shi Communications Equipment Ltd. Co.
-000EAC MINTRON ENTERPRISE CO., LTD.
-000EAD Metanoia Technologies, Inc.
-000EAE GAWELL TECHNOLOGIES CORP.
-000EAF CASTEL
-000EB0 Solutions Radio BV
-000EB1 Newcotech,Ltd
-000EB2 Micro-Research Finland Oy
-000EB3 LeftHand Networks
-000EB4 GUANGZHOU GAOKE COMMUNICATIONS TECHNOLOGY CO.LTD.
-000EB5 Ecastle Electronics Co., Ltd.
-000EB6 Riverbed Technology, Inc.
-000EB7 Knovative, Inc.
-000EB8 Iiga co.,Ltd
-000EB9 HASHIMOTO Electronics Industry Co.,Ltd.
-000EBA HANMI SEMICONDUCTOR CO., LTD.
-000EBB Everbee Networks
-000EBC Cullmann GmbH
-000EBD Burdick, a Quinton Compny
-000EBE B&B Electronics Manufacturing Co.
-000EC0 Nortel Networks
-000EC1 MYNAH Technologies
-000EC2 Lowrance Electronics, Inc.
-000EC3 Logic Controls, Inc.
-000EC4 Iskra Transmission d.d.
-000EC6 ASIX ELECTRONICS CORP.
-000EC7 Appeal Telecom Co.,Ltd.
-000EC8 Zoran Corporation
-000EC9 YOKO Technology Corp.
-000ECB VineSys Technology
-000ECC Tableau
-000ECD SKOV A/S
-000ECE S.I.T.T.I. S.p.A.
-000ECF PROFIBUS Nutzerorganisation e.V.
-000ED0 Privaris, Inc.
-000ED1 Osaka Micro Computer.
-000ED2 Filtronic plc
-000ED3 Epicenter, Inc.
-000ED4 CRESITT INDUSTRIE
-000ED5 COPAN Systems Inc.
-000ED6 Cisco Systems
-000ED7 Cisco Systems
-000ED8 Aktino, Inc.
-000ED9 Aksys, Ltd.
-000EDA C-TECH UNITED CORP.
-000EDB XiNCOM Corp.
-000EDC Tellion INC.
-000EDD SHURE INCORPORATED
-000EDE REMEC, Inc.
-000EDF PLX Technology
-000EE0 Mcharge
-000EE1 ExtremeSpeed Inc.
-000EE2 Custom Engineering S.p.A.
-000EE3 Chiyu Technology Co.,Ltd
-000EE5 bitWallet, Inc.
-000EE6 Adimos Systems LTD
-000EE7 AAC ELECTRONICS CORP.
-000EE8 zioncom
-000EE9 WayTech Development, Inc.
-000EEA Shadong Luneng Jicheng Electronics,Co.,Ltd
-000EEB Sandmartin(zhong shan)Electronics Co.,Ltd
-000EEC Orban
-000EED Nokia Danmark A/S
-000EEE Muco Industrie BV
-000EF0 Festo AG & Co. KG
-000EF1 EZQUEST INC.
-000EF3 Smarthome
-000EF4 Shenzhen Kasda Digital Technology Co.,Ltd
-000EF5 iPAC Technology Co., Ltd.
-000EF6 E-TEN Information Systems Co., Ltd.
-000EF7 Vulcan Portals Inc
-000EF8 SBC ASI
-000EF9 REA Elektronik GmbH
-000EFA Optoway Technology Incorporation
-000EFB Macey Enterprises
-000EFC JTAG Technologies B.V.
-000EFD FUJI PHOTO OPTICAL CO., LTD.
-000EFE EndRun Technologies LLC
-000EFF Megasolution,Inc.
-000F00 Legra Systems, Inc.
-000F01 DIGITALKS INC
-000F02 Digicube Technology Co., Ltd
-000F03 COM&C CO., LTD
-000F04 cim-usa inc
-000F05 3B SYSTEM INC.
-000F06 Nortel Networks
-000F07 Mangrove Systems, Inc.
-000F08 Indagon Oy
-000F0B Kentima Technologies AB
-000F0C SYNCHRONIC ENGINEERING
-000F0D Hunt Electronic Co., Ltd.
-000F0E WaveSplitter Technologies, Inc.
-000F0F Real ID Technology Co., Ltd.
-000F10 RDM Corporation
-000F11 Prodrive B.V.
-000F12 Panasonic AVC Networks Germany GmbH
-000F13 Nisca corporation
-000F14 Mindray Co., Ltd.
-000F15 Kjaerulff1 A/S
-000F16 JAY HOW TECHNOLOGY CO.,
-000F17 Insta Elektro GmbH
-000F18 Industrial Control Systems
-000F19 Guidant Corporation
-000F1A Gaming Support B.V.
-000F1B Ego Systems Inc.
-000F1C DigitAll World Co., Ltd
-000F1D Cosmo Techs Co., Ltd.
-000F1E Chengdu KT Electric Co.of High & New Technology
-000F1F WW PCBA Test
-000F20 WW Ops
-000F21 Scientific Atlanta, Inc
-000F22 Helius, Inc.
-000F23 Cisco Systems
-000F24 Cisco Systems
-000F25 AimValley B.V.
-000F26 WorldAccxx LLC
-000F27 TEAL Electronics, Inc.
-000F28 Itronix Corporation
-000F29 Augmentix Corporation
-000F2A Cableware Electronics
-000F2B GREENBELL SYSTEMS
-000F2C Uplogix, Inc.
-001000 CABLE TELEVISION LABORATORIES, INC.
-001001 MCK COMMUNICATIONS
-001002 ACTIA
-001003 IMATRON, INC.
-001004 THE BRANTLEY COILE COMPANY,INC
-001005 UEC COMMERCIAL
-001006 Thales Contact Solutions Ltd.
-001007 CISCO SYSTEMS, INC.
-001008 VIENNA SYSTEMS CORPORATION
-001009 HORO QUARTZ
-00100A WILLIAMS COMMUNICATIONS GROUP
-00100B CISCO SYSTEMS, INC.
-00100C ITO CO., LTD.
-00100D CISCO SYSTEMS, INC.
-00100E MICRO LINEAR COPORATION
-00100F INDUSTRIAL CPU SYSTEMS
-001010 INITIO CORPORATION
-001011 CISCO SYSTEMS, INC.
-001012 PROCESSOR SYSTEMS (I) PVT LTD
-001013 INDUSTRIAL COMPUTER SOURCE
-001014 CISCO SYSTEMS, INC.
-001015 OOmon Inc.
-001016 T.SQWARE
-001017 MICOS GmbH
-001018 BROADCOM CORPORATION
-001019 SIRONA DENTAL SYSTEMS GmbH & Co. KG
-00101A PictureTel Corp.
-00101B CORNET TECHNOLOGY, INC.
-00101C OHM TECHNOLOGIES INTL, LLC
-00101D WINBOND ELECTRONICS CORP.
-00101E MATSUSHITA ELECTRONIC INSTRUMENTS CORP.
-00101F CISCO SYSTEMS, INC.
-001020 WELCH ALLYN, DATA COLLECTION
-001021 ENCANTO NETWORKS, INC.
-001022 SatCom Media Corporation
-001023 FLOWWISE NETWORKS, INC.
-001024 NAGOYA ELECTRIC WORKS CO., LTD
-001025 GRAYHILL INC.
-001026 ACCELERATED NETWORKS, INC.
-001027 L-3 COMMUNICATIONS EAST
-001028 COMPUTER TECHNICA, INC.
-001029 CISCO SYSTEMS, INC.
-00102A ZF MICROSYSTEMS, INC.
-00102B UMAX DATA SYSTEMS, INC.
-00102C Lasat Networks A/S
-00102D HITACHI SOFTWARE ENGINEERING
-00102E NETWORK SYSTEMS & TECHNOLOGIES PVT. LTD.
-00102F CISCO SYSTEMS, INC.
-001030 Wi-LAN, Inc.
-001031 OBJECTIVE COMMUNICATIONS, INC.
-001032 ALTA TECHNOLOGY
-001033 ACCESSLAN COMMUNICATIONS, INC.
-001034 GNP Computers
-001035 ELITEGROUP COMPUTER SYSTEMS CO., LTD
-001036 INTER-TEL INTEGRATED SYSTEMS
-001037 CYQ've Technology Co., Ltd.
-001038 MICRO RESEARCH INSTITUTE, INC.
-001039 Vectron Systems AG
-00103A DIAMOND NETWORK TECH
-00103B HIPPI NETWORKING FORUM
-00103C IC ENSEMBLE, INC.
-00103D PHASECOM, LTD.
-00103E NETSCHOOLS CORPORATION
-00103F TOLLGRADE COMMUNICATIONS, INC.
-001040 INTERMEC CORPORATION
-001041 BRISTOL BABCOCK, INC.
-001042 AlacriTech
-001043 A2 CORPORATION
-001044 InnoLabs Corporation
-001045 Nortel Networks
-001046 ALCORN MCBRIDE INC.
-001047 ECHO ELETRIC CO. LTD.
-001048 HTRC AUTOMATION, INC.
-001049 SHORELINE TELEWORKS, INC.
-00104A THE PARVUC CORPORATION
-00104B 3COM CORPORATION
-00104C COMPUTER ACCESS TECHNOLOGY
-00104D SURTEC INDUSTRIES, INC.
-00104E CEOLOGIC
-00104F STORAGE TECHNOLOGY CORPORATION
-001050 RION CO., LTD.
-001051 CMICRO CORPORATION
-001052 METTLER-TOLEDO (ALBSTADT) GMBH
-001053 COMPUTER TECHNOLOGY CORP.
-001054 CISCO SYSTEMS, INC.
-001055 FUJITSU MICROELECTRONICS, INC.
-001056 SODICK CO., LTD.
-001057 Rebel.com, Inc.
-001058 ArrowPoint Communications
-001059 DIABLO RESEARCH CO. LLC
-00105A 3COM CORPORATION
-00105B NET INSIGHT AB
-00105C QUANTUM DESIGNS (H.K.) LTD.
-00105D Draeger Medical
-00105E HEKIMIAN LABORATORIES, INC.
-00105F IN-SNEC
-001060 BILLIONTON SYSTEMS, INC.
-001061 HOSTLINK CORP.
-001062 NX SERVER, ILNC.
-001063 STARGUIDE DIGITAL NETWORKS
-001064 DIGITAL EQUIPMENT CORP.
-001065 RADYNE CORPORATION
-001066 ADVANCED CONTROL SYSTEMS, INC.
-001067 REDBACK NETWORKS, INC.
-001068 COMOS TELECOM
-001069 HELIOSS COMMUNICATIONS, INC.
-00106A DIGITAL MICROWAVE CORPORATION
-00106B SONUS NETWORKS, INC.
-00106C INFRATEC PLUS GmbH
-00106D INTEGRITY COMMUNICATIONS, INC.
-00106E TADIRAN COM. LTD.
-00106F TRENTON TECHNOLOGY INC.
-001070 CARADON TREND LTD.
-001071 ADVANET INC.
-001072 GVN TECHNOLOGIES, INC.
-001073 TECHNOBOX, INC.
-001074 ATEN INTERNATIONAL CO., LTD.
-001075 Maxtor Corporation
-001076 EUREM GmbH
-001077 SAF DRIVE SYSTEMS, LTD.
-001078 NUERA COMMUNICATIONS, INC.
-001079 CISCO SYSTEMS, INC.
-00107A AmbiCom, Inc.
-00107B CISCO SYSTEMS, INC.
-00107C P-COM, INC.
-00107D AURORA COMMUNICATIONS, LTD.
-00107E BACHMANN ELECTRONIC GmbH
-00107F CRESTRON ELECTRONICS, INC.
-001080 METAWAVE COMMUNICATIONS
-001081 DPS, INC.
-001082 JNA TELECOMMUNICATIONS LIMITED
-001083 HEWLETT-PACKARD COMPANY
-001084 K-BOT COMMUNICATIONS
-001085 POLARIS COMMUNICATIONS, INC.
-001086 ATTO TECHNOLOGY, INC.
-001087 Xstreamis PLC
-001088 AMERICAN NETWORKS INC.
-001089 WebSonic
-00108A TeraLogic, Inc.
-00108B LASERANIMATION SOLLINGER GmbH
-00108C FUJITSU TELECOMMUNICATIONS EUROPE, LTD.
-00108D JOHNSON CONTROLS, INC.
-00108E HUGH SYMONS CONCEPT Technologies Ltd.
-00108F RAPTOR SYSTEMS
-001090 CIMETRICS, INC.
-001091 NO WIRES NEEDED BV
-001092 NETCORE INC.
-001093 CMS COMPUTERS, LTD.
-001094 Performance Analysis Broadband, Spirent plc
-001095 Thomson Multimedia, Inc.
-001096 TRACEWELL SYSTEMS, INC.
-001097 WinNet Metropolitan Communications Systems, Inc.
-001098 STARNET TECHNOLOGIES, INC.
-001099 InnoMedia, Inc.
-00109A NETLINE
-00109B VIXEL CORPORATION
-00109C M-SYSTEM CO., LTD.
-00109D CLARINET SYSTEMS, INC.
-00109E AWARE, INC.
-00109F PAVO, INC.
-0010A0 INNOVEX TECHNOLOGIES, INC.
-0010A1 KENDIN SEMICONDUCTOR, INC.
-0010A2 TNS
-0010A3 OMNITRONIX, INC.
-0010A4 XIRCOM
-0010A5 OXFORD INSTRUMENTS
-0010A6 CISCO SYSTEMS, INC.
-0010A7 UNEX TECHNOLOGY CORPORATION
-0010A8 RELIANCE COMPUTER CORP.
-0010A9 ADHOC TECHNOLOGIES
-0010AA MEDIA4, INC.
-0010AB KOITO INDUSTRIES, LTD.
-0010AC IMCI TECHNOLOGIES
-0010AD SOFTRONICS USB, INC.
-0010AE SHINKO ELECTRIC INDUSTRIES CO.
-0010AF TAC SYSTEMS, INC.
-0010B0 MERIDIAN TECHNOLOGY CORP.
-0010B1 FOR-A CO., LTD.
-0010B2 COACTIVE AESTHETICS
-0010B3 NOKIA MULTIMEDIA TERMINALS
-0010B4 ATMOSPHERE NETWORKS
-0010B5 ACCTON TECHNOLOGY CORPORATION
-0010B6 ENTRATA COMMUNICATIONS CORP.
-0010B7 COYOTE TECHNOLOGIES, LLC
-0010B8 ISHIGAKI COMPUTER SYSTEM CO.
-0010B9 MAXTOR CORP.
-0010BA MARTINHO-DAVIS SYSTEMS, INC.
-0010BB DATA & INFORMATION TECHNOLOGY
-0010BC Aastra Telecom
-0010BD THE TELECOMMUNICATION TECHNOLOGY COMMITTEE
-0010BE TELEXIS CORP.
-0010BF InterAir Wireless
-0010C0 ARMA, INC.
-0010C1 OI ELECTRIC CO., LTD.
-0010C2 WILLNET, INC.
-0010C3 CSI-CONTROL SYSTEMS
-0010C4 MEDIA LINKS CO., LTD.
-0010C5 PROTOCOL TECHNOLOGIES, INC.
-0010C6 USI
-0010C7 DATA TRANSMISSION NETWORK
-0010C8 COMMUNICATIONS ELECTRONICS SECURITY GROUP
-0010C9 MITSUBISHI ELECTRONICS LOGISTIC SUPPORT CO.
-0010CA INTEGRAL ACCESS
-0010CB FACIT K.K.
-0010CC CLP COMPUTER LOGISTIK PLANUNG GmbH
-0010CD INTERFACE CONCEPT
-0010CE VOLAMP, LTD.
-0010CF FIBERLANE COMMUNICATIONS
-0010D0 WITCOM, LTD.
-0010D1 Top Layer Networks, Inc.
-0010D2 NITTO TSUSHINKI CO., LTD
-0010D3 GRIPS ELECTRONIC GMBH
-0010D4 STORAGE COMPUTER CORPORATION
-0010D5 IMASDE CANARIAS, S.A.
-0010D6 ITT - A/CD
-0010D7 ARGOSY RESEARCH INC.
-0010D8 CALISTA
-0010D9 IBM JAPAN, FUJISAWA MT+D
-0010DA MOTION ENGINEERING, INC.
-0010DB NetScreen Technologies, Inc.
-0010DC MICRO-STAR INTERNATIONAL CO., LTD.
-0010DD ENABLE SEMICONDUCTOR, INC.
-0010DE INTERNATIONAL DATACASTING CORPORATION
-0010DF RISE COMPUTER INC.
-0010E0 COBALT MICROSERVER, INC.
-0010E1 S.I. TECH, INC.
-0010E2 ArrayComm, Inc.
-0010E3 COMPAQ COMPUTER CORPORATION
-0010E4 NSI CORPORATION
-0010E5 SOLECTRON TEXAS
-0010E6 APPLIED INTELLIGENT SYSTEMS, INC.
-0010E7 BreezeCom
-0010E8 TELOCITY, INCORPORATED
-0010E9 RAIDTEC LTD.
-0010EA ADEPT TECHNOLOGY
-0010EB SELSIUS SYSTEMS, INC.
-0010EC RPCG, LLC
-0010ED SUNDANCE TECHNOLOGY, INC.
-0010EE CTI PRODUCTS, INC.
-0010EF DBTEL INCORPORATED
-0010F1 I-O CORPORATION
-0010F2 ANTEC
-0010F3 Nexcom International Co., Ltd.
-0010F4 VERTICAL NETWORKS, INC.
-0010F5 AMHERST SYSTEMS, INC.
-0010F6 CISCO SYSTEMS, INC.
-0010F7 IRIICHI TECHNOLOGIES Inc.
-0010F8 KENWOOD TMI CORPORATION
-0010F9 UNIQUE SYSTEMS, INC.
-0010FA ZAYANTE, INC.
-0010FB ZIDA TECHNOLOGIES LIMITED
-0010FC BROADBAND NETWORKS, INC.
-0010FD COCOM A/S
-0010FE DIGITAL EQUIPMENT CORPORATION
-0010FF CISCO SYSTEMS, INC.
-001C7C PERQ SYSTEMS CORPORATION
-002000 LEXMARK INTERNATIONAL, INC.
-002001 DSP SOLUTIONS, INC.
-002002 SERITECH ENTERPRISE CO., LTD.
-002003 PIXEL POWER LTD.
-002004 YAMATAKE-HONEYWELL CO., LTD.
-002005 SIMPLE TECHNOLOGY
-002006 GARRETT COMMUNICATIONS, INC.
-002007 SFA, INC.
-002008 CABLE & COMPUTER TECHNOLOGY
-002009 PACKARD BELL ELEC., INC.
-00200A SOURCE-COMM CORP.
-00200B OCTAGON SYSTEMS CORP.
-00200C ADASTRA SYSTEMS CORP.
-00200D CARL ZEISS
-00200E SATELLITE TECHNOLOGY MGMT, INC
-00200F TANBAC CO., LTD.
-002010 JEOL SYSTEM TECHNOLOGY CO. LTD
-002011 CANOPUS CO., LTD.
-002012 CAMTRONICS MEDICAL SYSTEMS
-002013 DIVERSIFIED TECHNOLOGY, INC.
-002014 GLOBAL VIEW CO., LTD.
-002015 ACTIS COMPUTER SA
-002016 SHOWA ELECTRIC WIRE & CABLE CO
-002017 ORBOTECH
-002018 CIS TECHNOLOGY INC.
-002019 OHLER GmbH
-00201A N-BASE SWITCH COMMUNICATIONS
-00201B NORTHERN TELECOM/NETWORK
-00201C EXCEL, INC.
-00201D KATANA PRODUCTS
-00201E NETQUEST CORPORATION
-00201F BEST POWER TECHNOLOGY, INC.
-002020 MEGATRON COMPUTER INDUSTRIES PTY, LTD.
-002021 ALGORITHMS SOFTWARE PVT. LTD.
-002022 TEKNIQUE, INC.
-002023 T.C. TECHNOLOGIES PTY. LTD
-002024 PACIFIC COMMUNICATION SCIENCES
-002025 CONTROL TECHNOLOGY, INC.
-002026 AMKLY SYSTEMS, INC.
-002027 MING FORTUNE INDUSTRY CO., LTD
-002028 WEST EGG SYSTEMS, INC.
-002029 TELEPROCESSING PRODUCTS, INC.
-00202A N.V. DZINE
-00202B ADVANCED TELECOMMUNICATIONS MODULES, LTD.
-00202C WELLTRONIX CO., LTD.
-00202D TAIYO CORPORATION
-00202E DAYSTAR DIGITAL
-00202F ZETA COMMUNICATIONS, LTD.
-002030 ANALOG & DIGITAL SYSTEMS
-002031 ERTEC GmbH
-002032 ALCATEL TAISEL
-002033 SYNAPSE TECHNOLOGIES, INC.
-002034 ROTEC INDUSTRIEAUTOMATION GMBH
-002035 IBM CORPORATION
-002036 BMC SOFTWARE
-002037 SEAGATE TECHNOLOGY
-002038 VME MICROSYSTEMS INTERNATIONAL CORPORATION
-002039 SCINETS
-00203A DIGITAL BI0METRICS INC.
-00203B WISDM LTD.
-00203C EUROTIME AB
-00203D NOVAR ELECTRONICS CORPORATION
-00203E LogiCan Technologies, Inc.
-00203F JUKI CORPORATION
-002040 Motorola Broadband Communications Sector
-002041 DATA NET
-002042 DATAMETRICS CORP.
-002043 NEURON COMPANY LIMITED
-002044 GENITECH PTY LTD
-002045 ION Networks, Inc.
-002046 CIPRICO, INC.
-002047 STEINBRECHER CORP.
-002048 Marconi Communications
-002049 COMTRON, INC.
-00204A PRONET GMBH
-00204B AUTOCOMPUTER CO., LTD.
-00204C MITRON COMPUTER PTE LTD.
-00204D INOVIS GMBH
-00204E NETWORK SECURITY SYSTEMS, INC.
-00204F DEUTSCHE AEROSPACE AG
-002050 KOREA COMPUTER INC.
-002051 Verilink Corporation
-002052 RAGULA SYSTEMS
-002053 HUNTSVILLE MICROSYSTEMS, INC.
-002054 EASTERN RESEARCH, INC.
-002055 ALTECH CO., LTD.
-002056 NEOPRODUCTS
-002057 TITZE DATENTECHNIK GmbH
-002058 ALLIED SIGNAL INC.
-002059 MIRO COMPUTER PRODUCTS AG
-00205A COMPUTER IDENTICS
-00205B SKYLINE TECHNOLOGY
-00205C InterNet Systems of Florida, Inc.
-00205D NANOMATIC OY
-00205E CASTLE ROCK, INC.
-00205F GAMMADATA COMPUTER GMBH
-002060 ALCATEL ITALIA S.p.A.
-002061 DYNATECH COMMUNICATIONS, INC.
-002062 SCORPION LOGIC, LTD.
-002063 WIPRO INFOTECH LTD.
-002064 PROTEC MICROSYSTEMS, INC.
-002065 SUPERNET NETWORKING INC.
-002066 GENERAL MAGIC, INC.
-002068 ISDYNE
-002069 ISDN SYSTEMS CORPORATION
-00206A OSAKA COMPUTER CORP.
-00206B KONICA MINOLTA HOLDINGS, INC.
-00206C EVERGREEN TECHNOLOGY CORP.
-00206D DATA RACE, INC.
-00206E XACT, INC.
-00206F FLOWPOINT CORPORATION
-002070 HYNET, LTD.
-002071 IBR GMBH
-002072 WORKLINK INNOVATIONS
-002073 FUSION SYSTEMS CORPORATION
-002074 SUNGWOON SYSTEMS
-002075 MOTOROLA COMMUNICATION ISRAEL
-002076 REUDO CORPORATION
-002077 KARDIOS SYSTEMS CORP.
-002078 RUNTOP, INC.
-002079 MIKRON GMBH
-00207A WiSE Communications, Inc.
-00207B Intel Corporation
-00207C AUTEC GmbH
-00207D ADVANCED COMPUTER APPLICATIONS
-00207E FINECOM Co., Ltd.
-00207F KYOEI SANGYO CO., LTD.
-002080 SYNERGY (UK) LTD.
-002081 TITAN ELECTRONICS
-002082 ONEAC CORPORATION
-002083 PRESTICOM INCORPORATED
-002084 OCE PRINTING SYSTEMS, GMBH
-002085 EXIDE ELECTRONICS
-002086 MICROTECH ELECTRONICS LIMITED
-002087 MEMOTEC COMMUNICATIONS CORP.
-002088 GLOBAL VILLAGE COMMUNICATION
-002089 T3PLUS NETWORKING, INC.
-00208A SONIX COMMUNICATIONS, LTD.
-00208B LAPIS TECHNOLOGIES, INC.
-00208C GALAXY NETWORKS, INC.
-00208D CMD TECHNOLOGY
-00208E CHEVIN SOFTWARE ENG. LTD.
-00208F ECI TELECOM LTD.
-002090 ADVANCED COMPRESSION TECHNOLOGY, INC.
-002091 J125, NATIONAL SECURITY AGENCY
-002092 CHESS ENGINEERING B.V.
-002093 LANDINGS TECHNOLOGY CORP.
-002094 CUBIX CORPORATION
-002095 RIVA ELECTRONICS
-002096 Invensys
-002097 APPLIED SIGNAL TECHNOLOGY
-002098 HECTRONIC AB
-002099 BON ELECTRIC CO., LTD.
-00209A THE 3DO COMPANY
-00209B ERSAT ELECTRONIC GMBH
-00209C PRIMARY ACCESS CORP.
-00209D LIPPERT AUTOMATIONSTECHNIK
-00209E BROWN'S OPERATING SYSTEM SERVICES, LTD.
-00209F MERCURY COMPUTER SYSTEMS, INC.
-0020A0 OA LABORATORY CO., LTD.
-0020A1 DOVATRON
-0020A2 GALCOM NETWORKING LTD.
-0020A3 DIVICOM INC.
-0020A4 MULTIPOINT NETWORKS
-0020A5 API ENGINEERING
-0020A6 PROXIM, INC.
-0020A7 PAIRGAIN TECHNOLOGIES, INC.
-0020A8 SAST TECHNOLOGY CORP.
-0020A9 WHITE HORSE INDUSTRIAL
-0020AA DIGIMEDIA VISION LTD.
-0020AB MICRO INDUSTRIES CORP.
-0020AC INTERFLEX DATENSYSTEME GMBH
-0020AD LINQ SYSTEMS
-0020AE ORNET DATA COMMUNICATION TECH.
-0020AF 3COM CORPORATION
-0020B0 GATEWAY DEVICES, INC.
-0020B1 COMTECH RESEARCH INC.
-0020B2 GKD Gesellschaft Fur Kommunikation Und Datentechnik
-0020B3 SCLTEC COMMUNICATIONS SYSTEMS
-0020B4 TERMA ELEKTRONIK AS
-0020B5 YASKAWA ELECTRIC CORPORATION
-0020B6 AGILE NETWORKS, INC.
-0020B7 NAMAQUA COMPUTERWARE
-0020B8 PRIME OPTION, INC.
-0020B9 METRICOM, INC.
-0020BA CENTER FOR HIGH PERFORMANCE
-0020BB ZAX CORPORATION
-0020BC JTEC PTY LTD.
-0020BD NIOBRARA R & D CORPORATION
-0020BE LAN ACCESS CORP.
-0020BF AEHR TEST SYSTEMS
-0020C0 PULSE ELECTRONICS, INC.
-0020C1 TAIKO ELECTRIC WORKS, LTD.
-0020C2 TEXAS MEMORY SYSTEMS, INC.
-0020C3 COUNTER SOLUTIONS LTD.
-0020C4 INET,INC.
-0020C5 EAGLE TECHNOLOGY
-0020C6 NECTEC
-0020C7 AKAI Professional M.I. Corp.
-0020C8 LARSCOM INCORPORATED
-0020C9 VICTRON BV
-0020CA DIGITAL OCEAN
-0020CB PRETEC ELECTRONICS CORP.
-0020CC DIGITAL SERVICES, LTD.
-0020CD HYBRID NETWORKS, INC.
-0020CE LOGICAL DESIGN GROUP, INC.
-0020CF TEST & MEASUREMENT SYSTEMS INC
-0020D0 VERSALYNX CORPORATION
-0020D1 MICROCOMPUTER SYSTEMS (M) SDN.
-0020D2 RAD DATA COMMUNICATIONS, LTD.
-0020D3 OST (OUEST STANDARD TELEMATIQU
-0020D4 CABLETRON - ZEITTNET INC.
-0020D5 VIPA GMBH
-0020D6 BREEZECOM
-0020D7 JAPAN MINICOMPUTER SYSTEMS CO., Ltd.
-0020D8 Nortel Networks
-0020D9 PANASONIC TECHNOLOGIES, INC./MIECO-US
-0020DA XYLAN CORPORATION
-0020DB XNET TECHNOLOGY, INC.
-0020DC DENSITRON TAIWAN LTD.
-0020DD Cybertec Pty Ltd
-0020DE JAPAN DIGITAL LABORAT'Y CO.LTD
-0020DF KYOSAN ELECTRIC MFG. CO., LTD.
-0020E0 PREMAX ELECTRONICS, INC.
-0020E1 ALAMAR ELECTRONICS
-0020E2 INFORMATION RESOURCE ENGINEERING
-0020E3 MCD KENCOM CORPORATION
-0020E4 HSING TECH ENTERPRISE CO., LTD
-0020E5 APEX DATA, INC.
-0020E6 LIDKOPING MACHINE TOOLS AB
-0020E7 B&W NUCLEAR SERVICE COMPANY
-0020E8 DATATREK CORPORATION
-0020E9 DANTEL
-0020EA EFFICIENT NETWORKS, INC.
-0020EB CINCINNATI MICROWAVE, INC.
-0020EC TECHWARE SYSTEMS CORP.
-0020ED GIGA-BYTE TECHNOLOGY CO., LTD.
-0020EE GTECH CORPORATION
-0020EF USC CORPORATION
-0020F0 UNIVERSAL MICROELECTRONICS CO.
-0020F1 ALTOS INDIA LIMITED
-0020F2 SUN MICROSYSTEMS, INC.
-0020F3 RAYNET CORPORATION
-0020F4 SPECTRIX CORPORATION
-0020F5 PANDATEL AG
-0020F6 NET TEK AND KARLNET, INC.
-0020F7 CYBERDATA
-0020F8 CARRERA COMPUTERS, INC.
-0020F9 PARALINK NETWORKS, INC.
-0020FA GDE SYSTEMS, INC.
-0020FB OCTEL COMMUNICATIONS CORP.
-0020FC MATROX
-0020FD ITV TECHNOLOGIES, INC.
-0020FE TOPWARE INC. / GRAND COMPUTER
-0020FF SYMMETRICAL TECHNOLOGIES
-003000 ALLWELL TECHNOLOGY CORP.
-003001 SMP
-003002 Expand Networks
-003003 Phasys Ltd.
-003004 LEADTEK RESEARCH INC.
-003005 Fujitsu Siemens Computers
-003006 SUPERPOWER COMPUTER
-003007 OPTI, INC.
-003008 AVIO DIGITAL, INC.
-003009 Tachion Networks, Inc.
-00300A AZTECH SYSTEMS LTD.
-00300B mPHASE Technologies, Inc.
-00300C CONGRUENCY, LTD.
-00300D MMC Technology, Inc.
-00300E Klotz Digital AG
-00300F IMT - Information Management T
-003010 VISIONETICS INTERNATIONAL
-003011 HMS FIELDBUS SYSTEMS AB
-003012 DIGITAL ENGINEERING LTD.
-003013 NEC Corporation
-003014 DIVIO, INC.
-003015 CP CLARE CORP.
-003016 ISHIDA CO., LTD.
-003017 TERASTACK LTD.
-003018 Jetway Information Co., Ltd.
-003019 CISCO SYSTEMS, INC.
-00301A SMARTBRIDGES PTE. LTD.
-00301B SHUTTLE, INC.
-00301C ALTVATER AIRDATA SYSTEMS
-00301D SKYSTREAM, INC.
-00301E 3COM Europe Ltd.
-00301F OPTICAL NETWORKS, INC.
-003020 TSI, Inc..
-003021 HSING TECH. ENTERPRISE CO.,LTD
-003022 Fong Kai Industrial Co., Ltd.
-003023 COGENT COMPUTER SYSTEMS, INC.
-003024 CISCO SYSTEMS, INC.
-003025 CHECKOUT COMPUTER SYSTEMS, LTD
-003026 HEITEL
-003027 KERBANGO, INC.
-003028 FASE Saldatura srl
-003029 OPICOM
-00302A SOUTHERN INFORMATION
-00302B INALP NETWORKS, INC.
-00302C SYLANTRO SYSTEMS CORPORATION
-00302D QUANTUM BRIDGE COMMUNICATIONS
-00302E Hoft & Wessel AG
-00302F Smiths Industries
-003030 HARMONIX CORPORATION
-003031 LIGHTWAVE COMMUNICATIONS, INC.
-003032 MagicRam, Inc.
-003033 ORIENT TELECOM CO., LTD.
-003036 RMP ELEKTRONIKSYSTEME GMBH
-003037 Packard Bell Nec Services
-003038 XCP, INC.
-003039 SOFTBOOK PRESS
-00303A MAATEL
-00303B PowerCom Technology
-00303C ONNTO CORP.
-00303D IVA CORPORATION
-00303E Radcom Ltd.
-00303F TurboComm Tech Inc.
-003040 CISCO SYSTEMS, INC.
-003041 SAEJIN T & M CO., LTD.
-003042 DeTeWe-Deutsche Telephonwerke
-003043 IDREAM TECHNOLOGIES, PTE. LTD.
-003044 Portsmith LLC
-003045 Village Networks, Inc. (VNI)
-003046 Controlled Electronic Manageme
-003047 NISSEI ELECTRIC CO., LTD.
-003048 Supermicro Computer, Inc.
-003049 BRYANT TECHNOLOGY, LTD.
-00304A FRAUNHOFER INSTITUTE IMS
-00304B ORBACOM SYSTEMS, INC.
-00304C APPIAN COMMUNICATIONS, INC.
-00304D ESI
-00304E BUSTEC PRODUCTION LTD.
-00304F PLANET Technology Corporation
-003050 Versa Technology
-003051 ORBIT AVIONIC & COMMUNICATION
-003052 ELASTIC NETWORKS
-003053 Basler AG
-003054 CASTLENET TECHNOLOGY, INC.
-003055 Hitachi Semiconductor America,
-003056 Beck IPC GmbH
-003057 E-Tel Corporation
-003058 API MOTION
-003059 DIGITAL-LOGIC AG
-00305A TELGEN CORPORATION
-00305B MODULE DEPARTMENT
-00305C SMAR Laboratories Corp.
-00305D DIGITRA SYSTEMS, INC.
-00305E Abelko Innovation
-00305F IMACON APS
-003060 STARMATIX, INC.
-003061 MobyTEL
-003062 PATH 1 NETWORK TECHNOL'S INC.
-003063 SANTERA SYSTEMS, INC.
-003064 ADLINK TECHNOLOGY, INC.
-003065 APPLE COMPUTER, INC.
-003066 DIGITAL WIRELESS CORPORATION
-003067 BIOSTAR MICROTECH INT'L CORP.
-003068 CYBERNETICS TECH. CO., LTD.
-003069 IMPACCT TECHNOLOGY CORP.
-00306A PENTA MEDIA CO., LTD.
-00306B CMOS SYSTEMS, INC.
-00306C Hitex Holding GmbH
-00306D LUCENT TECHNOLOGIES
-00306E HEWLETT PACKARD
-00306F SEYEON TECH. CO., LTD.
-003070 1Net Corporation
-003071 Cisco Systems, Inc.
-003072 INTELLIBYTE INC.
-003073 International Microsystems, In
-003074 EQUIINET LTD.
-003075 ADTECH
-003076 Akamba Corporation
-003077 ONPREM NETWORKS
-003078 Cisco Systems, Inc.
-003079 CQOS, INC.
-00307A Advanced Technology & Systems
-00307B Cisco Systems, Inc.
-00307C ADID SA
-00307D GRE AMERICA, INC.
-00307E Redflex Communication Systems
-00307F IRLAN LTD.
-003080 CISCO SYSTEMS, INC.
-003081 ALTOS C&C
-003082 TAIHAN ELECTRIC WIRE CO., LTD.
-003083 Ivron Systems
-003084 ALLIED TELESYN INTERNAIONAL
-003085 CISCO SYSTEMS, INC.
-003086 Transistor Devices, Inc.
-003087 VEGA GRIESHABER KG
-003088 Siara Systems, Inc.
-003089 Spectrapoint Wireless, LLC
-00308A NICOTRA SISTEMI S.P.A
-00308B Brix Networks
-00308C ADVANCED DIGITAL INFORMATION
-00308D PINNACLE SYSTEMS, INC.
-00308E CROSS MATCH TECHNOLOGIES, INC.
-00308F MICRILOR, Inc.
-003090 CYRA TECHNOLOGIES, INC.
-003091 TAIWAN FIRST LINE ELEC. CORP.
-003092 ModuNORM GmbH
-003093 SONNET TECHNOLOGIES, INC.
-003094 Cisco Systems, Inc.
-003095 Procomp Informatics, Ltd.
-003096 CISCO SYSTEMS, INC.
-003097 EXOMATIC AB
-003098 Global Converging Technologies
-003099 BOENIG UND KALLENBACH OHG
-00309A ASTRO TERRA CORP.
-00309B Smartware
-00309C Timing Applications, Inc.
-00309D Nimble Microsystems, Inc.
-00309E WORKBIT CORPORATION.
-00309F AMBER NETWORKS
-0030A0 TYCO SUBMARINE SYSTEMS, LTD.
-0030A1 WEBGATE Inc.
-0030A2 Lightner Engineering
-0030A3 CISCO SYSTEMS, INC.
-0030A4 Woodwind Communications System
-0030A5 ACTIVE POWER
-0030A6 VIANET TECHNOLOGIES, LTD.
-0030A7 SCHWEITZER ENGINEERING
-0030A8 OL'E COMMUNICATIONS, INC.
-0030A9 Netiverse, Inc.
-0030AA AXUS MICROSYSTEMS, INC.
-0030AB DELTA NETWORKS, INC.
-0030AC Systeme Lauer GmbH & Co., Ltd.
-0030AD SHANGHAI COMMUNICATION
-0030AE Times N System, Inc.
-0030AF Honeywell GmbH
-0030B0 Convergenet Technologies
-0030B1 GOC GESELLSCHAFT FUR OPTISCHE
-0030B2 WESCAM - HEALDSBURG
-0030B3 San Valley Systems, Inc.
-0030B4 INTERSIL CORP.
-0030B5 Tadiran Microwave Networks
-0030B6 CISCO SYSTEMS, INC.
-0030B7 Teletrol Systems, Inc.
-0030B8 RiverDelta Networks
-0030B9 ECTEL
-0030BA AC&T SYSTEM CO., LTD.
-0030BB CacheFlow, Inc.
-0030BC Optronic AG
-0030BD BELKIN COMPONENTS
-0030BE City-Net Technology, Inc.
-0030BF MULTIDATA GMBH
-0030C0 Lara Technology, Inc.
-0030C1 HEWLETT-PACKARD
-0030C2 COMONE
-0030C3 FLUECKIGER ELEKTRONIK AG
-0030C4 Niigata Canotec Co., Inc.
-0030C5 CADENCE DESIGN SYSTEMS
-0030C6 CONTROL SOLUTIONS, INC.
-0030C7 MACROMATE CORP.
-0030C8 GAD LINE, LTD.
-0030C9 LuxN, N
-0030CA Discovery Com
-0030CB OMNI FLOW COMPUTERS, INC.
-0030CC Tenor Networks, Inc.
-0030CD CONEXANT SYSTEMS, INC.
-0030CE Zaffire
-0030CF TWO TECHNOLOGIES, INC.
-0030D1 INOVA CORPORATION
-0030D2 WIN TECHNOLOGIES, CO., LTD.
-0030D3 Agilent Technologies
-0030D4 COMTIER
-0030D5 DResearch GmbH
-0030D6 MSC VERTRIEBS GMBH
-0030D7 Innovative Systems, L.L.C.
-0030D8 SITEK
-0030D9 DATACORE SOFTWARE CORP.
-0030DA COMTREND CO.
-0030DB Mindready Solutions, Inc.
-0030DC RIGHTECH CORPORATION
-0030DD INDIGITA CORPORATION
-0030DE WAGO Kontakttechnik GmbH
-0030DF KB/TEL TELECOMUNICACIONES
-0030E0 OXFORD SEMICONDUCTOR LTD.
-0030E1 ACROTRON SYSTEMS, INC.
-0030E2 GARNET SYSTEMS CO., LTD.
-0030E3 SEDONA NETWORKS CORP.
-0030E4 CHIYODA SYSTEM RIKEN
-0030E5 Amper Datos S.A.
-0030E6 SIEMENS MEDICAL SYSTEMS
-0030E7 CNF MOBILE SOLUTIONS, INC.
-0030E8 ENSIM CORP.
-0030E9 GMA COMMUNICATION MANUFACT'G
-0030EA TeraForce Technology Corporation
-0030EB TURBONET COMMUNICATIONS, INC.
-0030EC BORGARDT
-0030ED Expert Magnetics Corp.
-0030EE DSG Technology, Inc.
-0030EF NEON TECHNOLOGY, INC.
-0030F0 Uniform Industrial Corp.
-0030F1 Accton Technology Corp.
-0030F2 CISCO SYSTEMS, INC.
-0030F3 At Work Computers
-0030F4 STARDOT TECHNOLOGIES
-0030F5 Wild Lab. Ltd.
-0030F6 SECURELOGIX CORPORATION
-0030F7 RAMIX INC.
-0030F8 Dynapro Systems, Inc.
-0030F9 Sollae Systems Co., Ltd.
-0030FA TELICA, INC.
-0030FB AZS Technology AG
-0030FC Terawave Communications, Inc.
-0030FD INTEGRATED SYSTEMS DESIGN
-0030FE DSA GmbH
-0030FF DATAFAB SYSTEMS, INC.
-004000 PCI COMPONENTES DA AMZONIA LTD
-004001 ZYXEL COMMUNICATIONS, INC.
-004002 PERLE SYSTEMS LIMITED
-004003 WESTINGHOUSE PROCESS CONTROL
-004004 ICM CO. LTD.
-004005 ANI COMMUNICATIONS INC.
-004006 SAMPO TECHNOLOGY CORPORATION
-004007 TELMAT INFORMATIQUE
-004008 A PLUS INFO CORPORATION
-004009 TACHIBANA TECTRON CO., LTD.
-00400A PIVOTAL TECHNOLOGIES, INC.
-00400B CISCO SYSTEMS, INC.
-00400C GENERAL MICRO SYSTEMS, INC.
-00400D LANNET DATA COMMUNICATIONS,LTD
-00400E MEMOTEC COMMUNICATIONS, INC.
-00400F DATACOM TECHNOLOGIES
-004010 SONIC SYSTEMS, INC.
-004011 ANDOVER CONTROLS CORPORATION
-004012 WINDATA, INC.
-004013 NTT DATA COMM. SYSTEMS CORP.
-004014 COMSOFT GMBH
-004015 ASCOM INFRASYS AG
-004016 HADAX ELECTRONICS, INC.
-004017 XCD INC.
-004018 ADOBE SYSTEMS, INC.
-004019 AEON SYSTEMS, INC.
-00401A FUJI ELECTRIC CO., LTD.
-00401B PRINTER SYSTEMS CORP.
-00401C AST RESEARCH, INC.
-00401D INVISIBLE SOFTWARE, INC.
-00401E ICC
-00401F COLORGRAPH LTD
-004020 PINACL COMMUNICATION
-004021 RASTER GRAPHICS
-004022 KLEVER COMPUTERS, INC.
-004023 LOGIC CORPORATION
-004024 COMPAC INC.
-004025 MOLECULAR DYNAMICS
-004026 MELCO, INC.
-004027 SMC MASSACHUSETTS, INC.
-004028 NETCOMM LIMITED
-004029 COMPEX
-00402A CANOGA-PERKINS
-00402B TRIGEM COMPUTER, INC.
-00402C ISIS DISTRIBUTED SYSTEMS, INC.
-00402D HARRIS ADACOM CORPORATION
-00402E PRECISION SOFTWARE, INC.
-00402F XLNT DESIGNS INC.
-004030 GK COMPUTER
-004031 KOKUSAI ELECTRIC CO., LTD
-004032 DIGITAL COMMUNICATIONS
-004033 ADDTRON TECHNOLOGY CO., LTD.
-004034 BUSTEK CORPORATION
-004035 OPCOM
-004036 TRIBE COMPUTER WORKS, INC.
-004037 SEA-ILAN, INC.
-004038 TALENT ELECTRIC INCORPORATED
-004039 OPTEC DAIICHI DENKO CO., LTD.
-00403A IMPACT TECHNOLOGIES
-00403B SYNERJET INTERNATIONAL CORP.
-00403C FORKS, INC.
-00403D TERADATA
-00403E RASTER OPS CORPORATION
-00403F SSANGYONG COMPUTER SYSTEMS
-004040 RING ACCESS, INC.
-004041 FUJIKURA LTD.
-004042 N.A.T. GMBH
-004043 NOKIA TELECOMMUNICATIONS
-004044 QNIX COMPUTER CO., LTD.
-004045 TWINHEAD CORPORATION
-004046 UDC RESEARCH LIMITED
-004047 WIND RIVER SYSTEMS
-004048 SMD INFORMATICA S.A.
-004049 TEGIMENTA AG
-00404A WEST AUSTRALIAN DEPARTMENT
-00404B MAPLE COMPUTER SYSTEMS
-00404C HYPERTEC PTY LTD.
-00404D TELECOMMUNICATIONS TECHNIQUES
-00404E FLUENT, INC.
-00404F SPACE & NAVAL WARFARE SYSTEMS
-004050 IRONICS, INCORPORATED
-004051 GRACILIS, INC.
-004052 STAR TECHNOLOGIES, INC.
-004053 AMPRO COMPUTERS
-004054 CONNECTION MACHINES SERVICES
-004055 METRONIX GMBH
-004056 MCM JAPAN LTD.
-004057 LOCKHEED - SANDERS
-004058 KRONOS, INC.
-004059 YOSHIDA KOGYO K. K.
-00405A GOLDSTAR INFORMATION & COMM.
-00405B FUNASSET LIMITED
-00405C FUTURE SYSTEMS, INC.
-00405D STAR-TEK, INC.
-00405E NORTH HILLS ISRAEL
-00405F AFE COMPUTERS LTD.
-004060 COMENDEC LTD
-004061 DATATECH ENTERPRISES CO., LTD.
-004062 E-SYSTEMS, INC./GARLAND DIV.
-004063 VIA TECHNOLOGIES, INC.
-004064 KLA INSTRUMENTS CORPORATION
-004065 GTE SPACENET
-004066 HITACHI CABLE, LTD.
-004067 OMNIBYTE CORPORATION
-004068 EXTENDED SYSTEMS
-004069 LEMCOM SYSTEMS, INC.
-00406A KENTEK INFORMATION SYSTEMS,INC
-00406B SYSGEN
-00406C COPERNIQUE
-00406D LANCO, INC.
-00406E COROLLARY, INC.
-00406F SYNC RESEARCH INC.
-004070 INTERWARE CO., LTD.
-004071 ATM COMPUTER GMBH
-004072 Applied Innovation Inc.
-004073 BASS ASSOCIATES
-004074 CABLE AND WIRELESS
-004075 M-TRADE (UK) LTD
-004076 Sun Conversion Technologies
-004077 MAXTON TECHNOLOGY CORPORATION
-004078 WEARNES AUTOMATION PTE LTD
-004079 JUKO MANUFACTURE COMPANY, LTD.
-00407A SOCIETE D'EXPLOITATION DU CNIT
-00407B SCIENTIFIC ATLANTA
-00407C QUME CORPORATION
-00407D EXTENSION TECHNOLOGY CORP.
-00407E EVERGREEN SYSTEMS, INC.
-00407F FLIR Systems
-004080 ATHENIX CORPORATION
-004081 MANNESMANN SCANGRAPHIC GMBH
-004082 LABORATORY EQUIPMENT CORP.
-004083 TDA INDUSTRIA DE PRODUTOS
-004084 HONEYWELL INC.
-004085 SAAB INSTRUMENTS AB
-004086 MICHELS & KLEBERHOFF COMPUTER
-004087 UBITREX CORPORATION
-004088 MOBIUS TECHNOLOGIES, INC.
-004089 MEIDENSHA CORPORATION
-00408A TPS TELEPROCESSING SYS. GMBH
-00408B RAYLAN CORPORATION
-00408C AXIS COMMUNICATIONS AB
-00408D THE GOODYEAR TIRE & RUBBER CO.
-00408E DIGILOG, INC.
-00408F WM-DATA MINFO AB
-004090 ANSEL COMMUNICATIONS
-004091 PROCOMP INDUSTRIA ELETRONICA
-004092 ASP COMPUTER PRODUCTS, INC.
-004093 PAXDATA NETWORKS LTD.
-004094 SHOGRAPHICS, INC.
-004095 R.P.T. INTERGROUPS INT'L LTD.
-004096 Aironet Wireless Communication
-004097 DATEX DIVISION OF
-004098 DRESSLER GMBH & CO.
-004099 NEWGEN SYSTEMS CORP.
-00409A NETWORK EXPRESS, INC.
-00409B HAL COMPUTER SYSTEMS INC.
-00409C TRANSWARE
-00409D DIGIBOARD, INC.
-00409E CONCURRENT TECHNOLOGIES LTD.
-00409F LANCAST/CASAT TECHNOLOGY, INC.
-0040A0 GOLDSTAR CO., LTD.
-0040A1 ERGO COMPUTING
-0040A2 KINGSTAR TECHNOLOGY INC.
-0040A3 MICROUNITY SYSTEMS ENGINEERING
-0040A4 ROSE ELECTRONICS
-0040A5 CLINICOMP INTL.
-0040A6 Cray, Inc.
-0040A7 ITAUTEC PHILCO S.A.
-0040A8 IMF INTERNATIONAL LTD.
-0040A9 DATACOM INC.
-0040AA VALMET AUTOMATION INC.
-0040AB ROLAND DG CORPORATION
-0040AC SUPER WORKSTATION, INC.
-0040AD SMA REGELSYSTEME GMBH
-0040AE DELTA CONTROLS, INC.
-0040AF DIGITAL PRODUCTS, INC.
-0040B0 BYTEX CORPORATION, ENGINEERING
-0040B1 CODONICS INC.
-0040B2 SYSTEMFORSCHUNG
-0040B3 PAR MICROSYSTEMS CORPORATION
-0040B4 NEXTCOM K.K.
-0040B5 VIDEO TECHNOLOGY COMPUTERS LTD
-0040B6 COMPUTERM CORPORATION
-0040B7 STEALTH COMPUTER SYSTEMS
-0040B8 IDEA ASSOCIATES
-0040B9 MACQ ELECTRONIQUE SA
-0040BA ALLIANT COMPUTER SYSTEMS CORP.
-0040BB GOLDSTAR CABLE CO., LTD.
-0040BC ALGORITHMICS LTD.
-0040BD STARLIGHT NETWORKS, INC.
-0040BE BOEING DEFENSE & SPACE
-0040BF CHANNEL SYSTEMS INTERN'L INC.
-0040C0 VISTA CONTROLS CORPORATION
-0040C1 BIZERBA-WERKE WILHEIM KRAUT
-0040C2 APPLIED COMPUTING DEVICES
-0040C3 FISCHER AND PORTER CO.
-0040C4 KINKEI SYSTEM CORPORATION
-0040C5 MICOM COMMUNICATIONS INC.
-0040C6 FIBERNET RESEARCH, INC.
-0040C7 RUBY TECH CORPORATION
-0040C8 MILAN TECHNOLOGY CORPORATION
-0040C9 NCUBE
-0040CA FIRST INTERNAT'L COMPUTER, INC
-0040CB LANWAN TECHNOLOGIES
-0040CC SILCOM MANUF'G TECHNOLOGY INC.
-0040CD TERA MICROSYSTEMS, INC.
-0040CE NET-SOURCE, INC.
-0040CF STRAWBERRY TREE, INC.
-0040D0 MITAC INTERNATIONAL CORP.
-0040D1 FUKUDA DENSHI CO., LTD.
-0040D2 PAGINE CORPORATION
-0040D3 KIMPSION INTERNATIONAL CORP.
-0040D4 GAGE TALKER CORP.
-0040D5 SARTORIUS AG
-0040D6 LOCAMATION B.V.
-0040D7 STUDIO GEN INC.
-0040D8 OCEAN OFFICE AUTOMATION LTD.
-0040D9 AMERICAN MEGATRENDS INC.
-0040DA TELSPEC LTD
-0040DB ADVANCED TECHNICAL SOLUTIONS
-0040DC TRITEC ELECTRONIC GMBH
-0040DD HONG TECHNOLOGIES
-0040DE ELETTRONICA SAN GIORGIO
-0040DF DIGALOG SYSTEMS, INC.
-0040E0 ATOMWIDE LTD.
-0040E1 MARNER INTERNATIONAL, INC.
-0040E2 MESA RIDGE TECHNOLOGIES, INC.
-0040E3 QUIN SYSTEMS LTD
-0040E4 E-M TECHNOLOGY, INC.
-0040E5 SYBUS CORPORATION
-0040E6 C.A.E.N.
-0040E7 ARNOS INSTRUMENTS & COMPUTER
-0040E8 CHARLES RIVER DATA SYSTEMS,INC
-0040E9 ACCORD SYSTEMS, INC.
-0040EA PLAIN TREE SYSTEMS INC
-0040EB MARTIN MARIETTA CORPORATION
-0040EC MIKASA SYSTEM ENGINEERING
-0040ED NETWORK CONTROLS INT'NATL INC.
-0040EE OPTIMEM
-0040EF HYPERCOM, INC.
-0040F0 MICRO SYSTEMS, INC.
-0040F1 CHUO ELECTRONICS CO., LTD.
-0040F2 JANICH & KLASS COMPUTERTECHNIK
-0040F3 NETCOR
-0040F4 CAMEO COMMUNICATIONS, INC.
-0040F5 OEM ENGINES
-0040F6 KATRON COMPUTERS INC.
-0040F7 POLAROID MEDICAL IMAGING SYS.
-0040F8 SYSTEMHAUS DISCOM
-0040F9 COMBINET
-0040FA MICROBOARDS, INC.
-0040FB CASCADE COMMUNICATIONS CORP.
-0040FC IBR COMPUTER TECHNIK GMBH
-0040FD LXE
-0040FE SYMPLEX COMMUNICATIONS
-0040FF TELEBIT CORPORATION
-004252 RLX Technologies
-005000 NEXO COMMUNICATIONS, INC.
-005001 YAMASHITA SYSTEMS CORP.
-005002 OMNISEC AG
-005003 GRETAG MACBETH AG
-005004 3COM CORPORATION
-005006 TAC AB
-005007 SIEMENS TELECOMMUNICATION SYSTEMS LIMITED
-005008 TIVA MICROCOMPUTER CORP. (TMC)
-005009 PHILIPS BROADBAND NETWORKS
-00500A IRIS TECHNOLOGIES, INC.
-00500B CISCO SYSTEMS, INC.
-00500C e-Tek Labs, Inc.
-00500D SATORI ELECTORIC CO., LTD.
-00500E CHROMATIS NETWORKS, INC.
-00500F CISCO SYSTEMS, INC.
-005010 NovaNET Learning, Inc.
-005012 CBL - GMBH
-005013 Chaparral Network Storage
-005014 CISCO SYSTEMS, INC.
-005015 BRIGHT STAR ENGINEERING
-005016 SST/WOODHEAD INDUSTRIES
-005017 RSR S.R.L.
-005018 ADVANCED MULTIMEDIA INTERNET TECHNOLOGY INC.
-005019 SPRING TIDE NETWORKS, INC.
-00501A UISIQN
-00501B ABL CANADA, INC.
-00501C JATOM SYSTEMS, INC.
-00501E Miranda Technologies, Inc.
-00501F MRG SYSTEMS, LTD.
-005020 MEDIASTAR CO., LTD.
-005021 EIS INTERNATIONAL, INC.
-005022 ZONET TECHNOLOGY, INC.
-005023 PG DESIGN ELECTRONICS, INC.
-005024 NAVIC SYSTEMS, INC.
-005026 COSYSTEMS, INC.
-005027 GENICOM CORPORATION
-005028 AVAL COMMUNICATIONS
-005029 1394 PRINTER WORKING GROUP
-00502A CISCO SYSTEMS, INC.
-00502B GENRAD LTD.
-00502C SOYO COMPUTER, INC.
-00502D ACCEL, INC.
-00502E CAMBEX CORPORATION
-00502F TollBridge Technologies, Inc.
-005030 FUTURE PLUS SYSTEMS
-005031 AEROFLEX LABORATORIES, INC.
-005032 PICAZO COMMUNICATIONS, INC.
-005033 MAYAN NETWORKS
-005036 NETCAM, LTD.
-005037 KOGA ELECTRONICS CO.
-005038 DAIN TELECOM CO., LTD.
-005039 MARINER NETWORKS
-00503A DATONG ELECTRONICS LTD.
-00503B MEDIAFIRE CORPORATION
-00503C TSINGHUA NOVEL ELECTRONICS
-00503E CISCO SYSTEMS, INC.
-00503F ANCHOR GAMES
-005040 EMWARE, INC.
-005041 CTX OPTO ELECTRONIC CORP.
-005042 SCI MANUFACTURING SINGAPORE PTE, LTD.
-005043 MARVELL SEMICONDUCTOR, INC.
-005044 ASACA CORPORATION
-005045 RIOWORKS SOLUTIONS, INC.
-005046 MENICX INTERNATIONAL CO., LTD.
-005048 INFOLIBRIA
-005049 ELLACOYA NETWORKS, INC.
-00504A ELTECO A.S.
-00504B BARCONET N.V.
-00504C GALIL MOTION CONTROL, INC.
-00504D TOKYO ELECTRON DEVICE LTD.
-00504E SIERRA MONITOR CORP.
-00504F OLENCOM ELECTRONICS
-005050 CISCO SYSTEMS, INC.
-005051 IWATSU ELECTRIC CO., LTD.
-005052 TIARA NETWORKS, INC.
-005053 CISCO SYSTEMS, INC.
-005054 CISCO SYSTEMS, INC.
-005055 DOMS A/S
-005056 VMWare, Inc.
-005057 BROADBAND ACCESS SYSTEMS
-005058 VEGASTREAM LIMITED
-005059 SUITE TECHNOLOGY SYSTEMS NETWORK
-00505A NETWORK ALCHEMY, INC.
-00505B KAWASAKI LSI U.S.A., INC.
-00505C TUNDO CORPORATION
-00505E DIGITEK MICROLOGIC S.A.
-00505F BRAND INNOVATORS
-005060 TANDBERG TELECOM AS
-005062 KOUWELL ELECTRONICS CORP. **
-005063 OY COMSEL SYSTEM AB
-005064 CAE ELECTRONICS
-005065 DENSEI-LAMBAD Co., Ltd.
-005066 AtecoM GmbH advanced telecomunication modules
-005067 AEROCOMM, INC.
-005068 ELECTRONIC INDUSTRIES ASSOCIATION
-005069 PixStream Incorporated
-00506A EDEVA, INC.
-00506B SPX-ATEG
-00506C G & L BEIJER ELECTRONICS AB
-00506D VIDEOJET SYSTEMS
-00506E CORDER ENGINEERING CORPORATION
-00506F G-CONNECT
-005070 CHAINTECH COMPUTER CO., LTD.
-005071 AIWA CO., LTD.
-005072 CORVIS CORPORATION
-005073 CISCO SYSTEMS, INC.
-005074 ADVANCED HI-TECH CORP.
-005075 KESTREL SOLUTIONS
-005076 IBM
-005077 PROLIFIC TECHNOLOGY, INC.
-005078 MEGATON HOUSE, LTD.
-00507A XPEED, INC.
-00507B MERLOT COMMUNICATIONS
-00507C VIDEOCON AG
-00507D IFP
-00507E NEWER TECHNOLOGY
-00507F DrayTek Corp.
-005080 CISCO SYSTEMS, INC.
-005081 MURATA MACHINERY, LTD.
-005082 FORESSON CORPORATION
-005083 GILBARCO, INC.
-005084 ATL PRODUCTS
-005086 TELKOM SA, LTD.
-005087 TERASAKI ELECTRIC CO., LTD.
-005088 AMANO CORPORATION
-005089 SAFETY MANAGEMENT SYSTEMS
-00508B COMPAQ COMPUTER CORPORATION
-00508C RSI SYSTEMS
-00508D ABIT COMPUTER CORPORATION
-00508E OPTIMATION, INC.
-00508F ASITA TECHNOLOGIES INT'L LTD.
-005090 DCTRI
-005091 NETACCESS, INC.
-005092 RIGAKU INDUSTRIAL CORPORATION
-005093 BOEING
-005094 PACE MICRO TECHNOLOGY PLC
-005095 PERACOM NETWORKS
-005096 SALIX TECHNOLOGIES, INC.
-005097 MMC-EMBEDDED COMPUTERTECHNIK GmbH
-005098 GLOBALOOP, LTD.
-005099 3COM EUROPE, LTD.
-00509A TAG ELECTRONIC SYSTEMS
-00509B SWITCHCORE AB
-00509C BETA RESEARCH
-00509D THE INDUSTREE B.V.
-00509E Les Technologies SoftAcoustik Inc.
-00509F HORIZON COMPUTER
-0050A0 DELTA COMPUTER SYSTEMS, INC.
-0050A1 CARLO GAVAZZI, INC.
-0050A2 CISCO SYSTEMS, INC.
-0050A3 TransMedia Communications, Inc.
-0050A4 IO TECH, INC.
-0050A5 CAPITOL BUSINESS SYSTEMS, LTD.
-0050A6 OPTRONICS
-0050A7 CISCO SYSTEMS, INC.
-0050A8 OpenCon Systems, Inc.
-0050A9 MOLDAT WIRELESS TECHNOLGIES
-0050AA KONICA MINOLTA HOLDINGS, INC.
-0050AB NALTEC, INC.
-0050AC MAPLE COMPUTER CORPORATION
-0050AD CommUnique Wireless Corp.
-0050AE IWAKI ELECTRONICS CO., LTD.
-0050AF INTERGON, INC.
-0050B0 TECHNOLOGY ATLANTA CORPORATION
-0050B1 GIDDINGS & LEWIS
-0050B2 BRODEL AUTOMATION
-0050B3 VOICEBOARD CORPORATION
-0050B4 SATCHWELL CONTROL SYSTEMS, LTD
-0050B5 FICHET-BAUCHE
-0050B6 GOOD WAY IND. CO., LTD.
-0050B7 BOSER TECHNOLOGY CO., LTD.
-0050B8 INOVA COMPUTERS GMBH & CO. KG
-0050B9 XITRON TECHNOLOGIES, INC.
-0050BA D-LINK
-0050BB CMS TECHNOLOGIES
-0050BC HAMMER STORAGE SOLUTIONS
-0050BD CISCO SYSTEMS, INC.
-0050BE FAST MULTIMEDIA AG
-0050BF MOTOTECH INC.
-0050C0 GATAN, INC.
-0050C1 GEMFLEX NETWORKS, LTD.
-0050C2 IEEE REGISTRATION AUTHORITY
-0050C4 IMD
-0050C5 ADS TECHNOLOGIES, INC.
-0050C6 LOOP TELECOMMUNICATION INTERNATIONAL, INC.
-0050C8 ADDONICS COMMUNICATIONS, INC.
-0050C9 MASPRO DENKOH CORP.
-0050CA NET TO NET TECHNOLOGIES
-0050CB JETTER
-0050CC XYRATEX
-0050CD DIGIANSWER A/S
-0050CE LG INTERNATIONAL CORP.
-0050CF VANLINK COMMUNICATION TECHNOLOGY RESEARCH INSTITUTE
-0050D0 MINERVA SYSTEMS
-0050D1 CISCO SYSTEMS, INC.
-0050D2 BAE Systems Canada, Inc.
-0050D3 DIGITAL AUDIO PROCESSING PTY. LTD.
-0050D4 JOOHONG INFORMATION &
-0050D5 AD SYSTEMS CORP.
-0050D6 ATLAS COPCO TOOLS AB
-0050D7 TELSTRAT
-0050D8 UNICORN COMPUTER CORP.
-0050D9 ENGETRON-ENGENHARIA ELETRONICA IND. e COM. LTDA
-0050DA 3COM CORPORATION
-0050DB CONTEMPORARY CONTROL
-0050DC TAS TELEFONBAU A. SCHWABE GMBH & CO. KG
-0050DD SERRA SOLDADURA, S.A.
-0050DE SIGNUM SYSTEMS CORP.
-0050DF AirFiber, Inc.
-0050E1 NS TECH ELECTRONICS SDN BHD
-0050E2 CISCO SYSTEMS, INC.
-0050E3 Terayon Communications Systems
-0050E4 APPLE COMPUTER, INC.
-0050E6 HAKUSAN CORPORATION
-0050E7 PARADISE INNOVATIONS (ASIA)
-0050E8 NOMADIX INC.
-0050EA XEL COMMUNICATIONS, INC.
-0050EB ALPHA-TOP CORPORATION
-0050EC OLICOM A/S
-0050ED ANDA NETWORKS
-0050EE TEK DIGITEL CORPORATION
-0050EF SPE Systemhaus GmbH
-0050F0 CISCO SYSTEMS, INC.
-0050F1 LIBIT SIGNAL PROCESSING, LTD.
-0050F2 MICROSOFT CORP.
-0050F3 GLOBAL NET INFORMATION CO., Ltd.
-0050F4 SIGMATEK GMBH & CO. KG
-0050F6 PAN-INTERNATIONAL INDUSTRIAL CORP.
-0050F7 VENTURE MANUFACTURING (SINGAPORE) LTD.
-0050F8 ENTREGA TECHNOLOGIES, INC.
-0050FA OXTEL, LTD.
-0050FB VSK ELECTRONICS
-0050FC EDIMAX TECHNOLOGY CO., LTD.
-0050FD VISIONCOMM CO., LTD.
-0050FE PCTVnet ASA
-0050FF HAKKO ELECTRONICS CO., LTD.
-006000 XYCOM INC.
-006001 InnoSys, Inc.
-006002 SCREEN SUBTITLING SYSTEMS, LTD
-006003 TERAOKA WEIGH SYSTEM PTE, LTD.
-006004 COMPUTADORES MODULARES SA
-006005 FEEDBACK DATA LTD.
-006006 SOTEC CO., LTD
-006007 ACRES GAMING, INC.
-006008 3COM CORPORATION
-006009 CISCO SYSTEMS, INC.
-00600A SORD COMPUTER CORPORATION
-00600B LOGWARE GmbH
-00600C APPLIED DATA SYSTEMS, INC.
-00600D Digital Logic GmbH
-00600E WAVENET INTERNATIONAL, INC.
-00600F WESTELL, INC.
-006010 NETWORK MACHINES, INC.
-006011 CRYSTAL SEMICONDUCTOR CORP.
-006012 POWER COMPUTING CORPORATION
-006013 NETSTAL MASCHINEN AG
-006014 EDEC CO., LTD.
-006015 NET2NET CORPORATION
-006016 CLARIION
-006017 TOKIMEC INC.
-006018 STELLAR ONE CORPORATION
-006019 Roche Diagnostics
-00601A KEITHLEY INSTRUMENTS
-00601B MESA ELECTRONICS
-00601C TELXON CORPORATION
-00601D LUCENT TECHNOLOGIES
-00601E SOFTLAB, INC.
-00601F STALLION TECHNOLOGIES
-006020 PIVOTAL NETWORKING, INC.
-006021 DSC CORPORATION
-006022 VICOM SYSTEMS, INC.
-006023 PERICOM SEMICONDUCTOR CORP.
-006024 GRADIENT TECHNOLOGIES, INC.
-006025 ACTIVE IMAGING PLC
-006026 VIKING COMPONENTS, INC.
-006027 Superior Modular Products
-006028 MACROVISION CORPORATION
-006029 CARY PERIPHERALS INC.
-00602A SYMICRON COMPUTER COMMUNICATIONS, LTD.
-00602B PEAK AUDIO
-00602C LINX Data Terminals, Inc.
-00602D ALERTON TECHNOLOGIES, INC.
-00602E CYCLADES CORPORATION
-00602F CISCO SYSTEMS, INC.
-006030 VILLAGE TRONIC ENTWICKLUNG
-006031 HRK SYSTEMS
-006032 I-CUBE, INC.
-006033 ACUITY IMAGING, INC.
-006034 ROBERT BOSCH GmbH
-006035 DALLAS SEMICONDUCTOR, INC.
-006036 AUSTRIAN RESEARCH CENTER SEIBERSDORF
-006037 PHILIPS SEMICONDUCTORS
-006038 Nortel Networks
-006039 SanCom Technology, Inc.
-00603A QUICK CONTROLS LTD.
-00603B AMTEC spa
-00603C HAGIWARA SYS-COM CO., LTD.
-00603D 3CX
-00603E CISCO SYSTEMS, INC.
-00603F PATAPSCO DESIGNS
-006040 NETRO CORP.
-006041 Yokogawa Electric Corporation
-006042 TKS (USA), INC.
-006043 ComSoft Systems, Inc.
-006044 LITTON/POLY-SCIENTIFIC
-006045 PATHLIGHT TECHNOLOGIES
-006046 VMETRO, INC.
-006047 CISCO SYSTEMS, INC.
-006048 EMC CORPORATION
-006049 VINA TECHNOLOGIES
-00604A SAIC IDEAS GROUP
-00604B BIODATA GmbH
-00604C SAT
-00604D MMC NETWORKS, INC.
-00604E CYCLE COMPUTER CORPORATION, INC.
-00604F SUZUKI MFG. CO., LTD.
-006050 INTERNIX INC.
-006051 QUALITY SEMICONDUCTOR
-006052 PERIPHERALS ENTERPRISE CO., Ltd.
-006053 TOYODA MACHINE WORKS, LTD.
-006054 CONTROLWARE GMBH
-006055 CORNELL UNIVERSITY
-006056 NETWORK TOOLS, INC.
-006057 MURATA MANUFACTURING CO., LTD.
-006058 COPPER MOUNTAIN COMMUNICATIONS, INC.
-006059 TECHNICAL COMMUNICATIONS CORP.
-00605A CELCORE, INC.
-00605B IntraServer Technology, Inc.
-00605C CISCO SYSTEMS, INC.
-00605D SCANIVALVE CORP.
-00605E LIBERTY TECHNOLOGY NETWORKING
-00605F NIPPON UNISOFT CORPORATION
-006060 DAWNING TECHNOLOGIES, INC.
-006061 WHISTLE COMMUNICATIONS CORP.
-006062 TELESYNC, INC.
-006063 PSION DACOM PLC.
-006064 NETCOMM LIMITED
-006065 BERNECKER & RAINER INDUSTRIE-ELEKTRONIC GmbH
-006066 LACROIX TECHNOLGIE
-006067 ACER NETXUS INC.
-006068 EICON TECHNOLOGY CORPORATION
-006069 BROCADE COMMUNICATIONS SYSTEMS, Inc.
-00606A MITSUBISHI WIRELESS COMMUNICATIONS. INC.
-00606B Synclayer Inc.
-00606C ARESCOM
-00606D DIGITAL EQUIPMENT CORP.
-00606E DAVICOM SEMICONDUCTOR, INC.
-00606F CLARION CORPORATION OF AMERICA
-006070 CISCO SYSTEMS, INC.
-006071 MIDAS LAB, INC.
-006072 VXL INSTRUMENTS, LIMITED
-006073 REDCREEK COMMUNICATIONS, INC.
-006074 QSC AUDIO PRODUCTS
-006075 PENTEK, INC.
-006076 SCHLUMBERGER TECHNOLOGIES RETAIL PETROLEUM SYSTEMS
-006077 PRISA NETWORKS
-006078 POWER MEASUREMENT LTD.
-006079 Mainstream Data, Inc.
-00607A DVS GmbH
-00607B FORE SYSTEMS, INC.
-00607C WaveAccess, Ltd.
-00607D SENTIENT NETWORKS INC.
-00607E GIGALABS, INC.
-00607F AURORA TECHNOLOGIES, INC.
-006080 MICROTRONIX DATACOM LTD.
-006081 TV/COM INTERNATIONAL
-006082 NOVALINK TECHNOLOGIES, INC.
-006083 CISCO SYSTEMS, INC.
-006084 DIGITAL VIDEO
-006085 Storage Concepts
-006086 LOGIC REPLACEMENT TECH. LTD.
-006087 KANSAI ELECTRIC CO., LTD.
-006088 WHITE MOUNTAIN DSP, INC.
-006089 XATA
-00608A CITADEL COMPUTER
-00608B ConferTech International
-00608C 3COM CORPORATION
-00608D UNIPULSE CORP.
-00608E HE ELECTRONICS, TECHNOLOGIE & SYSTEMTECHNIK GmbH
-00608F TEKRAM TECHNOLOGY CO., LTD.
-006090 ABLE COMMUNICATIONS, INC.
-006091 FIRST PACIFIC NETWORKS, INC.
-006092 MICRO/SYS, INC.
-006093 VARIAN
-006094 IBM CORP.
-006095 ACCU-TIME SYSTEMS, INC.
-006096 T.S. MICROTECH INC.
-006097 3COM CORPORATION
-006098 HT COMMUNICATIONS
-006099 LAN MEDIA CORPORATION
-00609A NJK TECHNO CO.
-00609B ASTRO-MED, INC.
-00609C Perkin-Elmer Incorporated
-00609D PMI FOOD EQUIPMENT GROUP
-00609E ASC X3 - INFORMATION TECHNOLOGY STANDARDS SECRETARIATS
-00609F PHAST CORPORATION
-0060A0 SWITCHED NETWORK TECHNOLOGIES, INC.
-0060A1 VPNet, Inc.
-0060A2 NIHON UNISYS LIMITED CO.
-0060A3 CONTINUUM TECHNOLOGY CORP.
-0060A4 GRINAKER SYSTEM TECHNOLOGIES
-0060A5 PERFORMANCE TELECOM CORP.
-0060A6 PARTICLE MEASURING SYSTEMS
-0060A7 MICROSENS GmbH & CO. KG
-0060A8 TIDOMAT AB
-0060A9 GESYTEC MbH
-0060AA INTELLIGENT DEVICES INC. (IDI)
-0060AB LARSCOM INCORPORATED
-0060AC RESILIENCE CORPORATION
-0060AD MegaChips Corporation
-0060AE TRIO INFORMATION SYSTEMS AB
-0060AF PACIFIC MICRO DATA, INC.
-0060B0 HEWLETT-PACKARD CO.
-0060B1 INPUT/OUTPUT, INC.
-0060B2 PROCESS CONTROL CORP.
-0060B3 Z-COM, INC.
-0060B4 GLENAYRE R&D INC.
-0060B5 KEBA GmbH
-0060B6 LAND COMPUTER CO., LTD.
-0060B7 CHANNELMATIC, INC.
-0060B8 CORELIS INC.
-0060B9 NITSUKO CORPORATION
-0060BA SAHARA NETWORKS, INC.
-0060BB CABLETRON - NETLINK, INC.
-0060BC KeunYoung Electronics & Communication Co., Ltd.
-0060BD HUBBELL-PULSECOM
-0060BE WEBTRONICS
-0060BF MACRAIGOR SYSTEMS, INC.
-0060C0 NERA AS
-0060C1 WaveSpan Corporation
-0060C2 MPL AG
-0060C3 NETVISION CORPORATION
-0060C4 SOLITON SYSTEMS K.K.
-0060C5 ANCOT CORP.
-0060C6 DCS AG
-0060C7 AMATI COMMUNICATIONS CORP.
-0060C8 KUKA WELDING SYSTEMS & ROBOTS
-0060C9 ControlNet, Inc.
-0060CA HARMONIC SYSTEMS INCORPORATED
-0060CB HITACHI ZOSEN CORPORATION
-0060CC EMTRAK, INCORPORATED
-0060CD VideoServer, Inc.
-0060CE ACCLAIM COMMUNICATIONS
-0060CF ALTEON NETWORKS, INC.
-0060D0 SNMP RESEARCH INCORPORATED
-0060D1 CASCADE COMMUNICATIONS
-0060D2 LUCENT TECHNOLOGIES TAIWAN TELECOMMUNICATIONS CO., LTD.
-0060D3 AT&T
-0060D4 ELDAT COMMUNICATION LTD.
-0060D5 MIYACHI TECHNOS CORP.
-0060D6 NovAtel Wireless Technologies Ltd.
-0060D7 ECOLE POLYTECHNIQUE FEDERALE DE LAUSANNE (EPFL)
-0060D8 ELMIC SYSTEMS, INC.
-0060D9 TRANSYS NETWORKS INC.
-0060DA JBM ELECTRONICS CO.
-0060DB NTP ELEKTRONIK A/S
-0060DC TOYO COMMUNICATION EQUIPMENT Co., Ltd.
-0060DD MYRICOM, INC.
-0060DE KAYSER-THREDE GmbH
-0060DF CNT Corporation
-0060E0 AXIOM TECHNOLOGY CO., LTD.
-0060E1 ORCKIT COMMUNICATIONS LTD.
-0060E2 QUEST ENGINEERING & DEVELOPMENT
-0060E3 ARBIN INSTRUMENTS
-0060E4 COMPUSERVE, INC.
-0060E5 FUJI AUTOMATION CO., LTD.
-0060E6 SHOMITI SYSTEMS INCORPORATED
-0060E7 RANDATA
-0060E8 HITACHI COMPUTER PRODUCTS (AMERICA), INC.
-0060E9 ATOP TECHNOLOGIES, INC.
-0060EA StreamLogic
-0060EB FOURTHTRACK SYSTEMS
-0060EC HERMARY OPTO ELECTRONICS INC.
-0060ED RICARDO TEST AUTOMATION LTD.
-0060EE APOLLO
-0060EF FLYTECH TECHNOLOGY CO., LTD.
-0060F0 JOHNSON & JOHNSON MEDICAL, INC
-0060F1 EXP COMPUTER, INC.
-0060F2 LASERGRAPHICS, INC.
-0060F3 Performance Analysis Broadband, Spirent plc
-0060F4 ADVANCED COMPUTER SOLUTIONS, Inc.
-0060F5 ICON WEST, INC.
-0060F6 NEXTEST COMMUNICATIONS PRODUCTS, INC.
-0060F7 DATAFUSION SYSTEMS
-0060F8 Loran International Technologies Inc.
-0060F9 DIAMOND LANE COMMUNICATIONS
-0060FA EDUCATIONAL TECHNOLOGY RESOURCES, INC.
-0060FB PACKETEER, INC.
-0060FC CONSERVATION THROUGH INNOVATION LTD.
-0060FD NetICs, Inc.
-0060FE LYNX SYSTEM DEVELOPERS, INC.
-0060FF QuVis, Inc.
-0070B0 M/A-COM INC. COMPANIES
-0070B3 DATA RECALL LTD.
-008000 MULTITECH SYSTEMS, INC.
-008001 PERIPHONICS CORPORATION
-008002 SATELCOM (UK) LTD
-008003 HYTEC ELECTRONICS LTD.
-008004 ANTLOW COMMUNICATIONS, LTD.
-008005 CACTUS COMPUTER INC.
-008006 COMPUADD CORPORATION
-008007 DLOG NC-SYSTEME
-008008 DYNATECH COMPUTER SYSTEMS
-008009 JUPITER SYSTEMS, INC.
-00800A JAPAN COMPUTER CORP.
-00800B CSK CORPORATION
-00800C VIDECOM LIMITED
-00800D VOSSWINKEL F.U.
-00800E ATLANTIX CORPORATION
-00800F STANDARD MICROSYSTEMS
-008010 COMMODORE INTERNATIONAL
-008011 DIGITAL SYSTEMS INT'L. INC.
-008012 INTEGRATED MEASUREMENT SYSTEMS
-008013 THOMAS-CONRAD CORPORATION
-008014 ESPRIT SYSTEMS
-008015 SEIKO SYSTEMS, INC.
-008016 WANDEL AND GOLTERMANN
-008017 PFU LIMITED
-008018 KOBE STEEL, LTD.
-008019 DAYNA COMMUNICATIONS, INC.
-00801A BELL ATLANTIC
-00801B KODIAK TECHNOLOGY
-00801C NEWPORT SYSTEMS SOLUTIONS
-00801D INTEGRATED INFERENCE MACHINES
-00801E XINETRON, INC.
-00801F KRUPP ATLAS ELECTRONIK GMBH
-008020 NETWORK PRODUCTS
-008021 Alcatel Canada Inc.
-008022 SCAN-OPTICS
-008023 INTEGRATED BUSINESS NETWORKS
-008024 KALPANA, INC.
-008025 STOLLMANN GMBH
-008026 NETWORK PRODUCTS CORPORATION
-008027 ADAPTIVE SYSTEMS, INC.
-008028 TRADPOST (HK) LTD
-008029 EAGLE TECHNOLOGY, INC.
-00802A TEST SYSTEMS & SIMULATIONS INC
-00802B INTEGRATED MARKETING CO
-00802C THE SAGE GROUP PLC
-00802D XYLOGICS INC
-00802E CASTLE ROCK COMPUTING
-00802F NATIONAL INSTRUMENTS CORP.
-008030 NEXUS ELECTRONICS
-008031 BASYS, CORP.
-008032 ACCESS CO., LTD.
-008033 FORMATION, INC.
-008034 SMT GOUPIL
-008035 TECHNOLOGY WORKS, INC.
-008036 REFLEX MANUFACTURING SYSTEMS
-008037 Ericsson Group
-008038 DATA RESEARCH & APPLICATIONS
-008039 ALCATEL STC AUSTRALIA
-00803A VARITYPER, INC.
-00803B APT COMMUNICATIONS, INC.
-00803C TVS ELECTRONICS LTD
-00803D SURIGIKEN CO., LTD.
-00803E SYNERNETICS
-00803F TATUNG COMPANY
-008040 JOHN FLUKE MANUFACTURING CO.
-008041 VEB KOMBINAT ROBOTRON
-008042 FORCE COMPUTERS
-008043 NETWORLD, INC.
-008044 SYSTECH COMPUTER CORP.
-008045 MATSUSHITA ELECTRIC IND. CO
-008046 UNIVERSITY OF TORONTO
-008047 IN-NET CORP.
-008048 COMPEX INCORPORATED
-008049 NISSIN ELECTRIC CO., LTD.
-00804A PRO-LOG
-00804B EAGLE TECHNOLOGIES PTY.LTD.
-00804C CONTEC CO., LTD.
-00804D CYCLONE MICROSYSTEMS, INC.
-00804E APEX COMPUTER COMPANY
-00804F DAIKIN INDUSTRIES, LTD.
-008050 ZIATECH CORPORATION
-008051 FIBERMUX
-008052 TECHNICALLY ELITE CONCEPTS
-008053 INTELLICOM, INC.
-008054 FRONTIER TECHNOLOGIES CORP.
-008055 FERMILAB
-008056 SPHINX ELEKTRONIK GMBH
-008057 ADSOFT, LTD.
-008058 PRINTER SYSTEMS CORPORATION
-008059 STANLEY ELECTRIC CO., LTD
-00805A TULIP COMPUTERS INTERNAT'L B.V
-00805B CONDOR SYSTEMS, INC.
-00805C AGILIS CORPORATION
-00805D CANSTAR
-00805E LSI LOGIC CORPORATION
-00805F COMPAQ COMPUTER CORPORATION
-008060 NETWORK INTERFACE CORPORATION
-008061 LITTON SYSTEMS, INC.
-008062 INTERFACE CO.
-008063 RICHARD HIRSCHMANN GMBH & CO.
-008064 WYSE TECHNOLOGY
-008065 CYBERGRAPHIC SYSTEMS PTY LTD.
-008066 ARCOM CONTROL SYSTEMS, LTD.
-008067 SQUARE D COMPANY
-008068 YAMATECH SCIENTIFIC LTD.
-008069 COMPUTONE SYSTEMS
-00806A ERI (EMPAC RESEARCH INC.)
-00806B SCHMID TELECOMMUNICATION
-00806C CEGELEC PROJECTS LTD
-00806D CENTURY SYSTEMS CORP.
-00806E NIPPON STEEL CORPORATION
-00806F ONELAN LTD.
-008070 COMPUTADORAS MICRON
-008071 SAI TECHNOLOGY
-008072 MICROPLEX SYSTEMS LTD.
-008073 DWB ASSOCIATES
-008074 FISHER CONTROLS
-008075 PARSYTEC GMBH
-008076 MCNC
-008077 BROTHER INDUSTRIES, LTD.
-008078 PRACTICAL PERIPHERALS, INC.
-008079 MICROBUS DESIGNS LTD.
-00807A AITECH SYSTEMS LTD.
-00807B ARTEL COMMUNICATIONS CORP.
-00807C FIBERCOM, INC.
-00807D EQUINOX SYSTEMS INC.
-00807E SOUTHERN PACIFIC LTD.
-00807F DY-4 INCORPORATED
-008080 DATAMEDIA CORPORATION
-008081 KENDALL SQUARE RESEARCH CORP.
-008082 PEP MODULAR COMPUTERS GMBH
-008083 AMDAHL
-008084 THE CLOUD INC.
-008085 H-THREE SYSTEMS CORPORATION
-008086 COMPUTER GENERATION INC.
-008087 OKI ELECTRIC INDUSTRY CO., LTD
-008088 VICTOR COMPANY OF JAPAN, LTD.
-008089 TECNETICS (PTY) LTD.
-00808A SUMMIT MICROSYSTEMS CORP.
-00808B DACOLL LIMITED
-00808C NetScout Systems, Inc.
-00808D WESTCOAST TECHNOLOGY B.V.
-00808E RADSTONE TECHNOLOGY
-00808F C. ITOH ELECTRONICS, INC.
-008090 MICROTEK INTERNATIONAL, INC.
-008091 TOKYO ELECTRIC CO.,LTD
-008092 JAPAN COMPUTER INDUSTRY, INC.
-008093 XYRON CORPORATION
-008094 ALFA LAVAL AUTOMATION AB
-008095 BASIC MERTON HANDELSGES.M.B.H.
-008096 HUMAN DESIGNED SYSTEMS, INC.
-008097 CENTRALP AUTOMATISMES
-008098 TDK CORPORATION
-008099 KLOCKNER MOELLER IPC
-00809A NOVUS NETWORKS LTD
-00809B JUSTSYSTEM CORPORATION
-00809C LUXCOM, INC.
-00809D Commscraft Ltd.
-00809E DATUS GMBH
-00809F ALCATEL BUSINESS SYSTEMS
-0080A0 EDISA HEWLETT PACKARD S/A
-0080A1 MICROTEST, INC.
-0080A2 CREATIVE ELECTRONIC SYSTEMS
-0080A3 LANTRONIX
-0080A4 LIBERTY ELECTRONICS
-0080A5 SPEED INTERNATIONAL
-0080A6 REPUBLIC TECHNOLOGY, INC.
-0080A7 MEASUREX CORP.
-0080A8 VITACOM CORPORATION
-0080A9 CLEARPOINT RESEARCH
-0080AA MAXPEED
-0080AB DUKANE NETWORK INTEGRATION
-0080AC IMLOGIX, DIVISION OF GENESYS
-0080AD CNET TECHNOLOGY, INC.
-0080AE HUGHES NETWORK SYSTEMS
-0080AF ALLUMER CO., LTD.
-0080B0 ADVANCED INFORMATION
-0080B1 SOFTCOM A/S
-0080B2 NETWORK EQUIPMENT TECHNOLOGIES
-0080B3 AVAL DATA CORPORATION
-0080B4 SOPHIA SYSTEMS
-0080B5 UNITED NETWORKS INC.
-0080B6 THEMIS COMPUTER
-0080B7 STELLAR COMPUTER
-0080B8 BUG, INCORPORATED
-0080B9 ARCHE TECHNOLIGIES INC.
-0080BA SPECIALIX (ASIA) PTE, LTD
-0080BB HUGHES LAN SYSTEMS
-0080BC HITACHI ENGINEERING CO., LTD
-0080BD THE FURUKAWA ELECTRIC CO., LTD
-0080BE ARIES RESEARCH
-0080BF TAKAOKA ELECTRIC MFG. CO. LTD.
-0080C0 PENRIL DATACOMM
-0080C1 LANEX CORPORATION
-0080C2 IEEE 802.1 COMMITTEE
-0080C3 BICC INFORMATION SYSTEMS & SVC
-0080C4 DOCUMENT TECHNOLOGIES, INC.
-0080C5 NOVELLCO DE MEXICO
-0080C6 NATIONAL DATACOMM CORPORATION
-0080C7 XIRCOM
-0080C8 D-LINK SYSTEMS, INC.
-0080C9 ALBERTA MICROELECTRONIC CENTRE
-0080CA NETCOM RESEARCH INCORPORATED
-0080CB FALCO DATA PRODUCTS
-0080CC MICROWAVE BYPASS SYSTEMS
-0080CD MICRONICS COMPUTER, INC.
-0080CE BROADCAST TELEVISION SYSTEMS
-0080CF EMBEDDED PERFORMANCE INC.
-0080D0 COMPUTER PERIPHERALS, INC.
-0080D1 KIMTRON CORPORATION
-0080D2 SHINNIHONDENKO CO., LTD.
-0080D3 SHIVA CORP.
-0080D4 CHASE RESEARCH LTD.
-0080D5 CADRE TECHNOLOGIES
-0080D6 NUVOTECH, INC.
-0080D7 Fantum Engineering
-0080D8 NETWORK PERIPHERALS INC.
-0080D9 EMK ELEKTRONIK
-0080DA BRUEL & KJAER
-0080DB GRAPHON CORPORATION
-0080DC PICKER INTERNATIONAL
-0080DD GMX INC/GIMIX
-0080DE GIPSI S.A.
-0080DF ADC CODENOLL TECHNOLOGY CORP.
-0080E0 XTP SYSTEMS, INC.
-0080E1 STMICROELECTRONICS
-0080E2 T.D.I. CO., LTD.
-0080E3 CORAL NETWORK CORPORATION
-0080E4 NORTHWEST DIGITAL SYSTEMS, INC
-0080E5 MYLEX CORPORATION
-0080E6 PEER NETWORKS, INC.
-0080E7 LYNWOOD SCIENTIFIC DEV. LTD.
-0080E8 CUMULUS CORPORATIION
-0080E9 Madge Ltd.
-0080EA ADVA Optical Networking Ltd.
-0080EB COMPCONTROL B.V.
-0080EC SUPERCOMPUTING SOLUTIONS, INC.
-0080ED IQ TECHNOLOGIES, INC.
-0080EE THOMSON CSF
-0080EF RATIONAL
-0080F0 Panasonic Communications Co., Ltd.
-0080F1 OPUS SYSTEMS
-0080F2 RAYCOM SYSTEMS INC
-0080F3 SUN ELECTRONICS CORP.
-0080F4 TELEMECANIQUE ELECTRIQUE
-0080F5 QUANTEL LTD
-0080F6 SYNERGY MICROSYSTEMS
-0080F7 ZENITH ELECTRONICS
-0080F8 MIZAR, INC.
-0080F9 HEURIKON CORPORATION
-0080FA RWT GMBH
-0080FB BVM LIMITED
-0080FC AVATAR CORPORATION
-0080FD EXSCEED CORPRATION
-0080FE AZURE TECHNOLOGIES, INC.
-0080FF SOC. DE TELEINFORMATIQUE RTC
-009000 DIAMOND MULTIMEDIA
-009001 NISHIMU ELECTRONICS INDUSTRIES CO., LTD.
-009002 ALLGON AB
-009003 APLIO
-009004 3COM EUROPE LTD.
-009005 PROTECH SYSTEMS CO., LTD.
-009006 HAMAMATSU PHOTONICS K.K.
-009007 DOMEX TECHNOLOGY CORP.
-009008 HanA Systems Inc.
-009009 i Controls, Inc.
-00900A PROTON ELECTRONIC INDUSTRIAL CO., LTD.
-00900B LANNER ELECTRONICS, INC.
-00900C CISCO SYSTEMS, INC.
-00900D OVERLAND DATA INC.
-00900E HANDLINK TECHNOLOGIES, INC.
-00900F KAWASAKI HEAVY INDUSTRIES, LTD
-009010 SIMULATION LABORATORIES, INC.
-009011 WAVTrace, Inc.
-009012 GLOBESPAN SEMICONDUCTOR, INC.
-009013 SAMSAN CORP.
-009014 ROTORK INSTRUMENTS, LTD.
-009015 CENTIGRAM COMMUNICATIONS CORP.
-009016 ZAC
-009017 ZYPCOM, INC.
-009018 ITO ELECTRIC INDUSTRY CO, LTD.
-009019 HERMES ELECTRONICS CO., LTD.
-00901A UNISPHERE SOLUTIONS
-00901B DIGITAL CONTROLS
-00901C mps Software Gmbh
-00901D PEC (NZ) LTD.
-00901E SELESTA INGEGNE RIA S.P.A.
-00901F ADTEC PRODUCTIONS, INC.
-009020 PHILIPS ANALYTICAL X-RAY B.V.
-009021 CISCO SYSTEMS, INC.
-009022 IVEX
-009023 ZILOG INC.
-009024 PIPELINKS, INC.
-009025 VISION SYSTEMS LTD. PTY
-009026 ADVANCED SWITCHING COMMUNICATIONS, INC.
-009027 INTEL CORPORATION
-009028 NIPPON SIGNAL CO., LTD.
-009029 CRYPTO AG
-00902A COMMUNICATION DEVICES, INC.
-00902B CISCO SYSTEMS, INC.
-00902C DATA & CONTROL EQUIPMENT LTD.
-00902D DATA ELECTRONICS (AUST.) PTY, LTD.
-00902E NAMCO LIMITED
-00902F NETCORE SYSTEMS, INC.
-009030 HONEYWELL-DATING
-009031 MYSTICOM, LTD.
-009032 PELCOMBE GROUP LTD.
-009033 INNOVAPHONE GmbH
-009034 IMAGIC, INC.
-009035 ALPHA TELECOM, INC.
-009036 ens, inc.
-009037 ACUCOMM, INC.
-009038 FOUNTAIN TECHNOLOGIES, INC.
-009039 SHASTA NETWORKS
-00903A NIHON MEDIA TOOL INC.
-00903B TriEMS Research Lab, Inc.
-00903C ATLANTIC NETWORK SYSTEMS
-00903D BIOPAC SYSTEMS, INC.
-00903E N.V. PHILIPS INDUSTRIAL ACTIVITIES
-00903F AZTEC RADIOMEDIA
-009040 Siemens Network Convergence LLC
-009041 APPLIED DIGITAL ACCESS
-009042 ECCS, Inc.
-009043 NICHIBEI DENSHI CO., LTD.
-009044 ASSURED DIGITAL, INC.
-009045 Marconi Communications
-009046 DEXDYNE, LTD.
-009047 GIGA FAST E. LTD.
-009048 ZEAL CORPORATION
-009049 ENTRIDIA CORPORATION
-00904A CONCUR SYSTEM TECHNOLOGIES
-00904B GemTek Technology Co., Ltd.
-00904C EPIGRAM, INC.
-00904D SPEC S.A.
-00904E DELEM BV
-00904F ABB POWER T&D COMPANY, INC.
-009050 TELESTE OY
-009051 ULTIMATE TECHNOLOGY CORP.
-009052 SELCOM ELETTRONICA S.R.L.
-009053 DAEWOO ELECTRONICS CO., LTD.
-009054 INNOVATIVE SEMICONDUCTORS, INC
-009055 PARKER HANNIFIN CORPORATION COMPUMOTOR DIVISION
-009056 TELESTREAM, INC.
-009057 AANetcom, Inc.
-009058 Ultra Electronics Ltd., Command and Control Systems
-009059 TELECOM DEVICE K.K.
-00905A DEARBORN GROUP, INC.
-00905B RAYMOND AND LAE ENGINEERING
-00905C EDMI
-00905D NETCOM SICHERHEITSTECHNIK GmbH
-00905E RAULAND-BORG CORPORATION
-00905F CISCO SYSTEMS, INC.
-009060 SYSTEM CREATE CORP.
-009061 PACIFIC RESEARCH & ENGINEERING CORPORATION
-009062 ICP VORTEX COMPUTERSYSTEME GmbH
-009063 COHERENT COMMUNICATIONS SYSTEMS CORPORATION
-009064 THOMSON BROADCAST SYSTEMS
-009065 FINISAR CORPORATION
-009066 Troika Networks, Inc.
-009067 WalkAbout Computers, Inc.
-009068 DVT CORP.
-009069 JUNIPER NETWORKS, INC.
-00906A TURNSTONE SYSTEMS, INC.
-00906B APPLIED RESOURCES, INC.
-00906C GWT GLOBAL WEIGHING TECHNOLOGIES GmbH
-00906D CISCO SYSTEMS, INC.
-00906E PRAXON, INC.
-00906F CISCO SYSTEMS, INC.
-009070 NEO NETWORKS, INC.
-009071 Applied Innovation Inc.
-009072 SIMRAD AS
-009073 GAIO TECHNOLOGY
-009074 ARGON NETWORKS, INC.
-009075 NEC DO BRASIL S.A.
-009076 FMT AIRCRAFT GATE SUPPORT SYSTEMS AB
-009077 ADVANCED FIBRE COMMUNICATIONS
-009078 MER TELEMANAGEMENT SOLUTIONS, LTD.
-009079 ClearOne, Inc.
-00907A SPECTRALINK CORP.
-00907B E-TECH, INC.
-00907C DIGITALCAST, INC.
-00907D Lake Communications
-00907E VETRONIX CORP.
-00907F WatchGuard Technologies, Inc.
-009080 NOT LIMITED, INC.
-009081 ALOHA NETWORKS, INC.
-009082 FORCE INSTITUTE
-009083 TURBO COMMUNICATION, INC.
-009084 ATECH SYSTEM
-009085 GOLDEN ENTERPRISES, INC.
-009086 CISCO SYSTEMS, INC.
-009087 ITIS
-009088 BAXALL SECURITY LTD.
-009089 SOFTCOM MICROSYSTEMS, INC.
-00908A BAYLY COMMUNICATIONS, INC.
-00908B CELL COMPUTING, INC.
-00908C ETREND ELECTRONICS, INC.
-00908D VICKERS ELECTRONICS SYSTEMS
-00908E Nortel Networks Broadband Access
-00908F AUDIO CODES LTD.
-009090 I-BUS
-009091 DigitalScape, Inc.
-009092 CISCO SYSTEMS, INC.
-009093 NANAO CORPORATION
-009094 OSPREY TECHNOLOGIES, INC.
-009095 UNIVERSAL AVIONICS
-009096 ASKEY COMPUTER CORP.
-009097 SYCAMORE NETWORKS
-009098 SBC DESIGNS, INC.
-009099 ALLIED TELESIS, K.K.
-00909A ONE WORLD SYSTEMS, INC.
-00909B MARKPOINT AB
-00909C Terayon Communications Systems
-00909D GSE SYSTEMS, INC.
-00909E Critical IO, LLC
-00909F DIGI-DATA CORPORATION
-0090A0 8X8 INC.
-0090A1 FLYING PIG SYSTEMS, LTD.
-0090A2 CYBERTAN TECHNOLOGY, INC.
-0090A3 Corecess Inc.
-0090A4 ALTIGA NETWORKS
-0090A5 SPECTRA LOGIC
-0090A6 CISCO SYSTEMS, INC.
-0090A7 CLIENTEC CORPORATION
-0090A8 NineTiles Networks, Ltd.
-0090A9 WESTERN DIGITAL
-0090AA INDIGO ACTIVE VISION SYSTEMS LIMITED
-0090AB CISCO SYSTEMS, INC.
-0090AC OPTIVISION, INC.
-0090AD ASPECT ELECTRONICS, INC.
-0090AE ITALTEL S.p.A.
-0090AF J. MORITA MFG. CORP.
-0090B0 VADEM
-0090B1 CISCO SYSTEMS, INC.
-0090B2 AVICI SYSTEMS INC.
-0090B3 AGRANAT SYSTEMS
-0090B4 WILLOWBROOK TECHNOLOGIES
-0090B5 NIKON CORPORATION
-0090B6 FIBEX SYSTEMS
-0090B7 DIGITAL LIGHTWAVE, INC.
-0090B8 ROHDE & SCHWARZ GMBH & CO. KG
-0090B9 BERAN INSTRUMENTS LTD.
-0090BA VALID NETWORKS, INC.
-0090BB TAINET COMMUNICATION SYSTEM Corp.
-0090BC TELEMANN CO., LTD.
-0090BD OMNIA COMMUNICATIONS, INC.
-0090BE IBC/INTEGRATED BUSINESS COMPUTERS
-0090BF CISCO SYSTEMS, INC.
-0090C0 K.J. LAW ENGINEERS, INC.
-0090C1 Peco II, Inc.
-0090C2 JK microsystems, Inc.
-0090C3 TOPIC SEMICONDUCTOR CORP.
-0090C4 JAVELIN SYSTEMS, INC.
-0090C5 INTERNET MAGIC, INC.
-0090C6 OPTIM SYSTEMS, INC.
-0090C7 ICOM INC.
-0090C8 WAVERIDER COMMUNICATIONS (CANADA) INC.
-0090C9 DPAC Technologies
-0090CA ACCORD VIDEO TELECOMMUNICATIONS, LTD.
-0090CB Wireless OnLine, Inc.
-0090CC PLANET COMMUNICATIONS, INC.
-0090CD ENT-EMPRESA NACIONAL DE TELECOMMUNICACOES, S.A.
-0090CE TETRA GmbH
-0090CF NORTEL
-0090D0 Thomson Belgium
-0090D1 LEICHU ENTERPRISE CO., LTD.
-0090D2 ARTEL VIDEO SYSTEMS
-0090D3 GIESECKE & DEVRIENT GmbH
-0090D4 BindView Development Corp.
-0090D5 EUPHONIX, INC.
-0090D6 CRYSTAL GROUP
-0090D7 NetBoost Corp.
-0090D8 WHITECROSS SYSTEMS
-0090D9 CISCO SYSTEMS, INC.
-0090DA DYNARC, INC.
-0090DB NEXT LEVEL COMMUNICATIONS
-0090DC TECO INFORMATION SYSTEMS
-0090DD THE MIHARU COMMUNICATIONS CO., LTD.
-0090DE CARDKEY SYSTEMS, INC.
-0090DF MITSUBISHI CHEMICAL AMERICA, INC.
-0090E0 SYSTRAN CORP.
-0090E1 TELENA S.P.A.
-0090E2 DISTRIBUTED PROCESSING TECHNOLOGY
-0090E3 AVEX ELECTRONICS INC.
-0090E4 NEC AMERICA, INC.
-0090E5 TEKNEMA, INC.
-0090E6 ACER LABORATORIES, INC.
-0090E7 HORSCH ELEKTRONIK AG
-0090E8 MOXA TECHNOLOGIES CORP., LTD.
-0090E9 JANZ COMPUTER AG
-0090EA ALPHA TECHNOLOGIES, INC.
-0090EB SENTRY TELECOM SYSTEMS
-0090EC PYRESCOM
-0090ED CENTRAL SYSTEM RESEARCH CO., LTD.
-0090EE PERSONAL COMMUNICATIONS TECHNOLOGIES
-0090EF INTEGRIX, INC.
-0090F0 HARMONIC LIGHTWAVES, LTD.
-0090F1 DOT HILL SYSTEMS CORPORATION
-0090F2 CISCO SYSTEMS, INC.
-0090F3 ASPECT COMMUNICATIONS
-0090F4 LIGHTNING INSTRUMENTATION
-0090F5 CLEVO CO.
-0090F6 ESCALATE NETWORKS, INC.
-0090F7 NBASE COMMUNICATIONS LTD.
-0090F8 MEDIATRIX TELECOM
-0090F9 LEITCH
-0090FA GigaNet, Inc.
-0090FB PORTWELL, INC.
-0090FC NETWORK COMPUTING DEVICES
-0090FD CopperCom, Inc.
-0090FE ELECOM CO., LTD. (LANEED DIV.)
-0090FF TELLUS TECHNOLOGY INC.
-0091D6 Crystal Group, Inc.
-009D8E CARDIAC RECORDERS, INC.
-00A000 CENTILLION NETWORKS, INC.
-00A001 WATKINS-JOHNSON COMPANY
-00A002 LEEDS & NORTHRUP AUSTRALIA PTY LTD
-00A003 STAEFA CONTROL SYSTEM
-00A004 NETPOWER, INC.
-00A005 DANIEL INSTRUMENTS, LTD.
-00A006 IMAGE DATA PROCESSING SYSTEM GROUP
-00A007 APEXX TECHNOLOGY, INC.
-00A008 NETCORP
-00A009 WHITETREE NETWORK
-00A00A R.D.C. COMMUNICATION
-00A00B COMPUTEX CO., LTD.
-00A00C KINGMAX TECHNOLOGY, INC.
-00A00D THE PANDA PROJECT
-00A00E VISUAL NETWORKS, INC.
-00A00F Broadband Technologies
-00A010 SYSLOGIC DATENTECHNIK AG
-00A011 MUTOH INDUSTRIES LTD.
-00A012 B.A.T.M. ADVANCED TECHNOLOGIES
-00A013 TELTREND LTD.
-00A014 CSIR
-00A015 WYLE
-00A016 MICROPOLIS CORP.
-00A017 J B M CORPORATION
-00A018 CREATIVE CONTROLLERS, INC.
-00A019 NEBULA CONSULTANTS, INC.
-00A01A BINAR ELEKTRONIK AB
-00A01B PREMISYS COMMUNICATIONS, INC.
-00A01C NASCENT NETWORKS CORPORATION
-00A01D SIXNET
-00A01E EST CORPORATION
-00A01F TRICORD SYSTEMS, INC.
-00A020 CITICORP/TTI
-00A021 GENERAL DYNAMICS-
-00A022 CENTRE FOR DEVELOPMENT OF ADVANCED COMPUTING
-00A023 APPLIED CREATIVE TECHNOLOGY, INC.
-00A024 3COM CORPORATION
-00A025 REDCOM LABS INC.
-00A026 TELDAT, S.A.
-00A027 FIREPOWER SYSTEMS, INC.
-00A028 CONNER PERIPHERALS
-00A029 COULTER CORPORATION
-00A02A TRANCELL SYSTEMS
-00A02B TRANSITIONS RESEARCH CORP.
-00A02C interWAVE Communications
-00A02D 1394 Trade Association
-00A02E BRAND COMMUNICATIONS, LTD.
-00A02F PIRELLI CAVI
-00A030 CAPTOR NV/SA
-00A031 HAZELTINE CORPORATION, MS 1-17
-00A032 GES SINGAPORE PTE. LTD.
-00A033 imc MeBsysteme GmbH
-00A034 AXEL
-00A035 CYLINK CORPORATION
-00A036 APPLIED NETWORK TECHNOLOGY
-00A037 DATASCOPE CORPORATION
-00A038 EMAIL ELECTRONICS
-00A039 ROSS TECHNOLOGY, INC.
-00A03A KUBOTEK CORPORATION
-00A03B TOSHIN ELECTRIC CO., LTD.
-00A03C EG&G NUCLEAR INSTRUMENTS
-00A03D OPTO-22
-00A03E ATM FORUM
-00A03F COMPUTER SOCIETY MICROPROCESSOR & MICROPROCESSOR STANDARDS C
-00A040 APPLE COMPUTER
-00A041 LEYBOLD-INFICON
-00A042 SPUR PRODUCTS CORP.
-00A043 AMERICAN TECHNOLOGY LABS, INC.
-00A044 NTT IT CO., LTD.
-00A045 PHOENIX CONTACT GMBH & CO.
-00A046 SCITEX CORP. LTD.
-00A047 INTEGRATED FITNESS CORP.
-00A048 QUESTECH, LTD.
-00A049 DIGITECH INDUSTRIES, INC.
-00A04A NISSHIN ELECTRIC CO., LTD.
-00A04B TFL LAN INC.
-00A04C INNOVATIVE SYSTEMS & TECHNOLOGIES, INC.
-00A04D EDA INSTRUMENTS, INC.
-00A04E VOELKER TECHNOLOGIES, INC.
-00A04F AMERITEC CORP.
-00A050 CYPRESS SEMICONDUCTOR
-00A051 ANGIA COMMUNICATIONS. INC.
-00A052 STANILITE ELECTRONICS PTY. LTD
-00A053 COMPACT DEVICES, INC.
-00A055 Data Device Corporation
-00A056 MICROPROSS
-00A057 LANCOM Systems GmbH
-00A058 GLORY, LTD.
-00A059 HAMILTON HALLMARK
-00A05A KOFAX IMAGE PRODUCTS
-00A05B MARQUIP, INC.
-00A05C INVENTORY CONVERSION, INC./
-00A05D CS COMPUTER SYSTEME GmbH
-00A05E MYRIAD LOGIC INC.
-00A05F BTG ENGINEERING BV
-00A060 ACER PERIPHERALS, INC.
-00A061 PURITAN BENNETT
-00A062 AES PRODATA
-00A063 JRL SYSTEMS, INC.
-00A064 KVB/ANALECT
-00A065 NEXLAND, INC.
-00A066 ISA CO., LTD.
-00A067 NETWORK SERVICES GROUP
-00A068 BHP LIMITED
-00A069 Symmetricom, Inc.
-00A06A Verilink Corporation
-00A06B DMS DORSCH MIKROSYSTEM GMBH
-00A06C SHINDENGEN ELECTRIC MFG. CO., LTD.
-00A06D MANNESMANN TALLY CORPORATION
-00A06E AUSTRON, INC.
-00A06F THE APPCON GROUP, INC.
-00A070 COASTCOM
-00A071 VIDEO LOTTERY TECHNOLOGIES,INC
-00A072 OVATION SYSTEMS LTD.
-00A073 COM21, INC.
-00A074 PERCEPTION TECHNOLOGY
-00A075 MICRON TECHNOLOGY, INC.
-00A076 CARDWARE LAB, INC.
-00A077 FUJITSU NEXION, INC.
-00A078 Marconi Communications
-00A079 ALPS ELECTRIC (USA), INC.
-00A07A ADVANCED PERIPHERALS TECHNOLOGIES, INC.
-00A07B DAWN COMPUTER INCORPORATION
-00A07C TONYANG NYLON CO., LTD.
-00A07D SEEQ TECHNOLOGY, INC.
-00A07E AVID TECHNOLOGY, INC.
-00A07F GSM-SYNTEL, LTD.
-00A080 ANTARES MICROSYSTEMS
-00A081 ALCATEL DATA NETWORKS
-00A082 NKT ELEKTRONIK A/S
-00A083 ASIMMPHONY TURKEY
-00A084 DATAPLEX PTY. LTD.
-00A086 AMBER WAVE SYSTEMS, INC.
-00A087 Zarlink Semiconductor Ltd.
-00A088 ESSENTIAL COMMUNICATIONS
-00A089 XPOINT TECHNOLOGIES, INC.
-00A08A BROOKTROUT TECHNOLOGY, INC.
-00A08B ASTON ELECTRONIC DESIGNS LTD.
-00A08C MultiMedia LANs, Inc.
-00A08D JACOMO CORPORATION
-00A08E Nokia Internet Communications
-00A08F DESKNET SYSTEMS, INC.
-00A090 TimeStep Corporation
-00A091 APPLICOM INTERNATIONAL
-00A092 H. BOLLMANN MANUFACTURERS, LTD
-00A093 B/E AEROSPACE, Inc.
-00A094 COMSAT CORPORATION
-00A095 ACACIA NETWORKS, INC.
-00A096 MITUMI ELECTRIC CO., LTD.
-00A097 JC INFORMATION SYSTEMS
-00A098 NETWORK APPLIANCE CORP.
-00A099 K-NET LTD.
-00A09A NIHON KOHDEN AMERICA
-00A09B QPSX COMMUNICATIONS, LTD.
-00A09C Xyplex, Inc.
-00A09D JOHNATHON FREEMAN TECHNOLOGIES
-00A09E ICTV
-00A09F COMMVISION CORP.
-00A0A0 COMPACT DATA, LTD.
-00A0A1 EPIC DATA INC.
-00A0A2 DIGICOM S.P.A.
-00A0A3 RELIABLE POWER METERS
-00A0A4 MICROS SYSTEMS, INC.
-00A0A5 TEKNOR MICROSYSTEME, INC.
-00A0A6 M.I. SYSTEMS, K.K.
-00A0A7 VORAX CORPORATION
-00A0A8 RENEX CORPORATION
-00A0A9 GN NETTEST (CANADA) NAVTEL DIVISION
-00A0AA SPACELABS MEDICAL
-00A0AB NETCS INFORMATIONSTECHNIK GMBH
-00A0AC GILAT SATELLITE NETWORKS, LTD.
-00A0AD MARCONI SPA
-00A0AE NUCOM SYSTEMS, INC.
-00A0AF WMS INDUSTRIES
-00A0B0 I-O DATA DEVICE, INC.
-00A0B1 FIRST VIRTUAL CORPORATION
-00A0B2 SHIMA SEIKI
-00A0B3 ZYKRONIX
-00A0B4 TEXAS MICROSYSTEMS, INC.
-00A0B5 3H TECHNOLOGY
-00A0B6 SANRITZ AUTOMATION CO., LTD.
-00A0B7 CORDANT, INC.
-00A0B8 SYMBIOS LOGIC INC.
-00A0B9 EAGLE TECHNOLOGY, INC.
-00A0BA PATTON ELECTRONICS CO.
-00A0BB HILAN GMBH
-00A0BC VIASAT, INCORPORATED
-00A0BD I-TECH CORP.
-00A0BE INTEGRATED CIRCUIT SYSTEMS, INC. COMMUNICATIONS GROUP
-00A0BF WIRELESS DATA GROUP MOTOROLA
-00A0C0 DIGITAL LINK CORP.
-00A0C1 ORTIVUS MEDICAL AB
-00A0C2 R.A. SYSTEMS CO., LTD.
-00A0C3 UNICOMPUTER GMBH
-00A0C4 CRISTIE ELECTRONICS LTD.
-00A0C5 ZYXEL COMMUNICATION
-00A0C6 QUALCOMM INCORPORATED
-00A0C7 TADIRAN TELECOMMUNICATIONS
-00A0C8 ADTRAN INC.
-00A0C9 INTEL CORPORATION - HF1-06
-00A0CA FUJITSU DENSO LTD.
-00A0CB ARK TELECOMMUNICATIONS, INC.
-00A0CC LITE-ON COMMUNICATIONS, INC.
-00A0CD DR. JOHANNES HEIDENHAIN GmbH
-00A0CE ASTROCOM CORPORATION
-00A0CF SOTAS, INC.
-00A0D0 TEN X TECHNOLOGY, INC.
-00A0D1 INVENTEC CORPORATION
-00A0D2 ALLIED TELESIS INTERNATIONAL CORPORATION
-00A0D3 INSTEM COMPUTER SYSTEMS, LTD.
-00A0D4 RADIOLAN, INC.
-00A0D5 SIERRA WIRELESS INC.
-00A0D6 SBE, INC.
-00A0D7 KASTEN CHASE APPLIED RESEARCH
-00A0D8 SPECTRA - TEK
-00A0D9 CONVEX COMPUTER CORPORATION
-00A0DA INTEGRATED SYSTEMS Technology, Inc.
-00A0DB FISHER & PAYKEL PRODUCTION
-00A0DC O.N. ELECTRONIC CO., LTD.
-00A0DD AZONIX CORPORATION
-00A0DE YAMAHA CORPORATION
-00A0DF STS TECHNOLOGIES, INC.
-00A0E0 TENNYSON TECHNOLOGIES PTY LTD
-00A0E1 WESTPORT RESEARCH ASSOCIATES, INC.
-00A0E2 KEISOKU GIKEN CORP.
-00A0E3 XKL SYSTEMS CORP.
-00A0E4 OPTIQUEST
-00A0E5 NHC COMMUNICATIONS
-00A0E6 DIALOGIC CORPORATION
-00A0E7 CENTRAL DATA CORPORATION
-00A0E8 REUTERS HOLDINGS PLC
-00A0E9 ELECTRONIC RETAILING SYSTEMS INTERNATIONAL
-00A0EA ETHERCOM CORP.
-00A0EB Encore Networks
-00A0EC TRANSMITTON LTD.
-00A0ED PRI AUTOMATION
-00A0EE NASHOBA NETWORKS
-00A0EF LUCIDATA LTD.
-00A0F0 TORONTO MICROELECTRONICS INC.
-00A0F1 MTI
-00A0F2 INFOTEK COMMUNICATIONS, INC.
-00A0F3 STAUBLI
-00A0F4 GE
-00A0F5 RADGUARD LTD.
-00A0F6 AutoGas Systems Inc.
-00A0F7 V.I COMPUTER CORP.
-00A0F8 SYMBOL TECHNOLOGIES, INC.
-00A0F9 BINTEC COMMUNICATIONS GMBH
-00A0FA Marconi Communication GmbH
-00A0FB TORAY ENGINEERING CO., LTD.
-00A0FC IMAGE SCIENCES, INC.
-00A0FD SCITEX DIGITAL PRINTING, INC.
-00A0FE BOSTON TECHNOLOGY, INC.
-00A0FF TELLABS OPERATIONS, INC.
-00AA00 INTEL CORPORATION
-00AA01 INTEL CORPORATION
-00AA02 INTEL CORPORATION
-00AA3C OLIVETTI TELECOM SPA (OLTECO)
-00B009 Grass Valley Group
-00B017 InfoGear Technology Corp.
-00B019 Casi-Rusco
-00B01C Westport Technologies
-00B01E Rantic Labs, Inc.
-00B02A ORSYS GmbH
-00B02D ViaGate Technologies, Inc.
-00B03B HiQ Networks
-00B048 Marconi Communications Inc.
-00B04A Cisco Systems, Inc.
-00B052 Intellon Corporation
-00B064 Cisco Systems, Inc.
-00B069 Honewell Oy
-00B06D Jones Futurex Inc.
-00B080 Mannesmann Ipulsys B.V.
-00B086 LocSoft Limited
-00B08E Cisco Systems, Inc.
-00B091 Transmeta Corp.
-00B094 Alaris, Inc.
-00B09A Morrow Technologies Corp.
-00B09D Point Grey Research Inc.
-00B0AC SIAE-Microelettronica S.p.A.
-00B0AE Symmetricom
-00B0B3 Xstreamis PLC
-00B0C2 Cisco Systems, Inc.
-00B0C7 Tellabs Operations, Inc.
-00B0CE TECHNOLOGY RESCUE
-00B0D0 Dell Computer Corp.
-00B0DB Nextcell, Inc.
-00B0DF Reliable Data Technology, Inc.
-00B0E7 British Federal Ltd.
-00B0EC EACEM
-00B0EE Ajile Systems, Inc.
-00B0F0 CALY NETWORKS
-00B0F5 NetWorth Technologies, Inc.
-00BB01 OCTOTHORPE CORP.
-00BBF0 UNGERMANN-BASS INC.
-00C000 LANOPTICS, LTD.
-00C001 DIATEK PATIENT MANAGMENT
-00C002 SERCOMM CORPORATION
-00C003 GLOBALNET COMMUNICATIONS
-00C004 JAPAN BUSINESS COMPUTER CO.LTD
-00C005 LIVINGSTON ENTERPRISES, INC.
-00C006 NIPPON AVIONICS CO., LTD.
-00C007 PINNACLE DATA SYSTEMS, INC.
-00C008 SECO SRL
-00C009 KT TECHNOLOGY (S) PTE LTD
-00C00A MICRO CRAFT
-00C00B NORCONTROL A.S.
-00C00C RELIA TECHNOLGIES
-00C00D ADVANCED LOGIC RESEARCH, INC.
-00C00E PSITECH, INC.
-00C00F QUANTUM SOFTWARE SYSTEMS LTD.
-00C010 HIRAKAWA HEWTECH CORP.
-00C011 INTERACTIVE COMPUTING DEVICES
-00C012 NETSPAN CORPORATION
-00C013 NETRIX
-00C014 TELEMATICS CALABASAS INT'L,INC
-00C015 NEW MEDIA CORPORATION
-00C016 ELECTRONIC THEATRE CONTROLS
-00C017 FORTE NETWORKS
-00C018 LANART CORPORATION
-00C019 LEAP TECHNOLOGY, INC.
-00C01A COROMETRICS MEDICAL SYSTEMS
-00C01B SOCKET COMMUNICATIONS, INC.
-00C01C INTERLINK COMMUNICATIONS LTD.
-00C01D GRAND JUNCTION NETWORKS, INC.
-00C01E LA FRANCAISE DES JEUX
-00C01F S.E.R.C.E.L.
-00C020 ARCO ELECTRONIC, CONTROL LTD.
-00C021 NETEXPRESS
-00C022 LASERMASTER TECHNOLOGIES, INC.
-00C023 TUTANKHAMON ELECTRONICS
-00C024 EDEN SISTEMAS DE COMPUTACAO SA
-00C025 DATAPRODUCTS CORPORATION
-00C026 LANS TECHNOLOGY CO., LTD.
-00C027 CIPHER SYSTEMS, INC.
-00C028 JASCO CORPORATION
-00C029 Nexans Deutschland AG - ANS
-00C02A OHKURA ELECTRIC CO., LTD.
-00C02B GERLOFF GESELLSCHAFT FUR
-00C02C CENTRUM COMMUNICATIONS, INC.
-00C02D FUJI PHOTO FILM CO., LTD.
-00C02E NETWIZ
-00C02F OKUMA CORPORATION
-00C030 INTEGRATED ENGINEERING B. V.
-00C031 DESIGN RESEARCH SYSTEMS, INC.
-00C032 I-CUBED LIMITED
-00C033 TELEBIT COMMUNICATIONS APS
-00C034 TRANSACTION NETWORK
-00C035 QUINTAR COMPANY
-00C036 RAYTECH ELECTRONIC CORP.
-00C037 DYNATEM
-00C038 RASTER IMAGE PROCESSING SYSTEM
-00C039 TDK SEMICONDUCTOR CORPORATION
-00C03A MEN-MIKRO ELEKTRONIK GMBH
-00C03B MULTIACCESS COMPUTING CORP.
-00C03C TOWER TECH S.R.L.
-00C03D WIESEMANN & THEIS GMBH
-00C03E FA. GEBR. HELLER GMBH
-00C03F STORES AUTOMATED SYSTEMS, INC.
-00C040 ECCI
-00C041 DIGITAL TRANSMISSION SYSTEMS
-00C042 DATALUX CORP.
-00C043 STRATACOM
-00C044 EMCOM CORPORATION
-00C045 ISOLATION SYSTEMS, LTD.
-00C046 KEMITRON LTD.
-00C047 UNIMICRO SYSTEMS, INC.
-00C048 BAY TECHNICAL ASSOCIATES
-00C049 U.S. ROBOTICS, INC.
-00C04A GROUP 2000 AG
-00C04B CREATIVE MICROSYSTEMS
-00C04C DEPARTMENT OF FOREIGN AFFAIRS
-00C04D MITEC, INC.
-00C04E COMTROL CORPORATION
-00C04F DELL COMPUTER CORPORATION
-00C050 TOYO DENKI SEIZO K.K.
-00C051 ADVANCED INTEGRATION RESEARCH
-00C052 BURR-BROWN
-00C053 DAVOX CORPORATION
-00C054 NETWORK PERIPHERALS, LTD.
-00C055 MODULAR COMPUTING TECHNOLOGIES
-00C056 SOMELEC
-00C057 MYCO ELECTRONICS
-00C058 DATAEXPERT CORP.
-00C059 NIPPON DENSO CO., LTD.
-00C05A SEMAPHORE COMMUNICATIONS CORP.
-00C05B NETWORKS NORTHWEST, INC.
-00C05C ELONEX PLC
-00C05D L&N TECHNOLOGIES
-00C05E VARI-LITE, INC.
-00C05F FINE-PAL COMPANY LIMITED
-00C060 ID SCANDINAVIA AS
-00C061 SOLECTEK CORPORATION
-00C062 IMPULSE TECHNOLOGY
-00C063 MORNING STAR TECHNOLOGIES, INC
-00C064 GENERAL DATACOMM IND. INC.
-00C065 SCOPE COMMUNICATIONS, INC.
-00C066 DOCUPOINT, INC.
-00C067 UNITED BARCODE INDUSTRIES
-00C068 PHILIP DRAKE ELECTRONICS LTD.
-00C069 Axxcelera Broadband Wireless
-00C06A ZAHNER-ELEKTRIK GMBH & CO. KG
-00C06B OSI PLUS CORPORATION
-00C06C SVEC COMPUTER CORP.
-00C06D BOCA RESEARCH, INC.
-00C06E HAFT TECHNOLOGY, INC.
-00C06F KOMATSU LTD.
-00C070 SECTRA SECURE-TRANSMISSION AB
-00C071 AREANEX COMMUNICATIONS, INC.
-00C072 KNX LTD.
-00C073 XEDIA CORPORATION
-00C074 TOYODA AUTOMATIC LOOM
-00C075 XANTE CORPORATION
-00C076 I-DATA INTERNATIONAL A-S
-00C077 DAEWOO TELECOM LTD.
-00C078 COMPUTER SYSTEMS ENGINEERING
-00C079 FONSYS CO.,LTD.
-00C07A PRIVA B.V.
-00C07B ASCEND COMMUNICATIONS, INC.
-00C07C HIGHTECH INFORMATION
-00C07D RISC DEVELOPMENTS LTD.
-00C07E KUBOTA CORPORATION ELECTRONIC
-00C07F NUPON COMPUTING CORP.
-00C080 NETSTAR, INC.
-00C081 METRODATA LTD.
-00C082 MOORE PRODUCTS CO.
-00C083 TRACE MOUNTAIN PRODUCTS, INC.
-00C084 DATA LINK CORP. LTD.
-00C085 ELECTRONICS FOR IMAGING, INC.
-00C086 THE LYNK CORPORATION
-00C087 UUNET TECHNOLOGIES, INC.
-00C088 EKF ELEKTRONIK GMBH
-00C089 TELINDUS DISTRIBUTION
-00C08A LAUTERBACH DATENTECHNIK GMBH
-00C08B RISQ MODULAR SYSTEMS, INC.
-00C08C PERFORMANCE TECHNOLOGIES, INC.
-00C08D TRONIX PRODUCT DEVELOPMENT
-00C08E NETWORK INFORMATION TECHNOLOGY
-00C08F MATSUSHITA ELECTRIC WORKS, LTD
-00C090 PRAIM S.R.L.
-00C091 JABIL CIRCUIT, INC.
-00C092 MENNEN MEDICAL INC.
-00C093 ALTA RESEARCH CORP.
-00C094 VMX INC.
-00C095 ZNYX
-00C096 TAMURA CORPORATION
-00C097 ARCHIPEL SA
-00C098 CHUNTEX ELECTRONIC CO., LTD.
-00C099 YOSHIKI INDUSTRIAL CO.,LTD.
-00C09A PHOTONICS CORPORATION
-00C09B RELIANCE COMM/TEC, R-TEC
-00C09C TOA ELECTRONIC LTD.
-00C09D DISTRIBUTED SYSTEMS INT'L, INC
-00C09E CACHE COMPUTERS, INC.
-00C09F QUANTA COMPUTER, INC.
-00C0A0 ADVANCE MICRO RESEARCH, INC.
-00C0A1 TOKYO DENSHI SEKEI CO.
-00C0A2 INTERMEDIUM A/S
-00C0A3 DUAL ENTERPRISES CORPORATION
-00C0A4 UNIGRAF OY
-00C0A5 DICKENS DATA SYSTEMS
-00C0A6 EXICOM AUSTRALIA PTY. LTD
-00C0A7 SEEL LTD.
-00C0A8 GVC CORPORATION
-00C0A9 BARRON MCCANN LTD.
-00C0AA SILICON VALLEY COMPUTER
-00C0AB Telco Systems, Inc.
-00C0AC GAMBIT COMPUTER COMMUNICATIONS
-00C0AD MARBEN COMMUNICATION SYSTEMS
-00C0AE TOWERCOM CO. INC. DBA PC HOUSE
-00C0AF TEKLOGIX INC.
-00C0B0 GCC TECHNOLOGIES,INC.
-00C0B1 GENIUS NET CO.
-00C0B2 NORAND CORPORATION
-00C0B3 COMSTAT DATACOMM CORPORATION
-00C0B4 MYSON TECHNOLOGY, INC.
-00C0B5 CORPORATE NETWORK SYSTEMS,INC.
-00C0B6 Snap Appliance, Inc.
-00C0B7 AMERICAN POWER CONVERSION CORP
-00C0B8 FRASER'S HILL LTD.
-00C0B9 FUNK SOFTWARE, INC.
-00C0BA NETVANTAGE
-00C0BB FORVAL CREATIVE, INC.
-00C0BC TELECOM AUSTRALIA/CSSC
-00C0BD INEX TECHNOLOGIES, INC.
-00C0BE ALCATEL - SEL
-00C0BF TECHNOLOGY CONCEPTS, LTD.
-00C0C0 SHORE MICROSYSTEMS, INC.
-00C0C1 QUAD/GRAPHICS, INC.
-00C0C2 INFINITE NETWORKS LTD.
-00C0C3 ACUSON COMPUTED SONOGRAPHY
-00C0C4 COMPUTER OPERATIONAL
-00C0C5 SID INFORMATICA
-00C0C6 PERSONAL MEDIA CORP.
-00C0C7 SPARKTRUM MICROSYSTEMS, INC.
-00C0C8 MICRO BYTE PTY. LTD.
-00C0C9 ELSAG BAILEY PROCESS
-00C0CA ALFA, INC.
-00C0CB CONTROL TECHNOLOGY CORPORATION
-00C0CC TELESCIENCES CO SYSTEMS, INC.
-00C0CD COMELTA, S.A.
-00C0CE CEI SYSTEMS & ENGINEERING PTE
-00C0CF IMATRAN VOIMA OY
-00C0D0 RATOC SYSTEM INC.
-00C0D1 COMTREE TECHNOLOGY CORPORATION
-00C0D2 SYNTELLECT, INC.
-00C0D3 OLYMPUS IMAGE SYSTEMS, INC.
-00C0D4 AXON NETWORKS, INC.
-00C0D5 QUANCOM ELECTRONIC GMBH
-00C0D6 J1 SYSTEMS, INC.
-00C0D7 TAIWAN TRADING CENTER DBA
-00C0D8 UNIVERSAL DATA SYSTEMS
-00C0D9 QUINTE NETWORK CONFIDENTIALITY
-00C0DA NICE SYSTEMS LTD.
-00C0DB IPC CORPORATION (PTE) LTD.
-00C0DC EOS TECHNOLOGIES, INC.
-00C0DD QLogic Corporation
-00C0DE ZCOMM, INC.
-00C0DF KYE Systems Corp.
-00C0E0 DSC COMMUNICATION CORP.
-00C0E1 SONIC SOLUTIONS
-00C0E2 CALCOMP, INC.
-00C0E3 OSITECH COMMUNICATIONS, INC.
-00C0E4 SIEMENS BUILDING
-00C0E5 GESPAC, S.A.
-00C0E6 Verilink Corporation
-00C0E7 FIBERDATA AB
-00C0E8 PLEXCOM, INC.
-00C0E9 OAK SOLUTIONS, LTD.
-00C0EA ARRAY TECHNOLOGY LTD.
-00C0EB SEH COMPUTERTECHNIK GMBH
-00C0EC DAUPHIN TECHNOLOGY
-00C0ED US ARMY ELECTRONIC
-00C0EE KYOCERA CORPORATION
-00C0EF ABIT CORPORATION
-00C0F0 KINGSTON TECHNOLOGY CORP.
-00C0F1 SHINKO ELECTRIC CO., LTD.
-00C0F2 TRANSITION NETWORKS
-00C0F3 NETWORK COMMUNICATIONS CORP.
-00C0F4 INTERLINK SYSTEM CO., LTD.
-00C0F5 METACOMP, INC.
-00C0F6 CELAN TECHNOLOGY INC.
-00C0F7 ENGAGE COMMUNICATION, INC.
-00C0F8 ABOUT COMPUTING INC.
-00C0F9 HARRIS AND JEFFRIES, INC.
-00C0FA CANARY COMMUNICATIONS, INC.
-00C0FB ADVANCED TECHNOLOGY LABS
-00C0FC ELASTIC REALITY, INC.
-00C0FD PROSUM
-00C0FE APTEC COMPUTER SYSTEMS, INC.
-00C0FF DOT HILL SYSTEMS CORPORATION
-00CBBD Cambridge Broadband Ltd.
-00CF1C COMMUNICATION MACHINERY CORP.
-00D000 FERRAN SCIENTIFIC, INC.
-00D001 VST TECHNOLOGIES, INC.
-00D002 DITECH CORPORATION
-00D003 COMDA ENTERPRISES CORP.
-00D004 PENTACOM LTD.
-00D005 ZHS ZEITMANAGEMENTSYSTEME
-00D006 CISCO SYSTEMS, INC.
-00D007 MIC ASSOCIATES, INC.
-00D008 MACTELL CORPORATION
-00D009 HSING TECH. ENTERPRISE CO. LTD
-00D00A LANACCESS TELECOM S.A.
-00D00B RHK TECHNOLOGY, INC.
-00D00C SNIJDER MICRO SYSTEMS
-00D00D MICROMERITICS INSTRUMENT
-00D00E PLURIS, INC.
-00D00F SPEECH DESIGN GMBH
-00D010 CONVERGENT NETWORKS, INC.
-00D011 PRISM VIDEO, INC.
-00D012 GATEWORKS CORP.
-00D013 PRIMEX AEROSPACE COMPANY
-00D014 ROOT, INC.
-00D015 UNIVEX MICROTECHNOLOGY CORP.
-00D016 SCM MICROSYSTEMS, INC.
-00D017 SYNTECH INFORMATION CO., LTD.
-00D018 QWES. COM, INC.
-00D019 DAINIPPON SCREEN CORPORATE
-00D01A URMET SUD S.P.A.
-00D01B MIMAKI ENGINEERING CO., LTD.
-00D01C SBS TECHNOLOGIES,
-00D01D FURUNO ELECTRIC CO., LTD.
-00D01E PINGTEL CORP.
-00D01F CTAM PTY. LTD.
-00D020 AIM SYSTEM, INC.
-00D021 REGENT ELECTRONICS CORP.
-00D022 INCREDIBLE TECHNOLOGIES, INC.
-00D023 INFORTREND TECHNOLOGY, INC.
-00D024 Cognex Corporation
-00D025 XROSSTECH, INC.
-00D026 HIRSCHMANN AUSTRIA GMBH
-00D027 APPLIED AUTOMATION, INC.
-00D028 OMNEON VIDEO NETWORKS
-00D029 WAKEFERN FOOD CORPORATION
-00D02A Voxent Systems Ltd.
-00D02B JETCELL, INC.
-00D02C CAMPBELL SCIENTIFIC, INC.
-00D02D ADEMCO
-00D02E COMMUNICATION AUTOMATION CORP.
-00D02F VLSI TECHNOLOGY INC.
-00D030 SAFETRAN SYSTEMS CORP.
-00D031 INDUSTRIAL LOGIC CORPORATION
-00D032 YANO ELECTRIC CO., LTD.
-00D033 DALIAN DAXIAN NETWORK
-00D034 ORMEC SYSTEMS CORP.
-00D035 BEHAVIOR TECH. COMPUTER CORP.
-00D036 TECHNOLOGY ATLANTA CORP.
-00D037 PHILIPS-DVS-LO BDR
-00D038 FIVEMERE, LTD.
-00D039 UTILICOM, INC.
-00D03A ZONEWORX, INC.
-00D03B VISION PRODUCTS PTY. LTD.
-00D03C Vieo, Inc.
-00D03D GALILEO TECHNOLOGY, LTD.
-00D03E ROCKETCHIPS, INC.
-00D03F AMERICAN COMMUNICATION
-00D040 SYSMATE CO., LTD.
-00D041 AMIGO TECHNOLOGY CO., LTD.
-00D042 MAHLO GMBH & CO. UG
-00D043 ZONAL RETAIL DATA SYSTEMS
-00D044 ALIDIAN NETWORKS, INC.
-00D045 KVASER AB
-00D046 DOLBY LABORATORIES, INC.
-00D047 XN TECHNOLOGIES
-00D048 ECTON, INC.
-00D049 IMPRESSTEK CO., LTD.
-00D04A PRESENCE TECHNOLOGY GMBH
-00D04B LA CIE GROUP S.A.
-00D04C EUROTEL TELECOM LTD.
-00D04D DIV OF RESEARCH & STATISTICS
-00D04E LOGIBAG
-00D04F BITRONICS, INC.
-00D050 ISKRATEL
-00D051 O2 MICRO, INC.
-00D052 ASCEND COMMUNICATIONS, INC.
-00D053 CONNECTED SYSTEMS
-00D054 SAS INSTITUTE INC.
-00D055 KATHREIN-WERKE KG
-00D056 SOMAT CORPORATION
-00D057 ULTRAK, INC.
-00D058 CISCO SYSTEMS, INC.
-00D059 AMBIT MICROSYSTEMS CORP.
-00D05A SYMBIONICS, LTD.
-00D05B ACROLOOP MOTION CONTROL
-00D05C TECHNOTREND SYSTEMTECHNIK GMBH
-00D05D INTELLIWORXX, INC.
-00D05E STRATABEAM TECHNOLOGY, INC.
-00D05F VALCOM, INC.
-00D060 PANASONIC EUROPEAN
-00D061 TREMON ENTERPRISES CO., LTD.
-00D062 DIGIGRAM
-00D063 CISCO SYSTEMS, INC.
-00D064 MULTITEL
-00D065 TOKO ELECTRIC
-00D066 WINTRISS ENGINEERING CORP.
-00D067 CAMPIO COMMUNICATIONS
-00D068 IWILL CORPORATION
-00D069 TECHNOLOGIC SYSTEMS
-00D06A LINKUP SYSTEMS CORPORATION
-00D06B SR TELECOM INC.
-00D06C SHAREWAVE, INC.
-00D06D ACRISON, INC.
-00D06E TRENDVIEW RECORDERS LTD.
-00D06F KMC CONTROLS
-00D070 LONG WELL ELECTRONICS CORP.
-00D071 ECHELON CORP.
-00D072 BROADLOGIC
-00D073 ACN ADVANCED COMMUNICATIONS
-00D074 TAQUA SYSTEMS, INC.
-00D075 ALARIS MEDICAL SYSTEMS, INC.
-00D076 MERRILL LYNCH & CO., INC.
-00D077 LUCENT TECHNOLOGIES
-00D078 ELTEX OF SWEDEN AB
-00D079 CISCO SYSTEMS, INC.
-00D07A AMAQUEST COMPUTER CORP.
-00D07B COMCAM INTERNATIONAL LTD.
-00D07C KOYO ELECTRONICS INC. CO.,LTD.
-00D07D COSINE COMMUNICATIONS
-00D07E KEYCORP LTD.
-00D07F STRATEGY & TECHNOLOGY, LIMITED
-00D080 EXABYTE CORPORATION
-00D081 REAL TIME DEVICES USA, INC.
-00D082 IOWAVE INC.
-00D083 INVERTEX, INC.
-00D084 NEXCOMM SYSTEMS, INC.
-00D085 OTIS ELEVATOR COMPANY
-00D086 FOVEON, INC.
-00D087 MICROFIRST INC.
-00D088 Terayon Communications Systems
-00D089 DYNACOLOR, INC.
-00D08A PHOTRON USA
-00D08B ADVA Limited
-00D08C GENOA TECHNOLOGY, INC.
-00D08D PHOENIX GROUP, INC.
-00D08E NVISION INC.
-00D08F ARDENT TECHNOLOGIES, INC.
-00D090 CISCO SYSTEMS, INC.
-00D091 SMARTSAN SYSTEMS, INC.
-00D092 GLENAYRE WESTERN MULTIPLEX
-00D093 TQ - COMPONENTS GMBH
-00D094 TIMELINE VISTA, INC.
-00D095 XYLAN CORPORATION
-00D096 3COM EUROPE LTD.
-00D097 CISCO SYSTEMS, INC.
-00D098 Photon Dynamics Canada Inc.
-00D099 ELCARD OY
-00D09A FILANET CORPORATION
-00D09B SPECTEL LTD.
-00D09C KAPADIA COMMUNICATIONS
-00D09D VERIS INDUSTRIES
-00D09E 2WIRE, INC.
-00D09F NOVTEK TEST SYSTEMS
-00D0A0 MIPS DENMARK
-00D0A1 OSKAR VIERLING GMBH + CO. KG
-00D0A2 INTEGRATED DEVICE
-00D0A3 VOCAL DATA, INC.
-00D0A4 ALANTRO COMMUNICATIONS
-00D0A5 AMERICAN ARIUM
-00D0A6 LANBIRD TECHNOLOGY CO., LTD.
-00D0A7 TOKYO SOKKI KENKYUJO CO., LTD.
-00D0A8 NETWORK ENGINES, INC.
-00D0A9 SHINANO KENSHI CO., LTD.
-00D0AA CHASE COMMUNICATIONS
-00D0AB DELTAKABEL TELECOM CV
-00D0AC GRAYSON WIRELESS
-00D0AD TL INDUSTRIES
-00D0AE ORESIS COMMUNICATIONS, INC.
-00D0AF CUTLER-HAMMER, INC.
-00D0B0 BITSWITCH LTD.
-00D0B1 OMEGA ELECTRONICS SA
-00D0B2 XIOTECH CORPORATION
-00D0B3 DRS FLIGHT SAFETY AND
-00D0B4 KATSUJIMA CO., LTD.
-00D0B5 IPricot formerly DotCom
-00D0B6 CRESCENT NETWORKS, INC.
-00D0B7 INTEL CORPORATION
-00D0B8 IOMEGA CORP.
-00D0B9 MICROTEK INTERNATIONAL, INC.
-00D0BA CISCO SYSTEMS, INC.
-00D0BB CISCO SYSTEMS, INC.
-00D0BC CISCO SYSTEMS, INC.
-00D0BD SICAN GMBH
-00D0BE EMUTEC INC.
-00D0BF PIVOTAL TECHNOLOGIES
-00D0C0 CISCO SYSTEMS, INC.
-00D0C1 HARMONIC DATA SYSTEMS, LTD.
-00D0C2 BALTHAZAR TECHNOLOGY AB
-00D0C3 VIVID TECHNOLOGY PTE, LTD.
-00D0C4 TERATECH CORPORATION
-00D0C5 COMPUTATIONAL SYSTEMS, INC.
-00D0C6 THOMAS & BETTS CORP.
-00D0C7 PATHWAY, INC.
-00D0C8 I/O CONSULTING A/S
-00D0C9 ADVANTECH CO., LTD.
-00D0CA INTRINSYC SOFTWARE INC.
-00D0CB DASAN CO., LTD.
-00D0CC TECHNOLOGIES LYRE INC.
-00D0CD ATAN TECHNOLOGY INC.
-00D0CE ASYST ELECTRONIC
-00D0CF MORETON BAY
-00D0D0 ZHONGXING TELECOM LTD.
-00D0D1 SIROCCO SYSTEMS, INC.
-00D0D2 EPILOG CORPORATION
-00D0D3 CISCO SYSTEMS, INC.
-00D0D4 V-BITS, INC.
-00D0D5 GRUNDIG AG
-00D0D6 AETHRA TELECOMUNICAZIONI
-00D0D7 B2C2, INC.
-00D0D8 3Com Corporation
-00D0D9 DEDICATED MICROCOMPUTERS
-00D0DA TAICOM DATA SYSTEMS CO., LTD.
-00D0DB MCQUAY INTERNATIONAL
-00D0DC MODULAR MINING SYSTEMS, INC.
-00D0DD SUNRISE TELECOM, INC.
-00D0DE PHILIPS MULTIMEDIA NETWORK
-00D0DF KUZUMI ELECTRONICS, INC.
-00D0E0 DOOIN ELECTRONICS CO.
-00D0E1 AVIONITEK ISRAEL INC.
-00D0E2 MRT MICRO, INC.
-00D0E3 ELE-CHEM ENGINEERING CO., LTD.
-00D0E4 CISCO SYSTEMS, INC.
-00D0E5 SOLIDUM SYSTEMS CORP.
-00D0E6 IBOND INC.
-00D0E7 VCON TELECOMMUNICATION LTD.
-00D0E8 MAC SYSTEM CO., LTD.
-00D0E9 ADVANTAGE CENTURY
-00D0EA NEXTONE COMMUNICATIONS, INC.
-00D0EB LIGHTERA NETWORKS, INC.
-00D0EC NAKAYO TELECOMMUNICATIONS, INC
-00D0ED XIOX
-00D0EE DICTAPHONE CORPORATION
-00D0EF IGT
-00D0F0 CONVISION TECHNOLOGY GMBH
-00D0F1 SEGA ENTERPRISES, LTD.
-00D0F2 MONTEREY NETWORKS
-00D0F3 SOLARI DI UDINE SPA
-00D0F4 CARINTHIAN TECH INSTITUTE
-00D0F5 ORANGE MICRO, INC.
-00D0F6 Alcatel Canada
-00D0F7 NEXT NETS CORPORATION
-00D0F8 FUJIAN STAR TERMINAL
-00D0F9 ACUTE COMMUNICATIONS CORP.
-00D0FA RACAL GUARDATA
-00D0FB TEK MICROSYSTEMS, INCORPORATED
-00D0FC GRANITE MICROSYSTEMS
-00D0FD OPTIMA TELE.COM, INC.
-00D0FE ASTRAL POINT
-00D0FF CISCO SYSTEMS, INC.
-00DD00 UNGERMANN-BASS INC.
-00DD01 UNGERMANN-BASS INC.
-00DD02 UNGERMANN-BASS INC.
-00DD03 UNGERMANN-BASS INC.
-00DD04 UNGERMANN-BASS INC.
-00DD05 UNGERMANN-BASS INC.
-00DD06 UNGERMANN-BASS INC.
-00DD07 UNGERMANN-BASS INC.
-00DD08 UNGERMANN-BASS INC.
-00DD09 UNGERMANN-BASS INC.
-00DD0A UNGERMANN-BASS INC.
-00DD0B UNGERMANN-BASS INC.
-00DD0C UNGERMANN-BASS INC.
-00DD0D UNGERMANN-BASS INC.
-00DD0E UNGERMANN-BASS INC.
-00DD0F UNGERMANN-BASS INC.
-00E000 FUJITSU, LTD
-00E001 STRAND LIGHTING LIMITED
-00E002 CROSSROADS SYSTEMS, INC.
-00E003 NOKIA WIRELESS BUSINESS COMMUN
-00E004 PMC-SIERRA, INC.
-00E005 TECHNICAL CORP.
-00E006 SILICON INTEGRATED SYS. CORP.
-00E007 NETWORK ALCHEMY LTD.
-00E008 AMAZING CONTROLS! INC.
-00E009 MARATHON TECHNOLOGIES CORP.
-00E00A DIBA, INC.
-00E00B ROOFTOP COMMUNICATIONS CORP.
-00E00C MOTOROLA
-00E00D RADIANT SYSTEMS
-00E00E AVALON IMAGING SYSTEMS, INC.
-00E00F SHANGHAI BAUD DATA
-00E010 HESS SB-AUTOMATENBAU GmbH
-00E011 UNIDEN SAN DIEGO R&D CENTER, INC.
-00E012 PLUTO TECHNOLOGIES INTERNATIONAL INC.
-00E013 EASTERN ELECTRONIC CO., LTD.
-00E014 CISCO SYSTEMS, INC.
-00E015 HEIWA CORPORATION
-00E016 RAPID CITY COMMUNICATIONS
-00E017 EXXACT GmbH
-00E018 ASUSTEK COMPUTER INC.
-00E019 ING. GIORDANO ELETTRONICA
-00E01A COMTEC SYSTEMS. CO., LTD.
-00E01B SPHERE COMMUNICATIONS, INC.
-00E01C MOBILITY ELECTRONICSY
-00E01D WebTV NETWORKS, INC.
-00E01E CISCO SYSTEMS, INC.
-00E01F AVIDIA Systems, Inc.
-00E020 TECNOMEN OY
-00E021 FREEGATE CORP.
-00E022 MediaLight, Inc.
-00E023 TELRAD
-00E024 GADZOOX NETWORKS
-00E025 dit CO., LTD.
-00E026 EASTMAN KODAK CO.
-00E027 DUX, INC.
-00E028 APTIX CORPORATION
-00E029 STANDARD MICROSYSTEMS CORP.
-00E02A TANDBERG TELEVISION AS
-00E02B EXTREME NETWORKS
-00E02C AST COMPUTER
-00E02D InnoMediaLogic, Inc.
-00E02E SPC ELECTRONICS CORPORATION
-00E02F MCNS HOLDINGS, L.P.
-00E030 MELITA INTERNATIONAL CORP.
-00E031 HAGIWARA ELECTRIC CO., LTD.
-00E032 MISYS FINANCIAL SYSTEMS, LTD.
-00E033 E.E.P.D. GmbH
-00E034 CISCO SYSTEMS, INC.
-00E035 LOUGHBOROUGH SOUND IMAGES, PLC
-00E036 PIONEER CORPORATION
-00E037 CENTURY CORPORATION
-00E038 PROXIMA CORPORATION
-00E039 PARADYNE CORP.
-00E03A CABLETRON SYSTEMS, INC.
-00E03B PROMINET CORPORATION
-00E03C AdvanSys
-00E03D FOCON ELECTRONIC SYSTEMS A/S
-00E03E ALFATECH, INC.
-00E03F JATON CORPORATION
-00E040 DeskStation Technology, Inc.
-00E041 CSPI
-00E042 Pacom Systems Ltd.
-00E043 VitalCom
-00E044 LSICS CORPORATION
-00E045 TOUCHWAVE, INC.
-00E046 BENTLY NEVADA CORP.
-00E047 INFOCUS SYSTEMS
-00E048 SDL COMMUNICATIONS, INC.
-00E049 MICROWI ELECTRONIC GmbH
-00E04A ENHANCED MESSAGING SYSTEMS, INC
-00E04B JUMP INDUSTRIELLE COMPUTERTECHNIK GmbH
-00E04C REALTEK SEMICONDUCTOR CORP.
-00E04D INTERNET INITIATIVE JAPAN, INC
-00E04E SANYO DENKI CO., LTD.
-00E04F CISCO SYSTEMS, INC.
-00E050 EXECUTONE INFORMATION SYSTEMS, INC.
-00E051 TALX CORPORATION
-00E052 FOUNDRY NETWORKS, INC.
-00E053 CELLPORT LABS, INC.
-00E054 KODAI HITEC CO., LTD.
-00E055 INGENIERIA ELECTRONICA COMERCIAL INELCOM S.A.
-00E056 HOLONTECH CORPORATION
-00E057 HAN MICROTELECOM. CO., LTD.
-00E058 PHASE ONE DENMARK A/S
-00E059 CONTROLLED ENVIRONMENTS, LTD.
-00E05A GALEA NETWORK SECURITY
-00E05B WEST END SYSTEMS CORP.
-00E05C MATSUSHITA KOTOBUKI ELECTRONICS INDUSTRIES, LTD.
-00E05D UNITEC CO., LTD.
-00E05E JAPAN AVIATION ELECTRONICS INDUSTRY, LTD.
-00E05F e-Net, Inc.
-00E060 SHERWOOD
-00E061 EdgePoint Networks, Inc.
-00E062 HOST ENGINEERING
-00E063 CABLETRON - YAGO SYSTEMS, INC.
-00E064 SAMSUNG ELECTRONICS
-00E065 OPTICAL ACCESS INTERNATIONAL
-00E066 ProMax Systems, Inc.
-00E067 eac AUTOMATION-CONSULTING GmbH
-00E068 MERRIMAC SYSTEMS INC.
-00E069 JAYCOR
-00E06A KAPSCH AG
-00E06B W&G SPECIAL PRODUCTS
-00E06C AEP Systems International Ltd
-00E06D COMPUWARE CORPORATION
-00E06E FAR SYSTEMS S.p.A.
-00E06F Terayon Communications Systems
-00E070 DH TECHNOLOGY
-00E071 EPIS MICROCOMPUTER
-00E072 LYNK
-00E073 NATIONAL AMUSEMENT NETWORK, INC.
-00E074 TIERNAN COMMUNICATIONS, INC.
-00E075 Verilink Corporation
-00E076 DEVELOPMENT CONCEPTS, INC.
-00E077 WEBGEAR, INC.
-00E078 BERKELEY NETWORKS
-00E079 A.T.N.R.
-00E07A MIKRODIDAKT AB
-00E07B BAY NETWORKS
-00E07C METTLER-TOLEDO, INC.
-00E07D NETRONIX, INC.
-00E07E WALT DISNEY IMAGINEERING
-00E07F LOGISTISTEM s.r.l.
-00E080 CONTROL RESOURCES CORPORATION
-00E081 TYAN COMPUTER CORP.
-00E082 ANERMA
-00E083 JATO TECHNOLOGIES, INC.
-00E084 COMPULITE R&D
-00E085 GLOBAL MAINTECH, INC.
-00E086 CYBEX COMPUTER PRODUCTS
-00E087 LeCroy - Networking Productions Division
-00E088 LTX CORPORATION
-00E089 ION Networks, Inc.
-00E08A GEC AVERY, LTD.
-00E08B QLogic Corp.
-00E08C NEOPARADIGM LABS, INC.
-00E08D PRESSURE SYSTEMS, INC.
-00E08E UTSTARCOM
-00E08F CISCO SYSTEMS, INC.
-00E090 BECKMAN LAB. AUTOMATION DIV.
-00E091 LG ELECTRONICS, INC.
-00E092 ADMTEK INCORPORATED
-00E093 ACKFIN NETWORKS
-00E094 OSAI SRL
-00E095 ADVANCED-VISION TECHNOLGIES CORP.
-00E096 SHIMADZU CORPORATION
-00E097 CARRIER ACCESS CORPORATION
-00E098 AboCom Systems, Inc.
-00E099 SAMSON AG
-00E09A POSITRON INDUSTRIES, INC.
-00E09B ENGAGE NETWORKS, INC.
-00E09C MII
-00E09D SARNOFF CORPORATION
-00E09E QUANTUM CORPORATION
-00E09F PIXEL VISION
-00E0A0 WILTRON CO.
-00E0A1 HIMA PAUL HILDEBRANDT GmbH Co. KG
-00E0A2 MICROSLATE INC.
-00E0A3 CISCO SYSTEMS, INC.
-00E0A4 ESAOTE S.p.A.
-00E0A5 ComCore Semiconductor, Inc.
-00E0A6 TELOGY NETWORKS, INC.
-00E0A7 IPC INFORMATION SYSTEMS, INC.
-00E0A8 SAT GmbH & Co.
-00E0A9 FUNAI ELECTRIC CO., LTD.
-00E0AA ELECTROSONIC LTD.
-00E0AB DIMAT S.A.
-00E0AC MIDSCO, INC.
-00E0AD EES TECHNOLOGY, LTD.
-00E0AE XAQTI CORPORATION
-00E0AF GENERAL DYNAMICS INFORMATION SYSTEMS
-00E0B0 CISCO SYSTEMS, INC.
-00E0B1 PACKET ENGINES, INC.
-00E0B2 TELMAX COMMUNICATIONS CORP.
-00E0B3 EtherWAN Systems, Inc.
-00E0B4 TECHNO SCOPE CO., LTD.
-00E0B5 ARDENT COMMUNICATIONS CORP.
-00E0B6 Entrada Networks
-00E0B7 PI GROUP, LTD.
-00E0B8 GATEWAY 2000
-00E0B9 BYAS SYSTEMS
-00E0BA BERGHOF AUTOMATIONSTECHNIK GmbH
-00E0BB NBX CORPORATION
-00E0BC SYMON COMMUNICATIONS, INC.
-00E0BD INTERFACE SYSTEMS, INC.
-00E0BE GENROCO INTERNATIONAL, INC.
-00E0BF TORRENT NETWORKING TECHNOLOGIES CORP.
-00E0C0 SEIWA ELECTRIC MFG. CO., LTD.
-00E0C1 MEMOREX TELEX JAPAN, LTD.
-00E0C2 NECSY S.p.A.
-00E0C3 SAKAI SYSTEM DEVELOPMENT CORP.
-00E0C4 HORNER ELECTRIC, INC.
-00E0C5 BCOM ELECTRONICS INC.
-00E0C6 LINK2IT, L.L.C.
-00E0C7 EUROTECH SRL
-00E0C8 VIRTUAL ACCESS, LTD.
-00E0C9 AutomatedLogic Corporation
-00E0CA BEST DATA PRODUCTS
-00E0CB RESON, INC.
-00E0CC HERO SYSTEMS, LTD.
-00E0CD SENSIS CORPORATION
-00E0CE ARN
-00E0CF INTEGRATED DEVICE TECHNOLOGY, INC.
-00E0D0 NETSPEED, INC.
-00E0D1 TELSIS LIMITED
-00E0D2 VERSANET COMMUNICATIONS, INC.
-00E0D3 DATENTECHNIK GmbH
-00E0D4 EXCELLENT COMPUTER
-00E0D5 ARCXEL TECHNOLOGIES, INC.
-00E0D6 COMPUTER & COMMUNICATION RESEARCH LAB.
-00E0D7 SUNSHINE ELECTRONICS, INC.
-00E0D8 LANBit Computer, Inc.
-00E0D9 TAZMO CO., LTD.
-00E0DA ASSURED ACCESS TECHNOLOGY, INC.
-00E0DB ViaVideo Communications, Inc.
-00E0DC NEXWARE CORP.
-00E0DD ZENITH ELECTRONICS CORPORATION
-00E0DE DATAX NV
-00E0DF KE KOMMUNIKATIONS-ELECTRONIK
-00E0E0 SI ELECTRONICS, LTD.
-00E0E1 G2 NETWORKS, INC.
-00E0E2 INNOVA CORP.
-00E0E3 SK-ELEKTRONIK GmbH
-00E0E4 FANUC ROBOTICS NORTH AMERICA, Inc.
-00E0E5 CINCO NETWORKS, INC.
-00E0E6 INCAA DATACOM B.V.
-00E0E7 RAYTHEON E-SYSTEMS, INC.
-00E0E8 GRETACODER Data Systems AG
-00E0E9 DATA LABS, INC.
-00E0EA INNOVAT COMMUNICATIONS, INC.
-00E0EB DIGICOM SYSTEMS, INCORPORATED
-00E0EC CELESTICA INC.
-00E0ED SILICOM, LTD.
-00E0EE MAREL HF
-00E0EF DIONEX
-00E0F0 ABLER TECHNOLOGY, INC.
-00E0F1 THAT CORPORATION
-00E0F2 ARLOTTO COMNET, INC.
-00E0F3 WebSprint Communications, Inc.
-00E0F4 INSIDE Technology A/S
-00E0F5 TELES AG
-00E0F6 DECISION EUROPE
-00E0F7 CISCO SYSTEMS, INC.
-00E0F8 DICNA CONTROL AB
-00E0F9 CISCO SYSTEMS, INC.
-00E0FA TRL TECHNOLOGY, LTD.
-00E0FB LEIGHTRONIX, INC.
-00E0FC HUAWEI TECHNOLOGIES CO., LTD.
-00E0FD A-TREND TECHNOLOGY CO., LTD.
-00E0FE CISCO SYSTEMS, INC.
-00E0FF SECURITY DYNAMICS TECHNOLOGIES, Inc.
-00E6D3 NIXDORF COMPUTER CORP.
-020701 RACAL-DATACOM
-021C7C PERQ SYSTEMS CORPORATION
-026086 LOGIC REPLACEMENT TECH. LTD.
-02608C 3COM CORPORATION
-027001 RACAL-DATACOM
-0270B0 M/A-COM INC. COMPANIES
-0270B3 DATA RECALL LTD
-029D8E CARDIAC RECORDERS INC.
-02AA3C OLIVETTI TELECOMM SPA (OLTECO)
-02BB01 OCTOTHORPE CORP.
-02C08C 3COM CORPORATION
-02CF1C COMMUNICATION MACHINERY CORP.
-02E6D3 NIXDORF COMPUTER CORPORATION
-040AE0 XMIT AG COMPUTER NETWORKS
-04E0C4 TRIUMPH-ADLER AG
-080001 COMPUTERVISION CORPORATION
-080002 BRIDGE COMMUNICATIONS INC.
-080003 ADVANCED COMPUTER COMM.
-080004 CROMEMCO INCORPORATED
-080005 SYMBOLICS INC.
-080006 SIEMENS AG
-080007 APPLE COMPUTER INC.
-080008 BOLT BERANEK AND NEWMAN INC.
-080009 HEWLETT PACKARD
-08000A NESTAR SYSTEMS INCORPORATED
-08000B UNISYS CORPORATION
-08000C MIKLYN DEVELOPMENT CO.
-08000D INTERNATIONAL COMPUTERS LTD.
-08000E NCR CORPORATION
-08000F MITEL CORPORATION
-080011 TEKTRONIX INC.
-080012 BELL ATLANTIC INTEGRATED SYST.
-080013 EXXON
-080014 EXCELAN
-080015 STC BUSINESS SYSTEMS
-080016 BARRISTER INFO SYS CORP
-080017 NATIONAL SEMICONDUCTOR
-080018 PIRELLI FOCOM NETWORKS
-080019 GENERAL ELECTRIC CORPORATION
-08001A TIARA/ 10NET
-08001B DATA GENERAL
-08001C KDD-KOKUSAI DEBNSIN DENWA CO.
-08001D ABLE COMMUNICATIONS INC.
-08001E APOLLO COMPUTER INC.
-08001F SHARP CORPORATION
-080020 SUN MICROSYSTEMS INC.
-080021 3M COMPANY
-080022 NBI INC.
-080023 Panasonic Communications Co., Ltd.
-080024 10NET COMMUNICATIONS/DCA
-080025 CONTROL DATA
-080026 NORSK DATA A.S.
-080027 CADMUS COMPUTER SYSTEMS
-080028 Texas Instruments
-080029 MEGATEK CORPORATION
-08002A MOSAIC TECHNOLOGIES INC.
-08002B DIGITAL EQUIPMENT CORPORATION
-08002C BRITTON LEE INC.
-08002D LAN-TEC INC.
-08002E METAPHOR COMPUTER SYSTEMS
-08002F PRIME COMPUTER INC.
-080030 NETWORK RESEARCH CORPORATION
-080030 CERN
-080030 ROYAL MELBOURNE INST OF TECH
-080031 LITTLE MACHINES INC.
-080032 TIGAN INCORPORATED
-080033 BAUSCH & LOMB
-080034 FILENET CORPORATION
-080035 MICROFIVE CORPORATION
-080036 INTERGRAPH CORPORATION
-080037 FUJI-XEROX CO. LTD.
-080038 CII HONEYWELL BULL
-080039 SPIDER SYSTEMS LIMITED
-08003A ORCATECH INC.
-08003B TORUS SYSTEMS LIMITED
-08003C SCHLUMBERGER WELL SERVICES
-08003D CADNETIX CORPORATIONS
-08003E CODEX CORPORATION
-08003F FRED KOSCHARA ENTERPRISES
-080040 FERRANTI COMPUTER SYS. LIMITED
-080041 RACAL-MILGO INFORMATION SYS..
-080042 JAPAN MACNICS CORP.
-080043 PIXEL COMPUTER INC.
-080044 DAVID SYSTEMS INC.
-080045 CONCURRENT COMPUTER CORP.
-080046 SONY CORPORATION LTD.
-080047 SEQUENT COMPUTER SYSTEMS INC.
-080048 EUROTHERM GAUGING SYSTEMS
-080049 UNIVATION
-08004A BANYAN SYSTEMS INC.
-08004B PLANNING RESEARCH CORP.
-08004C HYDRA COMPUTER SYSTEMS INC.
-08004D CORVUS SYSTEMS INC.
-08004E 3COM EUROPE LTD.
-08004F CYGNET SYSTEMS
-080050 DAISY SYSTEMS CORP.
-080051 EXPERDATA
-080052 INSYSTEC
-080053 MIDDLE EAST TECH. UNIVERSITY
-080055 STANFORD TELECOMM. INC.
-080056 STANFORD LINEAR ACCEL. CENTER
-080057 EVANS & SUTHERLAND
-080058 SYSTEMS CONCEPTS
-080059 A/S MYCRON
-08005A IBM CORPORATION
-08005B VTA TECHNOLOGIES INC.
-08005C FOUR PHASE SYSTEMS
-08005D GOULD INC.
-08005E COUNTERPOINT COMPUTER INC.
-08005F SABER TECHNOLOGY CORP.
-080060 INDUSTRIAL NETWORKING INC.
-080061 JAROGATE LTD.
-080062 GENERAL DYNAMICS
-080063 PLESSEY
-080064 AUTOPHON AG
-080065 GENRAD INC.
-080066 AGFA CORPORATION
-080067 COMDESIGN
-080068 RIDGE COMPUTERS
-080069 SILICON GRAPHICS INC.
-08006A ATT BELL LABORATORIES
-08006B ACCEL TECHNOLOGIES INC.
-08006C SUNTEK TECHNOLOGY INT'L
-08006D WHITECHAPEL COMPUTER WORKS
-08006E MASSCOMP
-08006F PHILIPS APELDOORN B.V.
-080070 MITSUBISHI ELECTRIC CORP.
-080071 MATRA (DSIE)
-080072 XEROX CORP UNIV GRANT PROGRAM
-080073 TECMAR INC.
-080074 CASIO COMPUTER CO. LTD.
-080075 DANSK DATA ELECTRONIK
-080076 PC LAN TECHNOLOGIES
-080077 TSL COMMUNICATIONS LTD.
-080078 ACCELL CORPORATION
-080079 THE DROID WORKS
-08007A INDATA
-08007B SANYO ELECTRIC CO. LTD.
-08007C VITALINK COMMUNICATIONS CORP.
-08007E AMALGAMATED WIRELESS(AUS) LTD
-08007F CARNEGIE-MELLON UNIVERSITY
-080080 AES DATA INC.
-080081 ,ASTECH INC.
-080082 VERITAS SOFTWARE
-080083 Seiko Instruments Inc.
-080084 TOMEN ELECTRONICS CORP.
-080085 ELXSI
-080086 KONICA MINOLTA HOLDINGS, INC.
-080087 XYPLEX
-080088 MCDATA CORPORATION
-080089 KINETICS
-08008A PERFORMANCE TECHNOLOGY
-08008B PYRAMID TECHNOLOGY CORP.
-08008C NETWORK RESEARCH CORPORATION
-08008D XYVISION INC.
-08008E TANDEM COMPUTERS
-08008F CHIPCOM CORPORATION
-080090 SONOMA SYSTEMS
-081443 UNIBRAIN S.A.
-08BBCC AK-NORD EDV VERTRIEBSGES. mbH
-10005A IBM CORPORATION
-1000E8 NATIONAL SEMICONDUCTOR
-800010 ATT BELL LABORATORIES
-A06A00 Verilink Corporation
-AA0000 DIGITAL EQUIPMENT CORPORATION
-AA0001 DIGITAL EQUIPMENT CORPORATION
-AA0002 DIGITAL EQUIPMENT CORPORATION
-AA0003 DIGITAL EQUIPMENT CORPORATION
-AA0004 DIGITAL EQUIPMENT CORPORATION
diff --git a/drivers/ieee1394/oui2c.sh b/drivers/ieee1394/oui2c.sh
deleted file mode 100644
index b9d0e8f10ab..00000000000
--- a/drivers/ieee1394/oui2c.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/sh
-
-cat <<EOF
-/* Generated file for OUI database */
-
-
-#ifdef CONFIG_IEEE1394_OUI_DB
-struct oui_list_struct {
- int oui;
- char *name;
-} oui_list[] = {
-EOF
-
-while read oui name; do
- echo " { 0x$oui, \"$name\" },"
-done
-
-cat <<EOF
-};
-
-#endif /* CONFIG_IEEE1394_OUI_DB */
-EOF
diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c
index ad2108f27a0..a77a832828c 100644
--- a/drivers/ieee1394/raw1394.c
+++ b/drivers/ieee1394/raw1394.c
@@ -636,27 +636,32 @@ static int state_initialized(struct file_info *fi, struct pending_request *req)
case RAW1394_REQ_SET_CARD:
spin_lock_irqsave(&host_info_lock, flags);
- if (req->req.misc < host_count) {
- list_for_each_entry(hi, &host_info_list, list) {
- if (!req->req.misc--)
- break;
- }
- get_device(&hi->host->device); // XXX Need to handle failure case
- list_add_tail(&fi->list, &hi->file_info_list);
- fi->host = hi->host;
- fi->state = connected;
-
- req->req.error = RAW1394_ERROR_NONE;
- req->req.generation = get_hpsb_generation(fi->host);
- req->req.misc = (fi->host->node_id << 16)
- | fi->host->node_count;
- if (fi->protocol_version > 3) {
- req->req.misc |=
- NODEID_TO_NODE(fi->host->irm_id) << 8;
- }
- } else {
+ if (req->req.misc >= host_count) {
req->req.error = RAW1394_ERROR_INVALID_ARG;
+ goto out_set_card;
}
+ list_for_each_entry(hi, &host_info_list, list)
+ if (!req->req.misc--)
+ break;
+ get_device(&hi->host->device); /* FIXME handle failure case */
+ list_add_tail(&fi->list, &hi->file_info_list);
+
+ /* prevent unloading of the host's low-level driver */
+ if (!try_module_get(hi->host->driver->owner)) {
+ req->req.error = RAW1394_ERROR_ABORTED;
+ goto out_set_card;
+ }
+ WARN_ON(fi->host);
+ fi->host = hi->host;
+ fi->state = connected;
+
+ req->req.error = RAW1394_ERROR_NONE;
+ req->req.generation = get_hpsb_generation(fi->host);
+ req->req.misc = (fi->host->node_id << 16)
+ | fi->host->node_count;
+ if (fi->protocol_version > 3)
+ req->req.misc |= NODEID_TO_NODE(fi->host->irm_id) << 8;
+out_set_card:
spin_unlock_irqrestore(&host_info_lock, flags);
req->req.length = 0;
@@ -2955,6 +2960,11 @@ static int raw1394_release(struct inode *inode, struct file *file)
put_device(&fi->host->device);
}
+ spin_lock_irqsave(&host_info_lock, flags);
+ if (fi->host)
+ module_put(fi->host->driver->owner);
+ spin_unlock_irqrestore(&host_info_lock, flags);
+
kfree(fi);
return 0;
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
index 4325aac7733..4edfff46b1e 100644
--- a/drivers/ieee1394/sbp2.c
+++ b/drivers/ieee1394/sbp2.c
@@ -51,7 +51,6 @@
* Grep for inline FIXME comments below.
*/
-#include <linux/blkdev.h>
#include <linux/compiler.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -304,10 +303,11 @@ static struct scsi_host_template sbp2_shost_template = {
.use_clustering = ENABLE_CLUSTERING,
.cmd_per_lun = SBP2_MAX_CMDS,
.can_queue = SBP2_MAX_CMDS,
- .emulated = 1,
.sdev_attrs = sbp2_sysfs_sdev_attrs,
};
+/* for match-all entries in sbp2_workarounds_table */
+#define SBP2_ROM_VALUE_WILDCARD 0x1000000
/*
* List of devices with known bugs.
@@ -329,22 +329,14 @@ static const struct {
},
/* Initio bridges, actually only needed for some older ones */ {
.firmware_revision = 0x000200,
+ .model_id = SBP2_ROM_VALUE_WILDCARD,
.workarounds = SBP2_WORKAROUND_INQUIRY_36,
},
/* Symbios bridge */ {
.firmware_revision = 0xa0b800,
+ .model_id = SBP2_ROM_VALUE_WILDCARD,
.workarounds = SBP2_WORKAROUND_128K_MAX_TRANS,
},
- /*
- * Note about the following Apple iPod blacklist entries:
- *
- * There are iPods (2nd gen, 3rd gen) with model_id==0. Since our
- * matching logic treats 0 as a wildcard, we cannot match this ID
- * without rewriting the matching routine. Fortunately these iPods
- * do not feature the read_capacity bug according to one report.
- * Read_capacity behaviour as well as model_id could change due to
- * Apple-supplied firmware updates though.
- */
/* iPod 4th generation */ {
.firmware_revision = 0x0a2700,
.model_id = 0x000021,
@@ -1307,11 +1299,13 @@ static void sbp2_parse_unit_directory(struct sbp2_lu *lu,
if (!(workarounds & SBP2_WORKAROUND_OVERRIDE))
for (i = 0; i < ARRAY_SIZE(sbp2_workarounds_table); i++) {
- if (sbp2_workarounds_table[i].firmware_revision &&
+ if (sbp2_workarounds_table[i].firmware_revision !=
+ SBP2_ROM_VALUE_WILDCARD &&
sbp2_workarounds_table[i].firmware_revision !=
(firmware_revision & 0xffff00))
continue;
- if (sbp2_workarounds_table[i].model_id &&
+ if (sbp2_workarounds_table[i].model_id !=
+ SBP2_ROM_VALUE_WILDCARD &&
sbp2_workarounds_table[i].model_id != ud->model_id)
continue;
workarounds |= sbp2_workarounds_table[i].workarounds;
@@ -2017,7 +2011,6 @@ static int sbp2scsi_slave_configure(struct scsi_device *sdev)
{
struct sbp2_lu *lu = (struct sbp2_lu *)sdev->host->hostdata[0];
- blk_queue_dma_alignment(sdev->request_queue, (512 - 1));
sdev->use_10_for_rw = 1;
if (sdev->type == TYPE_ROM)
diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c
index 598b19fc598..f4d1ec00af6 100644
--- a/drivers/ieee1394/video1394.c
+++ b/drivers/ieee1394/video1394.c
@@ -489,6 +489,9 @@ static void wakeup_dma_ir_ctx(unsigned long l)
reset_ir_status(d, i);
d->buffer_status[d->buffer_prg_assignment[i]] = VIDEO1394_BUFFER_READY;
do_gettimeofday(&d->buffer_time[d->buffer_prg_assignment[i]]);
+ dma_region_sync_for_cpu(&d->dma,
+ d->buffer_prg_assignment[i] * d->buf_size,
+ d->buf_size);
}
}
@@ -1096,6 +1099,8 @@ static long video1394_ioctl(struct file *file,
DBGMSG(ohci->host->id, "Starting iso transmit DMA ctx=%d",
d->ctx);
put_timestamp(ohci, d, d->last_buffer);
+ dma_region_sync_for_device(&d->dma,
+ v.buffer * d->buf_size, d->buf_size);
/* Tell the controller where the first program is */
reg_write(ohci, d->cmdPtr,
@@ -1111,6 +1116,9 @@ static long video1394_ioctl(struct file *file,
"Waking up iso transmit dma ctx=%d",
d->ctx);
put_timestamp(ohci, d, d->last_buffer);
+ dma_region_sync_for_device(&d->dma,
+ v.buffer * d->buf_size, d->buf_size);
+
reg_write(ohci, d->ctrlSet, 0x1000);
}
}
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
index af939796750..d2bb5a9a303 100644
--- a/drivers/infiniband/core/addr.c
+++ b/drivers/infiniband/core/addr.c
@@ -360,8 +360,7 @@ static int netevent_callback(struct notifier_block *self, unsigned long event,
if (event == NETEVENT_NEIGH_UPDATE) {
struct neighbour *neigh = ctx;
- if (neigh->dev->type == ARPHRD_INFINIBAND &&
- (neigh->nud_state & NUD_VALID)) {
+ if (neigh->nud_state & NUD_VALID) {
set_timeout(jiffies);
}
}
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
index 5ed141ebd1c..13efd417034 100644
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -642,7 +642,8 @@ static void snoop_recv(struct ib_mad_qp_info *qp_info,
spin_unlock_irqrestore(&qp_info->snoop_lock, flags);
}
-static void build_smp_wc(u64 wr_id, u16 slid, u16 pkey_index, u8 port_num,
+static void build_smp_wc(struct ib_qp *qp,
+ u64 wr_id, u16 slid, u16 pkey_index, u8 port_num,
struct ib_wc *wc)
{
memset(wc, 0, sizeof *wc);
@@ -652,7 +653,7 @@ static void build_smp_wc(u64 wr_id, u16 slid, u16 pkey_index, u8 port_num,
wc->pkey_index = pkey_index;
wc->byte_len = sizeof(struct ib_mad) + sizeof(struct ib_grh);
wc->src_qp = IB_QP0;
- wc->qp_num = IB_QP0;
+ wc->qp = qp;
wc->slid = slid;
wc->sl = 0;
wc->dlid_path_bits = 0;
@@ -713,7 +714,8 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv,
goto out;
}
- build_smp_wc(send_wr->wr_id, be16_to_cpu(smp->dr_slid),
+ build_smp_wc(mad_agent_priv->agent.qp,
+ send_wr->wr_id, be16_to_cpu(smp->dr_slid),
send_wr->wr.ud.pkey_index,
send_wr->wr.ud.port_num, &mad_wc);
@@ -2355,7 +2357,8 @@ static void local_completions(struct work_struct *work)
* Defined behavior is to complete response
* before request
*/
- build_smp_wc((unsigned long) local->mad_send_wr,
+ build_smp_wc(recv_mad_agent->agent.qp,
+ (unsigned long) local->mad_send_wr,
be16_to_cpu(IB_LID_PERMISSIVE),
0, recv_mad_agent->agent.port_num, &wc);
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index 743247ec065..df1efbc1088 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -933,7 +933,7 @@ ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file,
resp->wc[i].vendor_err = wc[i].vendor_err;
resp->wc[i].byte_len = wc[i].byte_len;
resp->wc[i].imm_data = (__u32 __force) wc[i].imm_data;
- resp->wc[i].qp_num = wc[i].qp_num;
+ resp->wc[i].qp_num = wc[i].qp->qp_num;
resp->wc[i].src_qp = wc[i].src_qp;
resp->wc[i].wc_flags = wc[i].wc_flags;
resp->wc[i].pkey_index = wc[i].pkey_index;
diff --git a/drivers/infiniband/hw/amso1100/c2_cq.c b/drivers/infiniband/hw/amso1100/c2_cq.c
index 05c9154d46f..5175c99ee58 100644
--- a/drivers/infiniband/hw/amso1100/c2_cq.c
+++ b/drivers/infiniband/hw/amso1100/c2_cq.c
@@ -153,7 +153,7 @@ static inline int c2_poll_one(struct c2_dev *c2dev,
entry->status = c2_cqe_status_to_openib(c2_wr_get_result(ce));
entry->wr_id = ce->hdr.context;
- entry->qp_num = ce->handle;
+ entry->qp = &qp->ibqp;
entry->wc_flags = 0;
entry->slid = 0;
entry->sl = 0;
diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h
index 1c722032319..cf95ee474b0 100644
--- a/drivers/infiniband/hw/ehca/ehca_classes.h
+++ b/drivers/infiniband/hw/ehca/ehca_classes.h
@@ -119,13 +119,14 @@ struct ehca_qp {
struct ipz_qp_handle ipz_qp_handle;
struct ehca_pfqp pf;
struct ib_qp_init_attr init_attr;
- u64 uspace_squeue;
- u64 uspace_rqueue;
- u64 uspace_fwh;
struct ehca_cq *send_cq;
struct ehca_cq *recv_cq;
unsigned int sqerr_purgeflag;
struct hlist_node list_entries;
+ /* mmap counter for resources mapped into user space */
+ u32 mm_count_squeue;
+ u32 mm_count_rqueue;
+ u32 mm_count_galpa;
};
/* must be power of 2 */
@@ -142,13 +143,14 @@ struct ehca_cq {
struct ipz_cq_handle ipz_cq_handle;
struct ehca_pfcq pf;
spinlock_t cb_lock;
- u64 uspace_queue;
- u64 uspace_fwh;
struct hlist_head qp_hashtab[QP_HASHTAB_LEN];
struct list_head entry;
u32 nr_callbacks;
spinlock_t task_lock;
u32 ownpid;
+ /* mmap counter for resources mapped into user space */
+ u32 mm_count_queue;
+ u32 mm_count_galpa;
};
enum ehca_mr_flag {
@@ -248,20 +250,6 @@ struct ehca_ucontext {
struct ib_ucontext ib_ucontext;
};
-struct ehca_module *ehca_module_new(void);
-
-int ehca_module_delete(struct ehca_module *me);
-
-int ehca_eq_ctor(struct ehca_eq *eq);
-
-int ehca_eq_dtor(struct ehca_eq *eq);
-
-struct ehca_shca *ehca_shca_new(void);
-
-int ehca_shca_delete(struct ehca_shca *me);
-
-struct ehca_sport *ehca_sport_new(struct ehca_shca *anchor);
-
int ehca_init_pd_cache(void);
void ehca_cleanup_pd_cache(void);
int ehca_init_cq_cache(void);
@@ -283,7 +271,6 @@ extern int ehca_port_act_time;
extern int ehca_use_hp_mr;
struct ipzu_queue_resp {
- u64 queue; /* points to first queue entry */
u32 qe_size; /* queue entry size */
u32 act_nr_of_sg;
u32 queue_length; /* queue length allocated in bytes */
@@ -296,7 +283,6 @@ struct ehca_create_cq_resp {
u32 cq_number;
u32 token;
struct ipzu_queue_resp ipz_queue;
- struct h_galpas galpas;
};
struct ehca_create_qp_resp {
@@ -309,7 +295,6 @@ struct ehca_create_qp_resp {
u32 dummy; /* padding for 8 byte alignment */
struct ipzu_queue_resp ipz_squeue;
struct ipzu_queue_resp ipz_rqueue;
- struct h_galpas galpas;
};
struct ehca_alloc_cq_parms {
diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c
index 6074c897f51..9291a86ca05 100644
--- a/drivers/infiniband/hw/ehca/ehca_cq.c
+++ b/drivers/infiniband/hw/ehca/ehca_cq.c
@@ -267,7 +267,6 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe,
if (context) {
struct ipz_queue *ipz_queue = &my_cq->ipz_queue;
struct ehca_create_cq_resp resp;
- struct vm_area_struct *vma;
memset(&resp, 0, sizeof(resp));
resp.cq_number = my_cq->cq_number;
resp.token = my_cq->token;
@@ -276,40 +275,14 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe,
resp.ipz_queue.queue_length = ipz_queue->queue_length;
resp.ipz_queue.pagesize = ipz_queue->pagesize;
resp.ipz_queue.toggle_state = ipz_queue->toggle_state;
- ret = ehca_mmap_nopage(((u64)(my_cq->token) << 32) | 0x12000000,
- ipz_queue->queue_length,
- (void**)&resp.ipz_queue.queue,
- &vma);
- if (ret) {
- ehca_err(device, "Could not mmap queue pages");
- cq = ERR_PTR(ret);
- goto create_cq_exit4;
- }
- my_cq->uspace_queue = resp.ipz_queue.queue;
- resp.galpas = my_cq->galpas;
- ret = ehca_mmap_register(my_cq->galpas.user.fw_handle,
- (void**)&resp.galpas.kernel.fw_handle,
- &vma);
- if (ret) {
- ehca_err(device, "Could not mmap fw_handle");
- cq = ERR_PTR(ret);
- goto create_cq_exit5;
- }
- my_cq->uspace_fwh = (u64)resp.galpas.kernel.fw_handle;
if (ib_copy_to_udata(udata, &resp, sizeof(resp))) {
ehca_err(device, "Copy to udata failed.");
- goto create_cq_exit6;
+ goto create_cq_exit4;
}
}
return cq;
-create_cq_exit6:
- ehca_munmap(my_cq->uspace_fwh, EHCA_PAGESIZE);
-
-create_cq_exit5:
- ehca_munmap(my_cq->uspace_queue, my_cq->ipz_queue.queue_length);
-
create_cq_exit4:
ipz_queue_dtor(&my_cq->ipz_queue);
@@ -333,7 +306,6 @@ create_cq_exit1:
int ehca_destroy_cq(struct ib_cq *cq)
{
u64 h_ret;
- int ret;
struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq);
int cq_num = my_cq->cq_number;
struct ib_device *device = cq->device;
@@ -343,6 +315,20 @@ int ehca_destroy_cq(struct ib_cq *cq)
u32 cur_pid = current->tgid;
unsigned long flags;
+ if (cq->uobject) {
+ if (my_cq->mm_count_galpa || my_cq->mm_count_queue) {
+ ehca_err(device, "Resources still referenced in "
+ "user space cq_num=%x", my_cq->cq_number);
+ return -EINVAL;
+ }
+ if (my_cq->ownpid != cur_pid) {
+ ehca_err(device, "Invalid caller pid=%x ownpid=%x "
+ "cq_num=%x",
+ cur_pid, my_cq->ownpid, my_cq->cq_number);
+ return -EINVAL;
+ }
+ }
+
spin_lock_irqsave(&ehca_cq_idr_lock, flags);
while (my_cq->nr_callbacks) {
spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
@@ -353,25 +339,6 @@ int ehca_destroy_cq(struct ib_cq *cq)
idr_remove(&ehca_cq_idr, my_cq->token);
spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
- if (my_cq->uspace_queue && my_cq->ownpid != cur_pid) {
- ehca_err(device, "Invalid caller pid=%x ownpid=%x",
- cur_pid, my_cq->ownpid);
- return -EINVAL;
- }
-
- /* un-mmap if vma alloc */
- if (my_cq->uspace_queue ) {
- ret = ehca_munmap(my_cq->uspace_queue,
- my_cq->ipz_queue.queue_length);
- if (ret)
- ehca_err(device, "Could not munmap queue ehca_cq=%p "
- "cq_num=%x", my_cq, cq_num);
- ret = ehca_munmap(my_cq->uspace_fwh, EHCA_PAGESIZE);
- if (ret)
- ehca_err(device, "Could not munmap fwh ehca_cq=%p "
- "cq_num=%x", my_cq, cq_num);
- }
-
h_ret = hipz_h_destroy_cq(adapter_handle, my_cq, 0);
if (h_ret == H_R_STATE) {
/* cq in err: read err data and destroy it forcibly */
@@ -400,7 +367,7 @@ int ehca_resize_cq(struct ib_cq *cq, int cqe, struct ib_udata *udata)
struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq);
u32 cur_pid = current->tgid;
- if (my_cq->uspace_queue && my_cq->ownpid != cur_pid) {
+ if (cq->uobject && my_cq->ownpid != cur_pid) {
ehca_err(cq->device, "Invalid caller pid=%x ownpid=%x",
cur_pid, my_cq->ownpid);
return -EINVAL;
diff --git a/drivers/infiniband/hw/ehca/ehca_iverbs.h b/drivers/infiniband/hw/ehca/ehca_iverbs.h
index cd7789f0d08..95fd59fb452 100644
--- a/drivers/infiniband/hw/ehca/ehca_iverbs.h
+++ b/drivers/infiniband/hw/ehca/ehca_iverbs.h
@@ -171,14 +171,6 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma);
void ehca_poll_eqs(unsigned long data);
-int ehca_mmap_nopage(u64 foffset,u64 length,void **mapped,
- struct vm_area_struct **vma);
-
-int ehca_mmap_register(u64 physical,void **mapped,
- struct vm_area_struct **vma);
-
-int ehca_munmap(unsigned long addr, size_t len);
-
#ifdef CONFIG_PPC_64K_PAGES
void *ehca_alloc_fw_ctrlblock(gfp_t flags);
void ehca_free_fw_ctrlblock(void *ptr);
diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c
index 6574fbbaead..1155bcf4821 100644
--- a/drivers/infiniband/hw/ehca/ehca_main.c
+++ b/drivers/infiniband/hw/ehca/ehca_main.c
@@ -52,7 +52,7 @@
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Christoph Raisch <raisch@de.ibm.com>");
MODULE_DESCRIPTION("IBM eServer HCA InfiniBand Device Driver");
-MODULE_VERSION("SVNEHCA_0019");
+MODULE_VERSION("SVNEHCA_0020");
int ehca_open_aqp1 = 0;
int ehca_debug_level = 0;
@@ -288,7 +288,7 @@ int ehca_init_device(struct ehca_shca *shca)
strlcpy(shca->ib_device.name, "ehca%d", IB_DEVICE_NAME_MAX);
shca->ib_device.owner = THIS_MODULE;
- shca->ib_device.uverbs_abi_ver = 5;
+ shca->ib_device.uverbs_abi_ver = 6;
shca->ib_device.uverbs_cmd_mask =
(1ull << IB_USER_VERBS_CMD_GET_CONTEXT) |
(1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) |
@@ -790,7 +790,7 @@ int __init ehca_module_init(void)
int ret;
printk(KERN_INFO "eHCA Infiniband Device Driver "
- "(Rel.: SVNEHCA_0019)\n");
+ "(Rel.: SVNEHCA_0020)\n");
idr_init(&ehca_qp_idr);
idr_init(&ehca_cq_idr);
spin_lock_init(&ehca_qp_idr_lock);
diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c
index 34b85556d01..95efef921f1 100644
--- a/drivers/infiniband/hw/ehca/ehca_qp.c
+++ b/drivers/infiniband/hw/ehca/ehca_qp.c
@@ -637,7 +637,6 @@ struct ib_qp *ehca_create_qp(struct ib_pd *pd,
struct ipz_queue *ipz_rqueue = &my_qp->ipz_rqueue;
struct ipz_queue *ipz_squeue = &my_qp->ipz_squeue;
struct ehca_create_qp_resp resp;
- struct vm_area_struct * vma;
memset(&resp, 0, sizeof(resp));
resp.qp_num = my_qp->real_qp_num;
@@ -651,59 +650,21 @@ struct ib_qp *ehca_create_qp(struct ib_pd *pd,
resp.ipz_rqueue.queue_length = ipz_rqueue->queue_length;
resp.ipz_rqueue.pagesize = ipz_rqueue->pagesize;
resp.ipz_rqueue.toggle_state = ipz_rqueue->toggle_state;
- ret = ehca_mmap_nopage(((u64)(my_qp->token) << 32) | 0x22000000,
- ipz_rqueue->queue_length,
- (void**)&resp.ipz_rqueue.queue,
- &vma);
- if (ret) {
- ehca_err(pd->device, "Could not mmap rqueue pages");
- goto create_qp_exit3;
- }
- my_qp->uspace_rqueue = resp.ipz_rqueue.queue;
/* squeue properties */
resp.ipz_squeue.qe_size = ipz_squeue->qe_size;
resp.ipz_squeue.act_nr_of_sg = ipz_squeue->act_nr_of_sg;
resp.ipz_squeue.queue_length = ipz_squeue->queue_length;
resp.ipz_squeue.pagesize = ipz_squeue->pagesize;
resp.ipz_squeue.toggle_state = ipz_squeue->toggle_state;
- ret = ehca_mmap_nopage(((u64)(my_qp->token) << 32) | 0x23000000,
- ipz_squeue->queue_length,
- (void**)&resp.ipz_squeue.queue,
- &vma);
- if (ret) {
- ehca_err(pd->device, "Could not mmap squeue pages");
- goto create_qp_exit4;
- }
- my_qp->uspace_squeue = resp.ipz_squeue.queue;
- /* fw_handle */
- resp.galpas = my_qp->galpas;
- ret = ehca_mmap_register(my_qp->galpas.user.fw_handle,
- (void**)&resp.galpas.kernel.fw_handle,
- &vma);
- if (ret) {
- ehca_err(pd->device, "Could not mmap fw_handle");
- goto create_qp_exit5;
- }
- my_qp->uspace_fwh = (u64)resp.galpas.kernel.fw_handle;
-
if (ib_copy_to_udata(udata, &resp, sizeof resp)) {
ehca_err(pd->device, "Copy to udata failed");
ret = -EINVAL;
- goto create_qp_exit6;
+ goto create_qp_exit3;
}
}
return &my_qp->ib_qp;
-create_qp_exit6:
- ehca_munmap(my_qp->uspace_fwh, EHCA_PAGESIZE);
-
-create_qp_exit5:
- ehca_munmap(my_qp->uspace_squeue, my_qp->ipz_squeue.queue_length);
-
-create_qp_exit4:
- ehca_munmap(my_qp->uspace_rqueue, my_qp->ipz_rqueue.queue_length);
-
create_qp_exit3:
ipz_queue_dtor(&my_qp->ipz_rqueue);
ipz_queue_dtor(&my_qp->ipz_squeue);
@@ -931,7 +892,7 @@ static int internal_modify_qp(struct ib_qp *ibqp,
my_qp->qp_type == IB_QPT_SMI) &&
statetrans == IB_QPST_SQE2RTS) {
/* mark next free wqe if kernel */
- if (my_qp->uspace_squeue == 0) {
+ if (!ibqp->uobject) {
struct ehca_wqe *wqe;
/* lock send queue */
spin_lock_irqsave(&my_qp->spinlock_s, spl_flags);
@@ -1417,11 +1378,18 @@ int ehca_destroy_qp(struct ib_qp *ibqp)
enum ib_qp_type qp_type;
unsigned long flags;
- if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
- my_pd->ownpid != cur_pid) {
- ehca_err(ibqp->device, "Invalid caller pid=%x ownpid=%x",
- cur_pid, my_pd->ownpid);
- return -EINVAL;
+ if (ibqp->uobject) {
+ if (my_qp->mm_count_galpa ||
+ my_qp->mm_count_rqueue || my_qp->mm_count_squeue) {
+ ehca_err(ibqp->device, "Resources still referenced in "
+ "user space qp_num=%x", ibqp->qp_num);
+ return -EINVAL;
+ }
+ if (my_pd->ownpid != cur_pid) {
+ ehca_err(ibqp->device, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, my_pd->ownpid);
+ return -EINVAL;
+ }
}
if (my_qp->send_cq) {
@@ -1439,24 +1407,6 @@ int ehca_destroy_qp(struct ib_qp *ibqp)
idr_remove(&ehca_qp_idr, my_qp->token);
spin_unlock_irqrestore(&ehca_qp_idr_lock, flags);
- /* un-mmap if vma alloc */
- if (my_qp->uspace_rqueue) {
- ret = ehca_munmap(my_qp->uspace_rqueue,
- my_qp->ipz_rqueue.queue_length);
- if (ret)
- ehca_err(ibqp->device, "Could not munmap rqueue "
- "qp_num=%x", qp_num);
- ret = ehca_munmap(my_qp->uspace_squeue,
- my_qp->ipz_squeue.queue_length);
- if (ret)
- ehca_err(ibqp->device, "Could not munmap squeue "
- "qp_num=%x", qp_num);
- ret = ehca_munmap(my_qp->uspace_fwh, EHCA_PAGESIZE);
- if (ret)
- ehca_err(ibqp->device, "Could not munmap fwh qp_num=%x",
- qp_num);
- }
-
h_ret = hipz_h_destroy_qp(shca->ipz_hca_handle, my_qp);
if (h_ret != H_SUCCESS) {
ehca_err(ibqp->device, "hipz_h_destroy_qp() failed rc=%lx "
diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c
index b46bda1bf85..08d3f892d9f 100644
--- a/drivers/infiniband/hw/ehca/ehca_reqs.c
+++ b/drivers/infiniband/hw/ehca/ehca_reqs.c
@@ -579,7 +579,7 @@ poll_cq_one_read_cqe:
} else
wc->status = IB_WC_SUCCESS;
- wc->qp_num = cqe->local_qp_number;
+ wc->qp = NULL;
wc->byte_len = cqe->nr_bytes_transferred;
wc->pkey_index = cqe->pkey_index;
wc->slid = cqe->rlid;
diff --git a/drivers/infiniband/hw/ehca/ehca_uverbs.c b/drivers/infiniband/hw/ehca/ehca_uverbs.c
index e08764e4aef..73db920b694 100644
--- a/drivers/infiniband/hw/ehca/ehca_uverbs.c
+++ b/drivers/infiniband/hw/ehca/ehca_uverbs.c
@@ -68,105 +68,183 @@ int ehca_dealloc_ucontext(struct ib_ucontext *context)
return 0;
}
-struct page *ehca_nopage(struct vm_area_struct *vma,
- unsigned long address, int *type)
+static void ehca_mm_open(struct vm_area_struct *vma)
{
- struct page *mypage = NULL;
- u64 fileoffset = vma->vm_pgoff << PAGE_SHIFT;
- u32 idr_handle = fileoffset >> 32;
- u32 q_type = (fileoffset >> 28) & 0xF; /* CQ, QP,... */
- u32 rsrc_type = (fileoffset >> 24) & 0xF; /* sq,rq,cmnd_window */
- u32 cur_pid = current->tgid;
- unsigned long flags;
- struct ehca_cq *cq;
- struct ehca_qp *qp;
- struct ehca_pd *pd;
- u64 offset;
- void *vaddr;
+ u32 *count = (u32*)vma->vm_private_data;
+ if (!count) {
+ ehca_gen_err("Invalid vma struct vm_start=%lx vm_end=%lx",
+ vma->vm_start, vma->vm_end);
+ return;
+ }
+ (*count)++;
+ if (!(*count))
+ ehca_gen_err("Use count overflow vm_start=%lx vm_end=%lx",
+ vma->vm_start, vma->vm_end);
+ ehca_gen_dbg("vm_start=%lx vm_end=%lx count=%x",
+ vma->vm_start, vma->vm_end, *count);
+}
- switch (q_type) {
- case 1: /* CQ */
- spin_lock_irqsave(&ehca_cq_idr_lock, flags);
- cq = idr_find(&ehca_cq_idr, idr_handle);
- spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
+static void ehca_mm_close(struct vm_area_struct *vma)
+{
+ u32 *count = (u32*)vma->vm_private_data;
+ if (!count) {
+ ehca_gen_err("Invalid vma struct vm_start=%lx vm_end=%lx",
+ vma->vm_start, vma->vm_end);
+ return;
+ }
+ (*count)--;
+ ehca_gen_dbg("vm_start=%lx vm_end=%lx count=%x",
+ vma->vm_start, vma->vm_end, *count);
+}
- /* make sure this mmap really belongs to the authorized user */
- if (!cq) {
- ehca_gen_err("cq is NULL ret=NOPAGE_SIGBUS");
- return NOPAGE_SIGBUS;
+static struct vm_operations_struct vm_ops = {
+ .open = ehca_mm_open,
+ .close = ehca_mm_close,
+};
+
+static int ehca_mmap_fw(struct vm_area_struct *vma, struct h_galpas *galpas,
+ u32 *mm_count)
+{
+ int ret;
+ u64 vsize, physical;
+
+ vsize = vma->vm_end - vma->vm_start;
+ if (vsize != EHCA_PAGESIZE) {
+ ehca_gen_err("invalid vsize=%lx", vma->vm_end - vma->vm_start);
+ return -EINVAL;
+ }
+
+ physical = galpas->user.fw_handle;
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ ehca_gen_dbg("vsize=%lx physical=%lx", vsize, physical);
+ /* VM_IO | VM_RESERVED are set by remap_pfn_range() */
+ ret = remap_pfn_range(vma, vma->vm_start, physical >> PAGE_SHIFT,
+ vsize, vma->vm_page_prot);
+ if (unlikely(ret)) {
+ ehca_gen_err("remap_pfn_range() failed ret=%x", ret);
+ return -ENOMEM;
+ }
+
+ vma->vm_private_data = mm_count;
+ (*mm_count)++;
+ vma->vm_ops = &vm_ops;
+
+ return 0;
+}
+
+static int ehca_mmap_queue(struct vm_area_struct *vma, struct ipz_queue *queue,
+ u32 *mm_count)
+{
+ int ret;
+ u64 start, ofs;
+ struct page *page;
+
+ vma->vm_flags |= VM_RESERVED;
+ start = vma->vm_start;
+ for (ofs = 0; ofs < queue->queue_length; ofs += PAGE_SIZE) {
+ u64 virt_addr = (u64)ipz_qeit_calc(queue, ofs);
+ page = virt_to_page(virt_addr);
+ ret = vm_insert_page(vma, start, page);
+ if (unlikely(ret)) {
+ ehca_gen_err("vm_insert_page() failed rc=%x", ret);
+ return ret;
}
+ start += PAGE_SIZE;
+ }
+ vma->vm_private_data = mm_count;
+ (*mm_count)++;
+ vma->vm_ops = &vm_ops;
- if (cq->ownpid != cur_pid) {
+ return 0;
+}
+
+static int ehca_mmap_cq(struct vm_area_struct *vma, struct ehca_cq *cq,
+ u32 rsrc_type)
+{
+ int ret;
+
+ switch (rsrc_type) {
+ case 1: /* galpa fw handle */
+ ehca_dbg(cq->ib_cq.device, "cq_num=%x fw", cq->cq_number);
+ ret = ehca_mmap_fw(vma, &cq->galpas, &cq->mm_count_galpa);
+ if (unlikely(ret)) {
ehca_err(cq->ib_cq.device,
- "Invalid caller pid=%x ownpid=%x",
- cur_pid, cq->ownpid);
- return NOPAGE_SIGBUS;
+ "ehca_mmap_fw() failed rc=%x cq_num=%x",
+ ret, cq->cq_number);
+ return ret;
}
+ break;
- if (rsrc_type == 2) {
- ehca_dbg(cq->ib_cq.device, "cq=%p cq queuearea", cq);
- offset = address - vma->vm_start;
- vaddr = ipz_qeit_calc(&cq->ipz_queue, offset);
- ehca_dbg(cq->ib_cq.device, "offset=%lx vaddr=%p",
- offset, vaddr);
- mypage = virt_to_page(vaddr);
+ case 2: /* cq queue_addr */
+ ehca_dbg(cq->ib_cq.device, "cq_num=%x queue", cq->cq_number);
+ ret = ehca_mmap_queue(vma, &cq->ipz_queue, &cq->mm_count_queue);
+ if (unlikely(ret)) {
+ ehca_err(cq->ib_cq.device,
+ "ehca_mmap_queue() failed rc=%x cq_num=%x",
+ ret, cq->cq_number);
+ return ret;
}
break;
- case 2: /* QP */
- spin_lock_irqsave(&ehca_qp_idr_lock, flags);
- qp = idr_find(&ehca_qp_idr, idr_handle);
- spin_unlock_irqrestore(&ehca_qp_idr_lock, flags);
+ default:
+ ehca_err(cq->ib_cq.device, "bad resource type=%x cq_num=%x",
+ rsrc_type, cq->cq_number);
+ return -EINVAL;
+ }
- /* make sure this mmap really belongs to the authorized user */
- if (!qp) {
- ehca_gen_err("qp is NULL ret=NOPAGE_SIGBUS");
- return NOPAGE_SIGBUS;
+ return 0;
+}
+
+static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp,
+ u32 rsrc_type)
+{
+ int ret;
+
+ switch (rsrc_type) {
+ case 1: /* galpa fw handle */
+ ehca_dbg(qp->ib_qp.device, "qp_num=%x fw", qp->ib_qp.qp_num);
+ ret = ehca_mmap_fw(vma, &qp->galpas, &qp->mm_count_galpa);
+ if (unlikely(ret)) {
+ ehca_err(qp->ib_qp.device,
+ "remap_pfn_range() failed ret=%x qp_num=%x",
+ ret, qp->ib_qp.qp_num);
+ return -ENOMEM;
}
+ break;
- pd = container_of(qp->ib_qp.pd, struct ehca_pd, ib_pd);
- if (pd->ownpid != cur_pid) {
+ case 2: /* qp rqueue_addr */
+ ehca_dbg(qp->ib_qp.device, "qp_num=%x rqueue",
+ qp->ib_qp.qp_num);
+ ret = ehca_mmap_queue(vma, &qp->ipz_rqueue, &qp->mm_count_rqueue);
+ if (unlikely(ret)) {
ehca_err(qp->ib_qp.device,
- "Invalid caller pid=%x ownpid=%x",
- cur_pid, pd->ownpid);
- return NOPAGE_SIGBUS;
+ "ehca_mmap_queue(rq) failed rc=%x qp_num=%x",
+ ret, qp->ib_qp.qp_num);
+ return ret;
}
+ break;
- if (rsrc_type == 2) { /* rqueue */
- ehca_dbg(qp->ib_qp.device, "qp=%p qp rqueuearea", qp);
- offset = address - vma->vm_start;
- vaddr = ipz_qeit_calc(&qp->ipz_rqueue, offset);
- ehca_dbg(qp->ib_qp.device, "offset=%lx vaddr=%p",
- offset, vaddr);
- mypage = virt_to_page(vaddr);
- } else if (rsrc_type == 3) { /* squeue */
- ehca_dbg(qp->ib_qp.device, "qp=%p qp squeuearea", qp);
- offset = address - vma->vm_start;
- vaddr = ipz_qeit_calc(&qp->ipz_squeue, offset);
- ehca_dbg(qp->ib_qp.device, "offset=%lx vaddr=%p",
- offset, vaddr);
- mypage = virt_to_page(vaddr);
+ case 3: /* qp squeue_addr */
+ ehca_dbg(qp->ib_qp.device, "qp_num=%x squeue",
+ qp->ib_qp.qp_num);
+ ret = ehca_mmap_queue(vma, &qp->ipz_squeue, &qp->mm_count_squeue);
+ if (unlikely(ret)) {
+ ehca_err(qp->ib_qp.device,
+ "ehca_mmap_queue(sq) failed rc=%x qp_num=%x",
+ ret, qp->ib_qp.qp_num);
+ return ret;
}
break;
default:
- ehca_gen_err("bad queue type %x", q_type);
- return NOPAGE_SIGBUS;
- }
-
- if (!mypage) {
- ehca_gen_err("Invalid page adr==NULL ret=NOPAGE_SIGBUS");
- return NOPAGE_SIGBUS;
+ ehca_err(qp->ib_qp.device, "bad resource type=%x qp=num=%x",
+ rsrc_type, qp->ib_qp.qp_num);
+ return -EINVAL;
}
- get_page(mypage);
- return mypage;
+ return 0;
}
-static struct vm_operations_struct ehcau_vm_ops = {
- .nopage = ehca_nopage,
-};
-
int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
{
u64 fileoffset = vma->vm_pgoff << PAGE_SHIFT;
@@ -175,7 +253,6 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
u32 rsrc_type = (fileoffset >> 24) & 0xF; /* sq,rq,cmnd_window */
u32 cur_pid = current->tgid;
u32 ret;
- u64 vsize, physical;
unsigned long flags;
struct ehca_cq *cq;
struct ehca_qp *qp;
@@ -201,44 +278,12 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
if (!cq->ib_cq.uobject || cq->ib_cq.uobject->context != context)
return -EINVAL;
- switch (rsrc_type) {
- case 1: /* galpa fw handle */
- ehca_dbg(cq->ib_cq.device, "cq=%p cq triggerarea", cq);
- vma->vm_flags |= VM_RESERVED;
- vsize = vma->vm_end - vma->vm_start;
- if (vsize != EHCA_PAGESIZE) {
- ehca_err(cq->ib_cq.device, "invalid vsize=%lx",
- vma->vm_end - vma->vm_start);
- return -EINVAL;
- }
-
- physical = cq->galpas.user.fw_handle;
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- vma->vm_flags |= VM_IO | VM_RESERVED;
-
- ehca_dbg(cq->ib_cq.device,
- "vsize=%lx physical=%lx", vsize, physical);
- ret = remap_pfn_range(vma, vma->vm_start,
- physical >> PAGE_SHIFT, vsize,
- vma->vm_page_prot);
- if (ret) {
- ehca_err(cq->ib_cq.device,
- "remap_pfn_range() failed ret=%x",
- ret);
- return -ENOMEM;
- }
- break;
-
- case 2: /* cq queue_addr */
- ehca_dbg(cq->ib_cq.device, "cq=%p cq q_addr", cq);
- vma->vm_flags |= VM_RESERVED;
- vma->vm_ops = &ehcau_vm_ops;
- break;
-
- default:
- ehca_err(cq->ib_cq.device, "bad resource type %x",
- rsrc_type);
- return -EINVAL;
+ ret = ehca_mmap_cq(vma, cq, rsrc_type);
+ if (unlikely(ret)) {
+ ehca_err(cq->ib_cq.device,
+ "ehca_mmap_cq() failed rc=%x cq_num=%x",
+ ret, cq->cq_number);
+ return ret;
}
break;
@@ -262,50 +307,12 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
if (!qp->ib_qp.uobject || qp->ib_qp.uobject->context != context)
return -EINVAL;
- switch (rsrc_type) {
- case 1: /* galpa fw handle */
- ehca_dbg(qp->ib_qp.device, "qp=%p qp triggerarea", qp);
- vma->vm_flags |= VM_RESERVED;
- vsize = vma->vm_end - vma->vm_start;
- if (vsize != EHCA_PAGESIZE) {
- ehca_err(qp->ib_qp.device, "invalid vsize=%lx",
- vma->vm_end - vma->vm_start);
- return -EINVAL;
- }
-
- physical = qp->galpas.user.fw_handle;
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- vma->vm_flags |= VM_IO | VM_RESERVED;
-
- ehca_dbg(qp->ib_qp.device, "vsize=%lx physical=%lx",
- vsize, physical);
- ret = remap_pfn_range(vma, vma->vm_start,
- physical >> PAGE_SHIFT, vsize,
- vma->vm_page_prot);
- if (ret) {
- ehca_err(qp->ib_qp.device,
- "remap_pfn_range() failed ret=%x",
- ret);
- return -ENOMEM;
- }
- break;
-
- case 2: /* qp rqueue_addr */
- ehca_dbg(qp->ib_qp.device, "qp=%p qp rqueue_addr", qp);
- vma->vm_flags |= VM_RESERVED;
- vma->vm_ops = &ehcau_vm_ops;
- break;
-
- case 3: /* qp squeue_addr */
- ehca_dbg(qp->ib_qp.device, "qp=%p qp squeue_addr", qp);
- vma->vm_flags |= VM_RESERVED;
- vma->vm_ops = &ehcau_vm_ops;
- break;
-
- default:
- ehca_err(qp->ib_qp.device, "bad resource type %x",
- rsrc_type);
- return -EINVAL;
+ ret = ehca_mmap_qp(vma, qp, rsrc_type);
+ if (unlikely(ret)) {
+ ehca_err(qp->ib_qp.device,
+ "ehca_mmap_qp() failed rc=%x qp_num=%x",
+ ret, qp->ib_qp.qp_num);
+ return ret;
}
break;
@@ -316,77 +323,3 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
return 0;
}
-
-int ehca_mmap_nopage(u64 foffset, u64 length, void **mapped,
- struct vm_area_struct **vma)
-{
- down_write(&current->mm->mmap_sem);
- *mapped = (void*)do_mmap(NULL,0, length, PROT_WRITE,
- MAP_SHARED | MAP_ANONYMOUS,
- foffset);
- up_write(&current->mm->mmap_sem);
- if (!(*mapped)) {
- ehca_gen_err("couldn't mmap foffset=%lx length=%lx",
- foffset, length);
- return -EINVAL;
- }
-
- *vma = find_vma(current->mm, (u64)*mapped);
- if (!(*vma)) {
- down_write(&current->mm->mmap_sem);
- do_munmap(current->mm, 0, length);
- up_write(&current->mm->mmap_sem);
- ehca_gen_err("couldn't find vma queue=%p", *mapped);
- return -EINVAL;
- }
- (*vma)->vm_flags |= VM_RESERVED;
- (*vma)->vm_ops = &ehcau_vm_ops;
-
- return 0;
-}
-
-int ehca_mmap_register(u64 physical, void **mapped,
- struct vm_area_struct **vma)
-{
- int ret;
- unsigned long vsize;
- /* ehca hw supports only 4k page */
- ret = ehca_mmap_nopage(0, EHCA_PAGESIZE, mapped, vma);
- if (ret) {
- ehca_gen_err("could'nt mmap physical=%lx", physical);
- return ret;
- }
-
- (*vma)->vm_flags |= VM_RESERVED;
- vsize = (*vma)->vm_end - (*vma)->vm_start;
- if (vsize != EHCA_PAGESIZE) {
- ehca_gen_err("invalid vsize=%lx",
- (*vma)->vm_end - (*vma)->vm_start);
- return -EINVAL;
- }
-
- (*vma)->vm_page_prot = pgprot_noncached((*vma)->vm_page_prot);
- (*vma)->vm_flags |= VM_IO | VM_RESERVED;
-
- ret = remap_pfn_range((*vma), (*vma)->vm_start,
- physical >> PAGE_SHIFT, vsize,
- (*vma)->vm_page_prot);
- if (ret) {
- ehca_gen_err("remap_pfn_range() failed ret=%x", ret);
- return -ENOMEM;
- }
-
- return 0;
-
-}
-
-int ehca_munmap(unsigned long addr, size_t len) {
- int ret = 0;
- struct mm_struct *mm = current->mm;
- if (mm) {
- down_write(&mm->mmap_sem);
- ret = do_munmap(mm, addr, len);
- up_write(&mm->mmap_sem);
- }
- return ret;
-}
diff --git a/drivers/infiniband/hw/ipath/ipath_qp.c b/drivers/infiniband/hw/ipath/ipath_qp.c
index 46c1c89bf6a..64f07b19349 100644
--- a/drivers/infiniband/hw/ipath/ipath_qp.c
+++ b/drivers/infiniband/hw/ipath/ipath_qp.c
@@ -379,7 +379,7 @@ void ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err)
wc.vendor_err = 0;
wc.byte_len = 0;
wc.imm_data = 0;
- wc.qp_num = qp->ibqp.qp_num;
+ wc.qp = &qp->ibqp;
wc.src_qp = 0;
wc.wc_flags = 0;
wc.pkey_index = 0;
diff --git a/drivers/infiniband/hw/ipath/ipath_rc.c b/drivers/infiniband/hw/ipath/ipath_rc.c
index ce6038743c5..5ff20cb0449 100644
--- a/drivers/infiniband/hw/ipath/ipath_rc.c
+++ b/drivers/infiniband/hw/ipath/ipath_rc.c
@@ -702,7 +702,7 @@ void ipath_restart_rc(struct ipath_qp *qp, u32 psn, struct ib_wc *wc)
wc->opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
wc->vendor_err = 0;
wc->byte_len = 0;
- wc->qp_num = qp->ibqp.qp_num;
+ wc->qp = &qp->ibqp;
wc->src_qp = qp->remote_qpn;
wc->pkey_index = 0;
wc->slid = qp->remote_ah_attr.dlid;
@@ -836,7 +836,7 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
wc.vendor_err = 0;
wc.byte_len = wqe->length;
- wc.qp_num = qp->ibqp.qp_num;
+ wc.qp = &qp->ibqp;
wc.src_qp = qp->remote_qpn;
wc.pkey_index = 0;
wc.slid = qp->remote_ah_attr.dlid;
@@ -951,7 +951,7 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
wc.vendor_err = 0;
wc.byte_len = 0;
- wc.qp_num = qp->ibqp.qp_num;
+ wc.qp = &qp->ibqp;
wc.src_qp = qp->remote_qpn;
wc.pkey_index = 0;
wc.slid = qp->remote_ah_attr.dlid;
@@ -1511,7 +1511,7 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
wc.status = IB_WC_SUCCESS;
wc.opcode = IB_WC_RECV;
wc.vendor_err = 0;
- wc.qp_num = qp->ibqp.qp_num;
+ wc.qp = &qp->ibqp;
wc.src_qp = qp->remote_qpn;
wc.pkey_index = 0;
wc.slid = qp->remote_ah_attr.dlid;
diff --git a/drivers/infiniband/hw/ipath/ipath_ruc.c b/drivers/infiniband/hw/ipath/ipath_ruc.c
index f7530512045..e86cb171872 100644
--- a/drivers/infiniband/hw/ipath/ipath_ruc.c
+++ b/drivers/infiniband/hw/ipath/ipath_ruc.c
@@ -137,7 +137,7 @@ bad_lkey:
wc.vendor_err = 0;
wc.byte_len = 0;
wc.imm_data = 0;
- wc.qp_num = qp->ibqp.qp_num;
+ wc.qp = &qp->ibqp;
wc.src_qp = 0;
wc.wc_flags = 0;
wc.pkey_index = 0;
@@ -336,7 +336,7 @@ again:
wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
wc.vendor_err = 0;
wc.byte_len = 0;
- wc.qp_num = sqp->ibqp.qp_num;
+ wc.qp = &sqp->ibqp;
wc.src_qp = sqp->remote_qpn;
wc.pkey_index = 0;
wc.slid = sqp->remote_ah_attr.dlid;
@@ -426,7 +426,7 @@ again:
wc.status = IB_WC_SUCCESS;
wc.vendor_err = 0;
wc.byte_len = wqe->length;
- wc.qp_num = qp->ibqp.qp_num;
+ wc.qp = &qp->ibqp;
wc.src_qp = qp->remote_qpn;
/* XXX do we know which pkey matched? Only needed for GSI. */
wc.pkey_index = 0;
@@ -447,7 +447,7 @@ send_comp:
wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
wc.vendor_err = 0;
wc.byte_len = wqe->length;
- wc.qp_num = sqp->ibqp.qp_num;
+ wc.qp = &sqp->ibqp;
wc.src_qp = 0;
wc.pkey_index = 0;
wc.slid = 0;
diff --git a/drivers/infiniband/hw/ipath/ipath_uc.c b/drivers/infiniband/hw/ipath/ipath_uc.c
index e636cfd67a8..325d6634ff5 100644
--- a/drivers/infiniband/hw/ipath/ipath_uc.c
+++ b/drivers/infiniband/hw/ipath/ipath_uc.c
@@ -49,7 +49,7 @@ static void complete_last_send(struct ipath_qp *qp, struct ipath_swqe *wqe,
wc->opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
wc->vendor_err = 0;
wc->byte_len = wqe->length;
- wc->qp_num = qp->ibqp.qp_num;
+ wc->qp = &qp->ibqp;
wc->src_qp = qp->remote_qpn;
wc->pkey_index = 0;
wc->slid = qp->remote_ah_attr.dlid;
@@ -411,7 +411,7 @@ void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
wc.status = IB_WC_SUCCESS;
wc.opcode = IB_WC_RECV;
wc.vendor_err = 0;
- wc.qp_num = qp->ibqp.qp_num;
+ wc.qp = &qp->ibqp;
wc.src_qp = qp->remote_qpn;
wc.pkey_index = 0;
wc.slid = qp->remote_ah_attr.dlid;
diff --git a/drivers/infiniband/hw/ipath/ipath_ud.c b/drivers/infiniband/hw/ipath/ipath_ud.c
index 49f1102af8b..9a3e54664ee 100644
--- a/drivers/infiniband/hw/ipath/ipath_ud.c
+++ b/drivers/infiniband/hw/ipath/ipath_ud.c
@@ -66,7 +66,7 @@ bad_lkey:
wc.vendor_err = 0;
wc.byte_len = 0;
wc.imm_data = 0;
- wc.qp_num = qp->ibqp.qp_num;
+ wc.qp = &qp->ibqp;
wc.src_qp = 0;
wc.wc_flags = 0;
wc.pkey_index = 0;
@@ -255,7 +255,7 @@ static void ipath_ud_loopback(struct ipath_qp *sqp,
wc->status = IB_WC_SUCCESS;
wc->opcode = IB_WC_RECV;
wc->vendor_err = 0;
- wc->qp_num = qp->ibqp.qp_num;
+ wc->qp = &qp->ibqp;
wc->src_qp = sqp->ibqp.qp_num;
/* XXX do we know which pkey matched? Only needed for GSI. */
wc->pkey_index = 0;
@@ -474,7 +474,7 @@ done:
wc.vendor_err = 0;
wc.opcode = IB_WC_SEND;
wc.byte_len = len;
- wc.qp_num = qp->ibqp.qp_num;
+ wc.qp = &qp->ibqp;
wc.src_qp = 0;
wc.wc_flags = 0;
/* XXX initialize other fields? */
@@ -651,7 +651,7 @@ void ipath_ud_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
wc.status = IB_WC_SUCCESS;
wc.opcode = IB_WC_RECV;
wc.vendor_err = 0;
- wc.qp_num = qp->ibqp.qp_num;
+ wc.qp = &qp->ibqp;
wc.src_qp = src_qp;
/* XXX do we know which pkey matched? Only needed for GSI. */
wc.pkey_index = 0;
diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c
index 768df7265b8..968d1519761 100644
--- a/drivers/infiniband/hw/mthca/mthca_cmd.c
+++ b/drivers/infiniband/hw/mthca/mthca_cmd.c
@@ -1854,7 +1854,7 @@ int mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey,
memset(inbox + 256, 0, 256);
- MTHCA_PUT(inbox, in_wc->qp_num, MAD_IFC_MY_QPN_OFFSET);
+ MTHCA_PUT(inbox, in_wc->qp->qp_num, MAD_IFC_MY_QPN_OFFSET);
MTHCA_PUT(inbox, in_wc->src_qp, MAD_IFC_RQPN_OFFSET);
val = in_wc->sl << 4;
diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c
index 1159c8a0f2c..efd79ef109a 100644
--- a/drivers/infiniband/hw/mthca/mthca_cq.c
+++ b/drivers/infiniband/hw/mthca/mthca_cq.c
@@ -534,7 +534,7 @@ static inline int mthca_poll_one(struct mthca_dev *dev,
}
}
- entry->qp_num = (*cur_qp)->qpn;
+ entry->qp = &(*cur_qp)->ibqp;
if (is_send) {
wq = &(*cur_qp)->sq;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index 705eb1d0e55..af5ee2ec449 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -958,16 +958,17 @@ struct ipoib_dev_priv *ipoib_intf_alloc(const char *name)
return netdev_priv(dev);
}
-static ssize_t show_pkey(struct class_device *cdev, char *buf)
+static ssize_t show_pkey(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct ipoib_dev_priv *priv =
- netdev_priv(container_of(cdev, struct net_device, class_dev));
+ struct ipoib_dev_priv *priv = netdev_priv(to_net_dev(dev));
return sprintf(buf, "0x%04x\n", priv->pkey);
}
-static CLASS_DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL);
+static DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL);
-static ssize_t create_child(struct class_device *cdev,
+static ssize_t create_child(struct device *dev,
+ struct device_attribute *attr,
const char *buf, size_t count)
{
int pkey;
@@ -985,14 +986,14 @@ static ssize_t create_child(struct class_device *cdev,
*/
pkey |= 0x8000;
- ret = ipoib_vlan_add(container_of(cdev, struct net_device, class_dev),
- pkey);
+ ret = ipoib_vlan_add(to_net_dev(dev), pkey);
return ret ? ret : count;
}
-static CLASS_DEVICE_ATTR(create_child, S_IWUGO, NULL, create_child);
+static DEVICE_ATTR(create_child, S_IWUGO, NULL, create_child);
-static ssize_t delete_child(struct class_device *cdev,
+static ssize_t delete_child(struct device *dev,
+ struct device_attribute *attr,
const char *buf, size_t count)
{
int pkey;
@@ -1004,18 +1005,16 @@ static ssize_t delete_child(struct class_device *cdev,
if (pkey < 0 || pkey > 0xffff)
return -EINVAL;
- ret = ipoib_vlan_delete(container_of(cdev, struct net_device, class_dev),
- pkey);
+ ret = ipoib_vlan_delete(to_net_dev(dev), pkey);
return ret ? ret : count;
}
-static CLASS_DEVICE_ATTR(delete_child, S_IWUGO, NULL, delete_child);
+static DEVICE_ATTR(delete_child, S_IWUGO, NULL, delete_child);
int ipoib_add_pkey_attr(struct net_device *dev)
{
- return class_device_create_file(&dev->class_dev,
- &class_device_attr_pkey);
+ return device_create_file(&dev->dev, &dev_attr_pkey);
}
static struct net_device *ipoib_add_port(const char *format,
@@ -1083,11 +1082,9 @@ static struct net_device *ipoib_add_port(const char *format,
if (ipoib_add_pkey_attr(priv->dev))
goto sysfs_failed;
- if (class_device_create_file(&priv->dev->class_dev,
- &class_device_attr_create_child))
+ if (device_create_file(&priv->dev->dev, &dev_attr_create_child))
goto sysfs_failed;
- if (class_device_create_file(&priv->dev->class_dev,
- &class_device_attr_delete_child))
+ if (device_create_file(&priv->dev->dev, &dev_attr_delete_child))
goto sysfs_failed;
return priv->dev;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
index f887780e809..085eafe6667 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
@@ -42,15 +42,15 @@
#include "ipoib.h"
-static ssize_t show_parent(struct class_device *class_dev, char *buf)
+static ssize_t show_parent(struct device *d, struct device_attribute *attr,
+ char *buf)
{
- struct net_device *dev =
- container_of(class_dev, struct net_device, class_dev);
+ struct net_device *dev = to_net_dev(d);
struct ipoib_dev_priv *priv = netdev_priv(dev);
return sprintf(buf, "%s\n", priv->parent->name);
}
-static CLASS_DEVICE_ATTR(parent, S_IRUGO, show_parent, NULL);
+static DEVICE_ATTR(parent, S_IRUGO, show_parent, NULL);
int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
{
@@ -118,8 +118,7 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
if (ipoib_add_pkey_attr(priv->dev))
goto sysfs_failed;
- if (class_device_create_file(&priv->dev->class_dev,
- &class_device_attr_parent))
+ if (device_create_file(&priv->dev->dev, &dev_attr_parent))
goto sysfs_failed;
list_add_tail(&priv->list, &ppriv->child_intfs);
diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c
index 0a7d1ab60e6..89e37283c83 100644
--- a/drivers/infiniband/ulp/iser/iser_initiator.c
+++ b/drivers/infiniband/ulp/iser/iser_initiator.c
@@ -567,7 +567,7 @@ void iser_rcv_completion(struct iser_desc *rx_desc,
opcode = hdr->opcode & ISCSI_OPCODE_MASK;
if (opcode == ISCSI_OP_SCSI_CMD_RSP) {
- itt = hdr->itt & ISCSI_ITT_MASK; /* mask out cid and age bits */
+ itt = get_itt(hdr->itt); /* mask out cid and age bits */
if (!(itt < session->cmds_max))
iser_err("itt can't be matched to task!!!"
"conn %p opcode %d cmds_max %d itt %d\n",
@@ -625,7 +625,7 @@ void iser_snd_completion(struct iser_desc *tx_desc)
/* this arithmetic is legal by libiscsi dd_data allocation */
mtask = (void *) ((long)(void *)tx_desc -
sizeof(struct iscsi_mgmt_task));
- if (mtask->hdr->itt == cpu_to_be32(ISCSI_RESERVED_TAG)) {
+ if (mtask->hdr->itt == RESERVED_ITT) {
struct iscsi_session *session = conn->session;
spin_lock(&conn->session->lock);
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 72611fd1510..5e8ac577f0a 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -548,6 +548,7 @@ static int srp_reconnect_target(struct srp_target_port *target)
target->tx_head = 0;
target->tx_tail = 0;
+ target->qp_in_error = 0;
ret = srp_connect_target(target);
if (ret)
goto err;
@@ -878,6 +879,7 @@ static void srp_completion(struct ib_cq *cq, void *target_ptr)
printk(KERN_ERR PFX "failed %s status %d\n",
wc.wr_id & SRP_OP_RECV ? "receive" : "send",
wc.status);
+ target->qp_in_error = 1;
break;
}
@@ -1337,6 +1339,8 @@ static int srp_abort(struct scsi_cmnd *scmnd)
printk(KERN_ERR "SRP abort called\n");
+ if (target->qp_in_error)
+ return FAILED;
if (srp_find_req(target, scmnd, &req))
return FAILED;
if (srp_send_tsk_mgmt(target, req, SRP_TSK_ABORT_TASK))
@@ -1365,6 +1369,8 @@ static int srp_reset_device(struct scsi_cmnd *scmnd)
printk(KERN_ERR "SRP reset_device called\n");
+ if (target->qp_in_error)
+ return FAILED;
if (srp_find_req(target, scmnd, &req))
return FAILED;
if (srp_send_tsk_mgmt(target, req, SRP_TSK_LUN_RESET))
@@ -1801,6 +1807,7 @@ static ssize_t srp_create_target(struct class_device *class_dev,
goto err_free;
}
+ target->qp_in_error = 0;
ret = srp_connect_target(target);
if (ret) {
printk(KERN_ERR PFX "Connection failed\n");
diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h
index c21772317b8..2f3319c719a 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.h
+++ b/drivers/infiniband/ulp/srp/ib_srp.h
@@ -158,6 +158,7 @@ struct srp_target_port {
struct completion done;
int status;
enum srp_target_state state;
+ int qp_in_error;
};
struct srp_iu {
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index f0ce822c102..17c8c63cbe1 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -45,7 +45,7 @@ EXPORT_SYMBOL(serio_interrupt);
EXPORT_SYMBOL(__serio_register_port);
EXPORT_SYMBOL(serio_unregister_port);
EXPORT_SYMBOL(serio_unregister_child_port);
-EXPORT_SYMBOL(serio_register_driver);
+EXPORT_SYMBOL(__serio_register_driver);
EXPORT_SYMBOL(serio_unregister_driver);
EXPORT_SYMBOL(serio_open);
EXPORT_SYMBOL(serio_close);
@@ -789,12 +789,14 @@ static void serio_attach_driver(struct serio_driver *drv)
drv->driver.name, error);
}
-int serio_register_driver(struct serio_driver *drv)
+int __serio_register_driver(struct serio_driver *drv, struct module *owner, const char *mod_name)
{
int manual_bind = drv->manual_bind;
int error;
drv->driver.bus = &serio_bus;
+ drv->driver.owner = owner;
+ drv->driver.mod_name = mod_name;
/*
* Temporarily disable automatic binding because probing
diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c
index 4358a0a78ea..c7db4032ef0 100644
--- a/drivers/input/touchscreen/ucb1400_ts.c
+++ b/drivers/input/touchscreen/ucb1400_ts.c
@@ -83,7 +83,7 @@
struct ucb1400 {
- ac97_t *ac97;
+ struct snd_ac97 *ac97;
struct input_dev *ts_idev;
int irq;
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index b10972ed0c9..099f0afd394 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -62,7 +62,7 @@ static struct kvm_stats_debugfs_item {
{ "halt_exits", &kvm_stat.halt_exits },
{ "request_irq", &kvm_stat.request_irq_exits },
{ "irq_exits", &kvm_stat.irq_exits },
- { 0, 0 }
+ { NULL, NULL }
};
static struct dentry *debugfs_dir;
@@ -205,7 +205,7 @@ static struct kvm_vcpu *vcpu_load(struct kvm *kvm, int vcpu_slot)
mutex_lock(&vcpu->mutex);
if (unlikely(!vcpu->vmcs)) {
mutex_unlock(&vcpu->mutex);
- return 0;
+ return NULL;
}
return kvm_arch_ops->vcpu_load(vcpu);
}
@@ -257,9 +257,9 @@ static void kvm_free_physmem_slot(struct kvm_memory_slot *free,
if (!dont || free->dirty_bitmap != dont->dirty_bitmap)
vfree(free->dirty_bitmap);
- free->phys_mem = 0;
+ free->phys_mem = NULL;
free->npages = 0;
- free->dirty_bitmap = 0;
+ free->dirty_bitmap = NULL;
}
static void kvm_free_physmem(struct kvm *kvm)
@@ -267,7 +267,7 @@ static void kvm_free_physmem(struct kvm *kvm)
int i;
for (i = 0; i < kvm->nmemslots; ++i)
- kvm_free_physmem_slot(&kvm->memslots[i], 0);
+ kvm_free_physmem_slot(&kvm->memslots[i], NULL);
}
static void kvm_free_vcpu(struct kvm_vcpu *vcpu)
@@ -640,11 +640,11 @@ raced:
/* Deallocate if slot is being removed */
if (!npages)
- new.phys_mem = 0;
+ new.phys_mem = NULL;
/* Free page dirty bitmap if unneeded */
if (!(new.flags & KVM_MEM_LOG_DIRTY_PAGES))
- new.dirty_bitmap = 0;
+ new.dirty_bitmap = NULL;
r = -ENOMEM;
@@ -799,14 +799,14 @@ struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn)
&& gfn < memslot->base_gfn + memslot->npages)
return memslot;
}
- return 0;
+ return NULL;
}
EXPORT_SYMBOL_GPL(gfn_to_memslot);
void mark_page_dirty(struct kvm *kvm, gfn_t gfn)
{
int i;
- struct kvm_memory_slot *memslot = 0;
+ struct kvm_memory_slot *memslot = NULL;
unsigned long rel_gfn;
for (i = 0; i < kvm->nmemslots; ++i) {
@@ -1778,6 +1778,7 @@ static long kvm_dev_ioctl(struct file *filp,
unsigned int ioctl, unsigned long arg)
{
struct kvm *kvm = filp->private_data;
+ void __user *argp = (void __user *)arg;
int r = -EINVAL;
switch (ioctl) {
@@ -1794,12 +1795,12 @@ static long kvm_dev_ioctl(struct file *filp,
struct kvm_run kvm_run;
r = -EFAULT;
- if (copy_from_user(&kvm_run, (void *)arg, sizeof kvm_run))
+ if (copy_from_user(&kvm_run, argp, sizeof kvm_run))
goto out;
r = kvm_dev_ioctl_run(kvm, &kvm_run);
if (r < 0 && r != -EINTR)
goto out;
- if (copy_to_user((void *)arg, &kvm_run, sizeof kvm_run)) {
+ if (copy_to_user(argp, &kvm_run, sizeof kvm_run)) {
r = -EFAULT;
goto out;
}
@@ -1809,13 +1810,13 @@ static long kvm_dev_ioctl(struct file *filp,
struct kvm_regs kvm_regs;
r = -EFAULT;
- if (copy_from_user(&kvm_regs, (void *)arg, sizeof kvm_regs))
+ if (copy_from_user(&kvm_regs, argp, sizeof kvm_regs))
goto out;
r = kvm_dev_ioctl_get_regs(kvm, &kvm_regs);
if (r)
goto out;
r = -EFAULT;
- if (copy_to_user((void *)arg, &kvm_regs, sizeof kvm_regs))
+ if (copy_to_user(argp, &kvm_regs, sizeof kvm_regs))
goto out;
r = 0;
break;
@@ -1824,7 +1825,7 @@ static long kvm_dev_ioctl(struct file *filp,
struct kvm_regs kvm_regs;
r = -EFAULT;
- if (copy_from_user(&kvm_regs, (void *)arg, sizeof kvm_regs))
+ if (copy_from_user(&kvm_regs, argp, sizeof kvm_regs))
goto out;
r = kvm_dev_ioctl_set_regs(kvm, &kvm_regs);
if (r)
@@ -1836,13 +1837,13 @@ static long kvm_dev_ioctl(struct file *filp,
struct kvm_sregs kvm_sregs;
r = -EFAULT;
- if (copy_from_user(&kvm_sregs, (void *)arg, sizeof kvm_sregs))
+ if (copy_from_user(&kvm_sregs, argp, sizeof kvm_sregs))
goto out;
r = kvm_dev_ioctl_get_sregs(kvm, &kvm_sregs);
if (r)
goto out;
r = -EFAULT;
- if (copy_to_user((void *)arg, &kvm_sregs, sizeof kvm_sregs))
+ if (copy_to_user(argp, &kvm_sregs, sizeof kvm_sregs))
goto out;
r = 0;
break;
@@ -1851,7 +1852,7 @@ static long kvm_dev_ioctl(struct file *filp,
struct kvm_sregs kvm_sregs;
r = -EFAULT;
- if (copy_from_user(&kvm_sregs, (void *)arg, sizeof kvm_sregs))
+ if (copy_from_user(&kvm_sregs, argp, sizeof kvm_sregs))
goto out;
r = kvm_dev_ioctl_set_sregs(kvm, &kvm_sregs);
if (r)
@@ -1863,13 +1864,13 @@ static long kvm_dev_ioctl(struct file *filp,
struct kvm_translation tr;
r = -EFAULT;
- if (copy_from_user(&tr, (void *)arg, sizeof tr))
+ if (copy_from_user(&tr, argp, sizeof tr))
goto out;
r = kvm_dev_ioctl_translate(kvm, &tr);
if (r)
goto out;
r = -EFAULT;
- if (copy_to_user((void *)arg, &tr, sizeof tr))
+ if (copy_to_user(argp, &tr, sizeof tr))
goto out;
r = 0;
break;
@@ -1878,7 +1879,7 @@ static long kvm_dev_ioctl(struct file *filp,
struct kvm_interrupt irq;
r = -EFAULT;
- if (copy_from_user(&irq, (void *)arg, sizeof irq))
+ if (copy_from_user(&irq, argp, sizeof irq))
goto out;
r = kvm_dev_ioctl_interrupt(kvm, &irq);
if (r)
@@ -1890,7 +1891,7 @@ static long kvm_dev_ioctl(struct file *filp,
struct kvm_debug_guest dbg;
r = -EFAULT;
- if (copy_from_user(&dbg, (void *)arg, sizeof dbg))
+ if (copy_from_user(&dbg, argp, sizeof dbg))
goto out;
r = kvm_dev_ioctl_debug_guest(kvm, &dbg);
if (r)
@@ -1902,7 +1903,7 @@ static long kvm_dev_ioctl(struct file *filp,
struct kvm_memory_region kvm_mem;
r = -EFAULT;
- if (copy_from_user(&kvm_mem, (void *)arg, sizeof kvm_mem))
+ if (copy_from_user(&kvm_mem, argp, sizeof kvm_mem))
goto out;
r = kvm_dev_ioctl_set_memory_region(kvm, &kvm_mem);
if (r)
@@ -1913,7 +1914,7 @@ static long kvm_dev_ioctl(struct file *filp,
struct kvm_dirty_log log;
r = -EFAULT;
- if (copy_from_user(&log, (void *)arg, sizeof log))
+ if (copy_from_user(&log, argp, sizeof log))
goto out;
r = kvm_dev_ioctl_get_dirty_log(kvm, &log);
if (r)
@@ -1921,13 +1922,13 @@ static long kvm_dev_ioctl(struct file *filp,
break;
}
case KVM_GET_MSRS:
- r = msr_io(kvm, (void __user *)arg, get_msr, 1);
+ r = msr_io(kvm, argp, get_msr, 1);
break;
case KVM_SET_MSRS:
- r = msr_io(kvm, (void __user *)arg, do_set_msr, 0);
+ r = msr_io(kvm, argp, do_set_msr, 0);
break;
case KVM_GET_MSR_INDEX_LIST: {
- struct kvm_msr_list __user *user_msr_list = (void __user *)arg;
+ struct kvm_msr_list __user *user_msr_list = argp;
struct kvm_msr_list msr_list;
unsigned n;
@@ -2014,7 +2015,7 @@ static int kvm_reboot(struct notifier_block *notifier, unsigned long val,
* in vmx root mode.
*/
printk(KERN_INFO "kvm: exiting hardware virtualization\n");
- on_each_cpu(kvm_arch_ops->hardware_disable, 0, 0, 1);
+ on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1);
}
return NOTIFY_OK;
}
@@ -2028,7 +2029,7 @@ static __init void kvm_init_debug(void)
{
struct kvm_stats_debugfs_item *p;
- debugfs_dir = debugfs_create_dir("kvm", 0);
+ debugfs_dir = debugfs_create_dir("kvm", NULL);
for (p = debugfs_entries; p->name; ++p)
p->dentry = debugfs_create_u32(p->name, 0444, debugfs_dir,
p->data);
@@ -2069,7 +2070,7 @@ int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module)
if (r < 0)
return r;
- on_each_cpu(kvm_arch_ops->hardware_enable, 0, 0, 1);
+ on_each_cpu(kvm_arch_ops->hardware_enable, NULL, 0, 1);
register_reboot_notifier(&kvm_reboot_notifier);
kvm_chardev_ops.owner = module;
@@ -2084,7 +2085,7 @@ int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module)
out_free:
unregister_reboot_notifier(&kvm_reboot_notifier);
- on_each_cpu(kvm_arch_ops->hardware_disable, 0, 0, 1);
+ on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1);
kvm_arch_ops->hardware_unsetup();
return r;
}
@@ -2094,7 +2095,7 @@ void kvm_exit_arch(void)
misc_deregister(&kvm_dev);
unregister_reboot_notifier(&kvm_reboot_notifier);
- on_each_cpu(kvm_arch_ops->hardware_disable, 0, 0, 1);
+ on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1);
kvm_arch_ops->hardware_unsetup();
kvm_arch_ops = NULL;
}
diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c
index 22c426cd8cb..be793770f31 100644
--- a/drivers/kvm/mmu.c
+++ b/drivers/kvm/mmu.c
@@ -333,7 +333,7 @@ static void rmap_desc_remove_entry(struct kvm_vcpu *vcpu,
for (j = RMAP_EXT - 1; !desc->shadow_ptes[j] && j > i; --j)
;
desc->shadow_ptes[i] = desc->shadow_ptes[j];
- desc->shadow_ptes[j] = 0;
+ desc->shadow_ptes[j] = NULL;
if (j != 0)
return;
if (!prev_desc && !desc->more)
diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c
index c79df79307e..85f61dd1e93 100644
--- a/drivers/kvm/svm.c
+++ b/drivers/kvm/svm.c
@@ -274,7 +274,7 @@ static void svm_hardware_disable(void *garbage)
wrmsrl(MSR_VM_HSAVE_PA, 0);
rdmsrl(MSR_EFER, efer);
wrmsrl(MSR_EFER, efer & ~MSR_EFER_SVME_MASK);
- per_cpu(svm_data, raw_smp_processor_id()) = 0;
+ per_cpu(svm_data, raw_smp_processor_id()) = NULL;
__free_page(svm_data->save_area);
kfree(svm_data);
}
@@ -642,7 +642,7 @@ static struct vmcb_seg *svm_seg(struct kvm_vcpu *vcpu, int seg)
case VCPU_SREG_LDTR: return &save->ldtr;
}
BUG();
- return 0;
+ return NULL;
}
static u64 svm_get_segment_base(struct kvm_vcpu *vcpu, int seg)
@@ -934,7 +934,7 @@ static int io_get_override(struct kvm_vcpu *vcpu,
return 0;
*addr_override = 0;
- *seg = 0;
+ *seg = NULL;
for (i = 0; i < ins_length; i++)
switch (inst[i]) {
case 0xf0:
@@ -1087,7 +1087,7 @@ static int cpuid_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
static int emulate_on_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
- if (emulate_instruction(vcpu, 0, 0, 0) != EMULATE_DONE)
+ if (emulate_instruction(vcpu, NULL, 0, 0) != EMULATE_DONE)
printk(KERN_ERR "%s: failed\n", __FUNCTION__);
return 1;
}
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c
index 54c35c0b318..27e05a77e21 100644
--- a/drivers/kvm/vmx.c
+++ b/drivers/kvm/vmx.c
@@ -98,7 +98,7 @@ static struct vmx_msr_entry *find_msr_entry(struct kvm_vcpu *vcpu, u32 msr)
for (i = 0; i < vcpu->nmsrs; ++i)
if (vcpu->guest_msrs[i].index == msr)
return &vcpu->guest_msrs[i];
- return 0;
+ return NULL;
}
static void vmcs_clear(struct vmcs *vmcs)
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index a9e747c3979..1a86387e23b 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -1,6 +1,6 @@
menu "Macintosh device drivers"
- depends on PPC || MAC
+ depends on PPC || MAC || X86
config ADB
bool "Apple Desktop Bus (ADB) support"
diff --git a/drivers/macintosh/rack-meter.c b/drivers/macintosh/rack-meter.c
index 5ed41fe84e5..f83fad2a3ff 100644
--- a/drivers/macintosh/rack-meter.c
+++ b/drivers/macintosh/rack-meter.c
@@ -171,11 +171,11 @@ static void rackmeter_setup_dbdma(struct rackmeter *rm)
/* Make sure dbdma is reset */
DBDMA_DO_RESET(rm->dma_regs);
- pr_debug("rackmeter: mark offset=0x%lx\n",
+ pr_debug("rackmeter: mark offset=0x%zx\n",
offsetof(struct rackmeter_dma, mark));
- pr_debug("rackmeter: buf1 offset=0x%lx\n",
+ pr_debug("rackmeter: buf1 offset=0x%zx\n",
offsetof(struct rackmeter_dma, buf1));
- pr_debug("rackmeter: buf2 offset=0x%lx\n",
+ pr_debug("rackmeter: buf2 offset=0x%zx\n",
offsetof(struct rackmeter_dma, buf2));
/* Prepare 4 dbdma commands for the 2 buffers */
diff --git a/drivers/macintosh/windfarm_core.c b/drivers/macintosh/windfarm_core.c
index e947af982f9..94c117ef20c 100644
--- a/drivers/macintosh/windfarm_core.c
+++ b/drivers/macintosh/windfarm_core.c
@@ -94,8 +94,6 @@ static int wf_thread_func(void *data)
DBG("wf: thread started\n");
while(!kthread_should_stop()) {
- try_to_freeze();
-
if (time_after_eq(jiffies, next)) {
wf_notify(WF_EVENT_TICK, NULL);
if (wf_overtemp) {
@@ -118,8 +116,8 @@ static int wf_thread_func(void *data)
if (delay <= HZ)
schedule_timeout_interruptible(delay);
- /* there should be no signal, but oh well */
- if (signal_pending(current)) {
+ /* there should be no non-suspend signal, but oh well */
+ if (signal_pending(current) && !try_to_freeze()) {
printk(KERN_WARNING "windfarm: thread got sigl !\n");
break;
}
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index 11108165e26..059704fbb75 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -1160,6 +1160,22 @@ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sect
return 0;
}
+ if (unlikely((*bmc & COUNTER_MAX) == COUNTER_MAX)) {
+ DEFINE_WAIT(__wait);
+ /* note that it is safe to do the prepare_to_wait
+ * after the test as long as we do it before dropping
+ * the spinlock.
+ */
+ prepare_to_wait(&bitmap->overflow_wait, &__wait,
+ TASK_UNINTERRUPTIBLE);
+ spin_unlock_irq(&bitmap->lock);
+ bitmap->mddev->queue
+ ->unplug_fn(bitmap->mddev->queue);
+ schedule();
+ finish_wait(&bitmap->overflow_wait, &__wait);
+ continue;
+ }
+
switch(*bmc) {
case 0:
bitmap_file_set_bit(bitmap, offset);
@@ -1169,7 +1185,7 @@ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sect
case 1:
*bmc = 2;
}
- BUG_ON((*bmc & COUNTER_MAX) == COUNTER_MAX);
+
(*bmc)++;
spin_unlock_irq(&bitmap->lock);
@@ -1207,6 +1223,9 @@ void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long secto
if (!success && ! (*bmc & NEEDED_MASK))
*bmc |= NEEDED_MASK;
+ if ((*bmc & COUNTER_MAX) == COUNTER_MAX)
+ wake_up(&bitmap->overflow_wait);
+
(*bmc)--;
if (*bmc <= 2) {
set_page_attr(bitmap,
@@ -1431,6 +1450,7 @@ int bitmap_create(mddev_t *mddev)
spin_lock_init(&bitmap->lock);
atomic_set(&bitmap->pending_writes, 0);
init_waitqueue_head(&bitmap->write_wait);
+ init_waitqueue_head(&bitmap->overflow_wait);
bitmap->mddev = mddev;
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 467c16982d0..11c3d7bfa79 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -2620,7 +2620,7 @@ static struct bio *remove_bio_from_retry(raid5_conf_t *conf)
}
bi = conf->retry_read_aligned_list;
if(bi) {
- conf->retry_read_aligned = bi->bi_next;
+ conf->retry_read_aligned_list = bi->bi_next;
bi->bi_next = NULL;
bi->bi_phys_segments = 1; /* biased count of active stripes */
bi->bi_hw_segments = 0; /* count of processed stripes */
@@ -2669,6 +2669,27 @@ static int raid5_align_endio(struct bio *bi, unsigned int bytes, int error)
return 0;
}
+static int bio_fits_rdev(struct bio *bi)
+{
+ request_queue_t *q = bdev_get_queue(bi->bi_bdev);
+
+ if ((bi->bi_size>>9) > q->max_sectors)
+ return 0;
+ blk_recount_segments(q, bi);
+ if (bi->bi_phys_segments > q->max_phys_segments ||
+ bi->bi_hw_segments > q->max_hw_segments)
+ return 0;
+
+ if (q->merge_bvec_fn)
+ /* it's too hard to apply the merge_bvec_fn at this stage,
+ * just just give up
+ */
+ return 0;
+
+ return 1;
+}
+
+
static int chunk_aligned_read(request_queue_t *q, struct bio * raid_bio)
{
mddev_t *mddev = q->queuedata;
@@ -2715,6 +2736,13 @@ static int chunk_aligned_read(request_queue_t *q, struct bio * raid_bio)
align_bi->bi_flags &= ~(1 << BIO_SEG_VALID);
align_bi->bi_sector += rdev->data_offset;
+ if (!bio_fits_rdev(align_bi)) {
+ /* too big in some way */
+ bio_put(align_bi);
+ rdev_dec_pending(rdev, mddev);
+ return 0;
+ }
+
spin_lock_irq(&conf->device_lock);
wait_event_lock_irq(conf->wait_for_stripe,
conf->quiesce == 0,
@@ -3107,7 +3135,9 @@ static int retry_aligned_read(raid5_conf_t *conf, struct bio *raid_bio)
last_sector = raid_bio->bi_sector + (raid_bio->bi_size>>9);
for (; logical_sector < last_sector;
- logical_sector += STRIPE_SECTORS, scnt++) {
+ logical_sector += STRIPE_SECTORS,
+ sector += STRIPE_SECTORS,
+ scnt++) {
if (scnt < raid_bio->bi_hw_segments)
/* already done this stripe */
@@ -3123,7 +3153,13 @@ static int retry_aligned_read(raid5_conf_t *conf, struct bio *raid_bio)
}
set_bit(R5_ReadError, &sh->dev[dd_idx].flags);
- add_stripe_bio(sh, raid_bio, dd_idx, 0);
+ if (!add_stripe_bio(sh, raid_bio, dd_idx, 0)) {
+ release_stripe(sh);
+ raid_bio->bi_hw_segments = scnt;
+ conf->retry_read_aligned = raid_bio;
+ return handled;
+ }
+
handle_stripe(sh, NULL);
release_stripe(sh);
handled++;
diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c
index f51e02fe365..0e948a5c5a0 100644
--- a/drivers/media/common/ir-keymaps.c
+++ b/drivers/media/common/ir-keymaps.c
@@ -698,7 +698,6 @@ IR_KEYTAB_TYPE ir_codes_pinnacle_grey[IR_KEYTAB_SIZE] = {
[ 0x29 ] = KEY_TEXT,
[ 0x2a ] = KEY_MEDIA,
[ 0x18 ] = KEY_EPG,
- [ 0x27 ] = KEY_RECORD,
};
EXPORT_SYMBOL_GPL(ir_codes_pinnacle_grey);
diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c
index 7243337b771..bdd6301d2a4 100644
--- a/drivers/media/video/usbvision/usbvision-video.c
+++ b/drivers/media/video/usbvision/usbvision-video.c
@@ -1072,7 +1072,7 @@ static int usbvision_v4l2_ioctl(struct inode *inode, struct file *file,
}
-static ssize_t usbvision_v4l2_read(struct file *file, char *buf,
+static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
struct video_device *dev = video_devdata(file);
diff --git a/drivers/media/video/zc0301/zc0301_sensor.h b/drivers/media/video/zc0301/zc0301_sensor.h
index 4363a915b1f..3daf049a288 100644
--- a/drivers/media/video/zc0301/zc0301_sensor.h
+++ b/drivers/media/video/zc0301/zc0301_sensor.h
@@ -75,7 +75,6 @@ static const struct usb_device_id zc0301_id_table[] = { \
{ ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */ \
{ ZC0301_USB_DEVICE(0x055f, 0xd003, 0xff), }, /* TAS5130 */ \
{ ZC0301_USB_DEVICE(0x055f, 0xd004, 0xff), }, /* TAS5130 */ \
- { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */ \
{ ZC0301_USB_DEVICE(0x0ac8, 0x0301, 0xff), }, \
{ ZC0301_USB_DEVICE(0x0ac8, 0x301b, 0xff), }, /* PB-0330/HV7131 */ \
{ ZC0301_USB_DEVICE(0x0ac8, 0x303b, 0xff), }, /* PB-0330 */ \
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 00db31c314e..bedae4ad3f7 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -42,7 +42,7 @@ config SGI_IOC4
config TIFM_CORE
tristate "TI Flash Media interface support (EXPERIMENTAL)"
- depends on EXPERIMENTAL
+ depends on EXPERIMENTAL && PCI
help
If you want support for Texas Instruments(R) Flash Media adapters
you should select this option and then also choose an appropriate
@@ -69,6 +69,25 @@ config TIFM_7XX1
To compile this driver as a module, choose M here: the module will
be called tifm_7xx1.
+config ASUS_LAPTOP
+ tristate "Asus Laptop Extras (EXPERIMENTAL)"
+ depends on X86
+ depends on ACPI
+ depends on EXPERIMENTAL && !ACPI_ASUS
+ depends on LEDS_CLASS
+ depends on BACKLIGHT_CLASS_DEVICE
+ ---help---
+ This is the new Linux driver for Asus laptops. It may also support some
+ MEDION, JVC or VICTOR laptops. It makes all the extra buttons generate
+ standard ACPI events that go through /proc/acpi/events. It also adds
+ support for video output switching, LCD backlight control, Bluetooth and
+ Wlan control, and most importantly, allows you to blink those fancy LEDs.
+
+ For more information and a userspace daemon for handling the extra
+ buttons see <http://acpi4asus.sf.net/>.
+
+ If you have an ACPI-compatible ASUS laptop, say Y or M here.
+
config MSI_LAPTOP
tristate "MSI Laptop Extras"
depends on X86
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index c9e98ab021c..35da53c409c 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -6,6 +6,7 @@ obj- := misc.o # Dummy rule to force built-in.o to be made
obj-$(CONFIG_IBM_ASM) += ibmasm/
obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/
obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
+obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
obj-$(CONFIG_LKDTM) += lkdtm.o
obj-$(CONFIG_TIFM_CORE) += tifm_core.o
obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o
diff --git a/drivers/misc/asus-laptop.c b/drivers/misc/asus-laptop.c
new file mode 100644
index 00000000000..861c39935f9
--- /dev/null
+++ b/drivers/misc/asus-laptop.c
@@ -0,0 +1,1165 @@
+/*
+ * asus-laptop.c - Asus Laptop Support
+ *
+ *
+ * Copyright (C) 2002-2005 Julien Lerouge, 2003-2006 Karol Kozimor
+ * Copyright (C) 2006 Corentin Chary
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *
+ * The development page for this driver is located at
+ * http://sourceforge.net/projects/acpi4asus/
+ *
+ * Credits:
+ * Pontus Fuchs - Helper functions, cleanup
+ * Johann Wiesner - Small compile fixes
+ * John Belmonte - ACPI code for Toshiba laptop was a good starting point.
+ * Eric Burghard - LED display support for W1N
+ * Josh Green - Light Sens support
+ * Thomas Tuttle - His first patch for led support was very helpfull
+ *
+ */
+
+#include <linux/autoconf.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/proc_fs.h>
+#include <linux/backlight.h>
+#include <linux/fb.h>
+#include <linux/leds.h>
+#include <linux/platform_device.h>
+#include <acpi/acpi_drivers.h>
+#include <acpi/acpi_bus.h>
+#include <asm/uaccess.h>
+
+#define ASUS_LAPTOP_VERSION "0.40"
+
+#define ASUS_HOTK_NAME "Asus Laptop Support"
+#define ASUS_HOTK_CLASS "hotkey"
+#define ASUS_HOTK_DEVICE_NAME "Hotkey"
+#define ASUS_HOTK_HID "ATK0100"
+#define ASUS_HOTK_FILE "asus-laptop"
+#define ASUS_HOTK_PREFIX "\\_SB.ATKD."
+
+/*
+ * Some events we use, same for all Asus
+ */
+#define ATKD_BR_UP 0x10
+#define ATKD_BR_DOWN 0x20
+#define ATKD_LCD_ON 0x33
+#define ATKD_LCD_OFF 0x34
+
+/*
+ * Known bits returned by \_SB.ATKD.HWRS
+ */
+#define WL_HWRS 0x80
+#define BT_HWRS 0x100
+
+/*
+ * Flags for hotk status
+ * WL_ON and BT_ON are also used for wireless_status()
+ */
+#define WL_ON 0x01 //internal Wifi
+#define BT_ON 0x02 //internal Bluetooth
+#define MLED_ON 0x04 //mail LED
+#define TLED_ON 0x08 //touchpad LED
+#define RLED_ON 0x10 //Record LED
+#define PLED_ON 0x20 //Phone LED
+#define LCD_ON 0x40 //LCD backlight
+
+#define ASUS_LOG ASUS_HOTK_FILE ": "
+#define ASUS_ERR KERN_ERR ASUS_LOG
+#define ASUS_WARNING KERN_WARNING ASUS_LOG
+#define ASUS_NOTICE KERN_NOTICE ASUS_LOG
+#define ASUS_INFO KERN_INFO ASUS_LOG
+#define ASUS_DEBUG KERN_DEBUG ASUS_LOG
+
+MODULE_AUTHOR("Julien Lerouge, Karol Kozimor, Corentin Chary");
+MODULE_DESCRIPTION(ASUS_HOTK_NAME);
+MODULE_LICENSE("GPL");
+
+#define ASUS_HANDLE(object, paths...) \
+ static acpi_handle object##_handle = NULL; \
+ static char *object##_paths[] = { paths }
+
+/* LED */
+ASUS_HANDLE(mled_set, ASUS_HOTK_PREFIX "MLED");
+ASUS_HANDLE(tled_set, ASUS_HOTK_PREFIX "TLED");
+ASUS_HANDLE(rled_set, ASUS_HOTK_PREFIX "RLED"); /* W1JC */
+ASUS_HANDLE(pled_set, ASUS_HOTK_PREFIX "PLED"); /* A7J */
+
+/* LEDD */
+ASUS_HANDLE(ledd_set, ASUS_HOTK_PREFIX "SLCM");
+
+/* Bluetooth and WLAN
+ * WLED and BLED are not handled like other XLED, because in some dsdt
+ * they also control the WLAN/Bluetooth device.
+ */
+ASUS_HANDLE(wl_switch, ASUS_HOTK_PREFIX "WLED");
+ASUS_HANDLE(bt_switch, ASUS_HOTK_PREFIX "BLED");
+ASUS_HANDLE(wireless_status, ASUS_HOTK_PREFIX "RSTS"); /* All new models */
+
+/* Brightness */
+ASUS_HANDLE(brightness_set, ASUS_HOTK_PREFIX "SPLV");
+ASUS_HANDLE(brightness_get, ASUS_HOTK_PREFIX "GPLV");
+
+/* Backlight */
+ASUS_HANDLE(lcd_switch, "\\_SB.PCI0.SBRG.EC0._Q10", /* All new models */
+ "\\_SB.PCI0.ISA.EC0._Q10", /* A1x */
+ "\\_SB.PCI0.PX40.ECD0._Q10", /* L3C */
+ "\\_SB.PCI0.PX40.EC0.Q10", /* M1A */
+ "\\_SB.PCI0.LPCB.EC0._Q10", /* P30 */
+ "\\_SB.PCI0.PX40.Q10", /* S1x */
+ "\\Q10"); /* A2x, L2D, L3D, M2E */
+
+/* Display */
+ASUS_HANDLE(display_set, ASUS_HOTK_PREFIX "SDSP");
+ASUS_HANDLE(display_get, "\\_SB.PCI0.P0P1.VGA.GETD", /* A6B, A6K A6R A7D F3JM L4R M6R A3G
+ M6A M6V VX-1 V6J V6V W3Z */
+ "\\_SB.PCI0.P0P2.VGA.GETD", /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V
+ S5A M5A z33A W1Jc W2V */
+ "\\_SB.PCI0.P0P3.VGA.GETD", /* A6V A6Q */
+ "\\_SB.PCI0.P0PA.VGA.GETD", /* A6T, A6M */
+ "\\_SB.PCI0.PCI1.VGAC.NMAP", /* L3C */
+ "\\_SB.PCI0.VGA.GETD", /* Z96F */
+ "\\ACTD", /* A2D */
+ "\\ADVG", /* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */
+ "\\DNXT", /* P30 */
+ "\\INFB", /* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */
+ "\\SSTE"); /* A3F A6F A3N A3L M6N W3N W6A */
+
+ASUS_HANDLE(ls_switch, ASUS_HOTK_PREFIX "ALSC"); /* Z71A Z71V */
+ASUS_HANDLE(ls_level, ASUS_HOTK_PREFIX "ALSL"); /* Z71A Z71V */
+
+/*
+ * This is the main structure, we can use it to store anything interesting
+ * about the hotk device
+ */
+struct asus_hotk {
+ char *name; //laptop name
+ struct acpi_device *device; //the device we are in
+ acpi_handle handle; //the handle of the hotk device
+ char status; //status of the hotk, for LEDs, ...
+ u32 ledd_status; //status of the LED display
+ u8 light_level; //light sensor level
+ u8 light_switch; //light sensor switch value
+ u16 event_count[128]; //count for each event TODO make this better
+};
+
+/*
+ * This header is made available to allow proper configuration given model,
+ * revision number , ... this info cannot go in struct asus_hotk because it is
+ * available before the hotk
+ */
+static struct acpi_table_header *asus_info;
+
+/* The actual device the driver binds to */
+static struct asus_hotk *hotk;
+
+/*
+ * The hotkey driver declaration
+ */
+static int asus_hotk_add(struct acpi_device *device);
+static int asus_hotk_remove(struct acpi_device *device, int type);
+static struct acpi_driver asus_hotk_driver = {
+ .name = ASUS_HOTK_NAME,
+ .class = ASUS_HOTK_CLASS,
+ .ids = ASUS_HOTK_HID,
+ .ops = {
+ .add = asus_hotk_add,
+ .remove = asus_hotk_remove,
+ },
+};
+
+/* The backlight device /sys/class/backlight */
+static struct backlight_device *asus_backlight_device;
+
+/*
+ * The backlight class declaration
+ */
+static int read_brightness(struct backlight_device *bd);
+static int update_bl_status(struct backlight_device *bd);
+static struct backlight_properties asusbl_data = {
+ .owner = THIS_MODULE,
+ .get_brightness = read_brightness,
+ .update_status = update_bl_status,
+ .max_brightness = 15,
+};
+
+/* These functions actually update the LED's, and are called from a
+ * workqueue. By doing this as separate work rather than when the LED
+ * subsystem asks, we avoid messing with the Asus ACPI stuff during a
+ * potentially bad time, such as a timer interrupt. */
+static struct workqueue_struct *led_workqueue;
+
+#define ASUS_LED(object, ledname) \
+ static void object##_led_set(struct led_classdev *led_cdev, \
+ enum led_brightness value); \
+ static void object##_led_update(struct work_struct *ignored); \
+ static int object##_led_wk; \
+ DECLARE_WORK(object##_led_work, object##_led_update); \
+ static struct led_classdev object##_led = { \
+ .name = "asus:" ledname, \
+ .brightness_set = object##_led_set, \
+ }
+
+ASUS_LED(mled, "mail");
+ASUS_LED(tled, "touchpad");
+ASUS_LED(rled, "record");
+ASUS_LED(pled, "phone");
+
+/*
+ * This function evaluates an ACPI method, given an int as parameter, the
+ * method is searched within the scope of the handle, can be NULL. The output
+ * of the method is written is output, which can also be NULL
+ *
+ * returns 1 if write is successful, 0 else.
+ */
+static int write_acpi_int(acpi_handle handle, const char *method, int val,
+ struct acpi_buffer *output)
+{
+ struct acpi_object_list params; //list of input parameters (an int here)
+ union acpi_object in_obj; //the only param we use
+ acpi_status status;
+
+ params.count = 1;
+ params.pointer = &in_obj;
+ in_obj.type = ACPI_TYPE_INTEGER;
+ in_obj.integer.value = val;
+
+ status = acpi_evaluate_object(handle, (char *)method, &params, output);
+ return (status == AE_OK);
+}
+
+static int read_acpi_int(acpi_handle handle, const char *method, int *val,
+ struct acpi_object_list *params)
+{
+ struct acpi_buffer output;
+ union acpi_object out_obj;
+ acpi_status status;
+
+ output.length = sizeof(out_obj);
+ output.pointer = &out_obj;
+
+ status = acpi_evaluate_object(handle, (char *)method, params, &output);
+ *val = out_obj.integer.value;
+ return (status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER);
+}
+
+static int read_wireless_status(int mask)
+{
+ int status;
+
+ if (!wireless_status_handle)
+ return (hotk->status & mask) ? 1 : 0;
+
+ if (read_acpi_int(wireless_status_handle, NULL, &status, NULL)) {
+ return (status & mask) ? 1 : 0;
+ } else
+ printk(ASUS_WARNING "Error reading Wireless status\n");
+
+ return (hotk->status & mask) ? 1 : 0;
+}
+
+/* Generic LED functions */
+static int read_status(int mask)
+{
+ /* There is a special method for both wireless devices */
+ if (mask == BT_ON || mask == WL_ON)
+ return read_wireless_status(mask);
+
+ return (hotk->status & mask) ? 1 : 0;
+}
+
+static void write_status(acpi_handle handle, int out, int mask, int invert)
+{
+ hotk->status = (out) ? (hotk->status | mask) : (hotk->status & ~mask);
+
+ if (invert) /* invert target value */
+ out = !out & 0x1;
+
+ if (handle && !write_acpi_int(handle, NULL, out, NULL))
+ printk(ASUS_WARNING " write failed\n");
+}
+
+/* /sys/class/led handlers */
+#define ASUS_LED_HANDLER(object, mask, invert) \
+ static void object##_led_set(struct led_classdev *led_cdev, \
+ enum led_brightness value) \
+ { \
+ object##_led_wk = value; \
+ queue_work(led_workqueue, &object##_led_work); \
+ } \
+ static void object##_led_update(struct work_struct *ignored) \
+ { \
+ int value = object##_led_wk; \
+ write_status(object##_set_handle, value, (mask), (invert)); \
+ }
+
+ASUS_LED_HANDLER(mled, MLED_ON, 1);
+ASUS_LED_HANDLER(pled, PLED_ON, 0);
+ASUS_LED_HANDLER(rled, RLED_ON, 0);
+ASUS_LED_HANDLER(tled, TLED_ON, 0);
+
+static int get_lcd_state(void)
+{
+ return read_status(LCD_ON);
+}
+
+static int set_lcd_state(int value)
+{
+ int lcd = 0;
+ acpi_status status = 0;
+
+ lcd = value ? 1 : 0;
+
+ if (lcd == get_lcd_state())
+ return 0;
+
+ if (lcd_switch_handle) {
+ status = acpi_evaluate_object(lcd_switch_handle,
+ NULL, NULL, NULL);
+
+ if (ACPI_FAILURE(status))
+ printk(ASUS_WARNING "Error switching LCD\n");
+ }
+
+ write_status(NULL, lcd, LCD_ON, 0);
+ return 0;
+}
+
+static void lcd_blank(int blank)
+{
+ struct backlight_device *bd = asus_backlight_device;
+
+ if (bd) {
+ down(&bd->sem);
+ if (likely(bd->props)) {
+ bd->props->power = blank;
+ if (likely(bd->props->update_status))
+ bd->props->update_status(bd);
+ }
+ up(&bd->sem);
+ }
+}
+
+static int read_brightness(struct backlight_device *bd)
+{
+ int value;
+
+ if (!read_acpi_int(brightness_get_handle, NULL, &value, NULL))
+ printk(ASUS_WARNING "Error reading brightness\n");
+
+ return value;
+}
+
+static int set_brightness(struct backlight_device *bd, int value)
+{
+ int ret = 0;
+
+ value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
+ /* 0 <= value <= 15 */
+
+ if (!write_acpi_int(brightness_set_handle, NULL, value, NULL)) {
+ printk(ASUS_WARNING "Error changing brightness\n");
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+static int update_bl_status(struct backlight_device *bd)
+{
+ int rv;
+ int value = bd->props->brightness;
+
+ rv = set_brightness(bd, value);
+ if (rv)
+ return rv;
+
+ value = (bd->props->power == FB_BLANK_UNBLANK) ? 1 : 0;
+ return set_lcd_state(value);
+}
+
+/*
+ * Platform device handlers
+ */
+
+/*
+ * We write our info in page, we begin at offset off and cannot write more
+ * than count bytes. We set eof to 1 if we handle those 2 values. We return the
+ * number of bytes written in page
+ */
+static ssize_t show_infos(struct device *dev,
+ struct device_attribute *attr, char *page)
+{
+ int len = 0;
+ int temp;
+ char buf[16]; //enough for all info
+ /*
+ * We use the easy way, we don't care of off and count, so we don't set eof
+ * to 1
+ */
+
+ len += sprintf(page, ASUS_HOTK_NAME " " ASUS_LAPTOP_VERSION "\n");
+ len += sprintf(page + len, "Model reference : %s\n", hotk->name);
+ /*
+ * The SFUN method probably allows the original driver to get the list
+ * of features supported by a given model. For now, 0x0100 or 0x0800
+ * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card.
+ * The significance of others is yet to be found.
+ */
+ if (read_acpi_int(hotk->handle, "SFUN", &temp, NULL))
+ len +=
+ sprintf(page + len, "SFUN value : 0x%04x\n", temp);
+ /*
+ * Another value for userspace: the ASYM method returns 0x02 for
+ * battery low and 0x04 for battery critical, its readings tend to be
+ * more accurate than those provided by _BST.
+ * Note: since not all the laptops provide this method, errors are
+ * silently ignored.
+ */
+ if (read_acpi_int(hotk->handle, "ASYM", &temp, NULL))
+ len +=
+ sprintf(page + len, "ASYM value : 0x%04x\n", temp);
+ if (asus_info) {
+ snprintf(buf, 16, "%d", asus_info->length);
+ len += sprintf(page + len, "DSDT length : %s\n", buf);
+ snprintf(buf, 16, "%d", asus_info->checksum);
+ len += sprintf(page + len, "DSDT checksum : %s\n", buf);
+ snprintf(buf, 16, "%d", asus_info->revision);
+ len += sprintf(page + len, "DSDT revision : %s\n", buf);
+ snprintf(buf, 7, "%s", asus_info->oem_id);
+ len += sprintf(page + len, "OEM id : %s\n", buf);
+ snprintf(buf, 9, "%s", asus_info->oem_table_id);
+ len += sprintf(page + len, "OEM table id : %s\n", buf);
+ snprintf(buf, 16, "%x", asus_info->oem_revision);
+ len += sprintf(page + len, "OEM revision : 0x%s\n", buf);
+ snprintf(buf, 5, "%s", asus_info->asl_compiler_id);
+ len += sprintf(page + len, "ASL comp vendor id : %s\n", buf);
+ snprintf(buf, 16, "%x", asus_info->asl_compiler_revision);
+ len += sprintf(page + len, "ASL comp revision : 0x%s\n", buf);
+ }
+
+ return len;
+}
+
+static int parse_arg(const char *buf, unsigned long count, int *val)
+{
+ if (!count)
+ return 0;
+ if (count > 31)
+ return -EINVAL;
+ if (sscanf(buf, "%i", val) != 1)
+ return -EINVAL;
+ return count;
+}
+
+static ssize_t store_status(const char *buf, size_t count,
+ acpi_handle handle, int mask, int invert)
+{
+ int rv, value;
+ int out = 0;
+
+ rv = parse_arg(buf, count, &value);
+ if (rv > 0)
+ out = value ? 1 : 0;
+
+ write_status(handle, out, mask, invert);
+
+ return rv;
+}
+
+/*
+ * LEDD display
+ */
+static ssize_t show_ledd(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "0x%08x\n", hotk->ledd_status);
+}
+
+static ssize_t store_ledd(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int rv, value;
+
+ rv = parse_arg(buf, count, &value);
+ if (rv > 0) {
+ if (!write_acpi_int(ledd_set_handle, NULL, value, NULL))
+ printk(ASUS_WARNING "LED display write failed\n");
+ else
+ hotk->ledd_status = (u32) value;
+ }
+ return rv;
+}
+
+/*
+ * WLAN
+ */
+static ssize_t show_wlan(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", read_status(WL_ON));
+}
+
+static ssize_t store_wlan(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return store_status(buf, count, wl_switch_handle, WL_ON, 0);
+}
+
+/*
+ * Bluetooth
+ */
+static ssize_t show_bluetooth(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", read_status(BT_ON));
+}
+
+static ssize_t store_bluetooth(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ return store_status(buf, count, bt_switch_handle, BT_ON, 0);
+}
+
+/*
+ * Display
+ */
+static void set_display(int value)
+{
+ /* no sanity check needed for now */
+ if (!write_acpi_int(display_set_handle, NULL, value, NULL))
+ printk(ASUS_WARNING "Error setting display\n");
+ return;
+}
+
+static int read_display(void)
+{
+ int value = 0;
+
+ /* In most of the case, we know how to set the display, but sometime
+ we can't read it */
+ if (display_get_handle) {
+ if (!read_acpi_int(display_get_handle, NULL, &value, NULL))
+ printk(ASUS_WARNING "Error reading display status\n");
+ }
+
+ value &= 0x0F; /* needed for some models, shouldn't hurt others */
+
+ return value;
+}
+
+/*
+ * Now, *this* one could be more user-friendly, but so far, no-one has
+ * complained. The significance of bits is the same as in store_disp()
+ */
+static ssize_t show_disp(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", read_display());
+}
+
+/*
+ * Experimental support for display switching. As of now: 1 should activate
+ * the LCD output, 2 should do for CRT, 4 for TV-Out and 8 for DVI.
+ * Any combination (bitwise) of these will suffice. I never actually tested 4
+ * displays hooked up simultaneously, so be warned. See the acpi4asus README
+ * for more info.
+ */
+static ssize_t store_disp(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int rv, value;
+
+ rv = parse_arg(buf, count, &value);
+ if (rv > 0)
+ set_display(value);
+ return rv;
+}
+
+/*
+ * Light Sens
+ */
+static void set_light_sens_switch(int value)
+{
+ if (!write_acpi_int(ls_switch_handle, NULL, value, NULL))
+ printk(ASUS_WARNING "Error setting light sensor switch\n");
+ hotk->light_switch = value;
+}
+
+static ssize_t show_lssw(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", hotk->light_switch);
+}
+
+static ssize_t store_lssw(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int rv, value;
+
+ rv = parse_arg(buf, count, &value);
+ if (rv > 0)
+ set_light_sens_switch(value ? 1 : 0);
+
+ return rv;
+}
+
+static void set_light_sens_level(int value)
+{
+ if (!write_acpi_int(ls_level_handle, NULL, value, NULL))
+ printk(ASUS_WARNING "Error setting light sensor level\n");
+ hotk->light_level = value;
+}
+
+static ssize_t show_lslvl(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", hotk->light_level);
+}
+
+static ssize_t store_lslvl(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int rv, value;
+
+ rv = parse_arg(buf, count, &value);
+ if (rv > 0) {
+ value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
+ /* 0 <= value <= 15 */
+ set_light_sens_level(value);
+ }
+
+ return rv;
+}
+
+static void asus_hotk_notify(acpi_handle handle, u32 event, void *data)
+{
+ /* TODO Find a better way to handle events count. */
+ if (!hotk)
+ return;
+
+ /*
+ * We need to tell the backlight device when the backlight power is
+ * switched
+ */
+ if (event == ATKD_LCD_ON) {
+ write_status(NULL, 1, LCD_ON, 0);
+ lcd_blank(FB_BLANK_UNBLANK);
+ } else if (event == ATKD_LCD_OFF) {
+ write_status(NULL, 0, LCD_ON, 0);
+ lcd_blank(FB_BLANK_POWERDOWN);
+ }
+
+ acpi_bus_generate_event(hotk->device, event,
+ hotk->event_count[event % 128]++);
+
+ return;
+}
+
+#define ASUS_CREATE_DEVICE_ATTR(_name) \
+ struct device_attribute dev_attr_##_name = { \
+ .attr = { \
+ .name = __stringify(_name), \
+ .mode = 0, \
+ .owner = THIS_MODULE }, \
+ .show = NULL, \
+ .store = NULL, \
+ }
+
+#define ASUS_SET_DEVICE_ATTR(_name, _mode, _show, _store) \
+ do { \
+ dev_attr_##_name.attr.mode = _mode; \
+ dev_attr_##_name.show = _show; \
+ dev_attr_##_name.store = _store; \
+ } while(0)
+
+static ASUS_CREATE_DEVICE_ATTR(infos);
+static ASUS_CREATE_DEVICE_ATTR(wlan);
+static ASUS_CREATE_DEVICE_ATTR(bluetooth);
+static ASUS_CREATE_DEVICE_ATTR(display);
+static ASUS_CREATE_DEVICE_ATTR(ledd);
+static ASUS_CREATE_DEVICE_ATTR(ls_switch);
+static ASUS_CREATE_DEVICE_ATTR(ls_level);
+
+static struct attribute *asuspf_attributes[] = {
+ &dev_attr_infos.attr,
+ &dev_attr_wlan.attr,
+ &dev_attr_bluetooth.attr,
+ &dev_attr_display.attr,
+ &dev_attr_ledd.attr,
+ &dev_attr_ls_switch.attr,
+ &dev_attr_ls_level.attr,
+ NULL
+};
+
+static struct attribute_group asuspf_attribute_group = {
+ .attrs = asuspf_attributes
+};
+
+static struct platform_driver asuspf_driver = {
+ .driver = {
+ .name = ASUS_HOTK_FILE,
+ .owner = THIS_MODULE,
+ }
+};
+
+static struct platform_device *asuspf_device;
+
+static void asus_hotk_add_fs(void)
+{
+ ASUS_SET_DEVICE_ATTR(infos, 0444, show_infos, NULL);
+
+ if (wl_switch_handle)
+ ASUS_SET_DEVICE_ATTR(wlan, 0644, show_wlan, store_wlan);
+
+ if (bt_switch_handle)
+ ASUS_SET_DEVICE_ATTR(bluetooth, 0644,
+ show_bluetooth, store_bluetooth);
+
+ if (display_set_handle && display_get_handle)
+ ASUS_SET_DEVICE_ATTR(display, 0644, show_disp, store_disp);
+ else if (display_set_handle)
+ ASUS_SET_DEVICE_ATTR(display, 0200, NULL, store_disp);
+
+ if (ledd_set_handle)
+ ASUS_SET_DEVICE_ATTR(ledd, 0644, show_ledd, store_ledd);
+
+ if (ls_switch_handle && ls_level_handle) {
+ ASUS_SET_DEVICE_ATTR(ls_level, 0644, show_lslvl, store_lslvl);
+ ASUS_SET_DEVICE_ATTR(ls_switch, 0644, show_lssw, store_lssw);
+ }
+}
+
+static int asus_handle_init(char *name, acpi_handle * handle,
+ char **paths, int num_paths)
+{
+ int i;
+ acpi_status status;
+
+ for (i = 0; i < num_paths; i++) {
+ status = acpi_get_handle(NULL, paths[i], handle);
+ if (ACPI_SUCCESS(status))
+ return 0;
+ }
+
+ *handle = NULL;
+ return -ENODEV;
+}
+
+#define ASUS_HANDLE_INIT(object) \
+ asus_handle_init(#object, &object##_handle, object##_paths, \
+ ARRAY_SIZE(object##_paths))
+
+/*
+ * This function is used to initialize the hotk with right values. In this
+ * method, we can make all the detection we want, and modify the hotk struct
+ */
+static int asus_hotk_get_info(void)
+{
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *model = NULL;
+ int bsts_result, hwrs_result;
+ char *string = NULL;
+ acpi_status status;
+
+ /*
+ * Get DSDT headers early enough to allow for differentiating between
+ * models, but late enough to allow acpi_bus_register_driver() to fail
+ * before doing anything ACPI-specific. Should we encounter a machine,
+ * which needs special handling (i.e. its hotkey device has a different
+ * HID), this bit will be moved. A global variable asus_info contains
+ * the DSDT header.
+ */
+ status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus_info);
+ if (ACPI_FAILURE(status))
+ printk(ASUS_WARNING "Couldn't get the DSDT table header\n");
+
+ /* We have to write 0 on init this far for all ASUS models */
+ if (!write_acpi_int(hotk->handle, "INIT", 0, &buffer)) {
+ printk(ASUS_ERR "Hotkey initialization failed\n");
+ return -ENODEV;
+ }
+
+ /* This needs to be called for some laptops to init properly */
+ if (!read_acpi_int(hotk->handle, "BSTS", &bsts_result, NULL))
+ printk(ASUS_WARNING "Error calling BSTS\n");
+ else if (bsts_result)
+ printk(ASUS_NOTICE "BSTS called, 0x%02x returned\n",
+ bsts_result);
+
+ /*
+ * Try to match the object returned by INIT to the specific model.
+ * Handle every possible object (or the lack of thereof) the DSDT
+ * writers might throw at us. When in trouble, we pass NULL to
+ * asus_model_match() and try something completely different.
+ */
+ if (buffer.pointer) {
+ model = buffer.pointer;
+ switch (model->type) {
+ case ACPI_TYPE_STRING:
+ string = model->string.pointer;
+ break;
+ case ACPI_TYPE_BUFFER:
+ string = model->buffer.pointer;
+ break;
+ default:
+ string = "";
+ break;
+ }
+ }
+ hotk->name = kstrdup(string, GFP_KERNEL);
+ if (!hotk->name)
+ return -ENOMEM;
+
+ if (*string)
+ printk(ASUS_NOTICE " %s model detected\n", string);
+
+ ASUS_HANDLE_INIT(mled_set);
+ ASUS_HANDLE_INIT(tled_set);
+ ASUS_HANDLE_INIT(rled_set);
+ ASUS_HANDLE_INIT(pled_set);
+
+ ASUS_HANDLE_INIT(ledd_set);
+
+ /*
+ * The HWRS method return informations about the hardware.
+ * 0x80 bit is for WLAN, 0x100 for Bluetooth.
+ * The significance of others is yet to be found.
+ * If we don't find the method, we assume the device are present.
+ */
+ if (!read_acpi_int(hotk->handle, "HRWS", &hwrs_result, NULL))
+ hwrs_result = WL_HWRS | BT_HWRS;
+
+ if (hwrs_result & WL_HWRS)
+ ASUS_HANDLE_INIT(wl_switch);
+ if (hwrs_result & BT_HWRS)
+ ASUS_HANDLE_INIT(bt_switch);
+
+ ASUS_HANDLE_INIT(wireless_status);
+
+ ASUS_HANDLE_INIT(brightness_set);
+ ASUS_HANDLE_INIT(brightness_get);
+
+ ASUS_HANDLE_INIT(lcd_switch);
+
+ ASUS_HANDLE_INIT(display_set);
+ ASUS_HANDLE_INIT(display_get);
+
+ /* There is a lot of models with "ALSL", but a few get
+ a real light sens, so we need to check it. */
+ if (ASUS_HANDLE_INIT(ls_switch))
+ ASUS_HANDLE_INIT(ls_level);
+
+ kfree(model);
+
+ return AE_OK;
+}
+
+static int asus_hotk_check(void)
+{
+ int result = 0;
+
+ result = acpi_bus_get_status(hotk->device);
+ if (result)
+ return result;
+
+ if (hotk->device->status.present) {
+ result = asus_hotk_get_info();
+ } else {
+ printk(ASUS_ERR "Hotkey device not present, aborting\n");
+ return -EINVAL;
+ }
+
+ return result;
+}
+
+static int asus_hotk_found;
+
+static int asus_hotk_add(struct acpi_device *device)
+{
+ acpi_status status = AE_OK;
+ int result;
+
+ if (!device)
+ return -EINVAL;
+
+ printk(ASUS_NOTICE "Asus Laptop Support version %s\n",
+ ASUS_LAPTOP_VERSION);
+
+ hotk = kmalloc(sizeof(struct asus_hotk), GFP_KERNEL);
+ if (!hotk)
+ return -ENOMEM;
+ memset(hotk, 0, sizeof(struct asus_hotk));
+
+ hotk->handle = device->handle;
+ strcpy(acpi_device_name(device), ASUS_HOTK_DEVICE_NAME);
+ strcpy(acpi_device_class(device), ASUS_HOTK_CLASS);
+ acpi_driver_data(device) = hotk;
+ hotk->device = device;
+
+ result = asus_hotk_check();
+ if (result)
+ goto end;
+
+ asus_hotk_add_fs();
+
+ /*
+ * We install the handler, it will receive the hotk in parameter, so, we
+ * could add other data to the hotk struct
+ */
+ status = acpi_install_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY,
+ asus_hotk_notify, hotk);
+ if (ACPI_FAILURE(status))
+ printk(ASUS_ERR "Error installing notify handler\n");
+
+ asus_hotk_found = 1;
+
+ /* WLED and BLED are on by default */
+ write_status(bt_switch_handle, 1, BT_ON, 0);
+ write_status(wl_switch_handle, 1, WL_ON, 0);
+
+ /* LCD Backlight is on by default */
+ write_status(NULL, 1, LCD_ON, 0);
+
+ /* LED display is off by default */
+ hotk->ledd_status = 0xFFF;
+
+ /* Set initial values of light sensor and level */
+ hotk->light_switch = 1; /* Default to light sensor disabled */
+ hotk->light_level = 0; /* level 5 for sensor sensitivity */
+
+ if (ls_switch_handle)
+ set_light_sens_switch(hotk->light_switch);
+
+ if (ls_level_handle)
+ set_light_sens_level(hotk->light_level);
+
+ end:
+ if (result) {
+ kfree(hotk->name);
+ kfree(hotk);
+ }
+
+ return result;
+}
+
+static int asus_hotk_remove(struct acpi_device *device, int type)
+{
+ acpi_status status = 0;
+
+ if (!device || !acpi_driver_data(device))
+ return -EINVAL;
+
+ status = acpi_remove_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY,
+ asus_hotk_notify);
+ if (ACPI_FAILURE(status))
+ printk(ASUS_ERR "Error removing notify handler\n");
+
+ kfree(hotk->name);
+ kfree(hotk);
+
+ return 0;
+}
+
+static void asus_backlight_exit(void)
+{
+ if (asus_backlight_device)
+ backlight_device_unregister(asus_backlight_device);
+}
+
+#define ASUS_LED_UNREGISTER(object) \
+ if(object##_led.class_dev \
+ && !IS_ERR(object##_led.class_dev)) \
+ led_classdev_unregister(&object##_led)
+
+static void asus_led_exit(void)
+{
+ ASUS_LED_UNREGISTER(mled);
+ ASUS_LED_UNREGISTER(tled);
+ ASUS_LED_UNREGISTER(pled);
+ ASUS_LED_UNREGISTER(rled);
+
+ destroy_workqueue(led_workqueue);
+}
+
+static void __exit asus_laptop_exit(void)
+{
+ asus_backlight_exit();
+ asus_led_exit();
+
+ acpi_bus_unregister_driver(&asus_hotk_driver);
+ sysfs_remove_group(&asuspf_device->dev.kobj, &asuspf_attribute_group);
+ platform_device_unregister(asuspf_device);
+ platform_driver_unregister(&asuspf_driver);
+}
+
+static int asus_backlight_init(struct device *dev)
+{
+ struct backlight_device *bd;
+
+ if (brightness_set_handle && lcd_switch_handle) {
+ bd = backlight_device_register(ASUS_HOTK_FILE, dev,
+ NULL, &asusbl_data);
+ if (IS_ERR(bd)) {
+ printk(ASUS_ERR
+ "Could not register asus backlight device\n");
+ asus_backlight_device = NULL;
+ return PTR_ERR(bd);
+ }
+
+ asus_backlight_device = bd;
+
+ down(&bd->sem);
+ if (likely(bd->props)) {
+ bd->props->brightness = read_brightness(NULL);
+ bd->props->power = FB_BLANK_UNBLANK;
+ if (likely(bd->props->update_status))
+ bd->props->update_status(bd);
+ }
+ up(&bd->sem);
+ }
+ return 0;
+}
+
+static int asus_led_register(acpi_handle handle,
+ struct led_classdev *ldev, struct device *dev)
+{
+ if (!handle)
+ return 0;
+
+ return led_classdev_register(dev, ldev);
+}
+
+#define ASUS_LED_REGISTER(object, device) \
+ asus_led_register(object##_set_handle, &object##_led, device)
+
+static int asus_led_init(struct device *dev)
+{
+ int rv;
+
+ rv = ASUS_LED_REGISTER(mled, dev);
+ if (rv)
+ return rv;
+
+ rv = ASUS_LED_REGISTER(tled, dev);
+ if (rv)
+ return rv;
+
+ rv = ASUS_LED_REGISTER(rled, dev);
+ if (rv)
+ return rv;
+
+ rv = ASUS_LED_REGISTER(pled, dev);
+ if (rv)
+ return rv;
+
+ led_workqueue = create_singlethread_workqueue("led_workqueue");
+ if (!led_workqueue)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int __init asus_laptop_init(void)
+{
+ struct device *dev;
+ int result;
+
+ if (acpi_disabled)
+ return -ENODEV;
+
+ if (!acpi_specific_hotkey_enabled) {
+ printk(ASUS_ERR "Using generic hotkey driver\n");
+ return -ENODEV;
+ }
+
+ result = acpi_bus_register_driver(&asus_hotk_driver);
+ if (result < 0)
+ return result;
+
+ /*
+ * This is a bit of a kludge. We only want this module loaded
+ * for ASUS systems, but there's currently no way to probe the
+ * ACPI namespace for ASUS HIDs. So we just return failure if
+ * we didn't find one, which will cause the module to be
+ * unloaded.
+ */
+ if (!asus_hotk_found) {
+ acpi_bus_unregister_driver(&asus_hotk_driver);
+ return -ENODEV;
+ }
+
+ dev = acpi_get_physical_device(hotk->device->handle);
+
+ result = asus_backlight_init(dev);
+ if (result)
+ goto fail_backlight;
+
+ result = asus_led_init(dev);
+ if (result)
+ goto fail_led;
+
+ /* Register platform stuff */
+ result = platform_driver_register(&asuspf_driver);
+ if (result)
+ goto fail_platform_driver;
+
+ asuspf_device = platform_device_alloc(ASUS_HOTK_FILE, -1);
+ if (!asuspf_device) {
+ result = -ENOMEM;
+ goto fail_platform_device1;
+ }
+
+ result = platform_device_add(asuspf_device);
+ if (result)
+ goto fail_platform_device2;
+
+ result = sysfs_create_group(&asuspf_device->dev.kobj,
+ &asuspf_attribute_group);
+ if (result)
+ goto fail_sysfs;
+
+ return 0;
+
+ fail_sysfs:
+ platform_device_del(asuspf_device);
+
+ fail_platform_device2:
+ platform_device_put(asuspf_device);
+
+ fail_platform_device1:
+ platform_driver_unregister(&asuspf_driver);
+
+ fail_platform_driver:
+ asus_led_exit();
+
+ fail_led:
+ asus_backlight_exit();
+
+ fail_backlight:
+
+ return result;
+}
+
+module_init(asus_laptop_init);
+module_exit(asus_laptop_exit);
diff --git a/drivers/misc/lkdtm.c b/drivers/misc/lkdtm.c
index db9d7df75ae..552b7957a92 100644
--- a/drivers/misc/lkdtm.c
+++ b/drivers/misc/lkdtm.c
@@ -108,8 +108,8 @@ static struct jprobe lkdtm;
static int lkdtm_parse_commandline(void);
static void lkdtm_handler(void);
-static char* cpoint_name = INVALID;
-static char* cpoint_type = NONE;
+static char* cpoint_name;
+static char* cpoint_type;
static int cpoint_count = DEFAULT_COUNT;
static int recur_count = REC_NUM_DEFAULT;
diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c
index 2ab7add78f9..e21e490fedb 100644
--- a/drivers/misc/tifm_7xx1.c
+++ b/drivers/misc/tifm_7xx1.c
@@ -11,66 +11,25 @@
#include <linux/tifm.h>
#include <linux/dma-mapping.h>
+#include <linux/freezer.h>
#define DRIVER_NAME "tifm_7xx1"
-#define DRIVER_VERSION "0.6"
+#define DRIVER_VERSION "0.7"
static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock)
{
- int cnt;
- unsigned long flags;
-
- spin_lock_irqsave(&fm->lock, flags);
- if (!fm->inhibit_new_cards) {
- for (cnt = 0; cnt < fm->max_sockets; cnt++) {
- if (fm->sockets[cnt] == sock) {
- fm->remove_mask |= (1 << cnt);
- queue_work(fm->wq, &fm->media_remover);
- break;
- }
- }
- }
- spin_unlock_irqrestore(&fm->lock, flags);
-}
-
-static void tifm_7xx1_remove_media(struct work_struct *work)
-{
- struct tifm_adapter *fm =
- container_of(work, struct tifm_adapter, media_remover);
unsigned long flags;
- int cnt;
- struct tifm_dev *sock;
- if (!class_device_get(&fm->cdev))
- return;
spin_lock_irqsave(&fm->lock, flags);
- for (cnt = 0; cnt < fm->max_sockets; cnt++) {
- if (fm->sockets[cnt] && (fm->remove_mask & (1 << cnt))) {
- printk(KERN_INFO DRIVER_NAME
- ": demand removing card from socket %d\n", cnt);
- sock = fm->sockets[cnt];
- fm->sockets[cnt] = NULL;
- fm->remove_mask &= ~(1 << cnt);
-
- writel(0x0e00, sock->addr + SOCK_CONTROL);
-
- writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
- fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
- writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
- fm->addr + FM_SET_INTERRUPT_ENABLE);
-
- spin_unlock_irqrestore(&fm->lock, flags);
- device_unregister(&sock->dev);
- spin_lock_irqsave(&fm->lock, flags);
- }
- }
+ fm->socket_change_set |= 1 << sock->socket_id;
+ wake_up_all(&fm->change_set_notify);
spin_unlock_irqrestore(&fm->lock, flags);
- class_device_put(&fm->cdev);
}
static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id)
{
struct tifm_adapter *fm = dev_id;
+ struct tifm_dev *sock;
unsigned int irq_status;
unsigned int sock_irq_status, cnt;
@@ -84,42 +43,32 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id)
if (irq_status & TIFM_IRQ_ENABLE) {
writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
- for (cnt = 0; cnt < fm->max_sockets; cnt++) {
- sock_irq_status = (irq_status >> cnt) &
- (TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK);
-
- if (fm->sockets[cnt]) {
- if (sock_irq_status &&
- fm->sockets[cnt]->signal_irq)
- sock_irq_status = fm->sockets[cnt]->
- signal_irq(fm->sockets[cnt],
- sock_irq_status);
+ for (cnt = 0; cnt < fm->num_sockets; cnt++) {
+ sock = fm->sockets[cnt];
+ sock_irq_status = (irq_status >> cnt)
+ & (TIFM_IRQ_FIFOMASK(1)
+ | TIFM_IRQ_CARDMASK(1));
- if (irq_status & (1 << cnt))
- fm->remove_mask |= 1 << cnt;
- } else {
- if (irq_status & (1 << cnt))
- fm->insert_mask |= 1 << cnt;
- }
+ if (sock && sock_irq_status)
+ sock->signal_irq(sock, sock_irq_status);
}
+
+ fm->socket_change_set |= irq_status
+ & ((1 << fm->num_sockets) - 1);
}
writel(irq_status, fm->addr + FM_INTERRUPT_STATUS);
- if (!fm->inhibit_new_cards) {
- if (!fm->remove_mask && !fm->insert_mask) {
- writel(TIFM_IRQ_ENABLE,
- fm->addr + FM_SET_INTERRUPT_ENABLE);
- } else {
- queue_work(fm->wq, &fm->media_remover);
- queue_work(fm->wq, &fm->media_inserter);
- }
- }
+ if (!fm->socket_change_set)
+ writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE);
+ else
+ wake_up_all(&fm->change_set_notify);
spin_unlock(&fm->lock);
return IRQ_HANDLED;
}
-static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, int is_x2)
+static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr,
+ int is_x2)
{
unsigned int s_state;
int cnt;
@@ -127,8 +76,8 @@ static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, int is
writel(0x0e00, sock_addr + SOCK_CONTROL);
for (cnt = 0; cnt < 100; cnt++) {
- if (!(TIFM_SOCK_STATE_POWERED &
- readl(sock_addr + SOCK_PRESENT_STATE)))
+ if (!(TIFM_SOCK_STATE_POWERED
+ & readl(sock_addr + SOCK_PRESENT_STATE)))
break;
msleep(10);
}
@@ -151,8 +100,8 @@ static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, int is
}
for (cnt = 0; cnt < 100; cnt++) {
- if ((TIFM_SOCK_STATE_POWERED &
- readl(sock_addr + SOCK_PRESENT_STATE)))
+ if ((TIFM_SOCK_STATE_POWERED
+ & readl(sock_addr + SOCK_PRESENT_STATE)))
break;
msleep(10);
}
@@ -170,130 +119,209 @@ tifm_7xx1_sock_addr(char __iomem *base_addr, unsigned int sock_num)
return base_addr + ((sock_num + 1) << 10);
}
-static void tifm_7xx1_insert_media(struct work_struct *work)
+static int tifm_7xx1_switch_media(void *data)
{
- struct tifm_adapter *fm =
- container_of(work, struct tifm_adapter, media_inserter);
+ struct tifm_adapter *fm = data;
unsigned long flags;
tifm_media_id media_id;
char *card_name = "xx";
- int cnt, ok_to_register;
- unsigned int insert_mask;
- struct tifm_dev *new_sock = NULL;
+ int cnt, rc;
+ struct tifm_dev *sock;
+ unsigned int socket_change_set;
- if (!class_device_get(&fm->cdev))
- return;
- spin_lock_irqsave(&fm->lock, flags);
- insert_mask = fm->insert_mask;
- fm->insert_mask = 0;
- if (fm->inhibit_new_cards) {
+ while (1) {
+ rc = wait_event_interruptible(fm->change_set_notify,
+ fm->socket_change_set);
+ if (rc == -ERESTARTSYS)
+ try_to_freeze();
+
+ spin_lock_irqsave(&fm->lock, flags);
+ socket_change_set = fm->socket_change_set;
+ fm->socket_change_set = 0;
+
+ dev_dbg(fm->dev, "checking media set %x\n",
+ socket_change_set);
+
+ if (kthread_should_stop())
+ socket_change_set = (1 << fm->num_sockets) - 1;
spin_unlock_irqrestore(&fm->lock, flags);
- class_device_put(&fm->cdev);
- return;
- }
- spin_unlock_irqrestore(&fm->lock, flags);
- for (cnt = 0; cnt < fm->max_sockets; cnt++) {
- if (!(insert_mask & (1 << cnt)))
+ if (!socket_change_set)
continue;
- media_id = tifm_7xx1_toggle_sock_power(tifm_7xx1_sock_addr(fm->addr, cnt),
- fm->max_sockets == 2);
- if (media_id) {
- ok_to_register = 0;
- new_sock = tifm_alloc_device(fm, cnt);
- if (new_sock) {
- new_sock->addr = tifm_7xx1_sock_addr(fm->addr,
- cnt);
- new_sock->media_id = media_id;
- switch (media_id) {
- case 1:
- card_name = "xd";
- break;
- case 2:
- card_name = "ms";
- break;
- case 3:
- card_name = "sd";
- break;
- default:
- break;
- }
- snprintf(new_sock->dev.bus_id, BUS_ID_SIZE,
- "tifm_%s%u:%u", card_name, fm->id, cnt);
+ spin_lock_irqsave(&fm->lock, flags);
+ for (cnt = 0; cnt < fm->num_sockets; cnt++) {
+ if (!(socket_change_set & (1 << cnt)))
+ continue;
+ sock = fm->sockets[cnt];
+ if (sock) {
printk(KERN_INFO DRIVER_NAME
- ": %s card detected in socket %d\n",
- card_name, cnt);
+ ": demand removing card from socket %d\n",
+ cnt);
+ fm->sockets[cnt] = NULL;
+ spin_unlock_irqrestore(&fm->lock, flags);
+ device_unregister(&sock->dev);
spin_lock_irqsave(&fm->lock, flags);
- if (!fm->sockets[cnt]) {
- fm->sockets[cnt] = new_sock;
- ok_to_register = 1;
+ writel(0x0e00,
+ tifm_7xx1_sock_addr(fm->addr, cnt)
+ + SOCK_CONTROL);
+ }
+ if (kthread_should_stop())
+ continue;
+
+ spin_unlock_irqrestore(&fm->lock, flags);
+ media_id = tifm_7xx1_toggle_sock_power(
+ tifm_7xx1_sock_addr(fm->addr, cnt),
+ fm->num_sockets == 2);
+ if (media_id) {
+ sock = tifm_alloc_device(fm);
+ if (sock) {
+ sock->addr = tifm_7xx1_sock_addr(fm->addr,
+ cnt);
+ sock->media_id = media_id;
+ sock->socket_id = cnt;
+ switch (media_id) {
+ case 1:
+ card_name = "xd";
+ break;
+ case 2:
+ card_name = "ms";
+ break;
+ case 3:
+ card_name = "sd";
+ break;
+ default:
+ tifm_free_device(&sock->dev);
+ spin_lock_irqsave(&fm->lock, flags);
+ continue;
+ }
+ snprintf(sock->dev.bus_id, BUS_ID_SIZE,
+ "tifm_%s%u:%u", card_name,
+ fm->id, cnt);
+ printk(KERN_INFO DRIVER_NAME
+ ": %s card detected in socket %d\n",
+ card_name, cnt);
+ if (!device_register(&sock->dev)) {
+ spin_lock_irqsave(&fm->lock, flags);
+ if (!fm->sockets[cnt]) {
+ fm->sockets[cnt] = sock;
+ sock = NULL;
+ }
+ spin_unlock_irqrestore(&fm->lock, flags);
+ }
+ if (sock)
+ tifm_free_device(&sock->dev);
}
+ spin_lock_irqsave(&fm->lock, flags);
+ }
+ }
+
+ if (!kthread_should_stop()) {
+ writel(TIFM_IRQ_FIFOMASK(socket_change_set)
+ | TIFM_IRQ_CARDMASK(socket_change_set),
+ fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+ writel(TIFM_IRQ_FIFOMASK(socket_change_set)
+ | TIFM_IRQ_CARDMASK(socket_change_set),
+ fm->addr + FM_SET_INTERRUPT_ENABLE);
+ writel(TIFM_IRQ_ENABLE,
+ fm->addr + FM_SET_INTERRUPT_ENABLE);
+ spin_unlock_irqrestore(&fm->lock, flags);
+ } else {
+ for (cnt = 0; cnt < fm->num_sockets; cnt++) {
+ if (fm->sockets[cnt])
+ fm->socket_change_set |= 1 << cnt;
+ }
+ if (!fm->socket_change_set) {
+ spin_unlock_irqrestore(&fm->lock, flags);
+ return 0;
+ } else {
spin_unlock_irqrestore(&fm->lock, flags);
- if (!ok_to_register ||
- device_register(&new_sock->dev)) {
- spin_lock_irqsave(&fm->lock, flags);
- fm->sockets[cnt] = NULL;
- spin_unlock_irqrestore(&fm->lock,
- flags);
- tifm_free_device(&new_sock->dev);
- }
}
}
- writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
- fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
- writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
- fm->addr + FM_SET_INTERRUPT_ENABLE);
}
-
- writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE);
- class_device_put(&fm->cdev);
+ return 0;
}
+#ifdef CONFIG_PM
+
static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state)
{
- struct tifm_adapter *fm = pci_get_drvdata(dev);
- unsigned long flags;
+ dev_dbg(&dev->dev, "suspending host\n");
- spin_lock_irqsave(&fm->lock, flags);
- fm->inhibit_new_cards = 1;
- fm->remove_mask = 0xf;
- fm->insert_mask = 0;
- writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
- spin_unlock_irqrestore(&fm->lock, flags);
- flush_workqueue(fm->wq);
-
- tifm_7xx1_remove_media(&fm->media_remover);
-
- pci_set_power_state(dev, PCI_D3hot);
- pci_disable_device(dev);
- pci_save_state(dev);
+ pci_save_state(dev);
+ pci_enable_wake(dev, pci_choose_state(dev, state), 0);
+ pci_disable_device(dev);
+ pci_set_power_state(dev, pci_choose_state(dev, state));
return 0;
}
static int tifm_7xx1_resume(struct pci_dev *dev)
{
struct tifm_adapter *fm = pci_get_drvdata(dev);
+ int cnt, rc;
unsigned long flags;
+ tifm_media_id new_ids[fm->num_sockets];
+ pci_set_power_state(dev, PCI_D0);
pci_restore_state(dev);
- pci_enable_device(dev);
- pci_set_power_state(dev, PCI_D0);
- pci_set_master(dev);
+ rc = pci_enable_device(dev);
+ if (rc)
+ return rc;
+ pci_set_master(dev);
+ dev_dbg(&dev->dev, "resuming host\n");
+
+ for (cnt = 0; cnt < fm->num_sockets; cnt++)
+ new_ids[cnt] = tifm_7xx1_toggle_sock_power(
+ tifm_7xx1_sock_addr(fm->addr, cnt),
+ fm->num_sockets == 2);
spin_lock_irqsave(&fm->lock, flags);
- fm->inhibit_new_cards = 0;
- writel(TIFM_IRQ_SETALL, fm->addr + FM_INTERRUPT_STATUS);
- writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
- writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SETALLSOCK,
- fm->addr + FM_SET_INTERRUPT_ENABLE);
- fm->insert_mask = 0xf;
+ fm->socket_change_set = 0;
+ for (cnt = 0; cnt < fm->num_sockets; cnt++) {
+ if (fm->sockets[cnt]) {
+ if (fm->sockets[cnt]->media_id == new_ids[cnt])
+ fm->socket_change_set |= 1 << cnt;
+
+ fm->sockets[cnt]->media_id = new_ids[cnt];
+ }
+ }
+
+ writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1),
+ fm->addr + FM_SET_INTERRUPT_ENABLE);
+ if (!fm->socket_change_set) {
+ spin_unlock_irqrestore(&fm->lock, flags);
+ return 0;
+ } else {
+ fm->socket_change_set = 0;
+ spin_unlock_irqrestore(&fm->lock, flags);
+ }
+
+ wait_event_timeout(fm->change_set_notify, fm->socket_change_set, HZ);
+
+ spin_lock_irqsave(&fm->lock, flags);
+ writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set)
+ | TIFM_IRQ_CARDMASK(fm->socket_change_set),
+ fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+ writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set)
+ | TIFM_IRQ_CARDMASK(fm->socket_change_set),
+ fm->addr + FM_SET_INTERRUPT_ENABLE);
+ writel(TIFM_IRQ_ENABLE,
+ fm->addr + FM_SET_INTERRUPT_ENABLE);
+ fm->socket_change_set = 0;
+
spin_unlock_irqrestore(&fm->lock, flags);
return 0;
}
+#else
+
+#define tifm_7xx1_suspend NULL
+#define tifm_7xx1_resume NULL
+
+#endif /* CONFIG_PM */
+
static int tifm_7xx1_probe(struct pci_dev *dev,
- const struct pci_device_id *dev_id)
+ const struct pci_device_id *dev_id)
{
struct tifm_adapter *fm;
int pci_dev_busy = 0;
@@ -324,19 +352,18 @@ static int tifm_7xx1_probe(struct pci_dev *dev,
}
fm->dev = &dev->dev;
- fm->max_sockets = (dev->device == 0x803B) ? 2 : 4;
- fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->max_sockets,
- GFP_KERNEL);
+ fm->num_sockets = (dev->device == PCI_DEVICE_ID_TI_XX21_XX11_FM)
+ ? 4 : 2;
+ fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->num_sockets,
+ GFP_KERNEL);
if (!fm->sockets)
goto err_out_free;
- INIT_WORK(&fm->media_inserter, tifm_7xx1_insert_media);
- INIT_WORK(&fm->media_remover, tifm_7xx1_remove_media);
fm->eject = tifm_7xx1_eject;
pci_set_drvdata(dev, fm);
fm->addr = ioremap(pci_resource_start(dev, 0),
- pci_resource_len(dev, 0));
+ pci_resource_len(dev, 0));
if (!fm->addr)
goto err_out_free;
@@ -344,16 +371,15 @@ static int tifm_7xx1_probe(struct pci_dev *dev,
if (rc)
goto err_out_unmap;
- rc = tifm_add_adapter(fm);
+ init_waitqueue_head(&fm->change_set_notify);
+ rc = tifm_add_adapter(fm, tifm_7xx1_switch_media);
if (rc)
goto err_out_irq;
writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
- writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SETALLSOCK,
- fm->addr + FM_SET_INTERRUPT_ENABLE);
-
- fm->insert_mask = 0xf;
-
+ writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1),
+ fm->addr + FM_SET_INTERRUPT_ENABLE);
+ wake_up_process(fm->media_switcher);
return 0;
err_out_irq:
@@ -377,19 +403,15 @@ static void tifm_7xx1_remove(struct pci_dev *dev)
struct tifm_adapter *fm = pci_get_drvdata(dev);
unsigned long flags;
+ writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+ mmiowb();
+ free_irq(dev->irq, fm);
+
spin_lock_irqsave(&fm->lock, flags);
- fm->inhibit_new_cards = 1;
- fm->remove_mask = 0xf;
- fm->insert_mask = 0;
- writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+ fm->socket_change_set = (1 << fm->num_sockets) - 1;
spin_unlock_irqrestore(&fm->lock, flags);
- flush_workqueue(fm->wq);
-
- tifm_7xx1_remove_media(&fm->media_remover);
-
- writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
- free_irq(dev->irq, fm);
+ kthread_stop(fm->media_switcher);
tifm_remove_adapter(fm);
@@ -404,10 +426,12 @@ static void tifm_7xx1_remove(struct pci_dev *dev)
}
static struct pci_device_id tifm_7xx1_pci_tbl [] = {
- { PCI_VENDOR_ID_TI, 0x8033, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- 0 }, /* xx21 - the one I have */
- { PCI_VENDOR_ID_TI, 0x803B, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- 0 }, /* xx12 - should be also supported */
+ { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX21_XX11_FM, PCI_ANY_ID,
+ PCI_ANY_ID, 0, 0, 0 }, /* xx21 - the one I have */
+ { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX12_FM, PCI_ANY_ID,
+ PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX20_FM, PCI_ANY_ID,
+ PCI_ANY_ID, 0, 0, 0 },
{ }
};
diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c
index d61df5c3ac3..6b10ebe9d93 100644
--- a/drivers/misc/tifm_core.c
+++ b/drivers/misc/tifm_core.c
@@ -14,7 +14,7 @@
#include <linux/idr.h>
#define DRIVER_NAME "tifm_core"
-#define DRIVER_VERSION "0.6"
+#define DRIVER_VERSION "0.7"
static DEFINE_IDR(tifm_adapter_idr);
static DEFINE_SPINLOCK(tifm_adapter_lock);
@@ -60,10 +60,41 @@ static int tifm_uevent(struct device *dev, char **envp, int num_envp,
return 0;
}
+#ifdef CONFIG_PM
+
+static int tifm_device_suspend(struct device *dev, pm_message_t state)
+{
+ struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
+ struct tifm_driver *drv = fm_dev->drv;
+
+ if (drv && drv->suspend)
+ return drv->suspend(fm_dev, state);
+ return 0;
+}
+
+static int tifm_device_resume(struct device *dev)
+{
+ struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
+ struct tifm_driver *drv = fm_dev->drv;
+
+ if (drv && drv->resume)
+ return drv->resume(fm_dev);
+ return 0;
+}
+
+#else
+
+#define tifm_device_suspend NULL
+#define tifm_device_resume NULL
+
+#endif /* CONFIG_PM */
+
static struct bus_type tifm_bus_type = {
.name = "tifm",
.match = tifm_match,
.uevent = tifm_uevent,
+ .suspend = tifm_device_suspend,
+ .resume = tifm_device_resume
};
static void tifm_free(struct class_device *cdev)
@@ -71,8 +102,6 @@ static void tifm_free(struct class_device *cdev)
struct tifm_adapter *fm = container_of(cdev, struct tifm_adapter, cdev);
kfree(fm->sockets);
- if (fm->wq)
- destroy_workqueue(fm->wq);
kfree(fm);
}
@@ -101,7 +130,8 @@ void tifm_free_adapter(struct tifm_adapter *fm)
}
EXPORT_SYMBOL(tifm_free_adapter);
-int tifm_add_adapter(struct tifm_adapter *fm)
+int tifm_add_adapter(struct tifm_adapter *fm,
+ int (*mediathreadfn)(void *data))
{
int rc;
@@ -113,10 +143,10 @@ int tifm_add_adapter(struct tifm_adapter *fm)
spin_unlock(&tifm_adapter_lock);
if (!rc) {
snprintf(fm->cdev.class_id, BUS_ID_SIZE, "tifm%u", fm->id);
- strncpy(fm->wq_name, fm->cdev.class_id, KOBJ_NAME_LEN);
+ fm->media_switcher = kthread_create(mediathreadfn,
+ fm, "tifm/%u", fm->id);
- fm->wq = create_singlethread_workqueue(fm->wq_name);
- if (fm->wq)
+ if (!IS_ERR(fm->media_switcher))
return class_device_add(&fm->cdev);
spin_lock(&tifm_adapter_lock);
@@ -141,27 +171,27 @@ EXPORT_SYMBOL(tifm_remove_adapter);
void tifm_free_device(struct device *dev)
{
struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
- if (fm_dev->wq)
- destroy_workqueue(fm_dev->wq);
kfree(fm_dev);
}
EXPORT_SYMBOL(tifm_free_device);
-struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id)
+static void tifm_dummy_signal_irq(struct tifm_dev *sock,
+ unsigned int sock_irq_status)
+{
+ return;
+}
+
+struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm)
{
struct tifm_dev *dev = kzalloc(sizeof(struct tifm_dev), GFP_KERNEL);
if (dev) {
spin_lock_init(&dev->lock);
- snprintf(dev->wq_name, KOBJ_NAME_LEN, "tifm%u:%u", fm->id, id);
- dev->wq = create_singlethread_workqueue(dev->wq_name);
- if (!dev->wq) {
- kfree(dev);
- return NULL;
- }
+
dev->dev.parent = fm->dev;
dev->dev.bus = &tifm_bus_type;
dev->dev.release = tifm_free_device;
+ dev->signal_irq = tifm_dummy_signal_irq;
}
return dev;
}
@@ -219,6 +249,7 @@ static int tifm_device_remove(struct device *dev)
struct tifm_driver *drv = fm_dev->drv;
if (drv) {
+ fm_dev->signal_irq = tifm_dummy_signal_irq;
if (drv->remove)
drv->remove(fm_dev);
fm_dev->drv = NULL;
@@ -233,6 +264,8 @@ int tifm_register_driver(struct tifm_driver *drv)
drv->driver.bus = &tifm_bus_type;
drv->driver.probe = tifm_device_probe;
drv->driver.remove = tifm_device_remove;
+ drv->driver.suspend = tifm_device_suspend;
+ drv->driver.resume = tifm_device_resume;
return driver_register(&drv->driver);
}
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index 4224686fdf2..12af9c71876 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -111,7 +111,7 @@ config MMC_IMX
config MMC_TIFM_SD
tristate "TI Flash Media MMC/SD Interface support (EXPERIMENTAL)"
- depends on MMC && EXPERIMENTAL
+ depends on MMC && EXPERIMENTAL && PCI
select TIFM_CORE
help
Say Y here if you want to be able to access MMC/SD cards with
diff --git a/drivers/mmc/at91_mci.c b/drivers/mmc/at91_mci.c
index aa152f31851..2ce50f38e3c 100644
--- a/drivers/mmc/at91_mci.c
+++ b/drivers/mmc/at91_mci.c
@@ -823,6 +823,9 @@ static int __init at91_mci_probe(struct platform_device *pdev)
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
mmc->caps = MMC_CAP_BYTEBLOCK;
+ mmc->max_blk_size = 4095;
+ mmc->max_blk_count = mmc->max_req_size;
+
host = mmc_priv(mmc);
host->mmc = mmc;
host->buffer = NULL;
diff --git a/drivers/mmc/au1xmmc.c b/drivers/mmc/au1xmmc.c
index 800527cf40d..b834be261ab 100644
--- a/drivers/mmc/au1xmmc.c
+++ b/drivers/mmc/au1xmmc.c
@@ -152,8 +152,9 @@ static inline int au1xmmc_card_inserted(struct au1xmmc_host *host)
? 1 : 0;
}
-static inline int au1xmmc_card_readonly(struct au1xmmc_host *host)
+static int au1xmmc_card_readonly(struct mmc_host *mmc)
{
+ struct au1xmmc_host *host = mmc_priv(mmc);
return (bcsr->status & au1xmmc_card_table[host->id].wpstatus)
? 1 : 0;
}
@@ -193,6 +194,8 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait,
u32 mmccmd = (cmd->opcode << SD_CMD_CI_SHIFT);
switch (mmc_resp_type(cmd)) {
+ case MMC_RSP_NONE:
+ break;
case MMC_RSP_R1:
mmccmd |= SD_CMD_RT_1;
break;
@@ -205,6 +208,10 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait,
case MMC_RSP_R3:
mmccmd |= SD_CMD_RT_3;
break;
+ default:
+ printk(KERN_INFO "au1xmmc: unhandled response type %02x\n",
+ mmc_resp_type(cmd));
+ return MMC_ERR_INVALID;
}
switch(cmd->opcode) {
@@ -878,6 +885,7 @@ static void au1xmmc_init_dma(struct au1xmmc_host *host)
static const struct mmc_host_ops au1xmmc_ops = {
.request = au1xmmc_request,
.set_ios = au1xmmc_set_ios,
+ .get_ro = au1xmmc_card_readonly,
};
static int __devinit au1xmmc_probe(struct platform_device *pdev)
@@ -914,6 +922,9 @@ static int __devinit au1xmmc_probe(struct platform_device *pdev)
mmc->max_seg_size = AU1XMMC_DESCRIPTOR_SIZE;
mmc->max_phys_segs = AU1XMMC_DESCRIPTOR_COUNT;
+ mmc->max_blk_size = 2048;
+ mmc->max_blk_count = 512;
+
mmc->ocr_avail = AU1XMMC_OCR;
host = mmc_priv(mmc);
diff --git a/drivers/mmc/imxmmc.c b/drivers/mmc/imxmmc.c
index bfb9ff69320..b060d4bfba2 100644
--- a/drivers/mmc/imxmmc.c
+++ b/drivers/mmc/imxmmc.c
@@ -958,8 +958,10 @@ static int imxmci_probe(struct platform_device *pdev)
/* MMC core transfer sizes tunable parameters */
mmc->max_hw_segs = 64;
mmc->max_phys_segs = 64;
- mmc->max_sectors = 64; /* default 1 << (PAGE_CACHE_SHIFT - 9) */
mmc->max_seg_size = 64*512; /* default PAGE_CACHE_SIZE */
+ mmc->max_req_size = 64*512; /* default PAGE_CACHE_SIZE */
+ mmc->max_blk_size = 2048;
+ mmc->max_blk_count = 65535;
host = mmc_priv(mmc);
host->mmc = mmc;
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 6f2a282e2b9..5046a166134 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -103,11 +103,16 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
mmc_hostname(host), mrq->cmd->opcode,
mrq->cmd->arg, mrq->cmd->flags);
- WARN_ON(host->card_busy == NULL);
+ WARN_ON(!host->claimed);
mrq->cmd->error = 0;
mrq->cmd->mrq = mrq;
if (mrq->data) {
+ BUG_ON(mrq->data->blksz > host->max_blk_size);
+ BUG_ON(mrq->data->blocks > host->max_blk_count);
+ BUG_ON(mrq->data->blocks * mrq->data->blksz >
+ host->max_req_size);
+
mrq->cmd->data = mrq->data;
mrq->data->error = 0;
mrq->data->mrq = mrq;
@@ -157,7 +162,7 @@ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries
{
struct mmc_request mrq;
- BUG_ON(host->card_busy == NULL);
+ BUG_ON(!host->claimed);
memset(&mrq, 0, sizeof(struct mmc_request));
@@ -195,7 +200,7 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, unsigned int rca,
int i, err;
- BUG_ON(host->card_busy == NULL);
+ BUG_ON(!host->claimed);
BUG_ON(retries < 0);
err = MMC_ERR_INVALID;
@@ -289,7 +294,10 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card,
else
limit_us = 100000;
- if (timeout_us > limit_us) {
+ /*
+ * SDHC cards always use these fixed values.
+ */
+ if (timeout_us > limit_us || mmc_card_blockaddr(card)) {
data->timeout_ns = limit_us * 1000;
data->timeout_clks = 0;
}
@@ -320,14 +328,14 @@ int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card)
spin_lock_irqsave(&host->lock, flags);
while (1) {
set_current_state(TASK_UNINTERRUPTIBLE);
- if (host->card_busy == NULL)
+ if (!host->claimed)
break;
spin_unlock_irqrestore(&host->lock, flags);
schedule();
spin_lock_irqsave(&host->lock, flags);
}
set_current_state(TASK_RUNNING);
- host->card_busy = card;
+ host->claimed = 1;
spin_unlock_irqrestore(&host->lock, flags);
remove_wait_queue(&host->wq, &wait);
@@ -353,10 +361,10 @@ void mmc_release_host(struct mmc_host *host)
{
unsigned long flags;
- BUG_ON(host->card_busy == NULL);
+ BUG_ON(!host->claimed);
spin_lock_irqsave(&host->lock, flags);
- host->card_busy = NULL;
+ host->claimed = 0;
spin_unlock_irqrestore(&host->lock, flags);
wake_up(&host->wq);
@@ -372,7 +380,7 @@ static inline void mmc_set_ios(struct mmc_host *host)
mmc_hostname(host), ios->clock, ios->bus_mode,
ios->power_mode, ios->chip_select, ios->vdd,
ios->bus_width);
-
+
host->ops->set_ios(host, ios);
}
@@ -381,7 +389,7 @@ static int mmc_select_card(struct mmc_host *host, struct mmc_card *card)
int err;
struct mmc_command cmd;
- BUG_ON(host->card_busy == NULL);
+ BUG_ON(!host->claimed);
if (host->card_selected == card)
return MMC_ERR_NONE;
@@ -588,34 +596,65 @@ static void mmc_decode_csd(struct mmc_card *card)
if (mmc_card_sd(card)) {
csd_struct = UNSTUFF_BITS(resp, 126, 2);
- if (csd_struct != 0) {
+
+ switch (csd_struct) {
+ case 0:
+ m = UNSTUFF_BITS(resp, 115, 4);
+ e = UNSTUFF_BITS(resp, 112, 3);
+ csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
+ csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100;
+
+ m = UNSTUFF_BITS(resp, 99, 4);
+ e = UNSTUFF_BITS(resp, 96, 3);
+ csd->max_dtr = tran_exp[e] * tran_mant[m];
+ csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
+
+ e = UNSTUFF_BITS(resp, 47, 3);
+ m = UNSTUFF_BITS(resp, 62, 12);
+ csd->capacity = (1 + m) << (e + 2);
+
+ csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
+ csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
+ csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
+ csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
+ csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
+ csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
+ csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
+ break;
+ case 1:
+ /*
+ * This is a block-addressed SDHC card. Most
+ * interesting fields are unused and have fixed
+ * values. To avoid getting tripped by buggy cards,
+ * we assume those fixed values ourselves.
+ */
+ mmc_card_set_blockaddr(card);
+
+ csd->tacc_ns = 0; /* Unused */
+ csd->tacc_clks = 0; /* Unused */
+
+ m = UNSTUFF_BITS(resp, 99, 4);
+ e = UNSTUFF_BITS(resp, 96, 3);
+ csd->max_dtr = tran_exp[e] * tran_mant[m];
+ csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
+
+ m = UNSTUFF_BITS(resp, 48, 22);
+ csd->capacity = (1 + m) << 10;
+
+ csd->read_blkbits = 9;
+ csd->read_partial = 0;
+ csd->write_misalign = 0;
+ csd->read_misalign = 0;
+ csd->r2w_factor = 4; /* Unused */
+ csd->write_blkbits = 9;
+ csd->write_partial = 0;
+ break;
+ default:
printk("%s: unrecognised CSD structure version %d\n",
mmc_hostname(card->host), csd_struct);
mmc_card_set_bad(card);
return;
}
-
- m = UNSTUFF_BITS(resp, 115, 4);
- e = UNSTUFF_BITS(resp, 112, 3);
- csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
- csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100;
-
- m = UNSTUFF_BITS(resp, 99, 4);
- e = UNSTUFF_BITS(resp, 96, 3);
- csd->max_dtr = tran_exp[e] * tran_mant[m];
- csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
-
- e = UNSTUFF_BITS(resp, 47, 3);
- m = UNSTUFF_BITS(resp, 62, 12);
- csd->capacity = (1 + m) << (e + 2);
-
- csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
- csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
- csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
- csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
- csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
- csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
- csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
} else {
/*
* We only understand CSD structure v1.1 and v1.2.
@@ -848,6 +887,41 @@ static int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
return err;
}
+static int mmc_send_if_cond(struct mmc_host *host, u32 ocr, int *rsd2)
+{
+ struct mmc_command cmd;
+ int err, sd2;
+ static const u8 test_pattern = 0xAA;
+
+ /*
+ * To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND
+ * before SD_APP_OP_COND. This command will harmlessly fail for
+ * SD 1.0 cards.
+ */
+ cmd.opcode = SD_SEND_IF_COND;
+ cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern;
+ cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR;
+
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+ if (err == MMC_ERR_NONE) {
+ if ((cmd.resp[0] & 0xFF) == test_pattern) {
+ sd2 = 1;
+ } else {
+ sd2 = 0;
+ err = MMC_ERR_FAILED;
+ }
+ } else {
+ /*
+ * Treat errors as SD 1.0 card.
+ */
+ sd2 = 0;
+ err = MMC_ERR_NONE;
+ }
+ if (rsd2)
+ *rsd2 = sd2;
+ return err;
+}
+
/*
* Discover cards by requesting their CID. If this command
* times out, it is not an error; there are no further cards
@@ -1018,7 +1092,8 @@ static void mmc_process_ext_csds(struct mmc_host *host)
mmc_wait_for_req(host, &mrq);
if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
- mmc_card_set_dead(card);
+ printk("%s: unable to read EXT_CSD, performance "
+ "might suffer.\n", mmc_hostname(card->host));
continue;
}
@@ -1034,7 +1109,6 @@ static void mmc_process_ext_csds(struct mmc_host *host)
printk("%s: card is mmc v4 but doesn't support "
"any high-speed modes.\n",
mmc_hostname(card->host));
- mmc_card_set_bad(card);
continue;
}
@@ -1215,7 +1289,9 @@ static void mmc_read_switch_caps(struct mmc_host *host)
mmc_wait_for_req(host, &mrq);
if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
- mmc_card_set_dead(card);
+ printk("%s: unable to read switch capabilities, "
+ "performance might suffer.\n",
+ mmc_hostname(card->host));
continue;
}
@@ -1247,12 +1323,8 @@ static void mmc_read_switch_caps(struct mmc_host *host)
mmc_wait_for_req(host, &mrq);
- if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
- mmc_card_set_dead(card);
- continue;
- }
-
- if ((status[16] & 0xF) != 1) {
+ if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE ||
+ (status[16] & 0xF) != 1) {
printk(KERN_WARNING "%s: Problem switching card "
"into high-speed mode!\n",
mmc_hostname(host));
@@ -1334,6 +1406,10 @@ static void mmc_setup(struct mmc_host *host)
mmc_power_up(host);
mmc_idle_cards(host);
+ err = mmc_send_if_cond(host, host->ocr_avail, NULL);
+ if (err != MMC_ERR_NONE) {
+ return;
+ }
err = mmc_send_app_op_cond(host, 0, &ocr);
/*
@@ -1386,10 +1462,21 @@ static void mmc_setup(struct mmc_host *host)
* all get the idea that they should be ready for CMD2.
* (My SanDisk card seems to need this.)
*/
- if (host->mode == MMC_MODE_SD)
- mmc_send_app_op_cond(host, host->ocr, NULL);
- else
+ if (host->mode == MMC_MODE_SD) {
+ int err, sd2;
+ err = mmc_send_if_cond(host, host->ocr, &sd2);
+ if (err == MMC_ERR_NONE) {
+ /*
+ * If SD_SEND_IF_COND indicates an SD 2.0
+ * compliant card and we should set bit 30
+ * of the ocr to indicate that we can handle
+ * block-addressed SDHC cards.
+ */
+ mmc_send_app_op_cond(host, host->ocr | (sd2 << 30), NULL);
+ }
+ } else {
mmc_send_op_cond(host, host->ocr, NULL);
+ }
mmc_discover_cards(host);
@@ -1519,8 +1606,11 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
*/
host->max_hw_segs = 1;
host->max_phys_segs = 1;
- host->max_sectors = 1 << (PAGE_CACHE_SHIFT - 9);
host->max_seg_size = PAGE_CACHE_SIZE;
+
+ host->max_req_size = PAGE_CACHE_SIZE;
+ host->max_blk_size = 512;
+ host->max_blk_count = PAGE_CACHE_SIZE / 512;
}
return host;
diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c
index 87713572293..05ba8ace70e 100644
--- a/drivers/mmc/mmc_block.c
+++ b/drivers/mmc/mmc_block.c
@@ -237,13 +237,17 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
brq.mrq.cmd = &brq.cmd;
brq.mrq.data = &brq.data;
- brq.cmd.arg = req->sector << 9;
+ brq.cmd.arg = req->sector;
+ if (!mmc_card_blockaddr(card))
+ brq.cmd.arg <<= 9;
brq.cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
brq.data.blksz = 1 << md->block_bits;
- brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
brq.stop.opcode = MMC_STOP_TRANSMISSION;
brq.stop.arg = 0;
brq.stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
+ brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
+ if (brq.data.blocks > card->host->max_blk_count)
+ brq.data.blocks = card->host->max_blk_count;
mmc_set_data_timeout(&brq.data, card, rq_data_dir(req) != READ);
@@ -375,9 +379,10 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
spin_unlock_irq(&md->lock);
}
+flush_queue:
+
mmc_card_release_host(card);
-flush_queue:
spin_lock_irq(&md->lock);
while (ret) {
ret = end_that_request_chunk(req, 0,
@@ -494,6 +499,10 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
struct mmc_command cmd;
int err;
+ /* Block-addressed cards ignore MMC_SET_BLOCKLEN. */
+ if (mmc_card_blockaddr(card))
+ return 0;
+
mmc_card_claim_host(card);
cmd.opcode = MMC_SET_BLOCKLEN;
cmd.arg = 1 << md->block_bits;
diff --git a/drivers/mmc/mmc_queue.c b/drivers/mmc/mmc_queue.c
index 3e35a43819f..c27e42645cd 100644
--- a/drivers/mmc/mmc_queue.c
+++ b/drivers/mmc/mmc_queue.c
@@ -147,7 +147,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
blk_queue_prep_rq(mq->queue, mmc_prep_request);
blk_queue_bounce_limit(mq->queue, limit);
- blk_queue_max_sectors(mq->queue, host->max_sectors);
+ blk_queue_max_sectors(mq->queue, host->max_req_size / 512);
blk_queue_max_phys_segments(mq->queue, host->max_phys_segs);
blk_queue_max_hw_segments(mq->queue, host->max_hw_segs);
blk_queue_max_segment_size(mq->queue, host->max_seg_size);
diff --git a/drivers/mmc/mmc_sysfs.c b/drivers/mmc/mmc_sysfs.c
index e334acd045b..d32698b02d7 100644
--- a/drivers/mmc/mmc_sysfs.c
+++ b/drivers/mmc/mmc_sysfs.c
@@ -199,7 +199,7 @@ void mmc_init_card(struct mmc_card *card, struct mmc_host *host)
memset(card, 0, sizeof(struct mmc_card));
card->host = host;
device_initialize(&card->dev);
- card->dev.parent = mmc_dev(host);
+ card->dev.parent = mmc_classdev(host);
card->dev.bus = &mmc_bus_type;
card->dev.release = mmc_release_card;
}
diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c
index ccfe6561be2..5941dd951e8 100644
--- a/drivers/mmc/mmci.c
+++ b/drivers/mmc/mmci.c
@@ -524,15 +524,24 @@ static int mmci_probe(struct amba_device *dev, void *id)
/*
* Since we only have a 16-bit data length register, we must
* ensure that we don't exceed 2^16-1 bytes in a single request.
- * Choose 64 (512-byte) sectors as the limit.
*/
- mmc->max_sectors = 64;
+ mmc->max_req_size = 65535;
/*
* Set the maximum segment size. Since we aren't doing DMA
* (yet) we are only limited by the data length register.
*/
- mmc->max_seg_size = mmc->max_sectors << 9;
+ mmc->max_seg_size = mmc->max_req_size;
+
+ /*
+ * Block size can be up to 2048 bytes, but must be a power of two.
+ */
+ mmc->max_blk_size = 2048;
+
+ /*
+ * No limit on the number of blocks transferred.
+ */
+ mmc->max_blk_count = mmc->max_req_size;
spin_lock_init(&host->lock);
diff --git a/drivers/mmc/omap.c b/drivers/mmc/omap.c
index d30540b2761..1e96a2f6502 100644
--- a/drivers/mmc/omap.c
+++ b/drivers/mmc/omap.c
@@ -1099,8 +1099,10 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
*/
mmc->max_phys_segs = 32;
mmc->max_hw_segs = 32;
- mmc->max_sectors = 256; /* NBLK max 11-bits, OMAP also limited by DMA */
- mmc->max_seg_size = mmc->max_sectors * 512;
+ mmc->max_blk_size = 2048; /* BLEN is 11 bits (+1) */
+ mmc->max_blk_count = 2048; /* NBLK is 11 bits (+1) */
+ mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
+ mmc->max_seg_size = mmc->max_req_size;
if (host->power_pin >= 0) {
if ((ret = omap_request_gpio(host->power_pin)) != 0) {
diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c
index 6073d998b11..9774fc68b61 100644
--- a/drivers/mmc/pxamci.c
+++ b/drivers/mmc/pxamci.c
@@ -450,6 +450,16 @@ static int pxamci_probe(struct platform_device *pdev)
*/
mmc->max_seg_size = PAGE_SIZE;
+ /*
+ * Block length register is 10 bits.
+ */
+ mmc->max_blk_size = 1023;
+
+ /*
+ * Block count register is 16 bits.
+ */
+ mmc->max_blk_count = 65535;
+
host = mmc_priv(mmc);
host->mmc = mmc;
host->dma = -1;
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index c2d13d7e991..4bf1fea5e2c 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -37,6 +37,7 @@ static unsigned int debug_quirks = 0;
#define SDHCI_QUIRK_FORCE_DMA (1<<1)
/* Controller doesn't like some resets when there is no card inserted. */
#define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<2)
+#define SDHCI_QUIRK_SINGLE_POWER_WRITE (1<<3)
static const struct pci_device_id pci_ids[] __devinitdata = {
{
@@ -65,6 +66,14 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
.driver_data = SDHCI_QUIRK_FORCE_DMA,
},
+ {
+ .vendor = PCI_VENDOR_ID_ENE,
+ .device = PCI_DEVICE_ID_ENE_CB712_SD,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = SDHCI_QUIRK_SINGLE_POWER_WRITE,
+ },
+
{ /* Generic SD host controller */
PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
},
@@ -197,15 +206,9 @@ static void sdhci_deactivate_led(struct sdhci_host *host)
* *
\*****************************************************************************/
-static inline char* sdhci_kmap_sg(struct sdhci_host* host)
+static inline char* sdhci_sg_to_buffer(struct sdhci_host* host)
{
- host->mapped_sg = kmap_atomic(host->cur_sg->page, KM_BIO_SRC_IRQ);
- return host->mapped_sg + host->cur_sg->offset;
-}
-
-static inline void sdhci_kunmap_sg(struct sdhci_host* host)
-{
- kunmap_atomic(host->mapped_sg, KM_BIO_SRC_IRQ);
+ return page_address(host->cur_sg->page) + host->cur_sg->offset;
}
static inline int sdhci_next_sg(struct sdhci_host* host)
@@ -240,7 +243,7 @@ static void sdhci_read_block_pio(struct sdhci_host *host)
chunk_remain = 0;
data = 0;
- buffer = sdhci_kmap_sg(host) + host->offset;
+ buffer = sdhci_sg_to_buffer(host) + host->offset;
while (blksize) {
if (chunk_remain == 0) {
@@ -264,16 +267,13 @@ static void sdhci_read_block_pio(struct sdhci_host *host)
}
if (host->remain == 0) {
- sdhci_kunmap_sg(host);
if (sdhci_next_sg(host) == 0) {
BUG_ON(blksize != 0);
return;
}
- buffer = sdhci_kmap_sg(host);
+ buffer = sdhci_sg_to_buffer(host);
}
}
-
- sdhci_kunmap_sg(host);
}
static void sdhci_write_block_pio(struct sdhci_host *host)
@@ -290,7 +290,7 @@ static void sdhci_write_block_pio(struct sdhci_host *host)
data = 0;
bytes = 0;
- buffer = sdhci_kmap_sg(host) + host->offset;
+ buffer = sdhci_sg_to_buffer(host) + host->offset;
while (blksize) {
size = min(host->size, host->remain);
@@ -314,16 +314,13 @@ static void sdhci_write_block_pio(struct sdhci_host *host)
}
if (host->remain == 0) {
- sdhci_kunmap_sg(host);
if (sdhci_next_sg(host) == 0) {
BUG_ON(blksize != 0);
return;
}
- buffer = sdhci_kmap_sg(host);
+ buffer = sdhci_sg_to_buffer(host);
}
}
-
- sdhci_kunmap_sg(host);
}
static void sdhci_transfer_pio(struct sdhci_host *host)
@@ -372,7 +369,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
/* Sanity checks */
BUG_ON(data->blksz * data->blocks > 524288);
- BUG_ON(data->blksz > host->max_block);
+ BUG_ON(data->blksz > host->mmc->max_blk_size);
BUG_ON(data->blocks > 65535);
/* timeout in us */
@@ -674,10 +671,17 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
if (host->power == power)
return;
- writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
-
- if (power == (unsigned short)-1)
+ if (power == (unsigned short)-1) {
+ writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
goto out;
+ }
+
+ /*
+ * Spec says that we should clear the power reg before setting
+ * a new value. Some controllers don't seem to like this though.
+ */
+ if (!(host->chip->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
+ writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
pwr = SDHCI_POWER_ON;
@@ -1109,7 +1113,9 @@ static int sdhci_resume (struct pci_dev *pdev)
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
- pci_enable_device(pdev);
+ ret = pci_enable_device(pdev);
+ if (ret)
+ return ret;
for (i = 0;i < chip->num_slots;i++) {
if (!chip->hosts[i])
@@ -1274,15 +1280,6 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
if (caps & SDHCI_TIMEOUT_CLK_UNIT)
host->timeout_clk *= 1000;
- host->max_block = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT;
- if (host->max_block >= 3) {
- printk(KERN_ERR "%s: Invalid maximum block size.\n",
- host->slot_descr);
- ret = -ENODEV;
- goto unmap;
- }
- host->max_block = 512 << host->max_block;
-
/*
* Set host parameters.
*/
@@ -1294,9 +1291,9 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
mmc->ocr_avail = 0;
if (caps & SDHCI_CAN_VDD_330)
mmc->ocr_avail |= MMC_VDD_32_33|MMC_VDD_33_34;
- else if (caps & SDHCI_CAN_VDD_300)
+ if (caps & SDHCI_CAN_VDD_300)
mmc->ocr_avail |= MMC_VDD_29_30|MMC_VDD_30_31;
- else if (caps & SDHCI_CAN_VDD_180)
+ if (caps & SDHCI_CAN_VDD_180)
mmc->ocr_avail |= MMC_VDD_17_18|MMC_VDD_18_19;
if ((host->max_clk > 25000000) && !(caps & SDHCI_CAN_DO_HISPD)) {
@@ -1326,15 +1323,33 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
/*
* Maximum number of sectors in one transfer. Limited by DMA boundary
- * size (512KiB), which means (512 KiB/512=) 1024 entries.
+ * size (512KiB).
*/
- mmc->max_sectors = 1024;
+ mmc->max_req_size = 524288;
/*
* Maximum segment size. Could be one segment with the maximum number
- * of sectors.
+ * of bytes.
+ */
+ mmc->max_seg_size = mmc->max_req_size;
+
+ /*
+ * Maximum block size. This varies from controller to controller and
+ * is specified in the capabilities register.
+ */
+ mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT;
+ if (mmc->max_blk_size >= 3) {
+ printk(KERN_ERR "%s: Invalid maximum block size.\n",
+ host->slot_descr);
+ ret = -ENODEV;
+ goto unmap;
+ }
+ mmc->max_blk_size = 512 << mmc->max_blk_size;
+
+ /*
+ * Maximum block count.
*/
- mmc->max_seg_size = mmc->max_sectors * 512;
+ mmc->max_blk_count = 65535;
/*
* Init tasklets.
diff --git a/drivers/mmc/sdhci.h b/drivers/mmc/sdhci.h
index f9d1a0a6f03..e324f0a623d 100644
--- a/drivers/mmc/sdhci.h
+++ b/drivers/mmc/sdhci.h
@@ -174,7 +174,6 @@ struct sdhci_host {
unsigned int max_clk; /* Max possible freq (MHz) */
unsigned int timeout_clk; /* Timeout freq (KHz) */
- unsigned int max_block; /* Max block size (bytes) */
unsigned int clock; /* Current clock (MHz) */
unsigned short power; /* Current voltage */
@@ -184,7 +183,6 @@ struct sdhci_host {
struct mmc_data *data; /* Current data request */
struct scatterlist *cur_sg; /* We're working on this */
- char *mapped_sg; /* This is where it's mapped */
int num_sg; /* Entries left */
int offset; /* Offset into current sg */
int remain; /* Bytes left in current */
diff --git a/drivers/mmc/tifm_sd.c b/drivers/mmc/tifm_sd.c
index fa4a52886b9..e65f8a0a934 100644
--- a/drivers/mmc/tifm_sd.c
+++ b/drivers/mmc/tifm_sd.c
@@ -17,7 +17,7 @@
#include <asm/io.h>
#define DRIVER_NAME "tifm_sd"
-#define DRIVER_VERSION "0.6"
+#define DRIVER_VERSION "0.7"
static int no_dma = 0;
static int fixed_timeout = 0;
@@ -79,7 +79,6 @@ typedef enum {
enum {
FIFO_RDY = 0x0001, /* hardware dependent value */
- HOST_REG = 0x0002,
EJECT = 0x0004,
EJECT_DONE = 0x0008,
CARD_BUSY = 0x0010,
@@ -95,46 +94,53 @@ struct tifm_sd {
card_state_t state;
unsigned int clk_freq;
unsigned int clk_div;
- unsigned long timeout_jiffies; // software timeout - 2 sec
+ unsigned long timeout_jiffies;
+ struct tasklet_struct finish_tasklet;
+ struct timer_list timer;
struct mmc_request *req;
- struct work_struct cmd_handler;
- struct delayed_work abort_handler;
- wait_queue_head_t can_eject;
+ wait_queue_head_t notify;
size_t written_blocks;
- char *buffer;
size_t buffer_size;
size_t buffer_pos;
};
+static char* tifm_sd_data_buffer(struct mmc_data *data)
+{
+ return page_address(data->sg->page) + data->sg->offset;
+}
+
static int tifm_sd_transfer_data(struct tifm_dev *sock, struct tifm_sd *host,
- unsigned int host_status)
+ unsigned int host_status)
{
struct mmc_command *cmd = host->req->cmd;
unsigned int t_val = 0, cnt = 0;
+ char *buffer;
if (host_status & TIFM_MMCSD_BRS) {
/* in non-dma rx mode BRS fires when fifo is still not empty */
- if (host->buffer && (cmd->data->flags & MMC_DATA_READ)) {
+ if (no_dma && (cmd->data->flags & MMC_DATA_READ)) {
+ buffer = tifm_sd_data_buffer(host->req->data);
while (host->buffer_size > host->buffer_pos) {
t_val = readl(sock->addr + SOCK_MMCSD_DATA);
- host->buffer[host->buffer_pos++] = t_val & 0xff;
- host->buffer[host->buffer_pos++] =
+ buffer[host->buffer_pos++] = t_val & 0xff;
+ buffer[host->buffer_pos++] =
(t_val >> 8) & 0xff;
}
}
return 1;
- } else if (host->buffer) {
+ } else if (no_dma) {
+ buffer = tifm_sd_data_buffer(host->req->data);
if ((cmd->data->flags & MMC_DATA_READ) &&
(host_status & TIFM_MMCSD_AF)) {
for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) {
t_val = readl(sock->addr + SOCK_MMCSD_DATA);
if (host->buffer_size > host->buffer_pos) {
- host->buffer[host->buffer_pos++] =
+ buffer[host->buffer_pos++] =
t_val & 0xff;
- host->buffer[host->buffer_pos++] =
+ buffer[host->buffer_pos++] =
(t_val >> 8) & 0xff;
}
}
@@ -142,11 +148,12 @@ static int tifm_sd_transfer_data(struct tifm_dev *sock, struct tifm_sd *host,
&& (host_status & TIFM_MMCSD_AE)) {
for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) {
if (host->buffer_size > host->buffer_pos) {
- t_val = host->buffer[host->buffer_pos++] & 0x00ff;
- t_val |= ((host->buffer[host->buffer_pos++]) << 8)
- & 0xff00;
+ t_val = buffer[host->buffer_pos++]
+ & 0x00ff;
+ t_val |= ((buffer[host->buffer_pos++])
+ << 8) & 0xff00;
writel(t_val,
- sock->addr + SOCK_MMCSD_DATA);
+ sock->addr + SOCK_MMCSD_DATA);
}
}
}
@@ -206,7 +213,7 @@ static void tifm_sd_exec(struct tifm_sd *host, struct mmc_command *cmd)
cmd_mask |= TIFM_MMCSD_READ;
dev_dbg(&sock->dev, "executing opcode 0x%x, arg: 0x%x, mask: 0x%x\n",
- cmd->opcode, cmd->arg, cmd_mask);
+ cmd->opcode, cmd->arg, cmd_mask);
writel((cmd->arg >> 16) & 0xffff, sock->addr + SOCK_MMCSD_ARG_HIGH);
writel(cmd->arg & 0xffff, sock->addr + SOCK_MMCSD_ARG_LOW);
@@ -239,65 +246,78 @@ change_state:
tifm_sd_fetch_resp(cmd, sock);
if (cmd->data) {
host->state = BRS;
- } else
+ } else {
host->state = READY;
+ }
goto change_state;
}
break;
case BRS:
if (tifm_sd_transfer_data(sock, host, host_status)) {
- if (!host->req->stop) {
- if (cmd->data->flags & MMC_DATA_WRITE) {
- host->state = CARD;
+ if (cmd->data->flags & MMC_DATA_WRITE) {
+ host->state = CARD;
+ } else {
+ if (no_dma) {
+ if (host->req->stop) {
+ tifm_sd_exec(host, host->req->stop);
+ host->state = SCMD;
+ } else {
+ host->state = READY;
+ }
} else {
- host->state =
- host->buffer ? READY : FIFO;
+ host->state = FIFO;
}
- goto change_state;
}
- tifm_sd_exec(host, host->req->stop);
- host->state = SCMD;
+ goto change_state;
}
break;
case SCMD:
if (host_status & TIFM_MMCSD_EOC) {
tifm_sd_fetch_resp(host->req->stop, sock);
- if (cmd->error) {
- host->state = READY;
- } else if (cmd->data->flags & MMC_DATA_WRITE) {
- host->state = CARD;
- } else {
- host->state = host->buffer ? READY : FIFO;
- }
+ host->state = READY;
goto change_state;
}
break;
case CARD:
+ dev_dbg(&sock->dev, "waiting for CARD, have %zd blocks\n",
+ host->written_blocks);
if (!(host->flags & CARD_BUSY)
&& (host->written_blocks == cmd->data->blocks)) {
- host->state = host->buffer ? READY : FIFO;
+ if (no_dma) {
+ if (host->req->stop) {
+ tifm_sd_exec(host, host->req->stop);
+ host->state = SCMD;
+ } else {
+ host->state = READY;
+ }
+ } else {
+ host->state = FIFO;
+ }
goto change_state;
}
break;
case FIFO:
if (host->flags & FIFO_RDY) {
- host->state = READY;
host->flags &= ~FIFO_RDY;
+ if (host->req->stop) {
+ tifm_sd_exec(host, host->req->stop);
+ host->state = SCMD;
+ } else {
+ host->state = READY;
+ }
goto change_state;
}
break;
case READY:
- queue_work(sock->wq, &host->cmd_handler);
+ tasklet_schedule(&host->finish_tasklet);
return;
}
- queue_delayed_work(sock->wq, &host->abort_handler,
- host->timeout_jiffies);
}
/* Called from interrupt handler */
-static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
- unsigned int sock_irq_status)
+static void tifm_sd_signal_irq(struct tifm_dev *sock,
+ unsigned int sock_irq_status)
{
struct tifm_sd *host;
unsigned int host_status = 0, fifo_status = 0;
@@ -305,7 +325,6 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
spin_lock(&sock->lock);
host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock));
- cancel_delayed_work(&host->abort_handler);
if (sock_irq_status & FIFO_EVENT) {
fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS);
@@ -318,19 +337,17 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
host_status = readl(sock->addr + SOCK_MMCSD_STATUS);
writel(host_status, sock->addr + SOCK_MMCSD_STATUS);
- if (!(host->flags & HOST_REG))
- queue_work(sock->wq, &host->cmd_handler);
if (!host->req)
goto done;
if (host_status & TIFM_MMCSD_ERRMASK) {
if (host_status & TIFM_MMCSD_CERR)
error_code = MMC_ERR_FAILED;
- else if (host_status &
- (TIFM_MMCSD_CTO | TIFM_MMCSD_DTO))
+ else if (host_status
+ & (TIFM_MMCSD_CTO | TIFM_MMCSD_DTO))
error_code = MMC_ERR_TIMEOUT;
- else if (host_status &
- (TIFM_MMCSD_CCRC | TIFM_MMCSD_DCRC))
+ else if (host_status
+ & (TIFM_MMCSD_CCRC | TIFM_MMCSD_DCRC))
error_code = MMC_ERR_BADCRC;
writel(TIFM_FIFO_INT_SETALL,
@@ -340,12 +357,11 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
if (host->req->stop) {
if (host->state == SCMD) {
host->req->stop->error = error_code;
- } else if(host->state == BRS) {
+ } else if (host->state == BRS
+ || host->state == CARD
+ || host->state == FIFO) {
host->req->cmd->error = error_code;
tifm_sd_exec(host, host->req->stop);
- queue_delayed_work(sock->wq,
- &host->abort_handler,
- host->timeout_jiffies);
host->state = SCMD;
goto done;
} else {
@@ -359,8 +375,8 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
if (host_status & TIFM_MMCSD_CB)
host->flags |= CARD_BUSY;
- if ((host_status & TIFM_MMCSD_EOFB) &&
- (host->flags & CARD_BUSY)) {
+ if ((host_status & TIFM_MMCSD_EOFB)
+ && (host->flags & CARD_BUSY)) {
host->written_blocks++;
host->flags &= ~CARD_BUSY;
}
@@ -370,22 +386,22 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
tifm_sd_process_cmd(sock, host, host_status);
done:
dev_dbg(&sock->dev, "host_status %x, fifo_status %x\n",
- host_status, fifo_status);
+ host_status, fifo_status);
spin_unlock(&sock->lock);
- return sock_irq_status;
}
-static void tifm_sd_prepare_data(struct tifm_sd *card, struct mmc_command *cmd)
+static void tifm_sd_prepare_data(struct tifm_sd *host, struct mmc_command *cmd)
{
- struct tifm_dev *sock = card->dev;
+ struct tifm_dev *sock = host->dev;
unsigned int dest_cnt;
/* DMA style IO */
-
+ dev_dbg(&sock->dev, "setting dma for %d blocks\n",
+ cmd->data->blocks);
writel(TIFM_FIFO_INT_SETALL,
- sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
+ sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
writel(ilog2(cmd->data->blksz) - 2,
- sock->addr + SOCK_FIFO_PAGE_SIZE);
+ sock->addr + SOCK_FIFO_PAGE_SIZE);
writel(TIFM_FIFO_ENABLE, sock->addr + SOCK_FIFO_CONTROL);
writel(TIFM_FIFO_INTMASK, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
@@ -399,7 +415,7 @@ static void tifm_sd_prepare_data(struct tifm_sd *card, struct mmc_command *cmd)
if (cmd->data->flags & MMC_DATA_WRITE) {
writel(TIFM_MMCSD_TXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
writel(dest_cnt | TIFM_DMA_TX | TIFM_DMA_EN,
- sock->addr + SOCK_DMA_CONTROL);
+ sock->addr + SOCK_DMA_CONTROL);
} else {
writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
writel(dest_cnt | TIFM_DMA_EN, sock->addr + SOCK_DMA_CONTROL);
@@ -407,7 +423,7 @@ static void tifm_sd_prepare_data(struct tifm_sd *card, struct mmc_command *cmd)
}
static void tifm_sd_set_data_timeout(struct tifm_sd *host,
- struct mmc_data *data)
+ struct mmc_data *data)
{
struct tifm_dev *sock = host->dev;
unsigned int data_timeout = data->timeout_clks;
@@ -416,22 +432,21 @@ static void tifm_sd_set_data_timeout(struct tifm_sd *host,
return;
data_timeout += data->timeout_ns /
- ((1000000000 / host->clk_freq) * host->clk_div);
- data_timeout *= 10; // call it fudge factor for now
+ ((1000000000UL / host->clk_freq) * host->clk_div);
if (data_timeout < 0xffff) {
- writel((~TIFM_MMCSD_DPE) &
- readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
- sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO);
+ writel((~TIFM_MMCSD_DPE)
+ & readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
+ sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
} else {
- writel(TIFM_MMCSD_DPE |
- readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
- sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
data_timeout = (data_timeout >> 10) + 1;
- if(data_timeout > 0xffff)
+ if (data_timeout > 0xffff)
data_timeout = 0; /* set to unlimited */
writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO);
+ writel(TIFM_MMCSD_DPE
+ | readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
+ sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
}
}
@@ -474,11 +489,10 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq)
}
host->req = mrq;
+ mod_timer(&host->timer, jiffies + host->timeout_jiffies);
host->state = CMD;
- queue_delayed_work(sock->wq, &host->abort_handler,
- host->timeout_jiffies);
writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL),
- sock->addr + SOCK_CONTROL);
+ sock->addr + SOCK_CONTROL);
tifm_sd_exec(host, mrq->cmd);
spin_unlock_irqrestore(&sock->lock, flags);
return;
@@ -493,9 +507,9 @@ err_out:
mmc_request_done(mmc, mrq);
}
-static void tifm_sd_end_cmd(struct work_struct *work)
+static void tifm_sd_end_cmd(unsigned long data)
{
- struct tifm_sd *host = container_of(work, struct tifm_sd, cmd_handler);
+ struct tifm_sd *host = (struct tifm_sd*)data;
struct tifm_dev *sock = host->dev;
struct mmc_host *mmc = tifm_get_drvdata(sock);
struct mmc_request *mrq;
@@ -504,6 +518,7 @@ static void tifm_sd_end_cmd(struct work_struct *work)
spin_lock_irqsave(&sock->lock, flags);
+ del_timer(&host->timer);
mrq = host->req;
host->req = NULL;
host->state = IDLE;
@@ -517,8 +532,8 @@ static void tifm_sd_end_cmd(struct work_struct *work)
r_data = mrq->cmd->data;
if (r_data) {
if (r_data->flags & MMC_DATA_WRITE) {
- r_data->bytes_xfered = host->written_blocks *
- r_data->blksz;
+ r_data->bytes_xfered = host->written_blocks
+ * r_data->blksz;
} else {
r_data->bytes_xfered = r_data->blocks -
readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1;
@@ -532,7 +547,7 @@ static void tifm_sd_end_cmd(struct work_struct *work)
}
writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL),
- sock->addr + SOCK_CONTROL);
+ sock->addr + SOCK_CONTROL);
spin_unlock_irqrestore(&sock->lock, flags);
mmc_request_done(mmc, mrq);
@@ -544,15 +559,6 @@ static void tifm_sd_request_nodma(struct mmc_host *mmc, struct mmc_request *mrq)
struct tifm_dev *sock = host->dev;
unsigned long flags;
struct mmc_data *r_data = mrq->cmd->data;
- char *t_buffer = NULL;
-
- if (r_data) {
- t_buffer = kmap(r_data->sg->page);
- if (!t_buffer) {
- printk(KERN_ERR DRIVER_NAME ": kmap failed\n");
- goto err_out;
- }
- }
spin_lock_irqsave(&sock->lock, flags);
if (host->flags & EJECT) {
@@ -569,15 +575,14 @@ static void tifm_sd_request_nodma(struct mmc_host *mmc, struct mmc_request *mrq)
if (r_data) {
tifm_sd_set_data_timeout(host, r_data);
- host->buffer = t_buffer + r_data->sg->offset;
- host->buffer_size = mrq->cmd->data->blocks *
- mrq->cmd->data->blksz;
+ host->buffer_size = mrq->cmd->data->blocks
+ * mrq->cmd->data->blksz;
- writel(TIFM_MMCSD_BUFINT |
- readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
+ writel(TIFM_MMCSD_BUFINT
+ | readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
sock->addr + SOCK_MMCSD_INT_ENABLE);
- writel(((TIFM_MMCSD_FIFO_SIZE - 1) << 8) |
- (TIFM_MMCSD_FIFO_SIZE - 1),
+ writel(((TIFM_MMCSD_FIFO_SIZE - 1) << 8)
+ | (TIFM_MMCSD_FIFO_SIZE - 1),
sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
host->written_blocks = 0;
@@ -588,26 +593,22 @@ static void tifm_sd_request_nodma(struct mmc_host *mmc, struct mmc_request *mrq)
}
host->req = mrq;
+ mod_timer(&host->timer, jiffies + host->timeout_jiffies);
host->state = CMD;
- queue_delayed_work(sock->wq, &host->abort_handler,
- host->timeout_jiffies);
writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL),
- sock->addr + SOCK_CONTROL);
+ sock->addr + SOCK_CONTROL);
tifm_sd_exec(host, mrq->cmd);
spin_unlock_irqrestore(&sock->lock, flags);
return;
err_out:
- if (t_buffer)
- kunmap(r_data->sg->page);
-
mrq->cmd->error = MMC_ERR_TIMEOUT;
mmc_request_done(mmc, mrq);
}
-static void tifm_sd_end_cmd_nodma(struct work_struct *work)
+static void tifm_sd_end_cmd_nodma(unsigned long data)
{
- struct tifm_sd *host = container_of(work, struct tifm_sd, cmd_handler);
+ struct tifm_sd *host = (struct tifm_sd*)data;
struct tifm_dev *sock = host->dev;
struct mmc_host *mmc = tifm_get_drvdata(sock);
struct mmc_request *mrq;
@@ -616,6 +617,7 @@ static void tifm_sd_end_cmd_nodma(struct work_struct *work)
spin_lock_irqsave(&sock->lock, flags);
+ del_timer(&host->timer);
mrq = host->req;
host->req = NULL;
host->state = IDLE;
@@ -633,8 +635,8 @@ static void tifm_sd_end_cmd_nodma(struct work_struct *work)
sock->addr + SOCK_MMCSD_INT_ENABLE);
if (r_data->flags & MMC_DATA_WRITE) {
- r_data->bytes_xfered = host->written_blocks *
- r_data->blksz;
+ r_data->bytes_xfered = host->written_blocks
+ * r_data->blksz;
} else {
r_data->bytes_xfered = r_data->blocks -
readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1;
@@ -642,29 +644,44 @@ static void tifm_sd_end_cmd_nodma(struct work_struct *work)
r_data->bytes_xfered += r_data->blksz -
readl(sock->addr + SOCK_MMCSD_BLOCK_LEN) + 1;
}
- host->buffer = NULL;
host->buffer_pos = 0;
host->buffer_size = 0;
}
writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL),
- sock->addr + SOCK_CONTROL);
+ sock->addr + SOCK_CONTROL);
spin_unlock_irqrestore(&sock->lock, flags);
- if (r_data)
- kunmap(r_data->sg->page);
-
mmc_request_done(mmc, mrq);
}
-static void tifm_sd_abort(struct work_struct *work)
+static void tifm_sd_terminate(struct tifm_sd *host)
+{
+ struct tifm_dev *sock = host->dev;
+ unsigned long flags;
+
+ writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
+ mmiowb();
+ spin_lock_irqsave(&sock->lock, flags);
+ host->flags |= EJECT;
+ if (host->req) {
+ writel(TIFM_FIFO_INT_SETALL,
+ sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
+ writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
+ tasklet_schedule(&host->finish_tasklet);
+ }
+ spin_unlock_irqrestore(&sock->lock, flags);
+}
+
+static void tifm_sd_abort(unsigned long data)
{
- struct tifm_sd *host =
- container_of(work, struct tifm_sd, abort_handler.work);
+ struct tifm_sd *host = (struct tifm_sd*)data;
printk(KERN_ERR DRIVER_NAME
- ": card failed to respond for a long period of time");
+ ": card failed to respond for a long period of time");
+
+ tifm_sd_terminate(host);
tifm_eject(host->dev);
}
@@ -683,9 +700,9 @@ static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios)
writel(TIFM_MMCSD_4BBUS | readl(sock->addr + SOCK_MMCSD_CONFIG),
sock->addr + SOCK_MMCSD_CONFIG);
} else {
- writel((~TIFM_MMCSD_4BBUS) &
- readl(sock->addr + SOCK_MMCSD_CONFIG),
- sock->addr + SOCK_MMCSD_CONFIG);
+ writel((~TIFM_MMCSD_4BBUS)
+ & readl(sock->addr + SOCK_MMCSD_CONFIG),
+ sock->addr + SOCK_MMCSD_CONFIG);
}
if (ios->clock) {
@@ -704,23 +721,24 @@ static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios)
if ((20000000 / clk_div1) > (24000000 / clk_div2)) {
host->clk_freq = 20000000;
host->clk_div = clk_div1;
- writel((~TIFM_CTRL_FAST_CLK) &
- readl(sock->addr + SOCK_CONTROL),
- sock->addr + SOCK_CONTROL);
+ writel((~TIFM_CTRL_FAST_CLK)
+ & readl(sock->addr + SOCK_CONTROL),
+ sock->addr + SOCK_CONTROL);
} else {
host->clk_freq = 24000000;
host->clk_div = clk_div2;
- writel(TIFM_CTRL_FAST_CLK |
- readl(sock->addr + SOCK_CONTROL),
- sock->addr + SOCK_CONTROL);
+ writel(TIFM_CTRL_FAST_CLK
+ | readl(sock->addr + SOCK_CONTROL),
+ sock->addr + SOCK_CONTROL);
}
} else {
host->clk_div = 0;
}
host->clk_div &= TIFM_MMCSD_CLKMASK;
- writel(host->clk_div | ((~TIFM_MMCSD_CLKMASK) &
- readl(sock->addr + SOCK_MMCSD_CONFIG)),
- sock->addr + SOCK_MMCSD_CONFIG);
+ writel(host->clk_div
+ | ((~TIFM_MMCSD_CLKMASK)
+ & readl(sock->addr + SOCK_MMCSD_CONFIG)),
+ sock->addr + SOCK_MMCSD_CONFIG);
if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
host->flags |= OPENDRAIN;
@@ -734,7 +752,7 @@ static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios)
// allow removal.
if ((host->flags & EJECT) && ios->power_mode == MMC_POWER_OFF) {
host->flags |= EJECT_DONE;
- wake_up_all(&host->can_eject);
+ wake_up_all(&host->notify);
}
spin_unlock_irqrestore(&sock->lock, flags);
@@ -762,20 +780,67 @@ static struct mmc_host_ops tifm_sd_ops = {
.get_ro = tifm_sd_ro
};
-static void tifm_sd_register_host(struct work_struct *work)
+static int tifm_sd_initialize_host(struct tifm_sd *host)
{
- struct tifm_sd *host = container_of(work, struct tifm_sd, cmd_handler);
+ int rc;
+ unsigned int host_status = 0;
struct tifm_dev *sock = host->dev;
- struct mmc_host *mmc = tifm_get_drvdata(sock);
- unsigned long flags;
- spin_lock_irqsave(&sock->lock, flags);
- host->flags |= HOST_REG;
- PREPARE_WORK(&host->cmd_handler,
- no_dma ? tifm_sd_end_cmd_nodma : tifm_sd_end_cmd);
- spin_unlock_irqrestore(&sock->lock, flags);
- dev_dbg(&sock->dev, "adding host\n");
- mmc_add_host(mmc);
+ writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
+ mmiowb();
+ host->clk_div = 61;
+ host->clk_freq = 20000000;
+ writel(TIFM_MMCSD_RESET, sock->addr + SOCK_MMCSD_SYSTEM_CONTROL);
+ writel(host->clk_div | TIFM_MMCSD_POWER,
+ sock->addr + SOCK_MMCSD_CONFIG);
+
+ /* wait up to 0.51 sec for reset */
+ for (rc = 2; rc <= 256; rc <<= 1) {
+ if (1 & readl(sock->addr + SOCK_MMCSD_SYSTEM_STATUS)) {
+ rc = 0;
+ break;
+ }
+ msleep(rc);
+ }
+
+ if (rc) {
+ printk(KERN_ERR DRIVER_NAME
+ ": controller failed to reset\n");
+ return -ENODEV;
+ }
+
+ writel(0, sock->addr + SOCK_MMCSD_NUM_BLOCKS);
+ writel(host->clk_div | TIFM_MMCSD_POWER,
+ sock->addr + SOCK_MMCSD_CONFIG);
+ writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
+
+ // command timeout fixed to 64 clocks for now
+ writel(64, sock->addr + SOCK_MMCSD_COMMAND_TO);
+ writel(TIFM_MMCSD_INAB, sock->addr + SOCK_MMCSD_COMMAND);
+
+ /* INAB should take much less than reset */
+ for (rc = 1; rc <= 16; rc <<= 1) {
+ host_status = readl(sock->addr + SOCK_MMCSD_STATUS);
+ writel(host_status, sock->addr + SOCK_MMCSD_STATUS);
+ if (!(host_status & TIFM_MMCSD_ERRMASK)
+ && (host_status & TIFM_MMCSD_EOC)) {
+ rc = 0;
+ break;
+ }
+ msleep(rc);
+ }
+
+ if (rc) {
+ printk(KERN_ERR DRIVER_NAME
+ ": card not ready - probe failed on initialization\n");
+ return -ENODEV;
+ }
+
+ writel(TIFM_MMCSD_DATAMASK | TIFM_MMCSD_ERRMASK,
+ sock->addr + SOCK_MMCSD_INT_ENABLE);
+ mmiowb();
+
+ return 0;
}
static int tifm_sd_probe(struct tifm_dev *sock)
@@ -784,8 +849,8 @@ static int tifm_sd_probe(struct tifm_dev *sock)
struct tifm_sd *host;
int rc = -EIO;
- if (!(TIFM_SOCK_STATE_OCCUPIED &
- readl(sock->addr + SOCK_PRESENT_STATE))) {
+ if (!(TIFM_SOCK_STATE_OCCUPIED
+ & readl(sock->addr + SOCK_PRESENT_STATE))) {
printk(KERN_WARNING DRIVER_NAME ": card gone, unexpectedly\n");
return rc;
}
@@ -795,109 +860,99 @@ static int tifm_sd_probe(struct tifm_dev *sock)
return -ENOMEM;
host = mmc_priv(mmc);
- host->dev = sock;
- host->clk_div = 61;
- init_waitqueue_head(&host->can_eject);
- INIT_WORK(&host->cmd_handler, tifm_sd_register_host);
- INIT_DELAYED_WORK(&host->abort_handler, tifm_sd_abort);
-
tifm_set_drvdata(sock, mmc);
- sock->signal_irq = tifm_sd_signal_irq;
-
- host->clk_freq = 20000000;
+ host->dev = sock;
host->timeout_jiffies = msecs_to_jiffies(1000);
+ init_waitqueue_head(&host->notify);
+ tasklet_init(&host->finish_tasklet,
+ no_dma ? tifm_sd_end_cmd_nodma : tifm_sd_end_cmd,
+ (unsigned long)host);
+ setup_timer(&host->timer, tifm_sd_abort, (unsigned long)host);
+
tifm_sd_ops.request = no_dma ? tifm_sd_request_nodma : tifm_sd_request;
mmc->ops = &tifm_sd_ops;
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
- mmc->caps = MMC_CAP_4_BIT_DATA;
+ mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE;
mmc->f_min = 20000000 / 60;
mmc->f_max = 24000000;
mmc->max_hw_segs = 1;
mmc->max_phys_segs = 1;
- mmc->max_sectors = 127;
- mmc->max_seg_size = mmc->max_sectors << 11; //2k maximum hw block length
-
- writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
- writel(TIFM_MMCSD_RESET, sock->addr + SOCK_MMCSD_SYSTEM_CONTROL);
- writel(host->clk_div | TIFM_MMCSD_POWER,
- sock->addr + SOCK_MMCSD_CONFIG);
+ // limited by DMA counter - it's safer to stick with
+ // block counter has 11 bits though
+ mmc->max_blk_count = 256;
+ // 2k maximum hw block length
+ mmc->max_blk_size = 2048;
+ mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
+ mmc->max_seg_size = mmc->max_req_size;
+ sock->signal_irq = tifm_sd_signal_irq;
+ rc = tifm_sd_initialize_host(host);
- for (rc = 0; rc < 50; rc++) {
- /* Wait for reset ack */
- if (1 & readl(sock->addr + SOCK_MMCSD_SYSTEM_STATUS)) {
- rc = 0;
- break;
- }
- msleep(10);
- }
+ if (!rc)
+ rc = mmc_add_host(mmc);
+ if (rc)
+ goto out_free_mmc;
- if (rc) {
- printk(KERN_ERR DRIVER_NAME
- ": card not ready - probe failed\n");
- mmc_free_host(mmc);
- return -ENODEV;
- }
+ return 0;
+out_free_mmc:
+ mmc_free_host(mmc);
+ return rc;
+}
- writel(0, sock->addr + SOCK_MMCSD_NUM_BLOCKS);
- writel(host->clk_div | TIFM_MMCSD_POWER,
- sock->addr + SOCK_MMCSD_CONFIG);
- writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
- writel(TIFM_MMCSD_DATAMASK | TIFM_MMCSD_ERRMASK,
- sock->addr + SOCK_MMCSD_INT_ENABLE);
+static void tifm_sd_remove(struct tifm_dev *sock)
+{
+ struct mmc_host *mmc = tifm_get_drvdata(sock);
+ struct tifm_sd *host = mmc_priv(mmc);
- writel(64, sock->addr + SOCK_MMCSD_COMMAND_TO); // command timeout 64 clocks for now
- writel(TIFM_MMCSD_INAB, sock->addr + SOCK_MMCSD_COMMAND);
- writel(host->clk_div | TIFM_MMCSD_POWER,
- sock->addr + SOCK_MMCSD_CONFIG);
+ del_timer_sync(&host->timer);
+ tifm_sd_terminate(host);
+ wait_event_timeout(host->notify, host->flags & EJECT_DONE,
+ host->timeout_jiffies);
+ tasklet_kill(&host->finish_tasklet);
+ mmc_remove_host(mmc);
- queue_delayed_work(sock->wq, &host->abort_handler,
- host->timeout_jiffies);
+ /* The meaning of the bit majority in this constant is unknown. */
+ writel(0xfff8 & readl(sock->addr + SOCK_CONTROL),
+ sock->addr + SOCK_CONTROL);
- return 0;
+ tifm_set_drvdata(sock, NULL);
+ mmc_free_host(mmc);
}
-static int tifm_sd_host_is_down(struct tifm_dev *sock)
+#ifdef CONFIG_PM
+
+static int tifm_sd_suspend(struct tifm_dev *sock, pm_message_t state)
{
struct mmc_host *mmc = tifm_get_drvdata(sock);
- struct tifm_sd *host = mmc_priv(mmc);
- unsigned long flags;
- int rc = 0;
+ int rc;
- spin_lock_irqsave(&sock->lock, flags);
- rc = (host->flags & EJECT_DONE);
- spin_unlock_irqrestore(&sock->lock, flags);
+ rc = mmc_suspend_host(mmc, state);
+ /* The meaning of the bit majority in this constant is unknown. */
+ writel(0xfff8 & readl(sock->addr + SOCK_CONTROL),
+ sock->addr + SOCK_CONTROL);
return rc;
}
-static void tifm_sd_remove(struct tifm_dev *sock)
+static int tifm_sd_resume(struct tifm_dev *sock)
{
struct mmc_host *mmc = tifm_get_drvdata(sock);
struct tifm_sd *host = mmc_priv(mmc);
- unsigned long flags;
- spin_lock_irqsave(&sock->lock, flags);
- host->flags |= EJECT;
- if (host->req)
- queue_work(sock->wq, &host->cmd_handler);
- spin_unlock_irqrestore(&sock->lock, flags);
- wait_event_timeout(host->can_eject, tifm_sd_host_is_down(sock),
- host->timeout_jiffies);
+ if (sock->media_id != FM_SD
+ || tifm_sd_initialize_host(host)) {
+ tifm_eject(sock);
+ return 0;
+ } else {
+ return mmc_resume_host(mmc);
+ }
+}
- if (host->flags & HOST_REG)
- mmc_remove_host(mmc);
+#else
- /* The meaning of the bit majority in this constant is unknown. */
- writel(0xfff8 & readl(sock->addr + SOCK_CONTROL),
- sock->addr + SOCK_CONTROL);
- writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
- writel(TIFM_FIFO_INT_SETALL,
- sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
- writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
+#define tifm_sd_suspend NULL
+#define tifm_sd_resume NULL
- tifm_set_drvdata(sock, NULL);
- mmc_free_host(mmc);
-}
+#endif /* CONFIG_PM */
static tifm_media_id tifm_sd_id_tbl[] = {
FM_SD, 0
@@ -910,7 +965,9 @@ static struct tifm_driver tifm_sd_driver = {
},
.id_table = tifm_sd_id_tbl,
.probe = tifm_sd_probe,
- .remove = tifm_sd_remove
+ .remove = tifm_sd_remove,
+ .suspend = tifm_sd_suspend,
+ .resume = tifm_sd_resume
};
static int __init tifm_sd_init(void)
diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c
index 7a282672f8e..a44d8777ab9 100644
--- a/drivers/mmc/wbsd.c
+++ b/drivers/mmc/wbsd.c
@@ -1,7 +1,7 @@
/*
* linux/drivers/mmc/wbsd.c - Winbond W83L51xD SD/MMC driver
*
- * Copyright (C) 2004-2005 Pierre Ossman, All Rights Reserved.
+ * Copyright (C) 2004-2006 Pierre Ossman, All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -272,16 +272,9 @@ static inline int wbsd_next_sg(struct wbsd_host *host)
return host->num_sg;
}
-static inline char *wbsd_kmap_sg(struct wbsd_host *host)
+static inline char *wbsd_sg_to_buffer(struct wbsd_host *host)
{
- host->mapped_sg = kmap_atomic(host->cur_sg->page, KM_BIO_SRC_IRQ) +
- host->cur_sg->offset;
- return host->mapped_sg;
-}
-
-static inline void wbsd_kunmap_sg(struct wbsd_host *host)
-{
- kunmap_atomic(host->mapped_sg, KM_BIO_SRC_IRQ);
+ return page_address(host->cur_sg->page) + host->cur_sg->offset;
}
static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data)
@@ -302,12 +295,11 @@ static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data)
* we do not transfer too much.
*/
for (i = 0; i < len; i++) {
- sgbuf = kmap_atomic(sg[i].page, KM_BIO_SRC_IRQ) + sg[i].offset;
+ sgbuf = page_address(sg[i].page) + sg[i].offset;
if (size < sg[i].length)
memcpy(dmabuf, sgbuf, size);
else
memcpy(dmabuf, sgbuf, sg[i].length);
- kunmap_atomic(sgbuf, KM_BIO_SRC_IRQ);
dmabuf += sg[i].length;
if (size < sg[i].length)
@@ -347,7 +339,7 @@ static inline void wbsd_dma_to_sg(struct wbsd_host *host, struct mmc_data *data)
* we do not transfer too much.
*/
for (i = 0; i < len; i++) {
- sgbuf = kmap_atomic(sg[i].page, KM_BIO_SRC_IRQ) + sg[i].offset;
+ sgbuf = page_address(sg[i].page) + sg[i].offset;
if (size < sg[i].length)
memcpy(sgbuf, dmabuf, size);
else
@@ -497,7 +489,7 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
if (data->bytes_xfered == host->size)
return;
- buffer = wbsd_kmap_sg(host) + host->offset;
+ buffer = wbsd_sg_to_buffer(host) + host->offset;
/*
* Drain the fifo. This has a tendency to loop longer
@@ -526,17 +518,13 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
/*
* Transfer done?
*/
- if (data->bytes_xfered == host->size) {
- wbsd_kunmap_sg(host);
+ if (data->bytes_xfered == host->size)
return;
- }
/*
* End of scatter list entry?
*/
if (host->remain == 0) {
- wbsd_kunmap_sg(host);
-
/*
* Get next entry. Check if last.
*/
@@ -554,13 +542,11 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
return;
}
- buffer = wbsd_kmap_sg(host);
+ buffer = wbsd_sg_to_buffer(host);
}
}
}
- wbsd_kunmap_sg(host);
-
/*
* This is a very dirty hack to solve a
* hardware problem. The chip doesn't trigger
@@ -583,7 +569,7 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
if (data->bytes_xfered == host->size)
return;
- buffer = wbsd_kmap_sg(host) + host->offset;
+ buffer = wbsd_sg_to_buffer(host) + host->offset;
/*
* Fill the fifo. This has a tendency to loop longer
@@ -612,17 +598,13 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
/*
* Transfer done?
*/
- if (data->bytes_xfered == host->size) {
- wbsd_kunmap_sg(host);
+ if (data->bytes_xfered == host->size)
return;
- }
/*
* End of scatter list entry?
*/
if (host->remain == 0) {
- wbsd_kunmap_sg(host);
-
/*
* Get next entry. Check if last.
*/
@@ -640,13 +622,11 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
return;
}
- buffer = wbsd_kmap_sg(host);
+ buffer = wbsd_sg_to_buffer(host);
}
}
}
- wbsd_kunmap_sg(host);
-
/*
* The controller stops sending interrupts for
* 'FIFO empty' under certain conditions. So we
@@ -910,6 +890,45 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
*/
if (cmd->data && (cmd->error == MMC_ERR_NONE)) {
/*
+ * The hardware is so delightfully stupid that it has a list
+ * of "data" commands. If a command isn't on this list, it'll
+ * just go back to the idle state and won't send any data
+ * interrupts.
+ */
+ switch (cmd->opcode) {
+ case 11:
+ case 17:
+ case 18:
+ case 20:
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ case 30:
+ case 42:
+ case 56:
+ break;
+
+ /* ACMDs. We don't keep track of state, so we just treat them
+ * like any other command. */
+ case 51:
+ break;
+
+ default:
+#ifdef CONFIG_MMC_DEBUG
+ printk(KERN_WARNING "%s: Data command %d is not "
+ "supported by this controller.\n",
+ mmc_hostname(host->mmc), cmd->opcode);
+#endif
+ cmd->data->error = MMC_ERR_INVALID;
+
+ if (cmd->data->stop)
+ wbsd_send_command(host, cmd->data->stop);
+
+ goto done;
+ };
+
+ /*
* Dirty fix for hardware bug.
*/
if (host->dma == -1)
@@ -1343,16 +1362,27 @@ static int __devinit wbsd_alloc_mmc(struct device *dev)
mmc->max_phys_segs = 128;
/*
- * Maximum number of sectors in one transfer. Also limited by 64kB
- * buffer.
+ * Maximum request size. Also limited by 64KiB buffer.
*/
- mmc->max_sectors = 128;
+ mmc->max_req_size = 65536;
/*
* Maximum segment size. Could be one segment with the maximum number
- * of segments.
+ * of bytes.
+ */
+ mmc->max_seg_size = mmc->max_req_size;
+
+ /*
+ * Maximum block size. We have 12 bits (= 4095) but have to subtract
+ * space for CRC. So the maximum is 4095 - 4*2 = 4087.
+ */
+ mmc->max_blk_size = 4087;
+
+ /*
+ * Maximum block count. There is no real limit so the maximum
+ * request size will be the only restriction.
*/
- mmc->max_seg_size = mmc->max_sectors * 512;
+ mmc->max_blk_count = mmc->max_req_size;
dev_set_drvdata(dev, mmc);
diff --git a/drivers/mmc/wbsd.h b/drivers/mmc/wbsd.h
index 6072993f01e..d06718b0e2a 100644
--- a/drivers/mmc/wbsd.h
+++ b/drivers/mmc/wbsd.h
@@ -154,7 +154,6 @@ struct wbsd_host
struct scatterlist* cur_sg; /* Current SG entry */
unsigned int num_sg; /* Number of entries left */
- void* mapped_sg; /* vaddr of mapped sg */
unsigned int offset; /* Offset into current entry */
unsigned int remain; /* Data left in curren entry */
diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c
index 7e34c4f07b7..bc7e906571d 100644
--- a/drivers/net/3c503.c
+++ b/drivers/net/3c503.c
@@ -600,8 +600,7 @@ el2_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring
count -= semi_count;
memcpy_fromio(skb->data + semi_count, base + ei_status.priv, count);
} else {
- /* Packet is in one chunk -- we can copy + cksum. */
- eth_io_copy_and_sum(skb, base + ring_offset, count, 0);
+ memcpy_fromio(skb->data, base + ring_offset, count);
}
return;
}
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 80bdcf84623..716a47210aa 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -792,8 +792,7 @@ static void poll_vortex(struct net_device *dev)
{
struct vortex_private *vp = netdev_priv(dev);
unsigned long flags;
- local_save_flags(flags);
- local_irq_disable();
+ local_irq_save(flags);
(vp->full_bus_master_rx ? boomerang_interrupt:vortex_interrupt)(dev->irq,dev);
local_irq_restore(flags);
}
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 8aa8dd02b91..38f41a593b1 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -190,7 +190,7 @@ config MII
config MACB
tristate "Atmel MACB support"
- depends on NET_ETHERNET && AVR32
+ depends on NET_ETHERNET && (AVR32 || ARCH_AT91SAM9260 || ARCH_AT91SAM9263)
select MII
help
The Atmel MACB ethernet interface is found on many AT32 and AT91
@@ -235,16 +235,6 @@ config BMAC
To compile this driver as a module, choose M here: the module
will be called bmac.
-config OAKNET
- tristate "National DP83902AV (Oak ethernet) support"
- depends on NET_ETHERNET && PPC && BROKEN
- select CRC32
- help
- Say Y if your machine has this type of Ethernet network card.
-
- To compile this driver as a module, choose M here: the module
- will be called oaknet.
-
config ARIADNE
tristate "Ariadne support"
depends on NET_ETHERNET && ZORRO
@@ -1155,21 +1145,6 @@ config SEEQ8005
<file:Documentation/networking/net-modules.txt>. The module
will be called seeq8005.
-config SKMC
- tristate "SKnet MCA support"
- depends on NET_ETHERNET && MCA && BROKEN
- ---help---
- These are Micro Channel Ethernet adapters. You need to say Y to "MCA
- support" in order to use this driver. Supported cards are the SKnet
- Junior MC2 and the SKnet MC2(+). The driver automatically
- distinguishes between the two cards. Note that using multiple boards
- of different type hasn't been tested with this driver. Say Y if you
- have one of these Ethernet adapters.
-
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
- will be called sk_mca.
-
config NE2_MCA
tristate "NE/2 (ne2000 MCA version) support"
depends on NET_ETHERNET && MCA_LEGACY
@@ -1788,6 +1763,18 @@ config LAN_SAA9730
workstations.
See <http://www.semiconductors.philips.com/pip/SAA9730_flyer_1>.
+config SC92031
+ tristate "Silan SC92031 PCI Fast Ethernet Adapter driver (EXPERIMENTAL)"
+ depends on NET_PCI && PCI && EXPERIMENTAL
+ select CRC32
+ ---help---
+ This is a driver for the Fast Ethernet PCI network cards based on
+ the Silan SC92031 chip (sometimes also called Rsltek 8139D). If you
+ have one of these, say Y here.
+
+ To compile this driver as a module, choose M here: the module
+ will be called sc92031. This is recommended.
+
config NET_POCKET
bool "Pocket and portable adapters"
depends on NET_ETHERNET && PARPORT
@@ -2348,6 +2335,17 @@ config QLA3XXX
To compile this driver as a module, choose M here: the module
will be called qla3xxx.
+config ATL1
+ tristate "Attansic L1 Gigabit Ethernet support (EXPERIMENTAL)"
+ depends on NET_PCI && PCI && EXPERIMENTAL
+ select CRC32
+ select MII
+ help
+ This driver supports the Attansic L1 gigabit ethernet adapter.
+
+ To compile this driver as a module, choose M here. The module
+ will be called atl1.
+
endmenu
#
@@ -2392,6 +2390,24 @@ config CHELSIO_T1_NAPI
NAPI is a driver API designed to reduce CPU and interrupt load
when the driver is receiving lots of packets from the card.
+config CHELSIO_T3
+ tristate "Chelsio Communications T3 10Gb Ethernet support"
+ depends on PCI
+ help
+ This driver supports Chelsio T3-based gigabit and 10Gb Ethernet
+ adapters.
+
+ For general information about Chelsio and our products, visit
+ our website at <http://www.chelsio.com>.
+
+ For customer support, please visit our customer support page at
+ <http://www.chelsio.com/support.htm>.
+
+ Please send feedback to <linux-bugs@chelsio.com>.
+
+ To compile this driver as a module, choose M here: the module
+ will be called cxgb3.
+
config EHEA
tristate "eHEA Ethernet support"
depends on IBMEBUS
@@ -2488,6 +2504,13 @@ config NETXEN_NIC
help
This enables the support for NetXen's Gigabit Ethernet card.
+config PASEMI_MAC
+ tristate "PA Semi 1/10Gbit MAC"
+ depends on PPC64 && PCI
+ help
+ This driver supports the on-chip 1/10Gbit Ethernet controller on
+ PA Semi's PWRficient line of chips.
+
endmenu
source "drivers/net/tokenring/Kconfig"
@@ -2522,7 +2545,7 @@ config RIONET_RX_SIZE
config FDDI
bool "FDDI driver support"
- depends on (PCI || EISA)
+ depends on (PCI || EISA || TC)
help
Fiber Distributed Data Interface is a high speed local area network
design; essentially a replacement for high speed Ethernet. FDDI can
@@ -2532,15 +2555,36 @@ config FDDI
will say N.
config DEFXX
- tristate "Digital DEFEA and DEFPA adapter support"
- depends on FDDI && (PCI || EISA)
- help
- This is support for the DIGITAL series of EISA (DEFEA) and PCI
- (DEFPA) controllers which can connect you to a local FDDI network.
+ tristate "Digital DEFTA/DEFEA/DEFPA adapter support"
+ depends on FDDI && (PCI || EISA || TC)
+ ---help---
+ This is support for the DIGITAL series of TURBOchannel (DEFTA),
+ EISA (DEFEA) and PCI (DEFPA) controllers which can connect you
+ to a local FDDI network.
+
+ To compile this driver as a module, choose M here: the module
+ will be called defxx. If unsure, say N.
+
+config DEFXX_MMIO
+ bool
+ prompt "Use MMIO instead of PIO" if PCI || EISA
+ depends on DEFXX
+ default n if PCI || EISA
+ default y
+ ---help---
+ This instructs the driver to use EISA or PCI memory-mapped I/O
+ (MMIO) as appropriate instead of programmed I/O ports (PIO).
+ Enabling this gives an improvement in processing time in parts
+ of the driver, but it may cause problems with EISA (DEFEA)
+ adapters. TURBOchannel does not have the concept of I/O ports,
+ so MMIO is always used for these (DEFTA) adapters.
+
+ If unsure, say N.
config SKFP
tristate "SysKonnect FDDI PCI support"
depends on FDDI && PCI
+ select BITREVERSE
---help---
Say Y here if you have a SysKonnect FDDI PCI adapter.
The following adapters are supported by this driver:
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 4c0d4e5ce42..33af833667d 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -6,8 +6,10 @@ obj-$(CONFIG_E1000) += e1000/
obj-$(CONFIG_IBM_EMAC) += ibm_emac/
obj-$(CONFIG_IXGB) += ixgb/
obj-$(CONFIG_CHELSIO_T1) += chelsio/
+obj-$(CONFIG_CHELSIO_T3) += cxgb3/
obj-$(CONFIG_EHEA) += ehea/
obj-$(CONFIG_BONDING) += bonding/
+obj-$(CONFIG_ATL1) += atl1/
obj-$(CONFIG_GIANFAR) += gianfar_driver.o
gianfar_driver-objs := gianfar.o \
@@ -36,8 +38,6 @@ obj-$(CONFIG_CASSINI) += cassini.o
obj-$(CONFIG_MACE) += mace.o
obj-$(CONFIG_BMAC) += bmac.o
-obj-$(CONFIG_OAKNET) += oaknet.o 8390.o
-
obj-$(CONFIG_DGRS) += dgrs.o
obj-$(CONFIG_VORTEX) += 3c59x.o
obj-$(CONFIG_TYPHOON) += typhoon.o
@@ -137,7 +137,6 @@ obj-$(CONFIG_AT1700) += at1700.o
obj-$(CONFIG_EL1) += 3c501.o
obj-$(CONFIG_EL16) += 3c507.o
obj-$(CONFIG_ELMC) += 3c523.o
-obj-$(CONFIG_SKMC) += sk_mca.o
obj-$(CONFIG_IBMLANA) += ibmlana.o
obj-$(CONFIG_ELMC_II) += 3c527.o
obj-$(CONFIG_EL3) += 3c509.o
@@ -160,6 +159,7 @@ obj-$(CONFIG_APRICOT) += 82596.o
obj-$(CONFIG_LASI_82596) += lasi_82596.o
obj-$(CONFIG_MVME16x_NET) += 82596.o
obj-$(CONFIG_BVME6000_NET) += 82596.o
+obj-$(CONFIG_SC92031) += sc92031.o
# This is also a 82596 and should probably be merged
obj-$(CONFIG_LP486E) += lp486e.o
@@ -196,6 +196,7 @@ obj-$(CONFIG_SMC91X) += smc91x.o
obj-$(CONFIG_SMC911X) += smc911x.o
obj-$(CONFIG_DM9000) += dm9000.o
obj-$(CONFIG_FEC_8XX) += fec_8xx/
+obj-$(CONFIG_PASEMI_MAC) += pasemi_mac.o
obj-$(CONFIG_MACB) += macb.o
diff --git a/drivers/net/Space.c b/drivers/net/Space.c
index 9305eb9b1b9..dd8ed456c8b 100644
--- a/drivers/net/Space.c
+++ b/drivers/net/Space.c
@@ -59,7 +59,6 @@ extern struct net_device *wavelan_probe(int unit);
extern struct net_device *arlan_probe(int unit);
extern struct net_device *el16_probe(int unit);
extern struct net_device *elmc_probe(int unit);
-extern struct net_device *skmca_probe(int unit);
extern struct net_device *elplus_probe(int unit);
extern struct net_device *ac3200_probe(int unit);
extern struct net_device *es_probe(int unit);
@@ -153,9 +152,6 @@ static struct devprobe2 mca_probes[] __initdata = {
#ifdef CONFIG_ELMC_II /* 3c527 */
{mc32_probe, 0},
#endif
-#ifdef CONFIG_SKMC /* SKnet Microchannel */
- {skmca_probe, 0},
-#endif
{NULL, 0},
};
diff --git a/drivers/net/ac3200.c b/drivers/net/ac3200.c
index c01f87f5bed..644c408515d 100644
--- a/drivers/net/ac3200.c
+++ b/drivers/net/ac3200.c
@@ -327,8 +327,7 @@ static void ac_block_input(struct net_device *dev, int count, struct sk_buff *sk
memcpy_fromio(skb->data + semi_count,
ei_status.mem + TX_PAGES*256, count);
} else {
- /* Packet is in one chunk -- we can copy + cksum. */
- eth_io_copy_and_sum(skb, start, count, 0);
+ memcpy_fromio(skb->data, start, count);
}
}
diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c
index 18896f24d40..9c399aaefbd 100644
--- a/drivers/net/amd8111e.c
+++ b/drivers/net/amd8111e.c
@@ -1334,8 +1334,7 @@ err_no_interrupt:
static void amd8111e_poll(struct net_device *dev)
{
unsigned long flags;
- local_save_flags(flags);
- local_irq_disable();
+ local_irq_save(flags);
amd8111e_interrupt(0, dev);
local_irq_restore(flags);
}
diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c
index fada15d959d..1621b8fe35c 100644
--- a/drivers/net/arm/at91_ether.c
+++ b/drivers/net/arm/at91_ether.c
@@ -641,7 +641,7 @@ static void at91ether_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo
{
strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
strlcpy(info->version, DRV_VERSION, sizeof(info->version));
- strlcpy(info->bus_info, dev->class_dev.dev->bus_id, sizeof(info->bus_info));
+ strlcpy(info->bus_info, dev->dev.parent->bus_id, sizeof(info->bus_info));
}
static const struct ethtool_ops at91ether_ethtool_ops = {
diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c
index f3faa4fe58e..72c41f5907f 100644
--- a/drivers/net/arm/etherh.c
+++ b/drivers/net/arm/etherh.c
@@ -587,7 +587,7 @@ static void etherh_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *i
{
strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
strlcpy(info->version, DRV_VERSION, sizeof(info->version));
- strlcpy(info->bus_info, dev->class_dev.dev->bus_id,
+ strlcpy(info->bus_info, dev->dev.parent->bus_id,
sizeof(info->bus_info));
}
diff --git a/drivers/net/atl1/Makefile b/drivers/net/atl1/Makefile
new file mode 100644
index 00000000000..a6b707e4e69
--- /dev/null
+++ b/drivers/net/atl1/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_ATL1) += atl1.o
+atl1-y += atl1_main.o atl1_hw.o atl1_ethtool.o atl1_param.o
diff --git a/drivers/net/atl1/atl1.h b/drivers/net/atl1/atl1.h
new file mode 100644
index 00000000000..b1c6034e68f
--- /dev/null
+++ b/drivers/net/atl1/atl1.h
@@ -0,0 +1,283 @@
+/*
+ * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved.
+ * Copyright(c) 2006 Chris Snook <csnook@redhat.com>
+ * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com>
+ *
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _ATL1_H_
+#define _ATL1_H_
+
+#include <linux/types.h>
+#include <linux/if_vlan.h>
+
+#include "atl1_hw.h"
+
+/* function prototypes needed by multiple files */
+s32 atl1_up(struct atl1_adapter *adapter);
+void atl1_down(struct atl1_adapter *adapter);
+int atl1_reset(struct atl1_adapter *adapter);
+s32 atl1_setup_ring_resources(struct atl1_adapter *adapter);
+void atl1_free_ring_resources(struct atl1_adapter *adapter);
+
+extern char atl1_driver_name[];
+extern char atl1_driver_version[];
+extern const struct ethtool_ops atl1_ethtool_ops;
+
+struct atl1_adapter;
+
+#define ATL1_MAX_INTR 3
+
+#define ATL1_DEFAULT_TPD 256
+#define ATL1_MAX_TPD 1024
+#define ATL1_MIN_TPD 64
+#define ATL1_DEFAULT_RFD 512
+#define ATL1_MIN_RFD 128
+#define ATL1_MAX_RFD 2048
+
+#define ATL1_GET_DESC(R, i, type) (&(((type *)((R)->desc))[i]))
+#define ATL1_RFD_DESC(R, i) ATL1_GET_DESC(R, i, struct rx_free_desc)
+#define ATL1_TPD_DESC(R, i) ATL1_GET_DESC(R, i, struct tx_packet_desc)
+#define ATL1_RRD_DESC(R, i) ATL1_GET_DESC(R, i, struct rx_return_desc)
+
+/*
+ * Some workarounds require millisecond delays and are run during interrupt
+ * context. Most notably, when establishing link, the phy may need tweaking
+ * but cannot process phy register reads/writes faster than millisecond
+ * intervals...and we establish link due to a "link status change" interrupt.
+ */
+
+/*
+ * wrapper around a pointer to a socket buffer,
+ * so a DMA handle can be stored along with the buffer
+ */
+struct atl1_buffer {
+ struct sk_buff *skb;
+ u16 length;
+ u16 alloced;
+ dma_addr_t dma;
+};
+
+#define MAX_TX_BUF_LEN 0x3000 /* 12KB */
+
+struct atl1_tpd_ring {
+ void *desc; /* pointer to the descriptor ring memory */
+ dma_addr_t dma; /* physical adress of the descriptor ring */
+ u16 size; /* length of descriptor ring in bytes */
+ u16 count; /* number of descriptors in the ring */
+ u16 hw_idx; /* hardware index */
+ atomic_t next_to_clean;
+ atomic_t next_to_use;
+ struct atl1_buffer *buffer_info;
+};
+
+struct atl1_rfd_ring {
+ void *desc;
+ dma_addr_t dma;
+ u16 size;
+ u16 count;
+ atomic_t next_to_use;
+ u16 next_to_clean;
+ struct atl1_buffer *buffer_info;
+};
+
+struct atl1_rrd_ring {
+ void *desc;
+ dma_addr_t dma;
+ unsigned int size;
+ u16 count;
+ u16 next_to_use;
+ atomic_t next_to_clean;
+};
+
+struct atl1_ring_header {
+ void *desc; /* pointer to the descriptor ring memory */
+ dma_addr_t dma; /* physical adress of the descriptor ring */
+ unsigned int size; /* length of descriptor ring in bytes */
+};
+
+struct atl1_cmb {
+ struct coals_msg_block *cmb;
+ dma_addr_t dma;
+};
+
+struct atl1_smb {
+ struct stats_msg_block *smb;
+ dma_addr_t dma;
+};
+
+/* Statistics counters */
+struct atl1_sft_stats {
+ u64 rx_packets;
+ u64 tx_packets;
+ u64 rx_bytes;
+ u64 tx_bytes;
+ u64 multicast;
+ u64 collisions;
+ u64 rx_errors;
+ u64 rx_length_errors;
+ u64 rx_crc_errors;
+ u64 rx_frame_errors;
+ u64 rx_fifo_errors;
+ u64 rx_missed_errors;
+ u64 tx_errors;
+ u64 tx_fifo_errors;
+ u64 tx_aborted_errors;
+ u64 tx_window_errors;
+ u64 tx_carrier_errors;
+
+ u64 tx_pause; /* num Pause packet transmitted. */
+ u64 excecol; /* num tx packets aborted due to excessive collisions. */
+ u64 deffer; /* num deferred tx packets */
+ u64 scc; /* num packets subsequently transmitted successfully w/ single prior collision. */
+ u64 mcc; /* num packets subsequently transmitted successfully w/ multiple prior collisions. */
+ u64 latecol; /* num tx packets w/ late collisions. */
+ u64 tx_underun; /* num tx packets aborted due to transmit FIFO underrun, or TRD FIFO underrun */
+ u64 tx_trunc; /* num tx packets truncated due to size exceeding MTU, regardless whether truncated by Selene or not. (The name doesn't really reflect the meaning in this case.) */
+ u64 rx_pause; /* num Pause packets received. */
+ u64 rx_rrd_ov;
+ u64 rx_trunc;
+};
+
+/* board specific private data structure */
+#define ATL1_REGS_LEN 8
+
+/* Structure containing variables used by the shared code */
+struct atl1_hw {
+ u8 __iomem *hw_addr;
+ struct atl1_adapter *back;
+ enum atl1_dma_order dma_ord;
+ enum atl1_dma_rcb rcb_value;
+ enum atl1_dma_req_block dmar_block;
+ enum atl1_dma_req_block dmaw_block;
+ u8 preamble_len;
+ u8 max_retry; /* Retransmission maximum, after which the packet will be discarded */
+ u8 jam_ipg; /* IPG to start JAM for collision based flow control in half-duplex mode. In units of 8-bit time */
+ u8 ipgt; /* Desired back to back inter-packet gap. The default is 96-bit time */
+ u8 min_ifg; /* Minimum number of IFG to enforce in between RX frames. Frame gap below such IFP is dropped */
+ u8 ipgr1; /* 64bit Carrier-Sense window */
+ u8 ipgr2; /* 96-bit IPG window */
+ u8 tpd_burst; /* Number of TPD to prefetch in cache-aligned burst. Each TPD is 16 bytes long */
+ u8 rfd_burst; /* Number of RFD to prefetch in cache-aligned burst. Each RFD is 12 bytes long */
+ u8 rfd_fetch_gap;
+ u8 rrd_burst; /* Threshold number of RRDs that can be retired in a burst. Each RRD is 16 bytes long */
+ u8 tpd_fetch_th;
+ u8 tpd_fetch_gap;
+ u16 tx_jumbo_task_th;
+ u16 txf_burst; /* Number of data bytes to read in a cache-aligned burst. Each SRAM entry is
+ 8 bytes long */
+ u16 rx_jumbo_th; /* Jumbo packet size for non-VLAN packet. VLAN packets should add 4 bytes */
+ u16 rx_jumbo_lkah;
+ u16 rrd_ret_timer; /* RRD retirement timer. Decrement by 1 after every 512ns passes. */
+ u16 lcol; /* Collision Window */
+
+ u16 cmb_tpd;
+ u16 cmb_rrd;
+ u16 cmb_rx_timer;
+ u16 cmb_tx_timer;
+ u32 smb_timer;
+ u16 media_type;
+ u16 autoneg_advertised;
+ u16 pci_cmd_word;
+
+ u16 mii_autoneg_adv_reg;
+ u16 mii_1000t_ctrl_reg;
+
+ u32 mem_rang;
+ u32 txcw;
+ u32 max_frame_size;
+ u32 min_frame_size;
+ u32 mc_filter_type;
+ u32 num_mc_addrs;
+ u32 collision_delta;
+ u32 tx_packet_delta;
+ u16 phy_spd_default;
+
+ u16 dev_rev;
+ u8 revision_id;
+
+ /* spi flash */
+ u8 flash_vendor;
+
+ u8 dma_fairness;
+ u8 mac_addr[ETH_ALEN];
+ u8 perm_mac_addr[ETH_ALEN];
+
+ /* bool phy_preamble_sup; */
+ bool phy_configured;
+};
+
+struct atl1_adapter {
+ /* OS defined structs */
+ struct net_device *netdev;
+ struct pci_dev *pdev;
+ struct net_device_stats net_stats;
+ struct atl1_sft_stats soft_stats;
+
+ struct vlan_group *vlgrp;
+ u32 rx_buffer_len;
+ u32 wol;
+ u16 link_speed;
+ u16 link_duplex;
+ spinlock_t lock;
+ atomic_t irq_sem;
+ struct work_struct tx_timeout_task;
+ struct work_struct link_chg_task;
+ struct work_struct pcie_dma_to_rst_task;
+ struct timer_list watchdog_timer;
+ struct timer_list phy_config_timer;
+ bool phy_timer_pending;
+
+ bool mac_disabled;
+
+ /* All descriptor rings' memory */
+ struct atl1_ring_header ring_header;
+
+ /* TX */
+ struct atl1_tpd_ring tpd_ring;
+ spinlock_t mb_lock;
+
+ /* RX */
+ struct atl1_rfd_ring rfd_ring;
+ struct atl1_rrd_ring rrd_ring;
+ u64 hw_csum_err;
+ u64 hw_csum_good;
+
+ u32 gorcl;
+ u64 gorcl_old;
+
+ /* Interrupt Moderator timer ( 2us resolution) */
+ u16 imt;
+ /* Interrupt Clear timer (2us resolution) */
+ u16 ict;
+
+ /* MII interface info */
+ struct mii_if_info mii;
+
+ /* structs defined in atl1_hw.h */
+ u32 bd_number; /* board number */
+ bool pci_using_64;
+ struct atl1_hw hw;
+ struct atl1_smb smb;
+ struct atl1_cmb cmb;
+
+ u32 pci_state[16];
+};
+
+#endif /* _ATL1_H_ */
diff --git a/drivers/net/atl1/atl1_ethtool.c b/drivers/net/atl1/atl1_ethtool.c
new file mode 100644
index 00000000000..c11c27798e5
--- /dev/null
+++ b/drivers/net/atl1/atl1_ethtool.c
@@ -0,0 +1,508 @@
+/*
+ * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved.
+ * Copyright(c) 2006 Chris Snook <csnook@redhat.com>
+ * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com>
+ *
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/ethtool.h>
+#include <linux/netdevice.h>
+#include <linux/mii.h>
+#include <asm/uaccess.h>
+
+#include "atl1.h"
+
+struct atl1_stats {
+ char stat_string[ETH_GSTRING_LEN];
+ int sizeof_stat;
+ int stat_offset;
+};
+
+#define ATL1_STAT(m) sizeof(((struct atl1_adapter *)0)->m), \
+ offsetof(struct atl1_adapter, m)
+
+static struct atl1_stats atl1_gstrings_stats[] = {
+ {"rx_packets", ATL1_STAT(soft_stats.rx_packets)},
+ {"tx_packets", ATL1_STAT(soft_stats.tx_packets)},
+ {"rx_bytes", ATL1_STAT(soft_stats.rx_bytes)},
+ {"tx_bytes", ATL1_STAT(soft_stats.tx_bytes)},
+ {"rx_errors", ATL1_STAT(soft_stats.rx_errors)},
+ {"tx_errors", ATL1_STAT(soft_stats.tx_errors)},
+ {"rx_dropped", ATL1_STAT(net_stats.rx_dropped)},
+ {"tx_dropped", ATL1_STAT(net_stats.tx_dropped)},
+ {"multicast", ATL1_STAT(soft_stats.multicast)},
+ {"collisions", ATL1_STAT(soft_stats.collisions)},
+ {"rx_length_errors", ATL1_STAT(soft_stats.rx_length_errors)},
+ {"rx_over_errors", ATL1_STAT(soft_stats.rx_missed_errors)},
+ {"rx_crc_errors", ATL1_STAT(soft_stats.rx_crc_errors)},
+ {"rx_frame_errors", ATL1_STAT(soft_stats.rx_frame_errors)},
+ {"rx_fifo_errors", ATL1_STAT(soft_stats.rx_fifo_errors)},
+ {"rx_missed_errors", ATL1_STAT(soft_stats.rx_missed_errors)},
+ {"tx_aborted_errors", ATL1_STAT(soft_stats.tx_aborted_errors)},
+ {"tx_carrier_errors", ATL1_STAT(soft_stats.tx_carrier_errors)},
+ {"tx_fifo_errors", ATL1_STAT(soft_stats.tx_fifo_errors)},
+ {"tx_window_errors", ATL1_STAT(soft_stats.tx_window_errors)},
+ {"tx_abort_exce_coll", ATL1_STAT(soft_stats.excecol)},
+ {"tx_abort_late_coll", ATL1_STAT(soft_stats.latecol)},
+ {"tx_deferred_ok", ATL1_STAT(soft_stats.deffer)},
+ {"tx_single_coll_ok", ATL1_STAT(soft_stats.scc)},
+ {"tx_multi_coll_ok", ATL1_STAT(soft_stats.mcc)},
+ {"tx_underun", ATL1_STAT(soft_stats.tx_underun)},
+ {"tx_trunc", ATL1_STAT(soft_stats.tx_trunc)},
+ {"tx_pause", ATL1_STAT(soft_stats.tx_pause)},
+ {"rx_pause", ATL1_STAT(soft_stats.rx_pause)},
+ {"rx_rrd_ov", ATL1_STAT(soft_stats.rx_rrd_ov)},
+ {"rx_trunc", ATL1_STAT(soft_stats.rx_trunc)}
+};
+
+static void atl1_get_ethtool_stats(struct net_device *netdev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ int i;
+ char *p;
+
+ for (i = 0; i < ARRAY_SIZE(atl1_gstrings_stats); i++) {
+ p = (char *)adapter+atl1_gstrings_stats[i].stat_offset;
+ data[i] = (atl1_gstrings_stats[i].sizeof_stat ==
+ sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
+ }
+
+}
+
+static int atl1_get_stats_count(struct net_device *netdev)
+{
+ return ARRAY_SIZE(atl1_gstrings_stats);
+}
+
+static int atl1_get_settings(struct net_device *netdev,
+ struct ethtool_cmd *ecmd)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ struct atl1_hw *hw = &adapter->hw;
+
+ ecmd->supported = (SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_1000baseT_Full |
+ SUPPORTED_Autoneg | SUPPORTED_TP);
+ ecmd->advertising = ADVERTISED_TP;
+ if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR ||
+ hw->media_type == MEDIA_TYPE_1000M_FULL) {
+ ecmd->advertising |= ADVERTISED_Autoneg;
+ if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR) {
+ ecmd->advertising |= ADVERTISED_Autoneg;
+ ecmd->advertising |=
+ (ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full |
+ ADVERTISED_1000baseT_Full);
+ }
+ else
+ ecmd->advertising |= (ADVERTISED_1000baseT_Full);
+ }
+ ecmd->port = PORT_TP;
+ ecmd->phy_address = 0;
+ ecmd->transceiver = XCVR_INTERNAL;
+
+ if (netif_carrier_ok(adapter->netdev)) {
+ u16 link_speed, link_duplex;
+ atl1_get_speed_and_duplex(hw, &link_speed, &link_duplex);
+ ecmd->speed = link_speed;
+ if (link_duplex == FULL_DUPLEX)
+ ecmd->duplex = DUPLEX_FULL;
+ else
+ ecmd->duplex = DUPLEX_HALF;
+ } else {
+ ecmd->speed = -1;
+ ecmd->duplex = -1;
+ }
+ if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR ||
+ hw->media_type == MEDIA_TYPE_1000M_FULL)
+ ecmd->autoneg = AUTONEG_ENABLE;
+ else
+ ecmd->autoneg = AUTONEG_DISABLE;
+
+ return 0;
+}
+
+static int atl1_set_settings(struct net_device *netdev,
+ struct ethtool_cmd *ecmd)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ struct atl1_hw *hw = &adapter->hw;
+ u16 phy_data;
+ int ret_val = 0;
+ u16 old_media_type = hw->media_type;
+
+ if (netif_running(adapter->netdev)) {
+ printk(KERN_DEBUG "%s: ethtool shutting down adapter\n",
+ atl1_driver_name);
+ atl1_down(adapter);
+ }
+
+ if (ecmd->autoneg == AUTONEG_ENABLE)
+ hw->media_type = MEDIA_TYPE_AUTO_SENSOR;
+ else {
+ if (ecmd->speed == SPEED_1000) {
+ if (ecmd->duplex != DUPLEX_FULL) {
+ printk(KERN_WARNING
+ "%s: can't force to 1000M half duplex\n",
+ atl1_driver_name);
+ ret_val = -EINVAL;
+ goto exit_sset;
+ }
+ hw->media_type = MEDIA_TYPE_1000M_FULL;
+ } else if (ecmd->speed == SPEED_100) {
+ if (ecmd->duplex == DUPLEX_FULL) {
+ hw->media_type = MEDIA_TYPE_100M_FULL;
+ } else
+ hw->media_type = MEDIA_TYPE_100M_HALF;
+ } else {
+ if (ecmd->duplex == DUPLEX_FULL)
+ hw->media_type = MEDIA_TYPE_10M_FULL;
+ else
+ hw->media_type = MEDIA_TYPE_10M_HALF;
+ }
+ }
+ switch (hw->media_type) {
+ case MEDIA_TYPE_AUTO_SENSOR:
+ ecmd->advertising =
+ ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full |
+ ADVERTISED_1000baseT_Full |
+ ADVERTISED_Autoneg | ADVERTISED_TP;
+ break;
+ case MEDIA_TYPE_1000M_FULL:
+ ecmd->advertising =
+ ADVERTISED_1000baseT_Full |
+ ADVERTISED_Autoneg | ADVERTISED_TP;
+ break;
+ default:
+ ecmd->advertising = 0;
+ break;
+ }
+ if (atl1_phy_setup_autoneg_adv(hw)) {
+ ret_val = -EINVAL;
+ printk(KERN_WARNING
+ "%s: invalid ethtool speed/duplex setting\n",
+ atl1_driver_name);
+ goto exit_sset;
+ }
+ if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR ||
+ hw->media_type == MEDIA_TYPE_1000M_FULL)
+ phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN;
+ else {
+ switch (hw->media_type) {
+ case MEDIA_TYPE_100M_FULL:
+ phy_data =
+ MII_CR_FULL_DUPLEX | MII_CR_SPEED_100 |
+ MII_CR_RESET;
+ break;
+ case MEDIA_TYPE_100M_HALF:
+ phy_data = MII_CR_SPEED_100 | MII_CR_RESET;
+ break;
+ case MEDIA_TYPE_10M_FULL:
+ phy_data =
+ MII_CR_FULL_DUPLEX | MII_CR_SPEED_10 | MII_CR_RESET;
+ break;
+ default: /* MEDIA_TYPE_10M_HALF: */
+ phy_data = MII_CR_SPEED_10 | MII_CR_RESET;
+ break;
+ }
+ }
+ atl1_write_phy_reg(hw, MII_BMCR, phy_data);
+exit_sset:
+ if (ret_val)
+ hw->media_type = old_media_type;
+
+ if (netif_running(adapter->netdev)) {
+ printk(KERN_DEBUG "%s: ethtool starting adapter\n",
+ atl1_driver_name);
+ atl1_up(adapter);
+ } else if (!ret_val) {
+ printk(KERN_DEBUG "%s: ethtool resetting adapter\n",
+ atl1_driver_name);
+ atl1_reset(adapter);
+ }
+ return ret_val;
+}
+
+static void atl1_get_drvinfo(struct net_device *netdev,
+ struct ethtool_drvinfo *drvinfo)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+
+ strncpy(drvinfo->driver, atl1_driver_name, sizeof(drvinfo->driver));
+ strncpy(drvinfo->version, atl1_driver_version,
+ sizeof(drvinfo->version));
+ strncpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
+ strncpy(drvinfo->bus_info, pci_name(adapter->pdev),
+ sizeof(drvinfo->bus_info));
+ drvinfo->eedump_len = ATL1_EEDUMP_LEN;
+}
+
+static void atl1_get_wol(struct net_device *netdev,
+ struct ethtool_wolinfo *wol)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+
+ wol->supported = WAKE_UCAST | WAKE_MCAST | WAKE_BCAST | WAKE_MAGIC;
+ wol->wolopts = 0;
+ if (adapter->wol & ATL1_WUFC_EX)
+ wol->wolopts |= WAKE_UCAST;
+ if (adapter->wol & ATL1_WUFC_MC)
+ wol->wolopts |= WAKE_MCAST;
+ if (adapter->wol & ATL1_WUFC_BC)
+ wol->wolopts |= WAKE_BCAST;
+ if (adapter->wol & ATL1_WUFC_MAG)
+ wol->wolopts |= WAKE_MAGIC;
+ return;
+}
+
+static int atl1_set_wol(struct net_device *netdev,
+ struct ethtool_wolinfo *wol)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+
+ if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE))
+ return -EOPNOTSUPP;
+ adapter->wol = 0;
+ if (wol->wolopts & WAKE_UCAST)
+ adapter->wol |= ATL1_WUFC_EX;
+ if (wol->wolopts & WAKE_MCAST)
+ adapter->wol |= ATL1_WUFC_MC;
+ if (wol->wolopts & WAKE_BCAST)
+ adapter->wol |= ATL1_WUFC_BC;
+ if (wol->wolopts & WAKE_MAGIC)
+ adapter->wol |= ATL1_WUFC_MAG;
+ return 0;
+}
+
+static void atl1_get_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ struct atl1_tpd_ring *txdr = &adapter->tpd_ring;
+ struct atl1_rfd_ring *rxdr = &adapter->rfd_ring;
+
+ ring->rx_max_pending = ATL1_MAX_RFD;
+ ring->tx_max_pending = ATL1_MAX_TPD;
+ ring->rx_mini_max_pending = 0;
+ ring->rx_jumbo_max_pending = 0;
+ ring->rx_pending = rxdr->count;
+ ring->tx_pending = txdr->count;
+ ring->rx_mini_pending = 0;
+ ring->rx_jumbo_pending = 0;
+}
+
+static int atl1_set_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ struct atl1_tpd_ring *tpdr = &adapter->tpd_ring;
+ struct atl1_rrd_ring *rrdr = &adapter->rrd_ring;
+ struct atl1_rfd_ring *rfdr = &adapter->rfd_ring;
+
+ struct atl1_tpd_ring tpd_old, tpd_new;
+ struct atl1_rfd_ring rfd_old, rfd_new;
+ struct atl1_rrd_ring rrd_old, rrd_new;
+ struct atl1_ring_header rhdr_old, rhdr_new;
+ int err;
+
+ tpd_old = adapter->tpd_ring;
+ rfd_old = adapter->rfd_ring;
+ rrd_old = adapter->rrd_ring;
+ rhdr_old = adapter->ring_header;
+
+ if (netif_running(adapter->netdev))
+ atl1_down(adapter);
+
+ rfdr->count = (u16) max(ring->rx_pending, (u32) ATL1_MIN_RFD);
+ rfdr->count = rfdr->count > ATL1_MAX_RFD ? ATL1_MAX_RFD :
+ rfdr->count;
+ rfdr->count = (rfdr->count + 3) & ~3;
+ rrdr->count = rfdr->count;
+
+ tpdr->count = (u16) max(ring->tx_pending, (u32) ATL1_MIN_TPD);
+ tpdr->count = tpdr->count > ATL1_MAX_TPD ? ATL1_MAX_TPD :
+ tpdr->count;
+ tpdr->count = (tpdr->count + 3) & ~3;
+
+ if (netif_running(adapter->netdev)) {
+ /* try to get new resources before deleting old */
+ err = atl1_setup_ring_resources(adapter);
+ if (err)
+ goto err_setup_ring;
+
+ /*
+ * save the new, restore the old in order to free it,
+ * then restore the new back again
+ */
+
+ rfd_new = adapter->rfd_ring;
+ rrd_new = adapter->rrd_ring;
+ tpd_new = adapter->tpd_ring;
+ rhdr_new = adapter->ring_header;
+ adapter->rfd_ring = rfd_old;
+ adapter->rrd_ring = rrd_old;
+ adapter->tpd_ring = tpd_old;
+ adapter->ring_header = rhdr_old;
+ atl1_free_ring_resources(adapter);
+ adapter->rfd_ring = rfd_new;
+ adapter->rrd_ring = rrd_new;
+ adapter->tpd_ring = tpd_new;
+ adapter->ring_header = rhdr_new;
+
+ err = atl1_up(adapter);
+ if (err)
+ return err;
+ }
+ return 0;
+
+err_setup_ring:
+ adapter->rfd_ring = rfd_old;
+ adapter->rrd_ring = rrd_old;
+ adapter->tpd_ring = tpd_old;
+ adapter->ring_header = rhdr_old;
+ atl1_up(adapter);
+ return err;
+}
+
+static void atl1_get_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *epause)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ struct atl1_hw *hw = &adapter->hw;
+
+ if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR ||
+ hw->media_type == MEDIA_TYPE_1000M_FULL) {
+ epause->autoneg = AUTONEG_ENABLE;
+ } else {
+ epause->autoneg = AUTONEG_DISABLE;
+ }
+ epause->rx_pause = 1;
+ epause->tx_pause = 1;
+}
+
+static int atl1_set_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *epause)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ struct atl1_hw *hw = &adapter->hw;
+
+ if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR ||
+ hw->media_type == MEDIA_TYPE_1000M_FULL) {
+ epause->autoneg = AUTONEG_ENABLE;
+ } else {
+ epause->autoneg = AUTONEG_DISABLE;
+ }
+
+ epause->rx_pause = 1;
+ epause->tx_pause = 1;
+
+ return 0;
+}
+
+static u32 atl1_get_rx_csum(struct net_device *netdev)
+{
+ return 1;
+}
+
+static void atl1_get_strings(struct net_device *netdev, u32 stringset,
+ u8 *data)
+{
+ u8 *p = data;
+ int i;
+
+ switch (stringset) {
+ case ETH_SS_STATS:
+ for (i = 0; i < ARRAY_SIZE(atl1_gstrings_stats); i++) {
+ memcpy(p, atl1_gstrings_stats[i].stat_string,
+ ETH_GSTRING_LEN);
+ p += ETH_GSTRING_LEN;
+ }
+ break;
+ }
+}
+
+static int atl1_nway_reset(struct net_device *netdev)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ struct atl1_hw *hw = &adapter->hw;
+
+ if (netif_running(netdev)) {
+ u16 phy_data;
+ atl1_down(adapter);
+
+ if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR ||
+ hw->media_type == MEDIA_TYPE_1000M_FULL) {
+ phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN;
+ } else {
+ switch (hw->media_type) {
+ case MEDIA_TYPE_100M_FULL:
+ phy_data = MII_CR_FULL_DUPLEX |
+ MII_CR_SPEED_100 | MII_CR_RESET;
+ break;
+ case MEDIA_TYPE_100M_HALF:
+ phy_data = MII_CR_SPEED_100 | MII_CR_RESET;
+ break;
+ case MEDIA_TYPE_10M_FULL:
+ phy_data = MII_CR_FULL_DUPLEX |
+ MII_CR_SPEED_10 | MII_CR_RESET;
+ break;
+ default: /* MEDIA_TYPE_10M_HALF */
+ phy_data = MII_CR_SPEED_10 | MII_CR_RESET;
+ }
+ }
+ atl1_write_phy_reg(hw, MII_BMCR, phy_data);
+ atl1_up(adapter);
+ }
+ return 0;
+}
+
+const struct ethtool_ops atl1_ethtool_ops = {
+ .get_settings = atl1_get_settings,
+ .set_settings = atl1_set_settings,
+ .get_drvinfo = atl1_get_drvinfo,
+ .get_wol = atl1_get_wol,
+ .set_wol = atl1_set_wol,
+ .get_ringparam = atl1_get_ringparam,
+ .set_ringparam = atl1_set_ringparam,
+ .get_pauseparam = atl1_get_pauseparam,
+ .set_pauseparam = atl1_set_pauseparam,
+ .get_rx_csum = atl1_get_rx_csum,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .set_tx_csum = ethtool_op_set_tx_hw_csum,
+ .get_link = ethtool_op_get_link,
+ .get_sg = ethtool_op_get_sg,
+ .set_sg = ethtool_op_set_sg,
+ .get_strings = atl1_get_strings,
+ .nway_reset = atl1_nway_reset,
+ .get_ethtool_stats = atl1_get_ethtool_stats,
+ .get_stats_count = atl1_get_stats_count,
+ .get_tso = ethtool_op_get_tso,
+ .set_tso = ethtool_op_set_tso,
+};
diff --git a/drivers/net/atl1/atl1_hw.c b/drivers/net/atl1/atl1_hw.c
new file mode 100644
index 00000000000..08b2d785469
--- /dev/null
+++ b/drivers/net/atl1/atl1_hw.c
@@ -0,0 +1,718 @@
+/*
+ * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved.
+ * Copyright(c) 2006 Chris Snook <csnook@redhat.com>
+ * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com>
+ *
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/if_vlan.h>
+#include <linux/etherdevice.h>
+#include <linux/crc32.h>
+#include <asm/byteorder.h>
+
+#include "atl1.h"
+
+/*
+ * Reset the transmit and receive units; mask and clear all interrupts.
+ * hw - Struct containing variables accessed by shared code
+ * return : ATL1_SUCCESS or idle status (if error)
+ */
+s32 atl1_reset_hw(struct atl1_hw *hw)
+{
+ u32 icr;
+ int i;
+
+ /*
+ * Clear Interrupt mask to stop board from generating
+ * interrupts & Clear any pending interrupt events
+ */
+ /*
+ * iowrite32(0, hw->hw_addr + REG_IMR);
+ * iowrite32(0xffffffff, hw->hw_addr + REG_ISR);
+ */
+
+ /*
+ * Issue Soft Reset to the MAC. This will reset the chip's
+ * transmit, receive, DMA. It will not effect
+ * the current PCI configuration. The global reset bit is self-
+ * clearing, and should clear within a microsecond.
+ */
+ iowrite32(MASTER_CTRL_SOFT_RST, hw->hw_addr + REG_MASTER_CTRL);
+ ioread32(hw->hw_addr + REG_MASTER_CTRL);
+
+ iowrite16(1, hw->hw_addr + REG_GPHY_ENABLE);
+ ioread16(hw->hw_addr + REG_GPHY_ENABLE);
+
+ msleep(1); /* delay about 1ms */
+
+ /* Wait at least 10ms for All module to be Idle */
+ for (i = 0; i < 10; i++) {
+ icr = ioread32(hw->hw_addr + REG_IDLE_STATUS);
+ if (!icr)
+ break;
+ msleep(1); /* delay 1 ms */
+ cpu_relax(); /* FIXME: is this still the right way to do this? */
+ }
+
+ if (icr) {
+ printk (KERN_DEBUG "icr = %x\n", icr);
+ return icr;
+ }
+
+ return ATL1_SUCCESS;
+}
+
+/* function about EEPROM
+ *
+ * check_eeprom_exist
+ * return 0 if eeprom exist
+ */
+static int atl1_check_eeprom_exist(struct atl1_hw *hw)
+{
+ u32 value;
+ value = ioread32(hw->hw_addr + REG_SPI_FLASH_CTRL);
+ if (value & SPI_FLASH_CTRL_EN_VPD) {
+ value &= ~SPI_FLASH_CTRL_EN_VPD;
+ iowrite32(value, hw->hw_addr + REG_SPI_FLASH_CTRL);
+ }
+
+ value = ioread16(hw->hw_addr + REG_PCIE_CAP_LIST);
+ return ((value & 0xFF00) == 0x6C00) ? 0 : 1;
+}
+
+static bool atl1_read_eeprom(struct atl1_hw *hw, u32 offset, u32 *p_value)
+{
+ int i;
+ u32 control;
+
+ if (offset & 3)
+ return false; /* address do not align */
+
+ iowrite32(0, hw->hw_addr + REG_VPD_DATA);
+ control = (offset & VPD_CAP_VPD_ADDR_MASK) << VPD_CAP_VPD_ADDR_SHIFT;
+ iowrite32(control, hw->hw_addr + REG_VPD_CAP);
+ ioread32(hw->hw_addr + REG_VPD_CAP);
+
+ for (i = 0; i < 10; i++) {
+ msleep(2);
+ control = ioread32(hw->hw_addr + REG_VPD_CAP);
+ if (control & VPD_CAP_VPD_FLAG)
+ break;
+ }
+ if (control & VPD_CAP_VPD_FLAG) {
+ *p_value = ioread32(hw->hw_addr + REG_VPD_DATA);
+ return true;
+ }
+ return false; /* timeout */
+}
+
+/*
+ * Reads the value from a PHY register
+ * hw - Struct containing variables accessed by shared code
+ * reg_addr - address of the PHY register to read
+ */
+s32 atl1_read_phy_reg(struct atl1_hw *hw, u16 reg_addr, u16 *phy_data)
+{
+ u32 val;
+ int i;
+
+ val = ((u32) (reg_addr & MDIO_REG_ADDR_MASK)) << MDIO_REG_ADDR_SHIFT |
+ MDIO_START | MDIO_SUP_PREAMBLE | MDIO_RW | MDIO_CLK_25_4 <<
+ MDIO_CLK_SEL_SHIFT;
+ iowrite32(val, hw->hw_addr + REG_MDIO_CTRL);
+ ioread32(hw->hw_addr + REG_MDIO_CTRL);
+
+ for (i = 0; i < MDIO_WAIT_TIMES; i++) {
+ udelay(2);
+ val = ioread32(hw->hw_addr + REG_MDIO_CTRL);
+ if (!(val & (MDIO_START | MDIO_BUSY)))
+ break;
+ }
+ if (!(val & (MDIO_START | MDIO_BUSY))) {
+ *phy_data = (u16) val;
+ return ATL1_SUCCESS;
+ }
+ return ATL1_ERR_PHY;
+}
+
+#define CUSTOM_SPI_CS_SETUP 2
+#define CUSTOM_SPI_CLK_HI 2
+#define CUSTOM_SPI_CLK_LO 2
+#define CUSTOM_SPI_CS_HOLD 2
+#define CUSTOM_SPI_CS_HI 3
+
+static bool atl1_spi_read(struct atl1_hw *hw, u32 addr, u32 *buf)
+{
+ int i;
+ u32 value;
+
+ iowrite32(0, hw->hw_addr + REG_SPI_DATA);
+ iowrite32(addr, hw->hw_addr + REG_SPI_ADDR);
+
+ value = SPI_FLASH_CTRL_WAIT_READY |
+ (CUSTOM_SPI_CS_SETUP & SPI_FLASH_CTRL_CS_SETUP_MASK) <<
+ SPI_FLASH_CTRL_CS_SETUP_SHIFT | (CUSTOM_SPI_CLK_HI &
+ SPI_FLASH_CTRL_CLK_HI_MASK) <<
+ SPI_FLASH_CTRL_CLK_HI_SHIFT | (CUSTOM_SPI_CLK_LO &
+ SPI_FLASH_CTRL_CLK_LO_MASK) <<
+ SPI_FLASH_CTRL_CLK_LO_SHIFT | (CUSTOM_SPI_CS_HOLD &
+ SPI_FLASH_CTRL_CS_HOLD_MASK) <<
+ SPI_FLASH_CTRL_CS_HOLD_SHIFT | (CUSTOM_SPI_CS_HI &
+ SPI_FLASH_CTRL_CS_HI_MASK) <<
+ SPI_FLASH_CTRL_CS_HI_SHIFT | (1 & SPI_FLASH_CTRL_INS_MASK) <<
+ SPI_FLASH_CTRL_INS_SHIFT;
+
+ iowrite32(value, hw->hw_addr + REG_SPI_FLASH_CTRL);
+
+ value |= SPI_FLASH_CTRL_START;
+ iowrite32(value, hw->hw_addr + REG_SPI_FLASH_CTRL);
+ ioread32(hw->hw_addr + REG_SPI_FLASH_CTRL);
+
+ for (i = 0; i < 10; i++) {
+ msleep(1); /* 1ms */
+ value = ioread32(hw->hw_addr + REG_SPI_FLASH_CTRL);
+ if (!(value & SPI_FLASH_CTRL_START))
+ break;
+ }
+
+ if (value & SPI_FLASH_CTRL_START)
+ return false;
+
+ *buf = ioread32(hw->hw_addr + REG_SPI_DATA);
+
+ return true;
+}
+
+/*
+ * get_permanent_address
+ * return 0 if get valid mac address,
+ */
+static int atl1_get_permanent_address(struct atl1_hw *hw)
+{
+ u32 addr[2];
+ u32 i, control;
+ u16 reg;
+ u8 eth_addr[ETH_ALEN];
+ bool key_valid;
+
+ if (is_valid_ether_addr(hw->perm_mac_addr))
+ return 0;
+
+ /* init */
+ addr[0] = addr[1] = 0;
+
+ if (!atl1_check_eeprom_exist(hw)) { /* eeprom exist */
+ reg = 0;
+ key_valid = false;
+ /* Read out all EEPROM content */
+ i = 0;
+ while (1) {
+ if (atl1_read_eeprom(hw, i + 0x100, &control)) {
+ if (key_valid) {
+ if (reg == REG_MAC_STA_ADDR)
+ addr[0] = control;
+ else if (reg == (REG_MAC_STA_ADDR + 4))
+ addr[1] = control;
+ key_valid = false;
+ } else if ((control & 0xff) == 0x5A) {
+ key_valid = true;
+ reg = (u16) (control >> 16);
+ } else
+ break; /* assume data end while encount an invalid KEYWORD */
+ } else
+ break; /* read error */
+ i += 4;
+ }
+
+/*
+ * The following 2 lines are the Attansic originals. Saving for posterity.
+ * *(u32 *) & eth_addr[2] = LONGSWAP(addr[0]);
+ * *(u16 *) & eth_addr[0] = SHORTSWAP(*(u16 *) & addr[1]);
+ */
+ *(u32 *) & eth_addr[2] = swab32(addr[0]);
+ *(u16 *) & eth_addr[0] = swab16(*(u16 *) & addr[1]);
+
+ if (is_valid_ether_addr(eth_addr)) {
+ memcpy(hw->perm_mac_addr, eth_addr, ETH_ALEN);
+ return 0;
+ }
+ return 1;
+ }
+
+ /* see if SPI FLAGS exist ? */
+ addr[0] = addr[1] = 0;
+ reg = 0;
+ key_valid = false;
+ i = 0;
+ while (1) {
+ if (atl1_spi_read(hw, i + 0x1f000, &control)) {
+ if (key_valid) {
+ if (reg == REG_MAC_STA_ADDR)
+ addr[0] = control;
+ else if (reg == (REG_MAC_STA_ADDR + 4))
+ addr[1] = control;
+ key_valid = false;
+ } else if ((control & 0xff) == 0x5A) {
+ key_valid = true;
+ reg = (u16) (control >> 16);
+ } else
+ break; /* data end */
+ } else
+ break; /* read error */
+ i += 4;
+ }
+
+/*
+ * The following 2 lines are the Attansic originals. Saving for posterity.
+ * *(u32 *) & eth_addr[2] = LONGSWAP(addr[0]);
+ * *(u16 *) & eth_addr[0] = SHORTSWAP(*(u16 *) & addr[1]);
+ */
+ *(u32 *) & eth_addr[2] = swab32(addr[0]);
+ *(u16 *) & eth_addr[0] = swab16(*(u16 *) & addr[1]);
+ if (is_valid_ether_addr(eth_addr)) {
+ memcpy(hw->perm_mac_addr, eth_addr, ETH_ALEN);
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * Reads the adapter's MAC address from the EEPROM
+ * hw - Struct containing variables accessed by shared code
+ */
+s32 atl1_read_mac_addr(struct atl1_hw *hw)
+{
+ u16 i;
+
+ if (atl1_get_permanent_address(hw))
+ random_ether_addr(hw->perm_mac_addr);
+
+ for (i = 0; i < ETH_ALEN; i++)
+ hw->mac_addr[i] = hw->perm_mac_addr[i];
+ return ATL1_SUCCESS;
+}
+
+/*
+ * Hashes an address to determine its location in the multicast table
+ * hw - Struct containing variables accessed by shared code
+ * mc_addr - the multicast address to hash
+ *
+ * atl1_hash_mc_addr
+ * purpose
+ * set hash value for a multicast address
+ * hash calcu processing :
+ * 1. calcu 32bit CRC for multicast address
+ * 2. reverse crc with MSB to LSB
+ */
+u32 atl1_hash_mc_addr(struct atl1_hw *hw, u8 *mc_addr)
+{
+ u32 crc32, value = 0;
+ int i;
+
+ crc32 = ether_crc_le(6, mc_addr);
+ crc32 = ~crc32;
+ for (i = 0; i < 32; i++)
+ value |= (((crc32 >> i) & 1) << (31 - i));
+
+ return value;
+}
+
+/*
+ * Sets the bit in the multicast table corresponding to the hash value.
+ * hw - Struct containing variables accessed by shared code
+ * hash_value - Multicast address hash value
+ */
+void atl1_hash_set(struct atl1_hw *hw, u32 hash_value)
+{
+ u32 hash_bit, hash_reg;
+ u32 mta;
+
+ /*
+ * The HASH Table is a register array of 2 32-bit registers.
+ * It is treated like an array of 64 bits. We want to set
+ * bit BitArray[hash_value]. So we figure out what register
+ * the bit is in, read it, OR in the new bit, then write
+ * back the new value. The register is determined by the
+ * upper 7 bits of the hash value and the bit within that
+ * register are determined by the lower 5 bits of the value.
+ */
+ hash_reg = (hash_value >> 31) & 0x1;
+ hash_bit = (hash_value >> 26) & 0x1F;
+ mta = ioread32((hw + REG_RX_HASH_TABLE) + (hash_reg << 2));
+ mta |= (1 << hash_bit);
+ iowrite32(mta, (hw->hw_addr + REG_RX_HASH_TABLE) + (hash_reg << 2));
+}
+
+/*
+ * Writes a value to a PHY register
+ * hw - Struct containing variables accessed by shared code
+ * reg_addr - address of the PHY register to write
+ * data - data to write to the PHY
+ */
+s32 atl1_write_phy_reg(struct atl1_hw *hw, u32 reg_addr, u16 phy_data)
+{
+ int i;
+ u32 val;
+
+ val = ((u32) (phy_data & MDIO_DATA_MASK)) << MDIO_DATA_SHIFT |
+ (reg_addr & MDIO_REG_ADDR_MASK) << MDIO_REG_ADDR_SHIFT |
+ MDIO_SUP_PREAMBLE |
+ MDIO_START | MDIO_CLK_25_4 << MDIO_CLK_SEL_SHIFT;
+ iowrite32(val, hw->hw_addr + REG_MDIO_CTRL);
+ ioread32(hw->hw_addr + REG_MDIO_CTRL);
+
+ for (i = 0; i < MDIO_WAIT_TIMES; i++) {
+ udelay(2);
+ val = ioread32(hw->hw_addr + REG_MDIO_CTRL);
+ if (!(val & (MDIO_START | MDIO_BUSY)))
+ break;
+ }
+
+ if (!(val & (MDIO_START | MDIO_BUSY)))
+ return ATL1_SUCCESS;
+
+ return ATL1_ERR_PHY;
+}
+
+/*
+ * Make L001's PHY out of Power Saving State (bug)
+ * hw - Struct containing variables accessed by shared code
+ * when power on, L001's PHY always on Power saving State
+ * (Gigabit Link forbidden)
+ */
+static s32 atl1_phy_leave_power_saving(struct atl1_hw *hw)
+{
+ s32 ret;
+ ret = atl1_write_phy_reg(hw, 29, 0x0029);
+ if (ret)
+ return ret;
+ return atl1_write_phy_reg(hw, 30, 0);
+}
+
+/*
+ *TODO: do something or get rid of this
+ */
+s32 atl1_phy_enter_power_saving(struct atl1_hw *hw)
+{
+/* s32 ret_val;
+ * u16 phy_data;
+ */
+
+/*
+ ret_val = atl1_write_phy_reg(hw, ...);
+ ret_val = atl1_write_phy_reg(hw, ...);
+ ....
+*/
+ return ATL1_SUCCESS;
+}
+
+/*
+ * Resets the PHY and make all config validate
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Sets bit 15 and 12 of the MII Control regiser (for F001 bug)
+ */
+static s32 atl1_phy_reset(struct atl1_hw *hw)
+{
+ s32 ret_val;
+ u16 phy_data;
+
+ if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR ||
+ hw->media_type == MEDIA_TYPE_1000M_FULL)
+ phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN;
+ else {
+ switch (hw->media_type) {
+ case MEDIA_TYPE_100M_FULL:
+ phy_data =
+ MII_CR_FULL_DUPLEX | MII_CR_SPEED_100 |
+ MII_CR_RESET;
+ break;
+ case MEDIA_TYPE_100M_HALF:
+ phy_data = MII_CR_SPEED_100 | MII_CR_RESET;
+ break;
+ case MEDIA_TYPE_10M_FULL:
+ phy_data =
+ MII_CR_FULL_DUPLEX | MII_CR_SPEED_10 | MII_CR_RESET;
+ break;
+ default: /* MEDIA_TYPE_10M_HALF: */
+ phy_data = MII_CR_SPEED_10 | MII_CR_RESET;
+ break;
+ }
+ }
+
+ ret_val = atl1_write_phy_reg(hw, MII_BMCR, phy_data);
+ if (ret_val) {
+ u32 val;
+ int i;
+ /* pcie serdes link may be down! */
+ printk(KERN_DEBUG "%s: autoneg caused pcie phy link down\n",
+ atl1_driver_name);
+
+ for (i = 0; i < 25; i++) {
+ msleep(1);
+ val = ioread32(hw->hw_addr + REG_MDIO_CTRL);
+ if (!(val & (MDIO_START | MDIO_BUSY)))
+ break;
+ }
+
+ if ((val & (MDIO_START | MDIO_BUSY)) != 0) {
+ printk(KERN_WARNING
+ "%s: pcie link down at least for 25ms\n",
+ atl1_driver_name);
+ return ret_val;
+ }
+ }
+ return ATL1_SUCCESS;
+}
+
+/*
+ * Configures PHY autoneg and flow control advertisement settings
+ * hw - Struct containing variables accessed by shared code
+ */
+s32 atl1_phy_setup_autoneg_adv(struct atl1_hw *hw)
+{
+ s32 ret_val;
+ s16 mii_autoneg_adv_reg;
+ s16 mii_1000t_ctrl_reg;
+
+ /* Read the MII Auto-Neg Advertisement Register (Address 4). */
+ mii_autoneg_adv_reg = MII_AR_DEFAULT_CAP_MASK;
+
+ /* Read the MII 1000Base-T Control Register (Address 9). */
+ mii_1000t_ctrl_reg = MII_AT001_CR_1000T_DEFAULT_CAP_MASK;
+
+ /*
+ * First we clear all the 10/100 mb speed bits in the Auto-Neg
+ * Advertisement Register (Address 4) and the 1000 mb speed bits in
+ * the 1000Base-T Control Register (Address 9).
+ */
+ mii_autoneg_adv_reg &= ~MII_AR_SPEED_MASK;
+ mii_1000t_ctrl_reg &= ~MII_AT001_CR_1000T_SPEED_MASK;
+
+ /*
+ * Need to parse media_type and set up
+ * the appropriate PHY registers.
+ */
+ switch (hw->media_type) {
+ case MEDIA_TYPE_AUTO_SENSOR:
+ mii_autoneg_adv_reg |= (MII_AR_10T_HD_CAPS |
+ MII_AR_10T_FD_CAPS |
+ MII_AR_100TX_HD_CAPS |
+ MII_AR_100TX_FD_CAPS);
+ mii_1000t_ctrl_reg |= MII_AT001_CR_1000T_FD_CAPS;
+ break;
+
+ case MEDIA_TYPE_1000M_FULL:
+ mii_1000t_ctrl_reg |= MII_AT001_CR_1000T_FD_CAPS;
+ break;
+
+ case MEDIA_TYPE_100M_FULL:
+ mii_autoneg_adv_reg |= MII_AR_100TX_FD_CAPS;
+ break;
+
+ case MEDIA_TYPE_100M_HALF:
+ mii_autoneg_adv_reg |= MII_AR_100TX_HD_CAPS;
+ break;
+
+ case MEDIA_TYPE_10M_FULL:
+ mii_autoneg_adv_reg |= MII_AR_10T_FD_CAPS;
+ break;
+
+ default:
+ mii_autoneg_adv_reg |= MII_AR_10T_HD_CAPS;
+ break;
+ }
+
+ /* flow control fixed to enable all */
+ mii_autoneg_adv_reg |= (MII_AR_ASM_DIR | MII_AR_PAUSE);
+
+ hw->mii_autoneg_adv_reg = mii_autoneg_adv_reg;
+ hw->mii_1000t_ctrl_reg = mii_1000t_ctrl_reg;
+
+ ret_val = atl1_write_phy_reg(hw, MII_ADVERTISE, mii_autoneg_adv_reg);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = atl1_write_phy_reg(hw, MII_AT001_CR, mii_1000t_ctrl_reg);
+ if (ret_val)
+ return ret_val;
+
+ return ATL1_SUCCESS;
+}
+
+/*
+ * Configures link settings.
+ * hw - Struct containing variables accessed by shared code
+ * Assumes the hardware has previously been reset and the
+ * transmitter and receiver are not enabled.
+ */
+static s32 atl1_setup_link(struct atl1_hw *hw)
+{
+ s32 ret_val;
+
+ /*
+ * Options:
+ * PHY will advertise value(s) parsed from
+ * autoneg_advertised and fc
+ * no matter what autoneg is , We will not wait link result.
+ */
+ ret_val = atl1_phy_setup_autoneg_adv(hw);
+ if (ret_val) {
+ printk(KERN_DEBUG "%s: error setting up autonegotiation\n",
+ atl1_driver_name);
+ return ret_val;
+ }
+ /* SW.Reset , En-Auto-Neg if needed */
+ ret_val = atl1_phy_reset(hw);
+ if (ret_val) {
+ printk(KERN_DEBUG "%s: error resetting the phy\n",
+ atl1_driver_name);
+ return ret_val;
+ }
+ hw->phy_configured = true;
+ return ret_val;
+}
+
+static struct atl1_spi_flash_dev flash_table[] = {
+/* MFR_NAME WRSR READ PRGM WREN WRDI RDSR RDID SECTOR_ERASE CHIP_ERASE */
+ {"Atmel", 0x00, 0x03, 0x02, 0x06, 0x04, 0x05, 0x15, 0x52, 0x62},
+ {"SST", 0x01, 0x03, 0x02, 0x06, 0x04, 0x05, 0x90, 0x20, 0x60},
+ {"ST", 0x01, 0x03, 0x02, 0x06, 0x04, 0x05, 0xAB, 0xD8, 0xC7},
+};
+
+static void atl1_init_flash_opcode(struct atl1_hw *hw)
+{
+ if (hw->flash_vendor >= sizeof(flash_table) / sizeof(flash_table[0]))
+ hw->flash_vendor = 0; /* ATMEL */
+
+ /* Init OP table */
+ iowrite8(flash_table[hw->flash_vendor].cmd_program,
+ hw->hw_addr + REG_SPI_FLASH_OP_PROGRAM);
+ iowrite8(flash_table[hw->flash_vendor].cmd_sector_erase,
+ hw->hw_addr + REG_SPI_FLASH_OP_SC_ERASE);
+ iowrite8(flash_table[hw->flash_vendor].cmd_chip_erase,
+ hw->hw_addr + REG_SPI_FLASH_OP_CHIP_ERASE);
+ iowrite8(flash_table[hw->flash_vendor].cmd_rdid,
+ hw->hw_addr + REG_SPI_FLASH_OP_RDID);
+ iowrite8(flash_table[hw->flash_vendor].cmd_wren,
+ hw->hw_addr + REG_SPI_FLASH_OP_WREN);
+ iowrite8(flash_table[hw->flash_vendor].cmd_rdsr,
+ hw->hw_addr + REG_SPI_FLASH_OP_RDSR);
+ iowrite8(flash_table[hw->flash_vendor].cmd_wrsr,
+ hw->hw_addr + REG_SPI_FLASH_OP_WRSR);
+ iowrite8(flash_table[hw->flash_vendor].cmd_read,
+ hw->hw_addr + REG_SPI_FLASH_OP_READ);
+}
+
+/*
+ * Performs basic configuration of the adapter.
+ * hw - Struct containing variables accessed by shared code
+ * Assumes that the controller has previously been reset and is in a
+ * post-reset uninitialized state. Initializes multicast table,
+ * and Calls routines to setup link
+ * Leaves the transmit and receive units disabled and uninitialized.
+ */
+s32 atl1_init_hw(struct atl1_hw *hw)
+{
+ u32 ret_val = 0;
+
+ /* Zero out the Multicast HASH table */
+ iowrite32(0, hw->hw_addr + REG_RX_HASH_TABLE);
+ /* clear the old settings from the multicast hash table */
+ iowrite32(0, (hw->hw_addr + REG_RX_HASH_TABLE) + (1 << 2));
+
+ atl1_init_flash_opcode(hw);
+
+ if (!hw->phy_configured) {
+ /* enable GPHY LinkChange Interrrupt */
+ ret_val = atl1_write_phy_reg(hw, 18, 0xC00);
+ if (ret_val)
+ return ret_val;
+ /* make PHY out of power-saving state */
+ ret_val = atl1_phy_leave_power_saving(hw);
+ if (ret_val)
+ return ret_val;
+ /* Call a subroutine to configure the link */
+ ret_val = atl1_setup_link(hw);
+ }
+ return ret_val;
+}
+
+/*
+ * Detects the current speed and duplex settings of the hardware.
+ * hw - Struct containing variables accessed by shared code
+ * speed - Speed of the connection
+ * duplex - Duplex setting of the connection
+ */
+s32 atl1_get_speed_and_duplex(struct atl1_hw *hw, u16 *speed, u16 *duplex)
+{
+ s32 ret_val;
+ u16 phy_data;
+
+ /* ; --- Read PHY Specific Status Register (17) */
+ ret_val = atl1_read_phy_reg(hw, MII_AT001_PSSR, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ if (!(phy_data & MII_AT001_PSSR_SPD_DPLX_RESOLVED))
+ return ATL1_ERR_PHY_RES;
+
+ switch (phy_data & MII_AT001_PSSR_SPEED) {
+ case MII_AT001_PSSR_1000MBS:
+ *speed = SPEED_1000;
+ break;
+ case MII_AT001_PSSR_100MBS:
+ *speed = SPEED_100;
+ break;
+ case MII_AT001_PSSR_10MBS:
+ *speed = SPEED_10;
+ break;
+ default:
+ printk(KERN_DEBUG "%s: error getting speed\n",
+ atl1_driver_name);
+ return ATL1_ERR_PHY_SPEED;
+ break;
+ }
+ if (phy_data & MII_AT001_PSSR_DPLX)
+ *duplex = FULL_DUPLEX;
+ else
+ *duplex = HALF_DUPLEX;
+
+ return ATL1_SUCCESS;
+}
+
+void atl1_set_mac_addr(struct atl1_hw *hw)
+{
+ u32 value;
+ /*
+ * 00-0B-6A-F6-00-DC
+ * 0: 6AF600DC 1: 000B
+ * low dword
+ */
+ value = (((u32) hw->mac_addr[2]) << 24) |
+ (((u32) hw->mac_addr[3]) << 16) |
+ (((u32) hw->mac_addr[4]) << 8) | (((u32) hw->mac_addr[5]));
+ iowrite32(value, hw->hw_addr + REG_MAC_STA_ADDR);
+ /* high dword */
+ value = (((u32) hw->mac_addr[0]) << 8) | (((u32) hw->mac_addr[1]));
+ iowrite32(value, (hw->hw_addr + REG_MAC_STA_ADDR) + (1 << 2));
+}
diff --git a/drivers/net/atl1/atl1_hw.h b/drivers/net/atl1/atl1_hw.h
new file mode 100644
index 00000000000..100c09c66e6
--- /dev/null
+++ b/drivers/net/atl1/atl1_hw.h
@@ -0,0 +1,951 @@
+/*
+ * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved.
+ * Copyright(c) 2006 Chris Snook <csnook@redhat.com>
+ * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com>
+ *
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * There are a lot of defines in here that are unused and/or have cryptic
+ * names. Please leave them alone, as they're the closest thing we have
+ * to a spec from Attansic at present. *ahem* -- CHS
+ */
+
+#ifndef _ATL1_HW_H_
+#define _ATL1_HW_H_
+
+#include <linux/types.h>
+#include <linux/mii.h>
+
+struct atl1_adapter;
+struct atl1_hw;
+
+/* function prototypes needed by multiple files */
+s32 atl1_phy_setup_autoneg_adv(struct atl1_hw *hw);
+s32 atl1_write_phy_reg(struct atl1_hw *hw, u32 reg_addr, u16 phy_data);
+s32 atl1_get_speed_and_duplex(struct atl1_hw *hw, u16 *speed, u16 *duplex);
+s32 atl1_read_mac_addr(struct atl1_hw *hw);
+s32 atl1_init_hw(struct atl1_hw *hw);
+s32 atl1_get_speed_and_duplex(struct atl1_hw *hw, u16 *speed, u16 *duplex);
+s32 atl1_set_speed_and_duplex(struct atl1_hw *hw, u16 speed, u16 duplex);
+u32 atl1_hash_mc_addr(struct atl1_hw *hw, u8 *mc_addr);
+void atl1_hash_set(struct atl1_hw *hw, u32 hash_value);
+s32 atl1_read_phy_reg(struct atl1_hw *hw, u16 reg_addr, u16 *phy_data);
+void atl1_set_mac_addr(struct atl1_hw *hw);
+s32 atl1_phy_enter_power_saving(struct atl1_hw *hw);
+s32 atl1_reset_hw(struct atl1_hw *hw);
+void atl1_check_options(struct atl1_adapter *adapter);
+
+/* register definitions */
+#define REG_PCIE_CAP_LIST 0x58
+
+#define REG_VPD_CAP 0x6C
+#define VPD_CAP_ID_MASK 0xff
+#define VPD_CAP_ID_SHIFT 0
+#define VPD_CAP_NEXT_PTR_MASK 0xFF
+#define VPD_CAP_NEXT_PTR_SHIFT 8
+#define VPD_CAP_VPD_ADDR_MASK 0x7FFF
+#define VPD_CAP_VPD_ADDR_SHIFT 16
+#define VPD_CAP_VPD_FLAG 0x80000000
+
+#define REG_VPD_DATA 0x70
+
+#define REG_SPI_FLASH_CTRL 0x200
+#define SPI_FLASH_CTRL_STS_NON_RDY 0x1
+#define SPI_FLASH_CTRL_STS_WEN 0x2
+#define SPI_FLASH_CTRL_STS_WPEN 0x80
+#define SPI_FLASH_CTRL_DEV_STS_MASK 0xFF
+#define SPI_FLASH_CTRL_DEV_STS_SHIFT 0
+#define SPI_FLASH_CTRL_INS_MASK 0x7
+#define SPI_FLASH_CTRL_INS_SHIFT 8
+#define SPI_FLASH_CTRL_START 0x800
+#define SPI_FLASH_CTRL_EN_VPD 0x2000
+#define SPI_FLASH_CTRL_LDSTART 0x8000
+#define SPI_FLASH_CTRL_CS_HI_MASK 0x3
+#define SPI_FLASH_CTRL_CS_HI_SHIFT 16
+#define SPI_FLASH_CTRL_CS_HOLD_MASK 0x3
+#define SPI_FLASH_CTRL_CS_HOLD_SHIFT 18
+#define SPI_FLASH_CTRL_CLK_LO_MASK 0x3
+#define SPI_FLASH_CTRL_CLK_LO_SHIFT 20
+#define SPI_FLASH_CTRL_CLK_HI_MASK 0x3
+#define SPI_FLASH_CTRL_CLK_HI_SHIFT 22
+#define SPI_FLASH_CTRL_CS_SETUP_MASK 0x3
+#define SPI_FLASH_CTRL_CS_SETUP_SHIFT 24
+#define SPI_FLASH_CTRL_EROM_PGSZ_MASK 0x3
+#define SPI_FLASH_CTRL_EROM_PGSZ_SHIFT 26
+#define SPI_FLASH_CTRL_WAIT_READY 0x10000000
+
+#define REG_SPI_ADDR 0x204
+
+#define REG_SPI_DATA 0x208
+
+#define REG_SPI_FLASH_CONFIG 0x20C
+#define SPI_FLASH_CONFIG_LD_ADDR_MASK 0xFFFFFF
+#define SPI_FLASH_CONFIG_LD_ADDR_SHIFT 0
+#define SPI_FLASH_CONFIG_VPD_ADDR_MASK 0x3
+#define SPI_FLASH_CONFIG_VPD_ADDR_SHIFT 24
+#define SPI_FLASH_CONFIG_LD_EXIST 0x4000000
+
+#define REG_SPI_FLASH_OP_PROGRAM 0x210
+#define REG_SPI_FLASH_OP_SC_ERASE 0x211
+#define REG_SPI_FLASH_OP_CHIP_ERASE 0x212
+#define REG_SPI_FLASH_OP_RDID 0x213
+#define REG_SPI_FLASH_OP_WREN 0x214
+#define REG_SPI_FLASH_OP_RDSR 0x215
+#define REG_SPI_FLASH_OP_WRSR 0x216
+#define REG_SPI_FLASH_OP_READ 0x217
+
+#define REG_TWSI_CTRL 0x218
+#define TWSI_CTRL_LD_OFFSET_MASK 0xFF
+#define TWSI_CTRL_LD_OFFSET_SHIFT 0
+#define TWSI_CTRL_LD_SLV_ADDR_MASK 0x7
+#define TWSI_CTRL_LD_SLV_ADDR_SHIFT 8
+#define TWSI_CTRL_SW_LDSTART 0x800
+#define TWSI_CTRL_HW_LDSTART 0x1000
+#define TWSI_CTRL_SMB_SLV_ADDR_MASK 0x7F
+#define TWSI_CTRL_SMB_SLV_ADDR_SHIFT 15
+#define TWSI_CTRL_LD_EXIST 0x400000
+#define TWSI_CTRL_READ_FREQ_SEL_MASK 0x3
+#define TWSI_CTRL_READ_FREQ_SEL_SHIFT 23
+#define TWSI_CTRL_FREQ_SEL_100K 0
+#define TWSI_CTRL_FREQ_SEL_200K 1
+#define TWSI_CTRL_FREQ_SEL_300K 2
+#define TWSI_CTRL_FREQ_SEL_400K 3
+#define TWSI_CTRL_SMB_SLV_ADDR
+#define TWSI_CTRL_WRITE_FREQ_SEL_MASK 0x3
+#define TWSI_CTRL_WRITE_FREQ_SEL_SHIFT 24
+
+#define REG_PCIE_DEV_MISC_CTRL 0x21C
+#define PCIE_DEV_MISC_CTRL_EXT_PIPE 0x2
+#define PCIE_DEV_MISC_CTRL_RETRY_BUFDIS 0x1
+#define PCIE_DEV_MISC_CTRL_SPIROM_EXIST 0x4
+#define PCIE_DEV_MISC_CTRL_SERDES_ENDIAN 0x8
+#define PCIE_DEV_MISC_CTRL_SERDES_SEL_DIN 0x10
+
+/* Selene Master Control Register */
+#define REG_MASTER_CTRL 0x1400
+#define MASTER_CTRL_SOFT_RST 0x1
+#define MASTER_CTRL_MTIMER_EN 0x2
+#define MASTER_CTRL_ITIMER_EN 0x4
+#define MASTER_CTRL_MANUAL_INT 0x8
+#define MASTER_CTRL_REV_NUM_SHIFT 16
+#define MASTER_CTRL_REV_NUM_MASK 0xff
+#define MASTER_CTRL_DEV_ID_SHIFT 24
+#define MASTER_CTRL_DEV_ID_MASK 0xff
+
+/* Timer Initial Value Register */
+#define REG_MANUAL_TIMER_INIT 0x1404
+
+/* IRQ ModeratorTimer Initial Value Register */
+#define REG_IRQ_MODU_TIMER_INIT 0x1408
+
+#define REG_GPHY_ENABLE 0x140C
+
+/* IRQ Anti-Lost Timer Initial Value Register */
+#define REG_CMBDISDMA_TIMER 0x140E
+
+/* Block IDLE Status Register */
+#define REG_IDLE_STATUS 0x1410
+#define IDLE_STATUS_RXMAC 1
+#define IDLE_STATUS_TXMAC 2
+#define IDLE_STATUS_RXQ 4
+#define IDLE_STATUS_TXQ 8
+#define IDLE_STATUS_DMAR 0x10
+#define IDLE_STATUS_DMAW 0x20
+#define IDLE_STATUS_SMB 0x40
+#define IDLE_STATUS_CMB 0x80
+
+/* MDIO Control Register */
+#define REG_MDIO_CTRL 0x1414
+#define MDIO_DATA_MASK 0xffff
+#define MDIO_DATA_SHIFT 0
+#define MDIO_REG_ADDR_MASK 0x1f
+#define MDIO_REG_ADDR_SHIFT 16
+#define MDIO_RW 0x200000
+#define MDIO_SUP_PREAMBLE 0x400000
+#define MDIO_START 0x800000
+#define MDIO_CLK_SEL_SHIFT 24
+#define MDIO_CLK_25_4 0
+#define MDIO_CLK_25_6 2
+#define MDIO_CLK_25_8 3
+#define MDIO_CLK_25_10 4
+#define MDIO_CLK_25_14 5
+#define MDIO_CLK_25_20 6
+#define MDIO_CLK_25_28 7
+#define MDIO_BUSY 0x8000000
+#define MDIO_WAIT_TIMES 30
+
+/* MII PHY Status Register */
+#define REG_PHY_STATUS 0x1418
+
+/* BIST Control and Status Register0 (for the Packet Memory) */
+#define REG_BIST0_CTRL 0x141c
+#define BIST0_NOW 0x1
+#define BIST0_SRAM_FAIL 0x2
+#define BIST0_FUSE_FLAG 0x4
+#define REG_BIST1_CTRL 0x1420
+#define BIST1_NOW 0x1
+#define BIST1_SRAM_FAIL 0x2
+#define BIST1_FUSE_FLAG 0x4
+
+/* MAC Control Register */
+#define REG_MAC_CTRL 0x1480
+#define MAC_CTRL_TX_EN 1
+#define MAC_CTRL_RX_EN 2
+#define MAC_CTRL_TX_FLOW 4
+#define MAC_CTRL_RX_FLOW 8
+#define MAC_CTRL_LOOPBACK 0x10
+#define MAC_CTRL_DUPLX 0x20
+#define MAC_CTRL_ADD_CRC 0x40
+#define MAC_CTRL_PAD 0x80
+#define MAC_CTRL_LENCHK 0x100
+#define MAC_CTRL_HUGE_EN 0x200
+#define MAC_CTRL_PRMLEN_SHIFT 10
+#define MAC_CTRL_PRMLEN_MASK 0xf
+#define MAC_CTRL_RMV_VLAN 0x4000
+#define MAC_CTRL_PROMIS_EN 0x8000
+#define MAC_CTRL_TX_PAUSE 0x10000
+#define MAC_CTRL_SCNT 0x20000
+#define MAC_CTRL_SRST_TX 0x40000
+#define MAC_CTRL_TX_SIMURST 0x80000
+#define MAC_CTRL_SPEED_SHIFT 20
+#define MAC_CTRL_SPEED_MASK 0x300000
+#define MAC_CTRL_SPEED_1000 2
+#define MAC_CTRL_SPEED_10_100 1
+#define MAC_CTRL_DBG_TX_BKPRESURE 0x400000
+#define MAC_CTRL_TX_HUGE 0x800000
+#define MAC_CTRL_RX_CHKSUM_EN 0x1000000
+#define MAC_CTRL_MC_ALL_EN 0x2000000
+#define MAC_CTRL_BC_EN 0x4000000
+#define MAC_CTRL_DBG 0x8000000
+
+/* MAC IPG/IFG Control Register */
+#define REG_MAC_IPG_IFG 0x1484
+#define MAC_IPG_IFG_IPGT_SHIFT 0
+#define MAC_IPG_IFG_IPGT_MASK 0x7f
+#define MAC_IPG_IFG_MIFG_SHIFT 8
+#define MAC_IPG_IFG_MIFG_MASK 0xff
+#define MAC_IPG_IFG_IPGR1_SHIFT 16
+#define MAC_IPG_IFG_IPGR1_MASK 0x7f
+#define MAC_IPG_IFG_IPGR2_SHIFT 24
+#define MAC_IPG_IFG_IPGR2_MASK 0x7f
+
+/* MAC STATION ADDRESS */
+#define REG_MAC_STA_ADDR 0x1488
+
+/* Hash table for multicast address */
+#define REG_RX_HASH_TABLE 0x1490
+
+/* MAC Half-Duplex Control Register */
+#define REG_MAC_HALF_DUPLX_CTRL 0x1498
+#define MAC_HALF_DUPLX_CTRL_LCOL_SHIFT 0
+#define MAC_HALF_DUPLX_CTRL_LCOL_MASK 0x3ff
+#define MAC_HALF_DUPLX_CTRL_RETRY_SHIFT 12
+#define MAC_HALF_DUPLX_CTRL_RETRY_MASK 0xf
+#define MAC_HALF_DUPLX_CTRL_EXC_DEF_EN 0x10000
+#define MAC_HALF_DUPLX_CTRL_NO_BACK_C 0x20000
+#define MAC_HALF_DUPLX_CTRL_NO_BACK_P 0x40000
+#define MAC_HALF_DUPLX_CTRL_ABEBE 0x80000
+#define MAC_HALF_DUPLX_CTRL_ABEBT_SHIFT 20
+#define MAC_HALF_DUPLX_CTRL_ABEBT_MASK 0xf
+#define MAC_HALF_DUPLX_CTRL_JAMIPG_SHIFT 24
+#define MAC_HALF_DUPLX_CTRL_JAMIPG_MASK 0xf
+
+/* Maximum Frame Length Control Register */
+#define REG_MTU 0x149c
+
+/* Wake-On-Lan control register */
+#define REG_WOL_CTRL 0x14a0
+#define WOL_PATTERN_EN 0x00000001
+#define WOL_PATTERN_PME_EN 0x00000002
+#define WOL_MAGIC_EN 0x00000004
+#define WOL_MAGIC_PME_EN 0x00000008
+#define WOL_LINK_CHG_EN 0x00000010
+#define WOL_LINK_CHG_PME_EN 0x00000020
+#define WOL_PATTERN_ST 0x00000100
+#define WOL_MAGIC_ST 0x00000200
+#define WOL_LINKCHG_ST 0x00000400
+#define WOL_CLK_SWITCH_EN 0x00008000
+#define WOL_PT0_EN 0x00010000
+#define WOL_PT1_EN 0x00020000
+#define WOL_PT2_EN 0x00040000
+#define WOL_PT3_EN 0x00080000
+#define WOL_PT4_EN 0x00100000
+#define WOL_PT5_EN 0x00200000
+#define WOL_PT6_EN 0x00400000
+
+/* WOL Length ( 2 DWORD ) */
+#define REG_WOL_PATTERN_LEN 0x14a4
+#define WOL_PT_LEN_MASK 0x7f
+#define WOL_PT0_LEN_SHIFT 0
+#define WOL_PT1_LEN_SHIFT 8
+#define WOL_PT2_LEN_SHIFT 16
+#define WOL_PT3_LEN_SHIFT 24
+#define WOL_PT4_LEN_SHIFT 0
+#define WOL_PT5_LEN_SHIFT 8
+#define WOL_PT6_LEN_SHIFT 16
+
+/* Internal SRAM Partition Register */
+#define REG_SRAM_RFD_ADDR 0x1500
+#define REG_SRAM_RFD_LEN (REG_SRAM_RFD_ADDR+ 4)
+#define REG_SRAM_RRD_ADDR (REG_SRAM_RFD_ADDR+ 8)
+#define REG_SRAM_RRD_LEN (REG_SRAM_RFD_ADDR+12)
+#define REG_SRAM_TPD_ADDR (REG_SRAM_RFD_ADDR+16)
+#define REG_SRAM_TPD_LEN (REG_SRAM_RFD_ADDR+20)
+#define REG_SRAM_TRD_ADDR (REG_SRAM_RFD_ADDR+24)
+#define REG_SRAM_TRD_LEN (REG_SRAM_RFD_ADDR+28)
+#define REG_SRAM_RXF_ADDR (REG_SRAM_RFD_ADDR+32)
+#define REG_SRAM_RXF_LEN (REG_SRAM_RFD_ADDR+36)
+#define REG_SRAM_TXF_ADDR (REG_SRAM_RFD_ADDR+40)
+#define REG_SRAM_TXF_LEN (REG_SRAM_RFD_ADDR+44)
+#define REG_SRAM_TCPH_PATH_ADDR (REG_SRAM_RFD_ADDR+48)
+#define SRAM_TCPH_ADDR_MASK 0x0fff
+#define SRAM_TCPH_ADDR_SHIFT 0
+#define SRAM_PATH_ADDR_MASK 0x0fff
+#define SRAM_PATH_ADDR_SHIFT 16
+
+/* Load Ptr Register */
+#define REG_LOAD_PTR (REG_SRAM_RFD_ADDR+52)
+
+/* Descriptor Control register */
+#define REG_DESC_BASE_ADDR_HI 0x1540
+#define REG_DESC_RFD_ADDR_LO (REG_DESC_BASE_ADDR_HI+4)
+#define REG_DESC_RRD_ADDR_LO (REG_DESC_BASE_ADDR_HI+8)
+#define REG_DESC_TPD_ADDR_LO (REG_DESC_BASE_ADDR_HI+12)
+#define REG_DESC_CMB_ADDR_LO (REG_DESC_BASE_ADDR_HI+16)
+#define REG_DESC_SMB_ADDR_LO (REG_DESC_BASE_ADDR_HI+20)
+#define REG_DESC_RFD_RRD_RING_SIZE (REG_DESC_BASE_ADDR_HI+24)
+#define DESC_RFD_RING_SIZE_MASK 0x7ff
+#define DESC_RFD_RING_SIZE_SHIFT 0
+#define DESC_RRD_RING_SIZE_MASK 0x7ff
+#define DESC_RRD_RING_SIZE_SHIFT 16
+#define REG_DESC_TPD_RING_SIZE (REG_DESC_BASE_ADDR_HI+28)
+#define DESC_TPD_RING_SIZE_MASK 0x3ff
+#define DESC_TPD_RING_SIZE_SHIFT 0
+
+/* TXQ Control Register */
+#define REG_TXQ_CTRL 0x1580
+#define TXQ_CTRL_TPD_BURST_NUM_SHIFT 0
+#define TXQ_CTRL_TPD_BURST_NUM_MASK 0x1f
+#define TXQ_CTRL_EN 0x20
+#define TXQ_CTRL_ENH_MODE 0x40
+#define TXQ_CTRL_TPD_FETCH_TH_SHIFT 8
+#define TXQ_CTRL_TPD_FETCH_TH_MASK 0x3f
+#define TXQ_CTRL_TXF_BURST_NUM_SHIFT 16
+#define TXQ_CTRL_TXF_BURST_NUM_MASK 0xffff
+
+/* Jumbo packet Threshold for task offload */
+#define REG_TX_JUMBO_TASK_TH_TPD_IPG 0x1584
+#define TX_JUMBO_TASK_TH_MASK 0x7ff
+#define TX_JUMBO_TASK_TH_SHIFT 0
+#define TX_TPD_MIN_IPG_MASK 0x1f
+#define TX_TPD_MIN_IPG_SHIFT 16
+
+/* RXQ Control Register */
+#define REG_RXQ_CTRL 0x15a0
+#define RXQ_CTRL_RFD_BURST_NUM_SHIFT 0
+#define RXQ_CTRL_RFD_BURST_NUM_MASK 0xff
+#define RXQ_CTRL_RRD_BURST_THRESH_SHIFT 8
+#define RXQ_CTRL_RRD_BURST_THRESH_MASK 0xff
+#define RXQ_CTRL_RFD_PREF_MIN_IPG_SHIFT 16
+#define RXQ_CTRL_RFD_PREF_MIN_IPG_MASK 0x1f
+#define RXQ_CTRL_CUT_THRU_EN 0x40000000
+#define RXQ_CTRL_EN 0x80000000
+
+/* Rx jumbo packet threshold and rrd retirement timer */
+#define REG_RXQ_JMBOSZ_RRDTIM (REG_RXQ_CTRL+ 4)
+#define RXQ_JMBOSZ_TH_MASK 0x7ff
+#define RXQ_JMBOSZ_TH_SHIFT 0
+#define RXQ_JMBO_LKAH_MASK 0xf
+#define RXQ_JMBO_LKAH_SHIFT 11
+#define RXQ_RRD_TIMER_MASK 0xffff
+#define RXQ_RRD_TIMER_SHIFT 16
+
+/* RFD flow control register */
+#define REG_RXQ_RXF_PAUSE_THRESH (REG_RXQ_CTRL+ 8)
+#define RXQ_RXF_PAUSE_TH_HI_SHIFT 16
+#define RXQ_RXF_PAUSE_TH_HI_MASK 0xfff
+#define RXQ_RXF_PAUSE_TH_LO_SHIFT 0
+#define RXQ_RXF_PAUSE_TH_LO_MASK 0xfff
+
+/* RRD flow control register */
+#define REG_RXQ_RRD_PAUSE_THRESH (REG_RXQ_CTRL+12)
+#define RXQ_RRD_PAUSE_TH_HI_SHIFT 0
+#define RXQ_RRD_PAUSE_TH_HI_MASK 0xfff
+#define RXQ_RRD_PAUSE_TH_LO_SHIFT 16
+#define RXQ_RRD_PAUSE_TH_LO_MASK 0xfff
+
+/* DMA Engine Control Register */
+#define REG_DMA_CTRL 0x15c0
+#define DMA_CTRL_DMAR_IN_ORDER 0x1
+#define DMA_CTRL_DMAR_ENH_ORDER 0x2
+#define DMA_CTRL_DMAR_OUT_ORDER 0x4
+#define DMA_CTRL_RCB_VALUE 0x8
+#define DMA_CTRL_DMAR_BURST_LEN_SHIFT 4
+#define DMA_CTRL_DMAR_BURST_LEN_MASK 7
+#define DMA_CTRL_DMAW_BURST_LEN_SHIFT 7
+#define DMA_CTRL_DMAW_BURST_LEN_MASK 7
+#define DMA_CTRL_DMAR_EN 0x400
+#define DMA_CTRL_DMAW_EN 0x800
+
+/* CMB/SMB Control Register */
+#define REG_CSMB_CTRL 0x15d0
+#define CSMB_CTRL_CMB_NOW 1
+#define CSMB_CTRL_SMB_NOW 2
+#define CSMB_CTRL_CMB_EN 4
+#define CSMB_CTRL_SMB_EN 8
+
+/* CMB DMA Write Threshold Register */
+#define REG_CMB_WRITE_TH (REG_CSMB_CTRL+ 4)
+#define CMB_RRD_TH_SHIFT 0
+#define CMB_RRD_TH_MASK 0x7ff
+#define CMB_TPD_TH_SHIFT 16
+#define CMB_TPD_TH_MASK 0x7ff
+
+/* RX/TX count-down timer to trigger CMB-write. 2us resolution. */
+#define REG_CMB_WRITE_TIMER (REG_CSMB_CTRL+ 8)
+#define CMB_RX_TM_SHIFT 0
+#define CMB_RX_TM_MASK 0xffff
+#define CMB_TX_TM_SHIFT 16
+#define CMB_TX_TM_MASK 0xffff
+
+/* Number of packet received since last CMB write */
+#define REG_CMB_RX_PKT_CNT (REG_CSMB_CTRL+12)
+
+/* Number of packet transmitted since last CMB write */
+#define REG_CMB_TX_PKT_CNT (REG_CSMB_CTRL+16)
+
+/* SMB auto DMA timer register */
+#define REG_SMB_TIMER (REG_CSMB_CTRL+20)
+
+/* Mailbox Register */
+#define REG_MAILBOX 0x15f0
+#define MB_RFD_PROD_INDX_SHIFT 0
+#define MB_RFD_PROD_INDX_MASK 0x7ff
+#define MB_RRD_CONS_INDX_SHIFT 11
+#define MB_RRD_CONS_INDX_MASK 0x7ff
+#define MB_TPD_PROD_INDX_SHIFT 22
+#define MB_TPD_PROD_INDX_MASK 0x3ff
+
+/* Interrupt Status Register */
+#define REG_ISR 0x1600
+#define ISR_SMB 1
+#define ISR_TIMER 2
+#define ISR_MANUAL 4
+#define ISR_RXF_OV 8
+#define ISR_RFD_UNRUN 0x10
+#define ISR_RRD_OV 0x20
+#define ISR_TXF_UNRUN 0x40
+#define ISR_LINK 0x80
+#define ISR_HOST_RFD_UNRUN 0x100
+#define ISR_HOST_RRD_OV 0x200
+#define ISR_DMAR_TO_RST 0x400
+#define ISR_DMAW_TO_RST 0x800
+#define ISR_GPHY 0x1000
+#define ISR_RX_PKT 0x10000
+#define ISR_TX_PKT 0x20000
+#define ISR_TX_DMA 0x40000
+#define ISR_RX_DMA 0x80000
+#define ISR_CMB_RX 0x100000
+#define ISR_CMB_TX 0x200000
+#define ISR_MAC_RX 0x400000
+#define ISR_MAC_TX 0x800000
+#define ISR_UR_DETECTED 0x1000000
+#define ISR_FERR_DETECTED 0x2000000
+#define ISR_NFERR_DETECTED 0x4000000
+#define ISR_CERR_DETECTED 0x8000000
+#define ISR_PHY_LINKDOWN 0x10000000
+#define ISR_DIS_SMB 0x20000000
+#define ISR_DIS_DMA 0x40000000
+#define ISR_DIS_INT 0x80000000
+
+/* Interrupt Mask Register */
+#define REG_IMR 0x1604
+
+/* Normal Interrupt mask */
+#define IMR_NORMAL_MASK (\
+ ISR_SMB |\
+ ISR_GPHY |\
+ ISR_PHY_LINKDOWN|\
+ ISR_DMAR_TO_RST |\
+ ISR_DMAW_TO_RST |\
+ ISR_CMB_TX |\
+ ISR_CMB_RX )
+
+/* Debug Interrupt Mask (enable all interrupt) */
+#define IMR_DEBUG_MASK (\
+ ISR_SMB |\
+ ISR_TIMER |\
+ ISR_MANUAL |\
+ ISR_RXF_OV |\
+ ISR_RFD_UNRUN |\
+ ISR_RRD_OV |\
+ ISR_TXF_UNRUN |\
+ ISR_LINK |\
+ ISR_CMB_TX |\
+ ISR_CMB_RX |\
+ ISR_RX_PKT |\
+ ISR_TX_PKT |\
+ ISR_MAC_RX |\
+ ISR_MAC_TX )
+
+/* Interrupt Status Register */
+#define REG_RFD_RRD_IDX 0x1800
+#define REG_TPD_IDX 0x1804
+
+/* MII definition */
+/* PHY Common Register */
+#define MII_AT001_CR 0x09
+#define MII_AT001_SR 0x0A
+#define MII_AT001_ESR 0x0F
+#define MII_AT001_PSCR 0x10
+#define MII_AT001_PSSR 0x11
+
+/* PHY Control Register */
+#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */
+#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */
+#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */
+#define MII_CR_ISOLATE 0x0400 /* Isolate PHY from MII */
+#define MII_CR_POWER_DOWN 0x0800 /* Power down */
+#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */
+#define MII_CR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */
+#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */
+#define MII_CR_SPEED_MASK 0x2040
+#define MII_CR_SPEED_1000 0x0040
+#define MII_CR_SPEED_100 0x2000
+#define MII_CR_SPEED_10 0x0000
+
+/* PHY Status Register */
+#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */
+#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */
+#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */
+#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */
+#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */
+#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */
+#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */
+#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */
+#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */
+#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */
+#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */
+#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */
+#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */
+#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */
+#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */
+
+/* Link partner ability register. */
+#define MII_LPA_SLCT 0x001f /* Same as advertise selector */
+#define MII_LPA_10HALF 0x0020 /* Can do 10mbps half-duplex */
+#define MII_LPA_10FULL 0x0040 /* Can do 10mbps full-duplex */
+#define MII_LPA_100HALF 0x0080 /* Can do 100mbps half-duplex */
+#define MII_LPA_100FULL 0x0100 /* Can do 100mbps full-duplex */
+#define MII_LPA_100BASE4 0x0200 /* 100BASE-T4 */
+#define MII_LPA_PAUSE 0x0400 /* PAUSE */
+#define MII_LPA_ASYPAUSE 0x0800 /* Asymmetrical PAUSE */
+#define MII_LPA_RFAULT 0x2000 /* Link partner faulted */
+#define MII_LPA_LPACK 0x4000 /* Link partner acked us */
+#define MII_LPA_NPAGE 0x8000 /* Next page bit */
+
+/* Autoneg Advertisement Register */
+#define MII_AR_SELECTOR_FIELD 0x0001 /* indicates IEEE 802.3 CSMA/CD */
+#define MII_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */
+#define MII_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */
+#define MII_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */
+#define MII_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */
+#define MII_AR_100T4_CAPS 0x0200 /* 100T4 Capable */
+#define MII_AR_PAUSE 0x0400 /* Pause operation desired */
+#define MII_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */
+#define MII_AR_REMOTE_FAULT 0x2000 /* Remote Fault detected */
+#define MII_AR_NEXT_PAGE 0x8000 /* Next Page ability supported */
+#define MII_AR_SPEED_MASK 0x01E0
+#define MII_AR_DEFAULT_CAP_MASK 0x0DE0
+
+/* 1000BASE-T Control Register */
+#define MII_AT001_CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */
+#define MII_AT001_CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */
+#define MII_AT001_CR_1000T_REPEATER_DTE 0x0400 /* 1=Repeater/switch device port, 0=DTE device */
+#define MII_AT001_CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master, 0=Configure PHY as Slave */
+#define MII_AT001_CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value, 0=Automatic Master/Slave config */
+#define MII_AT001_CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */
+#define MII_AT001_CR_1000T_TEST_MODE_1 0x2000 /* Transmit Waveform test */
+#define MII_AT001_CR_1000T_TEST_MODE_2 0x4000 /* Master Transmit Jitter test */
+#define MII_AT001_CR_1000T_TEST_MODE_3 0x6000 /* Slave Transmit Jitter test */
+#define MII_AT001_CR_1000T_TEST_MODE_4 0x8000 /* Transmitter Distortion test */
+#define MII_AT001_CR_1000T_SPEED_MASK 0x0300
+#define MII_AT001_CR_1000T_DEFAULT_CAP_MASK 0x0300
+
+/* 1000BASE-T Status Register */
+#define MII_AT001_SR_1000T_LP_HD_CAPS 0x0400 /* LP is 1000T HD capable */
+#define MII_AT001_SR_1000T_LP_FD_CAPS 0x0800 /* LP is 1000T FD capable */
+#define MII_AT001_SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
+#define MII_AT001_SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */
+#define MII_AT001_SR_1000T_MS_CONFIG_RES 0x4000 /* 1=Local TX is Master, 0=Slave */
+#define MII_AT001_SR_1000T_MS_CONFIG_FAULT 0x8000 /* Master/Slave config fault */
+#define MII_AT001_SR_1000T_REMOTE_RX_STATUS_SHIFT 12
+#define MII_AT001_SR_1000T_LOCAL_RX_STATUS_SHIFT 13
+
+/* Extended Status Register */
+#define MII_AT001_ESR_1000T_HD_CAPS 0x1000 /* 1000T HD capable */
+#define MII_AT001_ESR_1000T_FD_CAPS 0x2000 /* 1000T FD capable */
+#define MII_AT001_ESR_1000X_HD_CAPS 0x4000 /* 1000X HD capable */
+#define MII_AT001_ESR_1000X_FD_CAPS 0x8000 /* 1000X FD capable */
+
+/* AT001 PHY Specific Control Register */
+#define MII_AT001_PSCR_JABBER_DISABLE 0x0001 /* 1=Jabber Function disabled */
+#define MII_AT001_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */
+#define MII_AT001_PSCR_SQE_TEST 0x0004 /* 1=SQE Test enabled */
+#define MII_AT001_PSCR_MAC_POWERDOWN 0x0008
+#define MII_AT001_PSCR_CLK125_DISABLE 0x0010 /* 1=CLK125 low, 0=CLK125 toggling */
+#define MII_AT001_PSCR_MDI_MANUAL_MODE 0x0000 /* MDI Crossover Mode bits 6:5, Manual MDI configuration */
+#define MII_AT001_PSCR_MDIX_MANUAL_MODE 0x0020 /* Manual MDIX configuration */
+#define MII_AT001_PSCR_AUTO_X_1000T 0x0040 /* 1000BASE-T: Auto crossover, 100BASE-TX/10BASE-T: MDI Mode */
+#define MII_AT001_PSCR_AUTO_X_MODE 0x0060 /* Auto crossover enabled all speeds. */
+#define MII_AT001_PSCR_10BT_EXT_DIST_ENABLE 0x0080 /* 1=Enable Extended 10BASE-T distance (Lower 10BASE-T RX Threshold), 0=Normal 10BASE-T RX Threshold */
+#define MII_AT001_PSCR_MII_5BIT_ENABLE 0x0100 /* 1=5-Bit interface in 100BASE-TX, 0=MII interface in 100BASE-TX */
+#define MII_AT001_PSCR_SCRAMBLER_DISABLE 0x0200 /* 1=Scrambler disable */
+#define MII_AT001_PSCR_FORCE_LINK_GOOD 0x0400 /* 1=Force link good */
+#define MII_AT001_PSCR_ASSERT_CRS_ON_TX 0x0800 /* 1=Assert CRS on Transmit */
+#define MII_AT001_PSCR_POLARITY_REVERSAL_SHIFT 1
+#define MII_AT001_PSCR_AUTO_X_MODE_SHIFT 5
+#define MII_AT001_PSCR_10BT_EXT_DIST_ENABLE_SHIFT 7
+
+/* AT001 PHY Specific Status Register */
+#define MII_AT001_PSSR_SPD_DPLX_RESOLVED 0x0800 /* 1=Speed & Duplex resolved */
+#define MII_AT001_PSSR_DPLX 0x2000 /* 1=Duplex 0=Half Duplex */
+#define MII_AT001_PSSR_SPEED 0xC000 /* Speed, bits 14:15 */
+#define MII_AT001_PSSR_10MBS 0x0000 /* 00=10Mbs */
+#define MII_AT001_PSSR_100MBS 0x4000 /* 01=100Mbs */
+#define MII_AT001_PSSR_1000MBS 0x8000 /* 10=1000Mbs */
+
+/* PCI Command Register Bit Definitions */
+#define PCI_REG_COMMAND 0x04 /* PCI Command Register */
+#define CMD_IO_SPACE 0x0001
+#define CMD_MEMORY_SPACE 0x0002
+#define CMD_BUS_MASTER 0x0004
+
+/* Wake Up Filter Control */
+#define ATL1_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
+#define ATL1_WUFC_MAG 0x00000002 /* Magic Packet Wakeup Enable */
+#define ATL1_WUFC_EX 0x00000004 /* Directed Exact Wakeup Enable */
+#define ATL1_WUFC_MC 0x00000008 /* Multicast Wakeup Enable */
+#define ATL1_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */
+
+/* Error Codes */
+#define ATL1_SUCCESS 0
+#define ATL1_ERR_EEPROM 1
+#define ATL1_ERR_PHY 2
+#define ATL1_ERR_CONFIG 3
+#define ATL1_ERR_PARAM 4
+#define ATL1_ERR_MAC_TYPE 5
+#define ATL1_ERR_PHY_TYPE 6
+#define ATL1_ERR_PHY_SPEED 7
+#define ATL1_ERR_PHY_RES 8
+
+#define SPEED_0 0xffff
+#define SPEED_10 10
+#define SPEED_100 100
+#define SPEED_1000 1000
+#define HALF_DUPLEX 1
+#define FULL_DUPLEX 2
+
+#define MEDIA_TYPE_AUTO_SENSOR 0
+#define MEDIA_TYPE_1000M_FULL 1
+#define MEDIA_TYPE_100M_FULL 2
+#define MEDIA_TYPE_100M_HALF 3
+#define MEDIA_TYPE_10M_FULL 4
+#define MEDIA_TYPE_10M_HALF 5
+
+#define ADVERTISE_10_HALF 0x0001
+#define ADVERTISE_10_FULL 0x0002
+#define ADVERTISE_100_HALF 0x0004
+#define ADVERTISE_100_FULL 0x0008
+#define ADVERTISE_1000_HALF 0x0010
+#define ADVERTISE_1000_FULL 0x0020
+#define AUTONEG_ADVERTISE_SPEED_DEFAULT 0x002F /* Everything but 1000-Half */
+#define AUTONEG_ADVERTISE_10_100_ALL 0x000F /* All 10/100 speeds */
+#define AUTONEG_ADVERTISE_10_ALL 0x0003 /* 10Mbps Full & Half speeds */
+
+/* The size (in bytes) of a ethernet packet */
+#define ENET_HEADER_SIZE 14
+#define MAXIMUM_ETHERNET_FRAME_SIZE 1518 /* with FCS */
+#define MINIMUM_ETHERNET_FRAME_SIZE 64 /* with FCS */
+#define ETHERNET_FCS_SIZE 4
+#define MAX_JUMBO_FRAME_SIZE 0x2800
+
+#define PHY_AUTO_NEG_TIME 45 /* 4.5 Seconds */
+#define PHY_FORCE_TIME 20 /* 2.0 Seconds */
+
+/* For checksumming , the sum of all words in the EEPROM should equal 0xBABA */
+#define EEPROM_SUM 0xBABA
+
+#define ATL1_EEDUMP_LEN 48
+
+/* Statistics counters collected by the MAC */
+struct stats_msg_block {
+ /* rx */
+ u32 rx_ok; /* The number of good packet received. */
+ u32 rx_bcast; /* The number of good broadcast packet received. */
+ u32 rx_mcast; /* The number of good multicast packet received. */
+ u32 rx_pause; /* The number of Pause packet received. */
+ u32 rx_ctrl; /* The number of Control packet received other than Pause frame. */
+ u32 rx_fcs_err; /* The number of packets with bad FCS. */
+ u32 rx_len_err; /* The number of packets with mismatch of length field and actual size. */
+ u32 rx_byte_cnt; /* The number of bytes of good packet received. FCS is NOT included. */
+ u32 rx_runt; /* The number of packets received that are less than 64 byte long and with good FCS. */
+ u32 rx_frag; /* The number of packets received that are less than 64 byte long and with bad FCS. */
+ u32 rx_sz_64; /* The number of good and bad packets received that are 64 byte long. */
+ u32 rx_sz_65_127; /* The number of good and bad packets received that are between 65 and 127-byte long. */
+ u32 rx_sz_128_255; /* The number of good and bad packets received that are between 128 and 255-byte long. */
+ u32 rx_sz_256_511; /* The number of good and bad packets received that are between 256 and 511-byte long. */
+ u32 rx_sz_512_1023; /* The number of good and bad packets received that are between 512 and 1023-byte long. */
+ u32 rx_sz_1024_1518; /* The number of good and bad packets received that are between 1024 and 1518-byte long. */
+ u32 rx_sz_1519_max; /* The number of good and bad packets received that are between 1519-byte and MTU. */
+ u32 rx_sz_ov; /* The number of good and bad packets received that are more than MTU size Å¡C truncated by Selene. */
+ u32 rx_rxf_ov; /* The number of frame dropped due to occurrence of RX FIFO overflow. */
+ u32 rx_rrd_ov; /* The number of frame dropped due to occurrence of RRD overflow. */
+ u32 rx_align_err; /* Alignment Error */
+ u32 rx_bcast_byte_cnt; /* The byte count of broadcast packet received, excluding FCS. */
+ u32 rx_mcast_byte_cnt; /* The byte count of multicast packet received, excluding FCS. */
+ u32 rx_err_addr; /* The number of packets dropped due to address filtering. */
+
+ /* tx */
+ u32 tx_ok; /* The number of good packet transmitted. */
+ u32 tx_bcast; /* The number of good broadcast packet transmitted. */
+ u32 tx_mcast; /* The number of good multicast packet transmitted. */
+ u32 tx_pause; /* The number of Pause packet transmitted. */
+ u32 tx_exc_defer; /* The number of packets transmitted with excessive deferral. */
+ u32 tx_ctrl; /* The number of packets transmitted is a control frame, excluding Pause frame. */
+ u32 tx_defer; /* The number of packets transmitted that is deferred. */
+ u32 tx_byte_cnt; /* The number of bytes of data transmitted. FCS is NOT included. */
+ u32 tx_sz_64; /* The number of good and bad packets transmitted that are 64 byte long. */
+ u32 tx_sz_65_127; /* The number of good and bad packets transmitted that are between 65 and 127-byte long. */
+ u32 tx_sz_128_255; /* The number of good and bad packets transmitted that are between 128 and 255-byte long. */
+ u32 tx_sz_256_511; /* The number of good and bad packets transmitted that are between 256 and 511-byte long. */
+ u32 tx_sz_512_1023; /* The number of good and bad packets transmitted that are between 512 and 1023-byte long. */
+ u32 tx_sz_1024_1518; /* The number of good and bad packets transmitted that are between 1024 and 1518-byte long. */
+ u32 tx_sz_1519_max; /* The number of good and bad packets transmitted that are between 1519-byte and MTU. */
+ u32 tx_1_col; /* The number of packets subsequently transmitted successfully with a single prior collision. */
+ u32 tx_2_col; /* The number of packets subsequently transmitted successfully with multiple prior collisions. */
+ u32 tx_late_col; /* The number of packets transmitted with late collisions. */
+ u32 tx_abort_col; /* The number of transmit packets aborted due to excessive collisions. */
+ u32 tx_underrun; /* The number of transmit packets aborted due to transmit FIFO underrun, or TRD FIFO underrun */
+ u32 tx_rd_eop; /* The number of times that read beyond the EOP into the next frame area when TRD was not written timely */
+ u32 tx_len_err; /* The number of transmit packets with length field does NOT match the actual frame size. */
+ u32 tx_trunc; /* The number of transmit packets truncated due to size exceeding MTU. */
+ u32 tx_bcast_byte; /* The byte count of broadcast packet transmitted, excluding FCS. */
+ u32 tx_mcast_byte; /* The byte count of multicast packet transmitted, excluding FCS. */
+ u32 smb_updated; /* 1: SMB Updated. This is used by software as the indication of the statistics update.
+ * Software should clear this bit as soon as retrieving the statistics information. */
+};
+
+/* Coalescing Message Block */
+struct coals_msg_block {
+ u32 int_stats; /* interrupt status */
+ u16 rrd_prod_idx; /* TRD Producer Index. */
+ u16 rfd_cons_idx; /* RFD Consumer Index. */
+ u16 update; /* Selene sets this bit every time it DMA the CMB to host memory.
+ * Software supposes to clear this bit when CMB information is processed. */
+ u16 tpd_cons_idx; /* TPD Consumer Index. */
+};
+
+/* RRD descriptor */
+struct rx_return_desc {
+ u8 num_buf; /* Number of RFD buffers used by the received packet */
+ u8 resved;
+ u16 buf_indx; /* RFD Index of the first buffer */
+ union {
+ u32 valid;
+ struct {
+ u16 rx_chksum;
+ u16 pkt_size;
+ } xsum_sz;
+ } xsz;
+
+ u16 pkt_flg; /* Packet flags */
+ u16 err_flg; /* Error flags */
+ u16 resved2;
+ u16 vlan_tag; /* VLAN TAG */
+};
+
+#define PACKET_FLAG_ETH_TYPE 0x0080
+#define PACKET_FLAG_VLAN_INS 0x0100
+#define PACKET_FLAG_ERR 0x0200
+#define PACKET_FLAG_IPV4 0x0400
+#define PACKET_FLAG_UDP 0x0800
+#define PACKET_FLAG_TCP 0x1000
+#define PACKET_FLAG_BCAST 0x2000
+#define PACKET_FLAG_MCAST 0x4000
+#define PACKET_FLAG_PAUSE 0x8000
+
+#define ERR_FLAG_CRC 0x0001
+#define ERR_FLAG_CODE 0x0002
+#define ERR_FLAG_DRIBBLE 0x0004
+#define ERR_FLAG_RUNT 0x0008
+#define ERR_FLAG_OV 0x0010
+#define ERR_FLAG_TRUNC 0x0020
+#define ERR_FLAG_IP_CHKSUM 0x0040
+#define ERR_FLAG_L4_CHKSUM 0x0080
+#define ERR_FLAG_LEN 0x0100
+#define ERR_FLAG_DES_ADDR 0x0200
+
+/* RFD descriptor */
+struct rx_free_desc {
+ __le64 buffer_addr; /* Address of the descriptor's data buffer */
+ __le16 buf_len; /* Size of the receive buffer in host memory, in byte */
+ u16 coalese; /* Update consumer index to host after the reception of this frame */
+ /* __attribute__ ((packed)) is required */
+} __attribute__ ((packed));
+
+/* tsopu defines */
+#define TSO_PARAM_BUFLEN_MASK 0x3FFF
+#define TSO_PARAM_BUFLEN_SHIFT 0
+#define TSO_PARAM_DMAINT_MASK 0x0001
+#define TSO_PARAM_DMAINT_SHIFT 14
+#define TSO_PARAM_PKTNT_MASK 0x0001
+#define TSO_PARAM_PKTINT_SHIFT 15
+#define TSO_PARAM_VLANTAG_MASK 0xFFFF
+#define TSO_PARAM_VLAN_SHIFT 16
+
+/* tsopl defines */
+#define TSO_PARAM_EOP_MASK 0x0001
+#define TSO_PARAM_EOP_SHIFT 0
+#define TSO_PARAM_COALESCE_MASK 0x0001
+#define TSO_PARAM_COALESCE_SHIFT 1
+#define TSO_PARAM_INSVLAG_MASK 0x0001
+#define TSO_PARAM_INSVLAG_SHIFT 2
+#define TSO_PARAM_CUSTOMCKSUM_MASK 0x0001
+#define TSO_PARAM_CUSTOMCKSUM_SHIFT 3
+#define TSO_PARAM_SEGMENT_MASK 0x0001
+#define TSO_PARAM_SEGMENT_SHIFT 4
+#define TSO_PARAM_IPCKSUM_MASK 0x0001
+#define TSO_PARAM_IPCKSUM_SHIFT 5
+#define TSO_PARAM_TCPCKSUM_MASK 0x0001
+#define TSO_PARAM_TCPCKSUM_SHIFT 6
+#define TSO_PARAM_UDPCKSUM_MASK 0x0001
+#define TSO_PARAM_UDPCKSUM_SHIFT 7
+#define TSO_PARAM_VLANTAGGED_MASK 0x0001
+#define TSO_PARAM_VLANTAGGED_SHIFT 8
+#define TSO_PARAM_ETHTYPE_MASK 0x0001
+#define TSO_PARAM_ETHTYPE_SHIFT 9
+#define TSO_PARAM_IPHL_MASK 0x000F
+#define TSO_PARAM_IPHL_SHIFT 10
+#define TSO_PARAM_TCPHDRLEN_MASK 0x000F
+#define TSO_PARAM_TCPHDRLEN_SHIFT 14
+#define TSO_PARAM_HDRFLAG_MASK 0x0001
+#define TSO_PARAM_HDRFLAG_SHIFT 18
+#define TSO_PARAM_MSS_MASK 0x1FFF
+#define TSO_PARAM_MSS_SHIFT 19
+
+/* csumpu defines */
+#define CSUM_PARAM_BUFLEN_MASK 0x3FFF
+#define CSUM_PARAM_BUFLEN_SHIFT 0
+#define CSUM_PARAM_DMAINT_MASK 0x0001
+#define CSUM_PARAM_DMAINT_SHIFT 14
+#define CSUM_PARAM_PKTINT_MASK 0x0001
+#define CSUM_PARAM_PKTINT_SHIFT 15
+#define CSUM_PARAM_VALANTAG_MASK 0xFFFF
+#define CSUM_PARAM_VALAN_SHIFT 16
+
+/* csumpl defines*/
+#define CSUM_PARAM_EOP_MASK 0x0001
+#define CSUM_PARAM_EOP_SHIFT 0
+#define CSUM_PARAM_COALESCE_MASK 0x0001
+#define CSUM_PARAM_COALESCE_SHIFT 1
+#define CSUM_PARAM_INSVLAG_MASK 0x0001
+#define CSUM_PARAM_INSVLAG_SHIFT 2
+#define CSUM_PARAM_CUSTOMCKSUM_MASK 0x0001
+#define CSUM_PARAM_CUSTOMCKSUM_SHIFT 3
+#define CSUM_PARAM_SEGMENT_MASK 0x0001
+#define CSUM_PARAM_SEGMENT_SHIFT 4
+#define CSUM_PARAM_IPCKSUM_MASK 0x0001
+#define CSUM_PARAM_IPCKSUM_SHIFT 5
+#define CSUM_PARAM_TCPCKSUM_MASK 0x0001
+#define CSUM_PARAM_TCPCKSUM_SHIFT 6
+#define CSUM_PARAM_UDPCKSUM_MASK 0x0001
+#define CSUM_PARAM_UDPCKSUM_SHIFT 7
+#define CSUM_PARAM_VLANTAGGED_MASK 0x0001
+#define CSUM_PARAM_VLANTAGGED_SHIFT 8
+#define CSUM_PARAM_ETHTYPE_MASK 0x0001
+#define CSUM_PARAM_ETHTYPE_SHIFT 9
+#define CSUM_PARAM_IPHL_MASK 0x000F
+#define CSUM_PARAM_IPHL_SHIFT 10
+#define CSUM_PARAM_PLOADOFFSET_MASK 0x00FF
+#define CSUM_PARAM_PLOADOFFSET_SHIFT 16
+#define CSUM_PARAM_XSUMOFFSET_MASK 0x00FF
+#define CSUM_PARAM_XSUMOFFSET_SHIFT 24
+
+/* TPD descriptor */
+struct tso_param {
+ /* The order of these declarations is important -- don't change it */
+ u32 tsopu; /* tso_param upper word */
+ u32 tsopl; /* tso_param lower word */
+};
+
+struct csum_param {
+ /* The order of these declarations is important -- don't change it */
+ u32 csumpu; /* csum_param upper word */
+ u32 csumpl; /* csum_param lower word */
+};
+
+union tpd_descr {
+ u64 data;
+ struct csum_param csum;
+ struct tso_param tso;
+};
+
+struct tx_packet_desc {
+ __le64 buffer_addr;
+ union tpd_descr desc;
+};
+
+/* DMA Order Settings */
+enum atl1_dma_order {
+ atl1_dma_ord_in = 1,
+ atl1_dma_ord_enh = 2,
+ atl1_dma_ord_out = 4
+};
+
+enum atl1_dma_rcb {
+ atl1_rcb_64 = 0,
+ atl1_rcb_128 = 1
+};
+
+enum atl1_dma_req_block {
+ atl1_dma_req_128 = 0,
+ atl1_dma_req_256 = 1,
+ atl1_dma_req_512 = 2,
+ atl1_dam_req_1024 = 3,
+ atl1_dam_req_2048 = 4,
+ atl1_dma_req_4096 = 5
+};
+
+struct atl1_spi_flash_dev {
+ const char *manu_name; /* manufacturer id */
+ /* op-code */
+ u8 cmd_wrsr;
+ u8 cmd_read;
+ u8 cmd_program;
+ u8 cmd_wren;
+ u8 cmd_wrdi;
+ u8 cmd_rdsr;
+ u8 cmd_rdid;
+ u8 cmd_sector_erase;
+ u8 cmd_chip_erase;
+};
+
+#endif /* _ATL1_HW_H_ */
diff --git a/drivers/net/atl1/atl1_main.c b/drivers/net/atl1/atl1_main.c
new file mode 100644
index 00000000000..6655640eb4c
--- /dev/null
+++ b/drivers/net/atl1/atl1_main.c
@@ -0,0 +1,2468 @@
+/*
+ * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved.
+ * Copyright(c) 2006 Chris Snook <csnook@redhat.com>
+ * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com>
+ *
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called COPYING.
+ *
+ * Contact Information:
+ * Xiong Huang <xiong_huang@attansic.com>
+ * Attansic Technology Corp. 3F 147, Xianzheng 9th Road, Zhubei,
+ * Xinzhu 302, TAIWAN, REPUBLIC OF CHINA
+ *
+ * Chris Snook <csnook@redhat.com>
+ * Jay Cliburn <jcliburn@gmail.com>
+ *
+ * This version is adapted from the Attansic reference driver for
+ * inclusion in the Linux kernel. It is currently under heavy development.
+ * A very incomplete list of things that need to be dealt with:
+ *
+ * TODO:
+ * Fix TSO; tx performance is horrible with TSO enabled.
+ * Wake on LAN.
+ * Add more ethtool functions, including set ring parameters.
+ * Fix abstruse irq enable/disable condition described here:
+ * http://marc.theaimsgroup.com/?l=linux-netdev&m=116398508500553&w=2
+ *
+ * NEEDS TESTING:
+ * VLAN
+ * multicast
+ * promiscuous mode
+ * interrupt coalescing
+ * SMP torture testing
+ */
+
+#include <linux/types.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
+#include <linux/irqreturn.h>
+#include <linux/workqueue.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
+#include <linux/hardirq.h>
+#include <linux/interrupt.h>
+#include <linux/irqflags.h>
+#include <linux/dma-mapping.h>
+#include <linux/net.h>
+#include <linux/pm.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/compiler.h>
+#include <linux/delay.h>
+#include <linux/mii.h>
+#include <net/checksum.h>
+
+#include <asm/atomic.h>
+#include <asm/byteorder.h>
+
+#include "atl1.h"
+
+#define RUN_REALTIME 0
+#define DRIVER_VERSION "2.0.6"
+
+char atl1_driver_name[] = "atl1";
+static const char atl1_driver_string[] = "Attansic L1 Ethernet Network Driver";
+static const char atl1_copyright[] = "Copyright(c) 2005-2006 Attansic Corporation.";
+char atl1_driver_version[] = DRIVER_VERSION;
+
+MODULE_AUTHOR
+ ("Attansic Corporation <xiong_huang@attansic.com>, Chris Snook <csnook@redhat.com>, Jay Cliburn <jcliburn@gmail.com>");
+MODULE_DESCRIPTION("Attansic 1000M Ethernet Network Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
+
+/*
+ * atl1_pci_tbl - PCI Device ID Table
+ */
+static const struct pci_device_id atl1_pci_tbl[] = {
+ {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, 0x1048)},
+ /* required last entry */
+ {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, atl1_pci_tbl);
+
+/*
+ * atl1_sw_init - Initialize general software structures (struct atl1_adapter)
+ * @adapter: board private structure to initialize
+ *
+ * atl1_sw_init initializes the Adapter private data structure.
+ * Fields are initialized based on PCI device information and
+ * OS network device settings (MTU size).
+ */
+static int __devinit atl1_sw_init(struct atl1_adapter *adapter)
+{
+ struct atl1_hw *hw = &adapter->hw;
+ struct net_device *netdev = adapter->netdev;
+ struct pci_dev *pdev = adapter->pdev;
+
+ /* PCI config space info */
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id);
+
+ hw->max_frame_size = netdev->mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
+ hw->min_frame_size = MINIMUM_ETHERNET_FRAME_SIZE;
+
+ adapter->wol = 0;
+ adapter->rx_buffer_len = (hw->max_frame_size + 7) & ~7;
+ adapter->ict = 50000; /* 100ms */
+ adapter->link_speed = SPEED_0; /* hardware init */
+ adapter->link_duplex = FULL_DUPLEX;
+
+ hw->phy_configured = false;
+ hw->preamble_len = 7;
+ hw->ipgt = 0x60;
+ hw->min_ifg = 0x50;
+ hw->ipgr1 = 0x40;
+ hw->ipgr2 = 0x60;
+ hw->max_retry = 0xf;
+ hw->lcol = 0x37;
+ hw->jam_ipg = 7;
+ hw->rfd_burst = 8;
+ hw->rrd_burst = 8;
+ hw->rfd_fetch_gap = 1;
+ hw->rx_jumbo_th = adapter->rx_buffer_len / 8;
+ hw->rx_jumbo_lkah = 1;
+ hw->rrd_ret_timer = 16;
+ hw->tpd_burst = 4;
+ hw->tpd_fetch_th = 16;
+ hw->txf_burst = 0x100;
+ hw->tx_jumbo_task_th = (hw->max_frame_size + 7) >> 3;
+ hw->tpd_fetch_gap = 1;
+ hw->rcb_value = atl1_rcb_64;
+ hw->dma_ord = atl1_dma_ord_enh;
+ hw->dmar_block = atl1_dma_req_256;
+ hw->dmaw_block = atl1_dma_req_256;
+ hw->cmb_rrd = 4;
+ hw->cmb_tpd = 4;
+ hw->cmb_rx_timer = 1; /* about 2us */
+ hw->cmb_tx_timer = 1; /* about 2us */
+ hw->smb_timer = 100000; /* about 200ms */
+
+ atomic_set(&adapter->irq_sem, 0);
+ spin_lock_init(&adapter->lock);
+ spin_lock_init(&adapter->mb_lock);
+
+ return 0;
+}
+
+/*
+ * atl1_setup_mem_resources - allocate Tx / RX descriptor resources
+ * @adapter: board private structure
+ *
+ * Return 0 on success, negative on failure
+ */
+s32 atl1_setup_ring_resources(struct atl1_adapter *adapter)
+{
+ struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
+ struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring;
+ struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring;
+ struct atl1_ring_header *ring_header = &adapter->ring_header;
+ struct pci_dev *pdev = adapter->pdev;
+ int size;
+ u8 offset = 0;
+
+ size = sizeof(struct atl1_buffer) * (tpd_ring->count + rfd_ring->count);
+ tpd_ring->buffer_info = kzalloc(size, GFP_KERNEL);
+ if (unlikely(!tpd_ring->buffer_info)) {
+ printk(KERN_WARNING "%s: kzalloc failed , size = D%d\n",
+ atl1_driver_name, size);
+ goto err_nomem;
+ }
+ rfd_ring->buffer_info =
+ (struct atl1_buffer *)(tpd_ring->buffer_info + tpd_ring->count);
+
+ /* real ring DMA buffer */
+ ring_header->size = size = sizeof(struct tx_packet_desc) *
+ tpd_ring->count
+ + sizeof(struct rx_free_desc) * rfd_ring->count
+ + sizeof(struct rx_return_desc) * rrd_ring->count
+ + sizeof(struct coals_msg_block)
+ + sizeof(struct stats_msg_block)
+ + 40; /* "40: for 8 bytes align" huh? -- CHS */
+
+ ring_header->desc = pci_alloc_consistent(pdev, ring_header->size,
+ &ring_header->dma);
+ if (unlikely(!ring_header->desc)) {
+ printk(KERN_WARNING
+ "%s: pci_alloc_consistent failed, size = D%d\n",
+ atl1_driver_name, size);
+ goto err_nomem;
+ }
+
+ memset(ring_header->desc, 0, ring_header->size);
+
+ /* init TPD ring */
+ tpd_ring->dma = ring_header->dma;
+ offset = (tpd_ring->dma & 0x7) ? (8 - (ring_header->dma & 0x7)) : 0;
+ tpd_ring->dma += offset;
+ tpd_ring->desc = (u8 *) ring_header->desc + offset;
+ tpd_ring->size = sizeof(struct tx_packet_desc) * tpd_ring->count;
+ atomic_set(&tpd_ring->next_to_use, 0);
+ atomic_set(&tpd_ring->next_to_clean, 0);
+
+ /* init RFD ring */
+ rfd_ring->dma = tpd_ring->dma + tpd_ring->size;
+ offset = (rfd_ring->dma & 0x7) ? (8 - (rfd_ring->dma & 0x7)) : 0;
+ rfd_ring->dma += offset;
+ rfd_ring->desc = (u8 *) tpd_ring->desc + (tpd_ring->size + offset);
+ rfd_ring->size = sizeof(struct rx_free_desc) * rfd_ring->count;
+ rfd_ring->next_to_clean = 0;
+ /* rfd_ring->next_to_use = rfd_ring->count - 1; */
+ atomic_set(&rfd_ring->next_to_use, 0);
+
+ /* init RRD ring */
+ rrd_ring->dma = rfd_ring->dma + rfd_ring->size;
+ offset = (rrd_ring->dma & 0x7) ? (8 - (rrd_ring->dma & 0x7)) : 0;
+ rrd_ring->dma += offset;
+ rrd_ring->desc = (u8 *) rfd_ring->desc + (rfd_ring->size + offset);
+ rrd_ring->size = sizeof(struct rx_return_desc) * rrd_ring->count;
+ rrd_ring->next_to_use = 0;
+ atomic_set(&rrd_ring->next_to_clean, 0);
+
+ /* init CMB */
+ adapter->cmb.dma = rrd_ring->dma + rrd_ring->size;
+ offset = (adapter->cmb.dma & 0x7) ? (8 - (adapter->cmb.dma & 0x7)) : 0;
+ adapter->cmb.dma += offset;
+ adapter->cmb.cmb =
+ (struct coals_msg_block *) ((u8 *) rrd_ring->desc +
+ (rrd_ring->size + offset));
+
+ /* init SMB */
+ adapter->smb.dma = adapter->cmb.dma + sizeof(struct coals_msg_block);
+ offset = (adapter->smb.dma & 0x7) ? (8 - (adapter->smb.dma & 0x7)) : 0;
+ adapter->smb.dma += offset;
+ adapter->smb.smb = (struct stats_msg_block *)
+ ((u8 *) adapter->cmb.cmb + (sizeof(struct coals_msg_block) + offset));
+
+ return ATL1_SUCCESS;
+
+err_nomem:
+ kfree(tpd_ring->buffer_info);
+ return -ENOMEM;
+}
+
+/*
+ * atl1_irq_enable - Enable default interrupt generation settings
+ * @adapter: board private structure
+ */
+static void atl1_irq_enable(struct atl1_adapter *adapter)
+{
+ if (likely(!atomic_dec_and_test(&adapter->irq_sem)))
+ iowrite32(IMR_NORMAL_MASK, adapter->hw.hw_addr + REG_IMR);
+}
+
+static void atl1_clear_phy_int(struct atl1_adapter *adapter)
+{
+ u16 phy_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->lock, flags);
+ atl1_read_phy_reg(&adapter->hw, 19, &phy_data);
+ spin_unlock_irqrestore(&adapter->lock, flags);
+}
+
+static void atl1_inc_smb(struct atl1_adapter *adapter)
+{
+ struct stats_msg_block *smb = adapter->smb.smb;
+
+ /* Fill out the OS statistics structure */
+ adapter->soft_stats.rx_packets += smb->rx_ok;
+ adapter->soft_stats.tx_packets += smb->tx_ok;
+ adapter->soft_stats.rx_bytes += smb->rx_byte_cnt;
+ adapter->soft_stats.tx_bytes += smb->tx_byte_cnt;
+ adapter->soft_stats.multicast += smb->rx_mcast;
+ adapter->soft_stats.collisions += (smb->tx_1_col +
+ smb->tx_2_col * 2 +
+ smb->tx_late_col +
+ smb->tx_abort_col *
+ adapter->hw.max_retry);
+
+ /* Rx Errors */
+ adapter->soft_stats.rx_errors += (smb->rx_frag +
+ smb->rx_fcs_err +
+ smb->rx_len_err +
+ smb->rx_sz_ov +
+ smb->rx_rxf_ov +
+ smb->rx_rrd_ov + smb->rx_align_err);
+ adapter->soft_stats.rx_fifo_errors += smb->rx_rxf_ov;
+ adapter->soft_stats.rx_length_errors += smb->rx_len_err;
+ adapter->soft_stats.rx_crc_errors += smb->rx_fcs_err;
+ adapter->soft_stats.rx_frame_errors += smb->rx_align_err;
+ adapter->soft_stats.rx_missed_errors += (smb->rx_rrd_ov +
+ smb->rx_rxf_ov);
+
+ adapter->soft_stats.rx_pause += smb->rx_pause;
+ adapter->soft_stats.rx_rrd_ov += smb->rx_rrd_ov;
+ adapter->soft_stats.rx_trunc += smb->rx_sz_ov;
+
+ /* Tx Errors */
+ adapter->soft_stats.tx_errors += (smb->tx_late_col +
+ smb->tx_abort_col +
+ smb->tx_underrun + smb->tx_trunc);
+ adapter->soft_stats.tx_fifo_errors += smb->tx_underrun;
+ adapter->soft_stats.tx_aborted_errors += smb->tx_abort_col;
+ adapter->soft_stats.tx_window_errors += smb->tx_late_col;
+
+ adapter->soft_stats.excecol += smb->tx_abort_col;
+ adapter->soft_stats.deffer += smb->tx_defer;
+ adapter->soft_stats.scc += smb->tx_1_col;
+ adapter->soft_stats.mcc += smb->tx_2_col;
+ adapter->soft_stats.latecol += smb->tx_late_col;
+ adapter->soft_stats.tx_underun += smb->tx_underrun;
+ adapter->soft_stats.tx_trunc += smb->tx_trunc;
+ adapter->soft_stats.tx_pause += smb->tx_pause;
+
+ adapter->net_stats.rx_packets = adapter->soft_stats.rx_packets;
+ adapter->net_stats.tx_packets = adapter->soft_stats.tx_packets;
+ adapter->net_stats.rx_bytes = adapter->soft_stats.rx_bytes;
+ adapter->net_stats.tx_bytes = adapter->soft_stats.tx_bytes;
+ adapter->net_stats.multicast = adapter->soft_stats.multicast;
+ adapter->net_stats.collisions = adapter->soft_stats.collisions;
+ adapter->net_stats.rx_errors = adapter->soft_stats.rx_errors;
+ adapter->net_stats.rx_over_errors =
+ adapter->soft_stats.rx_missed_errors;
+ adapter->net_stats.rx_length_errors =
+ adapter->soft_stats.rx_length_errors;
+ adapter->net_stats.rx_crc_errors = adapter->soft_stats.rx_crc_errors;
+ adapter->net_stats.rx_frame_errors =
+ adapter->soft_stats.rx_frame_errors;
+ adapter->net_stats.rx_fifo_errors = adapter->soft_stats.rx_fifo_errors;
+ adapter->net_stats.rx_missed_errors =
+ adapter->soft_stats.rx_missed_errors;
+ adapter->net_stats.tx_errors = adapter->soft_stats.tx_errors;
+ adapter->net_stats.tx_fifo_errors = adapter->soft_stats.tx_fifo_errors;
+ adapter->net_stats.tx_aborted_errors =
+ adapter->soft_stats.tx_aborted_errors;
+ adapter->net_stats.tx_window_errors =
+ adapter->soft_stats.tx_window_errors;
+ adapter->net_stats.tx_carrier_errors =
+ adapter->soft_stats.tx_carrier_errors;
+}
+
+static void atl1_rx_checksum(struct atl1_adapter *adapter,
+ struct rx_return_desc *rrd,
+ struct sk_buff *skb)
+{
+ skb->ip_summed = CHECKSUM_NONE;
+
+ if (unlikely(rrd->pkt_flg & PACKET_FLAG_ERR)) {
+ if (rrd->err_flg & (ERR_FLAG_CRC | ERR_FLAG_TRUNC |
+ ERR_FLAG_CODE | ERR_FLAG_OV)) {
+ adapter->hw_csum_err++;
+ printk(KERN_DEBUG "%s: rx checksum error\n",
+ atl1_driver_name);
+ return;
+ }
+ }
+
+ /* not IPv4 */
+ if (!(rrd->pkt_flg & PACKET_FLAG_IPV4))
+ /* checksum is invalid, but it's not an IPv4 pkt, so ok */
+ return;
+
+ /* IPv4 packet */
+ if (likely(!(rrd->err_flg &
+ (ERR_FLAG_IP_CHKSUM | ERR_FLAG_L4_CHKSUM)))) {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ adapter->hw_csum_good++;
+ return;
+ }
+
+ /* IPv4, but hardware thinks its checksum is wrong */
+ printk(KERN_DEBUG "%s: hw csum wrong pkt_flag:%x, err_flag:%x\n",
+ atl1_driver_name, rrd->pkt_flg, rrd->err_flg);
+ skb->ip_summed = CHECKSUM_COMPLETE;
+ skb->csum = htons(rrd->xsz.xsum_sz.rx_chksum);
+ adapter->hw_csum_err++;
+ return;
+}
+
+/*
+ * atl1_alloc_rx_buffers - Replace used receive buffers
+ * @adapter: address of board private structure
+ */
+static u16 atl1_alloc_rx_buffers(struct atl1_adapter *adapter)
+{
+ struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring;
+ struct net_device *netdev = adapter->netdev;
+ struct pci_dev *pdev = adapter->pdev;
+ struct page *page;
+ unsigned long offset;
+ struct atl1_buffer *buffer_info, *next_info;
+ struct sk_buff *skb;
+ u16 num_alloc = 0;
+ u16 rfd_next_to_use, next_next;
+ struct rx_free_desc *rfd_desc;
+
+ next_next = rfd_next_to_use = atomic_read(&rfd_ring->next_to_use);
+ if (++next_next == rfd_ring->count)
+ next_next = 0;
+ buffer_info = &rfd_ring->buffer_info[rfd_next_to_use];
+ next_info = &rfd_ring->buffer_info[next_next];
+
+ while (!buffer_info->alloced && !next_info->alloced) {
+ if (buffer_info->skb) {
+ buffer_info->alloced = 1;
+ goto next;
+ }
+
+ rfd_desc = ATL1_RFD_DESC(rfd_ring, rfd_next_to_use);
+
+ skb = dev_alloc_skb(adapter->rx_buffer_len + NET_IP_ALIGN);
+ if (unlikely(!skb)) { /* Better luck next round */
+ adapter->net_stats.rx_dropped++;
+ break;
+ }
+
+ /*
+ * Make buffer alignment 2 beyond a 16 byte boundary
+ * this will result in a 16 byte aligned IP header after
+ * the 14 byte MAC header is removed
+ */
+ skb_reserve(skb, NET_IP_ALIGN);
+ skb->dev = netdev;
+
+ buffer_info->alloced = 1;
+ buffer_info->skb = skb;
+ buffer_info->length = (u16) adapter->rx_buffer_len;
+ page = virt_to_page(skb->data);
+ offset = (unsigned long)skb->data & ~PAGE_MASK;
+ buffer_info->dma = pci_map_page(pdev, page, offset,
+ adapter->rx_buffer_len,
+ PCI_DMA_FROMDEVICE);
+ rfd_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
+ rfd_desc->buf_len = cpu_to_le16(adapter->rx_buffer_len);
+ rfd_desc->coalese = 0;
+
+next:
+ rfd_next_to_use = next_next;
+ if (unlikely(++next_next == rfd_ring->count))
+ next_next = 0;
+
+ buffer_info = &rfd_ring->buffer_info[rfd_next_to_use];
+ next_info = &rfd_ring->buffer_info[next_next];
+ num_alloc++;
+ }
+
+ if (num_alloc) {
+ /*
+ * Force memory writes to complete before letting h/w
+ * know there are new descriptors to fetch. (Only
+ * applicable for weak-ordered memory model archs,
+ * such as IA-64).
+ */
+ wmb();
+ atomic_set(&rfd_ring->next_to_use, (int)rfd_next_to_use);
+ }
+ return num_alloc;
+}
+
+static void atl1_intr_rx(struct atl1_adapter *adapter)
+{
+ int i, count;
+ u16 length;
+ u16 rrd_next_to_clean;
+ u32 value;
+ struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring;
+ struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring;
+ struct atl1_buffer *buffer_info;
+ struct rx_return_desc *rrd;
+ struct sk_buff *skb;
+
+ count = 0;
+
+ rrd_next_to_clean = atomic_read(&rrd_ring->next_to_clean);
+
+ while (1) {
+ rrd = ATL1_RRD_DESC(rrd_ring, rrd_next_to_clean);
+ i = 1;
+ if (likely(rrd->xsz.valid)) { /* packet valid */
+chk_rrd:
+ /* check rrd status */
+ if (likely(rrd->num_buf == 1))
+ goto rrd_ok;
+
+ /* rrd seems to be bad */
+ if (unlikely(i-- > 0)) {
+ /* rrd may not be DMAed completely */
+ printk(KERN_DEBUG
+ "%s: RRD may not be DMAed completely\n",
+ atl1_driver_name);
+ udelay(1);
+ goto chk_rrd;
+ }
+ /* bad rrd */
+ printk(KERN_DEBUG "%s: bad RRD\n", atl1_driver_name);
+ /* see if update RFD index */
+ if (rrd->num_buf > 1) {
+ u16 num_buf;
+ num_buf =
+ (rrd->xsz.xsum_sz.pkt_size +
+ adapter->rx_buffer_len -
+ 1) / adapter->rx_buffer_len;
+ if (rrd->num_buf == num_buf) {
+ /* clean alloc flag for bad rrd */
+ while (rfd_ring->next_to_clean !=
+ (rrd->buf_indx + num_buf)) {
+ rfd_ring->buffer_info[rfd_ring->
+ next_to_clean].alloced = 0;
+ if (++rfd_ring->next_to_clean ==
+ rfd_ring->count) {
+ rfd_ring->
+ next_to_clean = 0;
+ }
+ }
+ }
+ }
+
+ /* update rrd */
+ rrd->xsz.valid = 0;
+ if (++rrd_next_to_clean == rrd_ring->count)
+ rrd_next_to_clean = 0;
+ count++;
+ continue;
+ } else { /* current rrd still not be updated */
+
+ break;
+ }
+rrd_ok:
+ /* clean alloc flag for bad rrd */
+ while (rfd_ring->next_to_clean != rrd->buf_indx) {
+ rfd_ring->buffer_info[rfd_ring->next_to_clean].alloced =
+ 0;
+ if (++rfd_ring->next_to_clean == rfd_ring->count)
+ rfd_ring->next_to_clean = 0;
+ }
+
+ buffer_info = &rfd_ring->buffer_info[rrd->buf_indx];
+ if (++rfd_ring->next_to_clean == rfd_ring->count)
+ rfd_ring->next_to_clean = 0;
+
+ /* update rrd next to clean */
+ if (++rrd_next_to_clean == rrd_ring->count)
+ rrd_next_to_clean = 0;
+ count++;
+
+ if (unlikely(rrd->pkt_flg & PACKET_FLAG_ERR)) {
+ if (!(rrd->err_flg &
+ (ERR_FLAG_IP_CHKSUM | ERR_FLAG_L4_CHKSUM
+ | ERR_FLAG_LEN))) {
+ /* packet error, don't need upstream */
+ buffer_info->alloced = 0;
+ rrd->xsz.valid = 0;
+ continue;
+ }
+ }
+
+ /* Good Receive */
+ pci_unmap_page(adapter->pdev, buffer_info->dma,
+ buffer_info->length, PCI_DMA_FROMDEVICE);
+ skb = buffer_info->skb;
+ length = le16_to_cpu(rrd->xsz.xsum_sz.pkt_size);
+
+ skb_put(skb, length - ETHERNET_FCS_SIZE);
+
+ /* Receive Checksum Offload */
+ atl1_rx_checksum(adapter, rrd, skb);
+ skb->protocol = eth_type_trans(skb, adapter->netdev);
+
+ if (adapter->vlgrp && (rrd->pkt_flg & PACKET_FLAG_VLAN_INS)) {
+ u16 vlan_tag = (rrd->vlan_tag >> 4) |
+ ((rrd->vlan_tag & 7) << 13) |
+ ((rrd->vlan_tag & 8) << 9);
+ vlan_hwaccel_rx(skb, adapter->vlgrp, vlan_tag);
+ } else
+ netif_rx(skb);
+
+ /* let protocol layer free skb */
+ buffer_info->skb = NULL;
+ buffer_info->alloced = 0;
+ rrd->xsz.valid = 0;
+
+ adapter->netdev->last_rx = jiffies;
+ }
+
+ atomic_set(&rrd_ring->next_to_clean, rrd_next_to_clean);
+
+ atl1_alloc_rx_buffers(adapter);
+
+ /* update mailbox ? */
+ if (count) {
+ u32 tpd_next_to_use;
+ u32 rfd_next_to_use;
+ u32 rrd_next_to_clean;
+
+ spin_lock(&adapter->mb_lock);
+
+ tpd_next_to_use = atomic_read(&adapter->tpd_ring.next_to_use);
+ rfd_next_to_use =
+ atomic_read(&adapter->rfd_ring.next_to_use);
+ rrd_next_to_clean =
+ atomic_read(&adapter->rrd_ring.next_to_clean);
+ value = ((rfd_next_to_use & MB_RFD_PROD_INDX_MASK) <<
+ MB_RFD_PROD_INDX_SHIFT) |
+ ((rrd_next_to_clean & MB_RRD_CONS_INDX_MASK) <<
+ MB_RRD_CONS_INDX_SHIFT) |
+ ((tpd_next_to_use & MB_TPD_PROD_INDX_MASK) <<
+ MB_TPD_PROD_INDX_SHIFT);
+ iowrite32(value, adapter->hw.hw_addr + REG_MAILBOX);
+ spin_unlock(&adapter->mb_lock);
+ }
+}
+
+static void atl1_intr_tx(struct atl1_adapter *adapter)
+{
+ struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
+ struct atl1_buffer *buffer_info;
+ u16 sw_tpd_next_to_clean;
+ u16 cmb_tpd_next_to_clean;
+ u8 update = 0;
+
+ sw_tpd_next_to_clean = atomic_read(&tpd_ring->next_to_clean);
+ cmb_tpd_next_to_clean = le16_to_cpu(adapter->cmb.cmb->tpd_cons_idx);
+
+ while (cmb_tpd_next_to_clean != sw_tpd_next_to_clean) {
+ struct tx_packet_desc *tpd;
+ update = 1;
+ tpd = ATL1_TPD_DESC(tpd_ring, sw_tpd_next_to_clean);
+ buffer_info = &tpd_ring->buffer_info[sw_tpd_next_to_clean];
+ if (buffer_info->dma) {
+ pci_unmap_page(adapter->pdev, buffer_info->dma,
+ buffer_info->length, PCI_DMA_TODEVICE);
+ buffer_info->dma = 0;
+ }
+
+ if (buffer_info->skb) {
+ dev_kfree_skb_irq(buffer_info->skb);
+ buffer_info->skb = NULL;
+ }
+ tpd->buffer_addr = 0;
+ tpd->desc.data = 0;
+
+ if (++sw_tpd_next_to_clean == tpd_ring->count)
+ sw_tpd_next_to_clean = 0;
+ }
+ atomic_set(&tpd_ring->next_to_clean, sw_tpd_next_to_clean);
+
+ if (netif_queue_stopped(adapter->netdev)
+ && netif_carrier_ok(adapter->netdev))
+ netif_wake_queue(adapter->netdev);
+}
+
+static void atl1_check_for_link(struct atl1_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ u16 phy_data = 0;
+
+ spin_lock(&adapter->lock);
+ adapter->phy_timer_pending = false;
+ atl1_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data);
+ atl1_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data);
+ spin_unlock(&adapter->lock);
+
+ /* notify upper layer link down ASAP */
+ if (!(phy_data & BMSR_LSTATUS)) { /* Link Down */
+ if (netif_carrier_ok(netdev)) { /* old link state: Up */
+ printk(KERN_INFO "%s: %s link is down\n",
+ atl1_driver_name, netdev->name);
+ adapter->link_speed = SPEED_0;
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+ }
+ }
+ schedule_work(&adapter->link_chg_task);
+}
+
+/*
+ * atl1_intr - Interrupt Handler
+ * @irq: interrupt number
+ * @data: pointer to a network interface device structure
+ * @pt_regs: CPU registers structure
+ */
+static irqreturn_t atl1_intr(int irq, void *data)
+{
+ /*struct atl1_adapter *adapter = ((struct net_device *)data)->priv;*/
+ struct atl1_adapter *adapter = netdev_priv(data);
+ u32 status;
+ u8 update_rx;
+ int max_ints = 10;
+
+ status = adapter->cmb.cmb->int_stats;
+ if (!status)
+ return IRQ_NONE;
+
+ update_rx = 0;
+
+ do {
+ /* clear CMB interrupt status at once */
+ adapter->cmb.cmb->int_stats = 0;
+
+ if (status & ISR_GPHY) /* clear phy status */
+ atl1_clear_phy_int(adapter);
+
+ /* clear ISR status, and Enable CMB DMA/Disable Interrupt */
+ iowrite32(status | ISR_DIS_INT, adapter->hw.hw_addr + REG_ISR);
+
+ /* check if SMB intr */
+ if (status & ISR_SMB)
+ atl1_inc_smb(adapter);
+
+ /* check if PCIE PHY Link down */
+ if (status & ISR_PHY_LINKDOWN) {
+ printk(KERN_DEBUG "%s: pcie phy link down %x\n",
+ atl1_driver_name, status);
+ if (netif_running(adapter->netdev)) { /* reset MAC */
+ iowrite32(0, adapter->hw.hw_addr + REG_IMR);
+ schedule_work(&adapter->pcie_dma_to_rst_task);
+ return IRQ_HANDLED;
+ }
+ }
+
+ /* check if DMA read/write error ? */
+ if (status & (ISR_DMAR_TO_RST | ISR_DMAW_TO_RST)) {
+ printk(KERN_DEBUG
+ "%s: pcie DMA r/w error (status = 0x%x)\n",
+ atl1_driver_name, status);
+ iowrite32(0, adapter->hw.hw_addr + REG_IMR);
+ schedule_work(&adapter->pcie_dma_to_rst_task);
+ return IRQ_HANDLED;
+ }
+
+ /* link event */
+ if (status & ISR_GPHY) {
+ adapter->soft_stats.tx_carrier_errors++;
+ atl1_check_for_link(adapter);
+ }
+
+ /* transmit event */
+ if (status & ISR_CMB_TX)
+ atl1_intr_tx(adapter);
+
+ /* rx exception */
+ if (unlikely(status & (ISR_RXF_OV | ISR_RFD_UNRUN |
+ ISR_RRD_OV | ISR_HOST_RFD_UNRUN |
+ ISR_HOST_RRD_OV | ISR_CMB_RX))) {
+ if (status &
+ (ISR_RXF_OV | ISR_RFD_UNRUN | ISR_RRD_OV |
+ ISR_HOST_RFD_UNRUN | ISR_HOST_RRD_OV))
+ printk(KERN_INFO
+ "%s: rx exception: status = 0x%x\n",
+ atl1_driver_name, status);
+ atl1_intr_rx(adapter);
+ }
+
+ if (--max_ints < 0)
+ break;
+
+ } while ((status = adapter->cmb.cmb->int_stats));
+
+ /* re-enable Interrupt */
+ iowrite32(ISR_DIS_SMB | ISR_DIS_DMA, adapter->hw.hw_addr + REG_ISR);
+ return IRQ_HANDLED;
+}
+
+/*
+ * atl1_set_multi - Multicast and Promiscuous mode set
+ * @netdev: network interface device structure
+ *
+ * The set_multi entry point is called whenever the multicast address
+ * list or the network interface flags are updated. This routine is
+ * responsible for configuring the hardware for proper multicast,
+ * promiscuous mode, and all-multi behavior.
+ */
+static void atl1_set_multi(struct net_device *netdev)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ struct atl1_hw *hw = &adapter->hw;
+ struct dev_mc_list *mc_ptr;
+ u32 rctl;
+ u32 hash_value;
+
+ /* Check for Promiscuous and All Multicast modes */
+ rctl = ioread32(hw->hw_addr + REG_MAC_CTRL);
+ if (netdev->flags & IFF_PROMISC)
+ rctl |= MAC_CTRL_PROMIS_EN;
+ else if (netdev->flags & IFF_ALLMULTI) {
+ rctl |= MAC_CTRL_MC_ALL_EN;
+ rctl &= ~MAC_CTRL_PROMIS_EN;
+ } else
+ rctl &= ~(MAC_CTRL_PROMIS_EN | MAC_CTRL_MC_ALL_EN);
+
+ iowrite32(rctl, hw->hw_addr + REG_MAC_CTRL);
+
+ /* clear the old settings from the multicast hash table */
+ iowrite32(0, hw->hw_addr + REG_RX_HASH_TABLE);
+ iowrite32(0, (hw->hw_addr + REG_RX_HASH_TABLE) + (1 << 2));
+
+ /* compute mc addresses' hash value ,and put it into hash table */
+ for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) {
+ hash_value = atl1_hash_mc_addr(hw, mc_ptr->dmi_addr);
+ atl1_hash_set(hw, hash_value);
+ }
+}
+
+static void atl1_setup_mac_ctrl(struct atl1_adapter *adapter)
+{
+ u32 value;
+ struct atl1_hw *hw = &adapter->hw;
+ struct net_device *netdev = adapter->netdev;
+ /* Config MAC CTRL Register */
+ value = MAC_CTRL_TX_EN | MAC_CTRL_RX_EN;
+ /* duplex */
+ if (FULL_DUPLEX == adapter->link_duplex)
+ value |= MAC_CTRL_DUPLX;
+ /* speed */
+ value |= ((u32) ((SPEED_1000 == adapter->link_speed) ?
+ MAC_CTRL_SPEED_1000 : MAC_CTRL_SPEED_10_100) <<
+ MAC_CTRL_SPEED_SHIFT);
+ /* flow control */
+ value |= (MAC_CTRL_TX_FLOW | MAC_CTRL_RX_FLOW);
+ /* PAD & CRC */
+ value |= (MAC_CTRL_ADD_CRC | MAC_CTRL_PAD);
+ /* preamble length */
+ value |= (((u32) adapter->hw.preamble_len
+ & MAC_CTRL_PRMLEN_MASK) << MAC_CTRL_PRMLEN_SHIFT);
+ /* vlan */
+ if (adapter->vlgrp)
+ value |= MAC_CTRL_RMV_VLAN;
+ /* rx checksum
+ if (adapter->rx_csum)
+ value |= MAC_CTRL_RX_CHKSUM_EN;
+ */
+ /* filter mode */
+ value |= MAC_CTRL_BC_EN;
+ if (netdev->flags & IFF_PROMISC)
+ value |= MAC_CTRL_PROMIS_EN;
+ else if (netdev->flags & IFF_ALLMULTI)
+ value |= MAC_CTRL_MC_ALL_EN;
+ /* value |= MAC_CTRL_LOOPBACK; */
+ iowrite32(value, hw->hw_addr + REG_MAC_CTRL);
+}
+
+static u32 atl1_check_link(struct atl1_adapter *adapter)
+{
+ struct atl1_hw *hw = &adapter->hw;
+ struct net_device *netdev = adapter->netdev;
+ u32 ret_val;
+ u16 speed, duplex, phy_data;
+ int reconfig = 0;
+
+ /* MII_BMSR must read twice */
+ atl1_read_phy_reg(hw, MII_BMSR, &phy_data);
+ atl1_read_phy_reg(hw, MII_BMSR, &phy_data);
+ if (!(phy_data & BMSR_LSTATUS)) { /* link down */
+ if (netif_carrier_ok(netdev)) { /* old link state: Up */
+ printk(KERN_INFO "%s: link is down\n",
+ atl1_driver_name);
+ adapter->link_speed = SPEED_0;
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+ }
+ return ATL1_SUCCESS;
+ }
+
+ /* Link Up */
+ ret_val = atl1_get_speed_and_duplex(hw, &speed, &duplex);
+ if (ret_val)
+ return ret_val;
+
+ switch (hw->media_type) {
+ case MEDIA_TYPE_1000M_FULL:
+ if (speed != SPEED_1000 || duplex != FULL_DUPLEX)
+ reconfig = 1;
+ break;
+ case MEDIA_TYPE_100M_FULL:
+ if (speed != SPEED_100 || duplex != FULL_DUPLEX)
+ reconfig = 1;
+ break;
+ case MEDIA_TYPE_100M_HALF:
+ if (speed != SPEED_100 || duplex != HALF_DUPLEX)
+ reconfig = 1;
+ break;
+ case MEDIA_TYPE_10M_FULL:
+ if (speed != SPEED_10 || duplex != FULL_DUPLEX)
+ reconfig = 1;
+ break;
+ case MEDIA_TYPE_10M_HALF:
+ if (speed != SPEED_10 || duplex != HALF_DUPLEX)
+ reconfig = 1;
+ break;
+ }
+
+ /* link result is our setting */
+ if (!reconfig) {
+ if (adapter->link_speed != speed
+ || adapter->link_duplex != duplex) {
+ adapter->link_speed = speed;
+ adapter->link_duplex = duplex;
+ atl1_setup_mac_ctrl(adapter);
+ printk(KERN_INFO "%s: %s link is up %d Mbps %s\n",
+ atl1_driver_name, netdev->name,
+ adapter->link_speed,
+ adapter->link_duplex ==
+ FULL_DUPLEX ? "full duplex" : "half duplex");
+ }
+ if (!netif_carrier_ok(netdev)) { /* Link down -> Up */
+ netif_carrier_on(netdev);
+ netif_wake_queue(netdev);
+ }
+ return ATL1_SUCCESS;
+ }
+
+ /* change orignal link status */
+ if (netif_carrier_ok(netdev)) {
+ adapter->link_speed = SPEED_0;
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+ }
+
+ if (hw->media_type != MEDIA_TYPE_AUTO_SENSOR &&
+ hw->media_type != MEDIA_TYPE_1000M_FULL) {
+ switch (hw->media_type) {
+ case MEDIA_TYPE_100M_FULL:
+ phy_data = MII_CR_FULL_DUPLEX | MII_CR_SPEED_100 |
+ MII_CR_RESET;
+ break;
+ case MEDIA_TYPE_100M_HALF:
+ phy_data = MII_CR_SPEED_100 | MII_CR_RESET;
+ break;
+ case MEDIA_TYPE_10M_FULL:
+ phy_data =
+ MII_CR_FULL_DUPLEX | MII_CR_SPEED_10 | MII_CR_RESET;
+ break;
+ default: /* MEDIA_TYPE_10M_HALF: */
+ phy_data = MII_CR_SPEED_10 | MII_CR_RESET;
+ break;
+ }
+ atl1_write_phy_reg(hw, MII_BMCR, phy_data);
+ return ATL1_SUCCESS;
+ }
+
+ /* auto-neg, insert timer to re-config phy */
+ if (!adapter->phy_timer_pending) {
+ adapter->phy_timer_pending = true;
+ mod_timer(&adapter->phy_config_timer, jiffies + 3 * HZ);
+ }
+
+ return ATL1_SUCCESS;
+}
+
+static void set_flow_ctrl_old(struct atl1_adapter *adapter)
+{
+ u32 hi, lo, value;
+
+ /* RFD Flow Control */
+ value = adapter->rfd_ring.count;
+ hi = value / 16;
+ if (hi < 2)
+ hi = 2;
+ lo = value * 7 / 8;
+
+ value = ((hi & RXQ_RXF_PAUSE_TH_HI_MASK) << RXQ_RXF_PAUSE_TH_HI_SHIFT) |
+ ((lo & RXQ_RXF_PAUSE_TH_LO_MASK) << RXQ_RXF_PAUSE_TH_LO_SHIFT);
+ iowrite32(value, adapter->hw.hw_addr + REG_RXQ_RXF_PAUSE_THRESH);
+
+ /* RRD Flow Control */
+ value = adapter->rrd_ring.count;
+ lo = value / 16;
+ hi = value * 7 / 8;
+ if (lo < 2)
+ lo = 2;
+ value = ((hi & RXQ_RRD_PAUSE_TH_HI_MASK) << RXQ_RRD_PAUSE_TH_HI_SHIFT) |
+ ((lo & RXQ_RRD_PAUSE_TH_LO_MASK) << RXQ_RRD_PAUSE_TH_LO_SHIFT);
+ iowrite32(value, adapter->hw.hw_addr + REG_RXQ_RRD_PAUSE_THRESH);
+}
+
+static void set_flow_ctrl_new(struct atl1_hw *hw)
+{
+ u32 hi, lo, value;
+
+ /* RXF Flow Control */
+ value = ioread32(hw->hw_addr + REG_SRAM_RXF_LEN);
+ lo = value / 16;
+ if (lo < 192)
+ lo = 192;
+ hi = value * 7 / 8;
+ if (hi < lo)
+ hi = lo + 16;
+ value = ((hi & RXQ_RXF_PAUSE_TH_HI_MASK) << RXQ_RXF_PAUSE_TH_HI_SHIFT) |
+ ((lo & RXQ_RXF_PAUSE_TH_LO_MASK) << RXQ_RXF_PAUSE_TH_LO_SHIFT);
+ iowrite32(value, hw->hw_addr + REG_RXQ_RXF_PAUSE_THRESH);
+
+ /* RRD Flow Control */
+ value = ioread32(hw->hw_addr + REG_SRAM_RRD_LEN);
+ lo = value / 8;
+ hi = value * 7 / 8;
+ if (lo < 2)
+ lo = 2;
+ if (hi < lo)
+ hi = lo + 3;
+ value = ((hi & RXQ_RRD_PAUSE_TH_HI_MASK) << RXQ_RRD_PAUSE_TH_HI_SHIFT) |
+ ((lo & RXQ_RRD_PAUSE_TH_LO_MASK) << RXQ_RRD_PAUSE_TH_LO_SHIFT);
+ iowrite32(value, hw->hw_addr + REG_RXQ_RRD_PAUSE_THRESH);
+}
+
+/*
+ * atl1_configure - Configure Transmit&Receive Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Tx /Rx unit of the MAC after a reset.
+ */
+static u32 atl1_configure(struct atl1_adapter *adapter)
+{
+ struct atl1_hw *hw = &adapter->hw;
+ u32 value;
+
+ /* clear interrupt status */
+ iowrite32(0xffffffff, adapter->hw.hw_addr + REG_ISR);
+
+ /* set MAC Address */
+ value = (((u32) hw->mac_addr[2]) << 24) |
+ (((u32) hw->mac_addr[3]) << 16) |
+ (((u32) hw->mac_addr[4]) << 8) |
+ (((u32) hw->mac_addr[5]));
+ iowrite32(value, hw->hw_addr + REG_MAC_STA_ADDR);
+ value = (((u32) hw->mac_addr[0]) << 8) | (((u32) hw->mac_addr[1]));
+ iowrite32(value, hw->hw_addr + (REG_MAC_STA_ADDR + 4));
+
+ /* tx / rx ring */
+
+ /* HI base address */
+ iowrite32((u32) ((adapter->tpd_ring.dma & 0xffffffff00000000ULL) >> 32),
+ hw->hw_addr + REG_DESC_BASE_ADDR_HI);
+ /* LO base address */
+ iowrite32((u32) (adapter->rfd_ring.dma & 0x00000000ffffffffULL),
+ hw->hw_addr + REG_DESC_RFD_ADDR_LO);
+ iowrite32((u32) (adapter->rrd_ring.dma & 0x00000000ffffffffULL),
+ hw->hw_addr + REG_DESC_RRD_ADDR_LO);
+ iowrite32((u32) (adapter->tpd_ring.dma & 0x00000000ffffffffULL),
+ hw->hw_addr + REG_DESC_TPD_ADDR_LO);
+ iowrite32((u32) (adapter->cmb.dma & 0x00000000ffffffffULL),
+ hw->hw_addr + REG_DESC_CMB_ADDR_LO);
+ iowrite32((u32) (adapter->smb.dma & 0x00000000ffffffffULL),
+ hw->hw_addr + REG_DESC_SMB_ADDR_LO);
+
+ /* element count */
+ value = adapter->rrd_ring.count;
+ value <<= 16;
+ value += adapter->rfd_ring.count;
+ iowrite32(value, hw->hw_addr + REG_DESC_RFD_RRD_RING_SIZE);
+ iowrite32(adapter->tpd_ring.count, hw->hw_addr + REG_DESC_TPD_RING_SIZE);
+
+ /* Load Ptr */
+ iowrite32(1, hw->hw_addr + REG_LOAD_PTR);
+
+ /* config Mailbox */
+ value = ((atomic_read(&adapter->tpd_ring.next_to_use)
+ & MB_TPD_PROD_INDX_MASK) << MB_TPD_PROD_INDX_SHIFT) |
+ ((atomic_read(&adapter->rrd_ring.next_to_clean)
+ & MB_RRD_CONS_INDX_MASK) << MB_RRD_CONS_INDX_SHIFT) |
+ ((atomic_read(&adapter->rfd_ring.next_to_use)
+ & MB_RFD_PROD_INDX_MASK) << MB_RFD_PROD_INDX_SHIFT);
+ iowrite32(value, hw->hw_addr + REG_MAILBOX);
+
+ /* config IPG/IFG */
+ value = (((u32) hw->ipgt & MAC_IPG_IFG_IPGT_MASK)
+ << MAC_IPG_IFG_IPGT_SHIFT) |
+ (((u32) hw->min_ifg & MAC_IPG_IFG_MIFG_MASK)
+ << MAC_IPG_IFG_MIFG_SHIFT) |
+ (((u32) hw->ipgr1 & MAC_IPG_IFG_IPGR1_MASK)
+ << MAC_IPG_IFG_IPGR1_SHIFT) |
+ (((u32) hw->ipgr2 & MAC_IPG_IFG_IPGR2_MASK)
+ << MAC_IPG_IFG_IPGR2_SHIFT);
+ iowrite32(value, hw->hw_addr + REG_MAC_IPG_IFG);
+
+ /* config Half-Duplex Control */
+ value = ((u32) hw->lcol & MAC_HALF_DUPLX_CTRL_LCOL_MASK) |
+ (((u32) hw->max_retry & MAC_HALF_DUPLX_CTRL_RETRY_MASK)
+ << MAC_HALF_DUPLX_CTRL_RETRY_SHIFT) |
+ MAC_HALF_DUPLX_CTRL_EXC_DEF_EN |
+ (0xa << MAC_HALF_DUPLX_CTRL_ABEBT_SHIFT) |
+ (((u32) hw->jam_ipg & MAC_HALF_DUPLX_CTRL_JAMIPG_MASK)
+ << MAC_HALF_DUPLX_CTRL_JAMIPG_SHIFT);
+ iowrite32(value, hw->hw_addr + REG_MAC_HALF_DUPLX_CTRL);
+
+ /* set Interrupt Moderator Timer */
+ iowrite16(adapter->imt, hw->hw_addr + REG_IRQ_MODU_TIMER_INIT);
+ iowrite32(MASTER_CTRL_ITIMER_EN, hw->hw_addr + REG_MASTER_CTRL);
+
+ /* set Interrupt Clear Timer */
+ iowrite16(adapter->ict, hw->hw_addr + REG_CMBDISDMA_TIMER);
+
+ /* set MTU, 4 : VLAN */
+ iowrite32(hw->max_frame_size + 4, hw->hw_addr + REG_MTU);
+
+ /* jumbo size & rrd retirement timer */
+ value = (((u32) hw->rx_jumbo_th & RXQ_JMBOSZ_TH_MASK)
+ << RXQ_JMBOSZ_TH_SHIFT) |
+ (((u32) hw->rx_jumbo_lkah & RXQ_JMBO_LKAH_MASK)
+ << RXQ_JMBO_LKAH_SHIFT) |
+ (((u32) hw->rrd_ret_timer & RXQ_RRD_TIMER_MASK)
+ << RXQ_RRD_TIMER_SHIFT);
+ iowrite32(value, hw->hw_addr + REG_RXQ_JMBOSZ_RRDTIM);
+
+ /* Flow Control */
+ switch (hw->dev_rev) {
+ case 0x8001:
+ case 0x9001:
+ case 0x9002:
+ case 0x9003:
+ set_flow_ctrl_old(adapter);
+ break;
+ default:
+ set_flow_ctrl_new(hw);
+ break;
+ }
+
+ /* config TXQ */
+ value = (((u32) hw->tpd_burst & TXQ_CTRL_TPD_BURST_NUM_MASK)
+ << TXQ_CTRL_TPD_BURST_NUM_SHIFT) |
+ (((u32) hw->txf_burst & TXQ_CTRL_TXF_BURST_NUM_MASK)
+ << TXQ_CTRL_TXF_BURST_NUM_SHIFT) |
+ (((u32) hw->tpd_fetch_th & TXQ_CTRL_TPD_FETCH_TH_MASK)
+ << TXQ_CTRL_TPD_FETCH_TH_SHIFT) | TXQ_CTRL_ENH_MODE | TXQ_CTRL_EN;
+ iowrite32(value, hw->hw_addr + REG_TXQ_CTRL);
+
+ /* min tpd fetch gap & tx jumbo packet size threshold for taskoffload */
+ value = (((u32) hw->tx_jumbo_task_th & TX_JUMBO_TASK_TH_MASK)
+ << TX_JUMBO_TASK_TH_SHIFT) |
+ (((u32) hw->tpd_fetch_gap & TX_TPD_MIN_IPG_MASK)
+ << TX_TPD_MIN_IPG_SHIFT);
+ iowrite32(value, hw->hw_addr + REG_TX_JUMBO_TASK_TH_TPD_IPG);
+
+ /* config RXQ */
+ value = (((u32) hw->rfd_burst & RXQ_CTRL_RFD_BURST_NUM_MASK)
+ << RXQ_CTRL_RFD_BURST_NUM_SHIFT) |
+ (((u32) hw->rrd_burst & RXQ_CTRL_RRD_BURST_THRESH_MASK)
+ << RXQ_CTRL_RRD_BURST_THRESH_SHIFT) |
+ (((u32) hw->rfd_fetch_gap & RXQ_CTRL_RFD_PREF_MIN_IPG_MASK)
+ << RXQ_CTRL_RFD_PREF_MIN_IPG_SHIFT) |
+ RXQ_CTRL_CUT_THRU_EN | RXQ_CTRL_EN;
+ iowrite32(value, hw->hw_addr + REG_RXQ_CTRL);
+
+ /* config DMA Engine */
+ value = ((((u32) hw->dmar_block) & DMA_CTRL_DMAR_BURST_LEN_MASK)
+ << DMA_CTRL_DMAR_BURST_LEN_SHIFT) |
+ ((((u32) hw->dmaw_block) & DMA_CTRL_DMAR_BURST_LEN_MASK)
+ << DMA_CTRL_DMAR_BURST_LEN_SHIFT) |
+ DMA_CTRL_DMAR_EN | DMA_CTRL_DMAW_EN;
+ value |= (u32) hw->dma_ord;
+ if (atl1_rcb_128 == hw->rcb_value)
+ value |= DMA_CTRL_RCB_VALUE;
+ iowrite32(value, hw->hw_addr + REG_DMA_CTRL);
+
+ /* config CMB / SMB */
+ value = hw->cmb_rrd | ((u32) hw->cmb_tpd << 16);
+ iowrite32(value, hw->hw_addr + REG_CMB_WRITE_TH);
+ value = hw->cmb_rx_timer | ((u32) hw->cmb_tx_timer << 16);
+ iowrite32(value, hw->hw_addr + REG_CMB_WRITE_TIMER);
+ iowrite32(hw->smb_timer, hw->hw_addr + REG_SMB_TIMER);
+
+ /* --- enable CMB / SMB */
+ value = CSMB_CTRL_CMB_EN | CSMB_CTRL_SMB_EN;
+ iowrite32(value, hw->hw_addr + REG_CSMB_CTRL);
+
+ value = ioread32(adapter->hw.hw_addr + REG_ISR);
+ if (unlikely((value & ISR_PHY_LINKDOWN) != 0))
+ value = 1; /* config failed */
+ else
+ value = 0;
+
+ /* clear all interrupt status */
+ iowrite32(0x3fffffff, adapter->hw.hw_addr + REG_ISR);
+ iowrite32(0, adapter->hw.hw_addr + REG_ISR);
+ return value;
+}
+
+/*
+ * atl1_irq_disable - Mask off interrupt generation on the NIC
+ * @adapter: board private structure
+ */
+static void atl1_irq_disable(struct atl1_adapter *adapter)
+{
+ atomic_inc(&adapter->irq_sem);
+ iowrite32(0, adapter->hw.hw_addr + REG_IMR);
+ ioread32(adapter->hw.hw_addr + REG_IMR);
+ synchronize_irq(adapter->pdev->irq);
+}
+
+static void atl1_vlan_rx_register(struct net_device *netdev,
+ struct vlan_group *grp)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ unsigned long flags;
+ u32 ctrl;
+
+ spin_lock_irqsave(&adapter->lock, flags);
+ /* atl1_irq_disable(adapter); */
+ adapter->vlgrp = grp;
+
+ if (grp) {
+ /* enable VLAN tag insert/strip */
+ ctrl = ioread32(adapter->hw.hw_addr + REG_MAC_CTRL);
+ ctrl |= MAC_CTRL_RMV_VLAN;
+ iowrite32(ctrl, adapter->hw.hw_addr + REG_MAC_CTRL);
+ } else {
+ /* disable VLAN tag insert/strip */
+ ctrl = ioread32(adapter->hw.hw_addr + REG_MAC_CTRL);
+ ctrl &= ~MAC_CTRL_RMV_VLAN;
+ iowrite32(ctrl, adapter->hw.hw_addr + REG_MAC_CTRL);
+ }
+
+ /* atl1_irq_enable(adapter); */
+ spin_unlock_irqrestore(&adapter->lock, flags);
+}
+
+/* FIXME: justify or remove -- CHS */
+static void atl1_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
+{
+ /* We don't do Vlan filtering */
+ return;
+}
+
+/* FIXME: this looks wrong too -- CHS */
+static void atl1_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->lock, flags);
+ /* atl1_irq_disable(adapter); */
+ if (adapter->vlgrp)
+ adapter->vlgrp->vlan_devices[vid] = NULL;
+ /* atl1_irq_enable(adapter); */
+ spin_unlock_irqrestore(&adapter->lock, flags);
+ /* We don't do Vlan filtering */
+ return;
+}
+
+static void atl1_restore_vlan(struct atl1_adapter *adapter)
+{
+ atl1_vlan_rx_register(adapter->netdev, adapter->vlgrp);
+ if (adapter->vlgrp) {
+ u16 vid;
+ for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) {
+ if (!adapter->vlgrp->vlan_devices[vid])
+ continue;
+ atl1_vlan_rx_add_vid(adapter->netdev, vid);
+ }
+ }
+}
+
+static u16 tpd_avail(struct atl1_tpd_ring *tpd_ring)
+{
+ u16 next_to_clean = atomic_read(&tpd_ring->next_to_clean);
+ u16 next_to_use = atomic_read(&tpd_ring->next_to_use);
+ return ((next_to_clean >
+ next_to_use) ? next_to_clean - next_to_use -
+ 1 : tpd_ring->count + next_to_clean - next_to_use - 1);
+}
+
+static int atl1_tso(struct atl1_adapter *adapter, struct sk_buff *skb,
+ struct tso_param *tso)
+{
+ /* We enter this function holding a spinlock. */
+ u8 ipofst;
+ int err;
+
+ if (skb_shinfo(skb)->gso_size) {
+ if (skb_header_cloned(skb)) {
+ err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+ if (unlikely(err))
+ return err;
+ }
+
+ if (skb->protocol == ntohs(ETH_P_IP)) {
+ skb->nh.iph->tot_len = 0;
+ skb->nh.iph->check = 0;
+ skb->h.th->check =
+ ~csum_tcpudp_magic(skb->nh.iph->saddr,
+ skb->nh.iph->daddr, 0,
+ IPPROTO_TCP, 0);
+ ipofst = skb->nh.raw - skb->data;
+ if (ipofst != ENET_HEADER_SIZE) /* 802.3 frame */
+ tso->tsopl |= 1 << TSO_PARAM_ETHTYPE_SHIFT;
+
+ tso->tsopl |= (skb->nh.iph->ihl &
+ CSUM_PARAM_IPHL_MASK) << CSUM_PARAM_IPHL_SHIFT;
+ tso->tsopl |= ((skb->h.th->doff << 2) &
+ TSO_PARAM_TCPHDRLEN_MASK) << TSO_PARAM_TCPHDRLEN_SHIFT;
+ tso->tsopl |= (skb_shinfo(skb)->gso_size &
+ TSO_PARAM_MSS_MASK) << TSO_PARAM_MSS_SHIFT;
+ tso->tsopl |= 1 << TSO_PARAM_IPCKSUM_SHIFT;
+ tso->tsopl |= 1 << TSO_PARAM_TCPCKSUM_SHIFT;
+ tso->tsopl |= 1 << TSO_PARAM_SEGMENT_SHIFT;
+ return true;
+ }
+ }
+ return false;
+}
+
+static int atl1_tx_csum(struct atl1_adapter *adapter, struct sk_buff *skb,
+ struct csum_param *csum)
+{
+ u8 css, cso;
+
+ if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
+ cso = skb->h.raw - skb->data;
+ css = (skb->h.raw + skb->csum) - skb->data;
+ if (unlikely(cso & 0x1)) {
+ printk(KERN_DEBUG "%s: payload offset != even number\n",
+ atl1_driver_name);
+ return -1;
+ }
+ csum->csumpl |= (cso & CSUM_PARAM_PLOADOFFSET_MASK) <<
+ CSUM_PARAM_PLOADOFFSET_SHIFT;
+ csum->csumpl |= (css & CSUM_PARAM_XSUMOFFSET_MASK) <<
+ CSUM_PARAM_XSUMOFFSET_SHIFT;
+ csum->csumpl |= 1 << CSUM_PARAM_CUSTOMCKSUM_SHIFT;
+ return true;
+ }
+
+ return true;
+}
+
+static void atl1_tx_map(struct atl1_adapter *adapter,
+ struct sk_buff *skb, bool tcp_seg)
+{
+ /* We enter this function holding a spinlock. */
+ struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
+ struct atl1_buffer *buffer_info;
+ struct page *page;
+ int first_buf_len = skb->len;
+ unsigned long offset;
+ unsigned int nr_frags;
+ unsigned int f;
+ u16 tpd_next_to_use;
+ u16 proto_hdr_len;
+ u16 i, m, len12;
+
+ first_buf_len -= skb->data_len;
+ nr_frags = skb_shinfo(skb)->nr_frags;
+ tpd_next_to_use = atomic_read(&tpd_ring->next_to_use);
+ buffer_info = &tpd_ring->buffer_info[tpd_next_to_use];
+ if (unlikely(buffer_info->skb))
+ BUG();
+ buffer_info->skb = NULL; /* put skb in last TPD */
+
+ if (tcp_seg) {
+ /* TSO/GSO */
+ proto_hdr_len =
+ ((skb->h.raw - skb->data) + (skb->h.th->doff << 2));
+ buffer_info->length = proto_hdr_len;
+ page = virt_to_page(skb->data);
+ offset = (unsigned long)skb->data & ~PAGE_MASK;
+ buffer_info->dma = pci_map_page(adapter->pdev, page,
+ offset, proto_hdr_len,
+ PCI_DMA_TODEVICE);
+
+ if (++tpd_next_to_use == tpd_ring->count)
+ tpd_next_to_use = 0;
+
+ if (first_buf_len > proto_hdr_len) {
+ len12 = first_buf_len - proto_hdr_len;
+ m = (len12 + MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN;
+ for (i = 0; i < m; i++) {
+ buffer_info =
+ &tpd_ring->buffer_info[tpd_next_to_use];
+ buffer_info->skb = NULL;
+ buffer_info->length =
+ (MAX_TX_BUF_LEN >=
+ len12) ? MAX_TX_BUF_LEN : len12;
+ len12 -= buffer_info->length;
+ page = virt_to_page(skb->data +
+ (proto_hdr_len +
+ i * MAX_TX_BUF_LEN));
+ offset = (unsigned long)(skb->data +
+ (proto_hdr_len +
+ i * MAX_TX_BUF_LEN)) &
+ ~PAGE_MASK;
+ buffer_info->dma =
+ pci_map_page(adapter->pdev, page, offset,
+ buffer_info->length,
+ PCI_DMA_TODEVICE);
+ if (++tpd_next_to_use == tpd_ring->count)
+ tpd_next_to_use = 0;
+ }
+ }
+ } else {
+ /* not TSO/GSO */
+ buffer_info->length = first_buf_len;
+ page = virt_to_page(skb->data);
+ offset = (unsigned long)skb->data & ~PAGE_MASK;
+ buffer_info->dma = pci_map_page(adapter->pdev, page,
+ offset, first_buf_len,
+ PCI_DMA_TODEVICE);
+ if (++tpd_next_to_use == tpd_ring->count)
+ tpd_next_to_use = 0;
+ }
+
+ for (f = 0; f < nr_frags; f++) {
+ struct skb_frag_struct *frag;
+ u16 lenf, i, m;
+
+ frag = &skb_shinfo(skb)->frags[f];
+ lenf = frag->size;
+
+ m = (lenf + MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN;
+ for (i = 0; i < m; i++) {
+ buffer_info = &tpd_ring->buffer_info[tpd_next_to_use];
+ if (unlikely(buffer_info->skb))
+ BUG();
+ buffer_info->skb = NULL;
+ buffer_info->length =
+ (lenf > MAX_TX_BUF_LEN) ? MAX_TX_BUF_LEN : lenf;
+ lenf -= buffer_info->length;
+ buffer_info->dma =
+ pci_map_page(adapter->pdev, frag->page,
+ frag->page_offset + i * MAX_TX_BUF_LEN,
+ buffer_info->length, PCI_DMA_TODEVICE);
+
+ if (++tpd_next_to_use == tpd_ring->count)
+ tpd_next_to_use = 0;
+ }
+ }
+
+ /* last tpd's buffer-info */
+ buffer_info->skb = skb;
+}
+
+static void atl1_tx_queue(struct atl1_adapter *adapter, int count,
+ union tpd_descr *descr)
+{
+ /* We enter this function holding a spinlock. */
+ struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
+ int j;
+ u32 val;
+ struct atl1_buffer *buffer_info;
+ struct tx_packet_desc *tpd;
+ u16 tpd_next_to_use = atomic_read(&tpd_ring->next_to_use);
+
+ for (j = 0; j < count; j++) {
+ buffer_info = &tpd_ring->buffer_info[tpd_next_to_use];
+ tpd = ATL1_TPD_DESC(&adapter->tpd_ring, tpd_next_to_use);
+ tpd->desc.csum.csumpu = descr->csum.csumpu;
+ tpd->desc.csum.csumpl = descr->csum.csumpl;
+ tpd->desc.tso.tsopu = descr->tso.tsopu;
+ tpd->desc.tso.tsopl = descr->tso.tsopl;
+ tpd->buffer_addr = cpu_to_le64(buffer_info->dma);
+ tpd->desc.data = descr->data;
+ tpd->desc.csum.csumpu |= (cpu_to_le16(buffer_info->length) &
+ CSUM_PARAM_BUFLEN_MASK) << CSUM_PARAM_BUFLEN_SHIFT;
+
+ val = (descr->tso.tsopl >> TSO_PARAM_SEGMENT_SHIFT) &
+ TSO_PARAM_SEGMENT_MASK;
+ if (val && !j)
+ tpd->desc.tso.tsopl |= 1 << TSO_PARAM_HDRFLAG_SHIFT;
+
+ if (j == (count - 1))
+ tpd->desc.csum.csumpl |= 1 << CSUM_PARAM_EOP_SHIFT;
+
+ if (++tpd_next_to_use == tpd_ring->count)
+ tpd_next_to_use = 0;
+ }
+ /*
+ * Force memory writes to complete before letting h/w
+ * know there are new descriptors to fetch. (Only
+ * applicable for weak-ordered memory model archs,
+ * such as IA-64).
+ */
+ wmb();
+
+ atomic_set(&tpd_ring->next_to_use, (int)tpd_next_to_use);
+}
+
+static void atl1_update_mailbox(struct atl1_adapter *adapter)
+{
+ unsigned long flags;
+ u32 tpd_next_to_use;
+ u32 rfd_next_to_use;
+ u32 rrd_next_to_clean;
+ u32 value;
+
+ spin_lock_irqsave(&adapter->mb_lock, flags);
+
+ tpd_next_to_use = atomic_read(&adapter->tpd_ring.next_to_use);
+ rfd_next_to_use = atomic_read(&adapter->rfd_ring.next_to_use);
+ rrd_next_to_clean = atomic_read(&adapter->rrd_ring.next_to_clean);
+
+ value = ((rfd_next_to_use & MB_RFD_PROD_INDX_MASK) <<
+ MB_RFD_PROD_INDX_SHIFT) |
+ ((rrd_next_to_clean & MB_RRD_CONS_INDX_MASK) <<
+ MB_RRD_CONS_INDX_SHIFT) |
+ ((tpd_next_to_use & MB_TPD_PROD_INDX_MASK) <<
+ MB_TPD_PROD_INDX_SHIFT);
+ iowrite32(value, adapter->hw.hw_addr + REG_MAILBOX);
+
+ spin_unlock_irqrestore(&adapter->mb_lock, flags);
+}
+
+static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ int len = skb->len;
+ int tso;
+ int count = 1;
+ int ret_val;
+ u32 val;
+ union tpd_descr param;
+ u16 frag_size;
+ u16 vlan_tag;
+ unsigned long flags;
+ unsigned int nr_frags = 0;
+ unsigned int mss = 0;
+ unsigned int f;
+ unsigned int proto_hdr_len;
+
+ len -= skb->data_len;
+
+ if (unlikely(skb->len == 0)) {
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ }
+
+ param.data = 0;
+ param.tso.tsopu = 0;
+ param.tso.tsopl = 0;
+ param.csum.csumpu = 0;
+ param.csum.csumpl = 0;
+
+ /* nr_frags will be nonzero if we're doing scatter/gather (SG) */
+ nr_frags = skb_shinfo(skb)->nr_frags;
+ for (f = 0; f < nr_frags; f++) {
+ frag_size = skb_shinfo(skb)->frags[f].size;
+ if (frag_size)
+ count +=
+ (frag_size + MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN;
+ }
+
+ /* mss will be nonzero if we're doing segment offload (TSO/GSO) */
+ mss = skb_shinfo(skb)->gso_size;
+ if (mss) {
+ if (skb->protocol == ntohs(ETH_P_IP)) {
+ proto_hdr_len = ((skb->h.raw - skb->data) +
+ (skb->h.th->doff << 2));
+ if (unlikely(proto_hdr_len > len)) {
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ }
+ /* need additional TPD ? */
+ if (proto_hdr_len != len)
+ count += (len - proto_hdr_len +
+ MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN;
+ }
+ }
+
+ local_irq_save(flags);
+ if (!spin_trylock(&adapter->lock)) {
+ /* Can't get lock - tell upper layer to requeue */
+ local_irq_restore(flags);
+ printk(KERN_DEBUG "%s: TX locked\n", atl1_driver_name);
+ return NETDEV_TX_LOCKED;
+ }
+
+ if (tpd_avail(&adapter->tpd_ring) < count) {
+ /* not enough descriptors */
+ netif_stop_queue(netdev);
+ spin_unlock_irqrestore(&adapter->lock, flags);
+ printk(KERN_DEBUG "%s: TX busy\n", atl1_driver_name);
+ return NETDEV_TX_BUSY;
+ }
+
+ param.data = 0;
+
+ if (adapter->vlgrp && vlan_tx_tag_present(skb)) {
+ vlan_tag = vlan_tx_tag_get(skb);
+ vlan_tag = (vlan_tag << 4) | (vlan_tag >> 13) |
+ ((vlan_tag >> 9) & 0x8);
+ param.csum.csumpl |= 1 << CSUM_PARAM_INSVLAG_SHIFT;
+ param.csum.csumpu |= (vlan_tag & CSUM_PARAM_VALANTAG_MASK) <<
+ CSUM_PARAM_VALAN_SHIFT;
+ }
+
+ tso = atl1_tso(adapter, skb, &param.tso);
+ if (tso < 0) {
+ spin_unlock_irqrestore(&adapter->lock, flags);
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ }
+
+ if (!tso) {
+ ret_val = atl1_tx_csum(adapter, skb, &param.csum);
+ if (ret_val < 0) {
+ spin_unlock_irqrestore(&adapter->lock, flags);
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ }
+ }
+
+ val = (param.csum.csumpl >> CSUM_PARAM_SEGMENT_SHIFT) &
+ CSUM_PARAM_SEGMENT_MASK;
+ atl1_tx_map(adapter, skb, 1 == val);
+ atl1_tx_queue(adapter, count, &param);
+ netdev->trans_start = jiffies;
+ spin_unlock_irqrestore(&adapter->lock, flags);
+ atl1_update_mailbox(adapter);
+ return NETDEV_TX_OK;
+}
+
+/*
+ * atl1_get_stats - Get System Network Statistics
+ * @netdev: network interface device structure
+ *
+ * Returns the address of the device statistics structure.
+ * The statistics are actually updated from the timer callback.
+ */
+static struct net_device_stats *atl1_get_stats(struct net_device *netdev)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ return &adapter->net_stats;
+}
+
+/*
+ * atl1_clean_rx_ring - Free RFD Buffers
+ * @adapter: board private structure
+ */
+static void atl1_clean_rx_ring(struct atl1_adapter *adapter)
+{
+ struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring;
+ struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring;
+ struct atl1_buffer *buffer_info;
+ struct pci_dev *pdev = adapter->pdev;
+ unsigned long size;
+ unsigned int i;
+
+ /* Free all the Rx ring sk_buffs */
+ for (i = 0; i < rfd_ring->count; i++) {
+ buffer_info = &rfd_ring->buffer_info[i];
+ if (buffer_info->dma) {
+ pci_unmap_page(pdev,
+ buffer_info->dma,
+ buffer_info->length,
+ PCI_DMA_FROMDEVICE);
+ buffer_info->dma = 0;
+ }
+ if (buffer_info->skb) {
+ dev_kfree_skb(buffer_info->skb);
+ buffer_info->skb = NULL;
+ }
+ }
+
+ size = sizeof(struct atl1_buffer) * rfd_ring->count;
+ memset(rfd_ring->buffer_info, 0, size);
+
+ /* Zero out the descriptor ring */
+ memset(rfd_ring->desc, 0, rfd_ring->size);
+
+ rfd_ring->next_to_clean = 0;
+ atomic_set(&rfd_ring->next_to_use, 0);
+
+ rrd_ring->next_to_use = 0;
+ atomic_set(&rrd_ring->next_to_clean, 0);
+}
+
+/*
+ * atl1_clean_tx_ring - Free Tx Buffers
+ * @adapter: board private structure
+ */
+static void atl1_clean_tx_ring(struct atl1_adapter *adapter)
+{
+ struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
+ struct atl1_buffer *buffer_info;
+ struct pci_dev *pdev = adapter->pdev;
+ unsigned long size;
+ unsigned int i;
+
+ /* Free all the Tx ring sk_buffs */
+ for (i = 0; i < tpd_ring->count; i++) {
+ buffer_info = &tpd_ring->buffer_info[i];
+ if (buffer_info->dma) {
+ pci_unmap_page(pdev, buffer_info->dma,
+ buffer_info->length, PCI_DMA_TODEVICE);
+ buffer_info->dma = 0;
+ }
+ }
+
+ for (i = 0; i < tpd_ring->count; i++) {
+ buffer_info = &tpd_ring->buffer_info[i];
+ if (buffer_info->skb) {
+ dev_kfree_skb_any(buffer_info->skb);
+ buffer_info->skb = NULL;
+ }
+ }
+
+ size = sizeof(struct atl1_buffer) * tpd_ring->count;
+ memset(tpd_ring->buffer_info, 0, size);
+
+ /* Zero out the descriptor ring */
+ memset(tpd_ring->desc, 0, tpd_ring->size);
+
+ atomic_set(&tpd_ring->next_to_use, 0);
+ atomic_set(&tpd_ring->next_to_clean, 0);
+}
+
+/*
+ * atl1_free_ring_resources - Free Tx / RX descriptor Resources
+ * @adapter: board private structure
+ *
+ * Free all transmit software resources
+ */
+void atl1_free_ring_resources(struct atl1_adapter *adapter)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
+ struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring;
+ struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring;
+ struct atl1_ring_header *ring_header = &adapter->ring_header;
+
+ atl1_clean_tx_ring(adapter);
+ atl1_clean_rx_ring(adapter);
+
+ kfree(tpd_ring->buffer_info);
+ pci_free_consistent(pdev, ring_header->size, ring_header->desc,
+ ring_header->dma);
+
+ tpd_ring->buffer_info = NULL;
+ tpd_ring->desc = NULL;
+ tpd_ring->dma = 0;
+
+ rfd_ring->buffer_info = NULL;
+ rfd_ring->desc = NULL;
+ rfd_ring->dma = 0;
+
+ rrd_ring->desc = NULL;
+ rrd_ring->dma = 0;
+}
+
+s32 atl1_up(struct atl1_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ int err;
+ int irq_flags = IRQF_SAMPLE_RANDOM;
+
+ /* hardware has been reset, we need to reload some things */
+ atl1_set_multi(netdev);
+ atl1_restore_vlan(adapter);
+ err = atl1_alloc_rx_buffers(adapter);
+ if (unlikely(!err)) /* no RX BUFFER allocated */
+ return -ENOMEM;
+
+ if (unlikely(atl1_configure(adapter))) {
+ err = -EIO;
+ goto err_up;
+ }
+
+ err = pci_enable_msi(adapter->pdev);
+ if (err) {
+ dev_info(&adapter->pdev->dev,
+ "Unable to enable MSI: %d\n", err);
+ irq_flags |= IRQF_SHARED;
+ }
+
+ err = request_irq(adapter->pdev->irq, &atl1_intr, irq_flags,
+ netdev->name, netdev);
+ if (unlikely(err))
+ goto err_up;
+
+ mod_timer(&adapter->watchdog_timer, jiffies);
+ atl1_irq_enable(adapter);
+ atl1_check_link(adapter);
+ return 0;
+
+ /* FIXME: unreachable code! -- CHS */
+ /* free irq disable any interrupt */
+ iowrite32(0, adapter->hw.hw_addr + REG_IMR);
+ free_irq(adapter->pdev->irq, netdev);
+
+err_up:
+ pci_disable_msi(adapter->pdev);
+ /* free rx_buffers */
+ atl1_clean_rx_ring(adapter);
+ return err;
+}
+
+void atl1_down(struct atl1_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+
+ del_timer_sync(&adapter->watchdog_timer);
+ del_timer_sync(&adapter->phy_config_timer);
+ adapter->phy_timer_pending = false;
+
+ atl1_irq_disable(adapter);
+ free_irq(adapter->pdev->irq, netdev);
+ pci_disable_msi(adapter->pdev);
+ atl1_reset_hw(&adapter->hw);
+ adapter->cmb.cmb->int_stats = 0;
+
+ adapter->link_speed = SPEED_0;
+ adapter->link_duplex = -1;
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+
+ atl1_clean_tx_ring(adapter);
+ atl1_clean_rx_ring(adapter);
+}
+
+/*
+ * atl1_change_mtu - Change the Maximum Transfer Unit
+ * @netdev: network interface device structure
+ * @new_mtu: new value for maximum frame size
+ *
+ * Returns 0 on success, negative on failure
+ */
+static int atl1_change_mtu(struct net_device *netdev, int new_mtu)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ int old_mtu = netdev->mtu;
+ int max_frame = new_mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
+
+ if ((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) ||
+ (max_frame > MAX_JUMBO_FRAME_SIZE)) {
+ printk(KERN_WARNING "%s: invalid MTU setting\n",
+ atl1_driver_name);
+ return -EINVAL;
+ }
+
+ adapter->hw.max_frame_size = max_frame;
+ adapter->hw.tx_jumbo_task_th = (max_frame + 7) >> 3;
+ adapter->rx_buffer_len = (max_frame + 7) & ~7;
+ adapter->hw.rx_jumbo_th = adapter->rx_buffer_len / 8;
+
+ netdev->mtu = new_mtu;
+ if ((old_mtu != new_mtu) && netif_running(netdev)) {
+ atl1_down(adapter);
+ atl1_up(adapter);
+ }
+
+ return 0;
+}
+
+/*
+ * atl1_set_mac - Change the Ethernet Address of the NIC
+ * @netdev: network interface device structure
+ * @p: pointer to an address structure
+ *
+ * Returns 0 on success, negative on failure
+ */
+static int atl1_set_mac(struct net_device *netdev, void *p)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ struct sockaddr *addr = p;
+
+ if (netif_running(netdev))
+ return -EBUSY;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+ memcpy(adapter->hw.mac_addr, addr->sa_data, netdev->addr_len);
+
+ atl1_set_mac_addr(&adapter->hw);
+ return 0;
+}
+
+/*
+ * atl1_watchdog - Timer Call-back
+ * @data: pointer to netdev cast into an unsigned long
+ */
+static void atl1_watchdog(unsigned long data)
+{
+ struct atl1_adapter *adapter = (struct atl1_adapter *)data;
+
+ /* Reset the timer */
+ mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);
+}
+
+static int mdio_read(struct net_device *netdev, int phy_id, int reg_num)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ u16 result;
+
+ atl1_read_phy_reg(&adapter->hw, reg_num & 0x1f, &result);
+
+ return result;
+}
+
+static void mdio_write(struct net_device *netdev, int phy_id, int reg_num, int val)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+
+ atl1_write_phy_reg(&adapter->hw, reg_num, val);
+}
+
+/*
+ * atl1_mii_ioctl -
+ * @netdev:
+ * @ifreq:
+ * @cmd:
+ */
+static int atl1_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ unsigned long flags;
+ int retval;
+
+ if (!netif_running(netdev))
+ return -EINVAL;
+
+ spin_lock_irqsave(&adapter->lock, flags);
+ retval = generic_mii_ioctl(&adapter->mii, if_mii(ifr), cmd, NULL);
+ spin_unlock_irqrestore(&adapter->lock, flags);
+
+ return retval;
+}
+
+/*
+ * atl1_ioctl -
+ * @netdev:
+ * @ifreq:
+ * @cmd:
+ */
+static int atl1_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+ switch (cmd) {
+ case SIOCGMIIPHY:
+ case SIOCGMIIREG:
+ case SIOCSMIIREG:
+ return atl1_mii_ioctl(netdev, ifr, cmd);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+/*
+ * atl1_tx_timeout - Respond to a Tx Hang
+ * @netdev: network interface device structure
+ */
+static void atl1_tx_timeout(struct net_device *netdev)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ /* Do the reset outside of interrupt context */
+ schedule_work(&adapter->tx_timeout_task);
+}
+
+/*
+ * atl1_phy_config - Timer Call-back
+ * @data: pointer to netdev cast into an unsigned long
+ */
+static void atl1_phy_config(unsigned long data)
+{
+ struct atl1_adapter *adapter = (struct atl1_adapter *)data;
+ struct atl1_hw *hw = &adapter->hw;
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->lock, flags);
+ adapter->phy_timer_pending = false;
+ atl1_write_phy_reg(hw, MII_ADVERTISE, hw->mii_autoneg_adv_reg);
+ atl1_write_phy_reg(hw, MII_AT001_CR, hw->mii_1000t_ctrl_reg);
+ atl1_write_phy_reg(hw, MII_BMCR, MII_CR_RESET | MII_CR_AUTO_NEG_EN);
+ spin_unlock_irqrestore(&adapter->lock, flags);
+}
+
+int atl1_reset(struct atl1_adapter *adapter)
+{
+ int ret;
+
+ ret = atl1_reset_hw(&adapter->hw);
+ if (ret != ATL1_SUCCESS)
+ return ret;
+ return atl1_init_hw(&adapter->hw);
+}
+
+/*
+ * atl1_open - Called when a network interface is made active
+ * @netdev: network interface device structure
+ *
+ * Returns 0 on success, negative value on failure
+ *
+ * The open entry point is called when a network interface is made
+ * active by the system (IFF_UP). At this point all resources needed
+ * for transmit and receive operations are allocated, the interrupt
+ * handler is registered with the OS, the watchdog timer is started,
+ * and the stack is notified that the interface is ready.
+ */
+static int atl1_open(struct net_device *netdev)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ int err;
+
+ /* allocate transmit descriptors */
+ err = atl1_setup_ring_resources(adapter);
+ if (err)
+ return err;
+
+ err = atl1_up(adapter);
+ if (err)
+ goto err_up;
+
+ return 0;
+
+err_up:
+ atl1_reset(adapter);
+ return err;
+}
+
+/*
+ * atl1_close - Disables a network interface
+ * @netdev: network interface device structure
+ *
+ * Returns 0, this is not allowed to fail
+ *
+ * The close entry point is called when an interface is de-activated
+ * by the OS. The hardware is still under the drivers control, but
+ * needs to be disabled. A global MAC reset is issued to stop the
+ * hardware, and all transmit and receive resources are freed.
+ */
+static int atl1_close(struct net_device *netdev)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ atl1_down(adapter);
+ atl1_free_ring_resources(adapter);
+ return 0;
+}
+
+/*
+ * If TPD Buffer size equal to 0, PCIE DMAR_TO_INT
+ * will assert. We do soft reset <0x1400=1> according
+ * with the SPEC. BUT, it seemes that PCIE or DMA
+ * state-machine will not be reset. DMAR_TO_INT will
+ * assert again and again.
+ */
+static void atl1_tx_timeout_task(struct work_struct *work)
+{
+ struct atl1_adapter *adapter =
+ container_of(work, struct atl1_adapter, tx_timeout_task);
+ struct net_device *netdev = adapter->netdev;
+
+ netif_device_detach(netdev);
+ atl1_down(adapter);
+ atl1_up(adapter);
+ netif_device_attach(netdev);
+}
+
+/*
+ * atl1_link_chg_task - deal with link change event Out of interrupt context
+ */
+static void atl1_link_chg_task(struct work_struct *work)
+{
+ struct atl1_adapter *adapter =
+ container_of(work, struct atl1_adapter, link_chg_task);
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->lock, flags);
+ atl1_check_link(adapter);
+ spin_unlock_irqrestore(&adapter->lock, flags);
+}
+
+/*
+ * atl1_pcie_patch - Patch for PCIE module
+ */
+static void atl1_pcie_patch(struct atl1_adapter *adapter)
+{
+ u32 value;
+ value = 0x6500;
+ iowrite32(value, adapter->hw.hw_addr + 0x12FC);
+ /* pcie flow control mode change */
+ value = ioread32(adapter->hw.hw_addr + 0x1008);
+ value |= 0x8000;
+ iowrite32(value, adapter->hw.hw_addr + 0x1008);
+}
+
+/*
+ * When ACPI resume on some VIA MotherBoard, the Interrupt Disable bit/0x400
+ * on PCI Command register is disable.
+ * The function enable this bit.
+ * Brackett, 2006/03/15
+ */
+static void atl1_via_workaround(struct atl1_adapter *adapter)
+{
+ unsigned long value;
+
+ value = ioread16(adapter->hw.hw_addr + PCI_COMMAND);
+ if (value & PCI_COMMAND_INTX_DISABLE)
+ value &= ~PCI_COMMAND_INTX_DISABLE;
+ iowrite32(value, adapter->hw.hw_addr + PCI_COMMAND);
+}
+
+/*
+ * atl1_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @ent: entry in atl1_pci_tbl
+ *
+ * Returns 0 on success, negative on failure
+ *
+ * atl1_probe initializes an adapter identified by a pci_dev structure.
+ * The OS initialization, configuring of the adapter private structure,
+ * and a hardware reset occur.
+ */
+static int __devinit atl1_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct net_device *netdev;
+ struct atl1_adapter *adapter;
+ static int cards_found = 0;
+ bool pci_using_64 = true;
+ int err;
+
+ err = pci_enable_device(pdev);
+ if (err)
+ return err;
+
+ err = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
+ if (err) {
+ err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (err) {
+ printk(KERN_DEBUG
+ "%s: no usable DMA configuration, aborting\n",
+ atl1_driver_name);
+ goto err_dma;
+ }
+ pci_using_64 = false;
+ }
+ /* Mark all PCI regions associated with PCI device
+ * pdev as being reserved by owner atl1_driver_name
+ */
+ err = pci_request_regions(pdev, atl1_driver_name);
+ if (err)
+ goto err_request_regions;
+
+ /* Enables bus-mastering on the device and calls
+ * pcibios_set_master to do the needed arch specific settings
+ */
+ pci_set_master(pdev);
+
+ netdev = alloc_etherdev(sizeof(struct atl1_adapter));
+ if (!netdev) {
+ err = -ENOMEM;
+ goto err_alloc_etherdev;
+ }
+ SET_MODULE_OWNER(netdev);
+ SET_NETDEV_DEV(netdev, &pdev->dev);
+
+ pci_set_drvdata(pdev, netdev);
+ adapter = netdev_priv(netdev);
+ adapter->netdev = netdev;
+ adapter->pdev = pdev;
+ adapter->hw.back = adapter;
+
+ adapter->hw.hw_addr = pci_iomap(pdev, 0, 0);
+ if (!adapter->hw.hw_addr) {
+ err = -EIO;
+ goto err_pci_iomap;
+ }
+ /* get device revision number */
+ adapter->hw.dev_rev = ioread16(adapter->hw.hw_addr + (REG_MASTER_CTRL + 2));
+
+ /* set default ring resource counts */
+ adapter->rfd_ring.count = adapter->rrd_ring.count = ATL1_DEFAULT_RFD;
+ adapter->tpd_ring.count = ATL1_DEFAULT_TPD;
+
+ adapter->mii.dev = netdev;
+ adapter->mii.mdio_read = mdio_read;
+ adapter->mii.mdio_write = mdio_write;
+ adapter->mii.phy_id_mask = 0x1f;
+ adapter->mii.reg_num_mask = 0x1f;
+
+ netdev->open = &atl1_open;
+ netdev->stop = &atl1_close;
+ netdev->hard_start_xmit = &atl1_xmit_frame;
+ netdev->get_stats = &atl1_get_stats;
+ netdev->set_multicast_list = &atl1_set_multi;
+ netdev->set_mac_address = &atl1_set_mac;
+ netdev->change_mtu = &atl1_change_mtu;
+ netdev->do_ioctl = &atl1_ioctl;
+ netdev->tx_timeout = &atl1_tx_timeout;
+ netdev->watchdog_timeo = 5 * HZ;
+ netdev->vlan_rx_register = atl1_vlan_rx_register;
+ netdev->vlan_rx_add_vid = atl1_vlan_rx_add_vid;
+ netdev->vlan_rx_kill_vid = atl1_vlan_rx_kill_vid;
+ netdev->ethtool_ops = &atl1_ethtool_ops;
+ adapter->bd_number = cards_found;
+ adapter->pci_using_64 = pci_using_64;
+
+ /* setup the private structure */
+ err = atl1_sw_init(adapter);
+ if (err)
+ goto err_common;
+
+ netdev->features = NETIF_F_HW_CSUM;
+ netdev->features |= NETIF_F_SG;
+ netdev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX);
+
+ /*
+ * FIXME - Until tso performance gets fixed, disable the feature.
+ * Enable it with ethtool -K if desired.
+ */
+ /* netdev->features |= NETIF_F_TSO; */
+
+ if (pci_using_64)
+ netdev->features |= NETIF_F_HIGHDMA;
+
+ netdev->features |= NETIF_F_LLTX;
+
+ /*
+ * patch for some L1 of old version,
+ * the final version of L1 may not need these
+ * patches
+ */
+ /* atl1_pcie_patch(adapter); */
+
+ /* really reset GPHY core */
+ iowrite16(0, adapter->hw.hw_addr + REG_GPHY_ENABLE);
+
+ /*
+ * reset the controller to
+ * put the device in a known good starting state
+ */
+ if (atl1_reset_hw(&adapter->hw)) {
+ err = -EIO;
+ goto err_common;
+ }
+
+ /* copy the MAC address out of the EEPROM */
+ atl1_read_mac_addr(&adapter->hw);
+ memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
+
+ if (!is_valid_ether_addr(netdev->dev_addr)) {
+ err = -EIO;
+ goto err_common;
+ }
+
+ atl1_check_options(adapter);
+
+ /* pre-init the MAC, and setup link */
+ err = atl1_init_hw(&adapter->hw);
+ if (err) {
+ err = -EIO;
+ goto err_common;
+ }
+
+ atl1_pcie_patch(adapter);
+ /* assume we have no link for now */
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+
+ init_timer(&adapter->watchdog_timer);
+ adapter->watchdog_timer.function = &atl1_watchdog;
+ adapter->watchdog_timer.data = (unsigned long)adapter;
+
+ init_timer(&adapter->phy_config_timer);
+ adapter->phy_config_timer.function = &atl1_phy_config;
+ adapter->phy_config_timer.data = (unsigned long)adapter;
+ adapter->phy_timer_pending = false;
+
+ INIT_WORK(&adapter->tx_timeout_task, atl1_tx_timeout_task);
+
+ INIT_WORK(&adapter->link_chg_task, atl1_link_chg_task);
+
+ INIT_WORK(&adapter->pcie_dma_to_rst_task, atl1_tx_timeout_task);
+
+ err = register_netdev(netdev);
+ if (err)
+ goto err_common;
+
+ cards_found++;
+ atl1_via_workaround(adapter);
+ return 0;
+
+err_common:
+ pci_iounmap(pdev, adapter->hw.hw_addr);
+err_pci_iomap:
+ free_netdev(netdev);
+err_alloc_etherdev:
+ pci_release_regions(pdev);
+err_dma:
+err_request_regions:
+ pci_disable_device(pdev);
+ return err;
+}
+
+/*
+ * atl1_remove - Device Removal Routine
+ * @pdev: PCI device information struct
+ *
+ * atl1_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device. The could be caused by a
+ * Hot-Plug event, or because the driver is going to be removed from
+ * memory.
+ */
+static void __devexit atl1_remove(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct atl1_adapter *adapter;
+ /* Device not available. Return. */
+ if (!netdev)
+ return;
+
+ adapter = netdev_priv(netdev);
+ iowrite16(0, adapter->hw.hw_addr + REG_GPHY_ENABLE);
+ unregister_netdev(netdev);
+ pci_iounmap(pdev, adapter->hw.hw_addr);
+ pci_release_regions(pdev);
+ free_netdev(netdev);
+ pci_disable_device(pdev);
+}
+
+#ifdef CONFIG_PM
+static int atl1_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ struct atl1_hw *hw = &adapter->hw;
+ u32 ctrl = 0;
+ u32 wufc = adapter->wol;
+
+ netif_device_detach(netdev);
+ if (netif_running(netdev))
+ atl1_down(adapter);
+
+ atl1_read_phy_reg(hw, MII_BMSR, (u16 *) & ctrl);
+ atl1_read_phy_reg(hw, MII_BMSR, (u16 *) & ctrl);
+ if (ctrl & BMSR_LSTATUS)
+ wufc &= ~ATL1_WUFC_LNKC;
+
+ /* reduce speed to 10/100M */
+ if (wufc) {
+ atl1_phy_enter_power_saving(hw);
+ /* if resume, let driver to re- setup link */
+ hw->phy_configured = false;
+ atl1_set_mac_addr(hw);
+ atl1_set_multi(netdev);
+
+ ctrl = 0;
+ /* turn on magic packet wol */
+ if (wufc & ATL1_WUFC_MAG)
+ ctrl = WOL_MAGIC_EN | WOL_MAGIC_PME_EN;
+
+ /* turn on Link change WOL */
+ if (wufc & ATL1_WUFC_LNKC)
+ ctrl |= (WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN);
+ iowrite32(ctrl, hw->hw_addr + REG_WOL_CTRL);
+
+ /* turn on all-multi mode if wake on multicast is enabled */
+ ctrl = ioread32(hw->hw_addr + REG_MAC_CTRL);
+ ctrl &= ~MAC_CTRL_DBG;
+ ctrl &= ~MAC_CTRL_PROMIS_EN;
+ if (wufc & ATL1_WUFC_MC)
+ ctrl |= MAC_CTRL_MC_ALL_EN;
+ else
+ ctrl &= ~MAC_CTRL_MC_ALL_EN;
+
+ /* turn on broadcast mode if wake on-BC is enabled */
+ if (wufc & ATL1_WUFC_BC)
+ ctrl |= MAC_CTRL_BC_EN;
+ else
+ ctrl &= ~MAC_CTRL_BC_EN;
+
+ /* enable RX */
+ ctrl |= MAC_CTRL_RX_EN;
+ iowrite32(ctrl, hw->hw_addr + REG_MAC_CTRL);
+ pci_enable_wake(pdev, PCI_D3hot, 1);
+ pci_enable_wake(pdev, PCI_D3cold, 1); /* 4 == D3 cold */
+ } else {
+ iowrite32(0, hw->hw_addr + REG_WOL_CTRL);
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ pci_enable_wake(pdev, PCI_D3cold, 0); /* 4 == D3 cold */
+ }
+
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+
+ pci_set_power_state(pdev, PCI_D3hot);
+
+ return 0;
+}
+
+static int atl1_resume(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ u32 ret_val;
+
+ pci_set_power_state(pdev, 0);
+ pci_restore_state(pdev);
+
+ ret_val = pci_enable_device(pdev);
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ pci_enable_wake(pdev, PCI_D3cold, 0);
+
+ iowrite32(0, adapter->hw.hw_addr + REG_WOL_CTRL);
+ atl1_reset(adapter);
+
+ if (netif_running(netdev))
+ atl1_up(adapter);
+ netif_device_attach(netdev);
+
+ atl1_via_workaround(adapter);
+
+ return 0;
+}
+#else
+#define atl1_suspend NULL
+#define atl1_resume NULL
+#endif
+
+static struct pci_driver atl1_driver = {
+ .name = atl1_driver_name,
+ .id_table = atl1_pci_tbl,
+ .probe = atl1_probe,
+ .remove = __devexit_p(atl1_remove),
+ /* Power Managment Hooks */
+ /* probably broken right now -- CHS */
+ .suspend = atl1_suspend,
+ .resume = atl1_resume
+};
+
+/*
+ * atl1_exit_module - Driver Exit Cleanup Routine
+ *
+ * atl1_exit_module is called just before the driver is removed
+ * from memory.
+ */
+static void __exit atl1_exit_module(void)
+{
+ pci_unregister_driver(&atl1_driver);
+}
+
+/*
+ * atl1_init_module - Driver Registration Routine
+ *
+ * atl1_init_module is the first routine called when the driver is
+ * loaded. All it does is register with the PCI subsystem.
+ */
+static int __init atl1_init_module(void)
+{
+ printk(KERN_INFO "%s - version %s\n", atl1_driver_string, DRIVER_VERSION);
+ printk(KERN_INFO "%s\n", atl1_copyright);
+ return pci_register_driver(&atl1_driver);
+}
+
+module_init(atl1_init_module);
+module_exit(atl1_exit_module);
diff --git a/drivers/net/atl1/atl1_param.c b/drivers/net/atl1/atl1_param.c
new file mode 100644
index 00000000000..c407214339f
--- /dev/null
+++ b/drivers/net/atl1/atl1_param.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved.
+ * Copyright(c) 2006 Chris Snook <csnook@redhat.com>
+ * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com>
+ *
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/moduleparam.h>
+#include "atl1.h"
+
+/*
+ * This is the only thing that needs to be changed to adjust the
+ * maximum number of ports that the driver can manage.
+ */
+#define ATL1_MAX_NIC 4
+
+#define OPTION_UNSET -1
+#define OPTION_DISABLED 0
+#define OPTION_ENABLED 1
+
+#define ATL1_PARAM_INIT { [0 ... ATL1_MAX_NIC] = OPTION_UNSET }
+
+/*
+ * Interrupt Moderate Timer in units of 2 us
+ *
+ * Valid Range: 10-65535
+ *
+ * Default Value: 100 (200us)
+ */
+static int __devinitdata int_mod_timer[ATL1_MAX_NIC+1] = ATL1_PARAM_INIT;
+static int num_int_mod_timer = 0;
+module_param_array_named(int_mod_timer, int_mod_timer, int, &num_int_mod_timer, 0);
+MODULE_PARM_DESC(int_mod_timer, "Interrupt moderator timer");
+
+/*
+ * flash_vendor
+ *
+ * Valid Range: 0-2
+ *
+ * 0 - Atmel
+ * 1 - SST
+ * 2 - ST
+ *
+ * Default Value: 0
+ */
+static int __devinitdata flash_vendor[ATL1_MAX_NIC+1] = ATL1_PARAM_INIT;
+static int num_flash_vendor = 0;
+module_param_array_named(flash_vendor, flash_vendor, int, &num_flash_vendor, 0);
+MODULE_PARM_DESC(flash_vendor, "SPI flash vendor");
+
+#define DEFAULT_INT_MOD_CNT 100 /* 200us */
+#define MAX_INT_MOD_CNT 65000
+#define MIN_INT_MOD_CNT 50
+
+#define FLASH_VENDOR_DEFAULT 0
+#define FLASH_VENDOR_MIN 0
+#define FLASH_VENDOR_MAX 2
+
+struct atl1_option {
+ enum { enable_option, range_option, list_option } type;
+ char *name;
+ char *err;
+ int def;
+ union {
+ struct { /* range_option info */
+ int min;
+ int max;
+ } r;
+ struct { /* list_option info */
+ int nr;
+ struct atl1_opt_list {
+ int i;
+ char *str;
+ } *p;
+ } l;
+ } arg;
+};
+
+static int __devinit atl1_validate_option(int *value, struct atl1_option *opt)
+{
+ if (*value == OPTION_UNSET) {
+ *value = opt->def;
+ return 0;
+ }
+
+ switch (opt->type) {
+ case enable_option:
+ switch (*value) {
+ case OPTION_ENABLED:
+ printk(KERN_INFO "%s: %s Enabled\n", atl1_driver_name,
+ opt->name);
+ return 0;
+ case OPTION_DISABLED:
+ printk(KERN_INFO "%s: %s Disabled\n", atl1_driver_name,
+ opt->name);
+ return 0;
+ }
+ break;
+ case range_option:
+ if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) {
+ printk(KERN_INFO "%s: %s set to %i\n",
+ atl1_driver_name, opt->name, *value);
+ return 0;
+ }
+ break;
+ case list_option:{
+ int i;
+ struct atl1_opt_list *ent;
+
+ for (i = 0; i < opt->arg.l.nr; i++) {
+ ent = &opt->arg.l.p[i];
+ if (*value == ent->i) {
+ if (ent->str[0] != '\0')
+ printk(KERN_INFO "%s: %s\n",
+ atl1_driver_name, ent->str);
+ return 0;
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ printk(KERN_INFO "%s: invalid %s specified (%i) %s\n",
+ atl1_driver_name, opt->name, *value, opt->err);
+ *value = opt->def;
+ return -1;
+}
+
+/*
+ * atl1_check_options - Range Checking for Command Line Parameters
+ * @adapter: board private structure
+ *
+ * This routine checks all command line parameters for valid user
+ * input. If an invalid value is given, or if no user specified
+ * value exists, a default value is used. The final value is stored
+ * in a variable in the adapter structure.
+ */
+void __devinit atl1_check_options(struct atl1_adapter *adapter)
+{
+ int bd = adapter->bd_number;
+ if (bd >= ATL1_MAX_NIC) {
+ printk(KERN_NOTICE "%s: warning: no configuration for board #%i\n",
+ atl1_driver_name, bd);
+ printk(KERN_NOTICE "%s: using defaults for all values\n",
+ atl1_driver_name);
+ }
+ { /* Interrupt Moderate Timer */
+ struct atl1_option opt = {
+ .type = range_option,
+ .name = "Interrupt Moderator Timer",
+ .err = "using default of "
+ __MODULE_STRING(DEFAULT_INT_MOD_CNT),
+ .def = DEFAULT_INT_MOD_CNT,
+ .arg = {.r =
+ {.min = MIN_INT_MOD_CNT,.max = MAX_INT_MOD_CNT}}
+ };
+ int val;
+ if (num_int_mod_timer > bd) {
+ val = int_mod_timer[bd];
+ atl1_validate_option(&val, &opt);
+ adapter->imt = (u16) val;
+ } else
+ adapter->imt = (u16) (opt.def);
+ }
+
+ { /* Flash Vendor */
+ struct atl1_option opt = {
+ .type = range_option,
+ .name = "SPI Flash Vendor",
+ .err = "using default of "
+ __MODULE_STRING(FLASH_VENDOR_DEFAULT),
+ .def = DEFAULT_INT_MOD_CNT,
+ .arg = {.r =
+ {.min = FLASH_VENDOR_MIN,.max =
+ FLASH_VENDOR_MAX}}
+ };
+ int val;
+ if (num_flash_vendor > bd) {
+ val = flash_vendor[bd];
+ atl1_validate_option(&val, &opt);
+ adapter->hw.flash_vendor = (u8) val;
+ } else
+ adapter->hw.flash_vendor = (u8) (opt.def);
+ }
+}
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index 303a8d94ad4..5ff7882297d 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -721,7 +721,7 @@ static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
struct ring_info *src_map, *dest_map;
struct rx_header *rh;
int dest_idx;
- u32 ctrl;
+ __le32 ctrl;
dest_idx = dest_idx_unmasked & (B44_RX_RING_SIZE - 1);
dest_desc = &bp->rx_ring[dest_idx];
@@ -783,7 +783,7 @@ static int b44_rx(struct b44 *bp, int budget)
RX_PKT_BUF_SZ,
PCI_DMA_FROMDEVICE);
rh = (struct rx_header *) skb->data;
- len = cpu_to_le16(rh->len);
+ len = le16_to_cpu(rh->len);
if ((len > (RX_PKT_BUF_SZ - bp->rx_offset)) ||
(rh->flags & cpu_to_le16(RX_FLAG_ERRORS))) {
drop_it:
@@ -799,7 +799,7 @@ static int b44_rx(struct b44 *bp, int budget)
do {
udelay(2);
barrier();
- len = cpu_to_le16(rh->len);
+ len = le16_to_cpu(rh->len);
} while (len == 0 && i++ < 5);
if (len == 0)
goto drop_it;
@@ -2061,7 +2061,7 @@ out:
static int b44_read_eeprom(struct b44 *bp, u8 *data)
{
long i;
- u16 *ptr = (u16 *) data;
+ __le16 *ptr = (__le16 *) data;
for (i = 0; i < 128; i += 2)
ptr[i / 2] = cpu_to_le16(readw(bp->regs + 4096 + i));
diff --git a/drivers/net/b44.h b/drivers/net/b44.h
index 4944507fad2..18fc1333662 100644
--- a/drivers/net/b44.h
+++ b/drivers/net/b44.h
@@ -308,8 +308,8 @@
#define MII_TLEDCTRL_ENABLE 0x0040
struct dma_desc {
- u32 ctrl;
- u32 addr;
+ __le32 ctrl;
+ __le32 addr;
};
/* There are only 12 bits in the DMA engine for descriptor offsetting
@@ -327,9 +327,9 @@ struct dma_desc {
#define RX_COPY_THRESHOLD 256
struct rx_header {
- u16 len;
- u16 flags;
- u16 pad[12];
+ __le16 len;
+ __le16 flags;
+ __le16 pad[12];
};
#define RX_HEADER_LEN 28
diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c
index 4528ce9c4e4..c143304dcff 100644
--- a/drivers/net/bmac.c
+++ b/drivers/net/bmac.c
@@ -18,6 +18,7 @@
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/crc32.h>
+#include <linux/bitrev.h>
#include <asm/prom.h>
#include <asm/dbdma.h>
#include <asm/io.h>
@@ -140,7 +141,6 @@ static unsigned char *bmac_emergency_rxbuf;
+ (N_RX_RING + N_TX_RING + 4) * sizeof(struct dbdma_cmd) \
+ sizeof(struct sk_buff_head))
-static unsigned char bitrev(unsigned char b);
static int bmac_open(struct net_device *dev);
static int bmac_close(struct net_device *dev);
static int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev);
@@ -586,18 +586,6 @@ bmac_construct_rxbuff(struct sk_buff *skb, volatile struct dbdma_cmd *cp)
virt_to_bus(addr), 0);
}
-/* Bit-reverse one byte of an ethernet hardware address. */
-static unsigned char
-bitrev(unsigned char b)
-{
- int d = 0, i;
-
- for (i = 0; i < 8; ++i, b >>= 1)
- d = (d << 1) | (b & 1);
- return d;
-}
-
-
static void
bmac_init_tx_ring(struct bmac_data *bp)
{
@@ -1224,8 +1212,8 @@ bmac_get_station_address(struct net_device *dev, unsigned char *ea)
{
reset_and_select_srom(dev);
data = read_srom(dev, i + EnetAddressOffset/2, SROMAddressBits);
- ea[2*i] = bitrev(data & 0x0ff);
- ea[2*i+1] = bitrev((data >> 8) & 0x0ff);
+ ea[2*i] = bitrev8(data & 0x0ff);
+ ea[2*i+1] = bitrev8((data >> 8) & 0x0ff);
}
}
@@ -1315,7 +1303,7 @@ static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_i
rev = addr[0] == 0 && addr[1] == 0xA0;
for (j = 0; j < 6; ++j)
- dev->dev_addr[j] = rev? bitrev(addr[j]): addr[j];
+ dev->dev_addr[j] = rev ? bitrev8(addr[j]): addr[j];
/* Enable chip without interrupts for now */
bmac_enable_and_reset_chip(dev);
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index ee7b75b976b..5a96d7611af 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -39,12 +39,9 @@
#include <linux/if_vlan.h>
#define BCM_VLAN 1
#endif
-#ifdef NETIF_F_TSO
#include <net/ip.h>
#include <net/tcp.h>
#include <net/checksum.h>
-#define BCM_TSO 1
-#endif
#include <linux/workqueue.h>
#include <linux/crc32.h>
#include <linux/prefetch.h>
@@ -1728,7 +1725,7 @@ bnx2_tx_int(struct bnx2 *bp)
tx_buf = &bp->tx_buf_ring[sw_ring_cons];
skb = tx_buf->skb;
-#ifdef BCM_TSO
+
/* partial BD completions possible with TSO packets */
if (skb_is_gso(skb)) {
u16 last_idx, last_ring_idx;
@@ -1744,7 +1741,7 @@ bnx2_tx_int(struct bnx2 *bp)
break;
}
}
-#endif
+
pci_unmap_single(bp->pdev, pci_unmap_addr(tx_buf, mapping),
skb_headlen(skb), PCI_DMA_TODEVICE);
@@ -4514,7 +4511,6 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
vlan_tag_flags |=
(TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16));
}
-#ifdef BCM_TSO
if ((mss = skb_shinfo(skb)->gso_size) &&
(skb->len > (bp->dev->mtu + ETH_HLEN))) {
u32 tcp_opt_len, ip_tcp_len;
@@ -4547,7 +4543,6 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
}
else
-#endif
{
mss = 0;
}
@@ -5544,10 +5539,8 @@ static const struct ethtool_ops bnx2_ethtool_ops = {
.set_tx_csum = ethtool_op_set_tx_csum,
.get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
-#ifdef BCM_TSO
.get_tso = ethtool_op_get_tso,
.set_tso = bnx2_set_tso,
-#endif
.self_test_count = bnx2_self_test_count,
.self_test = bnx2_self_test,
.get_strings = bnx2_get_strings,
@@ -5954,8 +5947,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
* responding after a while.
*
* AMD believes this incompatibility is unique to the 5706, and
- * prefers to locally disable MSI rather than globally disabling it
- * using pci_msi_quirk.
+ * prefers to locally disable MSI rather than globally disabling it.
*/
if (CHIP_NUM(bp) == CHIP_NUM_5706 && disable_msi == 0) {
struct pci_dev *amd_8132 = NULL;
@@ -6104,9 +6096,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
#ifdef BCM_VLAN
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
#endif
-#ifdef BCM_TSO
dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
-#endif
netif_carrier_off(bp->dev);
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 32923162179..217a2eedee0 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -184,7 +184,7 @@ static int tlb_initialize(struct bonding *bond)
spin_lock_init(&(bond_info->tx_hashtbl_lock));
- new_hashtbl = kmalloc(size, GFP_KERNEL);
+ new_hashtbl = kzalloc(size, GFP_KERNEL);
if (!new_hashtbl) {
printk(KERN_ERR DRV_NAME
": %s: Error: Failed to allocate TLB hash table\n",
@@ -195,8 +195,6 @@ static int tlb_initialize(struct bonding *bond)
bond_info->tx_hashtbl = new_hashtbl;
- memset(bond_info->tx_hashtbl, 0, size);
-
for (i = 0; i < TLB_HASH_TABLE_SIZE; i++) {
tlb_init_table_entry(&bond_info->tx_hashtbl[i], 1);
}
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 6482aed4bb7..8ce8fec615b 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1343,14 +1343,12 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
"inaccurate.\n", bond_dev->name, slave_dev->name);
}
- new_slave = kmalloc(sizeof(struct slave), GFP_KERNEL);
+ new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL);
if (!new_slave) {
res = -ENOMEM;
goto err_undo_flags;
}
- memset(new_slave, 0, sizeof(struct slave));
-
/* save slave's original flags before calling
* netdev_set_master and dev_open
*/
@@ -4704,6 +4702,7 @@ static int bond_check_params(struct bond_params *params)
static struct lock_class_key bonding_netdev_xmit_lock_key;
/* Create a new bond based on the specified name and bonding parameters.
+ * If name is NULL, obtain a suitable "bond%d" name for us.
* Caller must NOT hold rtnl_lock; we need to release it here before we
* set up our sysfs entries.
*/
@@ -4713,7 +4712,8 @@ int bond_create(char *name, struct bond_params *params, struct bonding **newbond
int res;
rtnl_lock();
- bond_dev = alloc_netdev(sizeof(struct bonding), name, ether_setup);
+ bond_dev = alloc_netdev(sizeof(struct bonding), name ? name : "",
+ ether_setup);
if (!bond_dev) {
printk(KERN_ERR DRV_NAME
": %s: eek! can't alloc netdev!\n",
@@ -4722,6 +4722,12 @@ int bond_create(char *name, struct bond_params *params, struct bonding **newbond
goto out_rtnl;
}
+ if (!name) {
+ res = dev_alloc_name(bond_dev, "bond%d");
+ if (res < 0)
+ goto out_netdev;
+ }
+
/* bond_init() must be called after dev_alloc_name() (for the
* /proc files), but before register_netdevice(), because we
* need to set function pointers.
@@ -4748,14 +4754,19 @@ int bond_create(char *name, struct bond_params *params, struct bonding **newbond
rtnl_unlock(); /* allows sysfs registration of net device */
res = bond_create_sysfs_entry(bond_dev->priv);
- goto done;
+ if (res < 0) {
+ rtnl_lock();
+ goto out_bond;
+ }
+
+ return 0;
+
out_bond:
bond_deinit(bond_dev);
out_netdev:
free_netdev(bond_dev);
out_rtnl:
rtnl_unlock();
-done:
return res;
}
@@ -4763,7 +4774,6 @@ static int __init bonding_init(void)
{
int i;
int res;
- char new_bond_name[8]; /* Enough room for 999 bonds at init. */
printk(KERN_INFO "%s", version);
@@ -4776,8 +4786,7 @@ static int __init bonding_init(void)
bond_create_proc_dir();
#endif
for (i = 0; i < max_bonds; i++) {
- sprintf(new_bond_name, "bond%d",i);
- res = bond_create(new_bond_name,&bonding_defaults, NULL);
+ res = bond_create(NULL, &bonding_defaults, NULL);
if (res)
goto err;
}
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index ced9ed8f995..878f7aabeea 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -39,8 +39,7 @@
/* #define BONDING_DEBUG 1 */
#include "bonding.h"
-#define to_class_dev(obj) container_of(obj,struct class_device,kobj)
-#define to_net_dev(class) container_of(class, struct net_device, class_dev)
+#define to_dev(obj) container_of(obj,struct device,kobj)
#define to_bond(cd) ((struct bonding *)(to_net_dev(cd)->priv))
/*---------------------------- Declarations -------------------------------*/
@@ -154,7 +153,7 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t
* If it's > expected, then there's a file open,
* and we have to fail.
*/
- if (atomic_read(&bond->dev->class_dev.kobj.kref.refcount)
+ if (atomic_read(&bond->dev->dev.kobj.kref.refcount)
> expected_refcount){
rtnl_unlock();
printk(KERN_INFO DRV_NAME
@@ -201,13 +200,13 @@ int bond_create_slave_symlinks(struct net_device *master, struct net_device *sla
int ret = 0;
/* first, create a link from the slave back to the master */
- ret = sysfs_create_link(&(slave->class_dev.kobj), &(master->class_dev.kobj),
+ ret = sysfs_create_link(&(slave->dev.kobj), &(master->dev.kobj),
"master");
if (ret)
return ret;
/* next, create a link from the master to the slave */
sprintf(linkname,"slave_%s",slave->name);
- ret = sysfs_create_link(&(master->class_dev.kobj), &(slave->class_dev.kobj),
+ ret = sysfs_create_link(&(master->dev.kobj), &(slave->dev.kobj),
linkname);
return ret;
@@ -217,20 +216,21 @@ void bond_destroy_slave_symlinks(struct net_device *master, struct net_device *s
{
char linkname[IFNAMSIZ+7];
- sysfs_remove_link(&(slave->class_dev.kobj), "master");
+ sysfs_remove_link(&(slave->dev.kobj), "master");
sprintf(linkname,"slave_%s",slave->name);
- sysfs_remove_link(&(master->class_dev.kobj), linkname);
+ sysfs_remove_link(&(master->dev.kobj), linkname);
}
/*
* Show the slaves in the current bond.
*/
-static ssize_t bonding_show_slaves(struct class_device *cd, char *buf)
+static ssize_t bonding_show_slaves(struct device *d,
+ struct device_attribute *attr, char *buf)
{
struct slave *slave;
int i, res = 0;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
read_lock_bh(&bond->lock);
bond_for_each_slave(bond, slave, i) {
@@ -254,14 +254,16 @@ static ssize_t bonding_show_slaves(struct class_device *cd, char *buf)
* up for this to succeed.
* This function is largely the same flow as bonding_update_bonds().
*/
-static ssize_t bonding_store_slaves(struct class_device *cd, const char *buffer, size_t count)
+static ssize_t bonding_store_slaves(struct device *d,
+ struct device_attribute *attr,
+ const char *buffer, size_t count)
{
char command[IFNAMSIZ + 1] = { 0, };
char *ifname;
int i, res, found, ret = count;
struct slave *slave;
struct net_device *dev = NULL;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
/* Quick sanity check -- is the bond interface up? */
if (!(bond->dev->flags & IFF_UP)) {
@@ -387,25 +389,28 @@ out:
return ret;
}
-static CLASS_DEVICE_ATTR(slaves, S_IRUGO | S_IWUSR, bonding_show_slaves, bonding_store_slaves);
+static DEVICE_ATTR(slaves, S_IRUGO | S_IWUSR, bonding_show_slaves, bonding_store_slaves);
/*
* Show and set the bonding mode. The bond interface must be down to
* change the mode.
*/
-static ssize_t bonding_show_mode(struct class_device *cd, char *buf)
+static ssize_t bonding_show_mode(struct device *d,
+ struct device_attribute *attr, char *buf)
{
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
return sprintf(buf, "%s %d\n",
bond_mode_tbl[bond->params.mode].modename,
bond->params.mode) + 1;
}
-static ssize_t bonding_store_mode(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_mode(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int new_value, ret = count;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (bond->dev->flags & IFF_UP) {
printk(KERN_ERR DRV_NAME
@@ -438,16 +443,18 @@ static ssize_t bonding_store_mode(struct class_device *cd, const char *buf, size
out:
return ret;
}
-static CLASS_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, bonding_show_mode, bonding_store_mode);
+static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, bonding_show_mode, bonding_store_mode);
/*
* Show and set the bonding transmit hash method. The bond interface must be down to
* change the xmit hash policy.
*/
-static ssize_t bonding_show_xmit_hash(struct class_device *cd, char *buf)
+static ssize_t bonding_show_xmit_hash(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
int count;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if ((bond->params.mode != BOND_MODE_XOR) &&
(bond->params.mode != BOND_MODE_8023AD)) {
@@ -462,10 +469,12 @@ static ssize_t bonding_show_xmit_hash(struct class_device *cd, char *buf)
return count;
}
-static ssize_t bonding_store_xmit_hash(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_xmit_hash(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int new_value, ret = count;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (bond->dev->flags & IFF_UP) {
printk(KERN_ERR DRV_NAME
@@ -501,24 +510,28 @@ static ssize_t bonding_store_xmit_hash(struct class_device *cd, const char *buf,
out:
return ret;
}
-static CLASS_DEVICE_ATTR(xmit_hash_policy, S_IRUGO | S_IWUSR, bonding_show_xmit_hash, bonding_store_xmit_hash);
+static DEVICE_ATTR(xmit_hash_policy, S_IRUGO | S_IWUSR, bonding_show_xmit_hash, bonding_store_xmit_hash);
/*
* Show and set arp_validate.
*/
-static ssize_t bonding_show_arp_validate(struct class_device *cd, char *buf)
+static ssize_t bonding_show_arp_validate(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
return sprintf(buf, "%s %d\n",
arp_validate_tbl[bond->params.arp_validate].modename,
bond->params.arp_validate) + 1;
}
-static ssize_t bonding_store_arp_validate(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_arp_validate(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int new_value;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
new_value = bond_parse_parm((char *)buf, arp_validate_tbl);
if (new_value < 0) {
@@ -548,7 +561,7 @@ static ssize_t bonding_store_arp_validate(struct class_device *cd, const char *b
return count;
}
-static CLASS_DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate, bonding_store_arp_validate);
+static DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate, bonding_store_arp_validate);
/*
* Show and set the arp timer interval. There are two tricky bits
@@ -556,17 +569,21 @@ static CLASS_DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_valid
* MII monitoring. Second, if the ARP timer isn't running, we must
* start it.
*/
-static ssize_t bonding_show_arp_interval(struct class_device *cd, char *buf)
+static ssize_t bonding_show_arp_interval(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
return sprintf(buf, "%d\n", bond->params.arp_interval) + 1;
}
-static ssize_t bonding_store_arp_interval(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_arp_interval(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int new_value, ret = count;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (sscanf(buf, "%d", &new_value) != 1) {
printk(KERN_ERR DRV_NAME
@@ -638,15 +655,17 @@ static ssize_t bonding_store_arp_interval(struct class_device *cd, const char *b
out:
return ret;
}
-static CLASS_DEVICE_ATTR(arp_interval, S_IRUGO | S_IWUSR , bonding_show_arp_interval, bonding_store_arp_interval);
+static DEVICE_ATTR(arp_interval, S_IRUGO | S_IWUSR , bonding_show_arp_interval, bonding_store_arp_interval);
/*
* Show and set the arp targets.
*/
-static ssize_t bonding_show_arp_targets(struct class_device *cd, char *buf)
+static ssize_t bonding_show_arp_targets(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
int i, res = 0;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) {
if (bond->params.arp_targets[i])
@@ -660,11 +679,13 @@ static ssize_t bonding_show_arp_targets(struct class_device *cd, char *buf)
return res;
}
-static ssize_t bonding_store_arp_targets(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_arp_targets(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
u32 newtarget;
int i = 0, done = 0, ret = count;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
u32 *targets;
targets = bond->params.arp_targets;
@@ -742,24 +763,28 @@ static ssize_t bonding_store_arp_targets(struct class_device *cd, const char *bu
out:
return ret;
}
-static CLASS_DEVICE_ATTR(arp_ip_target, S_IRUGO | S_IWUSR , bonding_show_arp_targets, bonding_store_arp_targets);
+static DEVICE_ATTR(arp_ip_target, S_IRUGO | S_IWUSR , bonding_show_arp_targets, bonding_store_arp_targets);
/*
* Show and set the up and down delays. These must be multiples of the
* MII monitoring value, and are stored internally as the multiplier.
* Thus, we must translate to MS for the real world.
*/
-static ssize_t bonding_show_downdelay(struct class_device *cd, char *buf)
+static ssize_t bonding_show_downdelay(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
return sprintf(buf, "%d\n", bond->params.downdelay * bond->params.miimon) + 1;
}
-static ssize_t bonding_store_downdelay(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_downdelay(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int new_value, ret = count;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (!(bond->params.miimon)) {
printk(KERN_ERR DRV_NAME
@@ -800,20 +825,24 @@ static ssize_t bonding_store_downdelay(struct class_device *cd, const char *buf,
out:
return ret;
}
-static CLASS_DEVICE_ATTR(downdelay, S_IRUGO | S_IWUSR , bonding_show_downdelay, bonding_store_downdelay);
+static DEVICE_ATTR(downdelay, S_IRUGO | S_IWUSR , bonding_show_downdelay, bonding_store_downdelay);
-static ssize_t bonding_show_updelay(struct class_device *cd, char *buf)
+static ssize_t bonding_show_updelay(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
return sprintf(buf, "%d\n", bond->params.updelay * bond->params.miimon) + 1;
}
-static ssize_t bonding_store_updelay(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_updelay(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int new_value, ret = count;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (!(bond->params.miimon)) {
printk(KERN_ERR DRV_NAME
@@ -854,25 +883,29 @@ static ssize_t bonding_store_updelay(struct class_device *cd, const char *buf, s
out:
return ret;
}
-static CLASS_DEVICE_ATTR(updelay, S_IRUGO | S_IWUSR , bonding_show_updelay, bonding_store_updelay);
+static DEVICE_ATTR(updelay, S_IRUGO | S_IWUSR , bonding_show_updelay, bonding_store_updelay);
/*
* Show and set the LACP interval. Interface must be down, and the mode
* must be set to 802.3ad mode.
*/
-static ssize_t bonding_show_lacp(struct class_device *cd, char *buf)
+static ssize_t bonding_show_lacp(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
return sprintf(buf, "%s %d\n",
bond_lacp_tbl[bond->params.lacp_fast].modename,
bond->params.lacp_fast) + 1;
}
-static ssize_t bonding_store_lacp(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_lacp(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int new_value, ret = count;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (bond->dev->flags & IFF_UP) {
printk(KERN_ERR DRV_NAME
@@ -906,7 +939,7 @@ static ssize_t bonding_store_lacp(struct class_device *cd, const char *buf, size
out:
return ret;
}
-static CLASS_DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, bonding_show_lacp, bonding_store_lacp);
+static DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, bonding_show_lacp, bonding_store_lacp);
/*
* Show and set the MII monitor interval. There are two tricky bits
@@ -914,17 +947,21 @@ static CLASS_DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, bonding_show_lacp, bondin
* ARP monitoring. Second, if the timer isn't running, we must
* start it.
*/
-static ssize_t bonding_show_miimon(struct class_device *cd, char *buf)
+static ssize_t bonding_show_miimon(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
return sprintf(buf, "%d\n", bond->params.miimon) + 1;
}
-static ssize_t bonding_store_miimon(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_miimon(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int new_value, ret = count;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (sscanf(buf, "%d", &new_value) != 1) {
printk(KERN_ERR DRV_NAME
@@ -1000,7 +1037,7 @@ static ssize_t bonding_store_miimon(struct class_device *cd, const char *buf, si
out:
return ret;
}
-static CLASS_DEVICE_ATTR(miimon, S_IRUGO | S_IWUSR, bonding_show_miimon, bonding_store_miimon);
+static DEVICE_ATTR(miimon, S_IRUGO | S_IWUSR, bonding_show_miimon, bonding_store_miimon);
/*
* Show and set the primary slave. The store function is much
@@ -1009,10 +1046,12 @@ static CLASS_DEVICE_ATTR(miimon, S_IRUGO | S_IWUSR, bonding_show_miimon, bonding
* The bond must be a mode that supports a primary for this be
* set.
*/
-static ssize_t bonding_show_primary(struct class_device *cd, char *buf)
+static ssize_t bonding_show_primary(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
int count = 0;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (bond->primary_slave)
count = sprintf(buf, "%s\n", bond->primary_slave->dev->name) + 1;
@@ -1022,11 +1061,13 @@ static ssize_t bonding_show_primary(struct class_device *cd, char *buf)
return count;
}
-static ssize_t bonding_store_primary(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_primary(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int i;
struct slave *slave;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
write_lock_bh(&bond->lock);
if (!USES_PRIMARY(bond->params.mode)) {
@@ -1065,22 +1106,26 @@ out:
write_unlock_bh(&bond->lock);
return count;
}
-static CLASS_DEVICE_ATTR(primary, S_IRUGO | S_IWUSR, bonding_show_primary, bonding_store_primary);
+static DEVICE_ATTR(primary, S_IRUGO | S_IWUSR, bonding_show_primary, bonding_store_primary);
/*
* Show and set the use_carrier flag.
*/
-static ssize_t bonding_show_carrier(struct class_device *cd, char *buf)
+static ssize_t bonding_show_carrier(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
return sprintf(buf, "%d\n", bond->params.use_carrier) + 1;
}
-static ssize_t bonding_store_carrier(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_carrier(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int new_value, ret = count;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (sscanf(buf, "%d", &new_value) != 1) {
@@ -1102,16 +1147,18 @@ static ssize_t bonding_store_carrier(struct class_device *cd, const char *buf, s
out:
return count;
}
-static CLASS_DEVICE_ATTR(use_carrier, S_IRUGO | S_IWUSR, bonding_show_carrier, bonding_store_carrier);
+static DEVICE_ATTR(use_carrier, S_IRUGO | S_IWUSR, bonding_show_carrier, bonding_store_carrier);
/*
* Show and set currently active_slave.
*/
-static ssize_t bonding_show_active_slave(struct class_device *cd, char *buf)
+static ssize_t bonding_show_active_slave(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
struct slave *curr;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
int count;
@@ -1126,13 +1173,15 @@ static ssize_t bonding_show_active_slave(struct class_device *cd, char *buf)
return count;
}
-static ssize_t bonding_store_active_slave(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_active_slave(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int i;
struct slave *slave;
struct slave *old_active = NULL;
struct slave *new_active = NULL;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
write_lock_bh(&bond->lock);
if (!USES_PRIMARY(bond->params.mode)) {
@@ -1194,16 +1243,18 @@ out:
return count;
}
-static CLASS_DEVICE_ATTR(active_slave, S_IRUGO | S_IWUSR, bonding_show_active_slave, bonding_store_active_slave);
+static DEVICE_ATTR(active_slave, S_IRUGO | S_IWUSR, bonding_show_active_slave, bonding_store_active_slave);
/*
* Show link status of the bond interface.
*/
-static ssize_t bonding_show_mii_status(struct class_device *cd, char *buf)
+static ssize_t bonding_show_mii_status(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
struct slave *curr;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
read_lock(&bond->curr_slave_lock);
curr = bond->curr_active_slave;
@@ -1211,16 +1262,18 @@ static ssize_t bonding_show_mii_status(struct class_device *cd, char *buf)
return sprintf(buf, "%s\n", (curr) ? "up" : "down") + 1;
}
-static CLASS_DEVICE_ATTR(mii_status, S_IRUGO, bonding_show_mii_status, NULL);
+static DEVICE_ATTR(mii_status, S_IRUGO, bonding_show_mii_status, NULL);
/*
* Show current 802.3ad aggregator ID.
*/
-static ssize_t bonding_show_ad_aggregator(struct class_device *cd, char *buf)
+static ssize_t bonding_show_ad_aggregator(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
int count = 0;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (bond->params.mode == BOND_MODE_8023AD) {
struct ad_info ad_info;
@@ -1231,16 +1284,18 @@ static ssize_t bonding_show_ad_aggregator(struct class_device *cd, char *buf)
return count;
}
-static CLASS_DEVICE_ATTR(ad_aggregator, S_IRUGO, bonding_show_ad_aggregator, NULL);
+static DEVICE_ATTR(ad_aggregator, S_IRUGO, bonding_show_ad_aggregator, NULL);
/*
* Show number of active 802.3ad ports.
*/
-static ssize_t bonding_show_ad_num_ports(struct class_device *cd, char *buf)
+static ssize_t bonding_show_ad_num_ports(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
int count = 0;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (bond->params.mode == BOND_MODE_8023AD) {
struct ad_info ad_info;
@@ -1251,16 +1306,18 @@ static ssize_t bonding_show_ad_num_ports(struct class_device *cd, char *buf)
return count;
}
-static CLASS_DEVICE_ATTR(ad_num_ports, S_IRUGO, bonding_show_ad_num_ports, NULL);
+static DEVICE_ATTR(ad_num_ports, S_IRUGO, bonding_show_ad_num_ports, NULL);
/*
* Show current 802.3ad actor key.
*/
-static ssize_t bonding_show_ad_actor_key(struct class_device *cd, char *buf)
+static ssize_t bonding_show_ad_actor_key(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
int count = 0;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (bond->params.mode == BOND_MODE_8023AD) {
struct ad_info ad_info;
@@ -1271,16 +1328,18 @@ static ssize_t bonding_show_ad_actor_key(struct class_device *cd, char *buf)
return count;
}
-static CLASS_DEVICE_ATTR(ad_actor_key, S_IRUGO, bonding_show_ad_actor_key, NULL);
+static DEVICE_ATTR(ad_actor_key, S_IRUGO, bonding_show_ad_actor_key, NULL);
/*
* Show current 802.3ad partner key.
*/
-static ssize_t bonding_show_ad_partner_key(struct class_device *cd, char *buf)
+static ssize_t bonding_show_ad_partner_key(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
int count = 0;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (bond->params.mode == BOND_MODE_8023AD) {
struct ad_info ad_info;
@@ -1291,16 +1350,18 @@ static ssize_t bonding_show_ad_partner_key(struct class_device *cd, char *buf)
return count;
}
-static CLASS_DEVICE_ATTR(ad_partner_key, S_IRUGO, bonding_show_ad_partner_key, NULL);
+static DEVICE_ATTR(ad_partner_key, S_IRUGO, bonding_show_ad_partner_key, NULL);
/*
* Show current 802.3ad partner mac.
*/
-static ssize_t bonding_show_ad_partner_mac(struct class_device *cd, char *buf)
+static ssize_t bonding_show_ad_partner_mac(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
int count = 0;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (bond->params.mode == BOND_MODE_8023AD) {
struct ad_info ad_info;
@@ -1319,30 +1380,30 @@ static ssize_t bonding_show_ad_partner_mac(struct class_device *cd, char *buf)
return count;
}
-static CLASS_DEVICE_ATTR(ad_partner_mac, S_IRUGO, bonding_show_ad_partner_mac, NULL);
+static DEVICE_ATTR(ad_partner_mac, S_IRUGO, bonding_show_ad_partner_mac, NULL);
static struct attribute *per_bond_attrs[] = {
- &class_device_attr_slaves.attr,
- &class_device_attr_mode.attr,
- &class_device_attr_arp_validate.attr,
- &class_device_attr_arp_interval.attr,
- &class_device_attr_arp_ip_target.attr,
- &class_device_attr_downdelay.attr,
- &class_device_attr_updelay.attr,
- &class_device_attr_lacp_rate.attr,
- &class_device_attr_xmit_hash_policy.attr,
- &class_device_attr_miimon.attr,
- &class_device_attr_primary.attr,
- &class_device_attr_use_carrier.attr,
- &class_device_attr_active_slave.attr,
- &class_device_attr_mii_status.attr,
- &class_device_attr_ad_aggregator.attr,
- &class_device_attr_ad_num_ports.attr,
- &class_device_attr_ad_actor_key.attr,
- &class_device_attr_ad_partner_key.attr,
- &class_device_attr_ad_partner_mac.attr,
+ &dev_attr_slaves.attr,
+ &dev_attr_mode.attr,
+ &dev_attr_arp_validate.attr,
+ &dev_attr_arp_interval.attr,
+ &dev_attr_arp_ip_target.attr,
+ &dev_attr_downdelay.attr,
+ &dev_attr_updelay.attr,
+ &dev_attr_lacp_rate.attr,
+ &dev_attr_xmit_hash_policy.attr,
+ &dev_attr_miimon.attr,
+ &dev_attr_primary.attr,
+ &dev_attr_use_carrier.attr,
+ &dev_attr_active_slave.attr,
+ &dev_attr_mii_status.attr,
+ &dev_attr_ad_aggregator.attr,
+ &dev_attr_ad_num_ports.attr,
+ &dev_attr_ad_actor_key.attr,
+ &dev_attr_ad_partner_key.attr,
+ &dev_attr_ad_partner_mac.attr,
NULL,
};
@@ -1367,11 +1428,26 @@ int bond_create_sysfs(void)
if (!firstbond)
return -ENODEV;
- netdev_class = firstbond->dev->class_dev.class;
+ netdev_class = firstbond->dev->dev.class;
if (!netdev_class)
return -ENODEV;
ret = class_create_file(netdev_class, &class_attr_bonding_masters);
+ /*
+ * Permit multiple loads of the module by ignoring failures to
+ * create the bonding_masters sysfs file. Bonding devices
+ * created by second or subsequent loads of the module will
+ * not be listed in, or controllable by, bonding_masters, but
+ * will have the usual "bonding" sysfs directory.
+ *
+ * This is done to preserve backwards compatibility for
+ * initscripts/sysconfig, which load bonding multiple times to
+ * configure multiple bonding devices.
+ */
+ if (ret == -EEXIST) {
+ netdev_class = NULL;
+ return 0;
+ }
return ret;
@@ -1395,13 +1471,13 @@ int bond_create_sysfs_entry(struct bonding *bond)
struct net_device *dev = bond->dev;
int err;
- err = sysfs_create_group(&(dev->class_dev.kobj), &bonding_group);
+ err = sysfs_create_group(&(dev->dev.kobj), &bonding_group);
if (err) {
printk(KERN_EMERG "eek! didn't create group!\n");
}
if (expected_refcount < 1)
- expected_refcount = atomic_read(&bond->dev->class_dev.kobj.kref.refcount);
+ expected_refcount = atomic_read(&bond->dev->dev.kobj.kref.refcount);
return err;
}
@@ -1412,6 +1488,6 @@ void bond_destroy_sysfs_entry(struct bonding *bond)
{
struct net_device *dev = bond->dev;
- sysfs_remove_group(&(dev->class_dev.kobj), &bonding_group);
+ sysfs_remove_group(&(dev->dev.kobj), &bonding_group);
}
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 0978c9ac6d2..41aa78bf1f7 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -22,8 +22,8 @@
#include "bond_3ad.h"
#include "bond_alb.h"
-#define DRV_VERSION "3.1.1"
-#define DRV_RELDATE "September 26, 2006"
+#define DRV_VERSION "3.1.2"
+#define DRV_RELDATE "January 20, 2007"
#define DRV_NAME "bonding"
#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver"
@@ -237,12 +237,13 @@ static inline struct bonding *bond_get_bond_by_slave(struct slave *slave)
#define BOND_ARP_VALIDATE_ALL (BOND_ARP_VALIDATE_ACTIVE | \
BOND_ARP_VALIDATE_BACKUP)
-extern inline int slave_do_arp_validate(struct bonding *bond, struct slave *slave)
+static inline int slave_do_arp_validate(struct bonding *bond,
+ struct slave *slave)
{
return bond->params.arp_validate & (1 << slave->state);
}
-extern inline unsigned long slave_last_rx(struct bonding *bond,
+static inline unsigned long slave_last_rx(struct bonding *bond,
struct slave *slave)
{
if (slave_do_arp_validate(bond, slave))
diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h
index 74758d2c7af..787f2f2820f 100644
--- a/drivers/net/chelsio/common.h
+++ b/drivers/net/chelsio/common.h
@@ -324,7 +324,7 @@ struct board_info {
unsigned char mdio_phybaseaddr;
struct gmac *gmac;
struct gphy *gphy;
- struct mdio_ops *mdio_ops;
+ struct mdio_ops *mdio_ops;
const char *desc;
};
diff --git a/drivers/net/chelsio/cpl5_cmd.h b/drivers/net/chelsio/cpl5_cmd.h
index 35f565be4fd..e36d45b78cc 100644
--- a/drivers/net/chelsio/cpl5_cmd.h
+++ b/drivers/net/chelsio/cpl5_cmd.h
@@ -103,7 +103,7 @@ enum CPL_opcode {
CPL_MIGRATE_C2T_RPL = 0xDD,
CPL_ERROR = 0xD7,
- /* internal: driver -> TOM */
+ /* internal: driver -> TOM */
CPL_MSS_CHANGE = 0xE1
};
@@ -159,8 +159,8 @@ enum { // TX_PKT_LSO ethernet types
};
union opcode_tid {
- u32 opcode_tid;
- u8 opcode;
+ u32 opcode_tid;
+ u8 opcode;
};
#define S_OPCODE 24
@@ -234,7 +234,7 @@ struct cpl_pass_accept_req {
u32 local_ip;
u32 peer_ip;
u32 tos_tid;
- struct tcp_options tcp_options;
+ struct tcp_options tcp_options;
u8 dst_mac[6];
u16 vlan_tag;
u8 src_mac[6];
@@ -250,12 +250,12 @@ struct cpl_pass_accept_rpl {
u32 peer_ip;
u32 opt0h;
union {
- u32 opt0l;
- struct {
- u8 rsvd[3];
- u8 status;
+ u32 opt0l;
+ struct {
+ u8 rsvd[3];
+ u8 status;
+ };
};
- };
};
struct cpl_act_open_req {
diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c
index fd5d821f3f2..7d0f24f6977 100644
--- a/drivers/net/chelsio/cxgb2.c
+++ b/drivers/net/chelsio/cxgb2.c
@@ -69,14 +69,14 @@ static inline void cancel_mac_stats_update(struct adapter *ap)
cancel_delayed_work(&ap->stats_update_task);
}
-#define MAX_CMDQ_ENTRIES 16384
-#define MAX_CMDQ1_ENTRIES 1024
-#define MAX_RX_BUFFERS 16384
-#define MAX_RX_JUMBO_BUFFERS 16384
+#define MAX_CMDQ_ENTRIES 16384
+#define MAX_CMDQ1_ENTRIES 1024
+#define MAX_RX_BUFFERS 16384
+#define MAX_RX_JUMBO_BUFFERS 16384
#define MAX_TX_BUFFERS_HIGH 16384U
#define MAX_TX_BUFFERS_LOW 1536U
#define MAX_TX_BUFFERS 1460U
-#define MIN_FL_ENTRIES 32
+#define MIN_FL_ENTRIES 32
#define DFLT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | \
NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP |\
@@ -143,7 +143,7 @@ static void link_report(struct port_info *p)
case SPEED_100: s = "100Mbps"; break;
}
- printk(KERN_INFO "%s: link up, %s, %s-duplex\n",
+ printk(KERN_INFO "%s: link up, %s, %s-duplex\n",
p->dev->name, s,
p->link_config.duplex == DUPLEX_FULL ? "full" : "half");
}
@@ -233,7 +233,7 @@ static int cxgb_up(struct adapter *adapter)
t1_sge_start(adapter->sge);
t1_interrupts_enable(adapter);
- out_err:
+out_err:
return err;
}
@@ -454,51 +454,21 @@ static void get_stats(struct net_device *dev, struct ethtool_stats *stats,
const struct cmac_statistics *s;
const struct sge_intr_counts *t;
struct sge_port_stats ss;
+ unsigned int len;
s = mac->ops->statistics_update(mac, MAC_STATS_UPDATE_FULL);
- *data++ = s->TxOctetsOK;
- *data++ = s->TxOctetsBad;
- *data++ = s->TxUnicastFramesOK;
- *data++ = s->TxMulticastFramesOK;
- *data++ = s->TxBroadcastFramesOK;
- *data++ = s->TxPauseFrames;
- *data++ = s->TxFramesWithDeferredXmissions;
- *data++ = s->TxLateCollisions;
- *data++ = s->TxTotalCollisions;
- *data++ = s->TxFramesAbortedDueToXSCollisions;
- *data++ = s->TxUnderrun;
- *data++ = s->TxLengthErrors;
- *data++ = s->TxInternalMACXmitError;
- *data++ = s->TxFramesWithExcessiveDeferral;
- *data++ = s->TxFCSErrors;
-
- *data++ = s->RxOctetsOK;
- *data++ = s->RxOctetsBad;
- *data++ = s->RxUnicastFramesOK;
- *data++ = s->RxMulticastFramesOK;
- *data++ = s->RxBroadcastFramesOK;
- *data++ = s->RxPauseFrames;
- *data++ = s->RxFCSErrors;
- *data++ = s->RxAlignErrors;
- *data++ = s->RxSymbolErrors;
- *data++ = s->RxDataErrors;
- *data++ = s->RxSequenceErrors;
- *data++ = s->RxRuntErrors;
- *data++ = s->RxJabberErrors;
- *data++ = s->RxInternalMACRcvError;
- *data++ = s->RxInRangeLengthErrors;
- *data++ = s->RxOutOfRangeLengthField;
- *data++ = s->RxFrameTooLongErrors;
+ len = sizeof(u64)*(&s->TxFCSErrors + 1 - &s->TxOctetsOK);
+ memcpy(data, &s->TxOctetsOK, len);
+ data += len;
+
+ len = sizeof(u64)*(&s->RxFrameTooLongErrors + 1 - &s->RxOctetsOK);
+ memcpy(data, &s->RxOctetsOK, len);
+ data += len;
t1_sge_get_port_stats(adapter->sge, dev->if_port, &ss);
- *data++ = ss.rx_packets;
- *data++ = ss.rx_cso_good;
- *data++ = ss.tx_packets;
- *data++ = ss.tx_cso;
- *data++ = ss.tx_tso;
- *data++ = ss.vlan_xtract;
- *data++ = ss.vlan_insert;
+ memcpy(data, &ss, sizeof(ss));
+ data += sizeof(ss);
t = t1_sge_get_intr_counts(adapter->sge);
*data++ = t->rx_drops;
@@ -749,7 +719,7 @@ static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
return -EINVAL;
if (adapter->flags & FULL_INIT_DONE)
- return -EBUSY;
+ return -EBUSY;
adapter->params.sge.freelQ_size[!jumbo_fl] = e->rx_pending;
adapter->params.sge.freelQ_size[jumbo_fl] = e->rx_jumbo_pending;
@@ -764,7 +734,7 @@ static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
struct adapter *adapter = dev->priv;
adapter->params.sge.rx_coalesce_usecs = c->rx_coalesce_usecs;
- adapter->params.sge.coalesce_enable = c->use_adaptive_rx_coalesce;
+ adapter->params.sge.coalesce_enable = c->use_adaptive_rx_coalesce;
adapter->params.sge.sample_interval_usecs = c->rate_sample_interval;
t1_sge_set_coalesce_params(adapter->sge, &adapter->params.sge);
return 0;
@@ -782,9 +752,9 @@ static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
static int get_eeprom_len(struct net_device *dev)
{
- struct adapter *adapter = dev->priv;
+ struct adapter *adapter = dev->priv;
- return t1_is_asic(adapter) ? EEPROM_SIZE : 0;
+ return t1_is_asic(adapter) ? EEPROM_SIZE : 0;
}
#define EEPROM_MAGIC(ap) \
@@ -848,7 +818,7 @@ static int t1_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
u32 val;
if (!phy->mdio_read)
- return -EOPNOTSUPP;
+ return -EOPNOTSUPP;
phy->mdio_read(adapter, data->phy_id, 0, data->reg_num & 0x1f,
&val);
data->val_out = val;
@@ -860,7 +830,7 @@ static int t1_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (!phy->mdio_write)
- return -EOPNOTSUPP;
+ return -EOPNOTSUPP;
phy->mdio_write(adapter, data->phy_id, 0, data->reg_num & 0x1f,
data->val_in);
break;
@@ -879,9 +849,9 @@ static int t1_change_mtu(struct net_device *dev, int new_mtu)
struct cmac *mac = adapter->port[dev->if_port].mac;
if (!mac->ops->set_mtu)
- return -EOPNOTSUPP;
+ return -EOPNOTSUPP;
if (new_mtu < 68)
- return -EINVAL;
+ return -EINVAL;
if ((ret = mac->ops->set_mtu(mac, new_mtu)))
return ret;
dev->mtu = new_mtu;
@@ -1211,9 +1181,9 @@ static int __devinit init_one(struct pci_dev *pdev,
return 0;
- out_release_adapter_res:
+out_release_adapter_res:
t1_free_sw_modules(adapter);
- out_free_dev:
+out_free_dev:
if (adapter) {
if (adapter->regs)
iounmap(adapter->regs);
@@ -1222,7 +1192,7 @@ static int __devinit init_one(struct pci_dev *pdev,
free_netdev(adapter->port[i].dev);
}
pci_release_regions(pdev);
- out_disable_pdev:
+out_disable_pdev:
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
return err;
@@ -1273,28 +1243,27 @@ static int t1_clock(struct adapter *adapter, int mode)
int M_MEM_VAL;
enum {
- M_CORE_BITS = 9,
- T_CORE_VAL = 0,
- T_CORE_BITS = 2,
- N_CORE_VAL = 0,
- N_CORE_BITS = 2,
- M_MEM_BITS = 9,
- T_MEM_VAL = 0,
- T_MEM_BITS = 2,
- N_MEM_VAL = 0,
- N_MEM_BITS = 2,
- NP_LOAD = 1 << 17,
- S_LOAD_MEM = 1 << 5,
- S_LOAD_CORE = 1 << 6,
- S_CLOCK = 1 << 3
+ M_CORE_BITS = 9,
+ T_CORE_VAL = 0,
+ T_CORE_BITS = 2,
+ N_CORE_VAL = 0,
+ N_CORE_BITS = 2,
+ M_MEM_BITS = 9,
+ T_MEM_VAL = 0,
+ T_MEM_BITS = 2,
+ N_MEM_VAL = 0,
+ N_MEM_BITS = 2,
+ NP_LOAD = 1 << 17,
+ S_LOAD_MEM = 1 << 5,
+ S_LOAD_CORE = 1 << 6,
+ S_CLOCK = 1 << 3
};
if (!t1_is_T1B(adapter))
return -ENODEV; /* Can't re-clock this chip. */
- if (mode & 2) {
+ if (mode & 2)
return 0; /* show current mode. */
- }
if ((adapter->t1powersave & 1) == (mode & 1))
return -EALREADY; /* ASIC already running in mode. */
@@ -1386,26 +1355,26 @@ static inline void t1_sw_reset(struct pci_dev *pdev)
static void __devexit remove_one(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
+ struct adapter *adapter = dev->priv;
+ int i;
- if (dev) {
- int i;
- struct adapter *adapter = dev->priv;
-
- for_each_port(adapter, i)
- if (test_bit(i, &adapter->registered_device_map))
- unregister_netdev(adapter->port[i].dev);
+ for_each_port(adapter, i) {
+ if (test_bit(i, &adapter->registered_device_map))
+ unregister_netdev(adapter->port[i].dev);
+ }
- t1_free_sw_modules(adapter);
- iounmap(adapter->regs);
- while (--i >= 0)
- if (adapter->port[i].dev)
- free_netdev(adapter->port[i].dev);
+ t1_free_sw_modules(adapter);
+ iounmap(adapter->regs);
- pci_release_regions(pdev);
- pci_disable_device(pdev);
- pci_set_drvdata(pdev, NULL);
- t1_sw_reset(pdev);
+ while (--i >= 0) {
+ if (adapter->port[i].dev)
+ free_netdev(adapter->port[i].dev);
}
+
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+ t1_sw_reset(pdev);
}
static struct pci_driver driver = {
diff --git a/drivers/net/chelsio/elmer0.h b/drivers/net/chelsio/elmer0.h
index 9ebecaa97d3..eef655c827d 100644
--- a/drivers/net/chelsio/elmer0.h
+++ b/drivers/net/chelsio/elmer0.h
@@ -46,14 +46,14 @@ enum {
};
/* ELMER0 registers */
-#define A_ELMER0_VERSION 0x100000
-#define A_ELMER0_PHY_CFG 0x100004
-#define A_ELMER0_INT_ENABLE 0x100008
-#define A_ELMER0_INT_CAUSE 0x10000c
-#define A_ELMER0_GPI_CFG 0x100010
-#define A_ELMER0_GPI_STAT 0x100014
-#define A_ELMER0_GPO 0x100018
-#define A_ELMER0_PORT0_MI1_CFG 0x400000
+#define A_ELMER0_VERSION 0x100000
+#define A_ELMER0_PHY_CFG 0x100004
+#define A_ELMER0_INT_ENABLE 0x100008
+#define A_ELMER0_INT_CAUSE 0x10000c
+#define A_ELMER0_GPI_CFG 0x100010
+#define A_ELMER0_GPI_STAT 0x100014
+#define A_ELMER0_GPO 0x100018
+#define A_ELMER0_PORT0_MI1_CFG 0x400000
#define S_MI1_MDI_ENABLE 0
#define V_MI1_MDI_ENABLE(x) ((x) << S_MI1_MDI_ENABLE)
@@ -111,18 +111,18 @@ enum {
#define V_MI1_OP_BUSY(x) ((x) << S_MI1_OP_BUSY)
#define F_MI1_OP_BUSY V_MI1_OP_BUSY(1U)
-#define A_ELMER0_PORT1_MI1_CFG 0x500000
-#define A_ELMER0_PORT1_MI1_ADDR 0x500004
-#define A_ELMER0_PORT1_MI1_DATA 0x500008
-#define A_ELMER0_PORT1_MI1_OP 0x50000c
-#define A_ELMER0_PORT2_MI1_CFG 0x600000
-#define A_ELMER0_PORT2_MI1_ADDR 0x600004
-#define A_ELMER0_PORT2_MI1_DATA 0x600008
-#define A_ELMER0_PORT2_MI1_OP 0x60000c
-#define A_ELMER0_PORT3_MI1_CFG 0x700000
-#define A_ELMER0_PORT3_MI1_ADDR 0x700004
-#define A_ELMER0_PORT3_MI1_DATA 0x700008
-#define A_ELMER0_PORT3_MI1_OP 0x70000c
+#define A_ELMER0_PORT1_MI1_CFG 0x500000
+#define A_ELMER0_PORT1_MI1_ADDR 0x500004
+#define A_ELMER0_PORT1_MI1_DATA 0x500008
+#define A_ELMER0_PORT1_MI1_OP 0x50000c
+#define A_ELMER0_PORT2_MI1_CFG 0x600000
+#define A_ELMER0_PORT2_MI1_ADDR 0x600004
+#define A_ELMER0_PORT2_MI1_DATA 0x600008
+#define A_ELMER0_PORT2_MI1_OP 0x60000c
+#define A_ELMER0_PORT3_MI1_CFG 0x700000
+#define A_ELMER0_PORT3_MI1_ADDR 0x700004
+#define A_ELMER0_PORT3_MI1_DATA 0x700008
+#define A_ELMER0_PORT3_MI1_OP 0x70000c
/* Simple bit definition for GPI and GP0 registers. */
#define ELMER0_GP_BIT0 0x0001
diff --git a/drivers/net/chelsio/espi.c b/drivers/net/chelsio/espi.c
index 4192f0f5b3e..d7c5406a6c3 100644
--- a/drivers/net/chelsio/espi.c
+++ b/drivers/net/chelsio/espi.c
@@ -202,9 +202,9 @@ static void espi_setup_for_pm3393(adapter_t *adapter)
static void espi_setup_for_vsc7321(adapter_t *adapter)
{
- writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN0);
- writel(0x1f401f4, adapter->regs + A_ESPI_SCH_TOKEN1);
- writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN2);
+ writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN0);
+ writel(0x1f401f4, adapter->regs + A_ESPI_SCH_TOKEN1);
+ writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN2);
writel(0xa00, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK);
writel(0x1ff, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK);
writel(1, adapter->regs + A_ESPI_CALENDAR_LENGTH);
@@ -247,10 +247,10 @@ int t1_espi_init(struct peespi *espi, int mac_type, int nports)
writel(V_OUT_OF_SYNC_COUNT(4) |
V_DIP2_PARITY_ERR_THRES(3) |
V_DIP4_THRES(1), adapter->regs + A_ESPI_MISC_CONTROL);
- writel(nports == 4 ? 0x200040 : 0x1000080,
+ writel(nports == 4 ? 0x200040 : 0x1000080,
adapter->regs + A_ESPI_MAXBURST1_MAXBURST2);
} else
- writel(0x800100, adapter->regs + A_ESPI_MAXBURST1_MAXBURST2);
+ writel(0x800100, adapter->regs + A_ESPI_MAXBURST1_MAXBURST2);
if (mac_type == CHBT_MAC_PM3393)
espi_setup_for_pm3393(adapter);
@@ -301,7 +301,8 @@ void t1_espi_set_misc_ctrl(adapter_t *adapter, u32 val)
{
struct peespi *espi = adapter->espi;
- if (!is_T2(adapter)) return;
+ if (!is_T2(adapter))
+ return;
spin_lock(&espi->lock);
espi->misc_ctrl = (val & ~MON_MASK) |
(espi->misc_ctrl & MON_MASK);
@@ -340,32 +341,31 @@ u32 t1_espi_get_mon(adapter_t *adapter, u32 addr, u8 wait)
* compare with t1_espi_get_mon(), it reads espiInTxSop[0 ~ 3] in
* one shot, since there is no per port counter on the out side.
*/
-int
-t1_espi_get_mon_t204(adapter_t *adapter, u32 *valp, u8 wait)
+int t1_espi_get_mon_t204(adapter_t *adapter, u32 *valp, u8 wait)
{
- struct peespi *espi = adapter->espi;
+ struct peespi *espi = adapter->espi;
u8 i, nport = (u8)adapter->params.nports;
- if (!wait) {
- if (!spin_trylock(&espi->lock))
- return -1;
- } else
- spin_lock(&espi->lock);
+ if (!wait) {
+ if (!spin_trylock(&espi->lock))
+ return -1;
+ } else
+ spin_lock(&espi->lock);
- if ( (espi->misc_ctrl & MON_MASK) != F_MONITORED_DIRECTION ) {
+ if ((espi->misc_ctrl & MON_MASK) != F_MONITORED_DIRECTION) {
espi->misc_ctrl = (espi->misc_ctrl & ~MON_MASK) |
F_MONITORED_DIRECTION;
- writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL);
- }
+ writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL);
+ }
for (i = 0 ; i < nport; i++, valp++) {
if (i) {
writel(espi->misc_ctrl | V_MONITORED_PORT_NUM(i),
adapter->regs + A_ESPI_MISC_CONTROL);
}
- *valp = readl(adapter->regs + A_ESPI_SCH_TOKEN3);
- }
+ *valp = readl(adapter->regs + A_ESPI_SCH_TOKEN3);
+ }
- writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL);
- spin_unlock(&espi->lock);
- return 0;
+ writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL);
+ spin_unlock(&espi->lock);
+ return 0;
}
diff --git a/drivers/net/chelsio/fpga_defs.h b/drivers/net/chelsio/fpga_defs.h
index 17a3c2ba36a..ccdb2bc9ae9 100644
--- a/drivers/net/chelsio/fpga_defs.h
+++ b/drivers/net/chelsio/fpga_defs.h
@@ -98,9 +98,9 @@
#define A_MI0_DATA_INT 0xb10
/* GMAC registers */
-#define A_GMAC_MACID_LO 0x28
-#define A_GMAC_MACID_HI 0x2c
-#define A_GMAC_CSR 0x30
+#define A_GMAC_MACID_LO 0x28
+#define A_GMAC_MACID_HI 0x2c
+#define A_GMAC_CSR 0x30
#define S_INTERFACE 0
#define M_INTERFACE 0x3
diff --git a/drivers/net/chelsio/gmac.h b/drivers/net/chelsio/gmac.h
index a2b8ad9b553..006a2eb2d36 100644
--- a/drivers/net/chelsio/gmac.h
+++ b/drivers/net/chelsio/gmac.h
@@ -42,8 +42,15 @@
#include "common.h"
-enum { MAC_STATS_UPDATE_FAST, MAC_STATS_UPDATE_FULL };
-enum { MAC_DIRECTION_RX = 1, MAC_DIRECTION_TX = 2 };
+enum {
+ MAC_STATS_UPDATE_FAST,
+ MAC_STATS_UPDATE_FULL
+};
+
+enum {
+ MAC_DIRECTION_RX = 1,
+ MAC_DIRECTION_TX = 2
+};
struct cmac_statistics {
/* Transmit */
diff --git a/drivers/net/chelsio/ixf1010.c b/drivers/net/chelsio/ixf1010.c
index 5b8f144e83d..10b2a9a1900 100644
--- a/drivers/net/chelsio/ixf1010.c
+++ b/drivers/net/chelsio/ixf1010.c
@@ -145,48 +145,61 @@ static void disable_port(struct cmac *mac)
t1_tpi_write(mac->adapter, REG_PORT_ENABLE, val);
}
-#define RMON_UPDATE(mac, name, stat_name) \
- t1_tpi_read((mac)->adapter, MACREG(mac, REG_##name), &val); \
- (mac)->stats.stat_name += val;
-
/*
* Read the current values of the RMON counters and add them to the cumulative
* port statistics. The HW RMON counters are cleared by this operation.
*/
static void port_stats_update(struct cmac *mac)
{
- u32 val;
+ static struct {
+ unsigned int reg;
+ unsigned int offset;
+ } hw_stats[] = {
+
+#define HW_STAT(name, stat_name) \
+ { REG_##name, \
+ (&((struct cmac_statistics *)NULL)->stat_name) - (u64 *)NULL }
+
+ /* Rx stats */
+ HW_STAT(RxOctetsTotalOK, RxOctetsOK),
+ HW_STAT(RxOctetsBad, RxOctetsBad),
+ HW_STAT(RxUCPkts, RxUnicastFramesOK),
+ HW_STAT(RxMCPkts, RxMulticastFramesOK),
+ HW_STAT(RxBCPkts, RxBroadcastFramesOK),
+ HW_STAT(RxJumboPkts, RxJumboFramesOK),
+ HW_STAT(RxFCSErrors, RxFCSErrors),
+ HW_STAT(RxAlignErrors, RxAlignErrors),
+ HW_STAT(RxLongErrors, RxFrameTooLongErrors),
+ HW_STAT(RxVeryLongErrors, RxFrameTooLongErrors),
+ HW_STAT(RxPauseMacControlCounter, RxPauseFrames),
+ HW_STAT(RxDataErrors, RxDataErrors),
+ HW_STAT(RxJabberErrors, RxJabberErrors),
+ HW_STAT(RxRuntErrors, RxRuntErrors),
+ HW_STAT(RxShortErrors, RxRuntErrors),
+ HW_STAT(RxSequenceErrors, RxSequenceErrors),
+ HW_STAT(RxSymbolErrors, RxSymbolErrors),
+
+ /* Tx stats (skip collision stats as we are full-duplex only) */
+ HW_STAT(TxOctetsTotalOK, TxOctetsOK),
+ HW_STAT(TxOctetsBad, TxOctetsBad),
+ HW_STAT(TxUCPkts, TxUnicastFramesOK),
+ HW_STAT(TxMCPkts, TxMulticastFramesOK),
+ HW_STAT(TxBCPkts, TxBroadcastFramesOK),
+ HW_STAT(TxJumboPkts, TxJumboFramesOK),
+ HW_STAT(TxPauseFrames, TxPauseFrames),
+ HW_STAT(TxExcessiveLengthDrop, TxLengthErrors),
+ HW_STAT(TxUnderrun, TxUnderrun),
+ HW_STAT(TxCRCErrors, TxFCSErrors)
+ }, *p = hw_stats;
+ u64 *stats = (u64 *) &mac->stats;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(hw_stats); i++) {
+ u32 val;
- /* Rx stats */
- RMON_UPDATE(mac, RxOctetsTotalOK, RxOctetsOK);
- RMON_UPDATE(mac, RxOctetsBad, RxOctetsBad);
- RMON_UPDATE(mac, RxUCPkts, RxUnicastFramesOK);
- RMON_UPDATE(mac, RxMCPkts, RxMulticastFramesOK);
- RMON_UPDATE(mac, RxBCPkts, RxBroadcastFramesOK);
- RMON_UPDATE(mac, RxJumboPkts, RxJumboFramesOK);
- RMON_UPDATE(mac, RxFCSErrors, RxFCSErrors);
- RMON_UPDATE(mac, RxAlignErrors, RxAlignErrors);
- RMON_UPDATE(mac, RxLongErrors, RxFrameTooLongErrors);
- RMON_UPDATE(mac, RxVeryLongErrors, RxFrameTooLongErrors);
- RMON_UPDATE(mac, RxPauseMacControlCounter, RxPauseFrames);
- RMON_UPDATE(mac, RxDataErrors, RxDataErrors);
- RMON_UPDATE(mac, RxJabberErrors, RxJabberErrors);
- RMON_UPDATE(mac, RxRuntErrors, RxRuntErrors);
- RMON_UPDATE(mac, RxShortErrors, RxRuntErrors);
- RMON_UPDATE(mac, RxSequenceErrors, RxSequenceErrors);
- RMON_UPDATE(mac, RxSymbolErrors, RxSymbolErrors);
-
- /* Tx stats (skip collision stats as we are full-duplex only) */
- RMON_UPDATE(mac, TxOctetsTotalOK, TxOctetsOK);
- RMON_UPDATE(mac, TxOctetsBad, TxOctetsBad);
- RMON_UPDATE(mac, TxUCPkts, TxUnicastFramesOK);
- RMON_UPDATE(mac, TxMCPkts, TxMulticastFramesOK);
- RMON_UPDATE(mac, TxBCPkts, TxBroadcastFramesOK);
- RMON_UPDATE(mac, TxJumboPkts, TxJumboFramesOK);
- RMON_UPDATE(mac, TxPauseFrames, TxPauseFrames);
- RMON_UPDATE(mac, TxExcessiveLengthDrop, TxLengthErrors);
- RMON_UPDATE(mac, TxUnderrun, TxUnderrun);
- RMON_UPDATE(mac, TxCRCErrors, TxFCSErrors);
+ t1_tpi_read(mac->adapter, MACREG(mac, p->reg), &val);
+ stats[p->offset] += val;
+ }
}
/* No-op interrupt operation as this MAC does not support interrupts */
@@ -273,7 +286,8 @@ static int mac_set_rx_mode(struct cmac *mac, struct t1_rx_mode *rm)
static int mac_set_mtu(struct cmac *mac, int mtu)
{
/* MAX_FRAME_SIZE inludes header + FCS, mtu doesn't */
- if (mtu > (MAX_FRAME_SIZE - 14 - 4)) return -EINVAL;
+ if (mtu > (MAX_FRAME_SIZE - 14 - 4))
+ return -EINVAL;
t1_tpi_write(mac->adapter, MACREG(mac, REG_MAX_FRAME_SIZE),
mtu + 14 + 4);
return 0;
@@ -357,8 +371,8 @@ static void enable_port(struct cmac *mac)
val |= (1 << index);
t1_tpi_write(adapter, REG_PORT_ENABLE, val);
- index <<= 2;
- if (is_T2(adapter)) {
+ index <<= 2;
+ if (is_T2(adapter)) {
/* T204: set the Fifo water level & threshold */
t1_tpi_write(adapter, RX_FIFO_HIGH_WATERMARK_BASE + index, 0x740);
t1_tpi_write(adapter, RX_FIFO_LOW_WATERMARK_BASE + index, 0x730);
@@ -389,6 +403,10 @@ static int mac_disable(struct cmac *mac, int which)
return 0;
}
+#define RMON_UPDATE(mac, name, stat_name) \
+ t1_tpi_read((mac)->adapter, MACREG(mac, REG_##name), &val); \
+ (mac)->stats.stat_name += val;
+
/*
* This function is called periodically to accumulate the current values of the
* RMON counters into the port statistics. Since the counters are only 32 bits
@@ -460,10 +478,12 @@ static struct cmac *ixf1010_mac_create(adapter_t *adapter, int index)
struct cmac *mac;
u32 val;
- if (index > 9) return NULL;
+ if (index > 9)
+ return NULL;
mac = kzalloc(sizeof(*mac) + sizeof(cmac_instance), GFP_KERNEL);
- if (!mac) return NULL;
+ if (!mac)
+ return NULL;
mac->ops = &ixf1010_ops;
mac->instance = (cmac_instance *)(mac + 1);
diff --git a/drivers/net/chelsio/mv88e1xxx.c b/drivers/net/chelsio/mv88e1xxx.c
index 28ac93ff7c4..5867e3b0a88 100644
--- a/drivers/net/chelsio/mv88e1xxx.c
+++ b/drivers/net/chelsio/mv88e1xxx.c
@@ -73,9 +73,8 @@ static int mv88e1xxx_interrupt_enable(struct cphy *cphy)
t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
elmer |= ELMER0_GP_BIT1;
- if (is_T2(cphy->adapter)) {
- elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
- }
+ if (is_T2(cphy->adapter))
+ elmer |= ELMER0_GP_BIT2 | ELMER0_GP_BIT3 | ELMER0_GP_BIT4;
t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
}
return 0;
@@ -92,9 +91,8 @@ static int mv88e1xxx_interrupt_disable(struct cphy *cphy)
t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
elmer &= ~ELMER0_GP_BIT1;
- if (is_T2(cphy->adapter)) {
+ if (is_T2(cphy->adapter))
elmer &= ~(ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4);
- }
t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
}
return 0;
@@ -112,9 +110,8 @@ static int mv88e1xxx_interrupt_clear(struct cphy *cphy)
if (t1_is_asic(cphy->adapter)) {
t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer);
elmer |= ELMER0_GP_BIT1;
- if (is_T2(cphy->adapter)) {
+ if (is_T2(cphy->adapter))
elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
- }
t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer);
}
return 0;
@@ -300,7 +297,7 @@ static int mv88e1xxx_interrupt_handler(struct cphy *cphy)
/*
* Loop until cause reads zero. Need to handle bouncing interrupts.
- */
+ */
while (1) {
u32 cause;
@@ -308,15 +305,16 @@ static int mv88e1xxx_interrupt_handler(struct cphy *cphy)
MV88E1XXX_INTERRUPT_STATUS_REGISTER,
&cause);
cause &= INTR_ENABLE_MASK;
- if (!cause) break;
+ if (!cause)
+ break;
if (cause & MV88E1XXX_INTR_LINK_CHNG) {
(void) simple_mdio_read(cphy,
MV88E1XXX_SPECIFIC_STATUS_REGISTER, &status);
- if (status & MV88E1XXX_INTR_LINK_CHNG) {
+ if (status & MV88E1XXX_INTR_LINK_CHNG)
cphy->state |= PHY_LINK_UP;
- } else {
+ else {
cphy->state &= ~PHY_LINK_UP;
if (cphy->state & PHY_AUTONEG_EN)
cphy->state &= ~PHY_AUTONEG_RDY;
@@ -360,7 +358,8 @@ static struct cphy *mv88e1xxx_phy_create(adapter_t *adapter, int phy_addr,
{
struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL);
- if (!cphy) return NULL;
+ if (!cphy)
+ return NULL;
cphy_init(cphy, adapter, phy_addr, &mv88e1xxx_ops, mdio_ops);
@@ -377,11 +376,11 @@ static struct cphy *mv88e1xxx_phy_create(adapter_t *adapter, int phy_addr,
}
(void) mv88e1xxx_downshift_set(cphy, 1); /* Enable downshift */
- /* LED */
+ /* LED */
if (is_T2(adapter)) {
(void) simple_mdio_write(cphy,
MV88E1XXX_LED_CONTROL_REGISTER, 0x1);
- }
+ }
return cphy;
}
diff --git a/drivers/net/chelsio/my3126.c b/drivers/net/chelsio/my3126.c
index 82fed1dd500..87dde3e6004 100644
--- a/drivers/net/chelsio/my3126.c
+++ b/drivers/net/chelsio/my3126.c
@@ -10,25 +10,25 @@ static int my3126_reset(struct cphy *cphy, int wait)
* This can be done through registers. It is not required since
* a full chip reset is used.
*/
- return (0);
+ return 0;
}
static int my3126_interrupt_enable(struct cphy *cphy)
{
schedule_delayed_work(&cphy->phy_update, HZ/30);
t1_tpi_read(cphy->adapter, A_ELMER0_GPO, &cphy->elmer_gpo);
- return (0);
+ return 0;
}
static int my3126_interrupt_disable(struct cphy *cphy)
{
cancel_rearming_delayed_work(&cphy->phy_update);
- return (0);
+ return 0;
}
static int my3126_interrupt_clear(struct cphy *cphy)
{
- return (0);
+ return 0;
}
#define OFFSET(REG_ADDR) (REG_ADDR << 2)
@@ -102,7 +102,7 @@ static void my3216_poll(struct work_struct *work)
static int my3126_set_loopback(struct cphy *cphy, int on)
{
- return (0);
+ return 0;
}
/* To check the activity LED */
@@ -146,7 +146,7 @@ static int my3126_get_link_status(struct cphy *cphy,
if (fc)
*fc = PAUSE_RX | PAUSE_TX;
- return (0);
+ return 0;
}
static void my3126_destroy(struct cphy *cphy)
@@ -177,7 +177,7 @@ static struct cphy *my3126_phy_create(adapter_t *adapter,
INIT_DELAYED_WORK(&cphy->phy_update, my3216_poll);
cphy->bmsr = 0;
- return (cphy);
+ return cphy;
}
/* Chip Reset */
@@ -198,7 +198,7 @@ static int my3126_phy_reset(adapter_t * adapter)
val |= 0x8000;
t1_tpi_write(adapter, A_ELMER0_GPO, val);
udelay(100);
- return (0);
+ return 0;
}
struct gphy t1_my3126_ops = {
diff --git a/drivers/net/chelsio/pm3393.c b/drivers/net/chelsio/pm3393.c
index 63cabeb98af..69129edeefd 100644
--- a/drivers/net/chelsio/pm3393.c
+++ b/drivers/net/chelsio/pm3393.c
@@ -446,17 +446,51 @@ static void pm3393_rmon_update(struct adapter *adapter, u32 offs, u64 *val,
*val += 1ull << 40;
}
-#define RMON_UPDATE(mac, name, stat_name) \
- pm3393_rmon_update((mac)->adapter, OFFSET(name), \
- &(mac)->stats.stat_name, \
- (ro &((name - SUNI1x10GEXP_REG_MSTAT_COUNTER_0_LOW) >> 2)))
-
-
static const struct cmac_statistics *pm3393_update_statistics(struct cmac *mac,
int flag)
{
- u64 ro;
- u32 val0, val1, val2, val3;
+ static struct {
+ unsigned int reg;
+ unsigned int offset;
+ } hw_stats [] = {
+
+#define HW_STAT(name, stat_name) \
+ { name, (&((struct cmac_statistics *)NULL)->stat_name) - (u64 *)NULL }
+
+ /* Rx stats */
+ HW_STAT(RxOctetsReceivedOK, RxOctetsOK),
+ HW_STAT(RxUnicastFramesReceivedOK, RxUnicastFramesOK),
+ HW_STAT(RxMulticastFramesReceivedOK, RxMulticastFramesOK),
+ HW_STAT(RxBroadcastFramesReceivedOK, RxBroadcastFramesOK),
+ HW_STAT(RxPAUSEMACCtrlFramesReceived, RxPauseFrames),
+ HW_STAT(RxFrameCheckSequenceErrors, RxFCSErrors),
+ HW_STAT(RxFramesLostDueToInternalMACErrors,
+ RxInternalMACRcvError),
+ HW_STAT(RxSymbolErrors, RxSymbolErrors),
+ HW_STAT(RxInRangeLengthErrors, RxInRangeLengthErrors),
+ HW_STAT(RxFramesTooLongErrors , RxFrameTooLongErrors),
+ HW_STAT(RxJabbers, RxJabberErrors),
+ HW_STAT(RxFragments, RxRuntErrors),
+ HW_STAT(RxUndersizedFrames, RxRuntErrors),
+ HW_STAT(RxJumboFramesReceivedOK, RxJumboFramesOK),
+ HW_STAT(RxJumboOctetsReceivedOK, RxJumboOctetsOK),
+
+ /* Tx stats */
+ HW_STAT(TxOctetsTransmittedOK, TxOctetsOK),
+ HW_STAT(TxFramesLostDueToInternalMACTransmissionError,
+ TxInternalMACXmitError),
+ HW_STAT(TxTransmitSystemError, TxFCSErrors),
+ HW_STAT(TxUnicastFramesTransmittedOK, TxUnicastFramesOK),
+ HW_STAT(TxMulticastFramesTransmittedOK, TxMulticastFramesOK),
+ HW_STAT(TxBroadcastFramesTransmittedOK, TxBroadcastFramesOK),
+ HW_STAT(TxPAUSEMACCtrlFramesTransmitted, TxPauseFrames),
+ HW_STAT(TxJumboFramesReceivedOK, TxJumboFramesOK),
+ HW_STAT(TxJumboOctetsReceivedOK, TxJumboOctetsOK)
+ }, *p = hw_stats;
+ u64 ro;
+ u32 val0, val1, val2, val3;
+ u64 *stats = (u64 *) &mac->stats;
+ unsigned int i;
/* Snap the counters */
pmwrite(mac, SUNI1x10GEXP_REG_MSTAT_CONTROL,
@@ -470,35 +504,14 @@ static const struct cmac_statistics *pm3393_update_statistics(struct cmac *mac,
ro = ((u64)val0 & 0xffff) | (((u64)val1 & 0xffff) << 16) |
(((u64)val2 & 0xffff) << 32) | (((u64)val3 & 0xffff) << 48);
- /* Rx stats */
- RMON_UPDATE(mac, RxOctetsReceivedOK, RxOctetsOK);
- RMON_UPDATE(mac, RxUnicastFramesReceivedOK, RxUnicastFramesOK);
- RMON_UPDATE(mac, RxMulticastFramesReceivedOK, RxMulticastFramesOK);
- RMON_UPDATE(mac, RxBroadcastFramesReceivedOK, RxBroadcastFramesOK);
- RMON_UPDATE(mac, RxPAUSEMACCtrlFramesReceived, RxPauseFrames);
- RMON_UPDATE(mac, RxFrameCheckSequenceErrors, RxFCSErrors);
- RMON_UPDATE(mac, RxFramesLostDueToInternalMACErrors,
- RxInternalMACRcvError);
- RMON_UPDATE(mac, RxSymbolErrors, RxSymbolErrors);
- RMON_UPDATE(mac, RxInRangeLengthErrors, RxInRangeLengthErrors);
- RMON_UPDATE(mac, RxFramesTooLongErrors , RxFrameTooLongErrors);
- RMON_UPDATE(mac, RxJabbers, RxJabberErrors);
- RMON_UPDATE(mac, RxFragments, RxRuntErrors);
- RMON_UPDATE(mac, RxUndersizedFrames, RxRuntErrors);
- RMON_UPDATE(mac, RxJumboFramesReceivedOK, RxJumboFramesOK);
- RMON_UPDATE(mac, RxJumboOctetsReceivedOK, RxJumboOctetsOK);
-
- /* Tx stats */
- RMON_UPDATE(mac, TxOctetsTransmittedOK, TxOctetsOK);
- RMON_UPDATE(mac, TxFramesLostDueToInternalMACTransmissionError,
- TxInternalMACXmitError);
- RMON_UPDATE(mac, TxTransmitSystemError, TxFCSErrors);
- RMON_UPDATE(mac, TxUnicastFramesTransmittedOK, TxUnicastFramesOK);
- RMON_UPDATE(mac, TxMulticastFramesTransmittedOK, TxMulticastFramesOK);
- RMON_UPDATE(mac, TxBroadcastFramesTransmittedOK, TxBroadcastFramesOK);
- RMON_UPDATE(mac, TxPAUSEMACCtrlFramesTransmitted, TxPauseFrames);
- RMON_UPDATE(mac, TxJumboFramesReceivedOK, TxJumboFramesOK);
- RMON_UPDATE(mac, TxJumboOctetsReceivedOK, TxJumboOctetsOK);
+ for (i = 0; i < ARRAY_SIZE(hw_stats); i++) {
+ unsigned reg = p->reg - SUNI1x10GEXP_REG_MSTAT_COUNTER_0_LOW;
+
+ pm3393_rmon_update((mac)->adapter, OFFSET(p->reg),
+ stats + p->offset, ro & (reg >> 2));
+ }
+
+
return &mac->stats;
}
@@ -534,9 +547,9 @@ static int pm3393_macaddress_set(struct cmac *cmac, u8 ma[6])
/* Store local copy */
memcpy(cmac->instance->mac_addr, ma, 6);
- lo = ((u32) ma[1] << 8) | (u32) ma[0];
+ lo = ((u32) ma[1] << 8) | (u32) ma[0];
mid = ((u32) ma[3] << 8) | (u32) ma[2];
- hi = ((u32) ma[5] << 8) | (u32) ma[4];
+ hi = ((u32) ma[5] << 8) | (u32) ma[4];
/* Disable Rx/Tx MAC before configuring it. */
if (enabled)
diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c
index 659cb2252e4..89a682702fa 100644
--- a/drivers/net/chelsio/sge.c
+++ b/drivers/net/chelsio/sge.c
@@ -71,12 +71,9 @@
#define SGE_FREEL_REFILL_THRESH 16
#define SGE_RESPQ_E_N 1024
#define SGE_INTRTIMER_NRES 1000
-#define SGE_RX_COPY_THRES 256
#define SGE_RX_SM_BUF_SIZE 1536
#define SGE_TX_DESC_MAX_PLEN 16384
-# define SGE_RX_DROP_THRES 2
-
#define SGE_RESPQ_REPLENISH_THRES (SGE_RESPQ_E_N / 4)
/*
@@ -85,10 +82,6 @@
*/
#define TX_RECLAIM_PERIOD (HZ / 4)
-#ifndef NET_IP_ALIGN
-# define NET_IP_ALIGN 2
-#endif
-
#define M_CMD_LEN 0x7fffffff
#define V_CMD_LEN(v) (v)
#define G_CMD_LEN(v) ((v) & M_CMD_LEN)
@@ -195,7 +188,7 @@ struct cmdQ {
struct cmdQ_e *entries; /* HW command descriptor Q */
struct cmdQ_ce *centries; /* SW command context descriptor Q */
dma_addr_t dma_addr; /* DMA addr HW command descriptor Q */
- spinlock_t lock; /* Lock to protect cmdQ enqueuing */
+ spinlock_t lock; /* Lock to protect cmdQ enqueuing */
};
struct freelQ {
@@ -241,9 +234,9 @@ struct sched_port {
/* Per T204 device */
struct sched {
ktime_t last_updated; /* last time quotas were computed */
- unsigned int max_avail; /* max bits to be sent to any port */
- unsigned int port; /* port index (round robin ports) */
- unsigned int num; /* num skbs in per port queues */
+ unsigned int max_avail; /* max bits to be sent to any port */
+ unsigned int port; /* port index (round robin ports) */
+ unsigned int num; /* num skbs in per port queues */
struct sched_port p[MAX_NPORTS];
struct tasklet_struct sched_tsk;/* tasklet used to run scheduler */
};
@@ -259,10 +252,10 @@ static void restart_sched(unsigned long);
* contention.
*/
struct sge {
- struct adapter *adapter; /* adapter backpointer */
+ struct adapter *adapter; /* adapter backpointer */
struct net_device *netdev; /* netdevice backpointer */
- struct freelQ freelQ[SGE_FREELQ_N]; /* buffer free lists */
- struct respQ respQ; /* response Q */
+ struct freelQ freelQ[SGE_FREELQ_N]; /* buffer free lists */
+ struct respQ respQ; /* response Q */
unsigned long stopped_tx_queues; /* bitmap of suspended Tx queues */
unsigned int rx_pkt_pad; /* RX padding for L2 packets */
unsigned int jumbo_fl; /* jumbo freelist Q index */
@@ -460,7 +453,7 @@ static struct sk_buff *sched_skb(struct sge *sge, struct sk_buff *skb,
if (credits < MAX_SKB_FRAGS + 1)
goto out;
- again:
+again:
for (i = 0; i < MAX_NPORTS; i++) {
s->port = ++s->port & (MAX_NPORTS - 1);
skbq = &s->p[s->port].skbq;
@@ -483,8 +476,8 @@ static struct sk_buff *sched_skb(struct sge *sge, struct sk_buff *skb,
if (update-- && sched_update_avail(sge))
goto again;
- out:
- /* If there are more pending skbs, we use the hardware to schedule us
+out:
+ /* If there are more pending skbs, we use the hardware to schedule us
* again.
*/
if (s->num && !skb) {
@@ -575,11 +568,10 @@ static int alloc_rx_resources(struct sge *sge, struct sge_params *p)
q->size = p->freelQ_size[i];
q->dma_offset = sge->rx_pkt_pad ? 0 : NET_IP_ALIGN;
size = sizeof(struct freelQ_e) * q->size;
- q->entries = (struct freelQ_e *)
- pci_alloc_consistent(pdev, size, &q->dma_addr);
+ q->entries = pci_alloc_consistent(pdev, size, &q->dma_addr);
if (!q->entries)
goto err_no_mem;
- memset(q->entries, 0, size);
+
size = sizeof(struct freelQ_ce) * q->size;
q->centries = kzalloc(size, GFP_KERNEL);
if (!q->centries)
@@ -613,11 +605,10 @@ static int alloc_rx_resources(struct sge *sge, struct sge_params *p)
sge->respQ.size = SGE_RESPQ_E_N;
sge->respQ.credits = 0;
size = sizeof(struct respQ_e) * sge->respQ.size;
- sge->respQ.entries = (struct respQ_e *)
+ sge->respQ.entries =
pci_alloc_consistent(pdev, size, &sge->respQ.dma_addr);
if (!sge->respQ.entries)
goto err_no_mem;
- memset(sge->respQ.entries, 0, size);
return 0;
err_no_mem:
@@ -637,20 +628,12 @@ static void free_cmdQ_buffers(struct sge *sge, struct cmdQ *q, unsigned int n)
q->in_use -= n;
ce = &q->centries[cidx];
while (n--) {
- if (q->sop) {
- if (likely(pci_unmap_len(ce, dma_len))) {
- pci_unmap_single(pdev,
- pci_unmap_addr(ce, dma_addr),
- pci_unmap_len(ce, dma_len),
- PCI_DMA_TODEVICE);
+ if (likely(pci_unmap_len(ce, dma_len))) {
+ pci_unmap_single(pdev, pci_unmap_addr(ce, dma_addr),
+ pci_unmap_len(ce, dma_len),
+ PCI_DMA_TODEVICE);
+ if (q->sop)
q->sop = 0;
- }
- } else {
- if (likely(pci_unmap_len(ce, dma_len))) {
- pci_unmap_page(pdev, pci_unmap_addr(ce, dma_addr),
- pci_unmap_len(ce, dma_len),
- PCI_DMA_TODEVICE);
- }
}
if (ce->skb) {
dev_kfree_skb_any(ce->skb);
@@ -711,11 +694,10 @@ static int alloc_tx_resources(struct sge *sge, struct sge_params *p)
q->stop_thres = 0;
spin_lock_init(&q->lock);
size = sizeof(struct cmdQ_e) * q->size;
- q->entries = (struct cmdQ_e *)
- pci_alloc_consistent(pdev, size, &q->dma_addr);
+ q->entries = pci_alloc_consistent(pdev, size, &q->dma_addr);
if (!q->entries)
goto err_no_mem;
- memset(q->entries, 0, size);
+
size = sizeof(struct cmdQ_ce) * q->size;
q->centries = kzalloc(size, GFP_KERNEL);
if (!q->centries)
@@ -770,7 +752,7 @@ void t1_set_vlan_accel(struct adapter *adapter, int on_off)
static void configure_sge(struct sge *sge, struct sge_params *p)
{
struct adapter *ap = sge->adapter;
-
+
writel(0, ap->regs + A_SG_CONTROL);
setup_ring_params(ap, sge->cmdQ[0].dma_addr, sge->cmdQ[0].size,
A_SG_CMD0BASELWR, A_SG_CMD0BASEUPR, A_SG_CMD0SIZE);
@@ -850,7 +832,6 @@ static void refill_free_list(struct sge *sge, struct freelQ *q)
struct freelQ_e *e = &q->entries[q->pidx];
unsigned int dma_len = q->rx_buffer_size - q->dma_offset;
-
while (q->credits < q->size) {
struct sk_buff *skb;
dma_addr_t mapping;
@@ -862,6 +843,8 @@ static void refill_free_list(struct sge *sge, struct freelQ *q)
skb_reserve(skb, q->dma_offset);
mapping = pci_map_single(pdev, skb->data, dma_len,
PCI_DMA_FROMDEVICE);
+ skb_reserve(skb, sge->rx_pkt_pad);
+
ce->skb = skb;
pci_unmap_addr_set(ce, dma_addr, mapping);
pci_unmap_len_set(ce, dma_len, dma_len);
@@ -881,7 +864,6 @@ static void refill_free_list(struct sge *sge, struct freelQ *q)
}
q->credits++;
}
-
}
/*
@@ -1041,6 +1023,10 @@ static void recycle_fl_buf(struct freelQ *fl, int idx)
}
}
+static int copybreak __read_mostly = 256;
+module_param(copybreak, int, 0);
+MODULE_PARM_DESC(copybreak, "Receive copy threshold");
+
/**
* get_packet - return the next ingress packet buffer
* @pdev: the PCI device that received the packet
@@ -1060,45 +1046,42 @@ static void recycle_fl_buf(struct freelQ *fl, int idx)
* be copied but there is no memory for the copy.
*/
static inline struct sk_buff *get_packet(struct pci_dev *pdev,
- struct freelQ *fl, unsigned int len,
- int dma_pad, int skb_pad,
- unsigned int copy_thres,
- unsigned int drop_thres)
+ struct freelQ *fl, unsigned int len)
{
struct sk_buff *skb;
- struct freelQ_ce *ce = &fl->centries[fl->cidx];
+ const struct freelQ_ce *ce = &fl->centries[fl->cidx];
- if (len < copy_thres) {
- skb = alloc_skb(len + skb_pad, GFP_ATOMIC);
- if (likely(skb != NULL)) {
- skb_reserve(skb, skb_pad);
- skb_put(skb, len);
- pci_dma_sync_single_for_cpu(pdev,
- pci_unmap_addr(ce, dma_addr),
- pci_unmap_len(ce, dma_len),
- PCI_DMA_FROMDEVICE);
- memcpy(skb->data, ce->skb->data + dma_pad, len);
- pci_dma_sync_single_for_device(pdev,
- pci_unmap_addr(ce, dma_addr),
- pci_unmap_len(ce, dma_len),
- PCI_DMA_FROMDEVICE);
- } else if (!drop_thres)
+ if (len < copybreak) {
+ skb = alloc_skb(len + 2, GFP_ATOMIC);
+ if (!skb)
goto use_orig_buf;
+ skb_reserve(skb, 2); /* align IP header */
+ skb_put(skb, len);
+ pci_dma_sync_single_for_cpu(pdev,
+ pci_unmap_addr(ce, dma_addr),
+ pci_unmap_len(ce, dma_len),
+ PCI_DMA_FROMDEVICE);
+ memcpy(skb->data, ce->skb->data, len);
+ pci_dma_sync_single_for_device(pdev,
+ pci_unmap_addr(ce, dma_addr),
+ pci_unmap_len(ce, dma_len),
+ PCI_DMA_FROMDEVICE);
recycle_fl_buf(fl, fl->cidx);
return skb;
}
- if (fl->credits < drop_thres) {
+use_orig_buf:
+ if (fl->credits < 2) {
recycle_fl_buf(fl, fl->cidx);
return NULL;
}
-use_orig_buf:
pci_unmap_single(pdev, pci_unmap_addr(ce, dma_addr),
pci_unmap_len(ce, dma_len), PCI_DMA_FROMDEVICE);
skb = ce->skb;
- skb_reserve(skb, dma_pad);
+ prefetch(skb->data);
+
skb_put(skb, len);
return skb;
}
@@ -1137,6 +1120,7 @@ static void unexpected_offload(struct adapter *adapter, struct freelQ *fl)
static inline unsigned int compute_large_page_tx_descs(struct sk_buff *skb)
{
unsigned int count = 0;
+
if (PAGE_SIZE > SGE_TX_DESC_MAX_PLEN) {
unsigned int nfrags = skb_shinfo(skb)->nr_frags;
unsigned int i, len = skb->len - skb->data_len;
@@ -1343,7 +1327,7 @@ static void restart_sched(unsigned long arg)
while ((skb = sched_skb(sge, NULL, credits)) != NULL) {
unsigned int genbit, pidx, count;
count = 1 + skb_shinfo(skb)->nr_frags;
- count += compute_large_page_tx_descs(skb);
+ count += compute_large_page_tx_descs(skb);
q->in_use += count;
genbit = q->genbit;
pidx = q->pidx;
@@ -1375,27 +1359,25 @@ static void restart_sched(unsigned long arg)
*
* Process an ingress ethernet pakcet and deliver it to the stack.
*/
-static int sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len)
+static void sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len)
{
struct sk_buff *skb;
- struct cpl_rx_pkt *p;
+ const struct cpl_rx_pkt *p;
struct adapter *adapter = sge->adapter;
struct sge_port_stats *st;
- skb = get_packet(adapter->pdev, fl, len - sge->rx_pkt_pad,
- sge->rx_pkt_pad, 2, SGE_RX_COPY_THRES,
- SGE_RX_DROP_THRES);
+ skb = get_packet(adapter->pdev, fl, len - sge->rx_pkt_pad);
if (unlikely(!skb)) {
sge->stats.rx_drops++;
- return 0;
+ return;
}
- p = (struct cpl_rx_pkt *)skb->data;
- skb_pull(skb, sizeof(*p));
+ p = (const struct cpl_rx_pkt *) skb->data;
if (p->iff >= adapter->params.nports) {
kfree_skb(skb);
- return 0;
+ return;
}
+ __skb_pull(skb, sizeof(*p));
skb->dev = adapter->port[p->iff].dev;
skb->dev->last_rx = jiffies;
@@ -1427,7 +1409,6 @@ static int sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len)
netif_rx(skb);
#endif
}
- return 0;
}
/*
@@ -1448,29 +1429,28 @@ static inline int enough_free_Tx_descs(const struct cmdQ *q)
static void restart_tx_queues(struct sge *sge)
{
struct adapter *adap = sge->adapter;
+ int i;
- if (enough_free_Tx_descs(&sge->cmdQ[0])) {
- int i;
+ if (!enough_free_Tx_descs(&sge->cmdQ[0]))
+ return;
- for_each_port(adap, i) {
- struct net_device *nd = adap->port[i].dev;
+ for_each_port(adap, i) {
+ struct net_device *nd = adap->port[i].dev;
- if (test_and_clear_bit(nd->if_port,
- &sge->stopped_tx_queues) &&
- netif_running(nd)) {
- sge->stats.cmdQ_restarted[2]++;
- netif_wake_queue(nd);
- }
+ if (test_and_clear_bit(nd->if_port, &sge->stopped_tx_queues) &&
+ netif_running(nd)) {
+ sge->stats.cmdQ_restarted[2]++;
+ netif_wake_queue(nd);
}
}
}
/*
- * update_tx_info is called from the interrupt handler/NAPI to return cmdQ0
+ * update_tx_info is called from the interrupt handler/NAPI to return cmdQ0
* information.
*/
-static unsigned int update_tx_info(struct adapter *adapter,
- unsigned int flags,
+static unsigned int update_tx_info(struct adapter *adapter,
+ unsigned int flags,
unsigned int pr0)
{
struct sge *sge = adapter->sge;
@@ -1510,29 +1490,30 @@ static int process_responses(struct adapter *adapter, int budget)
struct sge *sge = adapter->sge;
struct respQ *q = &sge->respQ;
struct respQ_e *e = &q->entries[q->cidx];
- int budget_left = budget;
+ int done = 0;
unsigned int flags = 0;
unsigned int cmdq_processed[SGE_CMDQ_N] = {0, 0};
-
- while (likely(budget_left && e->GenerationBit == q->genbit)) {
+ while (done < budget && e->GenerationBit == q->genbit) {
flags |= e->Qsleeping;
-
+
cmdq_processed[0] += e->Cmdq0CreditReturn;
cmdq_processed[1] += e->Cmdq1CreditReturn;
-
+
/* We batch updates to the TX side to avoid cacheline
* ping-pong of TX state information on MP where the sender
* might run on a different CPU than this function...
*/
- if (unlikely(flags & F_CMDQ0_ENABLE || cmdq_processed[0] > 64)) {
+ if (unlikely((flags & F_CMDQ0_ENABLE) || cmdq_processed[0] > 64)) {
flags = update_tx_info(adapter, flags, cmdq_processed[0]);
cmdq_processed[0] = 0;
}
+
if (unlikely(cmdq_processed[1] > 16)) {
sge->cmdQ[1].processed += cmdq_processed[1];
cmdq_processed[1] = 0;
}
+
if (likely(e->DataValid)) {
struct freelQ *fl = &sge->freelQ[e->FreelistQid];
@@ -1542,12 +1523,16 @@ static int process_responses(struct adapter *adapter, int budget)
else
sge_rx(sge, fl, e->BufferLength);
+ ++done;
+
/*
* Note: this depends on each packet consuming a
* single free-list buffer; cf. the BUG above.
*/
if (++fl->cidx == fl->size)
fl->cidx = 0;
+ prefetch(fl->centries[fl->cidx].skb);
+
if (unlikely(--fl->credits <
fl->size - SGE_FREEL_REFILL_THRESH))
refill_free_list(sge, fl);
@@ -1566,14 +1551,20 @@ static int process_responses(struct adapter *adapter, int budget)
writel(q->credits, adapter->regs + A_SG_RSPQUEUECREDIT);
q->credits = 0;
}
- --budget_left;
}
- flags = update_tx_info(adapter, flags, cmdq_processed[0]);
+ flags = update_tx_info(adapter, flags, cmdq_processed[0]);
sge->cmdQ[1].processed += cmdq_processed[1];
- budget -= budget_left;
- return budget;
+ return done;
+}
+
+static inline int responses_pending(const struct adapter *adapter)
+{
+ const struct respQ *Q = &adapter->sge->respQ;
+ const struct respQ_e *e = &Q->entries[Q->cidx];
+
+ return (e->GenerationBit == Q->genbit);
}
#ifdef CONFIG_CHELSIO_T1_NAPI
@@ -1585,19 +1576,25 @@ static int process_responses(struct adapter *adapter, int budget)
* which the caller must ensure is a valid pure response. Returns 1 if it
* encounters a valid data-carrying response, 0 otherwise.
*/
-static int process_pure_responses(struct adapter *adapter, struct respQ_e *e)
+static int process_pure_responses(struct adapter *adapter)
{
struct sge *sge = adapter->sge;
struct respQ *q = &sge->respQ;
+ struct respQ_e *e = &q->entries[q->cidx];
+ const struct freelQ *fl = &sge->freelQ[e->FreelistQid];
unsigned int flags = 0;
unsigned int cmdq_processed[SGE_CMDQ_N] = {0, 0};
+ prefetch(fl->centries[fl->cidx].skb);
+ if (e->DataValid)
+ return 1;
+
do {
flags |= e->Qsleeping;
cmdq_processed[0] += e->Cmdq0CreditReturn;
cmdq_processed[1] += e->Cmdq1CreditReturn;
-
+
e++;
if (unlikely(++q->cidx == q->size)) {
q->cidx = 0;
@@ -1613,7 +1610,7 @@ static int process_pure_responses(struct adapter *adapter, struct respQ_e *e)
sge->stats.pure_rsps++;
} while (e->GenerationBit == q->genbit && !e->DataValid);
- flags = update_tx_info(adapter, flags, cmdq_processed[0]);
+ flags = update_tx_info(adapter, flags, cmdq_processed[0]);
sge->cmdQ[1].processed += cmdq_processed[1];
return e->GenerationBit == q->genbit;
@@ -1627,23 +1624,20 @@ static int process_pure_responses(struct adapter *adapter, struct respQ_e *e)
int t1_poll(struct net_device *dev, int *budget)
{
struct adapter *adapter = dev->priv;
- int effective_budget = min(*budget, dev->quota);
- int work_done = process_responses(adapter, effective_budget);
+ int work_done;
+ work_done = process_responses(adapter, min(*budget, dev->quota));
*budget -= work_done;
dev->quota -= work_done;
- if (work_done >= effective_budget)
+ if (unlikely(responses_pending(adapter)))
return 1;
- spin_lock_irq(&adapter->async_lock);
- __netif_rx_complete(dev);
+ netif_rx_complete(dev);
writel(adapter->sge->respQ.cidx, adapter->regs + A_SG_SLEEPING);
- writel(adapter->slow_intr_mask | F_PL_INTR_SGE_DATA,
- adapter->regs + A_PL_ENABLE);
- spin_unlock_irq(&adapter->async_lock);
return 0;
+
}
/*
@@ -1652,44 +1646,33 @@ int t1_poll(struct net_device *dev, int *budget)
irqreturn_t t1_interrupt(int irq, void *data)
{
struct adapter *adapter = data;
- struct net_device *dev = adapter->sge->netdev;
struct sge *sge = adapter->sge;
- u32 cause;
- int handled = 0;
+ int handled;
- cause = readl(adapter->regs + A_PL_CAUSE);
- if (cause == 0 || cause == ~0)
- return IRQ_NONE;
+ if (likely(responses_pending(adapter))) {
+ struct net_device *dev = sge->netdev;
- spin_lock(&adapter->async_lock);
- if (cause & F_PL_INTR_SGE_DATA) {
- struct respQ *q = &adapter->sge->respQ;
- struct respQ_e *e = &q->entries[q->cidx];
-
- handled = 1;
- writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE);
-
- if (e->GenerationBit == q->genbit &&
- __netif_rx_schedule_prep(dev)) {
- if (e->DataValid || process_pure_responses(adapter, e)) {
- /* mask off data IRQ */
- writel(adapter->slow_intr_mask,
- adapter->regs + A_PL_ENABLE);
- __netif_rx_schedule(sge->netdev);
- goto unlock;
- }
- /* no data, no NAPI needed */
- netif_poll_enable(dev);
+ writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE);
+ if (__netif_rx_schedule_prep(dev)) {
+ if (process_pure_responses(adapter))
+ __netif_rx_schedule(dev);
+ else {
+ /* no data, no NAPI needed */
+ writel(sge->respQ.cidx, adapter->regs + A_SG_SLEEPING);
+ netif_poll_enable(dev); /* undo schedule_prep */
+ }
}
- writel(q->cidx, adapter->regs + A_SG_SLEEPING);
- } else
- handled = t1_slow_intr_handler(adapter);
+ return IRQ_HANDLED;
+ }
+
+ spin_lock(&adapter->async_lock);
+ handled = t1_slow_intr_handler(adapter);
+ spin_unlock(&adapter->async_lock);
if (!handled)
sge->stats.unhandled_irqs++;
-unlock:
- spin_unlock(&adapter->async_lock);
+
return IRQ_RETVAL(handled != 0);
}
@@ -1712,17 +1695,13 @@ unlock:
irqreturn_t t1_interrupt(int irq, void *cookie)
{
int work_done;
- struct respQ_e *e;
struct adapter *adapter = cookie;
- struct respQ *Q = &adapter->sge->respQ;
spin_lock(&adapter->async_lock);
- e = &Q->entries[Q->cidx];
- prefetch(e);
writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE);
- if (likely(e->GenerationBit == Q->genbit))
+ if (likely(responses_pending(adapter)))
work_done = process_responses(adapter, -1);
else
work_done = t1_slow_intr_handler(adapter);
@@ -1796,7 +1775,7 @@ static int t1_sge_tx(struct sk_buff *skb, struct adapter *adapter,
* through the scheduler.
*/
if (sge->tx_sched && !qid && skb->dev) {
- use_sched:
+use_sched:
use_sched_skb = 1;
/* Note that the scheduler might return a different skb than
* the one passed in.
@@ -1900,7 +1879,7 @@ int t1_start_xmit(struct sk_buff *skb, struct net_device *dev)
cpl = (struct cpl_tx_pkt *)hdr;
} else {
/*
- * Packets shorter than ETH_HLEN can break the MAC, drop them
+ * Packets shorter than ETH_HLEN can break the MAC, drop them
* early. Also, we may get oversized packets because some
* parts of the kernel don't handle our unusual hard_header_len
* right, drop those too.
@@ -1984,9 +1963,9 @@ send:
* then silently discard to avoid leak.
*/
if (unlikely(ret != NETDEV_TX_OK && skb != orig_skb)) {
- dev_kfree_skb_any(skb);
+ dev_kfree_skb_any(skb);
ret = NETDEV_TX_OK;
- }
+ }
return ret;
}
@@ -2099,31 +2078,35 @@ static void espibug_workaround_t204(unsigned long data)
if (adapter->open_device_map & PORT_MASK) {
int i;
- if (t1_espi_get_mon_t204(adapter, &(seop[0]), 0) < 0) {
+
+ if (t1_espi_get_mon_t204(adapter, &(seop[0]), 0) < 0)
return;
- }
+
for (i = 0; i < nports; i++) {
- struct sk_buff *skb = sge->espibug_skb[i];
- if ( (netif_running(adapter->port[i].dev)) &&
- !(netif_queue_stopped(adapter->port[i].dev)) &&
- (seop[i] && ((seop[i] & 0xfff) == 0)) &&
- skb ) {
- if (!skb->cb[0]) {
- u8 ch_mac_addr[ETH_ALEN] =
- {0x0, 0x7, 0x43, 0x0, 0x0, 0x0};
- memcpy(skb->data + sizeof(struct cpl_tx_pkt),
- ch_mac_addr, ETH_ALEN);
- memcpy(skb->data + skb->len - 10,
- ch_mac_addr, ETH_ALEN);
- skb->cb[0] = 0xff;
- }
-
- /* bump the reference count to avoid freeing of
- * the skb once the DMA has completed.
- */
- skb = skb_get(skb);
- t1_sge_tx(skb, adapter, 0, adapter->port[i].dev);
+ struct sk_buff *skb = sge->espibug_skb[i];
+
+ if (!netif_running(adapter->port[i].dev) ||
+ netif_queue_stopped(adapter->port[i].dev) ||
+ !seop[i] || ((seop[i] & 0xfff) != 0) || !skb)
+ continue;
+
+ if (!skb->cb[0]) {
+ u8 ch_mac_addr[ETH_ALEN] = {
+ 0x0, 0x7, 0x43, 0x0, 0x0, 0x0
+ };
+
+ memcpy(skb->data + sizeof(struct cpl_tx_pkt),
+ ch_mac_addr, ETH_ALEN);
+ memcpy(skb->data + skb->len - 10,
+ ch_mac_addr, ETH_ALEN);
+ skb->cb[0] = 0xff;
}
+
+ /* bump the reference count to avoid freeing of
+ * the skb once the DMA has completed.
+ */
+ skb = skb_get(skb);
+ t1_sge_tx(skb, adapter, 0, adapter->port[i].dev);
}
}
mod_timer(&sge->espibug_timer, jiffies + sge->espibug_timeout);
@@ -2192,9 +2175,8 @@ struct sge * __devinit t1_sge_create(struct adapter *adapter,
if (adapter->params.nports > 1) {
tx_sched_init(sge);
sge->espibug_timer.function = espibug_workaround_t204;
- } else {
+ } else
sge->espibug_timer.function = espibug_workaround;
- }
sge->espibug_timer.data = (unsigned long)sge->adapter;
sge->espibug_timeout = 1;
@@ -2202,7 +2184,7 @@ struct sge * __devinit t1_sge_create(struct adapter *adapter,
if (adapter->params.nports > 1)
sge->espibug_timeout = HZ/100;
}
-
+
p->cmdQ_size[0] = SGE_CMDQ0_E_N;
p->cmdQ_size[1] = SGE_CMDQ1_E_N;
diff --git a/drivers/net/chelsio/subr.c b/drivers/net/chelsio/subr.c
index 22ed9a383c0..c2522cdfab3 100644
--- a/drivers/net/chelsio/subr.c
+++ b/drivers/net/chelsio/subr.c
@@ -223,13 +223,13 @@ static int fpga_slow_intr(adapter_t *adapter)
t1_sge_intr_error_handler(adapter->sge);
if (cause & FPGA_PCIX_INTERRUPT_GMAC)
- fpga_phy_intr_handler(adapter);
+ fpga_phy_intr_handler(adapter);
if (cause & FPGA_PCIX_INTERRUPT_TP) {
- /*
+ /*
* FPGA doesn't support MC4 interrupts and it requires
* this odd layer of indirection for MC5.
- */
+ */
u32 tp_cause = readl(adapter->regs + FPGA_TP_ADDR_INTERRUPT_CAUSE);
/* Clear TP interrupt */
@@ -262,8 +262,7 @@ static int mi1_wait_until_ready(adapter_t *adapter, int mi1_reg)
udelay(10);
} while (busy && --attempts);
if (busy)
- CH_ALERT("%s: MDIO operation timed out\n",
- adapter->name);
+ CH_ALERT("%s: MDIO operation timed out\n", adapter->name);
return busy;
}
@@ -605,22 +604,23 @@ int t1_elmer0_ext_intr_handler(adapter_t *adapter)
switch (board_info(adapter)->board) {
#ifdef CONFIG_CHELSIO_T1_1G
- case CHBT_BOARD_CHT204:
- case CHBT_BOARD_CHT204E:
- case CHBT_BOARD_CHN204:
- case CHBT_BOARD_CHT204V: {
- int i, port_bit;
+ case CHBT_BOARD_CHT204:
+ case CHBT_BOARD_CHT204E:
+ case CHBT_BOARD_CHN204:
+ case CHBT_BOARD_CHT204V: {
+ int i, port_bit;
for_each_port(adapter, i) {
port_bit = i + 1;
- if (!(cause & (1 << port_bit))) continue;
+ if (!(cause & (1 << port_bit)))
+ continue;
- phy = adapter->port[i].phy;
+ phy = adapter->port[i].phy;
phy_cause = phy->ops->interrupt_handler(phy);
if (phy_cause & cphy_cause_link_change)
t1_link_changed(adapter, i);
}
- break;
- }
+ break;
+ }
case CHBT_BOARD_CHT101:
if (cause & ELMER0_GP_BIT1) { /* Marvell 88E1111 interrupt */
phy = adapter->port[0].phy;
@@ -631,13 +631,13 @@ int t1_elmer0_ext_intr_handler(adapter_t *adapter)
break;
case CHBT_BOARD_7500: {
int p;
- /*
+ /*
* Elmer0's interrupt cause isn't useful here because there is
* only one bit that can be set for all 4 ports. This means
* we are forced to check every PHY's interrupt status
* register to see who initiated the interrupt.
- */
- for_each_port(adapter, p) {
+ */
+ for_each_port(adapter, p) {
phy = adapter->port[p].phy;
phy_cause = phy->ops->interrupt_handler(phy);
if (phy_cause & cphy_cause_link_change)
@@ -658,7 +658,7 @@ int t1_elmer0_ext_intr_handler(adapter_t *adapter)
break;
case CHBT_BOARD_8000:
case CHBT_BOARD_CHT110:
- CH_DBG(adapter, INTR, "External interrupt cause 0x%x\n",
+ CH_DBG(adapter, INTR, "External interrupt cause 0x%x\n",
cause);
if (cause & ELMER0_GP_BIT1) { /* PMC3393 INTB */
struct cmac *mac = adapter->port[0].mac;
@@ -670,9 +670,9 @@ int t1_elmer0_ext_intr_handler(adapter_t *adapter)
t1_tpi_read(adapter,
A_ELMER0_GPI_STAT, &mod_detect);
- CH_MSG(adapter, INFO, LINK, "XPAK %s\n",
+ CH_MSG(adapter, INFO, LINK, "XPAK %s\n",
mod_detect ? "removed" : "inserted");
- }
+ }
break;
#ifdef CONFIG_CHELSIO_T1_COUGAR
case CHBT_BOARD_COUGAR:
@@ -688,7 +688,8 @@ int t1_elmer0_ext_intr_handler(adapter_t *adapter)
for_each_port(adapter, i) {
port_bit = i ? i + 1 : 0;
- if (!(cause & (1 << port_bit))) continue;
+ if (!(cause & (1 << port_bit)))
+ continue;
phy = adapter->port[i].phy;
phy_cause = phy->ops->interrupt_handler(phy);
@@ -755,7 +756,7 @@ void t1_interrupts_disable(adapter_t* adapter)
/* Disable PCIX & external chip interrupts. */
if (t1_is_asic(adapter))
- writel(0, adapter->regs + A_PL_ENABLE);
+ writel(0, adapter->regs + A_PL_ENABLE);
/* PCI-X interrupts */
pci_write_config_dword(adapter->pdev, A_PCICFG_INTR_ENABLE, 0);
@@ -830,11 +831,11 @@ int t1_slow_intr_handler(adapter_t *adapter)
/* Power sequencing is a work-around for Intel's XPAKs. */
static void power_sequence_xpak(adapter_t* adapter)
{
- u32 mod_detect;
- u32 gpo;
+ u32 mod_detect;
+ u32 gpo;
- /* Check for XPAK */
- t1_tpi_read(adapter, A_ELMER0_GPI_STAT, &mod_detect);
+ /* Check for XPAK */
+ t1_tpi_read(adapter, A_ELMER0_GPI_STAT, &mod_detect);
if (!(ELMER0_GP_BIT5 & mod_detect)) {
/* XPAK is present */
t1_tpi_read(adapter, A_ELMER0_GPO, &gpo);
@@ -877,31 +878,31 @@ static int board_init(adapter_t *adapter, const struct board_info *bi)
case CHBT_BOARD_N210:
case CHBT_BOARD_CHT210:
case CHBT_BOARD_COUGAR:
- t1_tpi_par(adapter, 0xf);
- t1_tpi_write(adapter, A_ELMER0_GPO, 0x800);
+ t1_tpi_par(adapter, 0xf);
+ t1_tpi_write(adapter, A_ELMER0_GPO, 0x800);
break;
case CHBT_BOARD_CHT110:
- t1_tpi_par(adapter, 0xf);
- t1_tpi_write(adapter, A_ELMER0_GPO, 0x1800);
+ t1_tpi_par(adapter, 0xf);
+ t1_tpi_write(adapter, A_ELMER0_GPO, 0x1800);
- /* TBD XXX Might not need. This fixes a problem
- * described in the Intel SR XPAK errata.
- */
- power_sequence_xpak(adapter);
+ /* TBD XXX Might not need. This fixes a problem
+ * described in the Intel SR XPAK errata.
+ */
+ power_sequence_xpak(adapter);
break;
#ifdef CONFIG_CHELSIO_T1_1G
- case CHBT_BOARD_CHT204E:
- /* add config space write here */
+ case CHBT_BOARD_CHT204E:
+ /* add config space write here */
case CHBT_BOARD_CHT204:
case CHBT_BOARD_CHT204V:
case CHBT_BOARD_CHN204:
- t1_tpi_par(adapter, 0xf);
- t1_tpi_write(adapter, A_ELMER0_GPO, 0x804);
- break;
+ t1_tpi_par(adapter, 0xf);
+ t1_tpi_write(adapter, A_ELMER0_GPO, 0x804);
+ break;
case CHBT_BOARD_CHT101:
case CHBT_BOARD_7500:
- t1_tpi_par(adapter, 0xf);
- t1_tpi_write(adapter, A_ELMER0_GPO, 0x1804);
+ t1_tpi_par(adapter, 0xf);
+ t1_tpi_write(adapter, A_ELMER0_GPO, 0x1804);
break;
#endif
}
@@ -941,7 +942,7 @@ int t1_init_hw_modules(adapter_t *adapter)
goto out_err;
err = 0;
- out_err:
+out_err:
return err;
}
@@ -983,7 +984,7 @@ void t1_free_sw_modules(adapter_t *adapter)
if (adapter->espi)
t1_espi_destroy(adapter->espi);
#ifdef CONFIG_CHELSIO_T1_COUGAR
- if (adapter->cspi)
+ if (adapter->cspi)
t1_cspi_destroy(adapter->cspi);
#endif
}
@@ -1010,7 +1011,7 @@ static void __devinit init_link_config(struct link_config *lc,
CH_ERR("%s: CSPI initialization failed\n",
adapter->name);
goto error;
- }
+ }
#endif
/*
diff --git a/drivers/net/chelsio/tp.c b/drivers/net/chelsio/tp.c
index 0ca0b6e19e4..6222d585e44 100644
--- a/drivers/net/chelsio/tp.c
+++ b/drivers/net/chelsio/tp.c
@@ -17,39 +17,36 @@ struct petp {
static void tp_init(adapter_t * ap, const struct tp_params *p,
unsigned int tp_clk)
{
- if (t1_is_asic(ap)) {
- u32 val;
-
- val = F_TP_IN_CSPI_CPL | F_TP_IN_CSPI_CHECK_IP_CSUM |
- F_TP_IN_CSPI_CHECK_TCP_CSUM | F_TP_IN_ESPI_ETHERNET;
- if (!p->pm_size)
- val |= F_OFFLOAD_DISABLE;
- else
- val |= F_TP_IN_ESPI_CHECK_IP_CSUM |
- F_TP_IN_ESPI_CHECK_TCP_CSUM;
- writel(val, ap->regs + A_TP_IN_CONFIG);
- writel(F_TP_OUT_CSPI_CPL |
- F_TP_OUT_ESPI_ETHERNET |
- F_TP_OUT_ESPI_GENERATE_IP_CSUM |
- F_TP_OUT_ESPI_GENERATE_TCP_CSUM,
- ap->regs + A_TP_OUT_CONFIG);
- writel(V_IP_TTL(64) |
- F_PATH_MTU /* IP DF bit */ |
- V_5TUPLE_LOOKUP(p->use_5tuple_mode) |
- V_SYN_COOKIE_PARAMETER(29),
- ap->regs + A_TP_GLOBAL_CONFIG);
- /*
- * Enable pause frame deadlock prevention.
- */
- if (is_T2(ap) && ap->params.nports > 1) {
- u32 drop_ticks = DROP_MSEC * (tp_clk / 1000);
-
- writel(F_ENABLE_TX_DROP | F_ENABLE_TX_ERROR |
- V_DROP_TICKS_CNT(drop_ticks) |
- V_NUM_PKTS_DROPPED(DROP_PKTS_CNT),
- ap->regs + A_TP_TX_DROP_CONFIG);
- }
+ u32 val;
+ if (!t1_is_asic(ap))
+ return;
+
+ val = F_TP_IN_CSPI_CPL | F_TP_IN_CSPI_CHECK_IP_CSUM |
+ F_TP_IN_CSPI_CHECK_TCP_CSUM | F_TP_IN_ESPI_ETHERNET;
+ if (!p->pm_size)
+ val |= F_OFFLOAD_DISABLE;
+ else
+ val |= F_TP_IN_ESPI_CHECK_IP_CSUM | F_TP_IN_ESPI_CHECK_TCP_CSUM;
+ writel(val, ap->regs + A_TP_IN_CONFIG);
+ writel(F_TP_OUT_CSPI_CPL |
+ F_TP_OUT_ESPI_ETHERNET |
+ F_TP_OUT_ESPI_GENERATE_IP_CSUM |
+ F_TP_OUT_ESPI_GENERATE_TCP_CSUM, ap->regs + A_TP_OUT_CONFIG);
+ writel(V_IP_TTL(64) |
+ F_PATH_MTU /* IP DF bit */ |
+ V_5TUPLE_LOOKUP(p->use_5tuple_mode) |
+ V_SYN_COOKIE_PARAMETER(29), ap->regs + A_TP_GLOBAL_CONFIG);
+ /*
+ * Enable pause frame deadlock prevention.
+ */
+ if (is_T2(ap) && ap->params.nports > 1) {
+ u32 drop_ticks = DROP_MSEC * (tp_clk / 1000);
+
+ writel(F_ENABLE_TX_DROP | F_ENABLE_TX_ERROR |
+ V_DROP_TICKS_CNT(drop_ticks) |
+ V_NUM_PKTS_DROPPED(DROP_PKTS_CNT),
+ ap->regs + A_TP_TX_DROP_CONFIG);
}
}
@@ -61,6 +58,7 @@ void t1_tp_destroy(struct petp *tp)
struct petp *__devinit t1_tp_create(adapter_t * adapter, struct tp_params *p)
{
struct petp *tp = kzalloc(sizeof(*tp), GFP_KERNEL);
+
if (!tp)
return NULL;
diff --git a/drivers/net/chelsio/vsc7326.c b/drivers/net/chelsio/vsc7326.c
index 85dc3b1dc30..534ffa0f616 100644
--- a/drivers/net/chelsio/vsc7326.c
+++ b/drivers/net/chelsio/vsc7326.c
@@ -226,22 +226,21 @@ static void run_table(adapter_t *adapter, struct init_table *ib, int len)
if (ib[i].addr == INITBLOCK_SLEEP) {
udelay( ib[i].data );
CH_ERR("sleep %d us\n",ib[i].data);
- } else {
+ } else
vsc_write( adapter, ib[i].addr, ib[i].data );
- }
}
}
static int bist_rd(adapter_t *adapter, int moduleid, int address)
{
- int data=0;
- u32 result=0;
-
- if( (address != 0x0) &&
- (address != 0x1) &&
- (address != 0x2) &&
- (address != 0xd) &&
- (address != 0xe))
+ int data = 0;
+ u32 result = 0;
+
+ if ((address != 0x0) &&
+ (address != 0x1) &&
+ (address != 0x2) &&
+ (address != 0xd) &&
+ (address != 0xe))
CH_ERR("No bist address: 0x%x\n", address);
data = ((0x00 << 24) | ((address & 0xff) << 16) | (0x00 << 8) |
@@ -251,27 +250,27 @@ static int bist_rd(adapter_t *adapter, int moduleid, int address)
udelay(10);
vsc_read(adapter, REG_RAM_BIST_RESULT, &result);
- if((result & (1<<9)) != 0x0)
+ if ((result & (1 << 9)) != 0x0)
CH_ERR("Still in bist read: 0x%x\n", result);
- else if((result & (1<<8)) != 0x0)
+ else if ((result & (1 << 8)) != 0x0)
CH_ERR("bist read error: 0x%x\n", result);
- return(result & 0xff);
+ return (result & 0xff);
}
static int bist_wr(adapter_t *adapter, int moduleid, int address, int value)
{
- int data=0;
- u32 result=0;
-
- if( (address != 0x0) &&
- (address != 0x1) &&
- (address != 0x2) &&
- (address != 0xd) &&
- (address != 0xe))
+ int data = 0;
+ u32 result = 0;
+
+ if ((address != 0x0) &&
+ (address != 0x1) &&
+ (address != 0x2) &&
+ (address != 0xd) &&
+ (address != 0xe))
CH_ERR("No bist address: 0x%x\n", address);
- if( value>255 )
+ if (value > 255)
CH_ERR("Suspicious write out of range value: 0x%x\n", value);
data = ((0x01 << 24) | ((address & 0xff) << 16) | (value << 8) |
@@ -281,12 +280,12 @@ static int bist_wr(adapter_t *adapter, int moduleid, int address, int value)
udelay(5);
vsc_read(adapter, REG_RAM_BIST_CMD, &result);
- if((result & (1<<27)) != 0x0)
+ if ((result & (1 << 27)) != 0x0)
CH_ERR("Still in bist write: 0x%x\n", result);
- else if((result & (1<<26)) != 0x0)
+ else if ((result & (1 << 26)) != 0x0)
CH_ERR("bist write error: 0x%x\n", result);
- return(0);
+ return 0;
}
static int run_bist(adapter_t *adapter, int moduleid)
@@ -295,7 +294,7 @@ static int run_bist(adapter_t *adapter, int moduleid)
(void) bist_wr(adapter,moduleid, 0x00, 0x02);
(void) bist_wr(adapter,moduleid, 0x01, 0x01);
- return(0);
+ return 0;
}
static int check_bist(adapter_t *adapter, int moduleid)
@@ -309,27 +308,26 @@ static int check_bist(adapter_t *adapter, int moduleid)
if ((result & 3) != 0x3)
CH_ERR("Result: 0x%x BIST error in ram %d, column: 0x%04x\n",
result, moduleid, column);
- return(0);
+ return 0;
}
static int enable_mem(adapter_t *adapter, int moduleid)
{
/*enable mem*/
(void) bist_wr(adapter,moduleid, 0x00, 0x00);
- return(0);
+ return 0;
}
static int run_bist_all(adapter_t *adapter)
{
- int port=0;
- u32 val=0;
+ int port = 0;
+ u32 val = 0;
vsc_write(adapter, REG_MEM_BIST, 0x5);
vsc_read(adapter, REG_MEM_BIST, &val);
- for(port=0; port<12; port++){
+ for (port = 0; port < 12; port++)
vsc_write(adapter, REG_DEV_SETUP(port), 0x0);
- }
udelay(300);
vsc_write(adapter, REG_SPI4_MISC, 0x00040409);
@@ -352,13 +350,13 @@ static int run_bist_all(adapter_t *adapter)
udelay(300);
vsc_write(adapter, REG_SPI4_MISC, 0x60040400);
udelay(300);
- for(port=0; port<12; port++){
+ for (port = 0; port < 12; port++)
vsc_write(adapter, REG_DEV_SETUP(port), 0x1);
- }
+
udelay(300);
vsc_write(adapter, REG_MEM_BIST, 0x0);
mdelay(10);
- return(0);
+ return 0;
}
static int mac_intr_handler(struct cmac *mac)
@@ -591,40 +589,46 @@ static void rmon_update(struct cmac *mac, unsigned int addr, u64 *stat)
static void port_stats_update(struct cmac *mac)
{
- int port = mac->instance->index;
+ struct {
+ unsigned int reg;
+ unsigned int offset;
+ } hw_stats[] = {
+
+#define HW_STAT(reg, stat_name) \
+ { reg, (&((struct cmac_statistics *)NULL)->stat_name) - (u64 *)NULL }
+
+ /* Rx stats */
+ HW_STAT(RxUnicast, RxUnicastFramesOK),
+ HW_STAT(RxMulticast, RxMulticastFramesOK),
+ HW_STAT(RxBroadcast, RxBroadcastFramesOK),
+ HW_STAT(Crc, RxFCSErrors),
+ HW_STAT(RxAlignment, RxAlignErrors),
+ HW_STAT(RxOversize, RxFrameTooLongErrors),
+ HW_STAT(RxPause, RxPauseFrames),
+ HW_STAT(RxJabbers, RxJabberErrors),
+ HW_STAT(RxFragments, RxRuntErrors),
+ HW_STAT(RxUndersize, RxRuntErrors),
+ HW_STAT(RxSymbolCarrier, RxSymbolErrors),
+ HW_STAT(RxSize1519ToMax, RxJumboFramesOK),
+
+ /* Tx stats (skip collision stats as we are full-duplex only) */
+ HW_STAT(TxUnicast, TxUnicastFramesOK),
+ HW_STAT(TxMulticast, TxMulticastFramesOK),
+ HW_STAT(TxBroadcast, TxBroadcastFramesOK),
+ HW_STAT(TxPause, TxPauseFrames),
+ HW_STAT(TxUnderrun, TxUnderrun),
+ HW_STAT(TxSize1519ToMax, TxJumboFramesOK),
+ }, *p = hw_stats;
+ unsigned int port = mac->instance->index;
+ u64 *stats = (u64 *)&mac->stats;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(hw_stats); i++)
+ rmon_update(mac, CRA(0x4, port, p->reg), stats + p->offset);
- /* Rx stats */
+ rmon_update(mac, REG_TX_OK_BYTES(port), &mac->stats.TxOctetsOK);
rmon_update(mac, REG_RX_OK_BYTES(port), &mac->stats.RxOctetsOK);
rmon_update(mac, REG_RX_BAD_BYTES(port), &mac->stats.RxOctetsBad);
- rmon_update(mac, REG_RX_UNICAST(port), &mac->stats.RxUnicastFramesOK);
- rmon_update(mac, REG_RX_MULTICAST(port),
- &mac->stats.RxMulticastFramesOK);
- rmon_update(mac, REG_RX_BROADCAST(port),
- &mac->stats.RxBroadcastFramesOK);
- rmon_update(mac, REG_CRC(port), &mac->stats.RxFCSErrors);
- rmon_update(mac, REG_RX_ALIGNMENT(port), &mac->stats.RxAlignErrors);
- rmon_update(mac, REG_RX_OVERSIZE(port),
- &mac->stats.RxFrameTooLongErrors);
- rmon_update(mac, REG_RX_PAUSE(port), &mac->stats.RxPauseFrames);
- rmon_update(mac, REG_RX_JABBERS(port), &mac->stats.RxJabberErrors);
- rmon_update(mac, REG_RX_FRAGMENTS(port), &mac->stats.RxRuntErrors);
- rmon_update(mac, REG_RX_UNDERSIZE(port), &mac->stats.RxRuntErrors);
- rmon_update(mac, REG_RX_SYMBOL_CARRIER(port),
- &mac->stats.RxSymbolErrors);
- rmon_update(mac, REG_RX_SIZE_1519_TO_MAX(port),
- &mac->stats.RxJumboFramesOK);
-
- /* Tx stats (skip collision stats as we are full-duplex only) */
- rmon_update(mac, REG_TX_OK_BYTES(port), &mac->stats.TxOctetsOK);
- rmon_update(mac, REG_TX_UNICAST(port), &mac->stats.TxUnicastFramesOK);
- rmon_update(mac, REG_TX_MULTICAST(port),
- &mac->stats.TxMulticastFramesOK);
- rmon_update(mac, REG_TX_BROADCAST(port),
- &mac->stats.TxBroadcastFramesOK);
- rmon_update(mac, REG_TX_PAUSE(port), &mac->stats.TxPauseFrames);
- rmon_update(mac, REG_TX_UNDERRUN(port), &mac->stats.TxUnderrun);
- rmon_update(mac, REG_TX_SIZE_1519_TO_MAX(port),
- &mac->stats.TxJumboFramesOK);
}
/*
@@ -686,7 +690,8 @@ static struct cmac *vsc7326_mac_create(adapter_t *adapter, int index)
int i;
mac = kzalloc(sizeof(*mac) + sizeof(cmac_instance), GFP_KERNEL);
- if (!mac) return NULL;
+ if (!mac)
+ return NULL;
mac->ops = &vsc7326_ops;
mac->instance = (cmac_instance *)(mac + 1);
diff --git a/drivers/net/chelsio/vsc7326_reg.h b/drivers/net/chelsio/vsc7326_reg.h
index 491bcf75c4f..479edbcabe6 100644
--- a/drivers/net/chelsio/vsc7326_reg.h
+++ b/drivers/net/chelsio/vsc7326_reg.h
@@ -192,73 +192,84 @@
#define REG_HDX(pn) CRA(0x1,pn,0x19) /* Half-duplex config */
/* Statistics */
+/* CRA(0x4,pn,reg) */
+/* reg below */
/* pn = port number, 0-a, a = 10GbE */
-#define REG_RX_IN_BYTES(pn) CRA(0x4,pn,0x00) /* # Rx in octets */
-#define REG_RX_SYMBOL_CARRIER(pn) CRA(0x4,pn,0x01) /* Frames w/ symbol errors */
-#define REG_RX_PAUSE(pn) CRA(0x4,pn,0x02) /* # pause frames received */
-#define REG_RX_UNSUP_OPCODE(pn) CRA(0x4,pn,0x03) /* # control frames with unsupported opcode */
-#define REG_RX_OK_BYTES(pn) CRA(0x4,pn,0x04) /* # octets in good frames */
-#define REG_RX_BAD_BYTES(pn) CRA(0x4,pn,0x05) /* # octets in bad frames */
-#define REG_RX_UNICAST(pn) CRA(0x4,pn,0x06) /* # good unicast frames */
-#define REG_RX_MULTICAST(pn) CRA(0x4,pn,0x07) /* # good multicast frames */
-#define REG_RX_BROADCAST(pn) CRA(0x4,pn,0x08) /* # good broadcast frames */
-#define REG_CRC(pn) CRA(0x4,pn,0x09) /* # frames w/ bad CRC only */
-#define REG_RX_ALIGNMENT(pn) CRA(0x4,pn,0x0a) /* # frames w/ alignment err */
-#define REG_RX_UNDERSIZE(pn) CRA(0x4,pn,0x0b) /* # frames undersize */
-#define REG_RX_FRAGMENTS(pn) CRA(0x4,pn,0x0c) /* # frames undersize w/ crc err */
-#define REG_RX_IN_RANGE_LENGTH_ERROR(pn) CRA(0x4,pn,0x0d) /* # frames with length error */
-#define REG_RX_OUT_OF_RANGE_ERROR(pn) CRA(0x4,pn,0x0e) /* # frames with illegal length field */
-#define REG_RX_OVERSIZE(pn) CRA(0x4,pn,0x0f) /* # frames oversize */
-#define REG_RX_JABBERS(pn) CRA(0x4,pn,0x10) /* # frames oversize w/ crc err */
-#define REG_RX_SIZE_64(pn) CRA(0x4,pn,0x11) /* # frames 64 octets long */
-#define REG_RX_SIZE_65_TO_127(pn) CRA(0x4,pn,0x12) /* # frames 65-127 octets */
-#define REG_RX_SIZE_128_TO_255(pn) CRA(0x4,pn,0x13) /* # frames 128-255 */
-#define REG_RX_SIZE_256_TO_511(pn) CRA(0x4,pn,0x14) /* # frames 256-511 */
-#define REG_RX_SIZE_512_TO_1023(pn) CRA(0x4,pn,0x15) /* # frames 512-1023 */
-#define REG_RX_SIZE_1024_TO_1518(pn) CRA(0x4,pn,0x16) /* # frames 1024-1518 */
-#define REG_RX_SIZE_1519_TO_MAX(pn) CRA(0x4,pn,0x17) /* # frames 1519-max */
-#define REG_TX_OUT_BYTES(pn) CRA(0x4,pn,0x18) /* # octets tx */
-#define REG_TX_PAUSE(pn) CRA(0x4,pn,0x19) /* # pause frames sent */
-#define REG_TX_OK_BYTES(pn) CRA(0x4,pn,0x1a) /* # octets tx OK */
-#define REG_TX_UNICAST(pn) CRA(0x4,pn,0x1b) /* # frames unicast */
-#define REG_TX_MULTICAST(pn) CRA(0x4,pn,0x1c) /* # frames multicast */
-#define REG_TX_BROADCAST(pn) CRA(0x4,pn,0x1d) /* # frames broadcast */
-#define REG_TX_MULTIPLE_COLL(pn) CRA(0x4,pn,0x1e) /* # frames tx after multiple collisions */
-#define REG_TX_LATE_COLL(pn) CRA(0x4,pn,0x1f) /* # late collisions detected */
-#define REG_TX_XCOLL(pn) CRA(0x4,pn,0x20) /* # frames lost, excessive collisions */
-#define REG_TX_DEFER(pn) CRA(0x4,pn,0x21) /* # frames deferred on first tx attempt */
-#define REG_TX_XDEFER(pn) CRA(0x4,pn,0x22) /* # frames excessively deferred */
-#define REG_TX_CSENSE(pn) CRA(0x4,pn,0x23) /* carrier sense errors at frame end */
-#define REG_TX_SIZE_64(pn) CRA(0x4,pn,0x24) /* # frames 64 octets long */
-#define REG_TX_SIZE_65_TO_127(pn) CRA(0x4,pn,0x25) /* # frames 65-127 octets */
-#define REG_TX_SIZE_128_TO_255(pn) CRA(0x4,pn,0x26) /* # frames 128-255 */
-#define REG_TX_SIZE_256_TO_511(pn) CRA(0x4,pn,0x27) /* # frames 256-511 */
-#define REG_TX_SIZE_512_TO_1023(pn) CRA(0x4,pn,0x28) /* # frames 512-1023 */
-#define REG_TX_SIZE_1024_TO_1518(pn) CRA(0x4,pn,0x29) /* # frames 1024-1518 */
-#define REG_TX_SIZE_1519_TO_MAX(pn) CRA(0x4,pn,0x2a) /* # frames 1519-max */
-#define REG_TX_SINGLE_COLL(pn) CRA(0x4,pn,0x2b) /* # frames tx after single collision */
-#define REG_TX_BACKOFF2(pn) CRA(0x4,pn,0x2c) /* # frames tx ok after 2 backoffs/collisions */
-#define REG_TX_BACKOFF3(pn) CRA(0x4,pn,0x2d) /* after 3 backoffs/collisions */
-#define REG_TX_BACKOFF4(pn) CRA(0x4,pn,0x2e) /* after 4 */
-#define REG_TX_BACKOFF5(pn) CRA(0x4,pn,0x2f) /* after 5 */
-#define REG_TX_BACKOFF6(pn) CRA(0x4,pn,0x30) /* after 6 */
-#define REG_TX_BACKOFF7(pn) CRA(0x4,pn,0x31) /* after 7 */
-#define REG_TX_BACKOFF8(pn) CRA(0x4,pn,0x32) /* after 8 */
-#define REG_TX_BACKOFF9(pn) CRA(0x4,pn,0x33) /* after 9 */
-#define REG_TX_BACKOFF10(pn) CRA(0x4,pn,0x34) /* after 10 */
-#define REG_TX_BACKOFF11(pn) CRA(0x4,pn,0x35) /* after 11 */
-#define REG_TX_BACKOFF12(pn) CRA(0x4,pn,0x36) /* after 12 */
-#define REG_TX_BACKOFF13(pn) CRA(0x4,pn,0x37) /* after 13 */
-#define REG_TX_BACKOFF14(pn) CRA(0x4,pn,0x38) /* after 14 */
-#define REG_TX_BACKOFF15(pn) CRA(0x4,pn,0x39) /* after 15 */
-#define REG_TX_UNDERRUN(pn) CRA(0x4,pn,0x3a) /* # frames dropped from underrun */
-#define REG_RX_XGMII_PROT_ERR CRA(0x4,0xa,0x3b) /* # protocol errors detected on XGMII interface */
-#define REG_RX_IPG_SHRINK(pn) CRA(0x4,pn,0x3c) /* # of IPG shrinks detected */
+enum {
+ RxInBytes = 0x00, // # Rx in octets
+ RxSymbolCarrier = 0x01, // Frames w/ symbol errors
+ RxPause = 0x02, // # pause frames received
+ RxUnsupOpcode = 0x03, // # control frames with unsupported opcode
+ RxOkBytes = 0x04, // # octets in good frames
+ RxBadBytes = 0x05, // # octets in bad frames
+ RxUnicast = 0x06, // # good unicast frames
+ RxMulticast = 0x07, // # good multicast frames
+ RxBroadcast = 0x08, // # good broadcast frames
+ Crc = 0x09, // # frames w/ bad CRC only
+ RxAlignment = 0x0a, // # frames w/ alignment err
+ RxUndersize = 0x0b, // # frames undersize
+ RxFragments = 0x0c, // # frames undersize w/ crc err
+ RxInRangeLengthError = 0x0d, // # frames with length error
+ RxOutOfRangeError = 0x0e, // # frames with illegal length field
+ RxOversize = 0x0f, // # frames oversize
+ RxJabbers = 0x10, // # frames oversize w/ crc err
+ RxSize64 = 0x11, // # frames 64 octets long
+ RxSize65To127 = 0x12, // # frames 65-127 octets
+ RxSize128To255 = 0x13, // # frames 128-255
+ RxSize256To511 = 0x14, // # frames 256-511
+ RxSize512To1023 = 0x15, // # frames 512-1023
+ RxSize1024To1518 = 0x16, // # frames 1024-1518
+ RxSize1519ToMax = 0x17, // # frames 1519-max
-#define REG_STAT_STICKY1G(pn) CRA(0x4,pn,0x3e) /* tri-speed sticky bits */
-#define REG_STAT_STICKY10G CRA(0x4,0xa,0x3e) /* 10GbE sticky bits */
-#define REG_STAT_INIT(pn) CRA(0x4,pn,0x3f) /* Clear all statistics */
+ TxOutBytes = 0x18, // # octets tx
+ TxPause = 0x19, // # pause frames sent
+ TxOkBytes = 0x1a, // # octets tx OK
+ TxUnicast = 0x1b, // # frames unicast
+ TxMulticast = 0x1c, // # frames multicast
+ TxBroadcast = 0x1d, // # frames broadcast
+ TxMultipleColl = 0x1e, // # frames tx after multiple collisions
+ TxLateColl = 0x1f, // # late collisions detected
+ TxXcoll = 0x20, // # frames lost, excessive collisions
+ TxDefer = 0x21, // # frames deferred on first tx attempt
+ TxXdefer = 0x22, // # frames excessively deferred
+ TxCsense = 0x23, // carrier sense errors at frame end
+ TxSize64 = 0x24, // # frames 64 octets long
+ TxSize65To127 = 0x25, // # frames 65-127 octets
+ TxSize128To255 = 0x26, // # frames 128-255
+ TxSize256To511 = 0x27, // # frames 256-511
+ TxSize512To1023 = 0x28, // # frames 512-1023
+ TxSize1024To1518 = 0x29, // # frames 1024-1518
+ TxSize1519ToMax = 0x2a, // # frames 1519-max
+ TxSingleColl = 0x2b, // # frames tx after single collision
+ TxBackoff2 = 0x2c, // # frames tx ok after 2 backoffs/collisions
+ TxBackoff3 = 0x2d, // after 3 backoffs/collisions
+ TxBackoff4 = 0x2e, // after 4
+ TxBackoff5 = 0x2f, // after 5
+ TxBackoff6 = 0x30, // after 6
+ TxBackoff7 = 0x31, // after 7
+ TxBackoff8 = 0x32, // after 8
+ TxBackoff9 = 0x33, // after 9
+ TxBackoff10 = 0x34, // after 10
+ TxBackoff11 = 0x35, // after 11
+ TxBackoff12 = 0x36, // after 12
+ TxBackoff13 = 0x37, // after 13
+ TxBackoff14 = 0x38, // after 14
+ TxBackoff15 = 0x39, // after 15
+ TxUnderrun = 0x3a, // # frames dropped from underrun
+ // Hole. See REG_RX_XGMII_PROT_ERR below.
+ RxIpgShrink = 0x3c, // # of IPG shrinks detected
+ // Duplicate. See REG_STAT_STICKY10G below.
+ StatSticky1G = 0x3e, // tri-speed sticky bits
+ StatInit = 0x3f // Clear all statistics
+};
+
+#define REG_RX_XGMII_PROT_ERR CRA(0x4,0xa,0x3b) /* # protocol errors detected on XGMII interface */
+#define REG_STAT_STICKY10G CRA(0x4,0xa,StatSticky1G) /* 10GbE sticky bits */
+
+#define REG_RX_OK_BYTES(pn) CRA(0x4,pn,RxOkBytes)
+#define REG_RX_BAD_BYTES(pn) CRA(0x4,pn,RxBadBytes)
+#define REG_TX_OK_BYTES(pn) CRA(0x4,pn,TxOkBytes)
/* MII-Management Block registers */
/* These are for MII-M interface 0, which is the bidirectional LVTTL one. If
diff --git a/drivers/net/chelsio/vsc8244.c b/drivers/net/chelsio/vsc8244.c
index c493e783d45..251d4859c91 100644
--- a/drivers/net/chelsio/vsc8244.c
+++ b/drivers/net/chelsio/vsc8244.c
@@ -54,7 +54,7 @@ enum {
};
#define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \
- VSC_INTR_NEG_DONE)
+ VSC_INTR_NEG_DONE)
#define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \
VSC_INTR_ENABLE)
@@ -94,19 +94,18 @@ static int vsc8244_intr_enable(struct cphy *cphy)
{
simple_mdio_write(cphy, VSC8244_INTR_ENABLE, INTR_MASK);
- /* Enable interrupts through Elmer */
+ /* Enable interrupts through Elmer */
if (t1_is_asic(cphy->adapter)) {
u32 elmer;
t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
elmer |= ELMER0_GP_BIT1;
- if (is_T2(cphy->adapter)) {
+ if (is_T2(cphy->adapter))
elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
- }
t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
}
- return 0;
+ return 0;
}
static int vsc8244_intr_disable(struct cphy *cphy)
@@ -118,19 +117,18 @@ static int vsc8244_intr_disable(struct cphy *cphy)
t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
elmer &= ~ELMER0_GP_BIT1;
- if (is_T2(cphy->adapter)) {
+ if (is_T2(cphy->adapter))
elmer &= ~(ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4);
- }
t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
}
- return 0;
+ return 0;
}
static int vsc8244_intr_clear(struct cphy *cphy)
{
u32 val;
- u32 elmer;
+ u32 elmer;
/* Clear PHY interrupts by reading the register. */
simple_mdio_read(cphy, VSC8244_INTR_ENABLE, &val);
@@ -138,13 +136,12 @@ static int vsc8244_intr_clear(struct cphy *cphy)
if (t1_is_asic(cphy->adapter)) {
t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer);
elmer |= ELMER0_GP_BIT1;
- if (is_T2(cphy->adapter)) {
+ if (is_T2(cphy->adapter))
elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
- }
t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer);
}
- return 0;
+ return 0;
}
/*
@@ -179,13 +176,13 @@ static int vsc8244_set_speed_duplex(struct cphy *phy, int speed, int duplex)
int t1_mdio_set_bits(struct cphy *phy, int mmd, int reg, unsigned int bits)
{
- int ret;
- unsigned int val;
+ int ret;
+ unsigned int val;
- ret = mdio_read(phy, mmd, reg, &val);
- if (!ret)
- ret = mdio_write(phy, mmd, reg, val | bits);
- return ret;
+ ret = mdio_read(phy, mmd, reg, &val);
+ if (!ret)
+ ret = mdio_write(phy, mmd, reg, val | bits);
+ return ret;
}
static int vsc8244_autoneg_enable(struct cphy *cphy)
@@ -235,7 +232,7 @@ static int vsc8244_advertise(struct cphy *phy, unsigned int advertise_map)
}
static int vsc8244_get_link_status(struct cphy *cphy, int *link_ok,
- int *speed, int *duplex, int *fc)
+ int *speed, int *duplex, int *fc)
{
unsigned int bmcr, status, lpa, adv;
int err, sp = -1, dplx = -1, pause = 0;
@@ -343,11 +340,13 @@ static struct cphy_ops vsc8244_ops = {
.get_link_status = vsc8244_get_link_status
};
-static struct cphy* vsc8244_phy_create(adapter_t *adapter, int phy_addr, struct mdio_ops *mdio_ops)
+static struct cphy* vsc8244_phy_create(adapter_t *adapter, int phy_addr,
+ struct mdio_ops *mdio_ops)
{
struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL);
- if (!cphy) return NULL;
+ if (!cphy)
+ return NULL;
cphy_init(cphy, adapter, phy_addr, &vsc8244_ops, mdio_ops);
diff --git a/drivers/net/cxgb3/Makefile b/drivers/net/cxgb3/Makefile
new file mode 100644
index 00000000000..34346798532
--- /dev/null
+++ b/drivers/net/cxgb3/Makefile
@@ -0,0 +1,8 @@
+#
+# Chelsio T3 driver
+#
+
+obj-$(CONFIG_CHELSIO_T3) += cxgb3.o
+
+cxgb3-objs := cxgb3_main.o ael1002.o vsc8211.o t3_hw.o mc5.o \
+ xgmac.o sge.o l2t.o cxgb3_offload.o
diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h
new file mode 100644
index 00000000000..5c97a64451c
--- /dev/null
+++ b/drivers/net/cxgb3/adapter.h
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* This file should not be included directly. Include common.h instead. */
+
+#ifndef __T3_ADAPTER_H__
+#define __T3_ADAPTER_H__
+
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/cache.h>
+#include <linux/mutex.h>
+#include "t3cdev.h"
+#include <asm/semaphore.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+typedef irqreturn_t(*intr_handler_t) (int, void *);
+
+struct vlan_group;
+
+struct port_info {
+ struct vlan_group *vlan_grp;
+ const struct port_type_info *port_type;
+ u8 port_id;
+ u8 rx_csum_offload;
+ u8 nqsets;
+ u8 first_qset;
+ struct cphy phy;
+ struct cmac mac;
+ struct link_config link_config;
+ struct net_device_stats netstats;
+ int activity;
+};
+
+enum { /* adapter flags */
+ FULL_INIT_DONE = (1 << 0),
+ USING_MSI = (1 << 1),
+ USING_MSIX = (1 << 2),
+ QUEUES_BOUND = (1 << 3),
+};
+
+struct rx_desc;
+struct rx_sw_desc;
+
+struct sge_fl { /* SGE per free-buffer list state */
+ unsigned int buf_size; /* size of each Rx buffer */
+ unsigned int credits; /* # of available Rx buffers */
+ unsigned int size; /* capacity of free list */
+ unsigned int cidx; /* consumer index */
+ unsigned int pidx; /* producer index */
+ unsigned int gen; /* free list generation */
+ struct rx_desc *desc; /* address of HW Rx descriptor ring */
+ struct rx_sw_desc *sdesc; /* address of SW Rx descriptor ring */
+ dma_addr_t phys_addr; /* physical address of HW ring start */
+ unsigned int cntxt_id; /* SGE context id for the free list */
+ unsigned long empty; /* # of times queue ran out of buffers */
+};
+
+/*
+ * Bundle size for grouping offload RX packets for delivery to the stack.
+ * Don't make this too big as we do prefetch on each packet in a bundle.
+ */
+# define RX_BUNDLE_SIZE 8
+
+struct rsp_desc;
+
+struct sge_rspq { /* state for an SGE response queue */
+ unsigned int credits; /* # of pending response credits */
+ unsigned int size; /* capacity of response queue */
+ unsigned int cidx; /* consumer index */
+ unsigned int gen; /* current generation bit */
+ unsigned int polling; /* is the queue serviced through NAPI? */
+ unsigned int holdoff_tmr; /* interrupt holdoff timer in 100ns */
+ unsigned int next_holdoff; /* holdoff time for next interrupt */
+ struct rsp_desc *desc; /* address of HW response ring */
+ dma_addr_t phys_addr; /* physical address of the ring */
+ unsigned int cntxt_id; /* SGE context id for the response q */
+ spinlock_t lock; /* guards response processing */
+ struct sk_buff *rx_head; /* offload packet receive queue head */
+ struct sk_buff *rx_tail; /* offload packet receive queue tail */
+
+ unsigned long offload_pkts;
+ unsigned long offload_bundles;
+ unsigned long eth_pkts; /* # of ethernet packets */
+ unsigned long pure_rsps; /* # of pure (non-data) responses */
+ unsigned long imm_data; /* responses with immediate data */
+ unsigned long rx_drops; /* # of packets dropped due to no mem */
+ unsigned long async_notif; /* # of asynchronous notification events */
+ unsigned long empty; /* # of times queue ran out of credits */
+ unsigned long nomem; /* # of responses deferred due to no mem */
+ unsigned long unhandled_irqs; /* # of spurious intrs */
+};
+
+struct tx_desc;
+struct tx_sw_desc;
+
+struct sge_txq { /* state for an SGE Tx queue */
+ unsigned long flags; /* HW DMA fetch status */
+ unsigned int in_use; /* # of in-use Tx descriptors */
+ unsigned int size; /* # of descriptors */
+ unsigned int processed; /* total # of descs HW has processed */
+ unsigned int cleaned; /* total # of descs SW has reclaimed */
+ unsigned int stop_thres; /* SW TX queue suspend threshold */
+ unsigned int cidx; /* consumer index */
+ unsigned int pidx; /* producer index */
+ unsigned int gen; /* current value of generation bit */
+ unsigned int unacked; /* Tx descriptors used since last COMPL */
+ struct tx_desc *desc; /* address of HW Tx descriptor ring */
+ struct tx_sw_desc *sdesc; /* address of SW Tx descriptor ring */
+ spinlock_t lock; /* guards enqueueing of new packets */
+ unsigned int token; /* WR token */
+ dma_addr_t phys_addr; /* physical address of the ring */
+ struct sk_buff_head sendq; /* List of backpressured offload packets */
+ struct tasklet_struct qresume_tsk; /* restarts the queue */
+ unsigned int cntxt_id; /* SGE context id for the Tx q */
+ unsigned long stops; /* # of times q has been stopped */
+ unsigned long restarts; /* # of queue restarts */
+};
+
+enum { /* per port SGE statistics */
+ SGE_PSTAT_TSO, /* # of TSO requests */
+ SGE_PSTAT_RX_CSUM_GOOD, /* # of successful RX csum offloads */
+ SGE_PSTAT_TX_CSUM, /* # of TX checksum offloads */
+ SGE_PSTAT_VLANEX, /* # of VLAN tag extractions */
+ SGE_PSTAT_VLANINS, /* # of VLAN tag insertions */
+
+ SGE_PSTAT_MAX /* must be last */
+};
+
+struct sge_qset { /* an SGE queue set */
+ struct sge_rspq rspq;
+ struct sge_fl fl[SGE_RXQ_PER_SET];
+ struct sge_txq txq[SGE_TXQ_PER_SET];
+ struct net_device *netdev; /* associated net device */
+ unsigned long txq_stopped; /* which Tx queues are stopped */
+ struct timer_list tx_reclaim_timer; /* reclaims TX buffers */
+ unsigned long port_stats[SGE_PSTAT_MAX];
+} ____cacheline_aligned;
+
+struct sge {
+ struct sge_qset qs[SGE_QSETS];
+ spinlock_t reg_lock; /* guards non-atomic SGE registers (eg context) */
+};
+
+struct adapter {
+ struct t3cdev tdev;
+ struct list_head adapter_list;
+ void __iomem *regs;
+ struct pci_dev *pdev;
+ unsigned long registered_device_map;
+ unsigned long open_device_map;
+ unsigned long flags;
+
+ const char *name;
+ int msg_enable;
+ unsigned int mmio_len;
+
+ struct adapter_params params;
+ unsigned int slow_intr_mask;
+ unsigned long irq_stats[IRQ_NUM_STATS];
+
+ struct {
+ unsigned short vec;
+ char desc[22];
+ } msix_info[SGE_QSETS + 1];
+
+ /* T3 modules */
+ struct sge sge;
+ struct mc7 pmrx;
+ struct mc7 pmtx;
+ struct mc7 cm;
+ struct mc5 mc5;
+
+ struct net_device *port[MAX_NPORTS];
+ unsigned int check_task_cnt;
+ struct delayed_work adap_check_task;
+ struct work_struct ext_intr_handler_task;
+
+ /*
+ * Dummy netdevices are needed when using multiple receive queues with
+ * NAPI as each netdevice can service only one queue.
+ */
+ struct net_device *dummy_netdev[SGE_QSETS - 1];
+
+ struct dentry *debugfs_root;
+
+ struct mutex mdio_lock;
+ spinlock_t stats_lock;
+ spinlock_t work_lock;
+};
+
+static inline u32 t3_read_reg(struct adapter *adapter, u32 reg_addr)
+{
+ u32 val = readl(adapter->regs + reg_addr);
+
+ CH_DBG(adapter, MMIO, "read register 0x%x value 0x%x\n", reg_addr, val);
+ return val;
+}
+
+static inline void t3_write_reg(struct adapter *adapter, u32 reg_addr, u32 val)
+{
+ CH_DBG(adapter, MMIO, "setting register 0x%x to 0x%x\n", reg_addr, val);
+ writel(val, adapter->regs + reg_addr);
+}
+
+static inline struct port_info *adap2pinfo(struct adapter *adap, int idx)
+{
+ return netdev_priv(adap->port[idx]);
+}
+
+/*
+ * We use the spare atalk_ptr to map a net device to its SGE queue set.
+ * This is a macro so it can be used as l-value.
+ */
+#define dev2qset(netdev) ((netdev)->atalk_ptr)
+
+#define OFFLOAD_DEVMAP_BIT 15
+
+#define tdev2adap(d) container_of(d, struct adapter, tdev)
+
+static inline int offload_running(struct adapter *adapter)
+{
+ return test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map);
+}
+
+int t3_offload_tx(struct t3cdev *tdev, struct sk_buff *skb);
+
+void t3_os_ext_intr_handler(struct adapter *adapter);
+void t3_os_link_changed(struct adapter *adapter, int port_id, int link_status,
+ int speed, int duplex, int fc);
+
+void t3_sge_start(struct adapter *adap);
+void t3_sge_stop(struct adapter *adap);
+void t3_free_sge_resources(struct adapter *adap);
+void t3_sge_err_intr_handler(struct adapter *adapter);
+intr_handler_t t3_intr_handler(struct adapter *adap, int polling);
+int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev);
+int t3_mgmt_tx(struct adapter *adap, struct sk_buff *skb);
+void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p);
+int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
+ int irq_vec_idx, const struct qset_params *p,
+ int ntxq, struct net_device *netdev);
+int t3_get_desc(const struct sge_qset *qs, unsigned int qnum, unsigned int idx,
+ unsigned char *data);
+irqreturn_t t3_sge_intr_msix(int irq, void *cookie);
+
+#endif /* __T3_ADAPTER_H__ */
diff --git a/drivers/net/cxgb3/ael1002.c b/drivers/net/cxgb3/ael1002.c
new file mode 100644
index 00000000000..73a41e6a5bf
--- /dev/null
+++ b/drivers/net/cxgb3/ael1002.c
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "common.h"
+#include "regs.h"
+
+enum {
+ AEL100X_TX_DISABLE = 9,
+ AEL100X_TX_CONFIG1 = 0xc002,
+ AEL1002_PWR_DOWN_HI = 0xc011,
+ AEL1002_PWR_DOWN_LO = 0xc012,
+ AEL1002_XFI_EQL = 0xc015,
+ AEL1002_LB_EN = 0xc017,
+
+ LASI_CTRL = 0x9002,
+ LASI_STAT = 0x9005
+};
+
+static void ael100x_txon(struct cphy *phy)
+{
+ int tx_on_gpio = phy->addr == 0 ? F_GPIO7_OUT_VAL : F_GPIO2_OUT_VAL;
+
+ msleep(100);
+ t3_set_reg_field(phy->adapter, A_T3DBG_GPIO_EN, 0, tx_on_gpio);
+ msleep(30);
+}
+
+static int ael1002_power_down(struct cphy *phy, int enable)
+{
+ int err;
+
+ err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_DISABLE, !!enable);
+ if (!err)
+ err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
+ BMCR_PDOWN, enable ? BMCR_PDOWN : 0);
+ return err;
+}
+
+static int ael1002_reset(struct cphy *phy, int wait)
+{
+ int err;
+
+ if ((err = ael1002_power_down(phy, 0)) ||
+ (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_CONFIG1, 1)) ||
+ (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_HI, 0)) ||
+ (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_LO, 0)) ||
+ (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_XFI_EQL, 0x18)) ||
+ (err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, AEL1002_LB_EN,
+ 0, 1 << 5)))
+ return err;
+ return 0;
+}
+
+static int ael1002_intr_noop(struct cphy *phy)
+{
+ return 0;
+}
+
+static int ael100x_get_link_status(struct cphy *phy, int *link_ok,
+ int *speed, int *duplex, int *fc)
+{
+ if (link_ok) {
+ unsigned int status;
+ int err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &status);
+
+ /*
+ * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it
+ * once more to get the current link state.
+ */
+ if (!err && !(status & BMSR_LSTATUS))
+ err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR,
+ &status);
+ if (err)
+ return err;
+ *link_ok = !!(status & BMSR_LSTATUS);
+ }
+ if (speed)
+ *speed = SPEED_10000;
+ if (duplex)
+ *duplex = DUPLEX_FULL;
+ return 0;
+}
+
+static struct cphy_ops ael1002_ops = {
+ .reset = ael1002_reset,
+ .intr_enable = ael1002_intr_noop,
+ .intr_disable = ael1002_intr_noop,
+ .intr_clear = ael1002_intr_noop,
+ .intr_handler = ael1002_intr_noop,
+ .get_link_status = ael100x_get_link_status,
+ .power_down = ael1002_power_down,
+};
+
+void t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter,
+ int phy_addr, const struct mdio_ops *mdio_ops)
+{
+ cphy_init(phy, adapter, phy_addr, &ael1002_ops, mdio_ops);
+ ael100x_txon(phy);
+}
+
+static int ael1006_reset(struct cphy *phy, int wait)
+{
+ return t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait);
+}
+
+static int ael1006_intr_enable(struct cphy *phy)
+{
+ return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 1);
+}
+
+static int ael1006_intr_disable(struct cphy *phy)
+{
+ return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 0);
+}
+
+static int ael1006_intr_clear(struct cphy *phy)
+{
+ u32 val;
+
+ return mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &val);
+}
+
+static int ael1006_intr_handler(struct cphy *phy)
+{
+ unsigned int status;
+ int err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &status);
+
+ if (err)
+ return err;
+ return (status & 1) ? cphy_cause_link_change : 0;
+}
+
+static int ael1006_power_down(struct cphy *phy, int enable)
+{
+ return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
+ BMCR_PDOWN, enable ? BMCR_PDOWN : 0);
+}
+
+static struct cphy_ops ael1006_ops = {
+ .reset = ael1006_reset,
+ .intr_enable = ael1006_intr_enable,
+ .intr_disable = ael1006_intr_disable,
+ .intr_clear = ael1006_intr_clear,
+ .intr_handler = ael1006_intr_handler,
+ .get_link_status = ael100x_get_link_status,
+ .power_down = ael1006_power_down,
+};
+
+void t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter,
+ int phy_addr, const struct mdio_ops *mdio_ops)
+{
+ cphy_init(phy, adapter, phy_addr, &ael1006_ops, mdio_ops);
+ ael100x_txon(phy);
+}
+
+static struct cphy_ops qt2045_ops = {
+ .reset = ael1006_reset,
+ .intr_enable = ael1006_intr_enable,
+ .intr_disable = ael1006_intr_disable,
+ .intr_clear = ael1006_intr_clear,
+ .intr_handler = ael1006_intr_handler,
+ .get_link_status = ael100x_get_link_status,
+ .power_down = ael1006_power_down,
+};
+
+void t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter,
+ int phy_addr, const struct mdio_ops *mdio_ops)
+{
+ unsigned int stat;
+
+ cphy_init(phy, adapter, phy_addr, &qt2045_ops, mdio_ops);
+
+ /*
+ * Some cards where the PHY is supposed to be at address 0 actually
+ * have it at 1.
+ */
+ if (!phy_addr && !mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &stat) &&
+ stat == 0xffff)
+ phy->addr = 1;
+}
+
+static int xaui_direct_reset(struct cphy *phy, int wait)
+{
+ return 0;
+}
+
+static int xaui_direct_get_link_status(struct cphy *phy, int *link_ok,
+ int *speed, int *duplex, int *fc)
+{
+ if (link_ok) {
+ unsigned int status;
+
+ status = t3_read_reg(phy->adapter,
+ XGM_REG(A_XGM_SERDES_STAT0, phy->addr));
+ *link_ok = !(status & F_LOWSIG0);
+ }
+ if (speed)
+ *speed = SPEED_10000;
+ if (duplex)
+ *duplex = DUPLEX_FULL;
+ return 0;
+}
+
+static int xaui_direct_power_down(struct cphy *phy, int enable)
+{
+ return 0;
+}
+
+static struct cphy_ops xaui_direct_ops = {
+ .reset = xaui_direct_reset,
+ .intr_enable = ael1002_intr_noop,
+ .intr_disable = ael1002_intr_noop,
+ .intr_clear = ael1002_intr_noop,
+ .intr_handler = ael1002_intr_noop,
+ .get_link_status = xaui_direct_get_link_status,
+ .power_down = xaui_direct_power_down,
+};
+
+void t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter,
+ int phy_addr, const struct mdio_ops *mdio_ops)
+{
+ cphy_init(phy, adapter, 1, &xaui_direct_ops, mdio_ops);
+}
diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h
new file mode 100644
index 00000000000..e23deeb7d06
--- /dev/null
+++ b/drivers/net/cxgb3/common.h
@@ -0,0 +1,729 @@
+/*
+ * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef __CHELSIO_COMMON_H
+#define __CHELSIO_COMMON_H
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include "version.h"
+
+#define CH_ERR(adap, fmt, ...) dev_err(&adap->pdev->dev, fmt, ## __VA_ARGS__)
+#define CH_WARN(adap, fmt, ...) dev_warn(&adap->pdev->dev, fmt, ## __VA_ARGS__)
+#define CH_ALERT(adap, fmt, ...) \
+ dev_printk(KERN_ALERT, &adap->pdev->dev, fmt, ## __VA_ARGS__)
+
+/*
+ * More powerful macro that selectively prints messages based on msg_enable.
+ * For info and debugging messages.
+ */
+#define CH_MSG(adapter, level, category, fmt, ...) do { \
+ if ((adapter)->msg_enable & NETIF_MSG_##category) \
+ dev_printk(KERN_##level, &adapter->pdev->dev, fmt, \
+ ## __VA_ARGS__); \
+} while (0)
+
+#ifdef DEBUG
+# define CH_DBG(adapter, category, fmt, ...) \
+ CH_MSG(adapter, DEBUG, category, fmt, ## __VA_ARGS__)
+#else
+# define CH_DBG(adapter, category, fmt, ...)
+#endif
+
+/* Additional NETIF_MSG_* categories */
+#define NETIF_MSG_MMIO 0x8000000
+
+struct t3_rx_mode {
+ struct net_device *dev;
+ struct dev_mc_list *mclist;
+ unsigned int idx;
+};
+
+static inline void init_rx_mode(struct t3_rx_mode *p, struct net_device *dev,
+ struct dev_mc_list *mclist)
+{
+ p->dev = dev;
+ p->mclist = mclist;
+ p->idx = 0;
+}
+
+static inline u8 *t3_get_next_mcaddr(struct t3_rx_mode *rm)
+{
+ u8 *addr = NULL;
+
+ if (rm->mclist && rm->idx < rm->dev->mc_count) {
+ addr = rm->mclist->dmi_addr;
+ rm->mclist = rm->mclist->next;
+ rm->idx++;
+ }
+ return addr;
+}
+
+enum {
+ MAX_NPORTS = 2, /* max # of ports */
+ MAX_FRAME_SIZE = 10240, /* max MAC frame size, including header + FCS */
+ EEPROMSIZE = 8192, /* Serial EEPROM size */
+ RSS_TABLE_SIZE = 64, /* size of RSS lookup and mapping tables */
+ TCB_SIZE = 128, /* TCB size */
+ NMTUS = 16, /* size of MTU table */
+ NCCTRL_WIN = 32, /* # of congestion control windows */
+};
+
+#define MAX_RX_COALESCING_LEN 16224U
+
+enum {
+ PAUSE_RX = 1 << 0,
+ PAUSE_TX = 1 << 1,
+ PAUSE_AUTONEG = 1 << 2
+};
+
+enum {
+ SUPPORTED_OFFLOAD = 1 << 24,
+ SUPPORTED_IRQ = 1 << 25
+};
+
+enum { /* adapter interrupt-maintained statistics */
+ STAT_ULP_CH0_PBL_OOB,
+ STAT_ULP_CH1_PBL_OOB,
+ STAT_PCI_CORR_ECC,
+
+ IRQ_NUM_STATS /* keep last */
+};
+
+enum {
+ SGE_QSETS = 8, /* # of SGE Tx/Rx/RspQ sets */
+ SGE_RXQ_PER_SET = 2, /* # of Rx queues per set */
+ SGE_TXQ_PER_SET = 3 /* # of Tx queues per set */
+};
+
+enum sge_context_type { /* SGE egress context types */
+ SGE_CNTXT_RDMA = 0,
+ SGE_CNTXT_ETH = 2,
+ SGE_CNTXT_OFLD = 4,
+ SGE_CNTXT_CTRL = 5
+};
+
+enum {
+ AN_PKT_SIZE = 32, /* async notification packet size */
+ IMMED_PKT_SIZE = 48 /* packet size for immediate data */
+};
+
+struct sg_ent { /* SGE scatter/gather entry */
+ u32 len[2];
+ u64 addr[2];
+};
+
+#ifndef SGE_NUM_GENBITS
+/* Must be 1 or 2 */
+# define SGE_NUM_GENBITS 2
+#endif
+
+#define TX_DESC_FLITS 16U
+#define WR_FLITS (TX_DESC_FLITS + 1 - SGE_NUM_GENBITS)
+
+struct cphy;
+struct adapter;
+
+struct mdio_ops {
+ int (*read)(struct adapter *adapter, int phy_addr, int mmd_addr,
+ int reg_addr, unsigned int *val);
+ int (*write)(struct adapter *adapter, int phy_addr, int mmd_addr,
+ int reg_addr, unsigned int val);
+};
+
+struct adapter_info {
+ unsigned char nports; /* # of ports */
+ unsigned char phy_base_addr; /* MDIO PHY base address */
+ unsigned char mdien;
+ unsigned char mdiinv;
+ unsigned int gpio_out; /* GPIO output settings */
+ unsigned int gpio_intr; /* GPIO IRQ enable mask */
+ unsigned long caps; /* adapter capabilities */
+ const struct mdio_ops *mdio_ops; /* MDIO operations */
+ const char *desc; /* product description */
+};
+
+struct port_type_info {
+ void (*phy_prep)(struct cphy *phy, struct adapter *adapter,
+ int phy_addr, const struct mdio_ops *ops);
+ unsigned int caps;
+ const char *desc;
+};
+
+struct mc5_stats {
+ unsigned long parity_err;
+ unsigned long active_rgn_full;
+ unsigned long nfa_srch_err;
+ unsigned long unknown_cmd;
+ unsigned long reqq_parity_err;
+ unsigned long dispq_parity_err;
+ unsigned long del_act_empty;
+};
+
+struct mc7_stats {
+ unsigned long corr_err;
+ unsigned long uncorr_err;
+ unsigned long parity_err;
+ unsigned long addr_err;
+};
+
+struct mac_stats {
+ u64 tx_octets; /* total # of octets in good frames */
+ u64 tx_octets_bad; /* total # of octets in error frames */
+ u64 tx_frames; /* all good frames */
+ u64 tx_mcast_frames; /* good multicast frames */
+ u64 tx_bcast_frames; /* good broadcast frames */
+ u64 tx_pause; /* # of transmitted pause frames */
+ u64 tx_deferred; /* frames with deferred transmissions */
+ u64 tx_late_collisions; /* # of late collisions */
+ u64 tx_total_collisions; /* # of total collisions */
+ u64 tx_excess_collisions; /* frame errors from excessive collissions */
+ u64 tx_underrun; /* # of Tx FIFO underruns */
+ u64 tx_len_errs; /* # of Tx length errors */
+ u64 tx_mac_internal_errs; /* # of internal MAC errors on Tx */
+ u64 tx_excess_deferral; /* # of frames with excessive deferral */
+ u64 tx_fcs_errs; /* # of frames with bad FCS */
+
+ u64 tx_frames_64; /* # of Tx frames in a particular range */
+ u64 tx_frames_65_127;
+ u64 tx_frames_128_255;
+ u64 tx_frames_256_511;
+ u64 tx_frames_512_1023;
+ u64 tx_frames_1024_1518;
+ u64 tx_frames_1519_max;
+
+ u64 rx_octets; /* total # of octets in good frames */
+ u64 rx_octets_bad; /* total # of octets in error frames */
+ u64 rx_frames; /* all good frames */
+ u64 rx_mcast_frames; /* good multicast frames */
+ u64 rx_bcast_frames; /* good broadcast frames */
+ u64 rx_pause; /* # of received pause frames */
+ u64 rx_fcs_errs; /* # of received frames with bad FCS */
+ u64 rx_align_errs; /* alignment errors */
+ u64 rx_symbol_errs; /* symbol errors */
+ u64 rx_data_errs; /* data errors */
+ u64 rx_sequence_errs; /* sequence errors */
+ u64 rx_runt; /* # of runt frames */
+ u64 rx_jabber; /* # of jabber frames */
+ u64 rx_short; /* # of short frames */
+ u64 rx_too_long; /* # of oversized frames */
+ u64 rx_mac_internal_errs; /* # of internal MAC errors on Rx */
+
+ u64 rx_frames_64; /* # of Rx frames in a particular range */
+ u64 rx_frames_65_127;
+ u64 rx_frames_128_255;
+ u64 rx_frames_256_511;
+ u64 rx_frames_512_1023;
+ u64 rx_frames_1024_1518;
+ u64 rx_frames_1519_max;
+
+ u64 rx_cong_drops; /* # of Rx drops due to SGE congestion */
+
+ unsigned long tx_fifo_parity_err;
+ unsigned long rx_fifo_parity_err;
+ unsigned long tx_fifo_urun;
+ unsigned long rx_fifo_ovfl;
+ unsigned long serdes_signal_loss;
+ unsigned long xaui_pcs_ctc_err;
+ unsigned long xaui_pcs_align_change;
+};
+
+struct tp_mib_stats {
+ u32 ipInReceive_hi;
+ u32 ipInReceive_lo;
+ u32 ipInHdrErrors_hi;
+ u32 ipInHdrErrors_lo;
+ u32 ipInAddrErrors_hi;
+ u32 ipInAddrErrors_lo;
+ u32 ipInUnknownProtos_hi;
+ u32 ipInUnknownProtos_lo;
+ u32 ipInDiscards_hi;
+ u32 ipInDiscards_lo;
+ u32 ipInDelivers_hi;
+ u32 ipInDelivers_lo;
+ u32 ipOutRequests_hi;
+ u32 ipOutRequests_lo;
+ u32 ipOutDiscards_hi;
+ u32 ipOutDiscards_lo;
+ u32 ipOutNoRoutes_hi;
+ u32 ipOutNoRoutes_lo;
+ u32 ipReasmTimeout;
+ u32 ipReasmReqds;
+ u32 ipReasmOKs;
+ u32 ipReasmFails;
+
+ u32 reserved[8];
+
+ u32 tcpActiveOpens;
+ u32 tcpPassiveOpens;
+ u32 tcpAttemptFails;
+ u32 tcpEstabResets;
+ u32 tcpOutRsts;
+ u32 tcpCurrEstab;
+ u32 tcpInSegs_hi;
+ u32 tcpInSegs_lo;
+ u32 tcpOutSegs_hi;
+ u32 tcpOutSegs_lo;
+ u32 tcpRetransSeg_hi;
+ u32 tcpRetransSeg_lo;
+ u32 tcpInErrs_hi;
+ u32 tcpInErrs_lo;
+ u32 tcpRtoMin;
+ u32 tcpRtoMax;
+};
+
+struct tp_params {
+ unsigned int nchan; /* # of channels */
+ unsigned int pmrx_size; /* total PMRX capacity */
+ unsigned int pmtx_size; /* total PMTX capacity */
+ unsigned int cm_size; /* total CM capacity */
+ unsigned int chan_rx_size; /* per channel Rx size */
+ unsigned int chan_tx_size; /* per channel Tx size */
+ unsigned int rx_pg_size; /* Rx page size */
+ unsigned int tx_pg_size; /* Tx page size */
+ unsigned int rx_num_pgs; /* # of Rx pages */
+ unsigned int tx_num_pgs; /* # of Tx pages */
+ unsigned int ntimer_qs; /* # of timer queues */
+};
+
+struct qset_params { /* SGE queue set parameters */
+ unsigned int polling; /* polling/interrupt service for rspq */
+ unsigned int coalesce_usecs; /* irq coalescing timer */
+ unsigned int rspq_size; /* # of entries in response queue */
+ unsigned int fl_size; /* # of entries in regular free list */
+ unsigned int jumbo_size; /* # of entries in jumbo free list */
+ unsigned int txq_size[SGE_TXQ_PER_SET]; /* Tx queue sizes */
+ unsigned int cong_thres; /* FL congestion threshold */
+};
+
+struct sge_params {
+ unsigned int max_pkt_size; /* max offload pkt size */
+ struct qset_params qset[SGE_QSETS];
+};
+
+struct mc5_params {
+ unsigned int mode; /* selects MC5 width */
+ unsigned int nservers; /* size of server region */
+ unsigned int nfilters; /* size of filter region */
+ unsigned int nroutes; /* size of routing region */
+};
+
+/* Default MC5 region sizes */
+enum {
+ DEFAULT_NSERVERS = 512,
+ DEFAULT_NFILTERS = 128
+};
+
+/* MC5 modes, these must be non-0 */
+enum {
+ MC5_MODE_144_BIT = 1,
+ MC5_MODE_72_BIT = 2
+};
+
+struct vpd_params {
+ unsigned int cclk;
+ unsigned int mclk;
+ unsigned int uclk;
+ unsigned int mdc;
+ unsigned int mem_timing;
+ u8 eth_base[6];
+ u8 port_type[MAX_NPORTS];
+ unsigned short xauicfg[2];
+};
+
+struct pci_params {
+ unsigned int vpd_cap_addr;
+ unsigned int pcie_cap_addr;
+ unsigned short speed;
+ unsigned char width;
+ unsigned char variant;
+};
+
+enum {
+ PCI_VARIANT_PCI,
+ PCI_VARIANT_PCIX_MODE1_PARITY,
+ PCI_VARIANT_PCIX_MODE1_ECC,
+ PCI_VARIANT_PCIX_266_MODE2,
+ PCI_VARIANT_PCIE
+};
+
+struct adapter_params {
+ struct sge_params sge;
+ struct mc5_params mc5;
+ struct tp_params tp;
+ struct vpd_params vpd;
+ struct pci_params pci;
+
+ const struct adapter_info *info;
+
+ unsigned short mtus[NMTUS];
+ unsigned short a_wnd[NCCTRL_WIN];
+ unsigned short b_wnd[NCCTRL_WIN];
+
+ unsigned int nports; /* # of ethernet ports */
+ unsigned int stats_update_period; /* MAC stats accumulation period */
+ unsigned int linkpoll_period; /* link poll period in 0.1s */
+ unsigned int rev; /* chip revision */
+};
+
+struct trace_params {
+ u32 sip;
+ u32 sip_mask;
+ u32 dip;
+ u32 dip_mask;
+ u16 sport;
+ u16 sport_mask;
+ u16 dport;
+ u16 dport_mask;
+ u32 vlan:12;
+ u32 vlan_mask:12;
+ u32 intf:4;
+ u32 intf_mask:4;
+ u8 proto;
+ u8 proto_mask;
+};
+
+struct link_config {
+ unsigned int supported; /* link capabilities */
+ unsigned int advertising; /* advertised capabilities */
+ unsigned short requested_speed; /* speed user has requested */
+ unsigned short speed; /* actual link speed */
+ unsigned char requested_duplex; /* duplex user has requested */
+ unsigned char duplex; /* actual link duplex */
+ unsigned char requested_fc; /* flow control user has requested */
+ unsigned char fc; /* actual link flow control */
+ unsigned char autoneg; /* autonegotiating? */
+ unsigned int link_ok; /* link up? */
+};
+
+#define SPEED_INVALID 0xffff
+#define DUPLEX_INVALID 0xff
+
+struct mc5 {
+ struct adapter *adapter;
+ unsigned int tcam_size;
+ unsigned char part_type;
+ unsigned char parity_enabled;
+ unsigned char mode;
+ struct mc5_stats stats;
+};
+
+static inline unsigned int t3_mc5_size(const struct mc5 *p)
+{
+ return p->tcam_size;
+}
+
+struct mc7 {
+ struct adapter *adapter; /* backpointer to adapter */
+ unsigned int size; /* memory size in bytes */
+ unsigned int width; /* MC7 interface width */
+ unsigned int offset; /* register address offset for MC7 instance */
+ const char *name; /* name of MC7 instance */
+ struct mc7_stats stats; /* MC7 statistics */
+};
+
+static inline unsigned int t3_mc7_size(const struct mc7 *p)
+{
+ return p->size;
+}
+
+struct cmac {
+ struct adapter *adapter;
+ unsigned int offset;
+ unsigned int nucast; /* # of address filters for unicast MACs */
+ struct mac_stats stats;
+};
+
+enum {
+ MAC_DIRECTION_RX = 1,
+ MAC_DIRECTION_TX = 2,
+ MAC_RXFIFO_SIZE = 32768
+};
+
+/* IEEE 802.3ae specified MDIO devices */
+enum {
+ MDIO_DEV_PMA_PMD = 1,
+ MDIO_DEV_WIS = 2,
+ MDIO_DEV_PCS = 3,
+ MDIO_DEV_XGXS = 4
+};
+
+/* PHY loopback direction */
+enum {
+ PHY_LOOPBACK_TX = 1,
+ PHY_LOOPBACK_RX = 2
+};
+
+/* PHY interrupt types */
+enum {
+ cphy_cause_link_change = 1,
+ cphy_cause_fifo_error = 2
+};
+
+/* PHY operations */
+struct cphy_ops {
+ void (*destroy)(struct cphy *phy);
+ int (*reset)(struct cphy *phy, int wait);
+
+ int (*intr_enable)(struct cphy *phy);
+ int (*intr_disable)(struct cphy *phy);
+ int (*intr_clear)(struct cphy *phy);
+ int (*intr_handler)(struct cphy *phy);
+
+ int (*autoneg_enable)(struct cphy *phy);
+ int (*autoneg_restart)(struct cphy *phy);
+
+ int (*advertise)(struct cphy *phy, unsigned int advertise_map);
+ int (*set_loopback)(struct cphy *phy, int mmd, int dir, int enable);
+ int (*set_speed_duplex)(struct cphy *phy, int speed, int duplex);
+ int (*get_link_status)(struct cphy *phy, int *link_ok, int *speed,
+ int *duplex, int *fc);
+ int (*power_down)(struct cphy *phy, int enable);
+};
+
+/* A PHY instance */
+struct cphy {
+ int addr; /* PHY address */
+ struct adapter *adapter; /* associated adapter */
+ unsigned long fifo_errors; /* FIFO over/under-flows */
+ const struct cphy_ops *ops; /* PHY operations */
+ int (*mdio_read)(struct adapter *adapter, int phy_addr, int mmd_addr,
+ int reg_addr, unsigned int *val);
+ int (*mdio_write)(struct adapter *adapter, int phy_addr, int mmd_addr,
+ int reg_addr, unsigned int val);
+};
+
+/* Convenience MDIO read/write wrappers */
+static inline int mdio_read(struct cphy *phy, int mmd, int reg,
+ unsigned int *valp)
+{
+ return phy->mdio_read(phy->adapter, phy->addr, mmd, reg, valp);
+}
+
+static inline int mdio_write(struct cphy *phy, int mmd, int reg,
+ unsigned int val)
+{
+ return phy->mdio_write(phy->adapter, phy->addr, mmd, reg, val);
+}
+
+/* Convenience initializer */
+static inline void cphy_init(struct cphy *phy, struct adapter *adapter,
+ int phy_addr, struct cphy_ops *phy_ops,
+ const struct mdio_ops *mdio_ops)
+{
+ phy->adapter = adapter;
+ phy->addr = phy_addr;
+ phy->ops = phy_ops;
+ if (mdio_ops) {
+ phy->mdio_read = mdio_ops->read;
+ phy->mdio_write = mdio_ops->write;
+ }
+}
+
+/* Accumulate MAC statistics every 180 seconds. For 1G we multiply by 10. */
+#define MAC_STATS_ACCUM_SECS 180
+
+#define XGM_REG(reg_addr, idx) \
+ ((reg_addr) + (idx) * (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR))
+
+struct addr_val_pair {
+ unsigned int reg_addr;
+ unsigned int val;
+};
+
+#include "adapter.h"
+
+#ifndef PCI_VENDOR_ID_CHELSIO
+# define PCI_VENDOR_ID_CHELSIO 0x1425
+#endif
+
+#define for_each_port(adapter, iter) \
+ for (iter = 0; iter < (adapter)->params.nports; ++iter)
+
+#define adapter_info(adap) ((adap)->params.info)
+
+static inline int uses_xaui(const struct adapter *adap)
+{
+ return adapter_info(adap)->caps & SUPPORTED_AUI;
+}
+
+static inline int is_10G(const struct adapter *adap)
+{
+ return adapter_info(adap)->caps & SUPPORTED_10000baseT_Full;
+}
+
+static inline int is_offload(const struct adapter *adap)
+{
+ return adapter_info(adap)->caps & SUPPORTED_OFFLOAD;
+}
+
+static inline unsigned int core_ticks_per_usec(const struct adapter *adap)
+{
+ return adap->params.vpd.cclk / 1000;
+}
+
+static inline unsigned int is_pcie(const struct adapter *adap)
+{
+ return adap->params.pci.variant == PCI_VARIANT_PCIE;
+}
+
+void t3_set_reg_field(struct adapter *adap, unsigned int addr, u32 mask,
+ u32 val);
+void t3_write_regs(struct adapter *adapter, const struct addr_val_pair *p,
+ int n, unsigned int offset);
+int t3_wait_op_done_val(struct adapter *adapter, int reg, u32 mask,
+ int polarity, int attempts, int delay, u32 *valp);
+static inline int t3_wait_op_done(struct adapter *adapter, int reg, u32 mask,
+ int polarity, int attempts, int delay)
+{
+ return t3_wait_op_done_val(adapter, reg, mask, polarity, attempts,
+ delay, NULL);
+}
+int t3_mdio_change_bits(struct cphy *phy, int mmd, int reg, unsigned int clear,
+ unsigned int set);
+int t3_phy_reset(struct cphy *phy, int mmd, int wait);
+int t3_phy_advertise(struct cphy *phy, unsigned int advert);
+int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex);
+
+void t3_intr_enable(struct adapter *adapter);
+void t3_intr_disable(struct adapter *adapter);
+void t3_intr_clear(struct adapter *adapter);
+void t3_port_intr_enable(struct adapter *adapter, int idx);
+void t3_port_intr_disable(struct adapter *adapter, int idx);
+void t3_port_intr_clear(struct adapter *adapter, int idx);
+int t3_slow_intr_handler(struct adapter *adapter);
+int t3_phy_intr_handler(struct adapter *adapter);
+
+void t3_link_changed(struct adapter *adapter, int port_id);
+int t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc);
+const struct adapter_info *t3_get_adapter_info(unsigned int board_id);
+int t3_seeprom_read(struct adapter *adapter, u32 addr, u32 *data);
+int t3_seeprom_write(struct adapter *adapter, u32 addr, u32 data);
+int t3_seeprom_wp(struct adapter *adapter, int enable);
+int t3_read_flash(struct adapter *adapter, unsigned int addr,
+ unsigned int nwords, u32 *data, int byte_oriented);
+int t3_load_fw(struct adapter *adapter, const u8 * fw_data, unsigned int size);
+int t3_get_fw_version(struct adapter *adapter, u32 *vers);
+int t3_check_fw_version(struct adapter *adapter);
+int t3_init_hw(struct adapter *adapter, u32 fw_params);
+void mac_prep(struct cmac *mac, struct adapter *adapter, int index);
+void early_hw_init(struct adapter *adapter, const struct adapter_info *ai);
+int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai,
+ int reset);
+void t3_led_ready(struct adapter *adapter);
+void t3_fatal_err(struct adapter *adapter);
+void t3_set_vlan_accel(struct adapter *adapter, unsigned int ports, int on);
+void t3_config_rss(struct adapter *adapter, unsigned int rss_config,
+ const u8 * cpus, const u16 *rspq);
+int t3_read_rss(struct adapter *adapter, u8 * lkup, u16 *map);
+int t3_mps_set_active_ports(struct adapter *adap, unsigned int port_mask);
+int t3_cim_ctl_blk_read(struct adapter *adap, unsigned int addr,
+ unsigned int n, unsigned int *valp);
+int t3_mc7_bd_read(struct mc7 *mc7, unsigned int start, unsigned int n,
+ u64 *buf);
+
+int t3_mac_reset(struct cmac *mac);
+void t3b_pcs_reset(struct cmac *mac);
+int t3_mac_enable(struct cmac *mac, int which);
+int t3_mac_disable(struct cmac *mac, int which);
+int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu);
+int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm);
+int t3_mac_set_address(struct cmac *mac, unsigned int idx, u8 addr[6]);
+int t3_mac_set_num_ucast(struct cmac *mac, int n);
+const struct mac_stats *t3_mac_update_stats(struct cmac *mac);
+int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc);
+
+void t3_mc5_prep(struct adapter *adapter, struct mc5 *mc5, int mode);
+int t3_mc5_init(struct mc5 *mc5, unsigned int nservers, unsigned int nfilters,
+ unsigned int nroutes);
+void t3_mc5_intr_handler(struct mc5 *mc5);
+int t3_read_mc5_range(const struct mc5 *mc5, unsigned int start, unsigned int n,
+ u32 *buf);
+
+int t3_tp_set_coalescing_size(struct adapter *adap, unsigned int size, int psh);
+void t3_tp_set_max_rxsize(struct adapter *adap, unsigned int size);
+void t3_tp_set_offload_mode(struct adapter *adap, int enable);
+void t3_tp_get_mib_stats(struct adapter *adap, struct tp_mib_stats *tps);
+void t3_load_mtus(struct adapter *adap, unsigned short mtus[NMTUS],
+ unsigned short alpha[NCCTRL_WIN],
+ unsigned short beta[NCCTRL_WIN], unsigned short mtu_cap);
+void t3_read_hw_mtus(struct adapter *adap, unsigned short mtus[NMTUS]);
+void t3_get_cong_cntl_tab(struct adapter *adap,
+ unsigned short incr[NMTUS][NCCTRL_WIN]);
+void t3_config_trace_filter(struct adapter *adapter,
+ const struct trace_params *tp, int filter_index,
+ int invert, int enable);
+int t3_config_sched(struct adapter *adap, unsigned int kbps, int sched);
+
+void t3_sge_prep(struct adapter *adap, struct sge_params *p);
+void t3_sge_init(struct adapter *adap, struct sge_params *p);
+int t3_sge_init_ecntxt(struct adapter *adapter, unsigned int id, int gts_enable,
+ enum sge_context_type type, int respq, u64 base_addr,
+ unsigned int size, unsigned int token, int gen,
+ unsigned int cidx);
+int t3_sge_init_flcntxt(struct adapter *adapter, unsigned int id,
+ int gts_enable, u64 base_addr, unsigned int size,
+ unsigned int esize, unsigned int cong_thres, int gen,
+ unsigned int cidx);
+int t3_sge_init_rspcntxt(struct adapter *adapter, unsigned int id,
+ int irq_vec_idx, u64 base_addr, unsigned int size,
+ unsigned int fl_thres, int gen, unsigned int cidx);
+int t3_sge_init_cqcntxt(struct adapter *adapter, unsigned int id, u64 base_addr,
+ unsigned int size, int rspq, int ovfl_mode,
+ unsigned int credits, unsigned int credit_thres);
+int t3_sge_enable_ecntxt(struct adapter *adapter, unsigned int id, int enable);
+int t3_sge_disable_fl(struct adapter *adapter, unsigned int id);
+int t3_sge_disable_rspcntxt(struct adapter *adapter, unsigned int id);
+int t3_sge_disable_cqcntxt(struct adapter *adapter, unsigned int id);
+int t3_sge_read_ecntxt(struct adapter *adapter, unsigned int id, u32 data[4]);
+int t3_sge_read_fl(struct adapter *adapter, unsigned int id, u32 data[4]);
+int t3_sge_read_cq(struct adapter *adapter, unsigned int id, u32 data[4]);
+int t3_sge_read_rspq(struct adapter *adapter, unsigned int id, u32 data[4]);
+int t3_sge_cqcntxt_op(struct adapter *adapter, unsigned int id, unsigned int op,
+ unsigned int credits);
+
+void t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter,
+ int phy_addr, const struct mdio_ops *mdio_ops);
+void t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter,
+ int phy_addr, const struct mdio_ops *mdio_ops);
+void t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter,
+ int phy_addr, const struct mdio_ops *mdio_ops);
+void t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr,
+ const struct mdio_ops *mdio_ops);
+void t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter,
+ int phy_addr, const struct mdio_ops *mdio_ops);
+#endif /* __CHELSIO_COMMON_H */
diff --git a/drivers/net/cxgb3/cxgb3_ctl_defs.h b/drivers/net/cxgb3/cxgb3_ctl_defs.h
new file mode 100644
index 00000000000..2095ddacff7
--- /dev/null
+++ b/drivers/net/cxgb3/cxgb3_ctl_defs.h
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _CXGB3_OFFLOAD_CTL_DEFS_H
+#define _CXGB3_OFFLOAD_CTL_DEFS_H
+
+enum {
+ GET_MAX_OUTSTANDING_WR,
+ GET_TX_MAX_CHUNK,
+ GET_TID_RANGE,
+ GET_STID_RANGE,
+ GET_RTBL_RANGE,
+ GET_L2T_CAPACITY,
+ GET_MTUS,
+ GET_WR_LEN,
+ GET_IFF_FROM_MAC,
+ GET_DDP_PARAMS,
+ GET_PORTS,
+
+ ULP_ISCSI_GET_PARAMS,
+ ULP_ISCSI_SET_PARAMS,
+
+ RDMA_GET_PARAMS,
+ RDMA_CQ_OP,
+ RDMA_CQ_SETUP,
+ RDMA_CQ_DISABLE,
+ RDMA_CTRL_QP_SETUP,
+ RDMA_GET_MEM,
+};
+
+/*
+ * Structure used to describe a TID range. Valid TIDs are [base, base+num).
+ */
+struct tid_range {
+ unsigned int base; /* first TID */
+ unsigned int num; /* number of TIDs in range */
+};
+
+/*
+ * Structure used to request the size and contents of the MTU table.
+ */
+struct mtutab {
+ unsigned int size; /* # of entries in the MTU table */
+ const unsigned short *mtus; /* the MTU table values */
+};
+
+struct net_device;
+
+/*
+ * Structure used to request the adapter net_device owning a given MAC address.
+ */
+struct iff_mac {
+ struct net_device *dev; /* the net_device */
+ const unsigned char *mac_addr; /* MAC address to lookup */
+ u16 vlan_tag;
+};
+
+struct pci_dev;
+
+/*
+ * Structure used to request the TCP DDP parameters.
+ */
+struct ddp_params {
+ unsigned int llimit; /* TDDP region start address */
+ unsigned int ulimit; /* TDDP region end address */
+ unsigned int tag_mask; /* TDDP tag mask */
+ struct pci_dev *pdev;
+};
+
+struct adap_ports {
+ unsigned int nports; /* number of ports on this adapter */
+ struct net_device *lldevs[2];
+};
+
+/*
+ * Structure used to return information to the iscsi layer.
+ */
+struct ulp_iscsi_info {
+ unsigned int offset;
+ unsigned int llimit;
+ unsigned int ulimit;
+ unsigned int tagmask;
+ unsigned int pgsz3;
+ unsigned int pgsz2;
+ unsigned int pgsz1;
+ unsigned int pgsz0;
+ unsigned int max_rxsz;
+ unsigned int max_txsz;
+ struct pci_dev *pdev;
+};
+
+/*
+ * Structure used to return information to the RDMA layer.
+ */
+struct rdma_info {
+ unsigned int tpt_base; /* TPT base address */
+ unsigned int tpt_top; /* TPT last entry address */
+ unsigned int pbl_base; /* PBL base address */
+ unsigned int pbl_top; /* PBL last entry address */
+ unsigned int rqt_base; /* RQT base address */
+ unsigned int rqt_top; /* RQT last entry address */
+ unsigned int udbell_len; /* user doorbell region length */
+ unsigned long udbell_physbase; /* user doorbell physical start addr */
+ void __iomem *kdb_addr; /* kernel doorbell register address */
+ struct pci_dev *pdev; /* associated PCI device */
+};
+
+/*
+ * Structure used to request an operation on an RDMA completion queue.
+ */
+struct rdma_cq_op {
+ unsigned int id;
+ unsigned int op;
+ unsigned int credits;
+};
+
+/*
+ * Structure used to setup RDMA completion queues.
+ */
+struct rdma_cq_setup {
+ unsigned int id;
+ unsigned long long base_addr;
+ unsigned int size;
+ unsigned int credits;
+ unsigned int credit_thres;
+ unsigned int ovfl_mode;
+};
+
+/*
+ * Structure used to setup the RDMA control egress context.
+ */
+struct rdma_ctrlqp_setup {
+ unsigned long long base_addr;
+ unsigned int size;
+};
+#endif /* _CXGB3_OFFLOAD_CTL_DEFS_H */
diff --git a/drivers/net/cxgb3/cxgb3_defs.h b/drivers/net/cxgb3/cxgb3_defs.h
new file mode 100644
index 00000000000..16e004990c5
--- /dev/null
+++ b/drivers/net/cxgb3/cxgb3_defs.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _CHELSIO_DEFS_H
+#define _CHELSIO_DEFS_H
+
+#include <linux/skbuff.h>
+#include <net/tcp.h>
+
+#include "t3cdev.h"
+
+#include "cxgb3_offload.h"
+
+#define VALIDATE_TID 1
+
+void *cxgb_alloc_mem(unsigned long size);
+void cxgb_free_mem(void *addr);
+void cxgb_neigh_update(struct neighbour *neigh);
+void cxgb_redirect(struct dst_entry *old, struct dst_entry *new);
+
+/*
+ * Map an ATID or STID to their entries in the corresponding TID tables.
+ */
+static inline union active_open_entry *atid2entry(const struct tid_info *t,
+ unsigned int atid)
+{
+ return &t->atid_tab[atid - t->atid_base];
+}
+
+static inline union listen_entry *stid2entry(const struct tid_info *t,
+ unsigned int stid)
+{
+ return &t->stid_tab[stid - t->stid_base];
+}
+
+/*
+ * Find the connection corresponding to a TID.
+ */
+static inline struct t3c_tid_entry *lookup_tid(const struct tid_info *t,
+ unsigned int tid)
+{
+ return tid < t->ntids ? &(t->tid_tab[tid]) : NULL;
+}
+
+/*
+ * Find the connection corresponding to a server TID.
+ */
+static inline struct t3c_tid_entry *lookup_stid(const struct tid_info *t,
+ unsigned int tid)
+{
+ if (tid < t->stid_base || tid >= t->stid_base + t->nstids)
+ return NULL;
+ return &(stid2entry(t, tid)->t3c_tid);
+}
+
+/*
+ * Find the connection corresponding to an active-open TID.
+ */
+static inline struct t3c_tid_entry *lookup_atid(const struct tid_info *t,
+ unsigned int tid)
+{
+ if (tid < t->atid_base || tid >= t->atid_base + t->natids)
+ return NULL;
+ return &(atid2entry(t, tid)->t3c_tid);
+}
+
+int process_rx(struct t3cdev *dev, struct sk_buff **skbs, int n);
+int attach_t3cdev(struct t3cdev *dev);
+void detach_t3cdev(struct t3cdev *dev);
+#endif
diff --git a/drivers/net/cxgb3/cxgb3_ioctl.h b/drivers/net/cxgb3/cxgb3_ioctl.h
new file mode 100644
index 00000000000..a94281861a6
--- /dev/null
+++ b/drivers/net/cxgb3/cxgb3_ioctl.h
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef __CHIOCTL_H__
+#define __CHIOCTL_H__
+
+/*
+ * Ioctl commands specific to this driver.
+ */
+enum {
+ CHELSIO_SETREG = 1024,
+ CHELSIO_GETREG,
+ CHELSIO_SETTPI,
+ CHELSIO_GETTPI,
+ CHELSIO_GETMTUTAB,
+ CHELSIO_SETMTUTAB,
+ CHELSIO_GETMTU,
+ CHELSIO_SET_PM,
+ CHELSIO_GET_PM,
+ CHELSIO_GET_TCAM,
+ CHELSIO_SET_TCAM,
+ CHELSIO_GET_TCB,
+ CHELSIO_GET_MEM,
+ CHELSIO_LOAD_FW,
+ CHELSIO_GET_PROTO,
+ CHELSIO_SET_PROTO,
+ CHELSIO_SET_TRACE_FILTER,
+ CHELSIO_SET_QSET_PARAMS,
+ CHELSIO_GET_QSET_PARAMS,
+ CHELSIO_SET_QSET_NUM,
+ CHELSIO_GET_QSET_NUM,
+ CHELSIO_SET_PKTSCHED,
+};
+
+struct ch_reg {
+ uint32_t cmd;
+ uint32_t addr;
+ uint32_t val;
+};
+
+struct ch_cntxt {
+ uint32_t cmd;
+ uint32_t cntxt_type;
+ uint32_t cntxt_id;
+ uint32_t data[4];
+};
+
+/* context types */
+enum { CNTXT_TYPE_EGRESS, CNTXT_TYPE_FL, CNTXT_TYPE_RSP, CNTXT_TYPE_CQ };
+
+struct ch_desc {
+ uint32_t cmd;
+ uint32_t queue_num;
+ uint32_t idx;
+ uint32_t size;
+ uint8_t data[128];
+};
+
+struct ch_mem_range {
+ uint32_t cmd;
+ uint32_t mem_id;
+ uint32_t addr;
+ uint32_t len;
+ uint32_t version;
+ uint8_t buf[0];
+};
+
+struct ch_qset_params {
+ uint32_t cmd;
+ uint32_t qset_idx;
+ int32_t txq_size[3];
+ int32_t rspq_size;
+ int32_t fl_size[2];
+ int32_t intr_lat;
+ int32_t polling;
+ int32_t cong_thres;
+};
+
+struct ch_pktsched_params {
+ uint32_t cmd;
+ uint8_t sched;
+ uint8_t idx;
+ uint8_t min;
+ uint8_t max;
+ uint8_t binding;
+};
+
+#ifndef TCB_SIZE
+# define TCB_SIZE 128
+#endif
+
+/* TCB size in 32-bit words */
+#define TCB_WORDS (TCB_SIZE / 4)
+
+enum { MEM_CM, MEM_PMRX, MEM_PMTX }; /* ch_mem_range.mem_id values */
+
+struct ch_mtus {
+ uint32_t cmd;
+ uint32_t nmtus;
+ uint16_t mtus[NMTUS];
+};
+
+struct ch_pm {
+ uint32_t cmd;
+ uint32_t tx_pg_sz;
+ uint32_t tx_num_pg;
+ uint32_t rx_pg_sz;
+ uint32_t rx_num_pg;
+ uint32_t pm_total;
+};
+
+struct ch_tcam {
+ uint32_t cmd;
+ uint32_t tcam_size;
+ uint32_t nservers;
+ uint32_t nroutes;
+ uint32_t nfilters;
+};
+
+struct ch_tcb {
+ uint32_t cmd;
+ uint32_t tcb_index;
+ uint32_t tcb_data[TCB_WORDS];
+};
+
+struct ch_tcam_word {
+ uint32_t cmd;
+ uint32_t addr;
+ uint32_t buf[3];
+};
+
+struct ch_trace {
+ uint32_t cmd;
+ uint32_t sip;
+ uint32_t sip_mask;
+ uint32_t dip;
+ uint32_t dip_mask;
+ uint16_t sport;
+ uint16_t sport_mask;
+ uint16_t dport;
+ uint16_t dport_mask;
+ uint32_t vlan:12;
+ uint32_t vlan_mask:12;
+ uint32_t intf:4;
+ uint32_t intf_mask:4;
+ uint8_t proto;
+ uint8_t proto_mask;
+ uint8_t invert_match:1;
+ uint8_t config_tx:1;
+ uint8_t config_rx:1;
+ uint8_t trace_tx:1;
+ uint8_t trace_rx:1;
+};
+
+#define SIOCCHIOCTL SIOCDEVPRIVATE
+
+#endif
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
new file mode 100644
index 00000000000..c67f7d3c2f9
--- /dev/null
+++ b/drivers/net/cxgb3/cxgb3_main.c
@@ -0,0 +1,2519 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
+#include <linux/mii.h>
+#include <linux/sockios.h>
+#include <linux/workqueue.h>
+#include <linux/proc_fs.h>
+#include <linux/rtnetlink.h>
+#include <asm/uaccess.h>
+
+#include "common.h"
+#include "cxgb3_ioctl.h"
+#include "regs.h"
+#include "cxgb3_offload.h"
+#include "version.h"
+
+#include "cxgb3_ctl_defs.h"
+#include "t3_cpl.h"
+#include "firmware_exports.h"
+
+enum {
+ MAX_TXQ_ENTRIES = 16384,
+ MAX_CTRL_TXQ_ENTRIES = 1024,
+ MAX_RSPQ_ENTRIES = 16384,
+ MAX_RX_BUFFERS = 16384,
+ MAX_RX_JUMBO_BUFFERS = 16384,
+ MIN_TXQ_ENTRIES = 4,
+ MIN_CTRL_TXQ_ENTRIES = 4,
+ MIN_RSPQ_ENTRIES = 32,
+ MIN_FL_ENTRIES = 32
+};
+
+#define PORT_MASK ((1 << MAX_NPORTS) - 1)
+
+#define DFLT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | \
+ NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP |\
+ NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
+
+#define EEPROM_MAGIC 0x38E2F10C
+
+#define CH_DEVICE(devid, ssid, idx) \
+ { PCI_VENDOR_ID_CHELSIO, devid, PCI_ANY_ID, ssid, 0, 0, idx }
+
+static const struct pci_device_id cxgb3_pci_tbl[] = {
+ CH_DEVICE(0x20, 1, 0), /* PE9000 */
+ CH_DEVICE(0x21, 1, 1), /* T302E */
+ CH_DEVICE(0x22, 1, 2), /* T310E */
+ CH_DEVICE(0x23, 1, 3), /* T320X */
+ CH_DEVICE(0x24, 1, 1), /* T302X */
+ CH_DEVICE(0x25, 1, 3), /* T320E */
+ CH_DEVICE(0x26, 1, 2), /* T310X */
+ CH_DEVICE(0x30, 1, 2), /* T3B10 */
+ CH_DEVICE(0x31, 1, 3), /* T3B20 */
+ CH_DEVICE(0x32, 1, 1), /* T3B02 */
+ {0,}
+};
+
+MODULE_DESCRIPTION(DRV_DESC);
+MODULE_AUTHOR("Chelsio Communications");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION(DRV_VERSION);
+MODULE_DEVICE_TABLE(pci, cxgb3_pci_tbl);
+
+static int dflt_msg_enable = DFLT_MSG_ENABLE;
+
+module_param(dflt_msg_enable, int, 0644);
+MODULE_PARM_DESC(dflt_msg_enable, "Chelsio T3 default message enable bitmap");
+
+/*
+ * The driver uses the best interrupt scheme available on a platform in the
+ * order MSI-X, MSI, legacy pin interrupts. This parameter determines which
+ * of these schemes the driver may consider as follows:
+ *
+ * msi = 2: choose from among all three options
+ * msi = 1: only consider MSI and pin interrupts
+ * msi = 0: force pin interrupts
+ */
+static int msi = 2;
+
+module_param(msi, int, 0644);
+MODULE_PARM_DESC(msi, "whether to use MSI or MSI-X");
+
+/*
+ * The driver enables offload as a default.
+ * To disable it, use ofld_disable = 1.
+ */
+
+static int ofld_disable = 0;
+
+module_param(ofld_disable, int, 0644);
+MODULE_PARM_DESC(ofld_disable, "whether to enable offload at init time or not");
+
+/*
+ * We have work elements that we need to cancel when an interface is taken
+ * down. Normally the work elements would be executed by keventd but that
+ * can deadlock because of linkwatch. If our close method takes the rtnl
+ * lock and linkwatch is ahead of our work elements in keventd, linkwatch
+ * will block keventd as it needs the rtnl lock, and we'll deadlock waiting
+ * for our work to complete. Get our own work queue to solve this.
+ */
+static struct workqueue_struct *cxgb3_wq;
+
+/**
+ * link_report - show link status and link speed/duplex
+ * @p: the port whose settings are to be reported
+ *
+ * Shows the link status, speed, and duplex of a port.
+ */
+static void link_report(struct net_device *dev)
+{
+ if (!netif_carrier_ok(dev))
+ printk(KERN_INFO "%s: link down\n", dev->name);
+ else {
+ const char *s = "10Mbps";
+ const struct port_info *p = netdev_priv(dev);
+
+ switch (p->link_config.speed) {
+ case SPEED_10000:
+ s = "10Gbps";
+ break;
+ case SPEED_1000:
+ s = "1000Mbps";
+ break;
+ case SPEED_100:
+ s = "100Mbps";
+ break;
+ }
+
+ printk(KERN_INFO "%s: link up, %s, %s-duplex\n", dev->name, s,
+ p->link_config.duplex == DUPLEX_FULL ? "full" : "half");
+ }
+}
+
+/**
+ * t3_os_link_changed - handle link status changes
+ * @adapter: the adapter associated with the link change
+ * @port_id: the port index whose limk status has changed
+ * @link_stat: the new status of the link
+ * @speed: the new speed setting
+ * @duplex: the new duplex setting
+ * @pause: the new flow-control setting
+ *
+ * This is the OS-dependent handler for link status changes. The OS
+ * neutral handler takes care of most of the processing for these events,
+ * then calls this handler for any OS-specific processing.
+ */
+void t3_os_link_changed(struct adapter *adapter, int port_id, int link_stat,
+ int speed, int duplex, int pause)
+{
+ struct net_device *dev = adapter->port[port_id];
+
+ /* Skip changes from disabled ports. */
+ if (!netif_running(dev))
+ return;
+
+ if (link_stat != netif_carrier_ok(dev)) {
+ if (link_stat)
+ netif_carrier_on(dev);
+ else
+ netif_carrier_off(dev);
+ link_report(dev);
+ }
+}
+
+static void cxgb_set_rxmode(struct net_device *dev)
+{
+ struct t3_rx_mode rm;
+ struct port_info *pi = netdev_priv(dev);
+
+ init_rx_mode(&rm, dev, dev->mc_list);
+ t3_mac_set_rx_mode(&pi->mac, &rm);
+}
+
+/**
+ * link_start - enable a port
+ * @dev: the device to enable
+ *
+ * Performs the MAC and PHY actions needed to enable a port.
+ */
+static void link_start(struct net_device *dev)
+{
+ struct t3_rx_mode rm;
+ struct port_info *pi = netdev_priv(dev);
+ struct cmac *mac = &pi->mac;
+
+ init_rx_mode(&rm, dev, dev->mc_list);
+ t3_mac_reset(mac);
+ t3_mac_set_mtu(mac, dev->mtu);
+ t3_mac_set_address(mac, 0, dev->dev_addr);
+ t3_mac_set_rx_mode(mac, &rm);
+ t3_link_start(&pi->phy, mac, &pi->link_config);
+ t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
+}
+
+static inline void cxgb_disable_msi(struct adapter *adapter)
+{
+ if (adapter->flags & USING_MSIX) {
+ pci_disable_msix(adapter->pdev);
+ adapter->flags &= ~USING_MSIX;
+ } else if (adapter->flags & USING_MSI) {
+ pci_disable_msi(adapter->pdev);
+ adapter->flags &= ~USING_MSI;
+ }
+}
+
+/*
+ * Interrupt handler for asynchronous events used with MSI-X.
+ */
+static irqreturn_t t3_async_intr_handler(int irq, void *cookie)
+{
+ t3_slow_intr_handler(cookie);
+ return IRQ_HANDLED;
+}
+
+/*
+ * Name the MSI-X interrupts.
+ */
+static void name_msix_vecs(struct adapter *adap)
+{
+ int i, j, msi_idx = 1, n = sizeof(adap->msix_info[0].desc) - 1;
+
+ snprintf(adap->msix_info[0].desc, n, "%s", adap->name);
+ adap->msix_info[0].desc[n] = 0;
+
+ for_each_port(adap, j) {
+ struct net_device *d = adap->port[j];
+ const struct port_info *pi = netdev_priv(d);
+
+ for (i = 0; i < pi->nqsets; i++, msi_idx++) {
+ snprintf(adap->msix_info[msi_idx].desc, n,
+ "%s (queue %d)", d->name, i);
+ adap->msix_info[msi_idx].desc[n] = 0;
+ }
+ }
+}
+
+static int request_msix_data_irqs(struct adapter *adap)
+{
+ int i, j, err, qidx = 0;
+
+ for_each_port(adap, i) {
+ int nqsets = adap2pinfo(adap, i)->nqsets;
+
+ for (j = 0; j < nqsets; ++j) {
+ err = request_irq(adap->msix_info[qidx + 1].vec,
+ t3_intr_handler(adap,
+ adap->sge.qs[qidx].
+ rspq.polling), 0,
+ adap->msix_info[qidx + 1].desc,
+ &adap->sge.qs[qidx]);
+ if (err) {
+ while (--qidx >= 0)
+ free_irq(adap->msix_info[qidx + 1].vec,
+ &adap->sge.qs[qidx]);
+ return err;
+ }
+ qidx++;
+ }
+ }
+ return 0;
+}
+
+/**
+ * setup_rss - configure RSS
+ * @adap: the adapter
+ *
+ * Sets up RSS to distribute packets to multiple receive queues. We
+ * configure the RSS CPU lookup table to distribute to the number of HW
+ * receive queues, and the response queue lookup table to narrow that
+ * down to the response queues actually configured for each port.
+ * We always configure the RSS mapping for two ports since the mapping
+ * table has plenty of entries.
+ */
+static void setup_rss(struct adapter *adap)
+{
+ int i;
+ unsigned int nq0 = adap2pinfo(adap, 0)->nqsets;
+ unsigned int nq1 = adap->port[1] ? adap2pinfo(adap, 1)->nqsets : 1;
+ u8 cpus[SGE_QSETS + 1];
+ u16 rspq_map[RSS_TABLE_SIZE];
+
+ for (i = 0; i < SGE_QSETS; ++i)
+ cpus[i] = i;
+ cpus[SGE_QSETS] = 0xff; /* terminator */
+
+ for (i = 0; i < RSS_TABLE_SIZE / 2; ++i) {
+ rspq_map[i] = i % nq0;
+ rspq_map[i + RSS_TABLE_SIZE / 2] = (i % nq1) + nq0;
+ }
+
+ t3_config_rss(adap, F_RQFEEDBACKENABLE | F_TNLLKPEN | F_TNLMAPEN |
+ F_TNLPRTEN | F_TNL2TUPEN | F_TNL4TUPEN |
+ V_RRCPLCPUSIZE(6), cpus, rspq_map);
+}
+
+/*
+ * If we have multiple receive queues per port serviced by NAPI we need one
+ * netdevice per queue as NAPI operates on netdevices. We already have one
+ * netdevice, namely the one associated with the interface, so we use dummy
+ * ones for any additional queues. Note that these netdevices exist purely
+ * so that NAPI has something to work with, they do not represent network
+ * ports and are not registered.
+ */
+static int init_dummy_netdevs(struct adapter *adap)
+{
+ int i, j, dummy_idx = 0;
+ struct net_device *nd;
+
+ for_each_port(adap, i) {
+ struct net_device *dev = adap->port[i];
+ const struct port_info *pi = netdev_priv(dev);
+
+ for (j = 0; j < pi->nqsets - 1; j++) {
+ if (!adap->dummy_netdev[dummy_idx]) {
+ nd = alloc_netdev(0, "", ether_setup);
+ if (!nd)
+ goto free_all;
+
+ nd->priv = adap;
+ nd->weight = 64;
+ set_bit(__LINK_STATE_START, &nd->state);
+ adap->dummy_netdev[dummy_idx] = nd;
+ }
+ strcpy(adap->dummy_netdev[dummy_idx]->name, dev->name);
+ dummy_idx++;
+ }
+ }
+ return 0;
+
+free_all:
+ while (--dummy_idx >= 0) {
+ free_netdev(adap->dummy_netdev[dummy_idx]);
+ adap->dummy_netdev[dummy_idx] = NULL;
+ }
+ return -ENOMEM;
+}
+
+/*
+ * Wait until all NAPI handlers are descheduled. This includes the handlers of
+ * both netdevices representing interfaces and the dummy ones for the extra
+ * queues.
+ */
+static void quiesce_rx(struct adapter *adap)
+{
+ int i;
+ struct net_device *dev;
+
+ for_each_port(adap, i) {
+ dev = adap->port[i];
+ while (test_bit(__LINK_STATE_RX_SCHED, &dev->state))
+ msleep(1);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(adap->dummy_netdev); i++) {
+ dev = adap->dummy_netdev[i];
+ if (dev)
+ while (test_bit(__LINK_STATE_RX_SCHED, &dev->state))
+ msleep(1);
+ }
+}
+
+/**
+ * setup_sge_qsets - configure SGE Tx/Rx/response queues
+ * @adap: the adapter
+ *
+ * Determines how many sets of SGE queues to use and initializes them.
+ * We support multiple queue sets per port if we have MSI-X, otherwise
+ * just one queue set per port.
+ */
+static int setup_sge_qsets(struct adapter *adap)
+{
+ int i, j, err, irq_idx = 0, qset_idx = 0, dummy_dev_idx = 0;
+ unsigned int ntxq = is_offload(adap) ? SGE_TXQ_PER_SET : 1;
+
+ if (adap->params.rev > 0 && !(adap->flags & USING_MSI))
+ irq_idx = -1;
+
+ for_each_port(adap, i) {
+ struct net_device *dev = adap->port[i];
+ const struct port_info *pi = netdev_priv(dev);
+
+ for (j = 0; j < pi->nqsets; ++j, ++qset_idx) {
+ err = t3_sge_alloc_qset(adap, qset_idx, 1,
+ (adap->flags & USING_MSIX) ? qset_idx + 1 :
+ irq_idx,
+ &adap->params.sge.qset[qset_idx], ntxq,
+ j == 0 ? dev :
+ adap-> dummy_netdev[dummy_dev_idx++]);
+ if (err) {
+ t3_free_sge_resources(adap);
+ return err;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static ssize_t attr_show(struct device *d, struct device_attribute *attr,
+ char *buf,
+ ssize_t(*format) (struct adapter *, char *))
+{
+ ssize_t len;
+ struct adapter *adap = to_net_dev(d)->priv;
+
+ /* Synchronize with ioctls that may shut down the device */
+ rtnl_lock();
+ len = (*format) (adap, buf);
+ rtnl_unlock();
+ return len;
+}
+
+static ssize_t attr_store(struct device *d, struct device_attribute *attr,
+ const char *buf, size_t len,
+ ssize_t(*set) (struct adapter *, unsigned int),
+ unsigned int min_val, unsigned int max_val)
+{
+ char *endp;
+ ssize_t ret;
+ unsigned int val;
+ struct adapter *adap = to_net_dev(d)->priv;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ val = simple_strtoul(buf, &endp, 0);
+ if (endp == buf || val < min_val || val > max_val)
+ return -EINVAL;
+
+ rtnl_lock();
+ ret = (*set) (adap, val);
+ if (!ret)
+ ret = len;
+ rtnl_unlock();
+ return ret;
+}
+
+#define CXGB3_SHOW(name, val_expr) \
+static ssize_t format_##name(struct adapter *adap, char *buf) \
+{ \
+ return sprintf(buf, "%u\n", val_expr); \
+} \
+static ssize_t show_##name(struct device *d, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ return attr_show(d, attr, buf, format_##name); \
+}
+
+static ssize_t set_nfilters(struct adapter *adap, unsigned int val)
+{
+ if (adap->flags & FULL_INIT_DONE)
+ return -EBUSY;
+ if (val && adap->params.rev == 0)
+ return -EINVAL;
+ if (val > t3_mc5_size(&adap->mc5) - adap->params.mc5.nservers)
+ return -EINVAL;
+ adap->params.mc5.nfilters = val;
+ return 0;
+}
+
+static ssize_t store_nfilters(struct device *d, struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ return attr_store(d, attr, buf, len, set_nfilters, 0, ~0);
+}
+
+static ssize_t set_nservers(struct adapter *adap, unsigned int val)
+{
+ if (adap->flags & FULL_INIT_DONE)
+ return -EBUSY;
+ if (val > t3_mc5_size(&adap->mc5) - adap->params.mc5.nfilters)
+ return -EINVAL;
+ adap->params.mc5.nservers = val;
+ return 0;
+}
+
+static ssize_t store_nservers(struct device *d, struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ return attr_store(d, attr, buf, len, set_nservers, 0, ~0);
+}
+
+#define CXGB3_ATTR_R(name, val_expr) \
+CXGB3_SHOW(name, val_expr) \
+static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
+
+#define CXGB3_ATTR_RW(name, val_expr, store_method) \
+CXGB3_SHOW(name, val_expr) \
+static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_method)
+
+CXGB3_ATTR_R(cam_size, t3_mc5_size(&adap->mc5));
+CXGB3_ATTR_RW(nfilters, adap->params.mc5.nfilters, store_nfilters);
+CXGB3_ATTR_RW(nservers, adap->params.mc5.nservers, store_nservers);
+
+static struct attribute *cxgb3_attrs[] = {
+ &dev_attr_cam_size.attr,
+ &dev_attr_nfilters.attr,
+ &dev_attr_nservers.attr,
+ NULL
+};
+
+static struct attribute_group cxgb3_attr_group = {.attrs = cxgb3_attrs };
+
+static ssize_t tm_attr_show(struct device *d, struct device_attribute *attr,
+ char *buf, int sched)
+{
+ ssize_t len;
+ unsigned int v, addr, bpt, cpt;
+ struct adapter *adap = to_net_dev(d)->priv;
+
+ addr = A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2;
+ rtnl_lock();
+ t3_write_reg(adap, A_TP_TM_PIO_ADDR, addr);
+ v = t3_read_reg(adap, A_TP_TM_PIO_DATA);
+ if (sched & 1)
+ v >>= 16;
+ bpt = (v >> 8) & 0xff;
+ cpt = v & 0xff;
+ if (!cpt)
+ len = sprintf(buf, "disabled\n");
+ else {
+ v = (adap->params.vpd.cclk * 1000) / cpt;
+ len = sprintf(buf, "%u Kbps\n", (v * bpt) / 125);
+ }
+ rtnl_unlock();
+ return len;
+}
+
+static ssize_t tm_attr_store(struct device *d, struct device_attribute *attr,
+ const char *buf, size_t len, int sched)
+{
+ char *endp;
+ ssize_t ret;
+ unsigned int val;
+ struct adapter *adap = to_net_dev(d)->priv;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ val = simple_strtoul(buf, &endp, 0);
+ if (endp == buf || val > 10000000)
+ return -EINVAL;
+
+ rtnl_lock();
+ ret = t3_config_sched(adap, val, sched);
+ if (!ret)
+ ret = len;
+ rtnl_unlock();
+ return ret;
+}
+
+#define TM_ATTR(name, sched) \
+static ssize_t show_##name(struct device *d, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ return tm_attr_show(d, attr, buf, sched); \
+} \
+static ssize_t store_##name(struct device *d, struct device_attribute *attr, \
+ const char *buf, size_t len) \
+{ \
+ return tm_attr_store(d, attr, buf, len, sched); \
+} \
+static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_##name)
+
+TM_ATTR(sched0, 0);
+TM_ATTR(sched1, 1);
+TM_ATTR(sched2, 2);
+TM_ATTR(sched3, 3);
+TM_ATTR(sched4, 4);
+TM_ATTR(sched5, 5);
+TM_ATTR(sched6, 6);
+TM_ATTR(sched7, 7);
+
+static struct attribute *offload_attrs[] = {
+ &dev_attr_sched0.attr,
+ &dev_attr_sched1.attr,
+ &dev_attr_sched2.attr,
+ &dev_attr_sched3.attr,
+ &dev_attr_sched4.attr,
+ &dev_attr_sched5.attr,
+ &dev_attr_sched6.attr,
+ &dev_attr_sched7.attr,
+ NULL
+};
+
+static struct attribute_group offload_attr_group = {.attrs = offload_attrs };
+
+/*
+ * Sends an sk_buff to an offload queue driver
+ * after dealing with any active network taps.
+ */
+static inline int offload_tx(struct t3cdev *tdev, struct sk_buff *skb)
+{
+ int ret;
+
+ local_bh_disable();
+ ret = t3_offload_tx(tdev, skb);
+ local_bh_enable();
+ return ret;
+}
+
+static int write_smt_entry(struct adapter *adapter, int idx)
+{
+ struct cpl_smt_write_req *req;
+ struct sk_buff *skb = alloc_skb(sizeof(*req), GFP_KERNEL);
+
+ if (!skb)
+ return -ENOMEM;
+
+ req = (struct cpl_smt_write_req *)__skb_put(skb, sizeof(*req));
+ req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+ OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, idx));
+ req->mtu_idx = NMTUS - 1; /* should be 0 but there's a T3 bug */
+ req->iff = idx;
+ memset(req->src_mac1, 0, sizeof(req->src_mac1));
+ memcpy(req->src_mac0, adapter->port[idx]->dev_addr, ETH_ALEN);
+ skb->priority = 1;
+ offload_tx(&adapter->tdev, skb);
+ return 0;
+}
+
+static int init_smt(struct adapter *adapter)
+{
+ int i;
+
+ for_each_port(adapter, i)
+ write_smt_entry(adapter, i);
+ return 0;
+}
+
+static void init_port_mtus(struct adapter *adapter)
+{
+ unsigned int mtus = adapter->port[0]->mtu;
+
+ if (adapter->port[1])
+ mtus |= adapter->port[1]->mtu << 16;
+ t3_write_reg(adapter, A_TP_MTU_PORT_TABLE, mtus);
+}
+
+static void send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo,
+ int hi, int port)
+{
+ struct sk_buff *skb;
+ struct mngt_pktsched_wr *req;
+
+ skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL);
+ req = (struct mngt_pktsched_wr *)skb_put(skb, sizeof(*req));
+ req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT));
+ req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET;
+ req->sched = sched;
+ req->idx = qidx;
+ req->min = lo;
+ req->max = hi;
+ req->binding = port;
+ t3_mgmt_tx(adap, skb);
+}
+
+static void bind_qsets(struct adapter *adap)
+{
+ int i, j;
+
+ for_each_port(adap, i) {
+ const struct port_info *pi = adap2pinfo(adap, i);
+
+ for (j = 0; j < pi->nqsets; ++j)
+ send_pktsched_cmd(adap, 1, pi->first_qset + j, -1,
+ -1, i);
+ }
+}
+
+/**
+ * cxgb_up - enable the adapter
+ * @adapter: adapter being enabled
+ *
+ * Called when the first port is enabled, this function performs the
+ * actions necessary to make an adapter operational, such as completing
+ * the initialization of HW modules, and enabling interrupts.
+ *
+ * Must be called with the rtnl lock held.
+ */
+static int cxgb_up(struct adapter *adap)
+{
+ int err = 0;
+
+ if (!(adap->flags & FULL_INIT_DONE)) {
+ err = t3_check_fw_version(adap);
+ if (err)
+ goto out;
+
+ err = init_dummy_netdevs(adap);
+ if (err)
+ goto out;
+
+ err = t3_init_hw(adap, 0);
+ if (err)
+ goto out;
+
+ err = setup_sge_qsets(adap);
+ if (err)
+ goto out;
+
+ setup_rss(adap);
+ adap->flags |= FULL_INIT_DONE;
+ }
+
+ t3_intr_clear(adap);
+
+ if (adap->flags & USING_MSIX) {
+ name_msix_vecs(adap);
+ err = request_irq(adap->msix_info[0].vec,
+ t3_async_intr_handler, 0,
+ adap->msix_info[0].desc, adap);
+ if (err)
+ goto irq_err;
+
+ if (request_msix_data_irqs(adap)) {
+ free_irq(adap->msix_info[0].vec, adap);
+ goto irq_err;
+ }
+ } else if ((err = request_irq(adap->pdev->irq,
+ t3_intr_handler(adap,
+ adap->sge.qs[0].rspq.
+ polling),
+ (adap->flags & USING_MSI) ? 0 : SA_SHIRQ,
+ adap->name, adap)))
+ goto irq_err;
+
+ t3_sge_start(adap);
+ t3_intr_enable(adap);
+
+ if ((adap->flags & (USING_MSIX | QUEUES_BOUND)) == USING_MSIX)
+ bind_qsets(adap);
+ adap->flags |= QUEUES_BOUND;
+
+out:
+ return err;
+irq_err:
+ CH_ERR(adap, "request_irq failed, err %d\n", err);
+ goto out;
+}
+
+/*
+ * Release resources when all the ports and offloading have been stopped.
+ */
+static void cxgb_down(struct adapter *adapter)
+{
+ t3_sge_stop(adapter);
+ spin_lock_irq(&adapter->work_lock); /* sync with PHY intr task */
+ t3_intr_disable(adapter);
+ spin_unlock_irq(&adapter->work_lock);
+
+ if (adapter->flags & USING_MSIX) {
+ int i, n = 0;
+
+ free_irq(adapter->msix_info[0].vec, adapter);
+ for_each_port(adapter, i)
+ n += adap2pinfo(adapter, i)->nqsets;
+
+ for (i = 0; i < n; ++i)
+ free_irq(adapter->msix_info[i + 1].vec,
+ &adapter->sge.qs[i]);
+ } else
+ free_irq(adapter->pdev->irq, adapter);
+
+ flush_workqueue(cxgb3_wq); /* wait for external IRQ handler */
+ quiesce_rx(adapter);
+}
+
+static void schedule_chk_task(struct adapter *adap)
+{
+ unsigned int timeo;
+
+ timeo = adap->params.linkpoll_period ?
+ (HZ * adap->params.linkpoll_period) / 10 :
+ adap->params.stats_update_period * HZ;
+ if (timeo)
+ queue_delayed_work(cxgb3_wq, &adap->adap_check_task, timeo);
+}
+
+static int offload_open(struct net_device *dev)
+{
+ struct adapter *adapter = dev->priv;
+ struct t3cdev *tdev = T3CDEV(dev);
+ int adap_up = adapter->open_device_map & PORT_MASK;
+ int err = 0;
+
+ if (test_and_set_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
+ return 0;
+
+ if (!adap_up && (err = cxgb_up(adapter)) < 0)
+ return err;
+
+ t3_tp_set_offload_mode(adapter, 1);
+ tdev->lldev = adapter->port[0];
+ err = cxgb3_offload_activate(adapter);
+ if (err)
+ goto out;
+
+ init_port_mtus(adapter);
+ t3_load_mtus(adapter, adapter->params.mtus, adapter->params.a_wnd,
+ adapter->params.b_wnd,
+ adapter->params.rev == 0 ?
+ adapter->port[0]->mtu : 0xffff);
+ init_smt(adapter);
+
+ /* Never mind if the next step fails */
+ sysfs_create_group(&tdev->lldev->dev.kobj, &offload_attr_group);
+
+ /* Call back all registered clients */
+ cxgb3_add_clients(tdev);
+
+out:
+ /* restore them in case the offload module has changed them */
+ if (err) {
+ t3_tp_set_offload_mode(adapter, 0);
+ clear_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map);
+ cxgb3_set_dummy_ops(tdev);
+ }
+ return err;
+}
+
+static int offload_close(struct t3cdev *tdev)
+{
+ struct adapter *adapter = tdev2adap(tdev);
+
+ if (!test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
+ return 0;
+
+ /* Call back all registered clients */
+ cxgb3_remove_clients(tdev);
+
+ sysfs_remove_group(&tdev->lldev->dev.kobj, &offload_attr_group);
+
+ tdev->lldev = NULL;
+ cxgb3_set_dummy_ops(tdev);
+ t3_tp_set_offload_mode(adapter, 0);
+ clear_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map);
+
+ if (!adapter->open_device_map)
+ cxgb_down(adapter);
+
+ cxgb3_offload_deactivate(adapter);
+ return 0;
+}
+
+static int cxgb_open(struct net_device *dev)
+{
+ int err;
+ struct adapter *adapter = dev->priv;
+ struct port_info *pi = netdev_priv(dev);
+ int other_ports = adapter->open_device_map & PORT_MASK;
+
+ if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0)
+ return err;
+
+ set_bit(pi->port_id, &adapter->open_device_map);
+ if (!ofld_disable) {
+ err = offload_open(dev);
+ if (err)
+ printk(KERN_WARNING
+ "Could not initialize offload capabilities\n");
+ }
+
+ link_start(dev);
+ t3_port_intr_enable(adapter, pi->port_id);
+ netif_start_queue(dev);
+ if (!other_ports)
+ schedule_chk_task(adapter);
+
+ return 0;
+}
+
+static int cxgb_close(struct net_device *dev)
+{
+ struct adapter *adapter = dev->priv;
+ struct port_info *p = netdev_priv(dev);
+
+ t3_port_intr_disable(adapter, p->port_id);
+ netif_stop_queue(dev);
+ p->phy.ops->power_down(&p->phy, 1);
+ netif_carrier_off(dev);
+ t3_mac_disable(&p->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);
+
+ spin_lock(&adapter->work_lock); /* sync with update task */
+ clear_bit(p->port_id, &adapter->open_device_map);
+ spin_unlock(&adapter->work_lock);
+
+ if (!(adapter->open_device_map & PORT_MASK))
+ cancel_rearming_delayed_workqueue(cxgb3_wq,
+ &adapter->adap_check_task);
+
+ if (!adapter->open_device_map)
+ cxgb_down(adapter);
+
+ return 0;
+}
+
+static struct net_device_stats *cxgb_get_stats(struct net_device *dev)
+{
+ struct adapter *adapter = dev->priv;
+ struct port_info *p = netdev_priv(dev);
+ struct net_device_stats *ns = &p->netstats;
+ const struct mac_stats *pstats;
+
+ spin_lock(&adapter->stats_lock);
+ pstats = t3_mac_update_stats(&p->mac);
+ spin_unlock(&adapter->stats_lock);
+
+ ns->tx_bytes = pstats->tx_octets;
+ ns->tx_packets = pstats->tx_frames;
+ ns->rx_bytes = pstats->rx_octets;
+ ns->rx_packets = pstats->rx_frames;
+ ns->multicast = pstats->rx_mcast_frames;
+
+ ns->tx_errors = pstats->tx_underrun;
+ ns->rx_errors = pstats->rx_symbol_errs + pstats->rx_fcs_errs +
+ pstats->rx_too_long + pstats->rx_jabber + pstats->rx_short +
+ pstats->rx_fifo_ovfl;
+
+ /* detailed rx_errors */
+ ns->rx_length_errors = pstats->rx_jabber + pstats->rx_too_long;
+ ns->rx_over_errors = 0;
+ ns->rx_crc_errors = pstats->rx_fcs_errs;
+ ns->rx_frame_errors = pstats->rx_symbol_errs;
+ ns->rx_fifo_errors = pstats->rx_fifo_ovfl;
+ ns->rx_missed_errors = pstats->rx_cong_drops;
+
+ /* detailed tx_errors */
+ ns->tx_aborted_errors = 0;
+ ns->tx_carrier_errors = 0;
+ ns->tx_fifo_errors = pstats->tx_underrun;
+ ns->tx_heartbeat_errors = 0;
+ ns->tx_window_errors = 0;
+ return ns;
+}
+
+static u32 get_msglevel(struct net_device *dev)
+{
+ struct adapter *adapter = dev->priv;
+
+ return adapter->msg_enable;
+}
+
+static void set_msglevel(struct net_device *dev, u32 val)
+{
+ struct adapter *adapter = dev->priv;
+
+ adapter->msg_enable = val;
+}
+
+static char stats_strings[][ETH_GSTRING_LEN] = {
+ "TxOctetsOK ",
+ "TxFramesOK ",
+ "TxMulticastFramesOK",
+ "TxBroadcastFramesOK",
+ "TxPauseFrames ",
+ "TxUnderrun ",
+ "TxExtUnderrun ",
+
+ "TxFrames64 ",
+ "TxFrames65To127 ",
+ "TxFrames128To255 ",
+ "TxFrames256To511 ",
+ "TxFrames512To1023 ",
+ "TxFrames1024To1518 ",
+ "TxFrames1519ToMax ",
+
+ "RxOctetsOK ",
+ "RxFramesOK ",
+ "RxMulticastFramesOK",
+ "RxBroadcastFramesOK",
+ "RxPauseFrames ",
+ "RxFCSErrors ",
+ "RxSymbolErrors ",
+ "RxShortErrors ",
+ "RxJabberErrors ",
+ "RxLengthErrors ",
+ "RxFIFOoverflow ",
+
+ "RxFrames64 ",
+ "RxFrames65To127 ",
+ "RxFrames128To255 ",
+ "RxFrames256To511 ",
+ "RxFrames512To1023 ",
+ "RxFrames1024To1518 ",
+ "RxFrames1519ToMax ",
+
+ "PhyFIFOErrors ",
+ "TSO ",
+ "VLANextractions ",
+ "VLANinsertions ",
+ "TxCsumOffload ",
+ "RxCsumGood ",
+ "RxDrops "
+};
+
+static int get_stats_count(struct net_device *dev)
+{
+ return ARRAY_SIZE(stats_strings);
+}
+
+#define T3_REGMAP_SIZE (3 * 1024)
+
+static int get_regs_len(struct net_device *dev)
+{
+ return T3_REGMAP_SIZE;
+}
+
+static int get_eeprom_len(struct net_device *dev)
+{
+ return EEPROMSIZE;
+}
+
+static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+ u32 fw_vers = 0;
+ struct adapter *adapter = dev->priv;
+
+ t3_get_fw_version(adapter, &fw_vers);
+
+ strcpy(info->driver, DRV_NAME);
+ strcpy(info->version, DRV_VERSION);
+ strcpy(info->bus_info, pci_name(adapter->pdev));
+ if (!fw_vers)
+ strcpy(info->fw_version, "N/A");
+ else {
+ snprintf(info->fw_version, sizeof(info->fw_version),
+ "%s %u.%u.%u",
+ G_FW_VERSION_TYPE(fw_vers) ? "T" : "N",
+ G_FW_VERSION_MAJOR(fw_vers),
+ G_FW_VERSION_MINOR(fw_vers),
+ G_FW_VERSION_MICRO(fw_vers));
+ }
+}
+
+static void get_strings(struct net_device *dev, u32 stringset, u8 * data)
+{
+ if (stringset == ETH_SS_STATS)
+ memcpy(data, stats_strings, sizeof(stats_strings));
+}
+
+static unsigned long collect_sge_port_stats(struct adapter *adapter,
+ struct port_info *p, int idx)
+{
+ int i;
+ unsigned long tot = 0;
+
+ for (i = 0; i < p->nqsets; ++i)
+ tot += adapter->sge.qs[i + p->first_qset].port_stats[idx];
+ return tot;
+}
+
+static void get_stats(struct net_device *dev, struct ethtool_stats *stats,
+ u64 *data)
+{
+ struct adapter *adapter = dev->priv;
+ struct port_info *pi = netdev_priv(dev);
+ const struct mac_stats *s;
+
+ spin_lock(&adapter->stats_lock);
+ s = t3_mac_update_stats(&pi->mac);
+ spin_unlock(&adapter->stats_lock);
+
+ *data++ = s->tx_octets;
+ *data++ = s->tx_frames;
+ *data++ = s->tx_mcast_frames;
+ *data++ = s->tx_bcast_frames;
+ *data++ = s->tx_pause;
+ *data++ = s->tx_underrun;
+ *data++ = s->tx_fifo_urun;
+
+ *data++ = s->tx_frames_64;
+ *data++ = s->tx_frames_65_127;
+ *data++ = s->tx_frames_128_255;
+ *data++ = s->tx_frames_256_511;
+ *data++ = s->tx_frames_512_1023;
+ *data++ = s->tx_frames_1024_1518;
+ *data++ = s->tx_frames_1519_max;
+
+ *data++ = s->rx_octets;
+ *data++ = s->rx_frames;
+ *data++ = s->rx_mcast_frames;
+ *data++ = s->rx_bcast_frames;
+ *data++ = s->rx_pause;
+ *data++ = s->rx_fcs_errs;
+ *data++ = s->rx_symbol_errs;
+ *data++ = s->rx_short;
+ *data++ = s->rx_jabber;
+ *data++ = s->rx_too_long;
+ *data++ = s->rx_fifo_ovfl;
+
+ *data++ = s->rx_frames_64;
+ *data++ = s->rx_frames_65_127;
+ *data++ = s->rx_frames_128_255;
+ *data++ = s->rx_frames_256_511;
+ *data++ = s->rx_frames_512_1023;
+ *data++ = s->rx_frames_1024_1518;
+ *data++ = s->rx_frames_1519_max;
+
+ *data++ = pi->phy.fifo_errors;
+
+ *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TSO);
+ *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_VLANEX);
+ *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_VLANINS);
+ *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TX_CSUM);
+ *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_RX_CSUM_GOOD);
+ *data++ = s->rx_cong_drops;
+}
+
+static inline void reg_block_dump(struct adapter *ap, void *buf,
+ unsigned int start, unsigned int end)
+{
+ u32 *p = buf + start;
+
+ for (; start <= end; start += sizeof(u32))
+ *p++ = t3_read_reg(ap, start);
+}
+
+static void get_regs(struct net_device *dev, struct ethtool_regs *regs,
+ void *buf)
+{
+ struct adapter *ap = dev->priv;
+
+ /*
+ * Version scheme:
+ * bits 0..9: chip version
+ * bits 10..15: chip revision
+ * bit 31: set for PCIe cards
+ */
+ regs->version = 3 | (ap->params.rev << 10) | (is_pcie(ap) << 31);
+
+ /*
+ * We skip the MAC statistics registers because they are clear-on-read.
+ * Also reading multi-register stats would need to synchronize with the
+ * periodic mac stats accumulation. Hard to justify the complexity.
+ */
+ memset(buf, 0, T3_REGMAP_SIZE);
+ reg_block_dump(ap, buf, 0, A_SG_RSPQ_CREDIT_RETURN);
+ reg_block_dump(ap, buf, A_SG_HI_DRB_HI_THRSH, A_ULPRX_PBL_ULIMIT);
+ reg_block_dump(ap, buf, A_ULPTX_CONFIG, A_MPS_INT_CAUSE);
+ reg_block_dump(ap, buf, A_CPL_SWITCH_CNTRL, A_CPL_MAP_TBL_DATA);
+ reg_block_dump(ap, buf, A_SMB_GLOBAL_TIME_CFG, A_XGM_SERDES_STAT3);
+ reg_block_dump(ap, buf, A_XGM_SERDES_STATUS0,
+ XGM_REG(A_XGM_SERDES_STAT3, 1));
+ reg_block_dump(ap, buf, XGM_REG(A_XGM_SERDES_STATUS0, 1),
+ XGM_REG(A_XGM_RX_SPI4_SOP_EOP_CNT, 1));
+}
+
+static int restart_autoneg(struct net_device *dev)
+{
+ struct port_info *p = netdev_priv(dev);
+
+ if (!netif_running(dev))
+ return -EAGAIN;
+ if (p->link_config.autoneg != AUTONEG_ENABLE)
+ return -EINVAL;
+ p->phy.ops->autoneg_restart(&p->phy);
+ return 0;
+}
+
+static int cxgb3_phys_id(struct net_device *dev, u32 data)
+{
+ int i;
+ struct adapter *adapter = dev->priv;
+
+ if (data == 0)
+ data = 2;
+
+ for (i = 0; i < data * 2; i++) {
+ t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL,
+ (i & 1) ? F_GPIO0_OUT_VAL : 0);
+ if (msleep_interruptible(500))
+ break;
+ }
+ t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL,
+ F_GPIO0_OUT_VAL);
+ return 0;
+}
+
+static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct port_info *p = netdev_priv(dev);
+
+ cmd->supported = p->link_config.supported;
+ cmd->advertising = p->link_config.advertising;
+
+ if (netif_carrier_ok(dev)) {
+ cmd->speed = p->link_config.speed;
+ cmd->duplex = p->link_config.duplex;
+ } else {
+ cmd->speed = -1;
+ cmd->duplex = -1;
+ }
+
+ cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE;
+ cmd->phy_address = p->phy.addr;
+ cmd->transceiver = XCVR_EXTERNAL;
+ cmd->autoneg = p->link_config.autoneg;
+ cmd->maxtxpkt = 0;
+ cmd->maxrxpkt = 0;
+ return 0;
+}
+
+static int speed_duplex_to_caps(int speed, int duplex)
+{
+ int cap = 0;
+
+ switch (speed) {
+ case SPEED_10:
+ if (duplex == DUPLEX_FULL)
+ cap = SUPPORTED_10baseT_Full;
+ else
+ cap = SUPPORTED_10baseT_Half;
+ break;
+ case SPEED_100:
+ if (duplex == DUPLEX_FULL)
+ cap = SUPPORTED_100baseT_Full;
+ else
+ cap = SUPPORTED_100baseT_Half;
+ break;
+ case SPEED_1000:
+ if (duplex == DUPLEX_FULL)
+ cap = SUPPORTED_1000baseT_Full;
+ else
+ cap = SUPPORTED_1000baseT_Half;
+ break;
+ case SPEED_10000:
+ if (duplex == DUPLEX_FULL)
+ cap = SUPPORTED_10000baseT_Full;
+ }
+ return cap;
+}
+
+#define ADVERTISED_MASK (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
+ ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \
+ ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full | \
+ ADVERTISED_10000baseT_Full)
+
+static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct port_info *p = netdev_priv(dev);
+ struct link_config *lc = &p->link_config;
+
+ if (!(lc->supported & SUPPORTED_Autoneg))
+ return -EOPNOTSUPP; /* can't change speed/duplex */
+
+ if (cmd->autoneg == AUTONEG_DISABLE) {
+ int cap = speed_duplex_to_caps(cmd->speed, cmd->duplex);
+
+ if (!(lc->supported & cap) || cmd->speed == SPEED_1000)
+ return -EINVAL;
+ lc->requested_speed = cmd->speed;
+ lc->requested_duplex = cmd->duplex;
+ lc->advertising = 0;
+ } else {
+ cmd->advertising &= ADVERTISED_MASK;
+ cmd->advertising &= lc->supported;
+ if (!cmd->advertising)
+ return -EINVAL;
+ lc->requested_speed = SPEED_INVALID;
+ lc->requested_duplex = DUPLEX_INVALID;
+ lc->advertising = cmd->advertising | ADVERTISED_Autoneg;
+ }
+ lc->autoneg = cmd->autoneg;
+ if (netif_running(dev))
+ t3_link_start(&p->phy, &p->mac, lc);
+ return 0;
+}
+
+static void get_pauseparam(struct net_device *dev,
+ struct ethtool_pauseparam *epause)
+{
+ struct port_info *p = netdev_priv(dev);
+
+ epause->autoneg = (p->link_config.requested_fc & PAUSE_AUTONEG) != 0;
+ epause->rx_pause = (p->link_config.fc & PAUSE_RX) != 0;
+ epause->tx_pause = (p->link_config.fc & PAUSE_TX) != 0;
+}
+
+static int set_pauseparam(struct net_device *dev,
+ struct ethtool_pauseparam *epause)
+{
+ struct port_info *p = netdev_priv(dev);
+ struct link_config *lc = &p->link_config;
+
+ if (epause->autoneg == AUTONEG_DISABLE)
+ lc->requested_fc = 0;
+ else if (lc->supported & SUPPORTED_Autoneg)
+ lc->requested_fc = PAUSE_AUTONEG;
+ else
+ return -EINVAL;
+
+ if (epause->rx_pause)
+ lc->requested_fc |= PAUSE_RX;
+ if (epause->tx_pause)
+ lc->requested_fc |= PAUSE_TX;
+ if (lc->autoneg == AUTONEG_ENABLE) {
+ if (netif_running(dev))
+ t3_link_start(&p->phy, &p->mac, lc);
+ } else {
+ lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
+ if (netif_running(dev))
+ t3_mac_set_speed_duplex_fc(&p->mac, -1, -1, lc->fc);
+ }
+ return 0;
+}
+
+static u32 get_rx_csum(struct net_device *dev)
+{
+ struct port_info *p = netdev_priv(dev);
+
+ return p->rx_csum_offload;
+}
+
+static int set_rx_csum(struct net_device *dev, u32 data)
+{
+ struct port_info *p = netdev_priv(dev);
+
+ p->rx_csum_offload = data;
+ return 0;
+}
+
+static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
+{
+ struct adapter *adapter = dev->priv;
+
+ e->rx_max_pending = MAX_RX_BUFFERS;
+ e->rx_mini_max_pending = 0;
+ e->rx_jumbo_max_pending = MAX_RX_JUMBO_BUFFERS;
+ e->tx_max_pending = MAX_TXQ_ENTRIES;
+
+ e->rx_pending = adapter->params.sge.qset[0].fl_size;
+ e->rx_mini_pending = adapter->params.sge.qset[0].rspq_size;
+ e->rx_jumbo_pending = adapter->params.sge.qset[0].jumbo_size;
+ e->tx_pending = adapter->params.sge.qset[0].txq_size[0];
+}
+
+static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
+{
+ int i;
+ struct adapter *adapter = dev->priv;
+
+ if (e->rx_pending > MAX_RX_BUFFERS ||
+ e->rx_jumbo_pending > MAX_RX_JUMBO_BUFFERS ||
+ e->tx_pending > MAX_TXQ_ENTRIES ||
+ e->rx_mini_pending > MAX_RSPQ_ENTRIES ||
+ e->rx_mini_pending < MIN_RSPQ_ENTRIES ||
+ e->rx_pending < MIN_FL_ENTRIES ||
+ e->rx_jumbo_pending < MIN_FL_ENTRIES ||
+ e->tx_pending < adapter->params.nports * MIN_TXQ_ENTRIES)
+ return -EINVAL;
+
+ if (adapter->flags & FULL_INIT_DONE)
+ return -EBUSY;
+
+ for (i = 0; i < SGE_QSETS; ++i) {
+ struct qset_params *q = &adapter->params.sge.qset[i];
+
+ q->rspq_size = e->rx_mini_pending;
+ q->fl_size = e->rx_pending;
+ q->jumbo_size = e->rx_jumbo_pending;
+ q->txq_size[0] = e->tx_pending;
+ q->txq_size[1] = e->tx_pending;
+ q->txq_size[2] = e->tx_pending;
+ }
+ return 0;
+}
+
+static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
+{
+ struct adapter *adapter = dev->priv;
+ struct qset_params *qsp = &adapter->params.sge.qset[0];
+ struct sge_qset *qs = &adapter->sge.qs[0];
+
+ if (c->rx_coalesce_usecs * 10 > M_NEWTIMER)
+ return -EINVAL;
+
+ qsp->coalesce_usecs = c->rx_coalesce_usecs;
+ t3_update_qset_coalesce(qs, qsp);
+ return 0;
+}
+
+static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
+{
+ struct adapter *adapter = dev->priv;
+ struct qset_params *q = adapter->params.sge.qset;
+
+ c->rx_coalesce_usecs = q->coalesce_usecs;
+ return 0;
+}
+
+static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e,
+ u8 * data)
+{
+ int i, err = 0;
+ struct adapter *adapter = dev->priv;
+
+ u8 *buf = kmalloc(EEPROMSIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ e->magic = EEPROM_MAGIC;
+ for (i = e->offset & ~3; !err && i < e->offset + e->len; i += 4)
+ err = t3_seeprom_read(adapter, i, (u32 *) & buf[i]);
+
+ if (!err)
+ memcpy(data, buf + e->offset, e->len);
+ kfree(buf);
+ return err;
+}
+
+static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
+ u8 * data)
+{
+ u8 *buf;
+ int err = 0;
+ u32 aligned_offset, aligned_len, *p;
+ struct adapter *adapter = dev->priv;
+
+ if (eeprom->magic != EEPROM_MAGIC)
+ return -EINVAL;
+
+ aligned_offset = eeprom->offset & ~3;
+ aligned_len = (eeprom->len + (eeprom->offset & 3) + 3) & ~3;
+
+ if (aligned_offset != eeprom->offset || aligned_len != eeprom->len) {
+ buf = kmalloc(aligned_len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+ err = t3_seeprom_read(adapter, aligned_offset, (u32 *) buf);
+ if (!err && aligned_len > 4)
+ err = t3_seeprom_read(adapter,
+ aligned_offset + aligned_len - 4,
+ (u32 *) & buf[aligned_len - 4]);
+ if (err)
+ goto out;
+ memcpy(buf + (eeprom->offset & 3), data, eeprom->len);
+ } else
+ buf = data;
+
+ err = t3_seeprom_wp(adapter, 0);
+ if (err)
+ goto out;
+
+ for (p = (u32 *) buf; !err && aligned_len; aligned_len -= 4, p++) {
+ err = t3_seeprom_write(adapter, aligned_offset, *p);
+ aligned_offset += 4;
+ }
+
+ if (!err)
+ err = t3_seeprom_wp(adapter, 1);
+out:
+ if (buf != data)
+ kfree(buf);
+ return err;
+}
+
+static void get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ wol->supported = 0;
+ wol->wolopts = 0;
+ memset(&wol->sopass, 0, sizeof(wol->sopass));
+}
+
+static const struct ethtool_ops cxgb_ethtool_ops = {
+ .get_settings = get_settings,
+ .set_settings = set_settings,
+ .get_drvinfo = get_drvinfo,
+ .get_msglevel = get_msglevel,
+ .set_msglevel = set_msglevel,
+ .get_ringparam = get_sge_param,
+ .set_ringparam = set_sge_param,
+ .get_coalesce = get_coalesce,
+ .set_coalesce = set_coalesce,
+ .get_eeprom_len = get_eeprom_len,
+ .get_eeprom = get_eeprom,
+ .set_eeprom = set_eeprom,
+ .get_pauseparam = get_pauseparam,
+ .set_pauseparam = set_pauseparam,
+ .get_rx_csum = get_rx_csum,
+ .set_rx_csum = set_rx_csum,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .set_tx_csum = ethtool_op_set_tx_csum,
+ .get_sg = ethtool_op_get_sg,
+ .set_sg = ethtool_op_set_sg,
+ .get_link = ethtool_op_get_link,
+ .get_strings = get_strings,
+ .phys_id = cxgb3_phys_id,
+ .nway_reset = restart_autoneg,
+ .get_stats_count = get_stats_count,
+ .get_ethtool_stats = get_stats,
+ .get_regs_len = get_regs_len,
+ .get_regs = get_regs,
+ .get_wol = get_wol,
+ .get_tso = ethtool_op_get_tso,
+ .set_tso = ethtool_op_set_tso,
+ .get_perm_addr = ethtool_op_get_perm_addr
+};
+
+static int in_range(int val, int lo, int hi)
+{
+ return val < 0 || (val <= hi && val >= lo);
+}
+
+static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
+{
+ int ret;
+ u32 cmd;
+ struct adapter *adapter = dev->priv;
+
+ if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
+ return -EFAULT;
+
+ switch (cmd) {
+ case CHELSIO_SETREG:{
+ struct ch_reg edata;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (copy_from_user(&edata, useraddr, sizeof(edata)))
+ return -EFAULT;
+ if ((edata.addr & 3) != 0
+ || edata.addr >= adapter->mmio_len)
+ return -EINVAL;
+ writel(edata.val, adapter->regs + edata.addr);
+ break;
+ }
+ case CHELSIO_GETREG:{
+ struct ch_reg edata;
+
+ if (copy_from_user(&edata, useraddr, sizeof(edata)))
+ return -EFAULT;
+ if ((edata.addr & 3) != 0
+ || edata.addr >= adapter->mmio_len)
+ return -EINVAL;
+ edata.val = readl(adapter->regs + edata.addr);
+ if (copy_to_user(useraddr, &edata, sizeof(edata)))
+ return -EFAULT;
+ break;
+ }
+ case CHELSIO_SET_QSET_PARAMS:{
+ int i;
+ struct qset_params *q;
+ struct ch_qset_params t;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (copy_from_user(&t, useraddr, sizeof(t)))
+ return -EFAULT;
+ if (t.qset_idx >= SGE_QSETS)
+ return -EINVAL;
+ if (!in_range(t.intr_lat, 0, M_NEWTIMER) ||
+ !in_range(t.cong_thres, 0, 255) ||
+ !in_range(t.txq_size[0], MIN_TXQ_ENTRIES,
+ MAX_TXQ_ENTRIES) ||
+ !in_range(t.txq_size[1], MIN_TXQ_ENTRIES,
+ MAX_TXQ_ENTRIES) ||
+ !in_range(t.txq_size[2], MIN_CTRL_TXQ_ENTRIES,
+ MAX_CTRL_TXQ_ENTRIES) ||
+ !in_range(t.fl_size[0], MIN_FL_ENTRIES,
+ MAX_RX_BUFFERS)
+ || !in_range(t.fl_size[1], MIN_FL_ENTRIES,
+ MAX_RX_JUMBO_BUFFERS)
+ || !in_range(t.rspq_size, MIN_RSPQ_ENTRIES,
+ MAX_RSPQ_ENTRIES))
+ return -EINVAL;
+ if ((adapter->flags & FULL_INIT_DONE) &&
+ (t.rspq_size >= 0 || t.fl_size[0] >= 0 ||
+ t.fl_size[1] >= 0 || t.txq_size[0] >= 0 ||
+ t.txq_size[1] >= 0 || t.txq_size[2] >= 0 ||
+ t.polling >= 0 || t.cong_thres >= 0))
+ return -EBUSY;
+
+ q = &adapter->params.sge.qset[t.qset_idx];
+
+ if (t.rspq_size >= 0)
+ q->rspq_size = t.rspq_size;
+ if (t.fl_size[0] >= 0)
+ q->fl_size = t.fl_size[0];
+ if (t.fl_size[1] >= 0)
+ q->jumbo_size = t.fl_size[1];
+ if (t.txq_size[0] >= 0)
+ q->txq_size[0] = t.txq_size[0];
+ if (t.txq_size[1] >= 0)
+ q->txq_size[1] = t.txq_size[1];
+ if (t.txq_size[2] >= 0)
+ q->txq_size[2] = t.txq_size[2];
+ if (t.cong_thres >= 0)
+ q->cong_thres = t.cong_thres;
+ if (t.intr_lat >= 0) {
+ struct sge_qset *qs =
+ &adapter->sge.qs[t.qset_idx];
+
+ q->coalesce_usecs = t.intr_lat;
+ t3_update_qset_coalesce(qs, q);
+ }
+ if (t.polling >= 0) {
+ if (adapter->flags & USING_MSIX)
+ q->polling = t.polling;
+ else {
+ /* No polling with INTx for T3A */
+ if (adapter->params.rev == 0 &&
+ !(adapter->flags & USING_MSI))
+ t.polling = 0;
+
+ for (i = 0; i < SGE_QSETS; i++) {
+ q = &adapter->params.sge.
+ qset[i];
+ q->polling = t.polling;
+ }
+ }
+ }
+ break;
+ }
+ case CHELSIO_GET_QSET_PARAMS:{
+ struct qset_params *q;
+ struct ch_qset_params t;
+
+ if (copy_from_user(&t, useraddr, sizeof(t)))
+ return -EFAULT;
+ if (t.qset_idx >= SGE_QSETS)
+ return -EINVAL;
+
+ q = &adapter->params.sge.qset[t.qset_idx];
+ t.rspq_size = q->rspq_size;
+ t.txq_size[0] = q->txq_size[0];
+ t.txq_size[1] = q->txq_size[1];
+ t.txq_size[2] = q->txq_size[2];
+ t.fl_size[0] = q->fl_size;
+ t.fl_size[1] = q->jumbo_size;
+ t.polling = q->polling;
+ t.intr_lat = q->coalesce_usecs;
+ t.cong_thres = q->cong_thres;
+
+ if (copy_to_user(useraddr, &t, sizeof(t)))
+ return -EFAULT;
+ break;
+ }
+ case CHELSIO_SET_QSET_NUM:{
+ struct ch_reg edata;
+ struct port_info *pi = netdev_priv(dev);
+ unsigned int i, first_qset = 0, other_qsets = 0;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (adapter->flags & FULL_INIT_DONE)
+ return -EBUSY;
+ if (copy_from_user(&edata, useraddr, sizeof(edata)))
+ return -EFAULT;
+ if (edata.val < 1 ||
+ (edata.val > 1 && !(adapter->flags & USING_MSIX)))
+ return -EINVAL;
+
+ for_each_port(adapter, i)
+ if (adapter->port[i] && adapter->port[i] != dev)
+ other_qsets += adap2pinfo(adapter, i)->nqsets;
+
+ if (edata.val + other_qsets > SGE_QSETS)
+ return -EINVAL;
+
+ pi->nqsets = edata.val;
+
+ for_each_port(adapter, i)
+ if (adapter->port[i]) {
+ pi = adap2pinfo(adapter, i);
+ pi->first_qset = first_qset;
+ first_qset += pi->nqsets;
+ }
+ break;
+ }
+ case CHELSIO_GET_QSET_NUM:{
+ struct ch_reg edata;
+ struct port_info *pi = netdev_priv(dev);
+
+ edata.cmd = CHELSIO_GET_QSET_NUM;
+ edata.val = pi->nqsets;
+ if (copy_to_user(useraddr, &edata, sizeof(edata)))
+ return -EFAULT;
+ break;
+ }
+ case CHELSIO_LOAD_FW:{
+ u8 *fw_data;
+ struct ch_mem_range t;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (copy_from_user(&t, useraddr, sizeof(t)))
+ return -EFAULT;
+
+ fw_data = kmalloc(t.len, GFP_KERNEL);
+ if (!fw_data)
+ return -ENOMEM;
+
+ if (copy_from_user
+ (fw_data, useraddr + sizeof(t), t.len)) {
+ kfree(fw_data);
+ return -EFAULT;
+ }
+
+ ret = t3_load_fw(adapter, fw_data, t.len);
+ kfree(fw_data);
+ if (ret)
+ return ret;
+ break;
+ }
+ case CHELSIO_SETMTUTAB:{
+ struct ch_mtus m;
+ int i;
+
+ if (!is_offload(adapter))
+ return -EOPNOTSUPP;
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (offload_running(adapter))
+ return -EBUSY;
+ if (copy_from_user(&m, useraddr, sizeof(m)))
+ return -EFAULT;
+ if (m.nmtus != NMTUS)
+ return -EINVAL;
+ if (m.mtus[0] < 81) /* accommodate SACK */
+ return -EINVAL;
+
+ /* MTUs must be in ascending order */
+ for (i = 1; i < NMTUS; ++i)
+ if (m.mtus[i] < m.mtus[i - 1])
+ return -EINVAL;
+
+ memcpy(adapter->params.mtus, m.mtus,
+ sizeof(adapter->params.mtus));
+ break;
+ }
+ case CHELSIO_GET_PM:{
+ struct tp_params *p = &adapter->params.tp;
+ struct ch_pm m = {.cmd = CHELSIO_GET_PM };
+
+ if (!is_offload(adapter))
+ return -EOPNOTSUPP;
+ m.tx_pg_sz = p->tx_pg_size;
+ m.tx_num_pg = p->tx_num_pgs;
+ m.rx_pg_sz = p->rx_pg_size;
+ m.rx_num_pg = p->rx_num_pgs;
+ m.pm_total = p->pmtx_size + p->chan_rx_size * p->nchan;
+ if (copy_to_user(useraddr, &m, sizeof(m)))
+ return -EFAULT;
+ break;
+ }
+ case CHELSIO_SET_PM:{
+ struct ch_pm m;
+ struct tp_params *p = &adapter->params.tp;
+
+ if (!is_offload(adapter))
+ return -EOPNOTSUPP;
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (adapter->flags & FULL_INIT_DONE)
+ return -EBUSY;
+ if (copy_from_user(&m, useraddr, sizeof(m)))
+ return -EFAULT;
+ if (!m.rx_pg_sz || (m.rx_pg_sz & (m.rx_pg_sz - 1)) ||
+ !m.tx_pg_sz || (m.tx_pg_sz & (m.tx_pg_sz - 1)))
+ return -EINVAL; /* not power of 2 */
+ if (!(m.rx_pg_sz & 0x14000))
+ return -EINVAL; /* not 16KB or 64KB */
+ if (!(m.tx_pg_sz & 0x1554000))
+ return -EINVAL;
+ if (m.tx_num_pg == -1)
+ m.tx_num_pg = p->tx_num_pgs;
+ if (m.rx_num_pg == -1)
+ m.rx_num_pg = p->rx_num_pgs;
+ if (m.tx_num_pg % 24 || m.rx_num_pg % 24)
+ return -EINVAL;
+ if (m.rx_num_pg * m.rx_pg_sz > p->chan_rx_size ||
+ m.tx_num_pg * m.tx_pg_sz > p->chan_tx_size)
+ return -EINVAL;
+ p->rx_pg_size = m.rx_pg_sz;
+ p->tx_pg_size = m.tx_pg_sz;
+ p->rx_num_pgs = m.rx_num_pg;
+ p->tx_num_pgs = m.tx_num_pg;
+ break;
+ }
+ case CHELSIO_GET_MEM:{
+ struct ch_mem_range t;
+ struct mc7 *mem;
+ u64 buf[32];
+
+ if (!is_offload(adapter))
+ return -EOPNOTSUPP;
+ if (!(adapter->flags & FULL_INIT_DONE))
+ return -EIO; /* need the memory controllers */
+ if (copy_from_user(&t, useraddr, sizeof(t)))
+ return -EFAULT;
+ if ((t.addr & 7) || (t.len & 7))
+ return -EINVAL;
+ if (t.mem_id == MEM_CM)
+ mem = &adapter->cm;
+ else if (t.mem_id == MEM_PMRX)
+ mem = &adapter->pmrx;
+ else if (t.mem_id == MEM_PMTX)
+ mem = &adapter->pmtx;
+ else
+ return -EINVAL;
+
+ /*
+ * Version scheme:
+ * bits 0..9: chip version
+ * bits 10..15: chip revision
+ */
+ t.version = 3 | (adapter->params.rev << 10);
+ if (copy_to_user(useraddr, &t, sizeof(t)))
+ return -EFAULT;
+
+ /*
+ * Read 256 bytes at a time as len can be large and we don't
+ * want to use huge intermediate buffers.
+ */
+ useraddr += sizeof(t); /* advance to start of buffer */
+ while (t.len) {
+ unsigned int chunk =
+ min_t(unsigned int, t.len, sizeof(buf));
+
+ ret =
+ t3_mc7_bd_read(mem, t.addr / 8, chunk / 8,
+ buf);
+ if (ret)
+ return ret;
+ if (copy_to_user(useraddr, buf, chunk))
+ return -EFAULT;
+ useraddr += chunk;
+ t.addr += chunk;
+ t.len -= chunk;
+ }
+ break;
+ }
+ case CHELSIO_SET_TRACE_FILTER:{
+ struct ch_trace t;
+ const struct trace_params *tp;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (!offload_running(adapter))
+ return -EAGAIN;
+ if (copy_from_user(&t, useraddr, sizeof(t)))
+ return -EFAULT;
+
+ tp = (const struct trace_params *)&t.sip;
+ if (t.config_tx)
+ t3_config_trace_filter(adapter, tp, 0,
+ t.invert_match,
+ t.trace_tx);
+ if (t.config_rx)
+ t3_config_trace_filter(adapter, tp, 1,
+ t.invert_match,
+ t.trace_rx);
+ break;
+ }
+ case CHELSIO_SET_PKTSCHED:{
+ struct ch_pktsched_params p;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (!adapter->open_device_map)
+ return -EAGAIN; /* uP and SGE must be running */
+ if (copy_from_user(&p, useraddr, sizeof(p)))
+ return -EFAULT;
+ send_pktsched_cmd(adapter, p.sched, p.idx, p.min, p.max,
+ p.binding);
+ break;
+
+ }
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
+{
+ int ret, mmd;
+ struct adapter *adapter = dev->priv;
+ struct port_info *pi = netdev_priv(dev);
+ struct mii_ioctl_data *data = if_mii(req);
+
+ switch (cmd) {
+ case SIOCGMIIPHY:
+ data->phy_id = pi->phy.addr;
+ /* FALLTHRU */
+ case SIOCGMIIREG:{
+ u32 val;
+ struct cphy *phy = &pi->phy;
+
+ if (!phy->mdio_read)
+ return -EOPNOTSUPP;
+ if (is_10G(adapter)) {
+ mmd = data->phy_id >> 8;
+ if (!mmd)
+ mmd = MDIO_DEV_PCS;
+ else if (mmd > MDIO_DEV_XGXS)
+ return -EINVAL;
+
+ ret =
+ phy->mdio_read(adapter, data->phy_id & 0x1f,
+ mmd, data->reg_num, &val);
+ } else
+ ret =
+ phy->mdio_read(adapter, data->phy_id & 0x1f,
+ 0, data->reg_num & 0x1f,
+ &val);
+ if (!ret)
+ data->val_out = val;
+ break;
+ }
+ case SIOCSMIIREG:{
+ struct cphy *phy = &pi->phy;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (!phy->mdio_write)
+ return -EOPNOTSUPP;
+ if (is_10G(adapter)) {
+ mmd = data->phy_id >> 8;
+ if (!mmd)
+ mmd = MDIO_DEV_PCS;
+ else if (mmd > MDIO_DEV_XGXS)
+ return -EINVAL;
+
+ ret =
+ phy->mdio_write(adapter,
+ data->phy_id & 0x1f, mmd,
+ data->reg_num,
+ data->val_in);
+ } else
+ ret =
+ phy->mdio_write(adapter,
+ data->phy_id & 0x1f, 0,
+ data->reg_num & 0x1f,
+ data->val_in);
+ break;
+ }
+ case SIOCCHIOCTL:
+ return cxgb_extension_ioctl(dev, req->ifr_data);
+ default:
+ return -EOPNOTSUPP;
+ }
+ return ret;
+}
+
+static int cxgb_change_mtu(struct net_device *dev, int new_mtu)
+{
+ int ret;
+ struct adapter *adapter = dev->priv;
+ struct port_info *pi = netdev_priv(dev);
+
+ if (new_mtu < 81) /* accommodate SACK */
+ return -EINVAL;
+ if ((ret = t3_mac_set_mtu(&pi->mac, new_mtu)))
+ return ret;
+ dev->mtu = new_mtu;
+ init_port_mtus(adapter);
+ if (adapter->params.rev == 0 && offload_running(adapter))
+ t3_load_mtus(adapter, adapter->params.mtus,
+ adapter->params.a_wnd, adapter->params.b_wnd,
+ adapter->port[0]->mtu);
+ return 0;
+}
+
+static int cxgb_set_mac_addr(struct net_device *dev, void *p)
+{
+ struct adapter *adapter = dev->priv;
+ struct port_info *pi = netdev_priv(dev);
+ struct sockaddr *addr = p;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EINVAL;
+
+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+ t3_mac_set_address(&pi->mac, 0, dev->dev_addr);
+ if (offload_running(adapter))
+ write_smt_entry(adapter, pi->port_id);
+ return 0;
+}
+
+/**
+ * t3_synchronize_rx - wait for current Rx processing on a port to complete
+ * @adap: the adapter
+ * @p: the port
+ *
+ * Ensures that current Rx processing on any of the queues associated with
+ * the given port completes before returning. We do this by acquiring and
+ * releasing the locks of the response queues associated with the port.
+ */
+static void t3_synchronize_rx(struct adapter *adap, const struct port_info *p)
+{
+ int i;
+
+ for (i = 0; i < p->nqsets; i++) {
+ struct sge_rspq *q = &adap->sge.qs[i + p->first_qset].rspq;
+
+ spin_lock_irq(&q->lock);
+ spin_unlock_irq(&q->lock);
+ }
+}
+
+static void vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
+{
+ struct adapter *adapter = dev->priv;
+ struct port_info *pi = netdev_priv(dev);
+
+ pi->vlan_grp = grp;
+ if (adapter->params.rev > 0)
+ t3_set_vlan_accel(adapter, 1 << pi->port_id, grp != NULL);
+ else {
+ /* single control for all ports */
+ unsigned int i, have_vlans = 0;
+ for_each_port(adapter, i)
+ have_vlans |= adap2pinfo(adapter, i)->vlan_grp != NULL;
+
+ t3_set_vlan_accel(adapter, 1, have_vlans);
+ }
+ t3_synchronize_rx(adapter, pi);
+}
+
+static void vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
+{
+ /* nothing */
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void cxgb_netpoll(struct net_device *dev)
+{
+ struct adapter *adapter = dev->priv;
+ struct sge_qset *qs = dev2qset(dev);
+
+ t3_intr_handler(adapter, qs->rspq.polling) (adapter->pdev->irq,
+ adapter);
+}
+#endif
+
+/*
+ * Periodic accumulation of MAC statistics.
+ */
+static void mac_stats_update(struct adapter *adapter)
+{
+ int i;
+
+ for_each_port(adapter, i) {
+ struct net_device *dev = adapter->port[i];
+ struct port_info *p = netdev_priv(dev);
+
+ if (netif_running(dev)) {
+ spin_lock(&adapter->stats_lock);
+ t3_mac_update_stats(&p->mac);
+ spin_unlock(&adapter->stats_lock);
+ }
+ }
+}
+
+static void check_link_status(struct adapter *adapter)
+{
+ int i;
+
+ for_each_port(adapter, i) {
+ struct net_device *dev = adapter->port[i];
+ struct port_info *p = netdev_priv(dev);
+
+ if (!(p->port_type->caps & SUPPORTED_IRQ) && netif_running(dev))
+ t3_link_changed(adapter, i);
+ }
+}
+
+static void t3_adap_check_task(struct work_struct *work)
+{
+ struct adapter *adapter = container_of(work, struct adapter,
+ adap_check_task.work);
+ const struct adapter_params *p = &adapter->params;
+
+ adapter->check_task_cnt++;
+
+ /* Check link status for PHYs without interrupts */
+ if (p->linkpoll_period)
+ check_link_status(adapter);
+
+ /* Accumulate MAC stats if needed */
+ if (!p->linkpoll_period ||
+ (adapter->check_task_cnt * p->linkpoll_period) / 10 >=
+ p->stats_update_period) {
+ mac_stats_update(adapter);
+ adapter->check_task_cnt = 0;
+ }
+
+ /* Schedule the next check update if any port is active. */
+ spin_lock(&adapter->work_lock);
+ if (adapter->open_device_map & PORT_MASK)
+ schedule_chk_task(adapter);
+ spin_unlock(&adapter->work_lock);
+}
+
+/*
+ * Processes external (PHY) interrupts in process context.
+ */
+static void ext_intr_task(struct work_struct *work)
+{
+ struct adapter *adapter = container_of(work, struct adapter,
+ ext_intr_handler_task);
+
+ t3_phy_intr_handler(adapter);
+
+ /* Now reenable external interrupts */
+ spin_lock_irq(&adapter->work_lock);
+ if (adapter->slow_intr_mask) {
+ adapter->slow_intr_mask |= F_T3DBG;
+ t3_write_reg(adapter, A_PL_INT_CAUSE0, F_T3DBG);
+ t3_write_reg(adapter, A_PL_INT_ENABLE0,
+ adapter->slow_intr_mask);
+ }
+ spin_unlock_irq(&adapter->work_lock);
+}
+
+/*
+ * Interrupt-context handler for external (PHY) interrupts.
+ */
+void t3_os_ext_intr_handler(struct adapter *adapter)
+{
+ /*
+ * Schedule a task to handle external interrupts as they may be slow
+ * and we use a mutex to protect MDIO registers. We disable PHY
+ * interrupts in the meantime and let the task reenable them when
+ * it's done.
+ */
+ spin_lock(&adapter->work_lock);
+ if (adapter->slow_intr_mask) {
+ adapter->slow_intr_mask &= ~F_T3DBG;
+ t3_write_reg(adapter, A_PL_INT_ENABLE0,
+ adapter->slow_intr_mask);
+ queue_work(cxgb3_wq, &adapter->ext_intr_handler_task);
+ }
+ spin_unlock(&adapter->work_lock);
+}
+
+void t3_fatal_err(struct adapter *adapter)
+{
+ unsigned int fw_status[4];
+
+ if (adapter->flags & FULL_INIT_DONE) {
+ t3_sge_stop(adapter);
+ t3_intr_disable(adapter);
+ }
+ CH_ALERT(adapter, "encountered fatal error, operation suspended\n");
+ if (!t3_cim_ctl_blk_read(adapter, 0xa0, 4, fw_status))
+ CH_ALERT(adapter, "FW status: 0x%x, 0x%x, 0x%x, 0x%x\n",
+ fw_status[0], fw_status[1],
+ fw_status[2], fw_status[3]);
+
+}
+
+static int __devinit cxgb_enable_msix(struct adapter *adap)
+{
+ struct msix_entry entries[SGE_QSETS + 1];
+ int i, err;
+
+ for (i = 0; i < ARRAY_SIZE(entries); ++i)
+ entries[i].entry = i;
+
+ err = pci_enable_msix(adap->pdev, entries, ARRAY_SIZE(entries));
+ if (!err) {
+ for (i = 0; i < ARRAY_SIZE(entries); ++i)
+ adap->msix_info[i].vec = entries[i].vector;
+ } else if (err > 0)
+ dev_info(&adap->pdev->dev,
+ "only %d MSI-X vectors left, not using MSI-X\n", err);
+ return err;
+}
+
+static void __devinit print_port_info(struct adapter *adap,
+ const struct adapter_info *ai)
+{
+ static const char *pci_variant[] = {
+ "PCI", "PCI-X", "PCI-X ECC", "PCI-X 266", "PCI Express"
+ };
+
+ int i;
+ char buf[80];
+
+ if (is_pcie(adap))
+ snprintf(buf, sizeof(buf), "%s x%d",
+ pci_variant[adap->params.pci.variant],
+ adap->params.pci.width);
+ else
+ snprintf(buf, sizeof(buf), "%s %dMHz/%d-bit",
+ pci_variant[adap->params.pci.variant],
+ adap->params.pci.speed, adap->params.pci.width);
+
+ for_each_port(adap, i) {
+ struct net_device *dev = adap->port[i];
+ const struct port_info *pi = netdev_priv(dev);
+
+ if (!test_bit(i, &adap->registered_device_map))
+ continue;
+ printk(KERN_INFO "%s: %s %s RNIC (rev %d) %s%s\n",
+ dev->name, ai->desc, pi->port_type->desc,
+ adap->params.rev, buf,
+ (adap->flags & USING_MSIX) ? " MSI-X" :
+ (adap->flags & USING_MSI) ? " MSI" : "");
+ if (adap->name == dev->name && adap->params.vpd.mclk)
+ printk(KERN_INFO "%s: %uMB CM, %uMB PMTX, %uMB PMRX\n",
+ adap->name, t3_mc7_size(&adap->cm) >> 20,
+ t3_mc7_size(&adap->pmtx) >> 20,
+ t3_mc7_size(&adap->pmrx) >> 20);
+ }
+}
+
+static int __devinit init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ static int version_printed;
+
+ int i, err, pci_using_dac = 0;
+ unsigned long mmio_start, mmio_len;
+ const struct adapter_info *ai;
+ struct adapter *adapter = NULL;
+ struct port_info *pi;
+
+ if (!version_printed) {
+ printk(KERN_INFO "%s - version %s\n", DRV_DESC, DRV_VERSION);
+ ++version_printed;
+ }
+
+ if (!cxgb3_wq) {
+ cxgb3_wq = create_singlethread_workqueue(DRV_NAME);
+ if (!cxgb3_wq) {
+ printk(KERN_ERR DRV_NAME
+ ": cannot initialize work queue\n");
+ return -ENOMEM;
+ }
+ }
+
+ err = pci_request_regions(pdev, DRV_NAME);
+ if (err) {
+ /* Just info, some other driver may have claimed the device. */
+ dev_info(&pdev->dev, "cannot obtain PCI resources\n");
+ return err;
+ }
+
+ err = pci_enable_device(pdev);
+ if (err) {
+ dev_err(&pdev->dev, "cannot enable PCI device\n");
+ goto out_release_regions;
+ }
+
+ if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
+ pci_using_dac = 1;
+ err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+ if (err) {
+ dev_err(&pdev->dev, "unable to obtain 64-bit DMA for "
+ "coherent allocations\n");
+ goto out_disable_device;
+ }
+ } else if ((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) != 0) {
+ dev_err(&pdev->dev, "no usable DMA configuration\n");
+ goto out_disable_device;
+ }
+
+ pci_set_master(pdev);
+
+ mmio_start = pci_resource_start(pdev, 0);
+ mmio_len = pci_resource_len(pdev, 0);
+ ai = t3_get_adapter_info(ent->driver_data);
+
+ adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
+ if (!adapter) {
+ err = -ENOMEM;
+ goto out_disable_device;
+ }
+
+ adapter->regs = ioremap_nocache(mmio_start, mmio_len);
+ if (!adapter->regs) {
+ dev_err(&pdev->dev, "cannot map device registers\n");
+ err = -ENOMEM;
+ goto out_free_adapter;
+ }
+
+ adapter->pdev = pdev;
+ adapter->name = pci_name(pdev);
+ adapter->msg_enable = dflt_msg_enable;
+ adapter->mmio_len = mmio_len;
+
+ mutex_init(&adapter->mdio_lock);
+ spin_lock_init(&adapter->work_lock);
+ spin_lock_init(&adapter->stats_lock);
+
+ INIT_LIST_HEAD(&adapter->adapter_list);
+ INIT_WORK(&adapter->ext_intr_handler_task, ext_intr_task);
+ INIT_DELAYED_WORK(&adapter->adap_check_task, t3_adap_check_task);
+
+ for (i = 0; i < ai->nports; ++i) {
+ struct net_device *netdev;
+
+ netdev = alloc_etherdev(sizeof(struct port_info));
+ if (!netdev) {
+ err = -ENOMEM;
+ goto out_free_dev;
+ }
+
+ SET_MODULE_OWNER(netdev);
+ SET_NETDEV_DEV(netdev, &pdev->dev);
+
+ adapter->port[i] = netdev;
+ pi = netdev_priv(netdev);
+ pi->rx_csum_offload = 1;
+ pi->nqsets = 1;
+ pi->first_qset = i;
+ pi->activity = 0;
+ pi->port_id = i;
+ netif_carrier_off(netdev);
+ netdev->irq = pdev->irq;
+ netdev->mem_start = mmio_start;
+ netdev->mem_end = mmio_start + mmio_len - 1;
+ netdev->priv = adapter;
+ netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
+ netdev->features |= NETIF_F_LLTX;
+ if (pci_using_dac)
+ netdev->features |= NETIF_F_HIGHDMA;
+
+ netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+ netdev->vlan_rx_register = vlan_rx_register;
+ netdev->vlan_rx_kill_vid = vlan_rx_kill_vid;
+
+ netdev->open = cxgb_open;
+ netdev->stop = cxgb_close;
+ netdev->hard_start_xmit = t3_eth_xmit;
+ netdev->get_stats = cxgb_get_stats;
+ netdev->set_multicast_list = cxgb_set_rxmode;
+ netdev->do_ioctl = cxgb_ioctl;
+ netdev->change_mtu = cxgb_change_mtu;
+ netdev->set_mac_address = cxgb_set_mac_addr;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ netdev->poll_controller = cxgb_netpoll;
+#endif
+ netdev->weight = 64;
+
+ SET_ETHTOOL_OPS(netdev, &cxgb_ethtool_ops);
+ }
+
+ pci_set_drvdata(pdev, adapter->port[0]);
+ if (t3_prep_adapter(adapter, ai, 1) < 0) {
+ err = -ENODEV;
+ goto out_free_dev;
+ }
+
+ /*
+ * The card is now ready to go. If any errors occur during device
+ * registration we do not fail the whole card but rather proceed only
+ * with the ports we manage to register successfully. However we must
+ * register at least one net device.
+ */
+ for_each_port(adapter, i) {
+ err = register_netdev(adapter->port[i]);
+ if (err)
+ dev_warn(&pdev->dev,
+ "cannot register net device %s, skipping\n",
+ adapter->port[i]->name);
+ else {
+ /*
+ * Change the name we use for messages to the name of
+ * the first successfully registered interface.
+ */
+ if (!adapter->registered_device_map)
+ adapter->name = adapter->port[i]->name;
+
+ __set_bit(i, &adapter->registered_device_map);
+ }
+ }
+ if (!adapter->registered_device_map) {
+ dev_err(&pdev->dev, "could not register any net devices\n");
+ goto out_free_dev;
+ }
+
+ /* Driver's ready. Reflect it on LEDs */
+ t3_led_ready(adapter);
+
+ if (is_offload(adapter)) {
+ __set_bit(OFFLOAD_DEVMAP_BIT, &adapter->registered_device_map);
+ cxgb3_adapter_ofld(adapter);
+ }
+
+ /* See what interrupts we'll be using */
+ if (msi > 1 && cxgb_enable_msix(adapter) == 0)
+ adapter->flags |= USING_MSIX;
+ else if (msi > 0 && pci_enable_msi(pdev) == 0)
+ adapter->flags |= USING_MSI;
+
+ err = sysfs_create_group(&adapter->port[0]->dev.kobj,
+ &cxgb3_attr_group);
+
+ print_port_info(adapter, ai);
+ return 0;
+
+out_free_dev:
+ iounmap(adapter->regs);
+ for (i = ai->nports - 1; i >= 0; --i)
+ if (adapter->port[i])
+ free_netdev(adapter->port[i]);
+
+out_free_adapter:
+ kfree(adapter);
+
+out_disable_device:
+ pci_disable_device(pdev);
+out_release_regions:
+ pci_release_regions(pdev);
+ pci_set_drvdata(pdev, NULL);
+ return err;
+}
+
+static void __devexit remove_one(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+
+ if (dev) {
+ int i;
+ struct adapter *adapter = dev->priv;
+
+ t3_sge_stop(adapter);
+ sysfs_remove_group(&adapter->port[0]->dev.kobj,
+ &cxgb3_attr_group);
+
+ for_each_port(adapter, i)
+ if (test_bit(i, &adapter->registered_device_map))
+ unregister_netdev(adapter->port[i]);
+
+ if (is_offload(adapter)) {
+ cxgb3_adapter_unofld(adapter);
+ if (test_bit(OFFLOAD_DEVMAP_BIT,
+ &adapter->open_device_map))
+ offload_close(&adapter->tdev);
+ }
+
+ t3_free_sge_resources(adapter);
+ cxgb_disable_msi(adapter);
+
+ for (i = 0; i < ARRAY_SIZE(adapter->dummy_netdev); i++)
+ if (adapter->dummy_netdev[i]) {
+ free_netdev(adapter->dummy_netdev[i]);
+ adapter->dummy_netdev[i] = NULL;
+ }
+
+ for_each_port(adapter, i)
+ if (adapter->port[i])
+ free_netdev(adapter->port[i]);
+
+ iounmap(adapter->regs);
+ kfree(adapter);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+ }
+}
+
+static struct pci_driver driver = {
+ .name = DRV_NAME,
+ .id_table = cxgb3_pci_tbl,
+ .probe = init_one,
+ .remove = __devexit_p(remove_one),
+};
+
+static int __init cxgb3_init_module(void)
+{
+ int ret;
+
+ cxgb3_offload_init();
+
+ ret = pci_register_driver(&driver);
+ return ret;
+}
+
+static void __exit cxgb3_cleanup_module(void)
+{
+ pci_unregister_driver(&driver);
+ if (cxgb3_wq)
+ destroy_workqueue(cxgb3_wq);
+}
+
+module_init(cxgb3_init_module);
+module_exit(cxgb3_cleanup_module);
diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c
new file mode 100644
index 00000000000..c6b72664318
--- /dev/null
+++ b/drivers/net/cxgb3/cxgb3_offload.c
@@ -0,0 +1,1222 @@
+/*
+ * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/list.h>
+#include <net/neighbour.h>
+#include <linux/notifier.h>
+#include <asm/atomic.h>
+#include <linux/proc_fs.h>
+#include <linux/if_vlan.h>
+#include <net/netevent.h>
+#include <linux/highmem.h>
+#include <linux/vmalloc.h>
+
+#include "common.h"
+#include "regs.h"
+#include "cxgb3_ioctl.h"
+#include "cxgb3_ctl_defs.h"
+#include "cxgb3_defs.h"
+#include "l2t.h"
+#include "firmware_exports.h"
+#include "cxgb3_offload.h"
+
+static LIST_HEAD(client_list);
+static LIST_HEAD(ofld_dev_list);
+static DEFINE_MUTEX(cxgb3_db_lock);
+
+static DEFINE_RWLOCK(adapter_list_lock);
+static LIST_HEAD(adapter_list);
+
+static const unsigned int MAX_ATIDS = 64 * 1024;
+static const unsigned int ATID_BASE = 0x100000;
+
+static inline int offload_activated(struct t3cdev *tdev)
+{
+ const struct adapter *adapter = tdev2adap(tdev);
+
+ return (test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map));
+}
+
+/**
+ * cxgb3_register_client - register an offload client
+ * @client: the client
+ *
+ * Add the client to the client list,
+ * and call backs the client for each activated offload device
+ */
+void cxgb3_register_client(struct cxgb3_client *client)
+{
+ struct t3cdev *tdev;
+
+ mutex_lock(&cxgb3_db_lock);
+ list_add_tail(&client->client_list, &client_list);
+
+ if (client->add) {
+ list_for_each_entry(tdev, &ofld_dev_list, ofld_dev_list) {
+ if (offload_activated(tdev))
+ client->add(tdev);
+ }
+ }
+ mutex_unlock(&cxgb3_db_lock);
+}
+
+EXPORT_SYMBOL(cxgb3_register_client);
+
+/**
+ * cxgb3_unregister_client - unregister an offload client
+ * @client: the client
+ *
+ * Remove the client to the client list,
+ * and call backs the client for each activated offload device.
+ */
+void cxgb3_unregister_client(struct cxgb3_client *client)
+{
+ struct t3cdev *tdev;
+
+ mutex_lock(&cxgb3_db_lock);
+ list_del(&client->client_list);
+
+ if (client->remove) {
+ list_for_each_entry(tdev, &ofld_dev_list, ofld_dev_list) {
+ if (offload_activated(tdev))
+ client->remove(tdev);
+ }
+ }
+ mutex_unlock(&cxgb3_db_lock);
+}
+
+EXPORT_SYMBOL(cxgb3_unregister_client);
+
+/**
+ * cxgb3_add_clients - activate registered clients for an offload device
+ * @tdev: the offload device
+ *
+ * Call backs all registered clients once a offload device is activated
+ */
+void cxgb3_add_clients(struct t3cdev *tdev)
+{
+ struct cxgb3_client *client;
+
+ mutex_lock(&cxgb3_db_lock);
+ list_for_each_entry(client, &client_list, client_list) {
+ if (client->add)
+ client->add(tdev);
+ }
+ mutex_unlock(&cxgb3_db_lock);
+}
+
+/**
+ * cxgb3_remove_clients - deactivates registered clients
+ * for an offload device
+ * @tdev: the offload device
+ *
+ * Call backs all registered clients once a offload device is deactivated
+ */
+void cxgb3_remove_clients(struct t3cdev *tdev)
+{
+ struct cxgb3_client *client;
+
+ mutex_lock(&cxgb3_db_lock);
+ list_for_each_entry(client, &client_list, client_list) {
+ if (client->remove)
+ client->remove(tdev);
+ }
+ mutex_unlock(&cxgb3_db_lock);
+}
+
+static struct net_device *get_iff_from_mac(struct adapter *adapter,
+ const unsigned char *mac,
+ unsigned int vlan)
+{
+ int i;
+
+ for_each_port(adapter, i) {
+ const struct vlan_group *grp;
+ struct net_device *dev = adapter->port[i];
+ const struct port_info *p = netdev_priv(dev);
+
+ if (!memcmp(dev->dev_addr, mac, ETH_ALEN)) {
+ if (vlan && vlan != VLAN_VID_MASK) {
+ grp = p->vlan_grp;
+ dev = grp ? grp->vlan_devices[vlan] : NULL;
+ } else
+ while (dev->master)
+ dev = dev->master;
+ return dev;
+ }
+ }
+ return NULL;
+}
+
+static int cxgb_ulp_iscsi_ctl(struct adapter *adapter, unsigned int req,
+ void *data)
+{
+ int ret = 0;
+ struct ulp_iscsi_info *uiip = data;
+
+ switch (req) {
+ case ULP_ISCSI_GET_PARAMS:
+ uiip->pdev = adapter->pdev;
+ uiip->llimit = t3_read_reg(adapter, A_ULPRX_ISCSI_LLIMIT);
+ uiip->ulimit = t3_read_reg(adapter, A_ULPRX_ISCSI_ULIMIT);
+ uiip->tagmask = t3_read_reg(adapter, A_ULPRX_ISCSI_TAGMASK);
+ /*
+ * On tx, the iscsi pdu has to be <= tx page size and has to
+ * fit into the Tx PM FIFO.
+ */
+ uiip->max_txsz = min(adapter->params.tp.tx_pg_size,
+ t3_read_reg(adapter, A_PM1_TX_CFG) >> 17);
+ /* on rx, the iscsi pdu has to be < rx page size and the
+ whole pdu + cpl headers has to fit into one sge buffer */
+ uiip->max_rxsz = min_t(unsigned int,
+ adapter->params.tp.rx_pg_size,
+ (adapter->sge.qs[0].fl[1].buf_size -
+ sizeof(struct cpl_rx_data) * 2 -
+ sizeof(struct cpl_rx_data_ddp)));
+ break;
+ case ULP_ISCSI_SET_PARAMS:
+ t3_write_reg(adapter, A_ULPRX_ISCSI_TAGMASK, uiip->tagmask);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ }
+ return ret;
+}
+
+/* Response queue used for RDMA events. */
+#define ASYNC_NOTIF_RSPQ 0
+
+static int cxgb_rdma_ctl(struct adapter *adapter, unsigned int req, void *data)
+{
+ int ret = 0;
+
+ switch (req) {
+ case RDMA_GET_PARAMS:{
+ struct rdma_info *req = data;
+ struct pci_dev *pdev = adapter->pdev;
+
+ req->udbell_physbase = pci_resource_start(pdev, 2);
+ req->udbell_len = pci_resource_len(pdev, 2);
+ req->tpt_base =
+ t3_read_reg(adapter, A_ULPTX_TPT_LLIMIT);
+ req->tpt_top = t3_read_reg(adapter, A_ULPTX_TPT_ULIMIT);
+ req->pbl_base =
+ t3_read_reg(adapter, A_ULPTX_PBL_LLIMIT);
+ req->pbl_top = t3_read_reg(adapter, A_ULPTX_PBL_ULIMIT);
+ req->rqt_base = t3_read_reg(adapter, A_ULPRX_RQ_LLIMIT);
+ req->rqt_top = t3_read_reg(adapter, A_ULPRX_RQ_ULIMIT);
+ req->kdb_addr = adapter->regs + A_SG_KDOORBELL;
+ req->pdev = pdev;
+ break;
+ }
+ case RDMA_CQ_OP:{
+ unsigned long flags;
+ struct rdma_cq_op *req = data;
+
+ /* may be called in any context */
+ spin_lock_irqsave(&adapter->sge.reg_lock, flags);
+ ret = t3_sge_cqcntxt_op(adapter, req->id, req->op,
+ req->credits);
+ spin_unlock_irqrestore(&adapter->sge.reg_lock, flags);
+ break;
+ }
+ case RDMA_GET_MEM:{
+ struct ch_mem_range *t = data;
+ struct mc7 *mem;
+
+ if ((t->addr & 7) || (t->len & 7))
+ return -EINVAL;
+ if (t->mem_id == MEM_CM)
+ mem = &adapter->cm;
+ else if (t->mem_id == MEM_PMRX)
+ mem = &adapter->pmrx;
+ else if (t->mem_id == MEM_PMTX)
+ mem = &adapter->pmtx;
+ else
+ return -EINVAL;
+
+ ret =
+ t3_mc7_bd_read(mem, t->addr / 8, t->len / 8,
+ (u64 *) t->buf);
+ if (ret)
+ return ret;
+ break;
+ }
+ case RDMA_CQ_SETUP:{
+ struct rdma_cq_setup *req = data;
+
+ spin_lock_irq(&adapter->sge.reg_lock);
+ ret =
+ t3_sge_init_cqcntxt(adapter, req->id,
+ req->base_addr, req->size,
+ ASYNC_NOTIF_RSPQ,
+ req->ovfl_mode, req->credits,
+ req->credit_thres);
+ spin_unlock_irq(&adapter->sge.reg_lock);
+ break;
+ }
+ case RDMA_CQ_DISABLE:
+ spin_lock_irq(&adapter->sge.reg_lock);
+ ret = t3_sge_disable_cqcntxt(adapter, *(unsigned int *)data);
+ spin_unlock_irq(&adapter->sge.reg_lock);
+ break;
+ case RDMA_CTRL_QP_SETUP:{
+ struct rdma_ctrlqp_setup *req = data;
+
+ spin_lock_irq(&adapter->sge.reg_lock);
+ ret = t3_sge_init_ecntxt(adapter, FW_RI_SGEEC_START, 0,
+ SGE_CNTXT_RDMA,
+ ASYNC_NOTIF_RSPQ,
+ req->base_addr, req->size,
+ FW_RI_TID_START, 1, 0);
+ spin_unlock_irq(&adapter->sge.reg_lock);
+ break;
+ }
+ default:
+ ret = -EOPNOTSUPP;
+ }
+ return ret;
+}
+
+static int cxgb_offload_ctl(struct t3cdev *tdev, unsigned int req, void *data)
+{
+ struct adapter *adapter = tdev2adap(tdev);
+ struct tid_range *tid;
+ struct mtutab *mtup;
+ struct iff_mac *iffmacp;
+ struct ddp_params *ddpp;
+ struct adap_ports *ports;
+ int i;
+
+ switch (req) {
+ case GET_MAX_OUTSTANDING_WR:
+ *(unsigned int *)data = FW_WR_NUM;
+ break;
+ case GET_WR_LEN:
+ *(unsigned int *)data = WR_FLITS;
+ break;
+ case GET_TX_MAX_CHUNK:
+ *(unsigned int *)data = 1 << 20; /* 1MB */
+ break;
+ case GET_TID_RANGE:
+ tid = data;
+ tid->num = t3_mc5_size(&adapter->mc5) -
+ adapter->params.mc5.nroutes -
+ adapter->params.mc5.nfilters - adapter->params.mc5.nservers;
+ tid->base = 0;
+ break;
+ case GET_STID_RANGE:
+ tid = data;
+ tid->num = adapter->params.mc5.nservers;
+ tid->base = t3_mc5_size(&adapter->mc5) - tid->num -
+ adapter->params.mc5.nfilters - adapter->params.mc5.nroutes;
+ break;
+ case GET_L2T_CAPACITY:
+ *(unsigned int *)data = 2048;
+ break;
+ case GET_MTUS:
+ mtup = data;
+ mtup->size = NMTUS;
+ mtup->mtus = adapter->params.mtus;
+ break;
+ case GET_IFF_FROM_MAC:
+ iffmacp = data;
+ iffmacp->dev = get_iff_from_mac(adapter, iffmacp->mac_addr,
+ iffmacp->vlan_tag &
+ VLAN_VID_MASK);
+ break;
+ case GET_DDP_PARAMS:
+ ddpp = data;
+ ddpp->llimit = t3_read_reg(adapter, A_ULPRX_TDDP_LLIMIT);
+ ddpp->ulimit = t3_read_reg(adapter, A_ULPRX_TDDP_ULIMIT);
+ ddpp->tag_mask = t3_read_reg(adapter, A_ULPRX_TDDP_TAGMASK);
+ break;
+ case GET_PORTS:
+ ports = data;
+ ports->nports = adapter->params.nports;
+ for_each_port(adapter, i)
+ ports->lldevs[i] = adapter->port[i];
+ break;
+ case ULP_ISCSI_GET_PARAMS:
+ case ULP_ISCSI_SET_PARAMS:
+ if (!offload_running(adapter))
+ return -EAGAIN;
+ return cxgb_ulp_iscsi_ctl(adapter, req, data);
+ case RDMA_GET_PARAMS:
+ case RDMA_CQ_OP:
+ case RDMA_CQ_SETUP:
+ case RDMA_CQ_DISABLE:
+ case RDMA_CTRL_QP_SETUP:
+ case RDMA_GET_MEM:
+ if (!offload_running(adapter))
+ return -EAGAIN;
+ return cxgb_rdma_ctl(adapter, req, data);
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+/*
+ * Dummy handler for Rx offload packets in case we get an offload packet before
+ * proper processing is setup. This complains and drops the packet as it isn't
+ * normal to get offload packets at this stage.
+ */
+static int rx_offload_blackhole(struct t3cdev *dev, struct sk_buff **skbs,
+ int n)
+{
+ CH_ERR(tdev2adap(dev), "%d unexpected offload packets, first data %u\n",
+ n, ntohl(*(__be32 *)skbs[0]->data));
+ while (n--)
+ dev_kfree_skb_any(skbs[n]);
+ return 0;
+}
+
+static void dummy_neigh_update(struct t3cdev *dev, struct neighbour *neigh)
+{
+}
+
+void cxgb3_set_dummy_ops(struct t3cdev *dev)
+{
+ dev->recv = rx_offload_blackhole;
+ dev->neigh_update = dummy_neigh_update;
+}
+
+/*
+ * Free an active-open TID.
+ */
+void *cxgb3_free_atid(struct t3cdev *tdev, int atid)
+{
+ struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
+ union active_open_entry *p = atid2entry(t, atid);
+ void *ctx = p->t3c_tid.ctx;
+
+ spin_lock_bh(&t->atid_lock);
+ p->next = t->afree;
+ t->afree = p;
+ t->atids_in_use--;
+ spin_unlock_bh(&t->atid_lock);
+
+ return ctx;
+}
+
+EXPORT_SYMBOL(cxgb3_free_atid);
+
+/*
+ * Free a server TID and return it to the free pool.
+ */
+void cxgb3_free_stid(struct t3cdev *tdev, int stid)
+{
+ struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
+ union listen_entry *p = stid2entry(t, stid);
+
+ spin_lock_bh(&t->stid_lock);
+ p->next = t->sfree;
+ t->sfree = p;
+ t->stids_in_use--;
+ spin_unlock_bh(&t->stid_lock);
+}
+
+EXPORT_SYMBOL(cxgb3_free_stid);
+
+void cxgb3_insert_tid(struct t3cdev *tdev, struct cxgb3_client *client,
+ void *ctx, unsigned int tid)
+{
+ struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
+
+ t->tid_tab[tid].client = client;
+ t->tid_tab[tid].ctx = ctx;
+ atomic_inc(&t->tids_in_use);
+}
+
+EXPORT_SYMBOL(cxgb3_insert_tid);
+
+/*
+ * Populate a TID_RELEASE WR. The skb must be already propely sized.
+ */
+static inline void mk_tid_release(struct sk_buff *skb, unsigned int tid)
+{
+ struct cpl_tid_release *req;
+
+ skb->priority = CPL_PRIORITY_SETUP;
+ req = (struct cpl_tid_release *)__skb_put(skb, sizeof(*req));
+ req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+ OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_TID_RELEASE, tid));
+}
+
+static void t3_process_tid_release_list(struct work_struct *work)
+{
+ struct t3c_data *td = container_of(work, struct t3c_data,
+ tid_release_task);
+ struct sk_buff *skb;
+ struct t3cdev *tdev = td->dev;
+
+
+ spin_lock_bh(&td->tid_release_lock);
+ while (td->tid_release_list) {
+ struct t3c_tid_entry *p = td->tid_release_list;
+
+ td->tid_release_list = (struct t3c_tid_entry *)p->ctx;
+ spin_unlock_bh(&td->tid_release_lock);
+
+ skb = alloc_skb(sizeof(struct cpl_tid_release),
+ GFP_KERNEL | __GFP_NOFAIL);
+ mk_tid_release(skb, p - td->tid_maps.tid_tab);
+ cxgb3_ofld_send(tdev, skb);
+ p->ctx = NULL;
+ spin_lock_bh(&td->tid_release_lock);
+ }
+ spin_unlock_bh(&td->tid_release_lock);
+}
+
+/* use ctx as a next pointer in the tid release list */
+void cxgb3_queue_tid_release(struct t3cdev *tdev, unsigned int tid)
+{
+ struct t3c_data *td = T3C_DATA(tdev);
+ struct t3c_tid_entry *p = &td->tid_maps.tid_tab[tid];
+
+ spin_lock_bh(&td->tid_release_lock);
+ p->ctx = (void *)td->tid_release_list;
+ td->tid_release_list = p;
+ if (!p->ctx)
+ schedule_work(&td->tid_release_task);
+ spin_unlock_bh(&td->tid_release_lock);
+}
+
+EXPORT_SYMBOL(cxgb3_queue_tid_release);
+
+/*
+ * Remove a tid from the TID table. A client may defer processing its last
+ * CPL message if it is locked at the time it arrives, and while the message
+ * sits in the client's backlog the TID may be reused for another connection.
+ * To handle this we atomically switch the TID association if it still points
+ * to the original client context.
+ */
+void cxgb3_remove_tid(struct t3cdev *tdev, void *ctx, unsigned int tid)
+{
+ struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
+
+ BUG_ON(tid >= t->ntids);
+ if (tdev->type == T3A)
+ (void)cmpxchg(&t->tid_tab[tid].ctx, ctx, NULL);
+ else {
+ struct sk_buff *skb;
+
+ skb = alloc_skb(sizeof(struct cpl_tid_release), GFP_ATOMIC);
+ if (likely(skb)) {
+ mk_tid_release(skb, tid);
+ cxgb3_ofld_send(tdev, skb);
+ t->tid_tab[tid].ctx = NULL;
+ } else
+ cxgb3_queue_tid_release(tdev, tid);
+ }
+ atomic_dec(&t->tids_in_use);
+}
+
+EXPORT_SYMBOL(cxgb3_remove_tid);
+
+int cxgb3_alloc_atid(struct t3cdev *tdev, struct cxgb3_client *client,
+ void *ctx)
+{
+ int atid = -1;
+ struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
+
+ spin_lock_bh(&t->atid_lock);
+ if (t->afree) {
+ union active_open_entry *p = t->afree;
+
+ atid = (p - t->atid_tab) + t->atid_base;
+ t->afree = p->next;
+ p->t3c_tid.ctx = ctx;
+ p->t3c_tid.client = client;
+ t->atids_in_use++;
+ }
+ spin_unlock_bh(&t->atid_lock);
+ return atid;
+}
+
+EXPORT_SYMBOL(cxgb3_alloc_atid);
+
+int cxgb3_alloc_stid(struct t3cdev *tdev, struct cxgb3_client *client,
+ void *ctx)
+{
+ int stid = -1;
+ struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
+
+ spin_lock_bh(&t->stid_lock);
+ if (t->sfree) {
+ union listen_entry *p = t->sfree;
+
+ stid = (p - t->stid_tab) + t->stid_base;
+ t->sfree = p->next;
+ p->t3c_tid.ctx = ctx;
+ p->t3c_tid.client = client;
+ t->stids_in_use++;
+ }
+ spin_unlock_bh(&t->stid_lock);
+ return stid;
+}
+
+EXPORT_SYMBOL(cxgb3_alloc_stid);
+
+static int do_smt_write_rpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+ struct cpl_smt_write_rpl *rpl = cplhdr(skb);
+
+ if (rpl->status != CPL_ERR_NONE)
+ printk(KERN_ERR
+ "Unexpected SMT_WRITE_RPL status %u for entry %u\n",
+ rpl->status, GET_TID(rpl));
+
+ return CPL_RET_BUF_DONE;
+}
+
+static int do_l2t_write_rpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+ struct cpl_l2t_write_rpl *rpl = cplhdr(skb);
+
+ if (rpl->status != CPL_ERR_NONE)
+ printk(KERN_ERR
+ "Unexpected L2T_WRITE_RPL status %u for entry %u\n",
+ rpl->status, GET_TID(rpl));
+
+ return CPL_RET_BUF_DONE;
+}
+
+static int do_act_open_rpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+ struct cpl_act_open_rpl *rpl = cplhdr(skb);
+ unsigned int atid = G_TID(ntohl(rpl->atid));
+ struct t3c_tid_entry *t3c_tid;
+
+ t3c_tid = lookup_atid(&(T3C_DATA(dev))->tid_maps, atid);
+ if (t3c_tid->ctx && t3c_tid->client && t3c_tid->client->handlers &&
+ t3c_tid->client->handlers[CPL_ACT_OPEN_RPL]) {
+ return t3c_tid->client->handlers[CPL_ACT_OPEN_RPL] (dev, skb,
+ t3c_tid->
+ ctx);
+ } else {
+ printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+ dev->name, CPL_ACT_OPEN_RPL);
+ return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+ }
+}
+
+static int do_stid_rpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+ union opcode_tid *p = cplhdr(skb);
+ unsigned int stid = G_TID(ntohl(p->opcode_tid));
+ struct t3c_tid_entry *t3c_tid;
+
+ t3c_tid = lookup_stid(&(T3C_DATA(dev))->tid_maps, stid);
+ if (t3c_tid->ctx && t3c_tid->client->handlers &&
+ t3c_tid->client->handlers[p->opcode]) {
+ return t3c_tid->client->handlers[p->opcode] (dev, skb,
+ t3c_tid->ctx);
+ } else {
+ printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+ dev->name, p->opcode);
+ return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+ }
+}
+
+static int do_hwtid_rpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+ union opcode_tid *p = cplhdr(skb);
+ unsigned int hwtid = G_TID(ntohl(p->opcode_tid));
+ struct t3c_tid_entry *t3c_tid;
+
+ t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid);
+ if (t3c_tid->ctx && t3c_tid->client->handlers &&
+ t3c_tid->client->handlers[p->opcode]) {
+ return t3c_tid->client->handlers[p->opcode]
+ (dev, skb, t3c_tid->ctx);
+ } else {
+ printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+ dev->name, p->opcode);
+ return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+ }
+}
+
+static int do_cr(struct t3cdev *dev, struct sk_buff *skb)
+{
+ struct cpl_pass_accept_req *req = cplhdr(skb);
+ unsigned int stid = G_PASS_OPEN_TID(ntohl(req->tos_tid));
+ struct t3c_tid_entry *t3c_tid;
+
+ t3c_tid = lookup_stid(&(T3C_DATA(dev))->tid_maps, stid);
+ if (t3c_tid->ctx && t3c_tid->client->handlers &&
+ t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ]) {
+ return t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ]
+ (dev, skb, t3c_tid->ctx);
+ } else {
+ printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+ dev->name, CPL_PASS_ACCEPT_REQ);
+ return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+ }
+}
+
+static int do_abort_req_rss(struct t3cdev *dev, struct sk_buff *skb)
+{
+ union opcode_tid *p = cplhdr(skb);
+ unsigned int hwtid = G_TID(ntohl(p->opcode_tid));
+ struct t3c_tid_entry *t3c_tid;
+
+ t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid);
+ if (t3c_tid->ctx && t3c_tid->client->handlers &&
+ t3c_tid->client->handlers[p->opcode]) {
+ return t3c_tid->client->handlers[p->opcode]
+ (dev, skb, t3c_tid->ctx);
+ } else {
+ struct cpl_abort_req_rss *req = cplhdr(skb);
+ struct cpl_abort_rpl *rpl;
+
+ struct sk_buff *skb =
+ alloc_skb(sizeof(struct cpl_abort_rpl), GFP_ATOMIC);
+ if (!skb) {
+ printk("do_abort_req_rss: couldn't get skb!\n");
+ goto out;
+ }
+ skb->priority = CPL_PRIORITY_DATA;
+ __skb_put(skb, sizeof(struct cpl_abort_rpl));
+ rpl = cplhdr(skb);
+ rpl->wr.wr_hi =
+ htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_RPL));
+ rpl->wr.wr_lo = htonl(V_WR_TID(GET_TID(req)));
+ OPCODE_TID(rpl) =
+ htonl(MK_OPCODE_TID(CPL_ABORT_RPL, GET_TID(req)));
+ rpl->cmd = req->status;
+ cxgb3_ofld_send(dev, skb);
+out:
+ return CPL_RET_BUF_DONE;
+ }
+}
+
+static int do_act_establish(struct t3cdev *dev, struct sk_buff *skb)
+{
+ struct cpl_act_establish *req = cplhdr(skb);
+ unsigned int atid = G_PASS_OPEN_TID(ntohl(req->tos_tid));
+ struct t3c_tid_entry *t3c_tid;
+
+ t3c_tid = lookup_atid(&(T3C_DATA(dev))->tid_maps, atid);
+ if (t3c_tid->ctx && t3c_tid->client->handlers &&
+ t3c_tid->client->handlers[CPL_ACT_ESTABLISH]) {
+ return t3c_tid->client->handlers[CPL_ACT_ESTABLISH]
+ (dev, skb, t3c_tid->ctx);
+ } else {
+ printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+ dev->name, CPL_PASS_ACCEPT_REQ);
+ return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+ }
+}
+
+static int do_set_tcb_rpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+ struct cpl_set_tcb_rpl *rpl = cplhdr(skb);
+
+ if (rpl->status != CPL_ERR_NONE)
+ printk(KERN_ERR
+ "Unexpected SET_TCB_RPL status %u for tid %u\n",
+ rpl->status, GET_TID(rpl));
+ return CPL_RET_BUF_DONE;
+}
+
+static int do_trace(struct t3cdev *dev, struct sk_buff *skb)
+{
+ struct cpl_trace_pkt *p = cplhdr(skb);
+
+ skb->protocol = htons(0xffff);
+ skb->dev = dev->lldev;
+ skb_pull(skb, sizeof(*p));
+ skb->mac.raw = skb->data;
+ netif_receive_skb(skb);
+ return 0;
+}
+
+static int do_term(struct t3cdev *dev, struct sk_buff *skb)
+{
+ unsigned int hwtid = ntohl(skb->priority) >> 8 & 0xfffff;
+ unsigned int opcode = G_OPCODE(ntohl(skb->csum));
+ struct t3c_tid_entry *t3c_tid;
+
+ t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid);
+ if (t3c_tid->ctx && t3c_tid->client->handlers &&
+ t3c_tid->client->handlers[opcode]) {
+ return t3c_tid->client->handlers[opcode] (dev, skb,
+ t3c_tid->ctx);
+ } else {
+ printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+ dev->name, opcode);
+ return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+ }
+}
+
+static int nb_callback(struct notifier_block *self, unsigned long event,
+ void *ctx)
+{
+ switch (event) {
+ case (NETEVENT_NEIGH_UPDATE):{
+ cxgb_neigh_update((struct neighbour *)ctx);
+ break;
+ }
+ case (NETEVENT_PMTU_UPDATE):
+ break;
+ case (NETEVENT_REDIRECT):{
+ struct netevent_redirect *nr = ctx;
+ cxgb_redirect(nr->old, nr->new);
+ cxgb_neigh_update(nr->new->neighbour);
+ break;
+ }
+ default:
+ break;
+ }
+ return 0;
+}
+
+static struct notifier_block nb = {
+ .notifier_call = nb_callback
+};
+
+/*
+ * Process a received packet with an unknown/unexpected CPL opcode.
+ */
+static int do_bad_cpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+ printk(KERN_ERR "%s: received bad CPL command 0x%x\n", dev->name,
+ *skb->data);
+ return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+}
+
+/*
+ * Handlers for each CPL opcode
+ */
+static cpl_handler_func cpl_handlers[NUM_CPL_CMDS];
+
+/*
+ * Add a new handler to the CPL dispatch table. A NULL handler may be supplied
+ * to unregister an existing handler.
+ */
+void t3_register_cpl_handler(unsigned int opcode, cpl_handler_func h)
+{
+ if (opcode < NUM_CPL_CMDS)
+ cpl_handlers[opcode] = h ? h : do_bad_cpl;
+ else
+ printk(KERN_ERR "T3C: handler registration for "
+ "opcode %x failed\n", opcode);
+}
+
+EXPORT_SYMBOL(t3_register_cpl_handler);
+
+/*
+ * T3CDEV's receive method.
+ */
+int process_rx(struct t3cdev *dev, struct sk_buff **skbs, int n)
+{
+ while (n--) {
+ struct sk_buff *skb = *skbs++;
+ unsigned int opcode = G_OPCODE(ntohl(skb->csum));
+ int ret = cpl_handlers[opcode] (dev, skb);
+
+#if VALIDATE_TID
+ if (ret & CPL_RET_UNKNOWN_TID) {
+ union opcode_tid *p = cplhdr(skb);
+
+ printk(KERN_ERR "%s: CPL message (opcode %u) had "
+ "unknown TID %u\n", dev->name, opcode,
+ G_TID(ntohl(p->opcode_tid)));
+ }
+#endif
+ if (ret & CPL_RET_BUF_DONE)
+ kfree_skb(skb);
+ }
+ return 0;
+}
+
+/*
+ * Sends an sk_buff to a T3C driver after dealing with any active network taps.
+ */
+int cxgb3_ofld_send(struct t3cdev *dev, struct sk_buff *skb)
+{
+ int r;
+
+ local_bh_disable();
+ r = dev->send(dev, skb);
+ local_bh_enable();
+ return r;
+}
+
+EXPORT_SYMBOL(cxgb3_ofld_send);
+
+static int is_offloading(struct net_device *dev)
+{
+ struct adapter *adapter;
+ int i;
+
+ read_lock_bh(&adapter_list_lock);
+ list_for_each_entry(adapter, &adapter_list, adapter_list) {
+ for_each_port(adapter, i) {
+ if (dev == adapter->port[i]) {
+ read_unlock_bh(&adapter_list_lock);
+ return 1;
+ }
+ }
+ }
+ read_unlock_bh(&adapter_list_lock);
+ return 0;
+}
+
+void cxgb_neigh_update(struct neighbour *neigh)
+{
+ struct net_device *dev = neigh->dev;
+
+ if (dev && (is_offloading(dev))) {
+ struct t3cdev *tdev = T3CDEV(dev);
+
+ BUG_ON(!tdev);
+ t3_l2t_update(tdev, neigh);
+ }
+}
+
+static void set_l2t_ix(struct t3cdev *tdev, u32 tid, struct l2t_entry *e)
+{
+ struct sk_buff *skb;
+ struct cpl_set_tcb_field *req;
+
+ skb = alloc_skb(sizeof(*req), GFP_ATOMIC);
+ if (!skb) {
+ printk(KERN_ERR "%s: cannot allocate skb!\n", __FUNCTION__);
+ return;
+ }
+ skb->priority = CPL_PRIORITY_CONTROL;
+ req = (struct cpl_set_tcb_field *)skb_put(skb, sizeof(*req));
+ req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+ OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid));
+ req->reply = 0;
+ req->cpu_idx = 0;
+ req->word = htons(W_TCB_L2T_IX);
+ req->mask = cpu_to_be64(V_TCB_L2T_IX(M_TCB_L2T_IX));
+ req->val = cpu_to_be64(V_TCB_L2T_IX(e->idx));
+ tdev->send(tdev, skb);
+}
+
+void cxgb_redirect(struct dst_entry *old, struct dst_entry *new)
+{
+ struct net_device *olddev, *newdev;
+ struct tid_info *ti;
+ struct t3cdev *tdev;
+ u32 tid;
+ int update_tcb;
+ struct l2t_entry *e;
+ struct t3c_tid_entry *te;
+
+ olddev = old->neighbour->dev;
+ newdev = new->neighbour->dev;
+ if (!is_offloading(olddev))
+ return;
+ if (!is_offloading(newdev)) {
+ printk(KERN_WARNING "%s: Redirect to non-offload"
+ "device ignored.\n", __FUNCTION__);
+ return;
+ }
+ tdev = T3CDEV(olddev);
+ BUG_ON(!tdev);
+ if (tdev != T3CDEV(newdev)) {
+ printk(KERN_WARNING "%s: Redirect to different "
+ "offload device ignored.\n", __FUNCTION__);
+ return;
+ }
+
+ /* Add new L2T entry */
+ e = t3_l2t_get(tdev, new->neighbour, newdev);
+ if (!e) {
+ printk(KERN_ERR "%s: couldn't allocate new l2t entry!\n",
+ __FUNCTION__);
+ return;
+ }
+
+ /* Walk tid table and notify clients of dst change. */
+ ti = &(T3C_DATA(tdev))->tid_maps;
+ for (tid = 0; tid < ti->ntids; tid++) {
+ te = lookup_tid(ti, tid);
+ BUG_ON(!te);
+ if (te->ctx && te->client && te->client->redirect) {
+ update_tcb = te->client->redirect(te->ctx, old, new, e);
+ if (update_tcb) {
+ l2t_hold(L2DATA(tdev), e);
+ set_l2t_ix(tdev, tid, e);
+ }
+ }
+ }
+ l2t_release(L2DATA(tdev), e);
+}
+
+/*
+ * Allocate a chunk of memory using kmalloc or, if that fails, vmalloc.
+ * The allocated memory is cleared.
+ */
+void *cxgb_alloc_mem(unsigned long size)
+{
+ void *p = kmalloc(size, GFP_KERNEL);
+
+ if (!p)
+ p = vmalloc(size);
+ if (p)
+ memset(p, 0, size);
+ return p;
+}
+
+/*
+ * Free memory allocated through t3_alloc_mem().
+ */
+void cxgb_free_mem(void *addr)
+{
+ unsigned long p = (unsigned long)addr;
+
+ if (p >= VMALLOC_START && p < VMALLOC_END)
+ vfree(addr);
+ else
+ kfree(addr);
+}
+
+/*
+ * Allocate and initialize the TID tables. Returns 0 on success.
+ */
+static int init_tid_tabs(struct tid_info *t, unsigned int ntids,
+ unsigned int natids, unsigned int nstids,
+ unsigned int atid_base, unsigned int stid_base)
+{
+ unsigned long size = ntids * sizeof(*t->tid_tab) +
+ natids * sizeof(*t->atid_tab) + nstids * sizeof(*t->stid_tab);
+
+ t->tid_tab = cxgb_alloc_mem(size);
+ if (!t->tid_tab)
+ return -ENOMEM;
+
+ t->stid_tab = (union listen_entry *)&t->tid_tab[ntids];
+ t->atid_tab = (union active_open_entry *)&t->stid_tab[nstids];
+ t->ntids = ntids;
+ t->nstids = nstids;
+ t->stid_base = stid_base;
+ t->sfree = NULL;
+ t->natids = natids;
+ t->atid_base = atid_base;
+ t->afree = NULL;
+ t->stids_in_use = t->atids_in_use = 0;
+ atomic_set(&t->tids_in_use, 0);
+ spin_lock_init(&t->stid_lock);
+ spin_lock_init(&t->atid_lock);
+
+ /*
+ * Setup the free lists for stid_tab and atid_tab.
+ */
+ if (nstids) {
+ while (--nstids)
+ t->stid_tab[nstids - 1].next = &t->stid_tab[nstids];
+ t->sfree = t->stid_tab;
+ }
+ if (natids) {
+ while (--natids)
+ t->atid_tab[natids - 1].next = &t->atid_tab[natids];
+ t->afree = t->atid_tab;
+ }
+ return 0;
+}
+
+static void free_tid_maps(struct tid_info *t)
+{
+ cxgb_free_mem(t->tid_tab);
+}
+
+static inline void add_adapter(struct adapter *adap)
+{
+ write_lock_bh(&adapter_list_lock);
+ list_add_tail(&adap->adapter_list, &adapter_list);
+ write_unlock_bh(&adapter_list_lock);
+}
+
+static inline void remove_adapter(struct adapter *adap)
+{
+ write_lock_bh(&adapter_list_lock);
+ list_del(&adap->adapter_list);
+ write_unlock_bh(&adapter_list_lock);
+}
+
+int cxgb3_offload_activate(struct adapter *adapter)
+{
+ struct t3cdev *dev = &adapter->tdev;
+ int natids, err;
+ struct t3c_data *t;
+ struct tid_range stid_range, tid_range;
+ struct mtutab mtutab;
+ unsigned int l2t_capacity;
+
+ t = kcalloc(1, sizeof(*t), GFP_KERNEL);
+ if (!t)
+ return -ENOMEM;
+
+ err = -EOPNOTSUPP;
+ if (dev->ctl(dev, GET_TX_MAX_CHUNK, &t->tx_max_chunk) < 0 ||
+ dev->ctl(dev, GET_MAX_OUTSTANDING_WR, &t->max_wrs) < 0 ||
+ dev->ctl(dev, GET_L2T_CAPACITY, &l2t_capacity) < 0 ||
+ dev->ctl(dev, GET_MTUS, &mtutab) < 0 ||
+ dev->ctl(dev, GET_TID_RANGE, &tid_range) < 0 ||
+ dev->ctl(dev, GET_STID_RANGE, &stid_range) < 0)
+ goto out_free;
+
+ err = -ENOMEM;
+ L2DATA(dev) = t3_init_l2t(l2t_capacity);
+ if (!L2DATA(dev))
+ goto out_free;
+
+ natids = min(tid_range.num / 2, MAX_ATIDS);
+ err = init_tid_tabs(&t->tid_maps, tid_range.num, natids,
+ stid_range.num, ATID_BASE, stid_range.base);
+ if (err)
+ goto out_free_l2t;
+
+ t->mtus = mtutab.mtus;
+ t->nmtus = mtutab.size;
+
+ INIT_WORK(&t->tid_release_task, t3_process_tid_release_list);
+ spin_lock_init(&t->tid_release_lock);
+ INIT_LIST_HEAD(&t->list_node);
+ t->dev = dev;
+
+ T3C_DATA(dev) = t;
+ dev->recv = process_rx;
+ dev->neigh_update = t3_l2t_update;
+
+ /* Register netevent handler once */
+ if (list_empty(&adapter_list))
+ register_netevent_notifier(&nb);
+
+ add_adapter(adapter);
+ return 0;
+
+out_free_l2t:
+ t3_free_l2t(L2DATA(dev));
+ L2DATA(dev) = NULL;
+out_free:
+ kfree(t);
+ return err;
+}
+
+void cxgb3_offload_deactivate(struct adapter *adapter)
+{
+ struct t3cdev *tdev = &adapter->tdev;
+ struct t3c_data *t = T3C_DATA(tdev);
+
+ remove_adapter(adapter);
+ if (list_empty(&adapter_list))
+ unregister_netevent_notifier(&nb);
+
+ free_tid_maps(&t->tid_maps);
+ T3C_DATA(tdev) = NULL;
+ t3_free_l2t(L2DATA(tdev));
+ L2DATA(tdev) = NULL;
+ kfree(t);
+}
+
+static inline void register_tdev(struct t3cdev *tdev)
+{
+ static int unit;
+
+ mutex_lock(&cxgb3_db_lock);
+ snprintf(tdev->name, sizeof(tdev->name), "ofld_dev%d", unit++);
+ list_add_tail(&tdev->ofld_dev_list, &ofld_dev_list);
+ mutex_unlock(&cxgb3_db_lock);
+}
+
+static inline void unregister_tdev(struct t3cdev *tdev)
+{
+ mutex_lock(&cxgb3_db_lock);
+ list_del(&tdev->ofld_dev_list);
+ mutex_unlock(&cxgb3_db_lock);
+}
+
+void __devinit cxgb3_adapter_ofld(struct adapter *adapter)
+{
+ struct t3cdev *tdev = &adapter->tdev;
+
+ INIT_LIST_HEAD(&tdev->ofld_dev_list);
+
+ cxgb3_set_dummy_ops(tdev);
+ tdev->send = t3_offload_tx;
+ tdev->ctl = cxgb_offload_ctl;
+ tdev->type = adapter->params.rev == 0 ? T3A : T3B;
+
+ register_tdev(tdev);
+}
+
+void __devexit cxgb3_adapter_unofld(struct adapter *adapter)
+{
+ struct t3cdev *tdev = &adapter->tdev;
+
+ tdev->recv = NULL;
+ tdev->neigh_update = NULL;
+
+ unregister_tdev(tdev);
+}
+
+void __init cxgb3_offload_init(void)
+{
+ int i;
+
+ for (i = 0; i < NUM_CPL_CMDS; ++i)
+ cpl_handlers[i] = do_bad_cpl;
+
+ t3_register_cpl_handler(CPL_SMT_WRITE_RPL, do_smt_write_rpl);
+ t3_register_cpl_handler(CPL_L2T_WRITE_RPL, do_l2t_write_rpl);
+ t3_register_cpl_handler(CPL_PASS_OPEN_RPL, do_stid_rpl);
+ t3_register_cpl_handler(CPL_CLOSE_LISTSRV_RPL, do_stid_rpl);
+ t3_register_cpl_handler(CPL_PASS_ACCEPT_REQ, do_cr);
+ t3_register_cpl_handler(CPL_PASS_ESTABLISH, do_hwtid_rpl);
+ t3_register_cpl_handler(CPL_ABORT_RPL_RSS, do_hwtid_rpl);
+ t3_register_cpl_handler(CPL_ABORT_RPL, do_hwtid_rpl);
+ t3_register_cpl_handler(CPL_RX_URG_NOTIFY, do_hwtid_rpl);
+ t3_register_cpl_handler(CPL_RX_DATA, do_hwtid_rpl);
+ t3_register_cpl_handler(CPL_TX_DATA_ACK, do_hwtid_rpl);
+ t3_register_cpl_handler(CPL_TX_DMA_ACK, do_hwtid_rpl);
+ t3_register_cpl_handler(CPL_ACT_OPEN_RPL, do_act_open_rpl);
+ t3_register_cpl_handler(CPL_PEER_CLOSE, do_hwtid_rpl);
+ t3_register_cpl_handler(CPL_CLOSE_CON_RPL, do_hwtid_rpl);
+ t3_register_cpl_handler(CPL_ABORT_REQ_RSS, do_abort_req_rss);
+ t3_register_cpl_handler(CPL_ACT_ESTABLISH, do_act_establish);
+ t3_register_cpl_handler(CPL_SET_TCB_RPL, do_set_tcb_rpl);
+ t3_register_cpl_handler(CPL_RDMA_TERMINATE, do_term);
+ t3_register_cpl_handler(CPL_RDMA_EC_STATUS, do_hwtid_rpl);
+ t3_register_cpl_handler(CPL_TRACE_PKT, do_trace);
+ t3_register_cpl_handler(CPL_RX_DATA_DDP, do_hwtid_rpl);
+ t3_register_cpl_handler(CPL_RX_DDP_COMPLETE, do_hwtid_rpl);
+ t3_register_cpl_handler(CPL_ISCSI_HDR, do_hwtid_rpl);
+}
diff --git a/drivers/net/cxgb3/cxgb3_offload.h b/drivers/net/cxgb3/cxgb3_offload.h
new file mode 100644
index 00000000000..0e6beb69ba1
--- /dev/null
+++ b/drivers/net/cxgb3/cxgb3_offload.h
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _CXGB3_OFFLOAD_H
+#define _CXGB3_OFFLOAD_H
+
+#include <linux/list.h>
+#include <linux/skbuff.h>
+
+#include "l2t.h"
+
+#include "t3cdev.h"
+#include "t3_cpl.h"
+
+struct adapter;
+
+void cxgb3_offload_init(void);
+
+void cxgb3_adapter_ofld(struct adapter *adapter);
+void cxgb3_adapter_unofld(struct adapter *adapter);
+int cxgb3_offload_activate(struct adapter *adapter);
+void cxgb3_offload_deactivate(struct adapter *adapter);
+
+void cxgb3_set_dummy_ops(struct t3cdev *dev);
+
+/*
+ * Client registration. Users of T3 driver must register themselves.
+ * The T3 driver will call the add function of every client for each T3
+ * adapter activated, passing up the t3cdev ptr. Each client fills out an
+ * array of callback functions to process CPL messages.
+ */
+
+void cxgb3_register_client(struct cxgb3_client *client);
+void cxgb3_unregister_client(struct cxgb3_client *client);
+void cxgb3_add_clients(struct t3cdev *tdev);
+void cxgb3_remove_clients(struct t3cdev *tdev);
+
+typedef int (*cxgb3_cpl_handler_func)(struct t3cdev *dev,
+ struct sk_buff *skb, void *ctx);
+
+struct cxgb3_client {
+ char *name;
+ void (*add) (struct t3cdev *);
+ void (*remove) (struct t3cdev *);
+ cxgb3_cpl_handler_func *handlers;
+ int (*redirect)(void *ctx, struct dst_entry *old,
+ struct dst_entry *new, struct l2t_entry *l2t);
+ struct list_head client_list;
+};
+
+/*
+ * TID allocation services.
+ */
+int cxgb3_alloc_atid(struct t3cdev *dev, struct cxgb3_client *client,
+ void *ctx);
+int cxgb3_alloc_stid(struct t3cdev *dev, struct cxgb3_client *client,
+ void *ctx);
+void *cxgb3_free_atid(struct t3cdev *dev, int atid);
+void cxgb3_free_stid(struct t3cdev *dev, int stid);
+void cxgb3_insert_tid(struct t3cdev *dev, struct cxgb3_client *client,
+ void *ctx, unsigned int tid);
+void cxgb3_queue_tid_release(struct t3cdev *dev, unsigned int tid);
+void cxgb3_remove_tid(struct t3cdev *dev, void *ctx, unsigned int tid);
+
+struct t3c_tid_entry {
+ struct cxgb3_client *client;
+ void *ctx;
+};
+
+/* CPL message priority levels */
+enum {
+ CPL_PRIORITY_DATA = 0, /* data messages */
+ CPL_PRIORITY_SETUP = 1, /* connection setup messages */
+ CPL_PRIORITY_TEARDOWN = 0, /* connection teardown messages */
+ CPL_PRIORITY_LISTEN = 1, /* listen start/stop messages */
+ CPL_PRIORITY_ACK = 1, /* RX ACK messages */
+ CPL_PRIORITY_CONTROL = 1 /* offload control messages */
+};
+
+/* Flags for return value of CPL message handlers */
+enum {
+ CPL_RET_BUF_DONE = 1, /* buffer processing done, buffer may be freed */
+ CPL_RET_BAD_MSG = 2, /* bad CPL message (e.g., unknown opcode) */
+ CPL_RET_UNKNOWN_TID = 4 /* unexpected unknown TID */
+};
+
+typedef int (*cpl_handler_func)(struct t3cdev *dev, struct sk_buff *skb);
+
+/*
+ * Returns a pointer to the first byte of the CPL header in an sk_buff that
+ * contains a CPL message.
+ */
+static inline void *cplhdr(struct sk_buff *skb)
+{
+ return skb->data;
+}
+
+void t3_register_cpl_handler(unsigned int opcode, cpl_handler_func h);
+
+union listen_entry {
+ struct t3c_tid_entry t3c_tid;
+ union listen_entry *next;
+};
+
+union active_open_entry {
+ struct t3c_tid_entry t3c_tid;
+ union active_open_entry *next;
+};
+
+/*
+ * Holds the size, base address, free list start, etc of the TID, server TID,
+ * and active-open TID tables for a offload device.
+ * The tables themselves are allocated dynamically.
+ */
+struct tid_info {
+ struct t3c_tid_entry *tid_tab;
+ unsigned int ntids;
+ atomic_t tids_in_use;
+
+ union listen_entry *stid_tab;
+ unsigned int nstids;
+ unsigned int stid_base;
+
+ union active_open_entry *atid_tab;
+ unsigned int natids;
+ unsigned int atid_base;
+
+ /*
+ * The following members are accessed R/W so we put them in their own
+ * cache lines.
+ *
+ * XXX We could combine the atid fields above with the lock here since
+ * atids are use once (unlike other tids). OTOH the above fields are
+ * usually in cache due to tid_tab.
+ */
+ spinlock_t atid_lock ____cacheline_aligned_in_smp;
+ union active_open_entry *afree;
+ unsigned int atids_in_use;
+
+ spinlock_t stid_lock ____cacheline_aligned;
+ union listen_entry *sfree;
+ unsigned int stids_in_use;
+};
+
+struct t3c_data {
+ struct list_head list_node;
+ struct t3cdev *dev;
+ unsigned int tx_max_chunk; /* max payload for TX_DATA */
+ unsigned int max_wrs; /* max in-flight WRs per connection */
+ unsigned int nmtus;
+ const unsigned short *mtus;
+ struct tid_info tid_maps;
+
+ struct t3c_tid_entry *tid_release_list;
+ spinlock_t tid_release_lock;
+ struct work_struct tid_release_task;
+};
+
+/*
+ * t3cdev -> t3c_data accessor
+ */
+#define T3C_DATA(dev) (*(struct t3c_data **)&(dev)->l4opt)
+
+#endif
diff --git a/drivers/net/cxgb3/firmware_exports.h b/drivers/net/cxgb3/firmware_exports.h
new file mode 100644
index 00000000000..6a835f6a262
--- /dev/null
+++ b/drivers/net/cxgb3/firmware_exports.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2004-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _FIRMWARE_EXPORTS_H_
+#define _FIRMWARE_EXPORTS_H_
+
+/* WR OPCODES supported by the firmware.
+ */
+#define FW_WROPCODE_FORWARD 0x01
+#define FW_WROPCODE_BYPASS 0x05
+
+#define FW_WROPCODE_TUNNEL_TX_PKT 0x03
+
+#define FW_WROPOCDE_ULPTX_DATA_SGL 0x00
+#define FW_WROPCODE_ULPTX_MEM_READ 0x02
+#define FW_WROPCODE_ULPTX_PKT 0x04
+#define FW_WROPCODE_ULPTX_INVALIDATE 0x06
+
+#define FW_WROPCODE_TUNNEL_RX_PKT 0x07
+
+#define FW_WROPCODE_OFLD_GETTCB_RPL 0x08
+#define FW_WROPCODE_OFLD_CLOSE_CON 0x09
+#define FW_WROPCODE_OFLD_TP_ABORT_CON_REQ 0x0A
+#define FW_WROPCODE_OFLD_HOST_ABORT_CON_RPL 0x0F
+#define FW_WROPCODE_OFLD_HOST_ABORT_CON_REQ 0x0B
+#define FW_WROPCODE_OFLD_TP_ABORT_CON_RPL 0x0C
+#define FW_WROPCODE_OFLD_TX_DATA 0x0D
+#define FW_WROPCODE_OFLD_TX_DATA_ACK 0x0E
+
+#define FW_WROPCODE_RI_RDMA_INIT 0x10
+#define FW_WROPCODE_RI_RDMA_WRITE 0x11
+#define FW_WROPCODE_RI_RDMA_READ_REQ 0x12
+#define FW_WROPCODE_RI_RDMA_READ_RESP 0x13
+#define FW_WROPCODE_RI_SEND 0x14
+#define FW_WROPCODE_RI_TERMINATE 0x15
+#define FW_WROPCODE_RI_RDMA_READ 0x16
+#define FW_WROPCODE_RI_RECEIVE 0x17
+#define FW_WROPCODE_RI_BIND_MW 0x18
+#define FW_WROPCODE_RI_FASTREGISTER_MR 0x19
+#define FW_WROPCODE_RI_LOCAL_INV 0x1A
+#define FW_WROPCODE_RI_MODIFY_QP 0x1B
+#define FW_WROPCODE_RI_BYPASS 0x1C
+
+#define FW_WROPOCDE_RSVD 0x1E
+
+#define FW_WROPCODE_SGE_EGRESSCONTEXT_RR 0x1F
+
+#define FW_WROPCODE_MNGT 0x1D
+#define FW_MNGTOPCODE_PKTSCHED_SET 0x00
+
+/* Maximum size of a WR sent from the host, limited by the SGE.
+ *
+ * Note: WR coming from ULP or TP are only limited by CIM.
+ */
+#define FW_WR_SIZE 128
+
+/* Maximum number of outstanding WRs sent from the host. Value must be
+ * programmed in the CTRL/TUNNEL/QP SGE Egress Context and used by
+ * offload modules to limit the number of WRs per connection.
+ */
+#define FW_T3_WR_NUM 16
+#define FW_N3_WR_NUM 7
+
+#ifndef N3
+# define FW_WR_NUM FW_T3_WR_NUM
+#else
+# define FW_WR_NUM FW_N3_WR_NUM
+#endif
+
+/* FW_TUNNEL_NUM corresponds to the number of supported TUNNEL Queues. These
+ * queues must start at SGE Egress Context FW_TUNNEL_SGEEC_START and must
+ * start at 'TID' (or 'uP Token') FW_TUNNEL_TID_START.
+ *
+ * Ingress Traffic (e.g. DMA completion credit) for TUNNEL Queue[i] is sent
+ * to RESP Queue[i].
+ */
+#define FW_TUNNEL_NUM 8
+#define FW_TUNNEL_SGEEC_START 8
+#define FW_TUNNEL_TID_START 65544
+
+/* FW_CTRL_NUM corresponds to the number of supported CTRL Queues. These queues
+ * must start at SGE Egress Context FW_CTRL_SGEEC_START and must start at 'TID'
+ * (or 'uP Token') FW_CTRL_TID_START.
+ *
+ * Ingress Traffic for CTRL Queue[i] is sent to RESP Queue[i].
+ */
+#define FW_CTRL_NUM 8
+#define FW_CTRL_SGEEC_START 65528
+#define FW_CTRL_TID_START 65536
+
+/* FW_OFLD_NUM corresponds to the number of supported OFFLOAD Queues. These
+ * queues must start at SGE Egress Context FW_OFLD_SGEEC_START.
+ *
+ * Note: the 'uP Token' in the SGE Egress Context fields is irrelevant for
+ * OFFLOAD Queues, as the host is responsible for providing the correct TID in
+ * every WR.
+ *
+ * Ingress Trafffic for OFFLOAD Queue[i] is sent to RESP Queue[i].
+ */
+#define FW_OFLD_NUM 8
+#define FW_OFLD_SGEEC_START 0
+
+/*
+ *
+ */
+#define FW_RI_NUM 1
+#define FW_RI_SGEEC_START 65527
+#define FW_RI_TID_START 65552
+
+/*
+ * The RX_PKT_TID
+ */
+#define FW_RX_PKT_NUM 1
+#define FW_RX_PKT_TID_START 65553
+
+/* FW_WRC_NUM corresponds to the number of Work Request Context that supported
+ * by the firmware.
+ */
+#define FW_WRC_NUM \
+ (65536 + FW_TUNNEL_NUM + FW_CTRL_NUM + FW_RI_NUM + FW_RX_PKT_NUM)
+
+/*
+ * FW type and version.
+ */
+#define S_FW_VERSION_TYPE 28
+#define M_FW_VERSION_TYPE 0xF
+#define V_FW_VERSION_TYPE(x) ((x) << S_FW_VERSION_TYPE)
+#define G_FW_VERSION_TYPE(x) \
+ (((x) >> S_FW_VERSION_TYPE) & M_FW_VERSION_TYPE)
+
+#define S_FW_VERSION_MAJOR 16
+#define M_FW_VERSION_MAJOR 0xFFF
+#define V_FW_VERSION_MAJOR(x) ((x) << S_FW_VERSION_MAJOR)
+#define G_FW_VERSION_MAJOR(x) \
+ (((x) >> S_FW_VERSION_MAJOR) & M_FW_VERSION_MAJOR)
+
+#define S_FW_VERSION_MINOR 8
+#define M_FW_VERSION_MINOR 0xFF
+#define V_FW_VERSION_MINOR(x) ((x) << S_FW_VERSION_MINOR)
+#define G_FW_VERSION_MINOR(x) \
+ (((x) >> S_FW_VERSION_MINOR) & M_FW_VERSION_MINOR)
+
+#define S_FW_VERSION_MICRO 0
+#define M_FW_VERSION_MICRO 0xFF
+#define V_FW_VERSION_MICRO(x) ((x) << S_FW_VERSION_MICRO)
+#define G_FW_VERSION_MICRO(x) \
+ (((x) >> S_FW_VERSION_MICRO) & M_FW_VERSION_MICRO)
+
+#endif /* _FIRMWARE_EXPORTS_H_ */
diff --git a/drivers/net/cxgb3/l2t.c b/drivers/net/cxgb3/l2t.c
new file mode 100644
index 00000000000..3c0cb855705
--- /dev/null
+++ b/drivers/net/cxgb3/l2t.c
@@ -0,0 +1,450 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/if.h>
+#include <linux/if_vlan.h>
+#include <linux/jhash.h>
+#include <net/neighbour.h>
+#include "common.h"
+#include "t3cdev.h"
+#include "cxgb3_defs.h"
+#include "l2t.h"
+#include "t3_cpl.h"
+#include "firmware_exports.h"
+
+#define VLAN_NONE 0xfff
+
+/*
+ * Module locking notes: There is a RW lock protecting the L2 table as a
+ * whole plus a spinlock per L2T entry. Entry lookups and allocations happen
+ * under the protection of the table lock, individual entry changes happen
+ * while holding that entry's spinlock. The table lock nests outside the
+ * entry locks. Allocations of new entries take the table lock as writers so
+ * no other lookups can happen while allocating new entries. Entry updates
+ * take the table lock as readers so multiple entries can be updated in
+ * parallel. An L2T entry can be dropped by decrementing its reference count
+ * and therefore can happen in parallel with entry allocation but no entry
+ * can change state or increment its ref count during allocation as both of
+ * these perform lookups.
+ */
+
+static inline unsigned int vlan_prio(const struct l2t_entry *e)
+{
+ return e->vlan >> 13;
+}
+
+static inline unsigned int arp_hash(u32 key, int ifindex,
+ const struct l2t_data *d)
+{
+ return jhash_2words(key, ifindex, 0) & (d->nentries - 1);
+}
+
+static inline void neigh_replace(struct l2t_entry *e, struct neighbour *n)
+{
+ neigh_hold(n);
+ if (e->neigh)
+ neigh_release(e->neigh);
+ e->neigh = n;
+}
+
+/*
+ * Set up an L2T entry and send any packets waiting in the arp queue. The
+ * supplied skb is used for the CPL_L2T_WRITE_REQ. Must be called with the
+ * entry locked.
+ */
+static int setup_l2e_send_pending(struct t3cdev *dev, struct sk_buff *skb,
+ struct l2t_entry *e)
+{
+ struct cpl_l2t_write_req *req;
+
+ if (!skb) {
+ skb = alloc_skb(sizeof(*req), GFP_ATOMIC);
+ if (!skb)
+ return -ENOMEM;
+ }
+
+ req = (struct cpl_l2t_write_req *)__skb_put(skb, sizeof(*req));
+ req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+ OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, e->idx));
+ req->params = htonl(V_L2T_W_IDX(e->idx) | V_L2T_W_IFF(e->smt_idx) |
+ V_L2T_W_VLAN(e->vlan & VLAN_VID_MASK) |
+ V_L2T_W_PRIO(vlan_prio(e)));
+ memcpy(e->dmac, e->neigh->ha, sizeof(e->dmac));
+ memcpy(req->dst_mac, e->dmac, sizeof(req->dst_mac));
+ skb->priority = CPL_PRIORITY_CONTROL;
+ cxgb3_ofld_send(dev, skb);
+ while (e->arpq_head) {
+ skb = e->arpq_head;
+ e->arpq_head = skb->next;
+ skb->next = NULL;
+ cxgb3_ofld_send(dev, skb);
+ }
+ e->arpq_tail = NULL;
+ e->state = L2T_STATE_VALID;
+
+ return 0;
+}
+
+/*
+ * Add a packet to the an L2T entry's queue of packets awaiting resolution.
+ * Must be called with the entry's lock held.
+ */
+static inline void arpq_enqueue(struct l2t_entry *e, struct sk_buff *skb)
+{
+ skb->next = NULL;
+ if (e->arpq_head)
+ e->arpq_tail->next = skb;
+ else
+ e->arpq_head = skb;
+ e->arpq_tail = skb;
+}
+
+int t3_l2t_send_slow(struct t3cdev *dev, struct sk_buff *skb,
+ struct l2t_entry *e)
+{
+again:
+ switch (e->state) {
+ case L2T_STATE_STALE: /* entry is stale, kick off revalidation */
+ neigh_event_send(e->neigh, NULL);
+ spin_lock_bh(&e->lock);
+ if (e->state == L2T_STATE_STALE)
+ e->state = L2T_STATE_VALID;
+ spin_unlock_bh(&e->lock);
+ case L2T_STATE_VALID: /* fast-path, send the packet on */
+ return cxgb3_ofld_send(dev, skb);
+ case L2T_STATE_RESOLVING:
+ spin_lock_bh(&e->lock);
+ if (e->state != L2T_STATE_RESOLVING) {
+ /* ARP already completed */
+ spin_unlock_bh(&e->lock);
+ goto again;
+ }
+ arpq_enqueue(e, skb);
+ spin_unlock_bh(&e->lock);
+
+ /*
+ * Only the first packet added to the arpq should kick off
+ * resolution. However, because the alloc_skb below can fail,
+ * we allow each packet added to the arpq to retry resolution
+ * as a way of recovering from transient memory exhaustion.
+ * A better way would be to use a work request to retry L2T
+ * entries when there's no memory.
+ */
+ if (!neigh_event_send(e->neigh, NULL)) {
+ skb = alloc_skb(sizeof(struct cpl_l2t_write_req),
+ GFP_ATOMIC);
+ if (!skb)
+ break;
+
+ spin_lock_bh(&e->lock);
+ if (e->arpq_head)
+ setup_l2e_send_pending(dev, skb, e);
+ else /* we lost the race */
+ __kfree_skb(skb);
+ spin_unlock_bh(&e->lock);
+ }
+ }
+ return 0;
+}
+
+EXPORT_SYMBOL(t3_l2t_send_slow);
+
+void t3_l2t_send_event(struct t3cdev *dev, struct l2t_entry *e)
+{
+again:
+ switch (e->state) {
+ case L2T_STATE_STALE: /* entry is stale, kick off revalidation */
+ neigh_event_send(e->neigh, NULL);
+ spin_lock_bh(&e->lock);
+ if (e->state == L2T_STATE_STALE) {
+ e->state = L2T_STATE_VALID;
+ }
+ spin_unlock_bh(&e->lock);
+ return;
+ case L2T_STATE_VALID: /* fast-path, send the packet on */
+ return;
+ case L2T_STATE_RESOLVING:
+ spin_lock_bh(&e->lock);
+ if (e->state != L2T_STATE_RESOLVING) {
+ /* ARP already completed */
+ spin_unlock_bh(&e->lock);
+ goto again;
+ }
+ spin_unlock_bh(&e->lock);
+
+ /*
+ * Only the first packet added to the arpq should kick off
+ * resolution. However, because the alloc_skb below can fail,
+ * we allow each packet added to the arpq to retry resolution
+ * as a way of recovering from transient memory exhaustion.
+ * A better way would be to use a work request to retry L2T
+ * entries when there's no memory.
+ */
+ neigh_event_send(e->neigh, NULL);
+ }
+ return;
+}
+
+EXPORT_SYMBOL(t3_l2t_send_event);
+
+/*
+ * Allocate a free L2T entry. Must be called with l2t_data.lock held.
+ */
+static struct l2t_entry *alloc_l2e(struct l2t_data *d)
+{
+ struct l2t_entry *end, *e, **p;
+
+ if (!atomic_read(&d->nfree))
+ return NULL;
+
+ /* there's definitely a free entry */
+ for (e = d->rover, end = &d->l2tab[d->nentries]; e != end; ++e)
+ if (atomic_read(&e->refcnt) == 0)
+ goto found;
+
+ for (e = &d->l2tab[1]; atomic_read(&e->refcnt); ++e) ;
+found:
+ d->rover = e + 1;
+ atomic_dec(&d->nfree);
+
+ /*
+ * The entry we found may be an inactive entry that is
+ * presently in the hash table. We need to remove it.
+ */
+ if (e->state != L2T_STATE_UNUSED) {
+ int hash = arp_hash(e->addr, e->ifindex, d);
+
+ for (p = &d->l2tab[hash].first; *p; p = &(*p)->next)
+ if (*p == e) {
+ *p = e->next;
+ break;
+ }
+ e->state = L2T_STATE_UNUSED;
+ }
+ return e;
+}
+
+/*
+ * Called when an L2T entry has no more users. The entry is left in the hash
+ * table since it is likely to be reused but we also bump nfree to indicate
+ * that the entry can be reallocated for a different neighbor. We also drop
+ * the existing neighbor reference in case the neighbor is going away and is
+ * waiting on our reference.
+ *
+ * Because entries can be reallocated to other neighbors once their ref count
+ * drops to 0 we need to take the entry's lock to avoid races with a new
+ * incarnation.
+ */
+void t3_l2e_free(struct l2t_data *d, struct l2t_entry *e)
+{
+ spin_lock_bh(&e->lock);
+ if (atomic_read(&e->refcnt) == 0) { /* hasn't been recycled */
+ if (e->neigh) {
+ neigh_release(e->neigh);
+ e->neigh = NULL;
+ }
+ }
+ spin_unlock_bh(&e->lock);
+ atomic_inc(&d->nfree);
+}
+
+EXPORT_SYMBOL(t3_l2e_free);
+
+/*
+ * Update an L2T entry that was previously used for the same next hop as neigh.
+ * Must be called with softirqs disabled.
+ */
+static inline void reuse_entry(struct l2t_entry *e, struct neighbour *neigh)
+{
+ unsigned int nud_state;
+
+ spin_lock(&e->lock); /* avoid race with t3_l2t_free */
+
+ if (neigh != e->neigh)
+ neigh_replace(e, neigh);
+ nud_state = neigh->nud_state;
+ if (memcmp(e->dmac, neigh->ha, sizeof(e->dmac)) ||
+ !(nud_state & NUD_VALID))
+ e->state = L2T_STATE_RESOLVING;
+ else if (nud_state & NUD_CONNECTED)
+ e->state = L2T_STATE_VALID;
+ else
+ e->state = L2T_STATE_STALE;
+ spin_unlock(&e->lock);
+}
+
+struct l2t_entry *t3_l2t_get(struct t3cdev *cdev, struct neighbour *neigh,
+ struct net_device *dev)
+{
+ struct l2t_entry *e;
+ struct l2t_data *d = L2DATA(cdev);
+ u32 addr = *(u32 *) neigh->primary_key;
+ int ifidx = neigh->dev->ifindex;
+ int hash = arp_hash(addr, ifidx, d);
+ struct port_info *p = netdev_priv(dev);
+ int smt_idx = p->port_id;
+
+ write_lock_bh(&d->lock);
+ for (e = d->l2tab[hash].first; e; e = e->next)
+ if (e->addr == addr && e->ifindex == ifidx &&
+ e->smt_idx == smt_idx) {
+ l2t_hold(d, e);
+ if (atomic_read(&e->refcnt) == 1)
+ reuse_entry(e, neigh);
+ goto done;
+ }
+
+ /* Need to allocate a new entry */
+ e = alloc_l2e(d);
+ if (e) {
+ spin_lock(&e->lock); /* avoid race with t3_l2t_free */
+ e->next = d->l2tab[hash].first;
+ d->l2tab[hash].first = e;
+ e->state = L2T_STATE_RESOLVING;
+ e->addr = addr;
+ e->ifindex = ifidx;
+ e->smt_idx = smt_idx;
+ atomic_set(&e->refcnt, 1);
+ neigh_replace(e, neigh);
+ if (neigh->dev->priv_flags & IFF_802_1Q_VLAN)
+ e->vlan = VLAN_DEV_INFO(neigh->dev)->vlan_id;
+ else
+ e->vlan = VLAN_NONE;
+ spin_unlock(&e->lock);
+ }
+done:
+ write_unlock_bh(&d->lock);
+ return e;
+}
+
+EXPORT_SYMBOL(t3_l2t_get);
+
+/*
+ * Called when address resolution fails for an L2T entry to handle packets
+ * on the arpq head. If a packet specifies a failure handler it is invoked,
+ * otherwise the packets is sent to the offload device.
+ *
+ * XXX: maybe we should abandon the latter behavior and just require a failure
+ * handler.
+ */
+static void handle_failed_resolution(struct t3cdev *dev, struct sk_buff *arpq)
+{
+ while (arpq) {
+ struct sk_buff *skb = arpq;
+ struct l2t_skb_cb *cb = L2T_SKB_CB(skb);
+
+ arpq = skb->next;
+ skb->next = NULL;
+ if (cb->arp_failure_handler)
+ cb->arp_failure_handler(dev, skb);
+ else
+ cxgb3_ofld_send(dev, skb);
+ }
+}
+
+/*
+ * Called when the host's ARP layer makes a change to some entry that is
+ * loaded into the HW L2 table.
+ */
+void t3_l2t_update(struct t3cdev *dev, struct neighbour *neigh)
+{
+ struct l2t_entry *e;
+ struct sk_buff *arpq = NULL;
+ struct l2t_data *d = L2DATA(dev);
+ u32 addr = *(u32 *) neigh->primary_key;
+ int ifidx = neigh->dev->ifindex;
+ int hash = arp_hash(addr, ifidx, d);
+
+ read_lock_bh(&d->lock);
+ for (e = d->l2tab[hash].first; e; e = e->next)
+ if (e->addr == addr && e->ifindex == ifidx) {
+ spin_lock(&e->lock);
+ goto found;
+ }
+ read_unlock_bh(&d->lock);
+ return;
+
+found:
+ read_unlock(&d->lock);
+ if (atomic_read(&e->refcnt)) {
+ if (neigh != e->neigh)
+ neigh_replace(e, neigh);
+
+ if (e->state == L2T_STATE_RESOLVING) {
+ if (neigh->nud_state & NUD_FAILED) {
+ arpq = e->arpq_head;
+ e->arpq_head = e->arpq_tail = NULL;
+ } else if (neigh_is_connected(neigh))
+ setup_l2e_send_pending(dev, NULL, e);
+ } else {
+ e->state = neigh_is_connected(neigh) ?
+ L2T_STATE_VALID : L2T_STATE_STALE;
+ if (memcmp(e->dmac, neigh->ha, 6))
+ setup_l2e_send_pending(dev, NULL, e);
+ }
+ }
+ spin_unlock_bh(&e->lock);
+
+ if (arpq)
+ handle_failed_resolution(dev, arpq);
+}
+
+struct l2t_data *t3_init_l2t(unsigned int l2t_capacity)
+{
+ struct l2t_data *d;
+ int i, size = sizeof(*d) + l2t_capacity * sizeof(struct l2t_entry);
+
+ d = cxgb_alloc_mem(size);
+ if (!d)
+ return NULL;
+
+ d->nentries = l2t_capacity;
+ d->rover = &d->l2tab[1]; /* entry 0 is not used */
+ atomic_set(&d->nfree, l2t_capacity - 1);
+ rwlock_init(&d->lock);
+
+ for (i = 0; i < l2t_capacity; ++i) {
+ d->l2tab[i].idx = i;
+ d->l2tab[i].state = L2T_STATE_UNUSED;
+ spin_lock_init(&d->l2tab[i].lock);
+ atomic_set(&d->l2tab[i].refcnt, 0);
+ }
+ return d;
+}
+
+void t3_free_l2t(struct l2t_data *d)
+{
+ cxgb_free_mem(d);
+}
+
diff --git a/drivers/net/cxgb3/l2t.h b/drivers/net/cxgb3/l2t.h
new file mode 100644
index 00000000000..ba5d2cbd724
--- /dev/null
+++ b/drivers/net/cxgb3/l2t.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _CHELSIO_L2T_H
+#define _CHELSIO_L2T_H
+
+#include <linux/spinlock.h>
+#include "t3cdev.h"
+#include <asm/atomic.h>
+
+enum {
+ L2T_STATE_VALID, /* entry is up to date */
+ L2T_STATE_STALE, /* entry may be used but needs revalidation */
+ L2T_STATE_RESOLVING, /* entry needs address resolution */
+ L2T_STATE_UNUSED /* entry not in use */
+};
+
+struct neighbour;
+struct sk_buff;
+
+/*
+ * Each L2T entry plays multiple roles. First of all, it keeps state for the
+ * corresponding entry of the HW L2 table and maintains a queue of offload
+ * packets awaiting address resolution. Second, it is a node of a hash table
+ * chain, where the nodes of the chain are linked together through their next
+ * pointer. Finally, each node is a bucket of a hash table, pointing to the
+ * first element in its chain through its first pointer.
+ */
+struct l2t_entry {
+ u16 state; /* entry state */
+ u16 idx; /* entry index */
+ u32 addr; /* dest IP address */
+ int ifindex; /* neighbor's net_device's ifindex */
+ u16 smt_idx; /* SMT index */
+ u16 vlan; /* VLAN TCI (id: bits 0-11, prio: 13-15 */
+ struct neighbour *neigh; /* associated neighbour */
+ struct l2t_entry *first; /* start of hash chain */
+ struct l2t_entry *next; /* next l2t_entry on chain */
+ struct sk_buff *arpq_head; /* queue of packets awaiting resolution */
+ struct sk_buff *arpq_tail;
+ spinlock_t lock;
+ atomic_t refcnt; /* entry reference count */
+ u8 dmac[6]; /* neighbour's MAC address */
+};
+
+struct l2t_data {
+ unsigned int nentries; /* number of entries */
+ struct l2t_entry *rover; /* starting point for next allocation */
+ atomic_t nfree; /* number of free entries */
+ rwlock_t lock;
+ struct l2t_entry l2tab[0];
+};
+
+typedef void (*arp_failure_handler_func)(struct t3cdev * dev,
+ struct sk_buff * skb);
+
+/*
+ * Callback stored in an skb to handle address resolution failure.
+ */
+struct l2t_skb_cb {
+ arp_failure_handler_func arp_failure_handler;
+};
+
+#define L2T_SKB_CB(skb) ((struct l2t_skb_cb *)(skb)->cb)
+
+static inline void set_arp_failure_handler(struct sk_buff *skb,
+ arp_failure_handler_func hnd)
+{
+ L2T_SKB_CB(skb)->arp_failure_handler = hnd;
+}
+
+/*
+ * Getting to the L2 data from an offload device.
+ */
+#define L2DATA(dev) ((dev)->l2opt)
+
+#define W_TCB_L2T_IX 0
+#define S_TCB_L2T_IX 7
+#define M_TCB_L2T_IX 0x7ffULL
+#define V_TCB_L2T_IX(x) ((x) << S_TCB_L2T_IX)
+
+void t3_l2e_free(struct l2t_data *d, struct l2t_entry *e);
+void t3_l2t_update(struct t3cdev *dev, struct neighbour *neigh);
+struct l2t_entry *t3_l2t_get(struct t3cdev *cdev, struct neighbour *neigh,
+ struct net_device *dev);
+int t3_l2t_send_slow(struct t3cdev *dev, struct sk_buff *skb,
+ struct l2t_entry *e);
+void t3_l2t_send_event(struct t3cdev *dev, struct l2t_entry *e);
+struct l2t_data *t3_init_l2t(unsigned int l2t_capacity);
+void t3_free_l2t(struct l2t_data *d);
+
+int cxgb3_ofld_send(struct t3cdev *dev, struct sk_buff *skb);
+
+static inline int l2t_send(struct t3cdev *dev, struct sk_buff *skb,
+ struct l2t_entry *e)
+{
+ if (likely(e->state == L2T_STATE_VALID))
+ return cxgb3_ofld_send(dev, skb);
+ return t3_l2t_send_slow(dev, skb, e);
+}
+
+static inline void l2t_release(struct l2t_data *d, struct l2t_entry *e)
+{
+ if (atomic_dec_and_test(&e->refcnt))
+ t3_l2e_free(d, e);
+}
+
+static inline void l2t_hold(struct l2t_data *d, struct l2t_entry *e)
+{
+ if (atomic_add_return(1, &e->refcnt) == 1) /* 0 -> 1 transition */
+ atomic_dec(&d->nfree);
+}
+
+#endif
diff --git a/drivers/net/cxgb3/mc5.c b/drivers/net/cxgb3/mc5.c
new file mode 100644
index 00000000000..644d62ea86a
--- /dev/null
+++ b/drivers/net/cxgb3/mc5.c
@@ -0,0 +1,473 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "common.h"
+#include "regs.h"
+
+enum {
+ IDT75P52100 = 4,
+ IDT75N43102 = 5
+};
+
+/* DBGI command mode */
+enum {
+ DBGI_MODE_MBUS = 0,
+ DBGI_MODE_IDT52100 = 5
+};
+
+/* IDT 75P52100 commands */
+#define IDT_CMD_READ 0
+#define IDT_CMD_WRITE 1
+#define IDT_CMD_SEARCH 2
+#define IDT_CMD_LEARN 3
+
+/* IDT LAR register address and value for 144-bit mode (low 32 bits) */
+#define IDT_LAR_ADR0 0x180006
+#define IDT_LAR_MODE144 0xffff0000
+
+/* IDT SCR and SSR addresses (low 32 bits) */
+#define IDT_SCR_ADR0 0x180000
+#define IDT_SSR0_ADR0 0x180002
+#define IDT_SSR1_ADR0 0x180004
+
+/* IDT GMR base address (low 32 bits) */
+#define IDT_GMR_BASE_ADR0 0x180020
+
+/* IDT data and mask array base addresses (low 32 bits) */
+#define IDT_DATARY_BASE_ADR0 0
+#define IDT_MSKARY_BASE_ADR0 0x80000
+
+/* IDT 75N43102 commands */
+#define IDT4_CMD_SEARCH144 3
+#define IDT4_CMD_WRITE 4
+#define IDT4_CMD_READ 5
+
+/* IDT 75N43102 SCR address (low 32 bits) */
+#define IDT4_SCR_ADR0 0x3
+
+/* IDT 75N43102 GMR base addresses (low 32 bits) */
+#define IDT4_GMR_BASE0 0x10
+#define IDT4_GMR_BASE1 0x20
+#define IDT4_GMR_BASE2 0x30
+
+/* IDT 75N43102 data and mask array base addresses (low 32 bits) */
+#define IDT4_DATARY_BASE_ADR0 0x1000000
+#define IDT4_MSKARY_BASE_ADR0 0x2000000
+
+#define MAX_WRITE_ATTEMPTS 5
+
+#define MAX_ROUTES 2048
+
+/*
+ * Issue a command to the TCAM and wait for its completion. The address and
+ * any data required by the command must have been setup by the caller.
+ */
+static int mc5_cmd_write(struct adapter *adapter, u32 cmd)
+{
+ t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_CMD, cmd);
+ return t3_wait_op_done(adapter, A_MC5_DB_DBGI_RSP_STATUS,
+ F_DBGIRSPVALID, 1, MAX_WRITE_ATTEMPTS, 1);
+}
+
+static inline void dbgi_wr_addr3(struct adapter *adapter, u32 v1, u32 v2,
+ u32 v3)
+{
+ t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR0, v1);
+ t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR1, v2);
+ t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR2, v3);
+}
+
+static inline void dbgi_wr_data3(struct adapter *adapter, u32 v1, u32 v2,
+ u32 v3)
+{
+ t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA0, v1);
+ t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA1, v2);
+ t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA2, v3);
+}
+
+static inline void dbgi_rd_rsp3(struct adapter *adapter, u32 *v1, u32 *v2,
+ u32 *v3)
+{
+ *v1 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA0);
+ *v2 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA1);
+ *v3 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA2);
+}
+
+/*
+ * Write data to the TCAM register at address (0, 0, addr_lo) using the TCAM
+ * command cmd. The data to be written must have been set up by the caller.
+ * Returns -1 on failure, 0 on success.
+ */
+static int mc5_write(struct adapter *adapter, u32 addr_lo, u32 cmd)
+{
+ t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR0, addr_lo);
+ if (mc5_cmd_write(adapter, cmd) == 0)
+ return 0;
+ CH_ERR(adapter, "MC5 timeout writing to TCAM address 0x%x\n",
+ addr_lo);
+ return -1;
+}
+
+static int init_mask_data_array(struct mc5 *mc5, u32 mask_array_base,
+ u32 data_array_base, u32 write_cmd,
+ int addr_shift)
+{
+ unsigned int i;
+ struct adapter *adap = mc5->adapter;
+
+ /*
+ * We need the size of the TCAM data and mask arrays in terms of
+ * 72-bit entries.
+ */
+ unsigned int size72 = mc5->tcam_size;
+ unsigned int server_base = t3_read_reg(adap, A_MC5_DB_SERVER_INDEX);
+
+ if (mc5->mode == MC5_MODE_144_BIT) {
+ size72 *= 2; /* 1 144-bit entry is 2 72-bit entries */
+ server_base *= 2;
+ }
+
+ /* Clear the data array */
+ dbgi_wr_data3(adap, 0, 0, 0);
+ for (i = 0; i < size72; i++)
+ if (mc5_write(adap, data_array_base + (i << addr_shift),
+ write_cmd))
+ return -1;
+
+ /* Initialize the mask array. */
+ dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff);
+ for (i = 0; i < size72; i++) {
+ if (i == server_base) /* entering server or routing region */
+ t3_write_reg(adap, A_MC5_DB_DBGI_REQ_DATA0,
+ mc5->mode == MC5_MODE_144_BIT ?
+ 0xfffffff9 : 0xfffffffd);
+ if (mc5_write(adap, mask_array_base + (i << addr_shift),
+ write_cmd))
+ return -1;
+ }
+ return 0;
+}
+
+static int init_idt52100(struct mc5 *mc5)
+{
+ int i;
+ struct adapter *adap = mc5->adapter;
+
+ t3_write_reg(adap, A_MC5_DB_RSP_LATENCY,
+ V_RDLAT(0x15) | V_LRNLAT(0x15) | V_SRCHLAT(0x15));
+ t3_write_reg(adap, A_MC5_DB_PART_ID_INDEX, 2);
+
+ /*
+ * Use GMRs 14-15 for ELOOKUP, GMRs 12-13 for SYN lookups, and
+ * GMRs 8-9 for ACK- and AOPEN searches.
+ */
+ t3_write_reg(adap, A_MC5_DB_POPEN_DATA_WR_CMD, IDT_CMD_WRITE);
+ t3_write_reg(adap, A_MC5_DB_POPEN_MASK_WR_CMD, IDT_CMD_WRITE);
+ t3_write_reg(adap, A_MC5_DB_AOPEN_SRCH_CMD, IDT_CMD_SEARCH);
+ t3_write_reg(adap, A_MC5_DB_AOPEN_LRN_CMD, IDT_CMD_LEARN);
+ t3_write_reg(adap, A_MC5_DB_SYN_SRCH_CMD, IDT_CMD_SEARCH | 0x6000);
+ t3_write_reg(adap, A_MC5_DB_SYN_LRN_CMD, IDT_CMD_LEARN);
+ t3_write_reg(adap, A_MC5_DB_ACK_SRCH_CMD, IDT_CMD_SEARCH);
+ t3_write_reg(adap, A_MC5_DB_ACK_LRN_CMD, IDT_CMD_LEARN);
+ t3_write_reg(adap, A_MC5_DB_ILOOKUP_CMD, IDT_CMD_SEARCH);
+ t3_write_reg(adap, A_MC5_DB_ELOOKUP_CMD, IDT_CMD_SEARCH | 0x7000);
+ t3_write_reg(adap, A_MC5_DB_DATA_WRITE_CMD, IDT_CMD_WRITE);
+ t3_write_reg(adap, A_MC5_DB_DATA_READ_CMD, IDT_CMD_READ);
+
+ /* Set DBGI command mode for IDT TCAM. */
+ t3_write_reg(adap, A_MC5_DB_DBGI_CONFIG, DBGI_MODE_IDT52100);
+
+ /* Set up LAR */
+ dbgi_wr_data3(adap, IDT_LAR_MODE144, 0, 0);
+ if (mc5_write(adap, IDT_LAR_ADR0, IDT_CMD_WRITE))
+ goto err;
+
+ /* Set up SSRs */
+ dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0);
+ if (mc5_write(adap, IDT_SSR0_ADR0, IDT_CMD_WRITE) ||
+ mc5_write(adap, IDT_SSR1_ADR0, IDT_CMD_WRITE))
+ goto err;
+
+ /* Set up GMRs */
+ for (i = 0; i < 32; ++i) {
+ if (i >= 12 && i < 15)
+ dbgi_wr_data3(adap, 0xfffffff9, 0xffffffff, 0xff);
+ else if (i == 15)
+ dbgi_wr_data3(adap, 0xfffffff9, 0xffff8007, 0xff);
+ else
+ dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff);
+
+ if (mc5_write(adap, IDT_GMR_BASE_ADR0 + i, IDT_CMD_WRITE))
+ goto err;
+ }
+
+ /* Set up SCR */
+ dbgi_wr_data3(adap, 1, 0, 0);
+ if (mc5_write(adap, IDT_SCR_ADR0, IDT_CMD_WRITE))
+ goto err;
+
+ return init_mask_data_array(mc5, IDT_MSKARY_BASE_ADR0,
+ IDT_DATARY_BASE_ADR0, IDT_CMD_WRITE, 0);
+err:
+ return -EIO;
+}
+
+static int init_idt43102(struct mc5 *mc5)
+{
+ int i;
+ struct adapter *adap = mc5->adapter;
+
+ t3_write_reg(adap, A_MC5_DB_RSP_LATENCY,
+ adap->params.rev == 0 ? V_RDLAT(0xd) | V_SRCHLAT(0x11) :
+ V_RDLAT(0xd) | V_SRCHLAT(0x12));
+
+ /*
+ * Use GMRs 24-25 for ELOOKUP, GMRs 20-21 for SYN lookups, and no mask
+ * for ACK- and AOPEN searches.
+ */
+ t3_write_reg(adap, A_MC5_DB_POPEN_DATA_WR_CMD, IDT4_CMD_WRITE);
+ t3_write_reg(adap, A_MC5_DB_POPEN_MASK_WR_CMD, IDT4_CMD_WRITE);
+ t3_write_reg(adap, A_MC5_DB_AOPEN_SRCH_CMD,
+ IDT4_CMD_SEARCH144 | 0x3800);
+ t3_write_reg(adap, A_MC5_DB_SYN_SRCH_CMD, IDT4_CMD_SEARCH144);
+ t3_write_reg(adap, A_MC5_DB_ACK_SRCH_CMD, IDT4_CMD_SEARCH144 | 0x3800);
+ t3_write_reg(adap, A_MC5_DB_ILOOKUP_CMD, IDT4_CMD_SEARCH144 | 0x3800);
+ t3_write_reg(adap, A_MC5_DB_ELOOKUP_CMD, IDT4_CMD_SEARCH144 | 0x800);
+ t3_write_reg(adap, A_MC5_DB_DATA_WRITE_CMD, IDT4_CMD_WRITE);
+ t3_write_reg(adap, A_MC5_DB_DATA_READ_CMD, IDT4_CMD_READ);
+
+ t3_write_reg(adap, A_MC5_DB_PART_ID_INDEX, 3);
+
+ /* Set DBGI command mode for IDT TCAM. */
+ t3_write_reg(adap, A_MC5_DB_DBGI_CONFIG, DBGI_MODE_IDT52100);
+
+ /* Set up GMRs */
+ dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff);
+ for (i = 0; i < 7; ++i)
+ if (mc5_write(adap, IDT4_GMR_BASE0 + i, IDT4_CMD_WRITE))
+ goto err;
+
+ for (i = 0; i < 4; ++i)
+ if (mc5_write(adap, IDT4_GMR_BASE2 + i, IDT4_CMD_WRITE))
+ goto err;
+
+ dbgi_wr_data3(adap, 0xfffffff9, 0xffffffff, 0xff);
+ if (mc5_write(adap, IDT4_GMR_BASE1, IDT4_CMD_WRITE) ||
+ mc5_write(adap, IDT4_GMR_BASE1 + 1, IDT4_CMD_WRITE) ||
+ mc5_write(adap, IDT4_GMR_BASE1 + 4, IDT4_CMD_WRITE))
+ goto err;
+
+ dbgi_wr_data3(adap, 0xfffffff9, 0xffff8007, 0xff);
+ if (mc5_write(adap, IDT4_GMR_BASE1 + 5, IDT4_CMD_WRITE))
+ goto err;
+
+ /* Set up SCR */
+ dbgi_wr_data3(adap, 0xf0000000, 0, 0);
+ if (mc5_write(adap, IDT4_SCR_ADR0, IDT4_CMD_WRITE))
+ goto err;
+
+ return init_mask_data_array(mc5, IDT4_MSKARY_BASE_ADR0,
+ IDT4_DATARY_BASE_ADR0, IDT4_CMD_WRITE, 1);
+err:
+ return -EIO;
+}
+
+/* Put MC5 in DBGI mode. */
+static inline void mc5_dbgi_mode_enable(const struct mc5 *mc5)
+{
+ t3_write_reg(mc5->adapter, A_MC5_DB_CONFIG,
+ V_TMMODE(mc5->mode == MC5_MODE_72_BIT) | F_DBGIEN);
+}
+
+/* Put MC5 in M-Bus mode. */
+static void mc5_dbgi_mode_disable(const struct mc5 *mc5)
+{
+ t3_write_reg(mc5->adapter, A_MC5_DB_CONFIG,
+ V_TMMODE(mc5->mode == MC5_MODE_72_BIT) |
+ V_COMPEN(mc5->mode == MC5_MODE_72_BIT) |
+ V_PRTYEN(mc5->parity_enabled) | F_MBUSEN);
+}
+
+/*
+ * Initialization that requires the OS and protocol layers to already
+ * be intialized goes here.
+ */
+int t3_mc5_init(struct mc5 *mc5, unsigned int nservers, unsigned int nfilters,
+ unsigned int nroutes)
+{
+ u32 cfg;
+ int err;
+ unsigned int tcam_size = mc5->tcam_size;
+ struct adapter *adap = mc5->adapter;
+
+ if (nroutes > MAX_ROUTES || nroutes + nservers + nfilters > tcam_size)
+ return -EINVAL;
+
+ /* Reset the TCAM */
+ cfg = t3_read_reg(adap, A_MC5_DB_CONFIG) & ~F_TMMODE;
+ cfg |= V_TMMODE(mc5->mode == MC5_MODE_72_BIT) | F_TMRST;
+ t3_write_reg(adap, A_MC5_DB_CONFIG, cfg);
+ if (t3_wait_op_done(adap, A_MC5_DB_CONFIG, F_TMRDY, 1, 500, 0)) {
+ CH_ERR(adap, "TCAM reset timed out\n");
+ return -1;
+ }
+
+ t3_write_reg(adap, A_MC5_DB_ROUTING_TABLE_INDEX, tcam_size - nroutes);
+ t3_write_reg(adap, A_MC5_DB_FILTER_TABLE,
+ tcam_size - nroutes - nfilters);
+ t3_write_reg(adap, A_MC5_DB_SERVER_INDEX,
+ tcam_size - nroutes - nfilters - nservers);
+
+ mc5->parity_enabled = 1;
+
+ /* All the TCAM addresses we access have only the low 32 bits non 0 */
+ t3_write_reg(adap, A_MC5_DB_DBGI_REQ_ADDR1, 0);
+ t3_write_reg(adap, A_MC5_DB_DBGI_REQ_ADDR2, 0);
+
+ mc5_dbgi_mode_enable(mc5);
+
+ switch (mc5->part_type) {
+ case IDT75P52100:
+ err = init_idt52100(mc5);
+ break;
+ case IDT75N43102:
+ err = init_idt43102(mc5);
+ break;
+ default:
+ CH_ERR(adap, "Unsupported TCAM type %d\n", mc5->part_type);
+ err = -EINVAL;
+ break;
+ }
+
+ mc5_dbgi_mode_disable(mc5);
+ return err;
+}
+
+/*
+ * read_mc5_range - dump a part of the memory managed by MC5
+ * @mc5: the MC5 handle
+ * @start: the start address for the dump
+ * @n: number of 72-bit words to read
+ * @buf: result buffer
+ *
+ * Read n 72-bit words from MC5 memory from the given start location.
+ */
+int t3_read_mc5_range(const struct mc5 *mc5, unsigned int start,
+ unsigned int n, u32 *buf)
+{
+ u32 read_cmd;
+ int err = 0;
+ struct adapter *adap = mc5->adapter;
+
+ if (mc5->part_type == IDT75P52100)
+ read_cmd = IDT_CMD_READ;
+ else if (mc5->part_type == IDT75N43102)
+ read_cmd = IDT4_CMD_READ;
+ else
+ return -EINVAL;
+
+ mc5_dbgi_mode_enable(mc5);
+
+ while (n--) {
+ t3_write_reg(adap, A_MC5_DB_DBGI_REQ_ADDR0, start++);
+ if (mc5_cmd_write(adap, read_cmd)) {
+ err = -EIO;
+ break;
+ }
+ dbgi_rd_rsp3(adap, buf + 2, buf + 1, buf);
+ buf += 3;
+ }
+
+ mc5_dbgi_mode_disable(mc5);
+ return 0;
+}
+
+#define MC5_INT_FATAL (F_PARITYERR | F_REQQPARERR | F_DISPQPARERR)
+
+/*
+ * MC5 interrupt handler
+ */
+void t3_mc5_intr_handler(struct mc5 *mc5)
+{
+ struct adapter *adap = mc5->adapter;
+ u32 cause = t3_read_reg(adap, A_MC5_DB_INT_CAUSE);
+
+ if ((cause & F_PARITYERR) && mc5->parity_enabled) {
+ CH_ALERT(adap, "MC5 parity error\n");
+ mc5->stats.parity_err++;
+ }
+
+ if (cause & F_REQQPARERR) {
+ CH_ALERT(adap, "MC5 request queue parity error\n");
+ mc5->stats.reqq_parity_err++;
+ }
+
+ if (cause & F_DISPQPARERR) {
+ CH_ALERT(adap, "MC5 dispatch queue parity error\n");
+ mc5->stats.dispq_parity_err++;
+ }
+
+ if (cause & F_ACTRGNFULL)
+ mc5->stats.active_rgn_full++;
+ if (cause & F_NFASRCHFAIL)
+ mc5->stats.nfa_srch_err++;
+ if (cause & F_UNKNOWNCMD)
+ mc5->stats.unknown_cmd++;
+ if (cause & F_DELACTEMPTY)
+ mc5->stats.del_act_empty++;
+ if (cause & MC5_INT_FATAL)
+ t3_fatal_err(adap);
+
+ t3_write_reg(adap, A_MC5_DB_INT_CAUSE, cause);
+}
+
+void __devinit t3_mc5_prep(struct adapter *adapter, struct mc5 *mc5, int mode)
+{
+#define K * 1024
+
+ static unsigned int tcam_part_size[] = { /* in K 72-bit entries */
+ 64 K, 128 K, 256 K, 32 K
+ };
+
+#undef K
+
+ u32 cfg = t3_read_reg(adapter, A_MC5_DB_CONFIG);
+
+ mc5->adapter = adapter;
+ mc5->mode = (unsigned char)mode;
+ mc5->part_type = (unsigned char)G_TMTYPE(cfg);
+ if (cfg & F_TMTYPEHI)
+ mc5->part_type |= 4;
+
+ mc5->tcam_size = tcam_part_size[G_TMPARTSIZE(cfg)];
+ if (mode == MC5_MODE_144_BIT)
+ mc5->tcam_size /= 2;
+}
diff --git a/drivers/net/cxgb3/regs.h b/drivers/net/cxgb3/regs.h
new file mode 100644
index 00000000000..b56c5f52bcd
--- /dev/null
+++ b/drivers/net/cxgb3/regs.h
@@ -0,0 +1,2195 @@
+#define A_SG_CONTROL 0x0
+
+#define S_DROPPKT 20
+#define V_DROPPKT(x) ((x) << S_DROPPKT)
+#define F_DROPPKT V_DROPPKT(1U)
+
+#define S_EGRGENCTRL 19
+#define V_EGRGENCTRL(x) ((x) << S_EGRGENCTRL)
+#define F_EGRGENCTRL V_EGRGENCTRL(1U)
+
+#define S_USERSPACESIZE 14
+#define M_USERSPACESIZE 0x1f
+#define V_USERSPACESIZE(x) ((x) << S_USERSPACESIZE)
+
+#define S_HOSTPAGESIZE 11
+#define M_HOSTPAGESIZE 0x7
+#define V_HOSTPAGESIZE(x) ((x) << S_HOSTPAGESIZE)
+
+#define S_FLMODE 9
+#define V_FLMODE(x) ((x) << S_FLMODE)
+#define F_FLMODE V_FLMODE(1U)
+
+#define S_PKTSHIFT 6
+#define M_PKTSHIFT 0x7
+#define V_PKTSHIFT(x) ((x) << S_PKTSHIFT)
+
+#define S_ONEINTMULTQ 5
+#define V_ONEINTMULTQ(x) ((x) << S_ONEINTMULTQ)
+#define F_ONEINTMULTQ V_ONEINTMULTQ(1U)
+
+#define S_BIGENDIANINGRESS 2
+#define V_BIGENDIANINGRESS(x) ((x) << S_BIGENDIANINGRESS)
+#define F_BIGENDIANINGRESS V_BIGENDIANINGRESS(1U)
+
+#define S_ISCSICOALESCING 1
+#define V_ISCSICOALESCING(x) ((x) << S_ISCSICOALESCING)
+#define F_ISCSICOALESCING V_ISCSICOALESCING(1U)
+
+#define S_GLOBALENABLE 0
+#define V_GLOBALENABLE(x) ((x) << S_GLOBALENABLE)
+#define F_GLOBALENABLE V_GLOBALENABLE(1U)
+
+#define S_AVOIDCQOVFL 24
+#define V_AVOIDCQOVFL(x) ((x) << S_AVOIDCQOVFL)
+#define F_AVOIDCQOVFL V_AVOIDCQOVFL(1U)
+
+#define S_OPTONEINTMULTQ 23
+#define V_OPTONEINTMULTQ(x) ((x) << S_OPTONEINTMULTQ)
+#define F_OPTONEINTMULTQ V_OPTONEINTMULTQ(1U)
+
+#define S_CQCRDTCTRL 22
+#define V_CQCRDTCTRL(x) ((x) << S_CQCRDTCTRL)
+#define F_CQCRDTCTRL V_CQCRDTCTRL(1U)
+
+#define A_SG_KDOORBELL 0x4
+
+#define S_SELEGRCNTX 31
+#define V_SELEGRCNTX(x) ((x) << S_SELEGRCNTX)
+#define F_SELEGRCNTX V_SELEGRCNTX(1U)
+
+#define S_EGRCNTX 0
+#define M_EGRCNTX 0xffff
+#define V_EGRCNTX(x) ((x) << S_EGRCNTX)
+
+#define A_SG_GTS 0x8
+
+#define S_RSPQ 29
+#define M_RSPQ 0x7
+#define V_RSPQ(x) ((x) << S_RSPQ)
+#define G_RSPQ(x) (((x) >> S_RSPQ) & M_RSPQ)
+
+#define S_NEWTIMER 16
+#define M_NEWTIMER 0x1fff
+#define V_NEWTIMER(x) ((x) << S_NEWTIMER)
+
+#define S_NEWINDEX 0
+#define M_NEWINDEX 0xffff
+#define V_NEWINDEX(x) ((x) << S_NEWINDEX)
+
+#define A_SG_CONTEXT_CMD 0xc
+
+#define S_CONTEXT_CMD_OPCODE 28
+#define M_CONTEXT_CMD_OPCODE 0xf
+#define V_CONTEXT_CMD_OPCODE(x) ((x) << S_CONTEXT_CMD_OPCODE)
+
+#define S_CONTEXT_CMD_BUSY 27
+#define V_CONTEXT_CMD_BUSY(x) ((x) << S_CONTEXT_CMD_BUSY)
+#define F_CONTEXT_CMD_BUSY V_CONTEXT_CMD_BUSY(1U)
+
+#define S_CQ_CREDIT 20
+
+#define M_CQ_CREDIT 0x7f
+
+#define V_CQ_CREDIT(x) ((x) << S_CQ_CREDIT)
+
+#define G_CQ_CREDIT(x) (((x) >> S_CQ_CREDIT) & M_CQ_CREDIT)
+
+#define S_CQ 19
+
+#define V_CQ(x) ((x) << S_CQ)
+#define F_CQ V_CQ(1U)
+
+#define S_RESPONSEQ 18
+#define V_RESPONSEQ(x) ((x) << S_RESPONSEQ)
+#define F_RESPONSEQ V_RESPONSEQ(1U)
+
+#define S_EGRESS 17
+#define V_EGRESS(x) ((x) << S_EGRESS)
+#define F_EGRESS V_EGRESS(1U)
+
+#define S_FREELIST 16
+#define V_FREELIST(x) ((x) << S_FREELIST)
+#define F_FREELIST V_FREELIST(1U)
+
+#define S_CONTEXT 0
+#define M_CONTEXT 0xffff
+#define V_CONTEXT(x) ((x) << S_CONTEXT)
+
+#define G_CONTEXT(x) (((x) >> S_CONTEXT) & M_CONTEXT)
+
+#define A_SG_CONTEXT_DATA0 0x10
+
+#define A_SG_CONTEXT_DATA1 0x14
+
+#define A_SG_CONTEXT_DATA2 0x18
+
+#define A_SG_CONTEXT_DATA3 0x1c
+
+#define A_SG_CONTEXT_MASK0 0x20
+
+#define A_SG_CONTEXT_MASK1 0x24
+
+#define A_SG_CONTEXT_MASK2 0x28
+
+#define A_SG_CONTEXT_MASK3 0x2c
+
+#define A_SG_RSPQ_CREDIT_RETURN 0x30
+
+#define S_CREDITS 0
+#define M_CREDITS 0xffff
+#define V_CREDITS(x) ((x) << S_CREDITS)
+
+#define A_SG_DATA_INTR 0x34
+
+#define S_ERRINTR 31
+#define V_ERRINTR(x) ((x) << S_ERRINTR)
+#define F_ERRINTR V_ERRINTR(1U)
+
+#define A_SG_HI_DRB_HI_THRSH 0x38
+
+#define A_SG_HI_DRB_LO_THRSH 0x3c
+
+#define A_SG_LO_DRB_HI_THRSH 0x40
+
+#define A_SG_LO_DRB_LO_THRSH 0x44
+
+#define A_SG_RSPQ_FL_STATUS 0x4c
+
+#define S_RSPQ0DISABLED 8
+
+#define A_SG_EGR_RCQ_DRB_THRSH 0x54
+
+#define S_HIRCQDRBTHRSH 16
+#define M_HIRCQDRBTHRSH 0x7ff
+#define V_HIRCQDRBTHRSH(x) ((x) << S_HIRCQDRBTHRSH)
+
+#define S_LORCQDRBTHRSH 0
+#define M_LORCQDRBTHRSH 0x7ff
+#define V_LORCQDRBTHRSH(x) ((x) << S_LORCQDRBTHRSH)
+
+#define A_SG_EGR_CNTX_BADDR 0x58
+
+#define A_SG_INT_CAUSE 0x5c
+
+#define S_RSPQDISABLED 3
+#define V_RSPQDISABLED(x) ((x) << S_RSPQDISABLED)
+#define F_RSPQDISABLED V_RSPQDISABLED(1U)
+
+#define S_RSPQCREDITOVERFOW 2
+#define V_RSPQCREDITOVERFOW(x) ((x) << S_RSPQCREDITOVERFOW)
+#define F_RSPQCREDITOVERFOW V_RSPQCREDITOVERFOW(1U)
+
+#define A_SG_INT_ENABLE 0x60
+
+#define A_SG_CMDQ_CREDIT_TH 0x64
+
+#define S_TIMEOUT 8
+#define M_TIMEOUT 0xffffff
+#define V_TIMEOUT(x) ((x) << S_TIMEOUT)
+
+#define S_THRESHOLD 0
+#define M_THRESHOLD 0xff
+#define V_THRESHOLD(x) ((x) << S_THRESHOLD)
+
+#define A_SG_TIMER_TICK 0x68
+
+#define A_SG_CQ_CONTEXT_BADDR 0x6c
+
+#define A_SG_OCO_BASE 0x70
+
+#define S_BASE1 16
+#define M_BASE1 0xffff
+#define V_BASE1(x) ((x) << S_BASE1)
+
+#define A_SG_DRB_PRI_THRESH 0x74
+
+#define A_PCIX_INT_ENABLE 0x80
+
+#define S_MSIXPARERR 22
+#define M_MSIXPARERR 0x7
+
+#define V_MSIXPARERR(x) ((x) << S_MSIXPARERR)
+
+#define S_CFPARERR 18
+#define M_CFPARERR 0xf
+
+#define V_CFPARERR(x) ((x) << S_CFPARERR)
+
+#define S_RFPARERR 14
+#define M_RFPARERR 0xf
+
+#define V_RFPARERR(x) ((x) << S_RFPARERR)
+
+#define S_WFPARERR 12
+#define M_WFPARERR 0x3
+
+#define V_WFPARERR(x) ((x) << S_WFPARERR)
+
+#define S_PIOPARERR 11
+#define V_PIOPARERR(x) ((x) << S_PIOPARERR)
+#define F_PIOPARERR V_PIOPARERR(1U)
+
+#define S_DETUNCECCERR 10
+#define V_DETUNCECCERR(x) ((x) << S_DETUNCECCERR)
+#define F_DETUNCECCERR V_DETUNCECCERR(1U)
+
+#define S_DETCORECCERR 9
+#define V_DETCORECCERR(x) ((x) << S_DETCORECCERR)
+#define F_DETCORECCERR V_DETCORECCERR(1U)
+
+#define S_RCVSPLCMPERR 8
+#define V_RCVSPLCMPERR(x) ((x) << S_RCVSPLCMPERR)
+#define F_RCVSPLCMPERR V_RCVSPLCMPERR(1U)
+
+#define S_UNXSPLCMP 7
+#define V_UNXSPLCMP(x) ((x) << S_UNXSPLCMP)
+#define F_UNXSPLCMP V_UNXSPLCMP(1U)
+
+#define S_SPLCMPDIS 6
+#define V_SPLCMPDIS(x) ((x) << S_SPLCMPDIS)
+#define F_SPLCMPDIS V_SPLCMPDIS(1U)
+
+#define S_DETPARERR 5
+#define V_DETPARERR(x) ((x) << S_DETPARERR)
+#define F_DETPARERR V_DETPARERR(1U)
+
+#define S_SIGSYSERR 4
+#define V_SIGSYSERR(x) ((x) << S_SIGSYSERR)
+#define F_SIGSYSERR V_SIGSYSERR(1U)
+
+#define S_RCVMSTABT 3
+#define V_RCVMSTABT(x) ((x) << S_RCVMSTABT)
+#define F_RCVMSTABT V_RCVMSTABT(1U)
+
+#define S_RCVTARABT 2
+#define V_RCVTARABT(x) ((x) << S_RCVTARABT)
+#define F_RCVTARABT V_RCVTARABT(1U)
+
+#define S_SIGTARABT 1
+#define V_SIGTARABT(x) ((x) << S_SIGTARABT)
+#define F_SIGTARABT V_SIGTARABT(1U)
+
+#define S_MSTDETPARERR 0
+#define V_MSTDETPARERR(x) ((x) << S_MSTDETPARERR)
+#define F_MSTDETPARERR V_MSTDETPARERR(1U)
+
+#define A_PCIX_INT_CAUSE 0x84
+
+#define A_PCIX_CFG 0x88
+
+#define S_CLIDECEN 18
+#define V_CLIDECEN(x) ((x) << S_CLIDECEN)
+#define F_CLIDECEN V_CLIDECEN(1U)
+
+#define A_PCIX_MODE 0x8c
+
+#define S_PCLKRANGE 6
+#define M_PCLKRANGE 0x3
+#define V_PCLKRANGE(x) ((x) << S_PCLKRANGE)
+#define G_PCLKRANGE(x) (((x) >> S_PCLKRANGE) & M_PCLKRANGE)
+
+#define S_PCIXINITPAT 2
+#define M_PCIXINITPAT 0xf
+#define V_PCIXINITPAT(x) ((x) << S_PCIXINITPAT)
+#define G_PCIXINITPAT(x) (((x) >> S_PCIXINITPAT) & M_PCIXINITPAT)
+
+#define S_64BIT 0
+#define V_64BIT(x) ((x) << S_64BIT)
+#define F_64BIT V_64BIT(1U)
+
+#define A_PCIE_INT_ENABLE 0x80
+
+#define S_BISTERR 15
+#define M_BISTERR 0xff
+
+#define V_BISTERR(x) ((x) << S_BISTERR)
+
+#define S_PCIE_MSIXPARERR 12
+#define M_PCIE_MSIXPARERR 0x7
+
+#define V_PCIE_MSIXPARERR(x) ((x) << S_PCIE_MSIXPARERR)
+
+#define S_PCIE_CFPARERR 11
+#define V_PCIE_CFPARERR(x) ((x) << S_PCIE_CFPARERR)
+#define F_PCIE_CFPARERR V_PCIE_CFPARERR(1U)
+
+#define S_PCIE_RFPARERR 10
+#define V_PCIE_RFPARERR(x) ((x) << S_PCIE_RFPARERR)
+#define F_PCIE_RFPARERR V_PCIE_RFPARERR(1U)
+
+#define S_PCIE_WFPARERR 9
+#define V_PCIE_WFPARERR(x) ((x) << S_PCIE_WFPARERR)
+#define F_PCIE_WFPARERR V_PCIE_WFPARERR(1U)
+
+#define S_PCIE_PIOPARERR 8
+#define V_PCIE_PIOPARERR(x) ((x) << S_PCIE_PIOPARERR)
+#define F_PCIE_PIOPARERR V_PCIE_PIOPARERR(1U)
+
+#define S_UNXSPLCPLERRC 7
+#define V_UNXSPLCPLERRC(x) ((x) << S_UNXSPLCPLERRC)
+#define F_UNXSPLCPLERRC V_UNXSPLCPLERRC(1U)
+
+#define S_UNXSPLCPLERRR 6
+#define V_UNXSPLCPLERRR(x) ((x) << S_UNXSPLCPLERRR)
+#define F_UNXSPLCPLERRR V_UNXSPLCPLERRR(1U)
+
+#define S_PEXERR 0
+#define V_PEXERR(x) ((x) << S_PEXERR)
+#define F_PEXERR V_PEXERR(1U)
+
+#define A_PCIE_INT_CAUSE 0x84
+
+#define A_PCIE_CFG 0x88
+
+#define S_PCIE_CLIDECEN 16
+#define V_PCIE_CLIDECEN(x) ((x) << S_PCIE_CLIDECEN)
+#define F_PCIE_CLIDECEN V_PCIE_CLIDECEN(1U)
+
+#define S_CRSTWRMMODE 0
+#define V_CRSTWRMMODE(x) ((x) << S_CRSTWRMMODE)
+#define F_CRSTWRMMODE V_CRSTWRMMODE(1U)
+
+#define A_PCIE_MODE 0x8c
+
+#define S_NUMFSTTRNSEQRX 10
+#define M_NUMFSTTRNSEQRX 0xff
+#define V_NUMFSTTRNSEQRX(x) ((x) << S_NUMFSTTRNSEQRX)
+#define G_NUMFSTTRNSEQRX(x) (((x) >> S_NUMFSTTRNSEQRX) & M_NUMFSTTRNSEQRX)
+
+#define A_PCIE_PEX_CTRL0 0x98
+
+#define S_NUMFSTTRNSEQ 22
+#define M_NUMFSTTRNSEQ 0xff
+#define V_NUMFSTTRNSEQ(x) ((x) << S_NUMFSTTRNSEQ)
+#define G_NUMFSTTRNSEQ(x) (((x) >> S_NUMFSTTRNSEQ) & M_NUMFSTTRNSEQ)
+
+#define S_REPLAYLMT 2
+#define M_REPLAYLMT 0xfffff
+
+#define V_REPLAYLMT(x) ((x) << S_REPLAYLMT)
+
+#define A_PCIE_PEX_CTRL1 0x9c
+
+#define S_T3A_ACKLAT 0
+#define M_T3A_ACKLAT 0x7ff
+
+#define V_T3A_ACKLAT(x) ((x) << S_T3A_ACKLAT)
+
+#define S_ACKLAT 0
+#define M_ACKLAT 0x1fff
+
+#define V_ACKLAT(x) ((x) << S_ACKLAT)
+
+#define A_PCIE_PEX_ERR 0xa4
+
+#define A_T3DBG_GPIO_EN 0xd0
+
+#define S_GPIO11_OEN 27
+#define V_GPIO11_OEN(x) ((x) << S_GPIO11_OEN)
+#define F_GPIO11_OEN V_GPIO11_OEN(1U)
+
+#define S_GPIO10_OEN 26
+#define V_GPIO10_OEN(x) ((x) << S_GPIO10_OEN)
+#define F_GPIO10_OEN V_GPIO10_OEN(1U)
+
+#define S_GPIO7_OEN 23
+#define V_GPIO7_OEN(x) ((x) << S_GPIO7_OEN)
+#define F_GPIO7_OEN V_GPIO7_OEN(1U)
+
+#define S_GPIO6_OEN 22
+#define V_GPIO6_OEN(x) ((x) << S_GPIO6_OEN)
+#define F_GPIO6_OEN V_GPIO6_OEN(1U)
+
+#define S_GPIO5_OEN 21
+#define V_GPIO5_OEN(x) ((x) << S_GPIO5_OEN)
+#define F_GPIO5_OEN V_GPIO5_OEN(1U)
+
+#define S_GPIO4_OEN 20
+#define V_GPIO4_OEN(x) ((x) << S_GPIO4_OEN)
+#define F_GPIO4_OEN V_GPIO4_OEN(1U)
+
+#define S_GPIO2_OEN 18
+#define V_GPIO2_OEN(x) ((x) << S_GPIO2_OEN)
+#define F_GPIO2_OEN V_GPIO2_OEN(1U)
+
+#define S_GPIO1_OEN 17
+#define V_GPIO1_OEN(x) ((x) << S_GPIO1_OEN)
+#define F_GPIO1_OEN V_GPIO1_OEN(1U)
+
+#define S_GPIO0_OEN 16
+#define V_GPIO0_OEN(x) ((x) << S_GPIO0_OEN)
+#define F_GPIO0_OEN V_GPIO0_OEN(1U)
+
+#define S_GPIO10_OUT_VAL 10
+#define V_GPIO10_OUT_VAL(x) ((x) << S_GPIO10_OUT_VAL)
+#define F_GPIO10_OUT_VAL V_GPIO10_OUT_VAL(1U)
+
+#define S_GPIO7_OUT_VAL 7
+#define V_GPIO7_OUT_VAL(x) ((x) << S_GPIO7_OUT_VAL)
+#define F_GPIO7_OUT_VAL V_GPIO7_OUT_VAL(1U)
+
+#define S_GPIO6_OUT_VAL 6
+#define V_GPIO6_OUT_VAL(x) ((x) << S_GPIO6_OUT_VAL)
+#define F_GPIO6_OUT_VAL V_GPIO6_OUT_VAL(1U)
+
+#define S_GPIO5_OUT_VAL 5
+#define V_GPIO5_OUT_VAL(x) ((x) << S_GPIO5_OUT_VAL)
+#define F_GPIO5_OUT_VAL V_GPIO5_OUT_VAL(1U)
+
+#define S_GPIO4_OUT_VAL 4
+#define V_GPIO4_OUT_VAL(x) ((x) << S_GPIO4_OUT_VAL)
+#define F_GPIO4_OUT_VAL V_GPIO4_OUT_VAL(1U)
+
+#define S_GPIO2_OUT_VAL 2
+#define V_GPIO2_OUT_VAL(x) ((x) << S_GPIO2_OUT_VAL)
+#define F_GPIO2_OUT_VAL V_GPIO2_OUT_VAL(1U)
+
+#define S_GPIO1_OUT_VAL 1
+#define V_GPIO1_OUT_VAL(x) ((x) << S_GPIO1_OUT_VAL)
+#define F_GPIO1_OUT_VAL V_GPIO1_OUT_VAL(1U)
+
+#define S_GPIO0_OUT_VAL 0
+#define V_GPIO0_OUT_VAL(x) ((x) << S_GPIO0_OUT_VAL)
+#define F_GPIO0_OUT_VAL V_GPIO0_OUT_VAL(1U)
+
+#define A_T3DBG_INT_ENABLE 0xd8
+
+#define S_GPIO11 11
+#define V_GPIO11(x) ((x) << S_GPIO11)
+#define F_GPIO11 V_GPIO11(1U)
+
+#define S_GPIO10 10
+#define V_GPIO10(x) ((x) << S_GPIO10)
+#define F_GPIO10 V_GPIO10(1U)
+
+#define S_GPIO7 7
+#define V_GPIO7(x) ((x) << S_GPIO7)
+#define F_GPIO7 V_GPIO7(1U)
+
+#define S_GPIO6 6
+#define V_GPIO6(x) ((x) << S_GPIO6)
+#define F_GPIO6 V_GPIO6(1U)
+
+#define S_GPIO5 5
+#define V_GPIO5(x) ((x) << S_GPIO5)
+#define F_GPIO5 V_GPIO5(1U)
+
+#define S_GPIO4 4
+#define V_GPIO4(x) ((x) << S_GPIO4)
+#define F_GPIO4 V_GPIO4(1U)
+
+#define S_GPIO3 3
+#define V_GPIO3(x) ((x) << S_GPIO3)
+#define F_GPIO3 V_GPIO3(1U)
+
+#define S_GPIO2 2
+#define V_GPIO2(x) ((x) << S_GPIO2)
+#define F_GPIO2 V_GPIO2(1U)
+
+#define S_GPIO1 1
+#define V_GPIO1(x) ((x) << S_GPIO1)
+#define F_GPIO1 V_GPIO1(1U)
+
+#define S_GPIO0 0
+#define V_GPIO0(x) ((x) << S_GPIO0)
+#define F_GPIO0 V_GPIO0(1U)
+
+#define A_T3DBG_INT_CAUSE 0xdc
+
+#define A_T3DBG_GPIO_ACT_LOW 0xf0
+
+#define MC7_PMRX_BASE_ADDR 0x100
+
+#define A_MC7_CFG 0x100
+
+#define S_IFEN 13
+#define V_IFEN(x) ((x) << S_IFEN)
+#define F_IFEN V_IFEN(1U)
+
+#define S_TERM150 11
+#define V_TERM150(x) ((x) << S_TERM150)
+#define F_TERM150 V_TERM150(1U)
+
+#define S_SLOW 10
+#define V_SLOW(x) ((x) << S_SLOW)
+#define F_SLOW V_SLOW(1U)
+
+#define S_WIDTH 8
+#define M_WIDTH 0x3
+#define V_WIDTH(x) ((x) << S_WIDTH)
+#define G_WIDTH(x) (((x) >> S_WIDTH) & M_WIDTH)
+
+#define S_BKS 6
+#define V_BKS(x) ((x) << S_BKS)
+#define F_BKS V_BKS(1U)
+
+#define S_ORG 5
+#define V_ORG(x) ((x) << S_ORG)
+#define F_ORG V_ORG(1U)
+
+#define S_DEN 2
+#define M_DEN 0x7
+#define V_DEN(x) ((x) << S_DEN)
+#define G_DEN(x) (((x) >> S_DEN) & M_DEN)
+
+#define S_RDY 1
+#define V_RDY(x) ((x) << S_RDY)
+#define F_RDY V_RDY(1U)
+
+#define S_CLKEN 0
+#define V_CLKEN(x) ((x) << S_CLKEN)
+#define F_CLKEN V_CLKEN(1U)
+
+#define A_MC7_MODE 0x104
+
+#define S_BUSY 31
+#define V_BUSY(x) ((x) << S_BUSY)
+#define F_BUSY V_BUSY(1U)
+
+#define S_BUSY 31
+#define V_BUSY(x) ((x) << S_BUSY)
+#define F_BUSY V_BUSY(1U)
+
+#define A_MC7_EXT_MODE1 0x108
+
+#define A_MC7_EXT_MODE2 0x10c
+
+#define A_MC7_EXT_MODE3 0x110
+
+#define A_MC7_PRE 0x114
+
+#define A_MC7_REF 0x118
+
+#define S_PREREFDIV 1
+#define M_PREREFDIV 0x3fff
+#define V_PREREFDIV(x) ((x) << S_PREREFDIV)
+
+#define S_PERREFEN 0
+#define V_PERREFEN(x) ((x) << S_PERREFEN)
+#define F_PERREFEN V_PERREFEN(1U)
+
+#define A_MC7_DLL 0x11c
+
+#define S_DLLENB 1
+#define V_DLLENB(x) ((x) << S_DLLENB)
+#define F_DLLENB V_DLLENB(1U)
+
+#define S_DLLRST 0
+#define V_DLLRST(x) ((x) << S_DLLRST)
+#define F_DLLRST V_DLLRST(1U)
+
+#define A_MC7_PARM 0x120
+
+#define S_ACTTOPREDLY 26
+#define M_ACTTOPREDLY 0xf
+#define V_ACTTOPREDLY(x) ((x) << S_ACTTOPREDLY)
+
+#define S_ACTTORDWRDLY 23
+#define M_ACTTORDWRDLY 0x7
+#define V_ACTTORDWRDLY(x) ((x) << S_ACTTORDWRDLY)
+
+#define S_PRECYC 20
+#define M_PRECYC 0x7
+#define V_PRECYC(x) ((x) << S_PRECYC)
+
+#define S_REFCYC 13
+#define M_REFCYC 0x7f
+#define V_REFCYC(x) ((x) << S_REFCYC)
+
+#define S_BKCYC 8
+#define M_BKCYC 0x1f
+#define V_BKCYC(x) ((x) << S_BKCYC)
+
+#define S_WRTORDDLY 4
+#define M_WRTORDDLY 0xf
+#define V_WRTORDDLY(x) ((x) << S_WRTORDDLY)
+
+#define S_RDTOWRDLY 0
+#define M_RDTOWRDLY 0xf
+#define V_RDTOWRDLY(x) ((x) << S_RDTOWRDLY)
+
+#define A_MC7_CAL 0x128
+
+#define S_BUSY 31
+#define V_BUSY(x) ((x) << S_BUSY)
+#define F_BUSY V_BUSY(1U)
+
+#define S_BUSY 31
+#define V_BUSY(x) ((x) << S_BUSY)
+#define F_BUSY V_BUSY(1U)
+
+#define S_CAL_FAULT 30
+#define V_CAL_FAULT(x) ((x) << S_CAL_FAULT)
+#define F_CAL_FAULT V_CAL_FAULT(1U)
+
+#define S_SGL_CAL_EN 20
+#define V_SGL_CAL_EN(x) ((x) << S_SGL_CAL_EN)
+#define F_SGL_CAL_EN V_SGL_CAL_EN(1U)
+
+#define A_MC7_ERR_ADDR 0x12c
+
+#define A_MC7_ECC 0x130
+
+#define S_ECCCHKEN 1
+#define V_ECCCHKEN(x) ((x) << S_ECCCHKEN)
+#define F_ECCCHKEN V_ECCCHKEN(1U)
+
+#define S_ECCGENEN 0
+#define V_ECCGENEN(x) ((x) << S_ECCGENEN)
+#define F_ECCGENEN V_ECCGENEN(1U)
+
+#define A_MC7_CE_ADDR 0x134
+
+#define A_MC7_CE_DATA0 0x138
+
+#define A_MC7_CE_DATA1 0x13c
+
+#define A_MC7_CE_DATA2 0x140
+
+#define S_DATA 0
+#define M_DATA 0xff
+
+#define G_DATA(x) (((x) >> S_DATA) & M_DATA)
+
+#define A_MC7_UE_ADDR 0x144
+
+#define A_MC7_UE_DATA0 0x148
+
+#define A_MC7_UE_DATA1 0x14c
+
+#define A_MC7_UE_DATA2 0x150
+
+#define A_MC7_BD_ADDR 0x154
+
+#define S_ADDR 3
+
+#define M_ADDR 0x1fffffff
+
+#define A_MC7_BD_DATA0 0x158
+
+#define A_MC7_BD_DATA1 0x15c
+
+#define A_MC7_BD_OP 0x164
+
+#define S_OP 0
+
+#define V_OP(x) ((x) << S_OP)
+#define F_OP V_OP(1U)
+
+#define F_OP V_OP(1U)
+#define A_SF_OP 0x6dc
+
+#define A_MC7_BIST_ADDR_BEG 0x168
+
+#define A_MC7_BIST_ADDR_END 0x16c
+
+#define A_MC7_BIST_DATA 0x170
+
+#define A_MC7_BIST_OP 0x174
+
+#define S_CONT 3
+#define V_CONT(x) ((x) << S_CONT)
+#define F_CONT V_CONT(1U)
+
+#define F_CONT V_CONT(1U)
+
+#define A_MC7_INT_ENABLE 0x178
+
+#define S_AE 17
+#define V_AE(x) ((x) << S_AE)
+#define F_AE V_AE(1U)
+
+#define S_PE 2
+#define M_PE 0x7fff
+
+#define V_PE(x) ((x) << S_PE)
+
+#define G_PE(x) (((x) >> S_PE) & M_PE)
+
+#define S_UE 1
+#define V_UE(x) ((x) << S_UE)
+#define F_UE V_UE(1U)
+
+#define S_CE 0
+#define V_CE(x) ((x) << S_CE)
+#define F_CE V_CE(1U)
+
+#define A_MC7_INT_CAUSE 0x17c
+
+#define MC7_PMTX_BASE_ADDR 0x180
+
+#define MC7_CM_BASE_ADDR 0x200
+
+#define A_CIM_BOOT_CFG 0x280
+
+#define S_BOOTADDR 2
+#define M_BOOTADDR 0x3fffffff
+#define V_BOOTADDR(x) ((x) << S_BOOTADDR)
+
+#define A_CIM_SDRAM_BASE_ADDR 0x28c
+
+#define A_CIM_SDRAM_ADDR_SIZE 0x290
+
+#define A_CIM_HOST_INT_ENABLE 0x298
+
+#define A_CIM_HOST_INT_CAUSE 0x29c
+
+#define S_BLKWRPLINT 12
+#define V_BLKWRPLINT(x) ((x) << S_BLKWRPLINT)
+#define F_BLKWRPLINT V_BLKWRPLINT(1U)
+
+#define S_BLKRDPLINT 11
+#define V_BLKRDPLINT(x) ((x) << S_BLKRDPLINT)
+#define F_BLKRDPLINT V_BLKRDPLINT(1U)
+
+#define S_BLKWRCTLINT 10
+#define V_BLKWRCTLINT(x) ((x) << S_BLKWRCTLINT)
+#define F_BLKWRCTLINT V_BLKWRCTLINT(1U)
+
+#define S_BLKRDCTLINT 9
+#define V_BLKRDCTLINT(x) ((x) << S_BLKRDCTLINT)
+#define F_BLKRDCTLINT V_BLKRDCTLINT(1U)
+
+#define S_BLKWRFLASHINT 8
+#define V_BLKWRFLASHINT(x) ((x) << S_BLKWRFLASHINT)
+#define F_BLKWRFLASHINT V_BLKWRFLASHINT(1U)
+
+#define S_BLKRDFLASHINT 7
+#define V_BLKRDFLASHINT(x) ((x) << S_BLKRDFLASHINT)
+#define F_BLKRDFLASHINT V_BLKRDFLASHINT(1U)
+
+#define S_SGLWRFLASHINT 6
+#define V_SGLWRFLASHINT(x) ((x) << S_SGLWRFLASHINT)
+#define F_SGLWRFLASHINT V_SGLWRFLASHINT(1U)
+
+#define S_WRBLKFLASHINT 5
+#define V_WRBLKFLASHINT(x) ((x) << S_WRBLKFLASHINT)
+#define F_WRBLKFLASHINT V_WRBLKFLASHINT(1U)
+
+#define S_BLKWRBOOTINT 4
+#define V_BLKWRBOOTINT(x) ((x) << S_BLKWRBOOTINT)
+#define F_BLKWRBOOTINT V_BLKWRBOOTINT(1U)
+
+#define S_FLASHRANGEINT 2
+#define V_FLASHRANGEINT(x) ((x) << S_FLASHRANGEINT)
+#define F_FLASHRANGEINT V_FLASHRANGEINT(1U)
+
+#define S_SDRAMRANGEINT 1
+#define V_SDRAMRANGEINT(x) ((x) << S_SDRAMRANGEINT)
+#define F_SDRAMRANGEINT V_SDRAMRANGEINT(1U)
+
+#define S_RSVDSPACEINT 0
+#define V_RSVDSPACEINT(x) ((x) << S_RSVDSPACEINT)
+#define F_RSVDSPACEINT V_RSVDSPACEINT(1U)
+
+#define A_CIM_HOST_ACC_CTRL 0x2b0
+
+#define S_HOSTBUSY 17
+#define V_HOSTBUSY(x) ((x) << S_HOSTBUSY)
+#define F_HOSTBUSY V_HOSTBUSY(1U)
+
+#define A_CIM_HOST_ACC_DATA 0x2b4
+
+#define A_TP_IN_CONFIG 0x300
+
+#define S_NICMODE 14
+#define V_NICMODE(x) ((x) << S_NICMODE)
+#define F_NICMODE V_NICMODE(1U)
+
+#define F_NICMODE V_NICMODE(1U)
+
+#define S_IPV6ENABLE 15
+#define V_IPV6ENABLE(x) ((x) << S_IPV6ENABLE)
+#define F_IPV6ENABLE V_IPV6ENABLE(1U)
+
+#define A_TP_OUT_CONFIG 0x304
+
+#define S_VLANEXTRACTIONENABLE 12
+
+#define A_TP_GLOBAL_CONFIG 0x308
+
+#define S_TXPACINGENABLE 24
+#define V_TXPACINGENABLE(x) ((x) << S_TXPACINGENABLE)
+#define F_TXPACINGENABLE V_TXPACINGENABLE(1U)
+
+#define S_PATHMTU 15
+#define V_PATHMTU(x) ((x) << S_PATHMTU)
+#define F_PATHMTU V_PATHMTU(1U)
+
+#define S_IPCHECKSUMOFFLOAD 13
+#define V_IPCHECKSUMOFFLOAD(x) ((x) << S_IPCHECKSUMOFFLOAD)
+#define F_IPCHECKSUMOFFLOAD V_IPCHECKSUMOFFLOAD(1U)
+
+#define S_UDPCHECKSUMOFFLOAD 12
+#define V_UDPCHECKSUMOFFLOAD(x) ((x) << S_UDPCHECKSUMOFFLOAD)
+#define F_UDPCHECKSUMOFFLOAD V_UDPCHECKSUMOFFLOAD(1U)
+
+#define S_TCPCHECKSUMOFFLOAD 11
+#define V_TCPCHECKSUMOFFLOAD(x) ((x) << S_TCPCHECKSUMOFFLOAD)
+#define F_TCPCHECKSUMOFFLOAD V_TCPCHECKSUMOFFLOAD(1U)
+
+#define S_IPTTL 0
+#define M_IPTTL 0xff
+#define V_IPTTL(x) ((x) << S_IPTTL)
+
+#define A_TP_CMM_MM_BASE 0x314
+
+#define A_TP_CMM_TIMER_BASE 0x318
+
+#define S_CMTIMERMAXNUM 28
+#define M_CMTIMERMAXNUM 0x3
+#define V_CMTIMERMAXNUM(x) ((x) << S_CMTIMERMAXNUM)
+
+#define A_TP_PMM_SIZE 0x31c
+
+#define A_TP_PMM_TX_BASE 0x320
+
+#define A_TP_PMM_RX_BASE 0x328
+
+#define A_TP_PMM_RX_PAGE_SIZE 0x32c
+
+#define A_TP_PMM_RX_MAX_PAGE 0x330
+
+#define A_TP_PMM_TX_PAGE_SIZE 0x334
+
+#define A_TP_PMM_TX_MAX_PAGE 0x338
+
+#define A_TP_TCP_OPTIONS 0x340
+
+#define S_MTUDEFAULT 16
+#define M_MTUDEFAULT 0xffff
+#define V_MTUDEFAULT(x) ((x) << S_MTUDEFAULT)
+
+#define S_MTUENABLE 10
+#define V_MTUENABLE(x) ((x) << S_MTUENABLE)
+#define F_MTUENABLE V_MTUENABLE(1U)
+
+#define S_SACKRX 8
+#define V_SACKRX(x) ((x) << S_SACKRX)
+#define F_SACKRX V_SACKRX(1U)
+
+#define S_SACKMODE 4
+
+#define M_SACKMODE 0x3
+
+#define V_SACKMODE(x) ((x) << S_SACKMODE)
+
+#define S_WINDOWSCALEMODE 2
+#define M_WINDOWSCALEMODE 0x3
+#define V_WINDOWSCALEMODE(x) ((x) << S_WINDOWSCALEMODE)
+
+#define S_TIMESTAMPSMODE 0
+
+#define M_TIMESTAMPSMODE 0x3
+
+#define V_TIMESTAMPSMODE(x) ((x) << S_TIMESTAMPSMODE)
+
+#define A_TP_DACK_CONFIG 0x344
+
+#define S_AUTOSTATE3 30
+#define M_AUTOSTATE3 0x3
+#define V_AUTOSTATE3(x) ((x) << S_AUTOSTATE3)
+
+#define S_AUTOSTATE2 28
+#define M_AUTOSTATE2 0x3
+#define V_AUTOSTATE2(x) ((x) << S_AUTOSTATE2)
+
+#define S_AUTOSTATE1 26
+#define M_AUTOSTATE1 0x3
+#define V_AUTOSTATE1(x) ((x) << S_AUTOSTATE1)
+
+#define S_BYTETHRESHOLD 5
+#define M_BYTETHRESHOLD 0xfffff
+#define V_BYTETHRESHOLD(x) ((x) << S_BYTETHRESHOLD)
+
+#define S_MSSTHRESHOLD 3
+#define M_MSSTHRESHOLD 0x3
+#define V_MSSTHRESHOLD(x) ((x) << S_MSSTHRESHOLD)
+
+#define S_AUTOCAREFUL 2
+#define V_AUTOCAREFUL(x) ((x) << S_AUTOCAREFUL)
+#define F_AUTOCAREFUL V_AUTOCAREFUL(1U)
+
+#define S_AUTOENABLE 1
+#define V_AUTOENABLE(x) ((x) << S_AUTOENABLE)
+#define F_AUTOENABLE V_AUTOENABLE(1U)
+
+#define S_DACK_MODE 0
+#define V_DACK_MODE(x) ((x) << S_DACK_MODE)
+#define F_DACK_MODE V_DACK_MODE(1U)
+
+#define A_TP_PC_CONFIG 0x348
+
+#define S_TXTOSQUEUEMAPMODE 26
+#define V_TXTOSQUEUEMAPMODE(x) ((x) << S_TXTOSQUEUEMAPMODE)
+#define F_TXTOSQUEUEMAPMODE V_TXTOSQUEUEMAPMODE(1U)
+
+#define S_ENABLEEPCMDAFULL 23
+#define V_ENABLEEPCMDAFULL(x) ((x) << S_ENABLEEPCMDAFULL)
+#define F_ENABLEEPCMDAFULL V_ENABLEEPCMDAFULL(1U)
+
+#define S_MODULATEUNIONMODE 22
+#define V_MODULATEUNIONMODE(x) ((x) << S_MODULATEUNIONMODE)
+#define F_MODULATEUNIONMODE V_MODULATEUNIONMODE(1U)
+
+#define S_TXDEFERENABLE 20
+#define V_TXDEFERENABLE(x) ((x) << S_TXDEFERENABLE)
+#define F_TXDEFERENABLE V_TXDEFERENABLE(1U)
+
+#define S_RXCONGESTIONMODE 19
+#define V_RXCONGESTIONMODE(x) ((x) << S_RXCONGESTIONMODE)
+#define F_RXCONGESTIONMODE V_RXCONGESTIONMODE(1U)
+
+#define S_HEARBEATDACK 16
+#define V_HEARBEATDACK(x) ((x) << S_HEARBEATDACK)
+#define F_HEARBEATDACK V_HEARBEATDACK(1U)
+
+#define S_TXCONGESTIONMODE 15
+#define V_TXCONGESTIONMODE(x) ((x) << S_TXCONGESTIONMODE)
+#define F_TXCONGESTIONMODE V_TXCONGESTIONMODE(1U)
+
+#define S_ENABLEOCSPIFULL 30
+#define V_ENABLEOCSPIFULL(x) ((x) << S_ENABLEOCSPIFULL)
+#define F_ENABLEOCSPIFULL V_ENABLEOCSPIFULL(1U)
+
+#define S_LOCKTID 28
+#define V_LOCKTID(x) ((x) << S_LOCKTID)
+#define F_LOCKTID V_LOCKTID(1U)
+
+#define A_TP_PC_CONFIG2 0x34c
+
+#define S_CHDRAFULL 4
+#define V_CHDRAFULL(x) ((x) << S_CHDRAFULL)
+#define F_CHDRAFULL V_CHDRAFULL(1U)
+
+#define A_TP_TCP_BACKOFF_REG0 0x350
+
+#define A_TP_TCP_BACKOFF_REG1 0x354
+
+#define A_TP_TCP_BACKOFF_REG2 0x358
+
+#define A_TP_TCP_BACKOFF_REG3 0x35c
+
+#define A_TP_PARA_REG2 0x368
+
+#define S_MAXRXDATA 16
+#define M_MAXRXDATA 0xffff
+#define V_MAXRXDATA(x) ((x) << S_MAXRXDATA)
+
+#define S_RXCOALESCESIZE 0
+#define M_RXCOALESCESIZE 0xffff
+#define V_RXCOALESCESIZE(x) ((x) << S_RXCOALESCESIZE)
+
+#define A_TP_PARA_REG3 0x36c
+
+#define S_TXDATAACKIDX 16
+#define M_TXDATAACKIDX 0xf
+
+#define V_TXDATAACKIDX(x) ((x) << S_TXDATAACKIDX)
+
+#define S_TXPACEAUTOSTRICT 10
+#define V_TXPACEAUTOSTRICT(x) ((x) << S_TXPACEAUTOSTRICT)
+#define F_TXPACEAUTOSTRICT V_TXPACEAUTOSTRICT(1U)
+
+#define S_TXPACEFIXED 9
+#define V_TXPACEFIXED(x) ((x) << S_TXPACEFIXED)
+#define F_TXPACEFIXED V_TXPACEFIXED(1U)
+
+#define S_TXPACEAUTO 8
+#define V_TXPACEAUTO(x) ((x) << S_TXPACEAUTO)
+#define F_TXPACEAUTO V_TXPACEAUTO(1U)
+
+#define S_RXCOALESCEENABLE 1
+#define V_RXCOALESCEENABLE(x) ((x) << S_RXCOALESCEENABLE)
+#define F_RXCOALESCEENABLE V_RXCOALESCEENABLE(1U)
+
+#define S_RXCOALESCEPSHEN 0
+#define V_RXCOALESCEPSHEN(x) ((x) << S_RXCOALESCEPSHEN)
+#define F_RXCOALESCEPSHEN V_RXCOALESCEPSHEN(1U)
+
+#define A_TP_PARA_REG4 0x370
+
+#define A_TP_PARA_REG6 0x378
+
+#define S_T3A_ENABLEESND 13
+#define V_T3A_ENABLEESND(x) ((x) << S_T3A_ENABLEESND)
+#define F_T3A_ENABLEESND V_T3A_ENABLEESND(1U)
+
+#define S_ENABLEESND 11
+#define V_ENABLEESND(x) ((x) << S_ENABLEESND)
+#define F_ENABLEESND V_ENABLEESND(1U)
+
+#define A_TP_PARA_REG7 0x37c
+
+#define S_PMMAXXFERLEN1 16
+#define M_PMMAXXFERLEN1 0xffff
+#define V_PMMAXXFERLEN1(x) ((x) << S_PMMAXXFERLEN1)
+
+#define S_PMMAXXFERLEN0 0
+#define M_PMMAXXFERLEN0 0xffff
+#define V_PMMAXXFERLEN0(x) ((x) << S_PMMAXXFERLEN0)
+
+#define A_TP_TIMER_RESOLUTION 0x390
+
+#define S_TIMERRESOLUTION 16
+#define M_TIMERRESOLUTION 0xff
+#define V_TIMERRESOLUTION(x) ((x) << S_TIMERRESOLUTION)
+
+#define S_TIMESTAMPRESOLUTION 8
+#define M_TIMESTAMPRESOLUTION 0xff
+#define V_TIMESTAMPRESOLUTION(x) ((x) << S_TIMESTAMPRESOLUTION)
+
+#define S_DELAYEDACKRESOLUTION 0
+#define M_DELAYEDACKRESOLUTION 0xff
+#define V_DELAYEDACKRESOLUTION(x) ((x) << S_DELAYEDACKRESOLUTION)
+
+#define A_TP_MSL 0x394
+
+#define A_TP_RXT_MIN 0x398
+
+#define A_TP_RXT_MAX 0x39c
+
+#define A_TP_PERS_MIN 0x3a0
+
+#define A_TP_PERS_MAX 0x3a4
+
+#define A_TP_KEEP_IDLE 0x3a8
+
+#define A_TP_KEEP_INTVL 0x3ac
+
+#define A_TP_INIT_SRTT 0x3b0
+
+#define A_TP_DACK_TIMER 0x3b4
+
+#define A_TP_FINWAIT2_TIMER 0x3b8
+
+#define A_TP_SHIFT_CNT 0x3c0
+
+#define S_SYNSHIFTMAX 24
+
+#define M_SYNSHIFTMAX 0xff
+
+#define V_SYNSHIFTMAX(x) ((x) << S_SYNSHIFTMAX)
+
+#define S_RXTSHIFTMAXR1 20
+
+#define M_RXTSHIFTMAXR1 0xf
+
+#define V_RXTSHIFTMAXR1(x) ((x) << S_RXTSHIFTMAXR1)
+
+#define S_RXTSHIFTMAXR2 16
+
+#define M_RXTSHIFTMAXR2 0xf
+
+#define V_RXTSHIFTMAXR2(x) ((x) << S_RXTSHIFTMAXR2)
+
+#define S_PERSHIFTBACKOFFMAX 12
+#define M_PERSHIFTBACKOFFMAX 0xf
+#define V_PERSHIFTBACKOFFMAX(x) ((x) << S_PERSHIFTBACKOFFMAX)
+
+#define S_PERSHIFTMAX 8
+#define M_PERSHIFTMAX 0xf
+#define V_PERSHIFTMAX(x) ((x) << S_PERSHIFTMAX)
+
+#define S_KEEPALIVEMAX 0
+
+#define M_KEEPALIVEMAX 0xff
+
+#define V_KEEPALIVEMAX(x) ((x) << S_KEEPALIVEMAX)
+
+#define A_TP_MTU_PORT_TABLE 0x3d0
+
+#define A_TP_CCTRL_TABLE 0x3dc
+
+#define A_TP_MTU_TABLE 0x3e4
+
+#define A_TP_RSS_MAP_TABLE 0x3e8
+
+#define A_TP_RSS_LKP_TABLE 0x3ec
+
+#define A_TP_RSS_CONFIG 0x3f0
+
+#define S_TNL4TUPEN 29
+#define V_TNL4TUPEN(x) ((x) << S_TNL4TUPEN)
+#define F_TNL4TUPEN V_TNL4TUPEN(1U)
+
+#define S_TNL2TUPEN 28
+#define V_TNL2TUPEN(x) ((x) << S_TNL2TUPEN)
+#define F_TNL2TUPEN V_TNL2TUPEN(1U)
+
+#define S_TNLPRTEN 26
+#define V_TNLPRTEN(x) ((x) << S_TNLPRTEN)
+#define F_TNLPRTEN V_TNLPRTEN(1U)
+
+#define S_TNLMAPEN 25
+#define V_TNLMAPEN(x) ((x) << S_TNLMAPEN)
+#define F_TNLMAPEN V_TNLMAPEN(1U)
+
+#define S_TNLLKPEN 24
+#define V_TNLLKPEN(x) ((x) << S_TNLLKPEN)
+#define F_TNLLKPEN V_TNLLKPEN(1U)
+
+#define S_RRCPLCPUSIZE 4
+#define M_RRCPLCPUSIZE 0x7
+#define V_RRCPLCPUSIZE(x) ((x) << S_RRCPLCPUSIZE)
+
+#define S_RQFEEDBACKENABLE 3
+#define V_RQFEEDBACKENABLE(x) ((x) << S_RQFEEDBACKENABLE)
+#define F_RQFEEDBACKENABLE V_RQFEEDBACKENABLE(1U)
+
+#define S_DISABLE 0
+
+#define A_TP_TM_PIO_ADDR 0x418
+
+#define A_TP_TM_PIO_DATA 0x41c
+
+#define A_TP_TX_MOD_QUE_TABLE 0x420
+
+#define A_TP_TX_RESOURCE_LIMIT 0x424
+
+#define A_TP_TX_MOD_QUEUE_REQ_MAP 0x428
+
+#define S_TX_MOD_QUEUE_REQ_MAP 0
+#define M_TX_MOD_QUEUE_REQ_MAP 0xff
+#define V_TX_MOD_QUEUE_REQ_MAP(x) ((x) << S_TX_MOD_QUEUE_REQ_MAP)
+
+#define A_TP_TX_MOD_QUEUE_WEIGHT1 0x42c
+
+#define A_TP_TX_MOD_QUEUE_WEIGHT0 0x430
+
+#define A_TP_MOD_CHANNEL_WEIGHT 0x434
+
+#define A_TP_PIO_ADDR 0x440
+
+#define A_TP_PIO_DATA 0x444
+
+#define A_TP_RESET 0x44c
+
+#define S_FLSTINITENABLE 1
+#define V_FLSTINITENABLE(x) ((x) << S_FLSTINITENABLE)
+#define F_FLSTINITENABLE V_FLSTINITENABLE(1U)
+
+#define S_TPRESET 0
+#define V_TPRESET(x) ((x) << S_TPRESET)
+#define F_TPRESET V_TPRESET(1U)
+
+#define A_TP_CMM_MM_RX_FLST_BASE 0x460
+
+#define A_TP_CMM_MM_TX_FLST_BASE 0x464
+
+#define A_TP_CMM_MM_PS_FLST_BASE 0x468
+
+#define A_TP_MIB_INDEX 0x450
+
+#define A_TP_MIB_RDATA 0x454
+
+#define A_TP_CMM_MM_MAX_PSTRUCT 0x46c
+
+#define A_TP_INT_ENABLE 0x470
+
+#define A_TP_INT_CAUSE 0x474
+
+#define A_TP_TX_MOD_Q1_Q0_RATE_LIMIT 0x8
+
+#define A_TP_TX_DROP_CFG_CH0 0x12b
+
+#define A_TP_TX_DROP_MODE 0x12f
+
+#define A_TP_EGRESS_CONFIG 0x145
+
+#define S_REWRITEFORCETOSIZE 0
+#define V_REWRITEFORCETOSIZE(x) ((x) << S_REWRITEFORCETOSIZE)
+#define F_REWRITEFORCETOSIZE V_REWRITEFORCETOSIZE(1U)
+
+#define A_TP_TX_TRC_KEY0 0x20
+
+#define A_TP_RX_TRC_KEY0 0x120
+
+#define A_ULPRX_CTL 0x500
+
+#define S_ROUND_ROBIN 4
+#define V_ROUND_ROBIN(x) ((x) << S_ROUND_ROBIN)
+#define F_ROUND_ROBIN V_ROUND_ROBIN(1U)
+
+#define A_ULPRX_INT_ENABLE 0x504
+
+#define S_PARERR 0
+#define V_PARERR(x) ((x) << S_PARERR)
+#define F_PARERR V_PARERR(1U)
+
+#define A_ULPRX_INT_CAUSE 0x508
+
+#define A_ULPRX_ISCSI_LLIMIT 0x50c
+
+#define A_ULPRX_ISCSI_ULIMIT 0x510
+
+#define A_ULPRX_ISCSI_TAGMASK 0x514
+
+#define A_ULPRX_TDDP_LLIMIT 0x51c
+
+#define A_ULPRX_TDDP_ULIMIT 0x520
+
+#define A_ULPRX_STAG_LLIMIT 0x52c
+
+#define A_ULPRX_STAG_ULIMIT 0x530
+
+#define A_ULPRX_RQ_LLIMIT 0x534
+#define A_ULPRX_RQ_LLIMIT 0x534
+
+#define A_ULPRX_RQ_ULIMIT 0x538
+#define A_ULPRX_RQ_ULIMIT 0x538
+
+#define A_ULPRX_PBL_LLIMIT 0x53c
+
+#define A_ULPRX_PBL_ULIMIT 0x540
+#define A_ULPRX_PBL_ULIMIT 0x540
+
+#define A_ULPRX_TDDP_TAGMASK 0x524
+
+#define A_ULPRX_RQ_LLIMIT 0x534
+#define A_ULPRX_RQ_LLIMIT 0x534
+
+#define A_ULPRX_RQ_ULIMIT 0x538
+#define A_ULPRX_RQ_ULIMIT 0x538
+
+#define A_ULPRX_PBL_ULIMIT 0x540
+#define A_ULPRX_PBL_ULIMIT 0x540
+
+#define A_ULPTX_CONFIG 0x580
+
+#define S_CFG_RR_ARB 0
+#define V_CFG_RR_ARB(x) ((x) << S_CFG_RR_ARB)
+#define F_CFG_RR_ARB V_CFG_RR_ARB(1U)
+
+#define A_ULPTX_INT_ENABLE 0x584
+
+#define S_PBL_BOUND_ERR_CH1 1
+#define V_PBL_BOUND_ERR_CH1(x) ((x) << S_PBL_BOUND_ERR_CH1)
+#define F_PBL_BOUND_ERR_CH1 V_PBL_BOUND_ERR_CH1(1U)
+
+#define S_PBL_BOUND_ERR_CH0 0
+#define V_PBL_BOUND_ERR_CH0(x) ((x) << S_PBL_BOUND_ERR_CH0)
+#define F_PBL_BOUND_ERR_CH0 V_PBL_BOUND_ERR_CH0(1U)
+
+#define A_ULPTX_INT_CAUSE 0x588
+
+#define A_ULPTX_TPT_LLIMIT 0x58c
+
+#define A_ULPTX_TPT_ULIMIT 0x590
+
+#define A_ULPTX_PBL_LLIMIT 0x594
+
+#define A_ULPTX_PBL_ULIMIT 0x598
+
+#define A_ULPTX_DMA_WEIGHT 0x5ac
+
+#define S_D1_WEIGHT 16
+#define M_D1_WEIGHT 0xffff
+#define V_D1_WEIGHT(x) ((x) << S_D1_WEIGHT)
+
+#define S_D0_WEIGHT 0
+#define M_D0_WEIGHT 0xffff
+#define V_D0_WEIGHT(x) ((x) << S_D0_WEIGHT)
+
+#define A_PM1_RX_CFG 0x5c0
+
+#define A_PM1_RX_INT_ENABLE 0x5d8
+
+#define S_ZERO_E_CMD_ERROR 18
+#define V_ZERO_E_CMD_ERROR(x) ((x) << S_ZERO_E_CMD_ERROR)
+#define F_ZERO_E_CMD_ERROR V_ZERO_E_CMD_ERROR(1U)
+
+#define S_IESPI0_FIFO2X_RX_FRAMING_ERROR 17
+#define V_IESPI0_FIFO2X_RX_FRAMING_ERROR(x) ((x) << S_IESPI0_FIFO2X_RX_FRAMING_ERROR)
+#define F_IESPI0_FIFO2X_RX_FRAMING_ERROR V_IESPI0_FIFO2X_RX_FRAMING_ERROR(1U)
+
+#define S_IESPI1_FIFO2X_RX_FRAMING_ERROR 16
+#define V_IESPI1_FIFO2X_RX_FRAMING_ERROR(x) ((x) << S_IESPI1_FIFO2X_RX_FRAMING_ERROR)
+#define F_IESPI1_FIFO2X_RX_FRAMING_ERROR V_IESPI1_FIFO2X_RX_FRAMING_ERROR(1U)
+
+#define S_IESPI0_RX_FRAMING_ERROR 15
+#define V_IESPI0_RX_FRAMING_ERROR(x) ((x) << S_IESPI0_RX_FRAMING_ERROR)
+#define F_IESPI0_RX_FRAMING_ERROR V_IESPI0_RX_FRAMING_ERROR(1U)
+
+#define S_IESPI1_RX_FRAMING_ERROR 14
+#define V_IESPI1_RX_FRAMING_ERROR(x) ((x) << S_IESPI1_RX_FRAMING_ERROR)
+#define F_IESPI1_RX_FRAMING_ERROR V_IESPI1_RX_FRAMING_ERROR(1U)
+
+#define S_IESPI0_TX_FRAMING_ERROR 13
+#define V_IESPI0_TX_FRAMING_ERROR(x) ((x) << S_IESPI0_TX_FRAMING_ERROR)
+#define F_IESPI0_TX_FRAMING_ERROR V_IESPI0_TX_FRAMING_ERROR(1U)
+
+#define S_IESPI1_TX_FRAMING_ERROR 12
+#define V_IESPI1_TX_FRAMING_ERROR(x) ((x) << S_IESPI1_TX_FRAMING_ERROR)
+#define F_IESPI1_TX_FRAMING_ERROR V_IESPI1_TX_FRAMING_ERROR(1U)
+
+#define S_OCSPI0_RX_FRAMING_ERROR 11
+#define V_OCSPI0_RX_FRAMING_ERROR(x) ((x) << S_OCSPI0_RX_FRAMING_ERROR)
+#define F_OCSPI0_RX_FRAMING_ERROR V_OCSPI0_RX_FRAMING_ERROR(1U)
+
+#define S_OCSPI1_RX_FRAMING_ERROR 10
+#define V_OCSPI1_RX_FRAMING_ERROR(x) ((x) << S_OCSPI1_RX_FRAMING_ERROR)
+#define F_OCSPI1_RX_FRAMING_ERROR V_OCSPI1_RX_FRAMING_ERROR(1U)
+
+#define S_OCSPI0_TX_FRAMING_ERROR 9
+#define V_OCSPI0_TX_FRAMING_ERROR(x) ((x) << S_OCSPI0_TX_FRAMING_ERROR)
+#define F_OCSPI0_TX_FRAMING_ERROR V_OCSPI0_TX_FRAMING_ERROR(1U)
+
+#define S_OCSPI1_TX_FRAMING_ERROR 8
+#define V_OCSPI1_TX_FRAMING_ERROR(x) ((x) << S_OCSPI1_TX_FRAMING_ERROR)
+#define F_OCSPI1_TX_FRAMING_ERROR V_OCSPI1_TX_FRAMING_ERROR(1U)
+
+#define S_OCSPI0_OFIFO2X_TX_FRAMING_ERROR 7
+#define V_OCSPI0_OFIFO2X_TX_FRAMING_ERROR(x) ((x) << S_OCSPI0_OFIFO2X_TX_FRAMING_ERROR)
+#define F_OCSPI0_OFIFO2X_TX_FRAMING_ERROR V_OCSPI0_OFIFO2X_TX_FRAMING_ERROR(1U)
+
+#define S_OCSPI1_OFIFO2X_TX_FRAMING_ERROR 6
+#define V_OCSPI1_OFIFO2X_TX_FRAMING_ERROR(x) ((x) << S_OCSPI1_OFIFO2X_TX_FRAMING_ERROR)
+#define F_OCSPI1_OFIFO2X_TX_FRAMING_ERROR V_OCSPI1_OFIFO2X_TX_FRAMING_ERROR(1U)
+
+#define S_IESPI_PAR_ERROR 3
+#define M_IESPI_PAR_ERROR 0x7
+
+#define V_IESPI_PAR_ERROR(x) ((x) << S_IESPI_PAR_ERROR)
+
+#define S_OCSPI_PAR_ERROR 0
+#define M_OCSPI_PAR_ERROR 0x7
+
+#define V_OCSPI_PAR_ERROR(x) ((x) << S_OCSPI_PAR_ERROR)
+
+#define A_PM1_RX_INT_CAUSE 0x5dc
+
+#define A_PM1_TX_CFG 0x5e0
+
+#define A_PM1_TX_INT_ENABLE 0x5f8
+
+#define S_ZERO_C_CMD_ERROR 18
+#define V_ZERO_C_CMD_ERROR(x) ((x) << S_ZERO_C_CMD_ERROR)
+#define F_ZERO_C_CMD_ERROR V_ZERO_C_CMD_ERROR(1U)
+
+#define S_ICSPI0_FIFO2X_RX_FRAMING_ERROR 17
+#define V_ICSPI0_FIFO2X_RX_FRAMING_ERROR(x) ((x) << S_ICSPI0_FIFO2X_RX_FRAMING_ERROR)
+#define F_ICSPI0_FIFO2X_RX_FRAMING_ERROR V_ICSPI0_FIFO2X_RX_FRAMING_ERROR(1U)
+
+#define S_ICSPI1_FIFO2X_RX_FRAMING_ERROR 16
+#define V_ICSPI1_FIFO2X_RX_FRAMING_ERROR(x) ((x) << S_ICSPI1_FIFO2X_RX_FRAMING_ERROR)
+#define F_ICSPI1_FIFO2X_RX_FRAMING_ERROR V_ICSPI1_FIFO2X_RX_FRAMING_ERROR(1U)
+
+#define S_ICSPI0_RX_FRAMING_ERROR 15
+#define V_ICSPI0_RX_FRAMING_ERROR(x) ((x) << S_ICSPI0_RX_FRAMING_ERROR)
+#define F_ICSPI0_RX_FRAMING_ERROR V_ICSPI0_RX_FRAMING_ERROR(1U)
+
+#define S_ICSPI1_RX_FRAMING_ERROR 14
+#define V_ICSPI1_RX_FRAMING_ERROR(x) ((x) << S_ICSPI1_RX_FRAMING_ERROR)
+#define F_ICSPI1_RX_FRAMING_ERROR V_ICSPI1_RX_FRAMING_ERROR(1U)
+
+#define S_ICSPI0_TX_FRAMING_ERROR 13
+#define V_ICSPI0_TX_FRAMING_ERROR(x) ((x) << S_ICSPI0_TX_FRAMING_ERROR)
+#define F_ICSPI0_TX_FRAMING_ERROR V_ICSPI0_TX_FRAMING_ERROR(1U)
+
+#define S_ICSPI1_TX_FRAMING_ERROR 12
+#define V_ICSPI1_TX_FRAMING_ERROR(x) ((x) << S_ICSPI1_TX_FRAMING_ERROR)
+#define F_ICSPI1_TX_FRAMING_ERROR V_ICSPI1_TX_FRAMING_ERROR(1U)
+
+#define S_OESPI0_RX_FRAMING_ERROR 11
+#define V_OESPI0_RX_FRAMING_ERROR(x) ((x) << S_OESPI0_RX_FRAMING_ERROR)
+#define F_OESPI0_RX_FRAMING_ERROR V_OESPI0_RX_FRAMING_ERROR(1U)
+
+#define S_OESPI1_RX_FRAMING_ERROR 10
+#define V_OESPI1_RX_FRAMING_ERROR(x) ((x) << S_OESPI1_RX_FRAMING_ERROR)
+#define F_OESPI1_RX_FRAMING_ERROR V_OESPI1_RX_FRAMING_ERROR(1U)
+
+#define S_OESPI0_TX_FRAMING_ERROR 9
+#define V_OESPI0_TX_FRAMING_ERROR(x) ((x) << S_OESPI0_TX_FRAMING_ERROR)
+#define F_OESPI0_TX_FRAMING_ERROR V_OESPI0_TX_FRAMING_ERROR(1U)
+
+#define S_OESPI1_TX_FRAMING_ERROR 8
+#define V_OESPI1_TX_FRAMING_ERROR(x) ((x) << S_OESPI1_TX_FRAMING_ERROR)
+#define F_OESPI1_TX_FRAMING_ERROR V_OESPI1_TX_FRAMING_ERROR(1U)
+
+#define S_OESPI0_OFIFO2X_TX_FRAMING_ERROR 7
+#define V_OESPI0_OFIFO2X_TX_FRAMING_ERROR(x) ((x) << S_OESPI0_OFIFO2X_TX_FRAMING_ERROR)
+#define F_OESPI0_OFIFO2X_TX_FRAMING_ERROR V_OESPI0_OFIFO2X_TX_FRAMING_ERROR(1U)
+
+#define S_OESPI1_OFIFO2X_TX_FRAMING_ERROR 6
+#define V_OESPI1_OFIFO2X_TX_FRAMING_ERROR(x) ((x) << S_OESPI1_OFIFO2X_TX_FRAMING_ERROR)
+#define F_OESPI1_OFIFO2X_TX_FRAMING_ERROR V_OESPI1_OFIFO2X_TX_FRAMING_ERROR(1U)
+
+#define S_ICSPI_PAR_ERROR 3
+#define M_ICSPI_PAR_ERROR 0x7
+
+#define V_ICSPI_PAR_ERROR(x) ((x) << S_ICSPI_PAR_ERROR)
+
+#define S_OESPI_PAR_ERROR 0
+#define M_OESPI_PAR_ERROR 0x7
+
+#define V_OESPI_PAR_ERROR(x) ((x) << S_OESPI_PAR_ERROR)
+
+#define A_PM1_TX_INT_CAUSE 0x5fc
+
+#define A_MPS_CFG 0x600
+
+#define S_TPRXPORTEN 4
+#define V_TPRXPORTEN(x) ((x) << S_TPRXPORTEN)
+#define F_TPRXPORTEN V_TPRXPORTEN(1U)
+
+#define S_TPTXPORT1EN 3
+#define V_TPTXPORT1EN(x) ((x) << S_TPTXPORT1EN)
+#define F_TPTXPORT1EN V_TPTXPORT1EN(1U)
+
+#define S_TPTXPORT0EN 2
+#define V_TPTXPORT0EN(x) ((x) << S_TPTXPORT0EN)
+#define F_TPTXPORT0EN V_TPTXPORT0EN(1U)
+
+#define S_PORT1ACTIVE 1
+#define V_PORT1ACTIVE(x) ((x) << S_PORT1ACTIVE)
+#define F_PORT1ACTIVE V_PORT1ACTIVE(1U)
+
+#define S_PORT0ACTIVE 0
+#define V_PORT0ACTIVE(x) ((x) << S_PORT0ACTIVE)
+#define F_PORT0ACTIVE V_PORT0ACTIVE(1U)
+
+#define S_ENFORCEPKT 11
+#define V_ENFORCEPKT(x) ((x) << S_ENFORCEPKT)
+#define F_ENFORCEPKT V_ENFORCEPKT(1U)
+
+#define A_MPS_INT_ENABLE 0x61c
+
+#define S_MCAPARERRENB 6
+#define M_MCAPARERRENB 0x7
+
+#define V_MCAPARERRENB(x) ((x) << S_MCAPARERRENB)
+
+#define S_RXTPPARERRENB 4
+#define M_RXTPPARERRENB 0x3
+
+#define V_RXTPPARERRENB(x) ((x) << S_RXTPPARERRENB)
+
+#define S_TX1TPPARERRENB 2
+#define M_TX1TPPARERRENB 0x3
+
+#define V_TX1TPPARERRENB(x) ((x) << S_TX1TPPARERRENB)
+
+#define S_TX0TPPARERRENB 0
+#define M_TX0TPPARERRENB 0x3
+
+#define V_TX0TPPARERRENB(x) ((x) << S_TX0TPPARERRENB)
+
+#define A_MPS_INT_CAUSE 0x620
+
+#define S_MCAPARERR 6
+#define M_MCAPARERR 0x7
+
+#define V_MCAPARERR(x) ((x) << S_MCAPARERR)
+
+#define S_RXTPPARERR 4
+#define M_RXTPPARERR 0x3
+
+#define V_RXTPPARERR(x) ((x) << S_RXTPPARERR)
+
+#define S_TX1TPPARERR 2
+#define M_TX1TPPARERR 0x3
+
+#define V_TX1TPPARERR(x) ((x) << S_TX1TPPARERR)
+
+#define S_TX0TPPARERR 0
+#define M_TX0TPPARERR 0x3
+
+#define V_TX0TPPARERR(x) ((x) << S_TX0TPPARERR)
+
+#define A_CPL_SWITCH_CNTRL 0x640
+
+#define A_CPL_INTR_ENABLE 0x650
+
+#define S_CIM_OVFL_ERROR 4
+#define V_CIM_OVFL_ERROR(x) ((x) << S_CIM_OVFL_ERROR)
+#define F_CIM_OVFL_ERROR V_CIM_OVFL_ERROR(1U)
+
+#define S_TP_FRAMING_ERROR 3
+#define V_TP_FRAMING_ERROR(x) ((x) << S_TP_FRAMING_ERROR)
+#define F_TP_FRAMING_ERROR V_TP_FRAMING_ERROR(1U)
+
+#define S_SGE_FRAMING_ERROR 2
+#define V_SGE_FRAMING_ERROR(x) ((x) << S_SGE_FRAMING_ERROR)
+#define F_SGE_FRAMING_ERROR V_SGE_FRAMING_ERROR(1U)
+
+#define S_CIM_FRAMING_ERROR 1
+#define V_CIM_FRAMING_ERROR(x) ((x) << S_CIM_FRAMING_ERROR)
+#define F_CIM_FRAMING_ERROR V_CIM_FRAMING_ERROR(1U)
+
+#define S_ZERO_SWITCH_ERROR 0
+#define V_ZERO_SWITCH_ERROR(x) ((x) << S_ZERO_SWITCH_ERROR)
+#define F_ZERO_SWITCH_ERROR V_ZERO_SWITCH_ERROR(1U)
+
+#define A_CPL_INTR_CAUSE 0x654
+
+#define A_CPL_MAP_TBL_DATA 0x65c
+
+#define A_SMB_GLOBAL_TIME_CFG 0x660
+
+#define A_I2C_CFG 0x6a0
+
+#define S_I2C_CLKDIV 0
+#define M_I2C_CLKDIV 0xfff
+#define V_I2C_CLKDIV(x) ((x) << S_I2C_CLKDIV)
+
+#define A_MI1_CFG 0x6b0
+
+#define S_CLKDIV 5
+#define M_CLKDIV 0xff
+#define V_CLKDIV(x) ((x) << S_CLKDIV)
+
+#define S_ST 3
+
+#define M_ST 0x3
+
+#define V_ST(x) ((x) << S_ST)
+
+#define G_ST(x) (((x) >> S_ST) & M_ST)
+
+#define S_PREEN 2
+#define V_PREEN(x) ((x) << S_PREEN)
+#define F_PREEN V_PREEN(1U)
+
+#define S_MDIINV 1
+#define V_MDIINV(x) ((x) << S_MDIINV)
+#define F_MDIINV V_MDIINV(1U)
+
+#define S_MDIEN 0
+#define V_MDIEN(x) ((x) << S_MDIEN)
+#define F_MDIEN V_MDIEN(1U)
+
+#define A_MI1_ADDR 0x6b4
+
+#define S_PHYADDR 5
+#define M_PHYADDR 0x1f
+#define V_PHYADDR(x) ((x) << S_PHYADDR)
+
+#define S_REGADDR 0
+#define M_REGADDR 0x1f
+#define V_REGADDR(x) ((x) << S_REGADDR)
+
+#define A_MI1_DATA 0x6b8
+
+#define A_MI1_OP 0x6bc
+
+#define S_MDI_OP 0
+#define M_MDI_OP 0x3
+#define V_MDI_OP(x) ((x) << S_MDI_OP)
+
+#define A_SF_DATA 0x6d8
+
+#define A_SF_OP 0x6dc
+
+#define S_BYTECNT 1
+#define M_BYTECNT 0x3
+#define V_BYTECNT(x) ((x) << S_BYTECNT)
+
+#define A_PL_INT_ENABLE0 0x6e0
+
+#define S_T3DBG 23
+#define V_T3DBG(x) ((x) << S_T3DBG)
+#define F_T3DBG V_T3DBG(1U)
+
+#define S_XGMAC0_1 20
+#define V_XGMAC0_1(x) ((x) << S_XGMAC0_1)
+#define F_XGMAC0_1 V_XGMAC0_1(1U)
+
+#define S_XGMAC0_0 19
+#define V_XGMAC0_0(x) ((x) << S_XGMAC0_0)
+#define F_XGMAC0_0 V_XGMAC0_0(1U)
+
+#define S_MC5A 18
+#define V_MC5A(x) ((x) << S_MC5A)
+#define F_MC5A V_MC5A(1U)
+
+#define S_CPL_SWITCH 12
+#define V_CPL_SWITCH(x) ((x) << S_CPL_SWITCH)
+#define F_CPL_SWITCH V_CPL_SWITCH(1U)
+
+#define S_MPS0 11
+#define V_MPS0(x) ((x) << S_MPS0)
+#define F_MPS0 V_MPS0(1U)
+
+#define S_PM1_TX 10
+#define V_PM1_TX(x) ((x) << S_PM1_TX)
+#define F_PM1_TX V_PM1_TX(1U)
+
+#define S_PM1_RX 9
+#define V_PM1_RX(x) ((x) << S_PM1_RX)
+#define F_PM1_RX V_PM1_RX(1U)
+
+#define S_ULP2_TX 8
+#define V_ULP2_TX(x) ((x) << S_ULP2_TX)
+#define F_ULP2_TX V_ULP2_TX(1U)
+
+#define S_ULP2_RX 7
+#define V_ULP2_RX(x) ((x) << S_ULP2_RX)
+#define F_ULP2_RX V_ULP2_RX(1U)
+
+#define S_TP1 6
+#define V_TP1(x) ((x) << S_TP1)
+#define F_TP1 V_TP1(1U)
+
+#define S_CIM 5
+#define V_CIM(x) ((x) << S_CIM)
+#define F_CIM V_CIM(1U)
+
+#define S_MC7_CM 4
+#define V_MC7_CM(x) ((x) << S_MC7_CM)
+#define F_MC7_CM V_MC7_CM(1U)
+
+#define S_MC7_PMTX 3
+#define V_MC7_PMTX(x) ((x) << S_MC7_PMTX)
+#define F_MC7_PMTX V_MC7_PMTX(1U)
+
+#define S_MC7_PMRX 2
+#define V_MC7_PMRX(x) ((x) << S_MC7_PMRX)
+#define F_MC7_PMRX V_MC7_PMRX(1U)
+
+#define S_PCIM0 1
+#define V_PCIM0(x) ((x) << S_PCIM0)
+#define F_PCIM0 V_PCIM0(1U)
+
+#define S_SGE3 0
+#define V_SGE3(x) ((x) << S_SGE3)
+#define F_SGE3 V_SGE3(1U)
+
+#define A_PL_INT_CAUSE0 0x6e4
+
+#define A_PL_RST 0x6f0
+
+#define S_CRSTWRM 1
+#define V_CRSTWRM(x) ((x) << S_CRSTWRM)
+#define F_CRSTWRM V_CRSTWRM(1U)
+
+#define A_PL_REV 0x6f4
+
+#define A_PL_CLI 0x6f8
+
+#define A_MC5_DB_CONFIG 0x704
+
+#define S_TMTYPEHI 30
+#define V_TMTYPEHI(x) ((x) << S_TMTYPEHI)
+#define F_TMTYPEHI V_TMTYPEHI(1U)
+
+#define S_TMPARTSIZE 28
+#define M_TMPARTSIZE 0x3
+#define V_TMPARTSIZE(x) ((x) << S_TMPARTSIZE)
+#define G_TMPARTSIZE(x) (((x) >> S_TMPARTSIZE) & M_TMPARTSIZE)
+
+#define S_TMTYPE 26
+#define M_TMTYPE 0x3
+#define V_TMTYPE(x) ((x) << S_TMTYPE)
+#define G_TMTYPE(x) (((x) >> S_TMTYPE) & M_TMTYPE)
+
+#define S_COMPEN 17
+#define V_COMPEN(x) ((x) << S_COMPEN)
+#define F_COMPEN V_COMPEN(1U)
+
+#define S_PRTYEN 6
+#define V_PRTYEN(x) ((x) << S_PRTYEN)
+#define F_PRTYEN V_PRTYEN(1U)
+
+#define S_MBUSEN 5
+#define V_MBUSEN(x) ((x) << S_MBUSEN)
+#define F_MBUSEN V_MBUSEN(1U)
+
+#define S_DBGIEN 4
+#define V_DBGIEN(x) ((x) << S_DBGIEN)
+#define F_DBGIEN V_DBGIEN(1U)
+
+#define S_TMRDY 2
+#define V_TMRDY(x) ((x) << S_TMRDY)
+#define F_TMRDY V_TMRDY(1U)
+
+#define S_TMRST 1
+#define V_TMRST(x) ((x) << S_TMRST)
+#define F_TMRST V_TMRST(1U)
+
+#define S_TMMODE 0
+#define V_TMMODE(x) ((x) << S_TMMODE)
+#define F_TMMODE V_TMMODE(1U)
+
+#define F_TMMODE V_TMMODE(1U)
+
+#define A_MC5_DB_ROUTING_TABLE_INDEX 0x70c
+
+#define A_MC5_DB_FILTER_TABLE 0x710
+
+#define A_MC5_DB_SERVER_INDEX 0x714
+
+#define A_MC5_DB_RSP_LATENCY 0x720
+
+#define S_RDLAT 16
+#define M_RDLAT 0x1f
+#define V_RDLAT(x) ((x) << S_RDLAT)
+
+#define S_LRNLAT 8
+#define M_LRNLAT 0x1f
+#define V_LRNLAT(x) ((x) << S_LRNLAT)
+
+#define S_SRCHLAT 0
+#define M_SRCHLAT 0x1f
+#define V_SRCHLAT(x) ((x) << S_SRCHLAT)
+
+#define A_MC5_DB_PART_ID_INDEX 0x72c
+
+#define A_MC5_DB_INT_ENABLE 0x740
+
+#define S_DELACTEMPTY 18
+#define V_DELACTEMPTY(x) ((x) << S_DELACTEMPTY)
+#define F_DELACTEMPTY V_DELACTEMPTY(1U)
+
+#define S_DISPQPARERR 17
+#define V_DISPQPARERR(x) ((x) << S_DISPQPARERR)
+#define F_DISPQPARERR V_DISPQPARERR(1U)
+
+#define S_REQQPARERR 16
+#define V_REQQPARERR(x) ((x) << S_REQQPARERR)
+#define F_REQQPARERR V_REQQPARERR(1U)
+
+#define S_UNKNOWNCMD 15
+#define V_UNKNOWNCMD(x) ((x) << S_UNKNOWNCMD)
+#define F_UNKNOWNCMD V_UNKNOWNCMD(1U)
+
+#define S_NFASRCHFAIL 8
+#define V_NFASRCHFAIL(x) ((x) << S_NFASRCHFAIL)
+#define F_NFASRCHFAIL V_NFASRCHFAIL(1U)
+
+#define S_ACTRGNFULL 7
+#define V_ACTRGNFULL(x) ((x) << S_ACTRGNFULL)
+#define F_ACTRGNFULL V_ACTRGNFULL(1U)
+
+#define S_PARITYERR 6
+#define V_PARITYERR(x) ((x) << S_PARITYERR)
+#define F_PARITYERR V_PARITYERR(1U)
+
+#define A_MC5_DB_INT_CAUSE 0x744
+
+#define A_MC5_DB_DBGI_CONFIG 0x774
+
+#define A_MC5_DB_DBGI_REQ_CMD 0x778
+
+#define A_MC5_DB_DBGI_REQ_ADDR0 0x77c
+
+#define A_MC5_DB_DBGI_REQ_ADDR1 0x780
+
+#define A_MC5_DB_DBGI_REQ_ADDR2 0x784
+
+#define A_MC5_DB_DBGI_REQ_DATA0 0x788
+
+#define A_MC5_DB_DBGI_REQ_DATA1 0x78c
+
+#define A_MC5_DB_DBGI_REQ_DATA2 0x790
+
+#define A_MC5_DB_DBGI_RSP_STATUS 0x7b0
+
+#define S_DBGIRSPVALID 0
+#define V_DBGIRSPVALID(x) ((x) << S_DBGIRSPVALID)
+#define F_DBGIRSPVALID V_DBGIRSPVALID(1U)
+
+#define A_MC5_DB_DBGI_RSP_DATA0 0x7b4
+
+#define A_MC5_DB_DBGI_RSP_DATA1 0x7b8
+
+#define A_MC5_DB_DBGI_RSP_DATA2 0x7bc
+
+#define A_MC5_DB_POPEN_DATA_WR_CMD 0x7cc
+
+#define A_MC5_DB_POPEN_MASK_WR_CMD 0x7d0
+
+#define A_MC5_DB_AOPEN_SRCH_CMD 0x7d4
+
+#define A_MC5_DB_AOPEN_LRN_CMD 0x7d8
+
+#define A_MC5_DB_SYN_SRCH_CMD 0x7dc
+
+#define A_MC5_DB_SYN_LRN_CMD 0x7e0
+
+#define A_MC5_DB_ACK_SRCH_CMD 0x7e4
+
+#define A_MC5_DB_ACK_LRN_CMD 0x7e8
+
+#define A_MC5_DB_ILOOKUP_CMD 0x7ec
+
+#define A_MC5_DB_ELOOKUP_CMD 0x7f0
+
+#define A_MC5_DB_DATA_WRITE_CMD 0x7f4
+
+#define A_MC5_DB_DATA_READ_CMD 0x7f8
+
+#define XGMAC0_0_BASE_ADDR 0x800
+
+#define A_XGM_TX_CTRL 0x800
+
+#define S_TXEN 0
+#define V_TXEN(x) ((x) << S_TXEN)
+#define F_TXEN V_TXEN(1U)
+
+#define A_XGM_TX_CFG 0x804
+
+#define S_TXPAUSEEN 0
+#define V_TXPAUSEEN(x) ((x) << S_TXPAUSEEN)
+#define F_TXPAUSEEN V_TXPAUSEEN(1U)
+
+#define A_XGM_RX_CTRL 0x80c
+
+#define S_RXEN 0
+#define V_RXEN(x) ((x) << S_RXEN)
+#define F_RXEN V_RXEN(1U)
+
+#define A_XGM_RX_CFG 0x810
+
+#define S_DISPAUSEFRAMES 9
+#define V_DISPAUSEFRAMES(x) ((x) << S_DISPAUSEFRAMES)
+#define F_DISPAUSEFRAMES V_DISPAUSEFRAMES(1U)
+
+#define S_EN1536BFRAMES 8
+#define V_EN1536BFRAMES(x) ((x) << S_EN1536BFRAMES)
+#define F_EN1536BFRAMES V_EN1536BFRAMES(1U)
+
+#define S_ENJUMBO 7
+#define V_ENJUMBO(x) ((x) << S_ENJUMBO)
+#define F_ENJUMBO V_ENJUMBO(1U)
+
+#define S_RMFCS 6
+#define V_RMFCS(x) ((x) << S_RMFCS)
+#define F_RMFCS V_RMFCS(1U)
+
+#define S_ENHASHMCAST 2
+#define V_ENHASHMCAST(x) ((x) << S_ENHASHMCAST)
+#define F_ENHASHMCAST V_ENHASHMCAST(1U)
+
+#define S_COPYALLFRAMES 0
+#define V_COPYALLFRAMES(x) ((x) << S_COPYALLFRAMES)
+#define F_COPYALLFRAMES V_COPYALLFRAMES(1U)
+
+#define A_XGM_RX_HASH_LOW 0x814
+
+#define A_XGM_RX_HASH_HIGH 0x818
+
+#define A_XGM_RX_EXACT_MATCH_LOW_1 0x81c
+
+#define A_XGM_RX_EXACT_MATCH_HIGH_1 0x820
+
+#define A_XGM_RX_EXACT_MATCH_LOW_2 0x824
+
+#define A_XGM_RX_EXACT_MATCH_LOW_3 0x82c
+
+#define A_XGM_RX_EXACT_MATCH_LOW_4 0x834
+
+#define A_XGM_RX_EXACT_MATCH_LOW_5 0x83c
+
+#define A_XGM_RX_EXACT_MATCH_LOW_6 0x844
+
+#define A_XGM_RX_EXACT_MATCH_LOW_7 0x84c
+
+#define A_XGM_RX_EXACT_MATCH_LOW_8 0x854
+
+#define A_XGM_STAT_CTRL 0x880
+
+#define S_CLRSTATS 2
+#define V_CLRSTATS(x) ((x) << S_CLRSTATS)
+#define F_CLRSTATS V_CLRSTATS(1U)
+
+#define A_XGM_RXFIFO_CFG 0x884
+
+#define S_RXFIFOPAUSEHWM 17
+#define M_RXFIFOPAUSEHWM 0xfff
+
+#define V_RXFIFOPAUSEHWM(x) ((x) << S_RXFIFOPAUSEHWM)
+
+#define G_RXFIFOPAUSEHWM(x) (((x) >> S_RXFIFOPAUSEHWM) & M_RXFIFOPAUSEHWM)
+
+#define S_RXFIFOPAUSELWM 5
+#define M_RXFIFOPAUSELWM 0xfff
+
+#define V_RXFIFOPAUSELWM(x) ((x) << S_RXFIFOPAUSELWM)
+
+#define G_RXFIFOPAUSELWM(x) (((x) >> S_RXFIFOPAUSELWM) & M_RXFIFOPAUSELWM)
+
+#define S_RXSTRFRWRD 1
+#define V_RXSTRFRWRD(x) ((x) << S_RXSTRFRWRD)
+#define F_RXSTRFRWRD V_RXSTRFRWRD(1U)
+
+#define S_DISERRFRAMES 0
+#define V_DISERRFRAMES(x) ((x) << S_DISERRFRAMES)
+#define F_DISERRFRAMES V_DISERRFRAMES(1U)
+
+#define A_XGM_TXFIFO_CFG 0x888
+
+#define S_TXFIFOTHRESH 4
+#define M_TXFIFOTHRESH 0x1ff
+
+#define V_TXFIFOTHRESH(x) ((x) << S_TXFIFOTHRESH)
+
+#define A_XGM_SERDES_CTRL 0x890
+#define A_XGM_SERDES_CTRL0 0x8e0
+
+#define S_SERDESRESET_ 24
+#define V_SERDESRESET_(x) ((x) << S_SERDESRESET_)
+#define F_SERDESRESET_ V_SERDESRESET_(1U)
+
+#define S_RXENABLE 4
+#define V_RXENABLE(x) ((x) << S_RXENABLE)
+#define F_RXENABLE V_RXENABLE(1U)
+
+#define S_TXENABLE 3
+#define V_TXENABLE(x) ((x) << S_TXENABLE)
+#define F_TXENABLE V_TXENABLE(1U)
+
+#define A_XGM_PAUSE_TIMER 0x890
+
+#define A_XGM_RGMII_IMP 0x89c
+
+#define S_XGM_IMPSETUPDATE 6
+#define V_XGM_IMPSETUPDATE(x) ((x) << S_XGM_IMPSETUPDATE)
+#define F_XGM_IMPSETUPDATE V_XGM_IMPSETUPDATE(1U)
+
+#define S_RGMIIIMPPD 3
+#define M_RGMIIIMPPD 0x7
+#define V_RGMIIIMPPD(x) ((x) << S_RGMIIIMPPD)
+
+#define S_RGMIIIMPPU 0
+#define M_RGMIIIMPPU 0x7
+#define V_RGMIIIMPPU(x) ((x) << S_RGMIIIMPPU)
+
+#define S_CALRESET 8
+#define V_CALRESET(x) ((x) << S_CALRESET)
+#define F_CALRESET V_CALRESET(1U)
+
+#define S_CALUPDATE 7
+#define V_CALUPDATE(x) ((x) << S_CALUPDATE)
+#define F_CALUPDATE V_CALUPDATE(1U)
+
+#define A_XGM_XAUI_IMP 0x8a0
+
+#define S_CALBUSY 31
+#define V_CALBUSY(x) ((x) << S_CALBUSY)
+#define F_CALBUSY V_CALBUSY(1U)
+
+#define S_XGM_CALFAULT 29
+#define V_XGM_CALFAULT(x) ((x) << S_XGM_CALFAULT)
+#define F_XGM_CALFAULT V_XGM_CALFAULT(1U)
+
+#define S_CALIMP 24
+#define M_CALIMP 0x1f
+#define V_CALIMP(x) ((x) << S_CALIMP)
+#define G_CALIMP(x) (((x) >> S_CALIMP) & M_CALIMP)
+
+#define S_XAUIIMP 0
+#define M_XAUIIMP 0x7
+#define V_XAUIIMP(x) ((x) << S_XAUIIMP)
+
+#define A_XGM_RX_MAX_PKT_SIZE 0x8a8
+#define A_XGM_RX_MAX_PKT_SIZE_ERR_CNT 0x9a4
+
+#define A_XGM_RESET_CTRL 0x8ac
+
+#define S_XG2G_RESET_ 3
+#define V_XG2G_RESET_(x) ((x) << S_XG2G_RESET_)
+#define F_XG2G_RESET_ V_XG2G_RESET_(1U)
+
+#define S_RGMII_RESET_ 2
+#define V_RGMII_RESET_(x) ((x) << S_RGMII_RESET_)
+#define F_RGMII_RESET_ V_RGMII_RESET_(1U)
+
+#define S_PCS_RESET_ 1
+#define V_PCS_RESET_(x) ((x) << S_PCS_RESET_)
+#define F_PCS_RESET_ V_PCS_RESET_(1U)
+
+#define S_MAC_RESET_ 0
+#define V_MAC_RESET_(x) ((x) << S_MAC_RESET_)
+#define F_MAC_RESET_ V_MAC_RESET_(1U)
+
+#define A_XGM_PORT_CFG 0x8b8
+
+#define S_CLKDIVRESET_ 3
+#define V_CLKDIVRESET_(x) ((x) << S_CLKDIVRESET_)
+#define F_CLKDIVRESET_ V_CLKDIVRESET_(1U)
+
+#define S_PORTSPEED 1
+#define M_PORTSPEED 0x3
+
+#define V_PORTSPEED(x) ((x) << S_PORTSPEED)
+
+#define S_ENRGMII 0
+#define V_ENRGMII(x) ((x) << S_ENRGMII)
+#define F_ENRGMII V_ENRGMII(1U)
+
+#define A_XGM_INT_ENABLE 0x8d4
+
+#define S_TXFIFO_PRTY_ERR 17
+#define M_TXFIFO_PRTY_ERR 0x7
+
+#define V_TXFIFO_PRTY_ERR(x) ((x) << S_TXFIFO_PRTY_ERR)
+
+#define S_RXFIFO_PRTY_ERR 14
+#define M_RXFIFO_PRTY_ERR 0x7
+
+#define V_RXFIFO_PRTY_ERR(x) ((x) << S_RXFIFO_PRTY_ERR)
+
+#define S_TXFIFO_UNDERRUN 13
+#define V_TXFIFO_UNDERRUN(x) ((x) << S_TXFIFO_UNDERRUN)
+#define F_TXFIFO_UNDERRUN V_TXFIFO_UNDERRUN(1U)
+
+#define S_RXFIFO_OVERFLOW 12
+#define V_RXFIFO_OVERFLOW(x) ((x) << S_RXFIFO_OVERFLOW)
+#define F_RXFIFO_OVERFLOW V_RXFIFO_OVERFLOW(1U)
+
+#define S_SERDES_LOS 4
+#define M_SERDES_LOS 0xf
+
+#define V_SERDES_LOS(x) ((x) << S_SERDES_LOS)
+
+#define S_XAUIPCSCTCERR 3
+#define V_XAUIPCSCTCERR(x) ((x) << S_XAUIPCSCTCERR)
+#define F_XAUIPCSCTCERR V_XAUIPCSCTCERR(1U)
+
+#define S_XAUIPCSALIGNCHANGE 2
+#define V_XAUIPCSALIGNCHANGE(x) ((x) << S_XAUIPCSALIGNCHANGE)
+#define F_XAUIPCSALIGNCHANGE V_XAUIPCSALIGNCHANGE(1U)
+
+#define A_XGM_INT_CAUSE 0x8d8
+
+#define A_XGM_XAUI_ACT_CTRL 0x8dc
+
+#define S_TXACTENABLE 1
+#define V_TXACTENABLE(x) ((x) << S_TXACTENABLE)
+#define F_TXACTENABLE V_TXACTENABLE(1U)
+
+#define A_XGM_SERDES_CTRL0 0x8e0
+
+#define S_RESET3 23
+#define V_RESET3(x) ((x) << S_RESET3)
+#define F_RESET3 V_RESET3(1U)
+
+#define S_RESET2 22
+#define V_RESET2(x) ((x) << S_RESET2)
+#define F_RESET2 V_RESET2(1U)
+
+#define S_RESET1 21
+#define V_RESET1(x) ((x) << S_RESET1)
+#define F_RESET1 V_RESET1(1U)
+
+#define S_RESET0 20
+#define V_RESET0(x) ((x) << S_RESET0)
+#define F_RESET0 V_RESET0(1U)
+
+#define S_PWRDN3 19
+#define V_PWRDN3(x) ((x) << S_PWRDN3)
+#define F_PWRDN3 V_PWRDN3(1U)
+
+#define S_PWRDN2 18
+#define V_PWRDN2(x) ((x) << S_PWRDN2)
+#define F_PWRDN2 V_PWRDN2(1U)
+
+#define S_PWRDN1 17
+#define V_PWRDN1(x) ((x) << S_PWRDN1)
+#define F_PWRDN1 V_PWRDN1(1U)
+
+#define S_PWRDN0 16
+#define V_PWRDN0(x) ((x) << S_PWRDN0)
+#define F_PWRDN0 V_PWRDN0(1U)
+
+#define S_RESETPLL23 15
+#define V_RESETPLL23(x) ((x) << S_RESETPLL23)
+#define F_RESETPLL23 V_RESETPLL23(1U)
+
+#define S_RESETPLL01 14
+#define V_RESETPLL01(x) ((x) << S_RESETPLL01)
+#define F_RESETPLL01 V_RESETPLL01(1U)
+
+#define A_XGM_SERDES_STAT0 0x8f0
+
+#define S_LOWSIG0 0
+#define V_LOWSIG0(x) ((x) << S_LOWSIG0)
+#define F_LOWSIG0 V_LOWSIG0(1U)
+
+#define A_XGM_SERDES_STAT3 0x8fc
+
+#define A_XGM_STAT_TX_BYTE_LOW 0x900
+
+#define A_XGM_STAT_TX_BYTE_HIGH 0x904
+
+#define A_XGM_STAT_TX_FRAME_LOW 0x908
+
+#define A_XGM_STAT_TX_FRAME_HIGH 0x90c
+
+#define A_XGM_STAT_TX_BCAST 0x910
+
+#define A_XGM_STAT_TX_MCAST 0x914
+
+#define A_XGM_STAT_TX_PAUSE 0x918
+
+#define A_XGM_STAT_TX_64B_FRAMES 0x91c
+
+#define A_XGM_STAT_TX_65_127B_FRAMES 0x920
+
+#define A_XGM_STAT_TX_128_255B_FRAMES 0x924
+
+#define A_XGM_STAT_TX_256_511B_FRAMES 0x928
+
+#define A_XGM_STAT_TX_512_1023B_FRAMES 0x92c
+
+#define A_XGM_STAT_TX_1024_1518B_FRAMES 0x930
+
+#define A_XGM_STAT_TX_1519_MAXB_FRAMES 0x934
+
+#define A_XGM_STAT_TX_ERR_FRAMES 0x938
+
+#define A_XGM_STAT_RX_BYTES_LOW 0x93c
+
+#define A_XGM_STAT_RX_BYTES_HIGH 0x940
+
+#define A_XGM_STAT_RX_FRAMES_LOW 0x944
+
+#define A_XGM_STAT_RX_FRAMES_HIGH 0x948
+
+#define A_XGM_STAT_RX_BCAST_FRAMES 0x94c
+
+#define A_XGM_STAT_RX_MCAST_FRAMES 0x950
+
+#define A_XGM_STAT_RX_PAUSE_FRAMES 0x954
+
+#define A_XGM_STAT_RX_64B_FRAMES 0x958
+
+#define A_XGM_STAT_RX_65_127B_FRAMES 0x95c
+
+#define A_XGM_STAT_RX_128_255B_FRAMES 0x960
+
+#define A_XGM_STAT_RX_256_511B_FRAMES 0x964
+
+#define A_XGM_STAT_RX_512_1023B_FRAMES 0x968
+
+#define A_XGM_STAT_RX_1024_1518B_FRAMES 0x96c
+
+#define A_XGM_STAT_RX_1519_MAXB_FRAMES 0x970
+
+#define A_XGM_STAT_RX_SHORT_FRAMES 0x974
+
+#define A_XGM_STAT_RX_OVERSIZE_FRAMES 0x978
+
+#define A_XGM_STAT_RX_JABBER_FRAMES 0x97c
+
+#define A_XGM_STAT_RX_CRC_ERR_FRAMES 0x980
+
+#define A_XGM_STAT_RX_LENGTH_ERR_FRAMES 0x984
+
+#define A_XGM_STAT_RX_SYM_CODE_ERR_FRAMES 0x988
+
+#define A_XGM_SERDES_STATUS0 0x98c
+
+#define A_XGM_SERDES_STATUS1 0x990
+
+#define S_CMULOCK 31
+#define V_CMULOCK(x) ((x) << S_CMULOCK)
+#define F_CMULOCK V_CMULOCK(1U)
+
+#define A_XGM_RX_MAX_PKT_SIZE_ERR_CNT 0x9a4
+
+#define A_XGM_RX_SPI4_SOP_EOP_CNT 0x9ac
+
+#define XGMAC0_1_BASE_ADDR 0xa00
diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c
new file mode 100644
index 00000000000..3f2cf8a07c6
--- /dev/null
+++ b/drivers/net/cxgb3/sge.c
@@ -0,0 +1,2681 @@
+/*
+ * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/dma-mapping.h>
+#include "common.h"
+#include "regs.h"
+#include "sge_defs.h"
+#include "t3_cpl.h"
+#include "firmware_exports.h"
+
+#define USE_GTS 0
+
+#define SGE_RX_SM_BUF_SIZE 1536
+#define SGE_RX_COPY_THRES 256
+
+# define SGE_RX_DROP_THRES 16
+
+/*
+ * Period of the Tx buffer reclaim timer. This timer does not need to run
+ * frequently as Tx buffers are usually reclaimed by new Tx packets.
+ */
+#define TX_RECLAIM_PERIOD (HZ / 4)
+
+/* WR size in bytes */
+#define WR_LEN (WR_FLITS * 8)
+
+/*
+ * Types of Tx queues in each queue set. Order here matters, do not change.
+ */
+enum { TXQ_ETH, TXQ_OFLD, TXQ_CTRL };
+
+/* Values for sge_txq.flags */
+enum {
+ TXQ_RUNNING = 1 << 0, /* fetch engine is running */
+ TXQ_LAST_PKT_DB = 1 << 1, /* last packet rang the doorbell */
+};
+
+struct tx_desc {
+ u64 flit[TX_DESC_FLITS];
+};
+
+struct rx_desc {
+ __be32 addr_lo;
+ __be32 len_gen;
+ __be32 gen2;
+ __be32 addr_hi;
+};
+
+struct tx_sw_desc { /* SW state per Tx descriptor */
+ struct sk_buff *skb;
+};
+
+struct rx_sw_desc { /* SW state per Rx descriptor */
+ struct sk_buff *skb;
+ DECLARE_PCI_UNMAP_ADDR(dma_addr);
+};
+
+struct rsp_desc { /* response queue descriptor */
+ struct rss_header rss_hdr;
+ __be32 flags;
+ __be32 len_cq;
+ u8 imm_data[47];
+ u8 intr_gen;
+};
+
+struct unmap_info { /* packet unmapping info, overlays skb->cb */
+ int sflit; /* start flit of first SGL entry in Tx descriptor */
+ u16 fragidx; /* first page fragment in current Tx descriptor */
+ u16 addr_idx; /* buffer index of first SGL entry in descriptor */
+ u32 len; /* mapped length of skb main body */
+};
+
+/*
+ * Maps a number of flits to the number of Tx descriptors that can hold them.
+ * The formula is
+ *
+ * desc = 1 + (flits - 2) / (WR_FLITS - 1).
+ *
+ * HW allows up to 4 descriptors to be combined into a WR.
+ */
+static u8 flit_desc_map[] = {
+ 0,
+#if SGE_NUM_GENBITS == 1
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
+#elif SGE_NUM_GENBITS == 2
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+#else
+# error "SGE_NUM_GENBITS must be 1 or 2"
+#endif
+};
+
+static inline struct sge_qset *fl_to_qset(const struct sge_fl *q, int qidx)
+{
+ return container_of(q, struct sge_qset, fl[qidx]);
+}
+
+static inline struct sge_qset *rspq_to_qset(const struct sge_rspq *q)
+{
+ return container_of(q, struct sge_qset, rspq);
+}
+
+static inline struct sge_qset *txq_to_qset(const struct sge_txq *q, int qidx)
+{
+ return container_of(q, struct sge_qset, txq[qidx]);
+}
+
+/**
+ * refill_rspq - replenish an SGE response queue
+ * @adapter: the adapter
+ * @q: the response queue to replenish
+ * @credits: how many new responses to make available
+ *
+ * Replenishes a response queue by making the supplied number of responses
+ * available to HW.
+ */
+static inline void refill_rspq(struct adapter *adapter,
+ const struct sge_rspq *q, unsigned int credits)
+{
+ t3_write_reg(adapter, A_SG_RSPQ_CREDIT_RETURN,
+ V_RSPQ(q->cntxt_id) | V_CREDITS(credits));
+}
+
+/**
+ * need_skb_unmap - does the platform need unmapping of sk_buffs?
+ *
+ * Returns true if the platfrom needs sk_buff unmapping. The compiler
+ * optimizes away unecessary code if this returns true.
+ */
+static inline int need_skb_unmap(void)
+{
+ /*
+ * This structure is used to tell if the platfrom needs buffer
+ * unmapping by checking if DECLARE_PCI_UNMAP_ADDR defines anything.
+ */
+ struct dummy {
+ DECLARE_PCI_UNMAP_ADDR(addr);
+ };
+
+ return sizeof(struct dummy) != 0;
+}
+
+/**
+ * unmap_skb - unmap a packet main body and its page fragments
+ * @skb: the packet
+ * @q: the Tx queue containing Tx descriptors for the packet
+ * @cidx: index of Tx descriptor
+ * @pdev: the PCI device
+ *
+ * Unmap the main body of an sk_buff and its page fragments, if any.
+ * Because of the fairly complicated structure of our SGLs and the desire
+ * to conserve space for metadata, we keep the information necessary to
+ * unmap an sk_buff partly in the sk_buff itself (in its cb), and partly
+ * in the Tx descriptors (the physical addresses of the various data
+ * buffers). The send functions initialize the state in skb->cb so we
+ * can unmap the buffers held in the first Tx descriptor here, and we
+ * have enough information at this point to update the state for the next
+ * Tx descriptor.
+ */
+static inline void unmap_skb(struct sk_buff *skb, struct sge_txq *q,
+ unsigned int cidx, struct pci_dev *pdev)
+{
+ const struct sg_ent *sgp;
+ struct unmap_info *ui = (struct unmap_info *)skb->cb;
+ int nfrags, frag_idx, curflit, j = ui->addr_idx;
+
+ sgp = (struct sg_ent *)&q->desc[cidx].flit[ui->sflit];
+
+ if (ui->len) {
+ pci_unmap_single(pdev, be64_to_cpu(sgp->addr[0]), ui->len,
+ PCI_DMA_TODEVICE);
+ ui->len = 0; /* so we know for next descriptor for this skb */
+ j = 1;
+ }
+
+ frag_idx = ui->fragidx;
+ curflit = ui->sflit + 1 + j;
+ nfrags = skb_shinfo(skb)->nr_frags;
+
+ while (frag_idx < nfrags && curflit < WR_FLITS) {
+ pci_unmap_page(pdev, be64_to_cpu(sgp->addr[j]),
+ skb_shinfo(skb)->frags[frag_idx].size,
+ PCI_DMA_TODEVICE);
+ j ^= 1;
+ if (j == 0) {
+ sgp++;
+ curflit++;
+ }
+ curflit++;
+ frag_idx++;
+ }
+
+ if (frag_idx < nfrags) { /* SGL continues into next Tx descriptor */
+ ui->fragidx = frag_idx;
+ ui->addr_idx = j;
+ ui->sflit = curflit - WR_FLITS - j; /* sflit can be -1 */
+ }
+}
+
+/**
+ * free_tx_desc - reclaims Tx descriptors and their buffers
+ * @adapter: the adapter
+ * @q: the Tx queue to reclaim descriptors from
+ * @n: the number of descriptors to reclaim
+ *
+ * Reclaims Tx descriptors from an SGE Tx queue and frees the associated
+ * Tx buffers. Called with the Tx queue lock held.
+ */
+static void free_tx_desc(struct adapter *adapter, struct sge_txq *q,
+ unsigned int n)
+{
+ struct tx_sw_desc *d;
+ struct pci_dev *pdev = adapter->pdev;
+ unsigned int cidx = q->cidx;
+
+ d = &q->sdesc[cidx];
+ while (n--) {
+ if (d->skb) { /* an SGL is present */
+ if (need_skb_unmap())
+ unmap_skb(d->skb, q, cidx, pdev);
+ if (d->skb->priority == cidx)
+ kfree_skb(d->skb);
+ }
+ ++d;
+ if (++cidx == q->size) {
+ cidx = 0;
+ d = q->sdesc;
+ }
+ }
+ q->cidx = cidx;
+}
+
+/**
+ * reclaim_completed_tx - reclaims completed Tx descriptors
+ * @adapter: the adapter
+ * @q: the Tx queue to reclaim completed descriptors from
+ *
+ * Reclaims Tx descriptors that the SGE has indicated it has processed,
+ * and frees the associated buffers if possible. Called with the Tx
+ * queue's lock held.
+ */
+static inline void reclaim_completed_tx(struct adapter *adapter,
+ struct sge_txq *q)
+{
+ unsigned int reclaim = q->processed - q->cleaned;
+
+ if (reclaim) {
+ free_tx_desc(adapter, q, reclaim);
+ q->cleaned += reclaim;
+ q->in_use -= reclaim;
+ }
+}
+
+/**
+ * should_restart_tx - are there enough resources to restart a Tx queue?
+ * @q: the Tx queue
+ *
+ * Checks if there are enough descriptors to restart a suspended Tx queue.
+ */
+static inline int should_restart_tx(const struct sge_txq *q)
+{
+ unsigned int r = q->processed - q->cleaned;
+
+ return q->in_use - r < (q->size >> 1);
+}
+
+/**
+ * free_rx_bufs - free the Rx buffers on an SGE free list
+ * @pdev: the PCI device associated with the adapter
+ * @rxq: the SGE free list to clean up
+ *
+ * Release the buffers on an SGE free-buffer Rx queue. HW fetching from
+ * this queue should be stopped before calling this function.
+ */
+static void free_rx_bufs(struct pci_dev *pdev, struct sge_fl *q)
+{
+ unsigned int cidx = q->cidx;
+
+ while (q->credits--) {
+ struct rx_sw_desc *d = &q->sdesc[cidx];
+
+ pci_unmap_single(pdev, pci_unmap_addr(d, dma_addr),
+ q->buf_size, PCI_DMA_FROMDEVICE);
+ kfree_skb(d->skb);
+ d->skb = NULL;
+ if (++cidx == q->size)
+ cidx = 0;
+ }
+}
+
+/**
+ * add_one_rx_buf - add a packet buffer to a free-buffer list
+ * @skb: the buffer to add
+ * @len: the buffer length
+ * @d: the HW Rx descriptor to write
+ * @sd: the SW Rx descriptor to write
+ * @gen: the generation bit value
+ * @pdev: the PCI device associated with the adapter
+ *
+ * Add a buffer of the given length to the supplied HW and SW Rx
+ * descriptors.
+ */
+static inline void add_one_rx_buf(struct sk_buff *skb, unsigned int len,
+ struct rx_desc *d, struct rx_sw_desc *sd,
+ unsigned int gen, struct pci_dev *pdev)
+{
+ dma_addr_t mapping;
+
+ sd->skb = skb;
+ mapping = pci_map_single(pdev, skb->data, len, PCI_DMA_FROMDEVICE);
+ pci_unmap_addr_set(sd, dma_addr, mapping);
+
+ d->addr_lo = cpu_to_be32(mapping);
+ d->addr_hi = cpu_to_be32((u64) mapping >> 32);
+ wmb();
+ d->len_gen = cpu_to_be32(V_FLD_GEN1(gen));
+ d->gen2 = cpu_to_be32(V_FLD_GEN2(gen));
+}
+
+/**
+ * refill_fl - refill an SGE free-buffer list
+ * @adapter: the adapter
+ * @q: the free-list to refill
+ * @n: the number of new buffers to allocate
+ * @gfp: the gfp flags for allocating new buffers
+ *
+ * (Re)populate an SGE free-buffer list with up to @n new packet buffers,
+ * allocated with the supplied gfp flags. The caller must assure that
+ * @n does not exceed the queue's capacity.
+ */
+static void refill_fl(struct adapter *adap, struct sge_fl *q, int n, gfp_t gfp)
+{
+ struct rx_sw_desc *sd = &q->sdesc[q->pidx];
+ struct rx_desc *d = &q->desc[q->pidx];
+
+ while (n--) {
+ struct sk_buff *skb = alloc_skb(q->buf_size, gfp);
+
+ if (!skb)
+ break;
+
+ add_one_rx_buf(skb, q->buf_size, d, sd, q->gen, adap->pdev);
+ d++;
+ sd++;
+ if (++q->pidx == q->size) {
+ q->pidx = 0;
+ q->gen ^= 1;
+ sd = q->sdesc;
+ d = q->desc;
+ }
+ q->credits++;
+ }
+
+ t3_write_reg(adap, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id));
+}
+
+static inline void __refill_fl(struct adapter *adap, struct sge_fl *fl)
+{
+ refill_fl(adap, fl, min(16U, fl->size - fl->credits), GFP_ATOMIC);
+}
+
+/**
+ * recycle_rx_buf - recycle a receive buffer
+ * @adapter: the adapter
+ * @q: the SGE free list
+ * @idx: index of buffer to recycle
+ *
+ * Recycles the specified buffer on the given free list by adding it at
+ * the next available slot on the list.
+ */
+static void recycle_rx_buf(struct adapter *adap, struct sge_fl *q,
+ unsigned int idx)
+{
+ struct rx_desc *from = &q->desc[idx];
+ struct rx_desc *to = &q->desc[q->pidx];
+
+ q->sdesc[q->pidx] = q->sdesc[idx];
+ to->addr_lo = from->addr_lo; /* already big endian */
+ to->addr_hi = from->addr_hi; /* likewise */
+ wmb();
+ to->len_gen = cpu_to_be32(V_FLD_GEN1(q->gen));
+ to->gen2 = cpu_to_be32(V_FLD_GEN2(q->gen));
+ q->credits++;
+
+ if (++q->pidx == q->size) {
+ q->pidx = 0;
+ q->gen ^= 1;
+ }
+ t3_write_reg(adap, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id));
+}
+
+/**
+ * alloc_ring - allocate resources for an SGE descriptor ring
+ * @pdev: the PCI device
+ * @nelem: the number of descriptors
+ * @elem_size: the size of each descriptor
+ * @sw_size: the size of the SW state associated with each ring element
+ * @phys: the physical address of the allocated ring
+ * @metadata: address of the array holding the SW state for the ring
+ *
+ * Allocates resources for an SGE descriptor ring, such as Tx queues,
+ * free buffer lists, or response queues. Each SGE ring requires
+ * space for its HW descriptors plus, optionally, space for the SW state
+ * associated with each HW entry (the metadata). The function returns
+ * three values: the virtual address for the HW ring (the return value
+ * of the function), the physical address of the HW ring, and the address
+ * of the SW ring.
+ */
+static void *alloc_ring(struct pci_dev *pdev, size_t nelem, size_t elem_size,
+ size_t sw_size, dma_addr_t *phys, void *metadata)
+{
+ size_t len = nelem * elem_size;
+ void *s = NULL;
+ void *p = dma_alloc_coherent(&pdev->dev, len, phys, GFP_KERNEL);
+
+ if (!p)
+ return NULL;
+ if (sw_size) {
+ s = kcalloc(nelem, sw_size, GFP_KERNEL);
+
+ if (!s) {
+ dma_free_coherent(&pdev->dev, len, p, *phys);
+ return NULL;
+ }
+ }
+ if (metadata)
+ *(void **)metadata = s;
+ memset(p, 0, len);
+ return p;
+}
+
+/**
+ * free_qset - free the resources of an SGE queue set
+ * @adapter: the adapter owning the queue set
+ * @q: the queue set
+ *
+ * Release the HW and SW resources associated with an SGE queue set, such
+ * as HW contexts, packet buffers, and descriptor rings. Traffic to the
+ * queue set must be quiesced prior to calling this.
+ */
+void t3_free_qset(struct adapter *adapter, struct sge_qset *q)
+{
+ int i;
+ struct pci_dev *pdev = adapter->pdev;
+
+ if (q->tx_reclaim_timer.function)
+ del_timer_sync(&q->tx_reclaim_timer);
+
+ for (i = 0; i < SGE_RXQ_PER_SET; ++i)
+ if (q->fl[i].desc) {
+ spin_lock(&adapter->sge.reg_lock);
+ t3_sge_disable_fl(adapter, q->fl[i].cntxt_id);
+ spin_unlock(&adapter->sge.reg_lock);
+ free_rx_bufs(pdev, &q->fl[i]);
+ kfree(q->fl[i].sdesc);
+ dma_free_coherent(&pdev->dev,
+ q->fl[i].size *
+ sizeof(struct rx_desc), q->fl[i].desc,
+ q->fl[i].phys_addr);
+ }
+
+ for (i = 0; i < SGE_TXQ_PER_SET; ++i)
+ if (q->txq[i].desc) {
+ spin_lock(&adapter->sge.reg_lock);
+ t3_sge_enable_ecntxt(adapter, q->txq[i].cntxt_id, 0);
+ spin_unlock(&adapter->sge.reg_lock);
+ if (q->txq[i].sdesc) {
+ free_tx_desc(adapter, &q->txq[i],
+ q->txq[i].in_use);
+ kfree(q->txq[i].sdesc);
+ }
+ dma_free_coherent(&pdev->dev,
+ q->txq[i].size *
+ sizeof(struct tx_desc),
+ q->txq[i].desc, q->txq[i].phys_addr);
+ __skb_queue_purge(&q->txq[i].sendq);
+ }
+
+ if (q->rspq.desc) {
+ spin_lock(&adapter->sge.reg_lock);
+ t3_sge_disable_rspcntxt(adapter, q->rspq.cntxt_id);
+ spin_unlock(&adapter->sge.reg_lock);
+ dma_free_coherent(&pdev->dev,
+ q->rspq.size * sizeof(struct rsp_desc),
+ q->rspq.desc, q->rspq.phys_addr);
+ }
+
+ if (q->netdev)
+ q->netdev->atalk_ptr = NULL;
+
+ memset(q, 0, sizeof(*q));
+}
+
+/**
+ * init_qset_cntxt - initialize an SGE queue set context info
+ * @qs: the queue set
+ * @id: the queue set id
+ *
+ * Initializes the TIDs and context ids for the queues of a queue set.
+ */
+static void init_qset_cntxt(struct sge_qset *qs, unsigned int id)
+{
+ qs->rspq.cntxt_id = id;
+ qs->fl[0].cntxt_id = 2 * id;
+ qs->fl[1].cntxt_id = 2 * id + 1;
+ qs->txq[TXQ_ETH].cntxt_id = FW_TUNNEL_SGEEC_START + id;
+ qs->txq[TXQ_ETH].token = FW_TUNNEL_TID_START + id;
+ qs->txq[TXQ_OFLD].cntxt_id = FW_OFLD_SGEEC_START + id;
+ qs->txq[TXQ_CTRL].cntxt_id = FW_CTRL_SGEEC_START + id;
+ qs->txq[TXQ_CTRL].token = FW_CTRL_TID_START + id;
+}
+
+/**
+ * sgl_len - calculates the size of an SGL of the given capacity
+ * @n: the number of SGL entries
+ *
+ * Calculates the number of flits needed for a scatter/gather list that
+ * can hold the given number of entries.
+ */
+static inline unsigned int sgl_len(unsigned int n)
+{
+ /* alternatively: 3 * (n / 2) + 2 * (n & 1) */
+ return (3 * n) / 2 + (n & 1);
+}
+
+/**
+ * flits_to_desc - returns the num of Tx descriptors for the given flits
+ * @n: the number of flits
+ *
+ * Calculates the number of Tx descriptors needed for the supplied number
+ * of flits.
+ */
+static inline unsigned int flits_to_desc(unsigned int n)
+{
+ BUG_ON(n >= ARRAY_SIZE(flit_desc_map));
+ return flit_desc_map[n];
+}
+
+/**
+ * get_packet - return the next ingress packet buffer from a free list
+ * @adap: the adapter that received the packet
+ * @fl: the SGE free list holding the packet
+ * @len: the packet length including any SGE padding
+ * @drop_thres: # of remaining buffers before we start dropping packets
+ *
+ * Get the next packet from a free list and complete setup of the
+ * sk_buff. If the packet is small we make a copy and recycle the
+ * original buffer, otherwise we use the original buffer itself. If a
+ * positive drop threshold is supplied packets are dropped and their
+ * buffers recycled if (a) the number of remaining buffers is under the
+ * threshold and the packet is too big to copy, or (b) the packet should
+ * be copied but there is no memory for the copy.
+ */
+static struct sk_buff *get_packet(struct adapter *adap, struct sge_fl *fl,
+ unsigned int len, unsigned int drop_thres)
+{
+ struct sk_buff *skb = NULL;
+ struct rx_sw_desc *sd = &fl->sdesc[fl->cidx];
+
+ prefetch(sd->skb->data);
+
+ if (len <= SGE_RX_COPY_THRES) {
+ skb = alloc_skb(len, GFP_ATOMIC);
+ if (likely(skb != NULL)) {
+ __skb_put(skb, len);
+ pci_dma_sync_single_for_cpu(adap->pdev,
+ pci_unmap_addr(sd,
+ dma_addr),
+ len, PCI_DMA_FROMDEVICE);
+ memcpy(skb->data, sd->skb->data, len);
+ pci_dma_sync_single_for_device(adap->pdev,
+ pci_unmap_addr(sd,
+ dma_addr),
+ len, PCI_DMA_FROMDEVICE);
+ } else if (!drop_thres)
+ goto use_orig_buf;
+ recycle:
+ recycle_rx_buf(adap, fl, fl->cidx);
+ return skb;
+ }
+
+ if (unlikely(fl->credits < drop_thres))
+ goto recycle;
+
+ use_orig_buf:
+ pci_unmap_single(adap->pdev, pci_unmap_addr(sd, dma_addr),
+ fl->buf_size, PCI_DMA_FROMDEVICE);
+ skb = sd->skb;
+ skb_put(skb, len);
+ __refill_fl(adap, fl);
+ return skb;
+}
+
+/**
+ * get_imm_packet - return the next ingress packet buffer from a response
+ * @resp: the response descriptor containing the packet data
+ *
+ * Return a packet containing the immediate data of the given response.
+ */
+static inline struct sk_buff *get_imm_packet(const struct rsp_desc *resp)
+{
+ struct sk_buff *skb = alloc_skb(IMMED_PKT_SIZE, GFP_ATOMIC);
+
+ if (skb) {
+ __skb_put(skb, IMMED_PKT_SIZE);
+ memcpy(skb->data, resp->imm_data, IMMED_PKT_SIZE);
+ }
+ return skb;
+}
+
+/**
+ * calc_tx_descs - calculate the number of Tx descriptors for a packet
+ * @skb: the packet
+ *
+ * Returns the number of Tx descriptors needed for the given Ethernet
+ * packet. Ethernet packets require addition of WR and CPL headers.
+ */
+static inline unsigned int calc_tx_descs(const struct sk_buff *skb)
+{
+ unsigned int flits;
+
+ if (skb->len <= WR_LEN - sizeof(struct cpl_tx_pkt))
+ return 1;
+
+ flits = sgl_len(skb_shinfo(skb)->nr_frags + 1) + 2;
+ if (skb_shinfo(skb)->gso_size)
+ flits++;
+ return flits_to_desc(flits);
+}
+
+/**
+ * make_sgl - populate a scatter/gather list for a packet
+ * @skb: the packet
+ * @sgp: the SGL to populate
+ * @start: start address of skb main body data to include in the SGL
+ * @len: length of skb main body data to include in the SGL
+ * @pdev: the PCI device
+ *
+ * Generates a scatter/gather list for the buffers that make up a packet
+ * and returns the SGL size in 8-byte words. The caller must size the SGL
+ * appropriately.
+ */
+static inline unsigned int make_sgl(const struct sk_buff *skb,
+ struct sg_ent *sgp, unsigned char *start,
+ unsigned int len, struct pci_dev *pdev)
+{
+ dma_addr_t mapping;
+ unsigned int i, j = 0, nfrags;
+
+ if (len) {
+ mapping = pci_map_single(pdev, start, len, PCI_DMA_TODEVICE);
+ sgp->len[0] = cpu_to_be32(len);
+ sgp->addr[0] = cpu_to_be64(mapping);
+ j = 1;
+ }
+
+ nfrags = skb_shinfo(skb)->nr_frags;
+ for (i = 0; i < nfrags; i++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+ mapping = pci_map_page(pdev, frag->page, frag->page_offset,
+ frag->size, PCI_DMA_TODEVICE);
+ sgp->len[j] = cpu_to_be32(frag->size);
+ sgp->addr[j] = cpu_to_be64(mapping);
+ j ^= 1;
+ if (j == 0)
+ ++sgp;
+ }
+ if (j)
+ sgp->len[j] = 0;
+ return ((nfrags + (len != 0)) * 3) / 2 + j;
+}
+
+/**
+ * check_ring_tx_db - check and potentially ring a Tx queue's doorbell
+ * @adap: the adapter
+ * @q: the Tx queue
+ *
+ * Ring the doorbel if a Tx queue is asleep. There is a natural race,
+ * where the HW is going to sleep just after we checked, however,
+ * then the interrupt handler will detect the outstanding TX packet
+ * and ring the doorbell for us.
+ *
+ * When GTS is disabled we unconditionally ring the doorbell.
+ */
+static inline void check_ring_tx_db(struct adapter *adap, struct sge_txq *q)
+{
+#if USE_GTS
+ clear_bit(TXQ_LAST_PKT_DB, &q->flags);
+ if (test_and_set_bit(TXQ_RUNNING, &q->flags) == 0) {
+ set_bit(TXQ_LAST_PKT_DB, &q->flags);
+ t3_write_reg(adap, A_SG_KDOORBELL,
+ F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
+ }
+#else
+ wmb(); /* write descriptors before telling HW */
+ t3_write_reg(adap, A_SG_KDOORBELL,
+ F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
+#endif
+}
+
+static inline void wr_gen2(struct tx_desc *d, unsigned int gen)
+{
+#if SGE_NUM_GENBITS == 2
+ d->flit[TX_DESC_FLITS - 1] = cpu_to_be64(gen);
+#endif
+}
+
+/**
+ * write_wr_hdr_sgl - write a WR header and, optionally, SGL
+ * @ndesc: number of Tx descriptors spanned by the SGL
+ * @skb: the packet corresponding to the WR
+ * @d: first Tx descriptor to be written
+ * @pidx: index of above descriptors
+ * @q: the SGE Tx queue
+ * @sgl: the SGL
+ * @flits: number of flits to the start of the SGL in the first descriptor
+ * @sgl_flits: the SGL size in flits
+ * @gen: the Tx descriptor generation
+ * @wr_hi: top 32 bits of WR header based on WR type (big endian)
+ * @wr_lo: low 32 bits of WR header based on WR type (big endian)
+ *
+ * Write a work request header and an associated SGL. If the SGL is
+ * small enough to fit into one Tx descriptor it has already been written
+ * and we just need to write the WR header. Otherwise we distribute the
+ * SGL across the number of descriptors it spans.
+ */
+static void write_wr_hdr_sgl(unsigned int ndesc, struct sk_buff *skb,
+ struct tx_desc *d, unsigned int pidx,
+ const struct sge_txq *q,
+ const struct sg_ent *sgl,
+ unsigned int flits, unsigned int sgl_flits,
+ unsigned int gen, unsigned int wr_hi,
+ unsigned int wr_lo)
+{
+ struct work_request_hdr *wrp = (struct work_request_hdr *)d;
+ struct tx_sw_desc *sd = &q->sdesc[pidx];
+
+ sd->skb = skb;
+ if (need_skb_unmap()) {
+ struct unmap_info *ui = (struct unmap_info *)skb->cb;
+
+ ui->fragidx = 0;
+ ui->addr_idx = 0;
+ ui->sflit = flits;
+ }
+
+ if (likely(ndesc == 1)) {
+ skb->priority = pidx;
+ wrp->wr_hi = htonl(F_WR_SOP | F_WR_EOP | V_WR_DATATYPE(1) |
+ V_WR_SGLSFLT(flits)) | wr_hi;
+ wmb();
+ wrp->wr_lo = htonl(V_WR_LEN(flits + sgl_flits) |
+ V_WR_GEN(gen)) | wr_lo;
+ wr_gen2(d, gen);
+ } else {
+ unsigned int ogen = gen;
+ const u64 *fp = (const u64 *)sgl;
+ struct work_request_hdr *wp = wrp;
+
+ wrp->wr_hi = htonl(F_WR_SOP | V_WR_DATATYPE(1) |
+ V_WR_SGLSFLT(flits)) | wr_hi;
+
+ while (sgl_flits) {
+ unsigned int avail = WR_FLITS - flits;
+
+ if (avail > sgl_flits)
+ avail = sgl_flits;
+ memcpy(&d->flit[flits], fp, avail * sizeof(*fp));
+ sgl_flits -= avail;
+ ndesc--;
+ if (!sgl_flits)
+ break;
+
+ fp += avail;
+ d++;
+ sd++;
+ if (++pidx == q->size) {
+ pidx = 0;
+ gen ^= 1;
+ d = q->desc;
+ sd = q->sdesc;
+ }
+
+ sd->skb = skb;
+ wrp = (struct work_request_hdr *)d;
+ wrp->wr_hi = htonl(V_WR_DATATYPE(1) |
+ V_WR_SGLSFLT(1)) | wr_hi;
+ wrp->wr_lo = htonl(V_WR_LEN(min(WR_FLITS,
+ sgl_flits + 1)) |
+ V_WR_GEN(gen)) | wr_lo;
+ wr_gen2(d, gen);
+ flits = 1;
+ }
+ skb->priority = pidx;
+ wrp->wr_hi |= htonl(F_WR_EOP);
+ wmb();
+ wp->wr_lo = htonl(V_WR_LEN(WR_FLITS) | V_WR_GEN(ogen)) | wr_lo;
+ wr_gen2((struct tx_desc *)wp, ogen);
+ WARN_ON(ndesc != 0);
+ }
+}
+
+/**
+ * write_tx_pkt_wr - write a TX_PKT work request
+ * @adap: the adapter
+ * @skb: the packet to send
+ * @pi: the egress interface
+ * @pidx: index of the first Tx descriptor to write
+ * @gen: the generation value to use
+ * @q: the Tx queue
+ * @ndesc: number of descriptors the packet will occupy
+ * @compl: the value of the COMPL bit to use
+ *
+ * Generate a TX_PKT work request to send the supplied packet.
+ */
+static void write_tx_pkt_wr(struct adapter *adap, struct sk_buff *skb,
+ const struct port_info *pi,
+ unsigned int pidx, unsigned int gen,
+ struct sge_txq *q, unsigned int ndesc,
+ unsigned int compl)
+{
+ unsigned int flits, sgl_flits, cntrl, tso_info;
+ struct sg_ent *sgp, sgl[MAX_SKB_FRAGS / 2 + 1];
+ struct tx_desc *d = &q->desc[pidx];
+ struct cpl_tx_pkt *cpl = (struct cpl_tx_pkt *)d;
+
+ cpl->len = htonl(skb->len | 0x80000000);
+ cntrl = V_TXPKT_INTF(pi->port_id);
+
+ if (vlan_tx_tag_present(skb) && pi->vlan_grp)
+ cntrl |= F_TXPKT_VLAN_VLD | V_TXPKT_VLAN(vlan_tx_tag_get(skb));
+
+ tso_info = V_LSO_MSS(skb_shinfo(skb)->gso_size);
+ if (tso_info) {
+ int eth_type;
+ struct cpl_tx_pkt_lso *hdr = (struct cpl_tx_pkt_lso *)cpl;
+
+ d->flit[2] = 0;
+ cntrl |= V_TXPKT_OPCODE(CPL_TX_PKT_LSO);
+ hdr->cntrl = htonl(cntrl);
+ eth_type = skb->nh.raw - skb->data == ETH_HLEN ?
+ CPL_ETH_II : CPL_ETH_II_VLAN;
+ tso_info |= V_LSO_ETH_TYPE(eth_type) |
+ V_LSO_IPHDR_WORDS(skb->nh.iph->ihl) |
+ V_LSO_TCPHDR_WORDS(skb->h.th->doff);
+ hdr->lso_info = htonl(tso_info);
+ flits = 3;
+ } else {
+ cntrl |= V_TXPKT_OPCODE(CPL_TX_PKT);
+ cntrl |= F_TXPKT_IPCSUM_DIS; /* SW calculates IP csum */
+ cntrl |= V_TXPKT_L4CSUM_DIS(skb->ip_summed != CHECKSUM_PARTIAL);
+ cpl->cntrl = htonl(cntrl);
+
+ if (skb->len <= WR_LEN - sizeof(*cpl)) {
+ q->sdesc[pidx].skb = NULL;
+ if (!skb->data_len)
+ memcpy(&d->flit[2], skb->data, skb->len);
+ else
+ skb_copy_bits(skb, 0, &d->flit[2], skb->len);
+
+ flits = (skb->len + 7) / 8 + 2;
+ cpl->wr.wr_hi = htonl(V_WR_BCNTLFLT(skb->len & 7) |
+ V_WR_OP(FW_WROPCODE_TUNNEL_TX_PKT)
+ | F_WR_SOP | F_WR_EOP | compl);
+ wmb();
+ cpl->wr.wr_lo = htonl(V_WR_LEN(flits) | V_WR_GEN(gen) |
+ V_WR_TID(q->token));
+ wr_gen2(d, gen);
+ kfree_skb(skb);
+ return;
+ }
+
+ flits = 2;
+ }
+
+ sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl;
+ sgl_flits = make_sgl(skb, sgp, skb->data, skb_headlen(skb), adap->pdev);
+ if (need_skb_unmap())
+ ((struct unmap_info *)skb->cb)->len = skb_headlen(skb);
+
+ write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits, gen,
+ htonl(V_WR_OP(FW_WROPCODE_TUNNEL_TX_PKT) | compl),
+ htonl(V_WR_TID(q->token)));
+}
+
+/**
+ * eth_xmit - add a packet to the Ethernet Tx queue
+ * @skb: the packet
+ * @dev: the egress net device
+ *
+ * Add a packet to an SGE Tx queue. Runs with softirqs disabled.
+ */
+int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ unsigned int ndesc, pidx, credits, gen, compl;
+ const struct port_info *pi = netdev_priv(dev);
+ struct adapter *adap = dev->priv;
+ struct sge_qset *qs = dev2qset(dev);
+ struct sge_txq *q = &qs->txq[TXQ_ETH];
+
+ /*
+ * The chip min packet length is 9 octets but play safe and reject
+ * anything shorter than an Ethernet header.
+ */
+ if (unlikely(skb->len < ETH_HLEN)) {
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
+ }
+
+ spin_lock(&q->lock);
+ reclaim_completed_tx(adap, q);
+
+ credits = q->size - q->in_use;
+ ndesc = calc_tx_descs(skb);
+
+ if (unlikely(credits < ndesc)) {
+ if (!netif_queue_stopped(dev)) {
+ netif_stop_queue(dev);
+ set_bit(TXQ_ETH, &qs->txq_stopped);
+ q->stops++;
+ dev_err(&adap->pdev->dev,
+ "%s: Tx ring %u full while queue awake!\n",
+ dev->name, q->cntxt_id & 7);
+ }
+ spin_unlock(&q->lock);
+ return NETDEV_TX_BUSY;
+ }
+
+ q->in_use += ndesc;
+ if (unlikely(credits - ndesc < q->stop_thres)) {
+ q->stops++;
+ netif_stop_queue(dev);
+ set_bit(TXQ_ETH, &qs->txq_stopped);
+#if !USE_GTS
+ if (should_restart_tx(q) &&
+ test_and_clear_bit(TXQ_ETH, &qs->txq_stopped)) {
+ q->restarts++;
+ netif_wake_queue(dev);
+ }
+#endif
+ }
+
+ gen = q->gen;
+ q->unacked += ndesc;
+ compl = (q->unacked & 8) << (S_WR_COMPL - 3);
+ q->unacked &= 7;
+ pidx = q->pidx;
+ q->pidx += ndesc;
+ if (q->pidx >= q->size) {
+ q->pidx -= q->size;
+ q->gen ^= 1;
+ }
+
+ /* update port statistics */
+ if (skb->ip_summed == CHECKSUM_COMPLETE)
+ qs->port_stats[SGE_PSTAT_TX_CSUM]++;
+ if (skb_shinfo(skb)->gso_size)
+ qs->port_stats[SGE_PSTAT_TSO]++;
+ if (vlan_tx_tag_present(skb) && pi->vlan_grp)
+ qs->port_stats[SGE_PSTAT_VLANINS]++;
+
+ dev->trans_start = jiffies;
+ spin_unlock(&q->lock);
+
+ /*
+ * We do not use Tx completion interrupts to free DMAd Tx packets.
+ * This is good for performamce but means that we rely on new Tx
+ * packets arriving to run the destructors of completed packets,
+ * which open up space in their sockets' send queues. Sometimes
+ * we do not get such new packets causing Tx to stall. A single
+ * UDP transmitter is a good example of this situation. We have
+ * a clean up timer that periodically reclaims completed packets
+ * but it doesn't run often enough (nor do we want it to) to prevent
+ * lengthy stalls. A solution to this problem is to run the
+ * destructor early, after the packet is queued but before it's DMAd.
+ * A cons is that we lie to socket memory accounting, but the amount
+ * of extra memory is reasonable (limited by the number of Tx
+ * descriptors), the packets do actually get freed quickly by new
+ * packets almost always, and for protocols like TCP that wait for
+ * acks to really free up the data the extra memory is even less.
+ * On the positive side we run the destructors on the sending CPU
+ * rather than on a potentially different completing CPU, usually a
+ * good thing. We also run them without holding our Tx queue lock,
+ * unlike what reclaim_completed_tx() would otherwise do.
+ *
+ * Run the destructor before telling the DMA engine about the packet
+ * to make sure it doesn't complete and get freed prematurely.
+ */
+ if (likely(!skb_shared(skb)))
+ skb_orphan(skb);
+
+ write_tx_pkt_wr(adap, skb, pi, pidx, gen, q, ndesc, compl);
+ check_ring_tx_db(adap, q);
+ return NETDEV_TX_OK;
+}
+
+/**
+ * write_imm - write a packet into a Tx descriptor as immediate data
+ * @d: the Tx descriptor to write
+ * @skb: the packet
+ * @len: the length of packet data to write as immediate data
+ * @gen: the generation bit value to write
+ *
+ * Writes a packet as immediate data into a Tx descriptor. The packet
+ * contains a work request at its beginning. We must write the packet
+ * carefully so the SGE doesn't read accidentally before it's written in
+ * its entirety.
+ */
+static inline void write_imm(struct tx_desc *d, struct sk_buff *skb,
+ unsigned int len, unsigned int gen)
+{
+ struct work_request_hdr *from = (struct work_request_hdr *)skb->data;
+ struct work_request_hdr *to = (struct work_request_hdr *)d;
+
+ memcpy(&to[1], &from[1], len - sizeof(*from));
+ to->wr_hi = from->wr_hi | htonl(F_WR_SOP | F_WR_EOP |
+ V_WR_BCNTLFLT(len & 7));
+ wmb();
+ to->wr_lo = from->wr_lo | htonl(V_WR_GEN(gen) |
+ V_WR_LEN((len + 7) / 8));
+ wr_gen2(d, gen);
+ kfree_skb(skb);
+}
+
+/**
+ * check_desc_avail - check descriptor availability on a send queue
+ * @adap: the adapter
+ * @q: the send queue
+ * @skb: the packet needing the descriptors
+ * @ndesc: the number of Tx descriptors needed
+ * @qid: the Tx queue number in its queue set (TXQ_OFLD or TXQ_CTRL)
+ *
+ * Checks if the requested number of Tx descriptors is available on an
+ * SGE send queue. If the queue is already suspended or not enough
+ * descriptors are available the packet is queued for later transmission.
+ * Must be called with the Tx queue locked.
+ *
+ * Returns 0 if enough descriptors are available, 1 if there aren't
+ * enough descriptors and the packet has been queued, and 2 if the caller
+ * needs to retry because there weren't enough descriptors at the
+ * beginning of the call but some freed up in the mean time.
+ */
+static inline int check_desc_avail(struct adapter *adap, struct sge_txq *q,
+ struct sk_buff *skb, unsigned int ndesc,
+ unsigned int qid)
+{
+ if (unlikely(!skb_queue_empty(&q->sendq))) {
+ addq_exit:__skb_queue_tail(&q->sendq, skb);
+ return 1;
+ }
+ if (unlikely(q->size - q->in_use < ndesc)) {
+ struct sge_qset *qs = txq_to_qset(q, qid);
+
+ set_bit(qid, &qs->txq_stopped);
+ smp_mb__after_clear_bit();
+
+ if (should_restart_tx(q) &&
+ test_and_clear_bit(qid, &qs->txq_stopped))
+ return 2;
+
+ q->stops++;
+ goto addq_exit;
+ }
+ return 0;
+}
+
+/**
+ * reclaim_completed_tx_imm - reclaim completed control-queue Tx descs
+ * @q: the SGE control Tx queue
+ *
+ * This is a variant of reclaim_completed_tx() that is used for Tx queues
+ * that send only immediate data (presently just the control queues) and
+ * thus do not have any sk_buffs to release.
+ */
+static inline void reclaim_completed_tx_imm(struct sge_txq *q)
+{
+ unsigned int reclaim = q->processed - q->cleaned;
+
+ q->in_use -= reclaim;
+ q->cleaned += reclaim;
+}
+
+static inline int immediate(const struct sk_buff *skb)
+{
+ return skb->len <= WR_LEN && !skb->data_len;
+}
+
+/**
+ * ctrl_xmit - send a packet through an SGE control Tx queue
+ * @adap: the adapter
+ * @q: the control queue
+ * @skb: the packet
+ *
+ * Send a packet through an SGE control Tx queue. Packets sent through
+ * a control queue must fit entirely as immediate data in a single Tx
+ * descriptor and have no page fragments.
+ */
+static int ctrl_xmit(struct adapter *adap, struct sge_txq *q,
+ struct sk_buff *skb)
+{
+ int ret;
+ struct work_request_hdr *wrp = (struct work_request_hdr *)skb->data;
+
+ if (unlikely(!immediate(skb))) {
+ WARN_ON(1);
+ dev_kfree_skb(skb);
+ return NET_XMIT_SUCCESS;
+ }
+
+ wrp->wr_hi |= htonl(F_WR_SOP | F_WR_EOP);
+ wrp->wr_lo = htonl(V_WR_TID(q->token));
+
+ spin_lock(&q->lock);
+ again:reclaim_completed_tx_imm(q);
+
+ ret = check_desc_avail(adap, q, skb, 1, TXQ_CTRL);
+ if (unlikely(ret)) {
+ if (ret == 1) {
+ spin_unlock(&q->lock);
+ return NET_XMIT_CN;
+ }
+ goto again;
+ }
+
+ write_imm(&q->desc[q->pidx], skb, skb->len, q->gen);
+
+ q->in_use++;
+ if (++q->pidx >= q->size) {
+ q->pidx = 0;
+ q->gen ^= 1;
+ }
+ spin_unlock(&q->lock);
+ wmb();
+ t3_write_reg(adap, A_SG_KDOORBELL,
+ F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
+ return NET_XMIT_SUCCESS;
+}
+
+/**
+ * restart_ctrlq - restart a suspended control queue
+ * @qs: the queue set cotaining the control queue
+ *
+ * Resumes transmission on a suspended Tx control queue.
+ */
+static void restart_ctrlq(unsigned long data)
+{
+ struct sk_buff *skb;
+ struct sge_qset *qs = (struct sge_qset *)data;
+ struct sge_txq *q = &qs->txq[TXQ_CTRL];
+ struct adapter *adap = qs->netdev->priv;
+
+ spin_lock(&q->lock);
+ again:reclaim_completed_tx_imm(q);
+
+ while (q->in_use < q->size && (skb = __skb_dequeue(&q->sendq)) != NULL) {
+
+ write_imm(&q->desc[q->pidx], skb, skb->len, q->gen);
+
+ if (++q->pidx >= q->size) {
+ q->pidx = 0;
+ q->gen ^= 1;
+ }
+ q->in_use++;
+ }
+
+ if (!skb_queue_empty(&q->sendq)) {
+ set_bit(TXQ_CTRL, &qs->txq_stopped);
+ smp_mb__after_clear_bit();
+
+ if (should_restart_tx(q) &&
+ test_and_clear_bit(TXQ_CTRL, &qs->txq_stopped))
+ goto again;
+ q->stops++;
+ }
+
+ spin_unlock(&q->lock);
+ t3_write_reg(adap, A_SG_KDOORBELL,
+ F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
+}
+
+/*
+ * Send a management message through control queue 0
+ */
+int t3_mgmt_tx(struct adapter *adap, struct sk_buff *skb)
+{
+ return ctrl_xmit(adap, &adap->sge.qs[0].txq[TXQ_CTRL], skb);
+}
+
+/**
+ * write_ofld_wr - write an offload work request
+ * @adap: the adapter
+ * @skb: the packet to send
+ * @q: the Tx queue
+ * @pidx: index of the first Tx descriptor to write
+ * @gen: the generation value to use
+ * @ndesc: number of descriptors the packet will occupy
+ *
+ * Write an offload work request to send the supplied packet. The packet
+ * data already carry the work request with most fields populated.
+ */
+static void write_ofld_wr(struct adapter *adap, struct sk_buff *skb,
+ struct sge_txq *q, unsigned int pidx,
+ unsigned int gen, unsigned int ndesc)
+{
+ unsigned int sgl_flits, flits;
+ struct work_request_hdr *from;
+ struct sg_ent *sgp, sgl[MAX_SKB_FRAGS / 2 + 1];
+ struct tx_desc *d = &q->desc[pidx];
+
+ if (immediate(skb)) {
+ q->sdesc[pidx].skb = NULL;
+ write_imm(d, skb, skb->len, gen);
+ return;
+ }
+
+ /* Only TX_DATA builds SGLs */
+
+ from = (struct work_request_hdr *)skb->data;
+ memcpy(&d->flit[1], &from[1], skb->h.raw - skb->data - sizeof(*from));
+
+ flits = (skb->h.raw - skb->data) / 8;
+ sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl;
+ sgl_flits = make_sgl(skb, sgp, skb->h.raw, skb->tail - skb->h.raw,
+ adap->pdev);
+ if (need_skb_unmap())
+ ((struct unmap_info *)skb->cb)->len = skb->tail - skb->h.raw;
+
+ write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits,
+ gen, from->wr_hi, from->wr_lo);
+}
+
+/**
+ * calc_tx_descs_ofld - calculate # of Tx descriptors for an offload packet
+ * @skb: the packet
+ *
+ * Returns the number of Tx descriptors needed for the given offload
+ * packet. These packets are already fully constructed.
+ */
+static inline unsigned int calc_tx_descs_ofld(const struct sk_buff *skb)
+{
+ unsigned int flits, cnt = skb_shinfo(skb)->nr_frags;
+
+ if (skb->len <= WR_LEN && cnt == 0)
+ return 1; /* packet fits as immediate data */
+
+ flits = (skb->h.raw - skb->data) / 8; /* headers */
+ if (skb->tail != skb->h.raw)
+ cnt++;
+ return flits_to_desc(flits + sgl_len(cnt));
+}
+
+/**
+ * ofld_xmit - send a packet through an offload queue
+ * @adap: the adapter
+ * @q: the Tx offload queue
+ * @skb: the packet
+ *
+ * Send an offload packet through an SGE offload queue.
+ */
+static int ofld_xmit(struct adapter *adap, struct sge_txq *q,
+ struct sk_buff *skb)
+{
+ int ret;
+ unsigned int ndesc = calc_tx_descs_ofld(skb), pidx, gen;
+
+ spin_lock(&q->lock);
+ again:reclaim_completed_tx(adap, q);
+
+ ret = check_desc_avail(adap, q, skb, ndesc, TXQ_OFLD);
+ if (unlikely(ret)) {
+ if (ret == 1) {
+ skb->priority = ndesc; /* save for restart */
+ spin_unlock(&q->lock);
+ return NET_XMIT_CN;
+ }
+ goto again;
+ }
+
+ gen = q->gen;
+ q->in_use += ndesc;
+ pidx = q->pidx;
+ q->pidx += ndesc;
+ if (q->pidx >= q->size) {
+ q->pidx -= q->size;
+ q->gen ^= 1;
+ }
+ spin_unlock(&q->lock);
+
+ write_ofld_wr(adap, skb, q, pidx, gen, ndesc);
+ check_ring_tx_db(adap, q);
+ return NET_XMIT_SUCCESS;
+}
+
+/**
+ * restart_offloadq - restart a suspended offload queue
+ * @qs: the queue set cotaining the offload queue
+ *
+ * Resumes transmission on a suspended Tx offload queue.
+ */
+static void restart_offloadq(unsigned long data)
+{
+ struct sk_buff *skb;
+ struct sge_qset *qs = (struct sge_qset *)data;
+ struct sge_txq *q = &qs->txq[TXQ_OFLD];
+ struct adapter *adap = qs->netdev->priv;
+
+ spin_lock(&q->lock);
+ again:reclaim_completed_tx(adap, q);
+
+ while ((skb = skb_peek(&q->sendq)) != NULL) {
+ unsigned int gen, pidx;
+ unsigned int ndesc = skb->priority;
+
+ if (unlikely(q->size - q->in_use < ndesc)) {
+ set_bit(TXQ_OFLD, &qs->txq_stopped);
+ smp_mb__after_clear_bit();
+
+ if (should_restart_tx(q) &&
+ test_and_clear_bit(TXQ_OFLD, &qs->txq_stopped))
+ goto again;
+ q->stops++;
+ break;
+ }
+
+ gen = q->gen;
+ q->in_use += ndesc;
+ pidx = q->pidx;
+ q->pidx += ndesc;
+ if (q->pidx >= q->size) {
+ q->pidx -= q->size;
+ q->gen ^= 1;
+ }
+ __skb_unlink(skb, &q->sendq);
+ spin_unlock(&q->lock);
+
+ write_ofld_wr(adap, skb, q, pidx, gen, ndesc);
+ spin_lock(&q->lock);
+ }
+ spin_unlock(&q->lock);
+
+#if USE_GTS
+ set_bit(TXQ_RUNNING, &q->flags);
+ set_bit(TXQ_LAST_PKT_DB, &q->flags);
+#endif
+ t3_write_reg(adap, A_SG_KDOORBELL,
+ F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
+}
+
+/**
+ * queue_set - return the queue set a packet should use
+ * @skb: the packet
+ *
+ * Maps a packet to the SGE queue set it should use. The desired queue
+ * set is carried in bits 1-3 in the packet's priority.
+ */
+static inline int queue_set(const struct sk_buff *skb)
+{
+ return skb->priority >> 1;
+}
+
+/**
+ * is_ctrl_pkt - return whether an offload packet is a control packet
+ * @skb: the packet
+ *
+ * Determines whether an offload packet should use an OFLD or a CTRL
+ * Tx queue. This is indicated by bit 0 in the packet's priority.
+ */
+static inline int is_ctrl_pkt(const struct sk_buff *skb)
+{
+ return skb->priority & 1;
+}
+
+/**
+ * t3_offload_tx - send an offload packet
+ * @tdev: the offload device to send to
+ * @skb: the packet
+ *
+ * Sends an offload packet. We use the packet priority to select the
+ * appropriate Tx queue as follows: bit 0 indicates whether the packet
+ * should be sent as regular or control, bits 1-3 select the queue set.
+ */
+int t3_offload_tx(struct t3cdev *tdev, struct sk_buff *skb)
+{
+ struct adapter *adap = tdev2adap(tdev);
+ struct sge_qset *qs = &adap->sge.qs[queue_set(skb)];
+
+ if (unlikely(is_ctrl_pkt(skb)))
+ return ctrl_xmit(adap, &qs->txq[TXQ_CTRL], skb);
+
+ return ofld_xmit(adap, &qs->txq[TXQ_OFLD], skb);
+}
+
+/**
+ * offload_enqueue - add an offload packet to an SGE offload receive queue
+ * @q: the SGE response queue
+ * @skb: the packet
+ *
+ * Add a new offload packet to an SGE response queue's offload packet
+ * queue. If the packet is the first on the queue it schedules the RX
+ * softirq to process the queue.
+ */
+static inline void offload_enqueue(struct sge_rspq *q, struct sk_buff *skb)
+{
+ skb->next = skb->prev = NULL;
+ if (q->rx_tail)
+ q->rx_tail->next = skb;
+ else {
+ struct sge_qset *qs = rspq_to_qset(q);
+
+ if (__netif_rx_schedule_prep(qs->netdev))
+ __netif_rx_schedule(qs->netdev);
+ q->rx_head = skb;
+ }
+ q->rx_tail = skb;
+}
+
+/**
+ * deliver_partial_bundle - deliver a (partial) bundle of Rx offload pkts
+ * @tdev: the offload device that will be receiving the packets
+ * @q: the SGE response queue that assembled the bundle
+ * @skbs: the partial bundle
+ * @n: the number of packets in the bundle
+ *
+ * Delivers a (partial) bundle of Rx offload packets to an offload device.
+ */
+static inline void deliver_partial_bundle(struct t3cdev *tdev,
+ struct sge_rspq *q,
+ struct sk_buff *skbs[], int n)
+{
+ if (n) {
+ q->offload_bundles++;
+ tdev->recv(tdev, skbs, n);
+ }
+}
+
+/**
+ * ofld_poll - NAPI handler for offload packets in interrupt mode
+ * @dev: the network device doing the polling
+ * @budget: polling budget
+ *
+ * The NAPI handler for offload packets when a response queue is serviced
+ * by the hard interrupt handler, i.e., when it's operating in non-polling
+ * mode. Creates small packet batches and sends them through the offload
+ * receive handler. Batches need to be of modest size as we do prefetches
+ * on the packets in each.
+ */
+static int ofld_poll(struct net_device *dev, int *budget)
+{
+ struct adapter *adapter = dev->priv;
+ struct sge_qset *qs = dev2qset(dev);
+ struct sge_rspq *q = &qs->rspq;
+ int work_done, limit = min(*budget, dev->quota), avail = limit;
+
+ while (avail) {
+ struct sk_buff *head, *tail, *skbs[RX_BUNDLE_SIZE];
+ int ngathered;
+
+ spin_lock_irq(&q->lock);
+ head = q->rx_head;
+ if (!head) {
+ work_done = limit - avail;
+ *budget -= work_done;
+ dev->quota -= work_done;
+ __netif_rx_complete(dev);
+ spin_unlock_irq(&q->lock);
+ return 0;
+ }
+
+ tail = q->rx_tail;
+ q->rx_head = q->rx_tail = NULL;
+ spin_unlock_irq(&q->lock);
+
+ for (ngathered = 0; avail && head; avail--) {
+ prefetch(head->data);
+ skbs[ngathered] = head;
+ head = head->next;
+ skbs[ngathered]->next = NULL;
+ if (++ngathered == RX_BUNDLE_SIZE) {
+ q->offload_bundles++;
+ adapter->tdev.recv(&adapter->tdev, skbs,
+ ngathered);
+ ngathered = 0;
+ }
+ }
+ if (head) { /* splice remaining packets back onto Rx queue */
+ spin_lock_irq(&q->lock);
+ tail->next = q->rx_head;
+ if (!q->rx_head)
+ q->rx_tail = tail;
+ q->rx_head = head;
+ spin_unlock_irq(&q->lock);
+ }
+ deliver_partial_bundle(&adapter->tdev, q, skbs, ngathered);
+ }
+ work_done = limit - avail;
+ *budget -= work_done;
+ dev->quota -= work_done;
+ return 1;
+}
+
+/**
+ * rx_offload - process a received offload packet
+ * @tdev: the offload device receiving the packet
+ * @rq: the response queue that received the packet
+ * @skb: the packet
+ * @rx_gather: a gather list of packets if we are building a bundle
+ * @gather_idx: index of the next available slot in the bundle
+ *
+ * Process an ingress offload pakcet and add it to the offload ingress
+ * queue. Returns the index of the next available slot in the bundle.
+ */
+static inline int rx_offload(struct t3cdev *tdev, struct sge_rspq *rq,
+ struct sk_buff *skb, struct sk_buff *rx_gather[],
+ unsigned int gather_idx)
+{
+ rq->offload_pkts++;
+ skb->mac.raw = skb->nh.raw = skb->h.raw = skb->data;
+
+ if (rq->polling) {
+ rx_gather[gather_idx++] = skb;
+ if (gather_idx == RX_BUNDLE_SIZE) {
+ tdev->recv(tdev, rx_gather, RX_BUNDLE_SIZE);
+ gather_idx = 0;
+ rq->offload_bundles++;
+ }
+ } else
+ offload_enqueue(rq, skb);
+
+ return gather_idx;
+}
+
+/**
+ * restart_tx - check whether to restart suspended Tx queues
+ * @qs: the queue set to resume
+ *
+ * Restarts suspended Tx queues of an SGE queue set if they have enough
+ * free resources to resume operation.
+ */
+static void restart_tx(struct sge_qset *qs)
+{
+ if (test_bit(TXQ_ETH, &qs->txq_stopped) &&
+ should_restart_tx(&qs->txq[TXQ_ETH]) &&
+ test_and_clear_bit(TXQ_ETH, &qs->txq_stopped)) {
+ qs->txq[TXQ_ETH].restarts++;
+ if (netif_running(qs->netdev))
+ netif_wake_queue(qs->netdev);
+ }
+
+ if (test_bit(TXQ_OFLD, &qs->txq_stopped) &&
+ should_restart_tx(&qs->txq[TXQ_OFLD]) &&
+ test_and_clear_bit(TXQ_OFLD, &qs->txq_stopped)) {
+ qs->txq[TXQ_OFLD].restarts++;
+ tasklet_schedule(&qs->txq[TXQ_OFLD].qresume_tsk);
+ }
+ if (test_bit(TXQ_CTRL, &qs->txq_stopped) &&
+ should_restart_tx(&qs->txq[TXQ_CTRL]) &&
+ test_and_clear_bit(TXQ_CTRL, &qs->txq_stopped)) {
+ qs->txq[TXQ_CTRL].restarts++;
+ tasklet_schedule(&qs->txq[TXQ_CTRL].qresume_tsk);
+ }
+}
+
+/**
+ * rx_eth - process an ingress ethernet packet
+ * @adap: the adapter
+ * @rq: the response queue that received the packet
+ * @skb: the packet
+ * @pad: amount of padding at the start of the buffer
+ *
+ * Process an ingress ethernet pakcet and deliver it to the stack.
+ * The padding is 2 if the packet was delivered in an Rx buffer and 0
+ * if it was immediate data in a response.
+ */
+static void rx_eth(struct adapter *adap, struct sge_rspq *rq,
+ struct sk_buff *skb, int pad)
+{
+ struct cpl_rx_pkt *p = (struct cpl_rx_pkt *)(skb->data + pad);
+ struct port_info *pi;
+
+ rq->eth_pkts++;
+ skb_pull(skb, sizeof(*p) + pad);
+ skb->dev = adap->port[p->iff];
+ skb->dev->last_rx = jiffies;
+ skb->protocol = eth_type_trans(skb, skb->dev);
+ pi = netdev_priv(skb->dev);
+ if (pi->rx_csum_offload && p->csum_valid && p->csum == 0xffff &&
+ !p->fragment) {
+ rspq_to_qset(rq)->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++;
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ } else
+ skb->ip_summed = CHECKSUM_NONE;
+
+ if (unlikely(p->vlan_valid)) {
+ struct vlan_group *grp = pi->vlan_grp;
+
+ rspq_to_qset(rq)->port_stats[SGE_PSTAT_VLANEX]++;
+ if (likely(grp))
+ __vlan_hwaccel_rx(skb, grp, ntohs(p->vlan),
+ rq->polling);
+ else
+ dev_kfree_skb_any(skb);
+ } else if (rq->polling)
+ netif_receive_skb(skb);
+ else
+ netif_rx(skb);
+}
+
+/**
+ * handle_rsp_cntrl_info - handles control information in a response
+ * @qs: the queue set corresponding to the response
+ * @flags: the response control flags
+ *
+ * Handles the control information of an SGE response, such as GTS
+ * indications and completion credits for the queue set's Tx queues.
+ * HW coalesces credits, we don't do any extra SW coalescing.
+ */
+static inline void handle_rsp_cntrl_info(struct sge_qset *qs, u32 flags)
+{
+ unsigned int credits;
+
+#if USE_GTS
+ if (flags & F_RSPD_TXQ0_GTS)
+ clear_bit(TXQ_RUNNING, &qs->txq[TXQ_ETH].flags);
+#endif
+
+ credits = G_RSPD_TXQ0_CR(flags);
+ if (credits)
+ qs->txq[TXQ_ETH].processed += credits;
+
+ credits = G_RSPD_TXQ2_CR(flags);
+ if (credits)
+ qs->txq[TXQ_CTRL].processed += credits;
+
+# if USE_GTS
+ if (flags & F_RSPD_TXQ1_GTS)
+ clear_bit(TXQ_RUNNING, &qs->txq[TXQ_OFLD].flags);
+# endif
+ credits = G_RSPD_TXQ1_CR(flags);
+ if (credits)
+ qs->txq[TXQ_OFLD].processed += credits;
+}
+
+/**
+ * check_ring_db - check if we need to ring any doorbells
+ * @adapter: the adapter
+ * @qs: the queue set whose Tx queues are to be examined
+ * @sleeping: indicates which Tx queue sent GTS
+ *
+ * Checks if some of a queue set's Tx queues need to ring their doorbells
+ * to resume transmission after idling while they still have unprocessed
+ * descriptors.
+ */
+static void check_ring_db(struct adapter *adap, struct sge_qset *qs,
+ unsigned int sleeping)
+{
+ if (sleeping & F_RSPD_TXQ0_GTS) {
+ struct sge_txq *txq = &qs->txq[TXQ_ETH];
+
+ if (txq->cleaned + txq->in_use != txq->processed &&
+ !test_and_set_bit(TXQ_LAST_PKT_DB, &txq->flags)) {
+ set_bit(TXQ_RUNNING, &txq->flags);
+ t3_write_reg(adap, A_SG_KDOORBELL, F_SELEGRCNTX |
+ V_EGRCNTX(txq->cntxt_id));
+ }
+ }
+
+ if (sleeping & F_RSPD_TXQ1_GTS) {
+ struct sge_txq *txq = &qs->txq[TXQ_OFLD];
+
+ if (txq->cleaned + txq->in_use != txq->processed &&
+ !test_and_set_bit(TXQ_LAST_PKT_DB, &txq->flags)) {
+ set_bit(TXQ_RUNNING, &txq->flags);
+ t3_write_reg(adap, A_SG_KDOORBELL, F_SELEGRCNTX |
+ V_EGRCNTX(txq->cntxt_id));
+ }
+ }
+}
+
+/**
+ * is_new_response - check if a response is newly written
+ * @r: the response descriptor
+ * @q: the response queue
+ *
+ * Returns true if a response descriptor contains a yet unprocessed
+ * response.
+ */
+static inline int is_new_response(const struct rsp_desc *r,
+ const struct sge_rspq *q)
+{
+ return (r->intr_gen & F_RSPD_GEN2) == q->gen;
+}
+
+#define RSPD_GTS_MASK (F_RSPD_TXQ0_GTS | F_RSPD_TXQ1_GTS)
+#define RSPD_CTRL_MASK (RSPD_GTS_MASK | \
+ V_RSPD_TXQ0_CR(M_RSPD_TXQ0_CR) | \
+ V_RSPD_TXQ1_CR(M_RSPD_TXQ1_CR) | \
+ V_RSPD_TXQ2_CR(M_RSPD_TXQ2_CR))
+
+/* How long to delay the next interrupt in case of memory shortage, in 0.1us. */
+#define NOMEM_INTR_DELAY 2500
+
+/**
+ * process_responses - process responses from an SGE response queue
+ * @adap: the adapter
+ * @qs: the queue set to which the response queue belongs
+ * @budget: how many responses can be processed in this round
+ *
+ * Process responses from an SGE response queue up to the supplied budget.
+ * Responses include received packets as well as credits and other events
+ * for the queues that belong to the response queue's queue set.
+ * A negative budget is effectively unlimited.
+ *
+ * Additionally choose the interrupt holdoff time for the next interrupt
+ * on this queue. If the system is under memory shortage use a fairly
+ * long delay to help recovery.
+ */
+static int process_responses(struct adapter *adap, struct sge_qset *qs,
+ int budget)
+{
+ struct sge_rspq *q = &qs->rspq;
+ struct rsp_desc *r = &q->desc[q->cidx];
+ int budget_left = budget;
+ unsigned int sleeping = 0;
+ struct sk_buff *offload_skbs[RX_BUNDLE_SIZE];
+ int ngathered = 0;
+
+ q->next_holdoff = q->holdoff_tmr;
+
+ while (likely(budget_left && is_new_response(r, q))) {
+ int eth, ethpad = 0;
+ struct sk_buff *skb = NULL;
+ u32 len, flags = ntohl(r->flags);
+ u32 rss_hi = *(const u32 *)r, rss_lo = r->rss_hdr.rss_hash_val;
+
+ eth = r->rss_hdr.opcode == CPL_RX_PKT;
+
+ if (unlikely(flags & F_RSPD_ASYNC_NOTIF)) {
+ skb = alloc_skb(AN_PKT_SIZE, GFP_ATOMIC);
+ if (!skb)
+ goto no_mem;
+
+ memcpy(__skb_put(skb, AN_PKT_SIZE), r, AN_PKT_SIZE);
+ skb->data[0] = CPL_ASYNC_NOTIF;
+ rss_hi = htonl(CPL_ASYNC_NOTIF << 24);
+ q->async_notif++;
+ } else if (flags & F_RSPD_IMM_DATA_VALID) {
+ skb = get_imm_packet(r);
+ if (unlikely(!skb)) {
+ no_mem:
+ q->next_holdoff = NOMEM_INTR_DELAY;
+ q->nomem++;
+ /* consume one credit since we tried */
+ budget_left--;
+ break;
+ }
+ q->imm_data++;
+ } else if ((len = ntohl(r->len_cq)) != 0) {
+ struct sge_fl *fl;
+
+ fl = (len & F_RSPD_FLQ) ? &qs->fl[1] : &qs->fl[0];
+ fl->credits--;
+ skb = get_packet(adap, fl, G_RSPD_LEN(len),
+ eth ? SGE_RX_DROP_THRES : 0);
+ if (!skb)
+ q->rx_drops++;
+ else if (r->rss_hdr.opcode == CPL_TRACE_PKT)
+ __skb_pull(skb, 2);
+ ethpad = 2;
+ if (++fl->cidx == fl->size)
+ fl->cidx = 0;
+ } else
+ q->pure_rsps++;
+
+ if (flags & RSPD_CTRL_MASK) {
+ sleeping |= flags & RSPD_GTS_MASK;
+ handle_rsp_cntrl_info(qs, flags);
+ }
+
+ r++;
+ if (unlikely(++q->cidx == q->size)) {
+ q->cidx = 0;
+ q->gen ^= 1;
+ r = q->desc;
+ }
+ prefetch(r);
+
+ if (++q->credits >= (q->size / 4)) {
+ refill_rspq(adap, q, q->credits);
+ q->credits = 0;
+ }
+
+ if (likely(skb != NULL)) {
+ if (eth)
+ rx_eth(adap, q, skb, ethpad);
+ else {
+ /* Preserve the RSS info in csum & priority */
+ skb->csum = rss_hi;
+ skb->priority = rss_lo;
+ ngathered = rx_offload(&adap->tdev, q, skb,
+ offload_skbs, ngathered);
+ }
+ }
+
+ --budget_left;
+ }
+
+ deliver_partial_bundle(&adap->tdev, q, offload_skbs, ngathered);
+ if (sleeping)
+ check_ring_db(adap, qs, sleeping);
+
+ smp_mb(); /* commit Tx queue .processed updates */
+ if (unlikely(qs->txq_stopped != 0))
+ restart_tx(qs);
+
+ budget -= budget_left;
+ return budget;
+}
+
+static inline int is_pure_response(const struct rsp_desc *r)
+{
+ u32 n = ntohl(r->flags) & (F_RSPD_ASYNC_NOTIF | F_RSPD_IMM_DATA_VALID);
+
+ return (n | r->len_cq) == 0;
+}
+
+/**
+ * napi_rx_handler - the NAPI handler for Rx processing
+ * @dev: the net device
+ * @budget: how many packets we can process in this round
+ *
+ * Handler for new data events when using NAPI.
+ */
+static int napi_rx_handler(struct net_device *dev, int *budget)
+{
+ struct adapter *adap = dev->priv;
+ struct sge_qset *qs = dev2qset(dev);
+ int effective_budget = min(*budget, dev->quota);
+
+ int work_done = process_responses(adap, qs, effective_budget);
+ *budget -= work_done;
+ dev->quota -= work_done;
+
+ if (work_done >= effective_budget)
+ return 1;
+
+ netif_rx_complete(dev);
+
+ /*
+ * Because we don't atomically flush the following write it is
+ * possible that in very rare cases it can reach the device in a way
+ * that races with a new response being written plus an error interrupt
+ * causing the NAPI interrupt handler below to return unhandled status
+ * to the OS. To protect against this would require flushing the write
+ * and doing both the write and the flush with interrupts off. Way too
+ * expensive and unjustifiable given the rarity of the race.
+ *
+ * The race cannot happen at all with MSI-X.
+ */
+ t3_write_reg(adap, A_SG_GTS, V_RSPQ(qs->rspq.cntxt_id) |
+ V_NEWTIMER(qs->rspq.next_holdoff) |
+ V_NEWINDEX(qs->rspq.cidx));
+ return 0;
+}
+
+/*
+ * Returns true if the device is already scheduled for polling.
+ */
+static inline int napi_is_scheduled(struct net_device *dev)
+{
+ return test_bit(__LINK_STATE_RX_SCHED, &dev->state);
+}
+
+/**
+ * process_pure_responses - process pure responses from a response queue
+ * @adap: the adapter
+ * @qs: the queue set owning the response queue
+ * @r: the first pure response to process
+ *
+ * A simpler version of process_responses() that handles only pure (i.e.,
+ * non data-carrying) responses. Such respones are too light-weight to
+ * justify calling a softirq under NAPI, so we handle them specially in
+ * the interrupt handler. The function is called with a pointer to a
+ * response, which the caller must ensure is a valid pure response.
+ *
+ * Returns 1 if it encounters a valid data-carrying response, 0 otherwise.
+ */
+static int process_pure_responses(struct adapter *adap, struct sge_qset *qs,
+ struct rsp_desc *r)
+{
+ struct sge_rspq *q = &qs->rspq;
+ unsigned int sleeping = 0;
+
+ do {
+ u32 flags = ntohl(r->flags);
+
+ r++;
+ if (unlikely(++q->cidx == q->size)) {
+ q->cidx = 0;
+ q->gen ^= 1;
+ r = q->desc;
+ }
+ prefetch(r);
+
+ if (flags & RSPD_CTRL_MASK) {
+ sleeping |= flags & RSPD_GTS_MASK;
+ handle_rsp_cntrl_info(qs, flags);
+ }
+
+ q->pure_rsps++;
+ if (++q->credits >= (q->size / 4)) {
+ refill_rspq(adap, q, q->credits);
+ q->credits = 0;
+ }
+ } while (is_new_response(r, q) && is_pure_response(r));
+
+ if (sleeping)
+ check_ring_db(adap, qs, sleeping);
+
+ smp_mb(); /* commit Tx queue .processed updates */
+ if (unlikely(qs->txq_stopped != 0))
+ restart_tx(qs);
+
+ return is_new_response(r, q);
+}
+
+/**
+ * handle_responses - decide what to do with new responses in NAPI mode
+ * @adap: the adapter
+ * @q: the response queue
+ *
+ * This is used by the NAPI interrupt handlers to decide what to do with
+ * new SGE responses. If there are no new responses it returns -1. If
+ * there are new responses and they are pure (i.e., non-data carrying)
+ * it handles them straight in hard interrupt context as they are very
+ * cheap and don't deliver any packets. Finally, if there are any data
+ * signaling responses it schedules the NAPI handler. Returns 1 if it
+ * schedules NAPI, 0 if all new responses were pure.
+ *
+ * The caller must ascertain NAPI is not already running.
+ */
+static inline int handle_responses(struct adapter *adap, struct sge_rspq *q)
+{
+ struct sge_qset *qs = rspq_to_qset(q);
+ struct rsp_desc *r = &q->desc[q->cidx];
+
+ if (!is_new_response(r, q))
+ return -1;
+ if (is_pure_response(r) && process_pure_responses(adap, qs, r) == 0) {
+ t3_write_reg(adap, A_SG_GTS, V_RSPQ(q->cntxt_id) |
+ V_NEWTIMER(q->holdoff_tmr) | V_NEWINDEX(q->cidx));
+ return 0;
+ }
+ if (likely(__netif_rx_schedule_prep(qs->netdev)))
+ __netif_rx_schedule(qs->netdev);
+ return 1;
+}
+
+/*
+ * The MSI-X interrupt handler for an SGE response queue for the non-NAPI case
+ * (i.e., response queue serviced in hard interrupt).
+ */
+irqreturn_t t3_sge_intr_msix(int irq, void *cookie)
+{
+ struct sge_qset *qs = cookie;
+ struct adapter *adap = qs->netdev->priv;
+ struct sge_rspq *q = &qs->rspq;
+
+ spin_lock(&q->lock);
+ if (process_responses(adap, qs, -1) == 0)
+ q->unhandled_irqs++;
+ t3_write_reg(adap, A_SG_GTS, V_RSPQ(q->cntxt_id) |
+ V_NEWTIMER(q->next_holdoff) | V_NEWINDEX(q->cidx));
+ spin_unlock(&q->lock);
+ return IRQ_HANDLED;
+}
+
+/*
+ * The MSI-X interrupt handler for an SGE response queue for the NAPI case
+ * (i.e., response queue serviced by NAPI polling).
+ */
+irqreturn_t t3_sge_intr_msix_napi(int irq, void *cookie)
+{
+ struct sge_qset *qs = cookie;
+ struct adapter *adap = qs->netdev->priv;
+ struct sge_rspq *q = &qs->rspq;
+
+ spin_lock(&q->lock);
+ BUG_ON(napi_is_scheduled(qs->netdev));
+
+ if (handle_responses(adap, q) < 0)
+ q->unhandled_irqs++;
+ spin_unlock(&q->lock);
+ return IRQ_HANDLED;
+}
+
+/*
+ * The non-NAPI MSI interrupt handler. This needs to handle data events from
+ * SGE response queues as well as error and other async events as they all use
+ * the same MSI vector. We use one SGE response queue per port in this mode
+ * and protect all response queues with queue 0's lock.
+ */
+static irqreturn_t t3_intr_msi(int irq, void *cookie)
+{
+ int new_packets = 0;
+ struct adapter *adap = cookie;
+ struct sge_rspq *q = &adap->sge.qs[0].rspq;
+
+ spin_lock(&q->lock);
+
+ if (process_responses(adap, &adap->sge.qs[0], -1)) {
+ t3_write_reg(adap, A_SG_GTS, V_RSPQ(q->cntxt_id) |
+ V_NEWTIMER(q->next_holdoff) | V_NEWINDEX(q->cidx));
+ new_packets = 1;
+ }
+
+ if (adap->params.nports == 2 &&
+ process_responses(adap, &adap->sge.qs[1], -1)) {
+ struct sge_rspq *q1 = &adap->sge.qs[1].rspq;
+
+ t3_write_reg(adap, A_SG_GTS, V_RSPQ(q1->cntxt_id) |
+ V_NEWTIMER(q1->next_holdoff) |
+ V_NEWINDEX(q1->cidx));
+ new_packets = 1;
+ }
+
+ if (!new_packets && t3_slow_intr_handler(adap) == 0)
+ q->unhandled_irqs++;
+
+ spin_unlock(&q->lock);
+ return IRQ_HANDLED;
+}
+
+static int rspq_check_napi(struct net_device *dev, struct sge_rspq *q)
+{
+ if (!napi_is_scheduled(dev) && is_new_response(&q->desc[q->cidx], q)) {
+ if (likely(__netif_rx_schedule_prep(dev)))
+ __netif_rx_schedule(dev);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * The MSI interrupt handler for the NAPI case (i.e., response queues serviced
+ * by NAPI polling). Handles data events from SGE response queues as well as
+ * error and other async events as they all use the same MSI vector. We use
+ * one SGE response queue per port in this mode and protect all response
+ * queues with queue 0's lock.
+ */
+irqreturn_t t3_intr_msi_napi(int irq, void *cookie)
+{
+ int new_packets;
+ struct adapter *adap = cookie;
+ struct sge_rspq *q = &adap->sge.qs[0].rspq;
+
+ spin_lock(&q->lock);
+
+ new_packets = rspq_check_napi(adap->sge.qs[0].netdev, q);
+ if (adap->params.nports == 2)
+ new_packets += rspq_check_napi(adap->sge.qs[1].netdev,
+ &adap->sge.qs[1].rspq);
+ if (!new_packets && t3_slow_intr_handler(adap) == 0)
+ q->unhandled_irqs++;
+
+ spin_unlock(&q->lock);
+ return IRQ_HANDLED;
+}
+
+/*
+ * A helper function that processes responses and issues GTS.
+ */
+static inline int process_responses_gts(struct adapter *adap,
+ struct sge_rspq *rq)
+{
+ int work;
+
+ work = process_responses(adap, rspq_to_qset(rq), -1);
+ t3_write_reg(adap, A_SG_GTS, V_RSPQ(rq->cntxt_id) |
+ V_NEWTIMER(rq->next_holdoff) | V_NEWINDEX(rq->cidx));
+ return work;
+}
+
+/*
+ * The legacy INTx interrupt handler. This needs to handle data events from
+ * SGE response queues as well as error and other async events as they all use
+ * the same interrupt pin. We use one SGE response queue per port in this mode
+ * and protect all response queues with queue 0's lock.
+ */
+static irqreturn_t t3_intr(int irq, void *cookie)
+{
+ int work_done, w0, w1;
+ struct adapter *adap = cookie;
+ struct sge_rspq *q0 = &adap->sge.qs[0].rspq;
+ struct sge_rspq *q1 = &adap->sge.qs[1].rspq;
+
+ spin_lock(&q0->lock);
+
+ w0 = is_new_response(&q0->desc[q0->cidx], q0);
+ w1 = adap->params.nports == 2 &&
+ is_new_response(&q1->desc[q1->cidx], q1);
+
+ if (likely(w0 | w1)) {
+ t3_write_reg(adap, A_PL_CLI, 0);
+ t3_read_reg(adap, A_PL_CLI); /* flush */
+
+ if (likely(w0))
+ process_responses_gts(adap, q0);
+
+ if (w1)
+ process_responses_gts(adap, q1);
+
+ work_done = w0 | w1;
+ } else
+ work_done = t3_slow_intr_handler(adap);
+
+ spin_unlock(&q0->lock);
+ return IRQ_RETVAL(work_done != 0);
+}
+
+/*
+ * Interrupt handler for legacy INTx interrupts for T3B-based cards.
+ * Handles data events from SGE response queues as well as error and other
+ * async events as they all use the same interrupt pin. We use one SGE
+ * response queue per port in this mode and protect all response queues with
+ * queue 0's lock.
+ */
+static irqreturn_t t3b_intr(int irq, void *cookie)
+{
+ u32 map;
+ struct adapter *adap = cookie;
+ struct sge_rspq *q0 = &adap->sge.qs[0].rspq;
+
+ t3_write_reg(adap, A_PL_CLI, 0);
+ map = t3_read_reg(adap, A_SG_DATA_INTR);
+
+ if (unlikely(!map)) /* shared interrupt, most likely */
+ return IRQ_NONE;
+
+ spin_lock(&q0->lock);
+
+ if (unlikely(map & F_ERRINTR))
+ t3_slow_intr_handler(adap);
+
+ if (likely(map & 1))
+ process_responses_gts(adap, q0);
+
+ if (map & 2)
+ process_responses_gts(adap, &adap->sge.qs[1].rspq);
+
+ spin_unlock(&q0->lock);
+ return IRQ_HANDLED;
+}
+
+/*
+ * NAPI interrupt handler for legacy INTx interrupts for T3B-based cards.
+ * Handles data events from SGE response queues as well as error and other
+ * async events as they all use the same interrupt pin. We use one SGE
+ * response queue per port in this mode and protect all response queues with
+ * queue 0's lock.
+ */
+static irqreturn_t t3b_intr_napi(int irq, void *cookie)
+{
+ u32 map;
+ struct net_device *dev;
+ struct adapter *adap = cookie;
+ struct sge_rspq *q0 = &adap->sge.qs[0].rspq;
+
+ t3_write_reg(adap, A_PL_CLI, 0);
+ map = t3_read_reg(adap, A_SG_DATA_INTR);
+
+ if (unlikely(!map)) /* shared interrupt, most likely */
+ return IRQ_NONE;
+
+ spin_lock(&q0->lock);
+
+ if (unlikely(map & F_ERRINTR))
+ t3_slow_intr_handler(adap);
+
+ if (likely(map & 1)) {
+ dev = adap->sge.qs[0].netdev;
+
+ if (likely(__netif_rx_schedule_prep(dev)))
+ __netif_rx_schedule(dev);
+ }
+ if (map & 2) {
+ dev = adap->sge.qs[1].netdev;
+
+ if (likely(__netif_rx_schedule_prep(dev)))
+ __netif_rx_schedule(dev);
+ }
+
+ spin_unlock(&q0->lock);
+ return IRQ_HANDLED;
+}
+
+/**
+ * t3_intr_handler - select the top-level interrupt handler
+ * @adap: the adapter
+ * @polling: whether using NAPI to service response queues
+ *
+ * Selects the top-level interrupt handler based on the type of interrupts
+ * (MSI-X, MSI, or legacy) and whether NAPI will be used to service the
+ * response queues.
+ */
+intr_handler_t t3_intr_handler(struct adapter *adap, int polling)
+{
+ if (adap->flags & USING_MSIX)
+ return polling ? t3_sge_intr_msix_napi : t3_sge_intr_msix;
+ if (adap->flags & USING_MSI)
+ return polling ? t3_intr_msi_napi : t3_intr_msi;
+ if (adap->params.rev > 0)
+ return polling ? t3b_intr_napi : t3b_intr;
+ return t3_intr;
+}
+
+/**
+ * t3_sge_err_intr_handler - SGE async event interrupt handler
+ * @adapter: the adapter
+ *
+ * Interrupt handler for SGE asynchronous (non-data) events.
+ */
+void t3_sge_err_intr_handler(struct adapter *adapter)
+{
+ unsigned int v, status = t3_read_reg(adapter, A_SG_INT_CAUSE);
+
+ if (status & F_RSPQCREDITOVERFOW)
+ CH_ALERT(adapter, "SGE response queue credit overflow\n");
+
+ if (status & F_RSPQDISABLED) {
+ v = t3_read_reg(adapter, A_SG_RSPQ_FL_STATUS);
+
+ CH_ALERT(adapter,
+ "packet delivered to disabled response queue "
+ "(0x%x)\n", (v >> S_RSPQ0DISABLED) & 0xff);
+ }
+
+ t3_write_reg(adapter, A_SG_INT_CAUSE, status);
+ if (status & (F_RSPQCREDITOVERFOW | F_RSPQDISABLED))
+ t3_fatal_err(adapter);
+}
+
+/**
+ * sge_timer_cb - perform periodic maintenance of an SGE qset
+ * @data: the SGE queue set to maintain
+ *
+ * Runs periodically from a timer to perform maintenance of an SGE queue
+ * set. It performs two tasks:
+ *
+ * a) Cleans up any completed Tx descriptors that may still be pending.
+ * Normal descriptor cleanup happens when new packets are added to a Tx
+ * queue so this timer is relatively infrequent and does any cleanup only
+ * if the Tx queue has not seen any new packets in a while. We make a
+ * best effort attempt to reclaim descriptors, in that we don't wait
+ * around if we cannot get a queue's lock (which most likely is because
+ * someone else is queueing new packets and so will also handle the clean
+ * up). Since control queues use immediate data exclusively we don't
+ * bother cleaning them up here.
+ *
+ * b) Replenishes Rx queues that have run out due to memory shortage.
+ * Normally new Rx buffers are added when existing ones are consumed but
+ * when out of memory a queue can become empty. We try to add only a few
+ * buffers here, the queue will be replenished fully as these new buffers
+ * are used up if memory shortage has subsided.
+ */
+static void sge_timer_cb(unsigned long data)
+{
+ spinlock_t *lock;
+ struct sge_qset *qs = (struct sge_qset *)data;
+ struct adapter *adap = qs->netdev->priv;
+
+ if (spin_trylock(&qs->txq[TXQ_ETH].lock)) {
+ reclaim_completed_tx(adap, &qs->txq[TXQ_ETH]);
+ spin_unlock(&qs->txq[TXQ_ETH].lock);
+ }
+ if (spin_trylock(&qs->txq[TXQ_OFLD].lock)) {
+ reclaim_completed_tx(adap, &qs->txq[TXQ_OFLD]);
+ spin_unlock(&qs->txq[TXQ_OFLD].lock);
+ }
+ lock = (adap->flags & USING_MSIX) ? &qs->rspq.lock :
+ &adap->sge.qs[0].rspq.lock;
+ if (spin_trylock_irq(lock)) {
+ if (!napi_is_scheduled(qs->netdev)) {
+ if (qs->fl[0].credits < qs->fl[0].size)
+ __refill_fl(adap, &qs->fl[0]);
+ if (qs->fl[1].credits < qs->fl[1].size)
+ __refill_fl(adap, &qs->fl[1]);
+ }
+ spin_unlock_irq(lock);
+ }
+ mod_timer(&qs->tx_reclaim_timer, jiffies + TX_RECLAIM_PERIOD);
+}
+
+/**
+ * t3_update_qset_coalesce - update coalescing settings for a queue set
+ * @qs: the SGE queue set
+ * @p: new queue set parameters
+ *
+ * Update the coalescing settings for an SGE queue set. Nothing is done
+ * if the queue set is not initialized yet.
+ */
+void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p)
+{
+ if (!qs->netdev)
+ return;
+
+ qs->rspq.holdoff_tmr = max(p->coalesce_usecs * 10, 1U);/* can't be 0 */
+ qs->rspq.polling = p->polling;
+ qs->netdev->poll = p->polling ? napi_rx_handler : ofld_poll;
+}
+
+/**
+ * t3_sge_alloc_qset - initialize an SGE queue set
+ * @adapter: the adapter
+ * @id: the queue set id
+ * @nports: how many Ethernet ports will be using this queue set
+ * @irq_vec_idx: the IRQ vector index for response queue interrupts
+ * @p: configuration parameters for this queue set
+ * @ntxq: number of Tx queues for the queue set
+ * @netdev: net device associated with this queue set
+ *
+ * Allocate resources and initialize an SGE queue set. A queue set
+ * comprises a response queue, two Rx free-buffer queues, and up to 3
+ * Tx queues. The Tx queues are assigned roles in the order Ethernet
+ * queue, offload queue, and control queue.
+ */
+int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
+ int irq_vec_idx, const struct qset_params *p,
+ int ntxq, struct net_device *netdev)
+{
+ int i, ret = -ENOMEM;
+ struct sge_qset *q = &adapter->sge.qs[id];
+
+ init_qset_cntxt(q, id);
+ init_timer(&q->tx_reclaim_timer);
+ q->tx_reclaim_timer.data = (unsigned long)q;
+ q->tx_reclaim_timer.function = sge_timer_cb;
+
+ q->fl[0].desc = alloc_ring(adapter->pdev, p->fl_size,
+ sizeof(struct rx_desc),
+ sizeof(struct rx_sw_desc),
+ &q->fl[0].phys_addr, &q->fl[0].sdesc);
+ if (!q->fl[0].desc)
+ goto err;
+
+ q->fl[1].desc = alloc_ring(adapter->pdev, p->jumbo_size,
+ sizeof(struct rx_desc),
+ sizeof(struct rx_sw_desc),
+ &q->fl[1].phys_addr, &q->fl[1].sdesc);
+ if (!q->fl[1].desc)
+ goto err;
+
+ q->rspq.desc = alloc_ring(adapter->pdev, p->rspq_size,
+ sizeof(struct rsp_desc), 0,
+ &q->rspq.phys_addr, NULL);
+ if (!q->rspq.desc)
+ goto err;
+
+ for (i = 0; i < ntxq; ++i) {
+ /*
+ * The control queue always uses immediate data so does not
+ * need to keep track of any sk_buffs.
+ */
+ size_t sz = i == TXQ_CTRL ? 0 : sizeof(struct tx_sw_desc);
+
+ q->txq[i].desc = alloc_ring(adapter->pdev, p->txq_size[i],
+ sizeof(struct tx_desc), sz,
+ &q->txq[i].phys_addr,
+ &q->txq[i].sdesc);
+ if (!q->txq[i].desc)
+ goto err;
+
+ q->txq[i].gen = 1;
+ q->txq[i].size = p->txq_size[i];
+ spin_lock_init(&q->txq[i].lock);
+ skb_queue_head_init(&q->txq[i].sendq);
+ }
+
+ tasklet_init(&q->txq[TXQ_OFLD].qresume_tsk, restart_offloadq,
+ (unsigned long)q);
+ tasklet_init(&q->txq[TXQ_CTRL].qresume_tsk, restart_ctrlq,
+ (unsigned long)q);
+
+ q->fl[0].gen = q->fl[1].gen = 1;
+ q->fl[0].size = p->fl_size;
+ q->fl[1].size = p->jumbo_size;
+
+ q->rspq.gen = 1;
+ q->rspq.size = p->rspq_size;
+ spin_lock_init(&q->rspq.lock);
+
+ q->txq[TXQ_ETH].stop_thres = nports *
+ flits_to_desc(sgl_len(MAX_SKB_FRAGS + 1) + 3);
+
+ if (ntxq == 1) {
+ q->fl[0].buf_size = SGE_RX_SM_BUF_SIZE + 2 +
+ sizeof(struct cpl_rx_pkt);
+ q->fl[1].buf_size = MAX_FRAME_SIZE + 2 +
+ sizeof(struct cpl_rx_pkt);
+ } else {
+ q->fl[0].buf_size = SGE_RX_SM_BUF_SIZE +
+ sizeof(struct cpl_rx_data);
+ q->fl[1].buf_size = (16 * 1024) -
+ SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+ }
+
+ spin_lock(&adapter->sge.reg_lock);
+
+ /* FL threshold comparison uses < */
+ ret = t3_sge_init_rspcntxt(adapter, q->rspq.cntxt_id, irq_vec_idx,
+ q->rspq.phys_addr, q->rspq.size,
+ q->fl[0].buf_size, 1, 0);
+ if (ret)
+ goto err_unlock;
+
+ for (i = 0; i < SGE_RXQ_PER_SET; ++i) {
+ ret = t3_sge_init_flcntxt(adapter, q->fl[i].cntxt_id, 0,
+ q->fl[i].phys_addr, q->fl[i].size,
+ q->fl[i].buf_size, p->cong_thres, 1,
+ 0);
+ if (ret)
+ goto err_unlock;
+ }
+
+ ret = t3_sge_init_ecntxt(adapter, q->txq[TXQ_ETH].cntxt_id, USE_GTS,
+ SGE_CNTXT_ETH, id, q->txq[TXQ_ETH].phys_addr,
+ q->txq[TXQ_ETH].size, q->txq[TXQ_ETH].token,
+ 1, 0);
+ if (ret)
+ goto err_unlock;
+
+ if (ntxq > 1) {
+ ret = t3_sge_init_ecntxt(adapter, q->txq[TXQ_OFLD].cntxt_id,
+ USE_GTS, SGE_CNTXT_OFLD, id,
+ q->txq[TXQ_OFLD].phys_addr,
+ q->txq[TXQ_OFLD].size, 0, 1, 0);
+ if (ret)
+ goto err_unlock;
+ }
+
+ if (ntxq > 2) {
+ ret = t3_sge_init_ecntxt(adapter, q->txq[TXQ_CTRL].cntxt_id, 0,
+ SGE_CNTXT_CTRL, id,
+ q->txq[TXQ_CTRL].phys_addr,
+ q->txq[TXQ_CTRL].size,
+ q->txq[TXQ_CTRL].token, 1, 0);
+ if (ret)
+ goto err_unlock;
+ }
+
+ spin_unlock(&adapter->sge.reg_lock);
+ q->netdev = netdev;
+ t3_update_qset_coalesce(q, p);
+
+ /*
+ * We use atalk_ptr as a backpointer to a qset. In case a device is
+ * associated with multiple queue sets only the first one sets
+ * atalk_ptr.
+ */
+ if (netdev->atalk_ptr == NULL)
+ netdev->atalk_ptr = q;
+
+ refill_fl(adapter, &q->fl[0], q->fl[0].size, GFP_KERNEL);
+ refill_fl(adapter, &q->fl[1], q->fl[1].size, GFP_KERNEL);
+ refill_rspq(adapter, &q->rspq, q->rspq.size - 1);
+
+ t3_write_reg(adapter, A_SG_GTS, V_RSPQ(q->rspq.cntxt_id) |
+ V_NEWTIMER(q->rspq.holdoff_tmr));
+
+ mod_timer(&q->tx_reclaim_timer, jiffies + TX_RECLAIM_PERIOD);
+ return 0;
+
+ err_unlock:
+ spin_unlock(&adapter->sge.reg_lock);
+ err:
+ t3_free_qset(adapter, q);
+ return ret;
+}
+
+/**
+ * t3_free_sge_resources - free SGE resources
+ * @adap: the adapter
+ *
+ * Frees resources used by the SGE queue sets.
+ */
+void t3_free_sge_resources(struct adapter *adap)
+{
+ int i;
+
+ for (i = 0; i < SGE_QSETS; ++i)
+ t3_free_qset(adap, &adap->sge.qs[i]);
+}
+
+/**
+ * t3_sge_start - enable SGE
+ * @adap: the adapter
+ *
+ * Enables the SGE for DMAs. This is the last step in starting packet
+ * transfers.
+ */
+void t3_sge_start(struct adapter *adap)
+{
+ t3_set_reg_field(adap, A_SG_CONTROL, F_GLOBALENABLE, F_GLOBALENABLE);
+}
+
+/**
+ * t3_sge_stop - disable SGE operation
+ * @adap: the adapter
+ *
+ * Disables the DMA engine. This can be called in emeregencies (e.g.,
+ * from error interrupts) or from normal process context. In the latter
+ * case it also disables any pending queue restart tasklets. Note that
+ * if it is called in interrupt context it cannot disable the restart
+ * tasklets as it cannot wait, however the tasklets will have no effect
+ * since the doorbells are disabled and the driver will call this again
+ * later from process context, at which time the tasklets will be stopped
+ * if they are still running.
+ */
+void t3_sge_stop(struct adapter *adap)
+{
+ t3_set_reg_field(adap, A_SG_CONTROL, F_GLOBALENABLE, 0);
+ if (!in_interrupt()) {
+ int i;
+
+ for (i = 0; i < SGE_QSETS; ++i) {
+ struct sge_qset *qs = &adap->sge.qs[i];
+
+ tasklet_kill(&qs->txq[TXQ_OFLD].qresume_tsk);
+ tasklet_kill(&qs->txq[TXQ_CTRL].qresume_tsk);
+ }
+ }
+}
+
+/**
+ * t3_sge_init - initialize SGE
+ * @adap: the adapter
+ * @p: the SGE parameters
+ *
+ * Performs SGE initialization needed every time after a chip reset.
+ * We do not initialize any of the queue sets here, instead the driver
+ * top-level must request those individually. We also do not enable DMA
+ * here, that should be done after the queues have been set up.
+ */
+void t3_sge_init(struct adapter *adap, struct sge_params *p)
+{
+ unsigned int ctrl, ups = ffs(pci_resource_len(adap->pdev, 2) >> 12);
+
+ ctrl = F_DROPPKT | V_PKTSHIFT(2) | F_FLMODE | F_AVOIDCQOVFL |
+ F_CQCRDTCTRL |
+ V_HOSTPAGESIZE(PAGE_SHIFT - 11) | F_BIGENDIANINGRESS |
+ V_USERSPACESIZE(ups ? ups - 1 : 0) | F_ISCSICOALESCING;
+#if SGE_NUM_GENBITS == 1
+ ctrl |= F_EGRGENCTRL;
+#endif
+ if (adap->params.rev > 0) {
+ if (!(adap->flags & (USING_MSIX | USING_MSI)))
+ ctrl |= F_ONEINTMULTQ | F_OPTONEINTMULTQ;
+ ctrl |= F_CQCRDTCTRL | F_AVOIDCQOVFL;
+ }
+ t3_write_reg(adap, A_SG_CONTROL, ctrl);
+ t3_write_reg(adap, A_SG_EGR_RCQ_DRB_THRSH, V_HIRCQDRBTHRSH(512) |
+ V_LORCQDRBTHRSH(512));
+ t3_write_reg(adap, A_SG_TIMER_TICK, core_ticks_per_usec(adap) / 10);
+ t3_write_reg(adap, A_SG_CMDQ_CREDIT_TH, V_THRESHOLD(32) |
+ V_TIMEOUT(200 * core_ticks_per_usec(adap)));
+ t3_write_reg(adap, A_SG_HI_DRB_HI_THRSH, 1000);
+ t3_write_reg(adap, A_SG_HI_DRB_LO_THRSH, 256);
+ t3_write_reg(adap, A_SG_LO_DRB_HI_THRSH, 1000);
+ t3_write_reg(adap, A_SG_LO_DRB_LO_THRSH, 256);
+ t3_write_reg(adap, A_SG_OCO_BASE, V_BASE1(0xfff));
+ t3_write_reg(adap, A_SG_DRB_PRI_THRESH, 63 * 1024);
+}
+
+/**
+ * t3_sge_prep - one-time SGE initialization
+ * @adap: the associated adapter
+ * @p: SGE parameters
+ *
+ * Performs one-time initialization of SGE SW state. Includes determining
+ * defaults for the assorted SGE parameters, which admins can change until
+ * they are used to initialize the SGE.
+ */
+void __devinit t3_sge_prep(struct adapter *adap, struct sge_params *p)
+{
+ int i;
+
+ p->max_pkt_size = (16 * 1024) - sizeof(struct cpl_rx_data) -
+ SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+
+ for (i = 0; i < SGE_QSETS; ++i) {
+ struct qset_params *q = p->qset + i;
+
+ q->polling = adap->params.rev > 0;
+ q->coalesce_usecs = 5;
+ q->rspq_size = 1024;
+ q->fl_size = 4096;
+ q->jumbo_size = 512;
+ q->txq_size[TXQ_ETH] = 1024;
+ q->txq_size[TXQ_OFLD] = 1024;
+ q->txq_size[TXQ_CTRL] = 256;
+ q->cong_thres = 0;
+ }
+
+ spin_lock_init(&adap->sge.reg_lock);
+}
+
+/**
+ * t3_get_desc - dump an SGE descriptor for debugging purposes
+ * @qs: the queue set
+ * @qnum: identifies the specific queue (0..2: Tx, 3:response, 4..5: Rx)
+ * @idx: the descriptor index in the queue
+ * @data: where to dump the descriptor contents
+ *
+ * Dumps the contents of a HW descriptor of an SGE queue. Returns the
+ * size of the descriptor.
+ */
+int t3_get_desc(const struct sge_qset *qs, unsigned int qnum, unsigned int idx,
+ unsigned char *data)
+{
+ if (qnum >= 6)
+ return -EINVAL;
+
+ if (qnum < 3) {
+ if (!qs->txq[qnum].desc || idx >= qs->txq[qnum].size)
+ return -EINVAL;
+ memcpy(data, &qs->txq[qnum].desc[idx], sizeof(struct tx_desc));
+ return sizeof(struct tx_desc);
+ }
+
+ if (qnum == 3) {
+ if (!qs->rspq.desc || idx >= qs->rspq.size)
+ return -EINVAL;
+ memcpy(data, &qs->rspq.desc[idx], sizeof(struct rsp_desc));
+ return sizeof(struct rsp_desc);
+ }
+
+ qnum -= 4;
+ if (!qs->fl[qnum].desc || idx >= qs->fl[qnum].size)
+ return -EINVAL;
+ memcpy(data, &qs->fl[qnum].desc[idx], sizeof(struct rx_desc));
+ return sizeof(struct rx_desc);
+}
diff --git a/drivers/net/cxgb3/sge_defs.h b/drivers/net/cxgb3/sge_defs.h
new file mode 100644
index 00000000000..514869e26a7
--- /dev/null
+++ b/drivers/net/cxgb3/sge_defs.h
@@ -0,0 +1,251 @@
+/*
+ * This file is automatically generated --- any changes will be lost.
+ */
+
+#ifndef _SGE_DEFS_H
+#define _SGE_DEFS_H
+
+#define S_EC_CREDITS 0
+#define M_EC_CREDITS 0x7FFF
+#define V_EC_CREDITS(x) ((x) << S_EC_CREDITS)
+#define G_EC_CREDITS(x) (((x) >> S_EC_CREDITS) & M_EC_CREDITS)
+
+#define S_EC_GTS 15
+#define V_EC_GTS(x) ((x) << S_EC_GTS)
+#define F_EC_GTS V_EC_GTS(1U)
+
+#define S_EC_INDEX 16
+#define M_EC_INDEX 0xFFFF
+#define V_EC_INDEX(x) ((x) << S_EC_INDEX)
+#define G_EC_INDEX(x) (((x) >> S_EC_INDEX) & M_EC_INDEX)
+
+#define S_EC_SIZE 0
+#define M_EC_SIZE 0xFFFF
+#define V_EC_SIZE(x) ((x) << S_EC_SIZE)
+#define G_EC_SIZE(x) (((x) >> S_EC_SIZE) & M_EC_SIZE)
+
+#define S_EC_BASE_LO 16
+#define M_EC_BASE_LO 0xFFFF
+#define V_EC_BASE_LO(x) ((x) << S_EC_BASE_LO)
+#define G_EC_BASE_LO(x) (((x) >> S_EC_BASE_LO) & M_EC_BASE_LO)
+
+#define S_EC_BASE_HI 0
+#define M_EC_BASE_HI 0xF
+#define V_EC_BASE_HI(x) ((x) << S_EC_BASE_HI)
+#define G_EC_BASE_HI(x) (((x) >> S_EC_BASE_HI) & M_EC_BASE_HI)
+
+#define S_EC_RESPQ 4
+#define M_EC_RESPQ 0x7
+#define V_EC_RESPQ(x) ((x) << S_EC_RESPQ)
+#define G_EC_RESPQ(x) (((x) >> S_EC_RESPQ) & M_EC_RESPQ)
+
+#define S_EC_TYPE 7
+#define M_EC_TYPE 0x7
+#define V_EC_TYPE(x) ((x) << S_EC_TYPE)
+#define G_EC_TYPE(x) (((x) >> S_EC_TYPE) & M_EC_TYPE)
+
+#define S_EC_GEN 10
+#define V_EC_GEN(x) ((x) << S_EC_GEN)
+#define F_EC_GEN V_EC_GEN(1U)
+
+#define S_EC_UP_TOKEN 11
+#define M_EC_UP_TOKEN 0xFFFFF
+#define V_EC_UP_TOKEN(x) ((x) << S_EC_UP_TOKEN)
+#define G_EC_UP_TOKEN(x) (((x) >> S_EC_UP_TOKEN) & M_EC_UP_TOKEN)
+
+#define S_EC_VALID 31
+#define V_EC_VALID(x) ((x) << S_EC_VALID)
+#define F_EC_VALID V_EC_VALID(1U)
+
+#define S_RQ_MSI_VEC 20
+#define M_RQ_MSI_VEC 0x3F
+#define V_RQ_MSI_VEC(x) ((x) << S_RQ_MSI_VEC)
+#define G_RQ_MSI_VEC(x) (((x) >> S_RQ_MSI_VEC) & M_RQ_MSI_VEC)
+
+#define S_RQ_INTR_EN 26
+#define V_RQ_INTR_EN(x) ((x) << S_RQ_INTR_EN)
+#define F_RQ_INTR_EN V_RQ_INTR_EN(1U)
+
+#define S_RQ_GEN 28
+#define V_RQ_GEN(x) ((x) << S_RQ_GEN)
+#define F_RQ_GEN V_RQ_GEN(1U)
+
+#define S_CQ_INDEX 0
+#define M_CQ_INDEX 0xFFFF
+#define V_CQ_INDEX(x) ((x) << S_CQ_INDEX)
+#define G_CQ_INDEX(x) (((x) >> S_CQ_INDEX) & M_CQ_INDEX)
+
+#define S_CQ_SIZE 16
+#define M_CQ_SIZE 0xFFFF
+#define V_CQ_SIZE(x) ((x) << S_CQ_SIZE)
+#define G_CQ_SIZE(x) (((x) >> S_CQ_SIZE) & M_CQ_SIZE)
+
+#define S_CQ_BASE_HI 0
+#define M_CQ_BASE_HI 0xFFFFF
+#define V_CQ_BASE_HI(x) ((x) << S_CQ_BASE_HI)
+#define G_CQ_BASE_HI(x) (((x) >> S_CQ_BASE_HI) & M_CQ_BASE_HI)
+
+#define S_CQ_RSPQ 20
+#define M_CQ_RSPQ 0x3F
+#define V_CQ_RSPQ(x) ((x) << S_CQ_RSPQ)
+#define G_CQ_RSPQ(x) (((x) >> S_CQ_RSPQ) & M_CQ_RSPQ)
+
+#define S_CQ_ASYNC_NOTIF 26
+#define V_CQ_ASYNC_NOTIF(x) ((x) << S_CQ_ASYNC_NOTIF)
+#define F_CQ_ASYNC_NOTIF V_CQ_ASYNC_NOTIF(1U)
+
+#define S_CQ_ARMED 27
+#define V_CQ_ARMED(x) ((x) << S_CQ_ARMED)
+#define F_CQ_ARMED V_CQ_ARMED(1U)
+
+#define S_CQ_ASYNC_NOTIF_SOL 28
+#define V_CQ_ASYNC_NOTIF_SOL(x) ((x) << S_CQ_ASYNC_NOTIF_SOL)
+#define F_CQ_ASYNC_NOTIF_SOL V_CQ_ASYNC_NOTIF_SOL(1U)
+
+#define S_CQ_GEN 29
+#define V_CQ_GEN(x) ((x) << S_CQ_GEN)
+#define F_CQ_GEN V_CQ_GEN(1U)
+
+#define S_CQ_OVERFLOW_MODE 31
+#define V_CQ_OVERFLOW_MODE(x) ((x) << S_CQ_OVERFLOW_MODE)
+#define F_CQ_OVERFLOW_MODE V_CQ_OVERFLOW_MODE(1U)
+
+#define S_CQ_CREDITS 0
+#define M_CQ_CREDITS 0xFFFF
+#define V_CQ_CREDITS(x) ((x) << S_CQ_CREDITS)
+#define G_CQ_CREDITS(x) (((x) >> S_CQ_CREDITS) & M_CQ_CREDITS)
+
+#define S_CQ_CREDIT_THRES 16
+#define M_CQ_CREDIT_THRES 0x1FFF
+#define V_CQ_CREDIT_THRES(x) ((x) << S_CQ_CREDIT_THRES)
+#define G_CQ_CREDIT_THRES(x) (((x) >> S_CQ_CREDIT_THRES) & M_CQ_CREDIT_THRES)
+
+#define S_FL_BASE_HI 0
+#define M_FL_BASE_HI 0xFFFFF
+#define V_FL_BASE_HI(x) ((x) << S_FL_BASE_HI)
+#define G_FL_BASE_HI(x) (((x) >> S_FL_BASE_HI) & M_FL_BASE_HI)
+
+#define S_FL_INDEX_LO 20
+#define M_FL_INDEX_LO 0xFFF
+#define V_FL_INDEX_LO(x) ((x) << S_FL_INDEX_LO)
+#define G_FL_INDEX_LO(x) (((x) >> S_FL_INDEX_LO) & M_FL_INDEX_LO)
+
+#define S_FL_INDEX_HI 0
+#define M_FL_INDEX_HI 0xF
+#define V_FL_INDEX_HI(x) ((x) << S_FL_INDEX_HI)
+#define G_FL_INDEX_HI(x) (((x) >> S_FL_INDEX_HI) & M_FL_INDEX_HI)
+
+#define S_FL_SIZE 4
+#define M_FL_SIZE 0xFFFF
+#define V_FL_SIZE(x) ((x) << S_FL_SIZE)
+#define G_FL_SIZE(x) (((x) >> S_FL_SIZE) & M_FL_SIZE)
+
+#define S_FL_GEN 20
+#define V_FL_GEN(x) ((x) << S_FL_GEN)
+#define F_FL_GEN V_FL_GEN(1U)
+
+#define S_FL_ENTRY_SIZE_LO 21
+#define M_FL_ENTRY_SIZE_LO 0x7FF
+#define V_FL_ENTRY_SIZE_LO(x) ((x) << S_FL_ENTRY_SIZE_LO)
+#define G_FL_ENTRY_SIZE_LO(x) (((x) >> S_FL_ENTRY_SIZE_LO) & M_FL_ENTRY_SIZE_LO)
+
+#define S_FL_ENTRY_SIZE_HI 0
+#define M_FL_ENTRY_SIZE_HI 0x1FFFFF
+#define V_FL_ENTRY_SIZE_HI(x) ((x) << S_FL_ENTRY_SIZE_HI)
+#define G_FL_ENTRY_SIZE_HI(x) (((x) >> S_FL_ENTRY_SIZE_HI) & M_FL_ENTRY_SIZE_HI)
+
+#define S_FL_CONG_THRES 21
+#define M_FL_CONG_THRES 0x3FF
+#define V_FL_CONG_THRES(x) ((x) << S_FL_CONG_THRES)
+#define G_FL_CONG_THRES(x) (((x) >> S_FL_CONG_THRES) & M_FL_CONG_THRES)
+
+#define S_FL_GTS 31
+#define V_FL_GTS(x) ((x) << S_FL_GTS)
+#define F_FL_GTS V_FL_GTS(1U)
+
+#define S_FLD_GEN1 31
+#define V_FLD_GEN1(x) ((x) << S_FLD_GEN1)
+#define F_FLD_GEN1 V_FLD_GEN1(1U)
+
+#define S_FLD_GEN2 0
+#define V_FLD_GEN2(x) ((x) << S_FLD_GEN2)
+#define F_FLD_GEN2 V_FLD_GEN2(1U)
+
+#define S_RSPD_TXQ1_CR 0
+#define M_RSPD_TXQ1_CR 0x7F
+#define V_RSPD_TXQ1_CR(x) ((x) << S_RSPD_TXQ1_CR)
+#define G_RSPD_TXQ1_CR(x) (((x) >> S_RSPD_TXQ1_CR) & M_RSPD_TXQ1_CR)
+
+#define S_RSPD_TXQ1_GTS 7
+#define V_RSPD_TXQ1_GTS(x) ((x) << S_RSPD_TXQ1_GTS)
+#define F_RSPD_TXQ1_GTS V_RSPD_TXQ1_GTS(1U)
+
+#define S_RSPD_TXQ2_CR 8
+#define M_RSPD_TXQ2_CR 0x7F
+#define V_RSPD_TXQ2_CR(x) ((x) << S_RSPD_TXQ2_CR)
+#define G_RSPD_TXQ2_CR(x) (((x) >> S_RSPD_TXQ2_CR) & M_RSPD_TXQ2_CR)
+
+#define S_RSPD_TXQ2_GTS 15
+#define V_RSPD_TXQ2_GTS(x) ((x) << S_RSPD_TXQ2_GTS)
+#define F_RSPD_TXQ2_GTS V_RSPD_TXQ2_GTS(1U)
+
+#define S_RSPD_TXQ0_CR 16
+#define M_RSPD_TXQ0_CR 0x7F
+#define V_RSPD_TXQ0_CR(x) ((x) << S_RSPD_TXQ0_CR)
+#define G_RSPD_TXQ0_CR(x) (((x) >> S_RSPD_TXQ0_CR) & M_RSPD_TXQ0_CR)
+
+#define S_RSPD_TXQ0_GTS 23
+#define V_RSPD_TXQ0_GTS(x) ((x) << S_RSPD_TXQ0_GTS)
+#define F_RSPD_TXQ0_GTS V_RSPD_TXQ0_GTS(1U)
+
+#define S_RSPD_EOP 24
+#define V_RSPD_EOP(x) ((x) << S_RSPD_EOP)
+#define F_RSPD_EOP V_RSPD_EOP(1U)
+
+#define S_RSPD_SOP 25
+#define V_RSPD_SOP(x) ((x) << S_RSPD_SOP)
+#define F_RSPD_SOP V_RSPD_SOP(1U)
+
+#define S_RSPD_ASYNC_NOTIF 26
+#define V_RSPD_ASYNC_NOTIF(x) ((x) << S_RSPD_ASYNC_NOTIF)
+#define F_RSPD_ASYNC_NOTIF V_RSPD_ASYNC_NOTIF(1U)
+
+#define S_RSPD_FL0_GTS 27
+#define V_RSPD_FL0_GTS(x) ((x) << S_RSPD_FL0_GTS)
+#define F_RSPD_FL0_GTS V_RSPD_FL0_GTS(1U)
+
+#define S_RSPD_FL1_GTS 28
+#define V_RSPD_FL1_GTS(x) ((x) << S_RSPD_FL1_GTS)
+#define F_RSPD_FL1_GTS V_RSPD_FL1_GTS(1U)
+
+#define S_RSPD_IMM_DATA_VALID 29
+#define V_RSPD_IMM_DATA_VALID(x) ((x) << S_RSPD_IMM_DATA_VALID)
+#define F_RSPD_IMM_DATA_VALID V_RSPD_IMM_DATA_VALID(1U)
+
+#define S_RSPD_OFFLOAD 30
+#define V_RSPD_OFFLOAD(x) ((x) << S_RSPD_OFFLOAD)
+#define F_RSPD_OFFLOAD V_RSPD_OFFLOAD(1U)
+
+#define S_RSPD_GEN1 31
+#define V_RSPD_GEN1(x) ((x) << S_RSPD_GEN1)
+#define F_RSPD_GEN1 V_RSPD_GEN1(1U)
+
+#define S_RSPD_LEN 0
+#define M_RSPD_LEN 0x7FFFFFFF
+#define V_RSPD_LEN(x) ((x) << S_RSPD_LEN)
+#define G_RSPD_LEN(x) (((x) >> S_RSPD_LEN) & M_RSPD_LEN)
+
+#define S_RSPD_FLQ 31
+#define V_RSPD_FLQ(x) ((x) << S_RSPD_FLQ)
+#define F_RSPD_FLQ V_RSPD_FLQ(1U)
+
+#define S_RSPD_GEN2 0
+#define V_RSPD_GEN2(x) ((x) << S_RSPD_GEN2)
+#define F_RSPD_GEN2 V_RSPD_GEN2(1U)
+
+#define S_RSPD_INR_VEC 1
+#define M_RSPD_INR_VEC 0x7F
+#define V_RSPD_INR_VEC(x) ((x) << S_RSPD_INR_VEC)
+#define G_RSPD_INR_VEC(x) (((x) >> S_RSPD_INR_VEC) & M_RSPD_INR_VEC)
+
+#endif /* _SGE_DEFS_H */
diff --git a/drivers/net/cxgb3/t3_cpl.h b/drivers/net/cxgb3/t3_cpl.h
new file mode 100644
index 00000000000..b7a1a310dfd
--- /dev/null
+++ b/drivers/net/cxgb3/t3_cpl.h
@@ -0,0 +1,1444 @@
+/*
+ * Copyright (c) 2004-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef T3_CPL_H
+#define T3_CPL_H
+
+#if !defined(__LITTLE_ENDIAN_BITFIELD) && !defined(__BIG_ENDIAN_BITFIELD)
+# include <asm/byteorder.h>
+#endif
+
+enum CPL_opcode {
+ CPL_PASS_OPEN_REQ = 0x1,
+ CPL_PASS_ACCEPT_RPL = 0x2,
+ CPL_ACT_OPEN_REQ = 0x3,
+ CPL_SET_TCB = 0x4,
+ CPL_SET_TCB_FIELD = 0x5,
+ CPL_GET_TCB = 0x6,
+ CPL_PCMD = 0x7,
+ CPL_CLOSE_CON_REQ = 0x8,
+ CPL_CLOSE_LISTSRV_REQ = 0x9,
+ CPL_ABORT_REQ = 0xA,
+ CPL_ABORT_RPL = 0xB,
+ CPL_TX_DATA = 0xC,
+ CPL_RX_DATA_ACK = 0xD,
+ CPL_TX_PKT = 0xE,
+ CPL_RTE_DELETE_REQ = 0xF,
+ CPL_RTE_WRITE_REQ = 0x10,
+ CPL_RTE_READ_REQ = 0x11,
+ CPL_L2T_WRITE_REQ = 0x12,
+ CPL_L2T_READ_REQ = 0x13,
+ CPL_SMT_WRITE_REQ = 0x14,
+ CPL_SMT_READ_REQ = 0x15,
+ CPL_TX_PKT_LSO = 0x16,
+ CPL_PCMD_READ = 0x17,
+ CPL_BARRIER = 0x18,
+ CPL_TID_RELEASE = 0x1A,
+
+ CPL_CLOSE_LISTSRV_RPL = 0x20,
+ CPL_ERROR = 0x21,
+ CPL_GET_TCB_RPL = 0x22,
+ CPL_L2T_WRITE_RPL = 0x23,
+ CPL_PCMD_READ_RPL = 0x24,
+ CPL_PCMD_RPL = 0x25,
+ CPL_PEER_CLOSE = 0x26,
+ CPL_RTE_DELETE_RPL = 0x27,
+ CPL_RTE_WRITE_RPL = 0x28,
+ CPL_RX_DDP_COMPLETE = 0x29,
+ CPL_RX_PHYS_ADDR = 0x2A,
+ CPL_RX_PKT = 0x2B,
+ CPL_RX_URG_NOTIFY = 0x2C,
+ CPL_SET_TCB_RPL = 0x2D,
+ CPL_SMT_WRITE_RPL = 0x2E,
+ CPL_TX_DATA_ACK = 0x2F,
+
+ CPL_ABORT_REQ_RSS = 0x30,
+ CPL_ABORT_RPL_RSS = 0x31,
+ CPL_CLOSE_CON_RPL = 0x32,
+ CPL_ISCSI_HDR = 0x33,
+ CPL_L2T_READ_RPL = 0x34,
+ CPL_RDMA_CQE = 0x35,
+ CPL_RDMA_CQE_READ_RSP = 0x36,
+ CPL_RDMA_CQE_ERR = 0x37,
+ CPL_RTE_READ_RPL = 0x38,
+ CPL_RX_DATA = 0x39,
+
+ CPL_ACT_OPEN_RPL = 0x40,
+ CPL_PASS_OPEN_RPL = 0x41,
+ CPL_RX_DATA_DDP = 0x42,
+ CPL_SMT_READ_RPL = 0x43,
+
+ CPL_ACT_ESTABLISH = 0x50,
+ CPL_PASS_ESTABLISH = 0x51,
+
+ CPL_PASS_ACCEPT_REQ = 0x70,
+
+ CPL_ASYNC_NOTIF = 0x80, /* fake opcode for async notifications */
+
+ CPL_TX_DMA_ACK = 0xA0,
+ CPL_RDMA_READ_REQ = 0xA1,
+ CPL_RDMA_TERMINATE = 0xA2,
+ CPL_TRACE_PKT = 0xA3,
+ CPL_RDMA_EC_STATUS = 0xA5,
+
+ NUM_CPL_CMDS /* must be last and previous entries must be sorted */
+};
+
+enum CPL_error {
+ CPL_ERR_NONE = 0,
+ CPL_ERR_TCAM_PARITY = 1,
+ CPL_ERR_TCAM_FULL = 3,
+ CPL_ERR_CONN_RESET = 20,
+ CPL_ERR_CONN_EXIST = 22,
+ CPL_ERR_ARP_MISS = 23,
+ CPL_ERR_BAD_SYN = 24,
+ CPL_ERR_CONN_TIMEDOUT = 30,
+ CPL_ERR_XMIT_TIMEDOUT = 31,
+ CPL_ERR_PERSIST_TIMEDOUT = 32,
+ CPL_ERR_FINWAIT2_TIMEDOUT = 33,
+ CPL_ERR_KEEPALIVE_TIMEDOUT = 34,
+ CPL_ERR_RTX_NEG_ADVICE = 35,
+ CPL_ERR_PERSIST_NEG_ADVICE = 36,
+ CPL_ERR_ABORT_FAILED = 42,
+ CPL_ERR_GENERAL = 99
+};
+
+enum {
+ CPL_CONN_POLICY_AUTO = 0,
+ CPL_CONN_POLICY_ASK = 1,
+ CPL_CONN_POLICY_DENY = 3
+};
+
+enum {
+ ULP_MODE_NONE = 0,
+ ULP_MODE_ISCSI = 2,
+ ULP_MODE_RDMA = 4,
+ ULP_MODE_TCPDDP = 5
+};
+
+enum {
+ ULP_CRC_HEADER = 1 << 0,
+ ULP_CRC_DATA = 1 << 1
+};
+
+enum {
+ CPL_PASS_OPEN_ACCEPT,
+ CPL_PASS_OPEN_REJECT
+};
+
+enum {
+ CPL_ABORT_SEND_RST = 0,
+ CPL_ABORT_NO_RST,
+ CPL_ABORT_POST_CLOSE_REQ = 2
+};
+
+enum { /* TX_PKT_LSO ethernet types */
+ CPL_ETH_II,
+ CPL_ETH_II_VLAN,
+ CPL_ETH_802_3,
+ CPL_ETH_802_3_VLAN
+};
+
+enum { /* TCP congestion control algorithms */
+ CONG_ALG_RENO,
+ CONG_ALG_TAHOE,
+ CONG_ALG_NEWRENO,
+ CONG_ALG_HIGHSPEED
+};
+
+union opcode_tid {
+ __be32 opcode_tid;
+ __u8 opcode;
+};
+
+#define S_OPCODE 24
+#define V_OPCODE(x) ((x) << S_OPCODE)
+#define G_OPCODE(x) (((x) >> S_OPCODE) & 0xFF)
+#define G_TID(x) ((x) & 0xFFFFFF)
+
+/* tid is assumed to be 24-bits */
+#define MK_OPCODE_TID(opcode, tid) (V_OPCODE(opcode) | (tid))
+
+#define OPCODE_TID(cmd) ((cmd)->ot.opcode_tid)
+
+/* extract the TID from a CPL command */
+#define GET_TID(cmd) (G_TID(ntohl(OPCODE_TID(cmd))))
+
+struct tcp_options {
+ __be16 mss;
+ __u8 wsf;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8:5;
+ __u8 ecn:1;
+ __u8 sack:1;
+ __u8 tstamp:1;
+#else
+ __u8 tstamp:1;
+ __u8 sack:1;
+ __u8 ecn:1;
+ __u8:5;
+#endif
+};
+
+struct rss_header {
+ __u8 opcode;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 cpu_idx:6;
+ __u8 hash_type:2;
+#else
+ __u8 hash_type:2;
+ __u8 cpu_idx:6;
+#endif
+ __be16 cq_idx;
+ __be32 rss_hash_val;
+};
+
+#ifndef CHELSIO_FW
+struct work_request_hdr {
+ __be32 wr_hi;
+ __be32 wr_lo;
+};
+
+/* wr_hi fields */
+#define S_WR_SGE_CREDITS 0
+#define M_WR_SGE_CREDITS 0xFF
+#define V_WR_SGE_CREDITS(x) ((x) << S_WR_SGE_CREDITS)
+#define G_WR_SGE_CREDITS(x) (((x) >> S_WR_SGE_CREDITS) & M_WR_SGE_CREDITS)
+
+#define S_WR_SGLSFLT 8
+#define M_WR_SGLSFLT 0xFF
+#define V_WR_SGLSFLT(x) ((x) << S_WR_SGLSFLT)
+#define G_WR_SGLSFLT(x) (((x) >> S_WR_SGLSFLT) & M_WR_SGLSFLT)
+
+#define S_WR_BCNTLFLT 16
+#define M_WR_BCNTLFLT 0xF
+#define V_WR_BCNTLFLT(x) ((x) << S_WR_BCNTLFLT)
+#define G_WR_BCNTLFLT(x) (((x) >> S_WR_BCNTLFLT) & M_WR_BCNTLFLT)
+
+#define S_WR_DATATYPE 20
+#define V_WR_DATATYPE(x) ((x) << S_WR_DATATYPE)
+#define F_WR_DATATYPE V_WR_DATATYPE(1U)
+
+#define S_WR_COMPL 21
+#define V_WR_COMPL(x) ((x) << S_WR_COMPL)
+#define F_WR_COMPL V_WR_COMPL(1U)
+
+#define S_WR_EOP 22
+#define V_WR_EOP(x) ((x) << S_WR_EOP)
+#define F_WR_EOP V_WR_EOP(1U)
+
+#define S_WR_SOP 23
+#define V_WR_SOP(x) ((x) << S_WR_SOP)
+#define F_WR_SOP V_WR_SOP(1U)
+
+#define S_WR_OP 24
+#define M_WR_OP 0xFF
+#define V_WR_OP(x) ((x) << S_WR_OP)
+#define G_WR_OP(x) (((x) >> S_WR_OP) & M_WR_OP)
+
+/* wr_lo fields */
+#define S_WR_LEN 0
+#define M_WR_LEN 0xFF
+#define V_WR_LEN(x) ((x) << S_WR_LEN)
+#define G_WR_LEN(x) (((x) >> S_WR_LEN) & M_WR_LEN)
+
+#define S_WR_TID 8
+#define M_WR_TID 0xFFFFF
+#define V_WR_TID(x) ((x) << S_WR_TID)
+#define G_WR_TID(x) (((x) >> S_WR_TID) & M_WR_TID)
+
+#define S_WR_CR_FLUSH 30
+#define V_WR_CR_FLUSH(x) ((x) << S_WR_CR_FLUSH)
+#define F_WR_CR_FLUSH V_WR_CR_FLUSH(1U)
+
+#define S_WR_GEN 31
+#define V_WR_GEN(x) ((x) << S_WR_GEN)
+#define F_WR_GEN V_WR_GEN(1U)
+
+# define WR_HDR struct work_request_hdr wr
+# define RSS_HDR
+#else
+# define WR_HDR
+# define RSS_HDR struct rss_header rss_hdr;
+#endif
+
+/* option 0 lower-half fields */
+#define S_CPL_STATUS 0
+#define M_CPL_STATUS 0xFF
+#define V_CPL_STATUS(x) ((x) << S_CPL_STATUS)
+#define G_CPL_STATUS(x) (((x) >> S_CPL_STATUS) & M_CPL_STATUS)
+
+#define S_INJECT_TIMER 6
+#define V_INJECT_TIMER(x) ((x) << S_INJECT_TIMER)
+#define F_INJECT_TIMER V_INJECT_TIMER(1U)
+
+#define S_NO_OFFLOAD 7
+#define V_NO_OFFLOAD(x) ((x) << S_NO_OFFLOAD)
+#define F_NO_OFFLOAD V_NO_OFFLOAD(1U)
+
+#define S_ULP_MODE 8
+#define M_ULP_MODE 0xF
+#define V_ULP_MODE(x) ((x) << S_ULP_MODE)
+#define G_ULP_MODE(x) (((x) >> S_ULP_MODE) & M_ULP_MODE)
+
+#define S_RCV_BUFSIZ 12
+#define M_RCV_BUFSIZ 0x3FFF
+#define V_RCV_BUFSIZ(x) ((x) << S_RCV_BUFSIZ)
+#define G_RCV_BUFSIZ(x) (((x) >> S_RCV_BUFSIZ) & M_RCV_BUFSIZ)
+
+#define S_TOS 26
+#define M_TOS 0x3F
+#define V_TOS(x) ((x) << S_TOS)
+#define G_TOS(x) (((x) >> S_TOS) & M_TOS)
+
+/* option 0 upper-half fields */
+#define S_DELACK 0
+#define V_DELACK(x) ((x) << S_DELACK)
+#define F_DELACK V_DELACK(1U)
+
+#define S_NO_CONG 1
+#define V_NO_CONG(x) ((x) << S_NO_CONG)
+#define F_NO_CONG V_NO_CONG(1U)
+
+#define S_SRC_MAC_SEL 2
+#define M_SRC_MAC_SEL 0x3
+#define V_SRC_MAC_SEL(x) ((x) << S_SRC_MAC_SEL)
+#define G_SRC_MAC_SEL(x) (((x) >> S_SRC_MAC_SEL) & M_SRC_MAC_SEL)
+
+#define S_L2T_IDX 4
+#define M_L2T_IDX 0x7FF
+#define V_L2T_IDX(x) ((x) << S_L2T_IDX)
+#define G_L2T_IDX(x) (((x) >> S_L2T_IDX) & M_L2T_IDX)
+
+#define S_TX_CHANNEL 15
+#define V_TX_CHANNEL(x) ((x) << S_TX_CHANNEL)
+#define F_TX_CHANNEL V_TX_CHANNEL(1U)
+
+#define S_TCAM_BYPASS 16
+#define V_TCAM_BYPASS(x) ((x) << S_TCAM_BYPASS)
+#define F_TCAM_BYPASS V_TCAM_BYPASS(1U)
+
+#define S_NAGLE 17
+#define V_NAGLE(x) ((x) << S_NAGLE)
+#define F_NAGLE V_NAGLE(1U)
+
+#define S_WND_SCALE 18
+#define M_WND_SCALE 0xF
+#define V_WND_SCALE(x) ((x) << S_WND_SCALE)
+#define G_WND_SCALE(x) (((x) >> S_WND_SCALE) & M_WND_SCALE)
+
+#define S_KEEP_ALIVE 22
+#define V_KEEP_ALIVE(x) ((x) << S_KEEP_ALIVE)
+#define F_KEEP_ALIVE V_KEEP_ALIVE(1U)
+
+#define S_MAX_RETRANS 23
+#define M_MAX_RETRANS 0xF
+#define V_MAX_RETRANS(x) ((x) << S_MAX_RETRANS)
+#define G_MAX_RETRANS(x) (((x) >> S_MAX_RETRANS) & M_MAX_RETRANS)
+
+#define S_MAX_RETRANS_OVERRIDE 27
+#define V_MAX_RETRANS_OVERRIDE(x) ((x) << S_MAX_RETRANS_OVERRIDE)
+#define F_MAX_RETRANS_OVERRIDE V_MAX_RETRANS_OVERRIDE(1U)
+
+#define S_MSS_IDX 28
+#define M_MSS_IDX 0xF
+#define V_MSS_IDX(x) ((x) << S_MSS_IDX)
+#define G_MSS_IDX(x) (((x) >> S_MSS_IDX) & M_MSS_IDX)
+
+/* option 1 fields */
+#define S_RSS_ENABLE 0
+#define V_RSS_ENABLE(x) ((x) << S_RSS_ENABLE)
+#define F_RSS_ENABLE V_RSS_ENABLE(1U)
+
+#define S_RSS_MASK_LEN 1
+#define M_RSS_MASK_LEN 0x7
+#define V_RSS_MASK_LEN(x) ((x) << S_RSS_MASK_LEN)
+#define G_RSS_MASK_LEN(x) (((x) >> S_RSS_MASK_LEN) & M_RSS_MASK_LEN)
+
+#define S_CPU_IDX 4
+#define M_CPU_IDX 0x3F
+#define V_CPU_IDX(x) ((x) << S_CPU_IDX)
+#define G_CPU_IDX(x) (((x) >> S_CPU_IDX) & M_CPU_IDX)
+
+#define S_MAC_MATCH_VALID 18
+#define V_MAC_MATCH_VALID(x) ((x) << S_MAC_MATCH_VALID)
+#define F_MAC_MATCH_VALID V_MAC_MATCH_VALID(1U)
+
+#define S_CONN_POLICY 19
+#define M_CONN_POLICY 0x3
+#define V_CONN_POLICY(x) ((x) << S_CONN_POLICY)
+#define G_CONN_POLICY(x) (((x) >> S_CONN_POLICY) & M_CONN_POLICY)
+
+#define S_SYN_DEFENSE 21
+#define V_SYN_DEFENSE(x) ((x) << S_SYN_DEFENSE)
+#define F_SYN_DEFENSE V_SYN_DEFENSE(1U)
+
+#define S_VLAN_PRI 22
+#define M_VLAN_PRI 0x3
+#define V_VLAN_PRI(x) ((x) << S_VLAN_PRI)
+#define G_VLAN_PRI(x) (((x) >> S_VLAN_PRI) & M_VLAN_PRI)
+
+#define S_VLAN_PRI_VALID 24
+#define V_VLAN_PRI_VALID(x) ((x) << S_VLAN_PRI_VALID)
+#define F_VLAN_PRI_VALID V_VLAN_PRI_VALID(1U)
+
+#define S_PKT_TYPE 25
+#define M_PKT_TYPE 0x3
+#define V_PKT_TYPE(x) ((x) << S_PKT_TYPE)
+#define G_PKT_TYPE(x) (((x) >> S_PKT_TYPE) & M_PKT_TYPE)
+
+#define S_MAC_MATCH 27
+#define M_MAC_MATCH 0x1F
+#define V_MAC_MATCH(x) ((x) << S_MAC_MATCH)
+#define G_MAC_MATCH(x) (((x) >> S_MAC_MATCH) & M_MAC_MATCH)
+
+/* option 2 fields */
+#define S_CPU_INDEX 0
+#define M_CPU_INDEX 0x7F
+#define V_CPU_INDEX(x) ((x) << S_CPU_INDEX)
+#define G_CPU_INDEX(x) (((x) >> S_CPU_INDEX) & M_CPU_INDEX)
+
+#define S_CPU_INDEX_VALID 7
+#define V_CPU_INDEX_VALID(x) ((x) << S_CPU_INDEX_VALID)
+#define F_CPU_INDEX_VALID V_CPU_INDEX_VALID(1U)
+
+#define S_RX_COALESCE 8
+#define M_RX_COALESCE 0x3
+#define V_RX_COALESCE(x) ((x) << S_RX_COALESCE)
+#define G_RX_COALESCE(x) (((x) >> S_RX_COALESCE) & M_RX_COALESCE)
+
+#define S_RX_COALESCE_VALID 10
+#define V_RX_COALESCE_VALID(x) ((x) << S_RX_COALESCE_VALID)
+#define F_RX_COALESCE_VALID V_RX_COALESCE_VALID(1U)
+
+#define S_CONG_CONTROL_FLAVOR 11
+#define M_CONG_CONTROL_FLAVOR 0x3
+#define V_CONG_CONTROL_FLAVOR(x) ((x) << S_CONG_CONTROL_FLAVOR)
+#define G_CONG_CONTROL_FLAVOR(x) (((x) >> S_CONG_CONTROL_FLAVOR) & M_CONG_CONTROL_FLAVOR)
+
+#define S_PACING_FLAVOR 13
+#define M_PACING_FLAVOR 0x3
+#define V_PACING_FLAVOR(x) ((x) << S_PACING_FLAVOR)
+#define G_PACING_FLAVOR(x) (((x) >> S_PACING_FLAVOR) & M_PACING_FLAVOR)
+
+#define S_FLAVORS_VALID 15
+#define V_FLAVORS_VALID(x) ((x) << S_FLAVORS_VALID)
+#define F_FLAVORS_VALID V_FLAVORS_VALID(1U)
+
+#define S_RX_FC_DISABLE 16
+#define V_RX_FC_DISABLE(x) ((x) << S_RX_FC_DISABLE)
+#define F_RX_FC_DISABLE V_RX_FC_DISABLE(1U)
+
+#define S_RX_FC_VALID 17
+#define V_RX_FC_VALID(x) ((x) << S_RX_FC_VALID)
+#define F_RX_FC_VALID V_RX_FC_VALID(1U)
+
+struct cpl_pass_open_req {
+ WR_HDR;
+ union opcode_tid ot;
+ __be16 local_port;
+ __be16 peer_port;
+ __be32 local_ip;
+ __be32 peer_ip;
+ __be32 opt0h;
+ __be32 opt0l;
+ __be32 peer_netmask;
+ __be32 opt1;
+};
+
+struct cpl_pass_open_rpl {
+ RSS_HDR union opcode_tid ot;
+ __be16 local_port;
+ __be16 peer_port;
+ __be32 local_ip;
+ __be32 peer_ip;
+ __u8 resvd[7];
+ __u8 status;
+};
+
+struct cpl_pass_establish {
+ RSS_HDR union opcode_tid ot;
+ __be16 local_port;
+ __be16 peer_port;
+ __be32 local_ip;
+ __be32 peer_ip;
+ __be32 tos_tid;
+ __be16 l2t_idx;
+ __be16 tcp_opt;
+ __be32 snd_isn;
+ __be32 rcv_isn;
+};
+
+/* cpl_pass_establish.tos_tid fields */
+#define S_PASS_OPEN_TID 0
+#define M_PASS_OPEN_TID 0xFFFFFF
+#define V_PASS_OPEN_TID(x) ((x) << S_PASS_OPEN_TID)
+#define G_PASS_OPEN_TID(x) (((x) >> S_PASS_OPEN_TID) & M_PASS_OPEN_TID)
+
+#define S_PASS_OPEN_TOS 24
+#define M_PASS_OPEN_TOS 0xFF
+#define V_PASS_OPEN_TOS(x) ((x) << S_PASS_OPEN_TOS)
+#define G_PASS_OPEN_TOS(x) (((x) >> S_PASS_OPEN_TOS) & M_PASS_OPEN_TOS)
+
+/* cpl_pass_establish.l2t_idx fields */
+#define S_L2T_IDX16 5
+#define M_L2T_IDX16 0x7FF
+#define V_L2T_IDX16(x) ((x) << S_L2T_IDX16)
+#define G_L2T_IDX16(x) (((x) >> S_L2T_IDX16) & M_L2T_IDX16)
+
+/* cpl_pass_establish.tcp_opt fields (also applies act_open_establish) */
+#define G_TCPOPT_WSCALE_OK(x) (((x) >> 5) & 1)
+#define G_TCPOPT_SACK(x) (((x) >> 6) & 1)
+#define G_TCPOPT_TSTAMP(x) (((x) >> 7) & 1)
+#define G_TCPOPT_SND_WSCALE(x) (((x) >> 8) & 0xf)
+#define G_TCPOPT_MSS(x) (((x) >> 12) & 0xf)
+
+struct cpl_pass_accept_req {
+ RSS_HDR union opcode_tid ot;
+ __be16 local_port;
+ __be16 peer_port;
+ __be32 local_ip;
+ __be32 peer_ip;
+ __be32 tos_tid;
+ struct tcp_options tcp_options;
+ __u8 dst_mac[6];
+ __be16 vlan_tag;
+ __u8 src_mac[6];
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8:3;
+ __u8 addr_idx:3;
+ __u8 port_idx:1;
+ __u8 exact_match:1;
+#else
+ __u8 exact_match:1;
+ __u8 port_idx:1;
+ __u8 addr_idx:3;
+ __u8:3;
+#endif
+ __u8 rsvd;
+ __be32 rcv_isn;
+ __be32 rsvd2;
+};
+
+struct cpl_pass_accept_rpl {
+ WR_HDR;
+ union opcode_tid ot;
+ __be32 opt2;
+ __be32 rsvd;
+ __be32 peer_ip;
+ __be32 opt0h;
+ __be32 opt0l_status;
+};
+
+struct cpl_act_open_req {
+ WR_HDR;
+ union opcode_tid ot;
+ __be16 local_port;
+ __be16 peer_port;
+ __be32 local_ip;
+ __be32 peer_ip;
+ __be32 opt0h;
+ __be32 opt0l;
+ __be32 params;
+ __be32 opt2;
+};
+
+/* cpl_act_open_req.params fields */
+#define S_AOPEN_VLAN_PRI 9
+#define M_AOPEN_VLAN_PRI 0x3
+#define V_AOPEN_VLAN_PRI(x) ((x) << S_AOPEN_VLAN_PRI)
+#define G_AOPEN_VLAN_PRI(x) (((x) >> S_AOPEN_VLAN_PRI) & M_AOPEN_VLAN_PRI)
+
+#define S_AOPEN_VLAN_PRI_VALID 11
+#define V_AOPEN_VLAN_PRI_VALID(x) ((x) << S_AOPEN_VLAN_PRI_VALID)
+#define F_AOPEN_VLAN_PRI_VALID V_AOPEN_VLAN_PRI_VALID(1U)
+
+#define S_AOPEN_PKT_TYPE 12
+#define M_AOPEN_PKT_TYPE 0x3
+#define V_AOPEN_PKT_TYPE(x) ((x) << S_AOPEN_PKT_TYPE)
+#define G_AOPEN_PKT_TYPE(x) (((x) >> S_AOPEN_PKT_TYPE) & M_AOPEN_PKT_TYPE)
+
+#define S_AOPEN_MAC_MATCH 14
+#define M_AOPEN_MAC_MATCH 0x1F
+#define V_AOPEN_MAC_MATCH(x) ((x) << S_AOPEN_MAC_MATCH)
+#define G_AOPEN_MAC_MATCH(x) (((x) >> S_AOPEN_MAC_MATCH) & M_AOPEN_MAC_MATCH)
+
+#define S_AOPEN_MAC_MATCH_VALID 19
+#define V_AOPEN_MAC_MATCH_VALID(x) ((x) << S_AOPEN_MAC_MATCH_VALID)
+#define F_AOPEN_MAC_MATCH_VALID V_AOPEN_MAC_MATCH_VALID(1U)
+
+#define S_AOPEN_IFF_VLAN 20
+#define M_AOPEN_IFF_VLAN 0xFFF
+#define V_AOPEN_IFF_VLAN(x) ((x) << S_AOPEN_IFF_VLAN)
+#define G_AOPEN_IFF_VLAN(x) (((x) >> S_AOPEN_IFF_VLAN) & M_AOPEN_IFF_VLAN)
+
+struct cpl_act_open_rpl {
+ RSS_HDR union opcode_tid ot;
+ __be16 local_port;
+ __be16 peer_port;
+ __be32 local_ip;
+ __be32 peer_ip;
+ __be32 atid;
+ __u8 rsvd[3];
+ __u8 status;
+};
+
+struct cpl_act_establish {
+ RSS_HDR union opcode_tid ot;
+ __be16 local_port;
+ __be16 peer_port;
+ __be32 local_ip;
+ __be32 peer_ip;
+ __be32 tos_tid;
+ __be16 l2t_idx;
+ __be16 tcp_opt;
+ __be32 snd_isn;
+ __be32 rcv_isn;
+};
+
+struct cpl_get_tcb {
+ WR_HDR;
+ union opcode_tid ot;
+ __be16 cpuno;
+ __be16 rsvd;
+};
+
+struct cpl_get_tcb_rpl {
+ RSS_HDR union opcode_tid ot;
+ __u8 rsvd;
+ __u8 status;
+ __be16 len;
+};
+
+struct cpl_set_tcb {
+ WR_HDR;
+ union opcode_tid ot;
+ __u8 reply;
+ __u8 cpu_idx;
+ __be16 len;
+};
+
+/* cpl_set_tcb.reply fields */
+#define S_NO_REPLY 7
+#define V_NO_REPLY(x) ((x) << S_NO_REPLY)
+#define F_NO_REPLY V_NO_REPLY(1U)
+
+struct cpl_set_tcb_field {
+ WR_HDR;
+ union opcode_tid ot;
+ __u8 reply;
+ __u8 cpu_idx;
+ __be16 word;
+ __be64 mask;
+ __be64 val;
+};
+
+struct cpl_set_tcb_rpl {
+ RSS_HDR union opcode_tid ot;
+ __u8 rsvd[3];
+ __u8 status;
+};
+
+struct cpl_pcmd {
+ WR_HDR;
+ union opcode_tid ot;
+ __u8 rsvd[3];
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 src:1;
+ __u8 bundle:1;
+ __u8 channel:1;
+ __u8:5;
+#else
+ __u8:5;
+ __u8 channel:1;
+ __u8 bundle:1;
+ __u8 src:1;
+#endif
+ __be32 pcmd_parm[2];
+};
+
+struct cpl_pcmd_reply {
+ RSS_HDR union opcode_tid ot;
+ __u8 status;
+ __u8 rsvd;
+ __be16 len;
+};
+
+struct cpl_close_con_req {
+ WR_HDR;
+ union opcode_tid ot;
+ __be32 rsvd;
+};
+
+struct cpl_close_con_rpl {
+ RSS_HDR union opcode_tid ot;
+ __u8 rsvd[3];
+ __u8 status;
+ __be32 snd_nxt;
+ __be32 rcv_nxt;
+};
+
+struct cpl_close_listserv_req {
+ WR_HDR;
+ union opcode_tid ot;
+ __u8 rsvd0;
+ __u8 cpu_idx;
+ __be16 rsvd1;
+};
+
+struct cpl_close_listserv_rpl {
+ RSS_HDR union opcode_tid ot;
+ __u8 rsvd[3];
+ __u8 status;
+};
+
+struct cpl_abort_req_rss {
+ RSS_HDR union opcode_tid ot;
+ __be32 rsvd0;
+ __u8 rsvd1;
+ __u8 status;
+ __u8 rsvd2[6];
+};
+
+struct cpl_abort_req {
+ WR_HDR;
+ union opcode_tid ot;
+ __be32 rsvd0;
+ __u8 rsvd1;
+ __u8 cmd;
+ __u8 rsvd2[6];
+};
+
+struct cpl_abort_rpl_rss {
+ RSS_HDR union opcode_tid ot;
+ __be32 rsvd0;
+ __u8 rsvd1;
+ __u8 status;
+ __u8 rsvd2[6];
+};
+
+struct cpl_abort_rpl {
+ WR_HDR;
+ union opcode_tid ot;
+ __be32 rsvd0;
+ __u8 rsvd1;
+ __u8 cmd;
+ __u8 rsvd2[6];
+};
+
+struct cpl_peer_close {
+ RSS_HDR union opcode_tid ot;
+ __be32 rcv_nxt;
+};
+
+struct tx_data_wr {
+ __be32 wr_hi;
+ __be32 wr_lo;
+ __be32 len;
+ __be32 flags;
+ __be32 sndseq;
+ __be32 param;
+};
+
+/* tx_data_wr.param fields */
+#define S_TX_PORT 0
+#define M_TX_PORT 0x7
+#define V_TX_PORT(x) ((x) << S_TX_PORT)
+#define G_TX_PORT(x) (((x) >> S_TX_PORT) & M_TX_PORT)
+
+#define S_TX_MSS 4
+#define M_TX_MSS 0xF
+#define V_TX_MSS(x) ((x) << S_TX_MSS)
+#define G_TX_MSS(x) (((x) >> S_TX_MSS) & M_TX_MSS)
+
+#define S_TX_QOS 8
+#define M_TX_QOS 0xFF
+#define V_TX_QOS(x) ((x) << S_TX_QOS)
+#define G_TX_QOS(x) (((x) >> S_TX_QOS) & M_TX_QOS)
+
+#define S_TX_SNDBUF 16
+#define M_TX_SNDBUF 0xFFFF
+#define V_TX_SNDBUF(x) ((x) << S_TX_SNDBUF)
+#define G_TX_SNDBUF(x) (((x) >> S_TX_SNDBUF) & M_TX_SNDBUF)
+
+struct cpl_tx_data {
+ union opcode_tid ot;
+ __be32 len;
+ __be32 rsvd;
+ __be16 urg;
+ __be16 flags;
+};
+
+/* cpl_tx_data.flags fields */
+#define S_TX_ULP_SUBMODE 6
+#define M_TX_ULP_SUBMODE 0xF
+#define V_TX_ULP_SUBMODE(x) ((x) << S_TX_ULP_SUBMODE)
+#define G_TX_ULP_SUBMODE(x) (((x) >> S_TX_ULP_SUBMODE) & M_TX_ULP_SUBMODE)
+
+#define S_TX_ULP_MODE 10
+#define M_TX_ULP_MODE 0xF
+#define V_TX_ULP_MODE(x) ((x) << S_TX_ULP_MODE)
+#define G_TX_ULP_MODE(x) (((x) >> S_TX_ULP_MODE) & M_TX_ULP_MODE)
+
+#define S_TX_SHOVE 14
+#define V_TX_SHOVE(x) ((x) << S_TX_SHOVE)
+#define F_TX_SHOVE V_TX_SHOVE(1U)
+
+#define S_TX_MORE 15
+#define V_TX_MORE(x) ((x) << S_TX_MORE)
+#define F_TX_MORE V_TX_MORE(1U)
+
+/* additional tx_data_wr.flags fields */
+#define S_TX_CPU_IDX 0
+#define M_TX_CPU_IDX 0x3F
+#define V_TX_CPU_IDX(x) ((x) << S_TX_CPU_IDX)
+#define G_TX_CPU_IDX(x) (((x) >> S_TX_CPU_IDX) & M_TX_CPU_IDX)
+
+#define S_TX_URG 16
+#define V_TX_URG(x) ((x) << S_TX_URG)
+#define F_TX_URG V_TX_URG(1U)
+
+#define S_TX_CLOSE 17
+#define V_TX_CLOSE(x) ((x) << S_TX_CLOSE)
+#define F_TX_CLOSE V_TX_CLOSE(1U)
+
+#define S_TX_INIT 18
+#define V_TX_INIT(x) ((x) << S_TX_INIT)
+#define F_TX_INIT V_TX_INIT(1U)
+
+#define S_TX_IMM_ACK 19
+#define V_TX_IMM_ACK(x) ((x) << S_TX_IMM_ACK)
+#define F_TX_IMM_ACK V_TX_IMM_ACK(1U)
+
+#define S_TX_IMM_DMA 20
+#define V_TX_IMM_DMA(x) ((x) << S_TX_IMM_DMA)
+#define F_TX_IMM_DMA V_TX_IMM_DMA(1U)
+
+struct cpl_tx_data_ack {
+ RSS_HDR union opcode_tid ot;
+ __be32 ack_seq;
+};
+
+struct cpl_wr_ack {
+ RSS_HDR union opcode_tid ot;
+ __be16 credits;
+ __be16 rsvd;
+ __be32 snd_nxt;
+ __be32 snd_una;
+};
+
+struct cpl_rdma_ec_status {
+ RSS_HDR union opcode_tid ot;
+ __u8 rsvd[3];
+ __u8 status;
+};
+
+struct mngt_pktsched_wr {
+ __be32 wr_hi;
+ __be32 wr_lo;
+ __u8 mngt_opcode;
+ __u8 rsvd[7];
+ __u8 sched;
+ __u8 idx;
+ __u8 min;
+ __u8 max;
+ __u8 binding;
+ __u8 rsvd1[3];
+};
+
+struct cpl_iscsi_hdr {
+ RSS_HDR union opcode_tid ot;
+ __be16 pdu_len_ddp;
+ __be16 len;
+ __be32 seq;
+ __be16 urg;
+ __u8 rsvd;
+ __u8 status;
+};
+
+/* cpl_iscsi_hdr.pdu_len_ddp fields */
+#define S_ISCSI_PDU_LEN 0
+#define M_ISCSI_PDU_LEN 0x7FFF
+#define V_ISCSI_PDU_LEN(x) ((x) << S_ISCSI_PDU_LEN)
+#define G_ISCSI_PDU_LEN(x) (((x) >> S_ISCSI_PDU_LEN) & M_ISCSI_PDU_LEN)
+
+#define S_ISCSI_DDP 15
+#define V_ISCSI_DDP(x) ((x) << S_ISCSI_DDP)
+#define F_ISCSI_DDP V_ISCSI_DDP(1U)
+
+struct cpl_rx_data {
+ RSS_HDR union opcode_tid ot;
+ __be16 rsvd;
+ __be16 len;
+ __be32 seq;
+ __be16 urg;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 dack_mode:2;
+ __u8 psh:1;
+ __u8 heartbeat:1;
+ __u8:4;
+#else
+ __u8:4;
+ __u8 heartbeat:1;
+ __u8 psh:1;
+ __u8 dack_mode:2;
+#endif
+ __u8 status;
+};
+
+struct cpl_rx_data_ack {
+ WR_HDR;
+ union opcode_tid ot;
+ __be32 credit_dack;
+};
+
+/* cpl_rx_data_ack.ack_seq fields */
+#define S_RX_CREDITS 0
+#define M_RX_CREDITS 0x7FFFFFF
+#define V_RX_CREDITS(x) ((x) << S_RX_CREDITS)
+#define G_RX_CREDITS(x) (((x) >> S_RX_CREDITS) & M_RX_CREDITS)
+
+#define S_RX_MODULATE 27
+#define V_RX_MODULATE(x) ((x) << S_RX_MODULATE)
+#define F_RX_MODULATE V_RX_MODULATE(1U)
+
+#define S_RX_FORCE_ACK 28
+#define V_RX_FORCE_ACK(x) ((x) << S_RX_FORCE_ACK)
+#define F_RX_FORCE_ACK V_RX_FORCE_ACK(1U)
+
+#define S_RX_DACK_MODE 29
+#define M_RX_DACK_MODE 0x3
+#define V_RX_DACK_MODE(x) ((x) << S_RX_DACK_MODE)
+#define G_RX_DACK_MODE(x) (((x) >> S_RX_DACK_MODE) & M_RX_DACK_MODE)
+
+#define S_RX_DACK_CHANGE 31
+#define V_RX_DACK_CHANGE(x) ((x) << S_RX_DACK_CHANGE)
+#define F_RX_DACK_CHANGE V_RX_DACK_CHANGE(1U)
+
+struct cpl_rx_urg_notify {
+ RSS_HDR union opcode_tid ot;
+ __be32 seq;
+};
+
+struct cpl_rx_ddp_complete {
+ RSS_HDR union opcode_tid ot;
+ __be32 ddp_report;
+};
+
+struct cpl_rx_data_ddp {
+ RSS_HDR union opcode_tid ot;
+ __be16 urg;
+ __be16 len;
+ __be32 seq;
+ union {
+ __be32 nxt_seq;
+ __be32 ddp_report;
+ };
+ __be32 ulp_crc;
+ __be32 ddpvld_status;
+};
+
+/* cpl_rx_data_ddp.ddpvld_status fields */
+#define S_DDP_STATUS 0
+#define M_DDP_STATUS 0xFF
+#define V_DDP_STATUS(x) ((x) << S_DDP_STATUS)
+#define G_DDP_STATUS(x) (((x) >> S_DDP_STATUS) & M_DDP_STATUS)
+
+#define S_DDP_VALID 15
+#define M_DDP_VALID 0x1FFFF
+#define V_DDP_VALID(x) ((x) << S_DDP_VALID)
+#define G_DDP_VALID(x) (((x) >> S_DDP_VALID) & M_DDP_VALID)
+
+#define S_DDP_PPOD_MISMATCH 15
+#define V_DDP_PPOD_MISMATCH(x) ((x) << S_DDP_PPOD_MISMATCH)
+#define F_DDP_PPOD_MISMATCH V_DDP_PPOD_MISMATCH(1U)
+
+#define S_DDP_PDU 16
+#define V_DDP_PDU(x) ((x) << S_DDP_PDU)
+#define F_DDP_PDU V_DDP_PDU(1U)
+
+#define S_DDP_LLIMIT_ERR 17
+#define V_DDP_LLIMIT_ERR(x) ((x) << S_DDP_LLIMIT_ERR)
+#define F_DDP_LLIMIT_ERR V_DDP_LLIMIT_ERR(1U)
+
+#define S_DDP_PPOD_PARITY_ERR 18
+#define V_DDP_PPOD_PARITY_ERR(x) ((x) << S_DDP_PPOD_PARITY_ERR)
+#define F_DDP_PPOD_PARITY_ERR V_DDP_PPOD_PARITY_ERR(1U)
+
+#define S_DDP_PADDING_ERR 19
+#define V_DDP_PADDING_ERR(x) ((x) << S_DDP_PADDING_ERR)
+#define F_DDP_PADDING_ERR V_DDP_PADDING_ERR(1U)
+
+#define S_DDP_HDRCRC_ERR 20
+#define V_DDP_HDRCRC_ERR(x) ((x) << S_DDP_HDRCRC_ERR)
+#define F_DDP_HDRCRC_ERR V_DDP_HDRCRC_ERR(1U)
+
+#define S_DDP_DATACRC_ERR 21
+#define V_DDP_DATACRC_ERR(x) ((x) << S_DDP_DATACRC_ERR)
+#define F_DDP_DATACRC_ERR V_DDP_DATACRC_ERR(1U)
+
+#define S_DDP_INVALID_TAG 22
+#define V_DDP_INVALID_TAG(x) ((x) << S_DDP_INVALID_TAG)
+#define F_DDP_INVALID_TAG V_DDP_INVALID_TAG(1U)
+
+#define S_DDP_ULIMIT_ERR 23
+#define V_DDP_ULIMIT_ERR(x) ((x) << S_DDP_ULIMIT_ERR)
+#define F_DDP_ULIMIT_ERR V_DDP_ULIMIT_ERR(1U)
+
+#define S_DDP_OFFSET_ERR 24
+#define V_DDP_OFFSET_ERR(x) ((x) << S_DDP_OFFSET_ERR)
+#define F_DDP_OFFSET_ERR V_DDP_OFFSET_ERR(1U)
+
+#define S_DDP_COLOR_ERR 25
+#define V_DDP_COLOR_ERR(x) ((x) << S_DDP_COLOR_ERR)
+#define F_DDP_COLOR_ERR V_DDP_COLOR_ERR(1U)
+
+#define S_DDP_TID_MISMATCH 26
+#define V_DDP_TID_MISMATCH(x) ((x) << S_DDP_TID_MISMATCH)
+#define F_DDP_TID_MISMATCH V_DDP_TID_MISMATCH(1U)
+
+#define S_DDP_INVALID_PPOD 27
+#define V_DDP_INVALID_PPOD(x) ((x) << S_DDP_INVALID_PPOD)
+#define F_DDP_INVALID_PPOD V_DDP_INVALID_PPOD(1U)
+
+#define S_DDP_ULP_MODE 28
+#define M_DDP_ULP_MODE 0xF
+#define V_DDP_ULP_MODE(x) ((x) << S_DDP_ULP_MODE)
+#define G_DDP_ULP_MODE(x) (((x) >> S_DDP_ULP_MODE) & M_DDP_ULP_MODE)
+
+/* cpl_rx_data_ddp.ddp_report fields */
+#define S_DDP_OFFSET 0
+#define M_DDP_OFFSET 0x3FFFFF
+#define V_DDP_OFFSET(x) ((x) << S_DDP_OFFSET)
+#define G_DDP_OFFSET(x) (((x) >> S_DDP_OFFSET) & M_DDP_OFFSET)
+
+#define S_DDP_URG 24
+#define V_DDP_URG(x) ((x) << S_DDP_URG)
+#define F_DDP_URG V_DDP_URG(1U)
+
+#define S_DDP_PSH 25
+#define V_DDP_PSH(x) ((x) << S_DDP_PSH)
+#define F_DDP_PSH V_DDP_PSH(1U)
+
+#define S_DDP_BUF_COMPLETE 26
+#define V_DDP_BUF_COMPLETE(x) ((x) << S_DDP_BUF_COMPLETE)
+#define F_DDP_BUF_COMPLETE V_DDP_BUF_COMPLETE(1U)
+
+#define S_DDP_BUF_TIMED_OUT 27
+#define V_DDP_BUF_TIMED_OUT(x) ((x) << S_DDP_BUF_TIMED_OUT)
+#define F_DDP_BUF_TIMED_OUT V_DDP_BUF_TIMED_OUT(1U)
+
+#define S_DDP_BUF_IDX 28
+#define V_DDP_BUF_IDX(x) ((x) << S_DDP_BUF_IDX)
+#define F_DDP_BUF_IDX V_DDP_BUF_IDX(1U)
+
+struct cpl_tx_pkt {
+ WR_HDR;
+ __be32 cntrl;
+ __be32 len;
+};
+
+struct cpl_tx_pkt_lso {
+ WR_HDR;
+ __be32 cntrl;
+ __be32 len;
+
+ __be32 rsvd;
+ __be32 lso_info;
+};
+
+/* cpl_tx_pkt*.cntrl fields */
+#define S_TXPKT_VLAN 0
+#define M_TXPKT_VLAN 0xFFFF
+#define V_TXPKT_VLAN(x) ((x) << S_TXPKT_VLAN)
+#define G_TXPKT_VLAN(x) (((x) >> S_TXPKT_VLAN) & M_TXPKT_VLAN)
+
+#define S_TXPKT_INTF 16
+#define M_TXPKT_INTF 0xF
+#define V_TXPKT_INTF(x) ((x) << S_TXPKT_INTF)
+#define G_TXPKT_INTF(x) (((x) >> S_TXPKT_INTF) & M_TXPKT_INTF)
+
+#define S_TXPKT_IPCSUM_DIS 20
+#define V_TXPKT_IPCSUM_DIS(x) ((x) << S_TXPKT_IPCSUM_DIS)
+#define F_TXPKT_IPCSUM_DIS V_TXPKT_IPCSUM_DIS(1U)
+
+#define S_TXPKT_L4CSUM_DIS 21
+#define V_TXPKT_L4CSUM_DIS(x) ((x) << S_TXPKT_L4CSUM_DIS)
+#define F_TXPKT_L4CSUM_DIS V_TXPKT_L4CSUM_DIS(1U)
+
+#define S_TXPKT_VLAN_VLD 22
+#define V_TXPKT_VLAN_VLD(x) ((x) << S_TXPKT_VLAN_VLD)
+#define F_TXPKT_VLAN_VLD V_TXPKT_VLAN_VLD(1U)
+
+#define S_TXPKT_LOOPBACK 23
+#define V_TXPKT_LOOPBACK(x) ((x) << S_TXPKT_LOOPBACK)
+#define F_TXPKT_LOOPBACK V_TXPKT_LOOPBACK(1U)
+
+#define S_TXPKT_OPCODE 24
+#define M_TXPKT_OPCODE 0xFF
+#define V_TXPKT_OPCODE(x) ((x) << S_TXPKT_OPCODE)
+#define G_TXPKT_OPCODE(x) (((x) >> S_TXPKT_OPCODE) & M_TXPKT_OPCODE)
+
+/* cpl_tx_pkt_lso.lso_info fields */
+#define S_LSO_MSS 0
+#define M_LSO_MSS 0x3FFF
+#define V_LSO_MSS(x) ((x) << S_LSO_MSS)
+#define G_LSO_MSS(x) (((x) >> S_LSO_MSS) & M_LSO_MSS)
+
+#define S_LSO_ETH_TYPE 14
+#define M_LSO_ETH_TYPE 0x3
+#define V_LSO_ETH_TYPE(x) ((x) << S_LSO_ETH_TYPE)
+#define G_LSO_ETH_TYPE(x) (((x) >> S_LSO_ETH_TYPE) & M_LSO_ETH_TYPE)
+
+#define S_LSO_TCPHDR_WORDS 16
+#define M_LSO_TCPHDR_WORDS 0xF
+#define V_LSO_TCPHDR_WORDS(x) ((x) << S_LSO_TCPHDR_WORDS)
+#define G_LSO_TCPHDR_WORDS(x) (((x) >> S_LSO_TCPHDR_WORDS) & M_LSO_TCPHDR_WORDS)
+
+#define S_LSO_IPHDR_WORDS 20
+#define M_LSO_IPHDR_WORDS 0xF
+#define V_LSO_IPHDR_WORDS(x) ((x) << S_LSO_IPHDR_WORDS)
+#define G_LSO_IPHDR_WORDS(x) (((x) >> S_LSO_IPHDR_WORDS) & M_LSO_IPHDR_WORDS)
+
+#define S_LSO_IPV6 24
+#define V_LSO_IPV6(x) ((x) << S_LSO_IPV6)
+#define F_LSO_IPV6 V_LSO_IPV6(1U)
+
+struct cpl_trace_pkt {
+#ifdef CHELSIO_FW
+ __u8 rss_opcode;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 err:1;
+ __u8:7;
+#else
+ __u8:7;
+ __u8 err:1;
+#endif
+ __u8 rsvd0;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 qid:4;
+ __u8:4;
+#else
+ __u8:4;
+ __u8 qid:4;
+#endif
+ __be32 tstamp;
+#endif /* CHELSIO_FW */
+
+ __u8 opcode;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 iff:4;
+ __u8:4;
+#else
+ __u8:4;
+ __u8 iff:4;
+#endif
+ __u8 rsvd[4];
+ __be16 len;
+};
+
+struct cpl_rx_pkt {
+ RSS_HDR __u8 opcode;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 iff:4;
+ __u8 csum_valid:1;
+ __u8 ipmi_pkt:1;
+ __u8 vlan_valid:1;
+ __u8 fragment:1;
+#else
+ __u8 fragment:1;
+ __u8 vlan_valid:1;
+ __u8 ipmi_pkt:1;
+ __u8 csum_valid:1;
+ __u8 iff:4;
+#endif
+ __be16 csum;
+ __be16 vlan;
+ __be16 len;
+};
+
+struct cpl_l2t_write_req {
+ WR_HDR;
+ union opcode_tid ot;
+ __be32 params;
+ __u8 rsvd[2];
+ __u8 dst_mac[6];
+};
+
+/* cpl_l2t_write_req.params fields */
+#define S_L2T_W_IDX 0
+#define M_L2T_W_IDX 0x7FF
+#define V_L2T_W_IDX(x) ((x) << S_L2T_W_IDX)
+#define G_L2T_W_IDX(x) (((x) >> S_L2T_W_IDX) & M_L2T_W_IDX)
+
+#define S_L2T_W_VLAN 11
+#define M_L2T_W_VLAN 0xFFF
+#define V_L2T_W_VLAN(x) ((x) << S_L2T_W_VLAN)
+#define G_L2T_W_VLAN(x) (((x) >> S_L2T_W_VLAN) & M_L2T_W_VLAN)
+
+#define S_L2T_W_IFF 23
+#define M_L2T_W_IFF 0xF
+#define V_L2T_W_IFF(x) ((x) << S_L2T_W_IFF)
+#define G_L2T_W_IFF(x) (((x) >> S_L2T_W_IFF) & M_L2T_W_IFF)
+
+#define S_L2T_W_PRIO 27
+#define M_L2T_W_PRIO 0x7
+#define V_L2T_W_PRIO(x) ((x) << S_L2T_W_PRIO)
+#define G_L2T_W_PRIO(x) (((x) >> S_L2T_W_PRIO) & M_L2T_W_PRIO)
+
+struct cpl_l2t_write_rpl {
+ RSS_HDR union opcode_tid ot;
+ __u8 status;
+ __u8 rsvd[3];
+};
+
+struct cpl_l2t_read_req {
+ WR_HDR;
+ union opcode_tid ot;
+ __be16 rsvd;
+ __be16 l2t_idx;
+};
+
+struct cpl_l2t_read_rpl {
+ RSS_HDR union opcode_tid ot;
+ __be32 params;
+ __u8 rsvd[2];
+ __u8 dst_mac[6];
+};
+
+/* cpl_l2t_read_rpl.params fields */
+#define S_L2T_R_PRIO 0
+#define M_L2T_R_PRIO 0x7
+#define V_L2T_R_PRIO(x) ((x) << S_L2T_R_PRIO)
+#define G_L2T_R_PRIO(x) (((x) >> S_L2T_R_PRIO) & M_L2T_R_PRIO)
+
+#define S_L2T_R_VLAN 8
+#define M_L2T_R_VLAN 0xFFF
+#define V_L2T_R_VLAN(x) ((x) << S_L2T_R_VLAN)
+#define G_L2T_R_VLAN(x) (((x) >> S_L2T_R_VLAN) & M_L2T_R_VLAN)
+
+#define S_L2T_R_IFF 20
+#define M_L2T_R_IFF 0xF
+#define V_L2T_R_IFF(x) ((x) << S_L2T_R_IFF)
+#define G_L2T_R_IFF(x) (((x) >> S_L2T_R_IFF) & M_L2T_R_IFF)
+
+#define S_L2T_STATUS 24
+#define M_L2T_STATUS 0xFF
+#define V_L2T_STATUS(x) ((x) << S_L2T_STATUS)
+#define G_L2T_STATUS(x) (((x) >> S_L2T_STATUS) & M_L2T_STATUS)
+
+struct cpl_smt_write_req {
+ WR_HDR;
+ union opcode_tid ot;
+ __u8 rsvd0;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 mtu_idx:4;
+ __u8 iff:4;
+#else
+ __u8 iff:4;
+ __u8 mtu_idx:4;
+#endif
+ __be16 rsvd2;
+ __be16 rsvd3;
+ __u8 src_mac1[6];
+ __be16 rsvd4;
+ __u8 src_mac0[6];
+};
+
+struct cpl_smt_write_rpl {
+ RSS_HDR union opcode_tid ot;
+ __u8 status;
+ __u8 rsvd[3];
+};
+
+struct cpl_smt_read_req {
+ WR_HDR;
+ union opcode_tid ot;
+ __u8 rsvd0;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8:4;
+ __u8 iff:4;
+#else
+ __u8 iff:4;
+ __u8:4;
+#endif
+ __be16 rsvd2;
+};
+
+struct cpl_smt_read_rpl {
+ RSS_HDR union opcode_tid ot;
+ __u8 status;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 mtu_idx:4;
+ __u8:4;
+#else
+ __u8:4;
+ __u8 mtu_idx:4;
+#endif
+ __be16 rsvd2;
+ __be16 rsvd3;
+ __u8 src_mac1[6];
+ __be16 rsvd4;
+ __u8 src_mac0[6];
+};
+
+struct cpl_rte_delete_req {
+ WR_HDR;
+ union opcode_tid ot;
+ __be32 params;
+};
+
+/* { cpl_rte_delete_req, cpl_rte_read_req }.params fields */
+#define S_RTE_REQ_LUT_IX 8
+#define M_RTE_REQ_LUT_IX 0x7FF
+#define V_RTE_REQ_LUT_IX(x) ((x) << S_RTE_REQ_LUT_IX)
+#define G_RTE_REQ_LUT_IX(x) (((x) >> S_RTE_REQ_LUT_IX) & M_RTE_REQ_LUT_IX)
+
+#define S_RTE_REQ_LUT_BASE 19
+#define M_RTE_REQ_LUT_BASE 0x7FF
+#define V_RTE_REQ_LUT_BASE(x) ((x) << S_RTE_REQ_LUT_BASE)
+#define G_RTE_REQ_LUT_BASE(x) (((x) >> S_RTE_REQ_LUT_BASE) & M_RTE_REQ_LUT_BASE)
+
+#define S_RTE_READ_REQ_SELECT 31
+#define V_RTE_READ_REQ_SELECT(x) ((x) << S_RTE_READ_REQ_SELECT)
+#define F_RTE_READ_REQ_SELECT V_RTE_READ_REQ_SELECT(1U)
+
+struct cpl_rte_delete_rpl {
+ RSS_HDR union opcode_tid ot;
+ __u8 status;
+ __u8 rsvd[3];
+};
+
+struct cpl_rte_write_req {
+ WR_HDR;
+ union opcode_tid ot;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8:6;
+ __u8 write_tcam:1;
+ __u8 write_l2t_lut:1;
+#else
+ __u8 write_l2t_lut:1;
+ __u8 write_tcam:1;
+ __u8:6;
+#endif
+ __u8 rsvd[3];
+ __be32 lut_params;
+ __be16 rsvd2;
+ __be16 l2t_idx;
+ __be32 netmask;
+ __be32 faddr;
+};
+
+/* cpl_rte_write_req.lut_params fields */
+#define S_RTE_WRITE_REQ_LUT_IX 10
+#define M_RTE_WRITE_REQ_LUT_IX 0x7FF
+#define V_RTE_WRITE_REQ_LUT_IX(x) ((x) << S_RTE_WRITE_REQ_LUT_IX)
+#define G_RTE_WRITE_REQ_LUT_IX(x) (((x) >> S_RTE_WRITE_REQ_LUT_IX) & M_RTE_WRITE_REQ_LUT_IX)
+
+#define S_RTE_WRITE_REQ_LUT_BASE 21
+#define M_RTE_WRITE_REQ_LUT_BASE 0x7FF
+#define V_RTE_WRITE_REQ_LUT_BASE(x) ((x) << S_RTE_WRITE_REQ_LUT_BASE)
+#define G_RTE_WRITE_REQ_LUT_BASE(x) (((x) >> S_RTE_WRITE_REQ_LUT_BASE) & M_RTE_WRITE_REQ_LUT_BASE)
+
+struct cpl_rte_write_rpl {
+ RSS_HDR union opcode_tid ot;
+ __u8 status;
+ __u8 rsvd[3];
+};
+
+struct cpl_rte_read_req {
+ WR_HDR;
+ union opcode_tid ot;
+ __be32 params;
+};
+
+struct cpl_rte_read_rpl {
+ RSS_HDR union opcode_tid ot;
+ __u8 status;
+ __u8 rsvd0;
+ __be16 l2t_idx;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8:7;
+ __u8 select:1;
+#else
+ __u8 select:1;
+ __u8:7;
+#endif
+ __u8 rsvd2[3];
+ __be32 addr;
+};
+
+struct cpl_tid_release {
+ WR_HDR;
+ union opcode_tid ot;
+ __be32 rsvd;
+};
+
+struct cpl_barrier {
+ WR_HDR;
+ __u8 opcode;
+ __u8 rsvd[7];
+};
+
+struct cpl_rdma_read_req {
+ __u8 opcode;
+ __u8 rsvd[15];
+};
+
+struct cpl_rdma_terminate {
+#ifdef CHELSIO_FW
+ __u8 opcode;
+ __u8 rsvd[2];
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 rspq:3;
+ __u8:5;
+#else
+ __u8:5;
+ __u8 rspq:3;
+#endif
+ __be32 tid_len;
+#endif
+ __be32 msn;
+ __be32 mo;
+ __u8 data[0];
+};
+
+/* cpl_rdma_terminate.tid_len fields */
+#define S_FLIT_CNT 0
+#define M_FLIT_CNT 0xFF
+#define V_FLIT_CNT(x) ((x) << S_FLIT_CNT)
+#define G_FLIT_CNT(x) (((x) >> S_FLIT_CNT) & M_FLIT_CNT)
+
+#define S_TERM_TID 8
+#define M_TERM_TID 0xFFFFF
+#define V_TERM_TID(x) ((x) << S_TERM_TID)
+#define G_TERM_TID(x) (((x) >> S_TERM_TID) & M_TERM_TID)
+#endif /* T3_CPL_H */
diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c
new file mode 100644
index 00000000000..365a7f5b1f9
--- /dev/null
+++ b/drivers/net/cxgb3/t3_hw.c
@@ -0,0 +1,3375 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "common.h"
+#include "regs.h"
+#include "sge_defs.h"
+#include "firmware_exports.h"
+
+/**
+ * t3_wait_op_done_val - wait until an operation is completed
+ * @adapter: the adapter performing the operation
+ * @reg: the register to check for completion
+ * @mask: a single-bit field within @reg that indicates completion
+ * @polarity: the value of the field when the operation is completed
+ * @attempts: number of check iterations
+ * @delay: delay in usecs between iterations
+ * @valp: where to store the value of the register at completion time
+ *
+ * Wait until an operation is completed by checking a bit in a register
+ * up to @attempts times. If @valp is not NULL the value of the register
+ * at the time it indicated completion is stored there. Returns 0 if the
+ * operation completes and -EAGAIN otherwise.
+ */
+
+int t3_wait_op_done_val(struct adapter *adapter, int reg, u32 mask,
+ int polarity, int attempts, int delay, u32 *valp)
+{
+ while (1) {
+ u32 val = t3_read_reg(adapter, reg);
+
+ if (!!(val & mask) == polarity) {
+ if (valp)
+ *valp = val;
+ return 0;
+ }
+ if (--attempts == 0)
+ return -EAGAIN;
+ if (delay)
+ udelay(delay);
+ }
+}
+
+/**
+ * t3_write_regs - write a bunch of registers
+ * @adapter: the adapter to program
+ * @p: an array of register address/register value pairs
+ * @n: the number of address/value pairs
+ * @offset: register address offset
+ *
+ * Takes an array of register address/register value pairs and writes each
+ * value to the corresponding register. Register addresses are adjusted
+ * by the supplied offset.
+ */
+void t3_write_regs(struct adapter *adapter, const struct addr_val_pair *p,
+ int n, unsigned int offset)
+{
+ while (n--) {
+ t3_write_reg(adapter, p->reg_addr + offset, p->val);
+ p++;
+ }
+}
+
+/**
+ * t3_set_reg_field - set a register field to a value
+ * @adapter: the adapter to program
+ * @addr: the register address
+ * @mask: specifies the portion of the register to modify
+ * @val: the new value for the register field
+ *
+ * Sets a register field specified by the supplied mask to the
+ * given value.
+ */
+void t3_set_reg_field(struct adapter *adapter, unsigned int addr, u32 mask,
+ u32 val)
+{
+ u32 v = t3_read_reg(adapter, addr) & ~mask;
+
+ t3_write_reg(adapter, addr, v | val);
+ t3_read_reg(adapter, addr); /* flush */
+}
+
+/**
+ * t3_read_indirect - read indirectly addressed registers
+ * @adap: the adapter
+ * @addr_reg: register holding the indirect address
+ * @data_reg: register holding the value of the indirect register
+ * @vals: where the read register values are stored
+ * @start_idx: index of first indirect register to read
+ * @nregs: how many indirect registers to read
+ *
+ * Reads registers that are accessed indirectly through an address/data
+ * register pair.
+ */
+void t3_read_indirect(struct adapter *adap, unsigned int addr_reg,
+ unsigned int data_reg, u32 *vals, unsigned int nregs,
+ unsigned int start_idx)
+{
+ while (nregs--) {
+ t3_write_reg(adap, addr_reg, start_idx);
+ *vals++ = t3_read_reg(adap, data_reg);
+ start_idx++;
+ }
+}
+
+/**
+ * t3_mc7_bd_read - read from MC7 through backdoor accesses
+ * @mc7: identifies MC7 to read from
+ * @start: index of first 64-bit word to read
+ * @n: number of 64-bit words to read
+ * @buf: where to store the read result
+ *
+ * Read n 64-bit words from MC7 starting at word start, using backdoor
+ * accesses.
+ */
+int t3_mc7_bd_read(struct mc7 *mc7, unsigned int start, unsigned int n,
+ u64 *buf)
+{
+ static const int shift[] = { 0, 0, 16, 24 };
+ static const int step[] = { 0, 32, 16, 8 };
+
+ unsigned int size64 = mc7->size / 8; /* # of 64-bit words */
+ struct adapter *adap = mc7->adapter;
+
+ if (start >= size64 || start + n > size64)
+ return -EINVAL;
+
+ start *= (8 << mc7->width);
+ while (n--) {
+ int i;
+ u64 val64 = 0;
+
+ for (i = (1 << mc7->width) - 1; i >= 0; --i) {
+ int attempts = 10;
+ u32 val;
+
+ t3_write_reg(adap, mc7->offset + A_MC7_BD_ADDR, start);
+ t3_write_reg(adap, mc7->offset + A_MC7_BD_OP, 0);
+ val = t3_read_reg(adap, mc7->offset + A_MC7_BD_OP);
+ while ((val & F_BUSY) && attempts--)
+ val = t3_read_reg(adap,
+ mc7->offset + A_MC7_BD_OP);
+ if (val & F_BUSY)
+ return -EIO;
+
+ val = t3_read_reg(adap, mc7->offset + A_MC7_BD_DATA1);
+ if (mc7->width == 0) {
+ val64 = t3_read_reg(adap,
+ mc7->offset +
+ A_MC7_BD_DATA0);
+ val64 |= (u64) val << 32;
+ } else {
+ if (mc7->width > 1)
+ val >>= shift[mc7->width];
+ val64 |= (u64) val << (step[mc7->width] * i);
+ }
+ start += 8;
+ }
+ *buf++ = val64;
+ }
+ return 0;
+}
+
+/*
+ * Initialize MI1.
+ */
+static void mi1_init(struct adapter *adap, const struct adapter_info *ai)
+{
+ u32 clkdiv = adap->params.vpd.cclk / (2 * adap->params.vpd.mdc) - 1;
+ u32 val = F_PREEN | V_MDIINV(ai->mdiinv) | V_MDIEN(ai->mdien) |
+ V_CLKDIV(clkdiv);
+
+ if (!(ai->caps & SUPPORTED_10000baseT_Full))
+ val |= V_ST(1);
+ t3_write_reg(adap, A_MI1_CFG, val);
+}
+
+#define MDIO_ATTEMPTS 10
+
+/*
+ * MI1 read/write operations for direct-addressed PHYs.
+ */
+static int mi1_read(struct adapter *adapter, int phy_addr, int mmd_addr,
+ int reg_addr, unsigned int *valp)
+{
+ int ret;
+ u32 addr = V_REGADDR(reg_addr) | V_PHYADDR(phy_addr);
+
+ if (mmd_addr)
+ return -EINVAL;
+
+ mutex_lock(&adapter->mdio_lock);
+ t3_write_reg(adapter, A_MI1_ADDR, addr);
+ t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(2));
+ ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20);
+ if (!ret)
+ *valp = t3_read_reg(adapter, A_MI1_DATA);
+ mutex_unlock(&adapter->mdio_lock);
+ return ret;
+}
+
+static int mi1_write(struct adapter *adapter, int phy_addr, int mmd_addr,
+ int reg_addr, unsigned int val)
+{
+ int ret;
+ u32 addr = V_REGADDR(reg_addr) | V_PHYADDR(phy_addr);
+
+ if (mmd_addr)
+ return -EINVAL;
+
+ mutex_lock(&adapter->mdio_lock);
+ t3_write_reg(adapter, A_MI1_ADDR, addr);
+ t3_write_reg(adapter, A_MI1_DATA, val);
+ t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(1));
+ ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20);
+ mutex_unlock(&adapter->mdio_lock);
+ return ret;
+}
+
+static const struct mdio_ops mi1_mdio_ops = {
+ mi1_read,
+ mi1_write
+};
+
+/*
+ * MI1 read/write operations for indirect-addressed PHYs.
+ */
+static int mi1_ext_read(struct adapter *adapter, int phy_addr, int mmd_addr,
+ int reg_addr, unsigned int *valp)
+{
+ int ret;
+ u32 addr = V_REGADDR(mmd_addr) | V_PHYADDR(phy_addr);
+
+ mutex_lock(&adapter->mdio_lock);
+ t3_write_reg(adapter, A_MI1_ADDR, addr);
+ t3_write_reg(adapter, A_MI1_DATA, reg_addr);
+ t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(0));
+ ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20);
+ if (!ret) {
+ t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(3));
+ ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0,
+ MDIO_ATTEMPTS, 20);
+ if (!ret)
+ *valp = t3_read_reg(adapter, A_MI1_DATA);
+ }
+ mutex_unlock(&adapter->mdio_lock);
+ return ret;
+}
+
+static int mi1_ext_write(struct adapter *adapter, int phy_addr, int mmd_addr,
+ int reg_addr, unsigned int val)
+{
+ int ret;
+ u32 addr = V_REGADDR(mmd_addr) | V_PHYADDR(phy_addr);
+
+ mutex_lock(&adapter->mdio_lock);
+ t3_write_reg(adapter, A_MI1_ADDR, addr);
+ t3_write_reg(adapter, A_MI1_DATA, reg_addr);
+ t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(0));
+ ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20);
+ if (!ret) {
+ t3_write_reg(adapter, A_MI1_DATA, val);
+ t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(1));
+ ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0,
+ MDIO_ATTEMPTS, 20);
+ }
+ mutex_unlock(&adapter->mdio_lock);
+ return ret;
+}
+
+static const struct mdio_ops mi1_mdio_ext_ops = {
+ mi1_ext_read,
+ mi1_ext_write
+};
+
+/**
+ * t3_mdio_change_bits - modify the value of a PHY register
+ * @phy: the PHY to operate on
+ * @mmd: the device address
+ * @reg: the register address
+ * @clear: what part of the register value to mask off
+ * @set: what part of the register value to set
+ *
+ * Changes the value of a PHY register by applying a mask to its current
+ * value and ORing the result with a new value.
+ */
+int t3_mdio_change_bits(struct cphy *phy, int mmd, int reg, unsigned int clear,
+ unsigned int set)
+{
+ int ret;
+ unsigned int val;
+
+ ret = mdio_read(phy, mmd, reg, &val);
+ if (!ret) {
+ val &= ~clear;
+ ret = mdio_write(phy, mmd, reg, val | set);
+ }
+ return ret;
+}
+
+/**
+ * t3_phy_reset - reset a PHY block
+ * @phy: the PHY to operate on
+ * @mmd: the device address of the PHY block to reset
+ * @wait: how long to wait for the reset to complete in 1ms increments
+ *
+ * Resets a PHY block and optionally waits for the reset to complete.
+ * @mmd should be 0 for 10/100/1000 PHYs and the device address to reset
+ * for 10G PHYs.
+ */
+int t3_phy_reset(struct cphy *phy, int mmd, int wait)
+{
+ int err;
+ unsigned int ctl;
+
+ err = t3_mdio_change_bits(phy, mmd, MII_BMCR, BMCR_PDOWN, BMCR_RESET);
+ if (err || !wait)
+ return err;
+
+ do {
+ err = mdio_read(phy, mmd, MII_BMCR, &ctl);
+ if (err)
+ return err;
+ ctl &= BMCR_RESET;
+ if (ctl)
+ msleep(1);
+ } while (ctl && --wait);
+
+ return ctl ? -1 : 0;
+}
+
+/**
+ * t3_phy_advertise - set the PHY advertisement registers for autoneg
+ * @phy: the PHY to operate on
+ * @advert: bitmap of capabilities the PHY should advertise
+ *
+ * Sets a 10/100/1000 PHY's advertisement registers to advertise the
+ * requested capabilities.
+ */
+int t3_phy_advertise(struct cphy *phy, unsigned int advert)
+{
+ int err;
+ unsigned int val = 0;
+
+ err = mdio_read(phy, 0, MII_CTRL1000, &val);
+ if (err)
+ return err;
+
+ val &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
+ if (advert & ADVERTISED_1000baseT_Half)
+ val |= ADVERTISE_1000HALF;
+ if (advert & ADVERTISED_1000baseT_Full)
+ val |= ADVERTISE_1000FULL;
+
+ err = mdio_write(phy, 0, MII_CTRL1000, val);
+ if (err)
+ return err;
+
+ val = 1;
+ if (advert & ADVERTISED_10baseT_Half)
+ val |= ADVERTISE_10HALF;
+ if (advert & ADVERTISED_10baseT_Full)
+ val |= ADVERTISE_10FULL;
+ if (advert & ADVERTISED_100baseT_Half)
+ val |= ADVERTISE_100HALF;
+ if (advert & ADVERTISED_100baseT_Full)
+ val |= ADVERTISE_100FULL;
+ if (advert & ADVERTISED_Pause)
+ val |= ADVERTISE_PAUSE_CAP;
+ if (advert & ADVERTISED_Asym_Pause)
+ val |= ADVERTISE_PAUSE_ASYM;
+ return mdio_write(phy, 0, MII_ADVERTISE, val);
+}
+
+/**
+ * t3_set_phy_speed_duplex - force PHY speed and duplex
+ * @phy: the PHY to operate on
+ * @speed: requested PHY speed
+ * @duplex: requested PHY duplex
+ *
+ * Force a 10/100/1000 PHY's speed and duplex. This also disables
+ * auto-negotiation except for GigE, where auto-negotiation is mandatory.
+ */
+int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex)
+{
+ int err;
+ unsigned int ctl;
+
+ err = mdio_read(phy, 0, MII_BMCR, &ctl);
+ if (err)
+ return err;
+
+ if (speed >= 0) {
+ ctl &= ~(BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);
+ if (speed == SPEED_100)
+ ctl |= BMCR_SPEED100;
+ else if (speed == SPEED_1000)
+ ctl |= BMCR_SPEED1000;
+ }
+ if (duplex >= 0) {
+ ctl &= ~(BMCR_FULLDPLX | BMCR_ANENABLE);
+ if (duplex == DUPLEX_FULL)
+ ctl |= BMCR_FULLDPLX;
+ }
+ if (ctl & BMCR_SPEED1000) /* auto-negotiation required for GigE */
+ ctl |= BMCR_ANENABLE;
+ return mdio_write(phy, 0, MII_BMCR, ctl);
+}
+
+static const struct adapter_info t3_adap_info[] = {
+ {2, 0, 0, 0,
+ F_GPIO2_OEN | F_GPIO4_OEN |
+ F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, F_GPIO3 | F_GPIO5,
+ SUPPORTED_OFFLOAD,
+ &mi1_mdio_ops, "Chelsio PE9000"},
+ {2, 0, 0, 0,
+ F_GPIO2_OEN | F_GPIO4_OEN |
+ F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, F_GPIO3 | F_GPIO5,
+ SUPPORTED_OFFLOAD,
+ &mi1_mdio_ops, "Chelsio T302"},
+ {1, 0, 0, 0,
+ F_GPIO1_OEN | F_GPIO6_OEN | F_GPIO7_OEN | F_GPIO10_OEN |
+ F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, 0,
+ SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_OFFLOAD,
+ &mi1_mdio_ext_ops, "Chelsio T310"},
+ {2, 0, 0, 0,
+ F_GPIO1_OEN | F_GPIO2_OEN | F_GPIO4_OEN | F_GPIO5_OEN | F_GPIO6_OEN |
+ F_GPIO7_OEN | F_GPIO10_OEN | F_GPIO11_OEN | F_GPIO1_OUT_VAL |
+ F_GPIO5_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, 0,
+ SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_OFFLOAD,
+ &mi1_mdio_ext_ops, "Chelsio T320"},
+};
+
+/*
+ * Return the adapter_info structure with a given index. Out-of-range indices
+ * return NULL.
+ */
+const struct adapter_info *t3_get_adapter_info(unsigned int id)
+{
+ return id < ARRAY_SIZE(t3_adap_info) ? &t3_adap_info[id] : NULL;
+}
+
+#define CAPS_1G (SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Full | \
+ SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_MII)
+#define CAPS_10G (SUPPORTED_10000baseT_Full | SUPPORTED_AUI)
+
+static const struct port_type_info port_types[] = {
+ {NULL},
+ {t3_ael1002_phy_prep, CAPS_10G | SUPPORTED_FIBRE,
+ "10GBASE-XR"},
+ {t3_vsc8211_phy_prep, CAPS_1G | SUPPORTED_TP | SUPPORTED_IRQ,
+ "10/100/1000BASE-T"},
+ {NULL, CAPS_1G | SUPPORTED_TP | SUPPORTED_IRQ,
+ "10/100/1000BASE-T"},
+ {t3_xaui_direct_phy_prep, CAPS_10G | SUPPORTED_TP, "10GBASE-CX4"},
+ {NULL, CAPS_10G, "10GBASE-KX4"},
+ {t3_qt2045_phy_prep, CAPS_10G | SUPPORTED_TP, "10GBASE-CX4"},
+ {t3_ael1006_phy_prep, CAPS_10G | SUPPORTED_FIBRE,
+ "10GBASE-SR"},
+ {NULL, CAPS_10G | SUPPORTED_TP, "10GBASE-CX4"},
+};
+
+#undef CAPS_1G
+#undef CAPS_10G
+
+#define VPD_ENTRY(name, len) \
+ u8 name##_kword[2]; u8 name##_len; u8 name##_data[len]
+
+/*
+ * Partial EEPROM Vital Product Data structure. Includes only the ID and
+ * VPD-R sections.
+ */
+struct t3_vpd {
+ u8 id_tag;
+ u8 id_len[2];
+ u8 id_data[16];
+ u8 vpdr_tag;
+ u8 vpdr_len[2];
+ VPD_ENTRY(pn, 16); /* part number */
+ VPD_ENTRY(ec, 16); /* EC level */
+ VPD_ENTRY(sn, 16); /* serial number */
+ VPD_ENTRY(na, 12); /* MAC address base */
+ VPD_ENTRY(cclk, 6); /* core clock */
+ VPD_ENTRY(mclk, 6); /* mem clock */
+ VPD_ENTRY(uclk, 6); /* uP clk */
+ VPD_ENTRY(mdc, 6); /* MDIO clk */
+ VPD_ENTRY(mt, 2); /* mem timing */
+ VPD_ENTRY(xaui0cfg, 6); /* XAUI0 config */
+ VPD_ENTRY(xaui1cfg, 6); /* XAUI1 config */
+ VPD_ENTRY(port0, 2); /* PHY0 complex */
+ VPD_ENTRY(port1, 2); /* PHY1 complex */
+ VPD_ENTRY(port2, 2); /* PHY2 complex */
+ VPD_ENTRY(port3, 2); /* PHY3 complex */
+ VPD_ENTRY(rv, 1); /* csum */
+ u32 pad; /* for multiple-of-4 sizing and alignment */
+};
+
+#define EEPROM_MAX_POLL 4
+#define EEPROM_STAT_ADDR 0x4000
+#define VPD_BASE 0xc00
+
+/**
+ * t3_seeprom_read - read a VPD EEPROM location
+ * @adapter: adapter to read
+ * @addr: EEPROM address
+ * @data: where to store the read data
+ *
+ * Read a 32-bit word from a location in VPD EEPROM using the card's PCI
+ * VPD ROM capability. A zero is written to the flag bit when the
+ * addres is written to the control register. The hardware device will
+ * set the flag to 1 when 4 bytes have been read into the data register.
+ */
+int t3_seeprom_read(struct adapter *adapter, u32 addr, u32 *data)
+{
+ u16 val;
+ int attempts = EEPROM_MAX_POLL;
+ unsigned int base = adapter->params.pci.vpd_cap_addr;
+
+ if ((addr >= EEPROMSIZE && addr != EEPROM_STAT_ADDR) || (addr & 3))
+ return -EINVAL;
+
+ pci_write_config_word(adapter->pdev, base + PCI_VPD_ADDR, addr);
+ do {
+ udelay(10);
+ pci_read_config_word(adapter->pdev, base + PCI_VPD_ADDR, &val);
+ } while (!(val & PCI_VPD_ADDR_F) && --attempts);
+
+ if (!(val & PCI_VPD_ADDR_F)) {
+ CH_ERR(adapter, "reading EEPROM address 0x%x failed\n", addr);
+ return -EIO;
+ }
+ pci_read_config_dword(adapter->pdev, base + PCI_VPD_DATA, data);
+ *data = le32_to_cpu(*data);
+ return 0;
+}
+
+/**
+ * t3_seeprom_write - write a VPD EEPROM location
+ * @adapter: adapter to write
+ * @addr: EEPROM address
+ * @data: value to write
+ *
+ * Write a 32-bit word to a location in VPD EEPROM using the card's PCI
+ * VPD ROM capability.
+ */
+int t3_seeprom_write(struct adapter *adapter, u32 addr, u32 data)
+{
+ u16 val;
+ int attempts = EEPROM_MAX_POLL;
+ unsigned int base = adapter->params.pci.vpd_cap_addr;
+
+ if ((addr >= EEPROMSIZE && addr != EEPROM_STAT_ADDR) || (addr & 3))
+ return -EINVAL;
+
+ pci_write_config_dword(adapter->pdev, base + PCI_VPD_DATA,
+ cpu_to_le32(data));
+ pci_write_config_word(adapter->pdev,base + PCI_VPD_ADDR,
+ addr | PCI_VPD_ADDR_F);
+ do {
+ msleep(1);
+ pci_read_config_word(adapter->pdev, base + PCI_VPD_ADDR, &val);
+ } while ((val & PCI_VPD_ADDR_F) && --attempts);
+
+ if (val & PCI_VPD_ADDR_F) {
+ CH_ERR(adapter, "write to EEPROM address 0x%x failed\n", addr);
+ return -EIO;
+ }
+ return 0;
+}
+
+/**
+ * t3_seeprom_wp - enable/disable EEPROM write protection
+ * @adapter: the adapter
+ * @enable: 1 to enable write protection, 0 to disable it
+ *
+ * Enables or disables write protection on the serial EEPROM.
+ */
+int t3_seeprom_wp(struct adapter *adapter, int enable)
+{
+ return t3_seeprom_write(adapter, EEPROM_STAT_ADDR, enable ? 0xc : 0);
+}
+
+/*
+ * Convert a character holding a hex digit to a number.
+ */
+static unsigned int hex2int(unsigned char c)
+{
+ return isdigit(c) ? c - '0' : toupper(c) - 'A' + 10;
+}
+
+/**
+ * get_vpd_params - read VPD parameters from VPD EEPROM
+ * @adapter: adapter to read
+ * @p: where to store the parameters
+ *
+ * Reads card parameters stored in VPD EEPROM.
+ */
+static int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
+{
+ int i, addr, ret;
+ struct t3_vpd vpd;
+
+ /*
+ * Card information is normally at VPD_BASE but some early cards had
+ * it at 0.
+ */
+ ret = t3_seeprom_read(adapter, VPD_BASE, (u32 *)&vpd);
+ if (ret)
+ return ret;
+ addr = vpd.id_tag == 0x82 ? VPD_BASE : 0;
+
+ for (i = 0; i < sizeof(vpd); i += 4) {
+ ret = t3_seeprom_read(adapter, addr + i,
+ (u32 *)((u8 *)&vpd + i));
+ if (ret)
+ return ret;
+ }
+
+ p->cclk = simple_strtoul(vpd.cclk_data, NULL, 10);
+ p->mclk = simple_strtoul(vpd.mclk_data, NULL, 10);
+ p->uclk = simple_strtoul(vpd.uclk_data, NULL, 10);
+ p->mdc = simple_strtoul(vpd.mdc_data, NULL, 10);
+ p->mem_timing = simple_strtoul(vpd.mt_data, NULL, 10);
+
+ /* Old eeproms didn't have port information */
+ if (adapter->params.rev == 0 && !vpd.port0_data[0]) {
+ p->port_type[0] = uses_xaui(adapter) ? 1 : 2;
+ p->port_type[1] = uses_xaui(adapter) ? 6 : 2;
+ } else {
+ p->port_type[0] = hex2int(vpd.port0_data[0]);
+ p->port_type[1] = hex2int(vpd.port1_data[0]);
+ p->xauicfg[0] = simple_strtoul(vpd.xaui0cfg_data, NULL, 16);
+ p->xauicfg[1] = simple_strtoul(vpd.xaui1cfg_data, NULL, 16);
+ }
+
+ for (i = 0; i < 6; i++)
+ p->eth_base[i] = hex2int(vpd.na_data[2 * i]) * 16 +
+ hex2int(vpd.na_data[2 * i + 1]);
+ return 0;
+}
+
+/* serial flash and firmware constants */
+enum {
+ SF_ATTEMPTS = 5, /* max retries for SF1 operations */
+ SF_SEC_SIZE = 64 * 1024, /* serial flash sector size */
+ SF_SIZE = SF_SEC_SIZE * 8, /* serial flash size */
+
+ /* flash command opcodes */
+ SF_PROG_PAGE = 2, /* program page */
+ SF_WR_DISABLE = 4, /* disable writes */
+ SF_RD_STATUS = 5, /* read status register */
+ SF_WR_ENABLE = 6, /* enable writes */
+ SF_RD_DATA_FAST = 0xb, /* read flash */
+ SF_ERASE_SECTOR = 0xd8, /* erase sector */
+
+ FW_FLASH_BOOT_ADDR = 0x70000, /* start address of FW in flash */
+ FW_VERS_ADDR = 0x77ffc /* flash address holding FW version */
+};
+
+/**
+ * sf1_read - read data from the serial flash
+ * @adapter: the adapter
+ * @byte_cnt: number of bytes to read
+ * @cont: whether another operation will be chained
+ * @valp: where to store the read data
+ *
+ * Reads up to 4 bytes of data from the serial flash. The location of
+ * the read needs to be specified prior to calling this by issuing the
+ * appropriate commands to the serial flash.
+ */
+static int sf1_read(struct adapter *adapter, unsigned int byte_cnt, int cont,
+ u32 *valp)
+{
+ int ret;
+
+ if (!byte_cnt || byte_cnt > 4)
+ return -EINVAL;
+ if (t3_read_reg(adapter, A_SF_OP) & F_BUSY)
+ return -EBUSY;
+ t3_write_reg(adapter, A_SF_OP, V_CONT(cont) | V_BYTECNT(byte_cnt - 1));
+ ret = t3_wait_op_done(adapter, A_SF_OP, F_BUSY, 0, SF_ATTEMPTS, 10);
+ if (!ret)
+ *valp = t3_read_reg(adapter, A_SF_DATA);
+ return ret;
+}
+
+/**
+ * sf1_write - write data to the serial flash
+ * @adapter: the adapter
+ * @byte_cnt: number of bytes to write
+ * @cont: whether another operation will be chained
+ * @val: value to write
+ *
+ * Writes up to 4 bytes of data to the serial flash. The location of
+ * the write needs to be specified prior to calling this by issuing the
+ * appropriate commands to the serial flash.
+ */
+static int sf1_write(struct adapter *adapter, unsigned int byte_cnt, int cont,
+ u32 val)
+{
+ if (!byte_cnt || byte_cnt > 4)
+ return -EINVAL;
+ if (t3_read_reg(adapter, A_SF_OP) & F_BUSY)
+ return -EBUSY;
+ t3_write_reg(adapter, A_SF_DATA, val);
+ t3_write_reg(adapter, A_SF_OP,
+ V_CONT(cont) | V_BYTECNT(byte_cnt - 1) | V_OP(1));
+ return t3_wait_op_done(adapter, A_SF_OP, F_BUSY, 0, SF_ATTEMPTS, 10);
+}
+
+/**
+ * flash_wait_op - wait for a flash operation to complete
+ * @adapter: the adapter
+ * @attempts: max number of polls of the status register
+ * @delay: delay between polls in ms
+ *
+ * Wait for a flash operation to complete by polling the status register.
+ */
+static int flash_wait_op(struct adapter *adapter, int attempts, int delay)
+{
+ int ret;
+ u32 status;
+
+ while (1) {
+ if ((ret = sf1_write(adapter, 1, 1, SF_RD_STATUS)) != 0 ||
+ (ret = sf1_read(adapter, 1, 0, &status)) != 0)
+ return ret;
+ if (!(status & 1))
+ return 0;
+ if (--attempts == 0)
+ return -EAGAIN;
+ if (delay)
+ msleep(delay);
+ }
+}
+
+/**
+ * t3_read_flash - read words from serial flash
+ * @adapter: the adapter
+ * @addr: the start address for the read
+ * @nwords: how many 32-bit words to read
+ * @data: where to store the read data
+ * @byte_oriented: whether to store data as bytes or as words
+ *
+ * Read the specified number of 32-bit words from the serial flash.
+ * If @byte_oriented is set the read data is stored as a byte array
+ * (i.e., big-endian), otherwise as 32-bit words in the platform's
+ * natural endianess.
+ */
+int t3_read_flash(struct adapter *adapter, unsigned int addr,
+ unsigned int nwords, u32 *data, int byte_oriented)
+{
+ int ret;
+
+ if (addr + nwords * sizeof(u32) > SF_SIZE || (addr & 3))
+ return -EINVAL;
+
+ addr = swab32(addr) | SF_RD_DATA_FAST;
+
+ if ((ret = sf1_write(adapter, 4, 1, addr)) != 0 ||
+ (ret = sf1_read(adapter, 1, 1, data)) != 0)
+ return ret;
+
+ for (; nwords; nwords--, data++) {
+ ret = sf1_read(adapter, 4, nwords > 1, data);
+ if (ret)
+ return ret;
+ if (byte_oriented)
+ *data = htonl(*data);
+ }
+ return 0;
+}
+
+/**
+ * t3_write_flash - write up to a page of data to the serial flash
+ * @adapter: the adapter
+ * @addr: the start address to write
+ * @n: length of data to write
+ * @data: the data to write
+ *
+ * Writes up to a page of data (256 bytes) to the serial flash starting
+ * at the given address.
+ */
+static int t3_write_flash(struct adapter *adapter, unsigned int addr,
+ unsigned int n, const u8 *data)
+{
+ int ret;
+ u32 buf[64];
+ unsigned int i, c, left, val, offset = addr & 0xff;
+
+ if (addr + n > SF_SIZE || offset + n > 256)
+ return -EINVAL;
+
+ val = swab32(addr) | SF_PROG_PAGE;
+
+ if ((ret = sf1_write(adapter, 1, 0, SF_WR_ENABLE)) != 0 ||
+ (ret = sf1_write(adapter, 4, 1, val)) != 0)
+ return ret;
+
+ for (left = n; left; left -= c) {
+ c = min(left, 4U);
+ for (val = 0, i = 0; i < c; ++i)
+ val = (val << 8) + *data++;
+
+ ret = sf1_write(adapter, c, c != left, val);
+ if (ret)
+ return ret;
+ }
+ if ((ret = flash_wait_op(adapter, 5, 1)) != 0)
+ return ret;
+
+ /* Read the page to verify the write succeeded */
+ ret = t3_read_flash(adapter, addr & ~0xff, ARRAY_SIZE(buf), buf, 1);
+ if (ret)
+ return ret;
+
+ if (memcmp(data - n, (u8 *) buf + offset, n))
+ return -EIO;
+ return 0;
+}
+
+enum fw_version_type {
+ FW_VERSION_N3,
+ FW_VERSION_T3
+};
+
+/**
+ * t3_get_fw_version - read the firmware version
+ * @adapter: the adapter
+ * @vers: where to place the version
+ *
+ * Reads the FW version from flash.
+ */
+int t3_get_fw_version(struct adapter *adapter, u32 *vers)
+{
+ return t3_read_flash(adapter, FW_VERS_ADDR, 1, vers, 0);
+}
+
+/**
+ * t3_check_fw_version - check if the FW is compatible with this driver
+ * @adapter: the adapter
+ *
+ * Checks if an adapter's FW is compatible with the driver. Returns 0
+ * if the versions are compatible, a negative error otherwise.
+ */
+int t3_check_fw_version(struct adapter *adapter)
+{
+ int ret;
+ u32 vers;
+ unsigned int type, major, minor;
+
+ ret = t3_get_fw_version(adapter, &vers);
+ if (ret)
+ return ret;
+
+ type = G_FW_VERSION_TYPE(vers);
+ major = G_FW_VERSION_MAJOR(vers);
+ minor = G_FW_VERSION_MINOR(vers);
+
+ if (type == FW_VERSION_T3 && major == 3 && minor == 1)
+ return 0;
+
+ CH_ERR(adapter, "found wrong FW version(%u.%u), "
+ "driver needs version 3.1\n", major, minor);
+ return -EINVAL;
+}
+
+/**
+ * t3_flash_erase_sectors - erase a range of flash sectors
+ * @adapter: the adapter
+ * @start: the first sector to erase
+ * @end: the last sector to erase
+ *
+ * Erases the sectors in the given range.
+ */
+static int t3_flash_erase_sectors(struct adapter *adapter, int start, int end)
+{
+ while (start <= end) {
+ int ret;
+
+ if ((ret = sf1_write(adapter, 1, 0, SF_WR_ENABLE)) != 0 ||
+ (ret = sf1_write(adapter, 4, 0,
+ SF_ERASE_SECTOR | (start << 8))) != 0 ||
+ (ret = flash_wait_op(adapter, 5, 500)) != 0)
+ return ret;
+ start++;
+ }
+ return 0;
+}
+
+/*
+ * t3_load_fw - download firmware
+ * @adapter: the adapter
+ * @fw_data: the firrware image to write
+ * @size: image size
+ *
+ * Write the supplied firmware image to the card's serial flash.
+ * The FW image has the following sections: @size - 8 bytes of code and
+ * data, followed by 4 bytes of FW version, followed by the 32-bit
+ * 1's complement checksum of the whole image.
+ */
+int t3_load_fw(struct adapter *adapter, const u8 *fw_data, unsigned int size)
+{
+ u32 csum;
+ unsigned int i;
+ const u32 *p = (const u32 *)fw_data;
+ int ret, addr, fw_sector = FW_FLASH_BOOT_ADDR >> 16;
+
+ if (size & 3)
+ return -EINVAL;
+ if (size > FW_VERS_ADDR + 8 - FW_FLASH_BOOT_ADDR)
+ return -EFBIG;
+
+ for (csum = 0, i = 0; i < size / sizeof(csum); i++)
+ csum += ntohl(p[i]);
+ if (csum != 0xffffffff) {
+ CH_ERR(adapter, "corrupted firmware image, checksum %u\n",
+ csum);
+ return -EINVAL;
+ }
+
+ ret = t3_flash_erase_sectors(adapter, fw_sector, fw_sector);
+ if (ret)
+ goto out;
+
+ size -= 8; /* trim off version and checksum */
+ for (addr = FW_FLASH_BOOT_ADDR; size;) {
+ unsigned int chunk_size = min(size, 256U);
+
+ ret = t3_write_flash(adapter, addr, chunk_size, fw_data);
+ if (ret)
+ goto out;
+
+ addr += chunk_size;
+ fw_data += chunk_size;
+ size -= chunk_size;
+ }
+
+ ret = t3_write_flash(adapter, FW_VERS_ADDR, 4, fw_data);
+out:
+ if (ret)
+ CH_ERR(adapter, "firmware download failed, error %d\n", ret);
+ return ret;
+}
+
+#define CIM_CTL_BASE 0x2000
+
+/**
+ * t3_cim_ctl_blk_read - read a block from CIM control region
+ *
+ * @adap: the adapter
+ * @addr: the start address within the CIM control region
+ * @n: number of words to read
+ * @valp: where to store the result
+ *
+ * Reads a block of 4-byte words from the CIM control region.
+ */
+int t3_cim_ctl_blk_read(struct adapter *adap, unsigned int addr,
+ unsigned int n, unsigned int *valp)
+{
+ int ret = 0;
+
+ if (t3_read_reg(adap, A_CIM_HOST_ACC_CTRL) & F_HOSTBUSY)
+ return -EBUSY;
+
+ for ( ; !ret && n--; addr += 4) {
+ t3_write_reg(adap, A_CIM_HOST_ACC_CTRL, CIM_CTL_BASE + addr);
+ ret = t3_wait_op_done(adap, A_CIM_HOST_ACC_CTRL, F_HOSTBUSY,
+ 0, 5, 2);
+ if (!ret)
+ *valp++ = t3_read_reg(adap, A_CIM_HOST_ACC_DATA);
+ }
+ return ret;
+}
+
+
+/**
+ * t3_link_changed - handle interface link changes
+ * @adapter: the adapter
+ * @port_id: the port index that changed link state
+ *
+ * Called when a port's link settings change to propagate the new values
+ * to the associated PHY and MAC. After performing the common tasks it
+ * invokes an OS-specific handler.
+ */
+void t3_link_changed(struct adapter *adapter, int port_id)
+{
+ int link_ok, speed, duplex, fc;
+ struct port_info *pi = adap2pinfo(adapter, port_id);
+ struct cphy *phy = &pi->phy;
+ struct cmac *mac = &pi->mac;
+ struct link_config *lc = &pi->link_config;
+
+ phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc);
+
+ if (link_ok != lc->link_ok && adapter->params.rev > 0 &&
+ uses_xaui(adapter)) {
+ if (link_ok)
+ t3b_pcs_reset(mac);
+ t3_write_reg(adapter, A_XGM_XAUI_ACT_CTRL + mac->offset,
+ link_ok ? F_TXACTENABLE | F_RXEN : 0);
+ }
+ lc->link_ok = link_ok;
+ lc->speed = speed < 0 ? SPEED_INVALID : speed;
+ lc->duplex = duplex < 0 ? DUPLEX_INVALID : duplex;
+ if (lc->requested_fc & PAUSE_AUTONEG)
+ fc &= lc->requested_fc;
+ else
+ fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
+
+ if (link_ok && speed >= 0 && lc->autoneg == AUTONEG_ENABLE) {
+ /* Set MAC speed, duplex, and flow control to match PHY. */
+ t3_mac_set_speed_duplex_fc(mac, speed, duplex, fc);
+ lc->fc = fc;
+ }
+
+ t3_os_link_changed(adapter, port_id, link_ok, speed, duplex, fc);
+}
+
+/**
+ * t3_link_start - apply link configuration to MAC/PHY
+ * @phy: the PHY to setup
+ * @mac: the MAC to setup
+ * @lc: the requested link configuration
+ *
+ * Set up a port's MAC and PHY according to a desired link configuration.
+ * - If the PHY can auto-negotiate first decide what to advertise, then
+ * enable/disable auto-negotiation as desired, and reset.
+ * - If the PHY does not auto-negotiate just reset it.
+ * - If auto-negotiation is off set the MAC to the proper speed/duplex/FC,
+ * otherwise do it later based on the outcome of auto-negotiation.
+ */
+int t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc)
+{
+ unsigned int fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
+
+ lc->link_ok = 0;
+ if (lc->supported & SUPPORTED_Autoneg) {
+ lc->advertising &= ~(ADVERTISED_Asym_Pause | ADVERTISED_Pause);
+ if (fc) {
+ lc->advertising |= ADVERTISED_Asym_Pause;
+ if (fc & PAUSE_RX)
+ lc->advertising |= ADVERTISED_Pause;
+ }
+ phy->ops->advertise(phy, lc->advertising);
+
+ if (lc->autoneg == AUTONEG_DISABLE) {
+ lc->speed = lc->requested_speed;
+ lc->duplex = lc->requested_duplex;
+ lc->fc = (unsigned char)fc;
+ t3_mac_set_speed_duplex_fc(mac, lc->speed, lc->duplex,
+ fc);
+ /* Also disables autoneg */
+ phy->ops->set_speed_duplex(phy, lc->speed, lc->duplex);
+ phy->ops->reset(phy, 0);
+ } else
+ phy->ops->autoneg_enable(phy);
+ } else {
+ t3_mac_set_speed_duplex_fc(mac, -1, -1, fc);
+ lc->fc = (unsigned char)fc;
+ phy->ops->reset(phy, 0);
+ }
+ return 0;
+}
+
+/**
+ * t3_set_vlan_accel - control HW VLAN extraction
+ * @adapter: the adapter
+ * @ports: bitmap of adapter ports to operate on
+ * @on: enable (1) or disable (0) HW VLAN extraction
+ *
+ * Enables or disables HW extraction of VLAN tags for the given port.
+ */
+void t3_set_vlan_accel(struct adapter *adapter, unsigned int ports, int on)
+{
+ t3_set_reg_field(adapter, A_TP_OUT_CONFIG,
+ ports << S_VLANEXTRACTIONENABLE,
+ on ? (ports << S_VLANEXTRACTIONENABLE) : 0);
+}
+
+struct intr_info {
+ unsigned int mask; /* bits to check in interrupt status */
+ const char *msg; /* message to print or NULL */
+ short stat_idx; /* stat counter to increment or -1 */
+ unsigned short fatal:1; /* whether the condition reported is fatal */
+};
+
+/**
+ * t3_handle_intr_status - table driven interrupt handler
+ * @adapter: the adapter that generated the interrupt
+ * @reg: the interrupt status register to process
+ * @mask: a mask to apply to the interrupt status
+ * @acts: table of interrupt actions
+ * @stats: statistics counters tracking interrupt occurences
+ *
+ * A table driven interrupt handler that applies a set of masks to an
+ * interrupt status word and performs the corresponding actions if the
+ * interrupts described by the mask have occured. The actions include
+ * optionally printing a warning or alert message, and optionally
+ * incrementing a stat counter. The table is terminated by an entry
+ * specifying mask 0. Returns the number of fatal interrupt conditions.
+ */
+static int t3_handle_intr_status(struct adapter *adapter, unsigned int reg,
+ unsigned int mask,
+ const struct intr_info *acts,
+ unsigned long *stats)
+{
+ int fatal = 0;
+ unsigned int status = t3_read_reg(adapter, reg) & mask;
+
+ for (; acts->mask; ++acts) {
+ if (!(status & acts->mask))
+ continue;
+ if (acts->fatal) {
+ fatal++;
+ CH_ALERT(adapter, "%s (0x%x)\n",
+ acts->msg, status & acts->mask);
+ } else if (acts->msg)
+ CH_WARN(adapter, "%s (0x%x)\n",
+ acts->msg, status & acts->mask);
+ if (acts->stat_idx >= 0)
+ stats[acts->stat_idx]++;
+ }
+ if (status) /* clear processed interrupts */
+ t3_write_reg(adapter, reg, status);
+ return fatal;
+}
+
+#define SGE_INTR_MASK (F_RSPQDISABLED)
+#define MC5_INTR_MASK (F_PARITYERR | F_ACTRGNFULL | F_UNKNOWNCMD | \
+ F_REQQPARERR | F_DISPQPARERR | F_DELACTEMPTY | \
+ F_NFASRCHFAIL)
+#define MC7_INTR_MASK (F_AE | F_UE | F_CE | V_PE(M_PE))
+#define XGM_INTR_MASK (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \
+ V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR) | \
+ F_TXFIFO_UNDERRUN | F_RXFIFO_OVERFLOW)
+#define PCIX_INTR_MASK (F_MSTDETPARERR | F_SIGTARABT | F_RCVTARABT | \
+ F_RCVMSTABT | F_SIGSYSERR | F_DETPARERR | \
+ F_SPLCMPDIS | F_UNXSPLCMP | F_RCVSPLCMPERR | \
+ F_DETCORECCERR | F_DETUNCECCERR | F_PIOPARERR | \
+ V_WFPARERR(M_WFPARERR) | V_RFPARERR(M_RFPARERR) | \
+ V_CFPARERR(M_CFPARERR) /* | V_MSIXPARERR(M_MSIXPARERR) */)
+#define PCIE_INTR_MASK (F_UNXSPLCPLERRR | F_UNXSPLCPLERRC | F_PCIE_PIOPARERR |\
+ F_PCIE_WFPARERR | F_PCIE_RFPARERR | F_PCIE_CFPARERR | \
+ /* V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR) | */ \
+ V_BISTERR(M_BISTERR) | F_PEXERR)
+#define ULPRX_INTR_MASK F_PARERR
+#define ULPTX_INTR_MASK 0
+#define CPLSW_INTR_MASK (F_TP_FRAMING_ERROR | \
+ F_SGE_FRAMING_ERROR | F_CIM_FRAMING_ERROR | \
+ F_ZERO_SWITCH_ERROR)
+#define CIM_INTR_MASK (F_BLKWRPLINT | F_BLKRDPLINT | F_BLKWRCTLINT | \
+ F_BLKRDCTLINT | F_BLKWRFLASHINT | F_BLKRDFLASHINT | \
+ F_SGLWRFLASHINT | F_WRBLKFLASHINT | F_BLKWRBOOTINT | \
+ F_FLASHRANGEINT | F_SDRAMRANGEINT | F_RSVDSPACEINT)
+#define PMTX_INTR_MASK (F_ZERO_C_CMD_ERROR | ICSPI_FRM_ERR | OESPI_FRM_ERR | \
+ V_ICSPI_PAR_ERROR(M_ICSPI_PAR_ERROR) | \
+ V_OESPI_PAR_ERROR(M_OESPI_PAR_ERROR))
+#define PMRX_INTR_MASK (F_ZERO_E_CMD_ERROR | IESPI_FRM_ERR | OCSPI_FRM_ERR | \
+ V_IESPI_PAR_ERROR(M_IESPI_PAR_ERROR) | \
+ V_OCSPI_PAR_ERROR(M_OCSPI_PAR_ERROR))
+#define MPS_INTR_MASK (V_TX0TPPARERRENB(M_TX0TPPARERRENB) | \
+ V_TX1TPPARERRENB(M_TX1TPPARERRENB) | \
+ V_RXTPPARERRENB(M_RXTPPARERRENB) | \
+ V_MCAPARERRENB(M_MCAPARERRENB))
+#define PL_INTR_MASK (F_T3DBG | F_XGMAC0_0 | F_XGMAC0_1 | F_MC5A | F_PM1_TX | \
+ F_PM1_RX | F_ULP2_TX | F_ULP2_RX | F_TP1 | F_CIM | \
+ F_MC7_CM | F_MC7_PMTX | F_MC7_PMRX | F_SGE3 | F_PCIM0 | \
+ F_MPS0 | F_CPL_SWITCH)
+
+/*
+ * Interrupt handler for the PCIX1 module.
+ */
+static void pci_intr_handler(struct adapter *adapter)
+{
+ static const struct intr_info pcix1_intr_info[] = {
+ {F_MSTDETPARERR, "PCI master detected parity error", -1, 1},
+ {F_SIGTARABT, "PCI signaled target abort", -1, 1},
+ {F_RCVTARABT, "PCI received target abort", -1, 1},
+ {F_RCVMSTABT, "PCI received master abort", -1, 1},
+ {F_SIGSYSERR, "PCI signaled system error", -1, 1},
+ {F_DETPARERR, "PCI detected parity error", -1, 1},
+ {F_SPLCMPDIS, "PCI split completion discarded", -1, 1},
+ {F_UNXSPLCMP, "PCI unexpected split completion error", -1, 1},
+ {F_RCVSPLCMPERR, "PCI received split completion error", -1,
+ 1},
+ {F_DETCORECCERR, "PCI correctable ECC error",
+ STAT_PCI_CORR_ECC, 0},
+ {F_DETUNCECCERR, "PCI uncorrectable ECC error", -1, 1},
+ {F_PIOPARERR, "PCI PIO FIFO parity error", -1, 1},
+ {V_WFPARERR(M_WFPARERR), "PCI write FIFO parity error", -1,
+ 1},
+ {V_RFPARERR(M_RFPARERR), "PCI read FIFO parity error", -1,
+ 1},
+ {V_CFPARERR(M_CFPARERR), "PCI command FIFO parity error", -1,
+ 1},
+ {V_MSIXPARERR(M_MSIXPARERR), "PCI MSI-X table/PBA parity "
+ "error", -1, 1},
+ {0}
+ };
+
+ if (t3_handle_intr_status(adapter, A_PCIX_INT_CAUSE, PCIX_INTR_MASK,
+ pcix1_intr_info, adapter->irq_stats))
+ t3_fatal_err(adapter);
+}
+
+/*
+ * Interrupt handler for the PCIE module.
+ */
+static void pcie_intr_handler(struct adapter *adapter)
+{
+ static const struct intr_info pcie_intr_info[] = {
+ {F_PEXERR, "PCI PEX error", -1, 1},
+ {F_UNXSPLCPLERRR,
+ "PCI unexpected split completion DMA read error", -1, 1},
+ {F_UNXSPLCPLERRC,
+ "PCI unexpected split completion DMA command error", -1, 1},
+ {F_PCIE_PIOPARERR, "PCI PIO FIFO parity error", -1, 1},
+ {F_PCIE_WFPARERR, "PCI write FIFO parity error", -1, 1},
+ {F_PCIE_RFPARERR, "PCI read FIFO parity error", -1, 1},
+ {F_PCIE_CFPARERR, "PCI command FIFO parity error", -1, 1},
+ {V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR),
+ "PCI MSI-X table/PBA parity error", -1, 1},
+ {V_BISTERR(M_BISTERR), "PCI BIST error", -1, 1},
+ {0}
+ };
+
+ if (t3_handle_intr_status(adapter, A_PCIE_INT_CAUSE, PCIE_INTR_MASK,
+ pcie_intr_info, adapter->irq_stats))
+ t3_fatal_err(adapter);
+}
+
+/*
+ * TP interrupt handler.
+ */
+static void tp_intr_handler(struct adapter *adapter)
+{
+ static const struct intr_info tp_intr_info[] = {
+ {0xffffff, "TP parity error", -1, 1},
+ {0x1000000, "TP out of Rx pages", -1, 1},
+ {0x2000000, "TP out of Tx pages", -1, 1},
+ {0}
+ };
+
+ if (t3_handle_intr_status(adapter, A_TP_INT_CAUSE, 0xffffffff,
+ tp_intr_info, NULL))
+ t3_fatal_err(adapter);
+}
+
+/*
+ * CIM interrupt handler.
+ */
+static void cim_intr_handler(struct adapter *adapter)
+{
+ static const struct intr_info cim_intr_info[] = {
+ {F_RSVDSPACEINT, "CIM reserved space write", -1, 1},
+ {F_SDRAMRANGEINT, "CIM SDRAM address out of range", -1, 1},
+ {F_FLASHRANGEINT, "CIM flash address out of range", -1, 1},
+ {F_BLKWRBOOTINT, "CIM block write to boot space", -1, 1},
+ {F_WRBLKFLASHINT, "CIM write to cached flash space", -1, 1},
+ {F_SGLWRFLASHINT, "CIM single write to flash space", -1, 1},
+ {F_BLKRDFLASHINT, "CIM block read from flash space", -1, 1},
+ {F_BLKWRFLASHINT, "CIM block write to flash space", -1, 1},
+ {F_BLKRDCTLINT, "CIM block read from CTL space", -1, 1},
+ {F_BLKWRCTLINT, "CIM block write to CTL space", -1, 1},
+ {F_BLKRDPLINT, "CIM block read from PL space", -1, 1},
+ {F_BLKWRPLINT, "CIM block write to PL space", -1, 1},
+ {0}
+ };
+
+ if (t3_handle_intr_status(adapter, A_CIM_HOST_INT_CAUSE, 0xffffffff,
+ cim_intr_info, NULL))
+ t3_fatal_err(adapter);
+}
+
+/*
+ * ULP RX interrupt handler.
+ */
+static void ulprx_intr_handler(struct adapter *adapter)
+{
+ static const struct intr_info ulprx_intr_info[] = {
+ {F_PARERR, "ULP RX parity error", -1, 1},
+ {0}
+ };
+
+ if (t3_handle_intr_status(adapter, A_ULPRX_INT_CAUSE, 0xffffffff,
+ ulprx_intr_info, NULL))
+ t3_fatal_err(adapter);
+}
+
+/*
+ * ULP TX interrupt handler.
+ */
+static void ulptx_intr_handler(struct adapter *adapter)
+{
+ static const struct intr_info ulptx_intr_info[] = {
+ {F_PBL_BOUND_ERR_CH0, "ULP TX channel 0 PBL out of bounds",
+ STAT_ULP_CH0_PBL_OOB, 0},
+ {F_PBL_BOUND_ERR_CH1, "ULP TX channel 1 PBL out of bounds",
+ STAT_ULP_CH1_PBL_OOB, 0},
+ {0}
+ };
+
+ if (t3_handle_intr_status(adapter, A_ULPTX_INT_CAUSE, 0xffffffff,
+ ulptx_intr_info, adapter->irq_stats))
+ t3_fatal_err(adapter);
+}
+
+#define ICSPI_FRM_ERR (F_ICSPI0_FIFO2X_RX_FRAMING_ERROR | \
+ F_ICSPI1_FIFO2X_RX_FRAMING_ERROR | F_ICSPI0_RX_FRAMING_ERROR | \
+ F_ICSPI1_RX_FRAMING_ERROR | F_ICSPI0_TX_FRAMING_ERROR | \
+ F_ICSPI1_TX_FRAMING_ERROR)
+#define OESPI_FRM_ERR (F_OESPI0_RX_FRAMING_ERROR | \
+ F_OESPI1_RX_FRAMING_ERROR | F_OESPI0_TX_FRAMING_ERROR | \
+ F_OESPI1_TX_FRAMING_ERROR | F_OESPI0_OFIFO2X_TX_FRAMING_ERROR | \
+ F_OESPI1_OFIFO2X_TX_FRAMING_ERROR)
+
+/*
+ * PM TX interrupt handler.
+ */
+static void pmtx_intr_handler(struct adapter *adapter)
+{
+ static const struct intr_info pmtx_intr_info[] = {
+ {F_ZERO_C_CMD_ERROR, "PMTX 0-length pcmd", -1, 1},
+ {ICSPI_FRM_ERR, "PMTX ispi framing error", -1, 1},
+ {OESPI_FRM_ERR, "PMTX ospi framing error", -1, 1},
+ {V_ICSPI_PAR_ERROR(M_ICSPI_PAR_ERROR),
+ "PMTX ispi parity error", -1, 1},
+ {V_OESPI_PAR_ERROR(M_OESPI_PAR_ERROR),
+ "PMTX ospi parity error", -1, 1},
+ {0}
+ };
+
+ if (t3_handle_intr_status(adapter, A_PM1_TX_INT_CAUSE, 0xffffffff,
+ pmtx_intr_info, NULL))
+ t3_fatal_err(adapter);
+}
+
+#define IESPI_FRM_ERR (F_IESPI0_FIFO2X_RX_FRAMING_ERROR | \
+ F_IESPI1_FIFO2X_RX_FRAMING_ERROR | F_IESPI0_RX_FRAMING_ERROR | \
+ F_IESPI1_RX_FRAMING_ERROR | F_IESPI0_TX_FRAMING_ERROR | \
+ F_IESPI1_TX_FRAMING_ERROR)
+#define OCSPI_FRM_ERR (F_OCSPI0_RX_FRAMING_ERROR | \
+ F_OCSPI1_RX_FRAMING_ERROR | F_OCSPI0_TX_FRAMING_ERROR | \
+ F_OCSPI1_TX_FRAMING_ERROR | F_OCSPI0_OFIFO2X_TX_FRAMING_ERROR | \
+ F_OCSPI1_OFIFO2X_TX_FRAMING_ERROR)
+
+/*
+ * PM RX interrupt handler.
+ */
+static void pmrx_intr_handler(struct adapter *adapter)
+{
+ static const struct intr_info pmrx_intr_info[] = {
+ {F_ZERO_E_CMD_ERROR, "PMRX 0-length pcmd", -1, 1},
+ {IESPI_FRM_ERR, "PMRX ispi framing error", -1, 1},
+ {OCSPI_FRM_ERR, "PMRX ospi framing error", -1, 1},
+ {V_IESPI_PAR_ERROR(M_IESPI_PAR_ERROR),
+ "PMRX ispi parity error", -1, 1},
+ {V_OCSPI_PAR_ERROR(M_OCSPI_PAR_ERROR),
+ "PMRX ospi parity error", -1, 1},
+ {0}
+ };
+
+ if (t3_handle_intr_status(adapter, A_PM1_RX_INT_CAUSE, 0xffffffff,
+ pmrx_intr_info, NULL))
+ t3_fatal_err(adapter);
+}
+
+/*
+ * CPL switch interrupt handler.
+ */
+static void cplsw_intr_handler(struct adapter *adapter)
+{
+ static const struct intr_info cplsw_intr_info[] = {
+/* { F_CIM_OVFL_ERROR, "CPL switch CIM overflow", -1, 1 }, */
+ {F_TP_FRAMING_ERROR, "CPL switch TP framing error", -1, 1},
+ {F_SGE_FRAMING_ERROR, "CPL switch SGE framing error", -1, 1},
+ {F_CIM_FRAMING_ERROR, "CPL switch CIM framing error", -1, 1},
+ {F_ZERO_SWITCH_ERROR, "CPL switch no-switch error", -1, 1},
+ {0}
+ };
+
+ if (t3_handle_intr_status(adapter, A_CPL_INTR_CAUSE, 0xffffffff,
+ cplsw_intr_info, NULL))
+ t3_fatal_err(adapter);
+}
+
+/*
+ * MPS interrupt handler.
+ */
+static void mps_intr_handler(struct adapter *adapter)
+{
+ static const struct intr_info mps_intr_info[] = {
+ {0x1ff, "MPS parity error", -1, 1},
+ {0}
+ };
+
+ if (t3_handle_intr_status(adapter, A_MPS_INT_CAUSE, 0xffffffff,
+ mps_intr_info, NULL))
+ t3_fatal_err(adapter);
+}
+
+#define MC7_INTR_FATAL (F_UE | V_PE(M_PE) | F_AE)
+
+/*
+ * MC7 interrupt handler.
+ */
+static void mc7_intr_handler(struct mc7 *mc7)
+{
+ struct adapter *adapter = mc7->adapter;
+ u32 cause = t3_read_reg(adapter, mc7->offset + A_MC7_INT_CAUSE);
+
+ if (cause & F_CE) {
+ mc7->stats.corr_err++;
+ CH_WARN(adapter, "%s MC7 correctable error at addr 0x%x, "
+ "data 0x%x 0x%x 0x%x\n", mc7->name,
+ t3_read_reg(adapter, mc7->offset + A_MC7_CE_ADDR),
+ t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA0),
+ t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA1),
+ t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA2));
+ }
+
+ if (cause & F_UE) {
+ mc7->stats.uncorr_err++;
+ CH_ALERT(adapter, "%s MC7 uncorrectable error at addr 0x%x, "
+ "data 0x%x 0x%x 0x%x\n", mc7->name,
+ t3_read_reg(adapter, mc7->offset + A_MC7_UE_ADDR),
+ t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA0),
+ t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA1),
+ t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA2));
+ }
+
+ if (G_PE(cause)) {
+ mc7->stats.parity_err++;
+ CH_ALERT(adapter, "%s MC7 parity error 0x%x\n",
+ mc7->name, G_PE(cause));
+ }
+
+ if (cause & F_AE) {
+ u32 addr = 0;
+
+ if (adapter->params.rev > 0)
+ addr = t3_read_reg(adapter,
+ mc7->offset + A_MC7_ERR_ADDR);
+ mc7->stats.addr_err++;
+ CH_ALERT(adapter, "%s MC7 address error: 0x%x\n",
+ mc7->name, addr);
+ }
+
+ if (cause & MC7_INTR_FATAL)
+ t3_fatal_err(adapter);
+
+ t3_write_reg(adapter, mc7->offset + A_MC7_INT_CAUSE, cause);
+}
+
+#define XGM_INTR_FATAL (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \
+ V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR))
+/*
+ * XGMAC interrupt handler.
+ */
+static int mac_intr_handler(struct adapter *adap, unsigned int idx)
+{
+ struct cmac *mac = &adap2pinfo(adap, idx)->mac;
+ u32 cause = t3_read_reg(adap, A_XGM_INT_CAUSE + mac->offset);
+
+ if (cause & V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR)) {
+ mac->stats.tx_fifo_parity_err++;
+ CH_ALERT(adap, "port%d: MAC TX FIFO parity error\n", idx);
+ }
+ if (cause & V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR)) {
+ mac->stats.rx_fifo_parity_err++;
+ CH_ALERT(adap, "port%d: MAC RX FIFO parity error\n", idx);
+ }
+ if (cause & F_TXFIFO_UNDERRUN)
+ mac->stats.tx_fifo_urun++;
+ if (cause & F_RXFIFO_OVERFLOW)
+ mac->stats.rx_fifo_ovfl++;
+ if (cause & V_SERDES_LOS(M_SERDES_LOS))
+ mac->stats.serdes_signal_loss++;
+ if (cause & F_XAUIPCSCTCERR)
+ mac->stats.xaui_pcs_ctc_err++;
+ if (cause & F_XAUIPCSALIGNCHANGE)
+ mac->stats.xaui_pcs_align_change++;
+
+ t3_write_reg(adap, A_XGM_INT_CAUSE + mac->offset, cause);
+ if (cause & XGM_INTR_FATAL)
+ t3_fatal_err(adap);
+ return cause != 0;
+}
+
+/*
+ * Interrupt handler for PHY events.
+ */
+int t3_phy_intr_handler(struct adapter *adapter)
+{
+ static const int intr_gpio_bits[] = { 8, 0x20 };
+
+ u32 i, cause = t3_read_reg(adapter, A_T3DBG_INT_CAUSE);
+
+ for_each_port(adapter, i) {
+ if (cause & intr_gpio_bits[i]) {
+ struct cphy *phy = &adap2pinfo(adapter, i)->phy;
+ int phy_cause = phy->ops->intr_handler(phy);
+
+ if (phy_cause & cphy_cause_link_change)
+ t3_link_changed(adapter, i);
+ if (phy_cause & cphy_cause_fifo_error)
+ phy->fifo_errors++;
+ }
+ }
+
+ t3_write_reg(adapter, A_T3DBG_INT_CAUSE, cause);
+ return 0;
+}
+
+/*
+ * T3 slow path (non-data) interrupt handler.
+ */
+int t3_slow_intr_handler(struct adapter *adapter)
+{
+ u32 cause = t3_read_reg(adapter, A_PL_INT_CAUSE0);
+
+ cause &= adapter->slow_intr_mask;
+ if (!cause)
+ return 0;
+ if (cause & F_PCIM0) {
+ if (is_pcie(adapter))
+ pcie_intr_handler(adapter);
+ else
+ pci_intr_handler(adapter);
+ }
+ if (cause & F_SGE3)
+ t3_sge_err_intr_handler(adapter);
+ if (cause & F_MC7_PMRX)
+ mc7_intr_handler(&adapter->pmrx);
+ if (cause & F_MC7_PMTX)
+ mc7_intr_handler(&adapter->pmtx);
+ if (cause & F_MC7_CM)
+ mc7_intr_handler(&adapter->cm);
+ if (cause & F_CIM)
+ cim_intr_handler(adapter);
+ if (cause & F_TP1)
+ tp_intr_handler(adapter);
+ if (cause & F_ULP2_RX)
+ ulprx_intr_handler(adapter);
+ if (cause & F_ULP2_TX)
+ ulptx_intr_handler(adapter);
+ if (cause & F_PM1_RX)
+ pmrx_intr_handler(adapter);
+ if (cause & F_PM1_TX)
+ pmtx_intr_handler(adapter);
+ if (cause & F_CPL_SWITCH)
+ cplsw_intr_handler(adapter);
+ if (cause & F_MPS0)
+ mps_intr_handler(adapter);
+ if (cause & F_MC5A)
+ t3_mc5_intr_handler(&adapter->mc5);
+ if (cause & F_XGMAC0_0)
+ mac_intr_handler(adapter, 0);
+ if (cause & F_XGMAC0_1)
+ mac_intr_handler(adapter, 1);
+ if (cause & F_T3DBG)
+ t3_os_ext_intr_handler(adapter);
+
+ /* Clear the interrupts just processed. */
+ t3_write_reg(adapter, A_PL_INT_CAUSE0, cause);
+ t3_read_reg(adapter, A_PL_INT_CAUSE0); /* flush */
+ return 1;
+}
+
+/**
+ * t3_intr_enable - enable interrupts
+ * @adapter: the adapter whose interrupts should be enabled
+ *
+ * Enable interrupts by setting the interrupt enable registers of the
+ * various HW modules and then enabling the top-level interrupt
+ * concentrator.
+ */
+void t3_intr_enable(struct adapter *adapter)
+{
+ static const struct addr_val_pair intr_en_avp[] = {
+ {A_SG_INT_ENABLE, SGE_INTR_MASK},
+ {A_MC7_INT_ENABLE, MC7_INTR_MASK},
+ {A_MC7_INT_ENABLE - MC7_PMRX_BASE_ADDR + MC7_PMTX_BASE_ADDR,
+ MC7_INTR_MASK},
+ {A_MC7_INT_ENABLE - MC7_PMRX_BASE_ADDR + MC7_CM_BASE_ADDR,
+ MC7_INTR_MASK},
+ {A_MC5_DB_INT_ENABLE, MC5_INTR_MASK},
+ {A_ULPRX_INT_ENABLE, ULPRX_INTR_MASK},
+ {A_TP_INT_ENABLE, 0x3bfffff},
+ {A_PM1_TX_INT_ENABLE, PMTX_INTR_MASK},
+ {A_PM1_RX_INT_ENABLE, PMRX_INTR_MASK},
+ {A_CIM_HOST_INT_ENABLE, CIM_INTR_MASK},
+ {A_MPS_INT_ENABLE, MPS_INTR_MASK},
+ };
+
+ adapter->slow_intr_mask = PL_INTR_MASK;
+
+ t3_write_regs(adapter, intr_en_avp, ARRAY_SIZE(intr_en_avp), 0);
+
+ if (adapter->params.rev > 0) {
+ t3_write_reg(adapter, A_CPL_INTR_ENABLE,
+ CPLSW_INTR_MASK | F_CIM_OVFL_ERROR);
+ t3_write_reg(adapter, A_ULPTX_INT_ENABLE,
+ ULPTX_INTR_MASK | F_PBL_BOUND_ERR_CH0 |
+ F_PBL_BOUND_ERR_CH1);
+ } else {
+ t3_write_reg(adapter, A_CPL_INTR_ENABLE, CPLSW_INTR_MASK);
+ t3_write_reg(adapter, A_ULPTX_INT_ENABLE, ULPTX_INTR_MASK);
+ }
+
+ t3_write_reg(adapter, A_T3DBG_GPIO_ACT_LOW,
+ adapter_info(adapter)->gpio_intr);
+ t3_write_reg(adapter, A_T3DBG_INT_ENABLE,
+ adapter_info(adapter)->gpio_intr);
+ if (is_pcie(adapter))
+ t3_write_reg(adapter, A_PCIE_INT_ENABLE, PCIE_INTR_MASK);
+ else
+ t3_write_reg(adapter, A_PCIX_INT_ENABLE, PCIX_INTR_MASK);
+ t3_write_reg(adapter, A_PL_INT_ENABLE0, adapter->slow_intr_mask);
+ t3_read_reg(adapter, A_PL_INT_ENABLE0); /* flush */
+}
+
+/**
+ * t3_intr_disable - disable a card's interrupts
+ * @adapter: the adapter whose interrupts should be disabled
+ *
+ * Disable interrupts. We only disable the top-level interrupt
+ * concentrator and the SGE data interrupts.
+ */
+void t3_intr_disable(struct adapter *adapter)
+{
+ t3_write_reg(adapter, A_PL_INT_ENABLE0, 0);
+ t3_read_reg(adapter, A_PL_INT_ENABLE0); /* flush */
+ adapter->slow_intr_mask = 0;
+}
+
+/**
+ * t3_intr_clear - clear all interrupts
+ * @adapter: the adapter whose interrupts should be cleared
+ *
+ * Clears all interrupts.
+ */
+void t3_intr_clear(struct adapter *adapter)
+{
+ static const unsigned int cause_reg_addr[] = {
+ A_SG_INT_CAUSE,
+ A_SG_RSPQ_FL_STATUS,
+ A_PCIX_INT_CAUSE,
+ A_MC7_INT_CAUSE,
+ A_MC7_INT_CAUSE - MC7_PMRX_BASE_ADDR + MC7_PMTX_BASE_ADDR,
+ A_MC7_INT_CAUSE - MC7_PMRX_BASE_ADDR + MC7_CM_BASE_ADDR,
+ A_CIM_HOST_INT_CAUSE,
+ A_TP_INT_CAUSE,
+ A_MC5_DB_INT_CAUSE,
+ A_ULPRX_INT_CAUSE,
+ A_ULPTX_INT_CAUSE,
+ A_CPL_INTR_CAUSE,
+ A_PM1_TX_INT_CAUSE,
+ A_PM1_RX_INT_CAUSE,
+ A_MPS_INT_CAUSE,
+ A_T3DBG_INT_CAUSE,
+ };
+ unsigned int i;
+
+ /* Clear PHY and MAC interrupts for each port. */
+ for_each_port(adapter, i)
+ t3_port_intr_clear(adapter, i);
+
+ for (i = 0; i < ARRAY_SIZE(cause_reg_addr); ++i)
+ t3_write_reg(adapter, cause_reg_addr[i], 0xffffffff);
+
+ t3_write_reg(adapter, A_PL_INT_CAUSE0, 0xffffffff);
+ t3_read_reg(adapter, A_PL_INT_CAUSE0); /* flush */
+}
+
+/**
+ * t3_port_intr_enable - enable port-specific interrupts
+ * @adapter: associated adapter
+ * @idx: index of port whose interrupts should be enabled
+ *
+ * Enable port-specific (i.e., MAC and PHY) interrupts for the given
+ * adapter port.
+ */
+void t3_port_intr_enable(struct adapter *adapter, int idx)
+{
+ struct cphy *phy = &adap2pinfo(adapter, idx)->phy;
+
+ t3_write_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx), XGM_INTR_MASK);
+ t3_read_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx)); /* flush */
+ phy->ops->intr_enable(phy);
+}
+
+/**
+ * t3_port_intr_disable - disable port-specific interrupts
+ * @adapter: associated adapter
+ * @idx: index of port whose interrupts should be disabled
+ *
+ * Disable port-specific (i.e., MAC and PHY) interrupts for the given
+ * adapter port.
+ */
+void t3_port_intr_disable(struct adapter *adapter, int idx)
+{
+ struct cphy *phy = &adap2pinfo(adapter, idx)->phy;
+
+ t3_write_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx), 0);
+ t3_read_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx)); /* flush */
+ phy->ops->intr_disable(phy);
+}
+
+/**
+ * t3_port_intr_clear - clear port-specific interrupts
+ * @adapter: associated adapter
+ * @idx: index of port whose interrupts to clear
+ *
+ * Clear port-specific (i.e., MAC and PHY) interrupts for the given
+ * adapter port.
+ */
+void t3_port_intr_clear(struct adapter *adapter, int idx)
+{
+ struct cphy *phy = &adap2pinfo(adapter, idx)->phy;
+
+ t3_write_reg(adapter, XGM_REG(A_XGM_INT_CAUSE, idx), 0xffffffff);
+ t3_read_reg(adapter, XGM_REG(A_XGM_INT_CAUSE, idx)); /* flush */
+ phy->ops->intr_clear(phy);
+}
+
+/**
+ * t3_sge_write_context - write an SGE context
+ * @adapter: the adapter
+ * @id: the context id
+ * @type: the context type
+ *
+ * Program an SGE context with the values already loaded in the
+ * CONTEXT_DATA? registers.
+ */
+static int t3_sge_write_context(struct adapter *adapter, unsigned int id,
+ unsigned int type)
+{
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0xffffffff);
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0xffffffff);
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0xffffffff);
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0xffffffff);
+ t3_write_reg(adapter, A_SG_CONTEXT_CMD,
+ V_CONTEXT_CMD_OPCODE(1) | type | V_CONTEXT(id));
+ return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
+ 0, 5, 1);
+}
+
+/**
+ * t3_sge_init_ecntxt - initialize an SGE egress context
+ * @adapter: the adapter to configure
+ * @id: the context id
+ * @gts_enable: whether to enable GTS for the context
+ * @type: the egress context type
+ * @respq: associated response queue
+ * @base_addr: base address of queue
+ * @size: number of queue entries
+ * @token: uP token
+ * @gen: initial generation value for the context
+ * @cidx: consumer pointer
+ *
+ * Initialize an SGE egress context and make it ready for use. If the
+ * platform allows concurrent context operations, the caller is
+ * responsible for appropriate locking.
+ */
+int t3_sge_init_ecntxt(struct adapter *adapter, unsigned int id, int gts_enable,
+ enum sge_context_type type, int respq, u64 base_addr,
+ unsigned int size, unsigned int token, int gen,
+ unsigned int cidx)
+{
+ unsigned int credits = type == SGE_CNTXT_OFLD ? 0 : FW_WR_NUM;
+
+ if (base_addr & 0xfff) /* must be 4K aligned */
+ return -EINVAL;
+ if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+ return -EBUSY;
+
+ base_addr >>= 12;
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_EC_INDEX(cidx) |
+ V_EC_CREDITS(credits) | V_EC_GTS(gts_enable));
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA1, V_EC_SIZE(size) |
+ V_EC_BASE_LO(base_addr & 0xffff));
+ base_addr >>= 16;
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA2, base_addr);
+ base_addr >>= 32;
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA3,
+ V_EC_BASE_HI(base_addr & 0xf) | V_EC_RESPQ(respq) |
+ V_EC_TYPE(type) | V_EC_GEN(gen) | V_EC_UP_TOKEN(token) |
+ F_EC_VALID);
+ return t3_sge_write_context(adapter, id, F_EGRESS);
+}
+
+/**
+ * t3_sge_init_flcntxt - initialize an SGE free-buffer list context
+ * @adapter: the adapter to configure
+ * @id: the context id
+ * @gts_enable: whether to enable GTS for the context
+ * @base_addr: base address of queue
+ * @size: number of queue entries
+ * @bsize: size of each buffer for this queue
+ * @cong_thres: threshold to signal congestion to upstream producers
+ * @gen: initial generation value for the context
+ * @cidx: consumer pointer
+ *
+ * Initialize an SGE free list context and make it ready for use. The
+ * caller is responsible for ensuring only one context operation occurs
+ * at a time.
+ */
+int t3_sge_init_flcntxt(struct adapter *adapter, unsigned int id,
+ int gts_enable, u64 base_addr, unsigned int size,
+ unsigned int bsize, unsigned int cong_thres, int gen,
+ unsigned int cidx)
+{
+ if (base_addr & 0xfff) /* must be 4K aligned */
+ return -EINVAL;
+ if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+ return -EBUSY;
+
+ base_addr >>= 12;
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA0, base_addr);
+ base_addr >>= 32;
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA1,
+ V_FL_BASE_HI((u32) base_addr) |
+ V_FL_INDEX_LO(cidx & M_FL_INDEX_LO));
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA2, V_FL_SIZE(size) |
+ V_FL_GEN(gen) | V_FL_INDEX_HI(cidx >> 12) |
+ V_FL_ENTRY_SIZE_LO(bsize & M_FL_ENTRY_SIZE_LO));
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA3,
+ V_FL_ENTRY_SIZE_HI(bsize >> (32 - S_FL_ENTRY_SIZE_LO)) |
+ V_FL_CONG_THRES(cong_thres) | V_FL_GTS(gts_enable));
+ return t3_sge_write_context(adapter, id, F_FREELIST);
+}
+
+/**
+ * t3_sge_init_rspcntxt - initialize an SGE response queue context
+ * @adapter: the adapter to configure
+ * @id: the context id
+ * @irq_vec_idx: MSI-X interrupt vector index, 0 if no MSI-X, -1 if no IRQ
+ * @base_addr: base address of queue
+ * @size: number of queue entries
+ * @fl_thres: threshold for selecting the normal or jumbo free list
+ * @gen: initial generation value for the context
+ * @cidx: consumer pointer
+ *
+ * Initialize an SGE response queue context and make it ready for use.
+ * The caller is responsible for ensuring only one context operation
+ * occurs at a time.
+ */
+int t3_sge_init_rspcntxt(struct adapter *adapter, unsigned int id,
+ int irq_vec_idx, u64 base_addr, unsigned int size,
+ unsigned int fl_thres, int gen, unsigned int cidx)
+{
+ unsigned int intr = 0;
+
+ if (base_addr & 0xfff) /* must be 4K aligned */
+ return -EINVAL;
+ if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+ return -EBUSY;
+
+ base_addr >>= 12;
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_CQ_SIZE(size) |
+ V_CQ_INDEX(cidx));
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA1, base_addr);
+ base_addr >>= 32;
+ if (irq_vec_idx >= 0)
+ intr = V_RQ_MSI_VEC(irq_vec_idx) | F_RQ_INTR_EN;
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA2,
+ V_CQ_BASE_HI((u32) base_addr) | intr | V_RQ_GEN(gen));
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA3, fl_thres);
+ return t3_sge_write_context(adapter, id, F_RESPONSEQ);
+}
+
+/**
+ * t3_sge_init_cqcntxt - initialize an SGE completion queue context
+ * @adapter: the adapter to configure
+ * @id: the context id
+ * @base_addr: base address of queue
+ * @size: number of queue entries
+ * @rspq: response queue for async notifications
+ * @ovfl_mode: CQ overflow mode
+ * @credits: completion queue credits
+ * @credit_thres: the credit threshold
+ *
+ * Initialize an SGE completion queue context and make it ready for use.
+ * The caller is responsible for ensuring only one context operation
+ * occurs at a time.
+ */
+int t3_sge_init_cqcntxt(struct adapter *adapter, unsigned int id, u64 base_addr,
+ unsigned int size, int rspq, int ovfl_mode,
+ unsigned int credits, unsigned int credit_thres)
+{
+ if (base_addr & 0xfff) /* must be 4K aligned */
+ return -EINVAL;
+ if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+ return -EBUSY;
+
+ base_addr >>= 12;
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_CQ_SIZE(size));
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA1, base_addr);
+ base_addr >>= 32;
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA2,
+ V_CQ_BASE_HI((u32) base_addr) | V_CQ_RSPQ(rspq) |
+ V_CQ_GEN(1) | V_CQ_OVERFLOW_MODE(ovfl_mode));
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_CQ_CREDITS(credits) |
+ V_CQ_CREDIT_THRES(credit_thres));
+ return t3_sge_write_context(adapter, id, F_CQ);
+}
+
+/**
+ * t3_sge_enable_ecntxt - enable/disable an SGE egress context
+ * @adapter: the adapter
+ * @id: the egress context id
+ * @enable: enable (1) or disable (0) the context
+ *
+ * Enable or disable an SGE egress context. The caller is responsible for
+ * ensuring only one context operation occurs at a time.
+ */
+int t3_sge_enable_ecntxt(struct adapter *adapter, unsigned int id, int enable)
+{
+ if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+ return -EBUSY;
+
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK3, F_EC_VALID);
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_EC_VALID(enable));
+ t3_write_reg(adapter, A_SG_CONTEXT_CMD,
+ V_CONTEXT_CMD_OPCODE(1) | F_EGRESS | V_CONTEXT(id));
+ return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
+ 0, 5, 1);
+}
+
+/**
+ * t3_sge_disable_fl - disable an SGE free-buffer list
+ * @adapter: the adapter
+ * @id: the free list context id
+ *
+ * Disable an SGE free-buffer list. The caller is responsible for
+ * ensuring only one context operation occurs at a time.
+ */
+int t3_sge_disable_fl(struct adapter *adapter, unsigned int id)
+{
+ if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+ return -EBUSY;
+
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK2, V_FL_SIZE(M_FL_SIZE));
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA2, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_CMD,
+ V_CONTEXT_CMD_OPCODE(1) | F_FREELIST | V_CONTEXT(id));
+ return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
+ 0, 5, 1);
+}
+
+/**
+ * t3_sge_disable_rspcntxt - disable an SGE response queue
+ * @adapter: the adapter
+ * @id: the response queue context id
+ *
+ * Disable an SGE response queue. The caller is responsible for
+ * ensuring only one context operation occurs at a time.
+ */
+int t3_sge_disable_rspcntxt(struct adapter *adapter, unsigned int id)
+{
+ if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+ return -EBUSY;
+
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK0, V_CQ_SIZE(M_CQ_SIZE));
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA0, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_CMD,
+ V_CONTEXT_CMD_OPCODE(1) | F_RESPONSEQ | V_CONTEXT(id));
+ return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
+ 0, 5, 1);
+}
+
+/**
+ * t3_sge_disable_cqcntxt - disable an SGE completion queue
+ * @adapter: the adapter
+ * @id: the completion queue context id
+ *
+ * Disable an SGE completion queue. The caller is responsible for
+ * ensuring only one context operation occurs at a time.
+ */
+int t3_sge_disable_cqcntxt(struct adapter *adapter, unsigned int id)
+{
+ if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+ return -EBUSY;
+
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK0, V_CQ_SIZE(M_CQ_SIZE));
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA0, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_CMD,
+ V_CONTEXT_CMD_OPCODE(1) | F_CQ | V_CONTEXT(id));
+ return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
+ 0, 5, 1);
+}
+
+/**
+ * t3_sge_cqcntxt_op - perform an operation on a completion queue context
+ * @adapter: the adapter
+ * @id: the context id
+ * @op: the operation to perform
+ *
+ * Perform the selected operation on an SGE completion queue context.
+ * The caller is responsible for ensuring only one context operation
+ * occurs at a time.
+ */
+int t3_sge_cqcntxt_op(struct adapter *adapter, unsigned int id, unsigned int op,
+ unsigned int credits)
+{
+ u32 val;
+
+ if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+ return -EBUSY;
+
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA0, credits << 16);
+ t3_write_reg(adapter, A_SG_CONTEXT_CMD, V_CONTEXT_CMD_OPCODE(op) |
+ V_CONTEXT(id) | F_CQ);
+ if (t3_wait_op_done_val(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
+ 0, 5, 1, &val))
+ return -EIO;
+
+ if (op >= 2 && op < 7) {
+ if (adapter->params.rev > 0)
+ return G_CQ_INDEX(val);
+
+ t3_write_reg(adapter, A_SG_CONTEXT_CMD,
+ V_CONTEXT_CMD_OPCODE(0) | F_CQ | V_CONTEXT(id));
+ if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD,
+ F_CONTEXT_CMD_BUSY, 0, 5, 1))
+ return -EIO;
+ return G_CQ_INDEX(t3_read_reg(adapter, A_SG_CONTEXT_DATA0));
+ }
+ return 0;
+}
+
+/**
+ * t3_sge_read_context - read an SGE context
+ * @type: the context type
+ * @adapter: the adapter
+ * @id: the context id
+ * @data: holds the retrieved context
+ *
+ * Read an SGE egress context. The caller is responsible for ensuring
+ * only one context operation occurs at a time.
+ */
+static int t3_sge_read_context(unsigned int type, struct adapter *adapter,
+ unsigned int id, u32 data[4])
+{
+ if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+ return -EBUSY;
+
+ t3_write_reg(adapter, A_SG_CONTEXT_CMD,
+ V_CONTEXT_CMD_OPCODE(0) | type | V_CONTEXT(id));
+ if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 0,
+ 5, 1))
+ return -EIO;
+ data[0] = t3_read_reg(adapter, A_SG_CONTEXT_DATA0);
+ data[1] = t3_read_reg(adapter, A_SG_CONTEXT_DATA1);
+ data[2] = t3_read_reg(adapter, A_SG_CONTEXT_DATA2);
+ data[3] = t3_read_reg(adapter, A_SG_CONTEXT_DATA3);
+ return 0;
+}
+
+/**
+ * t3_sge_read_ecntxt - read an SGE egress context
+ * @adapter: the adapter
+ * @id: the context id
+ * @data: holds the retrieved context
+ *
+ * Read an SGE egress context. The caller is responsible for ensuring
+ * only one context operation occurs at a time.
+ */
+int t3_sge_read_ecntxt(struct adapter *adapter, unsigned int id, u32 data[4])
+{
+ if (id >= 65536)
+ return -EINVAL;
+ return t3_sge_read_context(F_EGRESS, adapter, id, data);
+}
+
+/**
+ * t3_sge_read_cq - read an SGE CQ context
+ * @adapter: the adapter
+ * @id: the context id
+ * @data: holds the retrieved context
+ *
+ * Read an SGE CQ context. The caller is responsible for ensuring
+ * only one context operation occurs at a time.
+ */
+int t3_sge_read_cq(struct adapter *adapter, unsigned int id, u32 data[4])
+{
+ if (id >= 65536)
+ return -EINVAL;
+ return t3_sge_read_context(F_CQ, adapter, id, data);
+}
+
+/**
+ * t3_sge_read_fl - read an SGE free-list context
+ * @adapter: the adapter
+ * @id: the context id
+ * @data: holds the retrieved context
+ *
+ * Read an SGE free-list context. The caller is responsible for ensuring
+ * only one context operation occurs at a time.
+ */
+int t3_sge_read_fl(struct adapter *adapter, unsigned int id, u32 data[4])
+{
+ if (id >= SGE_QSETS * 2)
+ return -EINVAL;
+ return t3_sge_read_context(F_FREELIST, adapter, id, data);
+}
+
+/**
+ * t3_sge_read_rspq - read an SGE response queue context
+ * @adapter: the adapter
+ * @id: the context id
+ * @data: holds the retrieved context
+ *
+ * Read an SGE response queue context. The caller is responsible for
+ * ensuring only one context operation occurs at a time.
+ */
+int t3_sge_read_rspq(struct adapter *adapter, unsigned int id, u32 data[4])
+{
+ if (id >= SGE_QSETS)
+ return -EINVAL;
+ return t3_sge_read_context(F_RESPONSEQ, adapter, id, data);
+}
+
+/**
+ * t3_config_rss - configure Rx packet steering
+ * @adapter: the adapter
+ * @rss_config: RSS settings (written to TP_RSS_CONFIG)
+ * @cpus: values for the CPU lookup table (0xff terminated)
+ * @rspq: values for the response queue lookup table (0xffff terminated)
+ *
+ * Programs the receive packet steering logic. @cpus and @rspq provide
+ * the values for the CPU and response queue lookup tables. If they
+ * provide fewer values than the size of the tables the supplied values
+ * are used repeatedly until the tables are fully populated.
+ */
+void t3_config_rss(struct adapter *adapter, unsigned int rss_config,
+ const u8 * cpus, const u16 *rspq)
+{
+ int i, j, cpu_idx = 0, q_idx = 0;
+
+ if (cpus)
+ for (i = 0; i < RSS_TABLE_SIZE; ++i) {
+ u32 val = i << 16;
+
+ for (j = 0; j < 2; ++j) {
+ val |= (cpus[cpu_idx++] & 0x3f) << (8 * j);
+ if (cpus[cpu_idx] == 0xff)
+ cpu_idx = 0;
+ }
+ t3_write_reg(adapter, A_TP_RSS_LKP_TABLE, val);
+ }
+
+ if (rspq)
+ for (i = 0; i < RSS_TABLE_SIZE; ++i) {
+ t3_write_reg(adapter, A_TP_RSS_MAP_TABLE,
+ (i << 16) | rspq[q_idx++]);
+ if (rspq[q_idx] == 0xffff)
+ q_idx = 0;
+ }
+
+ t3_write_reg(adapter, A_TP_RSS_CONFIG, rss_config);
+}
+
+/**
+ * t3_read_rss - read the contents of the RSS tables
+ * @adapter: the adapter
+ * @lkup: holds the contents of the RSS lookup table
+ * @map: holds the contents of the RSS map table
+ *
+ * Reads the contents of the receive packet steering tables.
+ */
+int t3_read_rss(struct adapter *adapter, u8 * lkup, u16 *map)
+{
+ int i;
+ u32 val;
+
+ if (lkup)
+ for (i = 0; i < RSS_TABLE_SIZE; ++i) {
+ t3_write_reg(adapter, A_TP_RSS_LKP_TABLE,
+ 0xffff0000 | i);
+ val = t3_read_reg(adapter, A_TP_RSS_LKP_TABLE);
+ if (!(val & 0x80000000))
+ return -EAGAIN;
+ *lkup++ = val;
+ *lkup++ = (val >> 8);
+ }
+
+ if (map)
+ for (i = 0; i < RSS_TABLE_SIZE; ++i) {
+ t3_write_reg(adapter, A_TP_RSS_MAP_TABLE,
+ 0xffff0000 | i);
+ val = t3_read_reg(adapter, A_TP_RSS_MAP_TABLE);
+ if (!(val & 0x80000000))
+ return -EAGAIN;
+ *map++ = val;
+ }
+ return 0;
+}
+
+/**
+ * t3_tp_set_offload_mode - put TP in NIC/offload mode
+ * @adap: the adapter
+ * @enable: 1 to select offload mode, 0 for regular NIC
+ *
+ * Switches TP to NIC/offload mode.
+ */
+void t3_tp_set_offload_mode(struct adapter *adap, int enable)
+{
+ if (is_offload(adap) || !enable)
+ t3_set_reg_field(adap, A_TP_IN_CONFIG, F_NICMODE,
+ V_NICMODE(!enable));
+}
+
+/**
+ * pm_num_pages - calculate the number of pages of the payload memory
+ * @mem_size: the size of the payload memory
+ * @pg_size: the size of each payload memory page
+ *
+ * Calculate the number of pages, each of the given size, that fit in a
+ * memory of the specified size, respecting the HW requirement that the
+ * number of pages must be a multiple of 24.
+ */
+static inline unsigned int pm_num_pages(unsigned int mem_size,
+ unsigned int pg_size)
+{
+ unsigned int n = mem_size / pg_size;
+
+ return n - n % 24;
+}
+
+#define mem_region(adap, start, size, reg) \
+ t3_write_reg((adap), A_ ## reg, (start)); \
+ start += size
+
+/*
+ * partition_mem - partition memory and configure TP memory settings
+ * @adap: the adapter
+ * @p: the TP parameters
+ *
+ * Partitions context and payload memory and configures TP's memory
+ * registers.
+ */
+static void partition_mem(struct adapter *adap, const struct tp_params *p)
+{
+ unsigned int m, pstructs, tids = t3_mc5_size(&adap->mc5);
+ unsigned int timers = 0, timers_shift = 22;
+
+ if (adap->params.rev > 0) {
+ if (tids <= 16 * 1024) {
+ timers = 1;
+ timers_shift = 16;
+ } else if (tids <= 64 * 1024) {
+ timers = 2;
+ timers_shift = 18;
+ } else if (tids <= 256 * 1024) {
+ timers = 3;
+ timers_shift = 20;
+ }
+ }
+
+ t3_write_reg(adap, A_TP_PMM_SIZE,
+ p->chan_rx_size | (p->chan_tx_size >> 16));
+
+ t3_write_reg(adap, A_TP_PMM_TX_BASE, 0);
+ t3_write_reg(adap, A_TP_PMM_TX_PAGE_SIZE, p->tx_pg_size);
+ t3_write_reg(adap, A_TP_PMM_TX_MAX_PAGE, p->tx_num_pgs);
+ t3_set_reg_field(adap, A_TP_PARA_REG3, V_TXDATAACKIDX(M_TXDATAACKIDX),
+ V_TXDATAACKIDX(fls(p->tx_pg_size) - 12));
+
+ t3_write_reg(adap, A_TP_PMM_RX_BASE, 0);
+ t3_write_reg(adap, A_TP_PMM_RX_PAGE_SIZE, p->rx_pg_size);
+ t3_write_reg(adap, A_TP_PMM_RX_MAX_PAGE, p->rx_num_pgs);
+
+ pstructs = p->rx_num_pgs + p->tx_num_pgs;
+ /* Add a bit of headroom and make multiple of 24 */
+ pstructs += 48;
+ pstructs -= pstructs % 24;
+ t3_write_reg(adap, A_TP_CMM_MM_MAX_PSTRUCT, pstructs);
+
+ m = tids * TCB_SIZE;
+ mem_region(adap, m, (64 << 10) * 64, SG_EGR_CNTX_BADDR);
+ mem_region(adap, m, (64 << 10) * 64, SG_CQ_CONTEXT_BADDR);
+ t3_write_reg(adap, A_TP_CMM_TIMER_BASE, V_CMTIMERMAXNUM(timers) | m);
+ m += ((p->ntimer_qs - 1) << timers_shift) + (1 << 22);
+ mem_region(adap, m, pstructs * 64, TP_CMM_MM_BASE);
+ mem_region(adap, m, 64 * (pstructs / 24), TP_CMM_MM_PS_FLST_BASE);
+ mem_region(adap, m, 64 * (p->rx_num_pgs / 24), TP_CMM_MM_RX_FLST_BASE);
+ mem_region(adap, m, 64 * (p->tx_num_pgs / 24), TP_CMM_MM_TX_FLST_BASE);
+
+ m = (m + 4095) & ~0xfff;
+ t3_write_reg(adap, A_CIM_SDRAM_BASE_ADDR, m);
+ t3_write_reg(adap, A_CIM_SDRAM_ADDR_SIZE, p->cm_size - m);
+
+ tids = (p->cm_size - m - (3 << 20)) / 3072 - 32;
+ m = t3_mc5_size(&adap->mc5) - adap->params.mc5.nservers -
+ adap->params.mc5.nfilters - adap->params.mc5.nroutes;
+ if (tids < m)
+ adap->params.mc5.nservers += m - tids;
+}
+
+static inline void tp_wr_indirect(struct adapter *adap, unsigned int addr,
+ u32 val)
+{
+ t3_write_reg(adap, A_TP_PIO_ADDR, addr);
+ t3_write_reg(adap, A_TP_PIO_DATA, val);
+}
+
+static void tp_config(struct adapter *adap, const struct tp_params *p)
+{
+ t3_write_reg(adap, A_TP_GLOBAL_CONFIG, F_TXPACINGENABLE | F_PATHMTU |
+ F_IPCHECKSUMOFFLOAD | F_UDPCHECKSUMOFFLOAD |
+ F_TCPCHECKSUMOFFLOAD | V_IPTTL(64));
+ t3_write_reg(adap, A_TP_TCP_OPTIONS, V_MTUDEFAULT(576) |
+ F_MTUENABLE | V_WINDOWSCALEMODE(1) |
+ V_TIMESTAMPSMODE(1) | V_SACKMODE(1) | V_SACKRX(1));
+ t3_write_reg(adap, A_TP_DACK_CONFIG, V_AUTOSTATE3(1) |
+ V_AUTOSTATE2(1) | V_AUTOSTATE1(0) |
+ V_BYTETHRESHOLD(16384) | V_MSSTHRESHOLD(2) |
+ F_AUTOCAREFUL | F_AUTOENABLE | V_DACK_MODE(1));
+ t3_set_reg_field(adap, A_TP_IN_CONFIG, F_IPV6ENABLE | F_NICMODE,
+ F_IPV6ENABLE | F_NICMODE);
+ t3_write_reg(adap, A_TP_TX_RESOURCE_LIMIT, 0x18141814);
+ t3_write_reg(adap, A_TP_PARA_REG4, 0x5050105);
+ t3_set_reg_field(adap, A_TP_PARA_REG6,
+ adap->params.rev > 0 ? F_ENABLEESND : F_T3A_ENABLEESND,
+ 0);
+
+ t3_set_reg_field(adap, A_TP_PC_CONFIG,
+ F_ENABLEEPCMDAFULL | F_ENABLEOCSPIFULL,
+ F_TXDEFERENABLE | F_HEARBEATDACK | F_TXCONGESTIONMODE |
+ F_RXCONGESTIONMODE);
+ t3_set_reg_field(adap, A_TP_PC_CONFIG2, F_CHDRAFULL, 0);
+
+ if (adap->params.rev > 0) {
+ tp_wr_indirect(adap, A_TP_EGRESS_CONFIG, F_REWRITEFORCETOSIZE);
+ t3_set_reg_field(adap, A_TP_PARA_REG3, F_TXPACEAUTO,
+ F_TXPACEAUTO);
+ t3_set_reg_field(adap, A_TP_PC_CONFIG, F_LOCKTID, F_LOCKTID);
+ t3_set_reg_field(adap, A_TP_PARA_REG3, 0, F_TXPACEAUTOSTRICT);
+ } else
+ t3_set_reg_field(adap, A_TP_PARA_REG3, 0, F_TXPACEFIXED);
+
+ t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT1, 0x12121212);
+ t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT0, 0x12121212);
+ t3_write_reg(adap, A_TP_MOD_CHANNEL_WEIGHT, 0x1212);
+}
+
+/* Desired TP timer resolution in usec */
+#define TP_TMR_RES 50
+
+/* TCP timer values in ms */
+#define TP_DACK_TIMER 50
+#define TP_RTO_MIN 250
+
+/**
+ * tp_set_timers - set TP timing parameters
+ * @adap: the adapter to set
+ * @core_clk: the core clock frequency in Hz
+ *
+ * Set TP's timing parameters, such as the various timer resolutions and
+ * the TCP timer values.
+ */
+static void tp_set_timers(struct adapter *adap, unsigned int core_clk)
+{
+ unsigned int tre = fls(core_clk / (1000000 / TP_TMR_RES)) - 1;
+ unsigned int dack_re = fls(core_clk / 5000) - 1; /* 200us */
+ unsigned int tstamp_re = fls(core_clk / 1000); /* 1ms, at least */
+ unsigned int tps = core_clk >> tre;
+
+ t3_write_reg(adap, A_TP_TIMER_RESOLUTION, V_TIMERRESOLUTION(tre) |
+ V_DELAYEDACKRESOLUTION(dack_re) |
+ V_TIMESTAMPRESOLUTION(tstamp_re));
+ t3_write_reg(adap, A_TP_DACK_TIMER,
+ (core_clk >> dack_re) / (1000 / TP_DACK_TIMER));
+ t3_write_reg(adap, A_TP_TCP_BACKOFF_REG0, 0x3020100);
+ t3_write_reg(adap, A_TP_TCP_BACKOFF_REG1, 0x7060504);
+ t3_write_reg(adap, A_TP_TCP_BACKOFF_REG2, 0xb0a0908);
+ t3_write_reg(adap, A_TP_TCP_BACKOFF_REG3, 0xf0e0d0c);
+ t3_write_reg(adap, A_TP_SHIFT_CNT, V_SYNSHIFTMAX(6) |
+ V_RXTSHIFTMAXR1(4) | V_RXTSHIFTMAXR2(15) |
+ V_PERSHIFTBACKOFFMAX(8) | V_PERSHIFTMAX(8) |
+ V_KEEPALIVEMAX(9));
+
+#define SECONDS * tps
+
+ t3_write_reg(adap, A_TP_MSL, adap->params.rev > 0 ? 0 : 2 SECONDS);
+ t3_write_reg(adap, A_TP_RXT_MIN, tps / (1000 / TP_RTO_MIN));
+ t3_write_reg(adap, A_TP_RXT_MAX, 64 SECONDS);
+ t3_write_reg(adap, A_TP_PERS_MIN, 5 SECONDS);
+ t3_write_reg(adap, A_TP_PERS_MAX, 64 SECONDS);
+ t3_write_reg(adap, A_TP_KEEP_IDLE, 7200 SECONDS);
+ t3_write_reg(adap, A_TP_KEEP_INTVL, 75 SECONDS);
+ t3_write_reg(adap, A_TP_INIT_SRTT, 3 SECONDS);
+ t3_write_reg(adap, A_TP_FINWAIT2_TIMER, 600 SECONDS);
+
+#undef SECONDS
+}
+
+/**
+ * t3_tp_set_coalescing_size - set receive coalescing size
+ * @adap: the adapter
+ * @size: the receive coalescing size
+ * @psh: whether a set PSH bit should deliver coalesced data
+ *
+ * Set the receive coalescing size and PSH bit handling.
+ */
+int t3_tp_set_coalescing_size(struct adapter *adap, unsigned int size, int psh)
+{
+ u32 val;
+
+ if (size > MAX_RX_COALESCING_LEN)
+ return -EINVAL;
+
+ val = t3_read_reg(adap, A_TP_PARA_REG3);
+ val &= ~(F_RXCOALESCEENABLE | F_RXCOALESCEPSHEN);
+
+ if (size) {
+ val |= F_RXCOALESCEENABLE;
+ if (psh)
+ val |= F_RXCOALESCEPSHEN;
+ t3_write_reg(adap, A_TP_PARA_REG2, V_RXCOALESCESIZE(size) |
+ V_MAXRXDATA(MAX_RX_COALESCING_LEN));
+ }
+ t3_write_reg(adap, A_TP_PARA_REG3, val);
+ return 0;
+}
+
+/**
+ * t3_tp_set_max_rxsize - set the max receive size
+ * @adap: the adapter
+ * @size: the max receive size
+ *
+ * Set TP's max receive size. This is the limit that applies when
+ * receive coalescing is disabled.
+ */
+void t3_tp_set_max_rxsize(struct adapter *adap, unsigned int size)
+{
+ t3_write_reg(adap, A_TP_PARA_REG7,
+ V_PMMAXXFERLEN0(size) | V_PMMAXXFERLEN1(size));
+}
+
+static void __devinit init_mtus(unsigned short mtus[])
+{
+ /*
+ * See draft-mathis-plpmtud-00.txt for the values. The min is 88 so
+ * it can accomodate max size TCP/IP headers when SACK and timestamps
+ * are enabled and still have at least 8 bytes of payload.
+ */
+ mtus[0] = 88;
+ mtus[1] = 256;
+ mtus[2] = 512;
+ mtus[3] = 576;
+ mtus[4] = 808;
+ mtus[5] = 1024;
+ mtus[6] = 1280;
+ mtus[7] = 1492;
+ mtus[8] = 1500;
+ mtus[9] = 2002;
+ mtus[10] = 2048;
+ mtus[11] = 4096;
+ mtus[12] = 4352;
+ mtus[13] = 8192;
+ mtus[14] = 9000;
+ mtus[15] = 9600;
+}
+
+/*
+ * Initial congestion control parameters.
+ */
+static void __devinit init_cong_ctrl(unsigned short *a, unsigned short *b)
+{
+ a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = a[8] = 1;
+ a[9] = 2;
+ a[10] = 3;
+ a[11] = 4;
+ a[12] = 5;
+ a[13] = 6;
+ a[14] = 7;
+ a[15] = 8;
+ a[16] = 9;
+ a[17] = 10;
+ a[18] = 14;
+ a[19] = 17;
+ a[20] = 21;
+ a[21] = 25;
+ a[22] = 30;
+ a[23] = 35;
+ a[24] = 45;
+ a[25] = 60;
+ a[26] = 80;
+ a[27] = 100;
+ a[28] = 200;
+ a[29] = 300;
+ a[30] = 400;
+ a[31] = 500;
+
+ b[0] = b[1] = b[2] = b[3] = b[4] = b[5] = b[6] = b[7] = b[8] = 0;
+ b[9] = b[10] = 1;
+ b[11] = b[12] = 2;
+ b[13] = b[14] = b[15] = b[16] = 3;
+ b[17] = b[18] = b[19] = b[20] = b[21] = 4;
+ b[22] = b[23] = b[24] = b[25] = b[26] = b[27] = 5;
+ b[28] = b[29] = 6;
+ b[30] = b[31] = 7;
+}
+
+/* The minimum additive increment value for the congestion control table */
+#define CC_MIN_INCR 2U
+
+/**
+ * t3_load_mtus - write the MTU and congestion control HW tables
+ * @adap: the adapter
+ * @mtus: the unrestricted values for the MTU table
+ * @alphs: the values for the congestion control alpha parameter
+ * @beta: the values for the congestion control beta parameter
+ * @mtu_cap: the maximum permitted effective MTU
+ *
+ * Write the MTU table with the supplied MTUs capping each at &mtu_cap.
+ * Update the high-speed congestion control table with the supplied alpha,
+ * beta, and MTUs.
+ */
+void t3_load_mtus(struct adapter *adap, unsigned short mtus[NMTUS],
+ unsigned short alpha[NCCTRL_WIN],
+ unsigned short beta[NCCTRL_WIN], unsigned short mtu_cap)
+{
+ static const unsigned int avg_pkts[NCCTRL_WIN] = {
+ 2, 6, 10, 14, 20, 28, 40, 56, 80, 112, 160, 224, 320, 448, 640,
+ 896, 1281, 1792, 2560, 3584, 5120, 7168, 10240, 14336, 20480,
+ 28672, 40960, 57344, 81920, 114688, 163840, 229376
+ };
+
+ unsigned int i, w;
+
+ for (i = 0; i < NMTUS; ++i) {
+ unsigned int mtu = min(mtus[i], mtu_cap);
+ unsigned int log2 = fls(mtu);
+
+ if (!(mtu & ((1 << log2) >> 2))) /* round */
+ log2--;
+ t3_write_reg(adap, A_TP_MTU_TABLE,
+ (i << 24) | (log2 << 16) | mtu);
+
+ for (w = 0; w < NCCTRL_WIN; ++w) {
+ unsigned int inc;
+
+ inc = max(((mtu - 40) * alpha[w]) / avg_pkts[w],
+ CC_MIN_INCR);
+
+ t3_write_reg(adap, A_TP_CCTRL_TABLE, (i << 21) |
+ (w << 16) | (beta[w] << 13) | inc);
+ }
+ }
+}
+
+/**
+ * t3_read_hw_mtus - returns the values in the HW MTU table
+ * @adap: the adapter
+ * @mtus: where to store the HW MTU values
+ *
+ * Reads the HW MTU table.
+ */
+void t3_read_hw_mtus(struct adapter *adap, unsigned short mtus[NMTUS])
+{
+ int i;
+
+ for (i = 0; i < NMTUS; ++i) {
+ unsigned int val;
+
+ t3_write_reg(adap, A_TP_MTU_TABLE, 0xff000000 | i);
+ val = t3_read_reg(adap, A_TP_MTU_TABLE);
+ mtus[i] = val & 0x3fff;
+ }
+}
+
+/**
+ * t3_get_cong_cntl_tab - reads the congestion control table
+ * @adap: the adapter
+ * @incr: where to store the alpha values
+ *
+ * Reads the additive increments programmed into the HW congestion
+ * control table.
+ */
+void t3_get_cong_cntl_tab(struct adapter *adap,
+ unsigned short incr[NMTUS][NCCTRL_WIN])
+{
+ unsigned int mtu, w;
+
+ for (mtu = 0; mtu < NMTUS; ++mtu)
+ for (w = 0; w < NCCTRL_WIN; ++w) {
+ t3_write_reg(adap, A_TP_CCTRL_TABLE,
+ 0xffff0000 | (mtu << 5) | w);
+ incr[mtu][w] = t3_read_reg(adap, A_TP_CCTRL_TABLE) &
+ 0x1fff;
+ }
+}
+
+/**
+ * t3_tp_get_mib_stats - read TP's MIB counters
+ * @adap: the adapter
+ * @tps: holds the returned counter values
+ *
+ * Returns the values of TP's MIB counters.
+ */
+void t3_tp_get_mib_stats(struct adapter *adap, struct tp_mib_stats *tps)
+{
+ t3_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_RDATA, (u32 *) tps,
+ sizeof(*tps) / sizeof(u32), 0);
+}
+
+#define ulp_region(adap, name, start, len) \
+ t3_write_reg((adap), A_ULPRX_ ## name ## _LLIMIT, (start)); \
+ t3_write_reg((adap), A_ULPRX_ ## name ## _ULIMIT, \
+ (start) + (len) - 1); \
+ start += len
+
+#define ulptx_region(adap, name, start, len) \
+ t3_write_reg((adap), A_ULPTX_ ## name ## _LLIMIT, (start)); \
+ t3_write_reg((adap), A_ULPTX_ ## name ## _ULIMIT, \
+ (start) + (len) - 1)
+
+static void ulp_config(struct adapter *adap, const struct tp_params *p)
+{
+ unsigned int m = p->chan_rx_size;
+
+ ulp_region(adap, ISCSI, m, p->chan_rx_size / 8);
+ ulp_region(adap, TDDP, m, p->chan_rx_size / 8);
+ ulptx_region(adap, TPT, m, p->chan_rx_size / 4);
+ ulp_region(adap, STAG, m, p->chan_rx_size / 4);
+ ulp_region(adap, RQ, m, p->chan_rx_size / 4);
+ ulptx_region(adap, PBL, m, p->chan_rx_size / 4);
+ ulp_region(adap, PBL, m, p->chan_rx_size / 4);
+ t3_write_reg(adap, A_ULPRX_TDDP_TAGMASK, 0xffffffff);
+}
+
+void t3_config_trace_filter(struct adapter *adapter,
+ const struct trace_params *tp, int filter_index,
+ int invert, int enable)
+{
+ u32 addr, key[4], mask[4];
+
+ key[0] = tp->sport | (tp->sip << 16);
+ key[1] = (tp->sip >> 16) | (tp->dport << 16);
+ key[2] = tp->dip;
+ key[3] = tp->proto | (tp->vlan << 8) | (tp->intf << 20);
+
+ mask[0] = tp->sport_mask | (tp->sip_mask << 16);
+ mask[1] = (tp->sip_mask >> 16) | (tp->dport_mask << 16);
+ mask[2] = tp->dip_mask;
+ mask[3] = tp->proto_mask | (tp->vlan_mask << 8) | (tp->intf_mask << 20);
+
+ if (invert)
+ key[3] |= (1 << 29);
+ if (enable)
+ key[3] |= (1 << 28);
+
+ addr = filter_index ? A_TP_RX_TRC_KEY0 : A_TP_TX_TRC_KEY0;
+ tp_wr_indirect(adapter, addr++, key[0]);
+ tp_wr_indirect(adapter, addr++, mask[0]);
+ tp_wr_indirect(adapter, addr++, key[1]);
+ tp_wr_indirect(adapter, addr++, mask[1]);
+ tp_wr_indirect(adapter, addr++, key[2]);
+ tp_wr_indirect(adapter, addr++, mask[2]);
+ tp_wr_indirect(adapter, addr++, key[3]);
+ tp_wr_indirect(adapter, addr, mask[3]);
+ t3_read_reg(adapter, A_TP_PIO_DATA);
+}
+
+/**
+ * t3_config_sched - configure a HW traffic scheduler
+ * @adap: the adapter
+ * @kbps: target rate in Kbps
+ * @sched: the scheduler index
+ *
+ * Configure a HW scheduler for the target rate
+ */
+int t3_config_sched(struct adapter *adap, unsigned int kbps, int sched)
+{
+ unsigned int v, tps, cpt, bpt, delta, mindelta = ~0;
+ unsigned int clk = adap->params.vpd.cclk * 1000;
+ unsigned int selected_cpt = 0, selected_bpt = 0;
+
+ if (kbps > 0) {
+ kbps *= 125; /* -> bytes */
+ for (cpt = 1; cpt <= 255; cpt++) {
+ tps = clk / cpt;
+ bpt = (kbps + tps / 2) / tps;
+ if (bpt > 0 && bpt <= 255) {
+ v = bpt * tps;
+ delta = v >= kbps ? v - kbps : kbps - v;
+ if (delta <= mindelta) {
+ mindelta = delta;
+ selected_cpt = cpt;
+ selected_bpt = bpt;
+ }
+ } else if (selected_cpt)
+ break;
+ }
+ if (!selected_cpt)
+ return -EINVAL;
+ }
+ t3_write_reg(adap, A_TP_TM_PIO_ADDR,
+ A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2);
+ v = t3_read_reg(adap, A_TP_TM_PIO_DATA);
+ if (sched & 1)
+ v = (v & 0xffff) | (selected_cpt << 16) | (selected_bpt << 24);
+ else
+ v = (v & 0xffff0000) | selected_cpt | (selected_bpt << 8);
+ t3_write_reg(adap, A_TP_TM_PIO_DATA, v);
+ return 0;
+}
+
+static int tp_init(struct adapter *adap, const struct tp_params *p)
+{
+ int busy = 0;
+
+ tp_config(adap, p);
+ t3_set_vlan_accel(adap, 3, 0);
+
+ if (is_offload(adap)) {
+ tp_set_timers(adap, adap->params.vpd.cclk * 1000);
+ t3_write_reg(adap, A_TP_RESET, F_FLSTINITENABLE);
+ busy = t3_wait_op_done(adap, A_TP_RESET, F_FLSTINITENABLE,
+ 0, 1000, 5);
+ if (busy)
+ CH_ERR(adap, "TP initialization timed out\n");
+ }
+
+ if (!busy)
+ t3_write_reg(adap, A_TP_RESET, F_TPRESET);
+ return busy;
+}
+
+int t3_mps_set_active_ports(struct adapter *adap, unsigned int port_mask)
+{
+ if (port_mask & ~((1 << adap->params.nports) - 1))
+ return -EINVAL;
+ t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE | F_PORT0ACTIVE,
+ port_mask << S_PORT0ACTIVE);
+ return 0;
+}
+
+/*
+ * Perform the bits of HW initialization that are dependent on the number
+ * of available ports.
+ */
+static void init_hw_for_avail_ports(struct adapter *adap, int nports)
+{
+ int i;
+
+ if (nports == 1) {
+ t3_set_reg_field(adap, A_ULPRX_CTL, F_ROUND_ROBIN, 0);
+ t3_set_reg_field(adap, A_ULPTX_CONFIG, F_CFG_RR_ARB, 0);
+ t3_write_reg(adap, A_MPS_CFG, F_TPRXPORTEN | F_TPTXPORT0EN |
+ F_PORT0ACTIVE | F_ENFORCEPKT);
+ t3_write_reg(adap, A_PM1_TX_CFG, 0xc000c000);
+ } else {
+ t3_set_reg_field(adap, A_ULPRX_CTL, 0, F_ROUND_ROBIN);
+ t3_set_reg_field(adap, A_ULPTX_CONFIG, 0, F_CFG_RR_ARB);
+ t3_write_reg(adap, A_ULPTX_DMA_WEIGHT,
+ V_D1_WEIGHT(16) | V_D0_WEIGHT(16));
+ t3_write_reg(adap, A_MPS_CFG, F_TPTXPORT0EN | F_TPTXPORT1EN |
+ F_TPRXPORTEN | F_PORT0ACTIVE | F_PORT1ACTIVE |
+ F_ENFORCEPKT);
+ t3_write_reg(adap, A_PM1_TX_CFG, 0x80008000);
+ t3_set_reg_field(adap, A_TP_PC_CONFIG, 0, F_TXTOSQUEUEMAPMODE);
+ t3_write_reg(adap, A_TP_TX_MOD_QUEUE_REQ_MAP,
+ V_TX_MOD_QUEUE_REQ_MAP(0xaa));
+ for (i = 0; i < 16; i++)
+ t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE,
+ (i << 16) | 0x1010);
+ }
+}
+
+static int calibrate_xgm(struct adapter *adapter)
+{
+ if (uses_xaui(adapter)) {
+ unsigned int v, i;
+
+ for (i = 0; i < 5; ++i) {
+ t3_write_reg(adapter, A_XGM_XAUI_IMP, 0);
+ t3_read_reg(adapter, A_XGM_XAUI_IMP);
+ msleep(1);
+ v = t3_read_reg(adapter, A_XGM_XAUI_IMP);
+ if (!(v & (F_XGM_CALFAULT | F_CALBUSY))) {
+ t3_write_reg(adapter, A_XGM_XAUI_IMP,
+ V_XAUIIMP(G_CALIMP(v) >> 2));
+ return 0;
+ }
+ }
+ CH_ERR(adapter, "MAC calibration failed\n");
+ return -1;
+ } else {
+ t3_write_reg(adapter, A_XGM_RGMII_IMP,
+ V_RGMIIIMPPD(2) | V_RGMIIIMPPU(3));
+ t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_XGM_IMPSETUPDATE,
+ F_XGM_IMPSETUPDATE);
+ }
+ return 0;
+}
+
+static void calibrate_xgm_t3b(struct adapter *adapter)
+{
+ if (!uses_xaui(adapter)) {
+ t3_write_reg(adapter, A_XGM_RGMII_IMP, F_CALRESET |
+ F_CALUPDATE | V_RGMIIIMPPD(2) | V_RGMIIIMPPU(3));
+ t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_CALRESET, 0);
+ t3_set_reg_field(adapter, A_XGM_RGMII_IMP, 0,
+ F_XGM_IMPSETUPDATE);
+ t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_XGM_IMPSETUPDATE,
+ 0);
+ t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_CALUPDATE, 0);
+ t3_set_reg_field(adapter, A_XGM_RGMII_IMP, 0, F_CALUPDATE);
+ }
+}
+
+struct mc7_timing_params {
+ unsigned char ActToPreDly;
+ unsigned char ActToRdWrDly;
+ unsigned char PreCyc;
+ unsigned char RefCyc[5];
+ unsigned char BkCyc;
+ unsigned char WrToRdDly;
+ unsigned char RdToWrDly;
+};
+
+/*
+ * Write a value to a register and check that the write completed. These
+ * writes normally complete in a cycle or two, so one read should suffice.
+ * The very first read exists to flush the posted write to the device.
+ */
+static int wrreg_wait(struct adapter *adapter, unsigned int addr, u32 val)
+{
+ t3_write_reg(adapter, addr, val);
+ t3_read_reg(adapter, addr); /* flush */
+ if (!(t3_read_reg(adapter, addr) & F_BUSY))
+ return 0;
+ CH_ERR(adapter, "write to MC7 register 0x%x timed out\n", addr);
+ return -EIO;
+}
+
+static int mc7_init(struct mc7 *mc7, unsigned int mc7_clock, int mem_type)
+{
+ static const unsigned int mc7_mode[] = {
+ 0x632, 0x642, 0x652, 0x432, 0x442
+ };
+ static const struct mc7_timing_params mc7_timings[] = {
+ {12, 3, 4, {20, 28, 34, 52, 0}, 15, 6, 4},
+ {12, 4, 5, {20, 28, 34, 52, 0}, 16, 7, 4},
+ {12, 5, 6, {20, 28, 34, 52, 0}, 17, 8, 4},
+ {9, 3, 4, {15, 21, 26, 39, 0}, 12, 6, 4},
+ {9, 4, 5, {15, 21, 26, 39, 0}, 13, 7, 4}
+ };
+
+ u32 val;
+ unsigned int width, density, slow, attempts;
+ struct adapter *adapter = mc7->adapter;
+ const struct mc7_timing_params *p = &mc7_timings[mem_type];
+
+ val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG);
+ slow = val & F_SLOW;
+ width = G_WIDTH(val);
+ density = G_DEN(val);
+
+ t3_write_reg(adapter, mc7->offset + A_MC7_CFG, val | F_IFEN);
+ val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG); /* flush */
+ msleep(1);
+
+ if (!slow) {
+ t3_write_reg(adapter, mc7->offset + A_MC7_CAL, F_SGL_CAL_EN);
+ t3_read_reg(adapter, mc7->offset + A_MC7_CAL);
+ msleep(1);
+ if (t3_read_reg(adapter, mc7->offset + A_MC7_CAL) &
+ (F_BUSY | F_SGL_CAL_EN | F_CAL_FAULT)) {
+ CH_ERR(adapter, "%s MC7 calibration timed out\n",
+ mc7->name);
+ goto out_fail;
+ }
+ }
+
+ t3_write_reg(adapter, mc7->offset + A_MC7_PARM,
+ V_ACTTOPREDLY(p->ActToPreDly) |
+ V_ACTTORDWRDLY(p->ActToRdWrDly) | V_PRECYC(p->PreCyc) |
+ V_REFCYC(p->RefCyc[density]) | V_BKCYC(p->BkCyc) |
+ V_WRTORDDLY(p->WrToRdDly) | V_RDTOWRDLY(p->RdToWrDly));
+
+ t3_write_reg(adapter, mc7->offset + A_MC7_CFG,
+ val | F_CLKEN | F_TERM150);
+ t3_read_reg(adapter, mc7->offset + A_MC7_CFG); /* flush */
+
+ if (!slow)
+ t3_set_reg_field(adapter, mc7->offset + A_MC7_DLL, F_DLLENB,
+ F_DLLENB);
+ udelay(1);
+
+ val = slow ? 3 : 6;
+ if (wrreg_wait(adapter, mc7->offset + A_MC7_PRE, 0) ||
+ wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE2, 0) ||
+ wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE3, 0) ||
+ wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val))
+ goto out_fail;
+
+ if (!slow) {
+ t3_write_reg(adapter, mc7->offset + A_MC7_MODE, 0x100);
+ t3_set_reg_field(adapter, mc7->offset + A_MC7_DLL, F_DLLRST, 0);
+ udelay(5);
+ }
+
+ if (wrreg_wait(adapter, mc7->offset + A_MC7_PRE, 0) ||
+ wrreg_wait(adapter, mc7->offset + A_MC7_REF, 0) ||
+ wrreg_wait(adapter, mc7->offset + A_MC7_REF, 0) ||
+ wrreg_wait(adapter, mc7->offset + A_MC7_MODE,
+ mc7_mode[mem_type]) ||
+ wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val | 0x380) ||
+ wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val))
+ goto out_fail;
+
+ /* clock value is in KHz */
+ mc7_clock = mc7_clock * 7812 + mc7_clock / 2; /* ns */
+ mc7_clock /= 1000000; /* KHz->MHz, ns->us */
+
+ t3_write_reg(adapter, mc7->offset + A_MC7_REF,
+ F_PERREFEN | V_PREREFDIV(mc7_clock));
+ t3_read_reg(adapter, mc7->offset + A_MC7_REF); /* flush */
+
+ t3_write_reg(adapter, mc7->offset + A_MC7_ECC, F_ECCGENEN | F_ECCCHKEN);
+ t3_write_reg(adapter, mc7->offset + A_MC7_BIST_DATA, 0);
+ t3_write_reg(adapter, mc7->offset + A_MC7_BIST_ADDR_BEG, 0);
+ t3_write_reg(adapter, mc7->offset + A_MC7_BIST_ADDR_END,
+ (mc7->size << width) - 1);
+ t3_write_reg(adapter, mc7->offset + A_MC7_BIST_OP, V_OP(1));
+ t3_read_reg(adapter, mc7->offset + A_MC7_BIST_OP); /* flush */
+
+ attempts = 50;
+ do {
+ msleep(250);
+ val = t3_read_reg(adapter, mc7->offset + A_MC7_BIST_OP);
+ } while ((val & F_BUSY) && --attempts);
+ if (val & F_BUSY) {
+ CH_ERR(adapter, "%s MC7 BIST timed out\n", mc7->name);
+ goto out_fail;
+ }
+
+ /* Enable normal memory accesses. */
+ t3_set_reg_field(adapter, mc7->offset + A_MC7_CFG, 0, F_RDY);
+ return 0;
+
+out_fail:
+ return -1;
+}
+
+static void config_pcie(struct adapter *adap)
+{
+ static const u16 ack_lat[4][6] = {
+ {237, 416, 559, 1071, 2095, 4143},
+ {128, 217, 289, 545, 1057, 2081},
+ {73, 118, 154, 282, 538, 1050},
+ {67, 107, 86, 150, 278, 534}
+ };
+ static const u16 rpl_tmr[4][6] = {
+ {711, 1248, 1677, 3213, 6285, 12429},
+ {384, 651, 867, 1635, 3171, 6243},
+ {219, 354, 462, 846, 1614, 3150},
+ {201, 321, 258, 450, 834, 1602}
+ };
+
+ u16 val;
+ unsigned int log2_width, pldsize;
+ unsigned int fst_trn_rx, fst_trn_tx, acklat, rpllmt;
+
+ pci_read_config_word(adap->pdev,
+ adap->params.pci.pcie_cap_addr + PCI_EXP_DEVCTL,
+ &val);
+ pldsize = (val & PCI_EXP_DEVCTL_PAYLOAD) >> 5;
+ pci_read_config_word(adap->pdev,
+ adap->params.pci.pcie_cap_addr + PCI_EXP_LNKCTL,
+ &val);
+
+ fst_trn_tx = G_NUMFSTTRNSEQ(t3_read_reg(adap, A_PCIE_PEX_CTRL0));
+ fst_trn_rx = adap->params.rev == 0 ? fst_trn_tx :
+ G_NUMFSTTRNSEQRX(t3_read_reg(adap, A_PCIE_MODE));
+ log2_width = fls(adap->params.pci.width) - 1;
+ acklat = ack_lat[log2_width][pldsize];
+ if (val & 1) /* check LOsEnable */
+ acklat += fst_trn_tx * 4;
+ rpllmt = rpl_tmr[log2_width][pldsize] + fst_trn_rx * 4;
+
+ if (adap->params.rev == 0)
+ t3_set_reg_field(adap, A_PCIE_PEX_CTRL1,
+ V_T3A_ACKLAT(M_T3A_ACKLAT),
+ V_T3A_ACKLAT(acklat));
+ else
+ t3_set_reg_field(adap, A_PCIE_PEX_CTRL1, V_ACKLAT(M_ACKLAT),
+ V_ACKLAT(acklat));
+
+ t3_set_reg_field(adap, A_PCIE_PEX_CTRL0, V_REPLAYLMT(M_REPLAYLMT),
+ V_REPLAYLMT(rpllmt));
+
+ t3_write_reg(adap, A_PCIE_PEX_ERR, 0xffffffff);
+ t3_set_reg_field(adap, A_PCIE_CFG, F_PCIE_CLIDECEN, F_PCIE_CLIDECEN);
+}
+
+/*
+ * Initialize and configure T3 HW modules. This performs the
+ * initialization steps that need to be done once after a card is reset.
+ * MAC and PHY initialization is handled separarely whenever a port is enabled.
+ *
+ * fw_params are passed to FW and their value is platform dependent. Only the
+ * top 8 bits are available for use, the rest must be 0.
+ */
+int t3_init_hw(struct adapter *adapter, u32 fw_params)
+{
+ int err = -EIO, attempts = 100;
+ const struct vpd_params *vpd = &adapter->params.vpd;
+
+ if (adapter->params.rev > 0)
+ calibrate_xgm_t3b(adapter);
+ else if (calibrate_xgm(adapter))
+ goto out_err;
+
+ if (vpd->mclk) {
+ partition_mem(adapter, &adapter->params.tp);
+
+ if (mc7_init(&adapter->pmrx, vpd->mclk, vpd->mem_timing) ||
+ mc7_init(&adapter->pmtx, vpd->mclk, vpd->mem_timing) ||
+ mc7_init(&adapter->cm, vpd->mclk, vpd->mem_timing) ||
+ t3_mc5_init(&adapter->mc5, adapter->params.mc5.nservers,
+ adapter->params.mc5.nfilters,
+ adapter->params.mc5.nroutes))
+ goto out_err;
+ }
+
+ if (tp_init(adapter, &adapter->params.tp))
+ goto out_err;
+
+ t3_tp_set_coalescing_size(adapter,
+ min(adapter->params.sge.max_pkt_size,
+ MAX_RX_COALESCING_LEN), 1);
+ t3_tp_set_max_rxsize(adapter,
+ min(adapter->params.sge.max_pkt_size, 16384U));
+ ulp_config(adapter, &adapter->params.tp);
+
+ if (is_pcie(adapter))
+ config_pcie(adapter);
+ else
+ t3_set_reg_field(adapter, A_PCIX_CFG, 0, F_CLIDECEN);
+
+ t3_write_reg(adapter, A_PM1_RX_CFG, 0xf000f000);
+ init_hw_for_avail_ports(adapter, adapter->params.nports);
+ t3_sge_init(adapter, &adapter->params.sge);
+
+ t3_write_reg(adapter, A_CIM_HOST_ACC_DATA, vpd->uclk | fw_params);
+ t3_write_reg(adapter, A_CIM_BOOT_CFG,
+ V_BOOTADDR(FW_FLASH_BOOT_ADDR >> 2));
+ t3_read_reg(adapter, A_CIM_BOOT_CFG); /* flush */
+
+ do { /* wait for uP to initialize */
+ msleep(20);
+ } while (t3_read_reg(adapter, A_CIM_HOST_ACC_DATA) && --attempts);
+ if (!attempts)
+ goto out_err;
+
+ err = 0;
+out_err:
+ return err;
+}
+
+/**
+ * get_pci_mode - determine a card's PCI mode
+ * @adapter: the adapter
+ * @p: where to store the PCI settings
+ *
+ * Determines a card's PCI mode and associated parameters, such as speed
+ * and width.
+ */
+static void __devinit get_pci_mode(struct adapter *adapter,
+ struct pci_params *p)
+{
+ static unsigned short speed_map[] = { 33, 66, 100, 133 };
+ u32 pci_mode, pcie_cap;
+
+ pcie_cap = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP);
+ if (pcie_cap) {
+ u16 val;
+
+ p->variant = PCI_VARIANT_PCIE;
+ p->pcie_cap_addr = pcie_cap;
+ pci_read_config_word(adapter->pdev, pcie_cap + PCI_EXP_LNKSTA,
+ &val);
+ p->width = (val >> 4) & 0x3f;
+ return;
+ }
+
+ pci_mode = t3_read_reg(adapter, A_PCIX_MODE);
+ p->speed = speed_map[G_PCLKRANGE(pci_mode)];
+ p->width = (pci_mode & F_64BIT) ? 64 : 32;
+ pci_mode = G_PCIXINITPAT(pci_mode);
+ if (pci_mode == 0)
+ p->variant = PCI_VARIANT_PCI;
+ else if (pci_mode < 4)
+ p->variant = PCI_VARIANT_PCIX_MODE1_PARITY;
+ else if (pci_mode < 8)
+ p->variant = PCI_VARIANT_PCIX_MODE1_ECC;
+ else
+ p->variant = PCI_VARIANT_PCIX_266_MODE2;
+}
+
+/**
+ * init_link_config - initialize a link's SW state
+ * @lc: structure holding the link state
+ * @ai: information about the current card
+ *
+ * Initializes the SW state maintained for each link, including the link's
+ * capabilities and default speed/duplex/flow-control/autonegotiation
+ * settings.
+ */
+static void __devinit init_link_config(struct link_config *lc,
+ unsigned int caps)
+{
+ lc->supported = caps;
+ lc->requested_speed = lc->speed = SPEED_INVALID;
+ lc->requested_duplex = lc->duplex = DUPLEX_INVALID;
+ lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX;
+ if (lc->supported & SUPPORTED_Autoneg) {
+ lc->advertising = lc->supported;
+ lc->autoneg = AUTONEG_ENABLE;
+ lc->requested_fc |= PAUSE_AUTONEG;
+ } else {
+ lc->advertising = 0;
+ lc->autoneg = AUTONEG_DISABLE;
+ }
+}
+
+/**
+ * mc7_calc_size - calculate MC7 memory size
+ * @cfg: the MC7 configuration
+ *
+ * Calculates the size of an MC7 memory in bytes from the value of its
+ * configuration register.
+ */
+static unsigned int __devinit mc7_calc_size(u32 cfg)
+{
+ unsigned int width = G_WIDTH(cfg);
+ unsigned int banks = !!(cfg & F_BKS) + 1;
+ unsigned int org = !!(cfg & F_ORG) + 1;
+ unsigned int density = G_DEN(cfg);
+ unsigned int MBs = ((256 << density) * banks) / (org << width);
+
+ return MBs << 20;
+}
+
+static void __devinit mc7_prep(struct adapter *adapter, struct mc7 *mc7,
+ unsigned int base_addr, const char *name)
+{
+ u32 cfg;
+
+ mc7->adapter = adapter;
+ mc7->name = name;
+ mc7->offset = base_addr - MC7_PMRX_BASE_ADDR;
+ cfg = t3_read_reg(adapter, mc7->offset + A_MC7_CFG);
+ mc7->size = mc7_calc_size(cfg);
+ mc7->width = G_WIDTH(cfg);
+}
+
+void mac_prep(struct cmac *mac, struct adapter *adapter, int index)
+{
+ mac->adapter = adapter;
+ mac->offset = (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR) * index;
+ mac->nucast = 1;
+
+ if (adapter->params.rev == 0 && uses_xaui(adapter)) {
+ t3_write_reg(adapter, A_XGM_SERDES_CTRL + mac->offset,
+ is_10G(adapter) ? 0x2901c04 : 0x2301c04);
+ t3_set_reg_field(adapter, A_XGM_PORT_CFG + mac->offset,
+ F_ENRGMII, 0);
+ }
+}
+
+void early_hw_init(struct adapter *adapter, const struct adapter_info *ai)
+{
+ u32 val = V_PORTSPEED(is_10G(adapter) ? 3 : 2);
+
+ mi1_init(adapter, ai);
+ t3_write_reg(adapter, A_I2C_CFG, /* set for 80KHz */
+ V_I2C_CLKDIV(adapter->params.vpd.cclk / 80 - 1));
+ t3_write_reg(adapter, A_T3DBG_GPIO_EN,
+ ai->gpio_out | F_GPIO0_OEN | F_GPIO0_OUT_VAL);
+
+ if (adapter->params.rev == 0 || !uses_xaui(adapter))
+ val |= F_ENRGMII;
+
+ /* Enable MAC clocks so we can access the registers */
+ t3_write_reg(adapter, A_XGM_PORT_CFG, val);
+ t3_read_reg(adapter, A_XGM_PORT_CFG);
+
+ val |= F_CLKDIVRESET_;
+ t3_write_reg(adapter, A_XGM_PORT_CFG, val);
+ t3_read_reg(adapter, A_XGM_PORT_CFG);
+ t3_write_reg(adapter, XGM_REG(A_XGM_PORT_CFG, 1), val);
+ t3_read_reg(adapter, A_XGM_PORT_CFG);
+}
+
+/*
+ * Reset the adapter. PCIe cards lose their config space during reset, PCI-X
+ * ones don't.
+ */
+int t3_reset_adapter(struct adapter *adapter)
+{
+ int i;
+ uint16_t devid = 0;
+
+ if (is_pcie(adapter))
+ pci_save_state(adapter->pdev);
+ t3_write_reg(adapter, A_PL_RST, F_CRSTWRM | F_CRSTWRMMODE);
+
+ /*
+ * Delay. Give Some time to device to reset fully.
+ * XXX The delay time should be modified.
+ */
+ for (i = 0; i < 10; i++) {
+ msleep(50);
+ pci_read_config_word(adapter->pdev, 0x00, &devid);
+ if (devid == 0x1425)
+ break;
+ }
+
+ if (devid != 0x1425)
+ return -1;
+
+ if (is_pcie(adapter))
+ pci_restore_state(adapter->pdev);
+ return 0;
+}
+
+/*
+ * Initialize adapter SW state for the various HW modules, set initial values
+ * for some adapter tunables, take PHYs out of reset, and initialize the MDIO
+ * interface.
+ */
+int __devinit t3_prep_adapter(struct adapter *adapter,
+ const struct adapter_info *ai, int reset)
+{
+ int ret;
+ unsigned int i, j = 0;
+
+ get_pci_mode(adapter, &adapter->params.pci);
+
+ adapter->params.info = ai;
+ adapter->params.nports = ai->nports;
+ adapter->params.rev = t3_read_reg(adapter, A_PL_REV);
+ adapter->params.linkpoll_period = 0;
+ adapter->params.stats_update_period = is_10G(adapter) ?
+ MAC_STATS_ACCUM_SECS : (MAC_STATS_ACCUM_SECS * 10);
+ adapter->params.pci.vpd_cap_addr =
+ pci_find_capability(adapter->pdev, PCI_CAP_ID_VPD);
+ ret = get_vpd_params(adapter, &adapter->params.vpd);
+ if (ret < 0)
+ return ret;
+
+ if (reset && t3_reset_adapter(adapter))
+ return -1;
+
+ t3_sge_prep(adapter, &adapter->params.sge);
+
+ if (adapter->params.vpd.mclk) {
+ struct tp_params *p = &adapter->params.tp;
+
+ mc7_prep(adapter, &adapter->pmrx, MC7_PMRX_BASE_ADDR, "PMRX");
+ mc7_prep(adapter, &adapter->pmtx, MC7_PMTX_BASE_ADDR, "PMTX");
+ mc7_prep(adapter, &adapter->cm, MC7_CM_BASE_ADDR, "CM");
+
+ p->nchan = ai->nports;
+ p->pmrx_size = t3_mc7_size(&adapter->pmrx);
+ p->pmtx_size = t3_mc7_size(&adapter->pmtx);
+ p->cm_size = t3_mc7_size(&adapter->cm);
+ p->chan_rx_size = p->pmrx_size / 2; /* only 1 Rx channel */
+ p->chan_tx_size = p->pmtx_size / p->nchan;
+ p->rx_pg_size = 64 * 1024;
+ p->tx_pg_size = is_10G(adapter) ? 64 * 1024 : 16 * 1024;
+ p->rx_num_pgs = pm_num_pages(p->chan_rx_size, p->rx_pg_size);
+ p->tx_num_pgs = pm_num_pages(p->chan_tx_size, p->tx_pg_size);
+ p->ntimer_qs = p->cm_size >= (128 << 20) ||
+ adapter->params.rev > 0 ? 12 : 6;
+
+ adapter->params.mc5.nservers = DEFAULT_NSERVERS;
+ adapter->params.mc5.nfilters = adapter->params.rev > 0 ?
+ DEFAULT_NFILTERS : 0;
+ adapter->params.mc5.nroutes = 0;
+ t3_mc5_prep(adapter, &adapter->mc5, MC5_MODE_144_BIT);
+
+ init_mtus(adapter->params.mtus);
+ init_cong_ctrl(adapter->params.a_wnd, adapter->params.b_wnd);
+ }
+
+ early_hw_init(adapter, ai);
+
+ for_each_port(adapter, i) {
+ u8 hw_addr[6];
+ struct port_info *p = adap2pinfo(adapter, i);
+
+ while (!adapter->params.vpd.port_type[j])
+ ++j;
+
+ p->port_type = &port_types[adapter->params.vpd.port_type[j]];
+ p->port_type->phy_prep(&p->phy, adapter, ai->phy_base_addr + j,
+ ai->mdio_ops);
+ mac_prep(&p->mac, adapter, j);
+ ++j;
+
+ /*
+ * The VPD EEPROM stores the base Ethernet address for the
+ * card. A port's address is derived from the base by adding
+ * the port's index to the base's low octet.
+ */
+ memcpy(hw_addr, adapter->params.vpd.eth_base, 5);
+ hw_addr[5] = adapter->params.vpd.eth_base[5] + i;
+
+ memcpy(adapter->port[i]->dev_addr, hw_addr,
+ ETH_ALEN);
+ memcpy(adapter->port[i]->perm_addr, hw_addr,
+ ETH_ALEN);
+ init_link_config(&p->link_config, p->port_type->caps);
+ p->phy.ops->power_down(&p->phy, 1);
+ if (!(p->port_type->caps & SUPPORTED_IRQ))
+ adapter->params.linkpoll_period = 10;
+ }
+
+ return 0;
+}
+
+void t3_led_ready(struct adapter *adapter)
+{
+ t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL,
+ F_GPIO0_OUT_VAL);
+}
diff --git a/drivers/net/cxgb3/t3cdev.h b/drivers/net/cxgb3/t3cdev.h
new file mode 100644
index 00000000000..9af3bcd64b3
--- /dev/null
+++ b/drivers/net/cxgb3/t3cdev.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2006-2007 Chelsio Communications. All rights reserved.
+ * Copyright (C) 2006-2007 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _T3CDEV_H_
+#define _T3CDEV_H_
+
+#include <linux/list.h>
+#include <asm/atomic.h>
+#include <asm/semaphore.h>
+#include <linux/netdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/skbuff.h>
+#include <net/neighbour.h>
+
+#define T3CNAMSIZ 16
+
+/* Get the t3cdev associated with a net_device */
+#define T3CDEV(netdev) (struct t3cdev *)(netdev->priv)
+
+struct cxgb3_client;
+
+enum t3ctype {
+ T3A = 0,
+ T3B
+};
+
+struct t3cdev {
+ char name[T3CNAMSIZ]; /* T3C device name */
+ enum t3ctype type;
+ struct list_head ofld_dev_list; /* for list linking */
+ struct net_device *lldev; /* LL dev associated with T3C messages */
+ struct proc_dir_entry *proc_dir; /* root of proc dir for this T3C */
+ int (*send)(struct t3cdev *dev, struct sk_buff *skb);
+ int (*recv)(struct t3cdev *dev, struct sk_buff **skb, int n);
+ int (*ctl)(struct t3cdev *dev, unsigned int req, void *data);
+ void (*neigh_update)(struct t3cdev *dev, struct neighbour *neigh);
+ void *priv; /* driver private data */
+ void *l2opt; /* optional layer 2 data */
+ void *l3opt; /* optional layer 3 data */
+ void *l4opt; /* optional layer 4 data */
+ void *ulp; /* ulp stuff */
+};
+
+#endif /* _T3CDEV_H_ */
diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h
new file mode 100644
index 00000000000..2b67dd523cc
--- /dev/null
+++ b/drivers/net/cxgb3/version.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* $Date: 2006/10/31 18:57:51 $ $RCSfile: version.h,v $ $Revision: 1.3 $ */
+#ifndef __CHELSIO_VERSION_H
+#define __CHELSIO_VERSION_H
+#define DRV_DESC "Chelsio T3 Network Driver"
+#define DRV_NAME "cxgb3"
+/* Driver version */
+#define DRV_VERSION "1.0"
+#endif /* __CHELSIO_VERSION_H */
diff --git a/drivers/net/cxgb3/vsc8211.c b/drivers/net/cxgb3/vsc8211.c
new file mode 100644
index 00000000000..eee4285b31b
--- /dev/null
+++ b/drivers/net/cxgb3/vsc8211.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "common.h"
+
+/* VSC8211 PHY specific registers. */
+enum {
+ VSC8211_INTR_ENABLE = 25,
+ VSC8211_INTR_STATUS = 26,
+ VSC8211_AUX_CTRL_STAT = 28,
+};
+
+enum {
+ VSC_INTR_RX_ERR = 1 << 0,
+ VSC_INTR_MS_ERR = 1 << 1, /* master/slave resolution error */
+ VSC_INTR_CABLE = 1 << 2, /* cable impairment */
+ VSC_INTR_FALSE_CARR = 1 << 3, /* false carrier */
+ VSC_INTR_MEDIA_CHG = 1 << 4, /* AMS media change */
+ VSC_INTR_RX_FIFO = 1 << 5, /* Rx FIFO over/underflow */
+ VSC_INTR_TX_FIFO = 1 << 6, /* Tx FIFO over/underflow */
+ VSC_INTR_DESCRAMBL = 1 << 7, /* descrambler lock-lost */
+ VSC_INTR_SYMBOL_ERR = 1 << 8, /* symbol error */
+ VSC_INTR_NEG_DONE = 1 << 10, /* autoneg done */
+ VSC_INTR_NEG_ERR = 1 << 11, /* autoneg error */
+ VSC_INTR_LINK_CHG = 1 << 13, /* link change */
+ VSC_INTR_ENABLE = 1 << 15, /* interrupt enable */
+};
+
+#define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \
+ VSC_INTR_NEG_DONE)
+#define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \
+ VSC_INTR_ENABLE)
+
+/* PHY specific auxiliary control & status register fields */
+#define S_ACSR_ACTIPHY_TMR 0
+#define M_ACSR_ACTIPHY_TMR 0x3
+#define V_ACSR_ACTIPHY_TMR(x) ((x) << S_ACSR_ACTIPHY_TMR)
+
+#define S_ACSR_SPEED 3
+#define M_ACSR_SPEED 0x3
+#define G_ACSR_SPEED(x) (((x) >> S_ACSR_SPEED) & M_ACSR_SPEED)
+
+#define S_ACSR_DUPLEX 5
+#define F_ACSR_DUPLEX (1 << S_ACSR_DUPLEX)
+
+#define S_ACSR_ACTIPHY 6
+#define F_ACSR_ACTIPHY (1 << S_ACSR_ACTIPHY)
+
+/*
+ * Reset the PHY. This PHY completes reset immediately so we never wait.
+ */
+static int vsc8211_reset(struct cphy *cphy, int wait)
+{
+ return t3_phy_reset(cphy, 0, 0);
+}
+
+static int vsc8211_intr_enable(struct cphy *cphy)
+{
+ return mdio_write(cphy, 0, VSC8211_INTR_ENABLE, INTR_MASK);
+}
+
+static int vsc8211_intr_disable(struct cphy *cphy)
+{
+ return mdio_write(cphy, 0, VSC8211_INTR_ENABLE, 0);
+}
+
+static int vsc8211_intr_clear(struct cphy *cphy)
+{
+ u32 val;
+
+ /* Clear PHY interrupts by reading the register. */
+ return mdio_read(cphy, 0, VSC8211_INTR_STATUS, &val);
+}
+
+static int vsc8211_autoneg_enable(struct cphy *cphy)
+{
+ return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE,
+ BMCR_ANENABLE | BMCR_ANRESTART);
+}
+
+static int vsc8211_autoneg_restart(struct cphy *cphy)
+{
+ return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE,
+ BMCR_ANRESTART);
+}
+
+static int vsc8211_get_link_status(struct cphy *cphy, int *link_ok,
+ int *speed, int *duplex, int *fc)
+{
+ unsigned int bmcr, status, lpa, adv;
+ int err, sp = -1, dplx = -1, pause = 0;
+
+ err = mdio_read(cphy, 0, MII_BMCR, &bmcr);
+ if (!err)
+ err = mdio_read(cphy, 0, MII_BMSR, &status);
+ if (err)
+ return err;
+
+ if (link_ok) {
+ /*
+ * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it
+ * once more to get the current link state.
+ */
+ if (!(status & BMSR_LSTATUS))
+ err = mdio_read(cphy, 0, MII_BMSR, &status);
+ if (err)
+ return err;
+ *link_ok = (status & BMSR_LSTATUS) != 0;
+ }
+ if (!(bmcr & BMCR_ANENABLE)) {
+ dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
+ if (bmcr & BMCR_SPEED1000)
+ sp = SPEED_1000;
+ else if (bmcr & BMCR_SPEED100)
+ sp = SPEED_100;
+ else
+ sp = SPEED_10;
+ } else if (status & BMSR_ANEGCOMPLETE) {
+ err = mdio_read(cphy, 0, VSC8211_AUX_CTRL_STAT, &status);
+ if (err)
+ return err;
+
+ dplx = (status & F_ACSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF;
+ sp = G_ACSR_SPEED(status);
+ if (sp == 0)
+ sp = SPEED_10;
+ else if (sp == 1)
+ sp = SPEED_100;
+ else
+ sp = SPEED_1000;
+
+ if (fc && dplx == DUPLEX_FULL) {
+ err = mdio_read(cphy, 0, MII_LPA, &lpa);
+ if (!err)
+ err = mdio_read(cphy, 0, MII_ADVERTISE, &adv);
+ if (err)
+ return err;
+
+ if (lpa & adv & ADVERTISE_PAUSE_CAP)
+ pause = PAUSE_RX | PAUSE_TX;
+ else if ((lpa & ADVERTISE_PAUSE_CAP) &&
+ (lpa & ADVERTISE_PAUSE_ASYM) &&
+ (adv & ADVERTISE_PAUSE_ASYM))
+ pause = PAUSE_TX;
+ else if ((lpa & ADVERTISE_PAUSE_ASYM) &&
+ (adv & ADVERTISE_PAUSE_CAP))
+ pause = PAUSE_RX;
+ }
+ }
+ if (speed)
+ *speed = sp;
+ if (duplex)
+ *duplex = dplx;
+ if (fc)
+ *fc = pause;
+ return 0;
+}
+
+static int vsc8211_power_down(struct cphy *cphy, int enable)
+{
+ return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN,
+ enable ? BMCR_PDOWN : 0);
+}
+
+static int vsc8211_intr_handler(struct cphy *cphy)
+{
+ unsigned int cause;
+ int err, cphy_cause = 0;
+
+ err = mdio_read(cphy, 0, VSC8211_INTR_STATUS, &cause);
+ if (err)
+ return err;
+
+ cause &= INTR_MASK;
+ if (cause & CFG_CHG_INTR_MASK)
+ cphy_cause |= cphy_cause_link_change;
+ if (cause & (VSC_INTR_RX_FIFO | VSC_INTR_TX_FIFO))
+ cphy_cause |= cphy_cause_fifo_error;
+ return cphy_cause;
+}
+
+static struct cphy_ops vsc8211_ops = {
+ .reset = vsc8211_reset,
+ .intr_enable = vsc8211_intr_enable,
+ .intr_disable = vsc8211_intr_disable,
+ .intr_clear = vsc8211_intr_clear,
+ .intr_handler = vsc8211_intr_handler,
+ .autoneg_enable = vsc8211_autoneg_enable,
+ .autoneg_restart = vsc8211_autoneg_restart,
+ .advertise = t3_phy_advertise,
+ .set_speed_duplex = t3_set_phy_speed_duplex,
+ .get_link_status = vsc8211_get_link_status,
+ .power_down = vsc8211_power_down,
+};
+
+void t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter,
+ int phy_addr, const struct mdio_ops *mdio_ops)
+{
+ cphy_init(phy, adapter, phy_addr, &vsc8211_ops, mdio_ops);
+}
diff --git a/drivers/net/cxgb3/xgmac.c b/drivers/net/cxgb3/xgmac.c
new file mode 100644
index 00000000000..907a272ae32
--- /dev/null
+++ b/drivers/net/cxgb3/xgmac.c
@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "common.h"
+#include "regs.h"
+
+/*
+ * # of exact address filters. The first one is used for the station address,
+ * the rest are available for multicast addresses.
+ */
+#define EXACT_ADDR_FILTERS 8
+
+static inline int macidx(const struct cmac *mac)
+{
+ return mac->offset / (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR);
+}
+
+static void xaui_serdes_reset(struct cmac *mac)
+{
+ static const unsigned int clear[] = {
+ F_PWRDN0 | F_PWRDN1, F_RESETPLL01, F_RESET0 | F_RESET1,
+ F_PWRDN2 | F_PWRDN3, F_RESETPLL23, F_RESET2 | F_RESET3
+ };
+
+ int i;
+ struct adapter *adap = mac->adapter;
+ u32 ctrl = A_XGM_SERDES_CTRL0 + mac->offset;
+
+ t3_write_reg(adap, ctrl, adap->params.vpd.xauicfg[macidx(mac)] |
+ F_RESET3 | F_RESET2 | F_RESET1 | F_RESET0 |
+ F_PWRDN3 | F_PWRDN2 | F_PWRDN1 | F_PWRDN0 |
+ F_RESETPLL23 | F_RESETPLL01);
+ t3_read_reg(adap, ctrl);
+ udelay(15);
+
+ for (i = 0; i < ARRAY_SIZE(clear); i++) {
+ t3_set_reg_field(adap, ctrl, clear[i], 0);
+ udelay(15);
+ }
+}
+
+void t3b_pcs_reset(struct cmac *mac)
+{
+ t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,
+ F_PCS_RESET_, 0);
+ udelay(20);
+ t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, 0,
+ F_PCS_RESET_);
+}
+
+int t3_mac_reset(struct cmac *mac)
+{
+ static const struct addr_val_pair mac_reset_avp[] = {
+ {A_XGM_TX_CTRL, 0},
+ {A_XGM_RX_CTRL, 0},
+ {A_XGM_RX_CFG, F_DISPAUSEFRAMES | F_EN1536BFRAMES |
+ F_RMFCS | F_ENJUMBO | F_ENHASHMCAST},
+ {A_XGM_RX_HASH_LOW, 0},
+ {A_XGM_RX_HASH_HIGH, 0},
+ {A_XGM_RX_EXACT_MATCH_LOW_1, 0},
+ {A_XGM_RX_EXACT_MATCH_LOW_2, 0},
+ {A_XGM_RX_EXACT_MATCH_LOW_3, 0},
+ {A_XGM_RX_EXACT_MATCH_LOW_4, 0},
+ {A_XGM_RX_EXACT_MATCH_LOW_5, 0},
+ {A_XGM_RX_EXACT_MATCH_LOW_6, 0},
+ {A_XGM_RX_EXACT_MATCH_LOW_7, 0},
+ {A_XGM_RX_EXACT_MATCH_LOW_8, 0},
+ {A_XGM_STAT_CTRL, F_CLRSTATS}
+ };
+ u32 val;
+ struct adapter *adap = mac->adapter;
+ unsigned int oft = mac->offset;
+
+ t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_);
+ t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
+
+ t3_write_regs(adap, mac_reset_avp, ARRAY_SIZE(mac_reset_avp), oft);
+ t3_set_reg_field(adap, A_XGM_RXFIFO_CFG + oft,
+ F_RXSTRFRWRD | F_DISERRFRAMES,
+ uses_xaui(adap) ? 0 : F_RXSTRFRWRD);
+
+ if (uses_xaui(adap)) {
+ if (adap->params.rev == 0) {
+ t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0,
+ F_RXENABLE | F_TXENABLE);
+ if (t3_wait_op_done(adap, A_XGM_SERDES_STATUS1 + oft,
+ F_CMULOCK, 1, 5, 2)) {
+ CH_ERR(adap,
+ "MAC %d XAUI SERDES CMU lock failed\n",
+ macidx(mac));
+ return -1;
+ }
+ t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0,
+ F_SERDESRESET_);
+ } else
+ xaui_serdes_reset(mac);
+ }
+
+ if (adap->params.rev > 0)
+ t3_write_reg(adap, A_XGM_PAUSE_TIMER + oft, 0xf000);
+
+ val = F_MAC_RESET_;
+ if (is_10G(adap))
+ val |= F_PCS_RESET_;
+ else if (uses_xaui(adap))
+ val |= F_PCS_RESET_ | F_XG2G_RESET_;
+ else
+ val |= F_RGMII_RESET_ | F_XG2G_RESET_;
+ t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val);
+ t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
+ if ((val & F_PCS_RESET_) && adap->params.rev) {
+ msleep(1);
+ t3b_pcs_reset(mac);
+ }
+
+ memset(&mac->stats, 0, sizeof(mac->stats));
+ return 0;
+}
+
+/*
+ * Set the exact match register 'idx' to recognize the given Ethernet address.
+ */
+static void set_addr_filter(struct cmac *mac, int idx, const u8 * addr)
+{
+ u32 addr_lo, addr_hi;
+ unsigned int oft = mac->offset + idx * 8;
+
+ addr_lo = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
+ addr_hi = (addr[5] << 8) | addr[4];
+
+ t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1 + oft, addr_lo);
+ t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_HIGH_1 + oft, addr_hi);
+}
+
+/* Set one of the station's unicast MAC addresses. */
+int t3_mac_set_address(struct cmac *mac, unsigned int idx, u8 addr[6])
+{
+ if (idx >= mac->nucast)
+ return -EINVAL;
+ set_addr_filter(mac, idx, addr);
+ return 0;
+}
+
+/*
+ * Specify the number of exact address filters that should be reserved for
+ * unicast addresses. Caller should reload the unicast and multicast addresses
+ * after calling this.
+ */
+int t3_mac_set_num_ucast(struct cmac *mac, int n)
+{
+ if (n > EXACT_ADDR_FILTERS)
+ return -EINVAL;
+ mac->nucast = n;
+ return 0;
+}
+
+/* Calculate the RX hash filter index of an Ethernet address */
+static int hash_hw_addr(const u8 * addr)
+{
+ int hash = 0, octet, bit, i = 0, c;
+
+ for (octet = 0; octet < 6; ++octet)
+ for (c = addr[octet], bit = 0; bit < 8; c >>= 1, ++bit) {
+ hash ^= (c & 1) << i;
+ if (++i == 6)
+ i = 0;
+ }
+ return hash;
+}
+
+int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm)
+{
+ u32 val, hash_lo, hash_hi;
+ struct adapter *adap = mac->adapter;
+ unsigned int oft = mac->offset;
+
+ val = t3_read_reg(adap, A_XGM_RX_CFG + oft) & ~F_COPYALLFRAMES;
+ if (rm->dev->flags & IFF_PROMISC)
+ val |= F_COPYALLFRAMES;
+ t3_write_reg(adap, A_XGM_RX_CFG + oft, val);
+
+ if (rm->dev->flags & IFF_ALLMULTI)
+ hash_lo = hash_hi = 0xffffffff;
+ else {
+ u8 *addr;
+ int exact_addr_idx = mac->nucast;
+
+ hash_lo = hash_hi = 0;
+ while ((addr = t3_get_next_mcaddr(rm)))
+ if (exact_addr_idx < EXACT_ADDR_FILTERS)
+ set_addr_filter(mac, exact_addr_idx++, addr);
+ else {
+ int hash = hash_hw_addr(addr);
+
+ if (hash < 32)
+ hash_lo |= (1 << hash);
+ else
+ hash_hi |= (1 << (hash - 32));
+ }
+ }
+
+ t3_write_reg(adap, A_XGM_RX_HASH_LOW + oft, hash_lo);
+ t3_write_reg(adap, A_XGM_RX_HASH_HIGH + oft, hash_hi);
+ return 0;
+}
+
+int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
+{
+ int hwm, lwm;
+ unsigned int thres, v;
+ struct adapter *adap = mac->adapter;
+
+ /*
+ * MAX_FRAME_SIZE inludes header + FCS, mtu doesn't. The HW max
+ * packet size register includes header, but not FCS.
+ */
+ mtu += 14;
+ if (mtu > MAX_FRAME_SIZE - 4)
+ return -EINVAL;
+ t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, mtu);
+
+ /*
+ * Adjust the PAUSE frame watermarks. We always set the LWM, and the
+ * HWM only if flow-control is enabled.
+ */
+ hwm = max(MAC_RXFIFO_SIZE - 3 * mtu, MAC_RXFIFO_SIZE / 2U);
+ hwm = min(hwm, 3 * MAC_RXFIFO_SIZE / 4 + 1024);
+ lwm = hwm - 1024;
+ v = t3_read_reg(adap, A_XGM_RXFIFO_CFG + mac->offset);
+ v &= ~V_RXFIFOPAUSELWM(M_RXFIFOPAUSELWM);
+ v |= V_RXFIFOPAUSELWM(lwm / 8);
+ if (G_RXFIFOPAUSEHWM(v))
+ v = (v & ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM)) |
+ V_RXFIFOPAUSEHWM(hwm / 8);
+ t3_write_reg(adap, A_XGM_RXFIFO_CFG + mac->offset, v);
+
+ /* Adjust the TX FIFO threshold based on the MTU */
+ thres = (adap->params.vpd.cclk * 1000) / 15625;
+ thres = (thres * mtu) / 1000;
+ if (is_10G(adap))
+ thres /= 10;
+ thres = mtu > thres ? (mtu - thres + 7) / 8 : 0;
+ thres = max(thres, 8U); /* need at least 8 */
+ t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + mac->offset,
+ V_TXFIFOTHRESH(M_TXFIFOTHRESH), V_TXFIFOTHRESH(thres));
+ return 0;
+}
+
+int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc)
+{
+ u32 val;
+ struct adapter *adap = mac->adapter;
+ unsigned int oft = mac->offset;
+
+ if (duplex >= 0 && duplex != DUPLEX_FULL)
+ return -EINVAL;
+ if (speed >= 0) {
+ if (speed == SPEED_10)
+ val = V_PORTSPEED(0);
+ else if (speed == SPEED_100)
+ val = V_PORTSPEED(1);
+ else if (speed == SPEED_1000)
+ val = V_PORTSPEED(2);
+ else if (speed == SPEED_10000)
+ val = V_PORTSPEED(3);
+ else
+ return -EINVAL;
+
+ t3_set_reg_field(adap, A_XGM_PORT_CFG + oft,
+ V_PORTSPEED(M_PORTSPEED), val);
+ }
+
+ val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
+ val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
+ if (fc & PAUSE_TX)
+ val |= V_RXFIFOPAUSEHWM(G_RXFIFOPAUSELWM(val) + 128); /* +1KB */
+ t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
+
+ t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
+ (fc & PAUSE_RX) ? F_TXPAUSEEN : 0);
+ return 0;
+}
+
+int t3_mac_enable(struct cmac *mac, int which)
+{
+ int idx = macidx(mac);
+ struct adapter *adap = mac->adapter;
+ unsigned int oft = mac->offset;
+
+ if (which & MAC_DIRECTION_TX) {
+ t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
+ t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
+ t3_write_reg(adap, A_TP_PIO_DATA, 0xbf000001);
+ t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE);
+ t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 1 << idx);
+ }
+ if (which & MAC_DIRECTION_RX)
+ t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN);
+ return 0;
+}
+
+int t3_mac_disable(struct cmac *mac, int which)
+{
+ int idx = macidx(mac);
+ struct adapter *adap = mac->adapter;
+
+ if (which & MAC_DIRECTION_TX) {
+ t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
+ t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
+ t3_write_reg(adap, A_TP_PIO_DATA, 0xc000001f);
+ t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE);
+ t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 0);
+ }
+ if (which & MAC_DIRECTION_RX)
+ t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0);
+ return 0;
+}
+
+/*
+ * This function is called periodically to accumulate the current values of the
+ * RMON counters into the port statistics. Since the packet counters are only
+ * 32 bits they can overflow in ~286 secs at 10G, so the function should be
+ * called more frequently than that. The byte counters are 45-bit wide, they
+ * would overflow in ~7.8 hours.
+ */
+const struct mac_stats *t3_mac_update_stats(struct cmac *mac)
+{
+#define RMON_READ(mac, addr) t3_read_reg(mac->adapter, addr + mac->offset)
+#define RMON_UPDATE(mac, name, reg) \
+ (mac)->stats.name += (u64)RMON_READ(mac, A_XGM_STAT_##reg)
+#define RMON_UPDATE64(mac, name, reg_lo, reg_hi) \
+ (mac)->stats.name += RMON_READ(mac, A_XGM_STAT_##reg_lo) + \
+ ((u64)RMON_READ(mac, A_XGM_STAT_##reg_hi) << 32)
+
+ u32 v, lo;
+
+ RMON_UPDATE64(mac, rx_octets, RX_BYTES_LOW, RX_BYTES_HIGH);
+ RMON_UPDATE64(mac, rx_frames, RX_FRAMES_LOW, RX_FRAMES_HIGH);
+ RMON_UPDATE(mac, rx_mcast_frames, RX_MCAST_FRAMES);
+ RMON_UPDATE(mac, rx_bcast_frames, RX_BCAST_FRAMES);
+ RMON_UPDATE(mac, rx_fcs_errs, RX_CRC_ERR_FRAMES);
+ RMON_UPDATE(mac, rx_pause, RX_PAUSE_FRAMES);
+ RMON_UPDATE(mac, rx_jabber, RX_JABBER_FRAMES);
+ RMON_UPDATE(mac, rx_short, RX_SHORT_FRAMES);
+ RMON_UPDATE(mac, rx_symbol_errs, RX_SYM_CODE_ERR_FRAMES);
+
+ RMON_UPDATE(mac, rx_too_long, RX_OVERSIZE_FRAMES);
+ mac->stats.rx_too_long += RMON_READ(mac, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT);
+
+ RMON_UPDATE(mac, rx_frames_64, RX_64B_FRAMES);
+ RMON_UPDATE(mac, rx_frames_65_127, RX_65_127B_FRAMES);
+ RMON_UPDATE(mac, rx_frames_128_255, RX_128_255B_FRAMES);
+ RMON_UPDATE(mac, rx_frames_256_511, RX_256_511B_FRAMES);
+ RMON_UPDATE(mac, rx_frames_512_1023, RX_512_1023B_FRAMES);
+ RMON_UPDATE(mac, rx_frames_1024_1518, RX_1024_1518B_FRAMES);
+ RMON_UPDATE(mac, rx_frames_1519_max, RX_1519_MAXB_FRAMES);
+
+ RMON_UPDATE64(mac, tx_octets, TX_BYTE_LOW, TX_BYTE_HIGH);
+ RMON_UPDATE64(mac, tx_frames, TX_FRAME_LOW, TX_FRAME_HIGH);
+ RMON_UPDATE(mac, tx_mcast_frames, TX_MCAST);
+ RMON_UPDATE(mac, tx_bcast_frames, TX_BCAST);
+ RMON_UPDATE(mac, tx_pause, TX_PAUSE);
+ /* This counts error frames in general (bad FCS, underrun, etc). */
+ RMON_UPDATE(mac, tx_underrun, TX_ERR_FRAMES);
+
+ RMON_UPDATE(mac, tx_frames_64, TX_64B_FRAMES);
+ RMON_UPDATE(mac, tx_frames_65_127, TX_65_127B_FRAMES);
+ RMON_UPDATE(mac, tx_frames_128_255, TX_128_255B_FRAMES);
+ RMON_UPDATE(mac, tx_frames_256_511, TX_256_511B_FRAMES);
+ RMON_UPDATE(mac, tx_frames_512_1023, TX_512_1023B_FRAMES);
+ RMON_UPDATE(mac, tx_frames_1024_1518, TX_1024_1518B_FRAMES);
+ RMON_UPDATE(mac, tx_frames_1519_max, TX_1519_MAXB_FRAMES);
+
+ /* The next stat isn't clear-on-read. */
+ t3_write_reg(mac->adapter, A_TP_MIB_INDEX, mac->offset ? 51 : 50);
+ v = t3_read_reg(mac->adapter, A_TP_MIB_RDATA);
+ lo = (u32) mac->stats.rx_cong_drops;
+ mac->stats.rx_cong_drops += (u64) (v - lo);
+
+ return &mac->stats;
+}
diff --git a/drivers/net/declance.c b/drivers/net/declance.c
index 4ae0fed7122..9f7e1db8ce6 100644
--- a/drivers/net/declance.c
+++ b/drivers/net/declance.c
@@ -5,7 +5,7 @@
*
* adopted from sunlance.c by Richard van den Berg
*
- * Copyright (C) 2002, 2003, 2005 Maciej W. Rozycki
+ * Copyright (C) 2002, 2003, 2005, 2006 Maciej W. Rozycki
*
* additional sources:
* - PMAD-AA TURBOchannel Ethernet Module Functional Specification,
@@ -44,6 +44,8 @@
* v0.010: Fixes for the PMAD mapping of the LANCE buffer and for the
* PMAX requirement to only use halfword accesses to the
* buffer. macro
+ *
+ * v0.011: Converted the PMAD to the driver model. macro
*/
#include <linux/crc32.h>
@@ -58,6 +60,7 @@
#include <linux/spinlock.h>
#include <linux/stddef.h>
#include <linux/string.h>
+#include <linux/tc.h>
#include <linux/types.h>
#include <asm/addrspace.h>
@@ -69,15 +72,16 @@
#include <asm/dec/kn01.h>
#include <asm/dec/machtype.h>
#include <asm/dec/system.h>
-#include <asm/dec/tc.h>
static char version[] __devinitdata =
-"declance.c: v0.010 by Linux MIPS DECstation task force\n";
+"declance.c: v0.011 by Linux MIPS DECstation task force\n";
MODULE_AUTHOR("Linux MIPS DECstation task force");
MODULE_DESCRIPTION("DEC LANCE (DECstation onboard, PMAD-xx) driver");
MODULE_LICENSE("GPL");
+#define __unused __attribute__ ((unused))
+
/*
* card types
*/
@@ -246,7 +250,6 @@ struct lance_init_block {
struct lance_private {
struct net_device *next;
int type;
- int slot;
int dma_irq;
volatile struct lance_regs *ll;
@@ -288,6 +291,7 @@ struct lance_regs {
int dec_lance_debug = 2;
+static struct tc_driver dec_lance_tc_driver;
static struct net_device *root_lance_dev;
static inline void writereg(volatile unsigned short *regptr, short value)
@@ -1023,7 +1027,7 @@ static void lance_set_multicast_retry(unsigned long _opaque)
lance_set_multicast(dev);
}
-static int __init dec_lance_init(const int type, const int slot)
+static int __init dec_lance_probe(struct device *bdev, const int type)
{
static unsigned version_printed;
static const char fmt[] = "declance%d";
@@ -1031,6 +1035,7 @@ static int __init dec_lance_init(const int type, const int slot)
struct net_device *dev;
struct lance_private *lp;
volatile struct lance_regs *ll;
+ resource_size_t start = 0, len = 0;
int i, ret;
unsigned long esar_base;
unsigned char *esar;
@@ -1038,14 +1043,18 @@ static int __init dec_lance_init(const int type, const int slot)
if (dec_lance_debug && version_printed++ == 0)
printk(version);
- i = 0;
- dev = root_lance_dev;
- while (dev) {
- i++;
- lp = (struct lance_private *)dev->priv;
- dev = lp->next;
+ if (bdev)
+ snprintf(name, sizeof(name), "%s", bdev->bus_id);
+ else {
+ i = 0;
+ dev = root_lance_dev;
+ while (dev) {
+ i++;
+ lp = (struct lance_private *)dev->priv;
+ dev = lp->next;
+ }
+ snprintf(name, sizeof(name), fmt, i);
}
- snprintf(name, sizeof(name), fmt, i);
dev = alloc_etherdev(sizeof(struct lance_private));
if (!dev) {
@@ -1063,7 +1072,6 @@ static int __init dec_lance_init(const int type, const int slot)
spin_lock_init(&lp->lock);
lp->type = type;
- lp->slot = slot;
switch (type) {
case ASIC_LANCE:
dev->base_addr = CKSEG1ADDR(dec_kn_slot_base + IOASIC_LANCE);
@@ -1110,12 +1118,22 @@ static int __init dec_lance_init(const int type, const int slot)
break;
#ifdef CONFIG_TC
case PMAD_LANCE:
- claim_tc_card(slot);
+ dev_set_drvdata(bdev, dev);
+
+ start = to_tc_dev(bdev)->resource.start;
+ len = to_tc_dev(bdev)->resource.end - start + 1;
+ if (!request_mem_region(start, len, bdev->bus_id)) {
+ printk(KERN_ERR
+ "%s: Unable to reserve MMIO resource\n",
+ bdev->bus_id);
+ ret = -EBUSY;
+ goto err_out_dev;
+ }
- dev->mem_start = CKSEG1ADDR(get_tc_base_addr(slot));
+ dev->mem_start = CKSEG1ADDR(start);
dev->mem_end = dev->mem_start + 0x100000;
dev->base_addr = dev->mem_start + 0x100000;
- dev->irq = get_tc_irq_nr(slot);
+ dev->irq = to_tc_dev(bdev)->interrupt;
esar_base = dev->mem_start + 0x1c0002;
lp->dma_irq = -1;
@@ -1174,7 +1192,7 @@ static int __init dec_lance_init(const int type, const int slot)
printk(KERN_ERR "%s: declance_init called with unknown type\n",
name);
ret = -ENODEV;
- goto err_out_free_dev;
+ goto err_out_dev;
}
ll = (struct lance_regs *) dev->base_addr;
@@ -1188,7 +1206,7 @@ static int __init dec_lance_init(const int type, const int slot)
"%s: Ethernet station address prom not found!\n",
name);
ret = -ENODEV;
- goto err_out_free_dev;
+ goto err_out_resource;
}
/* Check the prom contents */
for (i = 0; i < 8; i++) {
@@ -1198,7 +1216,7 @@ static int __init dec_lance_init(const int type, const int slot)
printk(KERN_ERR "%s: Something is wrong with the "
"ethernet station address prom!\n", name);
ret = -ENODEV;
- goto err_out_free_dev;
+ goto err_out_resource;
}
}
@@ -1255,48 +1273,51 @@ static int __init dec_lance_init(const int type, const int slot)
if (ret) {
printk(KERN_ERR
"%s: Unable to register netdev, aborting.\n", name);
- goto err_out_free_dev;
+ goto err_out_resource;
}
- lp->next = root_lance_dev;
- root_lance_dev = dev;
+ if (!bdev) {
+ lp->next = root_lance_dev;
+ root_lance_dev = dev;
+ }
printk("%s: registered as %s.\n", name, dev->name);
return 0;
-err_out_free_dev:
+err_out_resource:
+ if (bdev)
+ release_mem_region(start, len);
+
+err_out_dev:
free_netdev(dev);
err_out:
return ret;
}
+static void __exit dec_lance_remove(struct device *bdev)
+{
+ struct net_device *dev = dev_get_drvdata(bdev);
+ resource_size_t start, len;
+
+ unregister_netdev(dev);
+ start = to_tc_dev(bdev)->resource.start;
+ len = to_tc_dev(bdev)->resource.end - start + 1;
+ release_mem_region(start, len);
+ free_netdev(dev);
+}
/* Find all the lance cards on the system and initialize them */
-static int __init dec_lance_probe(void)
+static int __init dec_lance_platform_probe(void)
{
int count = 0;
- /* Scan slots for PMAD-AA cards first. */
-#ifdef CONFIG_TC
- if (TURBOCHANNEL) {
- int slot;
-
- while ((slot = search_tc_card("PMAD-AA")) >= 0) {
- if (dec_lance_init(PMAD_LANCE, slot) < 0)
- break;
- count++;
- }
- }
-#endif
-
- /* Then handle onboard devices. */
if (dec_interrupt[DEC_IRQ_LANCE] >= 0) {
if (dec_interrupt[DEC_IRQ_LANCE_MERR] >= 0) {
- if (dec_lance_init(ASIC_LANCE, -1) >= 0)
+ if (dec_lance_probe(NULL, ASIC_LANCE) >= 0)
count++;
} else if (!TURBOCHANNEL) {
- if (dec_lance_init(PMAX_LANCE, -1) >= 0)
+ if (dec_lance_probe(NULL, PMAX_LANCE) >= 0)
count++;
}
}
@@ -1304,21 +1325,70 @@ static int __init dec_lance_probe(void)
return (count > 0) ? 0 : -ENODEV;
}
-static void __exit dec_lance_cleanup(void)
+static void __exit dec_lance_platform_remove(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)
- release_tc_card(lp->slot);
-#endif
root_lance_dev = lp->next;
free_netdev(dev);
}
}
-module_init(dec_lance_probe);
-module_exit(dec_lance_cleanup);
+#ifdef CONFIG_TC
+static int __init dec_lance_tc_probe(struct device *dev);
+static int __exit dec_lance_tc_remove(struct device *dev);
+
+static const struct tc_device_id dec_lance_tc_table[] = {
+ { "DEC ", "PMAD-AA " },
+ { }
+};
+MODULE_DEVICE_TABLE(tc, dec_lance_tc_table);
+
+static struct tc_driver dec_lance_tc_driver = {
+ .id_table = dec_lance_tc_table,
+ .driver = {
+ .name = "declance",
+ .bus = &tc_bus_type,
+ .probe = dec_lance_tc_probe,
+ .remove = __exit_p(dec_lance_tc_remove),
+ },
+};
+
+static int __init dec_lance_tc_probe(struct device *dev)
+{
+ int status = dec_lance_probe(dev, PMAD_LANCE);
+ if (!status)
+ get_device(dev);
+ return status;
+}
+
+static int __exit dec_lance_tc_remove(struct device *dev)
+{
+ put_device(dev);
+ dec_lance_remove(dev);
+ return 0;
+}
+#endif
+
+static int __init dec_lance_init(void)
+{
+ int status;
+
+ status = tc_register_driver(&dec_lance_tc_driver);
+ if (!status)
+ dec_lance_platform_probe();
+ return status;
+}
+
+static void __exit dec_lance_exit(void)
+{
+ dec_lance_platform_remove();
+ tc_unregister_driver(&dec_lance_tc_driver);
+}
+
+
+module_init(dec_lance_init);
+module_exit(dec_lance_exit);
diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c
index dc3ab3b5c8c..07d2731c1aa 100644
--- a/drivers/net/defxx.c
+++ b/drivers/net/defxx.c
@@ -10,10 +10,12 @@
*
* Abstract:
* A Linux device driver supporting the Digital Equipment Corporation
- * FDDI EISA and PCI controller families. Supported adapters include:
+ * FDDI TURBOchannel, EISA and PCI controller families. Supported
+ * adapters include:
*
- * DEC FDDIcontroller/EISA (DEFEA)
- * DEC FDDIcontroller/PCI (DEFPA)
+ * DEC FDDIcontroller/TURBOchannel (DEFTA)
+ * DEC FDDIcontroller/EISA (DEFEA)
+ * DEC FDDIcontroller/PCI (DEFPA)
*
* The original author:
* LVS Lawrence V. Stefani <lstefani@yahoo.com>
@@ -193,24 +195,27 @@
* 14 Aug 2004 macro Fix device names reported.
* 14 Jun 2005 macro Use irqreturn_t.
* 23 Oct 2006 macro Big-endian host support.
+ * 14 Dec 2006 macro TURBOchannel support.
*/
/* Include files */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
+#include <linux/bitops.h>
#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/eisa.h>
+#include <linux/errno.h>
+#include <linux/fddidevice.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/netdevice.h>
-#include <linux/fddidevice.h>
+#include <linux/pci.h>
#include <linux/skbuff.h>
-#include <linux/bitops.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/tc.h>
#include <asm/byteorder.h>
#include <asm/io.h>
@@ -219,8 +224,8 @@
/* Version information string should be updated prior to each new release! */
#define DRV_NAME "defxx"
-#define DRV_VERSION "v1.09"
-#define DRV_RELDATE "2006/10/23"
+#define DRV_VERSION "v1.10"
+#define DRV_RELDATE "2006/12/14"
static char version[] __devinitdata =
DRV_NAME ": " DRV_VERSION " " DRV_RELDATE
@@ -235,12 +240,41 @@ static char version[] __devinitdata =
*/
#define NEW_SKB_SIZE (PI_RCV_DATA_K_SIZE_MAX+128)
+#define __unused __attribute__ ((unused))
+
+#ifdef CONFIG_PCI
+#define DFX_BUS_PCI(dev) (dev->bus == &pci_bus_type)
+#else
+#define DFX_BUS_PCI(dev) 0
+#endif
+
+#ifdef CONFIG_EISA
+#define DFX_BUS_EISA(dev) (dev->bus == &eisa_bus_type)
+#else
+#define DFX_BUS_EISA(dev) 0
+#endif
+
+#ifdef CONFIG_TC
+#define DFX_BUS_TC(dev) (dev->bus == &tc_bus_type)
+#else
+#define DFX_BUS_TC(dev) 0
+#endif
+
+#ifdef CONFIG_DEFXX_MMIO
+#define DFX_MMIO 1
+#else
+#define DFX_MMIO 0
+#endif
+
/* Define module-wide (static) routines */
static void dfx_bus_init(struct net_device *dev);
+static void dfx_bus_uninit(struct net_device *dev);
static void dfx_bus_config_check(DFX_board_t *bp);
-static int dfx_driver_init(struct net_device *dev, const char *print_name);
+static int dfx_driver_init(struct net_device *dev,
+ const char *print_name,
+ resource_size_t bar_start);
static int dfx_adap_init(DFX_board_t *bp, int get_buffers);
static int dfx_open(struct net_device *dev);
@@ -273,13 +307,13 @@ static void dfx_xmt_flush(DFX_board_t *bp);
/* Define module-wide (static) variables */
-static struct net_device *root_dfx_eisa_dev;
+static struct pci_driver dfx_pci_driver;
+static struct eisa_driver dfx_eisa_driver;
+static struct tc_driver dfx_tc_driver;
/*
* =======================
- * = dfx_port_write_byte =
- * = dfx_port_read_byte =
* = dfx_port_write_long =
* = dfx_port_read_long =
* =======================
@@ -291,12 +325,11 @@ static struct net_device *root_dfx_eisa_dev;
* None
*
* Arguments:
- * bp - pointer to board information
- * offset - register offset from base I/O address
- * data - for dfx_port_write_byte and dfx_port_write_long, this
- * is a value to write.
- * for dfx_port_read_byte and dfx_port_read_byte, this
- * is a pointer to store the read value.
+ * bp - pointer to board information
+ * offset - register offset from base I/O address
+ * data - for dfx_port_write_long, this is a value to write;
+ * for dfx_port_read_long, this is a pointer to store
+ * the read value
*
* Functional Description:
* These routines perform the correct operation to read or write
@@ -310,7 +343,7 @@ static struct net_device *root_dfx_eisa_dev;
* registers using the register offsets defined in DEFXX.H.
*
* PCI port block base addresses are assigned by the PCI BIOS or system
- * firmware. There is one 128 byte port block which can be accessed. It
+ * firmware. There is one 128 byte port block which can be accessed. It
* allows for I/O mapping of both PDQ and PFI registers using the register
* offsets defined in DEFXX.H.
*
@@ -318,7 +351,7 @@ static struct net_device *root_dfx_eisa_dev;
* None
*
* Assumptions:
- * bp->base_addr is a valid base I/O address for this adapter.
+ * bp->base is a valid base I/O address for this adapter.
* offset is a valid register offset for this adapter.
*
* Side Effects:
@@ -329,69 +362,135 @@ static struct net_device *root_dfx_eisa_dev;
* advantage of strict data type checking.
*/
-static inline void dfx_port_write_byte(
- DFX_board_t *bp,
- int offset,
- u8 data
- )
+static inline void dfx_writel(DFX_board_t *bp, int offset, u32 data)
+{
+ writel(data, bp->base.mem + offset);
+ mb();
+}
- {
- u16 port = bp->base_addr + offset;
+static inline void dfx_outl(DFX_board_t *bp, int offset, u32 data)
+{
+ outl(data, bp->base.port + offset);
+}
- outb(data, port);
- }
+static void dfx_port_write_long(DFX_board_t *bp, int offset, u32 data)
+{
+ struct device __unused *bdev = bp->bus_dev;
+ int dfx_bus_tc = DFX_BUS_TC(bdev);
+ int dfx_use_mmio = DFX_MMIO || dfx_bus_tc;
-static inline void dfx_port_read_byte(
- DFX_board_t *bp,
- int offset,
- u8 *data
- )
+ if (dfx_use_mmio)
+ dfx_writel(bp, offset, data);
+ else
+ dfx_outl(bp, offset, data);
+}
- {
- u16 port = bp->base_addr + offset;
- *data = inb(port);
- }
+static inline void dfx_readl(DFX_board_t *bp, int offset, u32 *data)
+{
+ mb();
+ *data = readl(bp->base.mem + offset);
+}
-static inline void dfx_port_write_long(
- DFX_board_t *bp,
- int offset,
- u32 data
- )
+static inline void dfx_inl(DFX_board_t *bp, int offset, u32 *data)
+{
+ *data = inl(bp->base.port + offset);
+}
- {
- u16 port = bp->base_addr + offset;
+static void dfx_port_read_long(DFX_board_t *bp, int offset, u32 *data)
+{
+ struct device __unused *bdev = bp->bus_dev;
+ int dfx_bus_tc = DFX_BUS_TC(bdev);
+ int dfx_use_mmio = DFX_MMIO || dfx_bus_tc;
- outl(data, port);
- }
+ if (dfx_use_mmio)
+ dfx_readl(bp, offset, data);
+ else
+ dfx_inl(bp, offset, data);
+}
-static inline void dfx_port_read_long(
- DFX_board_t *bp,
- int offset,
- u32 *data
- )
- {
- u16 port = bp->base_addr + offset;
+/*
+ * ================
+ * = dfx_get_bars =
+ * ================
+ *
+ * Overview:
+ * Retrieves the address range used to access control and status
+ * registers.
+ *
+ * Returns:
+ * None
+ *
+ * Arguments:
+ * bdev - pointer to device information
+ * bar_start - pointer to store the start address
+ * bar_len - pointer to store the length of the area
+ *
+ * Assumptions:
+ * I am sure there are some.
+ *
+ * Side Effects:
+ * None
+ */
+static void dfx_get_bars(struct device *bdev,
+ resource_size_t *bar_start, resource_size_t *bar_len)
+{
+ int dfx_bus_pci = DFX_BUS_PCI(bdev);
+ int dfx_bus_eisa = DFX_BUS_EISA(bdev);
+ int dfx_bus_tc = DFX_BUS_TC(bdev);
+ int dfx_use_mmio = DFX_MMIO || dfx_bus_tc;
- *data = inl(port);
- }
+ if (dfx_bus_pci) {
+ int num = dfx_use_mmio ? 0 : 1;
+ *bar_start = pci_resource_start(to_pci_dev(bdev), num);
+ *bar_len = pci_resource_len(to_pci_dev(bdev), num);
+ }
+ if (dfx_bus_eisa) {
+ unsigned long base_addr = to_eisa_device(bdev)->base_addr;
+ resource_size_t bar;
+
+ if (dfx_use_mmio) {
+ bar = inb(base_addr + PI_ESIC_K_MEM_ADD_CMP_2);
+ bar <<= 8;
+ bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_CMP_1);
+ bar <<= 8;
+ bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_CMP_0);
+ bar <<= 16;
+ *bar_start = bar;
+ bar = inb(base_addr + PI_ESIC_K_MEM_ADD_MASK_2);
+ bar <<= 8;
+ bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_MASK_1);
+ bar <<= 8;
+ bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_MASK_0);
+ bar <<= 16;
+ *bar_len = (bar | PI_MEM_ADD_MASK_M) + 1;
+ } else {
+ *bar_start = base_addr;
+ *bar_len = PI_ESIC_K_CSR_IO_LEN;
+ }
+ }
+ if (dfx_bus_tc) {
+ *bar_start = to_tc_dev(bdev)->resource.start +
+ PI_TC_K_CSR_OFFSET;
+ *bar_len = PI_TC_K_CSR_LEN;
+ }
+}
/*
- * =============
- * = dfx_init_one_pci_or_eisa =
- * =============
+ * ================
+ * = dfx_register =
+ * ================
*
* Overview:
- * Initializes a supported FDDI EISA or PCI controller
+ * Initializes a supported FDDI controller
*
* Returns:
* Condition code
*
* Arguments:
- * pdev - pointer to pci device information (NULL for EISA)
- * ioaddr - pointer to port (NULL for PCI)
+ * bdev - pointer to device information
*
* Functional Description:
*
@@ -407,56 +506,74 @@ static inline void dfx_port_read_long(
* initialized and the board resources are read and stored in
* the device structure.
*/
-static int __devinit dfx_init_one_pci_or_eisa(struct pci_dev *pdev, long ioaddr)
+static int __devinit dfx_register(struct device *bdev)
{
static int version_disp;
- char *print_name = DRV_NAME;
+ int dfx_bus_pci = DFX_BUS_PCI(bdev);
+ int dfx_bus_tc = DFX_BUS_TC(bdev);
+ int dfx_use_mmio = DFX_MMIO || dfx_bus_tc;
+ char *print_name = bdev->bus_id;
struct net_device *dev;
DFX_board_t *bp; /* board pointer */
+ resource_size_t bar_start = 0; /* pointer to port */
+ resource_size_t bar_len = 0; /* resource length */
int alloc_size; /* total buffer size used */
- int err;
+ struct resource *region;
+ int err = 0;
if (!version_disp) { /* display version info if adapter is found */
version_disp = 1; /* set display flag to TRUE so that */
printk(version); /* we only display this string ONCE */
}
- if (pdev != NULL)
- print_name = pci_name(pdev);
-
dev = alloc_fddidev(sizeof(*bp));
if (!dev) {
- printk(KERN_ERR "%s: unable to allocate fddidev, aborting\n",
+ printk(KERN_ERR "%s: Unable to allocate fddidev, aborting\n",
print_name);
return -ENOMEM;
}
/* Enable PCI device. */
- if (pdev != NULL) {
- err = pci_enable_device (pdev);
- if (err) goto err_out;
- ioaddr = pci_resource_start (pdev, 1);
+ if (dfx_bus_pci && pci_enable_device(to_pci_dev(bdev))) {
+ printk(KERN_ERR "%s: Cannot enable PCI device, aborting\n",
+ print_name);
+ goto err_out;
}
SET_MODULE_OWNER(dev);
- if (pdev != NULL)
- SET_NETDEV_DEV(dev, &pdev->dev);
+ SET_NETDEV_DEV(dev, bdev);
+
+ bp = netdev_priv(dev);
+ bp->bus_dev = bdev;
+ dev_set_drvdata(bdev, dev);
- bp = dev->priv;
+ dfx_get_bars(bdev, &bar_start, &bar_len);
- if (!request_region(ioaddr,
- pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN,
- print_name)) {
+ if (dfx_use_mmio)
+ region = request_mem_region(bar_start, bar_len, print_name);
+ else
+ region = request_region(bar_start, bar_len, print_name);
+ if (!region) {
printk(KERN_ERR "%s: Cannot reserve I/O resource "
- "0x%x @ 0x%lx, aborting\n", print_name,
- pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN, ioaddr);
+ "0x%lx @ 0x%lx, aborting\n",
+ print_name, (long)bar_len, (long)bar_start);
err = -EBUSY;
- goto err_out;
+ goto err_out_disable;
}
- /* Initialize new device structure */
+ /* Set up I/O base address. */
+ if (dfx_use_mmio) {
+ bp->base.mem = ioremap_nocache(bar_start, bar_len);
+ if (!bp->base.mem) {
+ printk(KERN_ERR "%s: Cannot map MMIO\n", print_name);
+ goto err_out_region;
+ }
+ } else {
+ bp->base.port = bar_start;
+ dev->base_addr = bar_start;
+ }
- dev->base_addr = ioaddr; /* save port (I/O) base address */
+ /* Initialize new device structure */
dev->get_stats = dfx_ctl_get_stats;
dev->open = dfx_open;
@@ -465,22 +582,12 @@ static int __devinit dfx_init_one_pci_or_eisa(struct pci_dev *pdev, long ioaddr)
dev->set_multicast_list = dfx_ctl_set_multicast_list;
dev->set_mac_address = dfx_ctl_set_mac_address;
- if (pdev == NULL) {
- /* EISA board */
- bp->bus_type = DFX_BUS_TYPE_EISA;
- bp->next = root_dfx_eisa_dev;
- root_dfx_eisa_dev = dev;
- } else {
- /* PCI board */
- bp->bus_type = DFX_BUS_TYPE_PCI;
- bp->pci_dev = pdev;
- pci_set_drvdata (pdev, dev);
- pci_set_master (pdev);
- }
+ if (dfx_bus_pci)
+ pci_set_master(to_pci_dev(bdev));
- if (dfx_driver_init(dev, print_name) != DFX_K_SUCCESS) {
+ if (dfx_driver_init(dev, print_name, bar_start) != DFX_K_SUCCESS) {
err = -ENODEV;
- goto err_out_region;
+ goto err_out_unmap;
}
err = register_netdev(dev);
@@ -499,44 +606,28 @@ err_out_kfree:
sizeof(PI_CONSUMER_BLOCK) +
(PI_ALIGN_K_DESC_BLK - 1);
if (bp->kmalloced)
- pci_free_consistent(pdev, alloc_size,
- bp->kmalloced, bp->kmalloced_dma);
+ dma_free_coherent(bdev, alloc_size,
+ bp->kmalloced, bp->kmalloced_dma);
+
+err_out_unmap:
+ if (dfx_use_mmio)
+ iounmap(bp->base.mem);
+
err_out_region:
- release_region(ioaddr, pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN);
+ if (dfx_use_mmio)
+ release_mem_region(bar_start, bar_len);
+ else
+ release_region(bar_start, bar_len);
+
+err_out_disable:
+ if (dfx_bus_pci)
+ pci_disable_device(to_pci_dev(bdev));
+
err_out:
free_netdev(dev);
return err;
}
-static int __devinit dfx_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- return dfx_init_one_pci_or_eisa(pdev, 0);
-}
-
-static int __init dfx_eisa_init(void)
-{
- int rc = -ENODEV;
- int i; /* used in for loops */
- u16 port; /* temporary I/O (port) address */
- u32 slot_id; /* EISA hardware (slot) ID read from adapter */
-
- DBG_printk("In dfx_eisa_init...\n");
-
- /* Scan for FDDI EISA controllers */
-
- for (i=0; i < DFX_MAX_EISA_SLOTS; i++) /* only scan for up to 16 EISA slots */
- {
- port = (i << 12) + PI_ESIC_K_SLOT_ID; /* port = I/O address for reading slot ID */
- slot_id = inl(port); /* read EISA HW (slot) ID */
- if ((slot_id & 0xF0FFFFFF) == DEFEA_PRODUCT_ID)
- {
- port = (i << 12); /* recalc base addr */
-
- if (dfx_init_one_pci_or_eisa(NULL, port) == 0) rc = 0;
- }
- }
- return rc;
-}
/*
* ================
@@ -544,7 +635,7 @@ static int __init dfx_eisa_init(void)
* ================
*
* Overview:
- * Initializes EISA and PCI controller bus-specific logic.
+ * Initializes the bus-specific controller logic.
*
* Returns:
* None
@@ -560,7 +651,7 @@ static int __init dfx_eisa_init(void)
* None
*
* Assumptions:
- * dev->base_addr has already been set with the proper
+ * bp->base has already been set with the proper
* base I/O address for this device.
*
* Side Effects:
@@ -571,87 +662,103 @@ static int __init dfx_eisa_init(void)
static void __devinit dfx_bus_init(struct net_device *dev)
{
- DFX_board_t *bp = dev->priv;
- u8 val; /* used for I/O read/writes */
+ DFX_board_t *bp = netdev_priv(dev);
+ struct device *bdev = bp->bus_dev;
+ int dfx_bus_pci = DFX_BUS_PCI(bdev);
+ int dfx_bus_eisa = DFX_BUS_EISA(bdev);
+ int dfx_bus_tc = DFX_BUS_TC(bdev);
+ int dfx_use_mmio = DFX_MMIO || dfx_bus_tc;
+ u8 val;
DBG_printk("In dfx_bus_init...\n");
- /*
- * Initialize base I/O address field in bp structure
- *
- * Note: bp->base_addr is the same as dev->base_addr.
- * It's useful because often we'll need to read
- * or write registers where we already have the
- * bp pointer instead of the dev pointer. Having
- * the base address in the bp structure will
- * save a pointer dereference.
- *
- * IMPORTANT!! This field must be defined before
- * any of the dfx_port_* inline functions are
- * called.
- */
-
- bp->base_addr = dev->base_addr;
-
- /* And a pointer back to the net_device struct */
+ /* Initialize a pointer back to the net_device struct */
bp->dev = dev;
/* Initialize adapter based on bus type */
- if (bp->bus_type == DFX_BUS_TYPE_EISA)
- {
- /* Get the interrupt level from the ESIC chip */
-
- dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &val);
- switch ((val & PI_CONFIG_STAT_0_M_IRQ) >> PI_CONFIG_STAT_0_V_IRQ)
- {
- case PI_CONFIG_STAT_0_IRQ_K_9:
- dev->irq = 9;
- break;
-
- case PI_CONFIG_STAT_0_IRQ_K_10:
- dev->irq = 10;
- break;
+ if (dfx_bus_tc)
+ dev->irq = to_tc_dev(bdev)->interrupt;
+ if (dfx_bus_eisa) {
+ unsigned long base_addr = to_eisa_device(bdev)->base_addr;
- case PI_CONFIG_STAT_0_IRQ_K_11:
- dev->irq = 11;
- break;
+ /* Get the interrupt level from the ESIC chip. */
+ val = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0);
+ val &= PI_CONFIG_STAT_0_M_IRQ;
+ val >>= PI_CONFIG_STAT_0_V_IRQ;
- case PI_CONFIG_STAT_0_IRQ_K_15:
- dev->irq = 15;
- break;
- }
-
- /* Enable access to I/O on the board by writing 0x03 to Function Control Register */
+ switch (val) {
+ case PI_CONFIG_STAT_0_IRQ_K_9:
+ dev->irq = 9;
+ break;
- dfx_port_write_byte(bp, PI_ESIC_K_FUNCTION_CNTRL, PI_ESIC_K_FUNCTION_CNTRL_IO_ENB);
+ case PI_CONFIG_STAT_0_IRQ_K_10:
+ dev->irq = 10;
+ break;
- /* Set the I/O decode range of the board */
+ case PI_CONFIG_STAT_0_IRQ_K_11:
+ dev->irq = 11;
+ break;
- val = ((dev->base_addr >> 12) << PI_IO_CMP_V_SLOT);
- dfx_port_write_byte(bp, PI_ESIC_K_IO_CMP_0_1, val);
- dfx_port_write_byte(bp, PI_ESIC_K_IO_CMP_1_1, val);
+ case PI_CONFIG_STAT_0_IRQ_K_15:
+ dev->irq = 15;
+ break;
+ }
- /* Enable access to rest of module (including PDQ and packet memory) */
+ /*
+ * Enable memory decoding (MEMCS0) and/or port decoding
+ * (IOCS1/IOCS0) as appropriate in Function Control
+ * Register. One of the port chip selects seems to be
+ * used for the Burst Holdoff register, but this bit of
+ * documentation is missing and as yet it has not been
+ * determined which of the two. This is also the reason
+ * the size of the decoded port range is twice as large
+ * as one required by the PDQ.
+ */
- dfx_port_write_byte(bp, PI_ESIC_K_SLOT_CNTRL, PI_SLOT_CNTRL_M_ENB);
+ /* Set the decode range of the board. */
+ val = ((bp->base.port >> 12) << PI_IO_CMP_V_SLOT);
+ outb(base_addr + PI_ESIC_K_IO_ADD_CMP_0_1, val);
+ outb(base_addr + PI_ESIC_K_IO_ADD_CMP_0_0, 0);
+ outb(base_addr + PI_ESIC_K_IO_ADD_CMP_1_1, val);
+ outb(base_addr + PI_ESIC_K_IO_ADD_CMP_1_0, 0);
+ val = PI_ESIC_K_CSR_IO_LEN - 1;
+ outb(base_addr + PI_ESIC_K_IO_ADD_MASK_0_1, (val >> 8) & 0xff);
+ outb(base_addr + PI_ESIC_K_IO_ADD_MASK_0_0, val & 0xff);
+ outb(base_addr + PI_ESIC_K_IO_ADD_MASK_1_1, (val >> 8) & 0xff);
+ outb(base_addr + PI_ESIC_K_IO_ADD_MASK_1_0, val & 0xff);
+
+ /* Enable the decoders. */
+ val = PI_FUNCTION_CNTRL_M_IOCS1 | PI_FUNCTION_CNTRL_M_IOCS0;
+ if (dfx_use_mmio)
+ val |= PI_FUNCTION_CNTRL_M_MEMCS0;
+ outb(base_addr + PI_ESIC_K_FUNCTION_CNTRL, val);
/*
- * Map PDQ registers into I/O space. This is done by clearing a bit
- * in Burst Holdoff register.
+ * Enable access to the rest of the module
+ * (including PDQ and packet memory).
*/
+ val = PI_SLOT_CNTRL_M_ENB;
+ outb(base_addr + PI_ESIC_K_SLOT_CNTRL, val);
- dfx_port_read_byte(bp, PI_ESIC_K_BURST_HOLDOFF, &val);
- dfx_port_write_byte(bp, PI_ESIC_K_BURST_HOLDOFF, (val & ~PI_BURST_HOLDOFF_M_MEM_MAP));
+ /*
+ * Map PDQ registers into memory or port space. This is
+ * done with a bit in the Burst Holdoff register.
+ */
+ val = inb(base_addr + PI_DEFEA_K_BURST_HOLDOFF);
+ if (dfx_use_mmio)
+ val |= PI_BURST_HOLDOFF_V_MEM_MAP;
+ else
+ val &= ~PI_BURST_HOLDOFF_V_MEM_MAP;
+ outb(base_addr + PI_DEFEA_K_BURST_HOLDOFF, val);
/* Enable interrupts at EISA bus interface chip (ESIC) */
-
- dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &val);
- dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, (val | PI_CONFIG_STAT_0_M_INT_ENB));
- }
- else
- {
- struct pci_dev *pdev = bp->pci_dev;
+ val = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0);
+ val |= PI_CONFIG_STAT_0_M_INT_ENB;
+ outb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0, val);
+ }
+ if (dfx_bus_pci) {
+ struct pci_dev *pdev = to_pci_dev(bdev);
/* Get the interrupt level from the PCI Configuration Table */
@@ -660,17 +767,70 @@ static void __devinit dfx_bus_init(struct net_device *dev)
/* Check Latency Timer and set if less than minimal */
pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &val);
- if (val < PFI_K_LAT_TIMER_MIN) /* if less than min, override with default */
- {
+ if (val < PFI_K_LAT_TIMER_MIN) {
val = PFI_K_LAT_TIMER_DEF;
pci_write_config_byte(pdev, PCI_LATENCY_TIMER, val);
- }
+ }
/* Enable interrupts at PCI bus interface chip (PFI) */
+ val = PFI_MODE_M_PDQ_INT_ENB | PFI_MODE_M_DMA_ENB;
+ dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, val);
+ }
+}
- dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, (PFI_MODE_M_PDQ_INT_ENB | PFI_MODE_M_DMA_ENB));
- }
+/*
+ * ==================
+ * = dfx_bus_uninit =
+ * ==================
+ *
+ * Overview:
+ * Uninitializes the bus-specific controller logic.
+ *
+ * Returns:
+ * None
+ *
+ * Arguments:
+ * dev - pointer to device information
+ *
+ * Functional Description:
+ * Perform bus-specific logic uninitialization.
+ *
+ * Return Codes:
+ * None
+ *
+ * Assumptions:
+ * bp->base has already been set with the proper
+ * base I/O address for this device.
+ *
+ * Side Effects:
+ * Interrupts are disabled at the adapter bus-specific logic.
+ */
+
+static void __devinit dfx_bus_uninit(struct net_device *dev)
+{
+ DFX_board_t *bp = netdev_priv(dev);
+ struct device *bdev = bp->bus_dev;
+ int dfx_bus_pci = DFX_BUS_PCI(bdev);
+ int dfx_bus_eisa = DFX_BUS_EISA(bdev);
+ u8 val;
+
+ DBG_printk("In dfx_bus_uninit...\n");
+
+ /* Uninitialize adapter based on bus type */
+
+ if (dfx_bus_eisa) {
+ unsigned long base_addr = to_eisa_device(bdev)->base_addr;
+
+ /* Disable interrupts at EISA bus interface chip (ESIC) */
+ val = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0);
+ val &= ~PI_CONFIG_STAT_0_M_INT_ENB;
+ outb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0, val);
+ }
+ if (dfx_bus_pci) {
+ /* Disable interrupts at PCI bus interface chip (PFI) */
+ dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, 0);
}
+}
/*
@@ -705,18 +865,16 @@ static void __devinit dfx_bus_init(struct net_device *dev)
static void __devinit dfx_bus_config_check(DFX_board_t *bp)
{
+ struct device __unused *bdev = bp->bus_dev;
+ int dfx_bus_eisa = DFX_BUS_EISA(bdev);
int status; /* return code from adapter port control call */
- u32 slot_id; /* EISA-bus hardware id (DEC3001, DEC3002,...) */
u32 host_data; /* LW data returned from port control call */
DBG_printk("In dfx_bus_config_check...\n");
/* Configuration check only valid for EISA adapter */
- if (bp->bus_type == DFX_BUS_TYPE_EISA)
- {
- dfx_port_read_long(bp, PI_ESIC_K_SLOT_ID, &slot_id);
-
+ if (dfx_bus_eisa) {
/*
* First check if revision 2 EISA controller. Rev. 1 cards used
* PDQ revision B, so no workaround needed in this case. Rev. 3
@@ -724,14 +882,11 @@ static void __devinit dfx_bus_config_check(DFX_board_t *bp)
* case, either. Only Rev. 2 cards used either Rev. D or E
* chips, so we must verify the chip revision on Rev. 2 cards.
*/
-
- if (slot_id == DEFEA_PROD_ID_2)
- {
+ if (to_eisa_device(bdev)->id.driver_data == DEFEA_PROD_ID_2) {
/*
- * Revision 2 FDDI EISA controller found, so let's check PDQ
- * revision of adapter.
+ * Revision 2 FDDI EISA controller found,
+ * so let's check PDQ revision of adapter.
*/
-
status = dfx_hw_port_ctrl_req(bp,
PI_PCTRL_M_SUB_CMD,
PI_SUB_CMD_K_PDQ_REV_GET,
@@ -805,13 +960,20 @@ static void __devinit dfx_bus_config_check(DFX_board_t *bp)
*/
static int __devinit dfx_driver_init(struct net_device *dev,
- const char *print_name)
+ const char *print_name,
+ resource_size_t bar_start)
{
- DFX_board_t *bp = dev->priv;
- int alloc_size; /* total buffer size needed */
- char *top_v, *curr_v; /* virtual addrs into memory block */
- dma_addr_t top_p, curr_p; /* physical addrs into memory block */
- u32 data; /* host data register value */
+ DFX_board_t *bp = netdev_priv(dev);
+ struct device *bdev = bp->bus_dev;
+ int dfx_bus_pci = DFX_BUS_PCI(bdev);
+ int dfx_bus_eisa = DFX_BUS_EISA(bdev);
+ int dfx_bus_tc = DFX_BUS_TC(bdev);
+ int dfx_use_mmio = DFX_MMIO || dfx_bus_tc;
+ int alloc_size; /* total buffer size needed */
+ char *top_v, *curr_v; /* virtual addrs into memory block */
+ dma_addr_t top_p, curr_p; /* physical addrs into memory block */
+ u32 data, le32; /* host data register value */
+ char *board_name = NULL;
DBG_printk("In dfx_driver_init...\n");
@@ -860,8 +1022,8 @@ static int __devinit dfx_driver_init(struct net_device *dev,
print_name);
return(DFX_K_FAILURE);
}
- data = cpu_to_le32(data);
- memcpy(&bp->factory_mac_addr[0], &data, sizeof(u32));
+ le32 = cpu_to_le32(data);
+ memcpy(&bp->factory_mac_addr[0], &le32, sizeof(u32));
if (dfx_hw_port_ctrl_req(bp, PI_PCTRL_M_MLA, PI_PDATA_A_MLA_K_HI, 0,
&data) != DFX_K_SUCCESS) {
@@ -869,8 +1031,8 @@ static int __devinit dfx_driver_init(struct net_device *dev,
print_name);
return(DFX_K_FAILURE);
}
- data = cpu_to_le32(data);
- memcpy(&bp->factory_mac_addr[4], &data, sizeof(u16));
+ le32 = cpu_to_le32(data);
+ memcpy(&bp->factory_mac_addr[4], &le32, sizeof(u16));
/*
* Set current address to factory address
@@ -880,20 +1042,18 @@ static int __devinit dfx_driver_init(struct net_device *dev,
*/
memcpy(dev->dev_addr, bp->factory_mac_addr, FDDI_K_ALEN);
- if (bp->bus_type == DFX_BUS_TYPE_EISA)
- printk("%s: DEFEA at I/O addr = 0x%lX, IRQ = %d, "
- "Hardware addr = %02X-%02X-%02X-%02X-%02X-%02X\n",
- print_name, dev->base_addr, dev->irq,
- dev->dev_addr[0], dev->dev_addr[1],
- dev->dev_addr[2], dev->dev_addr[3],
- dev->dev_addr[4], dev->dev_addr[5]);
- else
- printk("%s: DEFPA at I/O addr = 0x%lX, IRQ = %d, "
- "Hardware addr = %02X-%02X-%02X-%02X-%02X-%02X\n",
- print_name, dev->base_addr, dev->irq,
- dev->dev_addr[0], dev->dev_addr[1],
- dev->dev_addr[2], dev->dev_addr[3],
- dev->dev_addr[4], dev->dev_addr[5]);
+ if (dfx_bus_tc)
+ board_name = "DEFTA";
+ if (dfx_bus_eisa)
+ board_name = "DEFEA";
+ if (dfx_bus_pci)
+ board_name = "DEFPA";
+ pr_info("%s: %s at %saddr = 0x%llx, IRQ = %d, "
+ "Hardware addr = %02X-%02X-%02X-%02X-%02X-%02X\n",
+ print_name, board_name, dfx_use_mmio ? "" : "I/O ",
+ (long long)bar_start, dev->irq,
+ dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+ dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
/*
* Get memory for descriptor block, consumer block, and other buffers
@@ -908,8 +1068,9 @@ static int __devinit dfx_driver_init(struct net_device *dev,
#endif
sizeof(PI_CONSUMER_BLOCK) +
(PI_ALIGN_K_DESC_BLK - 1);
- bp->kmalloced = top_v = pci_alloc_consistent(bp->pci_dev, alloc_size,
- &bp->kmalloced_dma);
+ bp->kmalloced = top_v = dma_alloc_coherent(bp->bus_dev, alloc_size,
+ &bp->kmalloced_dma,
+ GFP_ATOMIC);
if (top_v == NULL) {
printk("%s: Could not allocate memory for host buffers "
"and structures!\n", print_name);
@@ -1219,14 +1380,15 @@ static int dfx_adap_init(DFX_board_t *bp, int get_buffers)
static int dfx_open(struct net_device *dev)
{
+ DFX_board_t *bp = netdev_priv(dev);
int ret;
- DFX_board_t *bp = dev->priv;
DBG_printk("In dfx_open...\n");
/* Register IRQ - support shared interrupts by passing device ptr */
- ret = request_irq(dev->irq, dfx_interrupt, IRQF_SHARED, dev->name, dev);
+ ret = request_irq(dev->irq, dfx_interrupt, IRQF_SHARED, dev->name,
+ dev);
if (ret) {
printk(KERN_ERR "%s: Requested IRQ %d is busy\n", dev->name, dev->irq);
return ret;
@@ -1309,7 +1471,7 @@ static int dfx_open(struct net_device *dev)
static int dfx_close(struct net_device *dev)
{
- DFX_board_t *bp = dev->priv;
+ DFX_board_t *bp = netdev_priv(dev);
DBG_printk("In dfx_close...\n");
@@ -1645,7 +1807,7 @@ static void dfx_int_type_0_process(DFX_board_t *bp)
static void dfx_int_common(struct net_device *dev)
{
- DFX_board_t *bp = dev->priv;
+ DFX_board_t *bp = netdev_priv(dev);
PI_UINT32 port_status; /* Port Status register */
/* Process xmt interrupts - frequent case, so always call this routine */
@@ -1715,18 +1877,16 @@ static void dfx_int_common(struct net_device *dev)
static irqreturn_t dfx_interrupt(int irq, void *dev_id)
{
- struct net_device *dev = dev_id;
- DFX_board_t *bp; /* private board structure pointer */
-
- /* Get board pointer only if device structure is valid */
-
- bp = dev->priv;
-
- /* See if we're already servicing an interrupt */
+ struct net_device *dev = dev_id;
+ DFX_board_t *bp = netdev_priv(dev);
+ struct device *bdev = bp->bus_dev;
+ int dfx_bus_pci = DFX_BUS_PCI(bdev);
+ int dfx_bus_eisa = DFX_BUS_EISA(bdev);
+ int dfx_bus_tc = DFX_BUS_TC(bdev);
/* Service adapter interrupts */
- if (bp->bus_type == DFX_BUS_TYPE_PCI) {
+ if (dfx_bus_pci) {
u32 status;
dfx_port_read_long(bp, PFI_K_REG_STATUS, &status);
@@ -1750,10 +1910,12 @@ static irqreturn_t dfx_interrupt(int irq, void *dev_id)
PFI_MODE_M_DMA_ENB));
spin_unlock(&bp->lock);
- } else {
+ }
+ if (dfx_bus_eisa) {
+ unsigned long base_addr = to_eisa_device(bdev)->base_addr;
u8 status;
- dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &status);
+ status = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0);
if (!(status & PI_CONFIG_STAT_0_M_PEND))
return IRQ_NONE;
@@ -1761,15 +1923,35 @@ static irqreturn_t dfx_interrupt(int irq, void *dev_id)
/* Disable interrupts at the ESIC */
status &= ~PI_CONFIG_STAT_0_M_INT_ENB;
- dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, status);
+ outb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0, status);
/* Call interrupt service routine for this adapter */
dfx_int_common(dev);
/* Reenable interrupts at the ESIC */
- dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &status);
+ status = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0);
status |= PI_CONFIG_STAT_0_M_INT_ENB;
- dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, status);
+ outb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0, status);
+
+ spin_unlock(&bp->lock);
+ }
+ if (dfx_bus_tc) {
+ u32 status;
+
+ dfx_port_read_long(bp, PI_PDQ_K_REG_PORT_STATUS, &status);
+ if (!(status & (PI_PSTATUS_M_RCV_DATA_PENDING |
+ PI_PSTATUS_M_XMT_DATA_PENDING |
+ PI_PSTATUS_M_SMT_HOST_PENDING |
+ PI_PSTATUS_M_UNSOL_PENDING |
+ PI_PSTATUS_M_CMD_RSP_PENDING |
+ PI_PSTATUS_M_CMD_REQ_PENDING |
+ PI_PSTATUS_M_TYPE_0_PENDING)))
+ return IRQ_NONE;
+
+ spin_lock(&bp->lock);
+
+ /* Call interrupt service routine for this adapter */
+ dfx_int_common(dev);
spin_unlock(&bp->lock);
}
@@ -1823,7 +2005,7 @@ static irqreturn_t dfx_interrupt(int irq, void *dev_id)
static struct net_device_stats *dfx_ctl_get_stats(struct net_device *dev)
{
- DFX_board_t *bp = dev->priv;
+ DFX_board_t *bp = netdev_priv(dev);
/* Fill the bp->stats structure with driver-maintained counters */
@@ -2009,8 +2191,8 @@ static struct net_device_stats *dfx_ctl_get_stats(struct net_device *dev)
*/
static void dfx_ctl_set_multicast_list(struct net_device *dev)
- {
- DFX_board_t *bp = dev->priv;
+{
+ DFX_board_t *bp = netdev_priv(dev);
int i; /* used as index in for loop */
struct dev_mc_list *dmi; /* ptr to multicast addr entry */
@@ -2124,8 +2306,8 @@ static void dfx_ctl_set_multicast_list(struct net_device *dev)
static int dfx_ctl_set_mac_address(struct net_device *dev, void *addr)
{
- DFX_board_t *bp = dev->priv;
struct sockaddr *p_sockaddr = (struct sockaddr *)addr;
+ DFX_board_t *bp = netdev_priv(dev);
/* Copy unicast address to driver-maintained structs and update count */
@@ -2764,9 +2946,9 @@ static int dfx_rcv_init(DFX_board_t *bp, int get_buffers)
my_skb_align(newskb, 128);
bp->descr_block_virt->rcv_data[i + j].long_1 =
- (u32)pci_map_single(bp->pci_dev, newskb->data,
+ (u32)dma_map_single(bp->bus_dev, newskb->data,
NEW_SKB_SIZE,
- PCI_DMA_FROMDEVICE);
+ DMA_FROM_DEVICE);
/*
* p_rcv_buff_va is only used inside the
* kernel so we put the skb pointer here.
@@ -2880,17 +3062,17 @@ static void dfx_rcv_queue_process(
my_skb_align(newskb, 128);
skb = (struct sk_buff *)bp->p_rcv_buff_va[entry];
- pci_unmap_single(bp->pci_dev,
+ dma_unmap_single(bp->bus_dev,
bp->descr_block_virt->rcv_data[entry].long_1,
NEW_SKB_SIZE,
- PCI_DMA_FROMDEVICE);
+ DMA_FROM_DEVICE);
skb_reserve(skb, RCV_BUFF_K_PADDING);
bp->p_rcv_buff_va[entry] = (char *)newskb;
bp->descr_block_virt->rcv_data[entry].long_1 =
- (u32)pci_map_single(bp->pci_dev,
+ (u32)dma_map_single(bp->bus_dev,
newskb->data,
NEW_SKB_SIZE,
- PCI_DMA_FROMDEVICE);
+ DMA_FROM_DEVICE);
} else
skb = NULL;
} else
@@ -3010,7 +3192,7 @@ static int dfx_xmt_queue_pkt(
)
{
- DFX_board_t *bp = dev->priv;
+ DFX_board_t *bp = netdev_priv(dev);
u8 prod; /* local transmit producer index */
PI_XMT_DESCR *p_xmt_descr; /* ptr to transmit descriptor block entry */
XMT_DRIVER_DESCR *p_xmt_drv_descr; /* ptr to transmit driver descriptor */
@@ -3116,8 +3298,8 @@ static int dfx_xmt_queue_pkt(
*/
p_xmt_descr->long_0 = (u32) (PI_XMT_DESCR_M_SOP | PI_XMT_DESCR_M_EOP | ((skb->len) << PI_XMT_DESCR_V_SEG_LEN));
- p_xmt_descr->long_1 = (u32)pci_map_single(bp->pci_dev, skb->data,
- skb->len, PCI_DMA_TODEVICE);
+ p_xmt_descr->long_1 = (u32)dma_map_single(bp->bus_dev, skb->data,
+ skb->len, DMA_TO_DEVICE);
/*
* Verify that descriptor is actually available
@@ -3220,10 +3402,10 @@ static int dfx_xmt_done(DFX_board_t *bp)
/* Return skb to operating system */
comp = bp->rcv_xmt_reg.index.xmt_comp;
- pci_unmap_single(bp->pci_dev,
+ dma_unmap_single(bp->bus_dev,
bp->descr_block_virt->xmt_data[comp].long_1,
p_xmt_drv_descr->p_skb->len,
- PCI_DMA_TODEVICE);
+ DMA_TO_DEVICE);
dev_kfree_skb_irq(p_xmt_drv_descr->p_skb);
/*
@@ -3344,10 +3526,10 @@ static void dfx_xmt_flush( DFX_board_t *bp )
/* Return skb to operating system */
comp = bp->rcv_xmt_reg.index.xmt_comp;
- pci_unmap_single(bp->pci_dev,
+ dma_unmap_single(bp->bus_dev,
bp->descr_block_virt->xmt_data[comp].long_1,
p_xmt_drv_descr->p_skb->len,
- PCI_DMA_TODEVICE);
+ DMA_TO_DEVICE);
dev_kfree_skb(p_xmt_drv_descr->p_skb);
/* Increment transmit error counter */
@@ -3375,13 +3557,44 @@ static void dfx_xmt_flush( DFX_board_t *bp )
bp->cons_block_virt->xmt_rcv_data = prod_cons;
}
-static void __devexit dfx_remove_one_pci_or_eisa(struct pci_dev *pdev, struct net_device *dev)
+/*
+ * ==================
+ * = dfx_unregister =
+ * ==================
+ *
+ * Overview:
+ * Shuts down an FDDI controller
+ *
+ * Returns:
+ * Condition code
+ *
+ * Arguments:
+ * bdev - pointer to device information
+ *
+ * Functional Description:
+ *
+ * Return Codes:
+ * None
+ *
+ * Assumptions:
+ * It compiles so it should work :-( (PCI cards do :-)
+ *
+ * Side Effects:
+ * Device structures for FDDI adapters (fddi0, fddi1, etc) are
+ * freed.
+ */
+static void __devexit dfx_unregister(struct device *bdev)
{
- DFX_board_t *bp = dev->priv;
+ struct net_device *dev = dev_get_drvdata(bdev);
+ DFX_board_t *bp = netdev_priv(dev);
+ int dfx_bus_pci = DFX_BUS_PCI(bdev);
+ int dfx_bus_tc = DFX_BUS_TC(bdev);
+ int dfx_use_mmio = DFX_MMIO || dfx_bus_tc;
+ resource_size_t bar_start = 0; /* pointer to port */
+ resource_size_t bar_len = 0; /* resource length */
int alloc_size; /* total buffer size used */
unregister_netdev(dev);
- release_region(dev->base_addr, pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN );
alloc_size = sizeof(PI_DESCR_BLOCK) +
PI_CMD_REQ_K_SIZE_MAX + PI_CMD_RSP_K_SIZE_MAX +
@@ -3391,78 +3604,141 @@ static void __devexit dfx_remove_one_pci_or_eisa(struct pci_dev *pdev, struct ne
sizeof(PI_CONSUMER_BLOCK) +
(PI_ALIGN_K_DESC_BLK - 1);
if (bp->kmalloced)
- pci_free_consistent(pdev, alloc_size, bp->kmalloced,
- bp->kmalloced_dma);
+ dma_free_coherent(bdev, alloc_size,
+ bp->kmalloced, bp->kmalloced_dma);
+
+ dfx_bus_uninit(dev);
+
+ dfx_get_bars(bdev, &bar_start, &bar_len);
+ if (dfx_use_mmio) {
+ iounmap(bp->base.mem);
+ release_mem_region(bar_start, bar_len);
+ } else
+ release_region(bar_start, bar_len);
+
+ if (dfx_bus_pci)
+ pci_disable_device(to_pci_dev(bdev));
+
free_netdev(dev);
}
-static void __devexit dfx_remove_one (struct pci_dev *pdev)
-{
- struct net_device *dev = pci_get_drvdata(pdev);
- dfx_remove_one_pci_or_eisa(pdev, dev);
- pci_set_drvdata(pdev, NULL);
-}
+static int __devinit __unused dfx_dev_register(struct device *);
+static int __devexit __unused dfx_dev_unregister(struct device *);
-static struct pci_device_id dfx_pci_tbl[] = {
- { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_FDDI, PCI_ANY_ID, PCI_ANY_ID, },
- { 0, }
+#ifdef CONFIG_PCI
+static int __devinit dfx_pci_register(struct pci_dev *,
+ const struct pci_device_id *);
+static void __devexit dfx_pci_unregister(struct pci_dev *);
+
+static struct pci_device_id dfx_pci_table[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_FDDI) },
+ { }
};
-MODULE_DEVICE_TABLE(pci, dfx_pci_tbl);
+MODULE_DEVICE_TABLE(pci, dfx_pci_table);
-static struct pci_driver dfx_driver = {
+static struct pci_driver dfx_pci_driver = {
.name = "defxx",
- .probe = dfx_init_one,
- .remove = __devexit_p(dfx_remove_one),
- .id_table = dfx_pci_tbl,
+ .id_table = dfx_pci_table,
+ .probe = dfx_pci_register,
+ .remove = __devexit_p(dfx_pci_unregister),
};
-static int dfx_have_pci;
-static int dfx_have_eisa;
-
+static __devinit int dfx_pci_register(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ return dfx_register(&pdev->dev);
+}
-static void __exit dfx_eisa_cleanup(void)
+static void __devexit dfx_pci_unregister(struct pci_dev *pdev)
{
- struct net_device *dev = root_dfx_eisa_dev;
+ dfx_unregister(&pdev->dev);
+}
+#endif /* CONFIG_PCI */
+
+#ifdef CONFIG_EISA
+static struct eisa_device_id dfx_eisa_table[] = {
+ { "DEC3001", DEFEA_PROD_ID_1 },
+ { "DEC3002", DEFEA_PROD_ID_2 },
+ { "DEC3003", DEFEA_PROD_ID_3 },
+ { "DEC3004", DEFEA_PROD_ID_4 },
+ { }
+};
+MODULE_DEVICE_TABLE(eisa, dfx_eisa_table);
+
+static struct eisa_driver dfx_eisa_driver = {
+ .id_table = dfx_eisa_table,
+ .driver = {
+ .name = "defxx",
+ .bus = &eisa_bus_type,
+ .probe = dfx_dev_register,
+ .remove = __devexit_p(dfx_dev_unregister),
+ },
+};
+#endif /* CONFIG_EISA */
+
+#ifdef CONFIG_TC
+static struct tc_device_id const dfx_tc_table[] = {
+ { "DEC ", "PMAF-FA " },
+ { "DEC ", "PMAF-FD " },
+ { "DEC ", "PMAF-FS " },
+ { "DEC ", "PMAF-FU " },
+ { }
+};
+MODULE_DEVICE_TABLE(tc, dfx_tc_table);
+
+static struct tc_driver dfx_tc_driver = {
+ .id_table = dfx_tc_table,
+ .driver = {
+ .name = "defxx",
+ .bus = &tc_bus_type,
+ .probe = dfx_dev_register,
+ .remove = __devexit_p(dfx_dev_unregister),
+ },
+};
+#endif /* CONFIG_TC */
- while (dev)
- {
- struct net_device *tmp;
- DFX_board_t *bp;
+static int __devinit __unused dfx_dev_register(struct device *dev)
+{
+ int status;
- bp = (DFX_board_t*)dev->priv;
- tmp = bp->next;
- dfx_remove_one_pci_or_eisa(NULL, dev);
- dev = tmp;
- }
+ status = dfx_register(dev);
+ if (!status)
+ get_device(dev);
+ return status;
}
-static int __init dfx_init(void)
+static int __devexit __unused dfx_dev_unregister(struct device *dev)
{
- int rc_pci, rc_eisa;
-
- rc_pci = pci_register_driver(&dfx_driver);
- if (rc_pci >= 0) dfx_have_pci = 1;
+ put_device(dev);
+ dfx_unregister(dev);
+ return 0;
+}
- rc_eisa = dfx_eisa_init();
- if (rc_eisa >= 0) dfx_have_eisa = 1;
- return ((rc_eisa < 0) ? 0 : rc_eisa) + ((rc_pci < 0) ? 0 : rc_pci);
+static int __devinit dfx_init(void)
+{
+ int status;
+
+ status = pci_register_driver(&dfx_pci_driver);
+ if (!status)
+ status = eisa_driver_register(&dfx_eisa_driver);
+ if (!status)
+ status = tc_register_driver(&dfx_tc_driver);
+ return status;
}
-static void __exit dfx_cleanup(void)
+static void __devexit dfx_cleanup(void)
{
- if (dfx_have_pci)
- pci_unregister_driver(&dfx_driver);
- if (dfx_have_eisa)
- dfx_eisa_cleanup();
-
+ tc_unregister_driver(&dfx_tc_driver);
+ eisa_driver_unregister(&dfx_eisa_driver);
+ pci_unregister_driver(&dfx_pci_driver);
}
module_init(dfx_init);
module_exit(dfx_cleanup);
MODULE_AUTHOR("Lawrence V. Stefani");
-MODULE_DESCRIPTION("DEC FDDIcontroller EISA/PCI (DEFEA/DEFPA) driver "
+MODULE_DESCRIPTION("DEC FDDIcontroller TC/EISA/PCI (DEFTA/DEFEA/DEFPA) driver "
DRV_VERSION " " DRV_RELDATE);
MODULE_LICENSE("GPL");
diff --git a/drivers/net/defxx.h b/drivers/net/defxx.h
index 2ce8f97253e..19a6f64df19 100644
--- a/drivers/net/defxx.h
+++ b/drivers/net/defxx.h
@@ -26,6 +26,7 @@
* 12-Sep-96 LVS Removed packet request header pointers.
* 04 Aug 2003 macro Converted to the DMA API.
* 23 Oct 2006 macro Big-endian host support.
+ * 14 Dec 2006 macro TURBOchannel support.
*/
#ifndef _DEFXX_H_
@@ -1471,9 +1472,17 @@ typedef union
#endif /* __BIG_ENDIAN */
+/* Define TC PDQ CSR offset and length */
+
+#define PI_TC_K_CSR_OFFSET 0x100000
+#define PI_TC_K_CSR_LEN 0x40 /* 64 bytes */
+
/* Define EISA controller register offsets */
-#define PI_ESIC_K_BURST_HOLDOFF 0x040
+#define PI_ESIC_K_CSR_IO_LEN 0x80 /* 128 bytes */
+
+#define PI_DEFEA_K_BURST_HOLDOFF 0x040
+
#define PI_ESIC_K_SLOT_ID 0xC80
#define PI_ESIC_K_SLOT_CNTRL 0xC84
#define PI_ESIC_K_MEM_ADD_CMP_0 0xC85
@@ -1488,14 +1497,14 @@ typedef union
#define PI_ESIC_K_MEM_ADD_LO_CMP_0 0xC8E
#define PI_ESIC_K_MEM_ADD_LO_CMP_1 0xC8F
#define PI_ESIC_K_MEM_ADD_LO_CMP_2 0xC90
-#define PI_ESIC_K_IO_CMP_0_0 0xC91
-#define PI_ESIC_K_IO_CMP_0_1 0xC92
-#define PI_ESIC_K_IO_CMP_1_0 0xC93
-#define PI_ESIC_K_IO_CMP_1_1 0xC94
-#define PI_ESIC_K_IO_CMP_2_0 0xC95
-#define PI_ESIC_K_IO_CMP_2_1 0xC96
-#define PI_ESIC_K_IO_CMP_3_0 0xC97
-#define PI_ESIC_K_IO_CMP_3_1 0xC98
+#define PI_ESIC_K_IO_ADD_CMP_0_0 0xC91
+#define PI_ESIC_K_IO_ADD_CMP_0_1 0xC92
+#define PI_ESIC_K_IO_ADD_CMP_1_0 0xC93
+#define PI_ESIC_K_IO_ADD_CMP_1_1 0xC94
+#define PI_ESIC_K_IO_ADD_CMP_2_0 0xC95
+#define PI_ESIC_K_IO_ADD_CMP_2_1 0xC96
+#define PI_ESIC_K_IO_ADD_CMP_3_0 0xC97
+#define PI_ESIC_K_IO_ADD_CMP_3_1 0xC98
#define PI_ESIC_K_IO_ADD_MASK_0_0 0xC99
#define PI_ESIC_K_IO_ADD_MASK_0_1 0xC9A
#define PI_ESIC_K_IO_ADD_MASK_1_0 0xC9B
@@ -1518,11 +1527,16 @@ typedef union
#define PI_ESIC_K_INPUT_PORT 0xCAC
#define PI_ESIC_K_OUTPUT_PORT 0xCAD
#define PI_ESIC_K_FUNCTION_CNTRL 0xCAE
-#define PI_ESIC_K_CSR_IO_LEN PI_ESIC_K_FUNCTION_CNTRL+1 /* always last reg + 1 */
-/* Define the value all drivers must write to the function control register. */
+/* Define the bits in the function control register. */
-#define PI_ESIC_K_FUNCTION_CNTRL_IO_ENB 0x03
+#define PI_FUNCTION_CNTRL_M_IOCS0 0x01
+#define PI_FUNCTION_CNTRL_M_IOCS1 0x02
+#define PI_FUNCTION_CNTRL_M_IOCS2 0x04
+#define PI_FUNCTION_CNTRL_M_IOCS3 0x08
+#define PI_FUNCTION_CNTRL_M_MEMCS0 0x10
+#define PI_FUNCTION_CNTRL_M_MEMCS1 0x20
+#define PI_FUNCTION_CNTRL_M_DMA 0x80
/* Define the bits in the slot control register. */
@@ -1540,6 +1554,10 @@ typedef union
#define PI_BURST_HOLDOFF_V_RESERVED 1
#define PI_BURST_HOLDOFF_V_MEM_MAP 0
+/* Define the implicit mask of the Memory Address Mask Register. */
+
+#define PI_MEM_ADD_MASK_M 0x3ff
+
/*
* Define the fields in the IO Compare registers.
* The driver must initialize the slot field with the slot ID shifted by the
@@ -1577,6 +1595,7 @@ typedef union
#define DEFEA_PROD_ID_1 0x0130A310 /* DEC product 300, rev 1 */
#define DEFEA_PROD_ID_2 0x0230A310 /* DEC product 300, rev 2 */
#define DEFEA_PROD_ID_3 0x0330A310 /* DEC product 300, rev 3 */
+#define DEFEA_PROD_ID_4 0x0430A310 /* DEC product 300, rev 4 */
/**********************************************/
/* Digital PFI Specification v1.0 Definitions */
@@ -1633,12 +1652,6 @@ typedef union
#define PFI_STATUS_V_FIFO_EMPTY 1
#define PFI_STATUS_V_DMA_IN_PROGRESS 0
-#define DFX_MAX_EISA_SLOTS 16 /* maximum number of EISA slots to scan */
-#define DFX_MAX_NUM_BOARDS 8 /* maximum number of adapters supported */
-
-#define DFX_BUS_TYPE_PCI 0 /* type code for DEC FDDIcontroller/PCI */
-#define DFX_BUS_TYPE_EISA 1 /* type code for DEC FDDIcontroller/EISA */
-
#define DFX_FC_PRH2_PRH1_PRH0 0x54003820 /* Packet Request Header bytes + FC */
#define DFX_PRH0_BYTE 0x20 /* Packet Request Header byte 0 */
#define DFX_PRH1_BYTE 0x38 /* Packet Request Header byte 1 */
@@ -1756,10 +1769,11 @@ typedef struct DFX_board_tag
/* Store device, bus-specific, and parameter information for this adapter */
struct net_device *dev; /* pointer to device structure */
- struct net_device *next;
- u32 bus_type; /* bus type (0 == PCI, 1 == EISA) */
- u16 base_addr; /* base I/O address (same as dev->base_addr) */
- struct pci_dev * pci_dev;
+ union {
+ void __iomem *mem;
+ int port;
+ } base; /* base address */
+ struct device *bus_dev;
u32 full_duplex_enb; /* FDDI Full Duplex enable (1 == on, 2 == off) */
u32 req_ttrt; /* requested TTRT value (in 80ns units) */
u32 burst_size; /* adapter burst size (enumerated) */
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index f091042b146..689f158a469 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -59,17 +59,13 @@
#include <linux/capability.h>
#include <linux/in.h>
#include <linux/ip.h>
-#ifdef NETIF_F_TSO6
#include <linux/ipv6.h>
-#endif
#include <linux/tcp.h>
#include <linux/udp.h>
#include <net/pkt_sched.h>
#include <linux/list.h>
#include <linux/reboot.h>
-#ifdef NETIF_F_TSO
#include <net/checksum.h>
-#endif
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
@@ -257,7 +253,6 @@ struct e1000_adapter {
spinlock_t tx_queue_lock;
#endif
atomic_t irq_sem;
- unsigned int detect_link;
unsigned int total_tx_bytes;
unsigned int total_tx_packets;
unsigned int total_rx_bytes;
@@ -348,9 +343,7 @@ struct e1000_adapter {
boolean_t have_msi;
#endif
/* to not mess up cache alignment, always add to the bottom */
-#ifdef NETIF_F_TSO
boolean_t tso_force;
-#endif
boolean_t smart_power_down; /* phy smart power down */
boolean_t quad_port_a;
unsigned long flags;
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index fb96c87f9e5..44ebc72962d 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -338,7 +338,6 @@ e1000_set_tx_csum(struct net_device *netdev, uint32_t data)
return 0;
}
-#ifdef NETIF_F_TSO
static int
e1000_set_tso(struct net_device *netdev, uint32_t data)
{
@@ -352,18 +351,15 @@ e1000_set_tso(struct net_device *netdev, uint32_t data)
else
netdev->features &= ~NETIF_F_TSO;
-#ifdef NETIF_F_TSO6
if (data)
netdev->features |= NETIF_F_TSO6;
else
netdev->features &= ~NETIF_F_TSO6;
-#endif
DPRINTK(PROBE, INFO, "TSO is %s\n", data ? "Enabled" : "Disabled");
adapter->tso_force = TRUE;
return 0;
}
-#endif /* NETIF_F_TSO */
static uint32_t
e1000_get_msglevel(struct net_device *netdev)
@@ -1971,10 +1967,8 @@ static const struct ethtool_ops e1000_ethtool_ops = {
.set_tx_csum = e1000_set_tx_csum,
.get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
-#ifdef NETIF_F_TSO
.get_tso = ethtool_op_get_tso,
.set_tso = e1000_set_tso,
-#endif
.self_test_count = e1000_diag_test_count,
.self_test = e1000_diag_test,
.get_strings = e1000_get_strings,
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index c6259c7127f..619c89218b4 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.3.15-k2"DRIVERNAPI
+#define DRV_VERSION "7.3.20-k2"DRIVERNAPI
char e1000_driver_version[] = DRV_VERSION;
static char e1000_copyright[] = "Copyright (c) 1999-2006 Intel Corporation.";
@@ -990,16 +990,12 @@ e1000_probe(struct pci_dev *pdev,
netdev->features &= ~NETIF_F_HW_VLAN_FILTER;
}
-#ifdef NETIF_F_TSO
if ((adapter->hw.mac_type >= e1000_82544) &&
(adapter->hw.mac_type != e1000_82547))
netdev->features |= NETIF_F_TSO;
-#ifdef NETIF_F_TSO6
if (adapter->hw.mac_type > e1000_82547_rev_2)
netdev->features |= NETIF_F_TSO6;
-#endif
-#endif
if (pci_using_dac)
netdev->features |= NETIF_F_HIGHDMA;
@@ -2583,15 +2579,22 @@ e1000_watchdog(unsigned long data)
if (link) {
if (!netif_carrier_ok(netdev)) {
+ uint32_t ctrl;
boolean_t txb2b = 1;
e1000_get_speed_and_duplex(&adapter->hw,
&adapter->link_speed,
&adapter->link_duplex);
- DPRINTK(LINK, INFO, "NIC Link is Up %d Mbps %s\n",
- adapter->link_speed,
- adapter->link_duplex == FULL_DUPLEX ?
- "Full Duplex" : "Half Duplex");
+ ctrl = E1000_READ_REG(&adapter->hw, CTRL);
+ DPRINTK(LINK, INFO, "NIC Link is Up %d Mbps %s, "
+ "Flow Control: %s\n",
+ adapter->link_speed,
+ adapter->link_duplex == FULL_DUPLEX ?
+ "Full Duplex" : "Half Duplex",
+ ((ctrl & E1000_CTRL_TFCE) && (ctrl &
+ E1000_CTRL_RFCE)) ? "RX/TX" : ((ctrl &
+ E1000_CTRL_RFCE) ? "RX" : ((ctrl &
+ E1000_CTRL_TFCE) ? "TX" : "None" )));
/* tweak tx_queue_len according to speed/duplex
* and adjust the timeout factor */
@@ -2619,7 +2622,6 @@ e1000_watchdog(unsigned long data)
E1000_WRITE_REG(&adapter->hw, TARC0, tarc0);
}
-#ifdef NETIF_F_TSO
/* disable TSO for pcie and 10/100 speeds, to avoid
* some hardware issues */
if (!adapter->tso_force &&
@@ -2630,22 +2632,17 @@ e1000_watchdog(unsigned long data)
DPRINTK(PROBE,INFO,
"10/100 speed: disabling TSO\n");
netdev->features &= ~NETIF_F_TSO;
-#ifdef NETIF_F_TSO6
netdev->features &= ~NETIF_F_TSO6;
-#endif
break;
case SPEED_1000:
netdev->features |= NETIF_F_TSO;
-#ifdef NETIF_F_TSO6
netdev->features |= NETIF_F_TSO6;
-#endif
break;
default:
/* oops */
break;
}
}
-#endif
/* enable transmits in the hardware, need to do this
* after setting TARC0 */
@@ -2875,7 +2872,6 @@ static int
e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
struct sk_buff *skb)
{
-#ifdef NETIF_F_TSO
struct e1000_context_desc *context_desc;
struct e1000_buffer *buffer_info;
unsigned int i;
@@ -2904,7 +2900,6 @@ e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
0);
cmd_length = E1000_TXD_CMD_IP;
ipcse = skb->h.raw - skb->data - 1;
-#ifdef NETIF_F_TSO6
} else if (skb->protocol == htons(ETH_P_IPV6)) {
skb->nh.ipv6h->payload_len = 0;
skb->h.th->check =
@@ -2914,7 +2909,6 @@ e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
IPPROTO_TCP,
0);
ipcse = 0;
-#endif
}
ipcss = skb->nh.raw - skb->data;
ipcso = (void *)&(skb->nh.iph->check) - (void *)skb->data;
@@ -2947,8 +2941,6 @@ e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
return TRUE;
}
-#endif
-
return FALSE;
}
@@ -2968,8 +2960,9 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
buffer_info = &tx_ring->buffer_info[i];
context_desc = E1000_CONTEXT_DESC(*tx_ring, i);
+ context_desc->lower_setup.ip_config = 0;
context_desc->upper_setup.tcp_fields.tucss = css;
- context_desc->upper_setup.tcp_fields.tucso = css + skb->csum_offset;
+ context_desc->upper_setup.tcp_fields.tucso = css + skb->csum;
context_desc->upper_setup.tcp_fields.tucse = 0;
context_desc->tcp_seg_setup.data = 0;
context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT);
@@ -3005,7 +2998,6 @@ e1000_tx_map(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
while (len) {
buffer_info = &tx_ring->buffer_info[i];
size = min(len, max_per_txd);
-#ifdef NETIF_F_TSO
/* Workaround for Controller erratum --
* descriptor for non-tso packet in a linear SKB that follows a
* tso gets written back prematurely before the data is fully
@@ -3020,7 +3012,6 @@ e1000_tx_map(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
* in TSO mode. Append 4-byte sentinel desc */
if (unlikely(mss && !nr_frags && size == len && size > 8))
size -= 4;
-#endif
/* work-around for errata 10 and it applies
* to all controllers in PCI-X mode
* The fix is to make sure that the first descriptor of a
@@ -3062,12 +3053,10 @@ e1000_tx_map(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
while (len) {
buffer_info = &tx_ring->buffer_info[i];
size = min(len, max_per_txd);
-#ifdef NETIF_F_TSO
/* Workaround for premature desc write-backs
* in TSO mode. Append 4-byte sentinel desc */
if (unlikely(mss && f == (nr_frags-1) && size == len && size > 8))
size -= 4;
-#endif
/* Workaround for potential 82544 hang in PCI-X.
* Avoid terminating buffers within evenly-aligned
* dwords. */
@@ -3292,7 +3281,6 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
if (adapter->hw.mac_type >= e1000_82571)
max_per_txd = 8192;
-#ifdef NETIF_F_TSO
mss = skb_shinfo(skb)->gso_size;
/* The controller does a simple calculation to
* make sure there is enough room in the FIFO before
@@ -3346,16 +3334,10 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
if ((mss) || (skb->ip_summed == CHECKSUM_PARTIAL))
count++;
count++;
-#else
- if (skb->ip_summed == CHECKSUM_PARTIAL)
- count++;
-#endif
-#ifdef NETIF_F_TSO
/* Controller Erratum workaround */
if (!skb->data_len && tx_ring->last_tx_tso && !skb_is_gso(skb))
count++;
-#endif
count += TXD_USE_COUNT(len, max_txd_pwr);
@@ -3602,7 +3584,7 @@ e1000_update_stats(struct e1000_adapter *adapter)
*/
if (adapter->link_speed == 0)
return;
- if (pdev->error_state && pdev->error_state != pci_channel_io_normal)
+ if (pci_channel_offline(pdev))
return;
spin_lock_irqsave(&adapter->stats_lock, flags);
@@ -3765,8 +3747,8 @@ e1000_update_stats(struct e1000_adapter *adapter)
* @data: pointer to a network interface device structure
**/
-static
-irqreturn_t e1000_intr_msi(int irq, void *data)
+static irqreturn_t
+e1000_intr_msi(int irq, void *data)
{
struct net_device *netdev = data;
struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -3774,49 +3756,27 @@ irqreturn_t e1000_intr_msi(int irq, void *data)
#ifndef CONFIG_E1000_NAPI
int i;
#endif
+ uint32_t icr = E1000_READ_REG(hw, ICR);
- /* this code avoids the read of ICR but has to get 1000 interrupts
- * at every link change event before it will notice the change */
- if (++adapter->detect_link >= 1000) {
- uint32_t icr = E1000_READ_REG(hw, ICR);
#ifdef CONFIG_E1000_NAPI
- /* read ICR disables interrupts using IAM, so keep up with our
- * enable/disable accounting */
- atomic_inc(&adapter->irq_sem);
+ /* read ICR disables interrupts using IAM, so keep up with our
+ * enable/disable accounting */
+ atomic_inc(&adapter->irq_sem);
#endif
- adapter->detect_link = 0;
- if ((icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) &&
- (icr & E1000_ICR_INT_ASSERTED)) {
- hw->get_link_status = 1;
- /* 80003ES2LAN workaround--
- * For packet buffer work-around on link down event;
- * disable receives here in the ISR and
- * reset adapter in watchdog
- */
- if (netif_carrier_ok(netdev) &&
- (adapter->hw.mac_type == e1000_80003es2lan)) {
- /* disable receives */
- uint32_t rctl = E1000_READ_REG(hw, RCTL);
- E1000_WRITE_REG(hw, RCTL, rctl & ~E1000_RCTL_EN);
- }
- /* guard against interrupt when we're going down */
- if (!test_bit(__E1000_DOWN, &adapter->flags))
- mod_timer(&adapter->watchdog_timer,
- jiffies + 1);
+ if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
+ hw->get_link_status = 1;
+ /* 80003ES2LAN workaround-- For packet buffer work-around on
+ * link down event; disable receives here in the ISR and reset
+ * adapter in watchdog */
+ if (netif_carrier_ok(netdev) &&
+ (adapter->hw.mac_type == e1000_80003es2lan)) {
+ /* disable receives */
+ uint32_t rctl = E1000_READ_REG(hw, RCTL);
+ E1000_WRITE_REG(hw, RCTL, rctl & ~E1000_RCTL_EN);
}
- } else {
- E1000_WRITE_REG(hw, ICR, (0xffffffff & ~(E1000_ICR_RXSEQ |
- E1000_ICR_LSC)));
- /* bummer we have to flush here, but things break otherwise as
- * some event appears to be lost or delayed and throughput
- * drops. In almost all tests this flush is un-necessary */
- E1000_WRITE_FLUSH(hw);
-#ifdef CONFIG_E1000_NAPI
- /* Interrupt Auto-Mask (IAM)...upon writing ICR, interrupts are
- * masked. No need for the IMC write, but it does mean we
- * should account for it ASAP. */
- atomic_inc(&adapter->irq_sem);
-#endif
+ /* guard against interrupt when we're going down */
+ if (!test_bit(__E1000_DOWN, &adapter->flags))
+ mod_timer(&adapter->watchdog_timer, jiffies + 1);
}
#ifdef CONFIG_E1000_NAPI
@@ -3836,7 +3796,7 @@ irqreturn_t e1000_intr_msi(int irq, void *data)
for (i = 0; i < E1000_MAX_INTR; i++)
if (unlikely(!adapter->clean_rx(adapter, adapter->rx_ring) &
- !e1000_clean_tx_irq(adapter, adapter->tx_ring)))
+ e1000_clean_tx_irq(adapter, adapter->tx_ring)))
break;
if (likely(adapter->itr_setting & 3))
@@ -3939,7 +3899,7 @@ e1000_intr(int irq, void *data)
for (i = 0; i < E1000_MAX_INTR; i++)
if (unlikely(!adapter->clean_rx(adapter, adapter->rx_ring) &
- !e1000_clean_tx_irq(adapter, adapter->tx_ring)))
+ e1000_clean_tx_irq(adapter, adapter->tx_ring)))
break;
if (likely(adapter->itr_setting & 3))
@@ -3989,7 +3949,7 @@ e1000_clean(struct net_device *poll_dev, int *budget)
poll_dev->quota -= work_done;
/* If no Tx and not enough Rx work done, exit the polling mode */
- if ((!tx_cleaned && (work_done == 0)) ||
+ if ((tx_cleaned && (work_done < work_to_do)) ||
!netif_running(poll_dev)) {
quit_polling:
if (likely(adapter->itr_setting & 3))
@@ -4019,7 +3979,7 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter,
#ifdef CONFIG_E1000_NAPI
unsigned int count = 0;
#endif
- boolean_t cleaned = FALSE;
+ boolean_t cleaned = TRUE;
unsigned int total_tx_bytes=0, total_tx_packets=0;
i = tx_ring->next_to_clean;
@@ -4034,10 +3994,13 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter,
if (cleaned) {
struct sk_buff *skb = buffer_info->skb;
- unsigned int segs = skb_shinfo(skb)->gso_segs;
+ unsigned int segs, bytecount;
+ segs = skb_shinfo(skb)->gso_segs ?: 1;
+ /* multiply data chunks by size of headers */
+ bytecount = ((segs - 1) * skb_headlen(skb)) +
+ skb->len;
total_tx_packets += segs;
- total_tx_packets++;
- total_tx_bytes += skb->len;
+ total_tx_bytes += bytecount;
}
e1000_unmap_and_free_tx_resource(adapter, buffer_info);
tx_desc->upper.data = 0;
@@ -4050,7 +4013,10 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter,
#ifdef CONFIG_E1000_NAPI
#define E1000_TX_WEIGHT 64
/* weight of a sort for tx, to avoid endless transmit cleanup */
- if (count++ == E1000_TX_WEIGHT) break;
+ if (count++ == E1000_TX_WEIGHT) {
+ cleaned = FALSE;
+ break;
+ }
#endif
}
diff --git a/drivers/net/e1000/e1000_osdep.h b/drivers/net/e1000/e1000_osdep.h
index 18afc0c25da..10af742d8a2 100644
--- a/drivers/net/e1000/e1000_osdep.h
+++ b/drivers/net/e1000/e1000_osdep.h
@@ -48,8 +48,6 @@ typedef enum {
TRUE = 1
} boolean_t;
-#define MSGOUT(S, A, B) printk(KERN_DEBUG S "\n", A, B)
-
#ifdef DBG
#define DEBUGOUT(S) printk(KERN_DEBUG S "\n")
#define DEBUGOUT1(S, A...) printk(KERN_DEBUG S "\n", A)
@@ -58,7 +56,7 @@ typedef enum {
#define DEBUGOUT1(S, A...)
#endif
-#define DEBUGFUNC(F) DEBUGOUT(F)
+#define DEBUGFUNC(F) DEBUGOUT(F "\n")
#define DEBUGOUT2 DEBUGOUT1
#define DEBUGOUT3 DEBUGOUT2
#define DEBUGOUT7 DEBUGOUT3
diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c
index cf2a279307e..f8862e203ac 100644
--- a/drivers/net/e1000/e1000_param.c
+++ b/drivers/net/e1000/e1000_param.c
@@ -760,22 +760,13 @@ e1000_check_copper_options(struct e1000_adapter *adapter)
case SPEED_1000:
DPRINTK(PROBE, INFO, "1000 Mbps Speed specified without "
"Duplex\n");
- DPRINTK(PROBE, INFO,
- "Using Autonegotiation at 1000 Mbps "
- "Full Duplex only\n");
- adapter->hw.autoneg = adapter->fc_autoneg = 1;
- adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
- break;
+ goto full_duplex_only;
case SPEED_1000 + HALF_DUPLEX:
DPRINTK(PROBE, INFO,
"Half Duplex is not supported at 1000 Mbps\n");
- DPRINTK(PROBE, INFO,
- "Using Autonegotiation at 1000 Mbps "
- "Full Duplex only\n");
- adapter->hw.autoneg = adapter->fc_autoneg = 1;
- adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
- break;
+ /* fall through */
case SPEED_1000 + FULL_DUPLEX:
+full_duplex_only:
DPRINTK(PROBE, INFO,
"Using Autonegotiation at 1000 Mbps Full Duplex only\n");
adapter->hw.autoneg = adapter->fc_autoneg = 1;
diff --git a/drivers/net/e2100.c b/drivers/net/e2100.c
index c62d9c6363c..b2b0a96218c 100644
--- a/drivers/net/e2100.c
+++ b/drivers/net/e2100.c
@@ -355,8 +355,7 @@ e21_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring
mem_on(ioaddr, shared_mem, (ring_offset>>8));
- /* Packet is always in one chunk -- we can copy + cksum. */
- eth_io_copy_and_sum(skb, ei_status.mem + (ring_offset & 0xff), count, 0);
+ memcpy_fromio(skb->data, ei_status.mem + (ring_offset & 0xff), count);
mem_off(ioaddr);
}
diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h
index 272e1ec51aa..42295d61ecd 100644
--- a/drivers/net/ehea/ehea.h
+++ b/drivers/net/ehea/ehea.h
@@ -39,7 +39,7 @@
#include <asm/io.h>
#define DRV_NAME "ehea"
-#define DRV_VERSION "EHEA_0045"
+#define DRV_VERSION "EHEA_0046"
#define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \
| NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index 9de2d38a532..1ef3846a5ea 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -76,7 +76,7 @@ void ehea_dump(void *adr, int len, char *msg) {
int x;
unsigned char *deb = adr;
for (x = 0; x < len; x += 16) {
- printk(DRV_NAME "%s adr=%p ofs=%04x %016lx %016lx\n", msg,
+ printk(DRV_NAME " %s adr=%p ofs=%04x %016lx %016lx\n", msg,
deb, x, *((u64*)&deb[0]), *((u64*)&deb[8]));
deb += 16;
}
@@ -555,6 +555,7 @@ static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param)
{
struct ehea_port *port = param;
struct ehea_eqe *eqe;
+ struct ehea_qp *qp;
u32 qp_token;
eqe = ehea_poll_eq(port->qp_eq);
@@ -563,9 +564,14 @@ static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param)
qp_token = EHEA_BMASK_GET(EHEA_EQE_QP_TOKEN, eqe->entry);
ehea_error("QP aff_err: entry=0x%lx, token=0x%x",
eqe->entry, qp_token);
+
+ qp = port->port_res[qp_token].qp;
+ ehea_error_data(port->adapter, qp->fw_handle);
eqe = ehea_poll_eq(port->qp_eq);
}
+ queue_work(port->adapter->ehea_wq, &port->reset_task);
+
return IRQ_HANDLED;
}
diff --git a/drivers/net/ehea/ehea_phyp.c b/drivers/net/ehea/ehea_phyp.c
index 37716e05e80..bc3c0054726 100644
--- a/drivers/net/ehea/ehea_phyp.c
+++ b/drivers/net/ehea/ehea_phyp.c
@@ -612,3 +612,13 @@ u64 ehea_h_reset_events(const u64 adapter_handle, const u64 neq_handle,
event_mask, /* R6 */
0, 0, 0, 0); /* R7-R12 */
}
+
+u64 ehea_h_error_data(const u64 adapter_handle, const u64 ressource_handle,
+ void *rblock)
+{
+ return ehea_plpar_hcall_norets(H_ERROR_DATA,
+ adapter_handle, /* R4 */
+ ressource_handle, /* R5 */
+ virt_to_abs(rblock), /* R6 */
+ 0, 0, 0, 0); /* R7-R12 */
+}
diff --git a/drivers/net/ehea/ehea_phyp.h b/drivers/net/ehea/ehea_phyp.h
index 919f94b7593..90acddb068a 100644
--- a/drivers/net/ehea/ehea_phyp.h
+++ b/drivers/net/ehea/ehea_phyp.h
@@ -454,4 +454,7 @@ u64 ehea_h_reg_dereg_bcmc(const u64 adapter_handle, const u16 port_num,
u64 ehea_h_reset_events(const u64 adapter_handle, const u64 neq_handle,
const u64 event_mask);
+u64 ehea_h_error_data(const u64 adapter_handle, const u64 ressource_handle,
+ void *rblock);
+
#endif /* __EHEA_PHYP_H__ */
diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c
index f143e13b229..96ff3b67999 100644
--- a/drivers/net/ehea/ehea_qmr.c
+++ b/drivers/net/ehea/ehea_qmr.c
@@ -486,6 +486,7 @@ int ehea_destroy_qp(struct ehea_qp *qp)
if (!qp)
return 0;
+ ehea_h_disable_and_get_hea(qp->adapter->handle, qp->fw_handle);
hret = ehea_h_free_resource(qp->adapter->handle, qp->fw_handle);
if (hret != H_SUCCESS) {
ehea_error("destroy_qp failed");
@@ -581,4 +582,45 @@ out:
return ret;
}
+void print_error_data(u64 *data)
+{
+ int length;
+ u64 type = EHEA_BMASK_GET(ERROR_DATA_TYPE, data[2]);
+ u64 resource = data[1];
+
+ length = EHEA_BMASK_GET(ERROR_DATA_LENGTH, data[0]);
+
+ if (length > EHEA_PAGESIZE)
+ length = EHEA_PAGESIZE;
+
+ if (type == 0x8) /* Queue Pair */
+ ehea_error("QP (resource=%lX) state: AER=0x%lX, AERR=0x%lX, "
+ "port=%lX", resource, data[6], data[12], data[22]);
+
+ ehea_dump(data, length, "error data");
+}
+
+void ehea_error_data(struct ehea_adapter *adapter, u64 res_handle)
+{
+ unsigned long ret;
+ u64 *rblock;
+
+ rblock = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!rblock) {
+ ehea_error("Cannot allocate rblock memory.");
+ return;
+ }
+ ret = ehea_h_error_data(adapter->handle,
+ res_handle,
+ rblock);
+
+ if (ret == H_R_STATE)
+ ehea_error("No error data is available: %lX.", res_handle);
+ else if (ret == H_SUCCESS)
+ print_error_data(rblock);
+ else
+ ehea_error("Error data could not be fetched: %lX", res_handle);
+
+ kfree(rblock);
+}
diff --git a/drivers/net/ehea/ehea_qmr.h b/drivers/net/ehea/ehea_qmr.h
index 7efdc96919c..1ff60983504 100644
--- a/drivers/net/ehea/ehea_qmr.h
+++ b/drivers/net/ehea/ehea_qmr.h
@@ -180,6 +180,9 @@ struct ehea_eqe {
u64 entry;
};
+#define ERROR_DATA_LENGTH EHEA_BMASK_IBM(52,63)
+#define ERROR_DATA_TYPE EHEA_BMASK_IBM(0,7)
+
static inline void *hw_qeit_calc(struct hw_queue *queue, u64 q_offset)
{
struct ehea_page *current_page;
@@ -355,4 +358,6 @@ int ehea_destroy_qp(struct ehea_qp *qp);
int ehea_reg_mr_adapter(struct ehea_adapter *adapter);
+void ehea_error_data(struct ehea_adapter *adapter, u64 res_handle);
+
#endif /* __EHEA_QMR_H__ */
diff --git a/drivers/net/es3210.c b/drivers/net/es3210.c
index 2d2ea94a00b..822e5bfd1a7 100644
--- a/drivers/net/es3210.c
+++ b/drivers/net/es3210.c
@@ -375,7 +375,7 @@ static void es_block_input(struct net_device *dev, int count, struct sk_buff *sk
memcpy_fromio(skb->data + semi_count, ei_status.mem, count);
} else {
/* Packet is in one chunk. */
- eth_io_copy_and_sum(skb, xfer_start, count, 0);
+ memcpy_fromio(skb->data, xfer_start, count);
}
}
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 93f2b7a2216..a363148d019 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -111,6 +111,7 @@
* 0.57: 14 May 2006: Mac address set in probe/remove and order corrections.
* 0.58: 30 Oct 2006: Added support for sideband management unit.
* 0.59: 30 Oct 2006: Added support for recoverable error.
+ * 0.60: 20 Jan 2007: Code optimizations for rings, rx & tx data paths, and stats.
*
* Known bugs:
* We suspect that on some hardware no TX done interrupts are generated.
@@ -127,7 +128,7 @@
#else
#define DRIVERNAPI
#endif
-#define FORCEDETH_VERSION "0.59"
+#define FORCEDETH_VERSION "0.60"
#define DRV_NAME "forcedeth"
#include <linux/module.h>
@@ -173,9 +174,10 @@
#define DEV_HAS_MSI_X 0x0080 /* device supports MSI-X */
#define DEV_HAS_POWER_CNTRL 0x0100 /* device supports power savings */
#define DEV_HAS_PAUSEFRAME_TX 0x0200 /* device supports tx pause frames */
-#define DEV_HAS_STATISTICS 0x0400 /* device supports hw statistics */
-#define DEV_HAS_TEST_EXTENDED 0x0800 /* device supports extended diagnostic test */
-#define DEV_HAS_MGMT_UNIT 0x1000 /* device supports management unit */
+#define DEV_HAS_STATISTICS_V1 0x0400 /* device supports hw statistics version 1 */
+#define DEV_HAS_STATISTICS_V2 0x0800 /* device supports hw statistics version 2 */
+#define DEV_HAS_TEST_EXTENDED 0x1000 /* device supports extended diagnostic test */
+#define DEV_HAS_MGMT_UNIT 0x2000 /* device supports management unit */
enum {
NvRegIrqStatus = 0x000,
@@ -210,7 +212,7 @@ enum {
* NVREG_POLL_DEFAULT=97 would result in an interval length of 1 ms
*/
NvRegPollingInterval = 0x00c,
-#define NVREG_POLL_DEFAULT_THROUGHPUT 970
+#define NVREG_POLL_DEFAULT_THROUGHPUT 970 /* backup tx cleanup if loop max reached */
#define NVREG_POLL_DEFAULT_CPU 13
NvRegMSIMap0 = 0x020,
NvRegMSIMap1 = 0x024,
@@ -304,8 +306,8 @@ enum {
#define NVREG_TXRXCTL_RESET 0x0010
#define NVREG_TXRXCTL_RXCHECK 0x0400
#define NVREG_TXRXCTL_DESC_1 0
-#define NVREG_TXRXCTL_DESC_2 0x02100
-#define NVREG_TXRXCTL_DESC_3 0x02200
+#define NVREG_TXRXCTL_DESC_2 0x002100
+#define NVREG_TXRXCTL_DESC_3 0xc02200
#define NVREG_TXRXCTL_VLANSTRIP 0x00040
#define NVREG_TXRXCTL_VLANINS 0x00080
NvRegTxRingPhysAddrHigh = 0x148,
@@ -487,7 +489,8 @@ union ring_type {
/* Miscelaneous hardware related defines: */
#define NV_PCI_REGSZ_VER1 0x270
-#define NV_PCI_REGSZ_VER2 0x604
+#define NV_PCI_REGSZ_VER2 0x2d4
+#define NV_PCI_REGSZ_VER3 0x604
/* various timeout delays: all in usec */
#define NV_TXRX_RESET_DELAY 4
@@ -518,12 +521,6 @@ union ring_type {
#define TX_RING_MIN 64
#define RING_MAX_DESC_VER_1 1024
#define RING_MAX_DESC_VER_2_3 16384
-/*
- * Difference between the get and put pointers for the tx ring.
- * This is used to throttle the amount of data outstanding in the
- * tx ring.
- */
-#define TX_LIMIT_DIFFERENCE 1
/* rx/tx mac addr + type + vlan + align + slack*/
#define NV_RX_HEADERS (64)
@@ -611,9 +608,6 @@ static const struct nv_ethtool_str nv_estats_str[] = {
{ "tx_carrier_errors" },
{ "tx_excess_deferral" },
{ "tx_retry_error" },
- { "tx_deferral" },
- { "tx_packets" },
- { "tx_pause" },
{ "rx_frame_error" },
{ "rx_extra_byte" },
{ "rx_late_collision" },
@@ -626,11 +620,17 @@ static const struct nv_ethtool_str nv_estats_str[] = {
{ "rx_unicast" },
{ "rx_multicast" },
{ "rx_broadcast" },
+ { "rx_packets" },
+ { "rx_errors_total" },
+ { "tx_errors_total" },
+
+ /* version 2 stats */
+ { "tx_deferral" },
+ { "tx_packets" },
{ "rx_bytes" },
+ { "tx_pause" },
{ "rx_pause" },
- { "rx_drop_frame" },
- { "rx_packets" },
- { "rx_errors_total" }
+ { "rx_drop_frame" }
};
struct nv_ethtool_stats {
@@ -643,9 +643,6 @@ struct nv_ethtool_stats {
u64 tx_carrier_errors;
u64 tx_excess_deferral;
u64 tx_retry_error;
- u64 tx_deferral;
- u64 tx_packets;
- u64 tx_pause;
u64 rx_frame_error;
u64 rx_extra_byte;
u64 rx_late_collision;
@@ -658,13 +655,22 @@ struct nv_ethtool_stats {
u64 rx_unicast;
u64 rx_multicast;
u64 rx_broadcast;
+ u64 rx_packets;
+ u64 rx_errors_total;
+ u64 tx_errors_total;
+
+ /* version 2 stats */
+ u64 tx_deferral;
+ u64 tx_packets;
u64 rx_bytes;
+ u64 tx_pause;
u64 rx_pause;
u64 rx_drop_frame;
- u64 rx_packets;
- u64 rx_errors_total;
};
+#define NV_DEV_STATISTICS_V2_COUNT (sizeof(struct nv_ethtool_stats)/sizeof(u64))
+#define NV_DEV_STATISTICS_V1_COUNT (NV_DEV_STATISTICS_V2_COUNT - 6)
+
/* diagnostics */
#define NV_TEST_COUNT_BASE 3
#define NV_TEST_COUNT_EXTENDED 4
@@ -691,6 +697,12 @@ static const struct register_test nv_registers_test[] = {
{ 0,0 }
};
+struct nv_skb_map {
+ struct sk_buff *skb;
+ dma_addr_t dma;
+ unsigned int dma_len;
+};
+
/*
* SMP locking:
* All hardware access under dev->priv->lock, except the performance
@@ -741,10 +753,12 @@ struct fe_priv {
/* rx specific fields.
* Locking: Within irq hander or disable_irq+spin_lock(&np->lock);
*/
+ union ring_type get_rx, put_rx, first_rx, last_rx;
+ struct nv_skb_map *get_rx_ctx, *put_rx_ctx;
+ struct nv_skb_map *first_rx_ctx, *last_rx_ctx;
+ struct nv_skb_map *rx_skb;
+
union ring_type rx_ring;
- unsigned int cur_rx, refill_rx;
- struct sk_buff **rx_skbuff;
- dma_addr_t *rx_dma;
unsigned int rx_buf_sz;
unsigned int pkt_limit;
struct timer_list oom_kick;
@@ -761,15 +775,15 @@ struct fe_priv {
/*
* tx specific fields.
*/
+ union ring_type get_tx, put_tx, first_tx, last_tx;
+ struct nv_skb_map *get_tx_ctx, *put_tx_ctx;
+ struct nv_skb_map *first_tx_ctx, *last_tx_ctx;
+ struct nv_skb_map *tx_skb;
+
union ring_type tx_ring;
- unsigned int next_tx, nic_tx;
- struct sk_buff **tx_skbuff;
- dma_addr_t *tx_dma;
- unsigned int *tx_dma_len;
u32 tx_flags;
int tx_ring_size;
- int tx_limit_start;
- int tx_limit_stop;
+ int tx_stop;
/* vlan fields */
struct vlan_group *vlangrp;
@@ -921,16 +935,10 @@ static void free_rings(struct net_device *dev)
pci_free_consistent(np->pci_dev, sizeof(struct ring_desc_ex) * (np->rx_ring_size + np->tx_ring_size),
np->rx_ring.ex, np->ring_addr);
}
- if (np->rx_skbuff)
- kfree(np->rx_skbuff);
- if (np->rx_dma)
- kfree(np->rx_dma);
- if (np->tx_skbuff)
- kfree(np->tx_skbuff);
- if (np->tx_dma)
- kfree(np->tx_dma);
- if (np->tx_dma_len)
- kfree(np->tx_dma_len);
+ if (np->rx_skb)
+ kfree(np->rx_skb);
+ if (np->tx_skb)
+ kfree(np->tx_skb);
}
static int using_multi_irqs(struct net_device *dev)
@@ -1279,6 +1287,61 @@ static void nv_mac_reset(struct net_device *dev)
pci_push(base);
}
+static void nv_get_hw_stats(struct net_device *dev)
+{
+ struct fe_priv *np = netdev_priv(dev);
+ u8 __iomem *base = get_hwbase(dev);
+
+ np->estats.tx_bytes += readl(base + NvRegTxCnt);
+ np->estats.tx_zero_rexmt += readl(base + NvRegTxZeroReXmt);
+ np->estats.tx_one_rexmt += readl(base + NvRegTxOneReXmt);
+ np->estats.tx_many_rexmt += readl(base + NvRegTxManyReXmt);
+ np->estats.tx_late_collision += readl(base + NvRegTxLateCol);
+ np->estats.tx_fifo_errors += readl(base + NvRegTxUnderflow);
+ np->estats.tx_carrier_errors += readl(base + NvRegTxLossCarrier);
+ np->estats.tx_excess_deferral += readl(base + NvRegTxExcessDef);
+ np->estats.tx_retry_error += readl(base + NvRegTxRetryErr);
+ np->estats.rx_frame_error += readl(base + NvRegRxFrameErr);
+ np->estats.rx_extra_byte += readl(base + NvRegRxExtraByte);
+ np->estats.rx_late_collision += readl(base + NvRegRxLateCol);
+ np->estats.rx_runt += readl(base + NvRegRxRunt);
+ np->estats.rx_frame_too_long += readl(base + NvRegRxFrameTooLong);
+ np->estats.rx_over_errors += readl(base + NvRegRxOverflow);
+ np->estats.rx_crc_errors += readl(base + NvRegRxFCSErr);
+ np->estats.rx_frame_align_error += readl(base + NvRegRxFrameAlignErr);
+ np->estats.rx_length_error += readl(base + NvRegRxLenErr);
+ np->estats.rx_unicast += readl(base + NvRegRxUnicast);
+ np->estats.rx_multicast += readl(base + NvRegRxMulticast);
+ np->estats.rx_broadcast += readl(base + NvRegRxBroadcast);
+ np->estats.rx_packets =
+ np->estats.rx_unicast +
+ np->estats.rx_multicast +
+ np->estats.rx_broadcast;
+ np->estats.rx_errors_total =
+ np->estats.rx_crc_errors +
+ np->estats.rx_over_errors +
+ np->estats.rx_frame_error +
+ (np->estats.rx_frame_align_error - np->estats.rx_extra_byte) +
+ np->estats.rx_late_collision +
+ np->estats.rx_runt +
+ np->estats.rx_frame_too_long;
+ np->estats.tx_errors_total =
+ np->estats.tx_late_collision +
+ np->estats.tx_fifo_errors +
+ np->estats.tx_carrier_errors +
+ np->estats.tx_excess_deferral +
+ np->estats.tx_retry_error;
+
+ if (np->driver_data & DEV_HAS_STATISTICS_V2) {
+ np->estats.tx_deferral += readl(base + NvRegTxDef);
+ np->estats.tx_packets += readl(base + NvRegTxFrame);
+ np->estats.rx_bytes += readl(base + NvRegRxCnt);
+ np->estats.tx_pause += readl(base + NvRegTxPause);
+ np->estats.rx_pause += readl(base + NvRegRxPause);
+ np->estats.rx_drop_frame += readl(base + NvRegRxDropFrame);
+ }
+}
+
/*
* nv_get_stats: dev->get_stats function
* Get latest stats value from the nic.
@@ -1289,10 +1352,19 @@ static struct net_device_stats *nv_get_stats(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
- /* It seems that the nic always generates interrupts and doesn't
- * accumulate errors internally. Thus the current values in np->stats
- * are already up to date.
- */
+ /* If the nic supports hw counters then retrieve latest values */
+ if (np->driver_data & (DEV_HAS_STATISTICS_V1|DEV_HAS_STATISTICS_V2)) {
+ nv_get_hw_stats(dev);
+
+ /* copy to net_device stats */
+ np->stats.tx_bytes = np->estats.tx_bytes;
+ np->stats.tx_fifo_errors = np->estats.tx_fifo_errors;
+ np->stats.tx_carrier_errors = np->estats.tx_carrier_errors;
+ np->stats.rx_crc_errors = np->estats.rx_crc_errors;
+ np->stats.rx_over_errors = np->estats.rx_over_errors;
+ np->stats.rx_errors = np->estats.rx_errors_total;
+ np->stats.tx_errors = np->estats.tx_errors_total;
+ }
return &np->stats;
}
@@ -1304,43 +1376,63 @@ static struct net_device_stats *nv_get_stats(struct net_device *dev)
static int nv_alloc_rx(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
- unsigned int refill_rx = np->refill_rx;
- int nr;
+ struct ring_desc* less_rx;
- while (np->cur_rx != refill_rx) {
- struct sk_buff *skb;
-
- nr = refill_rx % np->rx_ring_size;
- if (np->rx_skbuff[nr] == NULL) {
-
- skb = dev_alloc_skb(np->rx_buf_sz + NV_RX_ALLOC_PAD);
- if (!skb)
- break;
+ less_rx = np->get_rx.orig;
+ if (less_rx-- == np->first_rx.orig)
+ less_rx = np->last_rx.orig;
+ while (np->put_rx.orig != less_rx) {
+ struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz + NV_RX_ALLOC_PAD);
+ if (skb) {
skb->dev = dev;
- np->rx_skbuff[nr] = skb;
+ np->put_rx_ctx->skb = skb;
+ np->put_rx_ctx->dma = pci_map_single(np->pci_dev, skb->data,
+ skb->end-skb->data, PCI_DMA_FROMDEVICE);
+ np->put_rx_ctx->dma_len = skb->end-skb->data;
+ np->put_rx.orig->buf = cpu_to_le32(np->put_rx_ctx->dma);
+ wmb();
+ np->put_rx.orig->flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX_AVAIL);
+ if (unlikely(np->put_rx.orig++ == np->last_rx.orig))
+ np->put_rx.orig = np->first_rx.orig;
+ if (unlikely(np->put_rx_ctx++ == np->last_rx_ctx))
+ np->put_rx_ctx = np->first_rx_ctx;
} else {
- skb = np->rx_skbuff[nr];
+ return 1;
}
- np->rx_dma[nr] = pci_map_single(np->pci_dev, skb->data,
- skb->end-skb->data, PCI_DMA_FROMDEVICE);
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- np->rx_ring.orig[nr].buf = cpu_to_le32(np->rx_dma[nr]);
+ }
+ return 0;
+}
+
+static int nv_alloc_rx_optimized(struct net_device *dev)
+{
+ struct fe_priv *np = netdev_priv(dev);
+ struct ring_desc_ex* less_rx;
+
+ less_rx = np->get_rx.ex;
+ if (less_rx-- == np->first_rx.ex)
+ less_rx = np->last_rx.ex;
+
+ while (np->put_rx.ex != less_rx) {
+ struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz + NV_RX_ALLOC_PAD);
+ if (skb) {
+ skb->dev = dev;
+ np->put_rx_ctx->skb = skb;
+ np->put_rx_ctx->dma = pci_map_single(np->pci_dev, skb->data,
+ skb->end-skb->data, PCI_DMA_FROMDEVICE);
+ np->put_rx_ctx->dma_len = skb->end-skb->data;
+ np->put_rx.ex->bufhigh = cpu_to_le64(np->put_rx_ctx->dma) >> 32;
+ np->put_rx.ex->buflow = cpu_to_le64(np->put_rx_ctx->dma) & 0x0FFFFFFFF;
wmb();
- np->rx_ring.orig[nr].flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX_AVAIL);
+ np->put_rx.ex->flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX2_AVAIL);
+ if (unlikely(np->put_rx.ex++ == np->last_rx.ex))
+ np->put_rx.ex = np->first_rx.ex;
+ if (unlikely(np->put_rx_ctx++ == np->last_rx_ctx))
+ np->put_rx_ctx = np->first_rx_ctx;
} else {
- np->rx_ring.ex[nr].bufhigh = cpu_to_le64(np->rx_dma[nr]) >> 32;
- np->rx_ring.ex[nr].buflow = cpu_to_le64(np->rx_dma[nr]) & 0x0FFFFFFFF;
- wmb();
- np->rx_ring.ex[nr].flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX2_AVAIL);
+ return 1;
}
- dprintk(KERN_DEBUG "%s: nv_alloc_rx: Packet %d marked as Available\n",
- dev->name, refill_rx);
- refill_rx++;
}
- np->refill_rx = refill_rx;
- if (np->cur_rx - refill_rx == np->rx_ring_size)
- return 1;
return 0;
}
@@ -1358,6 +1450,7 @@ static void nv_do_rx_refill(unsigned long data)
{
struct net_device *dev = (struct net_device *) data;
struct fe_priv *np = netdev_priv(dev);
+ int retcode;
if (!using_multi_irqs(dev)) {
if (np->msi_flags & NV_MSI_X_ENABLED)
@@ -1367,7 +1460,11 @@ static void nv_do_rx_refill(unsigned long data)
} else {
disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
}
- if (nv_alloc_rx(dev)) {
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ retcode = nv_alloc_rx(dev);
+ else
+ retcode = nv_alloc_rx_optimized(dev);
+ if (retcode) {
spin_lock_irq(&np->lock);
if (!np->in_shutdown)
mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
@@ -1388,56 +1485,81 @@ static void nv_init_rx(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
int i;
+ np->get_rx = np->put_rx = np->first_rx = np->rx_ring;
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ np->last_rx.orig = &np->rx_ring.orig[np->rx_ring_size-1];
+ else
+ np->last_rx.ex = &np->rx_ring.ex[np->rx_ring_size-1];
+ np->get_rx_ctx = np->put_rx_ctx = np->first_rx_ctx = np->rx_skb;
+ np->last_rx_ctx = &np->rx_skb[np->rx_ring_size-1];
- np->cur_rx = np->rx_ring_size;
- np->refill_rx = 0;
- for (i = 0; i < np->rx_ring_size; i++)
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ for (i = 0; i < np->rx_ring_size; i++) {
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
np->rx_ring.orig[i].flaglen = 0;
- else
+ np->rx_ring.orig[i].buf = 0;
+ } else {
np->rx_ring.ex[i].flaglen = 0;
+ np->rx_ring.ex[i].txvlan = 0;
+ np->rx_ring.ex[i].bufhigh = 0;
+ np->rx_ring.ex[i].buflow = 0;
+ }
+ np->rx_skb[i].skb = NULL;
+ np->rx_skb[i].dma = 0;
+ }
}
static void nv_init_tx(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
int i;
+ np->get_tx = np->put_tx = np->first_tx = np->tx_ring;
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ np->last_tx.orig = &np->tx_ring.orig[np->tx_ring_size-1];
+ else
+ np->last_tx.ex = &np->tx_ring.ex[np->tx_ring_size-1];
+ np->get_tx_ctx = np->put_tx_ctx = np->first_tx_ctx = np->tx_skb;
+ np->last_tx_ctx = &np->tx_skb[np->tx_ring_size-1];
- np->next_tx = np->nic_tx = 0;
for (i = 0; i < np->tx_ring_size; i++) {
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
np->tx_ring.orig[i].flaglen = 0;
- else
+ np->tx_ring.orig[i].buf = 0;
+ } else {
np->tx_ring.ex[i].flaglen = 0;
- np->tx_skbuff[i] = NULL;
- np->tx_dma[i] = 0;
+ np->tx_ring.ex[i].txvlan = 0;
+ np->tx_ring.ex[i].bufhigh = 0;
+ np->tx_ring.ex[i].buflow = 0;
+ }
+ np->tx_skb[i].skb = NULL;
+ np->tx_skb[i].dma = 0;
}
}
static int nv_init_ring(struct net_device *dev)
{
+ struct fe_priv *np = netdev_priv(dev);
+
nv_init_tx(dev);
nv_init_rx(dev);
- return nv_alloc_rx(dev);
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ return nv_alloc_rx(dev);
+ else
+ return nv_alloc_rx_optimized(dev);
}
-static int nv_release_txskb(struct net_device *dev, unsigned int skbnr)
+static int nv_release_txskb(struct net_device *dev, struct nv_skb_map* tx_skb)
{
struct fe_priv *np = netdev_priv(dev);
- dprintk(KERN_INFO "%s: nv_release_txskb for skbnr %d\n",
- dev->name, skbnr);
-
- if (np->tx_dma[skbnr]) {
- pci_unmap_page(np->pci_dev, np->tx_dma[skbnr],
- np->tx_dma_len[skbnr],
+ if (tx_skb->dma) {
+ pci_unmap_page(np->pci_dev, tx_skb->dma,
+ tx_skb->dma_len,
PCI_DMA_TODEVICE);
- np->tx_dma[skbnr] = 0;
+ tx_skb->dma = 0;
}
-
- if (np->tx_skbuff[skbnr]) {
- dev_kfree_skb_any(np->tx_skbuff[skbnr]);
- np->tx_skbuff[skbnr] = NULL;
+ if (tx_skb->skb) {
+ dev_kfree_skb_any(tx_skb->skb);
+ tx_skb->skb = NULL;
return 1;
} else {
return 0;
@@ -1450,11 +1572,16 @@ static void nv_drain_tx(struct net_device *dev)
unsigned int i;
for (i = 0; i < np->tx_ring_size; i++) {
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
np->tx_ring.orig[i].flaglen = 0;
- else
+ np->tx_ring.orig[i].buf = 0;
+ } else {
np->tx_ring.ex[i].flaglen = 0;
- if (nv_release_txskb(dev, i))
+ np->tx_ring.ex[i].txvlan = 0;
+ np->tx_ring.ex[i].bufhigh = 0;
+ np->tx_ring.ex[i].buflow = 0;
+ }
+ if (nv_release_txskb(dev, &np->tx_skb[i]))
np->stats.tx_dropped++;
}
}
@@ -1463,18 +1590,24 @@ static void nv_drain_rx(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
int i;
+
for (i = 0; i < np->rx_ring_size; i++) {
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
np->rx_ring.orig[i].flaglen = 0;
- else
+ np->rx_ring.orig[i].buf = 0;
+ } else {
np->rx_ring.ex[i].flaglen = 0;
+ np->rx_ring.ex[i].txvlan = 0;
+ np->rx_ring.ex[i].bufhigh = 0;
+ np->rx_ring.ex[i].buflow = 0;
+ }
wmb();
- if (np->rx_skbuff[i]) {
- pci_unmap_single(np->pci_dev, np->rx_dma[i],
- np->rx_skbuff[i]->end-np->rx_skbuff[i]->data,
+ if (np->rx_skb[i].skb) {
+ pci_unmap_single(np->pci_dev, np->rx_skb[i].dma,
+ np->rx_skb[i].skb->end-np->rx_skb[i].skb->data,
PCI_DMA_FROMDEVICE);
- dev_kfree_skb(np->rx_skbuff[i]);
- np->rx_skbuff[i] = NULL;
+ dev_kfree_skb(np->rx_skb[i].skb);
+ np->rx_skb[i].skb = NULL;
}
}
}
@@ -1485,6 +1618,11 @@ static void drain_ring(struct net_device *dev)
nv_drain_rx(dev);
}
+static inline u32 nv_get_empty_tx_slots(struct fe_priv *np)
+{
+ return (u32)(np->tx_ring_size - ((np->tx_ring_size + (np->put_tx_ctx - np->get_tx_ctx)) % np->tx_ring_size));
+}
+
/*
* nv_start_xmit: dev->hard_start_xmit function
* Called with netif_tx_lock held.
@@ -1495,14 +1633,16 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
u32 tx_flags = 0;
u32 tx_flags_extra = (np->desc_ver == DESC_VER_1 ? NV_TX_LASTPACKET : NV_TX2_LASTPACKET);
unsigned int fragments = skb_shinfo(skb)->nr_frags;
- unsigned int nr = (np->next_tx - 1) % np->tx_ring_size;
- unsigned int start_nr = np->next_tx % np->tx_ring_size;
unsigned int i;
u32 offset = 0;
u32 bcnt;
u32 size = skb->len-skb->data_len;
u32 entries = (size >> NV_TX2_TSO_MAX_SHIFT) + ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
- u32 tx_flags_vlan = 0;
+ u32 empty_slots;
+ struct ring_desc* put_tx;
+ struct ring_desc* start_tx;
+ struct ring_desc* prev_tx;
+ struct nv_skb_map* prev_tx_ctx;
/* add fragments to entries count */
for (i = 0; i < fragments; i++) {
@@ -1510,34 +1650,35 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
((skb_shinfo(skb)->frags[i].size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
}
- spin_lock_irq(&np->lock);
-
- if ((np->next_tx - np->nic_tx + entries - 1) > np->tx_limit_stop) {
- spin_unlock_irq(&np->lock);
+ empty_slots = nv_get_empty_tx_slots(np);
+ if (unlikely(empty_slots <= entries)) {
+ spin_lock_irq(&np->lock);
netif_stop_queue(dev);
+ np->tx_stop = 1;
+ spin_unlock_irq(&np->lock);
return NETDEV_TX_BUSY;
}
+ start_tx = put_tx = np->put_tx.orig;
+
/* setup the header buffer */
do {
+ prev_tx = put_tx;
+ prev_tx_ctx = np->put_tx_ctx;
bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size;
- nr = (nr + 1) % np->tx_ring_size;
-
- np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data + offset, bcnt,
+ np->put_tx_ctx->dma = pci_map_single(np->pci_dev, skb->data + offset, bcnt,
PCI_DMA_TODEVICE);
- np->tx_dma_len[nr] = bcnt;
+ np->put_tx_ctx->dma_len = bcnt;
+ put_tx->buf = cpu_to_le32(np->put_tx_ctx->dma);
+ put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags);
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- np->tx_ring.orig[nr].buf = cpu_to_le32(np->tx_dma[nr]);
- np->tx_ring.orig[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
- } else {
- np->tx_ring.ex[nr].bufhigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
- np->tx_ring.ex[nr].buflow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
- np->tx_ring.ex[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
- }
tx_flags = np->tx_flags;
offset += bcnt;
size -= bcnt;
+ if (unlikely(put_tx++ == np->last_tx.orig))
+ put_tx = np->first_tx.orig;
+ if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx))
+ np->put_tx_ctx = np->first_tx_ctx;
} while (size);
/* setup the fragments */
@@ -1547,58 +1688,174 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
offset = 0;
do {
+ prev_tx = put_tx;
+ prev_tx_ctx = np->put_tx_ctx;
bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size;
- nr = (nr + 1) % np->tx_ring_size;
-
- np->tx_dma[nr] = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt,
- PCI_DMA_TODEVICE);
- np->tx_dma_len[nr] = bcnt;
+ np->put_tx_ctx->dma = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt,
+ PCI_DMA_TODEVICE);
+ np->put_tx_ctx->dma_len = bcnt;
+ put_tx->buf = cpu_to_le32(np->put_tx_ctx->dma);
+ put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags);
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- np->tx_ring.orig[nr].buf = cpu_to_le32(np->tx_dma[nr]);
- np->tx_ring.orig[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
- } else {
- np->tx_ring.ex[nr].bufhigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
- np->tx_ring.ex[nr].buflow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
- np->tx_ring.ex[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
- }
offset += bcnt;
size -= bcnt;
+ if (unlikely(put_tx++ == np->last_tx.orig))
+ put_tx = np->first_tx.orig;
+ if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx))
+ np->put_tx_ctx = np->first_tx_ctx;
} while (size);
}
/* set last fragment flag */
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- np->tx_ring.orig[nr].flaglen |= cpu_to_le32(tx_flags_extra);
- } else {
- np->tx_ring.ex[nr].flaglen |= cpu_to_le32(tx_flags_extra);
+ prev_tx->flaglen |= cpu_to_le32(tx_flags_extra);
+
+ /* save skb in this slot's context area */
+ prev_tx_ctx->skb = skb;
+
+ if (skb_is_gso(skb))
+ tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->gso_size << NV_TX2_TSO_SHIFT);
+ else
+ tx_flags_extra = skb->ip_summed == CHECKSUM_PARTIAL ?
+ NV_TX2_CHECKSUM_L3 | NV_TX2_CHECKSUM_L4 : 0;
+
+ spin_lock_irq(&np->lock);
+
+ /* set tx flags */
+ start_tx->flaglen |= cpu_to_le32(tx_flags | tx_flags_extra);
+ np->put_tx.orig = put_tx;
+
+ spin_unlock_irq(&np->lock);
+
+ dprintk(KERN_DEBUG "%s: nv_start_xmit: entries %d queued for transmission. tx_flags_extra: %x\n",
+ dev->name, entries, tx_flags_extra);
+ {
+ int j;
+ for (j=0; j<64; j++) {
+ if ((j%16) == 0)
+ dprintk("\n%03x:", j);
+ dprintk(" %02x", ((unsigned char*)skb->data)[j]);
+ }
+ dprintk("\n");
+ }
+
+ dev->trans_start = jiffies;
+ writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
+ return NETDEV_TX_OK;
+}
+
+static int nv_start_xmit_optimized(struct sk_buff *skb, struct net_device *dev)
+{
+ struct fe_priv *np = netdev_priv(dev);
+ u32 tx_flags = 0;
+ u32 tx_flags_extra;
+ unsigned int fragments = skb_shinfo(skb)->nr_frags;
+ unsigned int i;
+ u32 offset = 0;
+ u32 bcnt;
+ u32 size = skb->len-skb->data_len;
+ u32 entries = (size >> NV_TX2_TSO_MAX_SHIFT) + ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
+ u32 empty_slots;
+ struct ring_desc_ex* put_tx;
+ struct ring_desc_ex* start_tx;
+ struct ring_desc_ex* prev_tx;
+ struct nv_skb_map* prev_tx_ctx;
+
+ /* add fragments to entries count */
+ for (i = 0; i < fragments; i++) {
+ entries += (skb_shinfo(skb)->frags[i].size >> NV_TX2_TSO_MAX_SHIFT) +
+ ((skb_shinfo(skb)->frags[i].size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
+ }
+
+ empty_slots = nv_get_empty_tx_slots(np);
+ if (unlikely(empty_slots <= entries)) {
+ spin_lock_irq(&np->lock);
+ netif_stop_queue(dev);
+ np->tx_stop = 1;
+ spin_unlock_irq(&np->lock);
+ return NETDEV_TX_BUSY;
+ }
+
+ start_tx = put_tx = np->put_tx.ex;
+
+ /* setup the header buffer */
+ do {
+ prev_tx = put_tx;
+ prev_tx_ctx = np->put_tx_ctx;
+ bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size;
+ np->put_tx_ctx->dma = pci_map_single(np->pci_dev, skb->data + offset, bcnt,
+ PCI_DMA_TODEVICE);
+ np->put_tx_ctx->dma_len = bcnt;
+ put_tx->bufhigh = cpu_to_le64(np->put_tx_ctx->dma) >> 32;
+ put_tx->buflow = cpu_to_le64(np->put_tx_ctx->dma) & 0x0FFFFFFFF;
+ put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags);
+
+ tx_flags = NV_TX2_VALID;
+ offset += bcnt;
+ size -= bcnt;
+ if (unlikely(put_tx++ == np->last_tx.ex))
+ put_tx = np->first_tx.ex;
+ if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx))
+ np->put_tx_ctx = np->first_tx_ctx;
+ } while (size);
+
+ /* setup the fragments */
+ for (i = 0; i < fragments; i++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ u32 size = frag->size;
+ offset = 0;
+
+ do {
+ prev_tx = put_tx;
+ prev_tx_ctx = np->put_tx_ctx;
+ bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size;
+ np->put_tx_ctx->dma = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt,
+ PCI_DMA_TODEVICE);
+ np->put_tx_ctx->dma_len = bcnt;
+ put_tx->bufhigh = cpu_to_le64(np->put_tx_ctx->dma) >> 32;
+ put_tx->buflow = cpu_to_le64(np->put_tx_ctx->dma) & 0x0FFFFFFFF;
+ put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags);
+
+ offset += bcnt;
+ size -= bcnt;
+ if (unlikely(put_tx++ == np->last_tx.ex))
+ put_tx = np->first_tx.ex;
+ if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx))
+ np->put_tx_ctx = np->first_tx_ctx;
+ } while (size);
}
- np->tx_skbuff[nr] = skb;
+ /* set last fragment flag */
+ prev_tx->flaglen |= cpu_to_le32(NV_TX2_LASTPACKET);
+
+ /* save skb in this slot's context area */
+ prev_tx_ctx->skb = skb;
-#ifdef NETIF_F_TSO
if (skb_is_gso(skb))
tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->gso_size << NV_TX2_TSO_SHIFT);
else
-#endif
- tx_flags_extra = skb->ip_summed == CHECKSUM_PARTIAL ?
+ tx_flags_extra = skb->ip_summed == CHECKSUM_PARTIAL ?
NV_TX2_CHECKSUM_L3 | NV_TX2_CHECKSUM_L4 : 0;
/* vlan tag */
- if (np->vlangrp && vlan_tx_tag_present(skb)) {
- tx_flags_vlan = NV_TX3_VLAN_TAG_PRESENT | vlan_tx_tag_get(skb);
+ if (likely(!np->vlangrp)) {
+ start_tx->txvlan = 0;
+ } else {
+ if (vlan_tx_tag_present(skb))
+ start_tx->txvlan = cpu_to_le32(NV_TX3_VLAN_TAG_PRESENT | vlan_tx_tag_get(skb));
+ else
+ start_tx->txvlan = 0;
}
+ spin_lock_irq(&np->lock);
+
/* set tx flags */
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- np->tx_ring.orig[start_nr].flaglen |= cpu_to_le32(tx_flags | tx_flags_extra);
- } else {
- np->tx_ring.ex[start_nr].txvlan = cpu_to_le32(tx_flags_vlan);
- np->tx_ring.ex[start_nr].flaglen |= cpu_to_le32(tx_flags | tx_flags_extra);
- }
+ start_tx->flaglen |= cpu_to_le32(tx_flags | tx_flags_extra);
+ np->put_tx.ex = put_tx;
+
+ spin_unlock_irq(&np->lock);
- dprintk(KERN_DEBUG "%s: nv_start_xmit: packet %d (entries %d) queued for transmission. tx_flags_extra: %x\n",
- dev->name, np->next_tx, entries, tx_flags_extra);
+ dprintk(KERN_DEBUG "%s: nv_start_xmit_optimized: entries %d queued for transmission. tx_flags_extra: %x\n",
+ dev->name, entries, tx_flags_extra);
{
int j;
for (j=0; j<64; j++) {
@@ -1609,12 +1866,8 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
dprintk("\n");
}
- np->next_tx += entries;
-
dev->trans_start = jiffies;
- spin_unlock_irq(&np->lock);
writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
- pci_push(get_hwbase(dev));
return NETDEV_TX_OK;
}
@@ -1627,26 +1880,22 @@ static void nv_tx_done(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
u32 flags;
- unsigned int i;
- struct sk_buff *skb;
+ struct ring_desc* orig_get_tx = np->get_tx.orig;
- while (np->nic_tx != np->next_tx) {
- i = np->nic_tx % np->tx_ring_size;
+ while ((np->get_tx.orig != np->put_tx.orig) &&
+ !((flags = le32_to_cpu(np->get_tx.orig->flaglen)) & NV_TX_VALID)) {
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
- flags = le32_to_cpu(np->tx_ring.orig[i].flaglen);
- else
- flags = le32_to_cpu(np->tx_ring.ex[i].flaglen);
+ dprintk(KERN_DEBUG "%s: nv_tx_done: flags 0x%x.\n",
+ dev->name, flags);
+
+ pci_unmap_page(np->pci_dev, np->get_tx_ctx->dma,
+ np->get_tx_ctx->dma_len,
+ PCI_DMA_TODEVICE);
+ np->get_tx_ctx->dma = 0;
- dprintk(KERN_DEBUG "%s: nv_tx_done: looking at packet %d, flags 0x%x.\n",
- dev->name, np->nic_tx, flags);
- if (flags & NV_TX_VALID)
- break;
if (np->desc_ver == DESC_VER_1) {
if (flags & NV_TX_LASTPACKET) {
- skb = np->tx_skbuff[i];
- if (flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION|
- NV_TX_UNDERFLOW|NV_TX_ERROR)) {
+ if (flags & NV_TX_ERROR) {
if (flags & NV_TX_UNDERFLOW)
np->stats.tx_fifo_errors++;
if (flags & NV_TX_CARRIERLOST)
@@ -1654,14 +1903,14 @@ static void nv_tx_done(struct net_device *dev)
np->stats.tx_errors++;
} else {
np->stats.tx_packets++;
- np->stats.tx_bytes += skb->len;
+ np->stats.tx_bytes += np->get_tx_ctx->skb->len;
}
+ dev_kfree_skb_any(np->get_tx_ctx->skb);
+ np->get_tx_ctx->skb = NULL;
}
} else {
if (flags & NV_TX2_LASTPACKET) {
- skb = np->tx_skbuff[i];
- if (flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION|
- NV_TX2_UNDERFLOW|NV_TX2_ERROR)) {
+ if (flags & NV_TX2_ERROR) {
if (flags & NV_TX2_UNDERFLOW)
np->stats.tx_fifo_errors++;
if (flags & NV_TX2_CARRIERLOST)
@@ -1669,15 +1918,56 @@ static void nv_tx_done(struct net_device *dev)
np->stats.tx_errors++;
} else {
np->stats.tx_packets++;
- np->stats.tx_bytes += skb->len;
+ np->stats.tx_bytes += np->get_tx_ctx->skb->len;
}
+ dev_kfree_skb_any(np->get_tx_ctx->skb);
+ np->get_tx_ctx->skb = NULL;
}
}
- nv_release_txskb(dev, i);
- np->nic_tx++;
+ if (unlikely(np->get_tx.orig++ == np->last_tx.orig))
+ np->get_tx.orig = np->first_tx.orig;
+ if (unlikely(np->get_tx_ctx++ == np->last_tx_ctx))
+ np->get_tx_ctx = np->first_tx_ctx;
}
- if (np->next_tx - np->nic_tx < np->tx_limit_start)
+ if (unlikely((np->tx_stop == 1) && (np->get_tx.orig != orig_get_tx))) {
+ np->tx_stop = 0;
netif_wake_queue(dev);
+ }
+}
+
+static void nv_tx_done_optimized(struct net_device *dev, int limit)
+{
+ struct fe_priv *np = netdev_priv(dev);
+ u32 flags;
+ struct ring_desc_ex* orig_get_tx = np->get_tx.ex;
+
+ while ((np->get_tx.ex != np->put_tx.ex) &&
+ !((flags = le32_to_cpu(np->get_tx.ex->flaglen)) & NV_TX_VALID) &&
+ (limit-- > 0)) {
+
+ dprintk(KERN_DEBUG "%s: nv_tx_done_optimized: flags 0x%x.\n",
+ dev->name, flags);
+
+ pci_unmap_page(np->pci_dev, np->get_tx_ctx->dma,
+ np->get_tx_ctx->dma_len,
+ PCI_DMA_TODEVICE);
+ np->get_tx_ctx->dma = 0;
+
+ if (flags & NV_TX2_LASTPACKET) {
+ if (!(flags & NV_TX2_ERROR))
+ np->stats.tx_packets++;
+ dev_kfree_skb_any(np->get_tx_ctx->skb);
+ np->get_tx_ctx->skb = NULL;
+ }
+ if (unlikely(np->get_tx.ex++ == np->last_tx.ex))
+ np->get_tx.ex = np->first_tx.ex;
+ if (unlikely(np->get_tx_ctx++ == np->last_tx_ctx))
+ np->get_tx_ctx = np->first_tx_ctx;
+ }
+ if (unlikely((np->tx_stop == 1) && (np->get_tx.ex != orig_get_tx))) {
+ np->tx_stop = 0;
+ netif_wake_queue(dev);
+ }
}
/*
@@ -1700,9 +1990,8 @@ static void nv_tx_timeout(struct net_device *dev)
{
int i;
- printk(KERN_INFO "%s: Ring at %lx: next %d nic %d\n",
- dev->name, (unsigned long)np->ring_addr,
- np->next_tx, np->nic_tx);
+ printk(KERN_INFO "%s: Ring at %lx\n",
+ dev->name, (unsigned long)np->ring_addr);
printk(KERN_INFO "%s: Dumping tx registers\n", dev->name);
for (i=0;i<=np->register_size;i+= 32) {
printk(KERN_INFO "%3x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
@@ -1750,13 +2039,16 @@ static void nv_tx_timeout(struct net_device *dev)
nv_stop_tx(dev);
/* 2) check that the packets were not sent already: */
- nv_tx_done(dev);
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ nv_tx_done(dev);
+ else
+ nv_tx_done_optimized(dev, np->tx_ring_size);
/* 3) if there are dead entries: clear everything */
- if (np->next_tx != np->nic_tx) {
+ if (np->get_tx_ctx != np->put_tx_ctx) {
printk(KERN_DEBUG "%s: tx_timeout: dead entries!\n", dev->name);
nv_drain_tx(dev);
- np->next_tx = np->nic_tx = 0;
+ nv_init_tx(dev);
setup_hw_rings(dev, NV_SETUP_TX_RING);
netif_wake_queue(dev);
}
@@ -1823,40 +2115,27 @@ static int nv_rx_process(struct net_device *dev, int limit)
{
struct fe_priv *np = netdev_priv(dev);
u32 flags;
- u32 vlanflags = 0;
- int count;
-
- for (count = 0; count < limit; ++count) {
- struct sk_buff *skb;
- int len;
- int i;
- if (np->cur_rx - np->refill_rx >= np->rx_ring_size)
- break; /* we scanned the whole ring - do not continue */
-
- i = np->cur_rx % np->rx_ring_size;
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- flags = le32_to_cpu(np->rx_ring.orig[i].flaglen);
- len = nv_descr_getlength(&np->rx_ring.orig[i], np->desc_ver);
- } else {
- flags = le32_to_cpu(np->rx_ring.ex[i].flaglen);
- len = nv_descr_getlength_ex(&np->rx_ring.ex[i], np->desc_ver);
- vlanflags = le32_to_cpu(np->rx_ring.ex[i].buflow);
- }
+ u32 rx_processed_cnt = 0;
+ struct sk_buff *skb;
+ int len;
- dprintk(KERN_DEBUG "%s: nv_rx_process: looking at packet %d, flags 0x%x.\n",
- dev->name, np->cur_rx, flags);
+ while((np->get_rx.orig != np->put_rx.orig) &&
+ !((flags = le32_to_cpu(np->get_rx.orig->flaglen)) & NV_RX_AVAIL) &&
+ (rx_processed_cnt++ < limit)) {
- if (flags & NV_RX_AVAIL)
- break; /* still owned by hardware, */
+ dprintk(KERN_DEBUG "%s: nv_rx_process: flags 0x%x.\n",
+ dev->name, flags);
/*
* the packet is for us - immediately tear down the pci mapping.
* TODO: check if a prefetch of the first cacheline improves
* the performance.
*/
- pci_unmap_single(np->pci_dev, np->rx_dma[i],
- np->rx_skbuff[i]->end-np->rx_skbuff[i]->data,
+ pci_unmap_single(np->pci_dev, np->get_rx_ctx->dma,
+ np->get_rx_ctx->dma_len,
PCI_DMA_FROMDEVICE);
+ skb = np->get_rx_ctx->skb;
+ np->get_rx_ctx->skb = NULL;
{
int j;
@@ -1864,123 +2143,228 @@ static int nv_rx_process(struct net_device *dev, int limit)
for (j=0; j<64; j++) {
if ((j%16) == 0)
dprintk("\n%03x:", j);
- dprintk(" %02x", ((unsigned char*)np->rx_skbuff[i]->data)[j]);
+ dprintk(" %02x", ((unsigned char*)skb->data)[j]);
}
dprintk("\n");
}
/* look at what we actually got: */
if (np->desc_ver == DESC_VER_1) {
- if (!(flags & NV_RX_DESCRIPTORVALID))
- goto next_pkt;
-
- if (flags & NV_RX_ERROR) {
- if (flags & NV_RX_MISSEDFRAME) {
- np->stats.rx_missed_errors++;
- np->stats.rx_errors++;
- goto next_pkt;
- }
- if (flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3)) {
- np->stats.rx_errors++;
- goto next_pkt;
- }
- if (flags & NV_RX_CRCERR) {
- np->stats.rx_crc_errors++;
- np->stats.rx_errors++;
- goto next_pkt;
- }
- if (flags & NV_RX_OVERFLOW) {
- np->stats.rx_over_errors++;
- np->stats.rx_errors++;
- goto next_pkt;
+ if (likely(flags & NV_RX_DESCRIPTORVALID)) {
+ len = flags & LEN_MASK_V1;
+ if (unlikely(flags & NV_RX_ERROR)) {
+ if (flags & NV_RX_ERROR4) {
+ len = nv_getlen(dev, skb->data, len);
+ if (len < 0) {
+ np->stats.rx_errors++;
+ dev_kfree_skb(skb);
+ goto next_pkt;
+ }
+ }
+ /* framing errors are soft errors */
+ else if (flags & NV_RX_FRAMINGERR) {
+ if (flags & NV_RX_SUBSTRACT1) {
+ len--;
+ }
+ }
+ /* the rest are hard errors */
+ else {
+ if (flags & NV_RX_MISSEDFRAME)
+ np->stats.rx_missed_errors++;
+ if (flags & NV_RX_CRCERR)
+ np->stats.rx_crc_errors++;
+ if (flags & NV_RX_OVERFLOW)
+ np->stats.rx_over_errors++;
+ np->stats.rx_errors++;
+ dev_kfree_skb(skb);
+ goto next_pkt;
+ }
}
- if (flags & NV_RX_ERROR4) {
- len = nv_getlen(dev, np->rx_skbuff[i]->data, len);
- if (len < 0) {
+ } else {
+ dev_kfree_skb(skb);
+ goto next_pkt;
+ }
+ } else {
+ if (likely(flags & NV_RX2_DESCRIPTORVALID)) {
+ len = flags & LEN_MASK_V2;
+ if (unlikely(flags & NV_RX2_ERROR)) {
+ if (flags & NV_RX2_ERROR4) {
+ len = nv_getlen(dev, skb->data, len);
+ if (len < 0) {
+ np->stats.rx_errors++;
+ dev_kfree_skb(skb);
+ goto next_pkt;
+ }
+ }
+ /* framing errors are soft errors */
+ else if (flags & NV_RX2_FRAMINGERR) {
+ if (flags & NV_RX2_SUBSTRACT1) {
+ len--;
+ }
+ }
+ /* the rest are hard errors */
+ else {
+ if (flags & NV_RX2_CRCERR)
+ np->stats.rx_crc_errors++;
+ if (flags & NV_RX2_OVERFLOW)
+ np->stats.rx_over_errors++;
np->stats.rx_errors++;
+ dev_kfree_skb(skb);
goto next_pkt;
}
}
- /* framing errors are soft errors. */
- if (flags & NV_RX_FRAMINGERR) {
- if (flags & NV_RX_SUBSTRACT1) {
- len--;
+ if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK2)/*ip and tcp */ {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ } else {
+ if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK1 ||
+ (flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK3) {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
}
}
- }
- } else {
- if (!(flags & NV_RX2_DESCRIPTORVALID))
+ } else {
+ dev_kfree_skb(skb);
goto next_pkt;
+ }
+ }
+ /* got a valid packet - forward it to the network core */
+ skb_put(skb, len);
+ skb->protocol = eth_type_trans(skb, dev);
+ dprintk(KERN_DEBUG "%s: nv_rx_process: %d bytes, proto %d accepted.\n",
+ dev->name, len, skb->protocol);
+#ifdef CONFIG_FORCEDETH_NAPI
+ netif_receive_skb(skb);
+#else
+ netif_rx(skb);
+#endif
+ dev->last_rx = jiffies;
+ np->stats.rx_packets++;
+ np->stats.rx_bytes += len;
+next_pkt:
+ if (unlikely(np->get_rx.orig++ == np->last_rx.orig))
+ np->get_rx.orig = np->first_rx.orig;
+ if (unlikely(np->get_rx_ctx++ == np->last_rx_ctx))
+ np->get_rx_ctx = np->first_rx_ctx;
+ }
- if (flags & NV_RX2_ERROR) {
- if (flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3)) {
- np->stats.rx_errors++;
- goto next_pkt;
- }
- if (flags & NV_RX2_CRCERR) {
- np->stats.rx_crc_errors++;
- np->stats.rx_errors++;
- goto next_pkt;
- }
- if (flags & NV_RX2_OVERFLOW) {
- np->stats.rx_over_errors++;
- np->stats.rx_errors++;
- goto next_pkt;
- }
+ return rx_processed_cnt;
+}
+
+static int nv_rx_process_optimized(struct net_device *dev, int limit)
+{
+ struct fe_priv *np = netdev_priv(dev);
+ u32 flags;
+ u32 vlanflags = 0;
+ u32 rx_processed_cnt = 0;
+ struct sk_buff *skb;
+ int len;
+
+ while((np->get_rx.ex != np->put_rx.ex) &&
+ !((flags = le32_to_cpu(np->get_rx.ex->flaglen)) & NV_RX2_AVAIL) &&
+ (rx_processed_cnt++ < limit)) {
+
+ dprintk(KERN_DEBUG "%s: nv_rx_process_optimized: flags 0x%x.\n",
+ dev->name, flags);
+
+ /*
+ * the packet is for us - immediately tear down the pci mapping.
+ * TODO: check if a prefetch of the first cacheline improves
+ * the performance.
+ */
+ pci_unmap_single(np->pci_dev, np->get_rx_ctx->dma,
+ np->get_rx_ctx->dma_len,
+ PCI_DMA_FROMDEVICE);
+ skb = np->get_rx_ctx->skb;
+ np->get_rx_ctx->skb = NULL;
+
+ {
+ int j;
+ dprintk(KERN_DEBUG "Dumping packet (flags 0x%x).",flags);
+ for (j=0; j<64; j++) {
+ if ((j%16) == 0)
+ dprintk("\n%03x:", j);
+ dprintk(" %02x", ((unsigned char*)skb->data)[j]);
+ }
+ dprintk("\n");
+ }
+ /* look at what we actually got: */
+ if (likely(flags & NV_RX2_DESCRIPTORVALID)) {
+ len = flags & LEN_MASK_V2;
+ if (unlikely(flags & NV_RX2_ERROR)) {
if (flags & NV_RX2_ERROR4) {
- len = nv_getlen(dev, np->rx_skbuff[i]->data, len);
+ len = nv_getlen(dev, skb->data, len);
if (len < 0) {
- np->stats.rx_errors++;
+ dev_kfree_skb(skb);
goto next_pkt;
}
}
/* framing errors are soft errors */
- if (flags & NV_RX2_FRAMINGERR) {
+ else if (flags & NV_RX2_FRAMINGERR) {
if (flags & NV_RX2_SUBSTRACT1) {
len--;
}
}
+ /* the rest are hard errors */
+ else {
+ dev_kfree_skb(skb);
+ goto next_pkt;
+ }
}
- if (np->rx_csum) {
- flags &= NV_RX2_CHECKSUMMASK;
- if (flags == NV_RX2_CHECKSUMOK1 ||
- flags == NV_RX2_CHECKSUMOK2 ||
- flags == NV_RX2_CHECKSUMOK3) {
- dprintk(KERN_DEBUG "%s: hw checksum hit!.\n", dev->name);
- np->rx_skbuff[i]->ip_summed = CHECKSUM_UNNECESSARY;
- } else {
- dprintk(KERN_DEBUG "%s: hwchecksum miss!.\n", dev->name);
+
+ if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK2)/*ip and tcp */ {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ } else {
+ if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK1 ||
+ (flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK3) {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
}
}
- }
- /* got a valid packet - forward it to the network core */
- skb = np->rx_skbuff[i];
- np->rx_skbuff[i] = NULL;
- skb_put(skb, len);
- skb->protocol = eth_type_trans(skb, dev);
- dprintk(KERN_DEBUG "%s: nv_rx_process: packet %d with %d bytes, proto %d accepted.\n",
- dev->name, np->cur_rx, len, skb->protocol);
+ /* got a valid packet - forward it to the network core */
+ skb_put(skb, len);
+ skb->protocol = eth_type_trans(skb, dev);
+ prefetch(skb->data);
+
+ dprintk(KERN_DEBUG "%s: nv_rx_process_optimized: %d bytes, proto %d accepted.\n",
+ dev->name, len, skb->protocol);
+
+ if (likely(!np->vlangrp)) {
#ifdef CONFIG_FORCEDETH_NAPI
- if (np->vlangrp && (vlanflags & NV_RX3_VLAN_TAG_PRESENT))
- vlan_hwaccel_receive_skb(skb, np->vlangrp,
- vlanflags & NV_RX3_VLAN_TAG_MASK);
- else
- netif_receive_skb(skb);
+ netif_receive_skb(skb);
#else
- if (np->vlangrp && (vlanflags & NV_RX3_VLAN_TAG_PRESENT))
- vlan_hwaccel_rx(skb, np->vlangrp,
- vlanflags & NV_RX3_VLAN_TAG_MASK);
- else
- netif_rx(skb);
+ netif_rx(skb);
#endif
- dev->last_rx = jiffies;
- np->stats.rx_packets++;
- np->stats.rx_bytes += len;
+ } else {
+ vlanflags = le32_to_cpu(np->get_rx.ex->buflow);
+ if (vlanflags & NV_RX3_VLAN_TAG_PRESENT) {
+#ifdef CONFIG_FORCEDETH_NAPI
+ vlan_hwaccel_receive_skb(skb, np->vlangrp,
+ vlanflags & NV_RX3_VLAN_TAG_MASK);
+#else
+ vlan_hwaccel_rx(skb, np->vlangrp,
+ vlanflags & NV_RX3_VLAN_TAG_MASK);
+#endif
+ } else {
+#ifdef CONFIG_FORCEDETH_NAPI
+ netif_receive_skb(skb);
+#else
+ netif_rx(skb);
+#endif
+ }
+ }
+
+ dev->last_rx = jiffies;
+ np->stats.rx_packets++;
+ np->stats.rx_bytes += len;
+ } else {
+ dev_kfree_skb(skb);
+ }
next_pkt:
- np->cur_rx++;
+ if (unlikely(np->get_rx.ex++ == np->last_rx.ex))
+ np->get_rx.ex = np->first_rx.ex;
+ if (unlikely(np->get_rx_ctx++ == np->last_rx_ctx))
+ np->get_rx_ctx = np->first_rx_ctx;
}
- return count;
+ return rx_processed_cnt;
}
static void set_bufsize(struct net_device *dev)
@@ -2456,7 +2840,6 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQSTAT_MASK;
writel(NVREG_IRQSTAT_MASK, base + NvRegMSIXIrqStatus);
}
- pci_push(base);
dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events);
if (!(events & np->irqmask))
break;
@@ -2465,22 +2848,46 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
nv_tx_done(dev);
spin_unlock(&np->lock);
- if (events & NVREG_IRQ_LINK) {
+#ifdef CONFIG_FORCEDETH_NAPI
+ if (events & NVREG_IRQ_RX_ALL) {
+ netif_rx_schedule(dev);
+
+ /* Disable furthur receive irq's */
+ spin_lock(&np->lock);
+ np->irqmask &= ~NVREG_IRQ_RX_ALL;
+
+ if (np->msi_flags & NV_MSI_X_ENABLED)
+ writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
+ else
+ writel(np->irqmask, base + NvRegIrqMask);
+ spin_unlock(&np->lock);
+ }
+#else
+ if (nv_rx_process(dev, dev->weight)) {
+ if (unlikely(nv_alloc_rx(dev))) {
+ spin_lock(&np->lock);
+ if (!np->in_shutdown)
+ mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
+ spin_unlock(&np->lock);
+ }
+ }
+#endif
+ if (unlikely(events & NVREG_IRQ_LINK)) {
spin_lock(&np->lock);
nv_link_irq(dev);
spin_unlock(&np->lock);
}
- if (np->need_linktimer && time_after(jiffies, np->link_timeout)) {
+ if (unlikely(np->need_linktimer && time_after(jiffies, np->link_timeout))) {
spin_lock(&np->lock);
nv_linkchange(dev);
spin_unlock(&np->lock);
np->link_timeout = jiffies + LINK_TIMEOUT;
}
- if (events & (NVREG_IRQ_TX_ERR)) {
+ if (unlikely(events & (NVREG_IRQ_TX_ERR))) {
dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n",
dev->name, events);
}
- if (events & (NVREG_IRQ_UNKNOWN)) {
+ if (unlikely(events & (NVREG_IRQ_UNKNOWN))) {
printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n",
dev->name, events);
}
@@ -2501,6 +2908,63 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
spin_unlock(&np->lock);
break;
}
+ if (unlikely(i > max_interrupt_work)) {
+ spin_lock(&np->lock);
+ /* disable interrupts on the nic */
+ if (!(np->msi_flags & NV_MSI_X_ENABLED))
+ writel(0, base + NvRegIrqMask);
+ else
+ writel(np->irqmask, base + NvRegIrqMask);
+ pci_push(base);
+
+ if (!np->in_shutdown) {
+ np->nic_poll_irq = np->irqmask;
+ mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
+ }
+ printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq.\n", dev->name, i);
+ spin_unlock(&np->lock);
+ break;
+ }
+
+ }
+ dprintk(KERN_DEBUG "%s: nv_nic_irq completed\n", dev->name);
+
+ return IRQ_RETVAL(i);
+}
+
+#define TX_WORK_PER_LOOP 64
+#define RX_WORK_PER_LOOP 64
+/**
+ * All _optimized functions are used to help increase performance
+ * (reduce CPU and increase throughput). They use descripter version 3,
+ * compiler directives, and reduce memory accesses.
+ */
+static irqreturn_t nv_nic_irq_optimized(int foo, void *data)
+{
+ struct net_device *dev = (struct net_device *) data;
+ struct fe_priv *np = netdev_priv(dev);
+ u8 __iomem *base = get_hwbase(dev);
+ u32 events;
+ int i;
+
+ dprintk(KERN_DEBUG "%s: nv_nic_irq_optimized\n", dev->name);
+
+ for (i=0; ; i++) {
+ if (!(np->msi_flags & NV_MSI_X_ENABLED)) {
+ events = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK;
+ writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
+ } else {
+ events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQSTAT_MASK;
+ writel(NVREG_IRQSTAT_MASK, base + NvRegMSIXIrqStatus);
+ }
+ dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events);
+ if (!(events & np->irqmask))
+ break;
+
+ spin_lock(&np->lock);
+ nv_tx_done_optimized(dev, TX_WORK_PER_LOOP);
+ spin_unlock(&np->lock);
+
#ifdef CONFIG_FORCEDETH_NAPI
if (events & NVREG_IRQ_RX_ALL) {
netif_rx_schedule(dev);
@@ -2516,15 +2980,53 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
spin_unlock(&np->lock);
}
#else
- nv_rx_process(dev, dev->weight);
- if (nv_alloc_rx(dev)) {
+ if (nv_rx_process_optimized(dev, dev->weight)) {
+ if (unlikely(nv_alloc_rx_optimized(dev))) {
+ spin_lock(&np->lock);
+ if (!np->in_shutdown)
+ mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
+ spin_unlock(&np->lock);
+ }
+ }
+#endif
+ if (unlikely(events & NVREG_IRQ_LINK)) {
spin_lock(&np->lock);
- if (!np->in_shutdown)
- mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
+ nv_link_irq(dev);
spin_unlock(&np->lock);
}
-#endif
- if (i > max_interrupt_work) {
+ if (unlikely(np->need_linktimer && time_after(jiffies, np->link_timeout))) {
+ spin_lock(&np->lock);
+ nv_linkchange(dev);
+ spin_unlock(&np->lock);
+ np->link_timeout = jiffies + LINK_TIMEOUT;
+ }
+ if (unlikely(events & (NVREG_IRQ_TX_ERR))) {
+ dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n",
+ dev->name, events);
+ }
+ if (unlikely(events & (NVREG_IRQ_UNKNOWN))) {
+ printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n",
+ dev->name, events);
+ }
+ if (unlikely(events & NVREG_IRQ_RECOVER_ERROR)) {
+ spin_lock(&np->lock);
+ /* disable interrupts on the nic */
+ if (!(np->msi_flags & NV_MSI_X_ENABLED))
+ writel(0, base + NvRegIrqMask);
+ else
+ writel(np->irqmask, base + NvRegIrqMask);
+ pci_push(base);
+
+ if (!np->in_shutdown) {
+ np->nic_poll_irq = np->irqmask;
+ np->recover_error = 1;
+ mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
+ }
+ spin_unlock(&np->lock);
+ break;
+ }
+
+ if (unlikely(i > max_interrupt_work)) {
spin_lock(&np->lock);
/* disable interrupts on the nic */
if (!(np->msi_flags & NV_MSI_X_ENABLED))
@@ -2543,7 +3045,7 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
}
}
- dprintk(KERN_DEBUG "%s: nv_nic_irq completed\n", dev->name);
+ dprintk(KERN_DEBUG "%s: nv_nic_irq_optimized completed\n", dev->name);
return IRQ_RETVAL(i);
}
@@ -2562,20 +3064,19 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data)
for (i=0; ; i++) {
events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_TX_ALL;
writel(NVREG_IRQ_TX_ALL, base + NvRegMSIXIrqStatus);
- pci_push(base);
dprintk(KERN_DEBUG "%s: tx irq: %08x\n", dev->name, events);
if (!(events & np->irqmask))
break;
spin_lock_irqsave(&np->lock, flags);
- nv_tx_done(dev);
+ nv_tx_done_optimized(dev, TX_WORK_PER_LOOP);
spin_unlock_irqrestore(&np->lock, flags);
- if (events & (NVREG_IRQ_TX_ERR)) {
+ if (unlikely(events & (NVREG_IRQ_TX_ERR))) {
dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n",
dev->name, events);
}
- if (i > max_interrupt_work) {
+ if (unlikely(i > max_interrupt_work)) {
spin_lock_irqsave(&np->lock, flags);
/* disable interrupts on the nic */
writel(NVREG_IRQ_TX_ALL, base + NvRegIrqMask);
@@ -2604,7 +3105,10 @@ static int nv_napi_poll(struct net_device *dev, int *budget)
u8 __iomem *base = get_hwbase(dev);
unsigned long flags;
- pkts = nv_rx_process(dev, limit);
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ pkts = nv_rx_process(dev, limit);
+ else
+ pkts = nv_rx_process_optimized(dev, limit);
if (nv_alloc_rx(dev)) {
spin_lock_irqsave(&np->lock, flags);
@@ -2670,20 +3174,20 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data)
for (i=0; ; i++) {
events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_RX_ALL;
writel(NVREG_IRQ_RX_ALL, base + NvRegMSIXIrqStatus);
- pci_push(base);
dprintk(KERN_DEBUG "%s: rx irq: %08x\n", dev->name, events);
if (!(events & np->irqmask))
break;
- nv_rx_process(dev, dev->weight);
- if (nv_alloc_rx(dev)) {
- spin_lock_irqsave(&np->lock, flags);
- if (!np->in_shutdown)
- mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
- spin_unlock_irqrestore(&np->lock, flags);
+ if (nv_rx_process_optimized(dev, dev->weight)) {
+ if (unlikely(nv_alloc_rx_optimized(dev))) {
+ spin_lock_irqsave(&np->lock, flags);
+ if (!np->in_shutdown)
+ mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
+ spin_unlock_irqrestore(&np->lock, flags);
+ }
}
- if (i > max_interrupt_work) {
+ if (unlikely(i > max_interrupt_work)) {
spin_lock_irqsave(&np->lock, flags);
/* disable interrupts on the nic */
writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
@@ -2718,11 +3222,15 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data)
for (i=0; ; i++) {
events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_OTHER;
writel(NVREG_IRQ_OTHER, base + NvRegMSIXIrqStatus);
- pci_push(base);
dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events);
if (!(events & np->irqmask))
break;
+ /* check tx in case we reached max loop limit in tx isr */
+ spin_lock_irqsave(&np->lock, flags);
+ nv_tx_done_optimized(dev, TX_WORK_PER_LOOP);
+ spin_unlock_irqrestore(&np->lock, flags);
+
if (events & NVREG_IRQ_LINK) {
spin_lock_irqsave(&np->lock, flags);
nv_link_irq(dev);
@@ -2752,7 +3260,7 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data)
printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n",
dev->name, events);
}
- if (i > max_interrupt_work) {
+ if (unlikely(i > max_interrupt_work)) {
spin_lock_irqsave(&np->lock, flags);
/* disable interrupts on the nic */
writel(NVREG_IRQ_OTHER, base + NvRegIrqMask);
@@ -2835,6 +3343,16 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
u8 __iomem *base = get_hwbase(dev);
int ret = 1;
int i;
+ irqreturn_t (*handler)(int foo, void *data);
+
+ if (intr_test) {
+ handler = nv_nic_irq_test;
+ } else {
+ if (np->desc_ver == DESC_VER_3)
+ handler = nv_nic_irq_optimized;
+ else
+ handler = nv_nic_irq;
+ }
if (np->msi_flags & NV_MSI_X_CAPABLE) {
for (i = 0; i < (np->msi_flags & NV_MSI_X_VECTORS_MASK); i++) {
@@ -2872,10 +3390,7 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
set_msix_vector_map(dev, NV_MSI_X_VECTOR_OTHER, NVREG_IRQ_OTHER);
} else {
/* Request irq for all interrupts */
- if ((!intr_test &&
- request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, &nv_nic_irq, IRQF_SHARED, dev->name, dev) != 0) ||
- (intr_test &&
- request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, &nv_nic_irq_test, IRQF_SHARED, dev->name, dev) != 0)) {
+ if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, handler, IRQF_SHARED, dev->name, dev) != 0) {
printk(KERN_INFO "forcedeth: request_irq failed %d\n", ret);
pci_disable_msix(np->pci_dev);
np->msi_flags &= ~NV_MSI_X_ENABLED;
@@ -2891,8 +3406,7 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
if (ret != 0 && np->msi_flags & NV_MSI_CAPABLE) {
if ((ret = pci_enable_msi(np->pci_dev)) == 0) {
np->msi_flags |= NV_MSI_ENABLED;
- if ((!intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq, IRQF_SHARED, dev->name, dev) != 0) ||
- (intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq_test, IRQF_SHARED, dev->name, dev) != 0)) {
+ if (request_irq(np->pci_dev->irq, handler, IRQF_SHARED, dev->name, dev) != 0) {
printk(KERN_INFO "forcedeth: request_irq failed %d\n", ret);
pci_disable_msi(np->pci_dev);
np->msi_flags &= ~NV_MSI_ENABLED;
@@ -2907,8 +3421,7 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
}
}
if (ret != 0) {
- if ((!intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq, IRQF_SHARED, dev->name, dev) != 0) ||
- (intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq_test, IRQF_SHARED, dev->name, dev) != 0))
+ if (request_irq(np->pci_dev->irq, handler, IRQF_SHARED, dev->name, dev) != 0)
goto out_err;
}
@@ -3051,47 +3564,8 @@ static void nv_do_stats_poll(unsigned long data)
{
struct net_device *dev = (struct net_device *) data;
struct fe_priv *np = netdev_priv(dev);
- u8 __iomem *base = get_hwbase(dev);
- np->estats.tx_bytes += readl(base + NvRegTxCnt);
- np->estats.tx_zero_rexmt += readl(base + NvRegTxZeroReXmt);
- np->estats.tx_one_rexmt += readl(base + NvRegTxOneReXmt);
- np->estats.tx_many_rexmt += readl(base + NvRegTxManyReXmt);
- np->estats.tx_late_collision += readl(base + NvRegTxLateCol);
- np->estats.tx_fifo_errors += readl(base + NvRegTxUnderflow);
- np->estats.tx_carrier_errors += readl(base + NvRegTxLossCarrier);
- np->estats.tx_excess_deferral += readl(base + NvRegTxExcessDef);
- np->estats.tx_retry_error += readl(base + NvRegTxRetryErr);
- np->estats.tx_deferral += readl(base + NvRegTxDef);
- np->estats.tx_packets += readl(base + NvRegTxFrame);
- np->estats.tx_pause += readl(base + NvRegTxPause);
- np->estats.rx_frame_error += readl(base + NvRegRxFrameErr);
- np->estats.rx_extra_byte += readl(base + NvRegRxExtraByte);
- np->estats.rx_late_collision += readl(base + NvRegRxLateCol);
- np->estats.rx_runt += readl(base + NvRegRxRunt);
- np->estats.rx_frame_too_long += readl(base + NvRegRxFrameTooLong);
- np->estats.rx_over_errors += readl(base + NvRegRxOverflow);
- np->estats.rx_crc_errors += readl(base + NvRegRxFCSErr);
- np->estats.rx_frame_align_error += readl(base + NvRegRxFrameAlignErr);
- np->estats.rx_length_error += readl(base + NvRegRxLenErr);
- np->estats.rx_unicast += readl(base + NvRegRxUnicast);
- np->estats.rx_multicast += readl(base + NvRegRxMulticast);
- np->estats.rx_broadcast += readl(base + NvRegRxBroadcast);
- np->estats.rx_bytes += readl(base + NvRegRxCnt);
- np->estats.rx_pause += readl(base + NvRegRxPause);
- np->estats.rx_drop_frame += readl(base + NvRegRxDropFrame);
- np->estats.rx_packets =
- np->estats.rx_unicast +
- np->estats.rx_multicast +
- np->estats.rx_broadcast;
- np->estats.rx_errors_total =
- np->estats.rx_crc_errors +
- np->estats.rx_over_errors +
- np->estats.rx_frame_error +
- (np->estats.rx_frame_align_error - np->estats.rx_extra_byte) +
- np->estats.rx_late_collision +
- np->estats.rx_runt +
- np->estats.rx_frame_too_long;
+ nv_get_hw_stats(dev);
if (!np->in_shutdown)
mod_timer(&np->stats_poll, jiffies + STATS_INTERVAL);
@@ -3465,7 +3939,7 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri
{
struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
- u8 *rxtx_ring, *rx_skbuff, *tx_skbuff, *rx_dma, *tx_dma, *tx_dma_len;
+ u8 *rxtx_ring, *rx_skbuff, *tx_skbuff;
dma_addr_t ring_addr;
if (ring->rx_pending < RX_RING_MIN ||
@@ -3491,12 +3965,9 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri
sizeof(struct ring_desc_ex) * (ring->rx_pending + ring->tx_pending),
&ring_addr);
}
- rx_skbuff = kmalloc(sizeof(struct sk_buff*) * ring->rx_pending, GFP_KERNEL);
- rx_dma = kmalloc(sizeof(dma_addr_t) * ring->rx_pending, GFP_KERNEL);
- tx_skbuff = kmalloc(sizeof(struct sk_buff*) * ring->tx_pending, GFP_KERNEL);
- tx_dma = kmalloc(sizeof(dma_addr_t) * ring->tx_pending, GFP_KERNEL);
- tx_dma_len = kmalloc(sizeof(unsigned int) * ring->tx_pending, GFP_KERNEL);
- if (!rxtx_ring || !rx_skbuff || !rx_dma || !tx_skbuff || !tx_dma || !tx_dma_len) {
+ rx_skbuff = kmalloc(sizeof(struct nv_skb_map) * ring->rx_pending, GFP_KERNEL);
+ tx_skbuff = kmalloc(sizeof(struct nv_skb_map) * ring->tx_pending, GFP_KERNEL);
+ if (!rxtx_ring || !rx_skbuff || !tx_skbuff) {
/* fall back to old rings */
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
if (rxtx_ring)
@@ -3509,14 +3980,8 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri
}
if (rx_skbuff)
kfree(rx_skbuff);
- if (rx_dma)
- kfree(rx_dma);
if (tx_skbuff)
kfree(tx_skbuff);
- if (tx_dma)
- kfree(tx_dma);
- if (tx_dma_len)
- kfree(tx_dma_len);
goto exit;
}
@@ -3538,8 +4003,6 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri
/* set new values */
np->rx_ring_size = ring->rx_pending;
np->tx_ring_size = ring->tx_pending;
- np->tx_limit_stop = ring->tx_pending - TX_LIMIT_DIFFERENCE;
- np->tx_limit_start = ring->tx_pending - TX_LIMIT_DIFFERENCE - 1;
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
np->rx_ring.orig = (struct ring_desc*)rxtx_ring;
np->tx_ring.orig = &np->rx_ring.orig[np->rx_ring_size];
@@ -3547,18 +4010,12 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri
np->rx_ring.ex = (struct ring_desc_ex*)rxtx_ring;
np->tx_ring.ex = &np->rx_ring.ex[np->rx_ring_size];
}
- np->rx_skbuff = (struct sk_buff**)rx_skbuff;
- np->rx_dma = (dma_addr_t*)rx_dma;
- np->tx_skbuff = (struct sk_buff**)tx_skbuff;
- np->tx_dma = (dma_addr_t*)tx_dma;
- np->tx_dma_len = (unsigned int*)tx_dma_len;
+ np->rx_skb = (struct nv_skb_map*)rx_skbuff;
+ np->tx_skb = (struct nv_skb_map*)tx_skbuff;
np->ring_addr = ring_addr;
- memset(np->rx_skbuff, 0, sizeof(struct sk_buff*) * np->rx_ring_size);
- memset(np->rx_dma, 0, sizeof(dma_addr_t) * np->rx_ring_size);
- memset(np->tx_skbuff, 0, sizeof(struct sk_buff*) * np->tx_ring_size);
- memset(np->tx_dma, 0, sizeof(dma_addr_t) * np->tx_ring_size);
- memset(np->tx_dma_len, 0, sizeof(unsigned int) * np->tx_ring_size);
+ memset(np->rx_skb, 0, sizeof(struct nv_skb_map) * np->rx_ring_size);
+ memset(np->tx_skb, 0, sizeof(struct nv_skb_map) * np->tx_ring_size);
if (netif_running(dev)) {
/* reinit driver view of the queues */
@@ -3727,8 +4184,10 @@ static int nv_get_stats_count(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
- if (np->driver_data & DEV_HAS_STATISTICS)
- return sizeof(struct nv_ethtool_stats)/sizeof(u64);
+ if (np->driver_data & DEV_HAS_STATISTICS_V1)
+ return NV_DEV_STATISTICS_V1_COUNT;
+ else if (np->driver_data & DEV_HAS_STATISTICS_V2)
+ return NV_DEV_STATISTICS_V2_COUNT;
else
return 0;
}
@@ -3955,7 +4414,7 @@ static int nv_loopback_test(struct net_device *dev)
dprintk(KERN_DEBUG "%s: loopback len mismatch %d vs %d\n",
dev->name, len, pkt_len);
} else {
- rx_skb = np->rx_skbuff[0];
+ rx_skb = np->rx_skb[0].skb;
for (i = 0; i < pkt_len; i++) {
if (rx_skb->data[i] != (u8)(i & 0xff)) {
ret = 0;
@@ -4315,7 +4774,7 @@ static int nv_open(struct net_device *dev)
mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
/* start statistics timer */
- if (np->driver_data & DEV_HAS_STATISTICS)
+ if (np->driver_data & (DEV_HAS_STATISTICS_V1|DEV_HAS_STATISTICS_V2))
mod_timer(&np->stats_poll, jiffies + STATS_INTERVAL);
spin_unlock_irq(&np->lock);
@@ -4412,7 +4871,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
if (err < 0)
goto out_disable;
- if (id->driver_data & (DEV_HAS_VLAN|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS))
+ if (id->driver_data & (DEV_HAS_VLAN|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V2))
+ np->register_size = NV_PCI_REGSZ_VER3;
+ else if (id->driver_data & DEV_HAS_STATISTICS_V1)
np->register_size = NV_PCI_REGSZ_VER2;
else
np->register_size = NV_PCI_REGSZ_VER1;
@@ -4475,10 +4936,8 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
np->rx_csum = 1;
np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK;
dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
-#ifdef NETIF_F_TSO
dev->features |= NETIF_F_TSO;
-#endif
- }
+ }
np->vlanctl_bits = 0;
if (id->driver_data & DEV_HAS_VLAN) {
@@ -4512,8 +4971,6 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
np->rx_ring_size = RX_RING_DEFAULT;
np->tx_ring_size = TX_RING_DEFAULT;
- np->tx_limit_stop = np->tx_ring_size - TX_LIMIT_DIFFERENCE;
- np->tx_limit_start = np->tx_ring_size - TX_LIMIT_DIFFERENCE - 1;
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
np->rx_ring.orig = pci_alloc_consistent(pci_dev,
@@ -4530,22 +4987,19 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
goto out_unmap;
np->tx_ring.ex = &np->rx_ring.ex[np->rx_ring_size];
}
- np->rx_skbuff = kmalloc(sizeof(struct sk_buff*) * np->rx_ring_size, GFP_KERNEL);
- np->rx_dma = kmalloc(sizeof(dma_addr_t) * np->rx_ring_size, GFP_KERNEL);
- np->tx_skbuff = kmalloc(sizeof(struct sk_buff*) * np->tx_ring_size, GFP_KERNEL);
- np->tx_dma = kmalloc(sizeof(dma_addr_t) * np->tx_ring_size, GFP_KERNEL);
- np->tx_dma_len = kmalloc(sizeof(unsigned int) * np->tx_ring_size, GFP_KERNEL);
- if (!np->rx_skbuff || !np->rx_dma || !np->tx_skbuff || !np->tx_dma || !np->tx_dma_len)
+ np->rx_skb = kmalloc(sizeof(struct nv_skb_map) * np->rx_ring_size, GFP_KERNEL);
+ np->tx_skb = kmalloc(sizeof(struct nv_skb_map) * np->tx_ring_size, GFP_KERNEL);
+ if (!np->rx_skb || !np->tx_skb)
goto out_freering;
- memset(np->rx_skbuff, 0, sizeof(struct sk_buff*) * np->rx_ring_size);
- memset(np->rx_dma, 0, sizeof(dma_addr_t) * np->rx_ring_size);
- memset(np->tx_skbuff, 0, sizeof(struct sk_buff*) * np->tx_ring_size);
- memset(np->tx_dma, 0, sizeof(dma_addr_t) * np->tx_ring_size);
- memset(np->tx_dma_len, 0, sizeof(unsigned int) * np->tx_ring_size);
+ memset(np->rx_skb, 0, sizeof(struct nv_skb_map) * np->rx_ring_size);
+ memset(np->tx_skb, 0, sizeof(struct nv_skb_map) * np->tx_ring_size);
dev->open = nv_open;
dev->stop = nv_close;
- dev->hard_start_xmit = nv_start_xmit;
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ dev->hard_start_xmit = nv_start_xmit;
+ else
+ dev->hard_start_xmit = nv_start_xmit_optimized;
dev->get_stats = nv_get_stats;
dev->change_mtu = nv_change_mtu;
dev->set_mac_address = nv_set_mac_address;
@@ -4553,7 +5007,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = nv_poll_controller;
#endif
- dev->weight = 64;
+ dev->weight = RX_WORK_PER_LOOP;
#ifdef CONFIG_FORCEDETH_NAPI
dev->poll = nv_napi_poll;
#endif
@@ -4868,83 +5322,83 @@ static struct pci_device_id pci_tbl[] = {
},
{ /* CK804 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_8),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1,
},
{ /* CK804 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_9),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1,
},
{ /* MCP04 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_10),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1,
},
{ /* MCP04 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_11),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1,
},
{ /* MCP51 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_12),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1,
},
{ /* MCP51 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_13),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1,
},
{ /* MCP55 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP55 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP61 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_16),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP61 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_17),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP61 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_18),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP61 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_19),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP65 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_20),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP65 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_21),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP65 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_22),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP65 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_23),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP67 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_24),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP67 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_25),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP67 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_26),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP67 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_27),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{0,},
};
diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h
index 92590d8fc24..569be225cd0 100644
--- a/drivers/net/fs_enet/fs_enet.h
+++ b/drivers/net/fs_enet/fs_enet.h
@@ -9,6 +9,7 @@
#include <linux/dma-mapping.h>
#include <linux/fs_enet_pd.h>
+#include <asm/fs_pd.h>
#ifdef CONFIG_CPM1
#include <asm/commproc.h>
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
index 6d71bea5e90..0d6943d6709 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/gianfar_ethtool.c
@@ -42,8 +42,6 @@
#include "gianfar.h"
-#define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0))
-
extern void gfar_start(struct net_device *dev);
extern int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
index 844c136e992..7dc5185aa2c 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -3034,7 +3034,7 @@ static int __init hp100_module_init(void)
goto out2;
#endif
#ifdef CONFIG_PCI
- err = pci_module_init(&hp100_pci_driver);
+ err = pci_register_driver(&hp100_pci_driver);
if (err && err != -ENODEV)
goto out3;
#endif
diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c
index 2194b567239..0e9ba3c3faf 100644
--- a/drivers/net/iseries_veth.c
+++ b/drivers/net/iseries_veth.c
@@ -1102,7 +1102,7 @@ static struct net_device * __init veth_probe_one(int vlan,
}
kobject_init(&port->kobject);
- port->kobject.parent = &dev->class_dev.kobj;
+ port->kobject.parent = &dev->dev.kobj;
port->kobject.ktype = &veth_port_ktype;
kobject_set_name(&port->kobject, "veth_port");
if (0 != kobject_add(&port->kobject))
diff --git a/drivers/net/ixgb/ixgb.h b/drivers/net/ixgb/ixgb.h
index f4aba4355b1..cf30a1059ce 100644
--- a/drivers/net/ixgb/ixgb.h
+++ b/drivers/net/ixgb/ixgb.h
@@ -61,9 +61,7 @@
#include <net/pkt_sched.h>
#include <linux/list.h>
#include <linux/reboot.h>
-#ifdef NETIF_F_TSO
#include <net/checksum.h>
-#endif
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c
index 82c044d6e08..d6628bd9590 100644
--- a/drivers/net/ixgb/ixgb_ethtool.c
+++ b/drivers/net/ixgb/ixgb_ethtool.c
@@ -82,10 +82,8 @@ static struct ixgb_stats ixgb_gstrings_stats[] = {
{"tx_restart_queue", IXGB_STAT(restart_queue) },
{"rx_long_length_errors", IXGB_STAT(stats.roc)},
{"rx_short_length_errors", IXGB_STAT(stats.ruc)},
-#ifdef NETIF_F_TSO
{"tx_tcp_seg_good", IXGB_STAT(stats.tsctc)},
{"tx_tcp_seg_failed", IXGB_STAT(stats.tsctfc)},
-#endif
{"rx_flow_control_xon", IXGB_STAT(stats.xonrxc)},
{"rx_flow_control_xoff", IXGB_STAT(stats.xoffrxc)},
{"tx_flow_control_xon", IXGB_STAT(stats.xontxc)},
@@ -240,7 +238,6 @@ ixgb_set_tx_csum(struct net_device *netdev, uint32_t data)
return 0;
}
-#ifdef NETIF_F_TSO
static int
ixgb_set_tso(struct net_device *netdev, uint32_t data)
{
@@ -250,7 +247,6 @@ ixgb_set_tso(struct net_device *netdev, uint32_t data)
netdev->features &= ~NETIF_F_TSO;
return 0;
}
-#endif /* NETIF_F_TSO */
static uint32_t
ixgb_get_msglevel(struct net_device *netdev)
@@ -722,10 +718,8 @@ static const struct ethtool_ops ixgb_ethtool_ops = {
.set_sg = ethtool_op_set_sg,
.get_msglevel = ixgb_get_msglevel,
.set_msglevel = ixgb_set_msglevel,
-#ifdef NETIF_F_TSO
.get_tso = ethtool_op_get_tso,
.set_tso = ixgb_set_tso,
-#endif
.get_strings = ixgb_get_strings,
.phys_id = ixgb_phys_id,
.get_stats_count = ixgb_get_stats_count,
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
index a083a918923..0c368288934 100644
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ixgb/ixgb_main.c
@@ -456,9 +456,7 @@ ixgb_probe(struct pci_dev *pdev,
NETIF_F_HW_VLAN_TX |
NETIF_F_HW_VLAN_RX |
NETIF_F_HW_VLAN_FILTER;
-#ifdef NETIF_F_TSO
netdev->features |= NETIF_F_TSO;
-#endif
#ifdef NETIF_F_LLTX
netdev->features |= NETIF_F_LLTX;
#endif
@@ -1176,7 +1174,6 @@ ixgb_watchdog(unsigned long data)
static int
ixgb_tso(struct ixgb_adapter *adapter, struct sk_buff *skb)
{
-#ifdef NETIF_F_TSO
struct ixgb_context_desc *context_desc;
unsigned int i;
uint8_t ipcss, ipcso, tucss, tucso, hdr_len;
@@ -1233,7 +1230,6 @@ ixgb_tso(struct ixgb_adapter *adapter, struct sk_buff *skb)
return 1;
}
-#endif
return 0;
}
@@ -1609,7 +1605,7 @@ ixgb_update_stats(struct ixgb_adapter *adapter)
struct pci_dev *pdev = adapter->pdev;
/* Prevent stats update while adapter is being reset */
- if (pdev->error_state && pdev->error_state != pci_channel_io_normal)
+ if (pci_channel_offline(pdev))
return;
if((netdev->flags & IFF_PROMISC) || (netdev->flags & IFF_ALLMULTI) ||
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index 25b559b5d5e..e67361e2bf5 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -27,8 +27,6 @@
#include "macb.h"
-#define to_net_dev(class) container_of(class, struct net_device, class_dev)
-
#define RX_BUFFER_SIZE 128
#define RX_RING_SIZE 512
#define RX_RING_BYTES (sizeof(struct dma_desc) * RX_RING_SIZE)
@@ -945,10 +943,10 @@ static int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
return ret;
}
-static ssize_t macb_mii_show(const struct class_device *cd, char *buf,
+static ssize_t macb_mii_show(const struct device *_dev, char *buf,
unsigned long addr)
{
- struct net_device *dev = to_net_dev(cd);
+ struct net_device *dev = to_net_dev(_dev);
struct macb *bp = netdev_priv(dev);
ssize_t ret = -EINVAL;
@@ -962,11 +960,13 @@ static ssize_t macb_mii_show(const struct class_device *cd, char *buf,
}
#define MII_ENTRY(name, addr) \
-static ssize_t show_##name(struct class_device *cd, char *buf) \
+static ssize_t show_##name(struct device *_dev, \
+ struct device_attribute *attr, \
+ char *buf) \
{ \
- return macb_mii_show(cd, buf, addr); \
+ return macb_mii_show(_dev, buf, addr); \
} \
-static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
+static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
MII_ENTRY(bmcr, MII_BMCR);
MII_ENTRY(bmsr, MII_BMSR);
@@ -977,13 +977,13 @@ MII_ENTRY(lpa, MII_LPA);
MII_ENTRY(expansion, MII_EXPANSION);
static struct attribute *macb_mii_attrs[] = {
- &class_device_attr_bmcr.attr,
- &class_device_attr_bmsr.attr,
- &class_device_attr_physid1.attr,
- &class_device_attr_physid2.attr,
- &class_device_attr_advertise.attr,
- &class_device_attr_lpa.attr,
- &class_device_attr_expansion.attr,
+ &dev_attr_bmcr.attr,
+ &dev_attr_bmsr.attr,
+ &dev_attr_physid1.attr,
+ &dev_attr_physid2.attr,
+ &dev_attr_advertise.attr,
+ &dev_attr_lpa.attr,
+ &dev_attr_expansion.attr,
NULL,
};
@@ -994,17 +994,17 @@ static struct attribute_group macb_mii_group = {
static void macb_unregister_sysfs(struct net_device *net)
{
- struct class_device *class_dev = &net->class_dev;
+ struct device *_dev = &net->dev;
- sysfs_remove_group(&class_dev->kobj, &macb_mii_group);
+ sysfs_remove_group(&_dev->kobj, &macb_mii_group);
}
static int macb_register_sysfs(struct net_device *net)
{
- struct class_device *class_dev = &net->class_dev;
+ struct device *_dev = &net->dev;
int ret;
- ret = sysfs_create_group(&class_dev->kobj, &macb_mii_group);
+ ret = sysfs_create_group(&_dev->kobj, &macb_mii_group);
if (ret)
printk(KERN_WARNING
"%s: sysfs mii attribute registration failed: %d\n",
@@ -1046,6 +1046,14 @@ static int __devinit macb_probe(struct platform_device *pdev)
spin_lock_init(&bp->lock);
+#if defined(CONFIG_ARCH_AT91)
+ bp->pclk = clk_get(&pdev->dev, "macb_clk");
+ if (IS_ERR(bp->pclk)) {
+ dev_err(&pdev->dev, "failed to get macb_clk\n");
+ goto err_out_free_dev;
+ }
+ clk_enable(bp->pclk);
+#else
bp->pclk = clk_get(&pdev->dev, "pclk");
if (IS_ERR(bp->pclk)) {
dev_err(&pdev->dev, "failed to get pclk\n");
@@ -1059,6 +1067,7 @@ static int __devinit macb_probe(struct platform_device *pdev)
clk_enable(bp->pclk);
clk_enable(bp->hclk);
+#endif
bp->regs = ioremap(regs->start, regs->end - regs->start + 1);
if (!bp->regs) {
@@ -1119,9 +1128,17 @@ static int __devinit macb_probe(struct platform_device *pdev)
pdata = pdev->dev.platform_data;
if (pdata && pdata->is_rmii)
+#if defined(CONFIG_ARCH_AT91)
+ macb_writel(bp, USRIO, (MACB_BIT(RMII) | MACB_BIT(CLKEN)) );
+#else
macb_writel(bp, USRIO, 0);
+#endif
else
+#if defined(CONFIG_ARCH_AT91)
+ macb_writel(bp, USRIO, MACB_BIT(CLKEN));
+#else
macb_writel(bp, USRIO, MACB_BIT(MII));
+#endif
bp->tx_pending = DEF_TX_RING_PENDING;
@@ -1148,9 +1165,11 @@ err_out_free_irq:
err_out_iounmap:
iounmap(bp->regs);
err_out_disable_clocks:
+#ifndef CONFIG_ARCH_AT91
clk_disable(bp->hclk);
- clk_disable(bp->pclk);
clk_put(bp->hclk);
+#endif
+ clk_disable(bp->pclk);
err_out_put_pclk:
clk_put(bp->pclk);
err_out_free_dev:
@@ -1173,9 +1192,11 @@ static int __devexit macb_remove(struct platform_device *pdev)
unregister_netdev(dev);
free_irq(dev->irq, dev);
iounmap(bp->regs);
+#ifndef CONFIG_ARCH_AT91
clk_disable(bp->hclk);
- clk_disable(bp->pclk);
clk_put(bp->hclk);
+#endif
+ clk_disable(bp->pclk);
clk_put(bp->pclk);
free_netdev(dev);
platform_set_drvdata(pdev, NULL);
diff --git a/drivers/net/macb.h b/drivers/net/macb.h
index 27bf0ae0f0b..b3bb2182edd 100644
--- a/drivers/net/macb.h
+++ b/drivers/net/macb.h
@@ -200,7 +200,7 @@
#define MACB_SOF_OFFSET 30
#define MACB_SOF_SIZE 2
-/* Bitfields in USRIO */
+/* Bitfields in USRIO (AVR32) */
#define MACB_MII_OFFSET 0
#define MACB_MII_SIZE 1
#define MACB_EAM_OFFSET 1
@@ -210,6 +210,12 @@
#define MACB_TX_PAUSE_ZERO_OFFSET 3
#define MACB_TX_PAUSE_ZERO_SIZE 1
+/* Bitfields in USRIO (AT91) */
+#define MACB_RMII_OFFSET 0
+#define MACB_RMII_SIZE 1
+#define MACB_CLKEN_OFFSET 1
+#define MACB_CLKEN_SIZE 1
+
/* Bitfields in WOL */
#define MACB_IP_OFFSET 0
#define MACB_IP_SIZE 16
diff --git a/drivers/net/mace.c b/drivers/net/mace.c
index 2907cfb12ad..9ec24f0d5d6 100644
--- a/drivers/net/mace.c
+++ b/drivers/net/mace.c
@@ -15,6 +15,7 @@
#include <linux/init.h>
#include <linux/crc32.h>
#include <linux/spinlock.h>
+#include <linux/bitrev.h>
#include <asm/prom.h>
#include <asm/dbdma.h>
#include <asm/io.h>
@@ -74,7 +75,6 @@ struct mace_data {
#define PRIV_BYTES (sizeof(struct mace_data) \
+ (N_RX_RING + NCMDS_TX * N_TX_RING + 3) * sizeof(struct dbdma_cmd))
-static int bitrev(int);
static int mace_open(struct net_device *dev);
static int mace_close(struct net_device *dev);
static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev);
@@ -96,18 +96,6 @@ static void __mace_set_address(struct net_device *dev, void *addr);
*/
static unsigned char *dummy_buf;
-/* Bit-reverse one byte of an ethernet hardware address. */
-static inline int
-bitrev(int b)
-{
- int d = 0, i;
-
- for (i = 0; i < 8; ++i, b >>= 1)
- d = (d << 1) | (b & 1);
- return d;
-}
-
-
static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_id *match)
{
struct device_node *mace = macio_get_of_node(mdev);
@@ -173,7 +161,7 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i
rev = addr[0] == 0 && addr[1] == 0xA0;
for (j = 0; j < 6; ++j) {
- dev->dev_addr[j] = rev? bitrev(addr[j]): addr[j];
+ dev->dev_addr[j] = rev ? bitrev8(addr[j]): addr[j];
}
mp->chipid = (in_8(&mp->mace->chipid_hi) << 8) |
in_8(&mp->mace->chipid_lo);
diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c
index 464e4a6f3d5..5d541e87304 100644
--- a/drivers/net/macmace.c
+++ b/drivers/net/macmace.c
@@ -22,6 +22,7 @@
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/crc32.h>
+#include <linux/bitrev.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/irq.h>
@@ -81,19 +82,6 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id);
static irqreturn_t mace_dma_intr(int irq, void *dev_id);
static void mace_tx_timeout(struct net_device *dev);
-/* Bit-reverse one byte of an ethernet hardware address. */
-
-static int bitrev(int b)
-{
- int d = 0, i;
-
- for (i = 0; i < 8; ++i, b >>= 1) {
- d = (d << 1) | (b & 1);
- }
-
- return d;
-}
-
/*
* Load a receive DMA channel with a base address and ring length
*/
@@ -219,12 +207,12 @@ struct net_device *mace_probe(int unit)
addr = (void *)MACE_PROM;
for (j = 0; j < 6; ++j) {
- u8 v=bitrev(addr[j<<4]);
+ u8 v = bitrev8(addr[j<<4]);
checksum ^= v;
dev->dev_addr[j] = v;
}
for (; j < 8; ++j) {
- checksum ^= bitrev(addr[j<<4]);
+ checksum ^= bitrev8(addr[j<<4]);
}
if (checksum != 0xFF) {
diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c
index 393d995f191..8ca57a0a4c1 100644
--- a/drivers/net/macsonic.c
+++ b/drivers/net/macsonic.c
@@ -49,6 +49,7 @@
#include <linux/skbuff.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
+#include <linux/bitrev.h>
#include <asm/bootinfo.h>
#include <asm/system.h>
@@ -121,16 +122,12 @@ enum macsonic_type {
* For reversing the PROM address
*/
-static unsigned char nibbletab[] = {0, 8, 4, 12, 2, 10, 6, 14,
- 1, 9, 5, 13, 3, 11, 7, 15};
-
static inline void bit_reverse_addr(unsigned char addr[6])
{
int i;
for(i = 0; i < 6; i++)
- addr[i] = ((nibbletab[addr[i] & 0xf] << 4) |
- nibbletab[(addr[i] >> 4) &0xf]);
+ addr[i] = bitrev8(addr[i]);
}
int __init macsonic_init(struct net_device* dev)
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index b3bf8642273..d98e53efa2e 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -2780,7 +2780,6 @@ static const struct ethtool_ops mv643xx_ethtool_ops = {
.get_link = mv643xx_eth_get_link,
.get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
- .get_strings = mv643xx_get_strings,
.get_stats_count = mv643xx_get_stats_count,
.get_ethtool_stats = mv643xx_get_ethtool_stats,
.get_strings = mv643xx_get_strings,
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index 61cbd4a6044..030924fb1ab 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -1412,10 +1412,8 @@ static const struct ethtool_ops myri10ge_ethtool_ops = {
.set_tx_csum = ethtool_op_set_tx_hw_csum,
.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,
-#endif
.get_strings = myri10ge_get_strings,
.get_stats_count = myri10ge_get_stats_count,
.get_ethtool_stats = myri10ge_get_ethtool_stats,
@@ -1975,13 +1973,11 @@ again:
mss = 0;
max_segments = MXGEFW_MAX_SEND_DESC;
-#ifdef NETIF_F_TSO
if (skb->len > (dev->mtu + ETH_HLEN)) {
mss = skb_shinfo(skb)->gso_size;
if (mss != 0)
max_segments = MYRI10GE_MAX_SEND_DESC_TSO;
}
-#endif /*NETIF_F_TSO */
if ((unlikely(avail < max_segments))) {
/* we are out of transmit resources */
@@ -2013,7 +2009,6 @@ again:
cum_len = 0;
-#ifdef NETIF_F_TSO
if (mss) { /* TSO */
/* this removes any CKSUM flag from before */
flags = (MXGEFW_FLAGS_TSO_HDR | MXGEFW_FLAGS_FIRST);
@@ -2029,7 +2024,6 @@ again:
* the checksum by parsing the header. */
pseudo_hdr_offset = mss;
} else
-#endif /*NETIF_F_TSO */
/* Mark small packets, and pad out tiny packets */
if (skb->len <= MXGEFW_SEND_SMALL_SIZE) {
flags |= MXGEFW_FLAGS_SMALL;
@@ -2097,7 +2091,6 @@ again:
seglen = len;
flags_next = flags & ~MXGEFW_FLAGS_FIRST;
cum_len_next = cum_len + seglen;
-#ifdef NETIF_F_TSO
if (mss) { /* TSO */
(req - rdma_count)->rdma_count = rdma_count + 1;
@@ -2124,7 +2117,6 @@ again:
(small * MXGEFW_FLAGS_SMALL);
}
}
-#endif /* NETIF_F_TSO */
req->addr_high = high_swapped;
req->addr_low = htonl(low);
req->pseudo_hdr_offset = htons(pseudo_hdr_offset);
@@ -2161,14 +2153,12 @@ again:
}
(req - rdma_count)->rdma_count = rdma_count;
-#ifdef NETIF_F_TSO
if (mss)
do {
req--;
req->flags |= MXGEFW_FLAGS_TSO_LAST;
} while (!(req->flags & (MXGEFW_FLAGS_TSO_CHOP |
MXGEFW_FLAGS_FIRST)));
-#endif
idx = ((count - 1) + tx->req) & tx->mask;
tx->info[idx].last = 1;
if (tx->wc_fifo == NULL)
diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h
index e8598b80922..e021a30abd8 100644
--- a/drivers/net/netxen/netxen_nic.h
+++ b/drivers/net/netxen/netxen_nic.h
@@ -63,11 +63,14 @@
#include "netxen_nic_hw.h"
-#define NETXEN_NIC_BUILD_NO "2"
#define _NETXEN_NIC_LINUX_MAJOR 3
#define _NETXEN_NIC_LINUX_MINOR 3
#define _NETXEN_NIC_LINUX_SUBVERSION 3
-#define NETXEN_NIC_LINUX_VERSIONID "3.3.3" "-" NETXEN_NIC_BUILD_NO
+#define NETXEN_NIC_LINUX_VERSIONID "3.3.3"
+
+#define NUM_FLASH_SECTORS (64)
+#define FLASH_SECTOR_SIZE (64 * 1024)
+#define FLASH_TOTAL_SIZE (NUM_FLASH_SECTORS * FLASH_SECTOR_SIZE)
#define RCV_DESC_RINGSIZE \
(sizeof(struct rcv_desc) * adapter->max_rx_desc_count)
@@ -85,6 +88,7 @@
#define NETXEN_RCV_PRODUCER_OFFSET 0
#define NETXEN_RCV_PEG_DB_ID 2
#define NETXEN_HOST_DUMMY_DMA_SIZE 1024
+#define FLASH_SUCCESS 0
#define ADDR_IN_WINDOW1(off) \
((off > NETXEN_CRB_PCIX_HOST2) && (off < NETXEN_CRB_MAX)) ? 1 : 0
@@ -1028,6 +1032,16 @@ void netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val);
void netxen_load_firmware(struct netxen_adapter *adapter);
int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose);
int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp);
+int netxen_rom_fast_read_words(struct netxen_adapter *adapter, int addr,
+ u8 *bytes, size_t size);
+int netxen_rom_fast_write_words(struct netxen_adapter *adapter, int addr,
+ u8 *bytes, size_t size);
+int netxen_flash_unlock(struct netxen_adapter *adapter);
+int netxen_backup_crbinit(struct netxen_adapter *adapter);
+int netxen_flash_erase_secondary(struct netxen_adapter *adapter);
+int netxen_flash_erase_primary(struct netxen_adapter *adapter);
+void netxen_halt_pegs(struct netxen_adapter *adapter);
+
int netxen_rom_fast_write(struct netxen_adapter *adapter, int addr, int data);
int netxen_rom_se(struct netxen_adapter *adapter, int addr);
int netxen_do_rom_se(struct netxen_adapter *adapter, int addr);
diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c
index c381d77a733..6252e9a8727 100644
--- a/drivers/net/netxen/netxen_nic_ethtool.c
+++ b/drivers/net/netxen/netxen_nic_ethtool.c
@@ -32,6 +32,7 @@
*/
#include <linux/types.h>
+#include <linux/delay.h>
#include <asm/uaccess.h>
#include <linux/pci.h>
#include <asm/io.h>
@@ -94,17 +95,7 @@ static const char netxen_nic_gstrings_test[][ETH_GSTRING_LEN] = {
static int netxen_nic_get_eeprom_len(struct net_device *dev)
{
- struct netxen_port *port = netdev_priv(dev);
- struct netxen_adapter *adapter = port->adapter;
- int n;
-
- if ((netxen_rom_fast_read(adapter, 0, &n) == 0)
- && (n & NETXEN_ROM_ROUNDUP)) {
- n &= ~NETXEN_ROM_ROUNDUP;
- if (n < NETXEN_MAX_EEPROM_LEN)
- return n;
- }
- return 0;
+ return FLASH_TOTAL_SIZE;
}
static void
@@ -411,7 +402,7 @@ netxen_nic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
wol->wolopts = 0;
}
-static u32 netxen_nic_get_link(struct net_device *dev)
+static u32 netxen_nic_test_link(struct net_device *dev)
{
struct netxen_port *port = netdev_priv(dev);
struct netxen_adapter *adapter = port->adapter;
@@ -440,18 +431,93 @@ netxen_nic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
struct netxen_port *port = netdev_priv(dev);
struct netxen_adapter *adapter = port->adapter;
int offset;
+ int ret;
if (eeprom->len == 0)
return -EINVAL;
eeprom->magic = (port->pdev)->vendor | ((port->pdev)->device << 16);
- for (offset = 0; offset < eeprom->len; offset++)
- if (netxen_rom_fast_read
- (adapter, (8 * offset) + 8, (int *)eeprom->data) == -1)
- return -EIO;
+ offset = eeprom->offset;
+
+ ret = netxen_rom_fast_read_words(adapter, offset, bytes,
+ eeprom->len);
+ if (ret < 0)
+ return ret;
+
return 0;
}
+static int
+netxen_nic_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
+ u8 * bytes)
+{
+ struct netxen_port *port = netdev_priv(dev);
+ struct netxen_adapter *adapter = port->adapter;
+ int offset = eeprom->offset;
+ static int flash_start;
+ static int ready_to_flash;
+ int ret;
+
+ if (flash_start == 0) {
+ netxen_halt_pegs(adapter);
+ ret = netxen_flash_unlock(adapter);
+ if (ret < 0) {
+ printk(KERN_ERR "%s: Flash unlock failed.\n",
+ netxen_nic_driver_name);
+ return ret;
+ }
+ printk(KERN_INFO "%s: flash unlocked. \n",
+ netxen_nic_driver_name);
+ ret = netxen_flash_erase_secondary(adapter);
+ if (ret != FLASH_SUCCESS) {
+ printk(KERN_ERR "%s: Flash erase failed.\n",
+ netxen_nic_driver_name);
+ return ret;
+ }
+ printk(KERN_INFO "%s: secondary flash erased successfully.\n",
+ netxen_nic_driver_name);
+ flash_start = 1;
+ return 0;
+ }
+
+ if (offset == BOOTLD_START) {
+ ret = netxen_flash_erase_primary(adapter);
+ if (ret != FLASH_SUCCESS) {
+ printk(KERN_ERR "%s: Flash erase failed.\n",
+ netxen_nic_driver_name);
+ return ret;
+ }
+
+ ret = netxen_rom_se(adapter, USER_START);
+ if (ret != FLASH_SUCCESS)
+ return ret;
+ ret = netxen_rom_se(adapter, FIXED_START);
+ if (ret != FLASH_SUCCESS)
+ return ret;
+
+ printk(KERN_INFO "%s: primary flash erased successfully\n",
+ netxen_nic_driver_name);
+
+ ret = netxen_backup_crbinit(adapter);
+ if (ret != FLASH_SUCCESS) {
+ printk(KERN_ERR "%s: CRBinit backup failed.\n",
+ netxen_nic_driver_name);
+ return ret;
+ }
+ printk(KERN_INFO "%s: CRBinit backup done.\n",
+ netxen_nic_driver_name);
+ ready_to_flash = 1;
+ }
+
+ if (!ready_to_flash) {
+ printk(KERN_ERR "%s: Invalid write sequence, returning...\n",
+ netxen_nic_driver_name);
+ return -EINVAL;
+ }
+
+ return netxen_rom_fast_write_words(adapter, offset, bytes, eeprom->len);
+}
+
static void
netxen_nic_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring)
{
@@ -647,7 +713,7 @@ netxen_nic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
{
if (eth_test->flags == ETH_TEST_FL_OFFLINE) { /* offline tests */
/* link test */
- if (!(data[4] = (u64) netxen_nic_get_link(dev)))
+ if (!(data[4] = (u64) netxen_nic_test_link(dev)))
eth_test->flags |= ETH_TEST_FL_FAILED;
if (netif_running(dev))
@@ -662,7 +728,7 @@ netxen_nic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
dev->open(dev);
} else { /* online tests */
/* link test */
- if (!(data[4] = (u64) netxen_nic_get_link(dev)))
+ if (!(data[4] = (u64) netxen_nic_test_link(dev)))
eth_test->flags |= ETH_TEST_FL_FAILED;
/* other tests pass by default */
@@ -718,9 +784,10 @@ struct ethtool_ops netxen_nic_ethtool_ops = {
.get_regs_len = netxen_nic_get_regs_len,
.get_regs = netxen_nic_get_regs,
.get_wol = netxen_nic_get_wol,
- .get_link = netxen_nic_get_link,
+ .get_link = ethtool_op_get_link,
.get_eeprom_len = netxen_nic_get_eeprom_len,
.get_eeprom = netxen_nic_get_eeprom,
+ .set_eeprom = netxen_nic_set_eeprom,
.get_ringparam = netxen_nic_get_ringparam,
.get_pauseparam = netxen_nic_get_pauseparam,
.set_pauseparam = netxen_nic_set_pauseparam,
diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c
index f263232f499..7195af3e8f3 100644
--- a/drivers/net/netxen/netxen_nic_hw.c
+++ b/drivers/net/netxen/netxen_nic_hw.c
@@ -420,6 +420,7 @@ static int netxen_get_flash_block(struct netxen_adapter *adapter, int base,
for (i = 0; i < size / sizeof(u32); i++) {
if (netxen_rom_fast_read(adapter, addr, ptr32) == -1)
return -1;
+ *ptr32 = cpu_to_le32(*ptr32);
ptr32++;
addr += sizeof(u32);
}
@@ -428,6 +429,7 @@ static int netxen_get_flash_block(struct netxen_adapter *adapter, int base,
if (netxen_rom_fast_read(adapter, addr, &local) == -1)
return -1;
+ local = cpu_to_le32(local);
memcpy(ptr32, &local, (char *)buf + size - (char *)ptr32);
}
diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c
index 973af96337a..2f324366784 100644
--- a/drivers/net/netxen/netxen_nic_init.c
+++ b/drivers/net/netxen/netxen_nic_init.c
@@ -110,6 +110,7 @@ static void crb_addr_transform_setup(void)
crb_addr_transform(CAM);
crb_addr_transform(C2C1);
crb_addr_transform(C2C0);
+ crb_addr_transform(SMB);
}
int netxen_init_firmware(struct netxen_adapter *adapter)
@@ -276,6 +277,7 @@ unsigned long netxen_decode_crb_addr(unsigned long addr)
static long rom_max_timeout = 10000;
static long rom_lock_timeout = 1000000;
+static long rom_write_timeout = 700;
static inline int rom_lock(struct netxen_adapter *adapter)
{
@@ -404,7 +406,7 @@ do_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp)
{
netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ADDRESS, addr);
netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 3);
- udelay(100); /* prevent bursting on CRB */
+ udelay(70); /* prevent bursting on CRB */
netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_INSTR_OPCODE, 0xb);
if (netxen_wait_rom_done(adapter)) {
@@ -413,13 +415,46 @@ do_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp)
}
/* reset abyte_cnt and dummy_byte_cnt */
netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 0);
- udelay(100); /* prevent bursting on CRB */
+ udelay(70); /* prevent bursting on CRB */
netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
*valp = netxen_nic_reg_read(adapter, NETXEN_ROMUSB_ROM_RDATA);
return 0;
}
+static inline int
+do_rom_fast_read_words(struct netxen_adapter *adapter, int addr,
+ u8 *bytes, size_t size)
+{
+ int addridx;
+ int ret = 0;
+
+ for (addridx = addr; addridx < (addr + size); addridx += 4) {
+ ret = do_rom_fast_read(adapter, addridx, (int *)bytes);
+ if (ret != 0)
+ break;
+ bytes += 4;
+ }
+
+ return ret;
+}
+
+int
+netxen_rom_fast_read_words(struct netxen_adapter *adapter, int addr,
+ u8 *bytes, size_t size)
+{
+ int ret;
+
+ ret = rom_lock(adapter);
+ if (ret < 0)
+ return ret;
+
+ ret = do_rom_fast_read_words(adapter, addr, bytes, size);
+
+ netxen_rom_unlock(adapter);
+ return ret;
+}
+
int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp)
{
int ret;
@@ -443,6 +478,152 @@ int netxen_rom_fast_write(struct netxen_adapter *adapter, int addr, int data)
netxen_rom_unlock(adapter);
return ret;
}
+
+static inline int do_rom_fast_write_words(struct netxen_adapter *adapter,
+ int addr, u8 *bytes, size_t size)
+{
+ int addridx = addr;
+ int ret = 0;
+
+ while (addridx < (addr + size)) {
+ int last_attempt = 0;
+ int timeout = 0;
+ int data;
+
+ data = *(u32*)bytes;
+
+ ret = do_rom_fast_write(adapter, addridx, data);
+ if (ret < 0)
+ return ret;
+
+ while(1) {
+ int data1;
+
+ do_rom_fast_read(adapter, addridx, &data1);
+ if (data1 == data)
+ break;
+
+ if (timeout++ >= rom_write_timeout) {
+ if (last_attempt++ < 4) {
+ ret = do_rom_fast_write(adapter,
+ addridx, data);
+ if (ret < 0)
+ return ret;
+ }
+ else {
+ printk(KERN_INFO "Data write did not "
+ "succeed at address 0x%x\n", addridx);
+ break;
+ }
+ }
+ }
+
+ bytes += 4;
+ addridx += 4;
+ }
+
+ return ret;
+}
+
+int netxen_rom_fast_write_words(struct netxen_adapter *adapter, int addr,
+ u8 *bytes, size_t size)
+{
+ int ret = 0;
+
+ ret = rom_lock(adapter);
+ if (ret < 0)
+ return ret;
+
+ ret = do_rom_fast_write_words(adapter, addr, bytes, size);
+ netxen_rom_unlock(adapter);
+
+ return ret;
+}
+
+int netxen_rom_wrsr(struct netxen_adapter *adapter, int data)
+{
+ int ret;
+
+ ret = netxen_rom_wren(adapter);
+ if (ret < 0)
+ return ret;
+
+ netxen_crb_writelit_adapter(adapter, NETXEN_ROMUSB_ROM_WDATA, data);
+ netxen_crb_writelit_adapter(adapter,
+ NETXEN_ROMUSB_ROM_INSTR_OPCODE, 0x1);
+
+ ret = netxen_wait_rom_done(adapter);
+ if (ret < 0)
+ return ret;
+
+ return netxen_rom_wip_poll(adapter);
+}
+
+int netxen_rom_rdsr(struct netxen_adapter *adapter)
+{
+ int ret;
+
+ ret = rom_lock(adapter);
+ if (ret < 0)
+ return ret;
+
+ ret = netxen_do_rom_rdsr(adapter);
+ netxen_rom_unlock(adapter);
+ return ret;
+}
+
+int netxen_backup_crbinit(struct netxen_adapter *adapter)
+{
+ int ret = FLASH_SUCCESS;
+ int val;
+ char *buffer = kmalloc(FLASH_SECTOR_SIZE, GFP_KERNEL);
+
+ if (!buffer)
+ return -ENOMEM;
+ /* unlock sector 63 */
+ val = netxen_rom_rdsr(adapter);
+ val = val & 0xe3;
+ ret = netxen_rom_wrsr(adapter, val);
+ if (ret != FLASH_SUCCESS)
+ goto out_kfree;
+
+ ret = netxen_rom_wip_poll(adapter);
+ if (ret != FLASH_SUCCESS)
+ goto out_kfree;
+
+ /* copy sector 0 to sector 63 */
+ ret = netxen_rom_fast_read_words(adapter, CRBINIT_START,
+ buffer, FLASH_SECTOR_SIZE);
+ if (ret != FLASH_SUCCESS)
+ goto out_kfree;
+
+ ret = netxen_rom_fast_write_words(adapter, FIXED_START,
+ buffer, FLASH_SECTOR_SIZE);
+ if (ret != FLASH_SUCCESS)
+ goto out_kfree;
+
+ /* lock sector 63 */
+ val = netxen_rom_rdsr(adapter);
+ if (!(val & 0x8)) {
+ val |= (0x1 << 2);
+ /* lock sector 63 */
+ if (netxen_rom_wrsr(adapter, val) == 0) {
+ ret = netxen_rom_wip_poll(adapter);
+ if (ret != FLASH_SUCCESS)
+ goto out_kfree;
+
+ /* lock SR writes */
+ ret = netxen_rom_wip_poll(adapter);
+ if (ret != FLASH_SUCCESS)
+ goto out_kfree;
+ }
+ }
+
+out_kfree:
+ kfree(buffer);
+ return ret;
+}
+
int netxen_do_rom_se(struct netxen_adapter *adapter, int addr)
{
netxen_rom_wren(adapter);
@@ -457,6 +638,27 @@ int netxen_do_rom_se(struct netxen_adapter *adapter, int addr)
return netxen_rom_wip_poll(adapter);
}
+void check_erased_flash(struct netxen_adapter *adapter, int addr)
+{
+ int i;
+ int val;
+ int count = 0, erased_errors = 0;
+ int range;
+
+ range = (addr == USER_START) ? FIXED_START : addr + FLASH_SECTOR_SIZE;
+
+ for (i = addr; i < range; i += 4) {
+ netxen_rom_fast_read(adapter, i, &val);
+ if (val != 0xffffffff)
+ erased_errors++;
+ count++;
+ }
+
+ if (erased_errors)
+ printk(KERN_INFO "0x%x out of 0x%x words fail to be erased "
+ "for sector address: %x\n", erased_errors, count, addr);
+}
+
int netxen_rom_se(struct netxen_adapter *adapter, int addr)
{
int ret = 0;
@@ -465,6 +667,76 @@ int netxen_rom_se(struct netxen_adapter *adapter, int addr)
}
ret = netxen_do_rom_se(adapter, addr);
netxen_rom_unlock(adapter);
+ msleep(30);
+ check_erased_flash(adapter, addr);
+
+ return ret;
+}
+
+int
+netxen_flash_erase_sections(struct netxen_adapter *adapter, int start, int end)
+{
+ int ret = FLASH_SUCCESS;
+ int i;
+
+ for (i = start; i < end; i++) {
+ ret = netxen_rom_se(adapter, i * FLASH_SECTOR_SIZE);
+ if (ret)
+ break;
+ ret = netxen_rom_wip_poll(adapter);
+ if (ret < 0)
+ return ret;
+ }
+
+ return ret;
+}
+
+int
+netxen_flash_erase_secondary(struct netxen_adapter *adapter)
+{
+ int ret = FLASH_SUCCESS;
+ int start, end;
+
+ start = SECONDARY_START / FLASH_SECTOR_SIZE;
+ end = USER_START / FLASH_SECTOR_SIZE;
+ ret = netxen_flash_erase_sections(adapter, start, end);
+
+ return ret;
+}
+
+int
+netxen_flash_erase_primary(struct netxen_adapter *adapter)
+{
+ int ret = FLASH_SUCCESS;
+ int start, end;
+
+ start = PRIMARY_START / FLASH_SECTOR_SIZE;
+ end = SECONDARY_START / FLASH_SECTOR_SIZE;
+ ret = netxen_flash_erase_sections(adapter, start, end);
+
+ return ret;
+}
+
+void netxen_halt_pegs(struct netxen_adapter *adapter)
+{
+ netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_0 + 0x3c, 1);
+ netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_1 + 0x3c, 1);
+ netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_2 + 0x3c, 1);
+ netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_3 + 0x3c, 1);
+}
+
+int netxen_flash_unlock(struct netxen_adapter *adapter)
+{
+ int ret = 0;
+
+ ret = netxen_rom_wrsr(adapter, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = netxen_rom_wren(adapter);
+ if (ret < 0)
+ return ret;
+
return ret;
}
@@ -543,9 +815,13 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose)
}
for (i = 0; i < n; i++) {
- off =
- netxen_decode_crb_addr((unsigned long)buf[i].addr) +
- NETXEN_PCI_CRBSPACE;
+ off = netxen_decode_crb_addr((unsigned long)buf[i].addr);
+ if (off == NETXEN_ADDR_ERROR) {
+ printk(KERN_ERR"CRB init value out of range %lx\n",
+ buf[i].addr);
+ continue;
+ }
+ off += NETXEN_PCI_CRBSPACE;
/* skipping cold reboot MAGIC */
if (off == NETXEN_CAM_RAM(0x1fc))
continue;
@@ -662,6 +938,7 @@ void netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val)
int loops = 0;
if (!pegtune_val) {
+ val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE));
while (val != PHAN_INITIALIZE_COMPLETE && loops < 200000) {
udelay(100);
schedule();
@@ -977,7 +1254,7 @@ int netxen_process_cmd_ring(unsigned long data)
* the netdev which is associated with that device.
*/
- consumer = *(adapter->cmd_consumer);
+ consumer = le32_to_cpu(*(adapter->cmd_consumer));
if (last_consumer == consumer) { /* Ring is empty */
DPRINTK(INFO, "last_consumer %d == consumer %d\n",
last_consumer, consumer);
@@ -1071,7 +1348,7 @@ int netxen_process_cmd_ring(unsigned long data)
if (adapter->last_cmd_consumer == consumer &&
(((adapter->cmd_producer + 1) %
adapter->max_tx_desc_count) == adapter->last_cmd_consumer)) {
- consumer = *(adapter->cmd_consumer);
+ consumer = le32_to_cpu(*(adapter->cmd_consumer));
}
done = (adapter->last_cmd_consumer == consumer);
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c
index 69c1b9d23a1..c2da7ec0248 100644
--- a/drivers/net/netxen/netxen_nic_main.c
+++ b/drivers/net/netxen/netxen_nic_main.c
@@ -434,12 +434,13 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
adapter->port_count++;
adapter->port[i] = port;
}
-
+#ifndef CONFIG_PPC64
writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE));
netxen_pinit_from_rom(adapter, 0);
udelay(500);
netxen_load_firmware(adapter);
netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
+#endif
/*
* delay a while to ensure that the Pegs are up & running.
* Otherwise, we might see some flaky behaviour.
diff --git a/drivers/net/netxen/netxen_nic_niu.c b/drivers/net/netxen/netxen_nic_niu.c
index 40d7003a371..d5d95074e56 100644
--- a/drivers/net/netxen/netxen_nic_niu.c
+++ b/drivers/net/netxen/netxen_nic_niu.c
@@ -458,7 +458,7 @@ int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port)
int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port)
{
- long reg = 0, ret = 0;
+ u32 reg = 0, ret = 0;
if (adapter->ahw.boardcfg.board_type == NETXEN_BRDTYPE_P2_SB31_10G_IMEZ) {
netxen_crb_writelit_adapter(adapter,
diff --git a/drivers/net/oaknet.c b/drivers/net/oaknet.c
deleted file mode 100644
index 702e3e95612..00000000000
--- a/drivers/net/oaknet.c
+++ /dev/null
@@ -1,666 +0,0 @@
-/*
- *
- * Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
- *
- * Module name: oaknet.c
- *
- * Description:
- * Driver for the National Semiconductor DP83902AV Ethernet controller
- * on-board the IBM PowerPC "Oak" evaluation board. Adapted from the
- * various other 8390 drivers written by Donald Becker and Paul Gortmaker.
- *
- * Additional inspiration from the "tcd8390.c" driver from TiVo, Inc.
- * and "enetLib.c" from IBM.
- *
- */
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/init.h>
-#include <linux/jiffies.h>
-
-#include <asm/board.h>
-#include <asm/io.h>
-
-#include "8390.h"
-
-
-/* Preprocessor Defines */
-
-#if !defined(TRUE) || TRUE != 1
-#define TRUE 1
-#endif
-
-#if !defined(FALSE) || FALSE != 0
-#define FALSE 0
-#endif
-
-#define OAKNET_START_PG 0x20 /* First page of TX buffer */
-#define OAKNET_STOP_PG 0x40 /* Last pagge +1 of RX ring */
-
-#define OAKNET_WAIT (2 * HZ / 100) /* 20 ms */
-
-/* Experimenting with some fixes for a broken driver... */
-
-#define OAKNET_DISINT
-#define OAKNET_HEADCHECK
-#define OAKNET_RWFIX
-
-
-/* Global Variables */
-
-static const char *name = "National DP83902AV";
-
-static struct net_device *oaknet_devs;
-
-
-/* Function Prototypes */
-
-static int oaknet_open(struct net_device *dev);
-static int oaknet_close(struct net_device *dev);
-
-static void oaknet_reset_8390(struct net_device *dev);
-static void oaknet_get_8390_hdr(struct net_device *dev,
- struct e8390_pkt_hdr *hdr, int ring_page);
-static void oaknet_block_input(struct net_device *dev, int count,
- struct sk_buff *skb, int ring_offset);
-static void oaknet_block_output(struct net_device *dev, int count,
- const unsigned char *buf, int start_page);
-
-static void oaknet_dma_error(struct net_device *dev, const char *name);
-
-
-/*
- * int oaknet_init()
- *
- * Description:
- * This routine performs all the necessary platform-specific initiali-
- * zation and set-up for the IBM "Oak" evaluation board's National
- * Semiconductor DP83902AV "ST-NIC" Ethernet controller.
- *
- * Input(s):
- * N/A
- *
- * Output(s):
- * N/A
- *
- * Returns:
- * 0 if OK, otherwise system error number on error.
- *
- */
-static int __init oaknet_init(void)
-{
- register int i;
- int reg0, regd;
- int ret = -ENOMEM;
- struct net_device *dev;
-#if 0
- unsigned long ioaddr = OAKNET_IO_BASE;
-#else
- unsigned long ioaddr = ioremap(OAKNET_IO_BASE, OAKNET_IO_SIZE);
-#endif
- bd_t *bip = (bd_t *)__res;
-
- if (!ioaddr)
- return -ENOMEM;
-
- dev = alloc_ei_netdev();
- if (!dev)
- goto out_unmap;
-
- ret = -EBUSY;
- if (!request_region(OAKNET_IO_BASE, OAKNET_IO_SIZE, name))
- goto out_dev;
-
- /* Quick register check to see if the device is really there. */
-
- ret = -ENODEV;
- if ((reg0 = ei_ibp(ioaddr)) == 0xFF)
- goto out_region;
-
- /*
- * That worked. Now a more thorough check, using the multicast
- * address registers, that the device is definitely out there
- * and semi-functional.
- */
-
- ei_obp(E8390_NODMA + E8390_PAGE1 + E8390_STOP, ioaddr + E8390_CMD);
- regd = ei_ibp(ioaddr + 0x0D);
- ei_obp(0xFF, ioaddr + 0x0D);
- ei_obp(E8390_NODMA + E8390_PAGE0, ioaddr + E8390_CMD);
- ei_ibp(ioaddr + EN0_COUNTER0);
-
- /* It's no good. Fix things back up and leave. */
-
- ret = -ENODEV;
- if (ei_ibp(ioaddr + EN0_COUNTER0) != 0) {
- ei_obp(reg0, ioaddr);
- ei_obp(regd, ioaddr + 0x0D);
- goto out_region;
- }
-
- SET_MODULE_OWNER(dev);
-
- /*
- * This controller is on an embedded board, so the base address
- * and interrupt assignments are pre-assigned and unchageable.
- */
-
- dev->base_addr = ioaddr;
- dev->irq = OAKNET_INT;
-
- /*
- * Disable all chip interrupts for now and ACK all pending
- * interrupts.
- */
-
- ei_obp(0x0, ioaddr + EN0_IMR);
- ei_obp(0xFF, ioaddr + EN0_ISR);
-
- /* Attempt to get the interrupt line */
-
- ret = -EAGAIN;
- if (request_irq(dev->irq, ei_interrupt, 0, name, dev)) {
- printk("%s: unable to request interrupt %d.\n",
- name, dev->irq);
- goto out_region;
- }
-
- /* Tell the world about what and where we've found. */
-
- printk("%s: %s at", dev->name, name);
- for (i = 0; i < ETHER_ADDR_LEN; ++i) {
- dev->dev_addr[i] = bip->bi_enetaddr[i];
- printk("%c%.2x", (i ? ':' : ' '), dev->dev_addr[i]);
- }
- printk(", found at %#lx, using IRQ %d.\n", dev->base_addr, dev->irq);
-
- /* Set up some required driver fields and then we're done. */
-
- ei_status.name = name;
- ei_status.word16 = FALSE;
- ei_status.tx_start_page = OAKNET_START_PG;
- ei_status.rx_start_page = OAKNET_START_PG + TX_PAGES;
- ei_status.stop_page = OAKNET_STOP_PG;
-
- ei_status.reset_8390 = &oaknet_reset_8390;
- ei_status.block_input = &oaknet_block_input;
- ei_status.block_output = &oaknet_block_output;
- ei_status.get_8390_hdr = &oaknet_get_8390_hdr;
-
- dev->open = oaknet_open;
- dev->stop = oaknet_close;
-#ifdef CONFIG_NET_POLL_CONTROLLER
- dev->poll_controller = ei_poll;
-#endif
-
- NS8390_init(dev, FALSE);
- ret = register_netdev(dev);
- if (ret)
- goto out_irq;
-
- oaknet_devs = dev;
- return 0;
-
-out_irq;
- free_irq(dev->irq, dev);
-out_region:
- release_region(OAKNET_IO_BASE, OAKNET_IO_SIZE);
-out_dev:
- free_netdev(dev);
-out_unmap:
- iounmap(ioaddr);
- return ret;
-}
-
-/*
- * static int oaknet_open()
- *
- * Description:
- * This routine is a modest wrapper around ei_open, the 8390-generic,
- * driver open routine. This just increments the module usage count
- * and passes along the status from ei_open.
- *
- * Input(s):
- * *dev - Pointer to the device structure for this driver.
- *
- * Output(s):
- * *dev - Pointer to the device structure for this driver, potentially
- * modified by ei_open.
- *
- * Returns:
- * 0 if OK, otherwise < 0 on error.
- *
- */
-static int
-oaknet_open(struct net_device *dev)
-{
- int status = ei_open(dev);
- return (status);
-}
-
-/*
- * static int oaknet_close()
- *
- * Description:
- * This routine is a modest wrapper around ei_close, the 8390-generic,
- * driver close routine. This just decrements the module usage count
- * and passes along the status from ei_close.
- *
- * Input(s):
- * *dev - Pointer to the device structure for this driver.
- *
- * Output(s):
- * *dev - Pointer to the device structure for this driver, potentially
- * modified by ei_close.
- *
- * Returns:
- * 0 if OK, otherwise < 0 on error.
- *
- */
-static int
-oaknet_close(struct net_device *dev)
-{
- int status = ei_close(dev);
- return (status);
-}
-
-/*
- * static void oaknet_reset_8390()
- *
- * Description:
- * This routine resets the DP83902 chip.
- *
- * Input(s):
- * *dev - Pointer to the device structure for this driver.
- *
- * Output(s):
- * N/A
- *
- * Returns:
- * N/A
- *
- */
-static void
-oaknet_reset_8390(struct net_device *dev)
-{
- int base = E8390_BASE;
-
- /*
- * We have no provision of reseting the controller as is done
- * in other drivers, such as "ne.c". However, the following
- * seems to work well enough in the TiVo driver.
- */
-
- printk("Resetting %s...\n", dev->name);
- ei_obp(E8390_STOP | E8390_NODMA | E8390_PAGE0, base + E8390_CMD);
- ei_status.txing = 0;
- ei_status.dmaing = 0;
-}
-
-/*
- * static void oaknet_get_8390_hdr()
- *
- * Description:
- * This routine grabs the 8390-specific header. It's similar to the
- * block input routine, but we don't need to be concerned with ring wrap
- * as the header will be at the start of a page, so we optimize accordingly.
- *
- * Input(s):
- * *dev - Pointer to the device structure for this driver.
- * *hdr - Pointer to storage for the 8390-specific packet header.
- * ring_page - ?
- *
- * Output(s):
- * *hdr - Pointer to the 8390-specific packet header for the just-
- * received frame.
- *
- * Returns:
- * N/A
- *
- */
-static void
-oaknet_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
- int ring_page)
-{
- int base = dev->base_addr;
-
- /*
- * This should NOT happen. If it does, it is the LAST thing you'll
- * see.
- */
-
- if (ei_status.dmaing) {
- oaknet_dma_error(dev, "oaknet_get_8390_hdr");
- return;
- }
-
- ei_status.dmaing |= 0x01;
- outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, base + OAKNET_CMD);
- outb_p(sizeof(struct e8390_pkt_hdr), base + EN0_RCNTLO);
- outb_p(0, base + EN0_RCNTHI);
- outb_p(0, base + EN0_RSARLO); /* On page boundary */
- outb_p(ring_page, base + EN0_RSARHI);
- outb_p(E8390_RREAD + E8390_START, base + OAKNET_CMD);
-
- if (ei_status.word16)
- insw(base + OAKNET_DATA, hdr,
- sizeof(struct e8390_pkt_hdr) >> 1);
- else
- insb(base + OAKNET_DATA, hdr,
- sizeof(struct e8390_pkt_hdr));
-
- /* Byte-swap the packet byte count */
-
- hdr->count = le16_to_cpu(hdr->count);
-
- outb_p(ENISR_RDC, base + EN0_ISR); /* ACK Remote DMA interrupt */
- ei_status.dmaing &= ~0x01;
-}
-
-/*
- * XXX - Document me.
- */
-static void
-oaknet_block_input(struct net_device *dev, int count, struct sk_buff *skb,
- int ring_offset)
-{
- int base = OAKNET_BASE;
- char *buf = skb->data;
-
- /*
- * This should NOT happen. If it does, it is the LAST thing you'll
- * see.
- */
-
- if (ei_status.dmaing) {
- oaknet_dma_error(dev, "oaknet_block_input");
- return;
- }
-
-#ifdef OAKNET_DISINT
- save_flags(flags);
- cli();
-#endif
-
- ei_status.dmaing |= 0x01;
- ei_obp(E8390_NODMA + E8390_PAGE0 + E8390_START, base + E8390_CMD);
- ei_obp(count & 0xff, base + EN0_RCNTLO);
- ei_obp(count >> 8, base + EN0_RCNTHI);
- ei_obp(ring_offset & 0xff, base + EN0_RSARLO);
- ei_obp(ring_offset >> 8, base + EN0_RSARHI);
- ei_obp(E8390_RREAD + E8390_START, base + E8390_CMD);
- if (ei_status.word16) {
- ei_isw(base + E8390_DATA, buf, count >> 1);
- if (count & 0x01) {
- buf[count - 1] = ei_ib(base + E8390_DATA);
-#ifdef OAKNET_HEADCHECK
- bytes++;
-#endif
- }
- } else {
- ei_isb(base + E8390_DATA, buf, count);
- }
-#ifdef OAKNET_HEADCHECK
- /*
- * This was for the ALPHA version only, but enough people have
- * been encountering problems so it is still here. If you see
- * this message you either 1) have a slightly incompatible clone
- * or 2) have noise/speed problems with your bus.
- */
-
- /* DMA termination address check... */
- {
- int addr, tries = 20;
- do {
- /* DON'T check for 'ei_ibp(EN0_ISR) & ENISR_RDC' here
- -- it's broken for Rx on some cards! */
- int high = ei_ibp(base + EN0_RSARHI);
- int low = ei_ibp(base + EN0_RSARLO);
- addr = (high << 8) + low;
- if (((ring_offset + bytes) & 0xff) == low)
- break;
- } while (--tries > 0);
- if (tries <= 0)
- printk("%s: RX transfer address mismatch,"
- "%#4.4x (expected) vs. %#4.4x (actual).\n",
- dev->name, ring_offset + bytes, addr);
- }
-#endif
- ei_obp(ENISR_RDC, base + EN0_ISR); /* ACK Remote DMA interrupt */
- ei_status.dmaing &= ~0x01;
-
-#ifdef OAKNET_DISINT
- restore_flags(flags);
-#endif
-}
-
-/*
- * static void oaknet_block_output()
- *
- * Description:
- * This routine...
- *
- * Input(s):
- * *dev - Pointer to the device structure for this driver.
- * count - Number of bytes to be transferred.
- * *buf -
- * start_page -
- *
- * Output(s):
- * N/A
- *
- * Returns:
- * N/A
- *
- */
-static void
-oaknet_block_output(struct net_device *dev, int count,
- const unsigned char *buf, int start_page)
-{
- int base = E8390_BASE;
-#if 0
- int bug;
-#endif
- unsigned long start;
-#ifdef OAKNET_DISINT
- unsigned long flags;
-#endif
-#ifdef OAKNET_HEADCHECK
- int retries = 0;
-#endif
-
- /* Round the count up for word writes. */
-
- if (ei_status.word16 && (count & 0x1))
- count++;
-
- /*
- * This should NOT happen. If it does, it is the LAST thing you'll
- * see.
- */
-
- if (ei_status.dmaing) {
- oaknet_dma_error(dev, "oaknet_block_output");
- return;
- }
-
-#ifdef OAKNET_DISINT
- save_flags(flags);
- cli();
-#endif
-
- ei_status.dmaing |= 0x01;
-
- /* Make sure we are in page 0. */
-
- ei_obp(E8390_PAGE0 + E8390_START + E8390_NODMA, base + E8390_CMD);
-
-#ifdef OAKNET_HEADCHECK
-retry:
-#endif
-
-#if 0
- /*
- * The 83902 documentation states that the processor needs to
- * do a "dummy read" before doing the remote write to work
- * around a chip bug they don't feel like fixing.
- */
-
- bug = 0;
- while (1) {
- unsigned int rdhi;
- unsigned int rdlo;
-
- /* Now the normal output. */
- ei_obp(ENISR_RDC, base + EN0_ISR);
- ei_obp(count & 0xff, base + EN0_RCNTLO);
- ei_obp(count >> 8, base + EN0_RCNTHI);
- ei_obp(0x00, base + EN0_RSARLO);
- ei_obp(start_page, base + EN0_RSARHI);
-
- if (bug++)
- break;
-
- /* Perform the dummy read */
- rdhi = ei_ibp(base + EN0_CRDAHI);
- rdlo = ei_ibp(base + EN0_CRDALO);
- ei_obp(E8390_RREAD + E8390_START, base + E8390_CMD);
-
- while (1) {
- unsigned int nrdhi;
- unsigned int nrdlo;
- nrdhi = ei_ibp(base + EN0_CRDAHI);
- nrdlo = ei_ibp(base + EN0_CRDALO);
- if ((rdhi != nrdhi) || (rdlo != nrdlo))
- break;
- }
- }
-#else
-#ifdef OAKNET_RWFIX
- /*
- * Handle the read-before-write bug the same way as the
- * Crynwr packet driver -- the Nat'l Semi. method doesn't work.
- * Actually this doesn't always work either, but if you have
- * problems with your 83902 this is better than nothing!
- */
-
- ei_obp(0x42, base + EN0_RCNTLO);
- ei_obp(0x00, base + EN0_RCNTHI);
- ei_obp(0x42, base + EN0_RSARLO);
- ei_obp(0x00, base + EN0_RSARHI);
- ei_obp(E8390_RREAD + E8390_START, base + E8390_CMD);
- /* Make certain that the dummy read has occurred. */
- udelay(6);
-#endif
-
- ei_obp(ENISR_RDC, base + EN0_ISR);
-
- /* Now the normal output. */
- ei_obp(count & 0xff, base + EN0_RCNTLO);
- ei_obp(count >> 8, base + EN0_RCNTHI);
- ei_obp(0x00, base + EN0_RSARLO);
- ei_obp(start_page, base + EN0_RSARHI);
-#endif /* 0/1 */
-
- ei_obp(E8390_RWRITE + E8390_START, base + E8390_CMD);
- if (ei_status.word16) {
- ei_osw(E8390_BASE + E8390_DATA, buf, count >> 1);
- } else {
- ei_osb(E8390_BASE + E8390_DATA, buf, count);
- }
-
-#ifdef OAKNET_DISINT
- restore_flags(flags);
-#endif
-
- start = jiffies;
-
-#ifdef OAKNET_HEADCHECK
- /*
- * This was for the ALPHA version only, but enough people have
- * been encountering problems so it is still here.
- */
-
- {
- /* DMA termination address check... */
- int addr, tries = 20;
- do {
- int high = ei_ibp(base + EN0_RSARHI);
- int low = ei_ibp(base + EN0_RSARLO);
- addr = (high << 8) + low;
- if ((start_page << 8) + count == addr)
- break;
- } while (--tries > 0);
-
- if (tries <= 0) {
- printk("%s: Tx packet transfer address mismatch,"
- "%#4.4x (expected) vs. %#4.4x (actual).\n",
- dev->name, (start_page << 8) + count, addr);
- if (retries++ == 0)
- goto retry;
- }
- }
-#endif
-
- while ((ei_ibp(base + EN0_ISR) & ENISR_RDC) == 0) {
- if (time_after(jiffies, start + OAKNET_WAIT)) {
- printk("%s: timeout waiting for Tx RDC.\n", dev->name);
- oaknet_reset_8390(dev);
- NS8390_init(dev, TRUE);
- break;
- }
- }
-
- ei_obp(ENISR_RDC, base + EN0_ISR); /* Ack intr. */
- ei_status.dmaing &= ~0x01;
-}
-
-/*
- * static void oaknet_dma_error()
- *
- * Description:
- * This routine prints out a last-ditch informative message to the console
- * indicating that a DMA error occurred. If you see this, it's the last
- * thing you'll see.
- *
- * Input(s):
- * *dev - Pointer to the device structure for this driver.
- * *name - Informative text (e.g. function name) indicating where the
- * DMA error occurred.
- *
- * Output(s):
- * N/A
- *
- * Returns:
- * N/A
- *
- */
-static void
-oaknet_dma_error(struct net_device *dev, const char *name)
-{
- printk(KERN_EMERG "%s: DMAing conflict in %s."
- "[DMAstat:%d][irqlock:%d][intr:%ld]\n",
- dev->name, name, ei_status.dmaing, ei_status.irqlock,
- dev->interrupt);
-}
-
-/*
- * Oak Ethernet module unload interface.
- */
-static void __exit oaknet_cleanup_module (void)
-{
- /* Convert to loop once driver supports multiple devices. */
- unregister_netdev(oaknet_dev);
- free_irq(oaknet_devs->irq, oaknet_devs);
- release_region(oaknet_devs->base_addr, OAKNET_IO_SIZE);
- iounmap(ioaddr);
- free_netdev(oaknet_devs);
-}
-
-module_init(oaknet_init);
-module_exit(oaknet_cleanup_module);
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c
new file mode 100644
index 00000000000..d670ac74824
--- /dev/null
+++ b/drivers/net/pasemi_mac.c
@@ -0,0 +1,1019 @@
+/*
+ * Copyright (C) 2006-2007 PA Semi, Inc
+ *
+ * Driver for the PA Semi PWRficient onchip 1G/10G Ethernet MACs
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/dmaengine.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <asm/dma-mapping.h>
+#include <linux/in.h>
+#include <linux/skbuff.h>
+
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <net/checksum.h>
+
+#include "pasemi_mac.h"
+
+
+/* TODO list
+ *
+ * - Get rid of pci_{read,write}_config(), map registers with ioremap
+ * for performance
+ * - PHY support
+ * - Multicast support
+ * - Large MTU support
+ * - Other performance improvements
+ */
+
+
+/* Must be a power of two */
+#define RX_RING_SIZE 512
+#define TX_RING_SIZE 512
+
+#define TX_DESC(mac, num) ((mac)->tx->desc[(num) & (TX_RING_SIZE-1)])
+#define TX_DESC_INFO(mac, num) ((mac)->tx->desc_info[(num) & (TX_RING_SIZE-1)])
+#define RX_DESC(mac, num) ((mac)->rx->desc[(num) & (RX_RING_SIZE-1)])
+#define RX_DESC_INFO(mac, num) ((mac)->rx->desc_info[(num) & (RX_RING_SIZE-1)])
+#define RX_BUFF(mac, num) ((mac)->rx->buffers[(num) & (RX_RING_SIZE-1)])
+
+#define BUF_SIZE 1646 /* 1500 MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */
+
+/* XXXOJN these should come out of the device tree some day */
+#define PAS_DMA_CAP_BASE 0xe00d0040
+#define PAS_DMA_CAP_SIZE 0x100
+#define PAS_DMA_COM_BASE 0xe00d0100
+#define PAS_DMA_COM_SIZE 0x100
+
+static struct pasdma_status *dma_status;
+
+static int pasemi_get_mac_addr(struct pasemi_mac *mac)
+{
+ struct pci_dev *pdev = mac->pdev;
+ struct device_node *dn = pci_device_to_OF_node(pdev);
+ const u8 *maddr;
+ u8 addr[6];
+
+ if (!dn) {
+ dev_dbg(&pdev->dev,
+ "No device node for mac, not configuring\n");
+ return -ENOENT;
+ }
+
+ maddr = get_property(dn, "mac-address", NULL);
+ if (maddr == NULL) {
+ dev_warn(&pdev->dev,
+ "no mac address in device tree, not configuring\n");
+ return -ENOENT;
+ }
+
+ if (sscanf(maddr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &addr[0],
+ &addr[1], &addr[2], &addr[3], &addr[4], &addr[5]) != 6) {
+ dev_warn(&pdev->dev,
+ "can't parse mac address, not configuring\n");
+ return -EINVAL;
+ }
+
+ memcpy(mac->mac_addr, addr, sizeof(addr));
+ return 0;
+}
+
+static int pasemi_mac_setup_rx_resources(struct net_device *dev)
+{
+ struct pasemi_mac_rxring *ring;
+ struct pasemi_mac *mac = netdev_priv(dev);
+ int chan_id = mac->dma_rxch;
+
+ ring = kzalloc(sizeof(*ring), GFP_KERNEL);
+
+ if (!ring)
+ goto out_ring;
+
+ spin_lock_init(&ring->lock);
+
+ ring->desc_info = kzalloc(sizeof(struct pasemi_mac_buffer) *
+ RX_RING_SIZE, GFP_KERNEL);
+
+ if (!ring->desc_info)
+ goto out_desc_info;
+
+ /* Allocate descriptors */
+ ring->desc = dma_alloc_coherent(&mac->dma_pdev->dev,
+ RX_RING_SIZE *
+ sizeof(struct pas_dma_xct_descr),
+ &ring->dma, GFP_KERNEL);
+
+ if (!ring->desc)
+ goto out_desc;
+
+ memset(ring->desc, 0, RX_RING_SIZE * sizeof(struct pas_dma_xct_descr));
+
+ ring->buffers = dma_alloc_coherent(&mac->dma_pdev->dev,
+ RX_RING_SIZE * sizeof(u64),
+ &ring->buf_dma, GFP_KERNEL);
+ if (!ring->buffers)
+ goto out_buffers;
+
+ memset(ring->buffers, 0, RX_RING_SIZE * sizeof(u64));
+
+ pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXCHAN_BASEL(chan_id),
+ PAS_DMA_RXCHAN_BASEL_BRBL(ring->dma));
+
+ pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXCHAN_BASEU(chan_id),
+ PAS_DMA_RXCHAN_BASEU_BRBH(ring->dma >> 32) |
+ PAS_DMA_RXCHAN_BASEU_SIZ(RX_RING_SIZE >> 2));
+
+ pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXCHAN_CFG(chan_id),
+ PAS_DMA_RXCHAN_CFG_HBU(1));
+
+ pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXINT_BASEL(mac->dma_if),
+ PAS_DMA_RXINT_BASEL_BRBL(__pa(ring->buffers)));
+
+ pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXINT_BASEU(mac->dma_if),
+ PAS_DMA_RXINT_BASEU_BRBH(__pa(ring->buffers) >> 32) |
+ PAS_DMA_RXINT_BASEU_SIZ(RX_RING_SIZE >> 3));
+
+ ring->next_to_fill = 0;
+ ring->next_to_clean = 0;
+
+ snprintf(ring->irq_name, sizeof(ring->irq_name),
+ "%s rx", dev->name);
+ mac->rx = ring;
+
+ return 0;
+
+out_buffers:
+ dma_free_coherent(&mac->dma_pdev->dev,
+ RX_RING_SIZE * sizeof(struct pas_dma_xct_descr),
+ mac->rx->desc, mac->rx->dma);
+out_desc:
+ kfree(ring->desc_info);
+out_desc_info:
+ kfree(ring);
+out_ring:
+ return -ENOMEM;
+}
+
+
+static int pasemi_mac_setup_tx_resources(struct net_device *dev)
+{
+ struct pasemi_mac *mac = netdev_priv(dev);
+ u32 val;
+ int chan_id = mac->dma_txch;
+ struct pasemi_mac_txring *ring;
+
+ ring = kzalloc(sizeof(*ring), GFP_KERNEL);
+ if (!ring)
+ goto out_ring;
+
+ spin_lock_init(&ring->lock);
+
+ ring->desc_info = kzalloc(sizeof(struct pasemi_mac_buffer) *
+ TX_RING_SIZE, GFP_KERNEL);
+ if (!ring->desc_info)
+ goto out_desc_info;
+
+ /* Allocate descriptors */
+ ring->desc = dma_alloc_coherent(&mac->dma_pdev->dev,
+ TX_RING_SIZE *
+ sizeof(struct pas_dma_xct_descr),
+ &ring->dma, GFP_KERNEL);
+ if (!ring->desc)
+ goto out_desc;
+
+ memset(ring->desc, 0, TX_RING_SIZE * sizeof(struct pas_dma_xct_descr));
+
+ pci_write_config_dword(mac->dma_pdev, PAS_DMA_TXCHAN_BASEL(chan_id),
+ PAS_DMA_TXCHAN_BASEL_BRBL(ring->dma));
+ val = PAS_DMA_TXCHAN_BASEU_BRBH(ring->dma >> 32);
+ val |= PAS_DMA_TXCHAN_BASEU_SIZ(TX_RING_SIZE >> 2);
+
+ pci_write_config_dword(mac->dma_pdev, PAS_DMA_TXCHAN_BASEU(chan_id), val);
+
+ pci_write_config_dword(mac->dma_pdev, PAS_DMA_TXCHAN_CFG(chan_id),
+ PAS_DMA_TXCHAN_CFG_TY_IFACE |
+ PAS_DMA_TXCHAN_CFG_TATTR(mac->dma_if) |
+ PAS_DMA_TXCHAN_CFG_UP |
+ PAS_DMA_TXCHAN_CFG_WT(2));
+
+ ring->next_to_use = 0;
+ ring->next_to_clean = 0;
+
+ snprintf(ring->irq_name, sizeof(ring->irq_name),
+ "%s tx", dev->name);
+ mac->tx = ring;
+
+ return 0;
+
+out_desc:
+ kfree(ring->desc_info);
+out_desc_info:
+ kfree(ring);
+out_ring:
+ return -ENOMEM;
+}
+
+static void pasemi_mac_free_tx_resources(struct net_device *dev)
+{
+ struct pasemi_mac *mac = netdev_priv(dev);
+ unsigned int i;
+ struct pasemi_mac_buffer *info;
+ struct pas_dma_xct_descr *dp;
+
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ info = &TX_DESC_INFO(mac, i);
+ dp = &TX_DESC(mac, i);
+ if (info->dma) {
+ if (info->skb) {
+ pci_unmap_single(mac->dma_pdev,
+ info->dma,
+ info->skb->len,
+ PCI_DMA_TODEVICE);
+ dev_kfree_skb_any(info->skb);
+ }
+ info->dma = 0;
+ info->skb = NULL;
+ dp->mactx = 0;
+ dp->ptr = 0;
+ }
+ }
+
+ dma_free_coherent(&mac->dma_pdev->dev,
+ TX_RING_SIZE * sizeof(struct pas_dma_xct_descr),
+ mac->tx->desc, mac->tx->dma);
+
+ kfree(mac->tx->desc_info);
+ kfree(mac->tx);
+ mac->tx = NULL;
+}
+
+static void pasemi_mac_free_rx_resources(struct net_device *dev)
+{
+ struct pasemi_mac *mac = netdev_priv(dev);
+ unsigned int i;
+ struct pasemi_mac_buffer *info;
+ struct pas_dma_xct_descr *dp;
+
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ info = &RX_DESC_INFO(mac, i);
+ dp = &RX_DESC(mac, i);
+ if (info->dma) {
+ if (info->skb) {
+ pci_unmap_single(mac->dma_pdev,
+ info->dma,
+ info->skb->len,
+ PCI_DMA_FROMDEVICE);
+ dev_kfree_skb_any(info->skb);
+ }
+ info->dma = 0;
+ info->skb = NULL;
+ dp->macrx = 0;
+ dp->ptr = 0;
+ }
+ }
+
+ dma_free_coherent(&mac->dma_pdev->dev,
+ RX_RING_SIZE * sizeof(struct pas_dma_xct_descr),
+ mac->rx->desc, mac->rx->dma);
+
+ dma_free_coherent(&mac->dma_pdev->dev, RX_RING_SIZE * sizeof(u64),
+ mac->rx->buffers, mac->rx->buf_dma);
+
+ kfree(mac->rx->desc_info);
+ kfree(mac->rx);
+ mac->rx = NULL;
+}
+
+static void pasemi_mac_replenish_rx_ring(struct net_device *dev)
+{
+ struct pasemi_mac *mac = netdev_priv(dev);
+ unsigned int i;
+ int start = mac->rx->next_to_fill;
+ unsigned int count;
+
+ count = (mac->rx->next_to_clean + RX_RING_SIZE -
+ mac->rx->next_to_fill) & (RX_RING_SIZE - 1);
+
+ /* Check to see if we're doing first-time setup */
+ if (unlikely(mac->rx->next_to_clean == 0 && mac->rx->next_to_fill == 0))
+ count = RX_RING_SIZE;
+
+ if (count <= 0)
+ return;
+
+ for (i = start; i < start + count; i++) {
+ struct pasemi_mac_buffer *info = &RX_DESC_INFO(mac, i);
+ u64 *buff = &RX_BUFF(mac, i);
+ struct sk_buff *skb;
+ dma_addr_t dma;
+
+ skb = dev_alloc_skb(BUF_SIZE);
+
+ if (!skb) {
+ count = i - start;
+ break;
+ }
+
+ skb->dev = dev;
+
+ dma = pci_map_single(mac->dma_pdev, skb->data, skb->len,
+ PCI_DMA_FROMDEVICE);
+
+ if (dma_mapping_error(dma)) {
+ dev_kfree_skb_irq(info->skb);
+ count = i - start;
+ break;
+ }
+
+ info->skb = skb;
+ info->dma = dma;
+ *buff = XCT_RXB_LEN(BUF_SIZE) | XCT_RXB_ADDR(dma);
+ }
+
+ wmb();
+
+ pci_write_config_dword(mac->dma_pdev,
+ PAS_DMA_RXCHAN_INCR(mac->dma_rxch),
+ count);
+ pci_write_config_dword(mac->dma_pdev,
+ PAS_DMA_RXINT_INCR(mac->dma_if),
+ count);
+
+ mac->rx->next_to_fill += count;
+}
+
+static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit)
+{
+ unsigned int i;
+ int start, count;
+
+ spin_lock(&mac->rx->lock);
+
+ start = mac->rx->next_to_clean;
+ count = 0;
+
+ for (i = start; i < (start + RX_RING_SIZE) && count < limit; i++) {
+ struct pas_dma_xct_descr *dp;
+ struct pasemi_mac_buffer *info;
+ struct sk_buff *skb;
+ unsigned int j, len;
+ dma_addr_t dma;
+
+ rmb();
+
+ dp = &RX_DESC(mac, i);
+
+ if (!(dp->macrx & XCT_MACRX_O))
+ break;
+
+ count++;
+
+ info = NULL;
+
+ /* We have to scan for our skb since there's no way
+ * to back-map them from the descriptor, and if we
+ * have several receive channels then they might not
+ * show up in the same order as they were put on the
+ * interface ring.
+ */
+
+ dma = (dp->ptr & XCT_PTR_ADDR_M);
+ for (j = start; j < (start + RX_RING_SIZE); j++) {
+ info = &RX_DESC_INFO(mac, j);
+ if (info->dma == dma)
+ break;
+ }
+
+ BUG_ON(!info);
+ BUG_ON(info->dma != dma);
+
+ pci_unmap_single(mac->dma_pdev, info->dma, info->skb->len,
+ PCI_DMA_FROMDEVICE);
+
+ skb = info->skb;
+
+ len = (dp->macrx & XCT_MACRX_LLEN_M) >> XCT_MACRX_LLEN_S;
+
+ skb_put(skb, len);
+
+ skb->protocol = eth_type_trans(skb, mac->netdev);
+
+ if ((dp->macrx & XCT_MACRX_HTY_M) == XCT_MACRX_HTY_IPV4_OK) {
+ skb->ip_summed = CHECKSUM_COMPLETE;
+ skb->csum = (dp->macrx & XCT_MACRX_CSUM_M) >>
+ XCT_MACRX_CSUM_S;
+ } else
+ skb->ip_summed = CHECKSUM_NONE;
+
+ mac->stats.rx_bytes += len;
+ mac->stats.rx_packets++;
+
+ netif_receive_skb(skb);
+
+ info->dma = 0;
+ info->skb = NULL;
+ dp->ptr = 0;
+ dp->macrx = 0;
+ }
+
+ mac->rx->next_to_clean += count;
+ pasemi_mac_replenish_rx_ring(mac->netdev);
+
+ spin_unlock(&mac->rx->lock);
+
+ return count;
+}
+
+static int pasemi_mac_clean_tx(struct pasemi_mac *mac)
+{
+ int i;
+ struct pasemi_mac_buffer *info;
+ struct pas_dma_xct_descr *dp;
+ int start, count;
+ int flags;
+
+ spin_lock_irqsave(&mac->tx->lock, flags);
+
+ start = mac->tx->next_to_clean;
+ count = 0;
+
+ for (i = start; i < mac->tx->next_to_use; i++) {
+ dp = &TX_DESC(mac, i);
+ if (!dp || (dp->mactx & XCT_MACTX_O))
+ break;
+
+ count++;
+
+ info = &TX_DESC_INFO(mac, i);
+
+ pci_unmap_single(mac->dma_pdev, info->dma,
+ info->skb->len, PCI_DMA_TODEVICE);
+ dev_kfree_skb_irq(info->skb);
+
+ info->skb = NULL;
+ info->dma = 0;
+ dp->mactx = 0;
+ dp->ptr = 0;
+ }
+ mac->tx->next_to_clean += count;
+ spin_unlock_irqrestore(&mac->tx->lock, flags);
+
+ return count;
+}
+
+
+static irqreturn_t pasemi_mac_rx_intr(int irq, void *data)
+{
+ struct net_device *dev = data;
+ struct pasemi_mac *mac = netdev_priv(dev);
+ unsigned int reg;
+
+ if (!(*mac->rx_status & PAS_STATUS_INT))
+ return IRQ_NONE;
+
+ netif_rx_schedule(dev);
+ pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG,
+ PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0));
+
+ reg = PAS_IOB_DMA_RXCH_RESET_PINTC | PAS_IOB_DMA_RXCH_RESET_SINTC |
+ PAS_IOB_DMA_RXCH_RESET_DINTC;
+ if (*mac->rx_status & PAS_STATUS_TIMER)
+ reg |= PAS_IOB_DMA_RXCH_RESET_TINTC;
+
+ pci_write_config_dword(mac->iob_pdev,
+ PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch), reg);
+
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t pasemi_mac_tx_intr(int irq, void *data)
+{
+ struct net_device *dev = data;
+ struct pasemi_mac *mac = netdev_priv(dev);
+ unsigned int reg;
+ int was_full;
+
+ was_full = mac->tx->next_to_clean - mac->tx->next_to_use == TX_RING_SIZE;
+
+ if (!(*mac->tx_status & PAS_STATUS_INT))
+ return IRQ_NONE;
+
+ pasemi_mac_clean_tx(mac);
+
+ reg = PAS_IOB_DMA_TXCH_RESET_PINTC | PAS_IOB_DMA_TXCH_RESET_SINTC;
+ if (*mac->tx_status & PAS_STATUS_TIMER)
+ reg |= PAS_IOB_DMA_TXCH_RESET_TINTC;
+
+ pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_TXCH_RESET(mac->dma_txch),
+ reg);
+
+ if (was_full)
+ netif_wake_queue(dev);
+
+ return IRQ_HANDLED;
+}
+
+static int pasemi_mac_open(struct net_device *dev)
+{
+ struct pasemi_mac *mac = netdev_priv(dev);
+ unsigned int flags;
+ int ret;
+
+ /* enable rx section */
+ pci_write_config_dword(mac->dma_pdev, PAS_DMA_COM_RXCMD,
+ PAS_DMA_COM_RXCMD_EN);
+
+ /* enable tx section */
+ pci_write_config_dword(mac->dma_pdev, PAS_DMA_COM_TXCMD,
+ PAS_DMA_COM_TXCMD_EN);
+
+ flags = PAS_MAC_CFG_TXP_FCE | PAS_MAC_CFG_TXP_FPC(3) |
+ PAS_MAC_CFG_TXP_SL(3) | PAS_MAC_CFG_TXP_COB(0xf) |
+ PAS_MAC_CFG_TXP_TIFT(8) | PAS_MAC_CFG_TXP_TIFG(12);
+
+ pci_write_config_dword(mac->pdev, PAS_MAC_CFG_TXP, flags);
+
+ flags = PAS_MAC_CFG_PCFG_S1 | PAS_MAC_CFG_PCFG_PE |
+ PAS_MAC_CFG_PCFG_PR | PAS_MAC_CFG_PCFG_CE;
+
+ flags |= PAS_MAC_CFG_PCFG_TSR_1G | PAS_MAC_CFG_PCFG_SPD_1G;
+
+ pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_RXCH_CFG(mac->dma_rxch),
+ PAS_IOB_DMA_RXCH_CFG_CNTTH(30));
+
+ pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG,
+ PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(1000000));
+
+ pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, flags);
+
+ ret = pasemi_mac_setup_rx_resources(dev);
+ if (ret)
+ goto out_rx_resources;
+
+ ret = pasemi_mac_setup_tx_resources(dev);
+ if (ret)
+ goto out_tx_resources;
+
+ pci_write_config_dword(mac->pdev, PAS_MAC_IPC_CHNL,
+ PAS_MAC_IPC_CHNL_DCHNO(mac->dma_rxch) |
+ PAS_MAC_IPC_CHNL_BCH(mac->dma_rxch));
+
+ /* enable rx if */
+ pci_write_config_dword(mac->dma_pdev,
+ PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
+ PAS_DMA_RXINT_RCMDSTA_EN);
+
+ /* enable rx channel */
+ pci_write_config_dword(mac->dma_pdev,
+ PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch),
+ PAS_DMA_RXCHAN_CCMDSTA_EN |
+ PAS_DMA_RXCHAN_CCMDSTA_DU);
+
+ /* enable tx channel */
+ pci_write_config_dword(mac->dma_pdev,
+ PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch),
+ PAS_DMA_TXCHAN_TCMDSTA_EN);
+
+ pasemi_mac_replenish_rx_ring(dev);
+
+ netif_start_queue(dev);
+ netif_poll_enable(dev);
+
+ ret = request_irq(mac->dma_pdev->irq + mac->dma_txch,
+ &pasemi_mac_tx_intr, IRQF_DISABLED,
+ mac->tx->irq_name, dev);
+ if (ret) {
+ dev_err(&mac->pdev->dev, "request_irq of irq %d failed: %d\n",
+ mac->dma_pdev->irq + mac->dma_txch, ret);
+ goto out_tx_int;
+ }
+
+ ret = request_irq(mac->dma_pdev->irq + 20 + mac->dma_rxch,
+ &pasemi_mac_rx_intr, IRQF_DISABLED,
+ mac->rx->irq_name, dev);
+ if (ret) {
+ dev_err(&mac->pdev->dev, "request_irq of irq %d failed: %d\n",
+ mac->dma_pdev->irq + 20 + mac->dma_rxch, ret);
+ goto out_rx_int;
+ }
+
+ return 0;
+
+out_rx_int:
+ free_irq(mac->dma_pdev->irq + mac->dma_txch, dev);
+out_tx_int:
+ netif_poll_disable(dev);
+ netif_stop_queue(dev);
+ pasemi_mac_free_tx_resources(dev);
+out_tx_resources:
+ pasemi_mac_free_rx_resources(dev);
+out_rx_resources:
+
+ return ret;
+}
+
+#define MAX_RETRIES 5000
+
+static int pasemi_mac_close(struct net_device *dev)
+{
+ struct pasemi_mac *mac = netdev_priv(dev);
+ unsigned int stat;
+ int retries;
+
+ netif_stop_queue(dev);
+
+ /* Clean out any pending buffers */
+ pasemi_mac_clean_tx(mac);
+ pasemi_mac_clean_rx(mac, RX_RING_SIZE);
+
+ /* Disable interface */
+ pci_write_config_dword(mac->dma_pdev,
+ PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch),
+ PAS_DMA_TXCHAN_TCMDSTA_ST);
+ pci_write_config_dword(mac->dma_pdev,
+ PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
+ PAS_DMA_RXINT_RCMDSTA_ST);
+ pci_write_config_dword(mac->dma_pdev,
+ PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch),
+ PAS_DMA_RXCHAN_CCMDSTA_ST);
+
+ for (retries = 0; retries < MAX_RETRIES; retries++) {
+ pci_read_config_dword(mac->dma_pdev,
+ PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch),
+ &stat);
+ if (stat & PAS_DMA_TXCHAN_TCMDSTA_ACT)
+ break;
+ cond_resched();
+ }
+
+ if (!(stat & PAS_DMA_TXCHAN_TCMDSTA_ACT)) {
+ dev_err(&mac->dma_pdev->dev, "Failed to stop tx channel\n");
+ }
+
+ for (retries = 0; retries < MAX_RETRIES; retries++) {
+ pci_read_config_dword(mac->dma_pdev,
+ PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch),
+ &stat);
+ if (stat & PAS_DMA_RXCHAN_CCMDSTA_ACT)
+ break;
+ cond_resched();
+ }
+
+ if (!(stat & PAS_DMA_RXCHAN_CCMDSTA_ACT)) {
+ dev_err(&mac->dma_pdev->dev, "Failed to stop rx channel\n");
+ }
+
+ for (retries = 0; retries < MAX_RETRIES; retries++) {
+ pci_read_config_dword(mac->dma_pdev,
+ PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
+ &stat);
+ if (stat & PAS_DMA_RXINT_RCMDSTA_ACT)
+ break;
+ cond_resched();
+ }
+
+ if (!(stat & PAS_DMA_RXINT_RCMDSTA_ACT)) {
+ dev_err(&mac->dma_pdev->dev, "Failed to stop rx interface\n");
+ }
+
+ /* Then, disable the channel. This must be done separately from
+ * stopping, since you can't disable when active.
+ */
+
+ pci_write_config_dword(mac->dma_pdev,
+ PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), 0);
+ pci_write_config_dword(mac->dma_pdev,
+ PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), 0);
+ pci_write_config_dword(mac->dma_pdev,
+ PAS_DMA_RXINT_RCMDSTA(mac->dma_if), 0);
+
+ free_irq(mac->dma_pdev->irq + mac->dma_txch, dev);
+ free_irq(mac->dma_pdev->irq + 20 + mac->dma_rxch, dev);
+
+ /* Free resources */
+ pasemi_mac_free_rx_resources(dev);
+ pasemi_mac_free_tx_resources(dev);
+
+ return 0;
+}
+
+static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev)
+{
+ struct pasemi_mac *mac = netdev_priv(dev);
+ struct pasemi_mac_txring *txring;
+ struct pasemi_mac_buffer *info;
+ struct pas_dma_xct_descr *dp;
+ u64 dflags;
+ dma_addr_t map;
+ int flags;
+
+ dflags = XCT_MACTX_O | XCT_MACTX_ST | XCT_MACTX_SS | XCT_MACTX_CRC_PAD;
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ switch (skb->nh.iph->protocol) {
+ case IPPROTO_TCP:
+ dflags |= XCT_MACTX_CSUM_TCP;
+ dflags |= XCT_MACTX_IPH((skb->h.raw - skb->nh.raw) >> 2);
+ dflags |= XCT_MACTX_IPO(skb->nh.raw - skb->data);
+ break;
+ case IPPROTO_UDP:
+ dflags |= XCT_MACTX_CSUM_UDP;
+ dflags |= XCT_MACTX_IPH((skb->h.raw - skb->nh.raw) >> 2);
+ dflags |= XCT_MACTX_IPO(skb->nh.raw - skb->data);
+ break;
+ }
+ }
+
+ map = pci_map_single(mac->dma_pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
+
+ if (dma_mapping_error(map))
+ return NETDEV_TX_BUSY;
+
+ txring = mac->tx;
+
+ spin_lock_irqsave(&txring->lock, flags);
+
+ if (txring->next_to_clean - txring->next_to_use == TX_RING_SIZE) {
+ spin_unlock_irqrestore(&txring->lock, flags);
+ pasemi_mac_clean_tx(mac);
+ spin_lock_irqsave(&txring->lock, flags);
+
+ if (txring->next_to_clean - txring->next_to_use ==
+ TX_RING_SIZE) {
+ /* Still no room -- stop the queue and wait for tx
+ * intr when there's room.
+ */
+ netif_stop_queue(dev);
+ goto out_err;
+ }
+ }
+
+
+ dp = &TX_DESC(mac, txring->next_to_use);
+ info = &TX_DESC_INFO(mac, txring->next_to_use);
+
+ dp->mactx = dflags | XCT_MACTX_LLEN(skb->len);
+ dp->ptr = XCT_PTR_LEN(skb->len) | XCT_PTR_ADDR(map);
+ info->dma = map;
+ info->skb = skb;
+
+ txring->next_to_use++;
+ mac->stats.tx_packets++;
+ mac->stats.tx_bytes += skb->len;
+
+ spin_unlock_irqrestore(&txring->lock, flags);
+
+ pci_write_config_dword(mac->dma_pdev,
+ PAS_DMA_TXCHAN_INCR(mac->dma_txch), 1);
+
+ return NETDEV_TX_OK;
+
+out_err:
+ spin_unlock_irqrestore(&txring->lock, flags);
+ pci_unmap_single(mac->dma_pdev, map, skb->len, PCI_DMA_TODEVICE);
+ return NETDEV_TX_BUSY;
+}
+
+static struct net_device_stats *pasemi_mac_get_stats(struct net_device *dev)
+{
+ struct pasemi_mac *mac = netdev_priv(dev);
+
+ return &mac->stats;
+}
+
+static void pasemi_mac_set_rx_mode(struct net_device *dev)
+{
+ struct pasemi_mac *mac = netdev_priv(dev);
+ unsigned int flags;
+
+ pci_read_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, &flags);
+
+ /* Set promiscuous */
+ if (dev->flags & IFF_PROMISC)
+ flags |= PAS_MAC_CFG_PCFG_PR;
+ else
+ flags &= ~PAS_MAC_CFG_PCFG_PR;
+
+ pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, flags);
+}
+
+
+static int pasemi_mac_poll(struct net_device *dev, int *budget)
+{
+ int pkts, limit = min(*budget, dev->quota);
+ struct pasemi_mac *mac = netdev_priv(dev);
+
+ pkts = pasemi_mac_clean_rx(mac, limit);
+
+ if (pkts < limit) {
+ /* all done, no more packets present */
+ netif_rx_complete(dev);
+
+ /* re-enable receive interrupts */
+ pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG,
+ PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(1000000));
+ return 0;
+ } else {
+ /* used up our quantum, so reschedule */
+ dev->quota -= pkts;
+ *budget -= pkts;
+ return 1;
+ }
+}
+
+static int __devinit
+pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int index = 0;
+ struct net_device *dev;
+ struct pasemi_mac *mac;
+ int err;
+
+ err = pci_enable_device(pdev);
+ if (err)
+ return err;
+
+ dev = alloc_etherdev(sizeof(struct pasemi_mac));
+ if (dev == NULL) {
+ dev_err(&pdev->dev,
+ "pasemi_mac: Could not allocate ethernet device.\n");
+ err = -ENOMEM;
+ goto out_disable_device;
+ }
+
+ SET_MODULE_OWNER(dev);
+ pci_set_drvdata(pdev, dev);
+ SET_NETDEV_DEV(dev, &pdev->dev);
+
+ mac = netdev_priv(dev);
+
+ mac->pdev = pdev;
+ mac->netdev = dev;
+ mac->dma_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa007, NULL);
+
+ if (!mac->dma_pdev) {
+ dev_err(&pdev->dev, "Can't find DMA Controller\n");
+ err = -ENODEV;
+ goto out_free_netdev;
+ }
+
+ mac->iob_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa001, NULL);
+
+ if (!mac->iob_pdev) {
+ dev_err(&pdev->dev, "Can't find I/O Bridge\n");
+ err = -ENODEV;
+ goto out_put_dma_pdev;
+ }
+
+ /* These should come out of the device tree eventually */
+ mac->dma_txch = index;
+ mac->dma_rxch = index;
+
+ /* We probe GMAC before XAUI, but the DMA interfaces are
+ * in XAUI, GMAC order.
+ */
+ if (index < 4)
+ mac->dma_if = index + 2;
+ else
+ mac->dma_if = index - 4;
+ index++;
+
+ switch (pdev->device) {
+ case 0xa005:
+ mac->type = MAC_TYPE_GMAC;
+ break;
+ case 0xa006:
+ mac->type = MAC_TYPE_XAUI;
+ break;
+ default:
+ err = -ENODEV;
+ goto out;
+ }
+
+ /* get mac addr from device tree */
+ if (pasemi_get_mac_addr(mac) || !is_valid_ether_addr(mac->mac_addr)) {
+ err = -ENODEV;
+ goto out;
+ }
+ memcpy(dev->dev_addr, mac->mac_addr, sizeof(mac->mac_addr));
+
+ dev->open = pasemi_mac_open;
+ dev->stop = pasemi_mac_close;
+ dev->hard_start_xmit = pasemi_mac_start_tx;
+ dev->get_stats = pasemi_mac_get_stats;
+ dev->set_multicast_list = pasemi_mac_set_rx_mode;
+ dev->weight = 64;
+ dev->poll = pasemi_mac_poll;
+ dev->features = NETIF_F_HW_CSUM;
+
+ /* The dma status structure is located in the I/O bridge, and
+ * is cache coherent.
+ */
+ if (!dma_status)
+ /* XXXOJN This should come from the device tree */
+ dma_status = __ioremap(0xfd800000, 0x1000, 0);
+
+ mac->rx_status = &dma_status->rx_sta[mac->dma_rxch];
+ mac->tx_status = &dma_status->tx_sta[mac->dma_txch];
+
+ err = register_netdev(dev);
+
+ if (err) {
+ dev_err(&mac->pdev->dev, "register_netdev failed with error %d\n",
+ err);
+ goto out;
+ } else
+ printk(KERN_INFO "%s: PA Semi %s: intf %d, txch %d, rxch %d, "
+ "hw addr %02x:%02x:%02x:%02x:%02x:%02x\n",
+ dev->name, mac->type == MAC_TYPE_GMAC ? "GMAC" : "XAUI",
+ mac->dma_if, mac->dma_txch, mac->dma_rxch,
+ dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+ dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+
+ return err;
+
+out:
+ pci_dev_put(mac->iob_pdev);
+out_put_dma_pdev:
+ pci_dev_put(mac->dma_pdev);
+out_free_netdev:
+ free_netdev(dev);
+out_disable_device:
+ pci_disable_device(pdev);
+ return err;
+
+}
+
+static void __devexit pasemi_mac_remove(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct pasemi_mac *mac;
+
+ if (!netdev)
+ return;
+
+ mac = netdev_priv(netdev);
+
+ unregister_netdev(netdev);
+
+ pci_disable_device(pdev);
+ pci_dev_put(mac->dma_pdev);
+ pci_dev_put(mac->iob_pdev);
+
+ pci_set_drvdata(pdev, NULL);
+ free_netdev(netdev);
+}
+
+static struct pci_device_id pasemi_mac_pci_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_PASEMI, 0xa005) },
+ { PCI_DEVICE(PCI_VENDOR_ID_PASEMI, 0xa006) },
+};
+
+MODULE_DEVICE_TABLE(pci, pasemi_mac_pci_tbl);
+
+static struct pci_driver pasemi_mac_driver = {
+ .name = "pasemi_mac",
+ .id_table = pasemi_mac_pci_tbl,
+ .probe = pasemi_mac_probe,
+ .remove = __devexit_p(pasemi_mac_remove),
+};
+
+static void __exit pasemi_mac_cleanup_module(void)
+{
+ pci_unregister_driver(&pasemi_mac_driver);
+ __iounmap(dma_status);
+ dma_status = NULL;
+}
+
+int pasemi_mac_init_module(void)
+{
+ return pci_register_driver(&pasemi_mac_driver);
+}
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR ("Olof Johansson <olof@lixom.net>");
+MODULE_DESCRIPTION("PA Semi PWRficient Ethernet driver");
+
+module_init(pasemi_mac_init_module);
+module_exit(pasemi_mac_cleanup_module);
diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h
new file mode 100644
index 00000000000..c3e37e46a18
--- /dev/null
+++ b/drivers/net/pasemi_mac.h
@@ -0,0 +1,460 @@
+/*
+ * Copyright (C) 2006 PA Semi, Inc
+ *
+ * Driver for the PA6T-1682M onchip 1G/10G Ethernet MACs, soft state and
+ * hardware register layouts.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PASEMI_MAC_H
+#define PASEMI_MAC_H
+
+#include <linux/ethtool.h>
+#include <linux/netdevice.h>
+#include <linux/spinlock.h>
+
+struct pasemi_mac_txring {
+ spinlock_t lock;
+ struct pas_dma_xct_descr *desc;
+ dma_addr_t dma;
+ unsigned int size;
+ unsigned int next_to_use;
+ unsigned int next_to_clean;
+ struct pasemi_mac_buffer *desc_info;
+ char irq_name[10]; /* "eth%d tx" */
+};
+
+struct pasemi_mac_rxring {
+ spinlock_t lock;
+ struct pas_dma_xct_descr *desc; /* RX channel descriptor ring */
+ dma_addr_t dma;
+ u64 *buffers; /* RX interface buffer ring */
+ dma_addr_t buf_dma;
+ unsigned int size;
+ unsigned int next_to_fill;
+ unsigned int next_to_clean;
+ struct pasemi_mac_buffer *desc_info;
+ char irq_name[10]; /* "eth%d rx" */
+};
+
+struct pasemi_mac {
+ struct net_device *netdev;
+ struct pci_dev *pdev;
+ struct pci_dev *dma_pdev;
+ struct pci_dev *iob_pdev;
+ struct net_device_stats stats;
+
+ /* Pointer to the cacheable per-channel status registers */
+ u64 *rx_status;
+ u64 *tx_status;
+
+ u8 type;
+#define MAC_TYPE_GMAC 1
+#define MAC_TYPE_XAUI 2
+ u32 dma_txch;
+ u32 dma_if;
+ u32 dma_rxch;
+
+ u8 mac_addr[6];
+
+ struct timer_list rxtimer;
+
+ struct pasemi_mac_txring *tx;
+ struct pasemi_mac_rxring *rx;
+};
+
+/* Software status descriptor (desc_info) */
+struct pasemi_mac_buffer {
+ struct sk_buff *skb;
+ dma_addr_t dma;
+};
+
+
+/* status register layout in IOB region, at 0xfb800000 */
+struct pasdma_status {
+ u64 rx_sta[64];
+ u64 tx_sta[20];
+};
+
+/* descriptor structure */
+struct pas_dma_xct_descr {
+ union {
+ u64 mactx;
+ u64 macrx;
+ };
+ union {
+ u64 ptr;
+ u64 rxb;
+ };
+};
+
+/* MAC CFG register offsets */
+
+enum {
+ PAS_MAC_CFG_PCFG = 0x80,
+ PAS_MAC_CFG_TXP = 0x98,
+ PAS_MAC_IPC_CHNL = 0x208,
+};
+
+/* MAC CFG register fields */
+#define PAS_MAC_CFG_PCFG_PE 0x80000000
+#define PAS_MAC_CFG_PCFG_CE 0x40000000
+#define PAS_MAC_CFG_PCFG_BU 0x20000000
+#define PAS_MAC_CFG_PCFG_TT 0x10000000
+#define PAS_MAC_CFG_PCFG_TSR_M 0x0c000000
+#define PAS_MAC_CFG_PCFG_TSR_10M 0x00000000
+#define PAS_MAC_CFG_PCFG_TSR_100M 0x04000000
+#define PAS_MAC_CFG_PCFG_TSR_1G 0x08000000
+#define PAS_MAC_CFG_PCFG_TSR_10G 0x0c000000
+#define PAS_MAC_CFG_PCFG_T24 0x02000000
+#define PAS_MAC_CFG_PCFG_PR 0x01000000
+#define PAS_MAC_CFG_PCFG_CRO_M 0x00ff0000
+#define PAS_MAC_CFG_PCFG_CRO_S 16
+#define PAS_MAC_CFG_PCFG_IPO_M 0x0000ff00
+#define PAS_MAC_CFG_PCFG_IPO_S 8
+#define PAS_MAC_CFG_PCFG_S1 0x00000080
+#define PAS_MAC_CFG_PCFG_IO_M 0x00000060
+#define PAS_MAC_CFG_PCFG_IO_MAC 0x00000000
+#define PAS_MAC_CFG_PCFG_IO_OFF 0x00000020
+#define PAS_MAC_CFG_PCFG_IO_IND_ETH 0x00000040
+#define PAS_MAC_CFG_PCFG_IO_IND_IP 0x00000060
+#define PAS_MAC_CFG_PCFG_LP 0x00000010
+#define PAS_MAC_CFG_PCFG_TS 0x00000008
+#define PAS_MAC_CFG_PCFG_HD 0x00000004
+#define PAS_MAC_CFG_PCFG_SPD_M 0x00000003
+#define PAS_MAC_CFG_PCFG_SPD_10M 0x00000000
+#define PAS_MAC_CFG_PCFG_SPD_100M 0x00000001
+#define PAS_MAC_CFG_PCFG_SPD_1G 0x00000002
+#define PAS_MAC_CFG_PCFG_SPD_10G 0x00000003
+#define PAS_MAC_CFG_TXP_FCF 0x01000000
+#define PAS_MAC_CFG_TXP_FCE 0x00800000
+#define PAS_MAC_CFG_TXP_FC 0x00400000
+#define PAS_MAC_CFG_TXP_FPC_M 0x00300000
+#define PAS_MAC_CFG_TXP_FPC_S 20
+#define PAS_MAC_CFG_TXP_FPC(x) (((x) << PAS_MAC_CFG_TXP_FPC_S) & \
+ PAS_MAC_CFG_TXP_FPC_M)
+#define PAS_MAC_CFG_TXP_RT 0x00080000
+#define PAS_MAC_CFG_TXP_BL 0x00040000
+#define PAS_MAC_CFG_TXP_SL_M 0x00030000
+#define PAS_MAC_CFG_TXP_SL_S 16
+#define PAS_MAC_CFG_TXP_SL(x) (((x) << PAS_MAC_CFG_TXP_SL_S) & \
+ PAS_MAC_CFG_TXP_SL_M)
+#define PAS_MAC_CFG_TXP_COB_M 0x0000f000
+#define PAS_MAC_CFG_TXP_COB_S 12
+#define PAS_MAC_CFG_TXP_COB(x) (((x) << PAS_MAC_CFG_TXP_COB_S) & \
+ PAS_MAC_CFG_TXP_COB_M)
+#define PAS_MAC_CFG_TXP_TIFT_M 0x00000f00
+#define PAS_MAC_CFG_TXP_TIFT_S 8
+#define PAS_MAC_CFG_TXP_TIFT(x) (((x) << PAS_MAC_CFG_TXP_TIFT_S) & \
+ PAS_MAC_CFG_TXP_TIFT_M)
+#define PAS_MAC_CFG_TXP_TIFG_M 0x000000ff
+#define PAS_MAC_CFG_TXP_TIFG_S 0
+#define PAS_MAC_CFG_TXP_TIFG(x) (((x) << PAS_MAC_CFG_TXP_TIFG_S) & \
+ PAS_MAC_CFG_TXP_TIFG_M)
+
+#define PAS_MAC_IPC_CHNL_DCHNO_M 0x003f0000
+#define PAS_MAC_IPC_CHNL_DCHNO_S 16
+#define PAS_MAC_IPC_CHNL_DCHNO(x) (((x) << PAS_MAC_IPC_CHNL_DCHNO_S) & \
+ PAS_MAC_IPC_CHNL_DCHNO_M)
+#define PAS_MAC_IPC_CHNL_BCH_M 0x0000003f
+#define PAS_MAC_IPC_CHNL_BCH_S 0
+#define PAS_MAC_IPC_CHNL_BCH(x) (((x) << PAS_MAC_IPC_CHNL_BCH_S) & \
+ PAS_MAC_IPC_CHNL_BCH_M)
+
+/* All these registers live in the PCI configuration space for the DMA PCI
+ * device. Use the normal PCI config access functions for them.
+ */
+enum {
+ PAS_DMA_COM_TXCMD = 0x100, /* Transmit Command Register */
+ PAS_DMA_COM_TXSTA = 0x104, /* Transmit Status Register */
+ PAS_DMA_COM_RXCMD = 0x108, /* Receive Command Register */
+ PAS_DMA_COM_RXSTA = 0x10c, /* Receive Status Register */
+};
+#define PAS_DMA_COM_TXCMD_EN 0x00000001 /* enable */
+#define PAS_DMA_COM_TXSTA_ACT 0x00000001 /* active */
+#define PAS_DMA_COM_RXCMD_EN 0x00000001 /* enable */
+#define PAS_DMA_COM_RXSTA_ACT 0x00000001 /* active */
+
+
+/* Per-interface and per-channel registers */
+#define _PAS_DMA_RXINT_STRIDE 0x20
+#define PAS_DMA_RXINT_RCMDSTA(i) (0x200+(i)*_PAS_DMA_RXINT_STRIDE)
+#define PAS_DMA_RXINT_RCMDSTA_EN 0x00000001
+#define PAS_DMA_RXINT_RCMDSTA_ST 0x00000002
+#define PAS_DMA_RXINT_RCMDSTA_OO 0x00000100
+#define PAS_DMA_RXINT_RCMDSTA_BP 0x00000200
+#define PAS_DMA_RXINT_RCMDSTA_DR 0x00000400
+#define PAS_DMA_RXINT_RCMDSTA_BT 0x00000800
+#define PAS_DMA_RXINT_RCMDSTA_TB 0x00001000
+#define PAS_DMA_RXINT_RCMDSTA_ACT 0x00010000
+#define PAS_DMA_RXINT_RCMDSTA_DROPS_M 0xfffe0000
+#define PAS_DMA_RXINT_RCMDSTA_DROPS_S 17
+#define PAS_DMA_RXINT_INCR(i) (0x210+(i)*_PAS_DMA_RXINT_STRIDE)
+#define PAS_DMA_RXINT_INCR_INCR_M 0x0000ffff
+#define PAS_DMA_RXINT_INCR_INCR_S 0
+#define PAS_DMA_RXINT_INCR_INCR(x) ((x) & 0x0000ffff)
+#define PAS_DMA_RXINT_BASEL(i) (0x218+(i)*_PAS_DMA_RXINT_STRIDE)
+#define PAS_DMA_RXINT_BASEL_BRBL(x) ((x) & ~0x3f)
+#define PAS_DMA_RXINT_BASEU(i) (0x21c+(i)*_PAS_DMA_RXINT_STRIDE)
+#define PAS_DMA_RXINT_BASEU_BRBH(x) ((x) & 0xfff)
+#define PAS_DMA_RXINT_BASEU_SIZ_M 0x3fff0000 /* # of cache lines worth of buffer ring */
+#define PAS_DMA_RXINT_BASEU_SIZ_S 16 /* 0 = 16K */
+#define PAS_DMA_RXINT_BASEU_SIZ(x) (((x) << PAS_DMA_RXINT_BASEU_SIZ_S) & \
+ PAS_DMA_RXINT_BASEU_SIZ_M)
+
+
+#define _PAS_DMA_TXCHAN_STRIDE 0x20 /* Size per channel */
+#define _PAS_DMA_TXCHAN_TCMDSTA 0x300 /* Command / Status */
+#define _PAS_DMA_TXCHAN_CFG 0x304 /* Configuration */
+#define _PAS_DMA_TXCHAN_DSCRBU 0x308 /* Descriptor BU Allocation */
+#define _PAS_DMA_TXCHAN_INCR 0x310 /* Descriptor increment */
+#define _PAS_DMA_TXCHAN_CNT 0x314 /* Descriptor count/offset */
+#define _PAS_DMA_TXCHAN_BASEL 0x318 /* Descriptor ring base (low) */
+#define _PAS_DMA_TXCHAN_BASEU 0x31c /* (high) */
+#define PAS_DMA_TXCHAN_TCMDSTA(c) (0x300+(c)*_PAS_DMA_TXCHAN_STRIDE)
+#define PAS_DMA_TXCHAN_TCMDSTA_EN 0x00000001 /* Enabled */
+#define PAS_DMA_TXCHAN_TCMDSTA_ST 0x00000002 /* Stop interface */
+#define PAS_DMA_TXCHAN_TCMDSTA_ACT 0x00010000 /* Active */
+#define PAS_DMA_TXCHAN_CFG(c) (0x304+(c)*_PAS_DMA_TXCHAN_STRIDE)
+#define PAS_DMA_TXCHAN_CFG_TY_IFACE 0x00000000 /* Type = interface */
+#define PAS_DMA_TXCHAN_CFG_TATTR_M 0x0000003c
+#define PAS_DMA_TXCHAN_CFG_TATTR_S 2
+#define PAS_DMA_TXCHAN_CFG_TATTR(x) (((x) << PAS_DMA_TXCHAN_CFG_TATTR_S) & \
+ PAS_DMA_TXCHAN_CFG_TATTR_M)
+#define PAS_DMA_TXCHAN_CFG_WT_M 0x000001c0
+#define PAS_DMA_TXCHAN_CFG_WT_S 6
+#define PAS_DMA_TXCHAN_CFG_WT(x) (((x) << PAS_DMA_TXCHAN_CFG_WT_S) & \
+ PAS_DMA_TXCHAN_CFG_WT_M)
+#define PAS_DMA_TXCHAN_CFG_CF 0x00001000 /* Clean first line */
+#define PAS_DMA_TXCHAN_CFG_CL 0x00002000 /* Clean last line */
+#define PAS_DMA_TXCHAN_CFG_UP 0x00004000 /* update tx descr when sent */
+#define PAS_DMA_TXCHAN_INCR(c) (0x310+(c)*_PAS_DMA_TXCHAN_STRIDE)
+#define PAS_DMA_TXCHAN_BASEL(c) (0x318+(c)*_PAS_DMA_TXCHAN_STRIDE)
+#define PAS_DMA_TXCHAN_BASEL_BRBL_M 0xffffffc0
+#define PAS_DMA_TXCHAN_BASEL_BRBL_S 0
+#define PAS_DMA_TXCHAN_BASEL_BRBL(x) (((x) << PAS_DMA_TXCHAN_BASEL_BRBL_S) & \
+ PAS_DMA_TXCHAN_BASEL_BRBL_M)
+#define PAS_DMA_TXCHAN_BASEU(c) (0x31c+(c)*_PAS_DMA_TXCHAN_STRIDE)
+#define PAS_DMA_TXCHAN_BASEU_BRBH_M 0x00000fff
+#define PAS_DMA_TXCHAN_BASEU_BRBH_S 0
+#define PAS_DMA_TXCHAN_BASEU_BRBH(x) (((x) << PAS_DMA_TXCHAN_BASEU_BRBH_S) & \
+ PAS_DMA_TXCHAN_BASEU_BRBH_M)
+/* # of cache lines worth of buffer ring */
+#define PAS_DMA_TXCHAN_BASEU_SIZ_M 0x3fff0000
+#define PAS_DMA_TXCHAN_BASEU_SIZ_S 16 /* 0 = 16K */
+#define PAS_DMA_TXCHAN_BASEU_SIZ(x) (((x) << PAS_DMA_TXCHAN_BASEU_SIZ_S) & \
+ PAS_DMA_TXCHAN_BASEU_SIZ_M)
+
+#define _PAS_DMA_RXCHAN_STRIDE 0x20 /* Size per channel */
+#define _PAS_DMA_RXCHAN_CCMDSTA 0x800 /* Command / Status */
+#define _PAS_DMA_RXCHAN_CFG 0x804 /* Configuration */
+#define _PAS_DMA_RXCHAN_INCR 0x810 /* Descriptor increment */
+#define _PAS_DMA_RXCHAN_CNT 0x814 /* Descriptor count/offset */
+#define _PAS_DMA_RXCHAN_BASEL 0x818 /* Descriptor ring base (low) */
+#define _PAS_DMA_RXCHAN_BASEU 0x81c /* (high) */
+#define PAS_DMA_RXCHAN_CCMDSTA(c) (0x800+(c)*_PAS_DMA_RXCHAN_STRIDE)
+#define PAS_DMA_RXCHAN_CCMDSTA_EN 0x00000001 /* Enabled */
+#define PAS_DMA_RXCHAN_CCMDSTA_ST 0x00000002 /* Stop interface */
+#define PAS_DMA_RXCHAN_CCMDSTA_ACT 0x00010000 /* Active */
+#define PAS_DMA_RXCHAN_CCMDSTA_DU 0x00020000
+#define PAS_DMA_RXCHAN_CFG(c) (0x804+(c)*_PAS_DMA_RXCHAN_STRIDE)
+#define PAS_DMA_RXCHAN_CFG_HBU_M 0x00000380
+#define PAS_DMA_RXCHAN_CFG_HBU_S 7
+#define PAS_DMA_RXCHAN_CFG_HBU(x) (((x) << PAS_DMA_RXCHAN_CFG_HBU_S) & \
+ PAS_DMA_RXCHAN_CFG_HBU_M)
+#define PAS_DMA_RXCHAN_INCR(c) (0x810+(c)*_PAS_DMA_RXCHAN_STRIDE)
+#define PAS_DMA_RXCHAN_BASEL(c) (0x818+(c)*_PAS_DMA_RXCHAN_STRIDE)
+#define PAS_DMA_RXCHAN_BASEL_BRBL_M 0xffffffc0
+#define PAS_DMA_RXCHAN_BASEL_BRBL_S 0
+#define PAS_DMA_RXCHAN_BASEL_BRBL(x) (((x) << PAS_DMA_RXCHAN_BASEL_BRBL_S) & \
+ PAS_DMA_RXCHAN_BASEL_BRBL_M)
+#define PAS_DMA_RXCHAN_BASEU(c) (0x81c+(c)*_PAS_DMA_RXCHAN_STRIDE)
+#define PAS_DMA_RXCHAN_BASEU_BRBH_M 0x00000fff
+#define PAS_DMA_RXCHAN_BASEU_BRBH_S 0
+#define PAS_DMA_RXCHAN_BASEU_BRBH(x) (((x) << PAS_DMA_RXCHAN_BASEU_BRBH_S) & \
+ PAS_DMA_RXCHAN_BASEU_BRBH_M)
+/* # of cache lines worth of buffer ring */
+#define PAS_DMA_RXCHAN_BASEU_SIZ_M 0x3fff0000
+#define PAS_DMA_RXCHAN_BASEU_SIZ_S 16 /* 0 = 16K */
+#define PAS_DMA_RXCHAN_BASEU_SIZ(x) (((x) << PAS_DMA_RXCHAN_BASEU_SIZ_S) & \
+ PAS_DMA_RXCHAN_BASEU_SIZ_M)
+
+#define PAS_STATUS_PCNT_M 0x000000000000ffffull
+#define PAS_STATUS_PCNT_S 0
+#define PAS_STATUS_DCNT_M 0x00000000ffff0000ull
+#define PAS_STATUS_DCNT_S 16
+#define PAS_STATUS_BPCNT_M 0x0000ffff00000000ull
+#define PAS_STATUS_BPCNT_S 32
+#define PAS_STATUS_TIMER 0x1000000000000000ull
+#define PAS_STATUS_ERROR 0x2000000000000000ull
+#define PAS_STATUS_SOFT 0x4000000000000000ull
+#define PAS_STATUS_INT 0x8000000000000000ull
+
+#define PAS_IOB_DMA_RXCH_CFG(i) (0x1100 + (i)*4)
+#define PAS_IOB_DMA_RXCH_CFG_CNTTH_M 0x00000fff
+#define PAS_IOB_DMA_RXCH_CFG_CNTTH_S 0
+#define PAS_IOB_DMA_RXCH_CFG_CNTTH(x) (((x) << PAS_IOB_DMA_RXCH_CFG_CNTTH_S) & \
+ PAS_IOB_DMA_RXCH_CFG_CNTTH_M)
+#define PAS_IOB_DMA_TXCH_CFG(i) (0x1200 + (i)*4)
+#define PAS_IOB_DMA_TXCH_CFG_CNTTH_M 0x00000fff
+#define PAS_IOB_DMA_TXCH_CFG_CNTTH_S 0
+#define PAS_IOB_DMA_TXCH_CFG_CNTTH(x) (((x) << PAS_IOB_DMA_TXCH_CFG_CNTTH_S) & \
+ PAS_IOB_DMA_TXCH_CFG_CNTTH_M)
+#define PAS_IOB_DMA_RXCH_STAT(i) (0x1300 + (i)*4)
+#define PAS_IOB_DMA_RXCH_STAT_INTGEN 0x00001000
+#define PAS_IOB_DMA_RXCH_STAT_CNTDEL_M 0x00000fff
+#define PAS_IOB_DMA_RXCH_STAT_CNTDEL_S 0
+#define PAS_IOB_DMA_RXCH_STAT_CNTDEL(x) (((x) << PAS_IOB_DMA_RXCH_STAT_CNTDEL_S) &\
+ PAS_IOB_DMA_RXCH_STAT_CNTDEL_M)
+#define PAS_IOB_DMA_TXCH_STAT(i) (0x1400 + (i)*4)
+#define PAS_IOB_DMA_TXCH_STAT_INTGEN 0x00001000
+#define PAS_IOB_DMA_TXCH_STAT_CNTDEL_M 0x00000fff
+#define PAS_IOB_DMA_TXCH_STAT_CNTDEL_S 0
+#define PAS_IOB_DMA_TXCH_STAT_CNTDEL(x) (((x) << PAS_IOB_DMA_TXCH_STAT_CNTDEL_S) &\
+ PAS_IOB_DMA_TXCH_STAT_CNTDEL_M)
+#define PAS_IOB_DMA_RXCH_RESET(i) (0x1500 + (i)*4)
+#define PAS_IOB_DMA_RXCH_RESET_PCNT_M 0xffff0000
+#define PAS_IOB_DMA_RXCH_RESET_PCNT_S 0
+#define PAS_IOB_DMA_RXCH_RESET_PCNT(x) (((x) << PAS_IOB_DMA_RXCH_RESET_PCNT_S) & \
+ PAS_IOB_DMA_RXCH_RESET_PCNT_M)
+#define PAS_IOB_DMA_RXCH_RESET_PCNTRST 0x00000020
+#define PAS_IOB_DMA_RXCH_RESET_DCNTRST 0x00000010
+#define PAS_IOB_DMA_RXCH_RESET_TINTC 0x00000008
+#define PAS_IOB_DMA_RXCH_RESET_DINTC 0x00000004
+#define PAS_IOB_DMA_RXCH_RESET_SINTC 0x00000002
+#define PAS_IOB_DMA_RXCH_RESET_PINTC 0x00000001
+#define PAS_IOB_DMA_TXCH_RESET(i) (0x1600 + (i)*4)
+#define PAS_IOB_DMA_TXCH_RESET_PCNT_M 0xffff0000
+#define PAS_IOB_DMA_TXCH_RESET_PCNT_S 0
+#define PAS_IOB_DMA_TXCH_RESET_PCNT(x) (((x) << PAS_IOB_DMA_TXCH_RESET_PCNT_S) & \
+ PAS_IOB_DMA_TXCH_RESET_PCNT_M)
+#define PAS_IOB_DMA_TXCH_RESET_PCNTRST 0x00000020
+#define PAS_IOB_DMA_TXCH_RESET_DCNTRST 0x00000010
+#define PAS_IOB_DMA_TXCH_RESET_TINTC 0x00000008
+#define PAS_IOB_DMA_TXCH_RESET_DINTC 0x00000004
+#define PAS_IOB_DMA_TXCH_RESET_SINTC 0x00000002
+#define PAS_IOB_DMA_TXCH_RESET_PINTC 0x00000001
+
+#define PAS_IOB_DMA_COM_TIMEOUTCFG 0x1700
+#define PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_M 0x00ffffff
+#define PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_S 0
+#define PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(x) (((x) << PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_S) & \
+ PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_M)
+
+/* Transmit descriptor fields */
+#define XCT_MACTX_T 0x8000000000000000ull
+#define XCT_MACTX_ST 0x4000000000000000ull
+#define XCT_MACTX_NORES 0x0000000000000000ull
+#define XCT_MACTX_8BRES 0x1000000000000000ull
+#define XCT_MACTX_24BRES 0x2000000000000000ull
+#define XCT_MACTX_40BRES 0x3000000000000000ull
+#define XCT_MACTX_I 0x0800000000000000ull
+#define XCT_MACTX_O 0x0400000000000000ull
+#define XCT_MACTX_E 0x0200000000000000ull
+#define XCT_MACTX_VLAN_M 0x0180000000000000ull
+#define XCT_MACTX_VLAN_NOP 0x0000000000000000ull
+#define XCT_MACTX_VLAN_REMOVE 0x0080000000000000ull
+#define XCT_MACTX_VLAN_INSERT 0x0100000000000000ull
+#define XCT_MACTX_VLAN_REPLACE 0x0180000000000000ull
+#define XCT_MACTX_CRC_M 0x0060000000000000ull
+#define XCT_MACTX_CRC_NOP 0x0000000000000000ull
+#define XCT_MACTX_CRC_INSERT 0x0020000000000000ull
+#define XCT_MACTX_CRC_PAD 0x0040000000000000ull
+#define XCT_MACTX_CRC_REPLACE 0x0060000000000000ull
+#define XCT_MACTX_SS 0x0010000000000000ull
+#define XCT_MACTX_LLEN_M 0x00007fff00000000ull
+#define XCT_MACTX_LLEN_S 32ull
+#define XCT_MACTX_LLEN(x) ((((long)(x)) << XCT_MACTX_LLEN_S) & \
+ XCT_MACTX_LLEN_M)
+#define XCT_MACTX_IPH_M 0x00000000f8000000ull
+#define XCT_MACTX_IPH_S 27ull
+#define XCT_MACTX_IPH(x) ((((long)(x)) << XCT_MACTX_IPH_S) & \
+ XCT_MACTX_IPH_M)
+#define XCT_MACTX_IPO_M 0x0000000007c00000ull
+#define XCT_MACTX_IPO_S 22ull
+#define XCT_MACTX_IPO(x) ((((long)(x)) << XCT_MACTX_IPO_S) & \
+ XCT_MACTX_IPO_M)
+#define XCT_MACTX_CSUM_M 0x0000000000000060ull
+#define XCT_MACTX_CSUM_NOP 0x0000000000000000ull
+#define XCT_MACTX_CSUM_TCP 0x0000000000000040ull
+#define XCT_MACTX_CSUM_UDP 0x0000000000000060ull
+#define XCT_MACTX_V6 0x0000000000000010ull
+#define XCT_MACTX_C 0x0000000000000004ull
+#define XCT_MACTX_AL2 0x0000000000000002ull
+
+/* Receive descriptor fields */
+#define XCT_MACRX_T 0x8000000000000000ull
+#define XCT_MACRX_ST 0x4000000000000000ull
+#define XCT_MACRX_NORES 0x0000000000000000ull
+#define XCT_MACRX_8BRES 0x1000000000000000ull
+#define XCT_MACRX_24BRES 0x2000000000000000ull
+#define XCT_MACRX_40BRES 0x3000000000000000ull
+#define XCT_MACRX_O 0x0400000000000000ull
+#define XCT_MACRX_E 0x0200000000000000ull
+#define XCT_MACRX_FF 0x0100000000000000ull
+#define XCT_MACRX_PF 0x0080000000000000ull
+#define XCT_MACRX_OB 0x0040000000000000ull
+#define XCT_MACRX_OD 0x0020000000000000ull
+#define XCT_MACRX_FS 0x0010000000000000ull
+#define XCT_MACRX_NB_M 0x000fc00000000000ull
+#define XCT_MACRX_NB_S 46ULL
+#define XCT_MACRX_NB(x) ((((long)(x)) << XCT_MACRX_NB_S) & \
+ XCT_MACRX_NB_M)
+#define XCT_MACRX_LLEN_M 0x00003fff00000000ull
+#define XCT_MACRX_LLEN_S 32ULL
+#define XCT_MACRX_LLEN(x) ((((long)(x)) << XCT_MACRX_LLEN_S) & \
+ XCT_MACRX_LLEN_M)
+#define XCT_MACRX_CRC 0x0000000080000000ull
+#define XCT_MACRX_LEN_M 0x0000000060000000ull
+#define XCT_MACRX_LEN_TOOSHORT 0x0000000020000000ull
+#define XCT_MACRX_LEN_BELOWMIN 0x0000000040000000ull
+#define XCT_MACRX_LEN_TRUNC 0x0000000060000000ull
+#define XCT_MACRX_CAST_M 0x0000000018000000ull
+#define XCT_MACRX_CAST_UNI 0x0000000000000000ull
+#define XCT_MACRX_CAST_MULTI 0x0000000008000000ull
+#define XCT_MACRX_CAST_BROAD 0x0000000010000000ull
+#define XCT_MACRX_CAST_PAUSE 0x0000000018000000ull
+#define XCT_MACRX_VLC_M 0x0000000006000000ull
+#define XCT_MACRX_FM 0x0000000001000000ull
+#define XCT_MACRX_HTY_M 0x0000000000c00000ull
+#define XCT_MACRX_HTY_IPV4_OK 0x0000000000000000ull
+#define XCT_MACRX_HTY_IPV6 0x0000000000400000ull
+#define XCT_MACRX_HTY_IPV4_BAD 0x0000000000800000ull
+#define XCT_MACRX_HTY_NONIP 0x0000000000c00000ull
+#define XCT_MACRX_IPP_M 0x00000000003f0000ull
+#define XCT_MACRX_IPP_S 16
+#define XCT_MACRX_CSUM_M 0x000000000000ffffull
+#define XCT_MACRX_CSUM_S 0
+
+#define XCT_PTR_T 0x8000000000000000ull
+#define XCT_PTR_LEN_M 0x7ffff00000000000ull
+#define XCT_PTR_LEN_S 44
+#define XCT_PTR_LEN(x) ((((long)(x)) << XCT_PTR_LEN_S) & \
+ XCT_PTR_LEN_M)
+#define XCT_PTR_ADDR_M 0x00000fffffffffffull
+#define XCT_PTR_ADDR_S 0
+#define XCT_PTR_ADDR(x) ((((long)(x)) << XCT_PTR_ADDR_S) & \
+ XCT_PTR_ADDR_M)
+
+/* Receive interface buffer fields */
+#define XCT_RXB_LEN_M 0x0ffff00000000000ull
+#define XCT_RXB_LEN_S 44
+#define XCT_RXB_LEN(x) ((((long)(x)) << XCT_PTR_LEN_S) & XCT_PTR_LEN_M)
+#define XCT_RXB_ADDR_M 0x00000fffffffffffull
+#define XCT_RXB_ADDR_S 0
+#define XCT_RXB_ADDR(x) ((((long)(x)) << XCT_PTR_ADDR_S) & XCT_PTR_ADDR_M)
+
+
+#endif /* PASEMI_MAC_H */
diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c
index 8844c20eac2..2429b274f0b 100644..100755
--- a/drivers/net/qla3xxx.c
+++ b/drivers/net/qla3xxx.c
@@ -22,6 +22,7 @@
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/ip.h>
+#include <linux/in.h>
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/netdevice.h>
@@ -63,6 +64,7 @@ MODULE_PARM_DESC(msi, "Turn on Message Signaled Interrupts.");
static struct pci_device_id ql3xxx_pci_tbl[] __devinitdata = {
{PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QL3022_DEVICE_ID)},
+ {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QL3032_DEVICE_ID)},
/* required last entry */
{0,}
};
@@ -1475,6 +1477,10 @@ static int ql_mii_setup(struct ql3_adapter *qdev)
2) << 7))
return -1;
+ if (qdev->device_id == QL3032_DEVICE_ID)
+ ql_write_page0_reg(qdev,
+ &port_regs->macMIIMgmtControlReg, 0x0f00000);
+
/* Divide 125MHz clock by 28 to meet PHY timing requirements */
reg = MAC_MII_CONTROL_CLK_SEL_DIV28;
@@ -1706,18 +1712,42 @@ static void ql_process_mac_tx_intr(struct ql3_adapter *qdev,
struct ob_mac_iocb_rsp *mac_rsp)
{
struct ql_tx_buf_cb *tx_cb;
+ int i;
tx_cb = &qdev->tx_buf[mac_rsp->transaction_id];
pci_unmap_single(qdev->pdev,
- pci_unmap_addr(tx_cb, mapaddr),
- pci_unmap_len(tx_cb, maplen), PCI_DMA_TODEVICE);
- dev_kfree_skb_irq(tx_cb->skb);
+ pci_unmap_addr(&tx_cb->map[0], mapaddr),
+ pci_unmap_len(&tx_cb->map[0], maplen),
+ PCI_DMA_TODEVICE);
+ tx_cb->seg_count--;
+ if (tx_cb->seg_count) {
+ for (i = 1; i < tx_cb->seg_count; i++) {
+ pci_unmap_page(qdev->pdev,
+ pci_unmap_addr(&tx_cb->map[i],
+ mapaddr),
+ pci_unmap_len(&tx_cb->map[i], maplen),
+ PCI_DMA_TODEVICE);
+ }
+ }
qdev->stats.tx_packets++;
qdev->stats.tx_bytes += tx_cb->skb->len;
+ dev_kfree_skb_irq(tx_cb->skb);
tx_cb->skb = NULL;
atomic_inc(&qdev->tx_count);
}
+/*
+ * The difference between 3022 and 3032 for inbound completions:
+ * 3022 uses two buffers per completion. The first buffer contains
+ * (some) header info, the second the remainder of the headers plus
+ * the data. For this chip we reserve some space at the top of the
+ * receive buffer so that the header info in buffer one can be
+ * prepended to the buffer two. Buffer two is the sent up while
+ * buffer one is returned to the hardware to be reused.
+ * 3032 receives all of it's data and headers in one buffer for a
+ * simpler process. 3032 also supports checksum verification as
+ * can be seen in ql_process_macip_rx_intr().
+ */
static void ql_process_mac_rx_intr(struct ql3_adapter *qdev,
struct ib_mac_iocb_rsp *ib_mac_rsp_ptr)
{
@@ -1740,14 +1770,17 @@ static void ql_process_mac_rx_intr(struct ql3_adapter *qdev,
qdev->last_rsp_offset = qdev->small_buf_phy_addr_low + offset;
qdev->small_buf_release_cnt++;
- /* start of first buffer */
- lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
- lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index];
- qdev->lrg_buf_release_cnt++;
- if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
- qdev->lrg_buf_index = 0;
- curr_ial_ptr++; /* 64-bit pointers require two incs. */
- curr_ial_ptr++;
+ if (qdev->device_id == QL3022_DEVICE_ID) {
+ /* start of first buffer (3022 only) */
+ lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
+ lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index];
+ qdev->lrg_buf_release_cnt++;
+ if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS) {
+ qdev->lrg_buf_index = 0;
+ }
+ curr_ial_ptr++; /* 64-bit pointers require two incs. */
+ curr_ial_ptr++;
+ }
/* start of second buffer */
lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
@@ -1778,7 +1811,8 @@ static void ql_process_mac_rx_intr(struct ql3_adapter *qdev,
qdev->ndev->last_rx = jiffies;
lrg_buf_cb2->skb = NULL;
- ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb1);
+ if (qdev->device_id == QL3022_DEVICE_ID)
+ ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb1);
ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb2);
}
@@ -1790,7 +1824,7 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev,
struct ql_rcv_buf_cb *lrg_buf_cb1 = NULL;
struct ql_rcv_buf_cb *lrg_buf_cb2 = NULL;
u32 *curr_ial_ptr;
- struct sk_buff *skb1, *skb2;
+ struct sk_buff *skb1 = NULL, *skb2;
struct net_device *ndev = qdev->ndev;
u16 length = le16_to_cpu(ib_ip_rsp_ptr->length);
u16 size = 0;
@@ -1806,16 +1840,20 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev,
qdev->last_rsp_offset = qdev->small_buf_phy_addr_low + offset;
qdev->small_buf_release_cnt++;
- /* start of first buffer */
- lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
- lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index];
-
- qdev->lrg_buf_release_cnt++;
- if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
- qdev->lrg_buf_index = 0;
- skb1 = lrg_buf_cb1->skb;
- curr_ial_ptr++; /* 64-bit pointers require two incs. */
- curr_ial_ptr++;
+ if (qdev->device_id == QL3022_DEVICE_ID) {
+ /* start of first buffer on 3022 */
+ lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
+ lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index];
+ qdev->lrg_buf_release_cnt++;
+ if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
+ qdev->lrg_buf_index = 0;
+ skb1 = lrg_buf_cb1->skb;
+ curr_ial_ptr++; /* 64-bit pointers require two incs. */
+ curr_ial_ptr++;
+ size = ETH_HLEN;
+ if (*((u16 *) skb1->data) != 0xFFFF)
+ size += VLAN_ETH_HLEN - ETH_HLEN;
+ }
/* start of second buffer */
lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
@@ -1825,18 +1863,6 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev,
if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
qdev->lrg_buf_index = 0;
- qdev->stats.rx_packets++;
- qdev->stats.rx_bytes += length;
-
- /*
- * Copy the ethhdr from first buffer to second. This
- * is necessary for IP completions.
- */
- if (*((u16 *) skb1->data) != 0xFFFF)
- size = VLAN_ETH_HLEN;
- else
- size = ETH_HLEN;
-
skb_put(skb2, length); /* Just the second buffer length here. */
pci_unmap_single(qdev->pdev,
pci_unmap_addr(lrg_buf_cb2, mapaddr),
@@ -1844,16 +1870,40 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev,
PCI_DMA_FROMDEVICE);
prefetch(skb2->data);
- memcpy(skb_push(skb2, size), skb1->data + VLAN_ID_LEN, size);
- skb2->dev = qdev->ndev;
skb2->ip_summed = CHECKSUM_NONE;
+ if (qdev->device_id == QL3022_DEVICE_ID) {
+ /*
+ * Copy the ethhdr from first buffer to second. This
+ * is necessary for 3022 IP completions.
+ */
+ memcpy(skb_push(skb2, size), skb1->data + VLAN_ID_LEN, size);
+ } else {
+ u16 checksum = le16_to_cpu(ib_ip_rsp_ptr->checksum);
+ if (checksum &
+ (IB_IP_IOCB_RSP_3032_ICE |
+ IB_IP_IOCB_RSP_3032_CE |
+ IB_IP_IOCB_RSP_3032_NUC)) {
+ printk(KERN_ERR
+ "%s: Bad checksum for this %s packet, checksum = %x.\n",
+ __func__,
+ ((checksum &
+ IB_IP_IOCB_RSP_3032_TCP) ? "TCP" :
+ "UDP"),checksum);
+ } else if (checksum & IB_IP_IOCB_RSP_3032_TCP) {
+ skb2->ip_summed = CHECKSUM_UNNECESSARY;
+ }
+ }
+ skb2->dev = qdev->ndev;
skb2->protocol = eth_type_trans(skb2, qdev->ndev);
netif_receive_skb(skb2);
+ qdev->stats.rx_packets++;
+ qdev->stats.rx_bytes += length;
ndev->last_rx = jiffies;
lrg_buf_cb2->skb = NULL;
- ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb1);
+ if (qdev->device_id == QL3022_DEVICE_ID)
+ ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb1);
ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb2);
}
@@ -1880,12 +1930,14 @@ static int ql_tx_rx_clean(struct ql3_adapter *qdev,
break;
case OPCODE_IB_MAC_IOCB:
+ case OPCODE_IB_3032_MAC_IOCB:
ql_process_mac_rx_intr(qdev, (struct ib_mac_iocb_rsp *)
net_rsp);
(*rx_cleaned)++;
break;
case OPCODE_IB_IP_IOCB:
+ case OPCODE_IB_3032_IP_IOCB:
ql_process_macip_rx_intr(qdev, (struct ib_ip_iocb_rsp *)
net_rsp);
(*rx_cleaned)++;
@@ -2032,13 +2084,96 @@ static irqreturn_t ql3xxx_isr(int irq, void *dev_id)
return IRQ_RETVAL(handled);
}
+/*
+ * Get the total number of segments needed for the
+ * given number of fragments. This is necessary because
+ * outbound address lists (OAL) will be used when more than
+ * two frags are given. Each address list has 5 addr/len
+ * pairs. The 5th pair in each AOL is used to point to
+ * the next AOL if more frags are coming.
+ * That is why the frags:segment count ratio is not linear.
+ */
+static int ql_get_seg_count(unsigned short frags)
+{
+ switch(frags) {
+ case 0: return 1; /* just the skb->data seg */
+ case 1: return 2; /* skb->data + 1 frag */
+ case 2: return 3; /* skb->data + 2 frags */
+ case 3: return 5; /* skb->data + 1 frag + 1 AOL containting 2 frags */
+ case 4: return 6;
+ case 5: return 7;
+ case 6: return 8;
+ case 7: return 10;
+ case 8: return 11;
+ case 9: return 12;
+ case 10: return 13;
+ case 11: return 15;
+ case 12: return 16;
+ case 13: return 17;
+ case 14: return 18;
+ case 15: return 20;
+ case 16: return 21;
+ case 17: return 22;
+ case 18: return 23;
+ }
+ return -1;
+}
+
+static void ql_hw_csum_setup(struct sk_buff *skb,
+ struct ob_mac_iocb_req *mac_iocb_ptr)
+{
+ struct ethhdr *eth;
+ struct iphdr *ip = NULL;
+ u8 offset = ETH_HLEN;
+
+ eth = (struct ethhdr *)(skb->data);
+
+ if (eth->h_proto == __constant_htons(ETH_P_IP)) {
+ ip = (struct iphdr *)&skb->data[ETH_HLEN];
+ } else if (eth->h_proto == htons(ETH_P_8021Q) &&
+ ((struct vlan_ethhdr *)skb->data)->
+ h_vlan_encapsulated_proto == __constant_htons(ETH_P_IP)) {
+ ip = (struct iphdr *)&skb->data[VLAN_ETH_HLEN];
+ offset = VLAN_ETH_HLEN;
+ }
+
+ if (ip) {
+ if (ip->protocol == IPPROTO_TCP) {
+ mac_iocb_ptr->flags1 |= OB_3032MAC_IOCB_REQ_TC;
+ mac_iocb_ptr->ip_hdr_off = offset;
+ mac_iocb_ptr->ip_hdr_len = ip->ihl;
+ } else if (ip->protocol == IPPROTO_UDP) {
+ mac_iocb_ptr->flags1 |= OB_3032MAC_IOCB_REQ_UC;
+ mac_iocb_ptr->ip_hdr_off = offset;
+ mac_iocb_ptr->ip_hdr_len = ip->ihl;
+ }
+ }
+}
+
+/*
+ * The difference between 3022 and 3032 sends:
+ * 3022 only supports a simple single segment transmission.
+ * 3032 supports checksumming and scatter/gather lists (fragments).
+ * The 3032 supports sglists by using the 3 addr/len pairs (ALP)
+ * in the IOCB plus a chain of outbound address lists (OAL) that
+ * each contain 5 ALPs. The last ALP of the IOCB (3rd) or OAL (5th)
+ * will used to point to an OAL when more ALP entries are required.
+ * The IOCB is always the top of the chain followed by one or more
+ * OALs (when necessary).
+ */
static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev)
{
struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
struct ql_tx_buf_cb *tx_cb;
+ u32 tot_len = skb->len;
+ struct oal *oal;
+ struct oal_entry *oal_entry;
+ int len;
struct ob_mac_iocb_req *mac_iocb_ptr;
u64 map;
+ int seg_cnt, seg = 0;
+ int frag_cnt = (int)skb_shinfo(skb)->nr_frags;
if (unlikely(atomic_read(&qdev->tx_count) < 2)) {
if (!netif_queue_stopped(ndev))
@@ -2046,21 +2181,79 @@ static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev)
return NETDEV_TX_BUSY;
}
tx_cb = &qdev->tx_buf[qdev->req_producer_index] ;
+ seg_cnt = tx_cb->seg_count = ql_get_seg_count((skb_shinfo(skb)->nr_frags));
+ if(seg_cnt == -1) {
+ printk(KERN_ERR PFX"%s: invalid segment count!\n",__func__);
+ return NETDEV_TX_OK;
+
+ }
mac_iocb_ptr = tx_cb->queue_entry;
memset((void *)mac_iocb_ptr, 0, sizeof(struct ob_mac_iocb_req));
mac_iocb_ptr->opcode = qdev->mac_ob_opcode;
mac_iocb_ptr->flags |= qdev->mb_bit_mask;
mac_iocb_ptr->transaction_id = qdev->req_producer_index;
- mac_iocb_ptr->data_len = cpu_to_le16((u16) skb->len);
+ mac_iocb_ptr->data_len = cpu_to_le16((u16) tot_len);
tx_cb->skb = skb;
- map = pci_map_single(qdev->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
- mac_iocb_ptr->buf_addr0_low = cpu_to_le32(LS_64BITS(map));
- mac_iocb_ptr->buf_addr0_high = cpu_to_le32(MS_64BITS(map));
- mac_iocb_ptr->buf_0_len = cpu_to_le32(skb->len | OB_MAC_IOCB_REQ_E);
- pci_unmap_addr_set(tx_cb, mapaddr, map);
- pci_unmap_len_set(tx_cb, maplen, skb->len);
- atomic_dec(&qdev->tx_count);
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ ql_hw_csum_setup(skb, mac_iocb_ptr);
+ len = skb_headlen(skb);
+ map = pci_map_single(qdev->pdev, skb->data, len, PCI_DMA_TODEVICE);
+ oal_entry = (struct oal_entry *)&mac_iocb_ptr->buf_addr0_low;
+ oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map));
+ oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map));
+ oal_entry->len = cpu_to_le32(len);
+ pci_unmap_addr_set(&tx_cb->map[seg], mapaddr, map);
+ pci_unmap_len_set(&tx_cb->map[seg], maplen, len);
+ seg++;
+
+ if (!skb_shinfo(skb)->nr_frags) {
+ /* Terminate the last segment. */
+ oal_entry->len =
+ cpu_to_le32(le32_to_cpu(oal_entry->len) | OAL_LAST_ENTRY);
+ } else {
+ int i;
+ oal = tx_cb->oal;
+ for (i=0; i<frag_cnt; i++,seg++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ oal_entry++;
+ if ((seg == 2 && seg_cnt > 3) || /* Check for continuation */
+ (seg == 7 && seg_cnt > 8) || /* requirements. It's strange */
+ (seg == 12 && seg_cnt > 13) || /* but necessary. */
+ (seg == 17 && seg_cnt > 18)) {
+ /* Continuation entry points to outbound address list. */
+ map = pci_map_single(qdev->pdev, oal,
+ sizeof(struct oal),
+ PCI_DMA_TODEVICE);
+ oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map));
+ oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map));
+ oal_entry->len =
+ cpu_to_le32(sizeof(struct oal) |
+ OAL_CONT_ENTRY);
+ pci_unmap_addr_set(&tx_cb->map[seg], mapaddr,
+ map);
+ pci_unmap_len_set(&tx_cb->map[seg], maplen,
+ len);
+ oal_entry = (struct oal_entry *)oal;
+ oal++;
+ seg++;
+ }
+ map =
+ pci_map_page(qdev->pdev, frag->page,
+ frag->page_offset, frag->size,
+ PCI_DMA_TODEVICE);
+ oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map));
+ oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map));
+ oal_entry->len = cpu_to_le32(frag->size);
+ pci_unmap_addr_set(&tx_cb->map[seg], mapaddr, map);
+ pci_unmap_len_set(&tx_cb->map[seg], maplen,
+ frag->size);
+ }
+ /* Terminate the last segment. */
+ oal_entry->len =
+ cpu_to_le32(le32_to_cpu(oal_entry->len) | OAL_LAST_ENTRY);
+ }
+ wmb();
qdev->req_producer_index++;
if (qdev->req_producer_index == NUM_REQ_Q_ENTRIES)
qdev->req_producer_index = 0;
@@ -2074,8 +2267,10 @@ static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev)
printk(KERN_DEBUG PFX "%s: tx queued, slot %d, len %d\n",
ndev->name, qdev->req_producer_index, skb->len);
+ atomic_dec(&qdev->tx_count);
return NETDEV_TX_OK;
}
+
static int ql_alloc_net_req_rsp_queues(struct ql3_adapter *qdev)
{
qdev->req_q_size =
@@ -2359,7 +2554,22 @@ static int ql_alloc_large_buffers(struct ql3_adapter *qdev)
return 0;
}
-static void ql_create_send_free_list(struct ql3_adapter *qdev)
+static void ql_free_send_free_list(struct ql3_adapter *qdev)
+{
+ struct ql_tx_buf_cb *tx_cb;
+ int i;
+
+ tx_cb = &qdev->tx_buf[0];
+ for (i = 0; i < NUM_REQ_Q_ENTRIES; i++) {
+ if (tx_cb->oal) {
+ kfree(tx_cb->oal);
+ tx_cb->oal = NULL;
+ }
+ tx_cb++;
+ }
+}
+
+static int ql_create_send_free_list(struct ql3_adapter *qdev)
{
struct ql_tx_buf_cb *tx_cb;
int i;
@@ -2368,11 +2578,16 @@ static void ql_create_send_free_list(struct ql3_adapter *qdev)
/* Create free list of transmit buffers */
for (i = 0; i < NUM_REQ_Q_ENTRIES; i++) {
+
tx_cb = &qdev->tx_buf[i];
tx_cb->skb = NULL;
tx_cb->queue_entry = req_q_curr;
req_q_curr++;
+ tx_cb->oal = kmalloc(512, GFP_KERNEL);
+ if (tx_cb->oal == NULL)
+ return -1;
}
+ return 0;
}
static int ql_alloc_mem_resources(struct ql3_adapter *qdev)
@@ -2447,12 +2662,14 @@ static int ql_alloc_mem_resources(struct ql3_adapter *qdev)
/* Initialize the large buffer queue. */
ql_init_large_buffers(qdev);
- ql_create_send_free_list(qdev);
+ if (ql_create_send_free_list(qdev))
+ goto err_free_list;
qdev->rsp_current = qdev->rsp_q_virt_addr;
return 0;
-
+err_free_list:
+ ql_free_send_free_list(qdev);
err_small_buffers:
ql_free_buffer_queues(qdev);
err_buffer_queues:
@@ -2468,6 +2685,7 @@ err_req_rsp:
static void ql_free_mem_resources(struct ql3_adapter *qdev)
{
+ ql_free_send_free_list(qdev);
ql_free_large_buffers(qdev);
ql_free_small_buffers(qdev);
ql_free_buffer_queues(qdev);
@@ -2766,11 +2984,20 @@ static int ql_adapter_initialize(struct ql3_adapter *qdev)
}
/* Enable Ethernet Function */
- value =
- (PORT_CONTROL_EF | PORT_CONTROL_ET | PORT_CONTROL_EI |
- PORT_CONTROL_HH);
- ql_write_page0_reg(qdev, &port_regs->portControl,
- ((value << 16) | value));
+ if (qdev->device_id == QL3032_DEVICE_ID) {
+ value =
+ (QL3032_PORT_CONTROL_EF | QL3032_PORT_CONTROL_KIE |
+ QL3032_PORT_CONTROL_EIv6 | QL3032_PORT_CONTROL_EIv4);
+ ql_write_page0_reg(qdev, &port_regs->functionControl,
+ ((value << 16) | value));
+ } else {
+ value =
+ (PORT_CONTROL_EF | PORT_CONTROL_ET | PORT_CONTROL_EI |
+ PORT_CONTROL_HH);
+ ql_write_page0_reg(qdev, &port_regs->portControl,
+ ((value << 16) | value));
+ }
+
out:
return status;
@@ -2917,8 +3144,10 @@ static void ql_display_dev_info(struct net_device *ndev)
struct pci_dev *pdev = qdev->pdev;
printk(KERN_INFO PFX
- "\n%s Adapter %d RevisionID %d found on PCI slot %d.\n",
- DRV_NAME, qdev->index, qdev->chip_rev_id, qdev->pci_slot);
+ "\n%s Adapter %d RevisionID %d found %s on PCI slot %d.\n",
+ DRV_NAME, qdev->index, qdev->chip_rev_id,
+ (qdev->device_id == QL3032_DEVICE_ID) ? "QLA3032" : "QLA3022",
+ qdev->pci_slot);
printk(KERN_INFO PFX
"%s Interface.\n",
test_bit(QL_LINK_OPTICAL,&qdev->flags) ? "OPTICAL" : "COPPER");
@@ -3212,15 +3441,22 @@ static void ql_reset_work(struct work_struct *work)
* Loop through the active list and return the skb.
*/
for (i = 0; i < NUM_REQ_Q_ENTRIES; i++) {
+ int j;
tx_cb = &qdev->tx_buf[i];
if (tx_cb->skb) {
-
printk(KERN_DEBUG PFX
"%s: Freeing lost SKB.\n",
qdev->ndev->name);
pci_unmap_single(qdev->pdev,
- pci_unmap_addr(tx_cb, mapaddr),
- pci_unmap_len(tx_cb, maplen), PCI_DMA_TODEVICE);
+ pci_unmap_addr(&tx_cb->map[0], mapaddr),
+ pci_unmap_len(&tx_cb->map[0], maplen),
+ PCI_DMA_TODEVICE);
+ for(j=1;j<tx_cb->seg_count;j++) {
+ pci_unmap_page(qdev->pdev,
+ pci_unmap_addr(&tx_cb->map[j],mapaddr),
+ pci_unmap_len(&tx_cb->map[j],maplen),
+ PCI_DMA_TODEVICE);
+ }
dev_kfree_skb(tx_cb->skb);
tx_cb->skb = NULL;
}
@@ -3379,21 +3615,24 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev,
SET_MODULE_OWNER(ndev);
SET_NETDEV_DEV(ndev, &pdev->dev);
- if (pci_using_dac)
- ndev->features |= NETIF_F_HIGHDMA;
-
pci_set_drvdata(pdev, ndev);
qdev = netdev_priv(ndev);
qdev->index = cards_found;
qdev->ndev = ndev;
qdev->pdev = pdev;
+ qdev->device_id = pci_entry->device;
qdev->port_link_state = LS_DOWN;
if (msi)
qdev->msi = 1;
qdev->msg_enable = netif_msg_init(debug, default_msg);
+ if (pci_using_dac)
+ ndev->features |= NETIF_F_HIGHDMA;
+ if (qdev->device_id == QL3032_DEVICE_ID)
+ ndev->features |= (NETIF_F_HW_CSUM | NETIF_F_SG);
+
qdev->mem_map_registers =
ioremap_nocache(pci_resource_start(pdev, 1),
pci_resource_len(qdev->pdev, 1));
diff --git a/drivers/net/qla3xxx.h b/drivers/net/qla3xxx.h
index ea94de7fd07..b2d76ea6882 100644..100755
--- a/drivers/net/qla3xxx.h
+++ b/drivers/net/qla3xxx.h
@@ -21,7 +21,9 @@
#define OPCODE_UPDATE_NCB_IOCB 0xF0
#define OPCODE_IB_MAC_IOCB 0xF9
+#define OPCODE_IB_3032_MAC_IOCB 0x09
#define OPCODE_IB_IP_IOCB 0xFA
+#define OPCODE_IB_3032_IP_IOCB 0x0A
#define OPCODE_IB_TCP_IOCB 0xFB
#define OPCODE_DUMP_PROTO_IOCB 0xFE
#define OPCODE_BUFFER_ALERT_IOCB 0xFB
@@ -37,18 +39,23 @@
struct ob_mac_iocb_req {
u8 opcode;
u8 flags;
-#define OB_MAC_IOCB_REQ_MA 0xC0
-#define OB_MAC_IOCB_REQ_F 0x20
-#define OB_MAC_IOCB_REQ_X 0x10
+#define OB_MAC_IOCB_REQ_MA 0xe0
+#define OB_MAC_IOCB_REQ_F 0x10
+#define OB_MAC_IOCB_REQ_X 0x08
#define OB_MAC_IOCB_REQ_D 0x02
#define OB_MAC_IOCB_REQ_I 0x01
- __le16 reserved0;
+ u8 flags1;
+#define OB_3032MAC_IOCB_REQ_IC 0x04
+#define OB_3032MAC_IOCB_REQ_TC 0x02
+#define OB_3032MAC_IOCB_REQ_UC 0x01
+ u8 reserved0;
__le32 transaction_id;
__le16 data_len;
- __le16 reserved1;
+ u8 ip_hdr_off;
+ u8 ip_hdr_len;
+ __le32 reserved1;
__le32 reserved2;
- __le32 reserved3;
__le32 buf_addr0_low;
__le32 buf_addr0_high;
__le32 buf_0_len;
@@ -58,8 +65,8 @@ struct ob_mac_iocb_req {
__le32 buf_addr2_low;
__le32 buf_addr2_high;
__le32 buf_2_len;
+ __le32 reserved3;
__le32 reserved4;
- __le32 reserved5;
};
/*
* The following constants define control bits for buffer
@@ -74,6 +81,7 @@ struct ob_mac_iocb_rsp {
u8 opcode;
u8 flags;
#define OB_MAC_IOCB_RSP_P 0x08
+#define OB_MAC_IOCB_RSP_L 0x04
#define OB_MAC_IOCB_RSP_S 0x02
#define OB_MAC_IOCB_RSP_I 0x01
@@ -85,6 +93,7 @@ struct ob_mac_iocb_rsp {
struct ib_mac_iocb_rsp {
u8 opcode;
+#define IB_MAC_IOCB_RSP_V 0x80
u8 flags;
#define IB_MAC_IOCB_RSP_S 0x80
#define IB_MAC_IOCB_RSP_H1 0x40
@@ -138,6 +147,7 @@ struct ob_ip_iocb_req {
struct ob_ip_iocb_rsp {
u8 opcode;
u8 flags;
+#define OB_MAC_IOCB_RSP_H 0x10
#define OB_MAC_IOCB_RSP_E 0x08
#define OB_MAC_IOCB_RSP_L 0x04
#define OB_MAC_IOCB_RSP_S 0x02
@@ -220,6 +230,10 @@ struct ob_tcp_iocb_rsp {
struct ib_ip_iocb_rsp {
u8 opcode;
+#define IB_IP_IOCB_RSP_3032_V 0x80
+#define IB_IP_IOCB_RSP_3032_O 0x40
+#define IB_IP_IOCB_RSP_3032_I 0x20
+#define IB_IP_IOCB_RSP_3032_R 0x10
u8 flags;
#define IB_IP_IOCB_RSP_S 0x80
#define IB_IP_IOCB_RSP_H1 0x40
@@ -230,6 +244,12 @@ struct ib_ip_iocb_rsp {
__le16 length;
__le16 checksum;
+#define IB_IP_IOCB_RSP_3032_ICE 0x01
+#define IB_IP_IOCB_RSP_3032_CE 0x02
+#define IB_IP_IOCB_RSP_3032_NUC 0x04
+#define IB_IP_IOCB_RSP_3032_UDP 0x08
+#define IB_IP_IOCB_RSP_3032_TCP 0x10
+#define IB_IP_IOCB_RSP_3032_IPE 0x20
__le16 reserved;
#define IB_IP_IOCB_RSP_R 0x01
__le32 ial_low;
@@ -524,6 +544,21 @@ enum {
IP_ADDR_INDEX_REG_FUNC_2_SEC = 0x0005,
IP_ADDR_INDEX_REG_FUNC_3_PRI = 0x0006,
IP_ADDR_INDEX_REG_FUNC_3_SEC = 0x0007,
+ IP_ADDR_INDEX_REG_6 = 0x0008,
+ IP_ADDR_INDEX_REG_OFFSET_MASK = 0x0030,
+ IP_ADDR_INDEX_REG_E = 0x0040,
+};
+enum {
+ QL3032_PORT_CONTROL_DS = 0x0001,
+ QL3032_PORT_CONTROL_HH = 0x0002,
+ QL3032_PORT_CONTROL_EIv6 = 0x0004,
+ QL3032_PORT_CONTROL_EIv4 = 0x0008,
+ QL3032_PORT_CONTROL_ET = 0x0010,
+ QL3032_PORT_CONTROL_EF = 0x0020,
+ QL3032_PORT_CONTROL_DRM = 0x0040,
+ QL3032_PORT_CONTROL_RLB = 0x0080,
+ QL3032_PORT_CONTROL_RCB = 0x0100,
+ QL3032_PORT_CONTROL_KIE = 0x0200,
};
enum {
@@ -657,7 +692,8 @@ struct ql3xxx_port_registers {
u32 internalRamWDataReg;
u32 reclaimedBufferAddrRegLow;
u32 reclaimedBufferAddrRegHigh;
- u32 reserved[2];
+ u32 tcpConfiguration;
+ u32 functionControl;
u32 fpgaRevID;
u32 localRamAddr;
u32 localRamDataAutoIncr;
@@ -963,6 +999,7 @@ struct eeprom_data {
#define QL3XXX_VENDOR_ID 0x1077
#define QL3022_DEVICE_ID 0x3022
+#define QL3032_DEVICE_ID 0x3032
/* MTU & Frame Size stuff */
#define NORMAL_MTU_SIZE ETH_DATA_LEN
@@ -1038,11 +1075,41 @@ struct ql_rcv_buf_cb {
int index;
};
+/*
+ * Original IOCB has 3 sg entries:
+ * first points to skb-data area
+ * second points to first frag
+ * third points to next oal.
+ * OAL has 5 entries:
+ * 1 thru 4 point to frags
+ * fifth points to next oal.
+ */
+#define MAX_OAL_CNT ((MAX_SKB_FRAGS-1)/4 + 1)
+
+struct oal_entry {
+ u32 dma_lo;
+ u32 dma_hi;
+ u32 len;
+#define OAL_LAST_ENTRY 0x80000000 /* Last valid buffer in list. */
+#define OAL_CONT_ENTRY 0x40000000 /* points to an OAL. (continuation) */
+ u32 reserved;
+};
+
+struct oal {
+ struct oal_entry oal_entry[5];
+};
+
+struct map_list {
+ DECLARE_PCI_UNMAP_ADDR(mapaddr);
+ DECLARE_PCI_UNMAP_LEN(maplen);
+};
+
struct ql_tx_buf_cb {
struct sk_buff *skb;
struct ob_mac_iocb_req *queue_entry ;
- DECLARE_PCI_UNMAP_ADDR(mapaddr);
- DECLARE_PCI_UNMAP_LEN(maplen);
+ int seg_count;
+ struct oal *oal;
+ struct map_list map[MAX_SKB_FRAGS+1];
};
/* definitions for type field */
@@ -1189,6 +1256,7 @@ struct ql3_adapter {
struct delayed_work reset_work;
struct delayed_work tx_timeout_work;
u32 max_frame_size;
+ u32 device_id;
};
#endif /* _QLA3XXX_H_ */
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 577babd4c93..5598d86380b 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -2016,7 +2016,7 @@ static int rtl8169_alloc_rx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff,
if (!skb)
goto err_out;
- skb_reserve(skb, (align - 1) & (u32)skb->data);
+ skb_reserve(skb, (align - 1) & (unsigned long)skb->data);
*sk_buff = skb;
mapping = pci_map_single(pdev, skb->data, rx_buf_sz,
@@ -2487,7 +2487,7 @@ static inline int rtl8169_try_rx_copy(struct sk_buff **sk_buff, int pkt_size,
skb = dev_alloc_skb(pkt_size + align);
if (skb) {
- skb_reserve(skb, (align - 1) & (u32)skb->data);
+ skb_reserve(skb, (align - 1) & (unsigned long)skb->data);
eth_copy_and_sum(skb, sk_buff[0]->data, pkt_size, 0);
*sk_buff = skb;
rtl8169_mark_to_asic(desc, rx_buf_sz);
diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h
index a914fef4430..0e345cbc2bf 100644
--- a/drivers/net/s2io-regs.h
+++ b/drivers/net/s2io-regs.h
@@ -15,7 +15,7 @@
#define TBD 0
-typedef struct _XENA_dev_config {
+struct XENA_dev_config {
/* Convention: mHAL_XXX is mask, vHAL_XXX is value */
/* General Control-Status Registers */
@@ -300,6 +300,7 @@ typedef struct _XENA_dev_config {
u64 gpio_control;
#define GPIO_CTRL_GPIO_0 BIT(8)
u64 misc_control;
+#define FAULT_BEHAVIOUR BIT(0)
#define EXT_REQ_EN BIT(1)
#define MISC_LINK_STABILITY_PRD(val) vBIT(val,29,3)
@@ -851,9 +852,9 @@ typedef struct _XENA_dev_config {
#define SPI_CONTROL_DONE BIT(6)
u64 spi_data;
#define SPI_DATA_WRITE(data,len) vBIT(data,0,len)
-} XENA_dev_config_t;
+};
-#define XENA_REG_SPACE sizeof(XENA_dev_config_t)
+#define XENA_REG_SPACE sizeof(struct XENA_dev_config)
#define XENA_EEPROM_SPACE (0x01 << 11)
#endif /* _REGS_H */
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index 1dd66b8ea0f..8646b64994a 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -77,7 +77,7 @@
#include "s2io.h"
#include "s2io-regs.h"
-#define DRV_VERSION "2.0.15.2"
+#define DRV_VERSION "2.0.16.1"
/* S2io Driver name & version. */
static char s2io_driver_name[] = "Neterion";
@@ -86,7 +86,7 @@ static char s2io_driver_version[] = DRV_VERSION;
static int rxd_size[4] = {32,48,48,64};
static int rxd_count[4] = {127,85,85,63};
-static inline int RXD_IS_UP2DT(RxD_t *rxdp)
+static inline int RXD_IS_UP2DT(struct RxD_t *rxdp)
{
int ret;
@@ -111,9 +111,9 @@ static inline int RXD_IS_UP2DT(RxD_t *rxdp)
#define TASKLET_IN_USE test_and_set_bit(0, (&sp->tasklet_status))
#define PANIC 1
#define LOW 2
-static inline int rx_buffer_level(nic_t * sp, int rxb_size, int ring)
+static inline int rx_buffer_level(struct s2io_nic * sp, int rxb_size, int ring)
{
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
mac_control = &sp->mac_control;
if (rxb_size <= rxd_count[sp->rxd_mode])
@@ -286,7 +286,7 @@ static char ethtool_stats_keys[][ETH_GSTRING_LEN] = {
static void s2io_vlan_rx_register(struct net_device *dev,
struct vlan_group *grp)
{
- nic_t *nic = dev->priv;
+ struct s2io_nic *nic = dev->priv;
unsigned long flags;
spin_lock_irqsave(&nic->tx_lock, flags);
@@ -297,7 +297,7 @@ static void s2io_vlan_rx_register(struct net_device *dev,
/* Unregister the vlan */
static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid)
{
- nic_t *nic = dev->priv;
+ struct s2io_nic *nic = dev->priv;
unsigned long flags;
spin_lock_irqsave(&nic->tx_lock, flags);
@@ -401,9 +401,10 @@ S2IO_PARM_INT(lro, 0);
* aggregation happens until we hit max IP pkt size(64K)
*/
S2IO_PARM_INT(lro_max_pkts, 0xFFFF);
-#ifndef CONFIG_S2IO_NAPI
S2IO_PARM_INT(indicate_max_pkts, 0);
-#endif
+
+S2IO_PARM_INT(napi, 1);
+S2IO_PARM_INT(ufo, 0);
static unsigned int tx_fifo_len[MAX_TX_FIFOS] =
{DEFAULT_FIFO_0_LEN, [1 ...(MAX_TX_FIFOS - 1)] = DEFAULT_FIFO_1_7_LEN};
@@ -457,14 +458,14 @@ static int init_shared_mem(struct s2io_nic *nic)
u32 size;
void *tmp_v_addr, *tmp_v_addr_next;
dma_addr_t tmp_p_addr, tmp_p_addr_next;
- RxD_block_t *pre_rxd_blk = NULL;
- int i, j, blk_cnt, rx_sz, tx_sz;
+ struct RxD_block *pre_rxd_blk = NULL;
+ int i, j, blk_cnt;
int lst_size, lst_per_page;
struct net_device *dev = nic->dev;
unsigned long tmp;
- buffAdd_t *ba;
+ struct buffAdd *ba;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
mac_control = &nic->mac_control;
@@ -482,13 +483,12 @@ static int init_shared_mem(struct s2io_nic *nic)
return -EINVAL;
}
- lst_size = (sizeof(TxD_t) * config->max_txds);
- tx_sz = lst_size * size;
+ lst_size = (sizeof(struct TxD) * config->max_txds);
lst_per_page = PAGE_SIZE / lst_size;
for (i = 0; i < config->tx_fifo_num; i++) {
int fifo_len = config->tx_cfg[i].fifo_len;
- int list_holder_size = fifo_len * sizeof(list_info_hold_t);
+ int list_holder_size = fifo_len * sizeof(struct list_info_hold);
mac_control->fifos[i].list_info = kmalloc(list_holder_size,
GFP_KERNEL);
if (!mac_control->fifos[i].list_info) {
@@ -579,10 +579,9 @@ static int init_shared_mem(struct s2io_nic *nic)
mac_control->rings[i].block_count;
}
if (nic->rxd_mode == RXD_MODE_1)
- size = (size * (sizeof(RxD1_t)));
+ size = (size * (sizeof(struct RxD1)));
else
- size = (size * (sizeof(RxD3_t)));
- rx_sz = size;
+ size = (size * (sizeof(struct RxD3)));
for (i = 0; i < config->rx_ring_num; i++) {
mac_control->rings[i].rx_curr_get_info.block_index = 0;
@@ -600,7 +599,7 @@ static int init_shared_mem(struct s2io_nic *nic)
(rxd_count[nic->rxd_mode] + 1);
/* Allocating all the Rx blocks */
for (j = 0; j < blk_cnt; j++) {
- rx_block_info_t *rx_blocks;
+ struct rx_block_info *rx_blocks;
int l;
rx_blocks = &mac_control->rings[i].rx_blocks[j];
@@ -620,9 +619,11 @@ static int init_shared_mem(struct s2io_nic *nic)
memset(tmp_v_addr, 0, size);
rx_blocks->block_virt_addr = tmp_v_addr;
rx_blocks->block_dma_addr = tmp_p_addr;
- rx_blocks->rxds = kmalloc(sizeof(rxd_info_t)*
+ rx_blocks->rxds = kmalloc(sizeof(struct rxd_info)*
rxd_count[nic->rxd_mode],
GFP_KERNEL);
+ if (!rx_blocks->rxds)
+ return -ENOMEM;
for (l=0; l<rxd_count[nic->rxd_mode];l++) {
rx_blocks->rxds[l].virt_addr =
rx_blocks->block_virt_addr +
@@ -645,7 +646,7 @@ static int init_shared_mem(struct s2io_nic *nic)
mac_control->rings[i].rx_blocks[(j + 1) %
blk_cnt].block_dma_addr;
- pre_rxd_blk = (RxD_block_t *) tmp_v_addr;
+ pre_rxd_blk = (struct RxD_block *) tmp_v_addr;
pre_rxd_blk->reserved_2_pNext_RxD_block =
(unsigned long) tmp_v_addr_next;
pre_rxd_blk->pNext_RxD_Blk_physical =
@@ -661,14 +662,14 @@ static int init_shared_mem(struct s2io_nic *nic)
blk_cnt = config->rx_cfg[i].num_rxd /
(rxd_count[nic->rxd_mode]+ 1);
mac_control->rings[i].ba =
- kmalloc((sizeof(buffAdd_t *) * blk_cnt),
+ kmalloc((sizeof(struct buffAdd *) * blk_cnt),
GFP_KERNEL);
if (!mac_control->rings[i].ba)
return -ENOMEM;
for (j = 0; j < blk_cnt; j++) {
int k = 0;
mac_control->rings[i].ba[j] =
- kmalloc((sizeof(buffAdd_t) *
+ kmalloc((sizeof(struct buffAdd) *
(rxd_count[nic->rxd_mode] + 1)),
GFP_KERNEL);
if (!mac_control->rings[i].ba[j])
@@ -700,7 +701,7 @@ static int init_shared_mem(struct s2io_nic *nic)
}
/* Allocation and initialization of Statistics block */
- size = sizeof(StatInfo_t);
+ size = sizeof(struct stat_block);
mac_control->stats_mem = pci_alloc_consistent
(nic->pdev, size, &mac_control->stats_mem_phy);
@@ -715,7 +716,7 @@ static int init_shared_mem(struct s2io_nic *nic)
mac_control->stats_mem_sz = size;
tmp_v_addr = mac_control->stats_mem;
- mac_control->stats_info = (StatInfo_t *) tmp_v_addr;
+ mac_control->stats_info = (struct stat_block *) tmp_v_addr;
memset(tmp_v_addr, 0, size);
DBG_PRINT(INIT_DBG, "%s:Ring Mem PHY: 0x%llx\n", dev->name,
(unsigned long long) tmp_p_addr);
@@ -735,7 +736,7 @@ static void free_shared_mem(struct s2io_nic *nic)
int i, j, blk_cnt, size;
void *tmp_v_addr;
dma_addr_t tmp_p_addr;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
int lst_size, lst_per_page;
struct net_device *dev = nic->dev;
@@ -746,7 +747,7 @@ static void free_shared_mem(struct s2io_nic *nic)
mac_control = &nic->mac_control;
config = &nic->config;
- lst_size = (sizeof(TxD_t) * config->max_txds);
+ lst_size = (sizeof(struct TxD) * config->max_txds);
lst_per_page = PAGE_SIZE / lst_size;
for (i = 0; i < config->tx_fifo_num; i++) {
@@ -809,7 +810,7 @@ static void free_shared_mem(struct s2io_nic *nic)
if (!mac_control->rings[i].ba[j])
continue;
while (k != rxd_count[nic->rxd_mode]) {
- buffAdd_t *ba =
+ struct buffAdd *ba =
&mac_control->rings[i].ba[j][k];
kfree(ba->ba_0_org);
kfree(ba->ba_1_org);
@@ -835,9 +836,9 @@ static void free_shared_mem(struct s2io_nic *nic)
* s2io_verify_pci_mode -
*/
-static int s2io_verify_pci_mode(nic_t *nic)
+static int s2io_verify_pci_mode(struct s2io_nic *nic)
{
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
register u64 val64 = 0;
int mode;
@@ -868,9 +869,9 @@ static int bus_speed[8] = {33, 133, 133, 200, 266, 133, 200, 266};
/**
* s2io_print_pci_mode -
*/
-static int s2io_print_pci_mode(nic_t *nic)
+static int s2io_print_pci_mode(struct s2io_nic *nic)
{
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
register u64 val64 = 0;
int mode;
struct config_param *config = &nic->config;
@@ -938,13 +939,13 @@ static int s2io_print_pci_mode(nic_t *nic)
static int init_nic(struct s2io_nic *nic)
{
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
struct net_device *dev = nic->dev;
register u64 val64 = 0;
void __iomem *add;
u32 time;
int i, j;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
int dtx_cnt = 0;
unsigned long long mem_share;
@@ -1414,7 +1415,7 @@ static int init_nic(struct s2io_nic *nic)
val64 = TTI_DATA2_MEM_TX_UFC_A(0x10) |
TTI_DATA2_MEM_TX_UFC_B(0x20) |
- TTI_DATA2_MEM_TX_UFC_C(0x70) | TTI_DATA2_MEM_TX_UFC_D(0x80);
+ TTI_DATA2_MEM_TX_UFC_C(0x40) | TTI_DATA2_MEM_TX_UFC_D(0x80);
writeq(val64, &bar0->tti_data2_mem);
val64 = TTI_CMD_MEM_WE | TTI_CMD_MEM_STROBE_NEW_CMD;
@@ -1610,7 +1611,8 @@ static int init_nic(struct s2io_nic *nic)
* that does not start on an ADB to reduce disconnects.
*/
if (nic->device_type == XFRAME_II_DEVICE) {
- val64 = EXT_REQ_EN | MISC_LINK_STABILITY_PRD(3);
+ val64 = FAULT_BEHAVIOUR | EXT_REQ_EN |
+ MISC_LINK_STABILITY_PRD(3);
writeq(val64, &bar0->misc_control);
val64 = readq(&bar0->pic_control2);
val64 &= ~(BIT(13)|BIT(14)|BIT(15));
@@ -1626,7 +1628,7 @@ static int init_nic(struct s2io_nic *nic)
#define LINK_UP_DOWN_INTERRUPT 1
#define MAC_RMAC_ERR_TIMER 2
-static int s2io_link_fault_indication(nic_t *nic)
+static int s2io_link_fault_indication(struct s2io_nic *nic)
{
if (nic->intr_type != INTA)
return MAC_RMAC_ERR_TIMER;
@@ -1649,14 +1651,14 @@ static int s2io_link_fault_indication(nic_t *nic)
static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
{
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
register u64 val64 = 0, temp64 = 0;
/* Top level interrupt classification */
/* PIC Interrupts */
if ((mask & (TX_PIC_INTR | RX_PIC_INTR))) {
/* Enable PIC Intrs in the general intr mask register */
- val64 = TXPIC_INT_M | PIC_RX_INT_M;
+ val64 = TXPIC_INT_M;
if (flag == ENABLE_INTRS) {
temp64 = readq(&bar0->general_int_mask);
temp64 &= ~((u64) val64);
@@ -1694,70 +1696,6 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
}
}
- /* DMA Interrupts */
- /* Enabling/Disabling Tx DMA interrupts */
- if (mask & TX_DMA_INTR) {
- /* Enable TxDMA Intrs in the general intr mask register */
- val64 = TXDMA_INT_M;
- if (flag == ENABLE_INTRS) {
- temp64 = readq(&bar0->general_int_mask);
- temp64 &= ~((u64) val64);
- writeq(temp64, &bar0->general_int_mask);
- /*
- * Keep all interrupts other than PFC interrupt
- * and PCC interrupt disabled in DMA level.
- */
- val64 = DISABLE_ALL_INTRS & ~(TXDMA_PFC_INT_M |
- TXDMA_PCC_INT_M);
- writeq(val64, &bar0->txdma_int_mask);
- /*
- * Enable only the MISC error 1 interrupt in PFC block
- */
- val64 = DISABLE_ALL_INTRS & (~PFC_MISC_ERR_1);
- writeq(val64, &bar0->pfc_err_mask);
- /*
- * Enable only the FB_ECC error interrupt in PCC block
- */
- val64 = DISABLE_ALL_INTRS & (~PCC_FB_ECC_ERR);
- writeq(val64, &bar0->pcc_err_mask);
- } else if (flag == DISABLE_INTRS) {
- /*
- * Disable TxDMA Intrs in the general intr mask
- * register
- */
- writeq(DISABLE_ALL_INTRS, &bar0->txdma_int_mask);
- writeq(DISABLE_ALL_INTRS, &bar0->pfc_err_mask);
- temp64 = readq(&bar0->general_int_mask);
- val64 |= temp64;
- writeq(val64, &bar0->general_int_mask);
- }
- }
-
- /* Enabling/Disabling Rx DMA interrupts */
- if (mask & RX_DMA_INTR) {
- /* Enable RxDMA Intrs in the general intr mask register */
- val64 = RXDMA_INT_M;
- if (flag == ENABLE_INTRS) {
- temp64 = readq(&bar0->general_int_mask);
- temp64 &= ~((u64) val64);
- writeq(temp64, &bar0->general_int_mask);
- /*
- * All RxDMA block interrupts are disabled for now
- * TODO
- */
- writeq(DISABLE_ALL_INTRS, &bar0->rxdma_int_mask);
- } else if (flag == DISABLE_INTRS) {
- /*
- * Disable RxDMA Intrs in the general intr mask
- * register
- */
- writeq(DISABLE_ALL_INTRS, &bar0->rxdma_int_mask);
- temp64 = readq(&bar0->general_int_mask);
- val64 |= temp64;
- writeq(val64, &bar0->general_int_mask);
- }
- }
-
/* MAC Interrupts */
/* Enabling/Disabling MAC interrupts */
if (mask & (TX_MAC_INTR | RX_MAC_INTR)) {
@@ -1784,53 +1722,6 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
}
}
- /* XGXS Interrupts */
- if (mask & (TX_XGXS_INTR | RX_XGXS_INTR)) {
- val64 = TXXGXS_INT_M | RXXGXS_INT_M;
- if (flag == ENABLE_INTRS) {
- temp64 = readq(&bar0->general_int_mask);
- temp64 &= ~((u64) val64);
- writeq(temp64, &bar0->general_int_mask);
- /*
- * All XGXS block error interrupts are disabled for now
- * TODO
- */
- writeq(DISABLE_ALL_INTRS, &bar0->xgxs_int_mask);
- } else if (flag == DISABLE_INTRS) {
- /*
- * Disable MC Intrs in the general intr mask register
- */
- writeq(DISABLE_ALL_INTRS, &bar0->xgxs_int_mask);
- temp64 = readq(&bar0->general_int_mask);
- val64 |= temp64;
- writeq(val64, &bar0->general_int_mask);
- }
- }
-
- /* Memory Controller(MC) interrupts */
- if (mask & MC_INTR) {
- val64 = MC_INT_M;
- if (flag == ENABLE_INTRS) {
- temp64 = readq(&bar0->general_int_mask);
- temp64 &= ~((u64) val64);
- writeq(temp64, &bar0->general_int_mask);
- /*
- * Enable all MC Intrs.
- */
- writeq(0x0, &bar0->mc_int_mask);
- writeq(0x0, &bar0->mc_err_mask);
- } else if (flag == DISABLE_INTRS) {
- /*
- * Disable MC Intrs in the general intr mask register
- */
- writeq(DISABLE_ALL_INTRS, &bar0->mc_int_mask);
- temp64 = readq(&bar0->general_int_mask);
- val64 |= temp64;
- writeq(val64, &bar0->general_int_mask);
- }
- }
-
-
/* Tx traffic interrupts */
if (mask & TX_TRAFFIC_INTR) {
val64 = TXTRAFFIC_INT_M;
@@ -1877,41 +1768,36 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
}
}
-static int check_prc_pcc_state(u64 val64, int flag, int rev_id, int herc)
+/**
+ * verify_pcc_quiescent- Checks for PCC quiescent state
+ * Return: 1 If PCC is quiescence
+ * 0 If PCC is not quiescence
+ */
+static int verify_pcc_quiescent(struct s2io_nic *sp, int flag)
{
- int ret = 0;
+ int ret = 0, herc;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
+ u64 val64 = readq(&bar0->adapter_status);
+
+ herc = (sp->device_type == XFRAME_II_DEVICE);
if (flag == FALSE) {
- if ((!herc && (rev_id >= 4)) || herc) {
- if (!(val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) &&
- ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
- ADAPTER_STATUS_RC_PRC_QUIESCENT)) {
+ if ((!herc && (get_xena_rev_id(sp->pdev) >= 4)) || herc) {
+ if (!(val64 & ADAPTER_STATUS_RMAC_PCC_IDLE))
ret = 1;
- }
- }else {
- if (!(val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) &&
- ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
- ADAPTER_STATUS_RC_PRC_QUIESCENT)) {
+ } else {
+ if (!(val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE))
ret = 1;
- }
}
} else {
- if ((!herc && (rev_id >= 4)) || herc) {
+ if ((!herc && (get_xena_rev_id(sp->pdev) >= 4)) || herc) {
if (((val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) ==
- ADAPTER_STATUS_RMAC_PCC_IDLE) &&
- (!(val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ||
- ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
- ADAPTER_STATUS_RC_PRC_QUIESCENT))) {
+ ADAPTER_STATUS_RMAC_PCC_IDLE))
ret = 1;
- }
} else {
if (((val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) ==
- ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) &&
- (!(val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ||
- ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
- ADAPTER_STATUS_RC_PRC_QUIESCENT))) {
+ ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE))
ret = 1;
- }
}
}
@@ -1919,9 +1805,6 @@ static int check_prc_pcc_state(u64 val64, int flag, int rev_id, int herc)
}
/**
* verify_xena_quiescence - Checks whether the H/W is ready
- * @val64 : Value read from adapter status register.
- * @flag : indicates if the adapter enable bit was ever written once
- * before.
* Description: Returns whether the H/W is ready to go or not. Depending
* on whether adapter enable bit was written or not the comparison
* differs and the calling function passes the input argument flag to
@@ -1930,24 +1813,63 @@ static int check_prc_pcc_state(u64 val64, int flag, int rev_id, int herc)
* 0 If Xena is not quiescence
*/
-static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag)
+static int verify_xena_quiescence(struct s2io_nic *sp)
{
- int ret = 0, herc;
- u64 tmp64 = ~((u64) val64);
- int rev_id = get_xena_rev_id(sp->pdev);
+ int mode;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
+ u64 val64 = readq(&bar0->adapter_status);
+ mode = s2io_verify_pci_mode(sp);
- herc = (sp->device_type == XFRAME_II_DEVICE);
- if (!
- (tmp64 &
- (ADAPTER_STATUS_TDMA_READY | ADAPTER_STATUS_RDMA_READY |
- ADAPTER_STATUS_PFC_READY | ADAPTER_STATUS_TMAC_BUF_EMPTY |
- ADAPTER_STATUS_PIC_QUIESCENT | ADAPTER_STATUS_MC_DRAM_READY |
- ADAPTER_STATUS_MC_QUEUES_READY | ADAPTER_STATUS_M_PLL_LOCK |
- ADAPTER_STATUS_P_PLL_LOCK))) {
- ret = check_prc_pcc_state(val64, flag, rev_id, herc);
+ if (!(val64 & ADAPTER_STATUS_TDMA_READY)) {
+ DBG_PRINT(ERR_DBG, "%s", "TDMA is not ready!");
+ return 0;
+ }
+ if (!(val64 & ADAPTER_STATUS_RDMA_READY)) {
+ DBG_PRINT(ERR_DBG, "%s", "RDMA is not ready!");
+ return 0;
+ }
+ if (!(val64 & ADAPTER_STATUS_PFC_READY)) {
+ DBG_PRINT(ERR_DBG, "%s", "PFC is not ready!");
+ return 0;
+ }
+ if (!(val64 & ADAPTER_STATUS_TMAC_BUF_EMPTY)) {
+ DBG_PRINT(ERR_DBG, "%s", "TMAC BUF is not empty!");
+ return 0;
+ }
+ if (!(val64 & ADAPTER_STATUS_PIC_QUIESCENT)) {
+ DBG_PRINT(ERR_DBG, "%s", "PIC is not QUIESCENT!");
+ return 0;
+ }
+ if (!(val64 & ADAPTER_STATUS_MC_DRAM_READY)) {
+ DBG_PRINT(ERR_DBG, "%s", "MC_DRAM is not ready!");
+ return 0;
+ }
+ if (!(val64 & ADAPTER_STATUS_MC_QUEUES_READY)) {
+ DBG_PRINT(ERR_DBG, "%s", "MC_QUEUES is not ready!");
+ return 0;
+ }
+ if (!(val64 & ADAPTER_STATUS_M_PLL_LOCK)) {
+ DBG_PRINT(ERR_DBG, "%s", "M_PLL is not locked!");
+ return 0;
}
- return ret;
+ /*
+ * In PCI 33 mode, the P_PLL is not used, and therefore,
+ * the the P_PLL_LOCK bit in the adapter_status register will
+ * not be asserted.
+ */
+ if (!(val64 & ADAPTER_STATUS_P_PLL_LOCK) &&
+ sp->device_type == XFRAME_II_DEVICE && mode !=
+ PCI_MODE_PCI_33) {
+ DBG_PRINT(ERR_DBG, "%s", "P_PLL is not locked!");
+ return 0;
+ }
+ if (!((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
+ ADAPTER_STATUS_RC_PRC_QUIESCENT)) {
+ DBG_PRINT(ERR_DBG, "%s", "RC_PRC is not QUIESCENT!");
+ return 0;
+ }
+ return 1;
}
/**
@@ -1958,9 +1880,9 @@ static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag)
*
*/
-static void fix_mac_address(nic_t * sp)
+static void fix_mac_address(struct s2io_nic * sp)
{
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64;
int i = 0;
@@ -1986,11 +1908,11 @@ static void fix_mac_address(nic_t * sp)
static int start_nic(struct s2io_nic *nic)
{
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
struct net_device *dev = nic->dev;
register u64 val64 = 0;
u16 subid, i;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
mac_control = &nic->mac_control;
@@ -2052,7 +1974,7 @@ static int start_nic(struct s2io_nic *nic)
* it.
*/
val64 = readq(&bar0->adapter_status);
- if (!verify_xena_quiescence(nic, val64, nic->device_enabled_once)) {
+ if (!verify_xena_quiescence(nic)) {
DBG_PRINT(ERR_DBG, "%s: device is not ready, ", dev->name);
DBG_PRINT(ERR_DBG, "Adapter status reads: 0x%llx\n",
(unsigned long long) val64);
@@ -2095,11 +2017,12 @@ static int start_nic(struct s2io_nic *nic)
/**
* s2io_txdl_getskb - Get the skb from txdl, unmap and return skb
*/
-static struct sk_buff *s2io_txdl_getskb(fifo_info_t *fifo_data, TxD_t *txdlp, int get_off)
+static struct sk_buff *s2io_txdl_getskb(struct fifo_info *fifo_data, struct \
+ TxD *txdlp, int get_off)
{
- nic_t *nic = fifo_data->nic;
+ struct s2io_nic *nic = fifo_data->nic;
struct sk_buff *skb;
- TxD_t *txds;
+ struct TxD *txds;
u16 j, frg_cnt;
txds = txdlp;
@@ -2113,7 +2036,7 @@ static struct sk_buff *s2io_txdl_getskb(fifo_info_t *fifo_data, TxD_t *txdlp, in
skb = (struct sk_buff *) ((unsigned long)
txds->Host_Control);
if (!skb) {
- memset(txdlp, 0, (sizeof(TxD_t) * fifo_data->max_txds));
+ memset(txdlp, 0, (sizeof(struct TxD) * fifo_data->max_txds));
return NULL;
}
pci_unmap_single(nic->pdev, (dma_addr_t)
@@ -2132,7 +2055,7 @@ static struct sk_buff *s2io_txdl_getskb(fifo_info_t *fifo_data, TxD_t *txdlp, in
frag->size, PCI_DMA_TODEVICE);
}
}
- memset(txdlp,0, (sizeof(TxD_t) * fifo_data->max_txds));
+ memset(txdlp,0, (sizeof(struct TxD) * fifo_data->max_txds));
return(skb);
}
@@ -2148,9 +2071,9 @@ static void free_tx_buffers(struct s2io_nic *nic)
{
struct net_device *dev = nic->dev;
struct sk_buff *skb;
- TxD_t *txdp;
+ struct TxD *txdp;
int i, j;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
int cnt = 0;
@@ -2159,7 +2082,7 @@ static void free_tx_buffers(struct s2io_nic *nic)
for (i = 0; i < config->tx_fifo_num; i++) {
for (j = 0; j < config->tx_cfg[i].fifo_len - 1; j++) {
- txdp = (TxD_t *) mac_control->fifos[i].list_info[j].
+ txdp = (struct TxD *) mac_control->fifos[i].list_info[j].
list_virt_addr;
skb = s2io_txdl_getskb(&mac_control->fifos[i], txdp, j);
if (skb) {
@@ -2187,10 +2110,10 @@ static void free_tx_buffers(struct s2io_nic *nic)
static void stop_nic(struct s2io_nic *nic)
{
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
register u64 val64 = 0;
u16 interruptible;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
mac_control = &nic->mac_control;
@@ -2208,14 +2131,15 @@ static void stop_nic(struct s2io_nic *nic)
writeq(val64, &bar0->adapter_control);
}
-static int fill_rxd_3buf(nic_t *nic, RxD_t *rxdp, struct sk_buff *skb)
+static int fill_rxd_3buf(struct s2io_nic *nic, struct RxD_t *rxdp, struct \
+ sk_buff *skb)
{
struct net_device *dev = nic->dev;
struct sk_buff *frag_list;
void *tmp;
/* Buffer-1 receives L3/L4 headers */
- ((RxD3_t*)rxdp)->Buffer1_ptr = pci_map_single
+ ((struct RxD3*)rxdp)->Buffer1_ptr = pci_map_single
(nic->pdev, skb->data, l3l4hdr_size + 4,
PCI_DMA_FROMDEVICE);
@@ -2226,13 +2150,14 @@ static int fill_rxd_3buf(nic_t *nic, RxD_t *rxdp, struct sk_buff *skb)
return -ENOMEM ;
}
frag_list = skb_shinfo(skb)->frag_list;
+ skb->truesize += frag_list->truesize;
frag_list->next = NULL;
tmp = (void *)ALIGN((long)frag_list->data, ALIGN_SIZE + 1);
frag_list->data = tmp;
frag_list->tail = tmp;
/* Buffer-2 receives L4 data payload */
- ((RxD3_t*)rxdp)->Buffer2_ptr = pci_map_single(nic->pdev,
+ ((struct RxD3*)rxdp)->Buffer2_ptr = pci_map_single(nic->pdev,
frag_list->data, dev->mtu,
PCI_DMA_FROMDEVICE);
rxdp->Control_2 |= SET_BUFFER1_SIZE_3(l3l4hdr_size + 4);
@@ -2266,18 +2191,16 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
{
struct net_device *dev = nic->dev;
struct sk_buff *skb;
- RxD_t *rxdp;
+ struct RxD_t *rxdp;
int off, off1, size, block_no, block_no1;
u32 alloc_tab = 0;
u32 alloc_cnt;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
u64 tmp;
- buffAdd_t *ba;
-#ifndef CONFIG_S2IO_NAPI
+ struct buffAdd *ba;
unsigned long flags;
-#endif
- RxD_t *first_rxdp = NULL;
+ struct RxD_t *first_rxdp = NULL;
mac_control = &nic->mac_control;
config = &nic->config;
@@ -2320,12 +2243,15 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
DBG_PRINT(INTR_DBG, "%s: Next block at: %p\n",
dev->name, rxdp);
}
-#ifndef CONFIG_S2IO_NAPI
- spin_lock_irqsave(&nic->put_lock, flags);
- mac_control->rings[ring_no].put_pos =
- (block_no * (rxd_count[nic->rxd_mode] + 1)) + off;
- spin_unlock_irqrestore(&nic->put_lock, flags);
-#endif
+ if(!napi) {
+ spin_lock_irqsave(&nic->put_lock, flags);
+ mac_control->rings[ring_no].put_pos =
+ (block_no * (rxd_count[nic->rxd_mode] + 1)) + off;
+ spin_unlock_irqrestore(&nic->put_lock, flags);
+ } else {
+ mac_control->rings[ring_no].put_pos =
+ (block_no * (rxd_count[nic->rxd_mode] + 1)) + off;
+ }
if ((rxdp->Control_1 & RXD_OWN_XENA) &&
((nic->rxd_mode >= RXD_MODE_3A) &&
(rxdp->Control_2 & BIT(0)))) {
@@ -2356,9 +2282,9 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
}
if (nic->rxd_mode == RXD_MODE_1) {
/* 1 buffer mode - normal operation mode */
- memset(rxdp, 0, sizeof(RxD1_t));
+ memset(rxdp, 0, sizeof(struct RxD1));
skb_reserve(skb, NET_IP_ALIGN);
- ((RxD1_t*)rxdp)->Buffer0_ptr = pci_map_single
+ ((struct RxD1*)rxdp)->Buffer0_ptr = pci_map_single
(nic->pdev, skb->data, size - NET_IP_ALIGN,
PCI_DMA_FROMDEVICE);
rxdp->Control_2 = SET_BUFFER0_SIZE_1(size - NET_IP_ALIGN);
@@ -2375,7 +2301,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
* payload
*/
- memset(rxdp, 0, sizeof(RxD3_t));
+ memset(rxdp, 0, sizeof(struct RxD3));
ba = &mac_control->rings[ring_no].ba[block_no][off];
skb_reserve(skb, BUF0_LEN);
tmp = (u64)(unsigned long) skb->data;
@@ -2384,13 +2310,13 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
skb->data = (void *) (unsigned long)tmp;
skb->tail = (void *) (unsigned long)tmp;
- if (!(((RxD3_t*)rxdp)->Buffer0_ptr))
- ((RxD3_t*)rxdp)->Buffer0_ptr =
+ if (!(((struct RxD3*)rxdp)->Buffer0_ptr))
+ ((struct RxD3*)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,
+ (dma_addr_t) ((struct RxD3*)rxdp)->Buffer0_ptr,
BUF0_LEN, PCI_DMA_FROMDEVICE);
rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
if (nic->rxd_mode == RXD_MODE_3B) {
@@ -2400,13 +2326,13 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
* Buffer2 will have L3/L4 header plus
* L4 payload
*/
- ((RxD3_t*)rxdp)->Buffer2_ptr = pci_map_single
+ ((struct RxD3*)rxdp)->Buffer2_ptr = pci_map_single
(nic->pdev, skb->data, dev->mtu + 4,
PCI_DMA_FROMDEVICE);
/* Buffer-1 will be dummy buffer. Not used */
- if (!(((RxD3_t*)rxdp)->Buffer1_ptr)) {
- ((RxD3_t*)rxdp)->Buffer1_ptr =
+ if (!(((struct RxD3*)rxdp)->Buffer1_ptr)) {
+ ((struct RxD3*)rxdp)->Buffer1_ptr =
pci_map_single(nic->pdev,
ba->ba_1, BUF1_LEN,
PCI_DMA_FROMDEVICE);
@@ -2466,9 +2392,9 @@ static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk)
struct net_device *dev = sp->dev;
int j;
struct sk_buff *skb;
- RxD_t *rxdp;
- mac_info_t *mac_control;
- buffAdd_t *ba;
+ struct RxD_t *rxdp;
+ struct mac_info *mac_control;
+ struct buffAdd *ba;
mac_control = &sp->mac_control;
for (j = 0 ; j < rxd_count[sp->rxd_mode]; j++) {
@@ -2481,41 +2407,41 @@ static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk)
}
if (sp->rxd_mode == RXD_MODE_1) {
pci_unmap_single(sp->pdev, (dma_addr_t)
- ((RxD1_t*)rxdp)->Buffer0_ptr,
+ ((struct RxD1*)rxdp)->Buffer0_ptr,
dev->mtu +
HEADER_ETHERNET_II_802_3_SIZE
+ HEADER_802_2_SIZE +
HEADER_SNAP_SIZE,
PCI_DMA_FROMDEVICE);
- memset(rxdp, 0, sizeof(RxD1_t));
+ memset(rxdp, 0, sizeof(struct RxD1));
} else if(sp->rxd_mode == RXD_MODE_3B) {
ba = &mac_control->rings[ring_no].
ba[blk][j];
pci_unmap_single(sp->pdev, (dma_addr_t)
- ((RxD3_t*)rxdp)->Buffer0_ptr,
+ ((struct RxD3*)rxdp)->Buffer0_ptr,
BUF0_LEN,
PCI_DMA_FROMDEVICE);
pci_unmap_single(sp->pdev, (dma_addr_t)
- ((RxD3_t*)rxdp)->Buffer1_ptr,
+ ((struct RxD3*)rxdp)->Buffer1_ptr,
BUF1_LEN,
PCI_DMA_FROMDEVICE);
pci_unmap_single(sp->pdev, (dma_addr_t)
- ((RxD3_t*)rxdp)->Buffer2_ptr,
+ ((struct RxD3*)rxdp)->Buffer2_ptr,
dev->mtu + 4,
PCI_DMA_FROMDEVICE);
- memset(rxdp, 0, sizeof(RxD3_t));
+ memset(rxdp, 0, sizeof(struct RxD3));
} else {
pci_unmap_single(sp->pdev, (dma_addr_t)
- ((RxD3_t*)rxdp)->Buffer0_ptr, BUF0_LEN,
+ ((struct RxD3*)rxdp)->Buffer0_ptr, BUF0_LEN,
PCI_DMA_FROMDEVICE);
pci_unmap_single(sp->pdev, (dma_addr_t)
- ((RxD3_t*)rxdp)->Buffer1_ptr,
+ ((struct RxD3*)rxdp)->Buffer1_ptr,
l3l4hdr_size + 4,
PCI_DMA_FROMDEVICE);
pci_unmap_single(sp->pdev, (dma_addr_t)
- ((RxD3_t*)rxdp)->Buffer2_ptr, dev->mtu,
+ ((struct RxD3*)rxdp)->Buffer2_ptr, dev->mtu,
PCI_DMA_FROMDEVICE);
- memset(rxdp, 0, sizeof(RxD3_t));
+ memset(rxdp, 0, sizeof(struct RxD3));
}
dev_kfree_skb(skb);
atomic_dec(&sp->rx_bufs_left[ring_no]);
@@ -2535,7 +2461,7 @@ static void free_rx_buffers(struct s2io_nic *sp)
{
struct net_device *dev = sp->dev;
int i, blk = 0, buf_cnt = 0;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
mac_control = &sp->mac_control;
@@ -2568,15 +2494,13 @@ static void free_rx_buffers(struct s2io_nic *sp)
* 0 on success and 1 if there are No Rx packets to be processed.
*/
-#if defined(CONFIG_S2IO_NAPI)
static int s2io_poll(struct net_device *dev, int *budget)
{
- nic_t *nic = dev->priv;
+ struct s2io_nic *nic = dev->priv;
int pkt_cnt = 0, org_pkts_to_process;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
- u64 val64 = 0xFFFFFFFFFFFFFFFFULL;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
int i;
atomic_inc(&nic->isr_cnt);
@@ -2588,8 +2512,8 @@ static int s2io_poll(struct net_device *dev, int *budget)
nic->pkts_to_process = dev->quota;
org_pkts_to_process = nic->pkts_to_process;
- writeq(val64, &bar0->rx_traffic_int);
- val64 = readl(&bar0->rx_traffic_int);
+ writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
+ readl(&bar0->rx_traffic_int);
for (i = 0; i < config->rx_ring_num; i++) {
rx_intr_handler(&mac_control->rings[i]);
@@ -2615,7 +2539,7 @@ static int s2io_poll(struct net_device *dev, int *budget)
}
/* Re enable the Rx interrupts. */
writeq(0x0, &bar0->rx_traffic_mask);
- val64 = readl(&bar0->rx_traffic_mask);
+ readl(&bar0->rx_traffic_mask);
atomic_dec(&nic->isr_cnt);
return 0;
@@ -2633,7 +2557,6 @@ no_rx:
atomic_dec(&nic->isr_cnt);
return 1;
}
-#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
/**
@@ -2647,10 +2570,10 @@ no_rx:
*/
static void s2io_netpoll(struct net_device *dev)
{
- nic_t *nic = dev->priv;
- mac_info_t *mac_control;
+ struct s2io_nic *nic = dev->priv;
+ struct mac_info *mac_control;
struct config_param *config;
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
u64 val64 = 0xFFFFFFFFFFFFFFFFULL;
int i;
@@ -2699,17 +2622,15 @@ static void s2io_netpoll(struct net_device *dev)
* Return Value:
* NONE.
*/
-static void rx_intr_handler(ring_info_t *ring_data)
+static void rx_intr_handler(struct ring_info *ring_data)
{
- nic_t *nic = ring_data->nic;
+ struct s2io_nic *nic = ring_data->nic;
struct net_device *dev = (struct net_device *) nic->dev;
int get_block, put_block, put_offset;
- rx_curr_get_info_t get_info, put_info;
- RxD_t *rxdp;
+ struct rx_curr_get_info get_info, put_info;
+ struct RxD_t *rxdp;
struct sk_buff *skb;
-#ifndef CONFIG_S2IO_NAPI
int pkt_cnt = 0;
-#endif
int i;
spin_lock(&nic->rx_lock);
@@ -2722,19 +2643,21 @@ static void rx_intr_handler(ring_info_t *ring_data)
get_info = ring_data->rx_curr_get_info;
get_block = get_info.block_index;
- put_info = ring_data->rx_curr_put_info;
+ memcpy(&put_info, &ring_data->rx_curr_put_info, sizeof(put_info));
put_block = put_info.block_index;
rxdp = ring_data->rx_blocks[get_block].rxds[get_info.offset].virt_addr;
-#ifndef CONFIG_S2IO_NAPI
- spin_lock(&nic->put_lock);
- put_offset = ring_data->put_pos;
- spin_unlock(&nic->put_lock);
-#else
- put_offset = (put_block * (rxd_count[nic->rxd_mode] + 1)) +
- put_info.offset;
-#endif
+ if (!napi) {
+ spin_lock(&nic->put_lock);
+ put_offset = ring_data->put_pos;
+ spin_unlock(&nic->put_lock);
+ } else
+ put_offset = ring_data->put_pos;
+
while (RXD_IS_UP2DT(rxdp)) {
- /* If your are next to put index then it's FIFO full condition */
+ /*
+ * 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(INTR_DBG, "%s: Ring Full\n",dev->name);
@@ -2750,7 +2673,7 @@ static void rx_intr_handler(ring_info_t *ring_data)
}
if (nic->rxd_mode == RXD_MODE_1) {
pci_unmap_single(nic->pdev, (dma_addr_t)
- ((RxD1_t*)rxdp)->Buffer0_ptr,
+ ((struct RxD1*)rxdp)->Buffer0_ptr,
dev->mtu +
HEADER_ETHERNET_II_802_3_SIZE +
HEADER_802_2_SIZE +
@@ -2758,22 +2681,22 @@ static void rx_intr_handler(ring_info_t *ring_data)
PCI_DMA_FROMDEVICE);
} else if (nic->rxd_mode == RXD_MODE_3B) {
pci_dma_sync_single_for_cpu(nic->pdev, (dma_addr_t)
- ((RxD3_t*)rxdp)->Buffer0_ptr,
+ ((struct RxD3*)rxdp)->Buffer0_ptr,
BUF0_LEN, PCI_DMA_FROMDEVICE);
pci_unmap_single(nic->pdev, (dma_addr_t)
- ((RxD3_t*)rxdp)->Buffer2_ptr,
+ ((struct RxD3*)rxdp)->Buffer2_ptr,
dev->mtu + 4,
PCI_DMA_FROMDEVICE);
} else {
pci_dma_sync_single_for_cpu(nic->pdev, (dma_addr_t)
- ((RxD3_t*)rxdp)->Buffer0_ptr, BUF0_LEN,
+ ((struct RxD3*)rxdp)->Buffer0_ptr, BUF0_LEN,
PCI_DMA_FROMDEVICE);
pci_unmap_single(nic->pdev, (dma_addr_t)
- ((RxD3_t*)rxdp)->Buffer1_ptr,
+ ((struct RxD3*)rxdp)->Buffer1_ptr,
l3l4hdr_size + 4,
PCI_DMA_FROMDEVICE);
pci_unmap_single(nic->pdev, (dma_addr_t)
- ((RxD3_t*)rxdp)->Buffer2_ptr,
+ ((struct RxD3*)rxdp)->Buffer2_ptr,
dev->mtu, PCI_DMA_FROMDEVICE);
}
prefetch(skb->data);
@@ -2792,20 +2715,17 @@ static void rx_intr_handler(ring_info_t *ring_data)
rxdp = ring_data->rx_blocks[get_block].block_virt_addr;
}
-#ifdef CONFIG_S2IO_NAPI
nic->pkts_to_process -= 1;
- if (!nic->pkts_to_process)
+ if ((napi) && (!nic->pkts_to_process))
break;
-#else
pkt_cnt++;
if ((indicate_max_pkts) && (pkt_cnt > indicate_max_pkts))
break;
-#endif
}
if (nic->lro) {
/* Clear all LRO sessions before exiting */
for (i=0; i<MAX_LRO_SESSIONS; i++) {
- lro_t *lro = &nic->lro0_n[i];
+ struct lro *lro = &nic->lro0_n[i];
if (lro->in_use) {
update_L3L4_header(nic, lro);
queue_rx_frame(lro->parent);
@@ -2829,17 +2749,17 @@ static void rx_intr_handler(ring_info_t *ring_data)
* NONE
*/
-static void tx_intr_handler(fifo_info_t *fifo_data)
+static void tx_intr_handler(struct fifo_info *fifo_data)
{
- nic_t *nic = fifo_data->nic;
+ struct s2io_nic *nic = fifo_data->nic;
struct net_device *dev = (struct net_device *) nic->dev;
- tx_curr_get_info_t get_info, put_info;
+ struct tx_curr_get_info get_info, put_info;
struct sk_buff *skb;
- TxD_t *txdlp;
+ struct TxD *txdlp;
get_info = fifo_data->tx_curr_get_info;
- put_info = fifo_data->tx_curr_put_info;
- txdlp = (TxD_t *) fifo_data->list_info[get_info.offset].
+ memcpy(&put_info, &fifo_data->tx_curr_put_info, sizeof(put_info));
+ txdlp = (struct TxD *) fifo_data->list_info[get_info.offset].
list_virt_addr;
while ((!(txdlp->Control_1 & TXD_LIST_OWN_XENA)) &&
(get_info.offset != put_info.offset) &&
@@ -2854,11 +2774,10 @@ static void tx_intr_handler(fifo_info_t *fifo_data)
}
if ((err >> 48) == 0xA) {
DBG_PRINT(TX_DBG, "TxD returned due \
-to loss of link\n");
+ to loss of link\n");
}
else {
- DBG_PRINT(ERR_DBG, "***TxD error \
-%llx\n", err);
+ DBG_PRINT(ERR_DBG, "***TxD error %llx\n", err);
}
}
@@ -2877,7 +2796,7 @@ to loss of link\n");
get_info.offset++;
if (get_info.offset == get_info.fifo_len + 1)
get_info.offset = 0;
- txdlp = (TxD_t *) fifo_data->list_info
+ txdlp = (struct TxD *) fifo_data->list_info
[get_info.offset].list_virt_addr;
fifo_data->tx_curr_get_info.offset =
get_info.offset;
@@ -2902,8 +2821,8 @@ to loss of link\n");
static void s2io_mdio_write(u32 mmd_type, u64 addr, u16 value, struct net_device *dev)
{
u64 val64 = 0x0;
- nic_t *sp = dev->priv;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct s2io_nic *sp = dev->priv;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
//address transaction
val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
@@ -2951,8 +2870,8 @@ static u64 s2io_mdio_read(u32 mmd_type, u64 addr, struct net_device *dev)
{
u64 val64 = 0x0;
u64 rval64 = 0x0;
- nic_t *sp = dev->priv;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct s2io_nic *sp = dev->priv;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
/* address transaction */
val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
@@ -3055,8 +2974,8 @@ static void s2io_updt_xpak_counter(struct net_device *dev)
u64 val64 = 0x0;
u64 addr = 0x0;
- nic_t *sp = dev->priv;
- StatInfo_t *stat_info = sp->mac_control.stats_info;
+ struct s2io_nic *sp = dev->priv;
+ struct stat_block *stat_info = sp->mac_control.stats_info;
/* Check the communication with the MDIO slave */
addr = 0x0000;
@@ -3154,10 +3073,12 @@ static void s2io_updt_xpak_counter(struct net_device *dev)
static void alarm_intr_handler(struct s2io_nic *nic)
{
struct net_device *dev = (struct net_device *) nic->dev;
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
register u64 val64 = 0, err_reg = 0;
u64 cnt;
int i;
+ if (atomic_read(&nic->card_state) == CARD_DOWN)
+ return;
nic->mac_control.stats_info->sw_stat.ring_full_cnt = 0;
/* Handling the XPAK counters update */
if(nic->mac_control.stats_info->xpak_stat.xpak_timer_count < 72000) {
@@ -3297,6 +3218,25 @@ static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit)
}
return ret;
}
+/*
+ * check_pci_device_id - Checks if the device id is supported
+ * @id : device id
+ * Description: Function to check if the pci device id is supported by driver.
+ * Return value: Actual device id if supported else PCI_ANY_ID
+ */
+static u16 check_pci_device_id(u16 id)
+{
+ switch (id) {
+ case PCI_DEVICE_ID_HERC_WIN:
+ case PCI_DEVICE_ID_HERC_UNI:
+ return XFRAME_II_DEVICE;
+ case PCI_DEVICE_ID_S2IO_UNI:
+ case PCI_DEVICE_ID_S2IO_WIN:
+ return XFRAME_I_DEVICE;
+ default:
+ return PCI_ANY_ID;
+ }
+}
/**
* s2io_reset - Resets the card.
@@ -3308,42 +3248,57 @@ static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit)
* void.
*/
-static void s2io_reset(nic_t * sp)
+static void s2io_reset(struct s2io_nic * sp)
{
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64;
u16 subid, pci_cmd;
+ int i;
+ u16 val16;
+ DBG_PRINT(INIT_DBG,"%s - Resetting XFrame card %s\n",
+ __FUNCTION__, sp->dev->name);
/* Back up the PCI-X CMD reg, dont want to lose MMRBC, OST settings */
pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, &(pci_cmd));
+ if (sp->device_type == XFRAME_II_DEVICE) {
+ int ret;
+ ret = pci_set_power_state(sp->pdev, 3);
+ if (!ret)
+ ret = pci_set_power_state(sp->pdev, 0);
+ else {
+ DBG_PRINT(ERR_DBG,"%s PME based SW_Reset failed!\n",
+ __FUNCTION__);
+ goto old_way;
+ }
+ msleep(20);
+ goto new_way;
+ }
+old_way:
val64 = SW_RESET_ALL;
writeq(val64, &bar0->sw_reset);
-
- /*
- * At this stage, if the PCI write is indeed completed, the
- * card is reset and so is the PCI Config space of the device.
- * So a read cannot be issued at this stage on any of the
- * registers to ensure the write into "sw_reset" register
- * has gone through.
- * Question: Is there any system call that will explicitly force
- * all the write commands still pending on the bus to be pushed
- * through?
- * As of now I'am just giving a 250ms delay and hoping that the
- * PCI write to sw_reset register is done by this time.
- */
- msleep(250);
+new_way:
if (strstr(sp->product_name, "CX4")) {
msleep(750);
}
+ msleep(250);
+ for (i = 0; i < S2IO_MAX_PCI_CONFIG_SPACE_REINIT; i++) {
- /* Restore the PCI state saved during initialization. */
- pci_restore_state(sp->pdev);
- pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
- pci_cmd);
- s2io_init_pci(sp);
+ /* Restore the PCI state saved during initialization. */
+ pci_restore_state(sp->pdev);
+ pci_read_config_word(sp->pdev, 0x2, &val16);
+ if (check_pci_device_id(val16) != (u16)PCI_ANY_ID)
+ break;
+ msleep(200);
+ }
- msleep(250);
+ if (check_pci_device_id(val16) == (u16)PCI_ANY_ID) {
+ DBG_PRINT(ERR_DBG,"%s SW_Reset failed!\n", __FUNCTION__);
+ }
+
+ pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER, pci_cmd);
+
+ s2io_init_pci(sp);
/* Set swapper to enable I/O register access */
s2io_set_swapper(sp);
@@ -3399,10 +3354,10 @@ static void s2io_reset(nic_t * sp)
* SUCCESS on success and FAILURE on failure.
*/
-static int s2io_set_swapper(nic_t * sp)
+static int s2io_set_swapper(struct s2io_nic * sp)
{
struct net_device *dev = sp->dev;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64, valt, valr;
/*
@@ -3527,9 +3482,9 @@ static int s2io_set_swapper(nic_t * sp)
return SUCCESS;
}
-static int wait_for_msix_trans(nic_t *nic, int i)
+static int wait_for_msix_trans(struct s2io_nic *nic, int i)
{
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
u64 val64;
int ret = 0, cnt = 0;
@@ -3548,9 +3503,9 @@ static int wait_for_msix_trans(nic_t *nic, int i)
return ret;
}
-static void restore_xmsi_data(nic_t *nic)
+static void restore_xmsi_data(struct s2io_nic *nic)
{
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
u64 val64;
int i;
@@ -3566,9 +3521,9 @@ static void restore_xmsi_data(nic_t *nic)
}
}
-static void store_xmsi_data(nic_t *nic)
+static void store_xmsi_data(struct s2io_nic *nic)
{
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
u64 val64, addr, data;
int i;
@@ -3589,9 +3544,9 @@ static void store_xmsi_data(nic_t *nic)
}
}
-int s2io_enable_msi(nic_t *nic)
+int s2io_enable_msi(struct s2io_nic *nic)
{
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
u16 msi_ctrl, msg_val;
struct config_param *config = &nic->config;
struct net_device *dev = nic->dev;
@@ -3639,9 +3594,9 @@ int s2io_enable_msi(nic_t *nic)
return 0;
}
-static int s2io_enable_msi_x(nic_t *nic)
+static int s2io_enable_msi_x(struct s2io_nic *nic)
{
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
u64 tx_mat, rx_mat;
u16 msi_control; /* Temp variable */
int ret, i, j, msix_indx = 1;
@@ -3749,7 +3704,7 @@ static int s2io_enable_msi_x(nic_t *nic)
static int s2io_open(struct net_device *dev)
{
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
int err = 0;
/*
@@ -3802,7 +3757,7 @@ hw_init_failed:
static int s2io_close(struct net_device *dev)
{
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
flush_scheduled_work();
netif_stop_queue(dev);
@@ -3828,15 +3783,15 @@ static int s2io_close(struct net_device *dev)
static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
{
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
u16 frg_cnt, frg_len, i, queue, queue_len, put_off, get_off;
register u64 val64;
- TxD_t *txdp;
- TxFIFO_element_t __iomem *tx_fifo;
+ struct TxD *txdp;
+ struct TxFIFO_element __iomem *tx_fifo;
unsigned long flags;
u16 vlan_tag = 0;
int vlan_priority = 0;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
int offload_type;
@@ -3864,7 +3819,7 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
put_off = (u16) mac_control->fifos[queue].tx_curr_put_info.offset;
get_off = (u16) mac_control->fifos[queue].tx_curr_get_info.offset;
- txdp = (TxD_t *) mac_control->fifos[queue].list_info[put_off].
+ txdp = (struct TxD *) mac_control->fifos[queue].list_info[put_off].
list_virt_addr;
queue_len = mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1;
@@ -3887,12 +3842,10 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
}
offload_type = s2io_offload_type(skb);
-#ifdef NETIF_F_TSO
if (offload_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) {
txdp->Control_1 |= TXD_TCP_LSO_EN;
txdp->Control_1 |= TXD_TCP_LSO_MSS(s2io_tcp_mss(skb));
}
-#endif
if (skb->ip_summed == CHECKSUM_PARTIAL) {
txdp->Control_2 |=
(TXD_TX_CKO_IPV4_EN | TXD_TX_CKO_TCP_EN |
@@ -3993,13 +3946,13 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
static void
s2io_alarm_handle(unsigned long data)
{
- nic_t *sp = (nic_t *)data;
+ struct s2io_nic *sp = (struct s2io_nic *)data;
alarm_intr_handler(sp);
mod_timer(&sp->alarm_timer, jiffies + HZ / 2);
}
-static int s2io_chk_rx_buffers(nic_t *sp, int rng_n)
+static int s2io_chk_rx_buffers(struct s2io_nic *sp, int rng_n)
{
int rxb_size, level;
@@ -4031,9 +3984,9 @@ static int s2io_chk_rx_buffers(nic_t *sp, int rng_n)
static irqreturn_t s2io_msi_handle(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *) dev_id;
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
int i;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
atomic_inc(&sp->isr_cnt);
@@ -4063,8 +4016,8 @@ static irqreturn_t s2io_msi_handle(int irq, void *dev_id)
static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id)
{
- ring_info_t *ring = (ring_info_t *)dev_id;
- nic_t *sp = ring->nic;
+ struct ring_info *ring = (struct ring_info *)dev_id;
+ struct s2io_nic *sp = ring->nic;
atomic_inc(&sp->isr_cnt);
@@ -4077,17 +4030,17 @@ static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id)
static irqreturn_t s2io_msix_fifo_handle(int irq, void *dev_id)
{
- fifo_info_t *fifo = (fifo_info_t *)dev_id;
- nic_t *sp = fifo->nic;
+ struct fifo_info *fifo = (struct fifo_info *)dev_id;
+ struct s2io_nic *sp = fifo->nic;
atomic_inc(&sp->isr_cnt);
tx_intr_handler(fifo);
atomic_dec(&sp->isr_cnt);
return IRQ_HANDLED;
}
-static void s2io_txpic_intr_handle(nic_t *sp)
+static void s2io_txpic_intr_handle(struct s2io_nic *sp)
{
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64;
val64 = readq(&bar0->pic_int_status);
@@ -4109,39 +4062,33 @@ static void s2io_txpic_intr_handle(nic_t *sp)
}
else if (val64 & GPIO_INT_REG_LINK_UP) {
val64 = readq(&bar0->adapter_status);
- if (verify_xena_quiescence(sp, val64,
- sp->device_enabled_once)) {
/* Enable Adapter */
- val64 = readq(&bar0->adapter_control);
- val64 |= ADAPTER_CNTL_EN;
- writeq(val64, &bar0->adapter_control);
- val64 |= ADAPTER_LED_ON;
- writeq(val64, &bar0->adapter_control);
- if (!sp->device_enabled_once)
- sp->device_enabled_once = 1;
+ val64 = readq(&bar0->adapter_control);
+ val64 |= ADAPTER_CNTL_EN;
+ writeq(val64, &bar0->adapter_control);
+ val64 |= ADAPTER_LED_ON;
+ writeq(val64, &bar0->adapter_control);
+ if (!sp->device_enabled_once)
+ sp->device_enabled_once = 1;
- s2io_link(sp, LINK_UP);
- /*
- * unmask link down interrupt and mask link-up
- * intr
- */
- val64 = readq(&bar0->gpio_int_mask);
- val64 &= ~GPIO_INT_MASK_LINK_DOWN;
- val64 |= GPIO_INT_MASK_LINK_UP;
- writeq(val64, &bar0->gpio_int_mask);
+ s2io_link(sp, LINK_UP);
+ /*
+ * unmask link down interrupt and mask link-up
+ * intr
+ */
+ val64 = readq(&bar0->gpio_int_mask);
+ val64 &= ~GPIO_INT_MASK_LINK_DOWN;
+ val64 |= GPIO_INT_MASK_LINK_UP;
+ writeq(val64, &bar0->gpio_int_mask);
- }
}else if (val64 & GPIO_INT_REG_LINK_DOWN) {
val64 = readq(&bar0->adapter_status);
- if (verify_xena_quiescence(sp, val64,
- sp->device_enabled_once)) {
- s2io_link(sp, LINK_DOWN);
- /* Link is down so unmaks link up interrupt */
- val64 = readq(&bar0->gpio_int_mask);
- val64 &= ~GPIO_INT_MASK_LINK_UP;
- val64 |= GPIO_INT_MASK_LINK_DOWN;
- writeq(val64, &bar0->gpio_int_mask);
- }
+ s2io_link(sp, LINK_DOWN);
+ /* Link is down so unmaks link up interrupt */
+ val64 = readq(&bar0->gpio_int_mask);
+ val64 &= ~GPIO_INT_MASK_LINK_UP;
+ val64 |= GPIO_INT_MASK_LINK_DOWN;
+ writeq(val64, &bar0->gpio_int_mask);
}
}
val64 = readq(&bar0->gpio_int_mask);
@@ -4163,11 +4110,11 @@ static void s2io_txpic_intr_handle(nic_t *sp)
static irqreturn_t s2io_isr(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *) dev_id;
- nic_t *sp = dev->priv;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct s2io_nic *sp = dev->priv;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
int i;
- u64 reason = 0, val64, org_mask;
- mac_info_t *mac_control;
+ u64 reason = 0;
+ struct mac_info *mac_control;
struct config_param *config;
atomic_inc(&sp->isr_cnt);
@@ -4185,43 +4132,48 @@ static irqreturn_t s2io_isr(int irq, void *dev_id)
reason = readq(&bar0->general_int_status);
if (!reason) {
- /* The interrupt was not raised by Xena. */
+ /* The interrupt was not raised by us. */
+ atomic_dec(&sp->isr_cnt);
+ return IRQ_NONE;
+ }
+ else if (unlikely(reason == S2IO_MINUS_ONE) ) {
+ /* Disable device and get out */
atomic_dec(&sp->isr_cnt);
return IRQ_NONE;
}
- val64 = 0xFFFFFFFFFFFFFFFFULL;
- /* Store current mask before masking all interrupts */
- org_mask = readq(&bar0->general_int_mask);
- writeq(val64, &bar0->general_int_mask);
+ if (napi) {
+ if (reason & GEN_INTR_RXTRAFFIC) {
+ if ( likely ( netif_rx_schedule_prep(dev)) ) {
+ __netif_rx_schedule(dev);
+ writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_mask);
+ }
+ else
+ writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
+ }
+ } else {
+ /*
+ * Rx handler is called by default, without checking for the
+ * cause of interrupt.
+ * rx_traffic_int reg is an R1 register, writing all 1's
+ * will ensure that the actual interrupt causing bit get's
+ * cleared and hence a read can be avoided.
+ */
+ if (reason & GEN_INTR_RXTRAFFIC)
+ writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
-#ifdef CONFIG_S2IO_NAPI
- if (reason & GEN_INTR_RXTRAFFIC) {
- if (netif_rx_schedule_prep(dev)) {
- writeq(val64, &bar0->rx_traffic_mask);
- __netif_rx_schedule(dev);
+ for (i = 0; i < config->rx_ring_num; i++) {
+ rx_intr_handler(&mac_control->rings[i]);
}
}
-#else
- /*
- * Rx handler is called by default, without checking for the
- * cause of interrupt.
- * rx_traffic_int reg is an R1 register, writing all 1's
- * will ensure that the actual interrupt causing bit get's
- * cleared and hence a read can be avoided.
- */
- writeq(val64, &bar0->rx_traffic_int);
- for (i = 0; i < config->rx_ring_num; i++) {
- rx_intr_handler(&mac_control->rings[i]);
- }
-#endif
/*
* tx_traffic_int reg is an R1 register, writing all 1's
* will ensure that the actual interrupt causing bit get's
* cleared and hence a read can be avoided.
*/
- writeq(val64, &bar0->tx_traffic_int);
+ if (reason & GEN_INTR_TXTRAFFIC)
+ writeq(S2IO_MINUS_ONE, &bar0->tx_traffic_int);
for (i = 0; i < config->tx_fifo_num; i++)
tx_intr_handler(&mac_control->fifos[i]);
@@ -4233,11 +4185,14 @@ static irqreturn_t s2io_isr(int irq, void *dev_id)
* reallocate the buffers from the interrupt handler itself,
* else schedule a tasklet to reallocate the buffers.
*/
-#ifndef CONFIG_S2IO_NAPI
- for (i = 0; i < config->rx_ring_num; i++)
- s2io_chk_rx_buffers(sp, i);
-#endif
- writeq(org_mask, &bar0->general_int_mask);
+ if (!napi) {
+ for (i = 0; i < config->rx_ring_num; i++)
+ s2io_chk_rx_buffers(sp, i);
+ }
+
+ writeq(0, &bar0->general_int_mask);
+ readl(&bar0->general_int_status);
+
atomic_dec(&sp->isr_cnt);
return IRQ_HANDLED;
}
@@ -4245,9 +4200,9 @@ static irqreturn_t s2io_isr(int irq, void *dev_id)
/**
* s2io_updt_stats -
*/
-static void s2io_updt_stats(nic_t *sp)
+static void s2io_updt_stats(struct s2io_nic *sp)
{
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64;
int cnt = 0;
@@ -4266,7 +4221,7 @@ static void s2io_updt_stats(nic_t *sp)
break; /* Updt failed */
} while(1);
} else {
- memset(sp->mac_control.stats_info, 0, sizeof(StatInfo_t));
+ memset(sp->mac_control.stats_info, 0, sizeof(struct stat_block));
}
}
@@ -4282,8 +4237,8 @@ static void s2io_updt_stats(nic_t *sp)
static struct net_device_stats *s2io_get_stats(struct net_device *dev)
{
- nic_t *sp = dev->priv;
- mac_info_t *mac_control;
+ struct s2io_nic *sp = dev->priv;
+ struct mac_info *mac_control;
struct config_param *config;
@@ -4324,8 +4279,8 @@ static void s2io_set_multicast(struct net_device *dev)
{
int i, j, prev_cnt;
struct dev_mc_list *mclist;
- nic_t *sp = dev->priv;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct s2io_nic *sp = dev->priv;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64 = 0, multi_mac = 0x010203040506ULL, mask =
0xfeffffffffffULL;
u64 dis_addr = 0xffffffffffffULL, mac_addr = 0;
@@ -4478,8 +4433,8 @@ static void s2io_set_multicast(struct net_device *dev)
static int s2io_set_mac_addr(struct net_device *dev, u8 * addr)
{
- nic_t *sp = dev->priv;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct s2io_nic *sp = dev->priv;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
register u64 val64, mac_addr = 0;
int i;
@@ -4525,7 +4480,7 @@ static int s2io_set_mac_addr(struct net_device *dev, u8 * addr)
static int s2io_ethtool_sset(struct net_device *dev,
struct ethtool_cmd *info)
{
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
if ((info->autoneg == AUTONEG_ENABLE) ||
(info->speed != SPEED_10000) || (info->duplex != DUPLEX_FULL))
return -EINVAL;
@@ -4551,7 +4506,7 @@ static int s2io_ethtool_sset(struct net_device *dev,
static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info)
{
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
info->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
info->advertising = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
info->port = PORT_FIBRE;
@@ -4584,7 +4539,7 @@ static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info)
static void s2io_ethtool_gdrvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
strncpy(info->driver, s2io_driver_name, sizeof(info->driver));
strncpy(info->version, s2io_driver_version, sizeof(info->version));
@@ -4616,7 +4571,7 @@ static void s2io_ethtool_gregs(struct net_device *dev,
int i;
u64 reg;
u8 *reg_space = (u8 *) space;
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
regs->len = XENA_REG_SPACE;
regs->version = sp->pdev->subsystem_device;
@@ -4638,8 +4593,8 @@ static void s2io_ethtool_gregs(struct net_device *dev,
*/
static void s2io_phy_id(unsigned long data)
{
- nic_t *sp = (nic_t *) data;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct s2io_nic *sp = (struct s2io_nic *) data;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64 = 0;
u16 subid;
@@ -4676,8 +4631,8 @@ static void s2io_phy_id(unsigned long data)
static int s2io_ethtool_idnic(struct net_device *dev, u32 data)
{
u64 val64 = 0, last_gpio_ctrl_val;
- nic_t *sp = dev->priv;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct s2io_nic *sp = dev->priv;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
u16 subid;
subid = sp->pdev->subsystem_device;
@@ -4725,8 +4680,8 @@ static void s2io_ethtool_getpause_data(struct net_device *dev,
struct ethtool_pauseparam *ep)
{
u64 val64;
- nic_t *sp = dev->priv;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct s2io_nic *sp = dev->priv;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
val64 = readq(&bar0->rmac_pause_cfg);
if (val64 & RMAC_PAUSE_GEN_ENABLE)
@@ -4752,8 +4707,8 @@ static int s2io_ethtool_setpause_data(struct net_device *dev,
struct ethtool_pauseparam *ep)
{
u64 val64;
- nic_t *sp = dev->priv;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct s2io_nic *sp = dev->priv;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
val64 = readq(&bar0->rmac_pause_cfg);
if (ep->tx_pause)
@@ -4785,12 +4740,12 @@ static int s2io_ethtool_setpause_data(struct net_device *dev,
*/
#define S2IO_DEV_ID 5
-static int read_eeprom(nic_t * sp, int off, u64 * data)
+static int read_eeprom(struct s2io_nic * sp, int off, u64 * data)
{
int ret = -1;
u32 exit_cnt = 0;
u64 val64;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
if (sp->device_type == XFRAME_I_DEVICE) {
val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) |
@@ -4850,11 +4805,11 @@ static int read_eeprom(nic_t * sp, int off, u64 * data)
* 0 on success, -1 on failure.
*/
-static int write_eeprom(nic_t * sp, int off, u64 data, int cnt)
+static int write_eeprom(struct s2io_nic * sp, int off, u64 data, int cnt)
{
int exit_cnt = 0, ret = -1;
u64 val64;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
if (sp->device_type == XFRAME_I_DEVICE) {
val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) |
@@ -4899,7 +4854,7 @@ static int write_eeprom(nic_t * sp, int off, u64 data, int cnt)
}
return ret;
}
-static void s2io_vpd_read(nic_t *nic)
+static void s2io_vpd_read(struct s2io_nic *nic)
{
u8 *vpd_data;
u8 data;
@@ -4914,6 +4869,7 @@ static void s2io_vpd_read(nic_t *nic)
strcpy(nic->product_name, "Xframe I 10GbE network adapter");
vpd_addr = 0x50;
}
+ strcpy(nic->serial_num, "NOT AVAILABLE");
vpd_data = kmalloc(256, GFP_KERNEL);
if (!vpd_data)
@@ -4937,7 +4893,22 @@ static void s2io_vpd_read(nic_t *nic)
pci_read_config_dword(nic->pdev, (vpd_addr + 4),
(u32 *)&vpd_data[i]);
}
- if ((!fail) && (vpd_data[1] < VPD_PRODUCT_NAME_LEN)) {
+
+ if(!fail) {
+ /* read serial number of adapter */
+ for (cnt = 0; cnt < 256; cnt++) {
+ if ((vpd_data[cnt] == 'S') &&
+ (vpd_data[cnt+1] == 'N') &&
+ (vpd_data[cnt+2] < VPD_STRING_LEN)) {
+ memset(nic->serial_num, 0, VPD_STRING_LEN);
+ memcpy(nic->serial_num, &vpd_data[cnt + 3],
+ vpd_data[cnt+2]);
+ break;
+ }
+ }
+ }
+
+ if ((!fail) && (vpd_data[1] < VPD_STRING_LEN)) {
memset(nic->product_name, 0, vpd_data[1]);
memcpy(nic->product_name, &vpd_data[3], vpd_data[1]);
}
@@ -4962,7 +4933,7 @@ static int s2io_ethtool_geeprom(struct net_device *dev,
{
u32 i, valid;
u64 data;
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
eeprom->magic = sp->pdev->vendor | (sp->pdev->device << 16);
@@ -5000,7 +4971,7 @@ static int s2io_ethtool_seeprom(struct net_device *dev,
{
int len = eeprom->len, cnt = 0;
u64 valid = 0, data;
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
if (eeprom->magic != (sp->pdev->vendor | (sp->pdev->device << 16))) {
DBG_PRINT(ERR_DBG,
@@ -5044,9 +5015,9 @@ static int s2io_ethtool_seeprom(struct net_device *dev,
* 0 on success.
*/
-static int s2io_register_test(nic_t * sp, uint64_t * data)
+static int s2io_register_test(struct s2io_nic * sp, uint64_t * data)
{
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64 = 0, exp_val;
int fail = 0;
@@ -5111,7 +5082,7 @@ static int s2io_register_test(nic_t * sp, uint64_t * data)
* 0 on success.
*/
-static int s2io_eeprom_test(nic_t * sp, uint64_t * data)
+static int s2io_eeprom_test(struct s2io_nic * sp, uint64_t * data)
{
int fail = 0;
u64 ret_data, org_4F0, org_7F0;
@@ -5213,7 +5184,7 @@ static int s2io_eeprom_test(nic_t * sp, uint64_t * data)
* 0 on success and -1 on failure.
*/
-static int s2io_bist_test(nic_t * sp, uint64_t * data)
+static int s2io_bist_test(struct s2io_nic * sp, uint64_t * data)
{
u8 bist = 0;
int cnt = 0, ret = -1;
@@ -5249,9 +5220,9 @@ static int s2io_bist_test(nic_t * sp, uint64_t * data)
* 0 on success.
*/
-static int s2io_link_test(nic_t * sp, uint64_t * data)
+static int s2io_link_test(struct s2io_nic * sp, uint64_t * data)
{
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64;
val64 = readq(&bar0->adapter_status);
@@ -5276,9 +5247,9 @@ static int s2io_link_test(nic_t * sp, uint64_t * data)
* 0 on success.
*/
-static int s2io_rldram_test(nic_t * sp, uint64_t * data)
+static int s2io_rldram_test(struct s2io_nic * sp, uint64_t * data)
{
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64;
int cnt, iteration = 0, test_fail = 0;
@@ -5380,7 +5351,7 @@ static void s2io_ethtool_test(struct net_device *dev,
struct ethtool_test *ethtest,
uint64_t * data)
{
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
int orig_state = netif_running(sp->dev);
if (ethtest->flags == ETH_TEST_FL_OFFLINE) {
@@ -5436,8 +5407,8 @@ static void s2io_get_ethtool_stats(struct net_device *dev,
u64 * tmp_stats)
{
int i = 0;
- nic_t *sp = dev->priv;
- StatInfo_t *stat_info = sp->mac_control.stats_info;
+ struct s2io_nic *sp = dev->priv;
+ struct stat_block *stat_info = sp->mac_control.stats_info;
s2io_updt_stats(sp);
tmp_stats[i++] =
@@ -5664,14 +5635,14 @@ static int s2io_ethtool_get_regs_len(struct net_device *dev)
static u32 s2io_ethtool_get_rx_csum(struct net_device * dev)
{
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
return (sp->rx_csum);
}
static int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data)
{
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
if (data)
sp->rx_csum = 1;
@@ -5750,10 +5721,8 @@ static const struct ethtool_ops netdev_ethtool_ops = {
.set_tx_csum = s2io_ethtool_op_set_tx_csum,
.get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
-#ifdef NETIF_F_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,
.self_test_count = s2io_ethtool_self_test_count,
@@ -5794,7 +5763,7 @@ static int s2io_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
static int s2io_change_mtu(struct net_device *dev, int new_mtu)
{
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
if ((new_mtu < MIN_MTU) || (new_mtu > S2IO_JUMBO_SIZE)) {
DBG_PRINT(ERR_DBG, "%s: MTU size is invalid.\n",
@@ -5813,7 +5782,7 @@ static int s2io_change_mtu(struct net_device *dev, int new_mtu)
if (netif_queue_stopped(dev))
netif_wake_queue(dev);
} else { /* Device is down */
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64 = new_mtu;
writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len);
@@ -5838,9 +5807,9 @@ static int s2io_change_mtu(struct net_device *dev, int new_mtu)
static void s2io_tasklet(unsigned long dev_addr)
{
struct net_device *dev = (struct net_device *) dev_addr;
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
int i, ret;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
mac_control = &sp->mac_control;
@@ -5873,9 +5842,9 @@ static void s2io_tasklet(unsigned long dev_addr)
static void s2io_set_link(struct work_struct *work)
{
- nic_t *nic = container_of(work, nic_t, set_link_task);
+ struct s2io_nic *nic = container_of(work, struct s2io_nic, set_link_task);
struct net_device *dev = nic->dev;
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
register u64 val64;
u16 subid;
@@ -5894,57 +5863,53 @@ static void s2io_set_link(struct work_struct *work)
}
val64 = readq(&bar0->adapter_status);
- if (verify_xena_quiescence(nic, val64, nic->device_enabled_once)) {
- if (LINK_IS_UP(val64)) {
- val64 = readq(&bar0->adapter_control);
- val64 |= ADAPTER_CNTL_EN;
- writeq(val64, &bar0->adapter_control);
- if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type,
- subid)) {
- val64 = readq(&bar0->gpio_control);
- val64 |= GPIO_CTRL_GPIO_0;
- writeq(val64, &bar0->gpio_control);
- val64 = readq(&bar0->gpio_control);
- } else {
- val64 |= ADAPTER_LED_ON;
+ if (LINK_IS_UP(val64)) {
+ if (!(readq(&bar0->adapter_control) & ADAPTER_CNTL_EN)) {
+ if (verify_xena_quiescence(nic)) {
+ val64 = readq(&bar0->adapter_control);
+ val64 |= ADAPTER_CNTL_EN;
writeq(val64, &bar0->adapter_control);
- }
- if (s2io_link_fault_indication(nic) ==
- MAC_RMAC_ERR_TIMER) {
- val64 = readq(&bar0->adapter_status);
- if (!LINK_IS_UP(val64)) {
- DBG_PRINT(ERR_DBG, "%s:", dev->name);
- DBG_PRINT(ERR_DBG, " Link down");
- DBG_PRINT(ERR_DBG, "after ");
- DBG_PRINT(ERR_DBG, "enabling ");
- DBG_PRINT(ERR_DBG, "device \n");
+ if (CARDS_WITH_FAULTY_LINK_INDICATORS(
+ nic->device_type, subid)) {
+ val64 = readq(&bar0->gpio_control);
+ val64 |= GPIO_CTRL_GPIO_0;
+ writeq(val64, &bar0->gpio_control);
+ val64 = readq(&bar0->gpio_control);
+ } else {
+ val64 |= ADAPTER_LED_ON;
+ writeq(val64, &bar0->adapter_control);
}
- }
- if (nic->device_enabled_once == FALSE) {
nic->device_enabled_once = TRUE;
+ } else {
+ DBG_PRINT(ERR_DBG, "%s: Error: ", dev->name);
+ DBG_PRINT(ERR_DBG, "device is not Quiescent\n");
+ netif_stop_queue(dev);
}
+ }
+ val64 = readq(&bar0->adapter_status);
+ if (!LINK_IS_UP(val64)) {
+ DBG_PRINT(ERR_DBG, "%s:", dev->name);
+ DBG_PRINT(ERR_DBG, " Link down after enabling ");
+ DBG_PRINT(ERR_DBG, "device \n");
+ } else
s2io_link(nic, LINK_UP);
- } else {
- if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type,
- subid)) {
- val64 = readq(&bar0->gpio_control);
- val64 &= ~GPIO_CTRL_GPIO_0;
- writeq(val64, &bar0->gpio_control);
- val64 = readq(&bar0->gpio_control);
- }
- s2io_link(nic, LINK_DOWN);
+ } else {
+ if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type,
+ subid)) {
+ val64 = readq(&bar0->gpio_control);
+ val64 &= ~GPIO_CTRL_GPIO_0;
+ writeq(val64, &bar0->gpio_control);
+ val64 = readq(&bar0->gpio_control);
}
- } else { /* NIC is not Quiescent. */
- DBG_PRINT(ERR_DBG, "%s: Error: ", dev->name);
- DBG_PRINT(ERR_DBG, "device is not Quiescent\n");
- netif_stop_queue(dev);
+ s2io_link(nic, LINK_DOWN);
}
clear_bit(0, &(nic->link_state));
}
-static int set_rxd_buffer_pointer(nic_t *sp, RxD_t *rxdp, buffAdd_t *ba,
- struct sk_buff **skb, u64 *temp0, u64 *temp1,
- u64 *temp2, int size)
+static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp,
+ struct buffAdd *ba,
+ struct sk_buff **skb, u64 *temp0, u64 *temp1,
+ u64 *temp2, int size)
{
struct net_device *dev = sp->dev;
struct sk_buff *frag_list;
@@ -5958,7 +5923,7 @@ static int set_rxd_buffer_pointer(nic_t *sp, RxD_t *rxdp, buffAdd_t *ba,
* using same mapped address for the Rxd
* buffer pointer
*/
- ((RxD1_t*)rxdp)->Buffer0_ptr = *temp0;
+ ((struct RxD1*)rxdp)->Buffer0_ptr = *temp0;
} else {
*skb = dev_alloc_skb(size);
if (!(*skb)) {
@@ -5970,7 +5935,7 @@ static int set_rxd_buffer_pointer(nic_t *sp, RxD_t *rxdp, buffAdd_t *ba,
* such it will be used for next rxd whose
* Host Control is NULL
*/
- ((RxD1_t*)rxdp)->Buffer0_ptr = *temp0 =
+ ((struct RxD1*)rxdp)->Buffer0_ptr = *temp0 =
pci_map_single( sp->pdev, (*skb)->data,
size - NET_IP_ALIGN,
PCI_DMA_FROMDEVICE);
@@ -5979,36 +5944,36 @@ static int set_rxd_buffer_pointer(nic_t *sp, RxD_t *rxdp, buffAdd_t *ba,
} else if ((sp->rxd_mode == RXD_MODE_3B) && (rxdp->Host_Control == 0)) {
/* Two buffer Mode */
if (*skb) {
- ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2;
- ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0;
- ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1;
+ ((struct RxD3*)rxdp)->Buffer2_ptr = *temp2;
+ ((struct RxD3*)rxdp)->Buffer0_ptr = *temp0;
+ ((struct RxD3*)rxdp)->Buffer1_ptr = *temp1;
} else {
*skb = dev_alloc_skb(size);
if (!(*skb)) {
DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n",
- dev->name);
+ dev->name);
return -ENOMEM;
}
- ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2 =
+ ((struct RxD3*)rxdp)->Buffer2_ptr = *temp2 =
pci_map_single(sp->pdev, (*skb)->data,
dev->mtu + 4,
PCI_DMA_FROMDEVICE);
- ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0 =
+ ((struct RxD3*)rxdp)->Buffer0_ptr = *temp0 =
pci_map_single( sp->pdev, ba->ba_0, BUF0_LEN,
PCI_DMA_FROMDEVICE);
rxdp->Host_Control = (unsigned long) (*skb);
/* Buffer-1 will be dummy buffer not used */
- ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1 =
+ ((struct RxD3*)rxdp)->Buffer1_ptr = *temp1 =
pci_map_single(sp->pdev, ba->ba_1, BUF1_LEN,
PCI_DMA_FROMDEVICE);
}
} else if ((rxdp->Host_Control == 0)) {
/* Three buffer mode */
if (*skb) {
- ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0;
- ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1;
- ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2;
+ ((struct RxD3*)rxdp)->Buffer0_ptr = *temp0;
+ ((struct RxD3*)rxdp)->Buffer1_ptr = *temp1;
+ ((struct RxD3*)rxdp)->Buffer2_ptr = *temp2;
} else {
*skb = dev_alloc_skb(size);
if (!(*skb)) {
@@ -6016,11 +5981,11 @@ static int set_rxd_buffer_pointer(nic_t *sp, RxD_t *rxdp, buffAdd_t *ba,
dev->name);
return -ENOMEM;
}
- ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0 =
+ ((struct RxD3*)rxdp)->Buffer0_ptr = *temp0 =
pci_map_single(sp->pdev, ba->ba_0, BUF0_LEN,
PCI_DMA_FROMDEVICE);
/* Buffer-1 receives L3/L4 headers */
- ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1 =
+ ((struct RxD3*)rxdp)->Buffer1_ptr = *temp1 =
pci_map_single( sp->pdev, (*skb)->data,
l3l4hdr_size + 4,
PCI_DMA_FROMDEVICE);
@@ -6040,14 +6005,15 @@ static int set_rxd_buffer_pointer(nic_t *sp, RxD_t *rxdp, buffAdd_t *ba,
/*
* Buffer-2 receives L4 data payload
*/
- ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2 =
+ ((struct RxD3*)rxdp)->Buffer2_ptr = *temp2 =
pci_map_single( sp->pdev, frag_list->data,
dev->mtu, PCI_DMA_FROMDEVICE);
}
}
return 0;
}
-static void set_rxd_buffer_size(nic_t *sp, RxD_t *rxdp, int size)
+static void set_rxd_buffer_size(struct s2io_nic *sp, struct RxD_t *rxdp,
+ int size)
{
struct net_device *dev = sp->dev;
if (sp->rxd_mode == RXD_MODE_1) {
@@ -6063,15 +6029,15 @@ static void set_rxd_buffer_size(nic_t *sp, RxD_t *rxdp, int size)
}
}
-static int rxd_owner_bit_reset(nic_t *sp)
+static int rxd_owner_bit_reset(struct s2io_nic *sp)
{
int i, j, k, blk_cnt = 0, size;
- mac_info_t * mac_control = &sp->mac_control;
+ struct mac_info * mac_control = &sp->mac_control;
struct config_param *config = &sp->config;
struct net_device *dev = sp->dev;
- RxD_t *rxdp = NULL;
+ struct RxD_t *rxdp = NULL;
struct sk_buff *skb = NULL;
- buffAdd_t *ba = NULL;
+ struct buffAdd *ba = NULL;
u64 temp0_64 = 0, temp1_64 = 0, temp2_64 = 0;
/* Calculate the size based on ring mode */
@@ -6110,7 +6076,7 @@ static int rxd_owner_bit_reset(nic_t *sp)
}
-static int s2io_add_isr(nic_t * sp)
+static int s2io_add_isr(struct s2io_nic * sp)
{
int ret = 0;
struct net_device *dev = sp->dev;
@@ -6125,7 +6091,7 @@ static int s2io_add_isr(nic_t * sp)
sp->intr_type = INTA;
}
- /* Store the values of the MSIX table in the nic_t structure */
+ /* Store the values of the MSIX table in the struct s2io_nic structure */
store_xmsi_data(sp);
/* After proper initialization of H/W, register ISR */
@@ -6180,7 +6146,7 @@ static int s2io_add_isr(nic_t * sp)
}
return 0;
}
-static void s2io_rem_isr(nic_t * sp)
+static void s2io_rem_isr(struct s2io_nic * sp)
{
int cnt = 0;
struct net_device *dev = sp->dev;
@@ -6222,10 +6188,10 @@ static void s2io_rem_isr(nic_t * sp)
} while(cnt < 5);
}
-static void s2io_card_down(nic_t * sp)
+static void s2io_card_down(struct s2io_nic * sp)
{
int cnt = 0;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
unsigned long flags;
register u64 val64 = 0;
@@ -6256,7 +6222,8 @@ static void s2io_card_down(nic_t * sp)
rxd_owner_bit_reset(sp);
val64 = readq(&bar0->adapter_status);
- if (verify_xena_quiescence(sp, val64, sp->device_enabled_once)) {
+ if (verify_xena_quiescence(sp)) {
+ if(verify_pcc_quiescent(sp, sp->device_enabled_once))
break;
}
@@ -6285,10 +6252,10 @@ static void s2io_card_down(nic_t * sp)
clear_bit(0, &(sp->link_state));
}
-static int s2io_card_up(nic_t * sp)
+static int s2io_card_up(struct s2io_nic * sp)
{
int i, ret = 0;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
struct net_device *dev = (struct net_device *) sp->dev;
u16 interruptible;
@@ -6319,6 +6286,13 @@ static int s2io_card_up(nic_t * sp)
DBG_PRINT(INFO_DBG, "Buf in ring:%d is %d:\n", i,
atomic_read(&sp->rx_bufs_left[i]));
}
+ /* Maintain the state prior to the open */
+ if (sp->promisc_flg)
+ sp->promisc_flg = 0;
+ if (sp->m_cast_flg) {
+ sp->m_cast_flg = 0;
+ sp->all_multi_pos= 0;
+ }
/* Setting its receive mode */
s2io_set_multicast(dev);
@@ -6380,7 +6354,7 @@ static int s2io_card_up(nic_t * sp)
static void s2io_restart_nic(struct work_struct *work)
{
- nic_t *sp = container_of(work, nic_t, rst_timer_task);
+ struct s2io_nic *sp = container_of(work, struct s2io_nic, rst_timer_task);
struct net_device *dev = sp->dev;
s2io_card_down(sp);
@@ -6409,7 +6383,7 @@ static void s2io_restart_nic(struct work_struct *work)
static void s2io_tx_watchdog(struct net_device *dev)
{
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
if (netif_carrier_ok(dev)) {
schedule_work(&sp->rst_timer_task);
@@ -6434,16 +6408,16 @@ static void s2io_tx_watchdog(struct net_device *dev)
* Return value:
* SUCCESS on success and -1 on failure.
*/
-static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp)
+static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
{
- nic_t *sp = ring_data->nic;
+ struct s2io_nic *sp = ring_data->nic;
struct net_device *dev = (struct net_device *) sp->dev;
struct sk_buff *skb = (struct sk_buff *)
((unsigned long) rxdp->Host_Control);
int ring_no = ring_data->ring_no;
u16 l3_csum, l4_csum;
unsigned long long err = rxdp->Control_1 & RXD_T_CODE;
- lro_t *lro;
+ struct lro *lro;
skb->dev = dev;
@@ -6488,7 +6462,7 @@ static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp)
int buf2_len = RXD_GET_BUFFER2_SIZE_3(rxdp->Control_2);
unsigned char *buff = skb_push(skb, buf0_len);
- buffAdd_t *ba = &ring_data->ba[get_block][get_off];
+ struct buffAdd *ba = &ring_data->ba[get_block][get_off];
sp->stats.rx_bytes += buf0_len + buf2_len;
memcpy(buff, ba->ba_0, buf0_len);
@@ -6498,7 +6472,6 @@ static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp)
skb_put(skb, buf1_len);
skb->len += buf2_len;
skb->data_len += buf2_len;
- skb->truesize += buf2_len;
skb_put(skb_shinfo(skb)->frag_list, buf2_len);
sp->stats.rx_bytes += buf1_len;
@@ -6582,23 +6555,20 @@ static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp)
if (!sp->lro) {
skb->protocol = eth_type_trans(skb, dev);
-#ifdef CONFIG_S2IO_NAPI
- if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) {
- /* Queueing the vlan frame to the upper layer */
- vlan_hwaccel_receive_skb(skb, sp->vlgrp,
- RXD_GET_VLAN_TAG(rxdp->Control_2));
- } else {
- netif_receive_skb(skb);
- }
-#else
if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) {
/* Queueing the vlan frame to the upper layer */
- vlan_hwaccel_rx(skb, sp->vlgrp,
- RXD_GET_VLAN_TAG(rxdp->Control_2));
+ if (napi)
+ vlan_hwaccel_receive_skb(skb, sp->vlgrp,
+ RXD_GET_VLAN_TAG(rxdp->Control_2));
+ else
+ vlan_hwaccel_rx(skb, sp->vlgrp,
+ RXD_GET_VLAN_TAG(rxdp->Control_2));
} else {
- netif_rx(skb);
+ if (napi)
+ netif_receive_skb(skb);
+ else
+ netif_rx(skb);
}
-#endif
} else {
send_up:
queue_rx_frame(skb);
@@ -6622,7 +6592,7 @@ aggregate:
* void.
*/
-static void s2io_link(nic_t * sp, int link)
+static void s2io_link(struct s2io_nic * sp, int link)
{
struct net_device *dev = (struct net_device *) sp->dev;
@@ -6666,7 +6636,7 @@ static int get_xena_rev_id(struct pci_dev *pdev)
* void
*/
-static void s2io_init_pci(nic_t * sp)
+static void s2io_init_pci(struct s2io_nic * sp)
{
u16 pci_cmd = 0, pcix_cmd = 0;
@@ -6699,13 +6669,9 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type)
DBG_PRINT(ERR_DBG, "s2io: Default to 8 Rx rings\n");
rx_ring_num = 8;
}
-#ifdef CONFIG_S2IO_NAPI
- if (*dev_intr_type != INTA) {
- DBG_PRINT(ERR_DBG, "s2io: NAPI cannot be enabled when "
- "MSI/MSI-X is enabled. Defaulting to INTA\n");
- *dev_intr_type = INTA;
- }
-#endif
+ if (*dev_intr_type != INTA)
+ napi = 0;
+
#ifndef CONFIG_PCI_MSI
if (*dev_intr_type != INTA) {
DBG_PRINT(ERR_DBG, "s2io: This kernel does not support"
@@ -6726,6 +6692,8 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type)
"Defaulting to INTA\n");
*dev_intr_type = INTA;
}
+ if ( (rx_ring_num > 1) && (*dev_intr_type != INTA) )
+ napi = 0;
if (rx_ring_mode > 3) {
DBG_PRINT(ERR_DBG, "s2io: Requested ring mode not supported\n");
DBG_PRINT(ERR_DBG, "s2io: Defaulting to 3-buffer mode\n");
@@ -6751,15 +6719,15 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type)
static int __devinit
s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
{
- nic_t *sp;
+ struct s2io_nic *sp;
struct net_device *dev;
int i, j, ret;
int dma_flag = FALSE;
u32 mac_up, mac_down;
u64 val64 = 0, tmp64 = 0;
- XENA_dev_config_t __iomem *bar0 = NULL;
+ struct XENA_dev_config __iomem *bar0 = NULL;
u16 subid;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
int mode;
u8 dev_intr_type = intr_type;
@@ -6814,7 +6782,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
}
}
- dev = alloc_etherdev(sizeof(nic_t));
+ dev = alloc_etherdev(sizeof(struct s2io_nic));
if (dev == NULL) {
DBG_PRINT(ERR_DBG, "Device allocation failed\n");
pci_disable_device(pdev);
@@ -6829,7 +6797,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
/* Private member variable initialized to s2io NIC structure */
sp = dev->priv;
- memset(sp, 0, sizeof(nic_t));
+ memset(sp, 0, sizeof(struct s2io_nic));
sp->dev = dev;
sp->pdev = pdev;
sp->high_dma_flag = dma_flag;
@@ -6925,7 +6893,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
sp->bar0 = ioremap(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0));
if (!sp->bar0) {
- DBG_PRINT(ERR_DBG, "%s: S2IO: cannot remap io mem1\n",
+ DBG_PRINT(ERR_DBG, "%s: Neterion: cannot remap io mem1\n",
dev->name);
ret = -ENOMEM;
goto bar0_remap_failed;
@@ -6934,7 +6902,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
sp->bar1 = ioremap(pci_resource_start(pdev, 2),
pci_resource_len(pdev, 2));
if (!sp->bar1) {
- DBG_PRINT(ERR_DBG, "%s: S2IO: cannot remap io mem2\n",
+ DBG_PRINT(ERR_DBG, "%s: Neterion: cannot remap io mem2\n",
dev->name);
ret = -ENOMEM;
goto bar1_remap_failed;
@@ -6945,7 +6913,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
/* Initializing the BAR1 address as the start of the FIFO pointer. */
for (j = 0; j < MAX_TX_FIFOS; j++) {
- mac_control->tx_FIFO_start[j] = (TxFIFO_element_t __iomem *)
+ mac_control->tx_FIFO_start[j] = (struct TxFIFO_element __iomem *)
(sp->bar1 + (j * 0x00020000));
}
@@ -6966,10 +6934,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
* will use eth_mac_addr() for dev->set_mac_address
* mac address will be set every time dev->open() is called
*/
-#if defined(CONFIG_S2IO_NAPI)
dev->poll = s2io_poll;
dev->weight = 32;
-#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = s2io_netpoll;
@@ -6978,13 +6944,9 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
if (sp->high_dma_flag == TRUE)
dev->features |= NETIF_F_HIGHDMA;
-#ifdef NETIF_F_TSO
dev->features |= NETIF_F_TSO;
-#endif
-#ifdef NETIF_F_TSO6
dev->features |= NETIF_F_TSO6;
-#endif
- if (sp->device_type & XFRAME_II_DEVICE) {
+ if ((sp->device_type & XFRAME_II_DEVICE) && (ufo)) {
dev->features |= NETIF_F_UFO;
dev->features |= NETIF_F_HW_CSUM;
}
@@ -7065,9 +7027,9 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
/* Initialize spinlocks */
spin_lock_init(&sp->tx_lock);
-#ifndef CONFIG_S2IO_NAPI
- spin_lock_init(&sp->put_lock);
-#endif
+
+ if (!napi)
+ spin_lock_init(&sp->put_lock);
spin_lock_init(&sp->rx_lock);
/*
@@ -7098,13 +7060,14 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
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,
+ "%02x:%02x:%02x:%02x:%02x:%02x", dev->name,
sp->def_mac_addr[0].mac_addr[0],
sp->def_mac_addr[0].mac_addr[1],
sp->def_mac_addr[0].mac_addr[2],
sp->def_mac_addr[0].mac_addr[3],
sp->def_mac_addr[0].mac_addr[4],
sp->def_mac_addr[0].mac_addr[5]);
+ DBG_PRINT(ERR_DBG, "SERIAL NUMBER: %s\n", sp->serial_num);
if (sp->device_type & XFRAME_II_DEVICE) {
mode = s2io_print_pci_mode(sp);
if (mode < 0) {
@@ -7128,9 +7091,9 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
dev->name);
break;
}
-#ifdef CONFIG_S2IO_NAPI
- DBG_PRINT(ERR_DBG, "%s: NAPI enabled\n", dev->name);
-#endif
+
+ if (napi)
+ DBG_PRINT(ERR_DBG, "%s: NAPI enabled\n", dev->name);
switch(sp->intr_type) {
case INTA:
DBG_PRINT(ERR_DBG, "%s: Interrupt type INTA\n", dev->name);
@@ -7145,7 +7108,9 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
if (sp->lro)
DBG_PRINT(ERR_DBG, "%s: Large receive offload enabled\n",
dev->name);
-
+ if (ufo)
+ DBG_PRINT(ERR_DBG, "%s: UDP Fragmentation Offload(UFO)"
+ " enabled\n", dev->name);
/* Initialize device name */
sprintf(sp->name, "%s Neterion %s", dev->name, sp->product_name);
@@ -7202,7 +7167,7 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev)
{
struct net_device *dev =
(struct net_device *) pci_get_drvdata(pdev);
- nic_t *sp;
+ struct s2io_nic *sp;
if (dev == NULL) {
DBG_PRINT(ERR_DBG, "Driver Data is NULL!!\n");
@@ -7215,7 +7180,6 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev)
free_shared_mem(sp);
iounmap(sp->bar0);
iounmap(sp->bar1);
- pci_disable_device(pdev);
if (sp->intr_type != MSI_X)
pci_release_regions(pdev);
else {
@@ -7226,6 +7190,7 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev)
}
pci_set_drvdata(pdev, NULL);
free_netdev(dev);
+ pci_disable_device(pdev);
}
/**
@@ -7244,7 +7209,7 @@ int __init s2io_starter(void)
* Description: This function is the cleanup routine for the driver. It unregist * ers the driver.
*/
-static void s2io_closer(void)
+static __exit void s2io_closer(void)
{
pci_unregister_driver(&s2io_driver);
DBG_PRINT(INIT_DBG, "cleanup done\n");
@@ -7254,7 +7219,7 @@ module_init(s2io_starter);
module_exit(s2io_closer);
static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip,
- struct tcphdr **tcp, RxD_t *rxdp)
+ struct tcphdr **tcp, struct RxD_t *rxdp)
{
int ip_off;
u8 l2_type = (u8)((rxdp->Control_1 >> 37) & 0x7), ip_len;
@@ -7288,7 +7253,7 @@ static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip,
return 0;
}
-static int check_for_socket_match(lro_t *lro, struct iphdr *ip,
+static int check_for_socket_match(struct lro *lro, struct iphdr *ip,
struct tcphdr *tcp)
{
DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
@@ -7303,7 +7268,7 @@ static inline int get_l4_pyld_length(struct iphdr *ip, struct tcphdr *tcp)
return(ntohs(ip->tot_len) - (ip->ihl << 2) - (tcp->doff << 2));
}
-static void initiate_new_session(lro_t *lro, u8 *l2h,
+static void initiate_new_session(struct lro *lro, u8 *l2h,
struct iphdr *ip, struct tcphdr *tcp, u32 tcp_pyld_len)
{
DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
@@ -7329,12 +7294,12 @@ static void initiate_new_session(lro_t *lro, u8 *l2h,
lro->in_use = 1;
}
-static void update_L3L4_header(nic_t *sp, lro_t *lro)
+static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro)
{
struct iphdr *ip = lro->iph;
struct tcphdr *tcp = lro->tcph;
- u16 nchk;
- StatInfo_t *statinfo = sp->mac_control.stats_info;
+ __sum16 nchk;
+ struct stat_block *statinfo = sp->mac_control.stats_info;
DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
/* Update L3 header */
@@ -7360,7 +7325,7 @@ static void update_L3L4_header(nic_t *sp, lro_t *lro)
statinfo->sw_stat.num_aggregations++;
}
-static void aggregate_new_rx(lro_t *lro, struct iphdr *ip,
+static void aggregate_new_rx(struct lro *lro, struct iphdr *ip,
struct tcphdr *tcp, u32 l4_pyld)
{
DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
@@ -7382,7 +7347,7 @@ static void aggregate_new_rx(lro_t *lro, struct iphdr *ip,
}
}
-static int verify_l3_l4_lro_capable(lro_t *l_lro, struct iphdr *ip,
+static int verify_l3_l4_lro_capable(struct lro *l_lro, struct iphdr *ip,
struct tcphdr *tcp, u32 tcp_pyld_len)
{
u8 *ptr;
@@ -7440,8 +7405,8 @@ static int verify_l3_l4_lro_capable(lro_t *l_lro, struct iphdr *ip,
}
static int
-s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro,
- RxD_t *rxdp, nic_t *sp)
+s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, struct lro **lro,
+ struct RxD_t *rxdp, struct s2io_nic *sp)
{
struct iphdr *ip;
struct tcphdr *tcph;
@@ -7458,7 +7423,7 @@ s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro,
tcph = (struct tcphdr *)*tcp;
*tcp_len = get_l4_pyld_length(ip, tcph);
for (i=0; i<MAX_LRO_SESSIONS; i++) {
- lro_t *l_lro = &sp->lro0_n[i];
+ struct lro *l_lro = &sp->lro0_n[i];
if (l_lro->in_use) {
if (check_for_socket_match(l_lro, ip, tcph))
continue;
@@ -7496,7 +7461,7 @@ s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro,
}
for (i=0; i<MAX_LRO_SESSIONS; i++) {
- lro_t *l_lro = &sp->lro0_n[i];
+ struct lro *l_lro = &sp->lro0_n[i];
if (!(l_lro->in_use)) {
*lro = l_lro;
ret = 3; /* Begin anew */
@@ -7535,9 +7500,9 @@ s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro,
return ret;
}
-static void clear_lro_session(lro_t *lro)
+static void clear_lro_session(struct lro *lro)
{
- static u16 lro_struct_size = sizeof(lro_t);
+ static u16 lro_struct_size = sizeof(struct lro);
memset(lro, 0, lro_struct_size);
}
@@ -7547,14 +7512,14 @@ static void queue_rx_frame(struct sk_buff *skb)
struct net_device *dev = skb->dev;
skb->protocol = eth_type_trans(skb, dev);
-#ifdef CONFIG_S2IO_NAPI
- netif_receive_skb(skb);
-#else
- netif_rx(skb);
-#endif
+ if (napi)
+ netif_receive_skb(skb);
+ else
+ netif_rx(skb);
}
-static void lro_append_pkt(nic_t *sp, lro_t *lro, struct sk_buff *skb,
+static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro,
+ struct sk_buff *skb,
u32 tcp_len)
{
struct sk_buff *first = lro->parent;
@@ -7566,6 +7531,7 @@ static void lro_append_pkt(nic_t *sp, lro_t *lro, struct sk_buff *skb,
lro->last_frag->next = skb;
else
skb_shinfo(first)->frag_list = skb;
+ first->truesize += skb->truesize;
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 3b0bafd273c..0de0c65f945 100644
--- a/drivers/net/s2io.h
+++ b/drivers/net/s2io.h
@@ -30,6 +30,8 @@
#undef SUCCESS
#define SUCCESS 0
#define FAILURE -1
+#define S2IO_MINUS_ONE 0xFFFFFFFFFFFFFFFFULL
+#define S2IO_MAX_PCI_CONFIG_SPACE_REINIT 100
#define CHECKBIT(value, nbit) (value & (1 << nbit))
@@ -37,7 +39,7 @@
#define MAX_FLICKER_TIME 60000 /* 60 Secs */
/* Maximum outstanding splits to be configured into xena. */
-typedef enum xena_max_outstanding_splits {
+enum {
XENA_ONE_SPLIT_TRANSACTION = 0,
XENA_TWO_SPLIT_TRANSACTION = 1,
XENA_THREE_SPLIT_TRANSACTION = 2,
@@ -46,7 +48,7 @@ typedef enum xena_max_outstanding_splits {
XENA_TWELVE_SPLIT_TRANSACTION = 5,
XENA_SIXTEEN_SPLIT_TRANSACTION = 6,
XENA_THIRTYTWO_SPLIT_TRANSACTION = 7
-} xena_max_outstanding_splits;
+};
#define XENA_MAX_OUTSTANDING_SPLITS(n) (n << 4)
/* OS concerned variables and constants */
@@ -77,7 +79,7 @@ static int debug_level = ERR_DBG;
#define S2IO_JUMBO_SIZE 9600
/* Driver statistics maintained by driver */
-typedef struct {
+struct swStat {
unsigned long long single_ecc_errs;
unsigned long long double_ecc_errs;
unsigned long long parity_err_cnt;
@@ -92,10 +94,10 @@ typedef struct {
unsigned long long flush_max_pkts;
unsigned long long sum_avg_pkts_aggregated;
unsigned long long num_aggregations;
-} swStat_t;
+};
/* Xpak releated alarm and warnings */
-typedef struct {
+struct xpakStat {
u64 alarm_transceiver_temp_high;
u64 alarm_transceiver_temp_low;
u64 alarm_laser_bias_current_high;
@@ -110,11 +112,11 @@ typedef struct {
u64 warn_laser_output_power_low;
u64 xpak_regs_stat;
u32 xpak_timer_count;
-} xpakStat_t;
+};
/* The statistics block of Xena */
-typedef struct stat_block {
+struct stat_block {
/* Tx MAC statistics counters. */
__le32 tmac_data_octets;
__le32 tmac_frms;
@@ -290,9 +292,9 @@ typedef struct stat_block {
__le32 reserved_14;
__le32 link_fault_cnt;
u8 buffer[20];
- swStat_t sw_stat;
- xpakStat_t xpak_stat;
-} StatInfo_t;
+ struct swStat sw_stat;
+ struct xpakStat xpak_stat;
+};
/*
* Structures representing different init time configuration
@@ -315,7 +317,7 @@ static int fifo_map[][MAX_TX_FIFOS] = {
};
/* Maintains Per FIFO related information. */
-typedef struct tx_fifo_config {
+struct tx_fifo_config {
#define MAX_AVAILABLE_TXDS 8192
u32 fifo_len; /* specifies len of FIFO upto 8192, ie no of TxDLs */
/* Priority definition */
@@ -332,11 +334,11 @@ typedef struct tx_fifo_config {
u8 f_no_snoop;
#define NO_SNOOP_TXD 0x01
#define NO_SNOOP_TXD_BUFFER 0x02
-} tx_fifo_config_t;
+};
/* Maintains per Ring related information */
-typedef struct rx_ring_config {
+struct rx_ring_config {
u32 num_rxd; /*No of RxDs per Rx Ring */
#define RX_RING_PRI_0 0 /* highest */
#define RX_RING_PRI_1 1
@@ -357,7 +359,7 @@ typedef struct rx_ring_config {
u8 f_no_snoop;
#define NO_SNOOP_RXD 0x01
#define NO_SNOOP_RXD_BUFFER 0x02
-} rx_ring_config_t;
+};
/* This structure provides contains values of the tunable parameters
* of the H/W
@@ -367,7 +369,7 @@ struct config_param {
u32 tx_fifo_num; /*Number of Tx FIFOs */
u8 fifo_mapping[MAX_TX_FIFOS];
- tx_fifo_config_t tx_cfg[MAX_TX_FIFOS]; /*Per-Tx FIFO config */
+ struct tx_fifo_config tx_cfg[MAX_TX_FIFOS]; /*Per-Tx FIFO config */
u32 max_txds; /*Max no. of Tx buffer descriptor per TxDL */
u64 tx_intr_type;
/* Specifies if Tx Intr is UTILZ or PER_LIST type. */
@@ -376,7 +378,7 @@ struct config_param {
u32 rx_ring_num; /*Number of receive rings */
#define MAX_RX_BLOCKS_PER_RING 150
- rx_ring_config_t rx_cfg[MAX_RX_RINGS]; /*Per-Rx Ring config */
+ struct rx_ring_config rx_cfg[MAX_RX_RINGS]; /*Per-Rx Ring config */
u8 bimodal; /*Flag for setting bimodal interrupts*/
#define HEADER_ETHERNET_II_802_3_SIZE 14
@@ -395,14 +397,14 @@ struct config_param {
};
/* Structure representing MAC Addrs */
-typedef struct mac_addr {
+struct mac_addr {
u8 mac_addr[ETH_ALEN];
-} macaddr_t;
+};
/* Structure that represent every FIFO element in the BAR1
* Address location.
*/
-typedef struct _TxFIFO_element {
+struct TxFIFO_element {
u64 TxDL_Pointer;
u64 List_Control;
@@ -413,10 +415,10 @@ typedef struct _TxFIFO_element {
#define TX_FIFO_SPECIAL_FUNC BIT(23)
#define TX_FIFO_DS_NO_SNOOP BIT(31)
#define TX_FIFO_BUFF_NO_SNOOP BIT(30)
-} TxFIFO_element_t;
+};
/* Tx descriptor structure */
-typedef struct _TxD {
+struct TxD {
u64 Control_1;
/* bit mask */
#define TXD_LIST_OWN_XENA BIT(7)
@@ -447,16 +449,16 @@ typedef struct _TxD {
u64 Buffer_Pointer;
u64 Host_Control; /* reserved for host */
-} TxD_t;
+};
/* Structure to hold the phy and virt addr of every TxDL. */
-typedef struct list_info_hold {
+struct list_info_hold {
dma_addr_t list_phy_addr;
void *list_virt_addr;
-} list_info_hold_t;
+};
/* Rx descriptor structure for 1 buffer mode */
-typedef struct _RxD_t {
+struct RxD_t {
u64 Host_Control; /* reserved for host */
u64 Control_1;
#define RXD_OWN_XENA BIT(7)
@@ -481,21 +483,21 @@ typedef struct _RxD_t {
#define SET_NUM_TAG(val) vBIT(val,16,32)
-} RxD_t;
+};
/* Rx descriptor structure for 1 buffer mode */
-typedef struct _RxD1_t {
- struct _RxD_t h;
+struct RxD1 {
+ struct RxD_t h;
#define MASK_BUFFER0_SIZE_1 vBIT(0x3FFF,2,14)
#define SET_BUFFER0_SIZE_1(val) vBIT(val,2,14)
#define RXD_GET_BUFFER0_SIZE_1(_Control_2) \
(u16)((_Control_2 & MASK_BUFFER0_SIZE_1) >> 48)
u64 Buffer0_ptr;
-} RxD1_t;
+};
/* Rx descriptor structure for 3 or 2 buffer mode */
-typedef struct _RxD3_t {
- struct _RxD_t h;
+struct RxD3 {
+ struct RxD_t h;
#define MASK_BUFFER0_SIZE_3 vBIT(0xFF,2,14)
#define MASK_BUFFER1_SIZE_3 vBIT(0xFFFF,16,16)
@@ -515,15 +517,15 @@ typedef struct _RxD3_t {
u64 Buffer0_ptr;
u64 Buffer1_ptr;
u64 Buffer2_ptr;
-} RxD3_t;
+};
/* Structure that represents the Rx descriptor block which contains
* 128 Rx descriptors.
*/
-typedef struct _RxD_block {
+struct RxD_block {
#define MAX_RXDS_PER_BLOCK_1 127
- RxD1_t rxd[MAX_RXDS_PER_BLOCK_1];
+ struct RxD1 rxd[MAX_RXDS_PER_BLOCK_1];
u64 reserved_0;
#define END_OF_BLOCK 0xFEFFFFFFFFFFFFFFULL
@@ -533,22 +535,22 @@ typedef struct _RxD_block {
u64 pNext_RxD_Blk_physical; /* Buff0_ptr.In a 32 bit arch
* the upper 32 bits should
* be 0 */
-} RxD_block_t;
+};
#define SIZE_OF_BLOCK 4096
-#define RXD_MODE_1 0
-#define RXD_MODE_3A 1
-#define RXD_MODE_3B 2
+#define RXD_MODE_1 0 /* One Buffer mode */
+#define RXD_MODE_3A 1 /* Three Buffer mode */
+#define RXD_MODE_3B 2 /* Two Buffer mode */
/* Structure to hold virtual addresses of Buf0 and Buf1 in
* 2buf mode. */
-typedef struct bufAdd {
+struct buffAdd {
void *ba_0_org;
void *ba_1_org;
void *ba_0;
void *ba_1;
-} buffAdd_t;
+};
/* Structure which stores all the MAC control parameters */
@@ -556,43 +558,46 @@ typedef struct bufAdd {
* from which the Rx Interrupt processor can start picking
* up the RxDs for processing.
*/
-typedef struct _rx_curr_get_info_t {
+struct rx_curr_get_info {
u32 block_index;
u32 offset;
u32 ring_len;
-} rx_curr_get_info_t;
+};
-typedef rx_curr_get_info_t rx_curr_put_info_t;
+struct rx_curr_put_info {
+ u32 block_index;
+ u32 offset;
+ u32 ring_len;
+};
/* This structure stores the offset of the TxDl in the FIFO
* from which the Tx Interrupt processor can start picking
* up the TxDLs for send complete interrupt processing.
*/
-typedef struct {
+struct tx_curr_get_info {
u32 offset;
u32 fifo_len;
-} tx_curr_get_info_t;
-
-typedef tx_curr_get_info_t tx_curr_put_info_t;
+};
+struct tx_curr_put_info {
+ u32 offset;
+ u32 fifo_len;
+};
-typedef struct rxd_info {
+struct rxd_info {
void *virt_addr;
dma_addr_t dma_addr;
-}rxd_info_t;
+};
/* Structure that holds the Phy and virt addresses of the Blocks */
-typedef struct rx_block_info {
+struct rx_block_info {
void *block_virt_addr;
dma_addr_t block_dma_addr;
- rxd_info_t *rxds;
-} rx_block_info_t;
-
-/* pre declaration of the nic structure */
-typedef struct s2io_nic nic_t;
+ struct rxd_info *rxds;
+};
/* Ring specific structure */
-typedef struct ring_info {
+struct ring_info {
/* The ring number */
int ring_no;
@@ -600,7 +605,7 @@ typedef struct ring_info {
* Place holders for the virtual and physical addresses of
* all the Rx Blocks
*/
- rx_block_info_t rx_blocks[MAX_RX_BLOCKS_PER_RING];
+ struct rx_block_info rx_blocks[MAX_RX_BLOCKS_PER_RING];
int block_count;
int pkt_cnt;
@@ -608,26 +613,24 @@ typedef struct ring_info {
* Put pointer info which indictes which RxD has to be replenished
* with a new buffer.
*/
- rx_curr_put_info_t rx_curr_put_info;
+ struct rx_curr_put_info rx_curr_put_info;
/*
* Get pointer info which indictes which is the last RxD that was
* processed by the driver.
*/
- rx_curr_get_info_t rx_curr_get_info;
+ struct rx_curr_get_info rx_curr_get_info;
-#ifndef CONFIG_S2IO_NAPI
/* Index to the absolute position of the put pointer of Rx ring */
int put_pos;
-#endif
/* Buffer Address store. */
- buffAdd_t **ba;
- nic_t *nic;
-} ring_info_t;
+ struct buffAdd **ba;
+ struct s2io_nic *nic;
+};
/* Fifo specific structure */
-typedef struct fifo_info {
+struct fifo_info {
/* FIFO number */
int fifo_no;
@@ -635,40 +638,40 @@ typedef struct fifo_info {
int max_txds;
/* Place holder of all the TX List's Phy and Virt addresses. */
- list_info_hold_t *list_info;
+ struct list_info_hold *list_info;
/*
* Current offset within the tx FIFO where driver would write
* new Tx frame
*/
- tx_curr_put_info_t tx_curr_put_info;
+ struct tx_curr_put_info tx_curr_put_info;
/*
* Current offset within tx FIFO from where the driver would start freeing
* the buffers
*/
- tx_curr_get_info_t tx_curr_get_info;
+ struct tx_curr_get_info tx_curr_get_info;
- nic_t *nic;
-}fifo_info_t;
+ struct s2io_nic *nic;
+};
/* Information related to the Tx and Rx FIFOs and Rings of Xena
* is maintained in this structure.
*/
-typedef struct mac_info {
+struct mac_info {
/* tx side stuff */
/* logical pointer of start of each Tx FIFO */
- TxFIFO_element_t __iomem *tx_FIFO_start[MAX_TX_FIFOS];
+ struct TxFIFO_element __iomem *tx_FIFO_start[MAX_TX_FIFOS];
/* Fifo specific structure */
- fifo_info_t fifos[MAX_TX_FIFOS];
+ struct fifo_info fifos[MAX_TX_FIFOS];
/* Save virtual address of TxD page with zero DMA addr(if any) */
void *zerodma_virt_addr;
/* rx side stuff */
/* Ring specific structure */
- ring_info_t rings[MAX_RX_RINGS];
+ struct ring_info rings[MAX_RX_RINGS];
u16 rmac_pause_time;
u16 mc_pause_threshold_q0q3;
@@ -677,14 +680,14 @@ typedef struct mac_info {
void *stats_mem; /* orignal pointer to allocated mem */
dma_addr_t stats_mem_phy; /* Physical address of the stat block */
u32 stats_mem_sz;
- StatInfo_t *stats_info; /* Logical address of the stat block */
-} mac_info_t;
+ struct stat_block *stats_info; /* Logical address of the stat block */
+};
/* structure representing the user defined MAC addresses */
-typedef struct {
+struct usr_addr {
char addr[ETH_ALEN];
int usage_cnt;
-} usr_addr_t;
+};
/* Default Tunable parameters of the NIC. */
#define DEFAULT_FIFO_0_LEN 4096
@@ -717,36 +720,34 @@ struct msix_info_st {
};
/* Data structure to represent a LRO session */
-typedef struct lro {
+struct lro {
struct sk_buff *parent;
struct sk_buff *last_frag;
u8 *l2h;
struct iphdr *iph;
struct tcphdr *tcph;
u32 tcp_next_seq;
- u32 tcp_ack;
+ __be32 tcp_ack;
int total_len;
int frags_len;
int sg_num;
int in_use;
- u16 window;
+ __be16 window;
u32 cur_tsval;
u32 cur_tsecr;
u8 saw_ts;
-}lro_t;
+};
/* Structure representing one instance of the NIC */
struct s2io_nic {
int rxd_mode;
-#ifdef CONFIG_S2IO_NAPI
/*
* Count of packets to be processed in a given iteration, it will be indicated
* by the quota field of the device structure when NAPI is enabled.
*/
int pkts_to_process;
-#endif
struct net_device *dev;
- mac_info_t mac_control;
+ struct mac_info mac_control;
struct config_param config;
struct pci_dev *pdev;
void __iomem *bar0;
@@ -754,8 +755,8 @@ struct s2io_nic {
#define MAX_MAC_SUPPORTED 16
#define MAX_SUPPORTED_MULTICASTS MAX_MAC_SUPPORTED
- macaddr_t def_mac_addr[MAX_MAC_SUPPORTED];
- macaddr_t pre_mac_addr[MAX_MAC_SUPPORTED];
+ struct mac_addr def_mac_addr[MAX_MAC_SUPPORTED];
+ struct mac_addr pre_mac_addr[MAX_MAC_SUPPORTED];
struct net_device_stats stats;
int high_dma_flag;
@@ -775,9 +776,7 @@ struct s2io_nic {
atomic_t rx_bufs_left[MAX_RX_RINGS];
spinlock_t tx_lock;
-#ifndef CONFIG_S2IO_NAPI
spinlock_t put_lock;
-#endif
#define PROMISC 1
#define ALL_MULTI 2
@@ -785,7 +784,7 @@ struct s2io_nic {
#define MAX_ADDRS_SUPPORTED 64
u16 usr_addr_count;
u16 mc_addr_count;
- usr_addr_t usr_addrs[MAX_ADDRS_SUPPORTED];
+ struct usr_addr usr_addrs[MAX_ADDRS_SUPPORTED];
u16 m_cast_flg;
u16 all_multi_pos;
@@ -841,7 +840,7 @@ struct s2io_nic {
u8 device_type;
#define MAX_LRO_SESSIONS 32
- lro_t lro0_n[MAX_LRO_SESSIONS];
+ struct lro lro0_n[MAX_LRO_SESSIONS];
unsigned long clubbed_frms_cnt;
unsigned long sending_both;
u8 lro;
@@ -855,8 +854,9 @@ struct s2io_nic {
spinlock_t rx_lock;
atomic_t isr_cnt;
u64 *ufo_in_band_v;
-#define VPD_PRODUCT_NAME_LEN 50
- u8 product_name[VPD_PRODUCT_NAME_LEN];
+#define VPD_STRING_LEN 80
+ u8 product_name[VPD_STRING_LEN];
+ u8 serial_num[VPD_STRING_LEN];
};
#define RESET_ERROR 1;
@@ -975,43 +975,50 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev);
static int init_shared_mem(struct s2io_nic *sp);
static void free_shared_mem(struct s2io_nic *sp);
static int init_nic(struct s2io_nic *nic);
-static void rx_intr_handler(ring_info_t *ring_data);
-static void tx_intr_handler(fifo_info_t *fifo_data);
+static void rx_intr_handler(struct ring_info *ring_data);
+static void tx_intr_handler(struct fifo_info *fifo_data);
static void alarm_intr_handler(struct s2io_nic *sp);
static int s2io_starter(void);
+static void s2io_closer(void);
static void s2io_tx_watchdog(struct net_device *dev);
static void s2io_tasklet(unsigned long dev_addr);
static void s2io_set_multicast(struct net_device *dev);
-static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp);
-static void s2io_link(nic_t * sp, int link);
-#if defined(CONFIG_S2IO_NAPI)
+static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp);
+static void s2io_link(struct s2io_nic * sp, int link);
+static void s2io_reset(struct s2io_nic * sp);
static int s2io_poll(struct net_device *dev, int *budget);
-#endif
-static void s2io_init_pci(nic_t * sp);
+static void s2io_init_pci(struct s2io_nic * sp);
static int s2io_set_mac_addr(struct net_device *dev, u8 * addr);
static void s2io_alarm_handle(unsigned long data);
-static int s2io_enable_msi(nic_t *nic);
+static int s2io_enable_msi(struct s2io_nic *nic);
static irqreturn_t s2io_msi_handle(int irq, void *dev_id);
static irqreturn_t
s2io_msix_ring_handle(int irq, void *dev_id);
static irqreturn_t
s2io_msix_fifo_handle(int irq, void *dev_id);
static irqreturn_t s2io_isr(int irq, void *dev_id);
-static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag);
+static int verify_xena_quiescence(struct s2io_nic *sp);
static const struct ethtool_ops netdev_ethtool_ops;
static void s2io_set_link(struct work_struct *work);
-static int s2io_set_swapper(nic_t * sp);
-static void s2io_card_down(nic_t *nic);
-static int s2io_card_up(nic_t *nic);
+static int s2io_set_swapper(struct s2io_nic * sp);
+static void s2io_card_down(struct s2io_nic *nic);
+static int s2io_card_up(struct s2io_nic *nic);
static int get_xena_rev_id(struct pci_dev *pdev);
-static void restore_xmsi_data(nic_t *nic);
+static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit);
+static int s2io_add_isr(struct s2io_nic * sp);
+static void s2io_rem_isr(struct s2io_nic * sp);
+
+static void restore_xmsi_data(struct s2io_nic *nic);
-static int s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro, RxD_t *rxdp, nic_t *sp);
-static void clear_lro_session(lro_t *lro);
+static int
+s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, struct lro **lro,
+ struct RxD_t *rxdp, struct s2io_nic *sp);
+static void clear_lro_session(struct lro *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);
+static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro);
+static void lro_append_pkt(struct s2io_nic *sp, struct lro *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
diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c
new file mode 100644
index 00000000000..7f800feaa9a
--- /dev/null
+++ b/drivers/net/sc92031.c
@@ -0,0 +1,1620 @@
+/* Silan SC92031 PCI Fast Ethernet Adapter driver
+ *
+ * Based on vendor drivers:
+ * Silan Fast Ethernet Netcard Driver:
+ * MODULE_AUTHOR ("gaoyonghong");
+ * MODULE_DESCRIPTION ("SILAN Fast Ethernet driver");
+ * MODULE_LICENSE("GPL");
+ * 8139D Fast Ethernet driver:
+ * (C) 2002 by gaoyonghong
+ * MODULE_AUTHOR ("gaoyonghong");
+ * MODULE_DESCRIPTION ("Rsltek 8139D PCI Fast Ethernet Adapter driver");
+ * MODULE_LICENSE("GPL");
+ * Both are almost identical and seem to be based on pci-skeleton.c
+ *
+ * Rewritten for 2.6 by Cesar Eduardo Barros
+ */
+
+/* Note about set_mac_address: I don't know how to change the hardware
+ * matching, so you need to enable IFF_PROMISC when using it.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/crc32.h>
+
+#include <asm/irq.h>
+
+#define PCI_VENDOR_ID_SILAN 0x1904
+#define PCI_DEVICE_ID_SILAN_SC92031 0x2031
+#define PCI_DEVICE_ID_SILAN_8139D 0x8139
+
+#define SC92031_NAME "sc92031"
+#define SC92031_DESCRIPTION "Silan SC92031 PCI Fast Ethernet Adapter driver"
+#define SC92031_VERSION "2.0c"
+
+/* BAR 0 is MMIO, BAR 1 is PIO */
+#ifndef SC92031_USE_BAR
+#define SC92031_USE_BAR 0
+#endif
+
+/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). */
+static int multicast_filter_limit = 64;
+module_param(multicast_filter_limit, int, 0);
+MODULE_PARM_DESC(multicast_filter_limit,
+ "Maximum number of filtered multicast addresses");
+
+static int media;
+module_param(media, int, 0);
+MODULE_PARM_DESC(media, "Media type (0x00 = autodetect,"
+ " 0x01 = 10M half, 0x02 = 10M full,"
+ " 0x04 = 100M half, 0x08 = 100M full)");
+
+/* Size of the in-memory receive ring. */
+#define RX_BUF_LEN_IDX 3 /* 0==8K, 1==16K, 2==32K, 3==64K ,4==128K*/
+#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX)
+
+/* Number of Tx descriptor registers. */
+#define NUM_TX_DESC 4
+
+/* max supported ethernet frame size -- must be at least (dev->mtu+14+4).*/
+#define MAX_ETH_FRAME_SIZE 1536
+
+/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */
+#define TX_BUF_SIZE MAX_ETH_FRAME_SIZE
+#define TX_BUF_TOT_LEN (TX_BUF_SIZE * NUM_TX_DESC)
+
+/* The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024, 7==end of packet. */
+#define RX_FIFO_THRESH 7 /* Rx buffer level before first PCI xfer. */
+
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT (4*HZ)
+
+#define SILAN_STATS_NUM 2 /* number of ETHTOOL_GSTATS */
+
+/* media options */
+#define AUTOSELECT 0x00
+#define M10_HALF 0x01
+#define M10_FULL 0x02
+#define M100_HALF 0x04
+#define M100_FULL 0x08
+
+ /* Symbolic offsets to registers. */
+enum silan_registers {
+ Config0 = 0x00, // Config0
+ Config1 = 0x04, // Config1
+ RxBufWPtr = 0x08, // Rx buffer writer poiter
+ IntrStatus = 0x0C, // Interrupt status
+ IntrMask = 0x10, // Interrupt mask
+ RxbufAddr = 0x14, // Rx buffer start address
+ RxBufRPtr = 0x18, // Rx buffer read pointer
+ Txstatusall = 0x1C, // Transmit status of all descriptors
+ TxStatus0 = 0x20, // Transmit status (Four 32bit registers).
+ TxAddr0 = 0x30, // Tx descriptors (also four 32bit).
+ RxConfig = 0x40, // Rx configuration
+ MAC0 = 0x44, // Ethernet hardware address.
+ MAR0 = 0x4C, // Multicast filter.
+ RxStatus0 = 0x54, // Rx status
+ TxConfig = 0x5C, // Tx configuration
+ PhyCtrl = 0x60, // physical control
+ FlowCtrlConfig = 0x64, // flow control
+ Miicmd0 = 0x68, // Mii command0 register
+ Miicmd1 = 0x6C, // Mii command1 register
+ Miistatus = 0x70, // Mii status register
+ Timercnt = 0x74, // Timer counter register
+ TimerIntr = 0x78, // Timer interrupt register
+ PMConfig = 0x7C, // Power Manager configuration
+ CRC0 = 0x80, // Power Manager CRC ( Two 32bit regisers)
+ Wakeup0 = 0x88, // power Manager wakeup( Eight 64bit regiser)
+ LSBCRC0 = 0xC8, // power Manager LSBCRC(Two 32bit regiser)
+ TestD0 = 0xD0,
+ TestD4 = 0xD4,
+ TestD8 = 0xD8,
+};
+
+#define MII_BMCR 0 // Basic mode control register
+#define MII_BMSR 1 // Basic mode status register
+#define MII_JAB 16
+#define MII_OutputStatus 24
+
+#define BMCR_FULLDPLX 0x0100 // Full duplex
+#define BMCR_ANRESTART 0x0200 // Auto negotiation restart
+#define BMCR_ANENABLE 0x1000 // Enable auto negotiation
+#define BMCR_SPEED100 0x2000 // Select 100Mbps
+#define BMSR_LSTATUS 0x0004 // Link status
+#define PHY_16_JAB_ENB 0x1000
+#define PHY_16_PORT_ENB 0x1
+
+enum IntrStatusBits {
+ LinkFail = 0x80000000,
+ LinkOK = 0x40000000,
+ TimeOut = 0x20000000,
+ RxOverflow = 0x0040,
+ RxOK = 0x0020,
+ TxOK = 0x0001,
+ IntrBits = LinkFail|LinkOK|TimeOut|RxOverflow|RxOK|TxOK,
+};
+
+enum TxStatusBits {
+ TxCarrierLost = 0x20000000,
+ TxAborted = 0x10000000,
+ TxOutOfWindow = 0x08000000,
+ TxNccShift = 22,
+ EarlyTxThresShift = 16,
+ TxStatOK = 0x8000,
+ TxUnderrun = 0x4000,
+ TxOwn = 0x2000,
+};
+
+enum RxStatusBits {
+ RxStatesOK = 0x80000,
+ RxBadAlign = 0x40000,
+ RxHugeFrame = 0x20000,
+ RxSmallFrame = 0x10000,
+ RxCRCOK = 0x8000,
+ RxCrlFrame = 0x4000,
+ Rx_Broadcast = 0x2000,
+ Rx_Multicast = 0x1000,
+ RxAddrMatch = 0x0800,
+ MiiErr = 0x0400,
+};
+
+enum RxConfigBits {
+ RxFullDx = 0x80000000,
+ RxEnb = 0x40000000,
+ RxSmall = 0x20000000,
+ RxHuge = 0x10000000,
+ RxErr = 0x08000000,
+ RxAllphys = 0x04000000,
+ RxMulticast = 0x02000000,
+ RxBroadcast = 0x01000000,
+ RxLoopBack = (1 << 23) | (1 << 22),
+ LowThresholdShift = 12,
+ HighThresholdShift = 2,
+};
+
+enum TxConfigBits {
+ TxFullDx = 0x80000000,
+ TxEnb = 0x40000000,
+ TxEnbPad = 0x20000000,
+ TxEnbHuge = 0x10000000,
+ TxEnbFCS = 0x08000000,
+ TxNoBackOff = 0x04000000,
+ TxEnbPrem = 0x02000000,
+ TxCareLostCrs = 0x1000000,
+ TxExdCollNum = 0xf00000,
+ TxDataRate = 0x80000,
+};
+
+enum PhyCtrlconfigbits {
+ PhyCtrlAne = 0x80000000,
+ PhyCtrlSpd100 = 0x40000000,
+ PhyCtrlSpd10 = 0x20000000,
+ PhyCtrlPhyBaseAddr = 0x1f000000,
+ PhyCtrlDux = 0x800000,
+ PhyCtrlReset = 0x400000,
+};
+
+enum FlowCtrlConfigBits {
+ FlowCtrlFullDX = 0x80000000,
+ FlowCtrlEnb = 0x40000000,
+};
+
+enum Config0Bits {
+ Cfg0_Reset = 0x80000000,
+ Cfg0_Anaoff = 0x40000000,
+ Cfg0_LDPS = 0x20000000,
+};
+
+enum Config1Bits {
+ Cfg1_EarlyRx = 1 << 31,
+ Cfg1_EarlyTx = 1 << 30,
+
+ //rx buffer size
+ Cfg1_Rcv8K = 0x0,
+ Cfg1_Rcv16K = 0x1,
+ Cfg1_Rcv32K = 0x3,
+ Cfg1_Rcv64K = 0x7,
+ Cfg1_Rcv128K = 0xf,
+};
+
+enum MiiCmd0Bits {
+ Mii_Divider = 0x20000000,
+ Mii_WRITE = 0x400000,
+ Mii_READ = 0x200000,
+ Mii_SCAN = 0x100000,
+ Mii_Tamod = 0x80000,
+ Mii_Drvmod = 0x40000,
+ Mii_mdc = 0x20000,
+ Mii_mdoen = 0x10000,
+ Mii_mdo = 0x8000,
+ Mii_mdi = 0x4000,
+};
+
+enum MiiStatusBits {
+ Mii_StatusBusy = 0x80000000,
+};
+
+enum PMConfigBits {
+ PM_Enable = 1 << 31,
+ PM_LongWF = 1 << 30,
+ PM_Magic = 1 << 29,
+ PM_LANWake = 1 << 28,
+ PM_LWPTN = (1 << 27 | 1<< 26),
+ PM_LinkUp = 1 << 25,
+ PM_WakeUp = 1 << 24,
+};
+
+/* Locking rules:
+ * priv->lock protects most of the fields of priv and most of the
+ * hardware registers. It does not have to protect against softirqs
+ * between sc92031_disable_interrupts and sc92031_enable_interrupts;
+ * it also does not need to be used in ->open and ->stop while the
+ * device interrupts are off.
+ * Not having to protect against softirqs is very useful due to heavy
+ * use of mdelay() at _sc92031_reset.
+ * Functions prefixed with _sc92031_ must be called with the lock held;
+ * functions prefixed with sc92031_ must be called without the lock held.
+ * Use mmiowb() before unlocking if the hardware was written to.
+ */
+
+/* Locking rules for the interrupt:
+ * - the interrupt and the tasklet never run at the same time
+ * - neither run between sc92031_disable_interrupts and
+ * sc92031_enable_interrupt
+ */
+
+struct sc92031_priv {
+ spinlock_t lock;
+ /* iomap.h cookie */
+ void __iomem *port_base;
+ /* pci device structure */
+ struct pci_dev *pdev;
+ /* tasklet */
+ struct tasklet_struct tasklet;
+
+ /* CPU address of rx ring */
+ void *rx_ring;
+ /* PCI address of rx ring */
+ dma_addr_t rx_ring_dma_addr;
+ /* PCI address of rx ring read pointer */
+ dma_addr_t rx_ring_tail;
+
+ /* tx ring write index */
+ unsigned tx_head;
+ /* tx ring read index */
+ unsigned tx_tail;
+ /* CPU address of tx bounce buffer */
+ void *tx_bufs;
+ /* PCI address of tx bounce buffer */
+ dma_addr_t tx_bufs_dma_addr;
+
+ /* copies of some hardware registers */
+ u32 intr_status;
+ atomic_t intr_mask;
+ u32 rx_config;
+ u32 tx_config;
+ u32 pm_config;
+
+ /* copy of some flags from dev->flags */
+ unsigned int mc_flags;
+
+ /* for ETHTOOL_GSTATS */
+ u64 tx_timeouts;
+ u64 rx_loss;
+
+ /* for dev->get_stats */
+ long rx_value;
+ struct net_device_stats stats;
+};
+
+/* I don't know which registers can be safely read; however, I can guess
+ * MAC0 is one of them. */
+static inline void _sc92031_dummy_read(void __iomem *port_base)
+{
+ ioread32(port_base + MAC0);
+}
+
+static u32 _sc92031_mii_wait(void __iomem *port_base)
+{
+ u32 mii_status;
+
+ do {
+ udelay(10);
+ mii_status = ioread32(port_base + Miistatus);
+ } while (mii_status & Mii_StatusBusy);
+
+ return mii_status;
+}
+
+static u32 _sc92031_mii_cmd(void __iomem *port_base, u32 cmd0, u32 cmd1)
+{
+ iowrite32(Mii_Divider, port_base + Miicmd0);
+
+ _sc92031_mii_wait(port_base);
+
+ iowrite32(cmd1, port_base + Miicmd1);
+ iowrite32(Mii_Divider | cmd0, port_base + Miicmd0);
+
+ return _sc92031_mii_wait(port_base);
+}
+
+static void _sc92031_mii_scan(void __iomem *port_base)
+{
+ _sc92031_mii_cmd(port_base, Mii_SCAN, 0x1 << 6);
+}
+
+static u16 _sc92031_mii_read(void __iomem *port_base, unsigned reg)
+{
+ return _sc92031_mii_cmd(port_base, Mii_READ, reg << 6) >> 13;
+}
+
+static void _sc92031_mii_write(void __iomem *port_base, unsigned reg, u16 val)
+{
+ _sc92031_mii_cmd(port_base, Mii_WRITE, (reg << 6) | ((u32)val << 11));
+}
+
+static void sc92031_disable_interrupts(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+
+ /* tell the tasklet/interrupt not to enable interrupts */
+ atomic_set(&priv->intr_mask, 0);
+ wmb();
+
+ /* stop interrupts */
+ iowrite32(0, port_base + IntrMask);
+ _sc92031_dummy_read(port_base);
+ mmiowb();
+
+ /* wait for any concurrent interrupt/tasklet to finish */
+ synchronize_irq(dev->irq);
+ tasklet_disable(&priv->tasklet);
+}
+
+static void sc92031_enable_interrupts(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+
+ tasklet_enable(&priv->tasklet);
+
+ atomic_set(&priv->intr_mask, IntrBits);
+ wmb();
+
+ iowrite32(IntrBits, port_base + IntrMask);
+ mmiowb();
+}
+
+static void _sc92031_disable_tx_rx(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+
+ priv->rx_config &= ~RxEnb;
+ priv->tx_config &= ~TxEnb;
+ iowrite32(priv->rx_config, port_base + RxConfig);
+ iowrite32(priv->tx_config, port_base + TxConfig);
+}
+
+static void _sc92031_enable_tx_rx(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+
+ priv->rx_config |= RxEnb;
+ priv->tx_config |= TxEnb;
+ iowrite32(priv->rx_config, port_base + RxConfig);
+ iowrite32(priv->tx_config, port_base + TxConfig);
+}
+
+static void _sc92031_tx_clear(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+
+ while (priv->tx_head - priv->tx_tail > 0) {
+ priv->tx_tail++;
+ priv->stats.tx_dropped++;
+ }
+ priv->tx_head = priv->tx_tail = 0;
+}
+
+static void _sc92031_set_mar(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+ u32 mar0 = 0, mar1 = 0;
+
+ if ((dev->flags & IFF_PROMISC)
+ || dev->mc_count > multicast_filter_limit
+ || (dev->flags & IFF_ALLMULTI))
+ mar0 = mar1 = 0xffffffff;
+ else if (dev->flags & IFF_MULTICAST) {
+ struct dev_mc_list *mc_list;
+
+ for (mc_list = dev->mc_list; mc_list; mc_list = mc_list->next) {
+ u32 crc;
+ unsigned bit = 0;
+
+ crc = ~ether_crc(ETH_ALEN, mc_list->dmi_addr);
+ crc >>= 24;
+
+ if (crc & 0x01) bit |= 0x02;
+ if (crc & 0x02) bit |= 0x01;
+ if (crc & 0x10) bit |= 0x20;
+ if (crc & 0x20) bit |= 0x10;
+ if (crc & 0x40) bit |= 0x08;
+ if (crc & 0x80) bit |= 0x04;
+
+ if (bit > 31)
+ mar0 |= 0x1 << (bit - 32);
+ else
+ mar1 |= 0x1 << bit;
+ }
+ }
+
+ iowrite32(mar0, port_base + MAR0);
+ iowrite32(mar1, port_base + MAR0 + 4);
+}
+
+static void _sc92031_set_rx_config(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+ unsigned int old_mc_flags;
+ u32 rx_config_bits = 0;
+
+ old_mc_flags = priv->mc_flags;
+
+ if (dev->flags & IFF_PROMISC)
+ rx_config_bits |= RxSmall | RxHuge | RxErr | RxBroadcast
+ | RxMulticast | RxAllphys;
+
+ if (dev->flags & (IFF_ALLMULTI | IFF_MULTICAST))
+ rx_config_bits |= RxMulticast;
+
+ if (dev->flags & IFF_BROADCAST)
+ rx_config_bits |= RxBroadcast;
+
+ priv->rx_config &= ~(RxSmall | RxHuge | RxErr | RxBroadcast
+ | RxMulticast | RxAllphys);
+ priv->rx_config |= rx_config_bits;
+
+ priv->mc_flags = dev->flags & (IFF_PROMISC | IFF_ALLMULTI
+ | IFF_MULTICAST | IFF_BROADCAST);
+
+ if (netif_carrier_ok(dev) && priv->mc_flags != old_mc_flags)
+ iowrite32(priv->rx_config, port_base + RxConfig);
+}
+
+static bool _sc92031_check_media(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+ u16 bmsr;
+
+ bmsr = _sc92031_mii_read(port_base, MII_BMSR);
+ rmb();
+ if (bmsr & BMSR_LSTATUS) {
+ bool speed_100, duplex_full;
+ u32 flow_ctrl_config = 0;
+ u16 output_status = _sc92031_mii_read(port_base,
+ MII_OutputStatus);
+ _sc92031_mii_scan(port_base);
+
+ speed_100 = output_status & 0x2;
+ duplex_full = output_status & 0x4;
+
+ /* Initial Tx/Rx configuration */
+ priv->rx_config = (0x40 << LowThresholdShift) | (0x1c0 << HighThresholdShift);
+ priv->tx_config = 0x48800000;
+
+ /* NOTE: vendor driver had dead code here to enable tx padding */
+
+ if (!speed_100)
+ priv->tx_config |= 0x80000;
+
+ // configure rx mode
+ _sc92031_set_rx_config(dev);
+
+ if (duplex_full) {
+ priv->rx_config |= RxFullDx;
+ priv->tx_config |= TxFullDx;
+ flow_ctrl_config = FlowCtrlFullDX | FlowCtrlEnb;
+ } else {
+ priv->rx_config &= ~RxFullDx;
+ priv->tx_config &= ~TxFullDx;
+ }
+
+ _sc92031_set_mar(dev);
+ _sc92031_set_rx_config(dev);
+ _sc92031_enable_tx_rx(dev);
+ iowrite32(flow_ctrl_config, port_base + FlowCtrlConfig);
+
+ netif_carrier_on(dev);
+
+ if (printk_ratelimit())
+ printk(KERN_INFO "%s: link up, %sMbps, %s-duplex\n",
+ dev->name,
+ speed_100 ? "100" : "10",
+ duplex_full ? "full" : "half");
+ return true;
+ } else {
+ _sc92031_mii_scan(port_base);
+
+ netif_carrier_off(dev);
+
+ _sc92031_disable_tx_rx(dev);
+
+ if (printk_ratelimit())
+ printk(KERN_INFO "%s: link down\n", dev->name);
+ return false;
+ }
+}
+
+static void _sc92031_phy_reset(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+ u32 phy_ctrl;
+
+ phy_ctrl = ioread32(port_base + PhyCtrl);
+ phy_ctrl &= ~(PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10);
+ phy_ctrl |= PhyCtrlAne | PhyCtrlReset;
+
+ switch (media) {
+ default:
+ case AUTOSELECT:
+ phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10;
+ break;
+ case M10_HALF:
+ phy_ctrl |= PhyCtrlSpd10;
+ break;
+ case M10_FULL:
+ phy_ctrl |= PhyCtrlDux | PhyCtrlSpd10;
+ break;
+ case M100_HALF:
+ phy_ctrl |= PhyCtrlSpd100;
+ break;
+ case M100_FULL:
+ phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100;
+ break;
+ }
+
+ iowrite32(phy_ctrl, port_base + PhyCtrl);
+ mdelay(10);
+
+ phy_ctrl &= ~PhyCtrlReset;
+ iowrite32(phy_ctrl, port_base + PhyCtrl);
+ mdelay(1);
+
+ _sc92031_mii_write(port_base, MII_JAB,
+ PHY_16_JAB_ENB | PHY_16_PORT_ENB);
+ _sc92031_mii_scan(port_base);
+
+ netif_carrier_off(dev);
+ netif_stop_queue(dev);
+}
+
+static void _sc92031_reset(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+
+ /* disable PM */
+ iowrite32(0, port_base + PMConfig);
+
+ /* soft reset the chip */
+ iowrite32(Cfg0_Reset, port_base + Config0);
+ mdelay(200);
+
+ iowrite32(0, port_base + Config0);
+ mdelay(10);
+
+ /* disable interrupts */
+ iowrite32(0, port_base + IntrMask);
+
+ /* clear multicast address */
+ iowrite32(0, port_base + MAR0);
+ iowrite32(0, port_base + MAR0 + 4);
+
+ /* init rx ring */
+ iowrite32(priv->rx_ring_dma_addr, port_base + RxbufAddr);
+ priv->rx_ring_tail = priv->rx_ring_dma_addr;
+
+ /* init tx ring */
+ _sc92031_tx_clear(dev);
+
+ /* clear old register values */
+ priv->intr_status = 0;
+ atomic_set(&priv->intr_mask, 0);
+ priv->rx_config = 0;
+ priv->tx_config = 0;
+ priv->mc_flags = 0;
+
+ /* configure rx buffer size */
+ /* NOTE: vendor driver had dead code here to enable early tx/rx */
+ iowrite32(Cfg1_Rcv64K, port_base + Config1);
+
+ _sc92031_phy_reset(dev);
+ _sc92031_check_media(dev);
+
+ /* calculate rx fifo overflow */
+ priv->rx_value = 0;
+
+ /* enable PM */
+ iowrite32(priv->pm_config, port_base + PMConfig);
+
+ /* clear intr register */
+ ioread32(port_base + IntrStatus);
+}
+
+static void _sc92031_tx_tasklet(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+
+ unsigned old_tx_tail;
+ unsigned entry;
+ u32 tx_status;
+
+ old_tx_tail = priv->tx_tail;
+ while (priv->tx_head - priv->tx_tail > 0) {
+ entry = priv->tx_tail % NUM_TX_DESC;
+ tx_status = ioread32(port_base + TxStatus0 + entry * 4);
+
+ if (!(tx_status & (TxStatOK | TxUnderrun | TxAborted)))
+ break;
+
+ priv->tx_tail++;
+
+ if (tx_status & TxStatOK) {
+ priv->stats.tx_bytes += tx_status & 0x1fff;
+ priv->stats.tx_packets++;
+ /* Note: TxCarrierLost is always asserted at 100mbps. */
+ priv->stats.collisions += (tx_status >> 22) & 0xf;
+ }
+
+ if (tx_status & (TxOutOfWindow | TxAborted)) {
+ priv->stats.tx_errors++;
+
+ if (tx_status & TxAborted)
+ priv->stats.tx_aborted_errors++;
+
+ if (tx_status & TxCarrierLost)
+ priv->stats.tx_carrier_errors++;
+
+ if (tx_status & TxOutOfWindow)
+ priv->stats.tx_window_errors++;
+ }
+
+ if (tx_status & TxUnderrun)
+ priv->stats.tx_fifo_errors++;
+ }
+
+ if (priv->tx_tail != old_tx_tail)
+ if (netif_queue_stopped(dev))
+ netif_wake_queue(dev);
+}
+
+static void _sc92031_rx_tasklet_error(u32 rx_status,
+ struct sc92031_priv *priv, unsigned rx_size)
+{
+ if(rx_size > (MAX_ETH_FRAME_SIZE + 4) || rx_size < 16) {
+ priv->stats.rx_errors++;
+ priv->stats.rx_length_errors++;
+ }
+
+ if (!(rx_status & RxStatesOK)) {
+ priv->stats.rx_errors++;
+
+ if (rx_status & (RxHugeFrame | RxSmallFrame))
+ priv->stats.rx_length_errors++;
+
+ if (rx_status & RxBadAlign)
+ priv->stats.rx_frame_errors++;
+
+ if (!(rx_status & RxCRCOK))
+ priv->stats.rx_crc_errors++;
+ } else
+ priv->rx_loss++;
+}
+
+static void _sc92031_rx_tasklet(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+
+ dma_addr_t rx_ring_head;
+ unsigned rx_len;
+ unsigned rx_ring_offset;
+ void *rx_ring = priv->rx_ring;
+
+ rx_ring_head = ioread32(port_base + RxBufWPtr);
+ rmb();
+
+ /* rx_ring_head is only 17 bits in the RxBufWPtr register.
+ * we need to change it to 32 bits physical address
+ */
+ rx_ring_head &= (dma_addr_t)(RX_BUF_LEN - 1);
+ rx_ring_head |= priv->rx_ring_dma_addr & ~(dma_addr_t)(RX_BUF_LEN - 1);
+ if (rx_ring_head < priv->rx_ring_dma_addr)
+ rx_ring_head += RX_BUF_LEN;
+
+ if (rx_ring_head >= priv->rx_ring_tail)
+ rx_len = rx_ring_head - priv->rx_ring_tail;
+ else
+ rx_len = RX_BUF_LEN - (priv->rx_ring_tail - rx_ring_head);
+
+ if (!rx_len)
+ return;
+
+ if (unlikely(rx_len > RX_BUF_LEN)) {
+ if (printk_ratelimit())
+ printk(KERN_ERR "%s: rx packets length > rx buffer\n",
+ dev->name);
+ return;
+ }
+
+ rx_ring_offset = (priv->rx_ring_tail - priv->rx_ring_dma_addr) % RX_BUF_LEN;
+
+ while (rx_len) {
+ u32 rx_status;
+ unsigned rx_size, rx_size_align, pkt_size;
+ struct sk_buff *skb;
+
+ rx_status = le32_to_cpup((__le32 *)(rx_ring + rx_ring_offset));
+ rmb();
+
+ rx_size = rx_status >> 20;
+ rx_size_align = (rx_size + 3) & ~3; // for 4 bytes aligned
+ pkt_size = rx_size - 4; // Omit the four octet CRC from the length.
+
+ rx_ring_offset = (rx_ring_offset + 4) % RX_BUF_LEN;
+
+ if (unlikely(rx_status == 0
+ || rx_size > (MAX_ETH_FRAME_SIZE + 4)
+ || rx_size < 16
+ || !(rx_status & RxStatesOK))) {
+ _sc92031_rx_tasklet_error(rx_status, priv, rx_size);
+ break;
+ }
+
+ if (unlikely(rx_size_align + 4 > rx_len)) {
+ if (printk_ratelimit())
+ printk(KERN_ERR "%s: rx_len is too small\n", dev->name);
+ break;
+ }
+
+ rx_len -= rx_size_align + 4;
+
+ skb = dev_alloc_skb(pkt_size + NET_IP_ALIGN);
+ if (unlikely(!skb)) {
+ if (printk_ratelimit())
+ printk(KERN_ERR "%s: Couldn't allocate a skb_buff for a packet of size %u\n",
+ dev->name, pkt_size);
+ goto next;
+ }
+
+ skb_reserve(skb, NET_IP_ALIGN);
+
+ if ((rx_ring_offset + pkt_size) > RX_BUF_LEN) {
+ memcpy(skb_put(skb, RX_BUF_LEN - rx_ring_offset),
+ rx_ring + rx_ring_offset, RX_BUF_LEN - rx_ring_offset);
+ memcpy(skb_put(skb, pkt_size - (RX_BUF_LEN - rx_ring_offset)),
+ rx_ring, pkt_size - (RX_BUF_LEN - rx_ring_offset));
+ } else {
+ memcpy(skb_put(skb, pkt_size), rx_ring + rx_ring_offset, pkt_size);
+ }
+
+ skb->dev = dev;
+ skb->protocol = eth_type_trans(skb, dev);
+ dev->last_rx = jiffies;
+ netif_rx(skb);
+
+ priv->stats.rx_bytes += pkt_size;
+ priv->stats.rx_packets++;
+
+ if (rx_status & Rx_Multicast)
+ priv->stats.multicast++;
+
+ next:
+ rx_ring_offset = (rx_ring_offset + rx_size_align) % RX_BUF_LEN;
+ }
+ mb();
+
+ priv->rx_ring_tail = rx_ring_head;
+ iowrite32(priv->rx_ring_tail, port_base + RxBufRPtr);
+}
+
+static void _sc92031_link_tasklet(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+
+ if (_sc92031_check_media(dev))
+ netif_wake_queue(dev);
+ else {
+ netif_stop_queue(dev);
+ priv->stats.tx_carrier_errors++;
+ }
+}
+
+static void sc92031_tasklet(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+ u32 intr_status, intr_mask;
+
+ intr_status = priv->intr_status;
+
+ spin_lock(&priv->lock);
+
+ if (unlikely(!netif_running(dev)))
+ goto out;
+
+ if (intr_status & TxOK)
+ _sc92031_tx_tasklet(dev);
+
+ if (intr_status & RxOK)
+ _sc92031_rx_tasklet(dev);
+
+ if (intr_status & RxOverflow)
+ priv->stats.rx_errors++;
+
+ if (intr_status & TimeOut) {
+ priv->stats.rx_errors++;
+ priv->stats.rx_length_errors++;
+ }
+
+ if (intr_status & (LinkFail | LinkOK))
+ _sc92031_link_tasklet(dev);
+
+out:
+ intr_mask = atomic_read(&priv->intr_mask);
+ rmb();
+
+ iowrite32(intr_mask, port_base + IntrMask);
+ mmiowb();
+
+ spin_unlock(&priv->lock);
+}
+
+static irqreturn_t sc92031_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+ u32 intr_status, intr_mask;
+
+ /* mask interrupts before clearing IntrStatus */
+ iowrite32(0, port_base + IntrMask);
+ _sc92031_dummy_read(port_base);
+
+ intr_status = ioread32(port_base + IntrStatus);
+ if (unlikely(intr_status == 0xffffffff))
+ return IRQ_NONE; // hardware has gone missing
+
+ intr_status &= IntrBits;
+ if (!intr_status)
+ goto out_none;
+
+ priv->intr_status = intr_status;
+ tasklet_schedule(&priv->tasklet);
+
+ return IRQ_HANDLED;
+
+out_none:
+ intr_mask = atomic_read(&priv->intr_mask);
+ rmb();
+
+ iowrite32(intr_mask, port_base + IntrMask);
+ mmiowb();
+
+ return IRQ_NONE;
+}
+
+static struct net_device_stats *sc92031_get_stats(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+
+ // FIXME I do not understand what is this trying to do.
+ if (netif_running(dev)) {
+ int temp;
+
+ spin_lock_bh(&priv->lock);
+
+ /* Update the error count. */
+ temp = (ioread32(port_base + RxStatus0) >> 16) & 0xffff;
+
+ if (temp == 0xffff) {
+ priv->rx_value += temp;
+ priv->stats.rx_fifo_errors = priv->rx_value;
+ } else {
+ priv->stats.rx_fifo_errors = temp + priv->rx_value;
+ }
+
+ spin_unlock_bh(&priv->lock);
+ }
+
+ return &priv->stats;
+}
+
+static int sc92031_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ int err = 0;
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+
+ unsigned len;
+ unsigned entry;
+ u32 tx_status;
+
+ if (unlikely(skb->len > TX_BUF_SIZE)) {
+ err = -EMSGSIZE;
+ priv->stats.tx_dropped++;
+ goto out;
+ }
+
+ spin_lock_bh(&priv->lock);
+
+ if (unlikely(!netif_carrier_ok(dev))) {
+ err = -ENOLINK;
+ priv->stats.tx_dropped++;
+ goto out_unlock;
+ }
+
+ BUG_ON(priv->tx_head - priv->tx_tail >= NUM_TX_DESC);
+
+ entry = priv->tx_head++ % NUM_TX_DESC;
+
+ skb_copy_and_csum_dev(skb, priv->tx_bufs + entry * TX_BUF_SIZE);
+
+ len = skb->len;
+ if (unlikely(len < ETH_ZLEN)) {
+ memset(priv->tx_bufs + entry * TX_BUF_SIZE + len,
+ 0, ETH_ZLEN - len);
+ len = ETH_ZLEN;
+ }
+
+ wmb();
+
+ if (len < 100)
+ tx_status = len;
+ else if (len < 300)
+ tx_status = 0x30000 | len;
+ else
+ tx_status = 0x50000 | len;
+
+ iowrite32(priv->tx_bufs_dma_addr + entry * TX_BUF_SIZE,
+ port_base + TxAddr0 + entry * 4);
+ iowrite32(tx_status, port_base + TxStatus0 + entry * 4);
+ mmiowb();
+
+ dev->trans_start = jiffies;
+
+ if (priv->tx_head - priv->tx_tail >= NUM_TX_DESC)
+ netif_stop_queue(dev);
+
+out_unlock:
+ spin_unlock_bh(&priv->lock);
+
+out:
+ dev_kfree_skb(skb);
+
+ return err;
+}
+
+static int sc92031_open(struct net_device *dev)
+{
+ int err;
+ struct sc92031_priv *priv = netdev_priv(dev);
+ struct pci_dev *pdev = priv->pdev;
+
+ priv->rx_ring = pci_alloc_consistent(pdev, RX_BUF_LEN,
+ &priv->rx_ring_dma_addr);
+ if (unlikely(!priv->rx_ring)) {
+ err = -ENOMEM;
+ goto out_alloc_rx_ring;
+ }
+
+ priv->tx_bufs = pci_alloc_consistent(pdev, TX_BUF_TOT_LEN,
+ &priv->tx_bufs_dma_addr);
+ if (unlikely(!priv->tx_bufs)) {
+ err = -ENOMEM;
+ goto out_alloc_tx_bufs;
+ }
+ priv->tx_head = priv->tx_tail = 0;
+
+ err = request_irq(pdev->irq, sc92031_interrupt,
+ SA_SHIRQ, dev->name, dev);
+ if (unlikely(err < 0))
+ goto out_request_irq;
+
+ priv->pm_config = 0;
+
+ /* Interrupts already disabled by sc92031_stop or sc92031_probe */
+ spin_lock(&priv->lock);
+
+ _sc92031_reset(dev);
+ mmiowb();
+
+ spin_unlock(&priv->lock);
+ sc92031_enable_interrupts(dev);
+
+ if (netif_carrier_ok(dev))
+ netif_start_queue(dev);
+ else
+ netif_tx_disable(dev);
+
+ return 0;
+
+out_request_irq:
+ pci_free_consistent(pdev, TX_BUF_TOT_LEN, priv->tx_bufs,
+ priv->tx_bufs_dma_addr);
+out_alloc_tx_bufs:
+ pci_free_consistent(pdev, RX_BUF_LEN, priv->rx_ring,
+ priv->rx_ring_dma_addr);
+out_alloc_rx_ring:
+ return err;
+}
+
+static int sc92031_stop(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ struct pci_dev *pdev = priv->pdev;
+
+ netif_tx_disable(dev);
+
+ /* Disable interrupts, stop Tx and Rx. */
+ sc92031_disable_interrupts(dev);
+
+ spin_lock(&priv->lock);
+
+ _sc92031_disable_tx_rx(dev);
+ _sc92031_tx_clear(dev);
+ mmiowb();
+
+ spin_unlock(&priv->lock);
+
+ free_irq(pdev->irq, dev);
+ pci_free_consistent(pdev, TX_BUF_TOT_LEN, priv->tx_bufs,
+ priv->tx_bufs_dma_addr);
+ pci_free_consistent(pdev, RX_BUF_LEN, priv->rx_ring,
+ priv->rx_ring_dma_addr);
+
+ return 0;
+}
+
+static void sc92031_set_multicast_list(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+
+ spin_lock_bh(&priv->lock);
+
+ _sc92031_set_mar(dev);
+ _sc92031_set_rx_config(dev);
+ mmiowb();
+
+ spin_unlock_bh(&priv->lock);
+}
+
+static void sc92031_tx_timeout(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+
+ /* Disable interrupts by clearing the interrupt mask.*/
+ sc92031_disable_interrupts(dev);
+
+ spin_lock(&priv->lock);
+
+ priv->tx_timeouts++;
+
+ _sc92031_reset(dev);
+ mmiowb();
+
+ spin_unlock(&priv->lock);
+
+ /* enable interrupts */
+ sc92031_enable_interrupts(dev);
+
+ if (netif_carrier_ok(dev))
+ netif_wake_queue(dev);
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void sc92031_poll_controller(struct net_device *dev)
+{
+ disable_irq(dev->irq);
+ if (sc92031_interrupt(dev->irq, dev) != IRQ_NONE)
+ sc92031_tasklet((unsigned long)dev);
+ enable_irq(dev->irq);
+}
+#endif
+
+static int sc92031_ethtool_get_settings(struct net_device *dev,
+ struct ethtool_cmd *cmd)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+ u8 phy_address;
+ u32 phy_ctrl;
+ u16 output_status;
+
+ spin_lock_bh(&priv->lock);
+
+ phy_address = ioread32(port_base + Miicmd1) >> 27;
+ phy_ctrl = ioread32(port_base + PhyCtrl);
+
+ output_status = _sc92031_mii_read(port_base, MII_OutputStatus);
+ _sc92031_mii_scan(port_base);
+ mmiowb();
+
+ spin_unlock_bh(&priv->lock);
+
+ cmd->supported = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full
+ | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full
+ | SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII;
+
+ cmd->advertising = ADVERTISED_TP | ADVERTISED_MII;
+
+ if ((phy_ctrl & (PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10))
+ == (PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10))
+ cmd->advertising |= ADVERTISED_Autoneg;
+
+ if ((phy_ctrl & PhyCtrlSpd10) == PhyCtrlSpd10)
+ cmd->advertising |= ADVERTISED_10baseT_Half;
+
+ if ((phy_ctrl & (PhyCtrlSpd10 | PhyCtrlDux))
+ == (PhyCtrlSpd10 | PhyCtrlDux))
+ cmd->advertising |= ADVERTISED_10baseT_Full;
+
+ if ((phy_ctrl & PhyCtrlSpd100) == PhyCtrlSpd100)
+ cmd->advertising |= ADVERTISED_100baseT_Half;
+
+ if ((phy_ctrl & (PhyCtrlSpd100 | PhyCtrlDux))
+ == (PhyCtrlSpd100 | PhyCtrlDux))
+ cmd->advertising |= ADVERTISED_100baseT_Full;
+
+ if (phy_ctrl & PhyCtrlAne)
+ cmd->advertising |= ADVERTISED_Autoneg;
+
+ cmd->speed = (output_status & 0x2) ? SPEED_100 : SPEED_10;
+ cmd->duplex = (output_status & 0x4) ? DUPLEX_FULL : DUPLEX_HALF;
+ cmd->port = PORT_MII;
+ cmd->phy_address = phy_address;
+ cmd->transceiver = XCVR_INTERNAL;
+ cmd->autoneg = (phy_ctrl & PhyCtrlAne) ? AUTONEG_ENABLE : AUTONEG_DISABLE;
+
+ return 0;
+}
+
+static int sc92031_ethtool_set_settings(struct net_device *dev,
+ struct ethtool_cmd *cmd)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+ u32 phy_ctrl;
+ u32 old_phy_ctrl;
+
+ if (!(cmd->speed == SPEED_10 || cmd->speed == SPEED_100))
+ return -EINVAL;
+ if (!(cmd->duplex == DUPLEX_HALF || cmd->duplex == DUPLEX_FULL))
+ return -EINVAL;
+ if (!(cmd->port == PORT_MII))
+ return -EINVAL;
+ if (!(cmd->phy_address == 0x1f))
+ return -EINVAL;
+ if (!(cmd->transceiver == XCVR_INTERNAL))
+ return -EINVAL;
+ if (!(cmd->autoneg == AUTONEG_DISABLE || cmd->autoneg == AUTONEG_ENABLE))
+ return -EINVAL;
+
+ if (cmd->autoneg == AUTONEG_ENABLE) {
+ if (!(cmd->advertising & (ADVERTISED_Autoneg
+ | ADVERTISED_100baseT_Full
+ | ADVERTISED_100baseT_Half
+ | ADVERTISED_10baseT_Full
+ | ADVERTISED_10baseT_Half)))
+ return -EINVAL;
+
+ phy_ctrl = PhyCtrlAne;
+
+ // FIXME: I'm not sure what the original code was trying to do
+ if (cmd->advertising & ADVERTISED_Autoneg)
+ phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10;
+ if (cmd->advertising & ADVERTISED_100baseT_Full)
+ phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100;
+ if (cmd->advertising & ADVERTISED_100baseT_Half)
+ phy_ctrl |= PhyCtrlSpd100;
+ if (cmd->advertising & ADVERTISED_10baseT_Full)
+ phy_ctrl |= PhyCtrlSpd10 | PhyCtrlDux;
+ if (cmd->advertising & ADVERTISED_10baseT_Half)
+ phy_ctrl |= PhyCtrlSpd10;
+ } else {
+ // FIXME: Whole branch guessed
+ phy_ctrl = 0;
+
+ if (cmd->speed == SPEED_10)
+ phy_ctrl |= PhyCtrlSpd10;
+ else /* cmd->speed == SPEED_100 */
+ phy_ctrl |= PhyCtrlSpd100;
+
+ if (cmd->duplex == DUPLEX_FULL)
+ phy_ctrl |= PhyCtrlDux;
+ }
+
+ spin_lock_bh(&priv->lock);
+
+ old_phy_ctrl = ioread32(port_base + PhyCtrl);
+ phy_ctrl |= old_phy_ctrl & ~(PhyCtrlAne | PhyCtrlDux
+ | PhyCtrlSpd100 | PhyCtrlSpd10);
+ if (phy_ctrl != old_phy_ctrl)
+ iowrite32(phy_ctrl, port_base + PhyCtrl);
+
+ spin_unlock_bh(&priv->lock);
+
+ return 0;
+}
+
+static void sc92031_ethtool_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *drvinfo)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ struct pci_dev *pdev = priv->pdev;
+
+ strcpy(drvinfo->driver, SC92031_NAME);
+ strcpy(drvinfo->version, SC92031_VERSION);
+ strcpy(drvinfo->bus_info, pci_name(pdev));
+}
+
+static void sc92031_ethtool_get_wol(struct net_device *dev,
+ struct ethtool_wolinfo *wolinfo)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+ u32 pm_config;
+
+ spin_lock_bh(&priv->lock);
+ pm_config = ioread32(port_base + PMConfig);
+ spin_unlock_bh(&priv->lock);
+
+ // FIXME: Guessed
+ wolinfo->supported = WAKE_PHY | WAKE_MAGIC
+ | WAKE_UCAST | WAKE_MCAST | WAKE_BCAST;
+ wolinfo->wolopts = 0;
+
+ if (pm_config & PM_LinkUp)
+ wolinfo->wolopts |= WAKE_PHY;
+
+ if (pm_config & PM_Magic)
+ wolinfo->wolopts |= WAKE_MAGIC;
+
+ if (pm_config & PM_WakeUp)
+ // FIXME: Guessed
+ wolinfo->wolopts |= WAKE_UCAST | WAKE_MCAST | WAKE_BCAST;
+}
+
+static int sc92031_ethtool_set_wol(struct net_device *dev,
+ struct ethtool_wolinfo *wolinfo)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+ u32 pm_config;
+
+ spin_lock_bh(&priv->lock);
+
+ pm_config = ioread32(port_base + PMConfig)
+ & ~(PM_LinkUp | PM_Magic | PM_WakeUp);
+
+ if (wolinfo->wolopts & WAKE_PHY)
+ pm_config |= PM_LinkUp;
+
+ if (wolinfo->wolopts & WAKE_MAGIC)
+ pm_config |= PM_Magic;
+
+ // FIXME: Guessed
+ if (wolinfo->wolopts & (WAKE_UCAST | WAKE_MCAST | WAKE_BCAST))
+ pm_config |= PM_WakeUp;
+
+ priv->pm_config = pm_config;
+ iowrite32(pm_config, port_base + PMConfig);
+ mmiowb();
+
+ spin_unlock_bh(&priv->lock);
+
+ return 0;
+}
+
+static int sc92031_ethtool_nway_reset(struct net_device *dev)
+{
+ int err = 0;
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+ u16 bmcr;
+
+ spin_lock_bh(&priv->lock);
+
+ bmcr = _sc92031_mii_read(port_base, MII_BMCR);
+ if (!(bmcr & BMCR_ANENABLE)) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ _sc92031_mii_write(port_base, MII_BMCR, bmcr | BMCR_ANRESTART);
+
+out:
+ _sc92031_mii_scan(port_base);
+ mmiowb();
+
+ spin_unlock_bh(&priv->lock);
+
+ return err;
+}
+
+static const char sc92031_ethtool_stats_strings[SILAN_STATS_NUM][ETH_GSTRING_LEN] = {
+ "tx_timeout",
+ "rx_loss",
+};
+
+static void sc92031_ethtool_get_strings(struct net_device *dev,
+ u32 stringset, u8 *data)
+{
+ if (stringset == ETH_SS_STATS)
+ memcpy(data, sc92031_ethtool_stats_strings,
+ SILAN_STATS_NUM * ETH_GSTRING_LEN);
+}
+
+static int sc92031_ethtool_get_stats_count(struct net_device *dev)
+{
+ return SILAN_STATS_NUM;
+}
+
+static void sc92031_ethtool_get_ethtool_stats(struct net_device *dev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+
+ spin_lock_bh(&priv->lock);
+ data[0] = priv->tx_timeouts;
+ data[1] = priv->rx_loss;
+ spin_unlock_bh(&priv->lock);
+}
+
+static struct ethtool_ops sc92031_ethtool_ops = {
+ .get_settings = sc92031_ethtool_get_settings,
+ .set_settings = sc92031_ethtool_set_settings,
+ .get_drvinfo = sc92031_ethtool_get_drvinfo,
+ .get_wol = sc92031_ethtool_get_wol,
+ .set_wol = sc92031_ethtool_set_wol,
+ .nway_reset = sc92031_ethtool_nway_reset,
+ .get_link = ethtool_op_get_link,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .get_sg = ethtool_op_get_sg,
+ .get_tso = ethtool_op_get_tso,
+ .get_strings = sc92031_ethtool_get_strings,
+ .get_stats_count = sc92031_ethtool_get_stats_count,
+ .get_ethtool_stats = sc92031_ethtool_get_ethtool_stats,
+ .get_perm_addr = ethtool_op_get_perm_addr,
+ .get_ufo = ethtool_op_get_ufo,
+};
+
+static int __devinit sc92031_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ int err;
+ void __iomem* port_base;
+ struct net_device *dev;
+ struct sc92031_priv *priv;
+ u32 mac0, mac1;
+
+ err = pci_enable_device(pdev);
+ if (unlikely(err < 0))
+ goto out_enable_device;
+
+ pci_set_master(pdev);
+
+ err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (unlikely(err < 0))
+ goto out_set_dma_mask;
+
+ err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ if (unlikely(err < 0))
+ goto out_set_dma_mask;
+
+ err = pci_request_regions(pdev, SC92031_NAME);
+ if (unlikely(err < 0))
+ goto out_request_regions;
+
+ port_base = pci_iomap(pdev, SC92031_USE_BAR, 0);
+ if (unlikely(!port_base)) {
+ err = -EIO;
+ goto out_iomap;
+ }
+
+ dev = alloc_etherdev(sizeof(struct sc92031_priv));
+ if (unlikely(!dev)) {
+ err = -ENOMEM;
+ goto out_alloc_etherdev;
+ }
+
+ pci_set_drvdata(pdev, dev);
+
+#if SC92031_USE_BAR == 0
+ dev->mem_start = pci_resource_start(pdev, SC92031_USE_BAR);
+ dev->mem_end = pci_resource_end(pdev, SC92031_USE_BAR);
+#elif SC92031_USE_BAR == 1
+ dev->base_addr = pci_resource_start(pdev, SC92031_USE_BAR);
+#endif
+ dev->irq = pdev->irq;
+
+ /* faked with skb_copy_and_csum_dev */
+ dev->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HIGHDMA;
+
+ dev->get_stats = sc92031_get_stats;
+ dev->ethtool_ops = &sc92031_ethtool_ops;
+ dev->hard_start_xmit = sc92031_start_xmit;
+ dev->watchdog_timeo = TX_TIMEOUT;
+ dev->open = sc92031_open;
+ dev->stop = sc92031_stop;
+ dev->set_multicast_list = sc92031_set_multicast_list;
+ dev->tx_timeout = sc92031_tx_timeout;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ dev->poll_controller = sc92031_poll_controller;
+#endif
+
+ priv = netdev_priv(dev);
+ spin_lock_init(&priv->lock);
+ priv->port_base = port_base;
+ priv->pdev = pdev;
+ tasklet_init(&priv->tasklet, sc92031_tasklet, (unsigned long)dev);
+ /* Fudge tasklet count so the call to sc92031_enable_interrupts at
+ * sc92031_open will work correctly */
+ tasklet_disable_nosync(&priv->tasklet);
+
+ /* PCI PM Wakeup */
+ iowrite32((~PM_LongWF & ~PM_LWPTN) | PM_Enable, port_base + PMConfig);
+
+ mac0 = ioread32(port_base + MAC0);
+ mac1 = ioread32(port_base + MAC0 + 4);
+ dev->dev_addr[0] = dev->perm_addr[0] = mac0 >> 24;
+ dev->dev_addr[1] = dev->perm_addr[1] = mac0 >> 16;
+ dev->dev_addr[2] = dev->perm_addr[2] = mac0 >> 8;
+ dev->dev_addr[3] = dev->perm_addr[3] = mac0;
+ dev->dev_addr[4] = dev->perm_addr[4] = mac1 >> 8;
+ dev->dev_addr[5] = dev->perm_addr[5] = mac1;
+
+ err = register_netdev(dev);
+ if (err < 0)
+ goto out_register_netdev;
+
+ return 0;
+
+out_register_netdev:
+ free_netdev(dev);
+out_alloc_etherdev:
+ pci_iounmap(pdev, port_base);
+out_iomap:
+ pci_release_regions(pdev);
+out_request_regions:
+out_set_dma_mask:
+ pci_disable_device(pdev);
+out_enable_device:
+ return err;
+}
+
+static void __devexit sc92031_remove(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem* port_base = priv->port_base;
+
+ unregister_netdev(dev);
+ free_netdev(dev);
+ pci_iounmap(pdev, port_base);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+}
+
+static int sc92031_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct sc92031_priv *priv = netdev_priv(dev);
+
+ pci_save_state(pdev);
+
+ if (!netif_running(dev))
+ goto out;
+
+ netif_device_detach(dev);
+
+ /* Disable interrupts, stop Tx and Rx. */
+ sc92031_disable_interrupts(dev);
+
+ spin_lock(&priv->lock);
+
+ _sc92031_disable_tx_rx(dev);
+ _sc92031_tx_clear(dev);
+ mmiowb();
+
+ spin_unlock(&priv->lock);
+
+out:
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+ return 0;
+}
+
+static int sc92031_resume(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct sc92031_priv *priv = netdev_priv(dev);
+
+ pci_restore_state(pdev);
+ pci_set_power_state(pdev, PCI_D0);
+
+ if (!netif_running(dev))
+ goto out;
+
+ /* Interrupts already disabled by sc92031_suspend */
+ spin_lock(&priv->lock);
+
+ _sc92031_reset(dev);
+ mmiowb();
+
+ spin_unlock(&priv->lock);
+ sc92031_enable_interrupts(dev);
+
+ netif_device_attach(dev);
+
+ if (netif_carrier_ok(dev))
+ netif_wake_queue(dev);
+ else
+ netif_tx_disable(dev);
+
+out:
+ return 0;
+}
+
+static struct pci_device_id sc92031_pci_device_id_table[] __devinitdata = {
+ { PCI_DEVICE(PCI_VENDOR_ID_SILAN, PCI_DEVICE_ID_SILAN_SC92031) },
+ { PCI_DEVICE(PCI_VENDOR_ID_SILAN, PCI_DEVICE_ID_SILAN_8139D) },
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, sc92031_pci_device_id_table);
+
+static struct pci_driver sc92031_pci_driver = {
+ .name = SC92031_NAME,
+ .id_table = sc92031_pci_device_id_table,
+ .probe = sc92031_probe,
+ .remove = __devexit_p(sc92031_remove),
+ .suspend = sc92031_suspend,
+ .resume = sc92031_resume,
+};
+
+static int __init sc92031_init(void)
+{
+ printk(KERN_INFO SC92031_DESCRIPTION " " SC92031_VERSION "\n");
+ return pci_register_driver(&sc92031_pci_driver);
+}
+
+static void __exit sc92031_exit(void)
+{
+ pci_unregister_driver(&sc92031_pci_driver);
+}
+
+module_init(sc92031_init);
+module_exit(sc92031_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Cesar Eduardo Barros <cesarb@cesarb.net>");
+MODULE_DESCRIPTION(SC92031_DESCRIPTION);
+MODULE_VERSION(SC92031_VERSION);
diff --git a/drivers/net/sk_mca.c b/drivers/net/sk_mca.c
deleted file mode 100644
index 96e06c51b75..00000000000
--- a/drivers/net/sk_mca.c
+++ /dev/null
@@ -1,1216 +0,0 @@
-/*
-net-3-driver for the SKNET MCA-based cards
-
-This is an extension to the Linux operating system, and is covered by the
-same GNU General Public License that covers that work.
-
-Copyright 1999 by Alfred Arnold (alfred@ccac.rwth-aachen.de,
- alfred.arnold@lancom.de)
-
-This driver is based both on the 3C523 driver and the SK_G16 driver.
-
-paper sources:
- 'PC Hardware: Aufbau, Funktionsweise, Programmierung' by
- Hans-Peter Messmer for the basic Microchannel stuff
-
- 'Linux Geraetetreiber' by Allesandro Rubini, Kalle Dalheimer
- for help on Ethernet driver programming
-
- 'Ethernet/IEEE 802.3 Family 1992 World Network Data Book/Handbook' by AMD
- for documentation on the AM7990 LANCE
-
- 'SKNET Personal Technisches Manual', Version 1.2 by Schneider&Koch
- for documentation on the Junior board
-
- 'SK-NET MC2+ Technical Manual", Version 1.1 by Schneider&Koch for
- documentation on the MC2 bord
-
- A big thank you to the S&K support for providing me so quickly with
- documentation!
-
- Also see http://www.syskonnect.com/
-
- Missing things:
-
- -> set debug level via ioctl instead of compile-time switches
- -> I didn't follow the development of the 2.1.x kernels, so my
- assumptions about which things changed with which kernel version
- are probably nonsense
-
-History:
- May 16th, 1999
- startup
- May 22st, 1999
- added private structure, methods
- begun building data structures in RAM
- May 23nd, 1999
- can receive frames, send frames
- May 24th, 1999
- modularized initialization of LANCE
- loadable as module
- still Tx problem :-(
- May 26th, 1999
- MC2 works
- support for multiple devices
- display media type for MC2+
- May 28th, 1999
- fixed problem in GetLANCE leaving interrupts turned off
- increase TX queue to 4 packets to improve send performance
- May 29th, 1999
- a few corrections in statistics, caught rcvr overruns
- reinitialization of LANCE/board in critical situations
- MCA info implemented
- implemented LANCE multicast filter
- Jun 6th, 1999
- additions for Linux 2.2
- Dec 25th, 1999
- unfortunately there seem to be newer MC2+ boards that react
- on IRQ 3/5/9/10 instead of 3/5/10/11, so we have to autoprobe
- in questionable cases...
- Dec 28th, 1999
- integrated patches from David Weinehall & Bill Wendling for 2.3
- kernels (isa_...functions). Things are defined in a way that
- it still works with 2.0.x 8-)
- Dec 30th, 1999
- added handling of the remaining interrupt conditions. That
- should cure the spurious hangs.
- Jan 30th, 2000
- newer kernels automatically probe more than one board, so the
- 'startslot' as a variable is also needed here
- June 1st, 2000
- added changes for recent 2.3 kernels
-
- *************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/time.h>
-#include <linux/mca-legacy.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/bitops.h>
-
-#include <asm/processor.h>
-#include <asm/io.h>
-
-#define _SK_MCA_DRIVER_
-#include "sk_mca.h"
-
-/* ------------------------------------------------------------------------
- * global static data - not more since we can handle multiple boards and
- * have to pack all state info into the device struct!
- * ------------------------------------------------------------------------ */
-
-static char *MediaNames[Media_Count] =
- { "10Base2", "10BaseT", "10Base5", "Unknown" };
-
-static unsigned char poly[] =
- { 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0,
- 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0
-};
-
-/* ------------------------------------------------------------------------
- * private subfunctions
- * ------------------------------------------------------------------------ */
-
-/* dump parts of shared memory - only needed during debugging */
-
-#ifdef DEBUG
-static void dumpmem(struct net_device *dev, u32 start, u32 len)
-{
- skmca_priv *priv = netdev_priv(dev);
- int z;
-
- for (z = 0; z < len; z++) {
- if ((z & 15) == 0)
- printk("%04x:", z);
- printk(" %02x", readb(priv->base + start + z));
- if ((z & 15) == 15)
- printk("\n");
- }
-}
-
-/* print exact time - ditto */
-
-static void PrTime(void)
-{
- struct timeval tv;
-
- do_gettimeofday(&tv);
- printk("%9d:%06d: ", tv.tv_sec, tv.tv_usec);
-}
-#endif
-
-/* deduce resources out of POS registers */
-
-static void __init getaddrs(int slot, int junior, int *base, int *irq,
- skmca_medium * medium)
-{
- u_char pos0, pos1, pos2;
-
- if (junior) {
- pos0 = mca_read_stored_pos(slot, 2);
- *base = ((pos0 & 0x0e) << 13) + 0xc0000;
- *irq = ((pos0 & 0x10) >> 4) + 10;
- *medium = Media_Unknown;
- } else {
- /* reset POS 104 Bits 0+1 so the shared memory region goes to the
- configured area between 640K and 1M. Afterwards, enable the MC2.
- I really don't know what rode SK to do this... */
-
- mca_write_pos(slot, 4,
- mca_read_stored_pos(slot, 4) & 0xfc);
- mca_write_pos(slot, 2,
- mca_read_stored_pos(slot, 2) | 0x01);
-
- pos1 = mca_read_stored_pos(slot, 3);
- pos2 = mca_read_stored_pos(slot, 4);
- *base = ((pos1 & 0x07) << 14) + 0xc0000;
- switch (pos2 & 0x0c) {
- case 0:
- *irq = 3;
- break;
- case 4:
- *irq = 5;
- break;
- case 8:
- *irq = -10;
- break;
- case 12:
- *irq = -11;
- break;
- }
- *medium = (pos2 >> 6) & 3;
- }
-}
-
-/* check for both cards:
- When the MC2 is turned off, it was configured for more than 15MB RAM,
- is disabled and won't get detected using the standard probe. We
- therefore have to scan the slots manually :-( */
-
-static int __init dofind(int *junior, int firstslot)
-{
- int slot;
- unsigned int id;
-
- for (slot = firstslot; slot < MCA_MAX_SLOT_NR; slot++) {
- id = mca_read_stored_pos(slot, 0)
- + (((unsigned int) mca_read_stored_pos(slot, 1)) << 8);
-
- *junior = 0;
- if (id == SKNET_MCA_ID)
- return slot;
- *junior = 1;
- if (id == SKNET_JUNIOR_MCA_ID)
- return slot;
- }
- return MCA_NOTFOUND;
-}
-
-/* reset the whole board */
-
-static void ResetBoard(struct net_device *dev)
-{
- skmca_priv *priv = netdev_priv(dev);
-
- writeb(CTRL_RESET_ON, priv->ctrladdr);
- udelay(10);
- writeb(CTRL_RESET_OFF, priv->ctrladdr);
-}
-
-/* wait for LANCE interface to become not busy */
-
-static int WaitLANCE(struct net_device *dev)
-{
- skmca_priv *priv = netdev_priv(dev);
- int t = 0;
-
- while ((readb(priv->ctrladdr) & STAT_IO_BUSY) ==
- STAT_IO_BUSY) {
- udelay(1);
- if (++t > 1000) {
- printk("%s: LANCE access timeout", dev->name);
- return 0;
- }
- }
-
- return 1;
-}
-
-/* set LANCE register - must be atomic */
-
-static void SetLANCE(struct net_device *dev, u16 addr, u16 value)
-{
- skmca_priv *priv = netdev_priv(dev);
- unsigned long flags;
-
- /* disable interrupts */
-
- spin_lock_irqsave(&priv->lock, flags);
-
- /* wait until no transfer is pending */
-
- WaitLANCE(dev);
-
- /* transfer register address to RAP */
-
- writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_RAP, priv->ctrladdr);
- writew(addr, priv->ioregaddr);
- writeb(IOCMD_GO, priv->cmdaddr);
- udelay(1);
- WaitLANCE(dev);
-
- /* transfer data to register */
-
- writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_DATA, priv->ctrladdr);
- writew(value, priv->ioregaddr);
- writeb(IOCMD_GO, priv->cmdaddr);
- udelay(1);
- WaitLANCE(dev);
-
- /* reenable interrupts */
-
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-/* get LANCE register */
-
-static u16 GetLANCE(struct net_device *dev, u16 addr)
-{
- skmca_priv *priv = netdev_priv(dev);
- unsigned long flags;
- unsigned int res;
-
- /* disable interrupts */
-
- spin_lock_irqsave(&priv->lock, flags);
-
- /* wait until no transfer is pending */
-
- WaitLANCE(dev);
-
- /* transfer register address to RAP */
-
- writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_RAP, priv->ctrladdr);
- writew(addr, priv->ioregaddr);
- writeb(IOCMD_GO, priv->cmdaddr);
- udelay(1);
- WaitLANCE(dev);
-
- /* transfer data from register */
-
- writeb(CTRL_RESET_OFF | CTRL_RW_READ | CTRL_ADR_DATA, priv->ctrladdr);
- writeb(IOCMD_GO, priv->cmdaddr);
- udelay(1);
- WaitLANCE(dev);
- res = readw(priv->ioregaddr);
-
- /* reenable interrupts */
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
- return res;
-}
-
-/* build up descriptors in shared RAM */
-
-static void InitDscrs(struct net_device *dev)
-{
- skmca_priv *priv = netdev_priv(dev);
- u32 bufaddr;
-
- /* Set up Tx descriptors. The board has only 16K RAM so bits 16..23
- are always 0. */
-
- bufaddr = RAM_DATABASE;
- {
- LANCE_TxDescr descr;
- int z;
-
- for (z = 0; z < TXCOUNT; z++) {
- descr.LowAddr = bufaddr;
- descr.Flags = 0;
- descr.Len = 0xf000;
- descr.Status = 0;
- memcpy_toio(priv->base + RAM_TXBASE +
- (z * sizeof(LANCE_TxDescr)), &descr,
- sizeof(LANCE_TxDescr));
- memset_io(priv->base + bufaddr, 0, RAM_BUFSIZE);
- bufaddr += RAM_BUFSIZE;
- }
- }
-
- /* do the same for the Rx descriptors */
-
- {
- LANCE_RxDescr descr;
- int z;
-
- for (z = 0; z < RXCOUNT; z++) {
- descr.LowAddr = bufaddr;
- descr.Flags = RXDSCR_FLAGS_OWN;
- descr.MaxLen = -RAM_BUFSIZE;
- descr.Len = 0;
- memcpy_toio(priv->base + RAM_RXBASE +
- (z * sizeof(LANCE_RxDescr)), &descr,
- sizeof(LANCE_RxDescr));
- memset_io(priv->base + bufaddr, 0, RAM_BUFSIZE);
- bufaddr += RAM_BUFSIZE;
- }
- }
-}
-
-/* calculate the hash bit position for a given multicast address
- taken more or less directly from the AMD datasheet... */
-
-static void UpdateCRC(unsigned char *CRC, int bit)
-{
- int j;
-
- /* shift CRC one bit */
-
- memmove(CRC + 1, CRC, 32 * sizeof(unsigned char));
- CRC[0] = 0;
-
- /* if bit XOR controlbit = 1, set CRC = CRC XOR polynomial */
-
- if (bit ^ CRC[32])
- for (j = 0; j < 32; j++)
- CRC[j] ^= poly[j];
-}
-
-static unsigned int GetHash(char *address)
-{
- unsigned char CRC[33];
- int i, byte, hashcode;
-
- /* a multicast address has bit 0 in the first byte set */
-
- if ((address[0] & 1) == 0)
- return -1;
-
- /* initialize CRC */
-
- memset(CRC, 1, sizeof(CRC));
-
- /* loop through address bits */
-
- for (byte = 0; byte < 6; byte++)
- for (i = 0; i < 8; i++)
- UpdateCRC(CRC, (address[byte] >> i) & 1);
-
- /* hashcode is the 6 least significant bits of the CRC */
-
- hashcode = 0;
- for (i = 0; i < 6; i++)
- hashcode = (hashcode << 1) + CRC[i];
- return hashcode;
-}
-
-/* feed ready-built initialization block into LANCE */
-
-static void InitLANCE(struct net_device *dev)
-{
- skmca_priv *priv = netdev_priv(dev);
-
- /* build up descriptors. */
-
- InitDscrs(dev);
-
- /* next RX descriptor to be read is the first one. Since the LANCE
- will start from the beginning after initialization, we have to
- reset out pointers too. */
-
- priv->nextrx = 0;
-
- /* no TX descriptors active */
-
- priv->nexttxput = priv->nexttxdone = priv->txbusy = 0;
-
- /* set up the LANCE bus control register - constant for SKnet boards */
-
- SetLANCE(dev, LANCE_CSR3,
- CSR3_BSWAP_OFF | CSR3_ALE_LOW | CSR3_BCON_HOLD);
-
- /* write address of initialization block into LANCE */
-
- SetLANCE(dev, LANCE_CSR1, RAM_INITBASE & 0xffff);
- SetLANCE(dev, LANCE_CSR2, (RAM_INITBASE >> 16) & 0xff);
-
- /* we don't get ready until the LANCE has read the init block */
-
- netif_stop_queue(dev);
-
- /* let LANCE read the initialization block. LANCE is ready
- when we receive the corresponding interrupt. */
-
- SetLANCE(dev, LANCE_CSR0, CSR0_INEA | CSR0_INIT);
-}
-
-/* stop the LANCE so we can reinitialize it */
-
-static void StopLANCE(struct net_device *dev)
-{
- /* can't take frames any more */
-
- netif_stop_queue(dev);
-
- /* disable interrupts, stop it */
-
- SetLANCE(dev, LANCE_CSR0, CSR0_STOP);
-}
-
-/* initialize card and LANCE for proper operation */
-
-static void InitBoard(struct net_device *dev)
-{
- skmca_priv *priv = netdev_priv(dev);
- LANCE_InitBlock block;
-
- /* Lay out the shared RAM - first we create the init block for the LANCE.
- We do not overwrite it later because we need it again when we switch
- promiscous mode on/off. */
-
- block.Mode = 0;
- if (dev->flags & IFF_PROMISC)
- block.Mode |= LANCE_INIT_PROM;
- memcpy(block.PAdr, dev->dev_addr, 6);
- memset(block.LAdrF, 0, sizeof(block.LAdrF));
- block.RdrP = (RAM_RXBASE & 0xffffff) | (LRXCOUNT << 29);
- block.TdrP = (RAM_TXBASE & 0xffffff) | (LTXCOUNT << 29);
-
- memcpy_toio(priv->base + RAM_INITBASE, &block, sizeof(block));
-
- /* initialize LANCE. Implicitly sets up other structures in RAM. */
-
- InitLANCE(dev);
-}
-
-/* deinitialize card and LANCE */
-
-static void DeinitBoard(struct net_device *dev)
-{
- /* stop LANCE */
-
- StopLANCE(dev);
-
- /* reset board */
-
- ResetBoard(dev);
-}
-
-/* probe for device's irq */
-
-static int __init ProbeIRQ(struct net_device *dev)
-{
- unsigned long imaskval, njiffies, irq;
- u16 csr0val;
-
- /* enable all interrupts */
-
- imaskval = probe_irq_on();
-
- /* initialize the board. Wait for interrupt 'Initialization done'. */
-
- ResetBoard(dev);
- InitBoard(dev);
-
- njiffies = jiffies + HZ;
- do {
- csr0val = GetLANCE(dev, LANCE_CSR0);
- }
- while (((csr0val & CSR0_IDON) == 0) && (jiffies != njiffies));
-
- /* turn of interrupts again */
-
- irq = probe_irq_off(imaskval);
-
- /* if we found something, ack the interrupt */
-
- if (irq)
- SetLANCE(dev, LANCE_CSR0, csr0val | CSR0_IDON);
-
- /* back to idle state */
-
- DeinitBoard(dev);
-
- return irq;
-}
-
-/* ------------------------------------------------------------------------
- * interrupt handler(s)
- * ------------------------------------------------------------------------ */
-
-/* LANCE has read initialization block -> start it */
-
-static u16 irqstart_handler(struct net_device *dev, u16 oldcsr0)
-{
- /* now we're ready to transmit */
-
- netif_wake_queue(dev);
-
- /* reset IDON bit, start LANCE */
-
- SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_IDON | CSR0_STRT);
- return GetLANCE(dev, LANCE_CSR0);
-}
-
-/* did we lose blocks due to a FIFO overrun ? */
-
-static u16 irqmiss_handler(struct net_device *dev, u16 oldcsr0)
-{
- skmca_priv *priv = netdev_priv(dev);
-
- /* update statistics */
-
- priv->stat.rx_fifo_errors++;
-
- /* reset MISS bit */
-
- SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_MISS);
- return GetLANCE(dev, LANCE_CSR0);
-}
-
-/* receive interrupt */
-
-static u16 irqrx_handler(struct net_device *dev, u16 oldcsr0)
-{
- skmca_priv *priv = netdev_priv(dev);
- LANCE_RxDescr descr;
- unsigned int descraddr;
-
- /* run through queue until we reach a descriptor we do not own */
-
- descraddr = RAM_RXBASE + (priv->nextrx * sizeof(LANCE_RxDescr));
- while (1) {
- /* read descriptor */
- memcpy_fromio(&descr, priv->base + descraddr,
- sizeof(LANCE_RxDescr));
-
- /* if we reach a descriptor we do not own, we're done */
- if ((descr.Flags & RXDSCR_FLAGS_OWN) != 0)
- break;
-
-#ifdef DEBUG
- PrTime();
- printk("Receive packet on descr %d len %d\n", priv->nextrx,
- descr.Len);
-#endif
-
- /* erroneous packet ? */
- if ((descr.Flags & RXDSCR_FLAGS_ERR) != 0) {
- priv->stat.rx_errors++;
- if ((descr.Flags & RXDSCR_FLAGS_CRC) != 0)
- priv->stat.rx_crc_errors++;
- else if ((descr.Flags & RXDSCR_FLAGS_CRC) != 0)
- priv->stat.rx_frame_errors++;
- else if ((descr.Flags & RXDSCR_FLAGS_OFLO) != 0)
- priv->stat.rx_fifo_errors++;
- }
-
- /* good packet ? */
- else {
- struct sk_buff *skb;
-
- skb = dev_alloc_skb(descr.Len + 2);
- if (skb == NULL)
- priv->stat.rx_dropped++;
- else {
- memcpy_fromio(skb_put(skb, descr.Len),
- priv->base +
- descr.LowAddr, descr.Len);
- skb->dev = dev;
- skb->protocol = eth_type_trans(skb, dev);
- skb->ip_summed = CHECKSUM_NONE;
- priv->stat.rx_packets++;
- priv->stat.rx_bytes += descr.Len;
- netif_rx(skb);
- dev->last_rx = jiffies;
- }
- }
-
- /* give descriptor back to LANCE */
- descr.Len = 0;
- descr.Flags |= RXDSCR_FLAGS_OWN;
-
- /* update descriptor in shared RAM */
- memcpy_toio(priv->base + descraddr, &descr,
- sizeof(LANCE_RxDescr));
-
- /* go to next descriptor */
- priv->nextrx++;
- descraddr += sizeof(LANCE_RxDescr);
- if (priv->nextrx >= RXCOUNT) {
- priv->nextrx = 0;
- descraddr = RAM_RXBASE;
- }
- }
-
- /* reset RINT bit */
-
- SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_RINT);
- return GetLANCE(dev, LANCE_CSR0);
-}
-
-/* transmit interrupt */
-
-static u16 irqtx_handler(struct net_device *dev, u16 oldcsr0)
-{
- skmca_priv *priv = netdev_priv(dev);
- LANCE_TxDescr descr;
- unsigned int descraddr;
-
- /* check descriptors at most until no busy one is left */
-
- descraddr =
- RAM_TXBASE + (priv->nexttxdone * sizeof(LANCE_TxDescr));
- while (priv->txbusy > 0) {
- /* read descriptor */
- memcpy_fromio(&descr, priv->base + descraddr,
- sizeof(LANCE_TxDescr));
-
- /* if the LANCE still owns this one, we've worked out all sent packets */
- if ((descr.Flags & TXDSCR_FLAGS_OWN) != 0)
- break;
-
-#ifdef DEBUG
- PrTime();
- printk("Send packet done on descr %d\n", priv->nexttxdone);
-#endif
-
- /* update statistics */
- if ((descr.Flags & TXDSCR_FLAGS_ERR) == 0) {
- priv->stat.tx_packets++;
- priv->stat.tx_bytes++;
- } else {
- priv->stat.tx_errors++;
- if ((descr.Status & TXDSCR_STATUS_UFLO) != 0) {
- priv->stat.tx_fifo_errors++;
- InitLANCE(dev);
- }
- else
- if ((descr.Status & TXDSCR_STATUS_LCOL) !=
- 0) priv->stat.tx_window_errors++;
- else if ((descr.Status & TXDSCR_STATUS_LCAR) != 0)
- priv->stat.tx_carrier_errors++;
- else if ((descr.Status & TXDSCR_STATUS_RTRY) != 0)
- priv->stat.tx_aborted_errors++;
- }
-
- /* go to next descriptor */
- priv->nexttxdone++;
- descraddr += sizeof(LANCE_TxDescr);
- if (priv->nexttxdone >= TXCOUNT) {
- priv->nexttxdone = 0;
- descraddr = RAM_TXBASE;
- }
- priv->txbusy--;
- }
-
- /* reset TX interrupt bit */
-
- SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_TINT);
- oldcsr0 = GetLANCE(dev, LANCE_CSR0);
-
- /* at least one descriptor is freed. Therefore we can accept
- a new one */
- /* inform upper layers we're in business again */
-
- netif_wake_queue(dev);
-
- return oldcsr0;
-}
-
-/* general interrupt entry */
-
-static irqreturn_t irq_handler(int irq, void *device)
-{
- struct net_device *dev = (struct net_device *) device;
- u16 csr0val;
-
- /* read CSR0 to get interrupt cause */
-
- csr0val = GetLANCE(dev, LANCE_CSR0);
-
- /* in case we're not meant... */
-
- if ((csr0val & CSR0_INTR) == 0)
- return IRQ_NONE;
-
-#if 0
- set_bit(LINK_STATE_RXSEM, &dev->state);
-#endif
-
- /* loop through the interrupt bits until everything is clear */
-
- do {
- if ((csr0val & CSR0_IDON) != 0)
- csr0val = irqstart_handler(dev, csr0val);
- if ((csr0val & CSR0_RINT) != 0)
- csr0val = irqrx_handler(dev, csr0val);
- if ((csr0val & CSR0_MISS) != 0)
- csr0val = irqmiss_handler(dev, csr0val);
- if ((csr0val & CSR0_TINT) != 0)
- csr0val = irqtx_handler(dev, csr0val);
- if ((csr0val & CSR0_MERR) != 0) {
- SetLANCE(dev, LANCE_CSR0, csr0val | CSR0_MERR);
- csr0val = GetLANCE(dev, LANCE_CSR0);
- }
- if ((csr0val & CSR0_BABL) != 0) {
- SetLANCE(dev, LANCE_CSR0, csr0val | CSR0_BABL);
- csr0val = GetLANCE(dev, LANCE_CSR0);
- }
- }
- while ((csr0val & CSR0_INTR) != 0);
-
-#if 0
- clear_bit(LINK_STATE_RXSEM, &dev->state);
-#endif
- return IRQ_HANDLED;
-}
-
-/* ------------------------------------------------------------------------
- * driver methods
- * ------------------------------------------------------------------------ */
-
-/* MCA info */
-
-static int skmca_getinfo(char *buf, int slot, void *d)
-{
- int len = 0, i;
- struct net_device *dev = (struct net_device *) d;
- skmca_priv *priv;
-
- /* can't say anything about an uninitialized device... */
-
- if (dev == NULL)
- return len;
- priv = netdev_priv(dev);
-
- /* print info */
-
- len += sprintf(buf + len, "IRQ: %d\n", priv->realirq);
- len += sprintf(buf + len, "Memory: %#lx-%#lx\n", dev->mem_start,
- dev->mem_end - 1);
- len +=
- sprintf(buf + len, "Transceiver: %s\n",
- MediaNames[priv->medium]);
- len += sprintf(buf + len, "Device: %s\n", dev->name);
- len += sprintf(buf + len, "MAC address:");
- for (i = 0; i < 6; i++)
- len += sprintf(buf + len, " %02x", dev->dev_addr[i]);
- buf[len++] = '\n';
- buf[len] = 0;
-
- return len;
-}
-
-/* open driver. Means also initialization and start of LANCE */
-
-static int skmca_open(struct net_device *dev)
-{
- int result;
- skmca_priv *priv = netdev_priv(dev);
-
- /* register resources - only necessary for IRQ */
- result =
- request_irq(priv->realirq, irq_handler,
- IRQF_SHARED | IRQF_SAMPLE_RANDOM, "sk_mca", dev);
- if (result != 0) {
- printk("%s: failed to register irq %d\n", dev->name,
- dev->irq);
- return result;
- }
- dev->irq = priv->realirq;
-
- /* set up the card and LANCE */
-
- InitBoard(dev);
-
- /* set up flags */
-
- netif_start_queue(dev);
-
- return 0;
-}
-
-/* close driver. Shut down board and free allocated resources */
-
-static int skmca_close(struct net_device *dev)
-{
- /* turn off board */
- DeinitBoard(dev);
-
- /* release resources */
- if (dev->irq != 0)
- free_irq(dev->irq, dev);
- dev->irq = 0;
-
- return 0;
-}
-
-/* transmit a block. */
-
-static int skmca_tx(struct sk_buff *skb, struct net_device *dev)
-{
- skmca_priv *priv = netdev_priv(dev);
- LANCE_TxDescr descr;
- unsigned int address;
- int tmplen, retval = 0;
- unsigned long flags;
-
- /* if we get called with a NULL descriptor, the Ethernet layer thinks
- our card is stuck an we should reset it. We'll do this completely: */
-
- if (skb == NULL) {
- DeinitBoard(dev);
- InitBoard(dev);
- return 0; /* don't try to free the block here ;-) */
- }
-
- /* is there space in the Tx queue ? If no, the upper layer gave us a
- packet in spite of us not being ready and is really in trouble.
- We'll do the dropping for him: */
- if (priv->txbusy >= TXCOUNT) {
- priv->stat.tx_dropped++;
- retval = -EIO;
- goto tx_done;
- }
-
- /* get TX descriptor */
- address = RAM_TXBASE + (priv->nexttxput * sizeof(LANCE_TxDescr));
- memcpy_fromio(&descr, priv->base + address, sizeof(LANCE_TxDescr));
-
- /* enter packet length as 2s complement - assure minimum length */
- tmplen = skb->len;
- if (tmplen < 60)
- tmplen = 60;
- descr.Len = 65536 - tmplen;
-
- /* copy filler into RAM - in case we're filling up...
- we're filling a bit more than necessary, but that doesn't harm
- since the buffer is far larger... */
- if (tmplen > skb->len) {
- char *fill = "NetBSD is a nice OS too! ";
- unsigned int destoffs = 0, l = strlen(fill);
-
- while (destoffs < tmplen) {
- memcpy_toio(priv->base + descr.LowAddr +
- destoffs, fill, l);
- destoffs += l;
- }
- }
-
- /* do the real data copying */
- memcpy_toio(priv->base + descr.LowAddr, skb->data, skb->len);
-
- /* hand descriptor over to LANCE - this is the first and last chunk */
- descr.Flags =
- TXDSCR_FLAGS_OWN | TXDSCR_FLAGS_STP | TXDSCR_FLAGS_ENP;
-
-#ifdef DEBUG
- PrTime();
- printk("Send packet on descr %d len %d\n", priv->nexttxput,
- skb->len);
-#endif
-
- /* one more descriptor busy */
-
- spin_lock_irqsave(&priv->lock, flags);
-
- priv->nexttxput++;
- if (priv->nexttxput >= TXCOUNT)
- priv->nexttxput = 0;
- priv->txbusy++;
-
- /* are we saturated ? */
-
- if (priv->txbusy >= TXCOUNT)
- netif_stop_queue(dev);
-
- /* write descriptor back to RAM */
- memcpy_toio(priv->base + address, &descr, sizeof(LANCE_TxDescr));
-
- /* if no descriptors were active, give the LANCE a hint to read it
- immediately */
-
- if (priv->txbusy == 0)
- SetLANCE(dev, LANCE_CSR0, CSR0_INEA | CSR0_TDMD);
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
- tx_done:
-
- dev_kfree_skb(skb);
-
- return retval;
-}
-
-/* return pointer to Ethernet statistics */
-
-static struct net_device_stats *skmca_stats(struct net_device *dev)
-{
- skmca_priv *priv = netdev_priv(dev);
-
- return &(priv->stat);
-}
-
-/* switch receiver mode. We use the LANCE's multicast filter to prefilter
- multicast addresses. */
-
-static void skmca_set_multicast_list(struct net_device *dev)
-{
- skmca_priv *priv = netdev_priv(dev);
- LANCE_InitBlock block;
-
- /* first stop the LANCE... */
- StopLANCE(dev);
-
- /* ...then modify the initialization block... */
- memcpy_fromio(&block, priv->base + RAM_INITBASE, sizeof(block));
- if (dev->flags & IFF_PROMISC)
- block.Mode |= LANCE_INIT_PROM;
- else
- block.Mode &= ~LANCE_INIT_PROM;
-
- if (dev->flags & IFF_ALLMULTI) { /* get all multicasts */
- memset(block.LAdrF, 0xff, sizeof(block.LAdrF));
- } else { /* get selected/no multicasts */
-
- struct dev_mc_list *mptr;
- int code;
-
- memset(block.LAdrF, 0, sizeof(block.LAdrF));
- for (mptr = dev->mc_list; mptr != NULL; mptr = mptr->next) {
- code = GetHash(mptr->dmi_addr);
- block.LAdrF[(code >> 3) & 7] |= 1 << (code & 7);
- }
- }
-
- memcpy_toio(priv->base + RAM_INITBASE, &block, sizeof(block));
-
- /* ...then reinit LANCE with the correct flags */
- InitLANCE(dev);
-}
-
-/* ------------------------------------------------------------------------
- * hardware check
- * ------------------------------------------------------------------------ */
-
-static int startslot; /* counts through slots when probing multiple devices */
-
-static void cleanup_card(struct net_device *dev)
-{
- skmca_priv *priv = netdev_priv(dev);
- DeinitBoard(dev);
- if (dev->irq != 0)
- free_irq(dev->irq, dev);
- iounmap(priv->base);
- mca_mark_as_unused(priv->slot);
- mca_set_adapter_procfn(priv->slot, NULL, NULL);
-}
-
-struct net_device * __init skmca_probe(int unit)
-{
- struct net_device *dev;
- int force_detect = 0;
- int junior, slot, i;
- int base = 0, irq = 0;
- skmca_priv *priv;
- skmca_medium medium;
- int err;
-
- /* can't work without an MCA bus ;-) */
-
- if (MCA_bus == 0)
- return ERR_PTR(-ENODEV);
-
- dev = alloc_etherdev(sizeof(skmca_priv));
- if (!dev)
- return ERR_PTR(-ENOMEM);
-
- if (unit >= 0) {
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
- }
-
- SET_MODULE_OWNER(dev);
-
- /* start address of 1 --> forced detection */
-
- if (dev->mem_start == 1)
- force_detect = 1;
-
- /* search through slots */
-
- base = dev->mem_start;
- irq = dev->base_addr;
- for (slot = startslot; (slot = dofind(&junior, slot)) != -1; slot++) {
- /* deduce card addresses */
-
- getaddrs(slot, junior, &base, &irq, &medium);
-
- /* slot already in use ? */
-
- if (mca_is_adapter_used(slot))
- continue;
-
- /* were we looking for something different ? */
-
- if (dev->irq && dev->irq != irq)
- continue;
- if (dev->mem_start && dev->mem_start != base)
- continue;
-
- /* found something that matches */
-
- break;
- }
-
- /* nothing found ? */
-
- if (slot == -1) {
- free_netdev(dev);
- return (base || irq) ? ERR_PTR(-ENXIO) : ERR_PTR(-ENODEV);
- }
-
- /* make procfs entries */
-
- if (junior)
- mca_set_adapter_name(slot,
- "SKNET junior MC2 Ethernet Adapter");
- else
- mca_set_adapter_name(slot, "SKNET MC2+ Ethernet Adapter");
- mca_set_adapter_procfn(slot, (MCA_ProcFn) skmca_getinfo, dev);
-
- mca_mark_as_used(slot);
-
- /* announce success */
- printk("%s: SKNet %s adapter found in slot %d\n", dev->name,
- junior ? "Junior MC2" : "MC2+", slot + 1);
-
- priv = netdev_priv(dev);
- priv->base = ioremap(base, 0x4000);
- if (!priv->base) {
- mca_set_adapter_procfn(slot, NULL, NULL);
- mca_mark_as_unused(slot);
- free_netdev(dev);
- return ERR_PTR(-ENOMEM);
- }
-
- priv->slot = slot;
- priv->macbase = priv->base + 0x3fc0;
- priv->ioregaddr = priv->base + 0x3ff0;
- priv->ctrladdr = priv->base + 0x3ff2;
- priv->cmdaddr = priv->base + 0x3ff3;
- priv->medium = medium;
- memset(&priv->stat, 0, sizeof(struct net_device_stats));
- spin_lock_init(&priv->lock);
-
- /* set base + irq for this device (irq not allocated so far) */
- dev->irq = 0;
- dev->mem_start = base;
- dev->mem_end = base + 0x4000;
-
- /* autoprobe ? */
- if (irq < 0) {
- int nirq;
-
- printk
- ("%s: ambigous POS bit combination, must probe for IRQ...\n",
- dev->name);
- nirq = ProbeIRQ(dev);
- if (nirq <= 0)
- printk("%s: IRQ probe failed, assuming IRQ %d",
- dev->name, priv->realirq = -irq);
- else
- priv->realirq = nirq;
- } else
- priv->realirq = irq;
-
- /* set methods */
- dev->open = skmca_open;
- dev->stop = skmca_close;
- dev->hard_start_xmit = skmca_tx;
- dev->do_ioctl = NULL;
- dev->get_stats = skmca_stats;
- dev->set_multicast_list = skmca_set_multicast_list;
- dev->flags |= IFF_MULTICAST;
-
- /* copy out MAC address */
- for (i = 0; i < 6; i++)
- dev->dev_addr[i] = readb(priv->macbase + (i << 1));
-
- /* print config */
- printk("%s: IRQ %d, memory %#lx-%#lx, "
- "MAC address %02x:%02x:%02x:%02x:%02x:%02x.\n",
- dev->name, priv->realirq, dev->mem_start, dev->mem_end - 1,
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
- printk("%s: %s medium\n", dev->name, MediaNames[priv->medium]);
-
- /* reset board */
-
- ResetBoard(dev);
-
- startslot = slot + 1;
-
- err = register_netdev(dev);
- if (err) {
- cleanup_card(dev);
- free_netdev(dev);
- dev = ERR_PTR(err);
- }
- return dev;
-}
-
-/* ------------------------------------------------------------------------
- * modularization support
- * ------------------------------------------------------------------------ */
-
-#ifdef MODULE
-MODULE_LICENSE("GPL");
-
-#define DEVMAX 5
-
-static struct net_device *moddevs[DEVMAX];
-
-int init_module(void)
-{
- int z;
-
- startslot = 0;
- for (z = 0; z < DEVMAX; z++) {
- struct net_device *dev = skmca_probe(-1);
- if (IS_ERR(dev))
- break;
- moddevs[z] = dev;
- }
- if (!z)
- return -EIO;
- return 0;
-}
-
-void cleanup_module(void)
-{
- int z;
-
- for (z = 0; z < DEVMAX; z++) {
- struct net_device *dev = moddevs[z];
- if (dev) {
- unregister_netdev(dev);
- cleanup_card(dev);
- free_netdev(dev);
- }
- }
-}
-#endif /* MODULE */
diff --git a/drivers/net/sk_mca.h b/drivers/net/sk_mca.h
deleted file mode 100644
index 0dae056fed9..00000000000
--- a/drivers/net/sk_mca.h
+++ /dev/null
@@ -1,170 +0,0 @@
-#ifndef _SK_MCA_INCLUDE_
-#define _SK_MCA_INCLUDE_
-
-#ifdef _SK_MCA_DRIVER_
-
-/* Adapter ID's */
-#define SKNET_MCA_ID 0x6afd
-#define SKNET_JUNIOR_MCA_ID 0x6be9
-
-/* media enumeration - defined in a way that it fits onto the MC2+'s
- POS registers... */
-
-typedef enum { Media_10Base2, Media_10BaseT,
- Media_10Base5, Media_Unknown, Media_Count
-} skmca_medium;
-
-/* private structure */
-typedef struct {
- unsigned int slot; /* MCA-Slot-# */
- void __iomem *base;
- void __iomem *macbase; /* base address of MAC address PROM */
- void __iomem *ioregaddr;/* address of I/O-register (Lo) */
- void __iomem *ctrladdr; /* address of control/stat register */
- void __iomem *cmdaddr; /* address of I/O-command register */
- int nextrx; /* index of next RX descriptor to
- be read */
- int nexttxput; /* index of next free TX descriptor */
- int nexttxdone; /* index of next TX descriptor to
- be finished */
- int txbusy; /* # of busy TX descriptors */
- struct net_device_stats stat; /* packet statistics */
- int realirq; /* memorizes actual IRQ, even when
- currently not allocated */
- skmca_medium medium; /* physical cannector */
- spinlock_t lock;
-} skmca_priv;
-
-/* card registers: control/status register bits */
-
-#define CTRL_ADR_DATA 0 /* Bit 0 = 0 ->access data register */
-#define CTRL_ADR_RAP 1 /* Bit 0 = 1 ->access RAP register */
-#define CTRL_RW_WRITE 0 /* Bit 1 = 0 ->write register */
-#define CTRL_RW_READ 2 /* Bit 1 = 1 ->read register */
-#define CTRL_RESET_ON 0 /* Bit 3 = 0 ->reset board */
-#define CTRL_RESET_OFF 8 /* Bit 3 = 1 ->no reset of board */
-
-#define STAT_ADR_DATA 0 /* Bit 0 of ctrl register read back */
-#define STAT_ADR_RAP 1
-#define STAT_RW_WRITE 0 /* Bit 1 of ctrl register read back */
-#define STAT_RW_READ 2
-#define STAT_RESET_ON 0 /* Bit 3 of ctrl register read back */
-#define STAT_RESET_OFF 8
-#define STAT_IRQ_ACT 0 /* interrupt pending */
-#define STAT_IRQ_NOACT 16 /* no interrupt pending */
-#define STAT_IO_NOBUSY 0 /* no transfer busy */
-#define STAT_IO_BUSY 32 /* transfer busy */
-
-/* I/O command register bits */
-
-#define IOCMD_GO 128 /* Bit 7 = 1 -> start register xfer */
-
-/* LANCE registers */
-
-#define LANCE_CSR0 0 /* Status/Control */
-
-#define CSR0_ERR 0x8000 /* general error flag */
-#define CSR0_BABL 0x4000 /* transmitter timeout */
-#define CSR0_CERR 0x2000 /* collision error */
-#define CSR0_MISS 0x1000 /* lost Rx block */
-#define CSR0_MERR 0x0800 /* memory access error */
-#define CSR0_RINT 0x0400 /* receiver interrupt */
-#define CSR0_TINT 0x0200 /* transmitter interrupt */
-#define CSR0_IDON 0x0100 /* initialization done */
-#define CSR0_INTR 0x0080 /* general interrupt flag */
-#define CSR0_INEA 0x0040 /* interrupt enable */
-#define CSR0_RXON 0x0020 /* receiver enabled */
-#define CSR0_TXON 0x0010 /* transmitter enabled */
-#define CSR0_TDMD 0x0008 /* force transmission now */
-#define CSR0_STOP 0x0004 /* stop LANCE */
-#define CSR0_STRT 0x0002 /* start LANCE */
-#define CSR0_INIT 0x0001 /* read initialization block */
-
-#define LANCE_CSR1 1 /* addr bit 0..15 of initialization */
-#define LANCE_CSR2 2 /* 16..23 block */
-
-#define LANCE_CSR3 3 /* Bus control */
-#define CSR3_BCON_HOLD 0 /* Bit 0 = 0 -> BM1,BM0,HOLD */
-#define CSR3_BCON_BUSRQ 1 /* Bit 0 = 1 -> BUSAK0,BYTE,BUSRQ */
-#define CSR3_ALE_HIGH 0 /* Bit 1 = 0 -> ALE asserted high */
-#define CSR3_ALE_LOW 2 /* Bit 1 = 1 -> ALE asserted low */
-#define CSR3_BSWAP_OFF 0 /* Bit 2 = 0 -> no byte swap */
-#define CSR3_BSWAP_ON 4 /* Bit 2 = 1 -> byte swap */
-
-/* LANCE structures */
-
-typedef struct { /* LANCE initialization block */
- u16 Mode; /* mode flags */
- u8 PAdr[6]; /* MAC address */
- u8 LAdrF[8]; /* Multicast filter */
- u32 RdrP; /* Receive descriptor */
- u32 TdrP; /* Transmit descriptor */
-} LANCE_InitBlock;
-
-/* Mode flags init block */
-
-#define LANCE_INIT_PROM 0x8000 /* enable promiscous mode */
-#define LANCE_INIT_INTL 0x0040 /* internal loopback */
-#define LANCE_INIT_DRTY 0x0020 /* disable retry */
-#define LANCE_INIT_COLL 0x0010 /* force collision */
-#define LANCE_INIT_DTCR 0x0008 /* disable transmit CRC */
-#define LANCE_INIT_LOOP 0x0004 /* loopback */
-#define LANCE_INIT_DTX 0x0002 /* disable transmitter */
-#define LANCE_INIT_DRX 0x0001 /* disable receiver */
-
-typedef struct { /* LANCE Tx descriptor */
- u16 LowAddr; /* bit 0..15 of address */
- u16 Flags; /* bit 16..23 of address + Flags */
- u16 Len; /* 2s complement of packet length */
- u16 Status; /* Result of transmission */
-} LANCE_TxDescr;
-
-#define TXDSCR_FLAGS_OWN 0x8000 /* LANCE owns descriptor */
-#define TXDSCR_FLAGS_ERR 0x4000 /* summary error flag */
-#define TXDSCR_FLAGS_MORE 0x1000 /* more than one retry needed? */
-#define TXDSCR_FLAGS_ONE 0x0800 /* one retry? */
-#define TXDSCR_FLAGS_DEF 0x0400 /* transmission deferred? */
-#define TXDSCR_FLAGS_STP 0x0200 /* first packet in chain? */
-#define TXDSCR_FLAGS_ENP 0x0100 /* last packet in chain? */
-
-#define TXDSCR_STATUS_BUFF 0x8000 /* buffer error? */
-#define TXDSCR_STATUS_UFLO 0x4000 /* silo underflow during transmit? */
-#define TXDSCR_STATUS_LCOL 0x1000 /* late collision? */
-#define TXDSCR_STATUS_LCAR 0x0800 /* loss of carrier? */
-#define TXDSCR_STATUS_RTRY 0x0400 /* retry error? */
-
-typedef struct { /* LANCE Rx descriptor */
- u16 LowAddr; /* bit 0..15 of address */
- u16 Flags; /* bit 16..23 of address + Flags */
- u16 MaxLen; /* 2s complement of buffer length */
- u16 Len; /* packet length */
-} LANCE_RxDescr;
-
-#define RXDSCR_FLAGS_OWN 0x8000 /* LANCE owns descriptor */
-#define RXDSCR_FLAGS_ERR 0x4000 /* summary error flag */
-#define RXDSCR_FLAGS_FRAM 0x2000 /* framing error flag */
-#define RXDSCR_FLAGS_OFLO 0x1000 /* FIFO overflow? */
-#define RXDSCR_FLAGS_CRC 0x0800 /* CRC error? */
-#define RXDSCR_FLAGS_BUFF 0x0400 /* buffer error? */
-#define RXDSCR_FLAGS_STP 0x0200 /* first packet in chain? */
-#define RXDCSR_FLAGS_ENP 0x0100 /* last packet in chain? */
-
-/* RAM layout */
-
-#define TXCOUNT 4 /* length of TX descriptor queue */
-#define LTXCOUNT 2 /* log2 of it */
-#define RXCOUNT 4 /* length of RX descriptor queue */
-#define LRXCOUNT 2 /* log2 of it */
-
-#define RAM_INITBASE 0 /* LANCE init block */
-#define RAM_TXBASE 24 /* Start of TX descriptor queue */
-#define RAM_RXBASE \
-(RAM_TXBASE + (TXCOUNT * 8)) /* Start of RX descriptor queue */
-#define RAM_DATABASE \
-(RAM_RXBASE + (RXCOUNT * 8)) /* Start of data area for frames */
-#define RAM_BUFSIZE 1580 /* max. frame size - should never be
- reached */
-
-#endif /* _SK_MCA_DRIVER_ */
-
-#endif /* _SK_MCA_INCLUDE_ */
diff --git a/drivers/net/skfp/can.c b/drivers/net/skfp/can.c
deleted file mode 100644
index 8a49abce796..00000000000
--- a/drivers/net/skfp/can.c
+++ /dev/null
@@ -1,83 +0,0 @@
-/******************************************************************************
- *
- * (C)Copyright 1998,1999 SysKonnect,
- * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
- *
- * See the file "skfddi.c" for further information.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * The information in this file is provided "AS IS" without warranty.
- *
- ******************************************************************************/
-
-#ifndef lint
-static const char xID_sccs[] = "@(#)can.c 1.5 97/04/07 (C) SK " ;
-#endif
-
-/*
- * canonical bit order
- */
-const u_char canonical[256] = {
- 0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0,
- 0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0,
- 0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8,
- 0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8,
- 0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4,
- 0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4,
- 0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec,
- 0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc,
- 0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2,
- 0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2,
- 0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea,
- 0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa,
- 0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6,
- 0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6,
- 0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee,
- 0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe,
- 0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1,
- 0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1,
- 0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9,
- 0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9,
- 0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5,
- 0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5,
- 0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed,
- 0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd,
- 0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3,
- 0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3,
- 0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb,
- 0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb,
- 0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7,
- 0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7,
- 0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef,
- 0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff
-} ;
-
-#ifdef MAKE_TABLE
-int byte_reverse(x)
-int x ;
-{
- int y = 0 ;
-
- if (x & 0x01)
- y |= 0x80 ;
- if (x & 0x02)
- y |= 0x40 ;
- if (x & 0x04)
- y |= 0x20 ;
- if (x & 0x08)
- y |= 0x10 ;
- if (x & 0x10)
- y |= 0x08 ;
- if (x & 0x20)
- y |= 0x04 ;
- if (x & 0x40)
- y |= 0x02 ;
- if (x & 0x80)
- y |= 0x01 ;
- return(y) ;
-}
-#endif
diff --git a/drivers/net/skfp/drvfbi.c b/drivers/net/skfp/drvfbi.c
index 5b475833f64..4fe624b0dd2 100644
--- a/drivers/net/skfp/drvfbi.c
+++ b/drivers/net/skfp/drvfbi.c
@@ -23,6 +23,7 @@
#include "h/smc.h"
#include "h/supern_2.h"
#include "h/skfbiinc.h"
+#include <linux/bitrev.h>
#ifndef lint
static const char ID_sccs[] = "@(#)drvfbi.c 1.63 99/02/11 (C) SK " ;
@@ -445,16 +446,14 @@ void read_address(struct s_smc *smc, u_char *mac_addr)
char PmdType ;
int i ;
- extern const u_char canonical[256] ;
-
#if (defined(ISA) || defined(MCA))
for (i = 0; i < 4 ;i++) { /* read mac address from board */
smc->hw.fddi_phys_addr.a[i] =
- canonical[(inpw(PR_A(i+SA_MAC))&0xff)] ;
+ bitrev8(inpw(PR_A(i+SA_MAC)));
}
for (i = 4; i < 6; i++) {
smc->hw.fddi_phys_addr.a[i] =
- canonical[(inpw(PR_A(i+SA_MAC+PRA_OFF))&0xff)] ;
+ bitrev8(inpw(PR_A(i+SA_MAC+PRA_OFF)));
}
#endif
#ifdef EISA
@@ -464,17 +463,17 @@ void read_address(struct s_smc *smc, u_char *mac_addr)
*/
for (i = 0; i < 4 ;i++) { /* read mac address from board */
smc->hw.fddi_phys_addr.a[i] =
- canonical[inp(PR_A(i+SA_MAC))] ;
+ bitrev8(inp(PR_A(i+SA_MAC)));
}
for (i = 4; i < 6; i++) {
smc->hw.fddi_phys_addr.a[i] =
- canonical[inp(PR_A(i+SA_MAC+PRA_OFF))] ;
+ bitrev8(inp(PR_A(i+SA_MAC+PRA_OFF)));
}
#endif
#ifdef PCI
for (i = 0; i < 6; i++) { /* read mac address from board */
smc->hw.fddi_phys_addr.a[i] =
- canonical[inp(ADDR(B2_MAC_0+i))] ;
+ bitrev8(inp(ADDR(B2_MAC_0+i)));
}
#endif
#ifndef PCI
@@ -493,7 +492,7 @@ void read_address(struct s_smc *smc, u_char *mac_addr)
if (mac_addr) {
for (i = 0; i < 6 ;i++) {
smc->hw.fddi_canon_addr.a[i] = mac_addr[i] ;
- smc->hw.fddi_home_addr.a[i] = canonical[mac_addr[i]] ;
+ smc->hw.fddi_home_addr.a[i] = bitrev8(mac_addr[i]);
}
return ;
}
@@ -501,7 +500,7 @@ void read_address(struct s_smc *smc, u_char *mac_addr)
for (i = 0; i < 6 ;i++) {
smc->hw.fddi_canon_addr.a[i] =
- canonical[smc->hw.fddi_phys_addr.a[i]] ;
+ bitrev8(smc->hw.fddi_phys_addr.a[i]);
}
}
@@ -1269,11 +1268,8 @@ void driver_get_bia(struct s_smc *smc, struct fddi_addr *bia_addr)
{
int i ;
- extern const u_char canonical[256] ;
-
- for (i = 0 ; i < 6 ; i++) {
- bia_addr->a[i] = canonical[smc->hw.fddi_phys_addr.a[i]] ;
- }
+ for (i = 0 ; i < 6 ; i++)
+ bia_addr->a[i] = bitrev8(smc->hw.fddi_phys_addr.a[i]);
}
void smt_start_watchdog(struct s_smc *smc)
diff --git a/drivers/net/skfp/fplustm.c b/drivers/net/skfp/fplustm.c
index 0784f558ca9..a45205da803 100644
--- a/drivers/net/skfp/fplustm.c
+++ b/drivers/net/skfp/fplustm.c
@@ -22,7 +22,7 @@
#include "h/fddi.h"
#include "h/smc.h"
#include "h/supern_2.h"
-#include "can.c"
+#include <linux/bitrev.h>
#ifndef lint
static const char ID_sccs[] = "@(#)fplustm.c 1.32 99/02/23 (C) SK " ;
@@ -1073,7 +1073,7 @@ static struct s_fpmc* mac_get_mc_table(struct s_smc *smc,
if (can) {
p = own->a ;
for (i = 0 ; i < 6 ; i++, p++)
- *p = canonical[*p] ;
+ *p = bitrev8(*p);
}
slot = NULL;
for (i = 0, tb = smc->hw.fp.mc.table ; i < FPMAX_MULTICAST ; i++, tb++){
diff --git a/drivers/net/skfp/smt.c b/drivers/net/skfp/smt.c
index 99a776a51fb..fe847800acd 100644
--- a/drivers/net/skfp/smt.c
+++ b/drivers/net/skfp/smt.c
@@ -18,6 +18,7 @@
#include "h/fddi.h"
#include "h/smc.h"
#include "h/smt_p.h"
+#include <linux/bitrev.h>
#define KERNEL
#include "h/smtstate.h"
@@ -26,8 +27,6 @@
static const char ID_sccs[] = "@(#)smt.c 2.43 98/11/23 (C) SK " ;
#endif
-extern const u_char canonical[256] ;
-
/*
* FC in SMbuf
*/
@@ -180,7 +179,7 @@ void smt_agent_init(struct s_smc *smc)
driver_get_bia(smc,&smc->mib.fddiSMTStationId.sid_node) ;
for (i = 0 ; i < 6 ; i ++) {
smc->mib.fddiSMTStationId.sid_node.a[i] =
- canonical[smc->mib.fddiSMTStationId.sid_node.a[i]] ;
+ bitrev8(smc->mib.fddiSMTStationId.sid_node.a[i]);
}
smc->mib.fddiSMTManufacturerData[0] =
smc->mib.fddiSMTStationId.sid_node.a[0] ;
@@ -2049,9 +2048,8 @@ static void hwm_conv_can(struct s_smc *smc, char *data, int len)
SK_UNUSED(smc) ;
- for (i = len; i ; i--, data++) {
- *data = canonical[*(u_char *)data] ;
- }
+ for (i = len; i ; i--, data++)
+ *data = bitrev8(*data);
}
#endif
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index 45283f3f95e..e482e7fcbb2 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -42,7 +42,7 @@
#include "skge.h"
#define DRV_NAME "skge"
-#define DRV_VERSION "1.9"
+#define DRV_VERSION "1.10"
#define PFX DRV_NAME " "
#define DEFAULT_TX_RING_SIZE 128
@@ -132,18 +132,93 @@ static void skge_get_regs(struct net_device *dev, struct ethtool_regs *regs,
}
/* Wake on Lan only supported on Yukon chips with rev 1 or above */
-static int wol_supported(const struct skge_hw *hw)
+static u32 wol_supported(const struct skge_hw *hw)
{
- return !((hw->chip_id == CHIP_ID_GENESIS ||
- (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev == 0)));
+ if (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev != 0)
+ return WAKE_MAGIC | WAKE_PHY;
+ else
+ return 0;
+}
+
+static u32 pci_wake_enabled(struct pci_dev *dev)
+{
+ int pm = pci_find_capability(dev, PCI_CAP_ID_PM);
+ u16 value;
+
+ /* If device doesn't support PM Capabilities, but request is to disable
+ * wake events, it's a nop; otherwise fail */
+ if (!pm)
+ return 0;
+
+ pci_read_config_word(dev, pm + PCI_PM_PMC, &value);
+
+ value &= PCI_PM_CAP_PME_MASK;
+ value >>= ffs(PCI_PM_CAP_PME_MASK) - 1; /* First bit of mask */
+
+ return value != 0;
+}
+
+static void skge_wol_init(struct skge_port *skge)
+{
+ struct skge_hw *hw = skge->hw;
+ int port = skge->port;
+ enum pause_control save_mode;
+ u32 ctrl;
+
+ /* Bring hardware out of reset */
+ skge_write16(hw, B0_CTST, CS_RST_CLR);
+ skge_write16(hw, SK_REG(port, GMAC_LINK_CTRL), GMLC_RST_CLR);
+
+ skge_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_CLR);
+ skge_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_CLR);
+
+ /* Force to 10/100 skge_reset will re-enable on resume */
+ save_mode = skge->flow_control;
+ skge->flow_control = FLOW_MODE_SYMMETRIC;
+
+ ctrl = skge->advertising;
+ skge->advertising &= ~(ADVERTISED_1000baseT_Half|ADVERTISED_1000baseT_Full);
+
+ skge_phy_reset(skge);
+
+ skge->flow_control = save_mode;
+ skge->advertising = ctrl;
+
+ /* Set GMAC to no flow control and auto update for speed/duplex */
+ gma_write16(hw, port, GM_GP_CTRL,
+ GM_GPCR_FC_TX_DIS|GM_GPCR_TX_ENA|GM_GPCR_RX_ENA|
+ GM_GPCR_DUP_FULL|GM_GPCR_FC_RX_DIS|GM_GPCR_AU_FCT_DIS);
+
+ /* Set WOL address */
+ memcpy_toio(hw->regs + WOL_REGS(port, WOL_MAC_ADDR),
+ skge->netdev->dev_addr, ETH_ALEN);
+
+ /* Turn on appropriate WOL control bits */
+ skge_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), WOL_CTL_CLEAR_RESULT);
+ ctrl = 0;
+ if (skge->wol & WAKE_PHY)
+ ctrl |= WOL_CTL_ENA_PME_ON_LINK_CHG|WOL_CTL_ENA_LINK_CHG_UNIT;
+ else
+ ctrl |= WOL_CTL_DIS_PME_ON_LINK_CHG|WOL_CTL_DIS_LINK_CHG_UNIT;
+
+ if (skge->wol & WAKE_MAGIC)
+ ctrl |= WOL_CTL_ENA_PME_ON_MAGIC_PKT|WOL_CTL_ENA_MAGIC_PKT_UNIT;
+ else
+ ctrl |= WOL_CTL_DIS_PME_ON_MAGIC_PKT|WOL_CTL_DIS_MAGIC_PKT_UNIT;;
+
+ ctrl |= WOL_CTL_DIS_PME_ON_PATTERN|WOL_CTL_DIS_PATTERN_UNIT;
+ skge_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), ctrl);
+
+ /* block receiver */
+ skge_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET);
}
static void skge_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
struct skge_port *skge = netdev_priv(dev);
- wol->supported = wol_supported(skge->hw) ? WAKE_MAGIC : 0;
- wol->wolopts = skge->wol ? WAKE_MAGIC : 0;
+ wol->supported = wol_supported(skge->hw);
+ wol->wolopts = skge->wol;
}
static int skge_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
@@ -151,23 +226,12 @@ static int skge_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
struct skge_port *skge = netdev_priv(dev);
struct skge_hw *hw = skge->hw;
- if (wol->wolopts != WAKE_MAGIC && wol->wolopts != 0)
+ if (wol->wolopts & wol_supported(hw))
return -EOPNOTSUPP;
- if (wol->wolopts == WAKE_MAGIC && !wol_supported(hw))
- return -EOPNOTSUPP;
-
- skge->wol = wol->wolopts == WAKE_MAGIC;
-
- if (skge->wol) {
- memcpy_toio(hw->regs + WOL_MAC_ADDR, dev->dev_addr, ETH_ALEN);
-
- skge_write16(hw, WOL_CTRL_STAT,
- WOL_CTL_ENA_PME_ON_MAGIC_PKT |
- WOL_CTL_ENA_MAGIC_PKT_UNIT);
- } else
- skge_write16(hw, WOL_CTRL_STAT, WOL_CTL_DEFAULT);
-
+ skge->wol = wol->wolopts;
+ if (!netif_running(dev))
+ skge_wol_init(skge);
return 0;
}
@@ -2373,6 +2437,9 @@ static int skge_up(struct net_device *dev)
size_t rx_size, tx_size;
int err;
+ if (!is_valid_ether_addr(dev->dev_addr))
+ return -EINVAL;
+
if (netif_msg_ifup(skge))
printk(KERN_INFO PFX "%s: enabling interface\n", dev->name);
@@ -2392,7 +2459,7 @@ static int skge_up(struct net_device *dev)
BUG_ON(skge->dma & 7);
if ((u64)skge->dma >> 32 != ((u64) skge->dma + skge->mem_size) >> 32) {
- printk(KERN_ERR PFX "pci_alloc_consistent region crosses 4G boundary\n");
+ dev_err(&hw->pdev->dev, "pci_alloc_consistent region crosses 4G boundary\n");
err = -EINVAL;
goto free_pci_mem;
}
@@ -3001,6 +3068,7 @@ static void skge_mac_intr(struct skge_hw *hw, int port)
/* Handle device specific framing and timeout interrupts */
static void skge_error_irq(struct skge_hw *hw)
{
+ struct pci_dev *pdev = hw->pdev;
u32 hwstatus = skge_read32(hw, B0_HWE_ISRC);
if (hw->chip_id == CHIP_ID_GENESIS) {
@@ -3016,12 +3084,12 @@ static void skge_error_irq(struct skge_hw *hw)
}
if (hwstatus & IS_RAM_RD_PAR) {
- printk(KERN_ERR PFX "Ram read data parity error\n");
+ dev_err(&pdev->dev, "Ram read data parity error\n");
skge_write16(hw, B3_RI_CTRL, RI_CLR_RD_PERR);
}
if (hwstatus & IS_RAM_WR_PAR) {
- printk(KERN_ERR PFX "Ram write data parity error\n");
+ dev_err(&pdev->dev, "Ram write data parity error\n");
skge_write16(hw, B3_RI_CTRL, RI_CLR_WR_PERR);
}
@@ -3032,38 +3100,38 @@ static void skge_error_irq(struct skge_hw *hw)
skge_mac_parity(hw, 1);
if (hwstatus & IS_R1_PAR_ERR) {
- printk(KERN_ERR PFX "%s: receive queue parity error\n",
- hw->dev[0]->name);
+ dev_err(&pdev->dev, "%s: receive queue parity error\n",
+ hw->dev[0]->name);
skge_write32(hw, B0_R1_CSR, CSR_IRQ_CL_P);
}
if (hwstatus & IS_R2_PAR_ERR) {
- printk(KERN_ERR PFX "%s: receive queue parity error\n",
- hw->dev[1]->name);
+ dev_err(&pdev->dev, "%s: receive queue parity error\n",
+ hw->dev[1]->name);
skge_write32(hw, B0_R2_CSR, CSR_IRQ_CL_P);
}
if (hwstatus & (IS_IRQ_MST_ERR|IS_IRQ_STAT)) {
u16 pci_status, pci_cmd;
- pci_read_config_word(hw->pdev, PCI_COMMAND, &pci_cmd);
- pci_read_config_word(hw->pdev, PCI_STATUS, &pci_status);
+ pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd);
+ pci_read_config_word(pdev, PCI_STATUS, &pci_status);
- printk(KERN_ERR PFX "%s: PCI error cmd=%#x status=%#x\n",
- pci_name(hw->pdev), pci_cmd, pci_status);
+ dev_err(&pdev->dev, "PCI error cmd=%#x status=%#x\n",
+ pci_cmd, pci_status);
/* Write the error bits back to clear them. */
pci_status &= PCI_STATUS_ERROR_BITS;
skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
- pci_write_config_word(hw->pdev, PCI_COMMAND,
+ pci_write_config_word(pdev, PCI_COMMAND,
pci_cmd | PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
- pci_write_config_word(hw->pdev, PCI_STATUS, pci_status);
+ pci_write_config_word(pdev, PCI_STATUS, pci_status);
skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
/* if error still set then just ignore it */
hwstatus = skge_read32(hw, B0_HWE_ISRC);
if (hwstatus & IS_IRQ_STAT) {
- printk(KERN_INFO PFX "unable to clear error (so ignoring them)\n");
+ dev_warn(&hw->pdev->dev, "unable to clear error (so ignoring them)\n");
hw->intr_mask &= ~IS_HW_ERR;
}
}
@@ -3277,8 +3345,8 @@ static int skge_reset(struct skge_hw *hw)
hw->phy_addr = PHY_ADDR_BCOM;
break;
default:
- printk(KERN_ERR PFX "%s: unsupported phy type 0x%x\n",
- pci_name(hw->pdev), hw->phy_type);
+ dev_err(&hw->pdev->dev, "unsupported phy type 0x%x\n",
+ hw->phy_type);
return -EOPNOTSUPP;
}
break;
@@ -3293,8 +3361,8 @@ static int skge_reset(struct skge_hw *hw)
break;
default:
- printk(KERN_ERR PFX "%s: unsupported chip type 0x%x\n",
- pci_name(hw->pdev), hw->chip_id);
+ dev_err(&hw->pdev->dev, "unsupported chip type 0x%x\n",
+ hw->chip_id);
return -EOPNOTSUPP;
}
@@ -3334,7 +3402,7 @@ static int skge_reset(struct skge_hw *hw)
/* avoid boards with stuck Hardware error bits */
if ((skge_read32(hw, B0_ISRC) & IS_HW_ERR) &&
(skge_read32(hw, B0_HWE_ISRC) & IS_IRQ_SENSOR)) {
- printk(KERN_WARNING PFX "stuck hardware sensor bit\n");
+ dev_warn(&hw->pdev->dev, "stuck hardware sensor bit\n");
hw->intr_mask &= ~IS_HW_ERR;
}
@@ -3408,7 +3476,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
struct net_device *dev = alloc_etherdev(sizeof(*skge));
if (!dev) {
- printk(KERN_ERR "skge etherdev alloc failed");
+ dev_err(&hw->pdev->dev, "etherdev alloc failed\n");
return NULL;
}
@@ -3452,6 +3520,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
skge->duplex = -1;
skge->speed = -1;
skge->advertising = skge_supported_modes(hw);
+ skge->wol = pci_wake_enabled(hw->pdev) ? wol_supported(hw) : 0;
hw->dev[port] = dev;
@@ -3496,15 +3565,13 @@ static int __devinit skge_probe(struct pci_dev *pdev,
err = pci_enable_device(pdev);
if (err) {
- printk(KERN_ERR PFX "%s cannot enable PCI device\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "cannot enable PCI device\n");
goto err_out;
}
err = pci_request_regions(pdev, DRV_NAME);
if (err) {
- printk(KERN_ERR PFX "%s cannot obtain PCI resources\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "cannot obtain PCI resources\n");
goto err_out_disable_pdev;
}
@@ -3519,8 +3586,7 @@ static int __devinit skge_probe(struct pci_dev *pdev,
}
if (err) {
- printk(KERN_ERR PFX "%s no usable DMA configuration\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "no usable DMA configuration\n");
goto err_out_free_regions;
}
@@ -3538,8 +3604,7 @@ static int __devinit skge_probe(struct pci_dev *pdev,
err = -ENOMEM;
hw = kzalloc(sizeof(*hw), GFP_KERNEL);
if (!hw) {
- printk(KERN_ERR PFX "%s: cannot allocate hardware struct\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "cannot allocate hardware struct\n");
goto err_out_free_regions;
}
@@ -3550,8 +3615,7 @@ static int __devinit skge_probe(struct pci_dev *pdev,
hw->regs = ioremap_nocache(pci_resource_start(pdev, 0), 0x4000);
if (!hw->regs) {
- printk(KERN_ERR PFX "%s: cannot map device registers\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "cannot map device registers\n");
goto err_out_free_hw;
}
@@ -3567,23 +3631,19 @@ static int __devinit skge_probe(struct pci_dev *pdev,
if (!dev)
goto err_out_led_off;
- if (!is_valid_ether_addr(dev->dev_addr)) {
- printk(KERN_ERR PFX "%s: bad (zero?) ethernet address in rom\n",
- pci_name(pdev));
- err = -EIO;
- goto err_out_free_netdev;
- }
+ /* Some motherboards are broken and has zero in ROM. */
+ if (!is_valid_ether_addr(dev->dev_addr))
+ dev_warn(&pdev->dev, "bad (zero?) ethernet address in rom\n");
err = register_netdev(dev);
if (err) {
- printk(KERN_ERR PFX "%s: cannot register net device\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "cannot register net device\n");
goto err_out_free_netdev;
}
err = request_irq(pdev->irq, skge_intr, IRQF_SHARED, dev->name, hw);
if (err) {
- printk(KERN_ERR PFX "%s: cannot assign irq %d\n",
+ dev_err(&pdev->dev, "%s: cannot assign irq %d\n",
dev->name, pdev->irq);
goto err_out_unregister;
}
@@ -3594,7 +3654,7 @@ static int __devinit skge_probe(struct pci_dev *pdev,
skge_show_addr(dev1);
else {
/* Failure to register second port need not be fatal */
- printk(KERN_WARNING PFX "register of second port failed\n");
+ dev_warn(&pdev->dev, "register of second port failed\n");
hw->dev[1] = NULL;
free_netdev(dev1);
}
@@ -3659,28 +3719,46 @@ static void __devexit skge_remove(struct pci_dev *pdev)
}
#ifdef CONFIG_PM
+static int vaux_avail(struct pci_dev *pdev)
+{
+ int pm_cap;
+
+ pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
+ if (pm_cap) {
+ u16 ctl;
+ pci_read_config_word(pdev, pm_cap + PCI_PM_PMC, &ctl);
+ if (ctl & PCI_PM_CAP_AUX_POWER)
+ return 1;
+ }
+ return 0;
+}
+
+
static int skge_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct skge_hw *hw = pci_get_drvdata(pdev);
- int i, wol = 0;
+ int i, err, wol = 0;
+
+ err = pci_save_state(pdev);
+ if (err)
+ return err;
- pci_save_state(pdev);
for (i = 0; i < hw->ports; i++) {
struct net_device *dev = hw->dev[i];
+ struct skge_port *skge = netdev_priv(dev);
- if (netif_running(dev)) {
- struct skge_port *skge = netdev_priv(dev);
+ if (netif_running(dev))
+ skge_down(dev);
+ if (skge->wol)
+ skge_wol_init(skge);
- netif_carrier_off(dev);
- if (skge->wol)
- netif_stop_queue(dev);
- else
- skge_down(dev);
- wol |= skge->wol;
- }
- netif_device_detach(dev);
+ wol |= skge->wol;
}
+ if (wol && vaux_avail(pdev))
+ skge_write8(hw, B0_POWER_CTRL,
+ PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_ON | PC_VCC_OFF);
+
skge_write32(hw, B0_IMSK, 0);
pci_enable_wake(pdev, pci_choose_state(pdev, state), wol);
pci_set_power_state(pdev, pci_choose_state(pdev, state));
@@ -3693,8 +3771,14 @@ static int skge_resume(struct pci_dev *pdev)
struct skge_hw *hw = pci_get_drvdata(pdev);
int i, err;
- pci_set_power_state(pdev, PCI_D0);
- pci_restore_state(pdev);
+ err = pci_set_power_state(pdev, PCI_D0);
+ if (err)
+ goto out;
+
+ err = pci_restore_state(pdev);
+ if (err)
+ goto out;
+
pci_enable_wake(pdev, PCI_D0, 0);
err = skge_reset(hw);
@@ -3704,7 +3788,6 @@ static int skge_resume(struct pci_dev *pdev)
for (i = 0; i < hw->ports; i++) {
struct net_device *dev = hw->dev[i];
- netif_device_attach(dev);
if (netif_running(dev)) {
err = skge_up(dev);
diff --git a/drivers/net/skge.h b/drivers/net/skge.h
index f6223c533c0..17b1b479dff 100644
--- a/drivers/net/skge.h
+++ b/drivers/net/skge.h
@@ -876,11 +876,13 @@ enum {
WOL_PATT_CNT_0 = 0x0f38,/* 32 bit WOL Pattern Counter 3..0 */
WOL_PATT_CNT_4 = 0x0f3c,/* 24 bit WOL Pattern Counter 6..4 */
};
+#define WOL_REGS(port, x) (x + (port)*0x80)
enum {
WOL_PATT_RAM_1 = 0x1000,/* WOL Pattern RAM Link 1 */
WOL_PATT_RAM_2 = 0x1400,/* WOL Pattern RAM Link 2 */
};
+#define WOL_PATT_RAM_BASE(port) (WOL_PATT_RAM_1 + (port)*0x400)
enum {
BASE_XMAC_1 = 0x2000,/* XMAC 1 registers */
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 822dd0b1313..f2ab3d56e56 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -49,7 +49,7 @@
#include "sky2.h"
#define DRV_NAME "sky2"
-#define DRV_VERSION "1.10"
+#define DRV_VERSION "1.12"
#define PFX DRV_NAME " "
/*
@@ -105,6 +105,7 @@ static const struct pci_device_id sky2_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b00) }, /* DGE-560T */
{ PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4001) }, /* DGE-550SX */
{ PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4B02) }, /* DGE-560SX */
+ { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4B03) }, /* DGE-550T */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4340) }, /* 88E8021 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4341) }, /* 88E8022 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4342) }, /* 88E8061 */
@@ -126,6 +127,9 @@ static const struct pci_device_id sky2_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4366) }, /* 88EC036 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4367) }, /* 88EC032 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4368) }, /* 88EC034 */
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4369) }, /* 88EC042 */
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436A) }, /* 88E8058 */
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436B) }, /* 88E8071 */
{ 0 }
};
@@ -140,7 +144,7 @@ static const u32 portirq_msk[] = { Y2_IS_PORT_1, Y2_IS_PORT_2 };
static const char *yukon2_name[] = {
"XL", /* 0xb3 */
"EC Ultra", /* 0xb4 */
- "UNKNOWN", /* 0xb5 */
+ "Extreme", /* 0xb5 */
"EC", /* 0xb6 */
"FE", /* 0xb7 */
};
@@ -192,76 +196,52 @@ static u16 gm_phy_read(struct sky2_hw *hw, unsigned port, u16 reg)
return v;
}
-static void sky2_set_power_state(struct sky2_hw *hw, pci_power_t state)
-{
- u16 power_control;
- int vaux;
-
- pr_debug("sky2_set_power_state %d\n", state);
- sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
-
- power_control = sky2_pci_read16(hw, hw->pm_cap + PCI_PM_PMC);
- vaux = (sky2_read16(hw, B0_CTST) & Y2_VAUX_AVAIL) &&
- (power_control & PCI_PM_CAP_PME_D3cold);
-
- power_control = sky2_pci_read16(hw, hw->pm_cap + PCI_PM_CTRL);
-
- power_control |= PCI_PM_CTRL_PME_STATUS;
- power_control &= ~(PCI_PM_CTRL_STATE_MASK);
- switch (state) {
- case PCI_D0:
- /* switch power to VCC (WA for VAUX problem) */
- sky2_write8(hw, B0_POWER_CTRL,
- PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_OFF | PC_VCC_ON);
-
- /* disable Core Clock Division, */
- sky2_write32(hw, B2_Y2_CLK_CTRL, Y2_CLK_DIV_DIS);
-
- if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
- /* enable bits are inverted */
- sky2_write8(hw, B2_Y2_CLK_GATE,
- Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS |
- Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS |
- Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS);
- else
- sky2_write8(hw, B2_Y2_CLK_GATE, 0);
+static void sky2_power_on(struct sky2_hw *hw)
+{
+ /* switch power to VCC (WA for VAUX problem) */
+ sky2_write8(hw, B0_POWER_CTRL,
+ PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_OFF | PC_VCC_ON);
- if (hw->chip_id == CHIP_ID_YUKON_EC_U) {
- u32 reg1;
+ /* disable Core Clock Division, */
+ sky2_write32(hw, B2_Y2_CLK_CTRL, Y2_CLK_DIV_DIS);
- sky2_pci_write32(hw, PCI_DEV_REG3, 0);
- reg1 = sky2_pci_read32(hw, PCI_DEV_REG4);
- reg1 &= P_ASPM_CONTROL_MSK;
- sky2_pci_write32(hw, PCI_DEV_REG4, reg1);
- sky2_pci_write32(hw, PCI_DEV_REG5, 0);
- }
+ if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
+ /* enable bits are inverted */
+ sky2_write8(hw, B2_Y2_CLK_GATE,
+ Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS |
+ Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS |
+ Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS);
+ else
+ sky2_write8(hw, B2_Y2_CLK_GATE, 0);
- break;
+ if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX) {
+ u32 reg1;
- case PCI_D3hot:
- case PCI_D3cold:
- if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
- sky2_write8(hw, B2_Y2_CLK_GATE, 0);
- else
- /* enable bits are inverted */
- sky2_write8(hw, B2_Y2_CLK_GATE,
- Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS |
- Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS |
- Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS);
-
- /* switch power to VAUX */
- if (vaux && state != PCI_D3cold)
- sky2_write8(hw, B0_POWER_CTRL,
- (PC_VAUX_ENA | PC_VCC_ENA |
- PC_VAUX_ON | PC_VCC_OFF));
- break;
- default:
- printk(KERN_ERR PFX "Unknown power state %d\n", state);
+ sky2_pci_write32(hw, PCI_DEV_REG3, 0);
+ reg1 = sky2_pci_read32(hw, PCI_DEV_REG4);
+ reg1 &= P_ASPM_CONTROL_MSK;
+ sky2_pci_write32(hw, PCI_DEV_REG4, reg1);
+ sky2_pci_write32(hw, PCI_DEV_REG5, 0);
}
+}
- sky2_pci_write16(hw, hw->pm_cap + PCI_PM_CTRL, power_control);
- sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+static void sky2_power_aux(struct sky2_hw *hw)
+{
+ if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
+ sky2_write8(hw, B2_Y2_CLK_GATE, 0);
+ else
+ /* enable bits are inverted */
+ sky2_write8(hw, B2_Y2_CLK_GATE,
+ Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS |
+ Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS |
+ Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS);
+
+ /* switch power to VAUX */
+ if (sky2_read16(hw, B0_CTST) & Y2_VAUX_AVAIL)
+ sky2_write8(hw, B0_POWER_CTRL,
+ (PC_VAUX_ENA | PC_VCC_ENA |
+ PC_VAUX_ON | PC_VCC_OFF));
}
static void sky2_gmac_reset(struct sky2_hw *hw, unsigned port)
@@ -313,8 +293,10 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
struct sky2_port *sky2 = netdev_priv(hw->dev[port]);
u16 ctrl, ct1000, adv, pg, ledctrl, ledover, reg;
- if (sky2->autoneg == AUTONEG_ENABLE &&
- !(hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)) {
+ if (sky2->autoneg == AUTONEG_ENABLE
+ && !(hw->chip_id == CHIP_ID_YUKON_XL
+ || hw->chip_id == CHIP_ID_YUKON_EC_U
+ || hw->chip_id == CHIP_ID_YUKON_EX)) {
u16 ectrl = gm_phy_read(hw, port, PHY_MARV_EXT_CTRL);
ectrl &= ~(PHY_M_EC_M_DSC_MSK | PHY_M_EC_S_DSC_MSK |
@@ -341,8 +323,10 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
/* enable automatic crossover */
ctrl |= PHY_M_PC_MDI_XMODE(PHY_M_PC_ENA_AUTO);
- if (sky2->autoneg == AUTONEG_ENABLE &&
- (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)) {
+ if (sky2->autoneg == AUTONEG_ENABLE
+ && (hw->chip_id == CHIP_ID_YUKON_XL
+ || hw->chip_id == CHIP_ID_YUKON_EC_U
+ || hw->chip_id == CHIP_ID_YUKON_EX)) {
ctrl &= ~PHY_M_PC_DSC_MSK;
ctrl |= PHY_M_PC_DSC(2) | PHY_M_PC_DOWN_S_ENA;
}
@@ -497,7 +481,9 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
/* restore page register */
gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
break;
+
case CHIP_ID_YUKON_EC_U:
+ case CHIP_ID_YUKON_EX:
pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
/* select page 3 to access LED control register */
@@ -539,7 +525,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
/* set page register to 0 */
gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
- } else {
+ } else if (hw->chip_id != CHIP_ID_YUKON_EX) {
gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl);
if (sky2->autoneg == AUTONEG_DISABLE || sky2->speed == SPEED_100) {
@@ -591,6 +577,73 @@ static void sky2_phy_reinit(struct sky2_port *sky2)
spin_unlock_bh(&sky2->phy_lock);
}
+/* Put device in state to listen for Wake On Lan */
+static void sky2_wol_init(struct sky2_port *sky2)
+{
+ struct sky2_hw *hw = sky2->hw;
+ unsigned port = sky2->port;
+ enum flow_control save_mode;
+ u16 ctrl;
+ u32 reg1;
+
+ /* Bring hardware out of reset */
+ sky2_write16(hw, B0_CTST, CS_RST_CLR);
+ sky2_write16(hw, SK_REG(port, GMAC_LINK_CTRL), GMLC_RST_CLR);
+
+ sky2_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_CLR);
+ sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_CLR);
+
+ /* Force to 10/100
+ * sky2_reset will re-enable on resume
+ */
+ save_mode = sky2->flow_mode;
+ ctrl = sky2->advertising;
+
+ sky2->advertising &= ~(ADVERTISED_1000baseT_Half|ADVERTISED_1000baseT_Full);
+ sky2->flow_mode = FC_NONE;
+ sky2_phy_power(hw, port, 1);
+ sky2_phy_reinit(sky2);
+
+ sky2->flow_mode = save_mode;
+ sky2->advertising = ctrl;
+
+ /* Set GMAC to no flow control and auto update for speed/duplex */
+ gma_write16(hw, port, GM_GP_CTRL,
+ GM_GPCR_FC_TX_DIS|GM_GPCR_TX_ENA|GM_GPCR_RX_ENA|
+ GM_GPCR_DUP_FULL|GM_GPCR_FC_RX_DIS|GM_GPCR_AU_FCT_DIS);
+
+ /* Set WOL address */
+ memcpy_toio(hw->regs + WOL_REGS(port, WOL_MAC_ADDR),
+ sky2->netdev->dev_addr, ETH_ALEN);
+
+ /* Turn on appropriate WOL control bits */
+ sky2_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), WOL_CTL_CLEAR_RESULT);
+ ctrl = 0;
+ if (sky2->wol & WAKE_PHY)
+ ctrl |= WOL_CTL_ENA_PME_ON_LINK_CHG|WOL_CTL_ENA_LINK_CHG_UNIT;
+ else
+ ctrl |= WOL_CTL_DIS_PME_ON_LINK_CHG|WOL_CTL_DIS_LINK_CHG_UNIT;
+
+ if (sky2->wol & WAKE_MAGIC)
+ ctrl |= WOL_CTL_ENA_PME_ON_MAGIC_PKT|WOL_CTL_ENA_MAGIC_PKT_UNIT;
+ else
+ ctrl |= WOL_CTL_DIS_PME_ON_MAGIC_PKT|WOL_CTL_DIS_MAGIC_PKT_UNIT;;
+
+ ctrl |= WOL_CTL_DIS_PME_ON_PATTERN|WOL_CTL_DIS_PATTERN_UNIT;
+ sky2_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), ctrl);
+
+ /* Turn on legacy PCI-Express PME mode */
+ sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
+ reg1 = sky2_pci_read32(hw, PCI_DEV_REG1);
+ reg1 |= PCI_Y2_PME_LEGACY;
+ sky2_pci_write32(hw, PCI_DEV_REG1, reg1);
+ sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+
+ /* block receiver */
+ sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET);
+
+}
+
static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
{
struct sky2_port *sky2 = netdev_priv(hw->dev[port]);
@@ -684,7 +737,7 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_CLR);
sky2_write16(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON);
- if (hw->chip_id == CHIP_ID_YUKON_EC_U) {
+ if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX) {
sky2_write8(hw, SK_REG(port, RX_GMF_LP_THR), 768/8);
sky2_write8(hw, SK_REG(port, RX_GMF_UP_THR), 1024/8);
if (hw->dev[port]->mtu > ETH_DATA_LEN) {
@@ -1467,6 +1520,9 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done)
if (unlikely(netif_msg_tx_done(sky2)))
printk(KERN_DEBUG "%s: tx done %u\n",
dev->name, idx);
+ sky2->net_stats.tx_packets++;
+ sky2->net_stats.tx_bytes += re->skb->len;
+
dev_kfree_skb_any(re->skb);
}
@@ -1641,7 +1697,9 @@ static void sky2_link_up(struct sky2_port *sky2)
sky2_write8(hw, SK_REG(port, LNK_LED_REG),
LINKLED_ON | LINKLED_BLINK_OFF | LINKLED_LINKSYNC_OFF);
- if (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U) {
+ if (hw->chip_id == CHIP_ID_YUKON_XL
+ || hw->chip_id == CHIP_ID_YUKON_EC_U
+ || hw->chip_id == CHIP_ID_YUKON_EX) {
u16 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
u16 led = PHY_M_LEDC_LOS_CTRL(1); /* link active */
@@ -1734,14 +1792,16 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux)
sky2->duplex = (aux & PHY_M_PS_FULL_DUP) ? DUPLEX_FULL : DUPLEX_HALF;
/* Pause bits are offset (9..8) */
- if (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)
+ if (hw->chip_id == CHIP_ID_YUKON_XL
+ || hw->chip_id == CHIP_ID_YUKON_EC_U
+ || hw->chip_id == CHIP_ID_YUKON_EX)
aux >>= 6;
sky2->flow_status = sky2_flow(aux & PHY_M_PS_RX_P_EN,
aux & PHY_M_PS_TX_P_EN);
if (sky2->duplex == DUPLEX_HALF && sky2->speed < SPEED_1000
- && hw->chip_id != CHIP_ID_YUKON_EC_U)
+ && !(hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX))
sky2->flow_status = FC_NONE;
if (aux & PHY_M_PS_RX_P_EN)
@@ -1794,48 +1854,37 @@ out:
}
-/* Transmit timeout is only called if we are running, carries is up
+/* Transmit timeout is only called if we are running, carrier is up
* and tx queue is full (stopped).
+ * Called with netif_tx_lock held.
*/
static void sky2_tx_timeout(struct net_device *dev)
{
struct sky2_port *sky2 = netdev_priv(dev);
struct sky2_hw *hw = sky2->hw;
- unsigned txq = txqaddr[sky2->port];
- u16 report, done;
+ u32 imask;
if (netif_msg_timer(sky2))
printk(KERN_ERR PFX "%s: tx timeout\n", dev->name);
- report = sky2_read16(hw, sky2->port == 0 ? STAT_TXA1_RIDX : STAT_TXA2_RIDX);
- done = sky2_read16(hw, Q_ADDR(txq, Q_DONE));
-
printk(KERN_DEBUG PFX "%s: transmit ring %u .. %u report=%u done=%u\n",
- dev->name,
- sky2->tx_cons, sky2->tx_prod, report, done);
+ dev->name, sky2->tx_cons, sky2->tx_prod,
+ sky2_read16(hw, sky2->port == 0 ? STAT_TXA1_RIDX : STAT_TXA2_RIDX),
+ sky2_read16(hw, Q_ADDR(txqaddr[sky2->port], Q_DONE)));
- if (report != done) {
- printk(KERN_INFO PFX "status burst pending (irq moderation?)\n");
-
- sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_STOP);
- sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START);
- } else if (report != sky2->tx_cons) {
- printk(KERN_INFO PFX "status report lost?\n");
+ imask = sky2_read32(hw, B0_IMSK); /* block IRQ in hw */
+ sky2_write32(hw, B0_IMSK, 0);
+ sky2_read32(hw, B0_IMSK);
- netif_tx_lock_bh(dev);
- sky2_tx_complete(sky2, report);
- netif_tx_unlock_bh(dev);
- } else {
- printk(KERN_INFO PFX "hardware hung? flushing\n");
+ netif_poll_disable(hw->dev[0]); /* stop NAPI poll */
+ synchronize_irq(hw->pdev->irq);
- sky2_write32(hw, Q_ADDR(txq, Q_CSR), BMU_STOP);
- sky2_write32(hw, Y2_QADDR(txq, PREF_UNIT_CTRL), PREF_UNIT_RST_SET);
+ netif_start_queue(dev); /* don't wakeup during flush */
+ sky2_tx_complete(sky2, sky2->tx_prod); /* Flush transmit queue */
- sky2_tx_clean(dev);
+ sky2_write32(hw, B0_IMSK, imask);
- sky2_qset(hw, txq);
- sky2_prefetch_init(hw, txq, sky2->tx_le_map, TX_RING_SIZE - 1);
- }
+ sky2_phy_reinit(sky2); /* this clears flow control etc */
}
static int sky2_change_mtu(struct net_device *dev, int new_mtu)
@@ -1849,8 +1898,9 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU)
return -EINVAL;
+ /* TSO on Yukon Ultra and MTU > 1500 not supported */
if (hw->chip_id == CHIP_ID_YUKON_EC_U && new_mtu > ETH_DATA_LEN)
- return -EINVAL;
+ dev->features &= ~NETIF_F_TSO;
if (!netif_running(dev)) {
dev->mtu = new_mtu;
@@ -2089,6 +2139,8 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
goto force_update;
skb->protocol = eth_type_trans(skb, dev);
+ sky2->net_stats.rx_packets++;
+ sky2->net_stats.rx_bytes += skb->len;
dev->last_rx = jiffies;
#ifdef SKY2_VLAN_TAG_USED
@@ -2218,8 +2270,8 @@ static void sky2_hw_intr(struct sky2_hw *hw)
pci_err = sky2_pci_read16(hw, PCI_STATUS);
if (net_ratelimit())
- printk(KERN_ERR PFX "%s: pci hw error (0x%x)\n",
- pci_name(hw->pdev), pci_err);
+ dev_err(&hw->pdev->dev, "PCI hardware error (0x%x)\n",
+ pci_err);
sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
sky2_pci_write16(hw, PCI_STATUS,
@@ -2234,8 +2286,8 @@ static void sky2_hw_intr(struct sky2_hw *hw)
pex_err = sky2_pci_read32(hw, PEX_UNC_ERR_STAT);
if (net_ratelimit())
- printk(KERN_ERR PFX "%s: pci express error (0x%x)\n",
- pci_name(hw->pdev), pex_err);
+ dev_err(&hw->pdev->dev, "PCI Express error (0x%x)\n",
+ pex_err);
/* clear the interrupt */
sky2_write32(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
@@ -2404,6 +2456,7 @@ static inline u32 sky2_mhz(const struct sky2_hw *hw)
switch (hw->chip_id) {
case CHIP_ID_YUKON_EC:
case CHIP_ID_YUKON_EC_U:
+ case CHIP_ID_YUKON_EX:
return 125; /* 125 Mhz */
case CHIP_ID_YUKON_FE:
return 100; /* 100 Mhz */
@@ -2423,34 +2476,62 @@ static inline u32 sky2_clk2us(const struct sky2_hw *hw, u32 clk)
}
-static int sky2_reset(struct sky2_hw *hw)
+static int __devinit sky2_init(struct sky2_hw *hw)
{
- u16 status;
u8 t8;
- int i;
sky2_write8(hw, B0_CTST, CS_RST_CLR);
hw->chip_id = sky2_read8(hw, B2_CHIP_ID);
if (hw->chip_id < CHIP_ID_YUKON_XL || hw->chip_id > CHIP_ID_YUKON_FE) {
- printk(KERN_ERR PFX "%s: unsupported chip type 0x%x\n",
- pci_name(hw->pdev), hw->chip_id);
+ dev_err(&hw->pdev->dev, "unsupported chip type 0x%x\n",
+ hw->chip_id);
return -EOPNOTSUPP;
}
+ if (hw->chip_id == CHIP_ID_YUKON_EX)
+ dev_warn(&hw->pdev->dev, "this driver not yet tested on this chip type\n"
+ "Please report success or failure to <netdev@vger.kernel.org>\n");
+
+ /* Make sure and enable all clocks */
+ if (hw->chip_id == CHIP_ID_YUKON_EX || hw->chip_id == CHIP_ID_YUKON_EC_U)
+ sky2_pci_write32(hw, PCI_DEV_REG3, 0);
+
hw->chip_rev = (sky2_read8(hw, B2_MAC_CFG) & CFG_CHIP_R_MSK) >> 4;
/* This rev is really old, and requires untested workarounds */
if (hw->chip_id == CHIP_ID_YUKON_EC && hw->chip_rev == CHIP_REV_YU_EC_A1) {
- printk(KERN_ERR PFX "%s: unsupported revision Yukon-%s (0x%x) rev %d\n",
- pci_name(hw->pdev), yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL],
- hw->chip_id, hw->chip_rev);
+ dev_err(&hw->pdev->dev, "unsupported revision Yukon-%s (0x%x) rev %d\n",
+ yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL],
+ hw->chip_id, hw->chip_rev);
return -EOPNOTSUPP;
}
+ hw->pmd_type = sky2_read8(hw, B2_PMD_TYP);
+ hw->ports = 1;
+ t8 = sky2_read8(hw, B2_Y2_HW_RES);
+ if ((t8 & CFG_DUAL_MAC_MSK) == CFG_DUAL_MAC_MSK) {
+ if (!(sky2_read8(hw, B2_Y2_CLK_GATE) & Y2_STATUS_LNK2_INAC))
+ ++hw->ports;
+ }
+
+ return 0;
+}
+
+static void sky2_reset(struct sky2_hw *hw)
+{
+ u16 status;
+ int i;
+
/* disable ASF */
if (hw->chip_id <= CHIP_ID_YUKON_EC) {
- sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET);
+ if (hw->chip_id == CHIP_ID_YUKON_EX) {
+ status = sky2_read16(hw, HCU_CCSR);
+ status &= ~(HCU_CCSR_AHB_RST | HCU_CCSR_CPU_RST_MODE |
+ HCU_CCSR_UC_STATE_MSK);
+ sky2_write16(hw, HCU_CCSR, status);
+ } else
+ sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET);
sky2_write16(hw, B0_CTST, Y2_ASF_DISABLE);
}
@@ -2472,15 +2553,7 @@ static int sky2_reset(struct sky2_hw *hw)
sky2_pci_write32(hw, PEX_UNC_ERR_STAT, 0xffffffffUL);
- hw->pmd_type = sky2_read8(hw, B2_PMD_TYP);
- hw->ports = 1;
- t8 = sky2_read8(hw, B2_Y2_HW_RES);
- if ((t8 & CFG_DUAL_MAC_MSK) == CFG_DUAL_MAC_MSK) {
- if (!(sky2_read8(hw, B2_Y2_CLK_GATE) & Y2_STATUS_LNK2_INAC))
- ++hw->ports;
- }
-
- sky2_set_power_state(hw, PCI_D0);
+ sky2_power_on(hw);
for (i = 0; i < hw->ports; i++) {
sky2_write8(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET);
@@ -2563,7 +2636,37 @@ static int sky2_reset(struct sky2_hw *hw)
sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START);
sky2_write8(hw, STAT_LEV_TIMER_CTRL, TIM_START);
sky2_write8(hw, STAT_ISR_TIMER_CTRL, TIM_START);
+}
+
+static inline u8 sky2_wol_supported(const struct sky2_hw *hw)
+{
+ return sky2_is_copper(hw) ? (WAKE_PHY | WAKE_MAGIC) : 0;
+}
+
+static void sky2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ const struct sky2_port *sky2 = netdev_priv(dev);
+
+ wol->supported = sky2_wol_supported(sky2->hw);
+ wol->wolopts = sky2->wol;
+}
+
+static int sky2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ struct sky2_port *sky2 = netdev_priv(dev);
+ struct sky2_hw *hw = sky2->hw;
+
+ if (wol->wolopts & ~sky2_wol_supported(sky2->hw))
+ return -EOPNOTSUPP;
+
+ sky2->wol = wol->wolopts;
+
+ if (hw->chip_id == CHIP_ID_YUKON_EC_U)
+ sky2_write32(hw, B0_CTST, sky2->wol
+ ? Y2_HW_WOL_ON : Y2_HW_WOL_OFF);
+ if (!netif_running(dev))
+ sky2_wol_init(sky2);
return 0;
}
@@ -2814,25 +2917,9 @@ static void sky2_get_strings(struct net_device *dev, u32 stringset, u8 * data)
}
}
-/* Use hardware MIB variables for critical path statistics and
- * transmit feedback not reported at interrupt.
- * Other errors are accounted for in interrupt handler.
- */
static struct net_device_stats *sky2_get_stats(struct net_device *dev)
{
struct sky2_port *sky2 = netdev_priv(dev);
- u64 data[13];
-
- sky2_phy_stats(sky2, data, ARRAY_SIZE(data));
-
- sky2->net_stats.tx_bytes = data[0];
- sky2->net_stats.rx_bytes = data[1];
- sky2->net_stats.tx_packets = data[2] + data[4] + data[6];
- sky2->net_stats.rx_packets = data[3] + data[5] + data[7];
- sky2->net_stats.multicast = data[3] + data[5];
- sky2->net_stats.collisions = data[10];
- sky2->net_stats.tx_aborted_errors = data[12];
-
return &sky2->net_stats;
}
@@ -3191,7 +3278,9 @@ static void sky2_get_regs(struct net_device *dev, struct ethtool_regs *regs,
static const struct ethtool_ops sky2_ethtool_ops = {
.get_settings = sky2_get_settings,
.set_settings = sky2_set_settings,
- .get_drvinfo = sky2_get_drvinfo,
+ .get_drvinfo = sky2_get_drvinfo,
+ .get_wol = sky2_get_wol,
+ .set_wol = sky2_set_wol,
.get_msglevel = sky2_get_msglevel,
.set_msglevel = sky2_set_msglevel,
.nway_reset = sky2_nway_reset,
@@ -3221,13 +3310,14 @@ static const struct ethtool_ops sky2_ethtool_ops = {
/* Initialize network device */
static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
- unsigned port, int highmem)
+ unsigned port,
+ int highmem, int wol)
{
struct sky2_port *sky2;
struct net_device *dev = alloc_etherdev(sizeof(*sky2));
if (!dev) {
- printk(KERN_ERR "sky2 etherdev alloc failed");
+ dev_err(&hw->pdev->dev, "etherdev alloc failed");
return NULL;
}
@@ -3269,6 +3359,7 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
sky2->speed = -1;
sky2->advertising = sky2_supported_modes(hw);
sky2->rx_csum = 1;
+ sky2->wol = wol;
spin_lock_init(&sky2->phy_lock);
sky2->tx_pending = TX_DEF_PENDING;
@@ -3278,11 +3369,9 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
sky2->port = port;
- if (hw->chip_id != CHIP_ID_YUKON_EC_U)
- dev->features |= NETIF_F_TSO;
+ dev->features |= NETIF_F_TSO | NETIF_F_IP_CSUM | NETIF_F_SG;
if (highmem)
dev->features |= NETIF_F_HIGHDMA;
- dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
#ifdef SKY2_VLAN_TAG_USED
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
@@ -3343,8 +3432,7 @@ static int __devinit sky2_test_msi(struct sky2_hw *hw)
err = request_irq(pdev->irq, sky2_test_intr, 0, DRV_NAME, hw);
if (err) {
- printk(KERN_ERR PFX "%s: cannot assign irq %d\n",
- pci_name(pdev), pdev->irq);
+ dev_err(&pdev->dev, "cannot assign irq %d\n", pdev->irq);
return err;
}
@@ -3355,9 +3443,8 @@ static int __devinit sky2_test_msi(struct sky2_hw *hw)
if (!hw->msi) {
/* MSI test failed, go back to INTx mode */
- printk(KERN_INFO PFX "%s: No interrupt generated using MSI, "
- "switching to INTx mode.\n",
- pci_name(pdev));
+ dev_info(&pdev->dev, "No interrupt generated using MSI, "
+ "switching to INTx mode.\n");
err = -EOPNOTSUPP;
sky2_write8(hw, B0_CTST, CS_CL_SW_IRQ);
@@ -3371,62 +3458,62 @@ static int __devinit sky2_test_msi(struct sky2_hw *hw)
return err;
}
+static int __devinit pci_wake_enabled(struct pci_dev *dev)
+{
+ int pm = pci_find_capability(dev, PCI_CAP_ID_PM);
+ u16 value;
+
+ if (!pm)
+ return 0;
+ if (pci_read_config_word(dev, pm + PCI_PM_CTRL, &value))
+ return 0;
+ return value & PCI_PM_CTRL_PME_ENABLE;
+}
+
static int __devinit sky2_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
- struct net_device *dev, *dev1 = NULL;
+ struct net_device *dev;
struct sky2_hw *hw;
- int err, pm_cap, using_dac = 0;
+ int err, using_dac = 0, wol_default;
err = pci_enable_device(pdev);
if (err) {
- printk(KERN_ERR PFX "%s cannot enable PCI device\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "cannot enable PCI device\n");
goto err_out;
}
err = pci_request_regions(pdev, DRV_NAME);
if (err) {
- printk(KERN_ERR PFX "%s cannot obtain PCI resources\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "cannot obtain PCI resources\n");
goto err_out;
}
pci_set_master(pdev);
- /* Find power-management capability. */
- pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
- if (pm_cap == 0) {
- printk(KERN_ERR PFX "Cannot find PowerManagement capability, "
- "aborting.\n");
- err = -EIO;
- goto err_out_free_regions;
- }
-
if (sizeof(dma_addr_t) > sizeof(u32) &&
!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK))) {
using_dac = 1;
err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
if (err < 0) {
- printk(KERN_ERR PFX "%s unable to obtain 64 bit DMA "
- "for consistent allocations\n", pci_name(pdev));
+ dev_err(&pdev->dev, "unable to obtain 64 bit DMA "
+ "for consistent allocations\n");
goto err_out_free_regions;
}
-
} else {
err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
if (err) {
- printk(KERN_ERR PFX "%s no usable DMA configuration\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "no usable DMA configuration\n");
goto err_out_free_regions;
}
}
+ wol_default = pci_wake_enabled(pdev) ? WAKE_MAGIC : 0;
+
err = -ENOMEM;
hw = kzalloc(sizeof(*hw), GFP_KERNEL);
if (!hw) {
- printk(KERN_ERR PFX "%s: cannot allocate hardware struct\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "cannot allocate hardware struct\n");
goto err_out_free_regions;
}
@@ -3434,11 +3521,9 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
hw->regs = ioremap_nocache(pci_resource_start(pdev, 0), 0x4000);
if (!hw->regs) {
- printk(KERN_ERR PFX "%s: cannot map device registers\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "cannot map device registers\n");
goto err_out_free_hw;
}
- hw->pm_cap = pm_cap;
#ifdef __BIG_ENDIAN
/* The sk98lin vendor driver uses hardware byte swapping but
@@ -3458,18 +3543,22 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
if (!hw->st_le)
goto err_out_iounmap;
- err = sky2_reset(hw);
+ err = sky2_init(hw);
if (err)
goto err_out_iounmap;
- printk(KERN_INFO PFX "v%s addr 0x%llx irq %d Yukon-%s (0x%x) rev %d\n",
+ dev_info(&pdev->dev, "v%s addr 0x%llx irq %d Yukon-%s (0x%x) rev %d\n",
DRV_VERSION, (unsigned long long)pci_resource_start(pdev, 0),
pdev->irq, yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL],
hw->chip_id, hw->chip_rev);
- dev = sky2_init_netdev(hw, 0, using_dac);
- if (!dev)
+ sky2_reset(hw);
+
+ dev = sky2_init_netdev(hw, 0, using_dac, wol_default);
+ if (!dev) {
+ err = -ENOMEM;
goto err_out_free_pci;
+ }
if (!disable_msi && pci_enable_msi(pdev) == 0) {
err = sky2_test_msi(hw);
@@ -3481,32 +3570,33 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
err = register_netdev(dev);
if (err) {
- printk(KERN_ERR PFX "%s: cannot register net device\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "cannot register net device\n");
goto err_out_free_netdev;
}
err = request_irq(pdev->irq, sky2_intr, hw->msi ? 0 : IRQF_SHARED,
dev->name, hw);
if (err) {
- printk(KERN_ERR PFX "%s: cannot assign irq %d\n",
- pci_name(pdev), pdev->irq);
+ dev_err(&pdev->dev, "cannot assign irq %d\n", pdev->irq);
goto err_out_unregister;
}
sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
sky2_show_addr(dev);
- if (hw->ports > 1 && (dev1 = sky2_init_netdev(hw, 1, using_dac))) {
- if (register_netdev(dev1) == 0)
- sky2_show_addr(dev1);
- else {
- /* Failure to register second port need not be fatal */
- printk(KERN_WARNING PFX
- "register of second port failed\n");
+ if (hw->ports > 1) {
+ struct net_device *dev1;
+
+ dev1 = sky2_init_netdev(hw, 1, using_dac, wol_default);
+ if (!dev1)
+ dev_warn(&pdev->dev, "allocation for second device failed\n");
+ else if ((err = register_netdev(dev1))) {
+ dev_warn(&pdev->dev,
+ "register of second port failed (%d)\n", err);
hw->dev[1] = NULL;
free_netdev(dev1);
- }
+ } else
+ sky2_show_addr(dev1);
}
setup_timer(&hw->idle_timer, sky2_idle, (unsigned long) hw);
@@ -3555,7 +3645,8 @@ static void __devexit sky2_remove(struct pci_dev *pdev)
unregister_netdev(dev1);
unregister_netdev(dev0);
- sky2_set_power_state(hw, PCI_D3hot);
+ sky2_power_aux(hw);
+
sky2_write16(hw, B0_Y2LED, LED_STAT_OFF);
sky2_write8(hw, B0_CTST, CS_RST_SET);
sky2_read8(hw, B0_CTST);
@@ -3580,27 +3671,31 @@ static void __devexit sky2_remove(struct pci_dev *pdev)
static int sky2_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct sky2_hw *hw = pci_get_drvdata(pdev);
- int i;
- pci_power_t pstate = pci_choose_state(pdev, state);
-
- if (!(pstate == PCI_D3hot || pstate == PCI_D3cold))
- return -EINVAL;
+ int i, wol = 0;
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];
+ struct sky2_port *sky2 = netdev_priv(dev);
- if (netif_running(dev)) {
+ if (netif_running(dev))
sky2_down(dev);
- netif_device_detach(dev);
- }
+
+ if (sky2->wol)
+ sky2_wol_init(sky2);
+
+ wol |= sky2->wol;
}
sky2_write32(hw, B0_IMSK, 0);
+ sky2_power_aux(hw);
+
pci_save_state(pdev);
- sky2_set_power_state(hw, pstate);
+ pci_enable_wake(pdev, pci_choose_state(pdev, state), wol);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
return 0;
}
@@ -3609,21 +3704,22 @@ static int sky2_resume(struct pci_dev *pdev)
struct sky2_hw *hw = pci_get_drvdata(pdev);
int i, err;
- pci_restore_state(pdev);
- pci_enable_wake(pdev, PCI_D0, 0);
- sky2_set_power_state(hw, PCI_D0);
+ err = pci_set_power_state(pdev, PCI_D0);
+ if (err)
+ goto out;
- err = sky2_reset(hw);
+ err = pci_restore_state(pdev);
if (err)
goto out;
+ pci_enable_wake(pdev, PCI_D0, 0);
+ sky2_reset(hw);
+
sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
for (i = 0; i < hw->ports; i++) {
struct net_device *dev = hw->dev[i];
if (netif_running(dev)) {
- netif_device_attach(dev);
-
err = sky2_up(dev);
if (err) {
printk(KERN_ERR PFX "%s: could not up: %d\n",
@@ -3636,11 +3732,43 @@ static int sky2_resume(struct pci_dev *pdev)
netif_poll_enable(hw->dev[0]);
sky2_idle_start(hw);
+ return 0;
out:
+ dev_err(&pdev->dev, "resume failed (%d)\n", err);
+ pci_disable_device(pdev);
return err;
}
#endif
+static void sky2_shutdown(struct pci_dev *pdev)
+{
+ struct sky2_hw *hw = pci_get_drvdata(pdev);
+ int i, wol = 0;
+
+ 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];
+ struct sky2_port *sky2 = netdev_priv(dev);
+
+ if (sky2->wol) {
+ wol = 1;
+ sky2_wol_init(sky2);
+ }
+ }
+
+ if (wol)
+ sky2_power_aux(hw);
+
+ pci_enable_wake(pdev, PCI_D3hot, wol);
+ pci_enable_wake(pdev, PCI_D3cold, wol);
+
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, PCI_D3hot);
+
+}
+
static struct pci_driver sky2_driver = {
.name = DRV_NAME,
.id_table = sky2_id_table,
@@ -3650,6 +3778,7 @@ static struct pci_driver sky2_driver = {
.suspend = sky2_suspend,
.resume = sky2_resume,
#endif
+ .shutdown = sky2_shutdown,
};
static int __init sky2_init_module(void)
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index 6ed1d47dbbd..3b0189569d5 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -32,6 +32,7 @@ enum pci_dev_reg_1 {
PCI_Y2_PHY1_COMA = 1<<28, /* Set PHY 1 to Coma Mode (YUKON-2) */
PCI_Y2_PHY2_POWD = 1<<27, /* Set PHY 2 to Power Down (YUKON-2) */
PCI_Y2_PHY1_POWD = 1<<26, /* Set PHY 1 to Power Down (YUKON-2) */
+ PCI_Y2_PME_LEGACY= 1<<15, /* PCI Express legacy power management mode */
};
enum pci_dev_reg_2 {
@@ -370,12 +371,9 @@ enum {
/* B2_CHIP_ID 8 bit Chip Identification Number */
enum {
- CHIP_ID_GENESIS = 0x0a, /* Chip ID for GENESIS */
- CHIP_ID_YUKON = 0xb0, /* Chip ID for YUKON */
- CHIP_ID_YUKON_LITE = 0xb1, /* Chip ID for YUKON-Lite (Rev. A1-A3) */
- CHIP_ID_YUKON_LP = 0xb2, /* Chip ID for YUKON-LP */
CHIP_ID_YUKON_XL = 0xb3, /* Chip ID for YUKON-2 XL */
CHIP_ID_YUKON_EC_U = 0xb4, /* Chip ID for YUKON-2 EC Ultra */
+ CHIP_ID_YUKON_EX = 0xb5, /* Chip ID for YUKON-2 Extreme */
CHIP_ID_YUKON_EC = 0xb6, /* Chip ID for YUKON-2 EC */
CHIP_ID_YUKON_FE = 0xb7, /* Chip ID for YUKON-2 FE */
@@ -767,6 +765,24 @@ enum {
POLL_LIST_ADDR_HI= 0x0e2c,/* 32 bit Poll. List Start Addr (high) */
};
+enum {
+ SMB_CFG = 0x0e40, /* 32 bit SMBus Config Register */
+ SMB_CSR = 0x0e44, /* 32 bit SMBus Control/Status Register */
+};
+
+enum {
+ CPU_WDOG = 0x0e48, /* 32 bit Watchdog Register */
+ CPU_CNTR = 0x0e4C, /* 32 bit Counter Register */
+ CPU_TIM = 0x0e50,/* 32 bit Timer Compare Register */
+ CPU_AHB_ADDR = 0x0e54, /* 32 bit CPU AHB Debug Register */
+ CPU_AHB_WDATA = 0x0e58, /* 32 bit CPU AHB Debug Register */
+ CPU_AHB_RDATA = 0x0e5C, /* 32 bit CPU AHB Debug Register */
+ HCU_MAP_BASE = 0x0e60, /* 32 bit Reset Mapping Base */
+ CPU_AHB_CTRL = 0x0e64, /* 32 bit CPU AHB Debug Register */
+ HCU_CCSR = 0x0e68, /* 32 bit CPU Control and Status Register */
+ HCU_HCSR = 0x0e6C, /* 32 bit Host Control and Status Register */
+};
+
/* ASF Subsystem Registers (Yukon-2 only) */
enum {
B28_Y2_SMB_CONFIG = 0x0e40,/* 32 bit ASF SMBus Config Register */
@@ -837,33 +853,27 @@ enum {
GMAC_LINK_CTRL = 0x0f10,/* 16 bit Link Control Reg */
/* Wake-up Frame Pattern Match Control Registers (YUKON only) */
-
- WOL_REG_OFFS = 0x20,/* HW-Bug: Address is + 0x20 against spec. */
-
WOL_CTRL_STAT = 0x0f20,/* 16 bit WOL Control/Status Reg */
WOL_MATCH_CTL = 0x0f22,/* 8 bit WOL Match Control Reg */
WOL_MATCH_RES = 0x0f23,/* 8 bit WOL Match Result Reg */
WOL_MAC_ADDR = 0x0f24,/* 32 bit WOL MAC Address */
- WOL_PATT_PME = 0x0f2a,/* 8 bit WOL PME Match Enable (Yukon-2) */
- WOL_PATT_ASFM = 0x0f2b,/* 8 bit WOL ASF Match Enable (Yukon-2) */
WOL_PATT_RPTR = 0x0f2c,/* 8 bit WOL Pattern Read Pointer */
/* WOL Pattern Length Registers (YUKON only) */
-
WOL_PATT_LEN_LO = 0x0f30,/* 32 bit WOL Pattern Length 3..0 */
WOL_PATT_LEN_HI = 0x0f34,/* 24 bit WOL Pattern Length 6..4 */
/* WOL Pattern Counter Registers (YUKON only) */
-
-
WOL_PATT_CNT_0 = 0x0f38,/* 32 bit WOL Pattern Counter 3..0 */
WOL_PATT_CNT_4 = 0x0f3c,/* 24 bit WOL Pattern Counter 6..4 */
};
+#define WOL_REGS(port, x) (x + (port)*0x80)
enum {
WOL_PATT_RAM_1 = 0x1000,/* WOL Pattern RAM Link 1 */
WOL_PATT_RAM_2 = 0x1400,/* WOL Pattern RAM Link 2 */
};
+#define WOL_PATT_RAM_BASE(port) (WOL_PATT_RAM_1 + (port)*0x400)
enum {
BASE_GMAC_1 = 0x2800,/* GMAC 1 registers */
@@ -1654,6 +1664,39 @@ enum {
Y2_ASF_CLR_ASFI = 1<<1, /* Clear host IRQ */
Y2_ASF_HOST_IRQ = 1<<0, /* Issue an IRQ to HOST system */
};
+/* HCU_CCSR CPU Control and Status Register */
+enum {
+ HCU_CCSR_SMBALERT_MONITOR= 1<<27, /* SMBALERT pin monitor */
+ HCU_CCSR_CPU_SLEEP = 1<<26, /* CPU sleep status */
+ /* Clock Stretching Timeout */
+ HCU_CCSR_CS_TO = 1<<25,
+ HCU_CCSR_WDOG = 1<<24, /* Watchdog Reset */
+
+ HCU_CCSR_CLR_IRQ_HOST = 1<<17, /* Clear IRQ_HOST */
+ HCU_CCSR_SET_IRQ_HCU = 1<<16, /* Set IRQ_HCU */
+
+ HCU_CCSR_AHB_RST = 1<<9, /* Reset AHB bridge */
+ HCU_CCSR_CPU_RST_MODE = 1<<8, /* CPU Reset Mode */
+
+ HCU_CCSR_SET_SYNC_CPU = 1<<5,
+ HCU_CCSR_CPU_CLK_DIVIDE_MSK = 3<<3,/* CPU Clock Divide */
+ HCU_CCSR_CPU_CLK_DIVIDE_BASE= 1<<3,
+ HCU_CCSR_OS_PRSNT = 1<<2, /* ASF OS Present */
+/* Microcontroller State */
+ HCU_CCSR_UC_STATE_MSK = 3,
+ HCU_CCSR_UC_STATE_BASE = 1<<0,
+ HCU_CCSR_ASF_RESET = 0,
+ HCU_CCSR_ASF_HALTED = 1<<1,
+ HCU_CCSR_ASF_RUNNING = 1<<0,
+};
+
+/* HCU_HCSR Host Control and Status Register */
+enum {
+ HCU_HCSR_SET_IRQ_CPU = 1<<16, /* Set IRQ_CPU */
+
+ HCU_HCSR_CLR_IRQ_HCU = 1<<1, /* Clear IRQ_HCU */
+ HCU_HCSR_SET_IRQ_HOST = 1<<0, /* Set IRQ_HOST */
+};
/* STAT_CTRL 32 bit Status BMU control register (Yukon-2 only) */
enum {
@@ -1715,14 +1758,17 @@ enum {
GM_IS_RX_COMPL = 1<<0, /* Frame Reception Complete */
#define GMAC_DEF_MSK GM_IS_TX_FF_UR
+};
/* GMAC_LINK_CTRL 16 bit GMAC Link Control Reg (YUKON only) */
- /* Bits 15.. 2: reserved */
+enum { /* Bits 15.. 2: reserved */
GMLC_RST_CLR = 1<<1, /* Clear GMAC Link Reset */
GMLC_RST_SET = 1<<0, /* Set GMAC Link Reset */
+};
/* WOL_CTRL_STAT 16 bit WOL Control/Status Reg */
+enum {
WOL_CTL_LINK_CHG_OCC = 1<<15,
WOL_CTL_MAGIC_PKT_OCC = 1<<14,
WOL_CTL_PATTERN_OCC = 1<<13,
@@ -1741,17 +1787,6 @@ enum {
WOL_CTL_DIS_PATTERN_UNIT = 1<<0,
};
-#define WOL_CTL_DEFAULT \
- (WOL_CTL_DIS_PME_ON_LINK_CHG | \
- WOL_CTL_DIS_PME_ON_PATTERN | \
- WOL_CTL_DIS_PME_ON_MAGIC_PKT | \
- WOL_CTL_DIS_LINK_CHG_UNIT | \
- WOL_CTL_DIS_PATTERN_UNIT | \
- WOL_CTL_DIS_MAGIC_PKT_UNIT)
-
-/* WOL_MATCH_CTL 8 bit WOL Match Control Reg */
-#define WOL_CTL_PATT_ENA(x) (1 << (x))
-
/* Control flags */
enum {
@@ -1875,6 +1910,7 @@ struct sky2_port {
u8 autoneg; /* AUTONEG_ENABLE, AUTONEG_DISABLE */
u8 duplex; /* DUPLEX_HALF, DUPLEX_FULL */
u8 rx_csum;
+ u8 wol;
enum flow_control flow_mode;
enum flow_control flow_status;
@@ -1887,7 +1923,6 @@ struct sky2_hw {
struct pci_dev *pdev;
struct net_device *dev[2];
- int pm_cap;
u8 chip_id;
u8 chip_rev;
u8 pmd_type;
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index a0806d262fc..2f4b1de7a2b 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -1343,15 +1343,12 @@ static int __init slip_init(void)
printk(KERN_INFO "SLIP linefill/keepalive option.\n");
#endif
- slip_devs = kmalloc(sizeof(struct net_device *)*slip_maxdev, GFP_KERNEL);
+ slip_devs = kzalloc(sizeof(struct net_device *)*slip_maxdev, GFP_KERNEL);
if (!slip_devs) {
printk(KERN_ERR "SLIP: Can't allocate slip devices array! Uaargh! (-> No SLIP available)\n");
return -ENOMEM;
}
- /* Clear the pointer array, we allocate devices when we need them */
- memset(slip_devs, 0, sizeof(struct net_device *)*slip_maxdev);
-
/* Fill in our line protocol discipline, and register it */
if ((status = tty_register_ldisc(N_SLIP, &sl_ldisc)) != 0) {
printk(KERN_ERR "SLIP: can't register line discipline (err = %d)\n", status);
diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c
index 7122932eac9..ae1ae343bee 100644
--- a/drivers/net/smc-mca.c
+++ b/drivers/net/smc-mca.c
@@ -482,8 +482,7 @@ static void ultramca_block_input(struct net_device *dev, int count, struct sk_bu
count -= semi_count;
memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count);
} else {
- /* Packet is in one chunk -- we can copy + cksum. */
- eth_io_copy_and_sum(skb, xfer_start, count, 0);
+ memcpy_fromio(skb->data, xfer_start, count);
}
}
diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c
index d70bc979534..a52b22d7db6 100644
--- a/drivers/net/smc-ultra.c
+++ b/drivers/net/smc-ultra.c
@@ -454,8 +454,7 @@ ultra_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ri
count -= semi_count;
memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count);
} else {
- /* Packet is in one chunk -- we can copy + cksum. */
- eth_io_copy_and_sum(skb, xfer_start, count, 0);
+ memcpy_fromio(skb->data, xfer_start, count);
}
outb(0x00, dev->base_addr - ULTRA_NIC_OFFSET); /* Disable memory. */
diff --git a/drivers/net/smc-ultra32.c b/drivers/net/smc-ultra32.c
index 2c5319c62fa..88a30e56c64 100644
--- a/drivers/net/smc-ultra32.c
+++ b/drivers/net/smc-ultra32.c
@@ -395,8 +395,7 @@ static void ultra32_block_input(struct net_device *dev,
memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count);
}
} else {
- /* Packet is in one chunk -- we can copy + cksum. */
- eth_io_copy_and_sum(skb, xfer_start, count, 0);
+ memcpy_fromio(skb->data, xfer_start, count);
}
}
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index 43af6143844..c9561413198 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -1659,7 +1659,7 @@ smc911x_ethtool_getdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
strncpy(info->driver, CARDNAME, sizeof(info->driver));
strncpy(info->version, version, sizeof(info->version));
- strncpy(info->bus_info, dev->class_dev.dev->bus_id, sizeof(info->bus_info));
+ strncpy(info->bus_info, dev->dev.parent->bus_id, sizeof(info->bus_info));
}
static int smc911x_ethtool_nwayreset(struct net_device *dev)
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
index e62a9586fb9..49f4b7712eb 100644
--- a/drivers/net/smc91x.c
+++ b/drivers/net/smc91x.c
@@ -1712,7 +1712,7 @@ smc_ethtool_getdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
strncpy(info->driver, CARDNAME, sizeof(info->driver));
strncpy(info->version, version, sizeof(info->version));
- strncpy(info->bus_info, dev->class_dev.dev->bus_id, sizeof(info->bus_info));
+ strncpy(info->bus_info, dev->dev.parent->bus_id, sizeof(info->bus_info));
}
static int smc_ethtool_nwayreset(struct net_device *dev)
diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c
index 8ea2fc1b96c..64ed8ff5b03 100644
--- a/drivers/net/spider_net.c
+++ b/drivers/net/spider_net.c
@@ -280,72 +280,67 @@ spider_net_free_chain(struct spider_net_card *card,
{
struct spider_net_descr *descr;
- for (descr = chain->tail; !descr->bus_addr; descr = descr->next) {
- pci_unmap_single(card->pdev, descr->bus_addr,
- SPIDER_NET_DESCR_SIZE, PCI_DMA_BIDIRECTIONAL);
+ descr = chain->ring;
+ do {
descr->bus_addr = 0;
- }
+ descr->next_descr_addr = 0;
+ descr = descr->next;
+ } while (descr != chain->ring);
+
+ dma_free_coherent(&card->pdev->dev, chain->num_desc,
+ chain->ring, chain->dma_addr);
}
/**
- * spider_net_init_chain - links descriptor chain
+ * spider_net_init_chain - alloc and link descriptor chain
* @card: card structure
* @chain: address of chain
- * @start_descr: address of descriptor array
- * @no: number of descriptors
*
- * we manage a circular list that mirrors the hardware structure,
+ * We manage a circular list that mirrors the hardware structure,
* except that the hardware uses bus addresses.
*
- * returns 0 on success, <0 on failure
+ * Returns 0 on success, <0 on failure
*/
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_chain *chain)
{
int i;
struct spider_net_descr *descr;
dma_addr_t buf;
+ size_t alloc_size;
- descr = start_descr;
- memset(descr, 0, sizeof(*descr) * no);
+ alloc_size = chain->num_desc * sizeof (struct spider_net_descr);
- /* set up the hardware pointers in each descriptor */
- for (i=0; i<no; i++, descr++) {
- descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
+ chain->ring = dma_alloc_coherent(&card->pdev->dev, alloc_size,
+ &chain->dma_addr, GFP_KERNEL);
+
+ if (!chain->ring)
+ return -ENOMEM;
- buf = pci_map_single(card->pdev, descr,
- SPIDER_NET_DESCR_SIZE,
- PCI_DMA_BIDIRECTIONAL);
+ descr = chain->ring;
+ memset(descr, 0, alloc_size);
- if (pci_dma_mapping_error(buf))
- goto iommu_error;
+ /* Set up the hardware pointers in each descriptor */
+ buf = chain->dma_addr;
+ for (i=0; i < chain->num_desc; i++, descr++) {
+ descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
descr->bus_addr = buf;
+ descr->next_descr_addr = 0;
descr->next = descr + 1;
descr->prev = descr - 1;
+ buf += sizeof(struct spider_net_descr);
}
/* do actual circular list */
- (descr-1)->next = start_descr;
- start_descr->prev = descr-1;
+ (descr-1)->next = chain->ring;
+ chain->ring->prev = descr-1;
spin_lock_init(&chain->lock);
- chain->head = start_descr;
- chain->tail = start_descr;
-
+ chain->head = chain->ring;
+ chain->tail = chain->ring;
return 0;
-
-iommu_error:
- descr = start_descr;
- for (i=0; i < no; i++, descr++)
- if (descr->bus_addr)
- pci_unmap_single(card->pdev, descr->bus_addr,
- SPIDER_NET_DESCR_SIZE,
- PCI_DMA_BIDIRECTIONAL);
- return -ENOMEM;
}
/**
@@ -372,21 +367,20 @@ spider_net_free_rx_chain_contents(struct spider_net_card *card)
}
/**
- * spider_net_prepare_rx_descr - reinitializes a rx descriptor
+ * spider_net_prepare_rx_descr - Reinitialize RX descriptor
* @card: card structure
* @descr: descriptor to re-init
*
- * return 0 on succes, <0 on failure
+ * Return 0 on succes, <0 on failure.
*
- * allocates a new rx skb, iommu-maps it and attaches it to the descriptor.
- * Activate the descriptor state-wise
+ * Allocates a new rx skb, iommu-maps it and attaches it to the
+ * descriptor. Mark the descriptor as activated, ready-to-use.
*/
static int
spider_net_prepare_rx_descr(struct spider_net_card *card,
struct spider_net_descr *descr)
{
dma_addr_t buf;
- int error = 0;
int offset;
int bufsize;
@@ -414,7 +408,7 @@ spider_net_prepare_rx_descr(struct spider_net_card *card,
(SPIDER_NET_RXBUF_ALIGN - 1);
if (offset)
skb_reserve(descr->skb, SPIDER_NET_RXBUF_ALIGN - offset);
- /* io-mmu-map the skb */
+ /* iommu-map the skb */
buf = pci_map_single(card->pdev, descr->skb->data,
SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE);
descr->buf_addr = buf;
@@ -425,11 +419,16 @@ spider_net_prepare_rx_descr(struct spider_net_card *card,
card->spider_stats.rx_iommu_map_error++;
descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
} else {
+ descr->next_descr_addr = 0;
+ wmb();
descr->dmac_cmd_status = SPIDER_NET_DESCR_CARDOWNED |
SPIDER_NET_DMAC_NOINTR_COMPLETE;
+
+ wmb();
+ descr->prev->next_descr_addr = descr->bus_addr;
}
- return error;
+ return 0;
}
/**
@@ -493,10 +492,10 @@ spider_net_refill_rx_chain(struct spider_net_card *card)
}
/**
- * spider_net_alloc_rx_skbs - allocates rx skbs in rx descriptor chains
+ * spider_net_alloc_rx_skbs - Allocates rx skbs in rx descriptor chains
* @card: card structure
*
- * returns 0 on success, <0 on failure
+ * Returns 0 on success, <0 on failure.
*/
static int
spider_net_alloc_rx_skbs(struct spider_net_card *card)
@@ -507,16 +506,16 @@ spider_net_alloc_rx_skbs(struct spider_net_card *card)
result = -ENOMEM;
chain = &card->rx_chain;
- /* put at least one buffer into the chain. if this fails,
- * we've got a problem. if not, spider_net_refill_rx_chain
- * will do the rest at the end of this function */
+ /* Put at least one buffer into the chain. if this fails,
+ * we've got a problem. If not, spider_net_refill_rx_chain
+ * will do the rest at the end of this function. */
if (spider_net_prepare_rx_descr(card, chain->head))
goto error;
else
chain->head = chain->head->next;
- /* this will allocate the rest of the rx buffers; if not, it's
- * business as usual later on */
+ /* This will allocate the rest of the rx buffers;
+ * if not, it's business as usual later on. */
spider_net_refill_rx_chain(card);
spider_net_enable_rxdmac(card);
return 0;
@@ -707,7 +706,7 @@ spider_net_set_low_watermark(struct spider_net_card *card)
}
/* If TX queue is short, don't even bother with interrupts */
- if (cnt < card->num_tx_desc/4)
+ if (cnt < card->tx_chain.num_desc/4)
return cnt;
/* Set low-watermark 3/4th's of the way into the queue. */
@@ -915,16 +914,13 @@ spider_net_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
* spider_net_pass_skb_up - takes an skb from a descriptor and passes it on
* @descr: descriptor to process
* @card: card structure
- * @napi: whether caller is in NAPI context
- *
- * returns 1 on success, 0 if no packet was passed to the stack
*
- * iommu-unmaps the skb, fills out skb structure and passes the data to the
- * stack. The descriptor state is not changed.
+ * Fills out skb structure and passes the data to the stack.
+ * The descriptor state is not changed.
*/
-static int
+static void
spider_net_pass_skb_up(struct spider_net_descr *descr,
- struct spider_net_card *card, int napi)
+ struct spider_net_card *card)
{
struct sk_buff *skb;
struct net_device *netdev;
@@ -932,23 +928,8 @@ spider_net_pass_skb_up(struct spider_net_descr *descr,
data_status = descr->data_status;
data_error = descr->data_error;
-
netdev = card->netdev;
- /* unmap descriptor */
- pci_unmap_single(card->pdev, descr->buf_addr, SPIDER_NET_MAX_FRAME,
- PCI_DMA_FROMDEVICE);
-
- /* the cases we'll throw away the packet immediately */
- if (data_error & SPIDER_NET_DESTROY_RX_FLAGS) {
- if (netif_msg_rx_err(card))
- pr_err("error in received descriptor found, "
- "data_status=x%08x, data_error=x%08x\n",
- data_status, data_error);
- card->spider_stats.rx_desc_error++;
- return 0;
- }
-
skb = descr->skb;
skb->dev = netdev;
skb_put(skb, descr->valid_size);
@@ -977,57 +958,72 @@ spider_net_pass_skb_up(struct spider_net_descr *descr,
}
/* pass skb up to stack */
- if (napi)
- netif_receive_skb(skb);
- else
- netif_rx_ni(skb);
+ netif_receive_skb(skb);
/* update netdevice statistics */
card->netdev_stats.rx_packets++;
card->netdev_stats.rx_bytes += skb->len;
+}
- return 1;
+#ifdef DEBUG
+static void show_rx_chain(struct spider_net_card *card)
+{
+ struct spider_net_descr_chain *chain = &card->rx_chain;
+ struct spider_net_descr *start= chain->tail;
+ struct spider_net_descr *descr= start;
+ int status;
+
+ int cnt = 0;
+ int cstat = spider_net_get_descr_status(descr);
+ printk(KERN_INFO "RX chain tail at descr=%ld\n",
+ (start - card->descr) - card->tx_chain.num_desc);
+ status = cstat;
+ do
+ {
+ status = spider_net_get_descr_status(descr);
+ if (cstat != status) {
+ printk(KERN_INFO "Have %d descrs with stat=x%08x\n", cnt, cstat);
+ cstat = status;
+ cnt = 0;
+ }
+ cnt ++;
+ descr = descr->next;
+ } while (descr != start);
+ printk(KERN_INFO "Last %d descrs with stat=x%08x\n", cnt, cstat);
}
+#endif
/**
* spider_net_decode_one_descr - processes an rx descriptor
* @card: card structure
- * @napi: whether caller is in NAPI context
*
- * returns 1 if a packet has been sent to the stack, otherwise 0
+ * Returns 1 if a packet has been sent to the stack, otherwise 0
*
- * processes an rx descriptor by iommu-unmapping the data buffer and passing
+ * Processes an rx descriptor by iommu-unmapping the data buffer and passing
* the packet up to the stack. This function is called in softirq
* context, e.g. either bottom half from interrupt or NAPI polling context
*/
static int
-spider_net_decode_one_descr(struct spider_net_card *card, int napi)
+spider_net_decode_one_descr(struct spider_net_card *card)
{
struct spider_net_descr_chain *chain = &card->rx_chain;
struct spider_net_descr *descr = chain->tail;
int status;
- int result;
status = spider_net_get_descr_status(descr);
- if (status == SPIDER_NET_DESCR_CARDOWNED) {
- /* nothing in the descriptor yet */
- result=0;
- goto out;
- }
-
- if (status == SPIDER_NET_DESCR_NOT_IN_USE) {
- /* not initialized yet, the ring must be empty */
- spider_net_refill_rx_chain(card);
- spider_net_enable_rxdmac(card);
- result=0;
- goto out;
- }
+ /* Nothing in the descriptor, or ring must be empty */
+ if ((status == SPIDER_NET_DESCR_CARDOWNED) ||
+ (status == SPIDER_NET_DESCR_NOT_IN_USE))
+ return 0;
/* descriptor definitively used -- move on tail */
chain->tail = descr->next;
- result = 0;
+ /* unmap descriptor */
+ pci_unmap_single(card->pdev, descr->buf_addr,
+ SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE);
+
if ( (status == SPIDER_NET_DESCR_RESPONSE_ERROR) ||
(status == SPIDER_NET_DESCR_PROTECTION_ERROR) ||
(status == SPIDER_NET_DESCR_FORCE_END) ) {
@@ -1035,31 +1031,55 @@ spider_net_decode_one_descr(struct spider_net_card *card, int napi)
pr_err("%s: dropping RX descriptor with state %d\n",
card->netdev->name, status);
card->netdev_stats.rx_dropped++;
- pci_unmap_single(card->pdev, descr->buf_addr,
- SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE);
- dev_kfree_skb_irq(descr->skb);
- goto refill;
+ goto bad_desc;
}
if ( (status != SPIDER_NET_DESCR_COMPLETE) &&
(status != SPIDER_NET_DESCR_FRAME_END) ) {
- if (netif_msg_rx_err(card)) {
- pr_err("%s: RX descriptor with state %d\n",
+ if (netif_msg_rx_err(card))
+ pr_err("%s: RX descriptor with unkown state %d\n",
card->netdev->name, status);
- card->spider_stats.rx_desc_unk_state++;
- }
- goto refill;
+ card->spider_stats.rx_desc_unk_state++;
+ goto bad_desc;
}
- /* ok, we've got a packet in descr */
- result = spider_net_pass_skb_up(descr, card, napi);
-refill:
+ /* The cases we'll throw away the packet immediately */
+ if (descr->data_error & SPIDER_NET_DESTROY_RX_FLAGS) {
+ if (netif_msg_rx_err(card))
+ pr_err("%s: error in received descriptor found, "
+ "data_status=x%08x, data_error=x%08x\n",
+ card->netdev->name,
+ descr->data_status, descr->data_error);
+ goto bad_desc;
+ }
+
+ if (descr->dmac_cmd_status & 0xfefe) {
+ pr_err("%s: bad status, cmd_status=x%08x\n",
+ card->netdev->name,
+ descr->dmac_cmd_status);
+ pr_err("buf_addr=x%08x\n", descr->buf_addr);
+ pr_err("buf_size=x%08x\n", descr->buf_size);
+ pr_err("next_descr_addr=x%08x\n", descr->next_descr_addr);
+ pr_err("result_size=x%08x\n", descr->result_size);
+ pr_err("valid_size=x%08x\n", descr->valid_size);
+ pr_err("data_status=x%08x\n", descr->data_status);
+ pr_err("data_error=x%08x\n", descr->data_error);
+ pr_err("bus_addr=x%08x\n", descr->bus_addr);
+ pr_err("which=%ld\n", descr - card->rx_chain.ring);
+
+ card->spider_stats.rx_desc_error++;
+ goto bad_desc;
+ }
+
+ /* Ok, we've got a packet in descr */
+ spider_net_pass_skb_up(descr, card);
descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
- /* change the descriptor state: */
- if (!napi)
- spider_net_refill_rx_chain(card);
-out:
- return result;
+ return 1;
+
+bad_desc:
+ dev_kfree_skb_irq(descr->skb);
+ descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
+ return 0;
}
/**
@@ -1085,7 +1105,7 @@ spider_net_poll(struct net_device *netdev, int *budget)
packets_to_do = min(*budget, netdev->quota);
while (packets_to_do) {
- if (spider_net_decode_one_descr(card, 1)) {
+ if (spider_net_decode_one_descr(card)) {
packets_done++;
packets_to_do--;
} else {
@@ -1098,6 +1118,7 @@ spider_net_poll(struct net_device *netdev, int *budget)
netdev->quota -= packets_done;
*budget -= packets_done;
spider_net_refill_rx_chain(card);
+ spider_net_enable_rxdmac(card);
/* if all packets are in the stack, enable interrupts and return 0 */
/* if not, return 1 */
@@ -1227,24 +1248,6 @@ spider_net_set_mac(struct net_device *netdev, void *p)
}
/**
- * spider_net_handle_rxram_full - cleans up RX ring upon RX RAM full interrupt
- * @card: card structure
- *
- * spider_net_handle_rxram_full empties the RX ring so that spider can put
- * more packets in it and empty its RX RAM. This is called in bottom half
- * context
- */
-static void
-spider_net_handle_rxram_full(struct spider_net_card *card)
-{
- while (spider_net_decode_one_descr(card, 0))
- ;
- spider_net_enable_rxchtails(card);
- spider_net_enable_rxdmac(card);
- netif_rx_schedule(card->netdev);
-}
-
-/**
* spider_net_handle_error_irq - handles errors raised by an interrupt
* @card: card structure
* @status_reg: interrupt status register 0 (GHIINT0STS)
@@ -1366,10 +1369,10 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
case SPIDER_NET_GRFAFLLINT: /* fallthrough */
case SPIDER_NET_GRMFLLINT:
if (netif_msg_intr(card) && net_ratelimit())
- pr_debug("Spider RX RAM full, incoming packets "
+ pr_err("Spider RX RAM full, incoming packets "
"might be discarded!\n");
spider_net_rx_irq_off(card);
- tasklet_schedule(&card->rxram_full_tl);
+ netif_rx_schedule(card->netdev);
show_error = 0;
break;
@@ -1384,7 +1387,7 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
case SPIDER_NET_GDCDCEINT: /* fallthrough */
case SPIDER_NET_GDBDCEINT: /* fallthrough */
case SPIDER_NET_GDADCEINT:
- if (netif_msg_intr(card))
+ if (netif_msg_intr(card) && net_ratelimit())
pr_err("got descriptor chain end interrupt, "
"restarting DMAC %c.\n",
'D'-(i-SPIDER_NET_GDDDCEINT)/3);
@@ -1455,7 +1458,7 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
break;
}
- if ((show_error) && (netif_msg_intr(card)))
+ if ((show_error) && (netif_msg_intr(card)) && net_ratelimit())
pr_err("Got error interrupt on %s, GHIINT0STS = 0x%08x, "
"GHIINT1STS = 0x%08x, GHIINT2STS = 0x%08x\n",
card->netdev->name,
@@ -1651,27 +1654,18 @@ int
spider_net_open(struct net_device *netdev)
{
struct spider_net_card *card = netdev_priv(netdev);
- struct spider_net_descr *descr;
- int i, result;
+ int result;
- result = -ENOMEM;
- if (spider_net_init_chain(card, &card->tx_chain, card->descr,
- card->num_tx_desc))
+ result = spider_net_init_chain(card, &card->tx_chain);
+ if (result)
goto alloc_tx_failed;
-
card->low_watermark = NULL;
- /* rx_chain is after tx_chain, so offset is descr + tx_count */
- if (spider_net_init_chain(card, &card->rx_chain,
- card->descr + card->num_tx_desc,
- card->num_rx_desc))
+ result = spider_net_init_chain(card, &card->rx_chain);
+ if (result)
goto alloc_rx_failed;
- descr = card->rx_chain.head;
- for (i=0; i < card->num_rx_desc; i++, descr++)
- descr->next_descr_addr = descr->next->bus_addr;
-
- /* allocate rx skbs */
+ /* Allocate rx skbs */
if (spider_net_alloc_rx_skbs(card))
goto alloc_skbs_failed;
@@ -1902,7 +1896,6 @@ 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);
@@ -1914,7 +1907,7 @@ spider_net_stop(struct net_device *netdev)
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);
+ free_irq(to_pci_dev(netdev->dev.parent)->irq, netdev);
spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR,
SPIDER_NET_DMA_TX_FEND_VALUE);
@@ -1924,6 +1917,7 @@ spider_net_stop(struct net_device *netdev)
/* release chains */
spider_net_release_tx_chain(card, 1);
+ spider_net_free_rx_chain_contents(card);
spider_net_free_rx_chain_contents(card);
@@ -2046,9 +2040,6 @@ spider_net_setup_netdev(struct spider_net_card *card)
pci_set_drvdata(card->pdev, netdev);
- card->rxram_full_tl.data = (unsigned long) card;
- card->rxram_full_tl.func =
- (void (*)(unsigned long)) spider_net_handle_rxram_full;
init_timer(&card->tx_timer);
card->tx_timer.function =
(void (*)(unsigned long)) spider_net_cleanup_tx_ring;
@@ -2057,8 +2048,8 @@ spider_net_setup_netdev(struct spider_net_card *card)
card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT;
- card->num_tx_desc = tx_descriptors;
- card->num_rx_desc = rx_descriptors;
+ card->tx_chain.num_desc = tx_descriptors;
+ card->rx_chain.num_desc = rx_descriptors;
spider_net_setup_netdev_ops(netdev);
@@ -2107,12 +2098,8 @@ spider_net_alloc_card(void)
{
struct net_device *netdev;
struct spider_net_card *card;
- size_t alloc_size;
- alloc_size = sizeof (*card) +
- sizeof (struct spider_net_descr) * rx_descriptors +
- sizeof (struct spider_net_descr) * tx_descriptors;
- netdev = alloc_etherdev(alloc_size);
+ netdev = alloc_etherdev(sizeof(struct spider_net_card));
if (!netdev)
return NULL;
diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h
index 3e196df2979..2fec5cf7692 100644
--- a/drivers/net/spider_net.h
+++ b/drivers/net/spider_net.h
@@ -24,7 +24,7 @@
#ifndef _SPIDER_NET_H
#define _SPIDER_NET_H
-#define VERSION "1.6 A"
+#define VERSION "1.6 B"
#include "sungem_phy.h"
@@ -378,6 +378,9 @@ struct spider_net_descr_chain {
spinlock_t lock;
struct spider_net_descr *head;
struct spider_net_descr *tail;
+ struct spider_net_descr *ring;
+ int num_desc;
+ dma_addr_t dma_addr;
};
/* descriptor data_status bits */
@@ -397,8 +400,6 @@ struct spider_net_descr_chain {
* 701b8000 would be correct, but every packets gets that flag */
#define SPIDER_NET_DESTROY_RX_FLAGS 0x700b8000
-#define SPIDER_NET_DESCR_SIZE 32
-
/* this will be bigger some time */
struct spider_net_options {
int rx_csum; /* for rx: if 0 ip_summed=NONE,
@@ -441,25 +442,16 @@ struct spider_net_card {
struct spider_net_descr_chain rx_chain;
struct spider_net_descr *low_watermark;
- struct net_device_stats netdev_stats;
-
- struct spider_net_options options;
-
- spinlock_t intmask_lock;
- struct tasklet_struct rxram_full_tl;
struct timer_list tx_timer;
-
struct work_struct tx_timeout_task;
atomic_t tx_timeout_task_counter;
wait_queue_head_t waitq;
/* for ethtool */
int msg_enable;
- int num_rx_desc;
- int num_tx_desc;
+ struct net_device_stats netdev_stats;
struct spider_net_extra_stats spider_stats;
-
- struct spider_net_descr descr[0];
+ struct spider_net_options options;
};
#define pr_err(fmt,arg...) \
diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/spider_net_ethtool.c
index 91b99510291..6bcf03fc89b 100644
--- a/drivers/net/spider_net_ethtool.c
+++ b/drivers/net/spider_net_ethtool.c
@@ -158,9 +158,9 @@ spider_net_ethtool_get_ringparam(struct net_device *netdev,
struct spider_net_card *card = netdev->priv;
ering->tx_max_pending = SPIDER_NET_TX_DESCRIPTORS_MAX;
- ering->tx_pending = card->num_tx_desc;
+ ering->tx_pending = card->tx_chain.num_desc;
ering->rx_max_pending = SPIDER_NET_RX_DESCRIPTORS_MAX;
- ering->rx_pending = card->num_rx_desc;
+ ering->rx_pending = card->rx_chain.num_desc;
}
static int spider_net_get_stats_count(struct net_device *netdev)
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index f4bf62c2a7a..e136bae6197 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -58,11 +58,7 @@
#define TG3_VLAN_TAG_USED 0
#endif
-#ifdef NETIF_F_TSO
#define TG3_TSO_SUPPORT 1
-#else
-#define TG3_TSO_SUPPORT 0
-#endif
#include "tg3.h"
@@ -3384,7 +3380,7 @@ next_pkt:
}
next_pkt_nopost:
sw_idx++;
- sw_idx %= TG3_RX_RCB_RING_SIZE(tp);
+ sw_idx &= (TG3_RX_RCB_RING_SIZE(tp) - 1);
/* Refresh hw_idx to see if there is new work */
if (sw_idx == hw_idx) {
@@ -3873,7 +3869,6 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
entry = tp->tx_prod;
base_flags = 0;
-#if TG3_TSO_SUPPORT != 0
mss = 0;
if (skb->len > (tp->dev->mtu + ETH_HLEN) &&
(mss = skb_shinfo(skb)->gso_size) != 0) {
@@ -3906,11 +3901,6 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
else if (skb->ip_summed == CHECKSUM_PARTIAL)
base_flags |= TXD_FLAG_TCPUDP_CSUM;
-#else
- mss = 0;
- if (skb->ip_summed == CHECKSUM_PARTIAL)
- base_flags |= TXD_FLAG_TCPUDP_CSUM;
-#endif
#if TG3_VLAN_TAG_USED
if (tp->vlgrp != NULL && vlan_tx_tag_present(skb))
base_flags |= (TXD_FLAG_VLAN |
@@ -3970,7 +3960,6 @@ out_unlock:
return NETDEV_TX_OK;
}
-#if TG3_TSO_SUPPORT != 0
static int tg3_start_xmit_dma_bug(struct sk_buff *, struct net_device *);
/* Use GSO to workaround a rare TSO bug that may be triggered when the
@@ -4002,7 +3991,6 @@ tg3_tso_bug_end:
return NETDEV_TX_OK;
}
-#endif
/* hard_start_xmit for devices that have the 4G bug and/or 40-bit bug and
* support TG3_FLG2_HW_TSO_1 or firmware TSO only.
@@ -4036,7 +4024,6 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
base_flags = 0;
if (skb->ip_summed == CHECKSUM_PARTIAL)
base_flags |= TXD_FLAG_TCPUDP_CSUM;
-#if TG3_TSO_SUPPORT != 0
mss = 0;
if (skb->len > (tp->dev->mtu + ETH_HLEN) &&
(mss = skb_shinfo(skb)->gso_size) != 0) {
@@ -4091,9 +4078,6 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
}
}
}
-#else
- mss = 0;
-#endif
#if TG3_VLAN_TAG_USED
if (tp->vlgrp != NULL && vlan_tx_tag_present(skb))
base_flags |= (TXD_FLAG_VLAN |
@@ -5329,7 +5313,6 @@ static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp)
return 0;
}
-#if TG3_TSO_SUPPORT != 0
#define TG3_TSO_FW_RELEASE_MAJOR 0x1
#define TG3_TSO_FW_RELASE_MINOR 0x6
@@ -5906,7 +5889,6 @@ static int tg3_load_tso_firmware(struct tg3 *tp)
return 0;
}
-#endif /* TG3_TSO_SUPPORT != 0 */
/* tp->lock is held. */
static void __tg3_set_mac_addr(struct tg3 *tp)
@@ -6120,7 +6102,6 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32(BUFMGR_DMA_DESC_POOL_ADDR, NIC_SRAM_DMA_DESC_POOL_BASE);
tw32(BUFMGR_DMA_DESC_POOL_SIZE, NIC_SRAM_DMA_DESC_POOL_SIZE);
}
-#if TG3_TSO_SUPPORT != 0
else if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) {
int fw_len;
@@ -6135,7 +6116,6 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32(BUFMGR_MB_POOL_SIZE,
NIC_SRAM_MBUF_POOL_SIZE5705 - fw_len - 0xa00);
}
-#endif
if (tp->dev->mtu <= ETH_DATA_LEN) {
tw32(BUFMGR_MB_RDMA_LOW_WATER,
@@ -6337,10 +6317,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)
rdmac_mode |= RDMAC_MODE_FIFO_LONG_BURST;
-#if TG3_TSO_SUPPORT != 0
if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
rdmac_mode |= (1 << 27);
-#endif
/* Receive/send statistics. */
if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) {
@@ -6511,10 +6489,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32(RCVBDI_MODE, RCVBDI_MODE_ENABLE | RCVBDI_MODE_RCB_ATTN_ENAB);
tw32(RCVDBDI_MODE, RCVDBDI_MODE_ENABLE | RCVDBDI_MODE_INV_RING_SZ);
tw32(SNDDATAI_MODE, SNDDATAI_MODE_ENABLE);
-#if TG3_TSO_SUPPORT != 0
if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
tw32(SNDDATAI_MODE, SNDDATAI_MODE_ENABLE | 0x8);
-#endif
tw32(SNDBDI_MODE, SNDBDI_MODE_ENABLE | SNDBDI_MODE_ATTN_ENABLE);
tw32(SNDBDS_MODE, SNDBDS_MODE_ENABLE | SNDBDS_MODE_ATTN_ENABLE);
@@ -6524,13 +6500,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
return err;
}
-#if TG3_TSO_SUPPORT != 0
if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) {
err = tg3_load_tso_firmware(tp);
if (err)
return err;
}
-#endif
tp->tx_mode = TX_MODE_ENABLE;
tw32_f(MAC_TX_MODE, tp->tx_mode);
@@ -8062,7 +8036,6 @@ static void tg3_set_msglevel(struct net_device *dev, u32 value)
tp->msg_enable = value;
}
-#if TG3_TSO_SUPPORT != 0
static int tg3_set_tso(struct net_device *dev, u32 value)
{
struct tg3 *tp = netdev_priv(dev);
@@ -8081,7 +8054,6 @@ static int tg3_set_tso(struct net_device *dev, u32 value)
}
return ethtool_op_set_tso(dev, value);
}
-#endif
static int tg3_nway_reset(struct net_device *dev)
{
@@ -9212,10 +9184,8 @@ static const struct ethtool_ops tg3_ethtool_ops = {
.set_tx_csum = tg3_set_tx_csum,
.get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
-#if TG3_TSO_SUPPORT != 0
.get_tso = ethtool_op_get_tso,
.set_tso = tg3_set_tso,
-#endif
.self_test_count = tg3_get_test_count,
.self_test = tg3_self_test,
.get_strings = tg3_get_strings,
@@ -11856,7 +11826,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
tg3_init_bufmgr_config(tp);
-#if TG3_TSO_SUPPORT != 0
if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) {
tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE;
}
@@ -11881,7 +11850,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
dev->features |= NETIF_F_TSO6;
}
-#endif
if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A1 &&
!(tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) &&
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index 7e4b23c7c1b..31c97a6591a 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -1709,75 +1709,13 @@ static void adjust_link(struct net_device *dev)
if (mii_info->speed != ugeth->oldspeed) {
switch (mii_info->speed) {
case 1000:
-#ifdef CONFIG_PPC_MPC836x
-/* FIXME: This code is for 100Mbs BUG fixing,
-remove this when it is fixed!!! */
- if (ugeth->ug_info->enet_interface ==
- ENET_1000_GMII)
- /* Run the commands which initialize the PHY */
- {
- tempval =
- (u32) mii_info->mdio_read(ugeth->
- dev, mii_info->mii_id, 0x1b);
- tempval |= 0x000f;
- mii_info->mdio_write(ugeth->dev,
- mii_info->mii_id, 0x1b,
- (u16) tempval);
- tempval =
- (u32) mii_info->mdio_read(ugeth->
- dev, mii_info->mii_id,
- MII_BMCR);
- mii_info->mdio_write(ugeth->dev,
- mii_info->mii_id, MII_BMCR,
- (u16) (tempval | BMCR_RESET));
- } else if (ugeth->ug_info->enet_interface ==
- ENET_1000_RGMII)
- /* Run the commands which initialize the PHY */
- {
- tempval =
- (u32) mii_info->mdio_read(ugeth->
- dev, mii_info->mii_id, 0x1b);
- tempval = (tempval & ~0x000f) | 0x000b;
- mii_info->mdio_write(ugeth->dev,
- mii_info->mii_id, 0x1b,
- (u16) tempval);
- tempval =
- (u32) mii_info->mdio_read(ugeth->
- dev, mii_info->mii_id,
- MII_BMCR);
- mii_info->mdio_write(ugeth->dev,
- mii_info->mii_id, MII_BMCR,
- (u16) (tempval | BMCR_RESET));
- }
- msleep(4000);
-#endif /* CONFIG_MPC8360 */
- adjust_enet_interface(ugeth);
+ ugeth->ug_info->enet_interface = ENET_1000_RGMII;
break;
case 100:
- case 10:
-#ifdef CONFIG_PPC_MPC836x
-/* FIXME: This code is for 100Mbs BUG fixing,
-remove this lines when it will be fixed!!! */
ugeth->ug_info->enet_interface = ENET_100_RGMII;
- tempval =
- (u32) mii_info->mdio_read(ugeth->dev,
- mii_info->mii_id,
- 0x1b);
- tempval = (tempval & ~0x000f) | 0x000b;
- mii_info->mdio_write(ugeth->dev,
- mii_info->mii_id, 0x1b,
- (u16) tempval);
- tempval =
- (u32) mii_info->mdio_read(ugeth->dev,
- mii_info->mii_id,
- MII_BMCR);
- mii_info->mdio_write(ugeth->dev,
- mii_info->mii_id, MII_BMCR,
- (u16) (tempval |
- BMCR_RESET));
- msleep(4000);
-#endif /* CONFIG_MPC8360 */
- adjust_enet_interface(ugeth);
+ break;
+ case 10:
+ ugeth->ug_info->enet_interface = ENET_10_RGMII;
break;
default:
ugeth_warn
@@ -1785,6 +1723,7 @@ remove this lines when it will be fixed!!! */
dev->name, mii_info->speed);
break;
}
+ adjust_enet_interface(ugeth);
ugeth_info("%s: Speed %dBT", dev->name,
mii_info->speed);
@@ -2865,8 +2804,8 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
if (UCC_GETH_TX_BD_RING_ALIGNMENT > 4)
align = UCC_GETH_TX_BD_RING_ALIGNMENT;
ugeth->tx_bd_ring_offset[j] =
- (u32) (kmalloc((u32) (length + align),
- GFP_KERNEL));
+ kmalloc((u32) (length + align), GFP_KERNEL);
+
if (ugeth->tx_bd_ring_offset[j] != 0)
ugeth->p_tx_bd_ring[j] =
(void*)((ugeth->tx_bd_ring_offset[j] +
@@ -2901,7 +2840,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
if (UCC_GETH_RX_BD_RING_ALIGNMENT > 4)
align = UCC_GETH_RX_BD_RING_ALIGNMENT;
ugeth->rx_bd_ring_offset[j] =
- (u32) (kmalloc((u32) (length + align), GFP_KERNEL));
+ kmalloc((u32) (length + align), GFP_KERNEL);
if (ugeth->rx_bd_ring_offset[j] != 0)
ugeth->p_rx_bd_ring[j] =
(void*)((ugeth->rx_bd_ring_offset[j] +
@@ -2927,10 +2866,9 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
/* Init Tx bds */
for (j = 0; j < ug_info->numQueuesTx; j++) {
/* Setup the skbuff rings */
- ugeth->tx_skbuff[j] =
- (struct sk_buff **)kmalloc(sizeof(struct sk_buff *) *
- ugeth->ug_info->bdRingLenTx[j],
- GFP_KERNEL);
+ ugeth->tx_skbuff[j] = kmalloc(sizeof(struct sk_buff *) *
+ ugeth->ug_info->bdRingLenTx[j],
+ GFP_KERNEL);
if (ugeth->tx_skbuff[j] == NULL) {
ugeth_err("%s: Could not allocate tx_skbuff",
@@ -2959,10 +2897,9 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
/* Init Rx bds */
for (j = 0; j < ug_info->numQueuesRx; j++) {
/* Setup the skbuff rings */
- ugeth->rx_skbuff[j] =
- (struct sk_buff **)kmalloc(sizeof(struct sk_buff *) *
- ugeth->ug_info->bdRingLenRx[j],
- GFP_KERNEL);
+ ugeth->rx_skbuff[j] = kmalloc(sizeof(struct sk_buff *) *
+ ugeth->ug_info->bdRingLenRx[j],
+ GFP_KERNEL);
if (ugeth->rx_skbuff[j] == NULL) {
ugeth_err("%s: Could not allocate rx_skbuff",
@@ -3453,8 +3390,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
* allocated resources can be released when the channel is freed.
*/
if (!(ugeth->p_init_enet_param_shadow =
- (struct ucc_geth_init_pram *) kmalloc(sizeof(struct ucc_geth_init_pram),
- GFP_KERNEL))) {
+ kmalloc(sizeof(struct ucc_geth_init_pram), GFP_KERNEL))) {
ugeth_err
("%s: Can not allocate memory for"
" p_UccInitEnetParamShadows.", __FUNCTION__);
@@ -4136,6 +4072,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
static int mii_mng_configured = 0;
const phandle *ph;
const unsigned int *prop;
+ const void *mac_addr;
ugeth_vdbg("%s: IN", __FUNCTION__);
@@ -4261,7 +4198,12 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
ugeth->ug_info = ug_info;
ugeth->dev = dev;
- memcpy(dev->dev_addr, get_property(np, "mac-address", NULL), 6);
+
+ mac_addr = get_property(np, "mac-address", NULL);
+ if (mac_addr == NULL)
+ mac_addr = get_property(np, "local-mac-address", NULL);
+ if (mac_addr)
+ memcpy(dev->dev_addr, mac_addr, 6);
return 0;
}
diff --git a/drivers/net/ucc_geth_phy.c b/drivers/net/ucc_geth_phy.c
index 3c86592ce03..6fda6d88be4 100644
--- a/drivers/net/ucc_geth_phy.c
+++ b/drivers/net/ucc_geth_phy.c
@@ -376,6 +376,8 @@ static int marvell_init(struct ugeth_mii_info *mii_info)
ugphy_vdbg("%s: IN", __FUNCTION__);
ucc_geth_phy_write(mii_info, 0x14, 0x0cd2);
+ ucc_geth_phy_write(mii_info, 0x1b,
+ (ucc_geth_phy_read(mii_info, 0x1b) & ~0x000f) | 0x000b);
ucc_geth_phy_write(mii_info, MII_BMCR,
ucc_geth_phy_read(mii_info, MII_BMCR) | BMCR_RESET);
msleep(4000);
diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig
index 21f76f51c95..61708cf4c85 100644
--- a/drivers/net/wan/Kconfig
+++ b/drivers/net/wan/Kconfig
@@ -235,6 +235,19 @@ comment "Cyclades-PC300 MLPPP support is disabled."
comment "Refer to the file README.mlppp, provided by PC300 package."
depends on WAN && HDLC && PC300 && (PPP=n || !PPP_MULTILINK || PPP_SYNC_TTY=n || !HDLC_PPP)
+config PC300TOO
+ tristate "Cyclades PC300 RSV/X21 alternative support"
+ depends on HDLC && PCI
+ help
+ Alternative driver for PC300 RSV/X21 PCI cards made by
+ Cyclades, Inc. If you have such a card, say Y here and see
+ <http://www.kernel.org/pub/linux/utils/net/hdlc/>.
+
+ To compile this as a module, choose M here: the module
+ will be called pc300too.
+
+ If unsure, say N here.
+
config N2
tristate "SDL RISCom/N2 support"
depends on HDLC && ISA
@@ -344,17 +357,6 @@ config DLCI
To compile this driver as a module, choose M here: the
module will be called dlci.
-config DLCI_COUNT
- int "Max open DLCI"
- depends on DLCI
- default "24"
- help
- Maximal number of logical point-to-point frame relay connections
- (the identifiers of which are called DCLIs) that the driver can
- handle.
-
- The default is probably fine.
-
config DLCI_MAX
int "Max DLCI per device"
depends on DLCI
diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile
index 83ec2c87ba3..d61fef36afc 100644
--- a/drivers/net/wan/Makefile
+++ b/drivers/net/wan/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_N2) += n2.o
obj-$(CONFIG_C101) += c101.o
obj-$(CONFIG_WANXL) += wanxl.o
obj-$(CONFIG_PCI200SYN) += pci200syn.o
+obj-$(CONFIG_PC300TOO) += pc300too.o
clean-files := wanxlfw.inc
$(obj)/wanxl.o: $(obj)/wanxlfw.inc
diff --git a/drivers/net/wan/hdlc.c b/drivers/net/wan/hdlc.c
index db354e0edbe..9040d7cf651 100644
--- a/drivers/net/wan/hdlc.c
+++ b/drivers/net/wan/hdlc.c
@@ -222,7 +222,7 @@ int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return -EINVAL;
}
-void hdlc_setup(struct net_device *dev)
+static void hdlc_setup(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
@@ -325,7 +325,6 @@ MODULE_LICENSE("GPL v2");
EXPORT_SYMBOL(hdlc_open);
EXPORT_SYMBOL(hdlc_close);
EXPORT_SYMBOL(hdlc_ioctl);
-EXPORT_SYMBOL(hdlc_setup);
EXPORT_SYMBOL(alloc_hdlcdev);
EXPORT_SYMBOL(unregister_hdlc_device);
EXPORT_SYMBOL(register_hdlc_protocol);
diff --git a/drivers/net/wan/pc300too.c b/drivers/net/wan/pc300too.c
new file mode 100644
index 00000000000..bc156b51678
--- /dev/null
+++ b/drivers/net/wan/pc300too.c
@@ -0,0 +1,565 @@
+/*
+ * Cyclades PC300 synchronous serial card driver for Linux
+ *
+ * Copyright (C) 2000-2007 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * For information see <http://www.kernel.org/pub/linux/utils/net/hdlc/>.
+ *
+ * Sources of information:
+ * Hitachi HD64572 SCA-II User's Manual
+ * Cyclades PC300 Linux driver
+ *
+ * This driver currently supports only PC300/RSV (V.24/V.35) and
+ * PC300/X21 cards.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/in.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/moduleparam.h>
+#include <linux/netdevice.h>
+#include <linux/hdlc.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+
+#include "hd64572.h"
+
+static const char* version = "Cyclades PC300 driver version: 1.17";
+static const char* devname = "PC300";
+
+#undef DEBUG_PKT
+#define DEBUG_RINGS
+
+#define PC300_PLX_SIZE 0x80 /* PLX control window size (128 B) */
+#define PC300_SCA_SIZE 0x400 /* SCA window size (1 KB) */
+#define ALL_PAGES_ALWAYS_MAPPED
+#define NEED_DETECT_RAM
+#define NEED_SCA_MSCI_INTR
+#define MAX_TX_BUFFERS 10
+
+static int pci_clock_freq = 33000000;
+static int use_crystal_clock = 0;
+static unsigned int CLOCK_BASE;
+
+/* Masks to access the init_ctrl PLX register */
+#define PC300_CLKSEL_MASK (0x00000004UL)
+#define PC300_CHMEDIA_MASK(port) (0x00000020UL << ((port) * 3))
+#define PC300_CTYPE_MASK (0x00000800UL)
+
+
+enum { PC300_RSV = 1, PC300_X21, PC300_TE }; /* card types */
+
+/*
+ * PLX PCI9050-1 local configuration and shared runtime registers.
+ * This structure can be used to access 9050 registers (memory mapped).
+ */
+typedef struct {
+ u32 loc_addr_range[4]; /* 00-0Ch : Local Address Ranges */
+ u32 loc_rom_range; /* 10h : Local ROM Range */
+ u32 loc_addr_base[4]; /* 14-20h : Local Address Base Addrs */
+ u32 loc_rom_base; /* 24h : Local ROM Base */
+ u32 loc_bus_descr[4]; /* 28-34h : Local Bus Descriptors */
+ u32 rom_bus_descr; /* 38h : ROM Bus Descriptor */
+ u32 cs_base[4]; /* 3C-48h : Chip Select Base Addrs */
+ u32 intr_ctrl_stat; /* 4Ch : Interrupt Control/Status */
+ u32 init_ctrl; /* 50h : EEPROM ctrl, Init Ctrl, etc */
+}plx9050;
+
+
+
+typedef struct port_s {
+ struct net_device *dev;
+ struct card_s *card;
+ spinlock_t lock; /* TX lock */
+ sync_serial_settings settings;
+ int rxpart; /* partial frame received, next frame invalid*/
+ unsigned short encoding;
+ unsigned short parity;
+ unsigned int iface;
+ u16 rxin; /* rx ring buffer 'in' pointer */
+ u16 txin; /* tx ring buffer 'in' and 'last' pointers */
+ u16 txlast;
+ u8 rxs, txs, tmc; /* SCA registers */
+ u8 phy_node; /* physical port # - 0 or 1 */
+}port_t;
+
+
+
+typedef struct card_s {
+ int type; /* RSV, X21, etc. */
+ int n_ports; /* 1 or 2 ports */
+ u8 __iomem *rambase; /* buffer memory base (virtual) */
+ u8 __iomem *scabase; /* SCA memory base (virtual) */
+ plx9050 __iomem *plxbase; /* PLX registers memory base (virtual) */
+ u32 init_ctrl_value; /* Saved value - 9050 bug workaround */
+ u16 rx_ring_buffers; /* number of buffers in a ring */
+ u16 tx_ring_buffers;
+ u16 buff_offset; /* offset of first buffer of first channel */
+ u8 irq; /* interrupt request level */
+
+ port_t ports[2];
+}card_t;
+
+
+#define sca_in(reg, card) readb(card->scabase + (reg))
+#define sca_out(value, reg, card) writeb(value, card->scabase + (reg))
+#define sca_inw(reg, card) readw(card->scabase + (reg))
+#define sca_outw(value, reg, card) writew(value, card->scabase + (reg))
+#define sca_inl(reg, card) readl(card->scabase + (reg))
+#define sca_outl(value, reg, card) writel(value, card->scabase + (reg))
+
+#define port_to_card(port) (port->card)
+#define log_node(port) (port->phy_node)
+#define phy_node(port) (port->phy_node)
+#define winbase(card) (card->rambase)
+#define get_port(card, port) ((port) < (card)->n_ports ? \
+ (&(card)->ports[port]) : (NULL))
+
+#include "hd6457x.c"
+
+
+static void pc300_set_iface(port_t *port)
+{
+ card_t *card = port->card;
+ u32 __iomem * init_ctrl = &card->plxbase->init_ctrl;
+ u16 msci = get_msci(port);
+ u8 rxs = port->rxs & CLK_BRG_MASK;
+ u8 txs = port->txs & CLK_BRG_MASK;
+
+ sca_out(EXS_TES1, (phy_node(port) ? MSCI1_OFFSET : MSCI0_OFFSET) + EXS,
+ port_to_card(port));
+ switch(port->settings.clock_type) {
+ case CLOCK_INT:
+ rxs |= CLK_BRG; /* BRG output */
+ txs |= CLK_PIN_OUT | CLK_TX_RXCLK; /* RX clock */
+ break;
+
+ case CLOCK_TXINT:
+ rxs |= CLK_LINE; /* RXC input */
+ txs |= CLK_PIN_OUT | CLK_BRG; /* BRG output */
+ break;
+
+ case CLOCK_TXFROMRX:
+ rxs |= CLK_LINE; /* RXC input */
+ txs |= CLK_PIN_OUT | CLK_TX_RXCLK; /* RX clock */
+ break;
+
+ default: /* EXTernal clock */
+ rxs |= CLK_LINE; /* RXC input */
+ txs |= CLK_PIN_OUT | CLK_LINE; /* TXC input */
+ break;
+ }
+
+ port->rxs = rxs;
+ port->txs = txs;
+ sca_out(rxs, msci + RXS, card);
+ sca_out(txs, msci + TXS, card);
+ sca_set_port(port);
+
+ if (port->card->type == PC300_RSV) {
+ if (port->iface == IF_IFACE_V35)
+ writel(card->init_ctrl_value |
+ PC300_CHMEDIA_MASK(port->phy_node), init_ctrl);
+ else
+ writel(card->init_ctrl_value &
+ ~PC300_CHMEDIA_MASK(port->phy_node), init_ctrl);
+ }
+}
+
+
+
+static int pc300_open(struct net_device *dev)
+{
+ port_t *port = dev_to_port(dev);
+
+ int result = hdlc_open(dev);
+ if (result)
+ return result;
+
+ sca_open(dev);
+ pc300_set_iface(port);
+ return 0;
+}
+
+
+
+static int pc300_close(struct net_device *dev)
+{
+ sca_close(dev);
+ hdlc_close(dev);
+ return 0;
+}
+
+
+
+static int pc300_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ const size_t size = sizeof(sync_serial_settings);
+ sync_serial_settings new_line;
+ sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync;
+ int new_type;
+ port_t *port = dev_to_port(dev);
+
+#ifdef DEBUG_RINGS
+ if (cmd == SIOCDEVPRIVATE) {
+ sca_dump_rings(dev);
+ return 0;
+ }
+#endif
+ if (cmd != SIOCWANDEV)
+ return hdlc_ioctl(dev, ifr, cmd);
+
+ if (ifr->ifr_settings.type == IF_GET_IFACE) {
+ ifr->ifr_settings.type = port->iface;
+ if (ifr->ifr_settings.size < size) {
+ ifr->ifr_settings.size = size; /* data size wanted */
+ return -ENOBUFS;
+ }
+ if (copy_to_user(line, &port->settings, size))
+ return -EFAULT;
+ return 0;
+
+ }
+
+ if (port->card->type == PC300_X21 &&
+ (ifr->ifr_settings.type == IF_IFACE_SYNC_SERIAL ||
+ ifr->ifr_settings.type == IF_IFACE_X21))
+ new_type = IF_IFACE_X21;
+
+ else if (port->card->type == PC300_RSV &&
+ (ifr->ifr_settings.type == IF_IFACE_SYNC_SERIAL ||
+ ifr->ifr_settings.type == IF_IFACE_V35))
+ new_type = IF_IFACE_V35;
+
+ else if (port->card->type == PC300_RSV &&
+ ifr->ifr_settings.type == IF_IFACE_V24)
+ new_type = IF_IFACE_V24;
+
+ else
+ return hdlc_ioctl(dev, ifr, cmd);
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (copy_from_user(&new_line, line, size))
+ return -EFAULT;
+
+ if (new_line.clock_type != CLOCK_EXT &&
+ new_line.clock_type != CLOCK_TXFROMRX &&
+ new_line.clock_type != CLOCK_INT &&
+ new_line.clock_type != CLOCK_TXINT)
+ return -EINVAL; /* No such clock setting */
+
+ if (new_line.loopback != 0 && new_line.loopback != 1)
+ return -EINVAL;
+
+ memcpy(&port->settings, &new_line, size); /* Update settings */
+ port->iface = new_type;
+ pc300_set_iface(port);
+ return 0;
+}
+
+
+
+static void pc300_pci_remove_one(struct pci_dev *pdev)
+{
+ int i;
+ card_t *card = pci_get_drvdata(pdev);
+
+ for (i = 0; i < 2; i++)
+ if (card->ports[i].card) {
+ struct net_device *dev = port_to_dev(&card->ports[i]);
+ unregister_hdlc_device(dev);
+ }
+
+ if (card->irq)
+ free_irq(card->irq, card);
+
+ if (card->rambase)
+ iounmap(card->rambase);
+ if (card->scabase)
+ iounmap(card->scabase);
+ if (card->plxbase)
+ iounmap(card->plxbase);
+
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+ if (card->ports[0].dev)
+ free_netdev(card->ports[0].dev);
+ if (card->ports[1].dev)
+ free_netdev(card->ports[1].dev);
+ kfree(card);
+}
+
+
+
+static int __devinit pc300_pci_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ card_t *card;
+ u8 rev_id;
+ u32 __iomem *p;
+ int i;
+ u32 ramsize;
+ u32 ramphys; /* buffer memory base */
+ u32 scaphys; /* SCA memory base */
+ u32 plxphys; /* PLX registers memory base */
+
+#ifndef MODULE
+ static int printed_version;
+ if (!printed_version++)
+ printk(KERN_INFO "%s\n", version);
+#endif
+
+ i = pci_enable_device(pdev);
+ if (i)
+ return i;
+
+ i = pci_request_regions(pdev, "PC300");
+ if (i) {
+ pci_disable_device(pdev);
+ return i;
+ }
+
+ card = kmalloc(sizeof(card_t), GFP_KERNEL);
+ if (card == NULL) {
+ printk(KERN_ERR "pc300: unable to allocate memory\n");
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ return -ENOBUFS;
+ }
+ memset(card, 0, sizeof(card_t));
+ pci_set_drvdata(pdev, card);
+
+ if (pdev->device == PCI_DEVICE_ID_PC300_TE_1 ||
+ pdev->device == PCI_DEVICE_ID_PC300_TE_2)
+ card->type = PC300_TE; /* not fully supported */
+ else if (card->init_ctrl_value & PC300_CTYPE_MASK)
+ card->type = PC300_X21;
+ else
+ card->type = PC300_RSV;
+
+ if (pdev->device == PCI_DEVICE_ID_PC300_RX_1 ||
+ pdev->device == PCI_DEVICE_ID_PC300_TE_1)
+ card->n_ports = 1;
+ else
+ card->n_ports = 2;
+
+ for (i = 0; i < card->n_ports; i++)
+ if (!(card->ports[i].dev = alloc_hdlcdev(&card->ports[i]))) {
+ printk(KERN_ERR "pc300: unable to allocate memory\n");
+ pc300_pci_remove_one(pdev);
+ return -ENOMEM;
+ }
+
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
+ if (pci_resource_len(pdev, 0) != PC300_PLX_SIZE ||
+ pci_resource_len(pdev, 2) != PC300_SCA_SIZE ||
+ pci_resource_len(pdev, 3) < 16384) {
+ printk(KERN_ERR "pc300: invalid card EEPROM parameters\n");
+ pc300_pci_remove_one(pdev);
+ return -EFAULT;
+ }
+
+ plxphys = pci_resource_start(pdev,0) & PCI_BASE_ADDRESS_MEM_MASK;
+ card->plxbase = ioremap(plxphys, PC300_PLX_SIZE);
+
+ scaphys = pci_resource_start(pdev,2) & PCI_BASE_ADDRESS_MEM_MASK;
+ card->scabase = ioremap(scaphys, PC300_SCA_SIZE);
+
+ ramphys = pci_resource_start(pdev,3) & PCI_BASE_ADDRESS_MEM_MASK;
+ card->rambase = ioremap(ramphys, pci_resource_len(pdev,3));
+
+ if (card->plxbase == NULL ||
+ card->scabase == NULL ||
+ card->rambase == NULL) {
+ printk(KERN_ERR "pc300: ioremap() failed\n");
+ pc300_pci_remove_one(pdev);
+ }
+
+ /* PLX PCI 9050 workaround for local configuration register read bug */
+ pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, scaphys);
+ card->init_ctrl_value = readl(&((plx9050 __iomem *)card->scabase)->init_ctrl);
+ pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, plxphys);
+
+ /* Reset PLX */
+ p = &card->plxbase->init_ctrl;
+ writel(card->init_ctrl_value | 0x40000000, p);
+ readl(p); /* Flush the write - do not use sca_flush */
+ udelay(1);
+
+ writel(card->init_ctrl_value, p);
+ readl(p); /* Flush the write - do not use sca_flush */
+ udelay(1);
+
+ /* Reload Config. Registers from EEPROM */
+ writel(card->init_ctrl_value | 0x20000000, p);
+ readl(p); /* Flush the write - do not use sca_flush */
+ udelay(1);
+
+ writel(card->init_ctrl_value, p);
+ readl(p); /* Flush the write - do not use sca_flush */
+ udelay(1);
+
+ ramsize = sca_detect_ram(card, card->rambase,
+ pci_resource_len(pdev, 3));
+
+ if (use_crystal_clock)
+ card->init_ctrl_value &= ~PC300_CLKSEL_MASK;
+ else
+ card->init_ctrl_value |= PC300_CLKSEL_MASK;
+
+ writel(card->init_ctrl_value, &card->plxbase->init_ctrl);
+ /* number of TX + RX buffers for one port */
+ i = ramsize / (card->n_ports * (sizeof(pkt_desc) + HDLC_MAX_MRU));
+ card->tx_ring_buffers = min(i / 2, MAX_TX_BUFFERS);
+ card->rx_ring_buffers = i - card->tx_ring_buffers;
+
+ card->buff_offset = card->n_ports * sizeof(pkt_desc) *
+ (card->tx_ring_buffers + card->rx_ring_buffers);
+
+ printk(KERN_INFO "pc300: PC300/%s, %u KB RAM at 0x%x, IRQ%u, "
+ "using %u TX + %u RX packets rings\n",
+ card->type == PC300_X21 ? "X21" :
+ card->type == PC300_TE ? "TE" : "RSV",
+ ramsize / 1024, ramphys, pdev->irq,
+ card->tx_ring_buffers, card->rx_ring_buffers);
+
+ if (card->tx_ring_buffers < 1) {
+ printk(KERN_ERR "pc300: RAM test failed\n");
+ pc300_pci_remove_one(pdev);
+ return -EFAULT;
+ }
+
+ /* Enable interrupts on the PCI bridge, LINTi1 active low */
+ writew(0x0041, &card->plxbase->intr_ctrl_stat);
+
+ /* Allocate IRQ */
+ if (request_irq(pdev->irq, sca_intr, IRQF_SHARED, devname, card)) {
+ printk(KERN_WARNING "pc300: could not allocate IRQ%d.\n",
+ pdev->irq);
+ pc300_pci_remove_one(pdev);
+ return -EBUSY;
+ }
+ card->irq = pdev->irq;
+
+ sca_init(card, 0);
+
+ // COTE not set - allows better TX DMA settings
+ // sca_out(sca_in(PCR, card) | PCR_COTE, PCR, card);
+
+ sca_out(0x10, BTCR, card);
+
+ for (i = 0; i < card->n_ports; i++) {
+ port_t *port = &card->ports[i];
+ struct net_device *dev = port_to_dev(port);
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+ port->phy_node = i;
+
+ spin_lock_init(&port->lock);
+ SET_MODULE_OWNER(dev);
+ dev->irq = card->irq;
+ dev->mem_start = ramphys;
+ dev->mem_end = ramphys + ramsize - 1;
+ dev->tx_queue_len = 50;
+ dev->do_ioctl = pc300_ioctl;
+ dev->open = pc300_open;
+ dev->stop = pc300_close;
+ hdlc->attach = sca_attach;
+ hdlc->xmit = sca_xmit;
+ port->settings.clock_type = CLOCK_EXT;
+ port->card = card;
+ if (card->type == PC300_X21)
+ port->iface = IF_IFACE_X21;
+ else
+ port->iface = IF_IFACE_V35;
+
+ if (register_hdlc_device(dev)) {
+ printk(KERN_ERR "pc300: unable to register hdlc "
+ "device\n");
+ port->card = NULL;
+ pc300_pci_remove_one(pdev);
+ return -ENOBUFS;
+ }
+ sca_init_sync_port(port); /* Set up SCA memory */
+
+ printk(KERN_INFO "%s: PC300 node %d\n",
+ dev->name, port->phy_node);
+ }
+ return 0;
+}
+
+
+
+static struct pci_device_id pc300_pci_tbl[] __devinitdata = {
+ { PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_PC300_RX_1, PCI_ANY_ID,
+ PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_PC300_RX_2, PCI_ANY_ID,
+ PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_PC300_TE_1, PCI_ANY_ID,
+ PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_PC300_TE_2, PCI_ANY_ID,
+ PCI_ANY_ID, 0, 0, 0 },
+ { 0, }
+};
+
+
+static struct pci_driver pc300_pci_driver = {
+ .name = "PC300",
+ .id_table = pc300_pci_tbl,
+ .probe = pc300_pci_init_one,
+ .remove = pc300_pci_remove_one,
+};
+
+
+static int __init pc300_init_module(void)
+{
+#ifdef MODULE
+ printk(KERN_INFO "%s\n", version);
+#endif
+ if (pci_clock_freq < 1000000 || pci_clock_freq > 80000000) {
+ printk(KERN_ERR "pc300: Invalid PCI clock frequency\n");
+ return -EINVAL;
+ }
+ if (use_crystal_clock != 0 && use_crystal_clock != 1) {
+ printk(KERN_ERR "pc300: Invalid 'use_crystal_clock' value\n");
+ return -EINVAL;
+ }
+
+ CLOCK_BASE = use_crystal_clock ? 24576000 : pci_clock_freq;
+
+ return pci_module_init(&pc300_pci_driver);
+}
+
+
+
+static void __exit pc300_cleanup_module(void)
+{
+ pci_unregister_driver(&pc300_pci_driver);
+}
+
+MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
+MODULE_DESCRIPTION("Cyclades PC300 serial port driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(pci, pc300_pci_tbl);
+module_param(pci_clock_freq, int, 0444);
+MODULE_PARM_DESC(pci_clock_freq, "System PCI clock frequency in Hz");
+module_param(use_crystal_clock, int, 0444);
+MODULE_PARM_DESC(use_crystal_clock,
+ "Use 24.576 MHz clock instead of PCI clock");
+module_init(pc300_init_module);
+module_exit(pc300_cleanup_module);
diff --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c
index 59ddd21c395..8dbcf83bb5f 100644
--- a/drivers/net/wan/z85230.c
+++ b/drivers/net/wan/z85230.c
@@ -331,8 +331,7 @@ static void z8530_rtsdtr(struct z8530_channel *c, int set)
static void z8530_rx(struct z8530_channel *c)
{
u8 ch,stat;
- spin_lock(c->lock);
-
+
while(1)
{
/* FIFO empty ? */
@@ -390,7 +389,6 @@ static void z8530_rx(struct z8530_channel *c)
*/
write_zsctrl(c, ERR_RES);
write_zsctrl(c, RES_H_IUS);
- spin_unlock(c->lock);
}
@@ -406,7 +404,6 @@ static void z8530_rx(struct z8530_channel *c)
static void z8530_tx(struct z8530_channel *c)
{
- spin_lock(c->lock);
while(c->txcount) {
/* FIFO full ? */
if(!(read_zsreg(c, R0)&4))
@@ -434,7 +431,6 @@ static void z8530_tx(struct z8530_channel *c)
z8530_tx_done(c);
write_zsctrl(c, RES_H_IUS);
- spin_unlock(c->lock);
}
/**
@@ -452,7 +448,6 @@ static void z8530_status(struct z8530_channel *chan)
{
u8 status, altered;
- spin_lock(chan->lock);
status=read_zsreg(chan, R0);
altered=chan->status^status;
@@ -487,7 +482,6 @@ static void z8530_status(struct z8530_channel *chan)
}
write_zsctrl(chan, RES_EXT_INT);
write_zsctrl(chan, RES_H_IUS);
- spin_unlock(chan->lock);
}
struct z8530_irqhandler z8530_sync=
@@ -511,7 +505,6 @@ EXPORT_SYMBOL(z8530_sync);
static void z8530_dma_rx(struct z8530_channel *chan)
{
- spin_lock(chan->lock);
if(chan->rxdma_on)
{
/* Special condition check only */
@@ -534,7 +527,6 @@ static void z8530_dma_rx(struct z8530_channel *chan)
/* DMA is off right now, drain the slow way */
z8530_rx(chan);
}
- spin_unlock(chan->lock);
}
/**
@@ -547,7 +539,6 @@ static void z8530_dma_rx(struct z8530_channel *chan)
static void z8530_dma_tx(struct z8530_channel *chan)
{
- spin_lock(chan->lock);
if(!chan->dma_tx)
{
printk(KERN_WARNING "Hey who turned the DMA off?\n");
@@ -557,7 +548,6 @@ static void z8530_dma_tx(struct z8530_channel *chan)
/* This shouldnt occur in DMA mode */
printk(KERN_ERR "DMA tx - bogus event!\n");
z8530_tx(chan);
- spin_unlock(chan->lock);
}
/**
@@ -596,7 +586,6 @@ static void z8530_dma_status(struct z8530_channel *chan)
}
}
- spin_lock(chan->lock);
if(altered&chan->dcdcheck)
{
if(status&chan->dcdcheck)
@@ -618,7 +607,6 @@ static void z8530_dma_status(struct z8530_channel *chan)
write_zsctrl(chan, RES_EXT_INT);
write_zsctrl(chan, RES_H_IUS);
- spin_unlock(chan->lock);
}
struct z8530_irqhandler z8530_dma_sync=
diff --git a/drivers/net/wd.c b/drivers/net/wd.c
index 7f38012b9c9..a0326818ff2 100644
--- a/drivers/net/wd.c
+++ b/drivers/net/wd.c
@@ -433,7 +433,7 @@ wd_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_
memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count);
} else {
/* Packet is in one chunk -- we can copy + cksum. */
- eth_io_copy_and_sum(skb, xfer_start, count, 0);
+ memcpy_fromio(skb->data, xfer_start, count);
}
/* Turn off 16 bit access so that reboot works. ISA brain-damage */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index 4168b1a807e..0e790efae68 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -352,6 +352,10 @@
#define BCM43xx_UCODEFLAG_UNKPACTRL 0x0040
#define BCM43xx_UCODEFLAG_JAPAN 0x0080
+/* Hardware Radio Enable masks */
+#define BCM43xx_MMIO_RADIO_HWENABLED_HI_MASK (1 << 16)
+#define BCM43xx_MMIO_RADIO_HWENABLED_LO_MASK (1 << 4)
+
/* Generic-Interrupt reasons. */
#define BCM43xx_IRQ_READY (1 << 0)
#define BCM43xx_IRQ_BEACON (1 << 1)
@@ -758,7 +762,8 @@ struct bcm43xx_private {
bad_frames_preempt:1, /* Use "Bad Frames Preemption" (default off) */
reg124_set_0x4:1, /* Some variable to keep track of IRQ stuff. */
short_preamble:1, /* TRUE, if short preamble is enabled. */
- firmware_norelease:1; /* Do not release the firmware. Used on suspend. */
+ firmware_norelease:1, /* Do not release the firmware. Used on suspend. */
+ radio_hw_enable:1; /* TRUE if radio is hardware enabled */
struct bcm43xx_stats stats;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
index 7d383a27b92..8f198befba3 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
@@ -26,6 +26,7 @@
*/
#include "bcm43xx_leds.h"
+#include "bcm43xx_radio.h"
#include "bcm43xx.h"
#include <asm/bitops.h>
@@ -108,6 +109,7 @@ static void bcm43xx_led_init_hardcoded(struct bcm43xx_private *bcm,
switch (led_index) {
case 0:
led->behaviour = BCM43xx_LED_ACTIVITY;
+ led->activelow = 1;
if (bcm->board_vendor == PCI_VENDOR_ID_COMPAQ)
led->behaviour = BCM43xx_LED_RADIO_ALL;
break;
@@ -199,20 +201,21 @@ void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity)
turn_on = activity;
break;
case BCM43xx_LED_RADIO_ALL:
- turn_on = radio->enabled;
+ turn_on = radio->enabled && bcm43xx_is_hw_radio_enabled(bcm);
break;
case BCM43xx_LED_RADIO_A:
case BCM43xx_LED_BCM4303_2:
- turn_on = (radio->enabled && phy->type == BCM43xx_PHYTYPE_A);
+ turn_on = (radio->enabled && bcm43xx_is_hw_radio_enabled(bcm) &&
+ phy->type == BCM43xx_PHYTYPE_A);
break;
case BCM43xx_LED_RADIO_B:
case BCM43xx_LED_BCM4303_1:
- turn_on = (radio->enabled &&
+ turn_on = (radio->enabled && bcm43xx_is_hw_radio_enabled(bcm) &&
(phy->type == BCM43xx_PHYTYPE_B ||
phy->type == BCM43xx_PHYTYPE_G));
break;
case BCM43xx_LED_MODE_BG:
- if (phy->type == BCM43xx_PHYTYPE_G &&
+ if (phy->type == BCM43xx_PHYTYPE_G && bcm43xx_is_hw_radio_enabled(bcm) &&
1/*FIXME: using G rates.*/)
turn_on = 1;
break;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index 63fc16f6e58..2e400aacc43 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -2437,6 +2437,9 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
if (err)
goto err_gpio_cleanup;
bcm43xx_radio_turn_on(bcm);
+ bcm->radio_hw_enable = bcm43xx_is_hw_radio_enabled(bcm);
+ dprintk(KERN_INFO PFX "Radio %s by hardware\n",
+ (bcm->radio_hw_enable == 0) ? "disabled" : "enabled");
bcm43xx_write16(bcm, 0x03E6, 0x0000);
err = bcm43xx_phy_init(bcm);
@@ -3173,9 +3176,24 @@ static void bcm43xx_periodic_every30sec(struct bcm43xx_private *bcm)
static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm)
{
+ bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning?
+ //TODO for APHY (temperature?)
+}
+
+static void bcm43xx_periodic_every1sec(struct bcm43xx_private *bcm)
+{
struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+ int radio_hw_enable;
+ /* check if radio hardware enabled status changed */
+ radio_hw_enable = bcm43xx_is_hw_radio_enabled(bcm);
+ if (unlikely(bcm->radio_hw_enable != radio_hw_enable)) {
+ bcm->radio_hw_enable = radio_hw_enable;
+ dprintk(KERN_INFO PFX "Radio hardware status changed to %s\n",
+ (radio_hw_enable == 0) ? "disabled" : "enabled");
+ bcm43xx_leds_update(bcm, 0);
+ }
if (phy->type == BCM43xx_PHYTYPE_G) {
//TODO: update_aci_moving_average
if (radio->aci_enable && radio->aci_wlan_automatic) {
@@ -3199,21 +3217,21 @@ static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm)
//TODO: implement rev1 workaround
}
}
- bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning?
- //TODO for APHY (temperature?)
}
static void do_periodic_work(struct bcm43xx_private *bcm)
{
- if (bcm->periodic_state % 8 == 0)
+ if (bcm->periodic_state % 120 == 0)
bcm43xx_periodic_every120sec(bcm);
- if (bcm->periodic_state % 4 == 0)
+ if (bcm->periodic_state % 60 == 0)
bcm43xx_periodic_every60sec(bcm);
- if (bcm->periodic_state % 2 == 0)
+ if (bcm->periodic_state % 30 == 0)
bcm43xx_periodic_every30sec(bcm);
- bcm43xx_periodic_every15sec(bcm);
+ if (bcm->periodic_state % 15 == 0)
+ bcm43xx_periodic_every15sec(bcm);
+ bcm43xx_periodic_every1sec(bcm);
- schedule_delayed_work(&bcm->periodic_work, HZ * 15);
+ schedule_delayed_work(&bcm->periodic_work, HZ);
}
static void bcm43xx_periodic_work_handler(struct work_struct *work)
@@ -3226,7 +3244,7 @@ static void bcm43xx_periodic_work_handler(struct work_struct *work)
unsigned long orig_trans_start = 0;
mutex_lock(&bcm->mutex);
- if (unlikely(bcm->periodic_state % 4 == 0)) {
+ if (unlikely(bcm->periodic_state % 60 == 0)) {
/* Periodic work will take a long time, so we want it to
* be preemtible.
*/
@@ -3258,7 +3276,7 @@ static void bcm43xx_periodic_work_handler(struct work_struct *work)
do_periodic_work(bcm);
- if (unlikely(bcm->periodic_state % 4 == 0)) {
+ if (unlikely(bcm->periodic_state % 60 == 0)) {
spin_lock_irqsave(&bcm->irq_lock, flags);
tasklet_enable(&bcm->isr_tasklet);
bcm43xx_interrupt_enable(bcm, savedirqs);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
index bb9c484d7e1..af19a07032a 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
@@ -1981,6 +1981,7 @@ void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm)
}
radio->enabled = 1;
dprintk(KERN_INFO PFX "Radio turned on\n");
+ bcm43xx_leds_update(bcm, 0);
}
void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm)
@@ -2001,6 +2002,7 @@ void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm)
bcm43xx_phy_write(bcm, 0x0015, 0xAA00);
radio->enabled = 0;
dprintk(KERN_INFO PFX "Radio turned off\n");
+ bcm43xx_leds_update(bcm, 0);
}
void bcm43xx_radio_clear_tssi(struct bcm43xx_private *bcm)
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.h b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h
index 9ed18039fa3..77a98a53a2e 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h
@@ -65,6 +65,22 @@ void bcm43xx_radio_init2060(struct bcm43xx_private *bcm);
void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm);
void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm);
+static inline
+int bcm43xx_is_hw_radio_enabled(struct bcm43xx_private *bcm)
+{
+ /* function to return state of hardware enable of radio
+ * returns 0 if radio disabled, 1 if radio enabled
+ */
+ if (bcm->current_core->rev >= 3)
+ return ((bcm43xx_read32(bcm, BCM43xx_MMIO_RADIO_HWENABLED_HI)
+ & BCM43xx_MMIO_RADIO_HWENABLED_HI_MASK)
+ == 0) ? 1 : 0;
+ else
+ return ((bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_HWENABLED_LO)
+ & BCM43xx_MMIO_RADIO_HWENABLED_LO_MASK)
+ == 0) ? 0 : 1;
+}
+
int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm, u8 channel,
int synthetic_pu_workaround);
diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c
index 04c19cefa1d..9077e6edde3 100644
--- a/drivers/net/wireless/hostap/hostap_main.c
+++ b/drivers/net/wireless/hostap/hostap_main.c
@@ -84,7 +84,7 @@ struct net_device * hostap_add_interface(struct local_info *local,
if (strchr(dev->name, '%'))
ret = dev_alloc_name(dev, dev->name);
- SET_NETDEV_DEV(dev, mdev->class_dev.dev);
+ SET_NETDEV_DEV(dev, mdev->dev.parent);
if (ret >= 0)
ret = register_netdevice(dev);
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index 22cb3fb7502..c878a2f3239 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -9166,7 +9166,7 @@ static int ipw_wx_set_rts(struct net_device *dev,
{
struct ipw_priv *priv = ieee80211_priv(dev);
mutex_lock(&priv->mutex);
- if (wrqu->rts.disabled)
+ if (wrqu->rts.disabled || !wrqu->rts.fixed)
priv->rts_threshold = DEFAULT_RTS_THRESHOLD;
else {
if (wrqu->rts.value < MIN_RTS_THRESHOLD ||
@@ -9255,7 +9255,7 @@ static int ipw_wx_set_frag(struct net_device *dev,
{
struct ipw_priv *priv = ieee80211_priv(dev);
mutex_lock(&priv->mutex);
- if (wrqu->frag.disabled)
+ if (wrqu->frag.disabled || !wrqu->frag.fixed)
priv->ieee->fts = DEFAULT_FTS;
else {
if (wrqu->frag.value < MIN_FRAG_THRESHOLD ||
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
index 936c888e03e..4e7f6cf5143 100644
--- a/drivers/net/wireless/orinoco.c
+++ b/drivers/net/wireless/orinoco.c
@@ -2059,7 +2059,7 @@ static int determine_firmware(struct net_device *dev)
int err;
struct comp_id nic_id, sta_id;
unsigned int firmver;
- char tmp[SYMBOL_MAX_VER_LEN+1];
+ char tmp[SYMBOL_MAX_VER_LEN+1] __attribute__((aligned(2)));
/* Get the hardware version */
err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id);
@@ -4293,8 +4293,8 @@ static void orinoco_get_drvinfo(struct net_device *dev,
strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 1);
strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1);
strncpy(info->fw_version, priv->fw_name, sizeof(info->fw_version) - 1);
- if (dev->class_dev.dev)
- strncpy(info->bus_info, dev->class_dev.dev->bus_id,
+ if (dev->dev.parent)
+ strncpy(info->bus_info, dev->dev.parent->bus_id,
sizeof(info->bus_info) - 1);
else
snprintf(info->bus_info, sizeof(info->bus_info) - 1,
diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c
index d08ae8d2726..d1e502236b2 100644
--- a/drivers/net/wireless/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco_cs.c
@@ -332,7 +332,7 @@ orinoco_cs_config(struct pcmcia_device *link)
/* Finally, report what we've done */
printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io "
- "0x%04x-0x%04x\n", dev->name, dev->class_dev.dev->bus_id,
+ "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id,
link->irq.AssignedIRQ, link->io.BasePort1,
link->io.BasePort1 + link->io.NumPorts1 - 1);
diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c
index f057fd9fcd7..a037b11dac9 100644
--- a/drivers/net/wireless/prism54/islpci_dev.c
+++ b/drivers/net/wireless/prism54/islpci_dev.c
@@ -21,6 +21,7 @@
#include <linux/module.h>
#include <linux/netdevice.h>
+#include <linux/ethtool.h>
#include <linux/pci.h>
#include <linux/etherdevice.h>
#include <linux/delay.h>
@@ -787,6 +788,17 @@ islpci_set_multicast_list(struct net_device *dev)
}
#endif
+static void islpci_ethtool_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ strcpy(info->driver, DRV_NAME);
+ strcpy(info->version, DRV_VERSION);
+}
+
+static struct ethtool_ops islpci_ethtool_ops = {
+ .get_drvinfo = islpci_ethtool_get_drvinfo,
+};
+
struct net_device *
islpci_setup(struct pci_dev *pdev)
{
@@ -813,6 +825,7 @@ islpci_setup(struct pci_dev *pdev)
ndev->do_ioctl = &prism54_ioctl;
ndev->wireless_handlers =
(struct iw_handler_def *) &prism54_handler_def;
+ ndev->ethtool_ops = &islpci_ethtool_ops;
ndev->hard_start_xmit = &islpci_eth_transmit;
/* ndev->set_multicast_list = &islpci_set_multicast_list; */
diff --git a/drivers/net/wireless/prism54/islpci_dev.h b/drivers/net/wireless/prism54/islpci_dev.h
index a9aa1662eaa..736666da6c2 100644
--- a/drivers/net/wireless/prism54/islpci_dev.h
+++ b/drivers/net/wireless/prism54/islpci_dev.h
@@ -211,4 +211,8 @@ islpci_trigger(islpci_private *priv)
int islpci_free_memory(islpci_private *);
struct net_device *islpci_setup(struct pci_dev *);
+
+#define DRV_NAME "prism54"
+#define DRV_VERSION "1.2"
+
#endif /* _ISLPCI_DEV_H */
diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c
index 58257b40c04..3dcb13bb7d5 100644
--- a/drivers/net/wireless/prism54/islpci_hotplug.c
+++ b/drivers/net/wireless/prism54/islpci_hotplug.c
@@ -28,9 +28,6 @@
#include "islpci_mgt.h" /* for pc_debug */
#include "isl_oid.h"
-#define DRV_NAME "prism54"
-#define DRV_VERSION "1.2"
-
MODULE_AUTHOR("[Intersil] R.Bastings and W.Termorshuizen, The prism54.org Development Team <prism54-devel@prism54.org>");
MODULE_DESCRIPTION("The Prism54 802.11 Wireless LAN adapter");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c
index cf2d1486b01..af70460f008 100644
--- a/drivers/net/wireless/spectrum_cs.c
+++ b/drivers/net/wireless/spectrum_cs.c
@@ -806,7 +806,7 @@ spectrum_cs_config(struct pcmcia_device *link)
/* Finally, report what we've done */
printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io "
- "0x%04x-0x%04x\n", dev->name, dev->class_dev.dev->bus_id,
+ "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id,
link->irq.AssignedIRQ, link->io.BasePort1,
link->io.BasePort1 + link->io.NumPorts1 - 1);
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
index 78ea72fb8f0..12dfc0b6efe 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.c
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -84,6 +84,18 @@ static void print_id(struct zd_chip *chip)
dev_info(zd_chip_dev(chip), "%s\n", buffer);
}
+static zd_addr_t inc_addr(zd_addr_t addr)
+{
+ u16 a = (u16)addr;
+ /* Control registers use byte addressing, but everything else uses word
+ * addressing. */
+ if ((a & 0xf000) == CR_START)
+ a += 2;
+ else
+ a += 1;
+ return (zd_addr_t)a;
+}
+
/* Read a variable number of 32-bit values. Parameter count is not allowed to
* exceed USB_MAX_IOREAD32_COUNT.
*/
@@ -114,7 +126,7 @@ int zd_ioread32v_locked(struct zd_chip *chip, u32 *values, const zd_addr_t *addr
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] = inc_addr(addr[i]);
a16[j+1] = addr[i];
}
@@ -163,7 +175,7 @@ int _zd_iowrite32v_locked(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs,
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].addr = inc_addr(ioreqs[i].addr);
ioreqs16[j+1].value = ioreqs[i].value;
ioreqs16[j+1].addr = ioreqs[i].addr;
}
@@ -466,7 +478,8 @@ static int read_values(struct zd_chip *chip, u8 *values, size_t count,
ZD_ASSERT(mutex_is_locked(&chip->mutex));
for (i = 0;;) {
- r = zd_ioread32_locked(chip, &v, e2p_addr+i/2);
+ r = zd_ioread32_locked(chip, &v,
+ (zd_addr_t)((u16)e2p_addr+i/2));
if (r)
return r;
v -= guard;
@@ -798,47 +811,18 @@ static int hw_reset_phy(struct zd_chip *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_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;
+ return zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
}
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 },
@@ -847,6 +831,20 @@ static int zd1211b_hw_init_hmac(struct zd_chip *chip)
{ CR_ZD1211B_AIFS_CTL1, 0x00280028 },
{ CR_ZD1211B_AIFS_CTL2, 0x008C003C },
{ CR_ZD1211B_TXOP, 0x01800824 },
+ { CR_RX_THRESHOLD, 0x000c0eff, },
+ };
+
+ dev_dbg_f(zd_chip_dev(chip), "\n");
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ return zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static int hw_init_hmac(struct zd_chip *chip)
+{
+ int r;
+ static const struct zd_ioreq32 ioreqs[] = {
+ { CR_ACK_TIMEOUT_EXT, 0x20 },
+ { CR_ADDA_MBIAS_WARMTIME, 0x30000808 },
{ CR_SNIFFER_ON, 0 },
{ CR_RX_FILTER, STA_RX_FILTER },
{ CR_GROUP_HASH_P1, 0x00 },
@@ -861,25 +859,16 @@ static int zd1211b_hw_init_hmac(struct zd_chip *chip)
{ CR_RX_PE_DELAY, 0x70 },
{ CR_PS_CTRL, 0x10000000 },
{ CR_RTS_CTS_RATE, 0x02030203 },
- { CR_RX_THRESHOLD, 0x000c0eff, },
{ CR_AFTER_PNP, 0x1 },
{ CR_WEP_PROTECT, 0x114 },
+ { CR_IFS_VALUE, IFS_VALUE_DEFAULT },
};
- 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;
-}
+ if (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);
}
@@ -974,16 +963,14 @@ static int hw_init(struct zd_chip *chip)
if (r)
return r;
- /* Although the vendor driver defaults to a different value during
- * init, it overwrites the IFS value with the following every time
- * the channel changes. We should aim to be more intelligent... */
- r = zd_iowrite32_locked(chip, IFS_VALUE_DEFAULT, CR_IFS_VALUE);
- if (r)
- return r;
-
return set_beacon_interval(chip, 100);
}
+static zd_addr_t fw_reg_addr(struct zd_chip *chip, u16 offset)
+{
+ return (zd_addr_t)((u16)chip->fw_regs_base + offset);
+}
+
#ifdef DEBUG
static int dump_cr(struct zd_chip *chip, const zd_addr_t addr,
const char *addr_string)
@@ -1018,9 +1005,11 @@ static int test_init(struct zd_chip *chip)
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
+ const zd_addr_t addr[4] = {
+ fw_reg_addr(chip, FW_REG_FIRMWARE_VER),
+ fw_reg_addr(chip, FW_REG_USB_SPEED),
+ fw_reg_addr(chip, FW_REG_FIX_TX_RATE),
+ fw_reg_addr(chip, FW_REG_LED_LINK_STATUS),
};
int r;
@@ -1046,7 +1035,8 @@ static int print_fw_version(struct zd_chip *chip)
int r;
u16 version;
- r = zd_ioread16_locked(chip, &version, FW_FIRMWARE_VER);
+ r = zd_ioread16_locked(chip, &version,
+ fw_reg_addr(chip, FW_REG_FIRMWARE_VER));
if (r)
return r;
@@ -1126,6 +1116,22 @@ int zd_chip_disable_hwint(struct zd_chip *chip)
return r;
}
+static int read_fw_regs_offset(struct zd_chip *chip)
+{
+ int r;
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ r = zd_ioread16_locked(chip, (u16*)&chip->fw_regs_base,
+ FWRAW_REGS_ADDR);
+ if (r)
+ return r;
+ dev_dbg_f(zd_chip_dev(chip), "fw_regs_base: %#06hx\n",
+ (u16)chip->fw_regs_base);
+
+ return 0;
+}
+
+
int zd_chip_init_hw(struct zd_chip *chip, u8 device_type)
{
int r;
@@ -1145,7 +1151,7 @@ int zd_chip_init_hw(struct zd_chip *chip, u8 device_type)
if (r)
goto out;
- r = zd_usb_init_hw(&chip->usb);
+ r = read_fw_regs_offset(chip);
if (r)
goto out;
@@ -1325,15 +1331,15 @@ u8 zd_chip_get_channel(struct zd_chip *chip)
int zd_chip_control_leds(struct zd_chip *chip, enum led_status status)
{
- static const zd_addr_t a[] = {
- FW_LINK_STATUS,
+ const zd_addr_t a[] = {
+ fw_reg_addr(chip, FW_REG_LED_LINK_STATUS),
CR_LED,
};
int r;
u16 v[ARRAY_SIZE(a)];
struct zd_ioreq16 ioreqs[ARRAY_SIZE(a)] = {
- [0] = { FW_LINK_STATUS },
+ [0] = { fw_reg_addr(chip, FW_REG_LED_LINK_STATUS) },
[1] = { CR_LED },
};
u16 other_led;
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h
index a4e3cee9b59..b07569e391e 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.h
+++ b/drivers/net/wireless/zd1211rw/zd_chip.h
@@ -18,7 +18,6 @@
#ifndef _ZD_CHIP_H
#define _ZD_CHIP_H
-#include "zd_types.h"
#include "zd_rf.h"
#include "zd_usb.h"
@@ -27,6 +26,37 @@
* adds a processor for handling the USB protocol.
*/
+/* Address space */
+enum {
+ /* CONTROL REGISTERS */
+ CR_START = 0x9000,
+
+
+ /* FIRMWARE */
+ FW_START = 0xee00,
+
+
+ /* EEPROM */
+ E2P_START = 0xf800,
+ E2P_LEN = 0x800,
+
+ /* EEPROM layout */
+ E2P_LOAD_CODE_LEN = 0xe, /* base 0xf800 */
+ E2P_LOAD_VECT_LEN = 0x9, /* base 0xf80e */
+ /* E2P_DATA indexes into this */
+ E2P_DATA_LEN = 0x7e, /* base 0xf817 */
+ E2P_BOOT_CODE_LEN = 0x760, /* base 0xf895 */
+ E2P_INTR_VECT_LEN = 0xb, /* base 0xfff5 */
+
+ /* Some precomputed offsets into the EEPROM */
+ E2P_DATA_OFFSET = E2P_LOAD_CODE_LEN + E2P_LOAD_VECT_LEN,
+ E2P_BOOT_CODE_OFFSET = E2P_DATA_OFFSET + E2P_DATA_LEN,
+};
+
+#define CTL_REG(offset) ((zd_addr_t)(CR_START + (offset)))
+#define E2P_DATA(offset) ((zd_addr_t)(E2P_START + E2P_DATA_OFFSET + (offset)))
+#define FWRAW_DATA(offset) ((zd_addr_t)(FW_START + (offset)))
+
/* 8-bit hardware registers */
#define CR0 CTL_REG(0x0000)
#define CR1 CTL_REG(0x0004)
@@ -302,7 +332,7 @@
#define CR_MAX_PHY_REG 255
-/* Taken from the ZYDAS driver, not all of them are relevant for the ZSD1211
+/* Taken from the ZYDAS driver, not all of them are relevant for the ZD1211
* driver.
*/
@@ -594,81 +624,71 @@
/*
* 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)
+#define E2P_SUBID E2P_DATA(0x00)
+#define E2P_POD E2P_DATA(0x02)
+#define E2P_MAC_ADDR_P1 E2P_DATA(0x04)
+#define E2P_MAC_ADDR_P2 E2P_DATA(0x06)
+#define E2P_PWR_CAL_VALUE1 E2P_DATA(0x08)
+#define E2P_PWR_CAL_VALUE2 E2P_DATA(0x0a)
+#define E2P_PWR_CAL_VALUE3 E2P_DATA(0x0c)
+#define E2P_PWR_CAL_VALUE4 E2P_DATA(0x0e)
+#define E2P_PWR_INT_VALUE1 E2P_DATA(0x10)
+#define E2P_PWR_INT_VALUE2 E2P_DATA(0x12)
+#define E2P_PWR_INT_VALUE3 E2P_DATA(0x14)
+#define E2P_PWR_INT_VALUE4 E2P_DATA(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)
+#define E2P_ALLOWED_CHANNEL E2P_DATA(0x18)
+
+#define E2P_PHY_REG E2P_DATA(0x1a)
+#define E2P_DEVICE_VER E2P_DATA(0x20)
+#define E2P_36M_CAL_VALUE1 E2P_DATA(0x28)
+#define E2P_36M_CAL_VALUE2 E2P_DATA(0x2a)
+#define E2P_36M_CAL_VALUE3 E2P_DATA(0x2c)
+#define E2P_36M_CAL_VALUE4 E2P_DATA(0x2e)
+#define E2P_11A_INT_VALUE1 E2P_DATA(0x30)
+#define E2P_11A_INT_VALUE2 E2P_DATA(0x32)
+#define E2P_11A_INT_VALUE3 E2P_DATA(0x34)
+#define E2P_11A_INT_VALUE4 E2P_DATA(0x36)
+#define E2P_48M_CAL_VALUE1 E2P_DATA(0x38)
+#define E2P_48M_CAL_VALUE2 E2P_DATA(0x3a)
+#define E2P_48M_CAL_VALUE3 E2P_DATA(0x3c)
+#define E2P_48M_CAL_VALUE4 E2P_DATA(0x3e)
+#define E2P_48M_INT_VALUE1 E2P_DATA(0x40)
+#define E2P_48M_INT_VALUE2 E2P_DATA(0x42)
+#define E2P_48M_INT_VALUE3 E2P_DATA(0x44)
+#define E2P_48M_INT_VALUE4 E2P_DATA(0x46)
+#define E2P_54M_CAL_VALUE1 E2P_DATA(0x48) /* ??? */
+#define E2P_54M_CAL_VALUE2 E2P_DATA(0x4a)
+#define E2P_54M_CAL_VALUE3 E2P_DATA(0x4c)
+#define E2P_54M_CAL_VALUE4 E2P_DATA(0x4e)
+#define E2P_54M_INT_VALUE1 E2P_DATA(0x50)
+#define E2P_54M_INT_VALUE2 E2P_DATA(0x52)
+#define E2P_54M_INT_VALUE3 E2P_DATA(0x54)
+#define E2P_54M_INT_VALUE4 E2P_DATA(0x56)
+
+/* This word contains the base address of the FW_REG_ registers below */
+#define FWRAW_REGS_ADDR FWRAW_DATA(0x1d)
+
+/* All 16 bit values, offset from the address in FWRAW_REGS_ADDR */
+enum {
+ FW_REG_FIRMWARE_VER = 0,
+ /* non-zero if USB high speed connection */
+ FW_REG_USB_SPEED = 1,
+ FW_REG_FIX_TX_RATE = 2,
+ /* Seems to be able to control LEDs over the firmware */
+ FW_REG_LED_LINK_STATUS = 3,
+ FW_REG_SOFT_RESET = 4,
+ FW_REG_FLASH_CHK = 5,
+};
+/* Values for FW_LINK_STATUS */
#define FW_LINK_OFF 0x0
#define FW_LINK_TX 0x1
/* 0x2 - link led on? */
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,
- EEPROM_REGS_SIZE = 0x7e, /* words */
- 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,
@@ -679,6 +699,8 @@ struct zd_chip {
struct zd_usb usb;
struct zd_rf rf;
struct mutex mutex;
+ /* Base address of FW_REG_ registers */
+ zd_addr_t fw_regs_base;
u8 e2p_mac[ETH_ALEN];
/* EepSetPoint in the vendor driver */
u8 pwr_cal_values[E2P_CHANNEL_COUNT];
diff --git a/drivers/net/wireless/zd1211rw/zd_def.h b/drivers/net/wireless/zd1211rw/zd_def.h
index fb22f62cf1f..deb99d1eaa7 100644
--- a/drivers/net/wireless/zd1211rw/zd_def.h
+++ b/drivers/net/wireless/zd1211rw/zd_def.h
@@ -23,6 +23,8 @@
#include <linux/device.h>
#include <linux/kernel.h>
+typedef u16 __nocast zd_addr_t;
+
#define dev_printk_f(level, dev, fmt, args...) \
dev_printk(level, dev, "%s() " fmt, __func__, ##args)
diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.h b/drivers/net/wireless/zd1211rw/zd_ieee80211.h
index 26b8298dff8..c4f36d39642 100644
--- a/drivers/net/wireless/zd1211rw/zd_ieee80211.h
+++ b/drivers/net/wireless/zd1211rw/zd_ieee80211.h
@@ -2,7 +2,6 @@
#define _ZD_IEEE80211_H
#include <net/ieee80211.h>
-#include "zd_types.h"
/* Additional definitions from the standards.
*/
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.h b/drivers/net/wireless/zd1211rw/zd_rf.h
index 676b3734f1e..a57732eb69e 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf.h
+++ b/drivers/net/wireless/zd1211rw/zd_rf.h
@@ -18,8 +18,6 @@
#ifndef _ZD_RF_H
#define _ZD_RF_H
-#include "zd_types.h"
-
#define UW2451_RF 0x2
#define UCHIP_RF 0x3
#define AL2230_RF 0x4
diff --git a/drivers/net/wireless/zd1211rw/zd_types.h b/drivers/net/wireless/zd1211rw/zd_types.h
deleted file mode 100644
index 0155a1584ed..00000000000
--- a/drivers/net/wireless/zd1211rw/zd_types.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/* 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
index a3217a8d37c..aac8a1c5ba0 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -58,6 +58,10 @@ static struct usb_device_id usb_ids[] = {
{ USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x050d, 0x705c), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x13b1, 0x0024), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0586, 0x340f), .driver_info = DEVICE_ZD1211B },
/* "Driverless" devices that need ejecting */
{ USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
{}
@@ -73,96 +77,6 @@ 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(
@@ -295,14 +209,13 @@ static int handle_version_mismatch(struct usb_device *udev, u8 device_type,
if (r)
goto error;
- r = upload_code(udev, ur_fw->data, ur_fw->size, FW_START_OFFSET,
- REBOOT);
+ r = upload_code(udev, ur_fw->data, ur_fw->size, FW_START, REBOOT);
if (r)
goto error;
- offset = ((EEPROM_REGS_OFFSET + EEPROM_REGS_SIZE) * sizeof(u16));
+ offset = (E2P_BOOT_CODE_OFFSET * sizeof(u16));
r = upload_code(udev, ub_fw->data + offset, ub_fw->size - offset,
- E2P_BASE_OFFSET + EEPROM_REGS_SIZE, REBOOT);
+ E2P_START + E2P_BOOT_CODE_OFFSET, REBOOT);
/* At this point, the vendor driver downloads the whole firmware
* image, hacks around with version IDs, and uploads it again,
@@ -331,7 +244,7 @@ static int upload_firmware(struct usb_device *udev, u8 device_type)
if (r)
goto error;
- fw_bcdDevice = get_word(ub_fw->data, EEPROM_REGS_OFFSET);
+ fw_bcdDevice = get_word(ub_fw->data, E2P_DATA_OFFSET);
if (fw_bcdDevice != bcdDevice) {
dev_info(&udev->dev,
@@ -357,8 +270,7 @@ static int upload_firmware(struct usb_device *udev, u8 device_type)
if (r)
goto error;
- r = upload_code(udev, uph_fw->data, uph_fw->size, FW_START_OFFSET,
- REBOOT);
+ r = upload_code(udev, uph_fw->data, uph_fw->size, FW_START, REBOOT);
if (r) {
dev_err(&udev->dev,
"Could not upload firmware code uph. Error number %d\n",
@@ -867,7 +779,7 @@ static inline void init_usb_interrupt(struct zd_usb *usb)
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));
+ intr->read_regs.cr_int_addr = cpu_to_le16((u16)CR_INTERRUPT);
}
static inline void init_usb_rx(struct zd_usb *usb)
@@ -899,22 +811,6 @@ void zd_usb_init(struct zd_usb *usb, struct net_device *netdev,
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);
@@ -1265,7 +1161,7 @@ int zd_usb_ioread16v(struct zd_usb *usb, u16 *values,
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]));
+ req->addr[i] = cpu_to_le16((u16)addresses[i]);
udev = zd_usb_to_usbdev(usb);
prepare_read_regs_int(usb);
@@ -1330,7 +1226,7 @@ int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs,
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->addr = cpu_to_le16((u16)ioreqs[i].addr);
rw->value = cpu_to_le16(ioreqs[i].value);
}
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h
index 317d37c3667..506ea6a7439 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.h
+++ b/drivers/net/wireless/zd1211rw/zd_usb.h
@@ -25,7 +25,6 @@
#include <linux/usb.h>
#include "zd_def.h"
-#include "zd_types.h"
enum devicetype {
DEVICE_ZD1211 = 0,
@@ -181,15 +180,14 @@ 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.
+/* Contains the usb parts. The structure doesn't require a lock because intf
+ * 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)
diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig
index adce4204d87..be92695a783 100644
--- a/drivers/pci/hotplug/Kconfig
+++ b/drivers/pci/hotplug/Kconfig
@@ -145,15 +145,6 @@ config HOTPLUG_PCI_SHPC
When in doubt, say N.
-config HOTPLUG_PCI_SHPC_POLL_EVENT_MODE
- bool "Use polling mechanism for hot-plug events (for testing purpose)"
- depends on HOTPLUG_PCI_SHPC
- help
- Say Y here if you want to use the polling mechanism for hot-plug
- events for early platform testing.
-
- When in doubt, say N.
-
config HOTPLUG_PCI_RPA
tristate "RPA PCI Hotplug driver"
depends on HOTPLUG_PCI && PPC_PSERIES && PPC64 && !HOTPLUG_PCI_FAKE
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index bd1faebf61a..fca978fb158 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -773,13 +773,13 @@ static int get_gsi_base(acpi_handle handle, u32 *gsi_base)
goto out;
table = obj->buffer.pointer;
- switch (((acpi_table_entry_header *)table)->type) {
- case ACPI_MADT_IOSAPIC:
- *gsi_base = ((struct acpi_table_iosapic *)table)->global_irq_base;
+ switch (((struct acpi_subtable_header *)table)->type) {
+ case ACPI_MADT_TYPE_IO_SAPIC:
+ *gsi_base = ((struct acpi_madt_io_sapic *)table)->global_irq_base;
result = 0;
break;
- case ACPI_MADT_IOAPIC:
- *gsi_base = ((struct acpi_table_ioapic *)table)->global_irq_base;
+ case ACPI_MADT_TYPE_IO_APIC:
+ *gsi_base = ((struct acpi_madt_io_apic *)table)->global_irq_base;
result = 0;
break;
default:
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index 4fb12fcda56..d19fcae8a7c 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -44,15 +44,20 @@ extern int pciehp_poll_time;
extern int pciehp_debug;
extern int pciehp_force;
-/*#define dbg(format, arg...) do { if (pciehp_debug) printk(KERN_DEBUG "%s: " format, MY_NAME , ## arg); } while (0)*/
-#define dbg(format, arg...) do { if (pciehp_debug) printk("%s: " format, MY_NAME , ## arg); } while (0)
-#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
-#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
-#define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
-
+#define dbg(format, arg...) \
+ do { \
+ if (pciehp_debug) \
+ printk("%s: " format, MY_NAME , ## arg); \
+ } while (0)
+#define err(format, arg...) \
+ printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
+#define info(format, arg...) \
+ printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
+#define warn(format, arg...) \
+ printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
+#define SLOT_NAME_SIZE 10
struct slot {
- struct slot *next;
u8 bus;
u8 device;
u32 number;
@@ -63,6 +68,8 @@ struct slot {
struct hpc_ops *hpc_ops;
struct hotplug_slot *hotplug_slot;
struct list_head slot_list;
+ char name[SLOT_NAME_SIZE];
+ unsigned long last_emi_toggle;
};
struct event_info {
@@ -70,34 +77,15 @@ struct event_info {
u8 hp_slot;
};
-typedef u8(*php_intr_callback_t) (u8 hp_slot, void *instance_id);
-
-struct php_ctlr_state_s {
- struct php_ctlr_state_s *pnext;
- struct pci_dev *pci_dev;
- unsigned int irq;
- unsigned long flags; /* spinlock's */
- u32 slot_device_offset;
- u32 num_slots;
- struct timer_list int_poll_timer; /* Added for poll event */
- php_intr_callback_t attention_button_callback;
- php_intr_callback_t switch_change_callback;
- php_intr_callback_t presence_change_callback;
- php_intr_callback_t power_fault_callback;
- void *callback_instance_id;
- struct ctrl_reg *creg; /* Ptr to controller register space */
-};
-
#define MAX_EVENTS 10
struct controller {
struct controller *next;
struct mutex crit_sect; /* critical section mutex */
struct mutex ctrl_lock; /* controller lock */
- struct php_ctlr_state_s *hpc_ctlr_handle; /* HPC controller handle */
int num_slots; /* Number of slots on ctlr */
int slot_num_inc; /* 1 or -1 */
struct pci_dev *pci_dev;
- struct pci_bus *pci_bus;
+ struct list_head slot_list;
struct event_info event_queue[MAX_EVENTS];
struct slot *slot;
struct hpc_ops *hpc_ops;
@@ -112,6 +100,8 @@ struct controller {
u8 ctrlcap;
u16 vendor_id;
u8 cap_base;
+ struct timer_list poll_timer;
+ volatile int cmd_busy;
};
#define INT_BUTTON_IGNORE 0
@@ -131,8 +121,6 @@ struct controller {
#define POWERON_STATE 3
#define POWEROFF_STATE 4
-#define PCI_TO_PCI_BRIDGE_CLASS 0x00060400
-
/* Error messages */
#define INTERLOCK_OPEN 0x00000002
#define ADD_NOT_SUPPORTED 0x00000003
@@ -144,10 +132,6 @@ struct controller {
#define WRONG_BUS_FREQUENCY 0x0000000D
#define POWER_FAILURE 0x0000000E
-#define REMOVE_NOT_SUPPORTED 0x00000003
-
-#define DISABLE_CARD 1
-
/* Field definitions in Slot Capabilities Register */
#define ATTN_BUTTN_PRSN 0x00000001
#define PWR_CTRL_PRSN 0x00000002
@@ -155,6 +139,7 @@ struct controller {
#define ATTN_LED_PRSN 0x00000008
#define PWR_LED_PRSN 0x00000010
#define HP_SUPR_RM_SUP 0x00000020
+#define EMI_PRSN 0x00020000
#define ATTN_BUTTN(cap) (cap & ATTN_BUTTN_PRSN)
#define POWER_CTRL(cap) (cap & PWR_CTRL_PRSN)
@@ -162,130 +147,65 @@ struct controller {
#define ATTN_LED(cap) (cap & ATTN_LED_PRSN)
#define PWR_LED(cap) (cap & PWR_LED_PRSN)
#define HP_SUPR_RM(cap) (cap & HP_SUPR_RM_SUP)
-
-/*
- * error Messages
- */
-#define msg_initialization_err "Initialization failure, error=%d\n"
-#define msg_button_on "PCI slot #%s - powering on due to button press.\n"
-#define msg_button_off "PCI slot #%s - powering off due to button press.\n"
-#define msg_button_cancel "PCI slot #%s - action canceled due to button press.\n"
-#define msg_button_ignore "PCI slot #%s - button press ignored. (action in progress...)\n"
-
-/* controller functions */
-extern int pciehp_event_start_thread (void);
-extern void pciehp_event_stop_thread (void);
-extern int pciehp_enable_slot (struct slot *slot);
-extern int pciehp_disable_slot (struct slot *slot);
-
-extern u8 pciehp_handle_attention_button (u8 hp_slot, void *inst_id);
-extern u8 pciehp_handle_switch_change (u8 hp_slot, void *inst_id);
-extern u8 pciehp_handle_presence_change (u8 hp_slot, void *inst_id);
-extern u8 pciehp_handle_power_fault (u8 hp_slot, void *inst_id);
-/* extern void long_delay (int delay); */
-
-/* pci functions */
-extern int pciehp_configure_device (struct slot *p_slot);
-extern int pciehp_unconfigure_device (struct slot *p_slot);
-
-
+#define EMI(cap) (cap & EMI_PRSN)
+
+extern int pciehp_event_start_thread(void);
+extern void pciehp_event_stop_thread(void);
+extern int pciehp_enable_slot(struct slot *slot);
+extern int pciehp_disable_slot(struct slot *slot);
+extern u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl);
+extern u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl);
+extern u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl);
+extern u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl);
+extern int pciehp_configure_device(struct slot *p_slot);
+extern int pciehp_unconfigure_device(struct slot *p_slot);
+int pcie_init(struct controller *ctrl, struct pcie_device *dev);
/* Global variables */
extern struct controller *pciehp_ctrl_list;
-/* Inline functions */
-
static inline struct slot *pciehp_find_slot(struct controller *ctrl, u8 device)
{
- struct slot *p_slot, *tmp_slot = NULL;
-
- p_slot = ctrl->slot;
+ struct slot *slot;
- while (p_slot && (p_slot->device != device)) {
- tmp_slot = p_slot;
- p_slot = p_slot->next;
+ list_for_each_entry(slot, &ctrl->slot_list, slot_list) {
+ if (slot->device == device)
+ return slot;
}
- if (p_slot == NULL) {
- err("ERROR: pciehp_find_slot device=0x%x\n", device);
- p_slot = tmp_slot;
- }
-
- return p_slot;
-}
-
-static inline int wait_for_ctrl_irq(struct controller *ctrl)
-{
- int retval = 0;
-
- DECLARE_WAITQUEUE(wait, current);
-
- add_wait_queue(&ctrl->queue, &wait);
- if (!pciehp_poll_mode)
- /* Sleep for up to 1 second */
- msleep_interruptible(1000);
- else
- msleep_interruptible(2500);
-
- remove_wait_queue(&ctrl->queue, &wait);
- if (signal_pending(current))
- retval = -EINTR;
-
- return retval;
-}
-
-#define SLOT_NAME_SIZE 10
-static inline void make_slot_name(char *buffer, int buffer_size, struct slot *slot)
-{
- snprintf(buffer, buffer_size, "%04d_%04d", slot->bus, slot->number);
+ err("%s: slot (device=0x%x) not found\n", __FUNCTION__, device);
+ return NULL;
}
-enum php_ctlr_type {
- PCI,
- ISA,
- ACPI
-};
-
-int pcie_init(struct controller *ctrl, struct pcie_device *dev);
-
-/* This has no meaning for PCI Express, as there is only 1 slot per port */
-int pcie_get_ctlr_slot_config(struct controller *ctrl,
- int *num_ctlr_slots,
- int *first_device_num,
- int *physical_slot_num,
- u8 *ctrlcap);
-
struct hpc_ops {
- int (*power_on_slot) (struct slot *slot);
- int (*power_off_slot) (struct slot *slot);
- int (*get_power_status) (struct slot *slot, u8 *status);
- int (*get_attention_status) (struct slot *slot, u8 *status);
- int (*set_attention_status) (struct slot *slot, u8 status);
- int (*get_latch_status) (struct slot *slot, u8 *status);
- int (*get_adapter_status) (struct slot *slot, u8 *status);
-
- int (*get_max_bus_speed) (struct slot *slot, enum pci_bus_speed *speed);
- int (*get_cur_bus_speed) (struct slot *slot, enum pci_bus_speed *speed);
-
- int (*get_max_lnk_width) (struct slot *slot, enum pcie_link_width *value);
- int (*get_cur_lnk_width) (struct slot *slot, enum pcie_link_width *value);
-
- int (*query_power_fault) (struct slot *slot);
- void (*green_led_on) (struct slot *slot);
- void (*green_led_off) (struct slot *slot);
- void (*green_led_blink) (struct slot *slot);
- void (*release_ctlr) (struct controller *ctrl);
- int (*check_lnk_status) (struct controller *ctrl);
+ int (*power_on_slot)(struct slot *slot);
+ int (*power_off_slot)(struct slot *slot);
+ int (*get_power_status)(struct slot *slot, u8 *status);
+ int (*get_attention_status)(struct slot *slot, u8 *status);
+ int (*set_attention_status)(struct slot *slot, u8 status);
+ int (*get_latch_status)(struct slot *slot, u8 *status);
+ int (*get_adapter_status)(struct slot *slot, u8 *status);
+ int (*get_emi_status)(struct slot *slot, u8 *status);
+ int (*toggle_emi)(struct slot *slot);
+ int (*get_max_bus_speed)(struct slot *slot, enum pci_bus_speed *speed);
+ int (*get_cur_bus_speed)(struct slot *slot, enum pci_bus_speed *speed);
+ int (*get_max_lnk_width)(struct slot *slot, enum pcie_link_width *val);
+ int (*get_cur_lnk_width)(struct slot *slot, enum pcie_link_width *val);
+ int (*query_power_fault)(struct slot *slot);
+ void (*green_led_on)(struct slot *slot);
+ void (*green_led_off)(struct slot *slot);
+ void (*green_led_blink)(struct slot *slot);
+ void (*release_ctlr)(struct controller *ctrl);
+ int (*check_lnk_status)(struct controller *ctrl);
};
-
#ifdef CONFIG_ACPI
#include <acpi/acpi.h>
#include <acpi/acpi_bus.h>
#include <acpi/actypes.h>
#include <linux/pci-acpi.h>
-#define pciehp_get_hp_hw_control_from_firmware(dev) \
+#define pciehp_get_hp_hw_control_from_firmware(dev) \
pciehp_acpi_get_hp_hw_control_from_firmware(dev)
static inline int pciehp_get_hp_params_from_firmware(struct pci_dev *dev,
struct hotplug_params *hpp)
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index f13f31323e8..a92eda6e02f 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -34,6 +34,7 @@
#include <linux/pci.h>
#include "pciehp.h"
#include <linux/interrupt.h>
+#include <linux/time.h>
/* Global variables */
int pciehp_debug;
@@ -87,6 +88,95 @@ static struct hotplug_slot_ops pciehp_hotplug_slot_ops = {
.get_cur_bus_speed = get_cur_bus_speed,
};
+/*
+ * Check the status of the Electro Mechanical Interlock (EMI)
+ */
+static int get_lock_status(struct hotplug_slot *hotplug_slot, u8 *value)
+{
+ struct slot *slot = hotplug_slot->private;
+ return (slot->hpc_ops->get_emi_status(slot, value));
+}
+
+/*
+ * sysfs interface for the Electro Mechanical Interlock (EMI)
+ * 1 == locked, 0 == unlocked
+ */
+static ssize_t lock_read_file(struct hotplug_slot *slot, char *buf)
+{
+ int retval;
+ u8 value;
+
+ retval = get_lock_status(slot, &value);
+ if (retval)
+ goto lock_read_exit;
+ retval = sprintf (buf, "%d\n", value);
+
+lock_read_exit:
+ return retval;
+}
+
+/*
+ * Change the status of the Electro Mechanical Interlock (EMI)
+ * This is a toggle - in addition there must be at least 1 second
+ * in between toggles.
+ */
+static int set_lock_status(struct hotplug_slot *hotplug_slot, u8 status)
+{
+ struct slot *slot = hotplug_slot->private;
+ int retval;
+ u8 value;
+
+ mutex_lock(&slot->ctrl->crit_sect);
+
+ /* has it been >1 sec since our last toggle? */
+ if ((get_seconds() - slot->last_emi_toggle) < 1)
+ return -EINVAL;
+
+ /* see what our current state is */
+ retval = get_lock_status(hotplug_slot, &value);
+ if (retval || (value == status))
+ goto set_lock_exit;
+
+ slot->hpc_ops->toggle_emi(slot);
+set_lock_exit:
+ mutex_unlock(&slot->ctrl->crit_sect);
+ return 0;
+}
+
+/*
+ * sysfs interface which allows the user to toggle the Electro Mechanical
+ * Interlock. Valid values are either 0 or 1. 0 == unlock, 1 == lock
+ */
+static ssize_t lock_write_file(struct hotplug_slot *slot, const char *buf,
+ size_t count)
+{
+ unsigned long llock;
+ u8 lock;
+ int retval = 0;
+
+ llock = simple_strtoul(buf, NULL, 10);
+ lock = (u8)(llock & 0xff);
+
+ switch (lock) {
+ case 0:
+ case 1:
+ retval = set_lock_status(slot, lock);
+ break;
+ default:
+ err ("%d is an invalid lock value\n", lock);
+ retval = -EINVAL;
+ }
+ if (retval)
+ return retval;
+ return count;
+}
+
+static struct hotplug_slot_attribute hotplug_slot_attr_lock = {
+ .attr = {.name = "lock", .mode = S_IFREG | S_IRUGO | S_IWUSR},
+ .show = lock_read_file,
+ .store = lock_write_file
+};
+
/**
* release_slot - free up the memory used by a slot
* @hotplug_slot: slot to free
@@ -98,148 +188,108 @@ static void release_slot(struct hotplug_slot *hotplug_slot)
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
kfree(slot->hotplug_slot->info);
- kfree(slot->hotplug_slot->name);
kfree(slot->hotplug_slot);
kfree(slot);
}
+static void make_slot_name(struct slot *slot)
+{
+ snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%04d_%04d",
+ slot->bus, slot->number);
+}
+
static int init_slots(struct controller *ctrl)
{
struct slot *slot;
- struct hpc_ops *hpc_ops;
struct hotplug_slot *hotplug_slot;
- struct hotplug_slot_info *hotplug_slot_info;
- u8 number_of_slots;
- u8 slot_device;
- u32 slot_number;
- int result = -ENOMEM;
+ struct hotplug_slot_info *info;
+ int retval = -ENOMEM;
+ int i;
- number_of_slots = ctrl->num_slots;
- slot_device = ctrl->slot_device_offset;
- slot_number = ctrl->first_slot;
-
- while (number_of_slots) {
+ for (i = 0; i < ctrl->num_slots; i++) {
slot = kzalloc(sizeof(*slot), GFP_KERNEL);
if (!slot)
goto error;
- slot->hotplug_slot =
- kzalloc(sizeof(*(slot->hotplug_slot)),
- GFP_KERNEL);
- if (!slot->hotplug_slot)
+ hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL);
+ if (!hotplug_slot)
goto error_slot;
- hotplug_slot = slot->hotplug_slot;
+ slot->hotplug_slot = hotplug_slot;
- hotplug_slot->info =
- kzalloc(sizeof(*(hotplug_slot->info)),
- GFP_KERNEL);
- if (!hotplug_slot->info)
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
goto error_hpslot;
- hotplug_slot_info = hotplug_slot->info;
- hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL);
- if (!hotplug_slot->name)
- goto error_info;
+ hotplug_slot->info = info;
- slot->ctrl = ctrl;
- slot->bus = ctrl->slot_bus;
- slot->device = slot_device;
- slot->hpc_ops = hpc_ops = ctrl->hpc_ops;
+ hotplug_slot->name = slot->name;
+ slot->hp_slot = i;
+ slot->ctrl = ctrl;
+ slot->bus = ctrl->pci_dev->subordinate->number;
+ slot->device = ctrl->slot_device_offset + i;
+ slot->hpc_ops = ctrl->hpc_ops;
slot->number = ctrl->first_slot;
- slot->hp_slot = slot_device - ctrl->slot_device_offset;
/* register this slot with the hotplug pci core */
hotplug_slot->private = slot;
hotplug_slot->release = &release_slot;
- make_slot_name(hotplug_slot->name, SLOT_NAME_SIZE, slot);
+ make_slot_name(slot);
hotplug_slot->ops = &pciehp_hotplug_slot_ops;
- hpc_ops->get_power_status(slot,
- &(hotplug_slot_info->power_status));
- hpc_ops->get_attention_status(slot,
- &(hotplug_slot_info->attention_status));
- hpc_ops->get_latch_status(slot,
- &(hotplug_slot_info->latch_status));
- hpc_ops->get_adapter_status(slot,
- &(hotplug_slot_info->adapter_status));
+ get_power_status(hotplug_slot, &info->power_status);
+ get_attention_status(hotplug_slot, &info->attention_status);
+ get_latch_status(hotplug_slot, &info->latch_status);
+ get_adapter_status(hotplug_slot, &info->adapter_status);
dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x "
- "slot_device_offset=%x\n",
- slot->bus, slot->device, slot->hp_slot, slot->number,
- ctrl->slot_device_offset);
- result = pci_hp_register(hotplug_slot);
- if (result) {
- err ("pci_hp_register failed with error %d\n", result);
- goto error_name;
+ "slot_device_offset=%x\n", slot->bus, slot->device,
+ slot->hp_slot, slot->number, ctrl->slot_device_offset);
+ retval = pci_hp_register(hotplug_slot);
+ if (retval) {
+ err ("pci_hp_register failed with error %d\n", retval);
+ goto error_info;
+ }
+ /* create additional sysfs entries */
+ if (EMI(ctrl->ctrlcap)) {
+ retval = sysfs_create_file(&hotplug_slot->kobj,
+ &hotplug_slot_attr_lock.attr);
+ if (retval) {
+ pci_hp_deregister(hotplug_slot);
+ err("cannot create additional sysfs entries\n");
+ goto error_info;
+ }
}
- slot->next = ctrl->slot;
- ctrl->slot = slot;
-
- number_of_slots--;
- slot_device++;
- slot_number += ctrl->slot_num_inc;
+ list_add(&slot->slot_list, &ctrl->slot_list);
}
return 0;
-
-error_name:
- kfree(hotplug_slot->name);
error_info:
- kfree(hotplug_slot_info);
+ kfree(info);
error_hpslot:
kfree(hotplug_slot);
error_slot:
kfree(slot);
error:
- return result;
-}
-
-
-static int cleanup_slots (struct controller * ctrl)
-{
- struct slot *old_slot, *next_slot;
-
- old_slot = ctrl->slot;
- ctrl->slot = NULL;
-
- while (old_slot) {
- next_slot = old_slot->next;
- pci_hp_deregister (old_slot->hotplug_slot);
- old_slot = next_slot;
- }
-
-
- return(0);
+ return retval;
}
-static int get_ctlr_slot_config(struct controller *ctrl)
+static void cleanup_slots(struct controller *ctrl)
{
- int num_ctlr_slots; /* Not needed; PCI Express has 1 slot per port*/
- int first_device_num; /* Not needed */
- int physical_slot_num;
- u8 ctrlcap;
- int rc;
+ struct list_head *tmp;
+ struct list_head *next;
+ struct slot *slot;
- rc = pcie_get_ctlr_slot_config(ctrl, &num_ctlr_slots, &first_device_num, &physical_slot_num, &ctrlcap);
- if (rc) {
- err("%s: get_ctlr_slot_config fail for b:d (%x:%x)\n", __FUNCTION__, ctrl->bus, ctrl->device);
- return (-1);
+ list_for_each_safe(tmp, next, &ctrl->slot_list) {
+ slot = list_entry(tmp, struct slot, slot_list);
+ list_del(&slot->slot_list);
+ if (EMI(ctrl->ctrlcap))
+ sysfs_remove_file(&slot->hotplug_slot->kobj,
+ &hotplug_slot_attr_lock.attr);
+ pci_hp_deregister(slot->hotplug_slot);
}
-
- ctrl->num_slots = num_ctlr_slots; /* PCI Express has 1 slot per port */
- ctrl->slot_device_offset = first_device_num;
- ctrl->first_slot = physical_slot_num;
- ctrl->ctrlcap = ctrlcap;
-
- dbg("%s: bus(0x%x) num_slot(0x%x) 1st_dev(0x%x) psn(0x%x) ctrlcap(%x) for b:d (%x:%x)\n",
- __FUNCTION__, ctrl->slot_bus, num_ctlr_slots, first_device_num, physical_slot_num, ctrlcap,
- ctrl->bus, ctrl->device);
-
- return (0);
}
-
/*
* set_attention_status - Turns the Amber LED for a slot on, off or blink
*/
@@ -378,8 +428,6 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
int rc;
struct controller *ctrl;
struct slot *t_slot;
- int first_device_num = 0 ; /* first PCI device number supported by this PCIE */
- int num_ctlr_slots; /* number of slots supported by this HPC */
u8 value;
struct pci_dev *pdev;
@@ -388,6 +436,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
err("%s : out of memory\n", __FUNCTION__);
goto err_out_none;
}
+ INIT_LIST_HEAD(&ctrl->slot_list);
pdev = dev->port;
ctrl->pci_dev = pdev;
@@ -400,13 +449,6 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
pci_set_drvdata(pdev, ctrl);
- ctrl->pci_bus = kmalloc(sizeof(*ctrl->pci_bus), GFP_KERNEL);
- if (!ctrl->pci_bus) {
- err("%s: out of memory\n", __FUNCTION__);
- rc = -ENOMEM;
- goto err_out_unmap_mmio_region;
- }
- memcpy (ctrl->pci_bus, pdev->bus, sizeof (*ctrl->pci_bus));
ctrl->bus = pdev->bus->number; /* ctrl bus */
ctrl->slot_bus = pdev->subordinate->number; /* bus controlled by this HPC */
@@ -415,26 +457,14 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
dbg("%s: ctrl bus=0x%x, device=%x, function=%x, irq=%x\n", __FUNCTION__,
ctrl->bus, ctrl->device, ctrl->function, pdev->irq);
- /*
- * Save configuration headers for this and subordinate PCI buses
- */
-
- rc = get_ctlr_slot_config(ctrl);
- if (rc) {
- err(msg_initialization_err, rc);
- goto err_out_free_ctrl_bus;
- }
- first_device_num = ctrl->slot_device_offset;
- num_ctlr_slots = ctrl->num_slots;
-
/* Setup the slot information structures */
rc = init_slots(ctrl);
if (rc) {
- err(msg_initialization_err, 6);
- goto err_out_free_ctrl_slot;
+ err("%s: slot initialization failed\n", PCIE_MODULE_NAME);
+ goto err_out_release_ctlr;
}
- t_slot = pciehp_find_slot(ctrl, first_device_num);
+ t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset);
/* Finish setting up the hot plug ctrl device */
ctrl->next_event = 0;
@@ -447,32 +477,18 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
pciehp_ctrl_list = ctrl;
}
- /* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->ctrl_lock);
-
t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */
-
if ((POWER_CTRL(ctrl->ctrlcap)) && !value) {
rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/
- if (rc) {
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
+ if (rc)
goto err_out_free_ctrl_slot;
- } else
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
}
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
-
return 0;
err_out_free_ctrl_slot:
cleanup_slots(ctrl);
-err_out_free_ctrl_bus:
- kfree(ctrl->pci_bus);
-err_out_unmap_mmio_region:
+err_out_release_ctlr:
ctrl->hpc_ops->release_ctlr(ctrl);
err_out_free_ctrl:
kfree(ctrl);
@@ -506,8 +522,6 @@ static void __exit unload_pciehpd(void)
while (ctrl) {
cleanup_slots(ctrl);
- kfree (ctrl->pci_bus);
-
ctrl->hpc_ops->release_ctlr(ctrl);
tctrl = ctrl;
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index 372c63e35aa..4283ef56dbd 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -48,9 +48,8 @@ static inline char *slot_name(struct slot *p_slot)
return p_slot->hotplug_slot->name;
}
-u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id)
+u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl)
{
- struct controller *ctrl = (struct controller *) inst_id;
struct slot *p_slot;
u8 rc = 0;
u8 getstatus;
@@ -101,9 +100,8 @@ u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id)
}
-u8 pciehp_handle_switch_change(u8 hp_slot, void *inst_id)
+u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl)
{
- struct controller *ctrl = (struct controller *) inst_id;
struct slot *p_slot;
u8 rc = 0;
u8 getstatus;
@@ -143,9 +141,8 @@ u8 pciehp_handle_switch_change(u8 hp_slot, void *inst_id)
return rc;
}
-u8 pciehp_handle_presence_change(u8 hp_slot, void *inst_id)
+u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl)
{
- struct controller *ctrl = (struct controller *) inst_id;
struct slot *p_slot;
u8 presence_save, rc = 0;
struct event_info *taskInfo;
@@ -187,9 +184,8 @@ u8 pciehp_handle_presence_change(u8 hp_slot, void *inst_id)
return rc;
}
-u8 pciehp_handle_power_fault(u8 hp_slot, void *inst_id)
+u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl)
{
- struct controller *ctrl = (struct controller *) inst_id;
struct slot *p_slot;
u8 rc = 0;
struct event_info *taskInfo;
@@ -233,35 +229,25 @@ u8 pciehp_handle_power_fault(u8 hp_slot, void *inst_id)
static void set_slot_off(struct controller *ctrl, struct slot * pslot)
{
- /* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->ctrl_lock);
-
/* turn off slot, turn on Amber LED, turn off Green LED if supported*/
if (POWER_CTRL(ctrl->ctrlcap)) {
if (pslot->hpc_ops->power_off_slot(pslot)) {
- err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__);
- mutex_unlock(&ctrl->ctrl_lock);
+ err("%s: Issue of Slot Power Off command failed\n",
+ __FUNCTION__);
return;
}
- wait_for_ctrl_irq (ctrl);
}
- if (PWR_LED(ctrl->ctrlcap)) {
+ if (PWR_LED(ctrl->ctrlcap))
pslot->hpc_ops->green_led_off(pslot);
- wait_for_ctrl_irq (ctrl);
- }
- if (ATTN_LED(ctrl->ctrlcap)) {
- if (pslot->hpc_ops->set_attention_status(pslot, 1)) {
- err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__);
- mutex_unlock(&ctrl->ctrl_lock);
+ if (ATTN_LED(ctrl->ctrlcap)) {
+ if (pslot->hpc_ops->set_attention_status(pslot, 1)) {
+ err("%s: Issue of Set Attention Led command failed\n",
+ __FUNCTION__);
return;
}
- wait_for_ctrl_irq (ctrl);
}
-
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
}
/**
@@ -274,7 +260,7 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot)
static int board_added(struct slot *p_slot)
{
u8 hp_slot;
- int rc = 0;
+ int retval = 0;
struct controller *ctrl = p_slot->ctrl;
hp_slot = p_slot->device - ctrl->slot_device_offset;
@@ -283,53 +269,38 @@ static int board_added(struct slot *p_slot)
__FUNCTION__, p_slot->device,
ctrl->slot_device_offset, hp_slot);
- /* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->ctrl_lock);
-
if (POWER_CTRL(ctrl->ctrlcap)) {
/* Power on slot */
- rc = p_slot->hpc_ops->power_on_slot(p_slot);
- if (rc) {
- mutex_unlock(&ctrl->ctrl_lock);
- return -1;
- }
-
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
+ retval = p_slot->hpc_ops->power_on_slot(p_slot);
+ if (retval)
+ return retval;
}
- if (PWR_LED(ctrl->ctrlcap)) {
+ if (PWR_LED(ctrl->ctrlcap))
p_slot->hpc_ops->green_led_blink(p_slot);
-
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
- }
-
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
/* Wait for ~1 second */
- wait_for_ctrl_irq (ctrl);
+ msleep(1000);
- /* Check link training status */
- rc = p_slot->hpc_ops->check_lnk_status(ctrl);
- if (rc) {
+ /* Check link training status */
+ retval = p_slot->hpc_ops->check_lnk_status(ctrl);
+ if (retval) {
err("%s: Failed to check link status\n", __FUNCTION__);
set_slot_off(ctrl, p_slot);
- return rc;
+ return retval;
}
/* Check for a power fault */
if (p_slot->hpc_ops->query_power_fault(p_slot)) {
dbg("%s: power fault detected\n", __FUNCTION__);
- rc = POWER_FAILURE;
+ retval = POWER_FAILURE;
goto err_exit;
}
- rc = pciehp_configure_device(p_slot);
- if (rc) {
+ retval = pciehp_configure_device(p_slot);
+ if (retval) {
err("Cannot add device 0x%x:%x\n", p_slot->bus,
- p_slot->device);
+ p_slot->device);
goto err_exit;
}
@@ -338,26 +309,16 @@ static int board_added(struct slot *p_slot)
*/
if (pcie_mch_quirk)
pci_fixup_device(pci_fixup_final, ctrl->pci_dev);
- if (PWR_LED(ctrl->ctrlcap)) {
- /* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->ctrl_lock);
-
+ if (PWR_LED(ctrl->ctrlcap))
p_slot->hpc_ops->green_led_on(p_slot);
-
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
-
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
- }
+
return 0;
err_exit:
set_slot_off(ctrl, p_slot);
- return -1;
+ return retval;
}
-
/**
* remove_board - Turns off slot and LED's
*
@@ -366,44 +327,32 @@ static int remove_board(struct slot *p_slot)
{
u8 device;
u8 hp_slot;
- int rc;
+ int retval = 0;
struct controller *ctrl = p_slot->ctrl;
- if (pciehp_unconfigure_device(p_slot))
- return 1;
+ retval = pciehp_unconfigure_device(p_slot);
+ if (retval)
+ return retval;
device = p_slot->device;
-
hp_slot = p_slot->device - ctrl->slot_device_offset;
p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot);
- /* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->ctrl_lock);
-
if (POWER_CTRL(ctrl->ctrlcap)) {
/* power off slot */
- rc = p_slot->hpc_ops->power_off_slot(p_slot);
- if (rc) {
- err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
- mutex_unlock(&ctrl->ctrl_lock);
- return rc;
+ retval = p_slot->hpc_ops->power_off_slot(p_slot);
+ if (retval) {
+ err("%s: Issue of Slot Disable command failed\n",
+ __FUNCTION__);
+ return retval;
}
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
}
- if (PWR_LED(ctrl->ctrlcap)) {
+ if (PWR_LED(ctrl->ctrlcap))
/* turn off Green LED */
p_slot->hpc_ops->green_led_off(p_slot);
-
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
- }
-
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
return 0;
}
@@ -448,18 +397,10 @@ static void pciehp_pushbutton_thread(unsigned long slot)
dbg("%s: adding bus:device(%x:%x)\n", __FUNCTION__,
p_slot->bus, p_slot->device);
- if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) {
- /* Wait for exclusive access to hardware */
- mutex_lock(&p_slot->ctrl->ctrl_lock);
-
+ if (pciehp_enable_slot(p_slot) &&
+ PWR_LED(p_slot->ctrl->ctrlcap))
p_slot->hpc_ops->green_led_off(p_slot);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (p_slot->ctrl);
-
- /* Done with exclusive hardware access */
- mutex_unlock(&p_slot->ctrl->ctrl_lock);
- }
p_slot->state = STATIC_STATE;
}
@@ -498,18 +439,10 @@ static void pciehp_surprise_rm_thread(unsigned long slot)
dbg("%s: adding bus:device(%x:%x)\n",
__FUNCTION__, p_slot->bus, p_slot->device);
- if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) {
- /* Wait for exclusive access to hardware */
- mutex_lock(&p_slot->ctrl->ctrl_lock);
-
+ if (pciehp_enable_slot(p_slot) &&
+ PWR_LED(p_slot->ctrl->ctrlcap))
p_slot->hpc_ops->green_led_off(p_slot);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (p_slot->ctrl);
-
- /* Done with exclusive hardware access */
- mutex_unlock(&p_slot->ctrl->ctrl_lock);
- }
p_slot->state = STATIC_STATE;
}
@@ -620,46 +553,24 @@ static void interrupt_event_handler(struct controller *ctrl)
switch (p_slot->state) {
case BLINKINGOFF_STATE:
- /* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->ctrl_lock);
-
- if (PWR_LED(ctrl->ctrlcap)) {
+ if (PWR_LED(ctrl->ctrlcap))
p_slot->hpc_ops->green_led_on(p_slot);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
- }
- if (ATTN_LED(ctrl->ctrlcap)) {
- p_slot->hpc_ops->set_attention_status(p_slot, 0);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
- }
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
+ if (ATTN_LED(ctrl->ctrlcap))
+ p_slot->hpc_ops->set_attention_status(p_slot, 0);
break;
case BLINKINGON_STATE:
- /* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->ctrl_lock);
-
- if (PWR_LED(ctrl->ctrlcap)) {
+ if (PWR_LED(ctrl->ctrlcap))
p_slot->hpc_ops->green_led_off(p_slot);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
- }
- if (ATTN_LED(ctrl->ctrlcap)){
- p_slot->hpc_ops->set_attention_status(p_slot, 0);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
- }
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
+ if (ATTN_LED(ctrl->ctrlcap))
+ p_slot->hpc_ops->set_attention_status(p_slot, 0);
break;
default:
warn("Not a valid state\n");
return;
}
- info(msg_button_cancel, slot_name(p_slot));
+ info("PCI slot #%s - action canceled due to button press.\n", slot_name(p_slot));
p_slot->state = STATIC_STATE;
}
/* ***********Button Pressed (No action on 1st press...) */
@@ -672,34 +583,21 @@ static void interrupt_event_handler(struct controller *ctrl)
/* slot is on */
dbg("slot is on\n");
p_slot->state = BLINKINGOFF_STATE;
- info(msg_button_off, slot_name(p_slot));
+ info("PCI slot #%s - powering off due to button press.\n", slot_name(p_slot));
} else {
/* slot is off */
dbg("slot is off\n");
p_slot->state = BLINKINGON_STATE;
- info(msg_button_on, slot_name(p_slot));
+ info("PCI slot #%s - powering on due to button press.\n", slot_name(p_slot));
}
- /* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->ctrl_lock);
-
/* blink green LED and turn off amber */
- if (PWR_LED(ctrl->ctrlcap)) {
+ if (PWR_LED(ctrl->ctrlcap))
p_slot->hpc_ops->green_led_blink(p_slot);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
- }
- if (ATTN_LED(ctrl->ctrlcap)) {
+ if (ATTN_LED(ctrl->ctrlcap))
p_slot->hpc_ops->set_attention_status(p_slot, 0);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
- }
-
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
-
init_timer(&p_slot->task_event);
p_slot->task_event.expires = jiffies + 5 * HZ; /* 5 second delay */
p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread;
@@ -712,21 +610,11 @@ static void interrupt_event_handler(struct controller *ctrl)
else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) {
if (POWER_CTRL(ctrl->ctrlcap)) {
dbg("power fault\n");
- /* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->ctrl_lock);
-
- if (ATTN_LED(ctrl->ctrlcap)) {
+ if (ATTN_LED(ctrl->ctrlcap))
p_slot->hpc_ops->set_attention_status(p_slot, 1);
- wait_for_ctrl_irq (ctrl);
- }
- if (PWR_LED(ctrl->ctrlcap)) {
+ if (PWR_LED(ctrl->ctrlcap))
p_slot->hpc_ops->green_led_off(p_slot);
- wait_for_ctrl_irq (ctrl);
- }
-
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
}
}
/***********SURPRISE REMOVAL********************/
@@ -754,7 +642,6 @@ static void interrupt_event_handler(struct controller *ctrl)
}
}
-
int pciehp_enable_slot(struct slot *p_slot)
{
u8 getstatus = 0;
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index 25d3aadfddb..fbc64aa2dd6 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -35,6 +35,7 @@
#include <linux/timer.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
+#include <linux/time.h>
#include "../pci.h"
#include "pciehp.h"
@@ -105,34 +106,30 @@ enum ctrl_offsets {
ROOTCTRL = offsetof(struct ctrl_reg, root_ctrl),
ROOTSTATUS = offsetof(struct ctrl_reg, root_status),
};
-static int pcie_cap_base = 0; /* Base of the PCI Express capability item structure */
-
-#define PCIE_CAP_ID(cb) ( cb + PCIECAPID )
-#define NXT_CAP_PTR(cb) ( cb + NXTCAPPTR )
-#define CAP_REG(cb) ( cb + CAPREG )
-#define DEV_CAP(cb) ( cb + DEVCAP )
-#define DEV_CTRL(cb) ( cb + DEVCTRL )
-#define DEV_STATUS(cb) ( cb + DEVSTATUS )
-#define LNK_CAP(cb) ( cb + LNKCAP )
-#define LNK_CTRL(cb) ( cb + LNKCTRL )
-#define LNK_STATUS(cb) ( cb + LNKSTATUS )
-#define SLOT_CAP(cb) ( cb + SLOTCAP )
-#define SLOT_CTRL(cb) ( cb + SLOTCTRL )
-#define SLOT_STATUS(cb) ( cb + SLOTSTATUS )
-#define ROOT_CTRL(cb) ( cb + ROOTCTRL )
-#define ROOT_STATUS(cb) ( cb + ROOTSTATUS )
-
-#define hp_register_read_word(pdev, reg , value) \
- pci_read_config_word(pdev, reg, &value)
-
-#define hp_register_read_dword(pdev, reg , value) \
- pci_read_config_dword(pdev, reg, &value)
-
-#define hp_register_write_word(pdev, reg , value) \
- pci_write_config_word(pdev, reg, value)
-
-#define hp_register_dwrite_word(pdev, reg , value) \
- pci_write_config_dword(pdev, reg, value)
+
+static inline int pciehp_readw(struct controller *ctrl, int reg, u16 *value)
+{
+ struct pci_dev *dev = ctrl->pci_dev;
+ return pci_read_config_word(dev, ctrl->cap_base + reg, value);
+}
+
+static inline int pciehp_readl(struct controller *ctrl, int reg, u32 *value)
+{
+ struct pci_dev *dev = ctrl->pci_dev;
+ return pci_read_config_dword(dev, ctrl->cap_base + reg, value);
+}
+
+static inline int pciehp_writew(struct controller *ctrl, int reg, u16 value)
+{
+ struct pci_dev *dev = ctrl->pci_dev;
+ return pci_write_config_word(dev, ctrl->cap_base + reg, value);
+}
+
+static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value)
+{
+ struct pci_dev *dev = ctrl->pci_dev;
+ return pci_write_config_dword(dev, ctrl->cap_base + reg, value);
+}
/* Field definitions in PCI Express Capabilities Register */
#define CAP_VER 0x000F
@@ -196,6 +193,7 @@ static int pcie_cap_base = 0; /* Base of the PCI Express capability item struct
#define ATTN_LED_CTRL 0x00C0
#define PWR_LED_CTRL 0x0300
#define PWR_CTRL 0x0400
+#define EMI_CTRL 0x0800
/* Attention indicator and Power indicator states */
#define LED_ON 0x01
@@ -206,6 +204,10 @@ static int pcie_cap_base = 0; /* Base of the PCI Express capability item struct
#define POWER_ON 0
#define POWER_OFF 0x0400
+/* EMI Status defines */
+#define EMI_DISENGAGED 0
+#define EMI_ENGAGED 1
+
/* Field definitions in Slot Status Register */
#define ATTN_BUTTN_PRESSED 0x0001
#define PWR_FAULT_DETECTED 0x0002
@@ -214,114 +216,117 @@ static int pcie_cap_base = 0; /* Base of the PCI Express capability item struct
#define CMD_COMPLETED 0x0010
#define MRL_STATE 0x0020
#define PRSN_STATE 0x0040
+#define EMI_STATE 0x0080
+#define EMI_STATUS_BIT 7
static spinlock_t hpc_event_lock;
DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */
-static struct php_ctlr_state_s *php_ctlr_list_head; /* HPC state linked list */
static int ctlr_seq_num = 0; /* Controller sequence # */
-static spinlock_t list_lock;
-
-static irqreturn_t pcie_isr(int IRQ, void *dev_id);
-static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds);
+static irqreturn_t pcie_isr(int irq, void *dev_id);
+static void start_int_poll_timer(struct controller *ctrl, int sec);
/* This is the interrupt polling timeout function. */
-static void int_poll_timeout(unsigned long lphp_ctlr)
+static void int_poll_timeout(unsigned long data)
{
- struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *)lphp_ctlr;
+ struct controller *ctrl = (struct controller *)data;
DBG_ENTER_ROUTINE
- if ( !php_ctlr ) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return;
- }
-
/* Poll for interrupt events. regs == NULL => polling */
- pcie_isr( 0, (void *)php_ctlr );
-
- init_timer(&php_ctlr->int_poll_timer);
+ pcie_isr(0, ctrl);
+ init_timer(&ctrl->poll_timer);
if (!pciehp_poll_time)
pciehp_poll_time = 2; /* reset timer to poll in 2 secs if user doesn't specify at module installation*/
- start_int_poll_timer(php_ctlr, pciehp_poll_time);
-
- return;
+ start_int_poll_timer(ctrl, pciehp_poll_time);
}
/* This function starts the interrupt polling timer. */
-static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds)
+static void start_int_poll_timer(struct controller *ctrl, int sec)
{
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return;
- }
+ /* Clamp to sane value */
+ if ((sec <= 0) || (sec > 60))
+ sec = 2;
+
+ ctrl->poll_timer.function = &int_poll_timeout;
+ ctrl->poll_timer.data = (unsigned long)ctrl;
+ ctrl->poll_timer.expires = jiffies + sec * HZ;
+ add_timer(&ctrl->poll_timer);
+}
- if ( ( seconds <= 0 ) || ( seconds > 60 ) )
- seconds = 2; /* Clamp to sane value */
+static inline int pcie_wait_cmd(struct controller *ctrl)
+{
+ int retval = 0;
+ unsigned int msecs = pciehp_poll_mode ? 2500 : 1000;
+ unsigned long timeout = msecs_to_jiffies(msecs);
+ int rc;
- php_ctlr->int_poll_timer.function = &int_poll_timeout;
- php_ctlr->int_poll_timer.data = (unsigned long)php_ctlr; /* Instance data */
- php_ctlr->int_poll_timer.expires = jiffies + seconds * HZ;
- add_timer(&php_ctlr->int_poll_timer);
+ rc = wait_event_interruptible_timeout(ctrl->queue,
+ !ctrl->cmd_busy, timeout);
+ if (!rc)
+ dbg("Command not completed in 1000 msec\n");
+ else if (rc < 0) {
+ retval = -EINTR;
+ info("Command was interrupted by a signal\n");
+ }
- return;
+ return retval;
}
static int pcie_write_cmd(struct slot *slot, u16 cmd)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
int retval = 0;
u16 slot_status;
DBG_ENTER_ROUTINE
-
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
- retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status);
+ mutex_lock(&ctrl->ctrl_lock);
+
+ retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (retval) {
- err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
- return retval;
- }
-
+ err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
+ goto out;
+ }
+
if ((slot_status & CMD_COMPLETED) == CMD_COMPLETED ) {
- /* After 1 sec and CMD_COMPLETED still not set, just proceed forward to issue
- the next command according to spec. Just print out the error message */
- dbg("%s : CMD_COMPLETED not clear after 1 sec.\n", __FUNCTION__);
+ /* After 1 sec and CMD_COMPLETED still not set, just
+ proceed forward to issue the next command according
+ to spec. Just print out the error message */
+ dbg("%s: CMD_COMPLETED not clear after 1 sec.\n",
+ __FUNCTION__);
}
- retval = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), cmd | CMD_CMPL_INTR_ENABLE);
+ ctrl->cmd_busy = 1;
+ retval = pciehp_writew(ctrl, SLOTCTRL, (cmd | CMD_CMPL_INTR_ENABLE));
if (retval) {
- err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
- return retval;
+ err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
+ goto out;
}
+ /*
+ * Wait for command completion.
+ */
+ retval = pcie_wait_cmd(ctrl);
+ out:
+ mutex_unlock(&ctrl->ctrl_lock);
DBG_LEAVE_ROUTINE
return retval;
}
static int hpc_check_lnk_status(struct controller *ctrl)
{
- struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
u16 lnk_status;
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(ctrl->cap_base), lnk_status);
-
+ retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
if (retval) {
- err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__);
return retval;
}
@@ -340,26 +345,21 @@ static int hpc_check_lnk_status(struct controller *ctrl)
static int hpc_get_attention_status(struct slot *slot, u8 *status)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_ctrl;
u8 atten_led_state;
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
-
+ retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (retval) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
return retval;
}
- dbg("%s: SLOT_CTRL %x, value read %x\n", __FUNCTION__,SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
+ dbg("%s: SLOTCTRL %x, value read %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
atten_led_state = (slot_ctrl & ATTN_LED_CTRL) >> 6;
@@ -385,27 +385,22 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status)
return 0;
}
-static int hpc_get_power_status(struct slot * slot, u8 *status)
+static int hpc_get_power_status(struct slot *slot, u8 *status)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_ctrl;
u8 pwr_state;
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
-
+ retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (retval) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
return retval;
}
- dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
+ dbg("%s: SLOTCTRL %x value read %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
pwr_state = (slot_ctrl & PWR_CTRL) >> 10;
@@ -428,21 +423,15 @@ static int hpc_get_power_status(struct slot * slot, u8 *status)
static int hpc_get_latch_status(struct slot *slot, u8 *status)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_status;
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status);
-
+ retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (retval) {
- err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
return retval;
}
@@ -454,22 +443,16 @@ static int hpc_get_latch_status(struct slot *slot, u8 *status)
static int hpc_get_adapter_status(struct slot *slot, u8 *status)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_status;
u8 card_state;
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status);
-
+ retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (retval) {
- err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
return retval;
}
card_state = (u8)((slot_status & PRSN_STATE) >> 6);
@@ -479,24 +462,18 @@ static int hpc_get_adapter_status(struct slot *slot, u8 *status)
return 0;
}
-static int hpc_query_power_fault(struct slot * slot)
+static int hpc_query_power_fault(struct slot *slot)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_status;
u8 pwr_fault;
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status);
-
+ retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (retval) {
- err("%s : Cannot check for power fault\n", __FUNCTION__);
+ err("%s: Cannot check for power fault\n", __FUNCTION__);
return retval;
}
pwr_fault = (u8)((slot_status & PWR_FAULT_DETECTED) >> 1);
@@ -505,28 +482,63 @@ static int hpc_query_power_fault(struct slot * slot)
return pwr_fault;
}
-static int hpc_set_attention_status(struct slot *slot, u8 value)
+static int hpc_get_emi_status(struct slot *slot, u8 *status)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
+ u16 slot_status;
+ int retval = 0;
+
+ DBG_ENTER_ROUTINE
+
+ retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
+ if (retval) {
+ err("%s : Cannot check EMI status\n", __FUNCTION__);
+ return retval;
+ }
+ *status = (slot_status & EMI_STATE) >> EMI_STATUS_BIT;
+
+ DBG_LEAVE_ROUTINE
+ return retval;
+}
+
+static int hpc_toggle_emi(struct slot *slot)
+{
+ struct controller *ctrl = slot->ctrl;
u16 slot_cmd = 0;
u16 slot_ctrl;
int rc = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
+ rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
+ if (rc) {
+ err("%s : hp_register_read_word SLOT_CTRL failed\n",
+ __FUNCTION__);
+ return rc;
}
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return -1;
- }
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
+ slot_cmd = (slot_ctrl | EMI_CTRL);
+ if (!pciehp_poll_mode)
+ slot_cmd = slot_cmd | HP_INTR_ENABLE;
+ pcie_write_cmd(slot, slot_cmd);
+ slot->last_emi_toggle = get_seconds();
+ DBG_LEAVE_ROUTINE
+ return rc;
+}
+
+static int hpc_set_attention_status(struct slot *slot, u8 value)
+{
+ struct controller *ctrl = slot->ctrl;
+ u16 slot_cmd = 0;
+ u16 slot_ctrl;
+ int rc = 0;
+
+ DBG_ENTER_ROUTINE
+
+ rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (rc) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
return rc;
}
@@ -547,7 +559,8 @@ static int hpc_set_attention_status(struct slot *slot, u8 value)
slot_cmd = slot_cmd | HP_INTR_ENABLE;
pcie_write_cmd(slot, slot_cmd);
- dbg("%s: SLOT_CTRL %x write cmd %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+ dbg("%s: SLOTCTRL %x write cmd %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
DBG_LEAVE_ROUTINE
return rc;
@@ -556,27 +569,16 @@ static int hpc_set_attention_status(struct slot *slot, u8 value)
static void hpc_set_green_led_on(struct slot *slot)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_cmd;
u16 slot_ctrl;
int rc = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return ;
- }
-
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return ;
- }
-
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
-
+ rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (rc) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
return;
}
slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0100;
@@ -585,34 +587,24 @@ static void hpc_set_green_led_on(struct slot *slot)
pcie_write_cmd(slot, slot_cmd);
- dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+ dbg("%s: SLOTCTRL %x write cmd %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
DBG_LEAVE_ROUTINE
return;
}
static void hpc_set_green_led_off(struct slot *slot)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_cmd;
u16 slot_ctrl;
int rc = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return ;
- }
-
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return ;
- }
-
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
-
+ rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (rc) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
return;
}
@@ -621,7 +613,8 @@ static void hpc_set_green_led_off(struct slot *slot)
if (!pciehp_poll_mode)
slot_cmd = slot_cmd | HP_INTR_ENABLE;
pcie_write_cmd(slot, slot_cmd);
- dbg("%s: SLOT_CTRL %x write cmd %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+ dbg("%s: SLOTCTRL %x write cmd %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
DBG_LEAVE_ROUTINE
return;
@@ -629,27 +622,16 @@ static void hpc_set_green_led_off(struct slot *slot)
static void hpc_set_green_led_blink(struct slot *slot)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_cmd;
u16 slot_ctrl;
int rc = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return ;
- }
-
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return ;
- }
-
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
-
+ rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (rc) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
return;
}
@@ -659,126 +641,54 @@ static void hpc_set_green_led_blink(struct slot *slot)
slot_cmd = slot_cmd | HP_INTR_ENABLE;
pcie_write_cmd(slot, slot_cmd);
- dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+ dbg("%s: SLOTCTRL %x write cmd %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
DBG_LEAVE_ROUTINE
return;
}
-int pcie_get_ctlr_slot_config(struct controller *ctrl,
- int *num_ctlr_slots, /* number of slots in this HPC; only 1 in PCIE */
- int *first_device_num, /* PCI dev num of the first slot in this PCIE */
- int *physical_slot_num, /* phy slot num of the first slot in this PCIE */
- u8 *ctrlcap)
-{
- struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
- u32 slot_cap;
- int rc = 0;
-
- DBG_ENTER_ROUTINE
-
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- *first_device_num = 0;
- *num_ctlr_slots = 1;
-
- rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP(ctrl->cap_base), slot_cap);
-
- if (rc) {
- err("%s : hp_register_read_dword SLOT_CAP failed\n", __FUNCTION__);
- return -1;
- }
-
- *physical_slot_num = slot_cap >> 19;
- dbg("%s: PSN %d \n", __FUNCTION__, *physical_slot_num);
-
- *ctrlcap = slot_cap & 0x0000007f;
-
- DBG_LEAVE_ROUTINE
- return 0;
-}
-
static void hpc_release_ctlr(struct controller *ctrl)
{
- struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
- struct php_ctlr_state_s *p, *p_prev;
-
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return ;
- }
-
- if (pciehp_poll_mode) {
- del_timer(&php_ctlr->int_poll_timer);
- } else {
- if (php_ctlr->irq) {
- free_irq(php_ctlr->irq, ctrl);
- php_ctlr->irq = 0;
- }
- }
- if (php_ctlr->pci_dev)
- php_ctlr->pci_dev = NULL;
-
- spin_lock(&list_lock);
- p = php_ctlr_list_head;
- p_prev = NULL;
- while (p) {
- if (p == php_ctlr) {
- if (p_prev)
- p_prev->pnext = p->pnext;
- else
- php_ctlr_list_head = p->pnext;
- break;
- } else {
- p_prev = p;
- p = p->pnext;
- }
- }
- spin_unlock(&list_lock);
-
- kfree(php_ctlr);
+ if (pciehp_poll_mode)
+ del_timer(&ctrl->poll_timer);
+ else
+ free_irq(ctrl->pci_dev->irq, ctrl);
DBG_LEAVE_ROUTINE
-
}
static int hpc_power_on_slot(struct slot * slot)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_cmd;
u16 slot_ctrl, slot_status;
-
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot);
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return -1;
- }
/* Clear sticky power-fault bit from previous power failures */
- hp_register_read_word(php_ctlr->pci_dev,
- SLOT_STATUS(slot->ctrl->cap_base), slot_status);
+ retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
+ if (retval) {
+ err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
+ return retval;
+ }
slot_status &= PWR_FAULT_DETECTED;
- if (slot_status)
- hp_register_write_word(php_ctlr->pci_dev,
- SLOT_STATUS(slot->ctrl->cap_base), slot_status);
-
- retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
+ if (slot_status) {
+ retval = pciehp_writew(ctrl, SLOTSTATUS, slot_status);
+ if (retval) {
+ err("%s: Cannot write to SLOTSTATUS register\n",
+ __FUNCTION__);
+ return retval;
+ }
+ }
+ retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (retval) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
return retval;
}
@@ -798,7 +708,8 @@ static int hpc_power_on_slot(struct slot * slot)
err("%s: Write %x command failed!\n", __FUNCTION__, slot_cmd);
return -1;
}
- dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+ dbg("%s: SLOTCTRL %x write cmd %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
DBG_LEAVE_ROUTINE
@@ -807,29 +718,18 @@ static int hpc_power_on_slot(struct slot * slot)
static int hpc_power_off_slot(struct slot * slot)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_cmd;
u16 slot_ctrl;
-
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot);
- slot->hp_slot = 0;
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return -1;
- }
- retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
+ retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (retval) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
return retval;
}
@@ -854,47 +754,25 @@ static int hpc_power_off_slot(struct slot * slot)
err("%s: Write command failed!\n", __FUNCTION__);
return -1;
}
- dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+ dbg("%s: SLOTCTRL %x write cmd %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
DBG_LEAVE_ROUTINE
return retval;
}
-static irqreturn_t pcie_isr(int IRQ, void *dev_id)
+static irqreturn_t pcie_isr(int irq, void *dev_id)
{
- struct controller *ctrl = NULL;
- struct php_ctlr_state_s *php_ctlr;
- u8 schedule_flag = 0;
+ struct controller *ctrl = (struct controller *)dev_id;
u16 slot_status, intr_detect, intr_loc;
u16 temp_word;
int hp_slot = 0; /* only 1 slot per PCI Express port */
int rc = 0;
- if (!dev_id)
- return IRQ_NONE;
-
- if (!pciehp_poll_mode) {
- ctrl = dev_id;
- php_ctlr = ctrl->hpc_ctlr_handle;
- } else {
- php_ctlr = dev_id;
- ctrl = (struct controller *)php_ctlr->callback_instance_id;
- }
-
- if (!ctrl) {
- dbg("%s: dev_id %p ctlr == NULL\n", __FUNCTION__, (void*) dev_id);
- return IRQ_NONE;
- }
-
- if (!php_ctlr) {
- dbg("%s: php_ctlr == NULL\n", __FUNCTION__);
- return IRQ_NONE;
- }
-
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
+ rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (rc) {
- err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
return IRQ_NONE;
}
@@ -910,33 +788,38 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id)
dbg("%s: intr_loc %x\n", __FUNCTION__, intr_loc);
/* Mask Hot-plug Interrupt Enable */
if (!pciehp_poll_mode) {
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
if (rc) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOT_CTRL register\n",
+ __FUNCTION__);
return IRQ_NONE;
}
- dbg("%s: hp_register_read_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word);
+ dbg("%s: pciehp_readw(SLOTCTRL) with value %x\n",
+ __FUNCTION__, temp_word);
temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00;
-
- rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
if (rc) {
- err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot write to SLOTCTRL register\n",
+ __FUNCTION__);
return IRQ_NONE;
}
-
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
+
+ rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (rc) {
- err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOT_STATUS register\n",
+ __FUNCTION__);
return IRQ_NONE;
}
- dbg("%s: hp_register_read_word SLOT_STATUS with value %x\n", __FUNCTION__, slot_status);
+ dbg("%s: pciehp_readw(SLOTSTATUS) with value %x\n",
+ __FUNCTION__, slot_status);
/* Clear command complete interrupt caused by this write */
temp_word = 0x1f;
- rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
if (rc) {
- err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot write to SLOTSTATUS register\n",
+ __FUNCTION__);
return IRQ_NONE;
}
}
@@ -945,60 +828,65 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id)
/*
* Command Complete Interrupt Pending
*/
+ ctrl->cmd_busy = 0;
wake_up_interruptible(&ctrl->queue);
}
- if ((php_ctlr->switch_change_callback) && (intr_loc & MRL_SENS_CHANGED))
- schedule_flag += php_ctlr->switch_change_callback(
- hp_slot, php_ctlr->callback_instance_id);
- if ((php_ctlr->attention_button_callback) && (intr_loc & ATTN_BUTTN_PRESSED))
- schedule_flag += php_ctlr->attention_button_callback(
- hp_slot, php_ctlr->callback_instance_id);
- if ((php_ctlr->presence_change_callback) && (intr_loc & PRSN_DETECT_CHANGED))
- schedule_flag += php_ctlr->presence_change_callback(
- hp_slot , php_ctlr->callback_instance_id);
- if ((php_ctlr->power_fault_callback) && (intr_loc & PWR_FAULT_DETECTED))
- schedule_flag += php_ctlr->power_fault_callback(
- hp_slot, php_ctlr->callback_instance_id);
+ if (intr_loc & MRL_SENS_CHANGED)
+ pciehp_handle_switch_change(hp_slot, ctrl);
+
+ if (intr_loc & ATTN_BUTTN_PRESSED)
+ pciehp_handle_attention_button(hp_slot, ctrl);
+
+ if (intr_loc & PRSN_DETECT_CHANGED)
+ pciehp_handle_presence_change(hp_slot, ctrl);
+
+ if (intr_loc & PWR_FAULT_DETECTED)
+ pciehp_handle_power_fault(hp_slot, ctrl);
/* Clear all events after serving them */
temp_word = 0x1F;
- rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
if (rc) {
- err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
return IRQ_NONE;
}
/* Unmask Hot-plug Interrupt Enable */
if (!pciehp_poll_mode) {
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
if (rc) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n",
+ __FUNCTION__);
return IRQ_NONE;
}
dbg("%s: Unmask Hot-plug Interrupt Enable\n", __FUNCTION__);
temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE;
- rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
if (rc) {
- err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot write to SLOTCTRL register\n",
+ __FUNCTION__);
return IRQ_NONE;
}
-
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
+
+ rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (rc) {
- err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOT_STATUS register\n",
+ __FUNCTION__);
return IRQ_NONE;
}
/* Clear command complete interrupt caused by this write */
temp_word = 0x1F;
- rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
if (rc) {
- err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot write to SLOTSTATUS failed\n",
+ __FUNCTION__);
return IRQ_NONE;
}
- dbg("%s: hp_register_write_word SLOT_STATUS with value %x\n", __FUNCTION__, temp_word);
+ dbg("%s: pciehp_writew(SLOTSTATUS) with value %x\n",
+ __FUNCTION__, temp_word);
}
return IRQ_HANDLED;
@@ -1006,27 +894,16 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id)
static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
enum pcie_link_speed lnk_speed;
u32 lnk_cap;
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP(slot->ctrl->cap_base), lnk_cap);
-
+ retval = pciehp_readl(ctrl, LNKCAP, &lnk_cap);
if (retval) {
- err("%s : hp_register_read_dword LNK_CAP failed\n", __FUNCTION__);
+ err("%s: Cannot read LNKCAP register\n", __FUNCTION__);
return retval;
}
@@ -1047,27 +924,16 @@ static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
enum pcie_link_width lnk_wdth;
u32 lnk_cap;
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP(slot->ctrl->cap_base), lnk_cap);
-
+ retval = pciehp_readl(ctrl, LNKCAP, &lnk_cap);
if (retval) {
- err("%s : hp_register_read_dword LNK_CAP failed\n", __FUNCTION__);
+ err("%s: Cannot read LNKCAP register\n", __FUNCTION__);
return retval;
}
@@ -1109,27 +975,16 @@ static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value
static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
enum pcie_link_speed lnk_speed = PCI_SPEED_UNKNOWN;
int retval = 0;
u16 lnk_status;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(slot->ctrl->cap_base), lnk_status);
-
+ retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
if (retval) {
- err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__);
return retval;
}
@@ -1150,27 +1005,16 @@ static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
static int hpc_get_cur_lnk_width (struct slot *slot, enum pcie_link_width *value)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
enum pcie_link_width lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN;
int retval = 0;
u16 lnk_status;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(slot->ctrl->cap_base), lnk_status);
-
+ retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
if (retval) {
- err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__);
return retval;
}
@@ -1218,6 +1062,8 @@ static struct hpc_ops pciehp_hpc_ops = {
.get_attention_status = hpc_get_attention_status,
.get_latch_status = hpc_get_latch_status,
.get_adapter_status = hpc_get_adapter_status,
+ .get_emi_status = hpc_get_emi_status,
+ .toggle_emi = hpc_toggle_emi,
.get_max_bus_speed = hpc_get_max_lnk_speed,
.get_cur_bus_speed = hpc_get_cur_lnk_speed,
@@ -1305,38 +1151,24 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev)
int pcie_init(struct controller * ctrl, struct pcie_device *dev)
{
- struct php_ctlr_state_s *php_ctlr, *p;
- void *instance_id = ctrl;
int rc;
static int first = 1;
u16 temp_word;
u16 cap_reg;
u16 intr_enable = 0;
u32 slot_cap;
- int cap_base, saved_cap_base;
+ int cap_base;
u16 slot_status, slot_ctrl;
struct pci_dev *pdev;
DBG_ENTER_ROUTINE
- spin_lock_init(&list_lock);
- php_ctlr = kmalloc(sizeof(struct php_ctlr_state_s), GFP_KERNEL);
-
- if (!php_ctlr) { /* allocate controller state data */
- err("%s: HPC controller memory allocation error!\n", __FUNCTION__);
- goto abort;
- }
-
- memset(php_ctlr, 0, sizeof(struct php_ctlr_state_s));
-
pdev = dev->port;
- php_ctlr->pci_dev = pdev; /* save pci_dev in context */
+ ctrl->pci_dev = pdev; /* save pci_dev in context */
dbg("%s: hotplug controller vendor id 0x%x device id 0x%x\n",
__FUNCTION__, pdev->vendor, pdev->device);
- saved_cap_base = pcie_cap_base;
-
if ((cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP)) == 0) {
dbg("%s: Can't find PCI_CAP_ID_EXP (0x10)\n", __FUNCTION__);
goto abort_free_ctlr;
@@ -1344,14 +1176,15 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
ctrl->cap_base = cap_base;
- dbg("%s: pcie_cap_base %x\n", __FUNCTION__, pcie_cap_base);
+ dbg("%s: pcie_cap_base %x\n", __FUNCTION__, cap_base);
- rc = hp_register_read_word(pdev, CAP_REG(ctrl->cap_base), cap_reg);
+ rc = pciehp_readw(ctrl, CAPREG, &cap_reg);
if (rc) {
- err("%s : hp_register_read_word CAP_REG failed\n", __FUNCTION__);
+ err("%s: Cannot read CAPREG register\n", __FUNCTION__);
goto abort_free_ctlr;
}
- dbg("%s: CAP_REG offset %x cap_reg %x\n", __FUNCTION__, CAP_REG(ctrl->cap_base), cap_reg);
+ dbg("%s: CAPREG offset %x cap_reg %x\n",
+ __FUNCTION__, ctrl->cap_base + CAPREG, cap_reg);
if (((cap_reg & SLOT_IMPL) == 0) || (((cap_reg & DEV_PORT_TYPE) != 0x0040)
&& ((cap_reg & DEV_PORT_TYPE) != 0x0060))) {
@@ -1359,31 +1192,34 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
goto abort_free_ctlr;
}
- rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP(ctrl->cap_base), slot_cap);
+ rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap);
if (rc) {
- err("%s : hp_register_read_word CAP_REG failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCAP register\n", __FUNCTION__);
goto abort_free_ctlr;
}
- dbg("%s: SLOT_CAP offset %x slot_cap %x\n", __FUNCTION__, SLOT_CAP(ctrl->cap_base), slot_cap);
+ dbg("%s: SLOTCAP offset %x slot_cap %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCAP, slot_cap);
if (!(slot_cap & HP_CAP)) {
dbg("%s : This slot is not hot-plug capable\n", __FUNCTION__);
goto abort_free_ctlr;
}
/* For debugging purpose */
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
+ rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (rc) {
- err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
goto abort_free_ctlr;
}
- dbg("%s: SLOT_STATUS offset %x slot_status %x\n", __FUNCTION__, SLOT_STATUS(ctrl->cap_base), slot_status);
+ dbg("%s: SLOTSTATUS offset %x slot_status %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTSTATUS, slot_status);
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), slot_ctrl);
+ rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (rc) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
goto abort_free_ctlr;
}
- dbg("%s: SLOT_CTRL offset %x slot_ctrl %x\n", __FUNCTION__, SLOT_CTRL(ctrl->cap_base), slot_ctrl);
+ dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
if (first) {
spin_lock_init(&hpc_event_lock);
@@ -1405,69 +1241,64 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
/* setup wait queue */
init_waitqueue_head(&ctrl->queue);
- /* find the IRQ */
- php_ctlr->irq = dev->irq;
-
- /* Save interrupt callback info */
- php_ctlr->attention_button_callback = pciehp_handle_attention_button;
- php_ctlr->switch_change_callback = pciehp_handle_switch_change;
- php_ctlr->presence_change_callback = pciehp_handle_presence_change;
- php_ctlr->power_fault_callback = pciehp_handle_power_fault;
- php_ctlr->callback_instance_id = instance_id;
-
/* return PCI Controller Info */
- php_ctlr->slot_device_offset = 0;
- php_ctlr->num_slots = 1;
+ ctrl->slot_device_offset = 0;
+ ctrl->num_slots = 1;
+ ctrl->first_slot = slot_cap >> 19;
+ ctrl->ctrlcap = slot_cap & 0x0000007f;
/* Mask Hot-plug Interrupt Enable */
- rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
if (rc) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
goto abort_free_ctlr;
}
- dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL(ctrl->cap_base), temp_word);
+ dbg("%s: SLOTCTRL %x value read %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, temp_word);
temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00;
- rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
if (rc) {
- err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
goto abort_free_ctlr;
}
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
+ rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (rc) {
- err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
goto abort_free_ctlr;
}
temp_word = 0x1F; /* Clear all events */
- rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
if (rc) {
- err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
goto abort_free_ctlr;
}
- if (pciehp_poll_mode) {/* Install interrupt polling code */
- /* Install and start the interrupt polling timer */
- init_timer(&php_ctlr->int_poll_timer);
- start_int_poll_timer( php_ctlr, 10 ); /* start with 10 second delay */
+ if (pciehp_poll_mode) {
+ /* Install interrupt polling timer. Start with 10 sec delay */
+ init_timer(&ctrl->poll_timer);
+ start_int_poll_timer(ctrl, 10);
} else {
/* Installs the interrupt handler */
- rc = request_irq(php_ctlr->irq, pcie_isr, IRQF_SHARED, MY_NAME, (void *) ctrl);
- dbg("%s: request_irq %d for hpc%d (returns %d)\n", __FUNCTION__, php_ctlr->irq, ctlr_seq_num, rc);
+ rc = request_irq(ctrl->pci_dev->irq, pcie_isr, IRQF_SHARED,
+ MY_NAME, (void *)ctrl);
+ dbg("%s: request_irq %d for hpc%d (returns %d)\n",
+ __FUNCTION__, ctrl->pci_dev->irq, ctlr_seq_num, rc);
if (rc) {
- err("Can't get irq %d for the hotplug controller\n", php_ctlr->irq);
+ err("Can't get irq %d for the hotplug controller\n",
+ ctrl->pci_dev->irq);
goto abort_free_ctlr;
}
}
-
dbg("pciehp ctrl b:d:f:irq=0x%x:%x:%x:%x\n", pdev->bus->number,
PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), dev->irq);
- rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
if (rc) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
goto abort_free_irq;
}
@@ -1491,21 +1322,21 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
}
/* Unmask Hot-plug Interrupt Enable for the interrupt notification mechanism case */
- rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
if (rc) {
- err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
goto abort_free_irq;
}
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
+ rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (rc) {
- err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
goto abort_disable_intr;
}
temp_word = 0x1F; /* Clear all events */
- rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
if (rc) {
- err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
goto abort_disable_intr;
}
@@ -1518,24 +1349,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
goto abort_disable_intr;
}
- /* Add this HPC instance into the HPC list */
- spin_lock(&list_lock);
- if (php_ctlr_list_head == 0) {
- php_ctlr_list_head = php_ctlr;
- p = php_ctlr_list_head;
- p->pnext = NULL;
- } else {
- p = php_ctlr_list_head;
-
- while (p->pnext)
- p = p->pnext;
-
- p->pnext = php_ctlr;
- }
- spin_unlock(&list_lock);
-
ctlr_seq_num++;
- ctrl->hpc_ctlr_handle = php_ctlr;
ctrl->hpc_ops = &pciehp_hpc_ops;
DBG_LEAVE_ROUTINE
@@ -1543,24 +1357,21 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
/* We end up here for the many possible ways to fail this API. */
abort_disable_intr:
- rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
if (!rc) {
temp_word &= ~(intr_enable | HP_INTR_ENABLE);
- rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
}
if (rc)
err("%s : disabling interrupts failed\n", __FUNCTION__);
abort_free_irq:
if (pciehp_poll_mode)
- del_timer_sync(&php_ctlr->int_poll_timer);
+ del_timer_sync(&ctrl->poll_timer);
else
- free_irq(php_ctlr->irq, ctrl);
+ free_irq(ctrl->pci_dev->irq, ctrl);
abort_free_ctlr:
- pcie_cap_base = saved_cap_base;
- kfree(php_ctlr);
-abort:
DBG_LEAVE_ROUTINE
return -1;
}
diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c
index 5d188c55838..78cf0711d1f 100644
--- a/drivers/pci/hotplug/sgi_hotplug.c
+++ b/drivers/pci/hotplug/sgi_hotplug.c
@@ -28,6 +28,8 @@
#include <asm/sn/sn_feature_sets.h>
#include <asm/sn/sn_sal.h>
#include <asm/sn/types.h>
+#include <linux/acpi.h>
+#include <asm/sn/acpi.h>
#include "../pci.h"
@@ -35,14 +37,17 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("SGI (prarit@sgi.com, dickie@sgi.com, habeck@sgi.com)");
MODULE_DESCRIPTION("SGI Altix Hot Plug PCI Controller Driver");
-#define PCIIO_ASIC_TYPE_TIOCA 4
+
+/* SAL call error codes. Keep in sync with prom header io/include/pcibr.h */
#define PCI_SLOT_ALREADY_UP 2 /* slot already up */
#define PCI_SLOT_ALREADY_DOWN 3 /* slot already down */
#define PCI_L1_ERR 7 /* L1 console command error */
#define PCI_EMPTY_33MHZ 15 /* empty 33 MHz bus */
+
+
+#define PCIIO_ASIC_TYPE_TIOCA 4
#define PCI_L1_QSIZE 128 /* our L1 message buffer size */
#define SN_MAX_HP_SLOTS 32 /* max hotplug slots */
-#define SGI_HOTPLUG_PROM_REV 0x0430 /* Min. required PROM version */
#define SN_SLOT_NAME_SIZE 33 /* size of name string */
/* internal list head */
@@ -227,7 +232,7 @@ static void sn_bus_free_data(struct pci_dev *dev)
}
static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot,
- int device_num)
+ int device_num, char **ssdt)
{
struct slot *slot = bss_hotplug_slot->private;
struct pcibus_info *pcibus_info;
@@ -240,7 +245,8 @@ static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot,
* Power-on and initialize the slot in the SN
* PCI infrastructure.
*/
- rc = sal_pcibr_slot_enable(pcibus_info, device_num, &resp);
+ rc = sal_pcibr_slot_enable(pcibus_info, device_num, &resp, ssdt);
+
if (rc == PCI_SLOT_ALREADY_UP) {
dev_dbg(slot->pci_bus->self, "is already active\n");
@@ -335,6 +341,7 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
int func, num_funcs;
int new_ppb = 0;
int rc;
+ char *ssdt = NULL;
void pcibios_fixup_device_resources(struct pci_dev *);
/* Serialize the Linux PCI infrastructure */
@@ -342,14 +349,29 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
/*
* Power-on and initialize the slot in the SN
- * PCI infrastructure.
+ * PCI infrastructure. Also, retrieve the ACPI SSDT
+ * table for the slot (if ACPI capable PROM).
*/
- rc = sn_slot_enable(bss_hotplug_slot, slot->device_num);
+ rc = sn_slot_enable(bss_hotplug_slot, slot->device_num, &ssdt);
if (rc) {
mutex_unlock(&sn_hotplug_mutex);
return rc;
}
+ if (ssdt)
+ ssdt = __va(ssdt);
+ /* Add the new SSDT for the slot to the ACPI namespace */
+ if (SN_ACPI_BASE_SUPPORT() && ssdt) {
+ acpi_status ret;
+
+ ret = acpi_load_table((struct acpi_table_header *)ssdt);
+ if (ACPI_FAILURE(ret)) {
+ printk(KERN_ERR "%s: acpi_load_table failed (0x%x)\n",
+ __FUNCTION__, ret);
+ /* try to continue on */
+ }
+ }
+
num_funcs = pci_scan_slot(slot->pci_bus,
PCI_DEVFN(slot->device_num + 1, 0));
if (!num_funcs) {
@@ -374,7 +396,10 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
* pdi_host_pcidev_info).
*/
pcibios_fixup_device_resources(dev);
- sn_pci_fixup_slot(dev);
+ if (SN_ACPI_BASE_SUPPORT())
+ sn_acpi_slot_fixup(dev);
+ else
+ sn_io_slot_fixup(dev);
if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
unsigned char sec_bus;
pci_read_config_byte(dev, PCI_SECONDARY_BUS,
@@ -388,6 +413,63 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
}
}
+ /*
+ * Add the slot's devices to the ACPI infrastructure */
+ if (SN_ACPI_BASE_SUPPORT() && ssdt) {
+ unsigned long adr;
+ struct acpi_device *pdevice;
+ struct acpi_device *device;
+ acpi_handle phandle;
+ acpi_handle chandle = NULL;
+ acpi_handle rethandle;
+ acpi_status ret;
+
+ phandle = PCI_CONTROLLER(slot->pci_bus)->acpi_handle;
+
+ if (acpi_bus_get_device(phandle, &pdevice)) {
+ dev_dbg(slot->pci_bus->self,
+ "no parent device, assuming NULL\n");
+ pdevice = NULL;
+ }
+
+ /*
+ * Walk the rootbus node's immediate children looking for
+ * the slot's device node(s). There can be more than
+ * one for multifunction devices.
+ */
+ for (;;) {
+ rethandle = NULL;
+ ret = acpi_get_next_object(ACPI_TYPE_DEVICE,
+ phandle, chandle,
+ &rethandle);
+
+ if (ret == AE_NOT_FOUND || rethandle == NULL)
+ break;
+
+ chandle = rethandle;
+
+ ret = acpi_evaluate_integer(chandle, METHOD_NAME__ADR,
+ NULL, &adr);
+
+ if (ACPI_SUCCESS(ret) &&
+ (adr>>16) == (slot->device_num + 1)) {
+
+ ret = acpi_bus_add(&device, pdevice, chandle,
+ ACPI_BUS_TYPE_DEVICE);
+ if (ACPI_FAILURE(ret)) {
+ printk(KERN_ERR "%s: acpi_bus_add "
+ "failed (0x%x) for slot %d "
+ "func %d\n", __FUNCTION__,
+ ret, (int)(adr>>16),
+ (int)(adr&0xffff));
+ /* try to continue on */
+ } else {
+ acpi_bus_start(device);
+ }
+ }
+ }
+ }
+
/* Call the driver for the new device */
pci_bus_add_devices(slot->pci_bus);
/* Call the drivers for the new devices subordinate to PPB */
@@ -412,6 +494,7 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
struct pci_dev *dev;
int func;
int rc;
+ acpi_owner_id ssdt_id = 0;
/* Acquire update access to the bus */
mutex_lock(&sn_hotplug_mutex);
@@ -422,6 +505,52 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
if (rc)
goto leaving;
+ /* free the ACPI resources for the slot */
+ if (SN_ACPI_BASE_SUPPORT() &&
+ PCI_CONTROLLER(slot->pci_bus)->acpi_handle) {
+ unsigned long adr;
+ struct acpi_device *device;
+ acpi_handle phandle;
+ acpi_handle chandle = NULL;
+ acpi_handle rethandle;
+ acpi_status ret;
+
+ /* Get the rootbus node pointer */
+ phandle = PCI_CONTROLLER(slot->pci_bus)->acpi_handle;
+
+ /*
+ * Walk the rootbus node's immediate children looking for
+ * the slot's device node(s). There can be more than
+ * one for multifunction devices.
+ */
+ for (;;) {
+ rethandle = NULL;
+ ret = acpi_get_next_object(ACPI_TYPE_DEVICE,
+ phandle, chandle,
+ &rethandle);
+
+ if (ret == AE_NOT_FOUND || rethandle == NULL)
+ break;
+
+ chandle = rethandle;
+
+ ret = acpi_evaluate_integer(chandle,
+ METHOD_NAME__ADR,
+ NULL, &adr);
+ if (ACPI_SUCCESS(ret) &&
+ (adr>>16) == (slot->device_num + 1)) {
+ /* retain the owner id */
+ acpi_get_id(chandle, &ssdt_id);
+
+ ret = acpi_bus_get_device(chandle,
+ &device);
+ if (ACPI_SUCCESS(ret))
+ acpi_bus_trim(device, 1);
+ }
+ }
+
+ }
+
/* Free the SN resources assigned to the Linux device.*/
for (func = 0; func < 8; func++) {
dev = pci_get_slot(slot->pci_bus,
@@ -434,6 +563,18 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
}
}
+ /* Remove the SSDT for the slot from the ACPI namespace */
+ if (SN_ACPI_BASE_SUPPORT() && ssdt_id) {
+ acpi_status ret;
+ ret = acpi_unload_table_id(ssdt_id);
+ if (ACPI_FAILURE(ret)) {
+ printk(KERN_ERR "%s: acpi_unload_table_id "
+ "failed (0x%x) for id %d\n",
+ __FUNCTION__, ret, ssdt_id);
+ /* try to continue on */
+ }
+ }
+
/* free the collected sysdata pointers */
sn_bus_free_sysdata();
diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h
index 3ca6a4f574b..01d31a1f697 100644
--- a/drivers/pci/hotplug/shpchp.h
+++ b/drivers/pci/hotplug/shpchp.h
@@ -106,7 +106,7 @@ struct controller {
};
/* Define AMD SHPC ID */
-#define PCI_DEVICE_ID_AMD_GOLAM_7450 0x7450
+#define PCI_DEVICE_ID_AMD_GOLAM_7450 0x7450
#define PCI_DEVICE_ID_AMD_POGO_7458 0x7458
/* AMD PCIX bridge registers */
@@ -221,7 +221,7 @@ enum ctrl_offsets {
};
static inline struct slot *get_slot(struct hotplug_slot *hotplug_slot)
-{
+{
return hotplug_slot->private;
}
diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c
index 590cd3cbe01..5f4bc08a633 100644
--- a/drivers/pci/hotplug/shpchp_core.c
+++ b/drivers/pci/hotplug/shpchp_core.c
@@ -401,10 +401,6 @@ static int __init shpcd_init(void)
{
int retval = 0;
-#ifdef CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE
- shpchp_poll_mode = 1;
-#endif
-
retval = pci_register_driver(&shpc_driver);
dbg("%s: pci_register_driver = %d\n", __FUNCTION__, retval);
info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c
index 6bb84734cd6..b746bd265bc 100644
--- a/drivers/pci/hotplug/shpchp_ctrl.c
+++ b/drivers/pci/hotplug/shpchp_ctrl.c
@@ -64,7 +64,7 @@ u8 shpchp_handle_attention_button(u8 hp_slot, struct controller *ctrl)
/* Attention Button Change */
dbg("shpchp: Attention button interrupt received.\n");
-
+
p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
@@ -128,7 +128,7 @@ u8 shpchp_handle_presence_change(u8 hp_slot, struct controller *ctrl)
p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
- /*
+ /*
* Save the presence state
*/
p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
@@ -184,12 +184,12 @@ u8 shpchp_handle_power_fault(u8 hp_slot, struct controller *ctrl)
return 1;
}
-/* The following routines constitute the bulk of the
+/* The following routines constitute the bulk of the
hotplug controller logic
*/
static int change_bus_speed(struct controller *ctrl, struct slot *p_slot,
enum pci_bus_speed speed)
-{
+{
int rc = 0;
dbg("%s: change to speed %d\n", __FUNCTION__, speed);
@@ -204,7 +204,7 @@ static int change_bus_speed(struct controller *ctrl, struct slot *p_slot,
static int fix_bus_speed(struct controller *ctrl, struct slot *pslot,
u8 flag, enum pci_bus_speed asp, enum pci_bus_speed bsp,
enum pci_bus_speed msp)
-{
+{
int rc = 0;
/*
@@ -257,23 +257,23 @@ static int board_added(struct slot *p_slot)
err("%s: Failed to power on slot\n", __FUNCTION__);
return -1;
}
-
+
if ((ctrl->pci_dev->vendor == 0x8086) && (ctrl->pci_dev->device == 0x0332)) {
if (slots_not_empty)
return WRONG_BUS_FREQUENCY;
-
+
if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, PCI_SPEED_33MHz))) {
err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
return WRONG_BUS_FREQUENCY;
}
-
+
/* turn on board, blink green LED, turn off Amber LED */
if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) {
err("%s: Issue of Slot Enable command failed\n", __FUNCTION__);
return rc;
}
}
-
+
rc = p_slot->hpc_ops->get_adapter_speed(p_slot, &asp);
if (rc) {
err("%s: Can't get adapter speed or bus mode mismatch\n",
@@ -378,7 +378,7 @@ static int remove_board(struct slot *p_slot)
err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
return rc;
}
-
+
rc = p_slot->hpc_ops->set_attention_status(p_slot, 0);
if (rc) {
err("%s: Issue of Set Attention command failed\n", __FUNCTION__);
diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c
index b7bede4b7c2..5183a45d45b 100644
--- a/drivers/pci/hotplug/shpchp_hpc.c
+++ b/drivers/pci/hotplug/shpchp_hpc.c
@@ -35,38 +35,6 @@
#include "shpchp.h"
-#ifdef DEBUG
-#define DBG_K_TRACE_ENTRY ((unsigned int)0x00000001) /* On function entry */
-#define DBG_K_TRACE_EXIT ((unsigned int)0x00000002) /* On function exit */
-#define DBG_K_INFO ((unsigned int)0x00000004) /* Info messages */
-#define DBG_K_ERROR ((unsigned int)0x00000008) /* Error messages */
-#define DBG_K_TRACE (DBG_K_TRACE_ENTRY|DBG_K_TRACE_EXIT)
-#define DBG_K_STANDARD (DBG_K_INFO|DBG_K_ERROR|DBG_K_TRACE)
-/* Redefine this flagword to set debug level */
-#define DEBUG_LEVEL DBG_K_STANDARD
-
-#define DEFINE_DBG_BUFFER char __dbg_str_buf[256];
-
-#define DBG_PRINT( dbg_flags, args... ) \
- do { \
- if ( DEBUG_LEVEL & ( dbg_flags ) ) \
- { \
- int len; \
- len = sprintf( __dbg_str_buf, "%s:%d: %s: ", \
- __FILE__, __LINE__, __FUNCTION__ ); \
- sprintf( __dbg_str_buf + len, args ); \
- printk( KERN_NOTICE "%s\n", __dbg_str_buf ); \
- } \
- } while (0)
-
-#define DBG_ENTER_ROUTINE DBG_PRINT (DBG_K_TRACE_ENTRY, "%s", "[Entry]");
-#define DBG_LEAVE_ROUTINE DBG_PRINT (DBG_K_TRACE_EXIT, "%s", "[Exit]");
-#else
-#define DEFINE_DBG_BUFFER
-#define DBG_ENTER_ROUTINE
-#define DBG_LEAVE_ROUTINE
-#endif /* DEBUG */
-
/* Slot Available Register I field definition */
#define SLOT_33MHZ 0x0000001f
#define SLOT_66MHZ_PCIX 0x00001f00
@@ -211,7 +179,6 @@
#define SLOT_EVENT_LATCH 0x2
#define SLOT_SERR_INT_MASK 0x3
-DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */
static atomic_t shpchp_num_controllers = ATOMIC_INIT(0);
static irqreturn_t shpc_isr(int irq, void *dev_id);
@@ -268,8 +235,6 @@ static void int_poll_timeout(unsigned long data)
{
struct controller *ctrl = (struct controller *)data;
- DBG_ENTER_ROUTINE
-
/* Poll for interrupt events. regs == NULL => polling */
shpc_isr(0, ctrl);
@@ -278,8 +243,6 @@ static void int_poll_timeout(unsigned long data)
shpchp_poll_time = 2; /* default polling interval is 2 sec */
start_int_poll_timer(ctrl, shpchp_poll_time);
-
- DBG_LEAVE_ROUTINE
}
/*
@@ -353,8 +316,6 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd)
int retval = 0;
u16 temp_word;
- DBG_ENTER_ROUTINE
-
mutex_lock(&slot->ctrl->cmd_lock);
if (!shpc_poll_ctrl_busy(ctrl)) {
@@ -368,9 +329,9 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd)
++t_slot;
temp_word = (t_slot << 8) | (cmd & 0xFF);
dbg("%s: t_slot %x cmd %x\n", __FUNCTION__, t_slot, cmd);
-
+
/* To make sure the Controller Busy bit is 0 before we send out the
- * command.
+ * command.
*/
shpc_writew(ctrl, CMD, temp_word);
@@ -389,20 +350,14 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd)
}
out:
mutex_unlock(&slot->ctrl->cmd_lock);
-
- DBG_LEAVE_ROUTINE
return retval;
}
static int hpc_check_cmd_status(struct controller *ctrl)
{
- u16 cmd_status;
int retval = 0;
+ u16 cmd_status = shpc_readw(ctrl, CMD_STATUS) & 0x000F;
- DBG_ENTER_ROUTINE
-
- cmd_status = shpc_readw(ctrl, CMD_STATUS) & 0x000F;
-
switch (cmd_status >> 1) {
case 0:
retval = 0;
@@ -423,7 +378,6 @@ static int hpc_check_cmd_status(struct controller *ctrl)
retval = cmd_status;
}
- DBG_LEAVE_ROUTINE
return retval;
}
@@ -431,13 +385,8 @@ static int hpc_check_cmd_status(struct controller *ctrl)
static int hpc_get_attention_status(struct slot *slot, u8 *status)
{
struct controller *ctrl = slot->ctrl;
- u32 slot_reg;
- u8 state;
-
- DBG_ENTER_ROUTINE
-
- slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
- state = (slot_reg & ATN_LED_STATE_MASK) >> ATN_LED_STATE_SHIFT;
+ u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
+ u8 state = (slot_reg & ATN_LED_STATE_MASK) >> ATN_LED_STATE_SHIFT;
switch (state) {
case ATN_LED_STATE_ON:
@@ -454,20 +403,14 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status)
break;
}
- DBG_LEAVE_ROUTINE
return 0;
}
static int hpc_get_power_status(struct slot * slot, u8 *status)
{
struct controller *ctrl = slot->ctrl;
- u32 slot_reg;
- u8 state;
-
- DBG_ENTER_ROUTINE
-
- slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
- state = (slot_reg & SLOT_STATE_MASK) >> SLOT_STATE_SHIFT;
+ u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
+ u8 state = (slot_reg & SLOT_STATE_MASK) >> SLOT_STATE_SHIFT;
switch (state) {
case SLOT_STATE_PWRONLY:
@@ -484,7 +427,6 @@ static int hpc_get_power_status(struct slot * slot, u8 *status)
break;
}
- DBG_LEAVE_ROUTINE
return 0;
}
@@ -492,30 +434,21 @@ static int hpc_get_power_status(struct slot * slot, u8 *status)
static int hpc_get_latch_status(struct slot *slot, u8 *status)
{
struct controller *ctrl = slot->ctrl;
- u32 slot_reg;
-
- DBG_ENTER_ROUTINE
+ u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
- slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
*status = !!(slot_reg & MRL_SENSOR); /* 0 -> close; 1 -> open */
- DBG_LEAVE_ROUTINE
return 0;
}
static int hpc_get_adapter_status(struct slot *slot, u8 *status)
{
struct controller *ctrl = slot->ctrl;
- u32 slot_reg;
- u8 state;
-
- DBG_ENTER_ROUTINE
+ u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
+ u8 state = (slot_reg & PRSNT_MASK) >> PRSNT_SHIFT;
- slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
- state = (slot_reg & PRSNT_MASK) >> PRSNT_SHIFT;
*status = (state != 0x3) ? 1 : 0;
- DBG_LEAVE_ROUTINE
return 0;
}
@@ -523,11 +456,8 @@ static int hpc_get_prog_int(struct slot *slot, u8 *prog_int)
{
struct controller *ctrl = slot->ctrl;
- DBG_ENTER_ROUTINE
-
*prog_int = shpc_readb(ctrl, PROG_INTERFACE);
- DBG_LEAVE_ROUTINE
return 0;
}
@@ -539,8 +469,6 @@ static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value)
u8 m66_cap = !!(slot_reg & MHZ66_CAP);
u8 pi, pcix_cap;
- DBG_ENTER_ROUTINE
-
if ((retval = hpc_get_prog_int(slot, &pi)))
return retval;
@@ -582,21 +510,15 @@ static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value)
}
dbg("Adapter speed = %d\n", *value);
- DBG_LEAVE_ROUTINE
return retval;
}
static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode)
{
- struct controller *ctrl = slot->ctrl;
- u16 sec_bus_status;
- u8 pi;
int retval = 0;
-
- DBG_ENTER_ROUTINE
-
- pi = shpc_readb(ctrl, PROG_INTERFACE);
- sec_bus_status = shpc_readw(ctrl, SEC_BUS_CONFIG);
+ struct controller *ctrl = slot->ctrl;
+ u16 sec_bus_status = shpc_readw(ctrl, SEC_BUS_CONFIG);
+ u8 pi = shpc_readb(ctrl, PROG_INTERFACE);
if (pi == 2) {
*mode = (sec_bus_status & 0x0100) >> 8;
@@ -605,21 +527,14 @@ static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode)
}
dbg("Mode 1 ECC cap = %d\n", *mode);
-
- DBG_LEAVE_ROUTINE
return retval;
}
static int hpc_query_power_fault(struct slot * slot)
{
struct controller *ctrl = slot->ctrl;
- u32 slot_reg;
-
- DBG_ENTER_ROUTINE
-
- slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
+ u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
- DBG_LEAVE_ROUTINE
/* Note: Logic 0 => fault */
return !(slot_reg & POWER_FAULT);
}
@@ -629,7 +544,7 @@ static int hpc_set_attention_status(struct slot *slot, u8 value)
u8 slot_cmd = 0;
switch (value) {
- case 0 :
+ case 0 :
slot_cmd = SET_ATTN_OFF; /* OFF */
break;
case 1:
@@ -666,8 +581,6 @@ static void hpc_release_ctlr(struct controller *ctrl)
int i;
u32 slot_reg, serr_int;
- DBG_ENTER_ROUTINE
-
/*
* Mask event interrupts and SERRs of all slots
*/
@@ -708,61 +621,43 @@ static void hpc_release_ctlr(struct controller *ctrl)
*/
if (atomic_dec_and_test(&shpchp_num_controllers))
destroy_workqueue(shpchp_wq);
-
- DBG_LEAVE_ROUTINE
}
static int hpc_power_on_slot(struct slot * slot)
{
int retval;
- DBG_ENTER_ROUTINE
-
retval = shpc_write_cmd(slot, slot->hp_slot, SET_SLOT_PWR);
- if (retval) {
+ if (retval)
err("%s: Write command failed!\n", __FUNCTION__);
- return retval;
- }
-
- DBG_LEAVE_ROUTINE
- return 0;
+ return retval;
}
static int hpc_slot_enable(struct slot * slot)
{
int retval;
- DBG_ENTER_ROUTINE
-
/* Slot - Enable, Power Indicator - Blink, Attention Indicator - Off */
retval = shpc_write_cmd(slot, slot->hp_slot,
SET_SLOT_ENABLE | SET_PWR_BLINK | SET_ATTN_OFF);
- if (retval) {
+ if (retval)
err("%s: Write command failed!\n", __FUNCTION__);
- return retval;
- }
- DBG_LEAVE_ROUTINE
- return 0;
+ return retval;
}
static int hpc_slot_disable(struct slot * slot)
{
int retval;
- DBG_ENTER_ROUTINE
-
/* Slot - Disable, Power Indicator - Off, Attention Indicator - On */
retval = shpc_write_cmd(slot, slot->hp_slot,
SET_SLOT_DISABLE | SET_PWR_OFF | SET_ATTN_ON);
- if (retval) {
+ if (retval)
err("%s: Write command failed!\n", __FUNCTION__);
- return retval;
- }
- DBG_LEAVE_ROUTINE
- return 0;
+ return retval;
}
static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value)
@@ -771,8 +666,6 @@ static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value)
struct controller *ctrl = slot->ctrl;
u8 pi, cmd;
- DBG_ENTER_ROUTINE
-
pi = shpc_readb(ctrl, PROG_INTERFACE);
if ((pi == 1) && (value > PCI_SPEED_133MHz_PCIX))
return -EINVAL;
@@ -828,7 +721,6 @@ static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value)
if (retval)
err("%s: Write command failed!\n", __FUNCTION__);
- DBG_LEAVE_ROUTINE
return retval;
}
@@ -843,7 +735,7 @@ static irqreturn_t shpc_isr(int irq, void *dev_id)
if (!intr_loc)
return IRQ_NONE;
- dbg("%s: intr_loc = %x\n",__FUNCTION__, intr_loc);
+ dbg("%s: intr_loc = %x\n",__FUNCTION__, intr_loc);
if(!shpchp_poll_mode) {
/*
@@ -856,12 +748,12 @@ static irqreturn_t shpc_isr(int irq, void *dev_id)
shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int);
intr_loc2 = shpc_readl(ctrl, INTR_LOC);
- dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2);
+ dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2);
}
if (intr_loc & CMD_INTR_PENDING) {
- /*
- * Command Complete Interrupt Pending
+ /*
+ * Command Complete Interrupt Pending
* RO only - clear by writing 1 to the Command Completion
* Detect bit in Controller SERR-INT register
*/
@@ -875,7 +767,7 @@ static irqreturn_t shpc_isr(int irq, void *dev_id)
if (!(intr_loc & ~CMD_INTR_PENDING))
goto out;
- for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) {
+ for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) {
/* To find out which slot has interrupt pending */
if (!(intr_loc & SLOT_INTR_PENDING(hp_slot)))
continue;
@@ -907,7 +799,7 @@ static irqreturn_t shpc_isr(int irq, void *dev_id)
serr_int &= ~(GLOBAL_INTR_MASK | SERR_INTR_RSVDZ_MASK);
shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int);
}
-
+
return IRQ_HANDLED;
}
@@ -920,8 +812,6 @@ static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value)
u32 slot_avail1 = shpc_readl(ctrl, SLOT_AVAIL1);
u32 slot_avail2 = shpc_readl(ctrl, SLOT_AVAIL2);
- DBG_ENTER_ROUTINE
-
if (pi == 2) {
if (slot_avail2 & SLOT_133MHZ_PCIX_533)
bus_speed = PCI_SPEED_133MHz_PCIX_533;
@@ -954,7 +844,7 @@ static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value)
*value = bus_speed;
dbg("Max bus speed = %d\n", bus_speed);
- DBG_LEAVE_ROUTINE
+
return retval;
}
@@ -967,8 +857,6 @@ static int hpc_get_cur_bus_speed (struct slot *slot, enum pci_bus_speed *value)
u8 pi = shpc_readb(ctrl, PROG_INTERFACE);
u8 speed_mode = (pi == 2) ? (sec_bus_reg & 0xF) : (sec_bus_reg & 0x7);
- DBG_ENTER_ROUTINE
-
if ((pi == 1) && (speed_mode > 4)) {
*value = PCI_SPEED_UNKNOWN;
return -ENODEV;
@@ -1024,7 +912,6 @@ static int hpc_get_cur_bus_speed (struct slot *slot, enum pci_bus_speed *value)
}
dbg("Current bus speed = %d\n", bus_speed);
- DBG_LEAVE_ROUTINE
return retval;
}
@@ -1032,7 +919,7 @@ static struct hpc_ops shpchp_hpc_ops = {
.power_on_slot = hpc_power_on_slot,
.slot_enable = hpc_slot_enable,
.slot_disable = hpc_slot_disable,
- .set_bus_speed_mode = hpc_set_bus_speed_mode,
+ .set_bus_speed_mode = hpc_set_bus_speed_mode,
.set_attention_status = hpc_set_attention_status,
.get_power_status = hpc_get_power_status,
.get_attention_status = hpc_get_attention_status,
@@ -1049,7 +936,7 @@ static struct hpc_ops shpchp_hpc_ops = {
.green_led_on = hpc_set_green_led_on,
.green_led_off = hpc_set_green_led_off,
.green_led_blink = hpc_set_green_led_blink,
-
+
.release_ctlr = hpc_release_ctlr,
};
@@ -1061,8 +948,6 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev)
u32 tempdword, slot_reg, slot_config;
u8 i;
- DBG_ENTER_ROUTINE
-
ctrl->pci_dev = pdev; /* pci_dev of the P2P bridge */
if ((pdev->vendor == PCI_VENDOR_ID_AMD) || (pdev->device ==
@@ -1108,9 +993,9 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev)
ctrl->mmio_size = 0x24 + 0x4 * num_slots;
}
- info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor,
+ info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor,
pdev->subsystem_device);
-
+
rc = pci_enable_device(pdev);
if (rc) {
err("%s: pci_enable_device failed\n", __FUNCTION__);
@@ -1172,7 +1057,7 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev)
slot_reg &= ~SLOT_REG_RSVDZ_MASK;
shpc_writel(ctrl, SLOT_REG(hp_slot), slot_reg);
}
-
+
if (shpchp_poll_mode) {
/* Install interrupt polling timer. Start with 10 sec delay */
init_timer(&ctrl->poll_timer);
@@ -1184,7 +1069,7 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev)
info("Can't get msi for the hotplug controller\n");
info("Use INTx for the hotplug controller\n");
}
-
+
rc = request_irq(ctrl->pci_dev->irq, shpc_isr, IRQF_SHARED,
MY_NAME, (void *)ctrl);
dbg("%s: request_irq %d for hpc%d (returns %d)\n",
@@ -1235,13 +1120,11 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev)
dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword);
}
- DBG_LEAVE_ROUTINE
return 0;
/* We end up here for the many possible ways to fail this API. */
abort_iounmap:
iounmap(ctrl->creg);
abort:
- DBG_LEAVE_ROUTINE
return rc;
}
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index ed3f7e1a563..68555c11f55 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -24,8 +24,6 @@
#include "pci.h"
#include "msi.h"
-static DEFINE_SPINLOCK(msi_lock);
-static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL };
static struct kmem_cache* msi_cachep;
static int pci_msi_enable = 1;
@@ -44,13 +42,13 @@ static void msi_set_mask_bit(unsigned int irq, int flag)
{
struct msi_desc *entry;
- entry = msi_desc[irq];
+ entry = get_irq_msi(irq);
BUG_ON(!entry || !entry->dev);
switch (entry->msi_attrib.type) {
case PCI_CAP_ID_MSI:
if (entry->msi_attrib.maskbit) {
- int pos;
- u32 mask_bits;
+ int pos;
+ u32 mask_bits;
pos = (long)entry->mask_base;
pci_read_config_dword(entry->dev, pos, &mask_bits);
@@ -74,7 +72,7 @@ static void msi_set_mask_bit(unsigned int irq, int flag)
void read_msi_msg(unsigned int irq, struct msi_msg *msg)
{
- struct msi_desc *entry = get_irq_data(irq);
+ struct msi_desc *entry = get_irq_msi(irq);
switch(entry->msi_attrib.type) {
case PCI_CAP_ID_MSI:
{
@@ -113,7 +111,7 @@ void read_msi_msg(unsigned int irq, struct msi_msg *msg)
void write_msi_msg(unsigned int irq, struct msi_msg *msg)
{
- struct msi_desc *entry = get_irq_data(irq);
+ struct msi_desc *entry = get_irq_msi(irq);
switch (entry->msi_attrib.type) {
case PCI_CAP_ID_MSI:
{
@@ -162,6 +160,7 @@ void unmask_msi_irq(unsigned int irq)
}
static int msi_free_irq(struct pci_dev* dev, int irq);
+
static int msi_init(void)
{
static int status = -ENOMEM;
@@ -169,13 +168,6 @@ static int msi_init(void)
if (!status)
return status;
- if (pci_msi_quirk) {
- pci_msi_enable = 0;
- printk(KERN_WARNING "PCI: MSI quirk detected. MSI disabled.\n");
- status = -EINVAL;
- return status;
- }
-
status = msi_cache_init();
if (status < 0) {
pci_msi_enable = 0;
@@ -200,46 +192,6 @@ static struct msi_desc* alloc_msi_entry(void)
return entry;
}
-static void attach_msi_entry(struct msi_desc *entry, int irq)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&msi_lock, flags);
- msi_desc[irq] = entry;
- spin_unlock_irqrestore(&msi_lock, flags);
-}
-
-static int create_msi_irq(void)
-{
- struct msi_desc *entry;
- int irq;
-
- entry = alloc_msi_entry();
- if (!entry)
- return -ENOMEM;
-
- irq = create_irq();
- if (irq < 0) {
- kmem_cache_free(msi_cachep, entry);
- return -EBUSY;
- }
-
- set_irq_data(irq, entry);
-
- return irq;
-}
-
-static void destroy_msi_irq(unsigned int irq)
-{
- struct msi_desc *entry;
-
- entry = get_irq_data(irq);
- set_irq_chip(irq, NULL);
- set_irq_data(irq, NULL);
- destroy_irq(irq);
- kmem_cache_free(msi_cachep, entry);
-}
-
static void enable_msi_mode(struct pci_dev *dev, int pos, int type)
{
u16 control;
@@ -278,36 +230,8 @@ void disable_msi_mode(struct pci_dev *dev, int pos, int type)
pci_intx(dev, 1); /* enable intx */
}
-static int msi_lookup_irq(struct pci_dev *dev, int type)
-{
- int irq;
- unsigned long flags;
-
- spin_lock_irqsave(&msi_lock, flags);
- for (irq = 0; irq < NR_IRQS; irq++) {
- if (!msi_desc[irq] || msi_desc[irq]->dev != dev ||
- msi_desc[irq]->msi_attrib.type != type ||
- msi_desc[irq]->msi_attrib.default_irq != dev->irq)
- continue;
- spin_unlock_irqrestore(&msi_lock, flags);
- /* This pre-assigned MSI irq for this device
- already exits. Override dev->irq with this irq */
- dev->irq = irq;
- return 0;
- }
- spin_unlock_irqrestore(&msi_lock, flags);
-
- return -EACCES;
-}
-
-void pci_scan_msi_device(struct pci_dev *dev)
-{
- if (!dev)
- return;
-}
-
#ifdef CONFIG_PM
-int pci_save_msi_state(struct pci_dev *dev)
+static int __pci_save_msi_state(struct pci_dev *dev)
{
int pos, i = 0;
u16 control;
@@ -345,7 +269,7 @@ int pci_save_msi_state(struct pci_dev *dev)
return 0;
}
-void pci_restore_msi_state(struct pci_dev *dev)
+static void __pci_restore_msi_state(struct pci_dev *dev)
{
int i = 0, pos;
u16 control;
@@ -373,14 +297,16 @@ void pci_restore_msi_state(struct pci_dev *dev)
kfree(save_state);
}
-int pci_save_msix_state(struct pci_dev *dev)
+static int __pci_save_msix_state(struct pci_dev *dev)
{
int pos;
- int temp;
int irq, head, tail = 0;
u16 control;
struct pci_cap_saved_state *save_state;
+ if (!dev->msix_enabled)
+ return 0;
+
pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
if (pos <= 0 || dev->no_msi)
return 0;
@@ -398,38 +324,46 @@ int pci_save_msix_state(struct pci_dev *dev)
*((u16 *)&save_state->data[0]) = control;
/* save the table */
- temp = dev->irq;
- if (msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
- kfree(save_state);
- return -EINVAL;
- }
-
- irq = head = dev->irq;
+ irq = head = dev->first_msi_irq;
while (head != tail) {
struct msi_desc *entry;
- entry = msi_desc[irq];
+ entry = get_irq_msi(irq);
read_msi_msg(irq, &entry->msg_save);
- tail = msi_desc[irq]->link.tail;
+ tail = entry->link.tail;
irq = tail;
}
- dev->irq = temp;
save_state->cap_nr = PCI_CAP_ID_MSIX;
pci_add_saved_cap(dev, save_state);
return 0;
}
-void pci_restore_msix_state(struct pci_dev *dev)
+int pci_save_msi_state(struct pci_dev *dev)
+{
+ int rc;
+
+ rc = __pci_save_msi_state(dev);
+ if (rc)
+ return rc;
+
+ rc = __pci_save_msix_state(dev);
+
+ return rc;
+}
+
+static void __pci_restore_msix_state(struct pci_dev *dev)
{
u16 save;
int pos;
int irq, head, tail = 0;
struct msi_desc *entry;
- int temp;
struct pci_cap_saved_state *save_state;
+ if (!dev->msix_enabled)
+ return;
+
save_state = pci_find_saved_cap(dev, PCI_CAP_ID_MSIX);
if (!save_state)
return;
@@ -442,23 +376,25 @@ void pci_restore_msix_state(struct pci_dev *dev)
return;
/* route the table */
- temp = dev->irq;
- if (msi_lookup_irq(dev, PCI_CAP_ID_MSIX))
- return;
- irq = head = dev->irq;
+ irq = head = dev->first_msi_irq;
while (head != tail) {
- entry = msi_desc[irq];
+ entry = get_irq_msi(irq);
write_msi_msg(irq, &entry->msg_save);
- tail = msi_desc[irq]->link.tail;
+ tail = entry->link.tail;
irq = tail;
}
- dev->irq = temp;
pci_write_config_word(dev, msi_control_reg(pos), save);
enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
}
-#endif
+
+void pci_restore_msi_state(struct pci_dev *dev)
+{
+ __pci_restore_msi_state(dev);
+ __pci_restore_msix_state(dev);
+}
+#endif /* CONFIG_PM */
/**
* msi_capability_init - configure device's MSI capability structure
@@ -471,7 +407,6 @@ void pci_restore_msix_state(struct pci_dev *dev)
**/
static int msi_capability_init(struct pci_dev *dev)
{
- int status;
struct msi_desc *entry;
int pos, irq;
u16 control;
@@ -479,13 +414,10 @@ static int msi_capability_init(struct pci_dev *dev)
pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
pci_read_config_word(dev, msi_control_reg(pos), &control);
/* MSI Entry Initialization */
- irq = create_msi_irq();
- if (irq < 0)
- return irq;
+ entry = alloc_msi_entry();
+ if (!entry)
+ return -ENOMEM;
- entry = get_irq_data(irq);
- entry->link.head = irq;
- entry->link.tail = irq;
entry->msi_attrib.type = PCI_CAP_ID_MSI;
entry->msi_attrib.is_64 = is_64bit_address(control);
entry->msi_attrib.entry_nr = 0;
@@ -511,13 +443,16 @@ static int msi_capability_init(struct pci_dev *dev)
maskbits);
}
/* Configure MSI capability structure */
- status = arch_setup_msi_irq(irq, dev);
- if (status < 0) {
- destroy_msi_irq(irq);
- return status;
+ irq = arch_setup_msi_irq(dev, entry);
+ if (irq < 0) {
+ kmem_cache_free(msi_cachep, entry);
+ return irq;
}
+ entry->link.head = irq;
+ entry->link.tail = irq;
+ dev->first_msi_irq = irq;
+ set_irq_msi(irq, entry);
- attach_msi_entry(entry, irq);
/* Set MSI enabled bits */
enable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
@@ -539,7 +474,6 @@ static int msix_capability_init(struct pci_dev *dev,
struct msix_entry *entries, int nvec)
{
struct msi_desc *head = NULL, *tail = NULL, *entry = NULL;
- int status;
int irq, pos, i, j, nr_entries, temp = 0;
unsigned long phys_addr;
u32 table_offset;
@@ -562,13 +496,11 @@ static int msix_capability_init(struct pci_dev *dev,
/* MSI-X Table Initialization */
for (i = 0; i < nvec; i++) {
- irq = create_msi_irq();
- if (irq < 0)
+ entry = alloc_msi_entry();
+ if (!entry)
break;
- entry = get_irq_data(irq);
j = entries[i].entry;
- entries[i].vector = irq;
entry->msi_attrib.type = PCI_CAP_ID_MSIX;
entry->msi_attrib.is_64 = 1;
entry->msi_attrib.entry_nr = j;
@@ -577,6 +509,14 @@ static int msix_capability_init(struct pci_dev *dev,
entry->msi_attrib.pos = pos;
entry->dev = dev;
entry->mask_base = base;
+
+ /* Configure MSI-X capability structure */
+ irq = arch_setup_msi_irq(dev, entry);
+ if (irq < 0) {
+ kmem_cache_free(msi_cachep, entry);
+ break;
+ }
+ entries[i].vector = irq;
if (!head) {
entry->link.head = irq;
entry->link.tail = irq;
@@ -589,14 +529,8 @@ static int msix_capability_init(struct pci_dev *dev,
}
temp = irq;
tail = entry;
- /* Configure MSI-X capability structure */
- status = arch_setup_msi_irq(irq, dev);
- if (status < 0) {
- destroy_msi_irq(irq);
- break;
- }
- attach_msi_entry(entry, irq);
+ set_irq_msi(irq, entry);
}
if (i != nvec) {
int avail = i - 1;
@@ -613,6 +547,7 @@ static int msix_capability_init(struct pci_dev *dev,
avail = -EBUSY;
return avail;
}
+ dev->first_msi_irq = entries[0].vector;
/* Set MSI-X enabled bits */
enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
@@ -660,13 +595,11 @@ int pci_msi_supported(struct pci_dev * dev)
**/
int pci_enable_msi(struct pci_dev* dev)
{
- int pos, temp, status;
+ int pos, status;
if (pci_msi_supported(dev) < 0)
return -EINVAL;
- temp = dev->irq;
-
status = msi_init();
if (status < 0)
return status;
@@ -675,15 +608,14 @@ int pci_enable_msi(struct pci_dev* dev)
if (!pos)
return -EINVAL;
- WARN_ON(!msi_lookup_irq(dev, PCI_CAP_ID_MSI));
+ WARN_ON(!!dev->msi_enabled);
/* Check whether driver already requested for MSI-X irqs */
pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
- if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
+ if (pos > 0 && dev->msix_enabled) {
printk(KERN_INFO "PCI: %s: Can't enable MSI. "
- "Device already has MSI-X irq assigned\n",
+ "Device already has MSI-X enabled\n",
pci_name(dev));
- dev->irq = temp;
return -EINVAL;
}
status = msi_capability_init(dev);
@@ -695,13 +627,15 @@ void pci_disable_msi(struct pci_dev* dev)
struct msi_desc *entry;
int pos, default_irq;
u16 control;
- unsigned long flags;
if (!pci_msi_enable)
return;
if (!dev)
return;
+ if (!dev->msi_enabled)
+ return;
+
pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
if (!pos)
return;
@@ -710,28 +644,26 @@ void pci_disable_msi(struct pci_dev* dev)
if (!(control & PCI_MSI_FLAGS_ENABLE))
return;
+
disable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
- spin_lock_irqsave(&msi_lock, flags);
- entry = msi_desc[dev->irq];
+ entry = get_irq_msi(dev->first_msi_irq);
if (!entry || !entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) {
- spin_unlock_irqrestore(&msi_lock, flags);
return;
}
- if (irq_has_action(dev->irq)) {
- spin_unlock_irqrestore(&msi_lock, flags);
+ if (irq_has_action(dev->first_msi_irq)) {
printk(KERN_WARNING "PCI: %s: pci_disable_msi() called without "
"free_irq() on MSI irq %d\n",
- pci_name(dev), dev->irq);
- BUG_ON(irq_has_action(dev->irq));
+ pci_name(dev), dev->first_msi_irq);
+ BUG_ON(irq_has_action(dev->first_msi_irq));
} else {
default_irq = entry->msi_attrib.default_irq;
- spin_unlock_irqrestore(&msi_lock, flags);
- msi_free_irq(dev, dev->irq);
+ msi_free_irq(dev, dev->first_msi_irq);
/* Restore dev->irq to its default pin-assertion irq */
dev->irq = default_irq;
}
+ dev->first_msi_irq = 0;
}
static int msi_free_irq(struct pci_dev* dev, int irq)
@@ -739,27 +671,20 @@ static int msi_free_irq(struct pci_dev* dev, int irq)
struct msi_desc *entry;
int head, entry_nr, type;
void __iomem *base;
- unsigned long flags;
- arch_teardown_msi_irq(irq);
-
- spin_lock_irqsave(&msi_lock, flags);
- entry = msi_desc[irq];
+ entry = get_irq_msi(irq);
if (!entry || entry->dev != dev) {
- spin_unlock_irqrestore(&msi_lock, flags);
return -EINVAL;
}
type = entry->msi_attrib.type;
entry_nr = entry->msi_attrib.entry_nr;
head = entry->link.head;
base = entry->mask_base;
- msi_desc[entry->link.head]->link.tail = entry->link.tail;
- msi_desc[entry->link.tail]->link.head = entry->link.head;
- entry->dev = NULL;
- msi_desc[irq] = NULL;
- spin_unlock_irqrestore(&msi_lock, flags);
+ get_irq_msi(entry->link.head)->link.tail = entry->link.tail;
+ get_irq_msi(entry->link.tail)->link.head = entry->link.head;
- destroy_msi_irq(irq);
+ arch_teardown_msi_irq(irq);
+ kmem_cache_free(msi_cachep, entry);
if (type == PCI_CAP_ID_MSIX) {
writel(1, base + entry_nr * PCI_MSIX_ENTRY_SIZE +
@@ -790,7 +715,7 @@ static int msi_free_irq(struct pci_dev* dev, int irq)
int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
{
int status, pos, nr_entries;
- int i, j, temp;
+ int i, j;
u16 control;
if (!entries || pci_msi_supported(dev) < 0)
@@ -818,16 +743,14 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
return -EINVAL; /* duplicate entry */
}
}
- temp = dev->irq;
- WARN_ON(!msi_lookup_irq(dev, PCI_CAP_ID_MSIX));
+ WARN_ON(!!dev->msix_enabled);
/* Check whether driver already requested for MSI irq */
if (pci_find_capability(dev, PCI_CAP_ID_MSI) > 0 &&
- !msi_lookup_irq(dev, PCI_CAP_ID_MSI)) {
+ dev->msi_enabled) {
printk(KERN_INFO "PCI: %s: Can't enable MSI-X. "
"Device already has an MSI irq assigned\n",
pci_name(dev));
- dev->irq = temp;
return -EINVAL;
}
status = msix_capability_init(dev, entries, nvec);
@@ -836,7 +759,8 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
void pci_disable_msix(struct pci_dev* dev)
{
- int pos, temp;
+ int irq, head, tail = 0, warning = 0;
+ int pos;
u16 control;
if (!pci_msi_enable)
@@ -844,6 +768,9 @@ void pci_disable_msix(struct pci_dev* dev)
if (!dev)
return;
+ if (!dev->msix_enabled)
+ return;
+
pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
if (!pos)
return;
@@ -854,31 +781,23 @@ void pci_disable_msix(struct pci_dev* dev)
disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
- temp = dev->irq;
- if (!msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
- int irq, head, tail = 0, warning = 0;
- unsigned long flags;
-
- irq = head = dev->irq;
- dev->irq = temp; /* Restore pin IRQ */
- while (head != tail) {
- spin_lock_irqsave(&msi_lock, flags);
- tail = msi_desc[irq]->link.tail;
- spin_unlock_irqrestore(&msi_lock, flags);
- if (irq_has_action(irq))
- warning = 1;
- else if (irq != head) /* Release MSI-X irq */
- msi_free_irq(dev, irq);
- irq = tail;
- }
- msi_free_irq(dev, irq);
- if (warning) {
- printk(KERN_WARNING "PCI: %s: pci_disable_msix() called without "
- "free_irq() on all MSI-X irqs\n",
- pci_name(dev));
- BUG_ON(warning > 0);
- }
+ irq = head = dev->first_msi_irq;
+ while (head != tail) {
+ tail = get_irq_msi(irq)->link.tail;
+ if (irq_has_action(irq))
+ warning = 1;
+ else if (irq != head) /* Release MSI-X irq */
+ msi_free_irq(dev, irq);
+ irq = tail;
+ }
+ msi_free_irq(dev, irq);
+ if (warning) {
+ printk(KERN_WARNING "PCI: %s: pci_disable_msix() called without "
+ "free_irq() on all MSI-X irqs\n",
+ pci_name(dev));
+ BUG_ON(warning > 0);
}
+ dev->first_msi_irq = 0;
}
/**
@@ -892,35 +811,26 @@ void pci_disable_msix(struct pci_dev* dev)
**/
void msi_remove_pci_irq_vectors(struct pci_dev* dev)
{
- int pos, temp;
- unsigned long flags;
-
if (!pci_msi_enable || !dev)
return;
- temp = dev->irq; /* Save IOAPIC IRQ */
- pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
- if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSI)) {
- if (irq_has_action(dev->irq)) {
+ if (dev->msi_enabled) {
+ if (irq_has_action(dev->first_msi_irq)) {
printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() "
"called without free_irq() on MSI irq %d\n",
- pci_name(dev), dev->irq);
- BUG_ON(irq_has_action(dev->irq));
+ pci_name(dev), dev->first_msi_irq);
+ BUG_ON(irq_has_action(dev->first_msi_irq));
} else /* Release MSI irq assigned to this device */
- msi_free_irq(dev, dev->irq);
- dev->irq = temp; /* Restore IOAPIC IRQ */
+ msi_free_irq(dev, dev->first_msi_irq);
}
- pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
- if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
+ if (dev->msix_enabled) {
int irq, head, tail = 0, warning = 0;
void __iomem *base = NULL;
- irq = head = dev->irq;
+ irq = head = dev->first_msi_irq;
while (head != tail) {
- spin_lock_irqsave(&msi_lock, flags);
- tail = msi_desc[irq]->link.tail;
- base = msi_desc[irq]->mask_base;
- spin_unlock_irqrestore(&msi_lock, flags);
+ tail = get_irq_msi(irq)->link.tail;
+ base = get_irq_msi(irq)->mask_base;
if (irq_has_action(irq))
warning = 1;
else if (irq != head) /* Release MSI-X irq */
@@ -935,7 +845,6 @@ void msi_remove_pci_irq_vectors(struct pci_dev* dev)
pci_name(dev));
BUG_ON(warning > 0);
}
- dev->irq = temp; /* Restore IOAPIC IRQ */
}
}
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 92d5e8db0de..4438ae1ede4 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -324,8 +324,7 @@ static int pci_default_resume(struct pci_dev *pci_dev)
/* restore the PCI config space */
pci_restore_state(pci_dev);
/* if the device was enabled before suspend, reenable */
- if (atomic_read(&pci_dev->enable_cnt))
- retval = __pci_enable_device(pci_dev);
+ retval = __pci_reenable_device(pci_dev);
/* if the device was busmaster before the suspend, make it busmaster again */
if (pci_dev->is_busmaster)
pci_set_master(pci_dev);
@@ -422,7 +421,8 @@ static struct kobj_type pci_driver_kobj_type = {
* If no error occurred, the driver remains registered even if
* no device was claimed during registration.
*/
-int __pci_register_driver(struct pci_driver *drv, struct module *owner)
+int __pci_register_driver(struct pci_driver *drv, struct module *owner,
+ const char *mod_name)
{
int error;
@@ -430,6 +430,7 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner)
drv->driver.name = drv->name;
drv->driver.bus = &pci_bus_type;
drv->driver.owner = owner;
+ drv->driver.mod_name = mod_name;
drv->driver.kobj.ktype = &pci_driver_kobj_type;
if (pci_multithread_probe)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 206c834d263..84c757ba066 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -392,6 +392,14 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state)
if (state > PCI_D3hot)
state = PCI_D3hot;
+ /*
+ * 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;
+
/* Validate current state:
* Can enter D0 from any state, but if we can only go deeper
* to sleep if we're already in a low power state
@@ -403,13 +411,6 @@ 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);
@@ -633,8 +634,6 @@ pci_save_state(struct pci_dev *dev)
pci_read_config_dword(dev, i * 4,&dev->saved_config_space[i]);
if ((i = pci_save_msi_state(dev)) != 0)
return i;
- if ((i = pci_save_msix_state(dev)) != 0)
- return i;
if ((i = pci_save_pcie_state(dev)) != 0)
return i;
if ((i = pci_save_pcix_state(dev)) != 0)
@@ -672,22 +671,11 @@ pci_restore_state(struct pci_dev *dev)
}
pci_restore_pcix_state(dev);
pci_restore_msi_state(dev);
- pci_restore_msix_state(dev);
+
return 0;
}
-/**
- * pci_enable_device_bars - Initialize some of a device for use
- * @dev: PCI device to be initialized
- * @bars: bitmask of BAR's that must be configured
- *
- * Initialize device before it's used by a driver. Ask low-level code
- * to enable selected I/O and memory resources. Wake up the device if it
- * was suspended. Beware, this function can fail.
- */
-
-int
-pci_enable_device_bars(struct pci_dev *dev, int bars)
+static int do_pci_enable_device(struct pci_dev *dev, int bars)
{
int err;
@@ -697,30 +685,47 @@ pci_enable_device_bars(struct pci_dev *dev, int bars)
err = pcibios_enable_device(dev, bars);
if (err < 0)
return err;
+ pci_fixup_device(pci_fixup_enable, dev);
+
return 0;
}
/**
- * __pci_enable_device - Initialize device before it's used by a driver.
+ * __pci_reenable_device - Resume abandoned device
+ * @dev: PCI device to be resumed
+ *
+ * Note this function is a backend of pci_default_resume and is not supposed
+ * to be called by normal code, write proper resume handler and use it instead.
+ */
+int
+__pci_reenable_device(struct pci_dev *dev)
+{
+ if (atomic_read(&dev->enable_cnt))
+ return do_pci_enable_device(dev, (1 << PCI_NUM_RESOURCES) - 1);
+ return 0;
+}
+
+/**
+ * pci_enable_device_bars - Initialize some of a device for use
* @dev: PCI device to be initialized
+ * @bars: bitmask of BAR's that must be configured
*
* Initialize device before it's used by a driver. Ask low-level code
- * to enable I/O and memory. Wake up the device if it was suspended.
- * Beware, this function can fail.
- *
- * Note this function is a backend and is not supposed to be called by
- * normal code, use pci_enable_device() instead.
+ * to enable selected I/O and memory resources. Wake up the device if it
+ * was suspended. Beware, this function can fail.
*/
int
-__pci_enable_device(struct pci_dev *dev)
+pci_enable_device_bars(struct pci_dev *dev, int bars)
{
int err;
- err = pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1);
- if (err)
- return err;
- pci_fixup_device(pci_fixup_enable, dev);
- return 0;
+ if (atomic_add_return(1, &dev->enable_cnt) > 1)
+ return 0; /* already enabled */
+
+ err = do_pci_enable_device(dev, bars);
+ if (err < 0)
+ atomic_dec(&dev->enable_cnt);
+ return err;
}
/**
@@ -736,13 +741,7 @@ __pci_enable_device(struct pci_dev *dev)
*/
int pci_enable_device(struct pci_dev *dev)
{
- int result;
- if (atomic_add_return(1, &dev->enable_cnt) > 1)
- return 0; /* already enabled */
- result = __pci_enable_device(dev);
- if (result < 0)
- atomic_dec(&dev->enable_cnt);
- return result;
+ return pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1);
}
/**
@@ -921,6 +920,47 @@ err_out:
return -EBUSY;
}
+/**
+ * pci_release_selected_regions - Release selected PCI I/O and memory resources
+ * @pdev: PCI device whose resources were previously reserved
+ * @bars: Bitmask of BARs to be released
+ *
+ * Release selected PCI I/O and memory resources previously reserved.
+ * Call this function only after all use of the PCI regions has ceased.
+ */
+void pci_release_selected_regions(struct pci_dev *pdev, int bars)
+{
+ int i;
+
+ for (i = 0; i < 6; i++)
+ if (bars & (1 << i))
+ pci_release_region(pdev, i);
+}
+
+/**
+ * pci_request_selected_regions - Reserve selected PCI I/O and memory resources
+ * @pdev: PCI device whose resources are to be reserved
+ * @bars: Bitmask of BARs to be requested
+ * @res_name: Name to be associated with resource
+ */
+int pci_request_selected_regions(struct pci_dev *pdev, int bars,
+ const char *res_name)
+{
+ int i;
+
+ for (i = 0; i < 6; i++)
+ if (bars & (1 << i))
+ if(pci_request_region(pdev, i, res_name))
+ goto err_out;
+ return 0;
+
+err_out:
+ while(--i >= 0)
+ if (bars & (1 << i))
+ pci_release_region(pdev, i);
+
+ return -EBUSY;
+}
/**
* pci_release_regions - Release reserved PCI I/O and memory resources
@@ -933,10 +973,7 @@ err_out:
void pci_release_regions(struct pci_dev *pdev)
{
- int i;
-
- for (i = 0; i < 6; i++)
- pci_release_region(pdev, i);
+ pci_release_selected_regions(pdev, (1 << 6) - 1);
}
/**
@@ -954,18 +991,7 @@ void pci_release_regions(struct pci_dev *pdev)
*/
int pci_request_regions(struct pci_dev *pdev, const char *res_name)
{
- int i;
-
- for (i = 0; i < 6; i++)
- if(pci_request_region(pdev, i, res_name))
- goto err_out;
- return 0;
-
-err_out:
- while(--i >= 0)
- pci_release_region(pdev, i);
-
- return -EBUSY;
+ return pci_request_selected_regions(pdev, ((1 << 6) - 1), res_name);
}
/**
@@ -1148,7 +1174,23 @@ pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask)
return 0;
}
#endif
-
+
+/**
+ * pci_select_bars - Make BAR mask from the type of resource
+ * @pdev: the PCI device for which BAR mask is made
+ * @flags: resource type mask to be selected
+ *
+ * This helper routine makes bar mask from the type of resource.
+ */
+int pci_select_bars(struct pci_dev *dev, unsigned long flags)
+{
+ int i, bars = 0;
+ for (i = 0; i < PCI_NUM_RESOURCES; i++)
+ if (pci_resource_flags(dev, i) & flags)
+ bars |= (1 << i);
+ return bars;
+}
+
static int __devinit pci_init(void)
{
struct pci_dev *dev = NULL;
@@ -1181,12 +1223,6 @@ early_param("pci", pci_setup);
device_initcall(pci_init);
-#if defined(CONFIG_ISA) || defined(CONFIG_EISA)
-/* FIXME: Some boxes have multiple ISA bridges! */
-struct pci_dev *isa_bridge;
-EXPORT_SYMBOL(isa_bridge);
-#endif
-
EXPORT_SYMBOL_GPL(pci_restore_bars);
EXPORT_SYMBOL(pci_enable_device_bars);
EXPORT_SYMBOL(pci_enable_device);
@@ -1197,6 +1233,8 @@ EXPORT_SYMBOL(pci_release_regions);
EXPORT_SYMBOL(pci_request_regions);
EXPORT_SYMBOL(pci_release_region);
EXPORT_SYMBOL(pci_request_region);
+EXPORT_SYMBOL(pci_release_selected_regions);
+EXPORT_SYMBOL(pci_request_selected_regions);
EXPORT_SYMBOL(pci_set_master);
EXPORT_SYMBOL(pci_set_mwi);
EXPORT_SYMBOL(pci_clear_mwi);
@@ -1205,13 +1243,10 @@ EXPORT_SYMBOL(pci_set_dma_mask);
EXPORT_SYMBOL(pci_set_consistent_dma_mask);
EXPORT_SYMBOL(pci_assign_resource);
EXPORT_SYMBOL(pci_find_parent_resource);
+EXPORT_SYMBOL(pci_select_bars);
EXPORT_SYMBOL(pci_set_power_state);
EXPORT_SYMBOL(pci_save_state);
EXPORT_SYMBOL(pci_restore_state);
EXPORT_SYMBOL(pci_enable_wake);
-/* Quirk info */
-
-EXPORT_SYMBOL(isa_dma_bridge_buggy);
-EXPORT_SYMBOL(pci_pci_problems);
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 398852f526a..a4f2d580625 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -1,6 +1,6 @@
/* Functions internal to the PCI core code */
-extern int __must_check __pci_enable_device(struct pci_dev *);
+extern int __must_check __pci_reenable_device(struct pci_dev *);
extern int pci_uevent(struct device *dev, char **envp, int num_envp,
char *buffer, int buffer_size);
extern int pci_create_sysfs_dev_files(struct pci_dev *pdev);
@@ -43,12 +43,8 @@ extern void pci_remove_legacy_files(struct pci_bus *bus);
/* Lock for read/write access to pci device and bus lists */
extern struct rw_semaphore pci_bus_sem;
-#ifdef CONFIG_PCI_MSI
-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);
@@ -56,17 +52,15 @@ void pci_no_msi(void);
static inline void disable_msi_mode(struct pci_dev *dev, int pos, int type) { }
static inline void pci_no_msi(void) { }
#endif
+
#if defined(CONFIG_PCI_MSI) && defined(CONFIG_PM)
int pci_save_msi_state(struct pci_dev *dev);
-int pci_save_msix_state(struct pci_dev *dev);
void pci_restore_msi_state(struct pci_dev *dev);
-void pci_restore_msix_state(struct pci_dev *dev);
#else
static inline int pci_save_msi_state(struct pci_dev *dev) { return 0; }
-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;
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 0e0401dd02c..2fe1d690eb1 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -144,6 +144,32 @@ static u32 pci_size(u32 base, u32 maxbase, u32 mask)
return size;
}
+static u64 pci_size64(u64 base, u64 maxbase, u64 mask)
+{
+ u64 size = mask & maxbase; /* Find the significant bits */
+ if (!size)
+ return 0;
+
+ /* Get the lowest of them to find the decode size, and
+ from that the extent. */
+ size = (size & ~(size-1)) - 1;
+
+ /* base == maxbase can be valid only if the BAR has
+ already been programmed with all 1s. */
+ if (base == maxbase && ((base | size) & mask) != mask)
+ return 0;
+
+ return size;
+}
+
+static inline int is_64bit_memory(u32 mask)
+{
+ if ((mask & (PCI_BASE_ADDRESS_SPACE|PCI_BASE_ADDRESS_MEM_TYPE_MASK)) ==
+ (PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64))
+ return 1;
+ return 0;
+}
+
static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
{
unsigned int pos, reg, next;
@@ -151,6 +177,10 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
struct resource *res;
for(pos=0; pos<howmany; pos = next) {
+ u64 l64;
+ u64 sz64;
+ u32 raw_sz;
+
next = pos+1;
res = &dev->resource[pos];
res->name = pci_name(dev);
@@ -163,9 +193,16 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
continue;
if (l == 0xffffffff)
l = 0;
- if ((l & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) {
+ raw_sz = sz;
+ if ((l & PCI_BASE_ADDRESS_SPACE) ==
+ PCI_BASE_ADDRESS_SPACE_MEMORY) {
sz = pci_size(l, sz, (u32)PCI_BASE_ADDRESS_MEM_MASK);
- if (!sz)
+ /*
+ * For 64bit prefetchable memory sz could be 0, if the
+ * real size is bigger than 4G, so we need to check
+ * szhi for that.
+ */
+ if (!is_64bit_memory(l) && !sz)
continue;
res->start = l & PCI_BASE_ADDRESS_MEM_MASK;
res->flags |= l & ~PCI_BASE_ADDRESS_MEM_MASK;
@@ -178,30 +215,36 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
}
res->end = res->start + (unsigned long) sz;
res->flags |= pci_calc_resource_flags(l);
- if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK))
- == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) {
+ if (is_64bit_memory(l)) {
u32 szhi, lhi;
+
pci_read_config_dword(dev, reg+4, &lhi);
pci_write_config_dword(dev, reg+4, ~0);
pci_read_config_dword(dev, reg+4, &szhi);
pci_write_config_dword(dev, reg+4, lhi);
- szhi = pci_size(lhi, szhi, 0xffffffff);
+ sz64 = ((u64)szhi << 32) | raw_sz;
+ l64 = ((u64)lhi << 32) | l;
+ sz64 = pci_size64(l64, sz64, PCI_BASE_ADDRESS_MEM_MASK);
next++;
#if BITS_PER_LONG == 64
- res->start |= ((unsigned long) lhi) << 32;
- res->end = res->start + sz;
- if (szhi) {
- /* This BAR needs > 4GB? Wow. */
- res->end |= (unsigned long)szhi<<32;
+ if (!sz64) {
+ res->start = 0;
+ res->end = 0;
+ res->flags = 0;
+ continue;
}
+ res->start = l64 & PCI_BASE_ADDRESS_MEM_MASK;
+ res->end = res->start + sz64;
#else
- if (szhi) {
- printk(KERN_ERR "PCI: Unable to handle 64-bit BAR for device %s\n", pci_name(dev));
+ if (sz64 > 0x100000000ULL) {
+ printk(KERN_ERR "PCI: Unable to handle 64-bit "
+ "BAR for device %s\n", pci_name(dev));
res->start = 0;
res->flags = 0;
} else if (lhi) {
/* 64-bit wide address, treat as disabled */
- pci_write_config_dword(dev, reg, l & ~(u32)PCI_BASE_ADDRESS_MEM_MASK);
+ pci_write_config_dword(dev, reg,
+ l & ~(u32)PCI_BASE_ADDRESS_MEM_MASK);
pci_write_config_dword(dev, reg+4, 0);
res->start = 0;
res->end = sz;
@@ -902,7 +945,6 @@ pci_scan_single_device(struct pci_bus *bus, int devfn)
return NULL;
pci_device_add(dev, bus);
- pci_scan_msi_device(dev);
return dev;
}
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index c913ea4e545..11217bda4b9 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -61,7 +61,8 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_p
This appears to be BIOS not version dependent. So presumably there is a
chipset level fix */
-int isa_dma_bridge_buggy; /* Exported */
+int isa_dma_bridge_buggy;
+EXPORT_SYMBOL(isa_dma_bridge_buggy);
static void __devinit quirk_isa_dma_hangs(struct pci_dev *dev)
{
@@ -83,6 +84,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_2, quirk_isa_d
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_3, quirk_isa_dma_hangs );
int pci_pci_problems;
+EXPORT_SYMBOL(pci_pci_problems);
/*
* Chipsets where PCI->PCI transfers vanish or hang
@@ -94,6 +96,8 @@ static void __devinit quirk_nopcipci(struct pci_dev *dev)
pci_pci_problems |= PCIPCI_FAIL;
}
}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, quirk_nopcipci );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, quirk_nopcipci );
static void __devinit quirk_nopciamd(struct pci_dev *dev)
{
@@ -105,9 +109,6 @@ static void __devinit quirk_nopciamd(struct pci_dev *dev)
pci_pci_problems |= PCIAGP_FAIL;
}
}
-
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, quirk_nopcipci );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, quirk_nopcipci );
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8151_0, quirk_nopciamd );
/*
@@ -976,52 +977,51 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev)
case 0x1626: /* L3C notebook */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_82845G_HB)
+ else if (dev->device == PCI_DEVICE_ID_INTEL_82845G_HB)
switch(dev->subsystem_device) {
case 0x80b1: /* P4GE-V */
case 0x80b2: /* P4PE */
case 0x8093: /* P4B533-V */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_82850_HB)
+ else if (dev->device == PCI_DEVICE_ID_INTEL_82850_HB)
switch(dev->subsystem_device) {
case 0x8030: /* P4T533 */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_7205_0)
+ else if (dev->device == PCI_DEVICE_ID_INTEL_7205_0)
switch (dev->subsystem_device) {
case 0x8070: /* P4G8X Deluxe */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_E7501_MCH)
+ else 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)
+ else if (dev->device == PCI_DEVICE_ID_INTEL_82855GM_HB)
switch (dev->subsystem_device) {
case 0x1751: /* M2N notebook */
case 0x1821: /* M5N notebook */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB)
+ else if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB)
switch (dev->subsystem_device) {
case 0x184b: /* W1N notebook */
case 0x186a: /* M6Ne notebook */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_82865_HB)
+ else if (dev->device == PCI_DEVICE_ID_INTEL_82865_HB)
switch (dev->subsystem_device) {
case 0x80f2: /* P4P800-X */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB) {
+ else if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB)
switch (dev->subsystem_device) {
case 0x1882: /* M6V notebook */
case 0x1977: /* A6VA notebook */
asus_hides_smbus = 1;
}
- }
} else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_HP)) {
if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB)
switch(dev->subsystem_device) {
@@ -1029,25 +1029,24 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev)
case 0x0890: /* HP Compaq nc6000 */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_82865_HB)
+ else if (dev->device == PCI_DEVICE_ID_INTEL_82865_HB)
switch (dev->subsystem_device) {
case 0x12bc: /* HP D330L */
case 0x12bd: /* HP D530 */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB) {
+ else if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB)
switch (dev->subsystem_device) {
case 0x099c: /* HP Compaq nx6110 */
asus_hides_smbus = 1;
}
- }
} else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_TOSHIBA)) {
if (dev->device == PCI_DEVICE_ID_INTEL_82855GM_HB)
switch(dev->subsystem_device) {
case 0x0001: /* Toshiba Satellite A40 */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB)
+ else if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB)
switch(dev->subsystem_device) {
case 0x0001: /* Toshiba Tecra M2 */
asus_hides_smbus = 1;
@@ -1136,6 +1135,14 @@ static void quirk_sis_96x_smbus(struct pci_dev *dev)
pci_write_config_byte(dev, 0x77, val & ~0x10);
}
}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus );
+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 );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus );
/*
* ... This is further complicated by the fact that some SiS96x south
@@ -1145,8 +1152,6 @@ static void quirk_sis_96x_smbus(struct pci_dev *dev)
*
* We can also enable the sis96x bit in the discovery register..
*/
-static int __devinitdata sis_96x_compatible = 0;
-
#define SIS_DETECT_REGISTER 0x40
static void quirk_sis_503(struct pci_dev *dev)
@@ -1162,9 +1167,6 @@ static void quirk_sis_503(struct pci_dev *dev)
return;
}
- /* Make people aware that we changed the config.. */
- printk(KERN_WARNING "Uncovering SIS%x that hid as a SIS503 (compatible=%d)\n", devid, sis_96x_compatible);
-
/*
* Ok, it now shows up as a 96x.. run the 96x quirk by
* hand in case it has already been processed.
@@ -1173,20 +1175,10 @@ static void quirk_sis_503(struct pci_dev *dev)
dev->device = devid;
quirk_sis_96x_smbus(dev);
}
-
-static void __init quirk_sis_96x_compatible(struct pci_dev *dev)
-{
- sis_96x_compatible = 1;
-}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_645, quirk_sis_96x_compatible );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_646, quirk_sis_96x_compatible );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_648, quirk_sis_96x_compatible );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_650, quirk_sis_96x_compatible );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_651, quirk_sis_96x_compatible );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_735, quirk_sis_96x_compatible );
-
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, quirk_sis_503 );
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, quirk_sis_503 );
+
+
/*
* On ASUS A8V and A8V Deluxe boards, the onboard AC97 audio controller
* and MC97 modem controller are disabled when a second PCI soundcard is
@@ -1217,21 +1209,8 @@ static void asus_hides_ac97_lpc(struct pci_dev *dev)
}
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc );
-
-
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus );
-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 );
-
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc );
-
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus );
-
#if defined(CONFIG_ATA) || defined(CONFIG_ATA_MODULE)
/*
@@ -1276,7 +1255,6 @@ static void quirk_jmicron_dualfn(struct pci_dev *pdev)
break;
}
}
-
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, quirk_jmicron_dualfn);
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, quirk_jmicron_dualfn);
@@ -1420,6 +1398,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_intel_ide_co
int pcie_mch_quirk;
+EXPORT_SYMBOL(pcie_mch_quirk);
static void __devinit quirk_pcie_mch(struct pci_dev *pdev)
{
@@ -1481,6 +1460,24 @@ 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);
+/*
+ * Toshiba TC86C001 IDE controller reports the standard 8-byte BAR0 size
+ * but the PIO transfers won't work if BAR0 falls at the odd 8 bytes.
+ * Re-allocate the region if needed...
+ */
+static void __init quirk_tc86c001_ide(struct pci_dev *dev)
+{
+ struct resource *r = &dev->resource[0];
+
+ if (r->start & 0x8) {
+ r->start = 0;
+ r->end = 0xf;
+ }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA_2,
+ PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE,
+ quirk_tc86c001_ide);
+
static void __devinit quirk_netmos(struct pci_dev *dev)
{
unsigned int num_parallel = (dev->subsystem_device & 0xf0) >> 4;
@@ -1646,6 +1643,7 @@ void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev)
}
pci_do_fixups(dev, start, end);
}
+EXPORT_SYMBOL(pci_fixup_device);
/* Enable 1k I/O space granularity on the Intel P64H2 */
static void __devinit quirk_p64h2_1k_io(struct pci_dev *dev)
@@ -1673,6 +1671,31 @@ static void __devinit quirk_p64h2_1k_io(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1460, quirk_p64h2_1k_io);
+/* Fix the IOBL_ADR for 1k I/O space granularity on the Intel P64H2
+ * The IOBL_ADR gets re-written to 4k boundaries in pci_setup_bridge()
+ * in drivers/pci/setup-bus.c
+ */
+static void __devinit quirk_p64h2_1k_io_fix_iobl(struct pci_dev *dev)
+{
+ u16 en1k, iobl_adr, iobl_adr_1k;
+ struct resource *res = dev->resource + PCI_BRIDGE_RESOURCES;
+
+ pci_read_config_word(dev, 0x40, &en1k);
+
+ if (en1k & 0x200) {
+ pci_read_config_word(dev, PCI_IO_BASE, &iobl_adr);
+
+ iobl_adr_1k = iobl_adr | (res->start >> 8) | (res->end & 0xfc00);
+
+ if (iobl_adr != iobl_adr_1k) {
+ printk(KERN_INFO "PCI: Fixing P64H2 IOBL_ADR from 0x%x to 0x%x for 1 KB Granularity\n",
+ iobl_adr,iobl_adr_1k);
+ pci_write_config_word(dev, PCI_IO_BASE, iobl_adr_1k);
+ }
+ }
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1460, quirk_p64h2_1k_io_fix_iobl);
+
/* Under some circumstances, AER is not linked with extended capabilities.
* Force it to be linked by setting the corresponding control bit in the
* config space.
@@ -1695,9 +1718,6 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE,
quirk_nvidia_ck804_pcie_aer_ext_cap);
#ifdef CONFIG_PCI_MSI
-/* To disable MSI globally */
-int pci_msi_quirk;
-
/* The Serverworks PCI-X chipset does not support MSI. We cannot easily rely
* on setting PCI_BUS_FLAGS_NO_MSI in its bus flags because there are actually
* some other busses controlled by the chipset even if Linux is not aware of it.
@@ -1706,8 +1726,8 @@ int pci_msi_quirk;
*/
static void __init quirk_svw_msi(struct pci_dev *dev)
{
- pci_msi_quirk = 1;
- printk(KERN_WARNING "PCI: MSI quirk detected. pci_msi_quirk set.\n");
+ pci_no_msi();
+ printk(KERN_WARNING "PCI: MSI quirk detected. MSI deactivated.\n");
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_GCNB_LE, quirk_svw_msi);
@@ -1788,8 +1808,3 @@ static void __devinit quirk_nvidia_ck804_msi_ht_cap(struct pci_dev *dev)
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE,
quirk_nvidia_ck804_msi_ht_cap);
#endif /* CONFIG_PCI_MSI */
-
-EXPORT_SYMBOL(pcie_mch_quirk);
-#ifdef CONFIG_HOTPLUG
-EXPORT_SYMBOL(pci_fixup_device);
-#endif
diff --git a/drivers/pci/search.c b/drivers/pci/search.c
index b2653c4afe9..ff98eaddaa7 100644
--- a/drivers/pci/search.c
+++ b/drivers/pci/search.c
@@ -358,43 +358,6 @@ exit:
}
/**
- * pci_find_device_reverse - begin or continue searching for a PCI device by vendor/device id
- * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
- * @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().
- * 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 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)
-{
- struct list_head *n;
- struct pci_dev *dev;
-
- WARN_ON(in_interrupt());
- down_read(&pci_bus_sem);
- n = from ? from->global_list.prev : pci_devices.prev;
-
- while (n && (n != &pci_devices)) {
- dev = pci_dev_g(n);
- if ((vendor == PCI_ANY_ID || dev->vendor == vendor) &&
- (device == PCI_ANY_ID || dev->device == device))
- goto exit;
- n = n->prev;
- }
- dev = NULL;
-exit:
- up_read(&pci_bus_sem);
- return dev;
-}
-
-/**
* pci_get_class - begin or continue searching for a PCI device by class
* @class: search for a PCI device with this class designation
* @from: Previous PCI device found in search, or %NULL for new search.
@@ -469,7 +432,6 @@ EXPORT_SYMBOL(pci_dev_present);
EXPORT_SYMBOL(pci_find_present);
EXPORT_SYMBOL(pci_find_device);
-EXPORT_SYMBOL(pci_find_device_reverse);
EXPORT_SYMBOL(pci_find_slot);
/* For boot time work */
EXPORT_SYMBOL(pci_find_bus);
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index 606a4674033..ac004248324 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -110,7 +110,7 @@ int pcmcia_socket_dev_suspend(struct device *dev, pm_message_t state)
down_read(&pcmcia_socket_list_rwsem);
list_for_each_entry(socket, &pcmcia_socket_list, socket_list) {
- if (socket->dev.dev != dev)
+ if (socket->dev.parent != dev)
continue;
mutex_lock(&socket->skt_mutex);
socket_suspend(socket);
@@ -128,7 +128,7 @@ int pcmcia_socket_dev_resume(struct device *dev)
down_read(&pcmcia_socket_list_rwsem);
list_for_each_entry(socket, &pcmcia_socket_list, socket_list) {
- if (socket->dev.dev != dev)
+ if (socket->dev.parent != dev)
continue;
mutex_lock(&socket->skt_mutex);
socket_resume(socket);
@@ -143,12 +143,12 @@ EXPORT_SYMBOL(pcmcia_socket_dev_resume);
struct pcmcia_socket * pcmcia_get_socket(struct pcmcia_socket *skt)
{
- struct class_device *cl_dev = class_device_get(&skt->dev);
- if (!cl_dev)
+ struct device *dev = get_device(&skt->dev);
+ if (!dev)
return NULL;
- skt = class_get_devdata(cl_dev);
+ skt = dev_get_drvdata(dev);
if (!try_module_get(skt->owner)) {
- class_device_put(&skt->dev);
+ put_device(&skt->dev);
return NULL;
}
return (skt);
@@ -159,14 +159,14 @@ EXPORT_SYMBOL(pcmcia_get_socket);
void pcmcia_put_socket(struct pcmcia_socket *skt)
{
module_put(skt->owner);
- class_device_put(&skt->dev);
+ put_device(&skt->dev);
}
EXPORT_SYMBOL(pcmcia_put_socket);
-static void pcmcia_release_socket(struct class_device *class_dev)
+static void pcmcia_release_socket(struct device *dev)
{
- struct pcmcia_socket *socket = class_get_devdata(class_dev);
+ struct pcmcia_socket *socket = dev_get_drvdata(dev);
complete(&socket->socket_released);
}
@@ -181,7 +181,7 @@ int pcmcia_register_socket(struct pcmcia_socket *socket)
struct task_struct *tsk;
int ret;
- if (!socket || !socket->ops || !socket->dev.dev || !socket->resource_ops)
+ if (!socket || !socket->ops || !socket->dev.parent || !socket->resource_ops)
return -EINVAL;
cs_dbg(socket, 0, "pcmcia_register_socket(0x%p)\n", socket->ops);
@@ -226,9 +226,9 @@ int pcmcia_register_socket(struct pcmcia_socket *socket)
#endif
/* set proper values in socket->dev */
- socket->dev.class_data = socket;
+ dev_set_drvdata(&socket->dev, socket);
socket->dev.class = &pcmcia_socket_class;
- snprintf(socket->dev.class_id, BUS_ID_SIZE, "pcmcia_socket%u", socket->sock);
+ snprintf(socket->dev.bus_id, BUS_ID_SIZE, "pcmcia_socket%u", socket->sock);
/* base address = 0, map = 0 */
socket->cis_mem.flags = 0;
@@ -640,7 +640,7 @@ static int pccardd(void *__skt)
skt->ops->set_socket(skt, &skt->socket);
/* register with the device core */
- ret = class_device_register(&skt->dev);
+ ret = device_register(&skt->dev);
if (ret) {
printk(KERN_WARNING "PCMCIA: unable to register socket 0x%p\n",
skt);
@@ -689,7 +689,7 @@ static int pccardd(void *__skt)
remove_wait_queue(&skt->thread_wait, &wait);
/* remove from the device core */
- class_device_unregister(&skt->dev);
+ device_unregister(&skt->dev);
return 0;
}
@@ -904,7 +904,7 @@ int pcmcia_insert_card(struct pcmcia_socket *skt)
EXPORT_SYMBOL(pcmcia_insert_card);
-static int pcmcia_socket_uevent(struct class_device *dev, char **envp,
+static int pcmcia_socket_uevent(struct device *dev, char **envp,
int num_envp, char *buffer, int buffer_size)
{
struct pcmcia_socket *s = container_of(dev, struct pcmcia_socket, dev);
@@ -930,8 +930,8 @@ static void pcmcia_release_socket_class(struct class *data)
struct class pcmcia_socket_class = {
.name = "pcmcia_socket",
- .uevent = pcmcia_socket_uevent,
- .release = pcmcia_release_socket,
+ .dev_uevent = pcmcia_socket_uevent,
+ .dev_release = pcmcia_release_socket,
.class_release = pcmcia_release_socket_class,
};
EXPORT_SYMBOL(pcmcia_socket_class);
diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h
index f573ea04db6..9fa207e3c7b 100644
--- a/drivers/pcmcia/cs_internal.h
+++ b/drivers/pcmcia/cs_internal.h
@@ -142,7 +142,7 @@ struct pcmcia_callback{
int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c);
-#define cs_socket_name(skt) ((skt)->dev.class_id)
+#define cs_socket_name(skt) ((skt)->dev.bus_id)
#ifdef DEBUG
extern int cs_debug_level(int);
@@ -158,6 +158,6 @@ extern int cs_debug_level(int);
#endif
#define cs_err(skt, fmt, arg...) \
- printk(KERN_ERR "cs: %s: " fmt, (skt)->dev.class_id , ## arg)
+ printk(KERN_ERR "cs: %s: " fmt, (skt)->dev.bus_id , ## arg)
#endif /* _LINUX_CS_INTERNAL_H */
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 7355eb455a8..18e111e1233 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -572,7 +572,7 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f
p_dev->func = function;
p_dev->dev.bus = &pcmcia_bus_type;
- p_dev->dev.parent = s->dev.dev;
+ p_dev->dev.parent = s->dev.parent;
p_dev->dev.release = pcmcia_release_dev;
bus_id_len = sprintf (p_dev->dev.bus_id, "%d.%d", p_dev->socket->sock, p_dev->device_no);
@@ -1328,10 +1328,10 @@ static struct pcmcia_callback pcmcia_bus_callback = {
.resume = pcmcia_bus_resume,
};
-static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev,
+static int __devinit pcmcia_bus_add_socket(struct device *dev,
struct class_interface *class_intf)
{
- struct pcmcia_socket *socket = class_get_devdata(class_dev);
+ struct pcmcia_socket *socket = dev_get_drvdata(dev);
int ret;
socket = pcmcia_get_socket(socket);
@@ -1364,10 +1364,10 @@ static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev,
return 0;
}
-static void pcmcia_bus_remove_socket(struct class_device *class_dev,
+static void pcmcia_bus_remove_socket(struct device *dev,
struct class_interface *class_intf)
{
- struct pcmcia_socket *socket = class_get_devdata(class_dev);
+ struct pcmcia_socket *socket = dev_get_drvdata(dev);
if (!socket)
return;
@@ -1389,8 +1389,8 @@ static void pcmcia_bus_remove_socket(struct class_device *class_dev,
/* the pcmcia_bus_interface is used to handle pcmcia socket devices */
static struct class_interface pcmcia_bus_interface = {
.class = &pcmcia_socket_class,
- .add = &pcmcia_bus_add_socket,
- .remove = &pcmcia_bus_remove_socket,
+ .add_dev = &pcmcia_bus_add_socket,
+ .remove_dev = &pcmcia_bus_remove_socket,
};
diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c
index c2ea07aa7a1..df21e2d16f8 100644
--- a/drivers/pcmcia/i82092.c
+++ b/drivers/pcmcia/i82092.c
@@ -161,7 +161,7 @@ static int __devinit i82092aa_pci_probe(struct pci_dev *dev, const struct pci_de
pci_set_drvdata(dev, &sockets[i].socket);
for (i = 0; i<socket_count; i++) {
- sockets[i].socket.dev.dev = &dev->dev;
+ sockets[i].socket.dev.parent = &dev->dev;
sockets[i].socket.ops = &i82092aa_operations;
sockets[i].socket.resource_ops = &pccard_nonstatic_ops;
ret = pcmcia_register_socket(&sockets[i].socket);
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
index ea74f98a735..72ff2f615b3 100644
--- a/drivers/pcmcia/i82365.c
+++ b/drivers/pcmcia/i82365.c
@@ -1298,7 +1298,7 @@ static int __init init_i82365(void)
/* register sockets with the pcmcia core */
for (i = 0; i < sockets; i++) {
- socket[i].socket.dev.dev = &i82365_device->dev;
+ socket[i].socket.dev.parent = &i82365_device->dev;
socket[i].socket.ops = &pcic_operations;
socket[i].socket.resource_ops = &pccard_nonstatic_ops;
socket[i].socket.owner = THIS_MODULE;
diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c
index bbf025874d0..4dbef076237 100644
--- a/drivers/pcmcia/m32r_pcc.c
+++ b/drivers/pcmcia/m32r_pcc.c
@@ -722,7 +722,7 @@ static int __init init_m32r_pcc(void)
/* Set up interrupt handler(s) */
for (i = 0 ; i < pcc_sockets ; i++) {
- socket[i].socket.dev.dev = &pcc_device.dev;
+ socket[i].socket.dev.parent = &pcc_device.dev;
socket[i].socket.ops = &pcc_operations;
socket[i].socket.resource_ops = &pccard_static_ops;
socket[i].socket.owner = THIS_MODULE;
diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c
index 327372b7a54..88494149e91 100644
--- a/drivers/pcmcia/pcmcia_ioctl.c
+++ b/drivers/pcmcia/pcmcia_ioctl.c
@@ -59,7 +59,6 @@ typedef struct user_info_t {
#ifdef DEBUG
extern int ds_pc_debug;
-#define cs_socket_name(skt) ((skt)->dev.class_id)
#define ds_dbg(lvl, fmt, arg...) do { \
if (ds_pc_debug >= lvl) \
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c
index b9201c2ec38..0ce39de834c 100644
--- a/drivers/pcmcia/pcmcia_resource.c
+++ b/drivers/pcmcia/pcmcia_resource.c
@@ -48,7 +48,6 @@ static u8 pcmcia_used_irq[NR_IRQS];
#ifdef DEBUG
extern int ds_pc_debug;
-#define cs_socket_name(skt) ((skt)->dev.class_id)
#define ds_dbg(skt, lvl, fmt, arg...) do { \
if (ds_pc_debug >= lvl) \
diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c
index 360c2489654..dd0ddf19ee5 100644
--- a/drivers/pcmcia/pd6729.c
+++ b/drivers/pcmcia/pd6729.c
@@ -682,7 +682,7 @@ static int __devinit pd6729_pci_probe(struct pci_dev *dev,
socket[i].socket.ops = &pd6729_operations;
socket[i].socket.resource_ops = &pccard_nonstatic_ops;
- socket[i].socket.dev.dev = &dev->dev;
+ socket[i].socket.dev.parent = &dev->dev;
socket[i].socket.driver_data = &socket[i];
}
diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c
index c3176b16b7b..bfcaad6021c 100644
--- a/drivers/pcmcia/rsrc_nonstatic.c
+++ b/drivers/pcmcia/rsrc_nonstatic.c
@@ -616,7 +616,7 @@ static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_star
static struct resource *nonstatic_find_io_region(unsigned long base, int num,
unsigned long align, struct pcmcia_socket *s)
{
- struct resource *res = make_resource(0, num, IORESOURCE_IO, s->dev.class_id);
+ struct resource *res = make_resource(0, num, IORESOURCE_IO, s->dev.bus_id);
struct socket_data *s_data = s->resource_data;
struct pcmcia_align_data data;
unsigned long min = base;
@@ -650,7 +650,7 @@ static struct resource *nonstatic_find_io_region(unsigned long base, int num,
static struct resource * nonstatic_find_mem_region(u_long base, u_long num,
u_long align, int low, struct pcmcia_socket *s)
{
- struct resource *res = make_resource(0, num, IORESOURCE_MEM, s->dev.class_id);
+ struct resource *res = make_resource(0, num, IORESOURCE_MEM, s->dev.bus_id);
struct socket_data *s_data = s->resource_data;
struct pcmcia_align_data data;
unsigned long min, max;
@@ -897,9 +897,10 @@ EXPORT_SYMBOL(pccard_nonstatic_ops);
/* sysfs interface to the resource database */
-static ssize_t show_io_db(struct class_device *class_dev, char *buf)
+static ssize_t show_io_db(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct pcmcia_socket *s = class_get_devdata(class_dev);
+ struct pcmcia_socket *s = dev_get_drvdata(dev);
struct socket_data *data;
struct resource_map *p;
ssize_t ret = 0;
@@ -920,9 +921,11 @@ static ssize_t show_io_db(struct class_device *class_dev, char *buf)
return (ret);
}
-static ssize_t store_io_db(struct class_device *class_dev, const char *buf, size_t count)
+static ssize_t store_io_db(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
- struct pcmcia_socket *s = class_get_devdata(class_dev);
+ struct pcmcia_socket *s = dev_get_drvdata(dev);
unsigned long start_addr, end_addr;
unsigned int add = ADD_MANAGED_RESOURCE;
ssize_t ret = 0;
@@ -947,11 +950,12 @@ static ssize_t store_io_db(struct class_device *class_dev, const char *buf, size
return ret ? ret : count;
}
-static CLASS_DEVICE_ATTR(available_resources_io, 0600, show_io_db, store_io_db);
+static DEVICE_ATTR(available_resources_io, 0600, show_io_db, store_io_db);
-static ssize_t show_mem_db(struct class_device *class_dev, char *buf)
+static ssize_t show_mem_db(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct pcmcia_socket *s = class_get_devdata(class_dev);
+ struct pcmcia_socket *s = dev_get_drvdata(dev);
struct socket_data *data;
struct resource_map *p;
ssize_t ret = 0;
@@ -972,9 +976,11 @@ static ssize_t show_mem_db(struct class_device *class_dev, char *buf)
return (ret);
}
-static ssize_t store_mem_db(struct class_device *class_dev, const char *buf, size_t count)
+static ssize_t store_mem_db(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
- struct pcmcia_socket *s = class_get_devdata(class_dev);
+ struct pcmcia_socket *s = dev_get_drvdata(dev);
unsigned long start_addr, end_addr;
unsigned int add = ADD_MANAGED_RESOURCE;
ssize_t ret = 0;
@@ -999,25 +1005,25 @@ static ssize_t store_mem_db(struct class_device *class_dev, const char *buf, siz
return ret ? ret : count;
}
-static CLASS_DEVICE_ATTR(available_resources_mem, 0600, show_mem_db, store_mem_db);
+static DEVICE_ATTR(available_resources_mem, 0600, show_mem_db, store_mem_db);
-static struct class_device_attribute *pccard_rsrc_attributes[] = {
- &class_device_attr_available_resources_io,
- &class_device_attr_available_resources_mem,
+static struct device_attribute *pccard_rsrc_attributes[] = {
+ &dev_attr_available_resources_io,
+ &dev_attr_available_resources_mem,
NULL,
};
-static int __devinit pccard_sysfs_add_rsrc(struct class_device *class_dev,
+static int __devinit pccard_sysfs_add_rsrc(struct device *dev,
struct class_interface *class_intf)
{
- struct pcmcia_socket *s = class_get_devdata(class_dev);
- struct class_device_attribute **attr;
+ struct pcmcia_socket *s = dev_get_drvdata(dev);
+ struct device_attribute **attr;
int ret = 0;
if (s->resource_ops != &pccard_nonstatic_ops)
return 0;
for (attr = pccard_rsrc_attributes; *attr; attr++) {
- ret = class_device_create_file(class_dev, *attr);
+ ret = device_create_file(dev, *attr);
if (ret)
break;
}
@@ -1025,23 +1031,23 @@ static int __devinit pccard_sysfs_add_rsrc(struct class_device *class_dev,
return ret;
}
-static void __devexit pccard_sysfs_remove_rsrc(struct class_device *class_dev,
+static void __devexit pccard_sysfs_remove_rsrc(struct device *dev,
struct class_interface *class_intf)
{
- struct pcmcia_socket *s = class_get_devdata(class_dev);
- struct class_device_attribute **attr;
+ struct pcmcia_socket *s = dev_get_drvdata(dev);
+ struct device_attribute **attr;
if (s->resource_ops != &pccard_nonstatic_ops)
return;
for (attr = pccard_rsrc_attributes; *attr; attr++)
- class_device_remove_file(class_dev, *attr);
+ device_remove_file(dev, *attr);
}
static struct class_interface pccard_rsrc_interface = {
.class = &pcmcia_socket_class,
- .add = &pccard_sysfs_add_rsrc,
- .remove = __devexit_p(&pccard_sysfs_remove_rsrc),
+ .add_dev = &pccard_sysfs_add_rsrc,
+ .remove_dev = __devexit_p(&pccard_sysfs_remove_rsrc),
};
static int __init nonstatic_sysfs_init(void)
diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c
index e433704e026..d2a3bea55de 100644
--- a/drivers/pcmcia/soc_common.c
+++ b/drivers/pcmcia/soc_common.c
@@ -478,10 +478,10 @@ dump_bits(char **p, const char *prefix, unsigned int val, struct bittbl *bits, i
*
* Returns: the number of characters added to the buffer
*/
-static ssize_t show_status(struct class_device *class_dev, char *buf)
+static ssize_t show_status(struct device *dev, char *buf)
{
struct soc_pcmcia_socket *skt =
- container_of(class_dev, struct soc_pcmcia_socket, socket.dev);
+ container_of(dev, struct soc_pcmcia_socket, socket.dev);
char *p = buf;
p+=sprintf(p, "slot : %d\n", skt->nr);
@@ -747,7 +747,7 @@ int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops
add_timer(&skt->poll_timer);
- class_device_create_file(&skt->socket.dev, &class_device_attr_status);
+ device_create_file(&skt->socket.dev, &device_attr_status);
}
dev_set_drvdata(dev, sinfo);
diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c
index b005602d6b5..ea5765c3bdc 100644
--- a/drivers/pcmcia/socket_sysfs.c
+++ b/drivers/pcmcia/socket_sysfs.c
@@ -40,7 +40,8 @@
#define to_socket(_dev) container_of(_dev, struct pcmcia_socket, dev)
-static ssize_t pccard_show_type(struct class_device *dev, char *buf)
+static ssize_t pccard_show_type(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct pcmcia_socket *s = to_socket(dev);
@@ -50,9 +51,10 @@ static ssize_t pccard_show_type(struct class_device *dev, char *buf)
return sprintf(buf, "32-bit\n");
return sprintf(buf, "16-bit\n");
}
-static CLASS_DEVICE_ATTR(card_type, 0444, pccard_show_type, NULL);
+static DEVICE_ATTR(card_type, 0444, pccard_show_type, NULL);
-static ssize_t pccard_show_voltage(struct class_device *dev, char *buf)
+static ssize_t pccard_show_voltage(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct pcmcia_socket *s = to_socket(dev);
@@ -63,28 +65,31 @@ static ssize_t pccard_show_voltage(struct class_device *dev, char *buf)
s->socket.Vcc % 10);
return sprintf(buf, "X.XV\n");
}
-static CLASS_DEVICE_ATTR(card_voltage, 0444, pccard_show_voltage, NULL);
+static DEVICE_ATTR(card_voltage, 0444, pccard_show_voltage, NULL);
-static ssize_t pccard_show_vpp(struct class_device *dev, char *buf)
+static ssize_t pccard_show_vpp(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct pcmcia_socket *s = to_socket(dev);
if (!(s->state & SOCKET_PRESENT))
return -ENODEV;
return sprintf(buf, "%d.%dV\n", s->socket.Vpp / 10, s->socket.Vpp % 10);
}
-static CLASS_DEVICE_ATTR(card_vpp, 0444, pccard_show_vpp, NULL);
+static DEVICE_ATTR(card_vpp, 0444, pccard_show_vpp, NULL);
-static ssize_t pccard_show_vcc(struct class_device *dev, char *buf)
+static ssize_t pccard_show_vcc(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct pcmcia_socket *s = to_socket(dev);
if (!(s->state & SOCKET_PRESENT))
return -ENODEV;
return sprintf(buf, "%d.%dV\n", s->socket.Vcc / 10, s->socket.Vcc % 10);
}
-static CLASS_DEVICE_ATTR(card_vcc, 0444, pccard_show_vcc, NULL);
+static DEVICE_ATTR(card_vcc, 0444, pccard_show_vcc, NULL);
-static ssize_t pccard_store_insert(struct class_device *dev, const char *buf, size_t count)
+static ssize_t pccard_store_insert(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
ssize_t ret;
struct pcmcia_socket *s = to_socket(dev);
@@ -96,16 +101,20 @@ static ssize_t pccard_store_insert(struct class_device *dev, const char *buf, si
return ret ? ret : count;
}
-static CLASS_DEVICE_ATTR(card_insert, 0200, NULL, pccard_store_insert);
+static DEVICE_ATTR(card_insert, 0200, NULL, pccard_store_insert);
-static ssize_t pccard_show_card_pm_state(struct class_device *dev, char *buf)
+static ssize_t pccard_show_card_pm_state(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
struct pcmcia_socket *s = to_socket(dev);
return sprintf(buf, "%s\n", s->state & SOCKET_SUSPEND ? "off" : "on");
}
-static ssize_t pccard_store_card_pm_state(struct class_device *dev, const char *buf, size_t count)
+static ssize_t pccard_store_card_pm_state(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
ssize_t ret = -EINVAL;
struct pcmcia_socket *s = to_socket(dev);
@@ -120,9 +129,11 @@ static ssize_t pccard_store_card_pm_state(struct class_device *dev, const char *
return ret ? -ENODEV : count;
}
-static CLASS_DEVICE_ATTR(card_pm_state, 0644, pccard_show_card_pm_state, pccard_store_card_pm_state);
+static DEVICE_ATTR(card_pm_state, 0644, pccard_show_card_pm_state, pccard_store_card_pm_state);
-static ssize_t pccard_store_eject(struct class_device *dev, const char *buf, size_t count)
+static ssize_t pccard_store_eject(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
ssize_t ret;
struct pcmcia_socket *s = to_socket(dev);
@@ -134,16 +145,20 @@ static ssize_t pccard_store_eject(struct class_device *dev, const char *buf, siz
return ret ? ret : count;
}
-static CLASS_DEVICE_ATTR(card_eject, 0200, NULL, pccard_store_eject);
+static DEVICE_ATTR(card_eject, 0200, NULL, pccard_store_eject);
-static ssize_t pccard_show_irq_mask(struct class_device *dev, char *buf)
+static ssize_t pccard_show_irq_mask(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
struct pcmcia_socket *s = to_socket(dev);
return sprintf(buf, "0x%04x\n", s->irq_mask);
}
-static ssize_t pccard_store_irq_mask(struct class_device *dev, const char *buf, size_t count)
+static ssize_t pccard_store_irq_mask(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
ssize_t ret;
struct pcmcia_socket *s = to_socket(dev);
@@ -161,16 +176,19 @@ static ssize_t pccard_store_irq_mask(struct class_device *dev, const char *buf,
return ret ? ret : count;
}
-static CLASS_DEVICE_ATTR(card_irq_mask, 0600, pccard_show_irq_mask, pccard_store_irq_mask);
+static DEVICE_ATTR(card_irq_mask, 0600, pccard_show_irq_mask, pccard_store_irq_mask);
-static ssize_t pccard_show_resource(struct class_device *dev, char *buf)
+static ssize_t pccard_show_resource(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct pcmcia_socket *s = to_socket(dev);
return sprintf(buf, "%s\n", s->resource_setup_done ? "yes" : "no");
}
-static ssize_t pccard_store_resource(struct class_device *dev, const char *buf, size_t count)
+static ssize_t pccard_store_resource(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
unsigned long flags;
struct pcmcia_socket *s = to_socket(dev);
@@ -196,7 +214,7 @@ static ssize_t pccard_store_resource(struct class_device *dev, const char *buf,
return count;
}
-static CLASS_DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource);
+static DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource);
static ssize_t pccard_extract_cis(struct pcmcia_socket *s, char *buf, loff_t off, size_t count)
@@ -279,7 +297,7 @@ static ssize_t pccard_show_cis(struct kobject *kobj, char *buf, loff_t off, size
if (off + count > size)
count = size - off;
- s = to_socket(container_of(kobj, struct class_device, kobj));
+ s = to_socket(container_of(kobj, struct device, kobj));
if (!(s->state & SOCKET_PRESENT))
return -ENODEV;
@@ -296,7 +314,7 @@ static ssize_t pccard_show_cis(struct kobject *kobj, char *buf, loff_t off, size
static ssize_t pccard_store_cis(struct kobject *kobj, char *buf, loff_t off, size_t count)
{
- struct pcmcia_socket *s = to_socket(container_of(kobj, struct class_device, kobj));
+ struct pcmcia_socket *s = to_socket(container_of(kobj, struct device, kobj));
cisdump_t *cis;
int error;
@@ -335,16 +353,16 @@ static ssize_t pccard_store_cis(struct kobject *kobj, char *buf, loff_t off, siz
}
-static struct class_device_attribute *pccard_socket_attributes[] = {
- &class_device_attr_card_type,
- &class_device_attr_card_voltage,
- &class_device_attr_card_vpp,
- &class_device_attr_card_vcc,
- &class_device_attr_card_insert,
- &class_device_attr_card_pm_state,
- &class_device_attr_card_eject,
- &class_device_attr_card_irq_mask,
- &class_device_attr_available_resources_setup_done,
+static struct device_attribute *pccard_socket_attributes[] = {
+ &dev_attr_card_type,
+ &dev_attr_card_voltage,
+ &dev_attr_card_vpp,
+ &dev_attr_card_vcc,
+ &dev_attr_card_insert,
+ &dev_attr_card_pm_state,
+ &dev_attr_card_eject,
+ &dev_attr_card_irq_mask,
+ &dev_attr_available_resources_setup_done,
NULL,
};
@@ -355,35 +373,35 @@ static struct bin_attribute pccard_cis_attr = {
.write = pccard_store_cis,
};
-static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev,
+static int __devinit pccard_sysfs_add_socket(struct device *dev,
struct class_interface *class_intf)
{
- struct class_device_attribute **attr;
+ struct device_attribute **attr;
int ret = 0;
for (attr = pccard_socket_attributes; *attr; attr++) {
- ret = class_device_create_file(class_dev, *attr);
+ ret = device_create_file(dev, *attr);
if (ret)
break;
}
if (!ret)
- ret = sysfs_create_bin_file(&class_dev->kobj, &pccard_cis_attr);
+ ret = sysfs_create_bin_file(&dev->kobj, &pccard_cis_attr);
return ret;
}
-static void __devexit pccard_sysfs_remove_socket(struct class_device *class_dev,
+static void __devexit pccard_sysfs_remove_socket(struct device *dev,
struct class_interface *class_intf)
{
- struct class_device_attribute **attr;
+ struct device_attribute **attr;
- sysfs_remove_bin_file(&class_dev->kobj, &pccard_cis_attr);
+ sysfs_remove_bin_file(&dev->kobj, &pccard_cis_attr);
for (attr = pccard_socket_attributes; *attr; attr++)
- class_device_remove_file(class_dev, *attr);
+ device_remove_file(dev, *attr);
}
struct class_interface pccard_sysfs_interface = {
.class = &pcmcia_socket_class,
- .add = &pccard_sysfs_add_socket,
- .remove = __devexit_p(&pccard_sysfs_remove_socket),
+ .add_dev = &pccard_sysfs_add_socket,
+ .remove_dev = __devexit_p(&pccard_sysfs_remove_socket),
};
diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c
index 2d2f415f80a..c158cf38b9d 100644
--- a/drivers/pcmcia/tcic.c
+++ b/drivers/pcmcia/tcic.c
@@ -512,7 +512,7 @@ static int __init init_tcic(void)
for (i = 0; i < sockets; i++) {
socket_table[i].socket.ops = &tcic_operations;
socket_table[i].socket.resource_ops = &pccard_nonstatic_ops;
- socket_table[i].socket.dev.dev = &tcic_device.dev;
+ socket_table[i].socket.dev.parent = &tcic_device.dev;
ret = pcmcia_register_socket(&socket_table[i].socket);
if (ret && i)
pcmcia_unregister_socket(&socket_table[0].socket);
diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c
index da471bddc97..a61d768f6e0 100644
--- a/drivers/pcmcia/yenta_socket.c
+++ b/drivers/pcmcia/yenta_socket.c
@@ -1104,7 +1104,7 @@ static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_i
/* prepare pcmcia_socket */
socket->socket.ops = &yenta_socket_operations;
socket->socket.resource_ops = &pccard_nonstatic_ops;
- socket->socket.dev.dev = &dev->dev;
+ socket->socket.dev.parent = &dev->dev;
socket->socket.driver_data = socket;
socket->socket.owner = THIS_MODULE;
socket->socket.features = SS_CAP_PAGE_REGS | SS_CAP_PCCARD;
diff --git a/drivers/pnp/pnpacpi/Kconfig b/drivers/pnp/pnpacpi/Kconfig
index b1854171b96..ad27e5e0101 100644
--- a/drivers/pnp/pnpacpi/Kconfig
+++ b/drivers/pnp/pnpacpi/Kconfig
@@ -2,8 +2,8 @@
# Plug and Play ACPI configuration
#
config PNPACPI
- bool "Plug and Play ACPI support (EXPERIMENTAL)"
- depends on PNP && ACPI && EXPERIMENTAL
+ bool "Plug and Play ACPI support"
+ depends on PNP && ACPI
default y
---help---
Linux uses the PNPACPI to autodetect built-in
diff --git a/drivers/pnp/system.c b/drivers/pnp/system.c
index d42015c382a..2065e74bb63 100644
--- a/drivers/pnp/system.c
+++ b/drivers/pnp/system.c
@@ -3,7 +3,8 @@
*
* Some code is based on pnpbios_core.c
* Copyright 2002 Adam Belay <ambx1@neo.rr.com>
- *
+ * (c) Copyright 2007 Hewlett-Packard Development Company, L.P.
+ * Bjorn Helgaas <bjorn.helgaas@hp.com>
*/
#include <linux/pnp.h>
@@ -21,18 +22,21 @@ static const struct pnp_device_id pnp_dev_table[] = {
{ "", 0 }
};
-static void reserve_ioport_range(char *pnpid, int start, int end)
+static void reserve_range(char *pnpid, int start, int end, int port)
{
struct resource *res;
char *regionid;
regionid = kmalloc(16, GFP_KERNEL);
- if ( regionid == NULL )
+ if (regionid == NULL)
return;
snprintf(regionid, 16, "pnp %s", pnpid);
- res = request_region(start,end-start+1,regionid);
- if ( res == NULL )
- kfree( regionid );
+ if (port)
+ res = request_region(start,end-start+1,regionid);
+ else
+ res = request_mem_region(start,end-start+1,regionid);
+ if (res == NULL)
+ kfree(regionid);
else
res->flags &= ~IORESOURCE_BUSY;
/*
@@ -41,26 +45,20 @@ static void reserve_ioport_range(char *pnpid, int start, int end)
* have double reservations.
*/
printk(KERN_INFO
- "pnp: %s: ioport range 0x%x-0x%x %s reserved\n",
- pnpid, start, end,
- NULL != res ? "has been" : "could not be"
- );
-
- return;
+ "pnp: %s: %s range 0x%x-0x%x %s reserved\n",
+ pnpid, port ? "ioport" : "iomem", start, end,
+ NULL != res ? "has been" : "could not be");
}
-static void reserve_resources_of_dev( struct pnp_dev *dev )
+static void reserve_resources_of_dev(struct pnp_dev *dev)
{
int i;
- for (i=0;i<PNP_MAX_PORT;i++) {
+ for (i = 0; i < PNP_MAX_PORT; i++) {
if (!pnp_port_valid(dev, i))
- /* end of resources */
continue;
if (pnp_port_start(dev, i) == 0)
- /* disabled */
- /* Do nothing */
- continue;
+ continue; /* disabled */
if (pnp_port_start(dev, i) < 0x100)
/*
* Below 0x100 is only standard PC hardware
@@ -72,14 +70,18 @@ static void reserve_resources_of_dev( struct pnp_dev *dev )
*/
continue;
if (pnp_port_end(dev, i) < pnp_port_start(dev, i))
- /* invalid endpoint */
- /* Do nothing */
+ continue; /* invalid */
+
+ reserve_range(dev->dev.bus_id, pnp_port_start(dev, i),
+ pnp_port_end(dev, i), 1);
+ }
+
+ for (i = 0; i < PNP_MAX_MEM; i++) {
+ if (!pnp_mem_valid(dev, i))
continue;
- reserve_ioport_range(
- dev->dev.bus_id,
- pnp_port_start(dev, i),
- pnp_port_end(dev, i)
- );
+
+ reserve_range(dev->dev.bus_id, pnp_mem_start(dev, i),
+ pnp_mem_end(dev, i), 0);
}
return;
diff --git a/drivers/ps3/Makefile b/drivers/ps3/Makefile
index 8433eb7562c..d547cf50ca9 100644
--- a/drivers/ps3/Makefile
+++ b/drivers/ps3/Makefile
@@ -1,2 +1 @@
-obj-y += system-bus.o
obj-$(CONFIG_PS3_VUART) += vuart.o
diff --git a/drivers/ps3/system-bus.c b/drivers/ps3/system-bus.c
deleted file mode 100644
index d79f949bcb2..00000000000
--- a/drivers/ps3/system-bus.c
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * PS3 system bus driver.
- *
- * Copyright (C) 2006 Sony Computer Entertainment Inc.
- * Copyright 2006 Sony Corp.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/dma-mapping.h>
-#include <linux/err.h>
-
-#include <asm/udbg.h>
-#include <asm/ps3.h>
-#include <asm/lv1call.h>
-#include <asm/firmware.h>
-
-#define dump_mmio_region(_a) _dump_mmio_region(_a, __func__, __LINE__)
-static void _dump_mmio_region(const struct ps3_mmio_region* r,
- const char* func, int line)
-{
- pr_debug("%s:%d: dev %u:%u\n", func, line, r->did.bus_id,
- r->did.dev_id);
- pr_debug("%s:%d: bus_addr %lxh\n", func, line, r->bus_addr);
- pr_debug("%s:%d: len %lxh\n", func, line, r->len);
- pr_debug("%s:%d: lpar_addr %lxh\n", func, line, r->lpar_addr);
-}
-
-int ps3_mmio_region_create(struct ps3_mmio_region *r)
-{
- int result;
-
- result = lv1_map_device_mmio_region(r->did.bus_id, r->did.dev_id,
- r->bus_addr, r->len, r->page_size, &r->lpar_addr);
-
- if (result) {
- pr_debug("%s:%d: lv1_map_device_mmio_region failed: %s\n",
- __func__, __LINE__, ps3_result(result));
- r->lpar_addr = r->len = r->bus_addr = 0;
- }
-
- dump_mmio_region(r);
- return result;
-}
-
-int ps3_free_mmio_region(struct ps3_mmio_region *r)
-{
- int result;
-
- result = lv1_unmap_device_mmio_region(r->did.bus_id, r->did.dev_id,
- r->bus_addr);
-
- if (result)
- pr_debug("%s:%d: lv1_unmap_device_mmio_region failed: %s\n",
- __func__, __LINE__, ps3_result(result));
-
- r->lpar_addr = r->len = r->bus_addr = 0;
- return result;
-}
-
-static int ps3_system_bus_match(struct device *_dev,
- struct device_driver *_drv)
-{
- int result;
- struct ps3_system_bus_driver *drv = to_ps3_system_bus_driver(_drv);
- struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
-
- result = dev->match_id == drv->match_id;
-
- pr_info("%s:%d: dev=%u(%s), drv=%u(%s): %s\n", __func__, __LINE__,
- dev->match_id, dev->core.bus_id, drv->match_id, drv->core.name,
- (result ? "match" : "miss"));
- return result;
-}
-
-static int ps3_system_bus_probe(struct device *_dev)
-{
- int result;
- struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
- struct ps3_system_bus_driver *drv =
- to_ps3_system_bus_driver(_dev->driver);
-
- result = lv1_open_device(dev->did.bus_id, dev->did.dev_id, 0);
-
- if (result) {
- pr_debug("%s:%d: lv1_open_device failed (%d)\n",
- __func__, __LINE__, result);
- result = -EACCES;
- goto clean_none;
- }
-
- if (dev->d_region->did.bus_id) {
- result = ps3_dma_region_create(dev->d_region);
-
- if (result) {
- pr_debug("%s:%d: ps3_dma_region_create failed (%d)\n",
- __func__, __LINE__, result);
- BUG_ON("check region type");
- result = -EINVAL;
- goto clean_device;
- }
- }
-
- BUG_ON(!drv);
-
- if (drv->probe)
- result = drv->probe(dev);
- else
- pr_info("%s:%d: %s no probe method\n", __func__, __LINE__,
- dev->core.bus_id);
-
- if (result) {
- pr_debug("%s:%d: drv->probe failed\n", __func__, __LINE__);
- goto clean_dma;
- }
-
- return result;
-
-clean_dma:
- ps3_dma_region_free(dev->d_region);
-clean_device:
- lv1_close_device(dev->did.bus_id, dev->did.dev_id);
-clean_none:
- return result;
-}
-
-static int ps3_system_bus_remove(struct device *_dev)
-{
- struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
- struct ps3_system_bus_driver *drv =
- to_ps3_system_bus_driver(_dev->driver);
-
- if (drv->remove)
- drv->remove(dev);
- else
- pr_info("%s:%d: %s no remove method\n", __func__, __LINE__,
- dev->core.bus_id);
-
- ps3_dma_region_free(dev->d_region);
- ps3_free_mmio_region(dev->m_region);
- lv1_close_device(dev->did.bus_id, dev->did.dev_id);
-
- return 0;
-}
-
-struct bus_type ps3_system_bus_type = {
- .name = "ps3_system_bus",
- .match = ps3_system_bus_match,
- .probe = ps3_system_bus_probe,
- .remove = ps3_system_bus_remove,
-};
-
-int __init ps3_system_bus_init(void)
-{
- int result;
-
- if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
- return 0;
-
- result = bus_register(&ps3_system_bus_type);
- BUG_ON(result);
- return result;
-}
-
-core_initcall(ps3_system_bus_init);
-
-/* Allocates a contiguous real buffer and creates mappings over it.
- * Returns the virtual address of the buffer and sets dma_handle
- * to the dma address (mapping) of the first page.
- */
-
-static void * ps3_alloc_coherent(struct device *_dev, size_t size,
- dma_addr_t *dma_handle, gfp_t flag)
-{
- int result;
- struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
- unsigned long virt_addr;
-
- BUG_ON(!dev->d_region->bus_addr);
-
- flag &= ~(__GFP_DMA | __GFP_HIGHMEM);
- flag |= __GFP_ZERO;
-
- virt_addr = __get_free_pages(flag, get_order(size));
-
- if (!virt_addr) {
- pr_debug("%s:%d: get_free_pages failed\n", __func__, __LINE__);
- goto clean_none;
- }
-
- result = ps3_dma_map(dev->d_region, virt_addr, size, dma_handle);
-
- if (result) {
- pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
- __func__, __LINE__, result);
- BUG_ON("check region type");
- goto clean_alloc;
- }
-
- return (void*)virt_addr;
-
-clean_alloc:
- free_pages(virt_addr, get_order(size));
-clean_none:
- dma_handle = NULL;
- return NULL;
-}
-
-static void ps3_free_coherent(struct device *_dev, size_t size, void *vaddr,
- dma_addr_t dma_handle)
-{
- struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
-
- ps3_dma_unmap(dev->d_region, dma_handle, size);
- free_pages((unsigned long)vaddr, get_order(size));
-}
-
-/* Creates TCEs for a user provided buffer. The user buffer must be
- * contiguous real kernel storage (not vmalloc). The address of the buffer
- * passed here is the kernel (virtual) address of the buffer. The buffer
- * need not be page aligned, the dma_addr_t returned will point to the same
- * byte within the page as vaddr.
- */
-
-static dma_addr_t ps3_map_single(struct device *_dev, void *ptr, size_t size,
- enum dma_data_direction direction)
-{
- struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
- int result;
- unsigned long bus_addr;
-
- result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size,
- &bus_addr);
-
- if (result) {
- pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
- __func__, __LINE__, result);
- }
-
- return bus_addr;
-}
-
-static void ps3_unmap_single(struct device *_dev, dma_addr_t dma_addr,
- size_t size, enum dma_data_direction direction)
-{
- struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
- int result;
-
- result = ps3_dma_unmap(dev->d_region, dma_addr, size);
-
- if (result) {
- pr_debug("%s:%d: ps3_dma_unmap failed (%d)\n",
- __func__, __LINE__, result);
- }
-}
-
-static int ps3_map_sg(struct device *_dev, struct scatterlist *sg, int nents,
- enum dma_data_direction direction)
-{
-#if defined(CONFIG_PS3_DYNAMIC_DMA)
- BUG_ON("do");
-#endif
- return 0;
-}
-
-static void ps3_unmap_sg(struct device *_dev, struct scatterlist *sg,
- int nents, enum dma_data_direction direction)
-{
-#if defined(CONFIG_PS3_DYNAMIC_DMA)
- BUG_ON("do");
-#endif
-}
-
-static int ps3_dma_supported(struct device *_dev, u64 mask)
-{
- return 1;
-}
-
-static struct dma_mapping_ops ps3_dma_ops = {
- .alloc_coherent = ps3_alloc_coherent,
- .free_coherent = ps3_free_coherent,
- .map_single = ps3_map_single,
- .unmap_single = ps3_unmap_single,
- .map_sg = ps3_map_sg,
- .unmap_sg = ps3_unmap_sg,
- .dma_supported = ps3_dma_supported
-};
-
-/**
- * ps3_system_bus_release_device - remove a device from the system bus
- */
-
-static void ps3_system_bus_release_device(struct device *_dev)
-{
- struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
- kfree(dev);
-}
-
-/**
- * ps3_system_bus_device_register - add a device to the system bus
- *
- * ps3_system_bus_device_register() expects the dev object to be allocated
- * dynamically by the caller. The system bus takes ownership of the dev
- * object and frees the object in ps3_system_bus_release_device().
- */
-
-int ps3_system_bus_device_register(struct ps3_system_bus_device *dev)
-{
- int result;
- static unsigned int dev_count = 1;
-
- dev->core.parent = NULL;
- dev->core.bus = &ps3_system_bus_type;
- dev->core.release = ps3_system_bus_release_device;
-
- dev->core.archdata.of_node = NULL;
- dev->core.archdata.dma_ops = &ps3_dma_ops;
- dev->core.archdata.numa_node = 0;
-
- snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), "sb_%02x",
- dev_count++);
-
- pr_debug("%s:%d add %s\n", __func__, __LINE__, dev->core.bus_id);
-
- result = device_register(&dev->core);
- return result;
-}
-
-EXPORT_SYMBOL_GPL(ps3_system_bus_device_register);
-
-int ps3_system_bus_driver_register(struct ps3_system_bus_driver *drv)
-{
- int result;
-
- drv->core.bus = &ps3_system_bus_type;
-
- result = driver_register(&drv->core);
- return result;
-}
-
-EXPORT_SYMBOL_GPL(ps3_system_bus_driver_register);
-
-void ps3_system_bus_driver_unregister(struct ps3_system_bus_driver *drv)
-{
- driver_unregister(&drv->core);
-}
-
-EXPORT_SYMBOL_GPL(ps3_system_bus_driver_unregister);
diff --git a/drivers/ps3/vuart.c b/drivers/ps3/vuart.c
index 6974f65bcda..a72da8f651f 100644
--- a/drivers/ps3/vuart.c
+++ b/drivers/ps3/vuart.c
@@ -783,8 +783,8 @@ static int ps3_vuart_probe(struct device *_dev)
vuart_private.in_use++;
if (vuart_private.in_use == 1) {
- result = ps3_alloc_vuart_irq((void*)&vuart_private.bmp.status,
- &vuart_private.virq);
+ result = ps3_alloc_vuart_irq(PS3_BINDING_CPU_ANY,
+ (void*)&vuart_private.bmp.status, &vuart_private.virq);
if (result) {
dev_dbg(&dev->core,
diff --git a/drivers/ps3/vuart.h b/drivers/ps3/vuart.h
index 28fd89f0c8a..11c421cf7a0 100644
--- a/drivers/ps3/vuart.h
+++ b/drivers/ps3/vuart.h
@@ -21,37 +21,6 @@
#if !defined(_PS3_VUART_H)
#define _PS3_VUART_H
-struct ps3_vuart_stats {
- unsigned long bytes_written;
- unsigned long bytes_read;
- unsigned long tx_interrupts;
- unsigned long rx_interrupts;
- unsigned long disconnect_interrupts;
-};
-
-/**
- * struct ps3_vuart_port_device - a device on a vuart port
- */
-
-struct ps3_vuart_port_device {
- enum ps3_match_id match_id;
- struct device core;
-
- /* private driver variables */
- unsigned int port_number;
- unsigned long interrupt_mask;
- struct {
- spinlock_t lock;
- struct list_head head;
- } tx_list;
- struct {
- unsigned long bytes_held;
- spinlock_t lock;
- struct list_head head;
- } rx_list;
- struct ps3_vuart_stats stats;
-};
-
/**
* struct ps3_vuart_port_driver - a driver for a device on a vuart port
*/
@@ -68,9 +37,9 @@ struct ps3_vuart_port_driver {
/* int (*resume)(struct ps3_vuart_port_device *); */
};
-int ps3_vuart_port_device_register(struct ps3_vuart_port_device *dev);
int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv);
void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv);
+
int ps3_vuart_write(struct ps3_vuart_port_device *dev,
const void* buf, unsigned int bytes);
int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf,
@@ -86,9 +55,4 @@ static inline struct ps3_vuart_port_device *to_ps3_vuart_port_device(
return container_of(_dev, struct ps3_vuart_port_device, core);
}
-int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf,
- unsigned int bytes);
-int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf,
- unsigned int bytes);
-
#endif
diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c
index 94d3df62a5f..82f2ac87ccd 100644
--- a/drivers/rtc/rtc-dev.c
+++ b/drivers/rtc/rtc-dev.c
@@ -305,7 +305,7 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
case RTC_IRQP_READ:
if (ops->irq_set_freq)
- err = put_user(rtc->irq_freq, (unsigned long *) arg);
+ err = put_user(rtc->irq_freq, (unsigned long __user *)uarg);
break;
case RTC_IRQP_SET:
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
index 4b72b8ef5d6..038118bbfae 100644
--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -53,6 +53,25 @@ I2C_CLIENT_INSMOD;
#define PCF8563_SC_LV 0x80 /* low voltage */
#define PCF8563_MO_C 0x80 /* century */
+struct pcf8563 {
+ struct i2c_client client;
+ /*
+ * The meaning of MO_C bit varies by the chip type.
+ * From PCF8563 datasheet: this bit is toggled when the years
+ * register overflows from 99 to 00
+ * 0 indicates the century is 20xx
+ * 1 indicates the century is 19xx
+ * From RTC8564 datasheet: this bit indicates change of
+ * century. When the year digit data overflows from 99 to 00,
+ * this bit is set. By presetting it to 0 while still in the
+ * 20th century, it will be set in year 2000, ...
+ * There seems no reliable way to know how the system use this
+ * bit. So let's do it heuristically, assuming we are live in
+ * 1970...2069.
+ */
+ int c_polarity; /* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */
+};
+
static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind);
static int pcf8563_detach(struct i2c_client *client);
@@ -62,6 +81,7 @@ static int pcf8563_detach(struct i2c_client *client);
*/
static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)
{
+ struct pcf8563 *pcf8563 = container_of(client, struct pcf8563, client);
unsigned char buf[13] = { PCF8563_REG_ST1 };
struct i2c_msg msgs[] = {
@@ -94,8 +114,12 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)
tm->tm_mday = BCD2BIN(buf[PCF8563_REG_DM] & 0x3F);
tm->tm_wday = buf[PCF8563_REG_DW] & 0x07;
tm->tm_mon = BCD2BIN(buf[PCF8563_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */
- tm->tm_year = BCD2BIN(buf[PCF8563_REG_YR])
- + (buf[PCF8563_REG_MO] & PCF8563_MO_C ? 0 : 100);
+ tm->tm_year = BCD2BIN(buf[PCF8563_REG_YR]);
+ if (tm->tm_year < 70)
+ tm->tm_year += 100; /* assume we are in 1970...2069 */
+ /* detect the polarity heuristically. see note above. */
+ pcf8563->c_polarity = (buf[PCF8563_REG_MO] & PCF8563_MO_C) ?
+ (tm->tm_year >= 100) : (tm->tm_year < 100);
dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
"mday=%d, mon=%d, year=%d, wday=%d\n",
@@ -114,6 +138,7 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)
static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm)
{
+ struct pcf8563 *pcf8563 = container_of(client, struct pcf8563, client);
int i, err;
unsigned char buf[9];
@@ -135,7 +160,7 @@ static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm)
/* year and century */
buf[PCF8563_REG_YR] = BIN2BCD(tm->tm_year % 100);
- if (tm->tm_year < 100)
+ if (pcf8563->c_polarity ? (tm->tm_year >= 100) : (tm->tm_year < 100))
buf[PCF8563_REG_MO] |= PCF8563_MO_C;
buf[PCF8563_REG_DW] = tm->tm_wday & 0x07;
@@ -248,6 +273,7 @@ static struct i2c_driver pcf8563_driver = {
static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind)
{
+ struct pcf8563 *pcf8563;
struct i2c_client *client;
struct rtc_device *rtc;
@@ -260,11 +286,12 @@ static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind)
goto exit;
}
- if (!(client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
+ if (!(pcf8563 = kzalloc(sizeof(struct pcf8563), GFP_KERNEL))) {
err = -ENOMEM;
goto exit;
}
+ client = &pcf8563->client;
client->addr = address;
client->driver = &pcf8563_driver;
client->adapter = adapter;
@@ -301,7 +328,7 @@ exit_detach:
i2c_detach_client(client);
exit_kfree:
- kfree(client);
+ kfree(pcf8563);
exit:
return err;
@@ -309,6 +336,7 @@ exit:
static int pcf8563_detach(struct i2c_client *client)
{
+ struct pcf8563 *pcf8563 = container_of(client, struct pcf8563, client);
int err;
struct rtc_device *rtc = i2c_get_clientdata(client);
@@ -318,7 +346,7 @@ static int pcf8563_detach(struct i2c_client *client)
if ((err = i2c_detach_client(client)))
return err;
- kfree(client);
+ kfree(pcf8563);
return 0;
}
diff --git a/drivers/s390/Kconfig b/drivers/s390/Kconfig
index ae89b9b8874..165af398fde 100644
--- a/drivers/s390/Kconfig
+++ b/drivers/s390/Kconfig
@@ -103,14 +103,8 @@ config CCW_CONSOLE
depends on TN3215_CONSOLE || TN3270_CONSOLE
default y
-config SCLP
- bool "Support for SCLP"
- help
- Include support for the SCLP interface to the service element.
-
config SCLP_TTY
bool "Support for SCLP line mode terminal"
- depends on SCLP
help
Include support for IBM SCLP line-mode terminals.
@@ -123,7 +117,6 @@ config SCLP_CONSOLE
config SCLP_VT220_TTY
bool "Support for SCLP VT220-compatible terminal"
- depends on SCLP
help
Include support for an IBM SCLP VT220-compatible terminal.
@@ -136,7 +129,6 @@ config SCLP_VT220_CONSOLE
config SCLP_CPI
tristate "Control-Program Identification"
- depends on SCLP
help
This option enables the hardware console interface for system
identification. This is commonly used for workload management and
diff --git a/drivers/s390/Makefile b/drivers/s390/Makefile
index 9803c9352d7..5a888704a8d 100644
--- a/drivers/s390/Makefile
+++ b/drivers/s390/Makefile
@@ -2,6 +2,8 @@
# Makefile for the S/390 specific device drivers
#
+CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w
+
obj-y += s390mach.o sysinfo.o s390_rdev.o
obj-y += cio/ block/ char/ crypto/ net/ scsi/
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 492b68bcd7c..eb5dc62f0d9 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -37,6 +37,7 @@
*/
debug_info_t *dasd_debug_area;
struct dasd_discipline *dasd_diag_discipline_pointer;
+void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *);
MODULE_AUTHOR("Holger Smolinski <Holger.Smolinski@de.ibm.com>");
MODULE_DESCRIPTION("Linux on S/390 DASD device driver,"
@@ -51,7 +52,6 @@ static int dasd_alloc_queue(struct dasd_device * device);
static void dasd_setup_queue(struct dasd_device * device);
static void dasd_free_queue(struct dasd_device * device);
static void dasd_flush_request_queue(struct dasd_device *);
-static void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *);
static int dasd_flush_ccw_queue(struct dasd_device *, int);
static void dasd_tasklet(struct dasd_device *);
static void do_kick_device(struct work_struct *);
@@ -483,7 +483,7 @@ unsigned int dasd_profile_level = DASD_PROFILE_OFF;
/*
* Add profiling information for cqr before execution.
*/
-static inline void
+static void
dasd_profile_start(struct dasd_device *device, struct dasd_ccw_req * cqr,
struct request *req)
{
@@ -505,7 +505,7 @@ dasd_profile_start(struct dasd_device *device, struct dasd_ccw_req * cqr,
/*
* Add profiling information for cqr after execution.
*/
-static inline void
+static void
dasd_profile_end(struct dasd_device *device, struct dasd_ccw_req * cqr,
struct request *req)
{
@@ -1022,8 +1022,6 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
irb->scsw.cstat == 0 &&
!irb->esw.esw0.erw.cons)
era = dasd_era_none;
- else if (!test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags))
- era = dasd_era_fatal; /* don't recover this request */
else if (irb->esw.esw0.erw.cons)
era = device->discipline->examine_error(cqr, irb);
else
@@ -1104,7 +1102,7 @@ __dasd_process_erp(struct dasd_device *device, struct dasd_ccw_req *cqr)
/*
* Process ccw request queue.
*/
-static inline void
+static void
__dasd_process_ccw_queue(struct dasd_device * device,
struct list_head *final_queue)
{
@@ -1127,7 +1125,9 @@ restart:
cqr->status = DASD_CQR_FAILED;
cqr->stopclk = get_clock();
} else {
- if (cqr->irb.esw.esw0.erw.cons) {
+ if (cqr->irb.esw.esw0.erw.cons &&
+ test_bit(DASD_CQR_FLAGS_USE_ERP,
+ &cqr->flags)) {
erp_fn = device->discipline->
erp_action(cqr);
erp_fn(cqr);
@@ -1181,7 +1181,7 @@ dasd_end_request_cb(struct dasd_ccw_req * cqr, void *data)
/*
* Fetch requests from the block device queue.
*/
-static inline void
+static void
__dasd_process_blk_queue(struct dasd_device * device)
{
request_queue_t *queue;
@@ -1232,6 +1232,19 @@ __dasd_process_blk_queue(struct dasd_device * device)
if (IS_ERR(cqr)) {
if (PTR_ERR(cqr) == -ENOMEM)
break; /* terminate request queue loop */
+ if (PTR_ERR(cqr) == -EAGAIN) {
+ /*
+ * The current request cannot be build right
+ * now, we have to try later. If this request
+ * is the head-of-queue we stop the device
+ * for 1/2 second.
+ */
+ if (!list_empty(&device->ccw_queue))
+ break;
+ device->stopped |= DASD_STOPPED_PENDING;
+ dasd_set_timer(device, HZ/2);
+ break;
+ }
DBF_DEV_EVENT(DBF_ERR, device,
"CCW creation failed (rc=%ld) "
"on request %p",
@@ -1254,7 +1267,7 @@ __dasd_process_blk_queue(struct dasd_device * device)
* Take a look at the first request on the ccw queue and check
* if it reached its expire time. If so, terminate the IO.
*/
-static inline void
+static void
__dasd_check_expire(struct dasd_device * device)
{
struct dasd_ccw_req *cqr;
@@ -1285,7 +1298,7 @@ __dasd_check_expire(struct dasd_device * device)
* Take a look at the first request on the ccw queue and check
* if it needs to be started.
*/
-static inline void
+static void
__dasd_start_head(struct dasd_device * device)
{
struct dasd_ccw_req *cqr;
diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c
index 4d01040c2c6..8b9d68f6e01 100644
--- a/drivers/s390/block/dasd_3990_erp.c
+++ b/drivers/s390/block/dasd_3990_erp.c
@@ -170,7 +170,6 @@ dasd_3990_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
/* log the erp chain if fatal error occurred */
if ((era == dasd_era_fatal) && (device->state >= DASD_STATE_READY)) {
dasd_log_sense(cqr, irb);
- dasd_log_ccw(cqr, 0, irb->scsw.cpa);
}
return era;
@@ -2640,7 +2639,6 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr)
struct dasd_ccw_req *erp = NULL;
struct dasd_device *device = cqr->device;
- __u32 cpa = cqr->irb.scsw.cpa;
struct dasd_ccw_req *temp_erp = NULL;
if (device->features & DASD_FEATURE_ERPLOG) {
@@ -2706,9 +2704,6 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr)
}
}
- if (erp->status == DASD_CQR_FAILED)
- dasd_log_ccw(erp, 1, cpa);
-
/* enqueue added ERP request */
if (erp->status == DASD_CQR_FILLED) {
erp->status = DASD_CQR_QUEUED;
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index 5943266152f..ed70852cc91 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -136,7 +136,7 @@ __setup ("dasd=", dasd_call_setup);
/*
* Read a device busid/devno from a string.
*/
-static inline int
+static int
dasd_busid(char **str, int *id0, int *id1, int *devno)
{
int val, old_style;
@@ -182,7 +182,7 @@ dasd_busid(char **str, int *id0, int *id1, int *devno)
* only one: "ro" for read-only devices. The default feature set
* is empty (value 0).
*/
-static inline int
+static int
dasd_feature_list(char *str, char **endp)
{
int features, len, rc;
@@ -341,7 +341,7 @@ dasd_parse_range( char *parsestring ) {
return ERR_PTR(-EINVAL);
}
-static inline char *
+static char *
dasd_parse_next_element( char *parsestring ) {
char * residual_str;
residual_str = dasd_parse_keyword(parsestring);
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
index 53db58a6861..ab782bb46ac 100644
--- a/drivers/s390/block/dasd_diag.c
+++ b/drivers/s390/block/dasd_diag.c
@@ -43,7 +43,7 @@ MODULE_LICENSE("GPL");
#define DIAG_MAX_RETRIES 32
#define DIAG_TIMEOUT 50 * HZ
-struct dasd_discipline dasd_diag_discipline;
+static struct dasd_discipline dasd_diag_discipline;
struct dasd_diag_private {
struct dasd_diag_characteristics rdc_data;
@@ -90,7 +90,7 @@ static inline int dia250(void *iob, int cmd)
* block offset. On success, return zero and set end_block to contain the
* number of blocks on the device minus the specified offset. Return non-zero
* otherwise. */
-static __inline__ int
+static inline int
mdsk_init_io(struct dasd_device *device, unsigned int blocksize,
blocknum_t offset, blocknum_t *end_block)
{
@@ -117,7 +117,7 @@ mdsk_init_io(struct dasd_device *device, unsigned int blocksize,
/* Remove block I/O environment for device. Return zero on success, non-zero
* otherwise. */
-static __inline__ int
+static inline int
mdsk_term_io(struct dasd_device * device)
{
struct dasd_diag_private *private;
@@ -576,7 +576,7 @@ dasd_diag_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
"dump sense not available for DIAG data");
}
-struct dasd_discipline dasd_diag_discipline = {
+static struct dasd_discipline dasd_diag_discipline = {
.owner = THIS_MODULE,
.name = "DIAG",
.ebcname = "DIAG",
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index fdaa471e845..cecab2274a6 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -134,44 +134,7 @@ ceil_quot(unsigned int d1, unsigned int d2)
return (d1 + (d2 - 1)) / d2;
}
-static inline int
-bytes_per_record(struct dasd_eckd_characteristics *rdc, int kl, int dl)
-{
- unsigned int fl1, fl2, int1, int2;
- int bpr;
-
- switch (rdc->formula) {
- case 0x01:
- fl1 = round_up_multiple(ECKD_F2(rdc) + dl, ECKD_F1(rdc));
- fl2 = round_up_multiple(kl ? ECKD_F2(rdc) + kl : 0,
- ECKD_F1(rdc));
- bpr = fl1 + fl2;
- break;
- case 0x02:
- int1 = ceil_quot(dl + ECKD_F6(rdc), ECKD_F5(rdc) << 1);
- int2 = ceil_quot(kl + ECKD_F6(rdc), ECKD_F5(rdc) << 1);
- fl1 = round_up_multiple(ECKD_F1(rdc) * ECKD_F2(rdc) + dl +
- ECKD_F6(rdc) + ECKD_F4(rdc) * int1,
- ECKD_F1(rdc));
- fl2 = round_up_multiple(ECKD_F1(rdc) * ECKD_F3(rdc) + kl +
- ECKD_F6(rdc) + ECKD_F4(rdc) * int2,
- ECKD_F1(rdc));
- bpr = fl1 + fl2;
- break;
- default:
- bpr = 0;
- break;
- }
- return bpr;
-}
-
-static inline unsigned int
-bytes_per_track(struct dasd_eckd_characteristics *rdc)
-{
- return *(unsigned int *) (rdc->byte_per_track) >> 8;
-}
-
-static inline unsigned int
+static unsigned int
recs_per_track(struct dasd_eckd_characteristics * rdc,
unsigned int kl, unsigned int dl)
{
@@ -204,37 +167,39 @@ recs_per_track(struct dasd_eckd_characteristics * rdc,
return 0;
}
-static inline void
+static int
check_XRC (struct ccw1 *de_ccw,
struct DE_eckd_data *data,
struct dasd_device *device)
{
struct dasd_eckd_private *private;
+ int rc;
private = (struct dasd_eckd_private *) device->private;
+ if (!private->rdc_data.facilities.XRC_supported)
+ return 0;
/* switch on System Time Stamp - needed for XRC Support */
- if (private->rdc_data.facilities.XRC_supported) {
-
- data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid' */
- data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */
-
- data->ep_sys_time = get_clock ();
-
- de_ccw->count = sizeof (struct DE_eckd_data);
- de_ccw->flags |= CCW_FLAG_SLI;
- }
+ data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid' */
+ data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */
- return;
+ rc = get_sync_clock(&data->ep_sys_time);
+ /* Ignore return code if sync clock is switched off. */
+ if (rc == -ENOSYS || rc == -EACCES)
+ rc = 0;
-} /* end check_XRC */
+ de_ccw->count = sizeof (struct DE_eckd_data);
+ de_ccw->flags |= CCW_FLAG_SLI;
+ return rc;
+}
-static inline void
+static int
define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
int totrk, int cmd, struct dasd_device * device)
{
struct dasd_eckd_private *private;
struct ch_t geo, beg, end;
+ int rc = 0;
private = (struct dasd_eckd_private *) device->private;
@@ -263,12 +228,12 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
case DASD_ECKD_CCW_WRITE_KD_MT:
data->mask.perm = 0x02;
data->attributes.operation = private->attrib.operation;
- check_XRC (ccw, data, device);
+ rc = check_XRC (ccw, data, device);
break;
case DASD_ECKD_CCW_WRITE_CKD:
case DASD_ECKD_CCW_WRITE_CKD_MT:
data->attributes.operation = DASD_BYPASS_CACHE;
- check_XRC (ccw, data, device);
+ rc = check_XRC (ccw, data, device);
break;
case DASD_ECKD_CCW_ERASE:
case DASD_ECKD_CCW_WRITE_HOME_ADDRESS:
@@ -276,7 +241,7 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
data->mask.perm = 0x3;
data->mask.auth = 0x1;
data->attributes.operation = DASD_BYPASS_CACHE;
- check_XRC (ccw, data, device);
+ rc = check_XRC (ccw, data, device);
break;
default:
DEV_MESSAGE(KERN_ERR, device, "unknown opcode 0x%x", cmd);
@@ -312,9 +277,10 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
data->beg_ext.head = beg.head;
data->end_ext.cyl = end.cyl;
data->end_ext.head = end.head;
+ return rc;
}
-static inline void
+static void
locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk,
int rec_on_trk, int no_rec, int cmd,
struct dasd_device * device, int reclen)
@@ -548,7 +514,7 @@ dasd_eckd_read_conf(struct dasd_device *device)
/*
* Build CP for Perform Subsystem Function - SSC.
*/
-struct dasd_ccw_req *
+static struct dasd_ccw_req *
dasd_eckd_build_psf_ssc(struct dasd_device *device)
{
struct dasd_ccw_req *cqr;
@@ -1200,7 +1166,12 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
return cqr;
ccw = cqr->cpaddr;
/* First ccw is define extent. */
- define_extent(ccw++, cqr->data, first_trk, last_trk, cmd, device);
+ if (define_extent(ccw++, cqr->data, first_trk,
+ last_trk, cmd, device) == -EAGAIN) {
+ /* Clock not in sync and XRC is enabled. Try again later. */
+ dasd_sfree_request(cqr, device);
+ return ERR_PTR(-EAGAIN);
+ }
/* Build locate_record+read/write/ccws. */
idaws = (unsigned long *) (cqr->data + sizeof(struct DE_eckd_data));
LO_data = (struct LO_eckd_data *) (idaws + cidaw);
@@ -1380,7 +1351,7 @@ dasd_eckd_release(struct dasd_device *device)
cqr->device = device;
clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
- cqr->retries = 0;
+ cqr->retries = 2; /* set retry counter to enable basic ERP */
cqr->expires = 2 * HZ;
cqr->buildclk = get_clock();
cqr->status = DASD_CQR_FILLED;
@@ -1420,7 +1391,7 @@ dasd_eckd_reserve(struct dasd_device *device)
cqr->device = device;
clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
- cqr->retries = 0;
+ cqr->retries = 2; /* set retry counter to enable basic ERP */
cqr->expires = 2 * HZ;
cqr->buildclk = get_clock();
cqr->status = DASD_CQR_FILLED;
@@ -1459,7 +1430,7 @@ dasd_eckd_steal_lock(struct dasd_device *device)
cqr->device = device;
clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
- cqr->retries = 0;
+ cqr->retries = 2; /* set retry counter to enable basic ERP */
cqr->expires = 2 * HZ;
cqr->buildclk = get_clock();
cqr->status = DASD_CQR_FILLED;
@@ -1609,7 +1580,7 @@ dasd_eckd_ioctl(struct dasd_device *device, unsigned int cmd, void __user *argp)
* Dump the range of CCWs into 'page' buffer
* and return number of printed chars.
*/
-static inline int
+static int
dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page)
{
int len, count;
diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c
index e0bf30ebb21..6cedc914077 100644
--- a/drivers/s390/block/dasd_eer.c
+++ b/drivers/s390/block/dasd_eer.c
@@ -658,18 +658,24 @@ static struct file_operations dasd_eer_fops = {
.owner = THIS_MODULE,
};
-static struct miscdevice dasd_eer_dev = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = "dasd_eer",
- .fops = &dasd_eer_fops,
-};
+static struct miscdevice *dasd_eer_dev = NULL;
int __init dasd_eer_init(void)
{
int rc;
- rc = misc_register(&dasd_eer_dev);
+ dasd_eer_dev = kzalloc(sizeof(*dasd_eer_dev), GFP_KERNEL);
+ if (!dasd_eer_dev)
+ return -ENOMEM;
+
+ dasd_eer_dev->minor = MISC_DYNAMIC_MINOR;
+ dasd_eer_dev->name = "dasd_eer";
+ dasd_eer_dev->fops = &dasd_eer_fops;
+
+ rc = misc_register(dasd_eer_dev);
if (rc) {
+ kfree(dasd_eer_dev);
+ dasd_eer_dev = NULL;
MESSAGE(KERN_ERR, "%s", "dasd_eer_init could not "
"register misc device");
return rc;
@@ -680,5 +686,9 @@ int __init dasd_eer_init(void)
void dasd_eer_exit(void)
{
- WARN_ON(misc_deregister(&dasd_eer_dev) != 0);
+ if (dasd_eer_dev) {
+ WARN_ON(misc_deregister(dasd_eer_dev) != 0);
+ kfree(dasd_eer_dev);
+ dasd_eer_dev = NULL;
+ }
}
diff --git a/drivers/s390/block/dasd_erp.c b/drivers/s390/block/dasd_erp.c
index 58a65097922..caa5d91420f 100644
--- a/drivers/s390/block/dasd_erp.c
+++ b/drivers/s390/block/dasd_erp.c
@@ -152,25 +152,6 @@ dasd_default_erp_postaction(struct dasd_ccw_req * cqr)
} /* end default_erp_postaction */
-/*
- * Print the hex dump of the memory used by a request. This includes
- * all error recovery ccws that have been chained in from of the
- * real request.
- */
-static inline void
-hex_dump_memory(struct dasd_device *device, void *data, int len)
-{
- int *pint;
-
- pint = (int *) data;
- while (len > 0) {
- DEV_MESSAGE(KERN_ERR, device, "%p: %08x %08x %08x %08x",
- pint, pint[0], pint[1], pint[2], pint[3]);
- pint += 4;
- len -= 16;
- }
-}
-
void
dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb)
{
@@ -182,69 +163,8 @@ dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb)
device->discipline->dump_sense(device, cqr, irb);
}
-void
-dasd_log_ccw(struct dasd_ccw_req * cqr, int caller, __u32 cpa)
-{
- struct dasd_device *device;
- struct dasd_ccw_req *lcqr;
- struct ccw1 *ccw;
- int cplength;
-
- device = cqr->device;
- /* log the channel program */
- for (lcqr = cqr; lcqr != NULL; lcqr = lcqr->refers) {
- DEV_MESSAGE(KERN_ERR, device,
- "(%s) ERP chain report for req: %p",
- caller == 0 ? "EXAMINE" : "ACTION", lcqr);
- hex_dump_memory(device, lcqr, sizeof(struct dasd_ccw_req));
-
- cplength = 1;
- ccw = lcqr->cpaddr;
- while (ccw++->flags & (CCW_FLAG_DC | CCW_FLAG_CC))
- cplength++;
-
- if (cplength > 40) { /* log only parts of the CP */
- DEV_MESSAGE(KERN_ERR, device, "%s",
- "Start of channel program:");
- hex_dump_memory(device, lcqr->cpaddr,
- 40*sizeof(struct ccw1));
-
- DEV_MESSAGE(KERN_ERR, device, "%s",
- "End of channel program:");
- hex_dump_memory(device, lcqr->cpaddr + cplength - 10,
- 10*sizeof(struct ccw1));
- } else { /* log the whole CP */
- DEV_MESSAGE(KERN_ERR, device, "%s",
- "Channel program (complete):");
- hex_dump_memory(device, lcqr->cpaddr,
- cplength*sizeof(struct ccw1));
- }
-
- if (lcqr != cqr)
- continue;
-
- /*
- * Log bytes arround failed CCW but only if we did
- * not log the whole CP of the CCW is outside the
- * logged CP.
- */
- if (cplength > 40 ||
- ((addr_t) cpa < (addr_t) lcqr->cpaddr &&
- (addr_t) cpa > (addr_t) (lcqr->cpaddr + cplength + 4))) {
-
- DEV_MESSAGE(KERN_ERR, device,
- "Failed CCW (%p) (area):",
- (void *) (long) cpa);
- hex_dump_memory(device, cqr->cpaddr - 10,
- 20*sizeof(struct ccw1));
- }
- }
-
-} /* end log_erp_chain */
-
EXPORT_SYMBOL(dasd_default_erp_action);
EXPORT_SYMBOL(dasd_default_erp_postaction);
EXPORT_SYMBOL(dasd_alloc_erp_request);
EXPORT_SYMBOL(dasd_free_erp_request);
EXPORT_SYMBOL(dasd_log_sense);
-EXPORT_SYMBOL(dasd_log_ccw);
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c
index b857fd5893f..be0909e3922 100644
--- a/drivers/s390/block/dasd_fba.c
+++ b/drivers/s390/block/dasd_fba.c
@@ -75,7 +75,7 @@ static struct ccw_driver dasd_fba_driver = {
.notify = dasd_generic_notify,
};
-static inline void
+static void
define_extent(struct ccw1 * ccw, struct DE_fba_data *data, int rw,
int blksize, int beg, int nr)
{
@@ -95,7 +95,7 @@ define_extent(struct ccw1 * ccw, struct DE_fba_data *data, int rw,
data->ext_end = nr - 1;
}
-static inline void
+static void
locate_record(struct ccw1 * ccw, struct LO_fba_data *data, int rw,
int block_nr, int block_ct)
{
diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c
index d163632101d..47ba4462708 100644
--- a/drivers/s390/block/dasd_genhd.c
+++ b/drivers/s390/block/dasd_genhd.c
@@ -147,7 +147,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 = (void __user *) &bpart;
+ barg.data = (void __force __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_int.h b/drivers/s390/block/dasd_int.h
index fb725e3b08f..a2cc69e1141 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -559,7 +559,6 @@ struct dasd_ccw_req *dasd_alloc_erp_request(char *, int, int,
struct dasd_device *);
void dasd_free_erp_request(struct dasd_ccw_req *, struct dasd_device *);
void dasd_log_sense(struct dasd_ccw_req *, struct irb *);
-void dasd_log_ccw(struct dasd_ccw_req *, int, __u32);
/* externals in dasd_3370_erp.c */
dasd_era_t dasd_3370_erp_examine(struct dasd_ccw_req *, struct irb *);
diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c
index bfa010f6dab..8b7e11815d7 100644
--- a/drivers/s390/block/dasd_proc.c
+++ b/drivers/s390/block/dasd_proc.c
@@ -28,7 +28,7 @@ static struct proc_dir_entry *dasd_proc_root_entry = NULL;
static struct proc_dir_entry *dasd_devices_entry = NULL;
static struct proc_dir_entry *dasd_statistics_entry = NULL;
-static inline char *
+static char *
dasd_get_user_string(const char __user *user_buf, size_t user_len)
{
char *buffer;
@@ -154,7 +154,7 @@ static struct file_operations dasd_devices_file_ops = {
.release = seq_release,
};
-static inline int
+static int
dasd_calc_metrics(char *page, char **start, off_t off,
int count, int *eof, int len)
{
@@ -167,8 +167,8 @@ dasd_calc_metrics(char *page, char **start, off_t off,
return len;
}
-static inline char *
-dasd_statistics_array(char *str, int *array, int shift)
+static char *
+dasd_statistics_array(char *str, unsigned int *array, int shift)
{
int i;
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index be9b05347b4..1340451ea40 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -102,7 +102,7 @@ dcssblk_release_segment(struct device *dev)
* device needs to be enqueued before the semaphore is
* freed.
*/
-static inline int
+static int
dcssblk_assign_free_minor(struct dcssblk_dev_info *dev_info)
{
int minor, found;
@@ -230,7 +230,7 @@ dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const ch
SEGMENT_SHARED);
if (rc < 0) {
BUG_ON(rc == -EINVAL);
- if (rc == -EIO || rc == -ENOENT)
+ if (rc != -EAGAIN)
goto removeseg;
} else {
dev_info->is_shared = 1;
@@ -253,7 +253,7 @@ dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const ch
SEGMENT_EXCLUSIVE);
if (rc < 0) {
BUG_ON(rc == -EINVAL);
- if (rc == -EIO || rc == -ENOENT)
+ if (rc != -EAGAIN)
goto removeseg;
} else {
dev_info->is_shared = 0;
diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile
index c3e97b4fc18..293e667b50f 100644
--- a/drivers/s390/char/Makefile
+++ b/drivers/s390/char/Makefile
@@ -2,7 +2,8 @@
# S/390 character devices
#
-obj-y += ctrlchar.o keyboard.o defkeymap.o
+obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \
+ sclp_info.o
obj-$(CONFIG_TN3270) += raw3270.o
obj-$(CONFIG_TN3270_CONSOLE) += con3270.o
@@ -11,7 +12,6 @@ obj-$(CONFIG_TN3270_FS) += fs3270.o
obj-$(CONFIG_TN3215) += con3215.o
-obj-$(CONFIG_SCLP) += sclp.o sclp_rw.o sclp_quiesce.o
obj-$(CONFIG_SCLP_TTY) += sclp_tty.o
obj-$(CONFIG_SCLP_CONSOLE) += sclp_con.o
obj-$(CONFIG_SCLP_VT220_TTY) += sclp_vt220.o
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index 25b5d7a6641..9a328f14a64 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -1121,7 +1121,7 @@ static const struct tty_operations tty3215_ops = {
* 3215 tty registration code called from tty_init().
* Most kernel services (incl. kmalloc) are available at this poimt.
*/
-int __init
+static int __init
tty3215_init(void)
{
struct tty_driver *driver;
diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c
index 7566be89068..8e7f2d7633d 100644
--- a/drivers/s390/char/con3270.c
+++ b/drivers/s390/char/con3270.c
@@ -69,8 +69,7 @@ static void con3270_update(struct con3270 *);
/*
* Setup timeout for a device. On timeout trigger an update.
*/
-void
-con3270_set_timer(struct con3270 *cp, int expires)
+static void con3270_set_timer(struct con3270 *cp, int expires)
{
if (expires == 0) {
if (timer_pending(&cp->timer))
diff --git a/drivers/s390/char/defkeymap.c b/drivers/s390/char/defkeymap.c
index 17027d918cf..564baca01b7 100644
--- a/drivers/s390/char/defkeymap.c
+++ b/drivers/s390/char/defkeymap.c
@@ -5,6 +5,8 @@
#include <linux/types.h>
#include <linux/keyboard.h>
#include <linux/kd.h>
+#include <linux/kbd_kern.h>
+#include <linux/kbd_diacr.h>
u_short plain_map[NR_KEYS] = {
0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000,
diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c
index 0893d306ae8..e1a746269c4 100644
--- a/drivers/s390/char/fs3270.c
+++ b/drivers/s390/char/fs3270.c
@@ -23,7 +23,7 @@
#include "raw3270.h"
#include "ctrlchar.h"
-struct raw3270_fn fs3270_fn;
+static struct raw3270_fn fs3270_fn;
struct fs3270 {
struct raw3270_view view;
@@ -401,7 +401,7 @@ fs3270_release(struct raw3270_view *view)
}
/* View to a 3270 device. Can be console, tty or fullscreen. */
-struct raw3270_fn fs3270_fn = {
+static struct raw3270_fn fs3270_fn = {
.activate = fs3270_activate,
.deactivate = fs3270_deactivate,
.intv = (void *) fs3270_irq,
diff --git a/drivers/s390/char/keyboard.c b/drivers/s390/char/keyboard.c
index 3e86fd1756e..f62f9a4e895 100644
--- a/drivers/s390/char/keyboard.c
+++ b/drivers/s390/char/keyboard.c
@@ -148,6 +148,7 @@ kbd_ascebc(struct kbd_data *kbd, unsigned char *ascebc)
}
}
+#if 0
/*
* Generate ebcdic -> ascii translation table from kbd_data.
*/
@@ -173,6 +174,7 @@ kbd_ebcasc(struct kbd_data *kbd, unsigned char *ebcasc)
}
}
}
+#endif
/*
* We have a combining character DIACR here, followed by the character CH.
diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c
index a138b151009..3a1a958fb5f 100644
--- a/drivers/s390/char/monreader.c
+++ b/drivers/s390/char/monreader.c
@@ -3,7 +3,7 @@
*
* Character device driver for reading z/VM *MONITOR service records.
*
- * Copyright (C) 2004 IBM Corporation, IBM Deutschland Entwicklung GmbH.
+ * Copyright 2004 IBM Corporation, IBM Deutschland Entwicklung GmbH.
*
* Author: Gerald Schaefer <geraldsc@de.ibm.com>
*/
@@ -22,7 +22,7 @@
#include <asm/ebcdic.h>
#include <asm/extmem.h>
#include <linux/poll.h>
-#include "../net/iucv.h"
+#include <net/iucv/iucv.h>
//#define MON_DEBUG /* Debug messages on/off */
@@ -50,14 +50,13 @@ static char mon_dcss_name[9] = "MONDCSS\0";
struct mon_msg {
u32 pos;
u32 mca_offset;
- iucv_MessagePending local_eib;
+ struct iucv_message msg;
char msglim_reached;
char replied_msglim;
};
struct mon_private {
- u16 pathid;
- iucv_handle_t iucv_handle;
+ struct iucv_path *path;
struct mon_msg *msg_array[MON_MSGLIM];
unsigned int write_index;
unsigned int read_index;
@@ -75,8 +74,6 @@ static unsigned long mon_dcss_end;
static DECLARE_WAIT_QUEUE_HEAD(mon_read_wait_queue);
static DECLARE_WAIT_QUEUE_HEAD(mon_conn_wait_queue);
-static u8 iucv_host[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-
static u8 user_data_connect[16] = {
/* Version code, must be 0x01 for shared mode */
0x01,
@@ -100,8 +97,7 @@ static u8 user_data_sever[16] = {
* Create the 8 bytes EBCDIC DCSS segment name from
* an ASCII name, incl. padding
*/
-static inline void
-dcss_mkname(char *ascii_name, char *ebcdic_name)
+static inline void dcss_mkname(char *ascii_name, char *ebcdic_name)
{
int i;
@@ -119,8 +115,7 @@ dcss_mkname(char *ascii_name, char *ebcdic_name)
* print appropriate error message for segment_load()/segment_type()
* return code
*/
-static void
-mon_segment_warn(int rc, char* seg_name)
+static void mon_segment_warn(int rc, char* seg_name)
{
switch (rc) {
case -ENOENT:
@@ -166,44 +161,37 @@ mon_segment_warn(int rc, char* seg_name)
}
}
-static inline unsigned long
-mon_mca_start(struct mon_msg *monmsg)
+static inline unsigned long mon_mca_start(struct mon_msg *monmsg)
{
- return monmsg->local_eib.ln1msg1.iprmmsg1_u32;
+ return *(u32 *) &monmsg->msg.rmmsg;
}
-static inline unsigned long
-mon_mca_end(struct mon_msg *monmsg)
+static inline unsigned long mon_mca_end(struct mon_msg *monmsg)
{
- return monmsg->local_eib.ln1msg2.ipbfln1f;
+ return *(u32 *) &monmsg->msg.rmmsg[4];
}
-static inline u8
-mon_mca_type(struct mon_msg *monmsg, u8 index)
+static inline u8 mon_mca_type(struct mon_msg *monmsg, u8 index)
{
return *((u8 *) mon_mca_start(monmsg) + monmsg->mca_offset + index);
}
-static inline u32
-mon_mca_size(struct mon_msg *monmsg)
+static inline u32 mon_mca_size(struct mon_msg *monmsg)
{
return mon_mca_end(monmsg) - mon_mca_start(monmsg) + 1;
}
-static inline u32
-mon_rec_start(struct mon_msg *monmsg)
+static inline u32 mon_rec_start(struct mon_msg *monmsg)
{
return *((u32 *) (mon_mca_start(monmsg) + monmsg->mca_offset + 4));
}
-static inline u32
-mon_rec_end(struct mon_msg *monmsg)
+static inline u32 mon_rec_end(struct mon_msg *monmsg)
{
return *((u32 *) (mon_mca_start(monmsg) + monmsg->mca_offset + 8));
}
-static inline int
-mon_check_mca(struct mon_msg *monmsg)
+static inline int mon_check_mca(struct mon_msg *monmsg)
{
if ((mon_rec_end(monmsg) <= mon_rec_start(monmsg)) ||
(mon_rec_start(monmsg) < mon_dcss_start) ||
@@ -221,20 +209,17 @@ mon_check_mca(struct mon_msg *monmsg)
return 0;
}
-static inline int
-mon_send_reply(struct mon_msg *monmsg, struct mon_private *monpriv)
+static inline int mon_send_reply(struct mon_msg *monmsg,
+ struct mon_private *monpriv)
{
- u8 prmmsg[8];
int rc;
P_DEBUG("read, REPLY: pathid = 0x%04X, msgid = 0x%08X, trgcls = "
"0x%08X\n\n",
- monmsg->local_eib.ippathid, monmsg->local_eib.ipmsgid,
- monmsg->local_eib.iptrgcls);
- rc = iucv_reply_prmmsg(monmsg->local_eib.ippathid,
- monmsg->local_eib.ipmsgid,
- monmsg->local_eib.iptrgcls,
- 0, prmmsg);
+ monpriv->path->pathid, monmsg->msg.id, monmsg->msg.class);
+
+ rc = iucv_message_reply(monpriv->path, &monmsg->msg,
+ IUCV_IPRMDATA, NULL, 0);
atomic_dec(&monpriv->msglim_count);
if (likely(!monmsg->msglim_reached)) {
monmsg->pos = 0;
@@ -251,10 +236,19 @@ mon_send_reply(struct mon_msg *monmsg, struct mon_private *monpriv)
return 0;
}
-static inline struct mon_private *
-mon_alloc_mem(void)
+static inline void mon_free_mem(struct mon_private *monpriv)
+{
+ int i;
+
+ for (i = 0; i < MON_MSGLIM; i++)
+ if (monpriv->msg_array[i])
+ kfree(monpriv->msg_array[i]);
+ kfree(monpriv);
+}
+
+static inline struct mon_private *mon_alloc_mem(void)
{
- int i,j;
+ int i;
struct mon_private *monpriv;
monpriv = kzalloc(sizeof(struct mon_private), GFP_KERNEL);
@@ -267,16 +261,15 @@ mon_alloc_mem(void)
GFP_KERNEL);
if (!monpriv->msg_array[i]) {
P_ERROR("open, no memory for msg_array\n");
- for (j = 0; j < i; j++)
- kfree(monpriv->msg_array[j]);
+ mon_free_mem(monpriv);
return NULL;
}
}
return monpriv;
}
-static inline void
-mon_read_debug(struct mon_msg *monmsg, struct mon_private *monpriv)
+static inline void mon_read_debug(struct mon_msg *monmsg,
+ struct mon_private *monpriv)
{
#ifdef MON_DEBUG
u8 msg_type[2], mca_type;
@@ -284,7 +277,7 @@ mon_read_debug(struct mon_msg *monmsg, struct mon_private *monpriv)
records_len = mon_rec_end(monmsg) - mon_rec_start(monmsg) + 1;
- memcpy(msg_type, &monmsg->local_eib.iptrgcls, 2);
+ memcpy(msg_type, &monmsg->msg.class, 2);
EBCASC(msg_type, 2);
mca_type = mon_mca_type(monmsg, 0);
EBCASC(&mca_type, 1);
@@ -292,8 +285,7 @@ mon_read_debug(struct mon_msg *monmsg, struct mon_private *monpriv)
P_DEBUG("read, mon_read_index = %i, mon_write_index = %i\n",
monpriv->read_index, monpriv->write_index);
P_DEBUG("read, pathid = 0x%04X, msgid = 0x%08X, trgcls = 0x%08X\n",
- monmsg->local_eib.ippathid, monmsg->local_eib.ipmsgid,
- monmsg->local_eib.iptrgcls);
+ monpriv->path->pathid, monmsg->msg.id, monmsg->msg.class);
P_DEBUG("read, msg_type = '%c%c', mca_type = '%c' / 0x%X / 0x%X\n",
msg_type[0], msg_type[1], mca_type ? mca_type : 'X',
mon_mca_type(monmsg, 1), mon_mca_type(monmsg, 2));
@@ -306,8 +298,7 @@ mon_read_debug(struct mon_msg *monmsg, struct mon_private *monpriv)
#endif
}
-static inline void
-mon_next_mca(struct mon_msg *monmsg)
+static inline void mon_next_mca(struct mon_msg *monmsg)
{
if (likely((mon_mca_size(monmsg) - monmsg->mca_offset) == 12))
return;
@@ -316,8 +307,7 @@ mon_next_mca(struct mon_msg *monmsg)
monmsg->pos = 0;
}
-static inline struct mon_msg *
-mon_next_message(struct mon_private *monpriv)
+static inline struct mon_msg *mon_next_message(struct mon_private *monpriv)
{
struct mon_msg *monmsg;
@@ -342,39 +332,37 @@ mon_next_message(struct mon_private *monpriv)
/******************************************************************************
* IUCV handler *
*****************************************************************************/
-static void
-mon_iucv_ConnectionComplete(iucv_ConnectionComplete *eib, void *pgm_data)
+static void mon_iucv_path_complete(struct iucv_path *path, u8 ipuser[16])
{
- struct mon_private *monpriv = (struct mon_private *) pgm_data;
+ struct mon_private *monpriv = path->private;
P_DEBUG("IUCV connection completed\n");
P_DEBUG("IUCV ACCEPT (from *MONITOR): Version = 0x%02X, Event = "
"0x%02X, Sample = 0x%02X\n",
- eib->ipuser[0], eib->ipuser[1], eib->ipuser[2]);
+ ipuser[0], ipuser[1], ipuser[2]);
atomic_set(&monpriv->iucv_connected, 1);
wake_up(&mon_conn_wait_queue);
}
-static void
-mon_iucv_ConnectionSevered(iucv_ConnectionSevered *eib, void *pgm_data)
+static void mon_iucv_path_severed(struct iucv_path *path, u8 ipuser[16])
{
- struct mon_private *monpriv = (struct mon_private *) pgm_data;
+ struct mon_private *monpriv = path->private;
- P_ERROR("IUCV connection severed with rc = 0x%X\n",
- (u8) eib->ipuser[0]);
+ P_ERROR("IUCV connection severed with rc = 0x%X\n", ipuser[0]);
+ iucv_path_sever(path, NULL);
atomic_set(&monpriv->iucv_severed, 1);
wake_up(&mon_conn_wait_queue);
wake_up_interruptible(&mon_read_wait_queue);
}
-static void
-mon_iucv_MessagePending(iucv_MessagePending *eib, void *pgm_data)
+static void mon_iucv_message_pending(struct iucv_path *path,
+ struct iucv_message *msg)
{
- struct mon_private *monpriv = (struct mon_private *) pgm_data;
+ struct mon_private *monpriv = path->private;
P_DEBUG("IUCV message pending\n");
- memcpy(&monpriv->msg_array[monpriv->write_index]->local_eib, eib,
- sizeof(iucv_MessagePending));
+ memcpy(&monpriv->msg_array[monpriv->write_index]->msg,
+ msg, sizeof(*msg));
if (atomic_inc_return(&monpriv->msglim_count) == MON_MSGLIM) {
P_WARNING("IUCV message pending, message limit (%i) reached\n",
MON_MSGLIM);
@@ -385,54 +373,45 @@ mon_iucv_MessagePending(iucv_MessagePending *eib, void *pgm_data)
wake_up_interruptible(&mon_read_wait_queue);
}
-static iucv_interrupt_ops_t mon_iucvops = {
- .ConnectionComplete = mon_iucv_ConnectionComplete,
- .ConnectionSevered = mon_iucv_ConnectionSevered,
- .MessagePending = mon_iucv_MessagePending,
+static struct iucv_handler monreader_iucv_handler = {
+ .path_complete = mon_iucv_path_complete,
+ .path_severed = mon_iucv_path_severed,
+ .message_pending = mon_iucv_message_pending,
};
/******************************************************************************
* file operations *
*****************************************************************************/
-static int
-mon_open(struct inode *inode, struct file *filp)
+static int mon_open(struct inode *inode, struct file *filp)
{
- int rc, i;
struct mon_private *monpriv;
+ int rc;
/*
* only one user allowed
*/
+ rc = -EBUSY;
if (test_and_set_bit(MON_IN_USE, &mon_in_use))
- return -EBUSY;
+ goto out;
+ rc = -ENOMEM;
monpriv = mon_alloc_mem();
if (!monpriv)
- return -ENOMEM;
+ goto out_use;
/*
- * Register with IUCV and connect to *MONITOR service
+ * Connect to *MONITOR service
*/
- monpriv->iucv_handle = iucv_register_program("my_monreader ",
- MON_SERVICE,
- NULL,
- &mon_iucvops,
- monpriv);
- if (!monpriv->iucv_handle) {
- P_ERROR("failed to register with iucv driver\n");
- rc = -EIO;
- goto out_error;
- }
- P_INFO("open, registered with IUCV\n");
-
- rc = iucv_connect(&monpriv->pathid, MON_MSGLIM, user_data_connect,
- MON_SERVICE, iucv_host, IPRMDATA, NULL, NULL,
- monpriv->iucv_handle, NULL);
+ monpriv->path = iucv_path_alloc(MON_MSGLIM, IUCV_IPRMDATA, GFP_KERNEL);
+ if (!monpriv->path)
+ goto out_priv;
+ rc = iucv_path_connect(monpriv->path, &monreader_iucv_handler,
+ MON_SERVICE, NULL, user_data_connect, monpriv);
if (rc) {
P_ERROR("iucv connection to *MONITOR failed with "
"IPUSER SEVER code = %i\n", rc);
rc = -EIO;
- goto out_unregister;
+ goto out_path;
}
/*
* Wait for connection confirmation
@@ -444,24 +423,23 @@ mon_open(struct inode *inode, struct file *filp)
atomic_set(&monpriv->iucv_severed, 0);
atomic_set(&monpriv->iucv_connected, 0);
rc = -EIO;
- goto out_unregister;
+ goto out_path;
}
P_INFO("open, established connection to *MONITOR service\n\n");
filp->private_data = monpriv;
return nonseekable_open(inode, filp);
-out_unregister:
- iucv_unregister_program(monpriv->iucv_handle);
-out_error:
- for (i = 0; i < MON_MSGLIM; i++)
- kfree(monpriv->msg_array[i]);
- kfree(monpriv);
+out_path:
+ kfree(monpriv->path);
+out_priv:
+ mon_free_mem(monpriv);
+out_use:
clear_bit(MON_IN_USE, &mon_in_use);
+out:
return rc;
}
-static int
-mon_close(struct inode *inode, struct file *filp)
+static int mon_close(struct inode *inode, struct file *filp)
{
int rc, i;
struct mon_private *monpriv = filp->private_data;
@@ -469,18 +447,12 @@ mon_close(struct inode *inode, struct file *filp)
/*
* Close IUCV connection and unregister
*/
- rc = iucv_sever(monpriv->pathid, user_data_sever);
+ rc = iucv_path_sever(monpriv->path, user_data_sever);
if (rc)
P_ERROR("close, iucv_sever failed with rc = %i\n", rc);
else
P_INFO("close, terminated connection to *MONITOR service\n");
- rc = iucv_unregister_program(monpriv->iucv_handle);
- if (rc)
- P_ERROR("close, iucv_unregister failed with rc = %i\n", rc);
- else
- P_INFO("close, unregistered with IUCV\n");
-
atomic_set(&monpriv->iucv_severed, 0);
atomic_set(&monpriv->iucv_connected, 0);
atomic_set(&monpriv->read_ready, 0);
@@ -495,8 +467,8 @@ mon_close(struct inode *inode, struct file *filp)
return 0;
}
-static ssize_t
-mon_read(struct file *filp, char __user *data, size_t count, loff_t *ppos)
+static ssize_t mon_read(struct file *filp, char __user *data,
+ size_t count, loff_t *ppos)
{
struct mon_private *monpriv = filp->private_data;
struct mon_msg *monmsg;
@@ -563,8 +535,7 @@ out_copy:
return count;
}
-static unsigned int
-mon_poll(struct file *filp, struct poll_table_struct *p)
+static unsigned int mon_poll(struct file *filp, struct poll_table_struct *p)
{
struct mon_private *monpriv = filp->private_data;
@@ -593,8 +564,7 @@ static struct miscdevice mon_dev = {
/******************************************************************************
* module init/exit *
*****************************************************************************/
-static int __init
-mon_init(void)
+static int __init mon_init(void)
{
int rc;
@@ -603,22 +573,34 @@ mon_init(void)
return -ENODEV;
}
+ /*
+ * Register with IUCV and connect to *MONITOR service
+ */
+ rc = iucv_register(&monreader_iucv_handler, 1);
+ if (rc) {
+ P_ERROR("failed to register with iucv driver\n");
+ return rc;
+ }
+ P_INFO("open, registered with IUCV\n");
+
rc = segment_type(mon_dcss_name);
if (rc < 0) {
mon_segment_warn(rc, mon_dcss_name);
- return rc;
+ goto out_iucv;
}
if (rc != SEG_TYPE_SC) {
P_ERROR("segment %s has unsupported type, should be SC\n",
mon_dcss_name);
- return -EINVAL;
+ rc = -EINVAL;
+ goto out_iucv;
}
rc = segment_load(mon_dcss_name, SEGMENT_SHARED,
&mon_dcss_start, &mon_dcss_end);
if (rc < 0) {
mon_segment_warn(rc, mon_dcss_name);
- return -EINVAL;
+ rc = -EINVAL;
+ goto out_iucv;
}
dcss_mkname(mon_dcss_name, &user_data_connect[8]);
@@ -634,14 +616,16 @@ mon_init(void)
out:
segment_unload(mon_dcss_name);
+out_iucv:
+ iucv_unregister(&monreader_iucv_handler, 1);
return rc;
}
-static void __exit
-mon_exit(void)
+static void __exit mon_exit(void)
{
segment_unload(mon_dcss_name);
WARN_ON(misc_deregister(&mon_dev) != 0);
+ iucv_unregister(&monreader_iucv_handler, 1);
return;
}
diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c
index cdb24f52811..9e451acc649 100644
--- a/drivers/s390/char/monwriter.c
+++ b/drivers/s390/char/monwriter.c
@@ -67,8 +67,8 @@ static int monwrite_diag(struct monwrite_hdr *myhdr, char *buffer, int fcn)
return -EINVAL;
}
-static inline struct mon_buf *monwrite_find_hdr(struct mon_private *monpriv,
- struct monwrite_hdr *monhdr)
+static struct mon_buf *monwrite_find_hdr(struct mon_private *monpriv,
+ struct monwrite_hdr *monhdr)
{
struct mon_buf *entry, *next;
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c
index 7a84014f203..8facd14adb7 100644
--- a/drivers/s390/char/raw3270.c
+++ b/drivers/s390/char/raw3270.c
@@ -29,7 +29,7 @@
#include <linux/device.h>
#include <linux/mutex.h>
-struct class *class3270;
+static struct class *class3270;
/* The main 3270 data structure. */
struct raw3270 {
@@ -86,7 +86,7 @@ DECLARE_WAIT_QUEUE_HEAD(raw3270_wait_queue);
/*
* Encode array for 12 bit 3270 addresses.
*/
-unsigned char raw3270_ebcgraf[64] = {
+static unsigned char raw3270_ebcgraf[64] = {
0x40, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
0xc8, 0xc9, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c
index 8a056df09d6..f171de3b0b1 100644
--- a/drivers/s390/char/sclp.c
+++ b/drivers/s390/char/sclp.c
@@ -59,7 +59,8 @@ static volatile enum sclp_init_state_t {
/* Internal state: is a request active at the sclp? */
static volatile enum sclp_running_state_t {
sclp_running_state_idle,
- sclp_running_state_running
+ sclp_running_state_running,
+ sclp_running_state_reset_pending
} sclp_running_state = sclp_running_state_idle;
/* Internal state: is a read request pending? */
@@ -88,15 +89,15 @@ static volatile enum sclp_mask_state_t {
/* Timeout intervals in seconds.*/
#define SCLP_BUSY_INTERVAL 10
-#define SCLP_RETRY_INTERVAL 15
+#define SCLP_RETRY_INTERVAL 30
static void sclp_process_queue(void);
static int sclp_init_mask(int calculate);
static int sclp_init(void);
/* Perform service call. Return 0 on success, non-zero otherwise. */
-static int
-service_call(sclp_cmdw_t command, void *sccb)
+int
+sclp_service_call(sclp_cmdw_t command, void *sccb)
{
int cc;
@@ -113,19 +114,17 @@ service_call(sclp_cmdw_t command, void *sccb)
return 0;
}
-/* Request timeout handler. Restart the request queue. If DATA is non-zero,
- * force restart of running request. */
+static inline void __sclp_make_read_req(void);
+
static void
-sclp_request_timeout(unsigned long data)
+__sclp_queue_read_req(void)
{
- unsigned long flags;
-
- if (data) {
- spin_lock_irqsave(&sclp_lock, flags);
- sclp_running_state = sclp_running_state_idle;
- spin_unlock_irqrestore(&sclp_lock, flags);
+ if (sclp_reading_state == sclp_reading_state_idle) {
+ sclp_reading_state = sclp_reading_state_reading;
+ __sclp_make_read_req();
+ /* Add request to head of queue */
+ list_add(&sclp_read_req.list, &sclp_req_queue);
}
- sclp_process_queue();
}
/* Set up request retry timer. Called while sclp_lock is locked. */
@@ -140,6 +139,29 @@ __sclp_set_request_timer(unsigned long time, void (*function)(unsigned long),
add_timer(&sclp_request_timer);
}
+/* Request timeout handler. Restart the request queue. If DATA is non-zero,
+ * force restart of running request. */
+static void
+sclp_request_timeout(unsigned long data)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&sclp_lock, flags);
+ if (data) {
+ if (sclp_running_state == sclp_running_state_running) {
+ /* Break running state and queue NOP read event request
+ * to get a defined interface state. */
+ __sclp_queue_read_req();
+ sclp_running_state = sclp_running_state_idle;
+ }
+ } else {
+ __sclp_set_request_timer(SCLP_BUSY_INTERVAL * HZ,
+ sclp_request_timeout, 0);
+ }
+ spin_unlock_irqrestore(&sclp_lock, flags);
+ sclp_process_queue();
+}
+
/* Try to start a request. Return zero if the request was successfully
* started or if it will be started at a later time. Return non-zero otherwise.
* Called while sclp_lock is locked. */
@@ -151,7 +173,7 @@ __sclp_start_request(struct sclp_req *req)
if (sclp_running_state != sclp_running_state_idle)
return 0;
del_timer(&sclp_request_timer);
- rc = service_call(req->command, req->sccb);
+ rc = sclp_service_call(req->command, req->sccb);
req->start_count++;
if (rc == 0) {
@@ -191,7 +213,15 @@ sclp_process_queue(void)
rc = __sclp_start_request(req);
if (rc == 0)
break;
- /* Request failed. */
+ /* Request failed */
+ if (req->start_count > 1) {
+ /* Cannot abort already submitted request - could still
+ * be active at the SCLP */
+ __sclp_set_request_timer(SCLP_BUSY_INTERVAL * HZ,
+ sclp_request_timeout, 0);
+ break;
+ }
+ /* Post-processing for aborted request */
list_del(&req->list);
if (req->callback) {
spin_unlock_irqrestore(&sclp_lock, flags);
@@ -221,7 +251,8 @@ sclp_add_request(struct sclp_req *req)
list_add_tail(&req->list, &sclp_req_queue);
rc = 0;
/* Start if request is first in list */
- if (req->list.prev == &sclp_req_queue) {
+ if (sclp_running_state == sclp_running_state_idle &&
+ req->list.prev == &sclp_req_queue) {
rc = __sclp_start_request(req);
if (rc)
list_del(&req->list);
@@ -294,7 +325,7 @@ __sclp_make_read_req(void)
sccb = (struct sccb_header *) sclp_read_sccb;
clear_page(sccb);
memset(&sclp_read_req, 0, sizeof(struct sclp_req));
- sclp_read_req.command = SCLP_CMDW_READDATA;
+ sclp_read_req.command = SCLP_CMDW_READ_EVENT_DATA;
sclp_read_req.status = SCLP_REQ_QUEUED;
sclp_read_req.start_count = 0;
sclp_read_req.callback = sclp_read_cb;
@@ -334,6 +365,8 @@ sclp_interrupt_handler(__u16 code)
finished_sccb = S390_lowcore.ext_params & 0xfffffff8;
evbuf_pending = S390_lowcore.ext_params & 0x3;
if (finished_sccb) {
+ del_timer(&sclp_request_timer);
+ sclp_running_state = sclp_running_state_reset_pending;
req = __sclp_find_req(finished_sccb);
if (req) {
/* Request post-processing */
@@ -348,13 +381,8 @@ sclp_interrupt_handler(__u16 code)
sclp_running_state = sclp_running_state_idle;
}
if (evbuf_pending && sclp_receive_mask != 0 &&
- sclp_reading_state == sclp_reading_state_idle &&
- sclp_activation_state == sclp_activation_state_active ) {
- sclp_reading_state = sclp_reading_state_reading;
- __sclp_make_read_req();
- /* Add request to head of queue */
- list_add(&sclp_read_req.list, &sclp_req_queue);
- }
+ sclp_activation_state == sclp_activation_state_active)
+ __sclp_queue_read_req();
spin_unlock(&sclp_lock);
sclp_process_queue();
}
@@ -374,6 +402,7 @@ sclp_sync_wait(void)
unsigned long flags;
unsigned long cr0, cr0_sync;
u64 timeout;
+ int irq_context;
/* We'll be disabling timer interrupts, so we need a custom timeout
* mechanism */
@@ -386,7 +415,9 @@ sclp_sync_wait(void)
}
local_irq_save(flags);
/* Prevent bottom half from executing once we force interrupts open */
- local_bh_disable();
+ irq_context = in_interrupt();
+ if (!irq_context)
+ local_bh_disable();
/* Enable service-signal interruption, disable timer interrupts */
trace_hardirqs_on();
__ctl_store(cr0, 0, 0);
@@ -402,19 +433,19 @@ sclp_sync_wait(void)
get_clock() > timeout &&
del_timer(&sclp_request_timer))
sclp_request_timer.function(sclp_request_timer.data);
- barrier();
cpu_relax();
}
local_irq_disable();
__ctl_load(cr0, 0, 0);
- _local_bh_enable();
+ if (!irq_context)
+ _local_bh_enable();
local_irq_restore(flags);
}
EXPORT_SYMBOL(sclp_sync_wait);
/* Dispatch changes in send and receive mask to registered listeners. */
-static inline void
+static void
sclp_dispatch_state_change(void)
{
struct list_head *l;
@@ -597,7 +628,7 @@ __sclp_make_init_req(u32 receive_mask, u32 send_mask)
sccb = (struct init_sccb *) sclp_init_sccb;
clear_page(sccb);
memset(&sclp_init_req, 0, sizeof(struct sclp_req));
- sclp_init_req.command = SCLP_CMDW_WRITEMASK;
+ sclp_init_req.command = SCLP_CMDW_WRITE_EVENT_MASK;
sclp_init_req.status = SCLP_REQ_FILLED;
sclp_init_req.start_count = 0;
sclp_init_req.callback = NULL;
@@ -800,7 +831,7 @@ sclp_check_interface(void)
for (retry = 0; retry <= SCLP_INIT_RETRY; retry++) {
__sclp_make_init_req(0, 0);
sccb = (struct init_sccb *) sclp_init_req.sccb;
- rc = service_call(sclp_init_req.command, sccb);
+ rc = sclp_service_call(sclp_init_req.command, sccb);
if (rc == -EIO)
break;
sclp_init_req.status = SCLP_REQ_RUNNING;
diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h
index 2c71d6ee7b5..7d29ab45a6e 100644
--- a/drivers/s390/char/sclp.h
+++ b/drivers/s390/char/sclp.h
@@ -12,7 +12,7 @@
#include <linux/types.h>
#include <linux/list.h>
-
+#include <asm/sclp.h>
#include <asm/ebcdic.h>
/* maximum number of pages concerning our own memory management */
@@ -49,9 +49,11 @@
typedef unsigned int sclp_cmdw_t;
-#define SCLP_CMDW_READDATA 0x00770005
-#define SCLP_CMDW_WRITEDATA 0x00760005
-#define SCLP_CMDW_WRITEMASK 0x00780005
+#define SCLP_CMDW_READ_EVENT_DATA 0x00770005
+#define SCLP_CMDW_WRITE_EVENT_DATA 0x00760005
+#define SCLP_CMDW_WRITE_EVENT_MASK 0x00780005
+#define SCLP_CMDW_READ_SCP_INFO 0x00020001
+#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001
#define GDS_ID_MDSMU 0x1310
#define GDS_ID_MDSRouteInfo 0x1311
@@ -66,13 +68,6 @@ typedef unsigned int sclp_cmdw_t;
typedef u32 sccb_mask_t; /* ATTENTION: assumes 32bit mask !!! */
-struct sccb_header {
- u16 length;
- u8 function_code;
- u8 control_mask[3];
- u16 response_code;
-} __attribute__((packed));
-
struct gds_subvector {
u8 length;
u8 key;
@@ -131,6 +126,7 @@ void sclp_unregister(struct sclp_register *reg);
int sclp_remove_processed(struct sccb_header *sccb);
int sclp_deactivate(void);
int sclp_reactivate(void);
+int sclp_service_call(sclp_cmdw_t command, void *sccb);
/* useful inlines */
diff --git a/drivers/s390/char/sclp_con.c b/drivers/s390/char/sclp_con.c
index 86864f64171..ead1043d788 100644
--- a/drivers/s390/char/sclp_con.c
+++ b/drivers/s390/char/sclp_con.c
@@ -66,7 +66,7 @@ sclp_conbuf_callback(struct sclp_buffer *buffer, int rc)
} while (buffer && sclp_emit_buffer(buffer, sclp_conbuf_callback));
}
-static inline void
+static void
sclp_conbuf_emit(void)
{
struct sclp_buffer* buffer;
diff --git a/drivers/s390/char/sclp_cpi.c b/drivers/s390/char/sclp_cpi.c
index 4f873ae148b..65aa2c85737 100644
--- a/drivers/s390/char/sclp_cpi.c
+++ b/drivers/s390/char/sclp_cpi.c
@@ -169,7 +169,7 @@ cpi_prepare_req(void)
}
/* prepare request data structure presented to SCLP driver */
- req->command = SCLP_CMDW_WRITEDATA;
+ req->command = SCLP_CMDW_WRITE_EVENT_DATA;
req->sccb = sccb;
req->status = SCLP_REQ_FILLED;
req->callback = cpi_callback;
diff --git a/drivers/s390/char/sclp_info.c b/drivers/s390/char/sclp_info.c
new file mode 100644
index 00000000000..7bcbe643b08
--- /dev/null
+++ b/drivers/s390/char/sclp_info.c
@@ -0,0 +1,57 @@
+/*
+ * drivers/s390/char/sclp_info.c
+ *
+ * Copyright IBM Corp. 2007
+ * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
+ */
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <asm/sclp.h>
+#include "sclp.h"
+
+struct sclp_readinfo_sccb s390_readinfo_sccb;
+
+void __init sclp_readinfo_early(void)
+{
+ sclp_cmdw_t command;
+ struct sccb_header *sccb;
+ int ret;
+
+ __ctl_set_bit(0, 9); /* enable service signal subclass mask */
+
+ sccb = &s390_readinfo_sccb.header;
+ command = SCLP_CMDW_READ_SCP_INFO_FORCED;
+ while (1) {
+ u16 response;
+
+ memset(&s390_readinfo_sccb, 0, sizeof(s390_readinfo_sccb));
+ sccb->length = sizeof(s390_readinfo_sccb);
+ sccb->control_mask[2] = 0x80;
+
+ ret = sclp_service_call(command, &s390_readinfo_sccb);
+
+ if (ret == -EIO)
+ goto out;
+ if (ret == -EBUSY)
+ continue;
+
+ __load_psw_mask(PSW_BASE_BITS | PSW_MASK_EXT |
+ PSW_MASK_WAIT | PSW_DEFAULT_KEY);
+ local_irq_disable();
+ barrier();
+
+ response = sccb->response_code;
+
+ if (response == 0x10)
+ break;
+
+ if (response != 0x1f0 || command == SCLP_CMDW_READ_SCP_INFO)
+ break;
+
+ command = SCLP_CMDW_READ_SCP_INFO;
+ }
+out:
+ __ctl_clear_bit(0, 9); /* disable service signal subclass mask */
+}
diff --git a/drivers/s390/char/sclp_rw.c b/drivers/s390/char/sclp_rw.c
index 0c92d3909cc..2486783ea58 100644
--- a/drivers/s390/char/sclp_rw.c
+++ b/drivers/s390/char/sclp_rw.c
@@ -460,7 +460,7 @@ sclp_emit_buffer(struct sclp_buffer *buffer,
sccb->msg_buf.header.type = EvTyp_PMsgCmd;
else
return -ENOSYS;
- buffer->request.command = SCLP_CMDW_WRITEDATA;
+ buffer->request.command = SCLP_CMDW_WRITE_EVENT_DATA;
buffer->request.status = SCLP_REQ_FILLED;
buffer->request.callback = sclp_writedata_callback;
buffer->request.callback_data = buffer;
diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c
index 2d173e5c8a0..90536f60bf5 100644
--- a/drivers/s390/char/sclp_tty.c
+++ b/drivers/s390/char/sclp_tty.c
@@ -721,7 +721,7 @@ static const struct tty_operations sclp_ops = {
.ioctl = sclp_tty_ioctl,
};
-int __init
+static int __init
sclp_tty_init(void)
{
struct tty_driver *driver;
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c
index 723bf4191bf..544f137d70d 100644
--- a/drivers/s390/char/sclp_vt220.c
+++ b/drivers/s390/char/sclp_vt220.c
@@ -207,7 +207,7 @@ __sclp_vt220_emit(struct sclp_vt220_request *request)
request->sclp_req.status = SCLP_REQ_FAILED;
return -EIO;
}
- request->sclp_req.command = SCLP_CMDW_WRITEDATA;
+ request->sclp_req.command = SCLP_CMDW_WRITE_EVENT_DATA;
request->sclp_req.status = SCLP_REQ_FILLED;
request->sclp_req.callback = sclp_vt220_callback;
request->sclp_req.callback_data = (void *) request;
@@ -669,7 +669,7 @@ static const struct tty_operations sclp_vt220_ops = {
/*
* Register driver with SCLP and Linux and initialize internal tty structures.
*/
-int __init
+static int __init
sclp_vt220_tty_init(void)
{
struct tty_driver *driver;
diff --git a/drivers/s390/char/tape.h b/drivers/s390/char/tape.h
index c9f1c4c8bb1..bb4ff537729 100644
--- a/drivers/s390/char/tape.h
+++ b/drivers/s390/char/tape.h
@@ -3,7 +3,7 @@
* tape device driver for 3480/3490E/3590 tapes.
*
* S390 and zSeries version
- * Copyright (C) 2001,2005 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright IBM Corp. 2001,2006
* Author(s): Carsten Otte <cotte@de.ibm.com>
* Tuan Ngo-Anh <ngoanh@de.ibm.com>
* Martin Schwidefsky <schwidefsky@de.ibm.com>
@@ -99,7 +99,11 @@ enum tape_op {
TO_DIS, /* Tape display */
TO_ASSIGN, /* Assign tape to channel path */
TO_UNASSIGN, /* Unassign tape from channel path */
- TO_SIZE /* #entries in tape_op_t */
+ TO_CRYPT_ON, /* Enable encrpytion */
+ TO_CRYPT_OFF, /* Disable encrpytion */
+ TO_KEKL_SET, /* Set KEK label */
+ TO_KEKL_QUERY, /* Query KEK label */
+ TO_SIZE, /* #entries in tape_op_t */
};
/* Forward declaration */
@@ -112,6 +116,7 @@ enum tape_request_status {
TAPE_REQUEST_IN_IO, /* request is currently in IO */
TAPE_REQUEST_DONE, /* request is completed. */
TAPE_REQUEST_CANCEL, /* request should be canceled. */
+ TAPE_REQUEST_LONG_BUSY, /* request has to be restarted after long busy */
};
/* Tape CCW request */
@@ -164,10 +169,11 @@ struct tape_discipline {
* The discipline irq function either returns an error code (<0) which
* means that the request has failed with an error or one of the following:
*/
-#define TAPE_IO_SUCCESS 0 /* request successful */
-#define TAPE_IO_PENDING 1 /* request still running */
-#define TAPE_IO_RETRY 2 /* retry to current request */
-#define TAPE_IO_STOP 3 /* stop the running request */
+#define TAPE_IO_SUCCESS 0 /* request successful */
+#define TAPE_IO_PENDING 1 /* request still running */
+#define TAPE_IO_RETRY 2 /* retry to current request */
+#define TAPE_IO_STOP 3 /* stop the running request */
+#define TAPE_IO_LONG_BUSY 4 /* delay the running request */
/* Char Frontend Data */
struct tape_char_data {
@@ -242,6 +248,10 @@ struct tape_device {
/* Function to start or stop the next request later. */
struct delayed_work tape_dnr;
+
+ /* Timer for long busy */
+ struct timer_list lb_timeout;
+
};
/* Externals from tape_core.c */
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c
index 9df912f6318..50f5edab83d 100644
--- a/drivers/s390/char/tape_3590.c
+++ b/drivers/s390/char/tape_3590.c
@@ -2,7 +2,7 @@
* drivers/s390/char/tape_3590.c
* tape device discipline for 3590 tapes.
*
- * Copyright (C) IBM Corp. 2001,2006
+ * Copyright IBM Corp. 2001,2006
* Author(s): Stefan Bader <shbader@de.ibm.com>
* Michael Holzheu <holzheu@de.ibm.com>
* Martin Schwidefsky <schwidefsky@de.ibm.com>
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/bio.h>
+#include <asm/ebcdic.h>
#define TAPE_DBF_AREA tape_3590_dbf
@@ -30,7 +31,7 @@ EXPORT_SYMBOL(TAPE_DBF_AREA);
* - Read Device (buffered) log: BRA
* - Read Library log: BRA
* - Swap Devices: BRA
- * - Long Busy: BRA
+ * - Long Busy: implemented
* - Special Intercept: BRA
* - Read Alternate: implemented
*******************************************************************/
@@ -94,6 +95,332 @@ static const char *tape_3590_msg[TAPE_3590_MAX_MSG] = {
[0xae] = "Subsystem environmental alert",
};
+static int crypt_supported(struct tape_device *device)
+{
+ return TAPE390_CRYPT_SUPPORTED(TAPE_3590_CRYPT_INFO(device));
+}
+
+static int crypt_enabled(struct tape_device *device)
+{
+ return TAPE390_CRYPT_ON(TAPE_3590_CRYPT_INFO(device));
+}
+
+static void ext_to_int_kekl(struct tape390_kekl *in,
+ struct tape3592_kekl *out)
+{
+ int i;
+
+ memset(out, 0, sizeof(*out));
+ if (in->type == TAPE390_KEKL_TYPE_HASH)
+ out->flags |= 0x40;
+ if (in->type_on_tape == TAPE390_KEKL_TYPE_HASH)
+ out->flags |= 0x80;
+ strncpy(out->label, in->label, 64);
+ for (i = strlen(in->label); i < sizeof(out->label); i++)
+ out->label[i] = ' ';
+ ASCEBC(out->label, sizeof(out->label));
+}
+
+static void int_to_ext_kekl(struct tape3592_kekl *in,
+ struct tape390_kekl *out)
+{
+ memset(out, 0, sizeof(*out));
+ if(in->flags & 0x40)
+ out->type = TAPE390_KEKL_TYPE_HASH;
+ else
+ out->type = TAPE390_KEKL_TYPE_LABEL;
+ if(in->flags & 0x80)
+ out->type_on_tape = TAPE390_KEKL_TYPE_HASH;
+ else
+ out->type_on_tape = TAPE390_KEKL_TYPE_LABEL;
+ memcpy(out->label, in->label, sizeof(in->label));
+ EBCASC(out->label, sizeof(in->label));
+ strstrip(out->label);
+}
+
+static void int_to_ext_kekl_pair(struct tape3592_kekl_pair *in,
+ struct tape390_kekl_pair *out)
+{
+ if (in->count == 0) {
+ out->kekl[0].type = TAPE390_KEKL_TYPE_NONE;
+ out->kekl[0].type_on_tape = TAPE390_KEKL_TYPE_NONE;
+ out->kekl[1].type = TAPE390_KEKL_TYPE_NONE;
+ out->kekl[1].type_on_tape = TAPE390_KEKL_TYPE_NONE;
+ } else if (in->count == 1) {
+ int_to_ext_kekl(&in->kekl[0], &out->kekl[0]);
+ out->kekl[1].type = TAPE390_KEKL_TYPE_NONE;
+ out->kekl[1].type_on_tape = TAPE390_KEKL_TYPE_NONE;
+ } else if (in->count == 2) {
+ int_to_ext_kekl(&in->kekl[0], &out->kekl[0]);
+ int_to_ext_kekl(&in->kekl[1], &out->kekl[1]);
+ } else {
+ printk("Invalid KEKL number: %d\n", in->count);
+ BUG();
+ }
+}
+
+static int check_ext_kekl(struct tape390_kekl *kekl)
+{
+ if (kekl->type == TAPE390_KEKL_TYPE_NONE)
+ goto invalid;
+ if (kekl->type > TAPE390_KEKL_TYPE_HASH)
+ goto invalid;
+ if (kekl->type_on_tape == TAPE390_KEKL_TYPE_NONE)
+ goto invalid;
+ if (kekl->type_on_tape > TAPE390_KEKL_TYPE_HASH)
+ goto invalid;
+ if ((kekl->type == TAPE390_KEKL_TYPE_HASH) &&
+ (kekl->type_on_tape == TAPE390_KEKL_TYPE_LABEL))
+ goto invalid;
+
+ return 0;
+invalid:
+ return -EINVAL;
+}
+
+static int check_ext_kekl_pair(struct tape390_kekl_pair *kekls)
+{
+ if (check_ext_kekl(&kekls->kekl[0]))
+ goto invalid;
+ if (check_ext_kekl(&kekls->kekl[1]))
+ goto invalid;
+
+ return 0;
+invalid:
+ return -EINVAL;
+}
+
+/*
+ * Query KEKLs
+ */
+static int tape_3592_kekl_query(struct tape_device *device,
+ struct tape390_kekl_pair *ext_kekls)
+{
+ struct tape_request *request;
+ struct tape3592_kekl_query_order *order;
+ struct tape3592_kekl_query_data *int_kekls;
+ int rc;
+
+ DBF_EVENT(6, "tape3592_kekl_query\n");
+ int_kekls = kmalloc(sizeof(*int_kekls), GFP_KERNEL|GFP_DMA);
+ if (!int_kekls)
+ return -ENOMEM;
+ request = tape_alloc_request(2, sizeof(*order));
+ if (IS_ERR(request)) {
+ rc = PTR_ERR(request);
+ goto fail_malloc;
+ }
+ order = request->cpdata;
+ memset(order,0,sizeof(*order));
+ order->code = 0xe2;
+ order->max_count = 2;
+ request->op = TO_KEKL_QUERY;
+ tape_ccw_cc(request->cpaddr, PERF_SUBSYS_FUNC, sizeof(*order), order);
+ tape_ccw_end(request->cpaddr + 1, READ_SS_DATA, sizeof(*int_kekls),
+ int_kekls);
+ rc = tape_do_io(device, request);
+ if (rc)
+ goto fail_request;
+ int_to_ext_kekl_pair(&int_kekls->kekls, ext_kekls);
+
+ rc = 0;
+fail_request:
+ tape_free_request(request);
+fail_malloc:
+ kfree(int_kekls);
+ return rc;
+}
+
+/*
+ * IOCTL: Query KEKLs
+ */
+static int tape_3592_ioctl_kekl_query(struct tape_device *device,
+ unsigned long arg)
+{
+ int rc;
+ struct tape390_kekl_pair *ext_kekls;
+
+ DBF_EVENT(6, "tape_3592_ioctl_kekl_query\n");
+ if (!crypt_supported(device))
+ return -ENOSYS;
+ if (!crypt_enabled(device))
+ return -EUNATCH;
+ ext_kekls = kmalloc(sizeof(*ext_kekls), GFP_KERNEL);
+ if (!ext_kekls)
+ return -ENOMEM;
+ rc = tape_3592_kekl_query(device, ext_kekls);
+ if (rc != 0)
+ goto fail;
+ if (copy_to_user((char __user *) arg, ext_kekls, sizeof(*ext_kekls))) {
+ rc = -EFAULT;
+ goto fail;
+ }
+ rc = 0;
+fail:
+ kfree(ext_kekls);
+ return rc;
+}
+
+static int tape_3590_mttell(struct tape_device *device, int mt_count);
+
+/*
+ * Set KEKLs
+ */
+static int tape_3592_kekl_set(struct tape_device *device,
+ struct tape390_kekl_pair *ext_kekls)
+{
+ struct tape_request *request;
+ struct tape3592_kekl_set_order *order;
+
+ DBF_EVENT(6, "tape3592_kekl_set\n");
+ if (check_ext_kekl_pair(ext_kekls)) {
+ DBF_EVENT(6, "invalid kekls\n");
+ return -EINVAL;
+ }
+ if (tape_3590_mttell(device, 0) != 0)
+ return -EBADSLT;
+ request = tape_alloc_request(1, sizeof(*order));
+ if (IS_ERR(request))
+ return PTR_ERR(request);
+ order = request->cpdata;
+ memset(order, 0, sizeof(*order));
+ order->code = 0xe3;
+ order->kekls.count = 2;
+ ext_to_int_kekl(&ext_kekls->kekl[0], &order->kekls.kekl[0]);
+ ext_to_int_kekl(&ext_kekls->kekl[1], &order->kekls.kekl[1]);
+ request->op = TO_KEKL_SET;
+ tape_ccw_end(request->cpaddr, PERF_SUBSYS_FUNC, sizeof(*order), order);
+
+ return tape_do_io_free(device, request);
+}
+
+/*
+ * IOCTL: Set KEKLs
+ */
+static int tape_3592_ioctl_kekl_set(struct tape_device *device,
+ unsigned long arg)
+{
+ int rc;
+ struct tape390_kekl_pair *ext_kekls;
+
+ DBF_EVENT(6, "tape_3592_ioctl_kekl_set\n");
+ if (!crypt_supported(device))
+ return -ENOSYS;
+ if (!crypt_enabled(device))
+ return -EUNATCH;
+ ext_kekls = kmalloc(sizeof(*ext_kekls), GFP_KERNEL);
+ if (!ext_kekls)
+ return -ENOMEM;
+ if (copy_from_user(ext_kekls, (char __user *)arg, sizeof(*ext_kekls))) {
+ rc = -EFAULT;
+ goto out;
+ }
+ rc = tape_3592_kekl_set(device, ext_kekls);
+out:
+ kfree(ext_kekls);
+ return rc;
+}
+
+/*
+ * Enable encryption
+ */
+static int tape_3592_enable_crypt(struct tape_device *device)
+{
+ struct tape_request *request;
+ char *data;
+
+ DBF_EVENT(6, "tape_3592_enable_crypt\n");
+ if (!crypt_supported(device))
+ return -ENOSYS;
+ request = tape_alloc_request(2, 72);
+ if (IS_ERR(request))
+ return PTR_ERR(request);
+ data = request->cpdata;
+ memset(data,0,72);
+
+ data[0] = 0x05;
+ data[36 + 0] = 0x03;
+ data[36 + 1] = 0x03;
+ data[36 + 4] = 0x40;
+ data[36 + 6] = 0x01;
+ data[36 + 14] = 0x2f;
+ data[36 + 18] = 0xc3;
+ data[36 + 35] = 0x72;
+ request->op = TO_CRYPT_ON;
+ tape_ccw_cc(request->cpaddr, MODE_SET_CB, 36, data);
+ tape_ccw_end(request->cpaddr + 1, MODE_SET_CB, 36, data + 36);
+ return tape_do_io_free(device, request);
+}
+
+/*
+ * Disable encryption
+ */
+static int tape_3592_disable_crypt(struct tape_device *device)
+{
+ struct tape_request *request;
+ char *data;
+
+ DBF_EVENT(6, "tape_3592_disable_crypt\n");
+ if (!crypt_supported(device))
+ return -ENOSYS;
+ request = tape_alloc_request(2, 72);
+ if (IS_ERR(request))
+ return PTR_ERR(request);
+ data = request->cpdata;
+ memset(data,0,72);
+
+ data[0] = 0x05;
+ data[36 + 0] = 0x03;
+ data[36 + 1] = 0x03;
+ data[36 + 35] = 0x32;
+
+ request->op = TO_CRYPT_OFF;
+ tape_ccw_cc(request->cpaddr, MODE_SET_CB, 36, data);
+ tape_ccw_end(request->cpaddr + 1, MODE_SET_CB, 36, data + 36);
+
+ return tape_do_io_free(device, request);
+}
+
+/*
+ * IOCTL: Set encryption status
+ */
+static int tape_3592_ioctl_crypt_set(struct tape_device *device,
+ unsigned long arg)
+{
+ struct tape390_crypt_info info;
+
+ DBF_EVENT(6, "tape_3592_ioctl_crypt_set\n");
+ if (!crypt_supported(device))
+ return -ENOSYS;
+ if (copy_from_user(&info, (char __user *)arg, sizeof(info)))
+ return -EFAULT;
+ if (info.status & ~TAPE390_CRYPT_ON_MASK)
+ return -EINVAL;
+ if (info.status & TAPE390_CRYPT_ON_MASK)
+ return tape_3592_enable_crypt(device);
+ else
+ return tape_3592_disable_crypt(device);
+}
+
+static int tape_3590_sense_medium(struct tape_device *device);
+
+/*
+ * IOCTL: Query enryption status
+ */
+static int tape_3592_ioctl_crypt_query(struct tape_device *device,
+ unsigned long arg)
+{
+ DBF_EVENT(6, "tape_3592_ioctl_crypt_query\n");
+ if (!crypt_supported(device))
+ return -ENOSYS;
+ tape_3590_sense_medium(device);
+ if (copy_to_user((char __user *) arg, &TAPE_3590_CRYPT_INFO(device),
+ sizeof(TAPE_3590_CRYPT_INFO(device))))
+ return -EFAULT;
+ else
+ return 0;
+}
+
/*
* 3590 IOCTL Overload
*/
@@ -109,6 +436,14 @@ tape_3590_ioctl(struct tape_device *device, unsigned int cmd, unsigned long arg)
return tape_std_display(device, &disp);
}
+ case TAPE390_KEKL_SET:
+ return tape_3592_ioctl_kekl_set(device, arg);
+ case TAPE390_KEKL_QUERY:
+ return tape_3592_ioctl_kekl_query(device, arg);
+ case TAPE390_CRYPT_SET:
+ return tape_3592_ioctl_crypt_set(device, arg);
+ case TAPE390_CRYPT_QUERY:
+ return tape_3592_ioctl_crypt_query(device, arg);
default:
return -EINVAL; /* no additional ioctls */
}
@@ -248,6 +583,12 @@ tape_3590_work_handler(struct work_struct *work)
case TO_READ_ATTMSG:
tape_3590_read_attmsg(p->device);
break;
+ case TO_CRYPT_ON:
+ tape_3592_enable_crypt(p->device);
+ break;
+ case TO_CRYPT_OFF:
+ tape_3592_disable_crypt(p->device);
+ break;
default:
DBF_EVENT(3, "T3590: work handler undefined for "
"operation 0x%02x\n", p->op);
@@ -365,6 +706,33 @@ tape_3590_check_locate(struct tape_device *device, struct tape_request *request)
}
#endif
+static void tape_3590_med_state_set(struct tape_device *device,
+ struct tape_3590_med_sense *sense)
+{
+ struct tape390_crypt_info *c_info;
+
+ c_info = &TAPE_3590_CRYPT_INFO(device);
+
+ if (sense->masst == MSENSE_UNASSOCIATED) {
+ tape_med_state_set(device, MS_UNLOADED);
+ TAPE_3590_CRYPT_INFO(device).medium_status = 0;
+ return;
+ }
+ if (sense->masst != MSENSE_ASSOCIATED_MOUNT) {
+ PRINT_ERR("Unknown medium state: %x\n", sense->masst);
+ return;
+ }
+ tape_med_state_set(device, MS_LOADED);
+ c_info->medium_status |= TAPE390_MEDIUM_LOADED_MASK;
+ if (sense->flags & MSENSE_CRYPT_MASK) {
+ PRINT_INFO("Medium is encrypted (%04x)\n", sense->flags);
+ c_info->medium_status |= TAPE390_MEDIUM_ENCRYPTED_MASK;
+ } else {
+ DBF_EVENT(6, "Medium is not encrypted %04x\n", sense->flags);
+ c_info->medium_status &= ~TAPE390_MEDIUM_ENCRYPTED_MASK;
+ }
+}
+
/*
* The done handler is called at device/channel end and wakes up the sleeping
* process
@@ -372,9 +740,10 @@ tape_3590_check_locate(struct tape_device *device, struct tape_request *request)
static int
tape_3590_done(struct tape_device *device, struct tape_request *request)
{
- struct tape_3590_med_sense *sense;
+ struct tape_3590_disc_data *disc_data;
DBF_EVENT(6, "%s done\n", tape_op_verbose[request->op]);
+ disc_data = device->discdata;
switch (request->op) {
case TO_BSB:
@@ -394,13 +763,20 @@ tape_3590_done(struct tape_device *device, struct tape_request *request)
break;
case TO_RUN:
tape_med_state_set(device, MS_UNLOADED);
+ tape_3590_schedule_work(device, TO_CRYPT_OFF);
break;
case TO_MSEN:
- sense = (struct tape_3590_med_sense *) request->cpdata;
- if (sense->masst == MSENSE_UNASSOCIATED)
- tape_med_state_set(device, MS_UNLOADED);
- if (sense->masst == MSENSE_ASSOCIATED_MOUNT)
- tape_med_state_set(device, MS_LOADED);
+ tape_3590_med_state_set(device, request->cpdata);
+ break;
+ case TO_CRYPT_ON:
+ TAPE_3590_CRYPT_INFO(device).status
+ |= TAPE390_CRYPT_ON_MASK;
+ *(device->modeset_byte) |= 0x03;
+ break;
+ case TO_CRYPT_OFF:
+ TAPE_3590_CRYPT_INFO(device).status
+ &= ~TAPE390_CRYPT_ON_MASK;
+ *(device->modeset_byte) &= ~0x03;
break;
case TO_RBI: /* RBI seems to succeed even without medium loaded. */
case TO_NOP: /* Same to NOP. */
@@ -409,8 +785,9 @@ tape_3590_done(struct tape_device *device, struct tape_request *request)
case TO_DIS:
case TO_ASSIGN:
case TO_UNASSIGN:
- break;
case TO_SIZE:
+ case TO_KEKL_SET:
+ case TO_KEKL_QUERY:
break;
}
return TAPE_IO_SUCCESS;
@@ -540,10 +917,8 @@ static int
tape_3590_erp_long_busy(struct tape_device *device,
struct tape_request *request, struct irb *irb)
{
- /* FIXME: how about WAITING for a minute ? */
- PRINT_WARN("(%s): Device is busy! Please wait a minute!\n",
- device->cdev->dev.bus_id);
- return tape_3590_erp_basic(device, request, irb, -EBUSY);
+ DBF_EVENT(6, "Device is busy\n");
+ return TAPE_IO_LONG_BUSY;
}
/*
@@ -951,6 +1326,34 @@ tape_3590_print_era_msg(struct tape_device *device, struct irb *irb)
device->cdev->dev.bus_id, sense->mc);
}
+static int tape_3590_crypt_error(struct tape_device *device,
+ struct tape_request *request, struct irb *irb)
+{
+ u8 cu_rc, ekm_rc1;
+ u16 ekm_rc2;
+ u32 drv_rc;
+ char *bus_id, *sense;
+
+ sense = ((struct tape_3590_sense *) irb->ecw)->fmt.data;
+ bus_id = device->cdev->dev.bus_id;
+ cu_rc = sense[0];
+ drv_rc = *((u32*) &sense[5]) & 0xffffff;
+ ekm_rc1 = sense[9];
+ ekm_rc2 = *((u16*) &sense[10]);
+ if ((cu_rc == 0) && (ekm_rc2 == 0xee31))
+ /* key not defined on EKM */
+ return tape_3590_erp_basic(device, request, irb, -EKEYREJECTED);
+ if ((cu_rc == 1) || (cu_rc == 2))
+ /* No connection to EKM */
+ return tape_3590_erp_basic(device, request, irb, -ENOTCONN);
+
+ PRINT_ERR("(%s): Unable to get encryption key from EKM\n", bus_id);
+ PRINT_ERR("(%s): CU=%02X DRIVE=%06X EKM=%02X:%04X\n", bus_id, cu_rc,
+ drv_rc, ekm_rc1, ekm_rc2);
+
+ return tape_3590_erp_basic(device, request, irb, -ENOKEY);
+}
+
/*
* 3590 error Recovery routine:
* If possible, it tries to recover from the error. If this is not possible,
@@ -979,6 +1382,8 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,
sense = (struct tape_3590_sense *) irb->ecw;
+ DBF_EVENT(6, "Unit Check: RQC = %x\n", sense->rc_rqc);
+
/*
* First check all RC-QRCs where we want to do something special
* - "break": basic error recovery is done
@@ -999,6 +1404,8 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,
case 0x2231:
tape_3590_print_era_msg(device, irb);
return tape_3590_erp_special_interrupt(device, request, irb);
+ case 0x2240:
+ return tape_3590_crypt_error(device, request, irb);
case 0x3010:
DBF_EVENT(2, "(%08x): Backward at Beginning of Partition\n",
@@ -1020,6 +1427,7 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,
DBF_EVENT(2, "(%08x): Rewind Unload complete\n",
device->cdev_id);
tape_med_state_set(device, MS_UNLOADED);
+ tape_3590_schedule_work(device, TO_CRYPT_OFF);
return tape_3590_erp_basic(device, request, irb, 0);
case 0x4010:
@@ -1030,9 +1438,15 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,
PRINT_WARN("(%s): Tape operation when medium not loaded\n",
device->cdev->dev.bus_id);
tape_med_state_set(device, MS_UNLOADED);
+ tape_3590_schedule_work(device, TO_CRYPT_OFF);
return tape_3590_erp_basic(device, request, irb, -ENOMEDIUM);
case 0x4012: /* Device Long Busy */
+ /* XXX: Also use long busy handling here? */
+ DBF_EVENT(6, "(%08x): LONG BUSY\n", device->cdev_id);
tape_3590_print_era_msg(device, irb);
+ return tape_3590_erp_basic(device, request, irb, -EBUSY);
+ case 0x4014:
+ DBF_EVENT(6, "(%08x): Crypto LONG BUSY\n", device->cdev_id);
return tape_3590_erp_long_busy(device, request, irb);
case 0x5010:
@@ -1064,6 +1478,7 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,
case 0x5120:
case 0x1120:
tape_med_state_set(device, MS_UNLOADED);
+ tape_3590_schedule_work(device, TO_CRYPT_OFF);
return tape_3590_erp_basic(device, request, irb, -ENOMEDIUM);
case 0x6020:
@@ -1142,21 +1557,47 @@ tape_3590_setup_device(struct tape_device *device)
{
int rc;
struct tape_3590_disc_data *data;
+ char *rdc_data;
DBF_EVENT(6, "3590 device setup\n");
- data = kmalloc(sizeof(struct tape_3590_disc_data),
- GFP_KERNEL | GFP_DMA);
+ data = kzalloc(sizeof(struct tape_3590_disc_data), GFP_KERNEL | GFP_DMA);
if (data == NULL)
return -ENOMEM;
data->read_back_op = READ_PREVIOUS;
device->discdata = data;
- if ((rc = tape_std_assign(device)) == 0) {
- /* Try to find out if medium is loaded */
- if ((rc = tape_3590_sense_medium(device)) != 0)
- DBF_LH(3, "3590 medium sense returned %d\n", rc);
+ rdc_data = kmalloc(64, GFP_KERNEL | GFP_DMA);
+ if (!rdc_data) {
+ rc = -ENOMEM;
+ goto fail_kmalloc;
+ }
+ rc = read_dev_chars(device->cdev, (void**)&rdc_data, 64);
+ if (rc) {
+ DBF_LH(3, "Read device characteristics failed!\n");
+ goto fail_kmalloc;
+ }
+ rc = tape_std_assign(device);
+ if (rc)
+ goto fail_rdc_data;
+ if (rdc_data[31] == 0x13) {
+ PRINT_INFO("Device has crypto support\n");
+ data->crypt_info.capability |= TAPE390_CRYPT_SUPPORTED_MASK;
+ tape_3592_disable_crypt(device);
+ } else {
+ DBF_EVENT(6, "Device has NO crypto support\n");
}
+ /* Try to find out if medium is loaded */
+ rc = tape_3590_sense_medium(device);
+ if (rc) {
+ DBF_LH(3, "3590 medium sense returned %d\n", rc);
+ goto fail_rdc_data;
+ }
+ return 0;
+fail_rdc_data:
+ kfree(rdc_data);
+fail_kmalloc:
+ kfree(data);
return rc;
}
diff --git a/drivers/s390/char/tape_3590.h b/drivers/s390/char/tape_3590.h
index cf274b9445a..aa5138807af 100644
--- a/drivers/s390/char/tape_3590.h
+++ b/drivers/s390/char/tape_3590.h
@@ -2,7 +2,7 @@
* drivers/s390/char/tape_3590.h
* tape device discipline for 3590 tapes.
*
- * Copyright (C) IBM Corp. 2001,2006
+ * Copyright IBM Corp. 2001,2006
* Author(s): Stefan Bader <shbader@de.ibm.com>
* Michael Holzheu <holzheu@de.ibm.com>
* Martin Schwidefsky <schwidefsky@de.ibm.com>
@@ -38,16 +38,22 @@
#define MSENSE_UNASSOCIATED 0x00
#define MSENSE_ASSOCIATED_MOUNT 0x01
#define MSENSE_ASSOCIATED_UMOUNT 0x02
+#define MSENSE_CRYPT_MASK 0x00000010
#define TAPE_3590_MAX_MSG 0xb0
/* Datatypes */
struct tape_3590_disc_data {
- unsigned char modeset_byte;
+ struct tape390_crypt_info crypt_info;
int read_back_op;
};
+#define TAPE_3590_CRYPT_INFO(device) \
+ ((struct tape_3590_disc_data*)(device->discdata))->crypt_info
+#define TAPE_3590_READ_BACK_OP(device) \
+ ((struct tape_3590_disc_data*)(device->discdata))->read_back_op
+
struct tape_3590_sense {
unsigned int command_rej:1;
@@ -118,7 +124,48 @@ struct tape_3590_sense {
struct tape_3590_med_sense {
unsigned int macst:4;
unsigned int masst:4;
- char pad[127];
+ char pad1[7];
+ unsigned int flags;
+ char pad2[116];
+} __attribute__ ((packed));
+
+/* Datastructures for 3592 encryption support */
+
+struct tape3592_kekl {
+ __u8 flags;
+ char label[64];
+} __attribute__ ((packed));
+
+struct tape3592_kekl_pair {
+ __u8 count;
+ struct tape3592_kekl kekl[2];
+} __attribute__ ((packed));
+
+struct tape3592_kekl_query_data {
+ __u16 len;
+ __u8 fmt;
+ __u8 mc;
+ __u32 id;
+ __u8 flags;
+ struct tape3592_kekl_pair kekls;
+ char reserved[116];
+} __attribute__ ((packed));
+
+struct tape3592_kekl_query_order {
+ __u8 code;
+ __u8 flags;
+ char reserved1[2];
+ __u8 max_count;
+ char reserved2[35];
+} __attribute__ ((packed));
+
+struct tape3592_kekl_set_order {
+ __u8 code;
+ __u8 flags;
+ char reserved1[2];
+ __u8 op;
+ struct tape3592_kekl_pair kekls;
+ char reserved2[120];
} __attribute__ ((packed));
#endif /* _TAPE_3590_H */
diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c
index c8a89b3b87d..dd0ecaed592 100644
--- a/drivers/s390/char/tape_block.c
+++ b/drivers/s390/char/tape_block.c
@@ -73,7 +73,7 @@ tapeblock_trigger_requeue(struct tape_device *device)
/*
* Post finished request.
*/
-static inline void
+static void
tapeblock_end_request(struct request *req, int uptodate)
{
if (end_that_request_first(req, uptodate, req->hard_nr_sectors))
@@ -108,7 +108,7 @@ __tapeblock_end_request(struct tape_request *ccw_req, void *data)
/*
* Feed the tape device CCW queue with requests supplied in a list.
*/
-static inline int
+static int
tapeblock_start_request(struct tape_device *device, struct request *req)
{
struct tape_request * ccw_req;
diff --git a/drivers/s390/char/tape_char.c b/drivers/s390/char/tape_char.c
index 31198c8f271..9faea04e11e 100644
--- a/drivers/s390/char/tape_char.c
+++ b/drivers/s390/char/tape_char.c
@@ -3,7 +3,7 @@
* character device frontend for tape device driver
*
* S390 and zSeries version
- * Copyright (C) 2001,2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright IBM Corp. 2001,2006
* Author(s): Carsten Otte <cotte@de.ibm.com>
* Michael Holzheu <holzheu@de.ibm.com>
* Tuan Ngo-Anh <ngoanh@de.ibm.com>
@@ -89,22 +89,7 @@ tapechar_cleanup_device(struct tape_device *device)
device->nt = NULL;
}
-/*
- * Terminate write command (we write two TMs and skip backward over last)
- * This ensures that the tape is always correctly terminated.
- * When the user writes afterwards a new file, he will overwrite the
- * second TM and therefore one TM will remain to separate the
- * two files on the tape...
- */
-static inline void
-tapechar_terminate_write(struct tape_device *device)
-{
- if (tape_mtop(device, MTWEOF, 1) == 0 &&
- tape_mtop(device, MTWEOF, 1) == 0)
- tape_mtop(device, MTBSR, 1);
-}
-
-static inline int
+static int
tapechar_check_idalbuffer(struct tape_device *device, size_t block_size)
{
struct idal_buffer *new;
@@ -137,7 +122,7 @@ tapechar_check_idalbuffer(struct tape_device *device, size_t block_size)
/*
* Tape device read function
*/
-ssize_t
+static ssize_t
tapechar_read(struct file *filp, char __user *data, size_t count, loff_t *ppos)
{
struct tape_device *device;
@@ -201,7 +186,7 @@ tapechar_read(struct file *filp, char __user *data, size_t count, loff_t *ppos)
/*
* Tape device write function
*/
-ssize_t
+static ssize_t
tapechar_write(struct file *filp, const char __user *data, size_t count, loff_t *ppos)
{
struct tape_device *device;
@@ -291,7 +276,7 @@ tapechar_write(struct file *filp, const char __user *data, size_t count, loff_t
/*
* Character frontend tape device open function.
*/
-int
+static int
tapechar_open (struct inode *inode, struct file *filp)
{
struct tape_device *device;
@@ -326,7 +311,7 @@ tapechar_open (struct inode *inode, struct file *filp)
* Character frontend tape device release function.
*/
-int
+static int
tapechar_release(struct inode *inode, struct file *filp)
{
struct tape_device *device;
diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c
index c6c2e918b99..e2a8a1a04ba 100644
--- a/drivers/s390/char/tape_core.c
+++ b/drivers/s390/char/tape_core.c
@@ -3,7 +3,7 @@
* basic function of the tape device driver
*
* S390 and zSeries version
- * Copyright (C) 2001,2005 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright IBM Corp. 2001,2006
* Author(s): Carsten Otte <cotte@de.ibm.com>
* Michael Holzheu <holzheu@de.ibm.com>
* Tuan Ngo-Anh <ngoanh@de.ibm.com>
@@ -26,9 +26,11 @@
#include "tape_std.h"
#define PRINTK_HEADER "TAPE_CORE: "
+#define LONG_BUSY_TIMEOUT 180 /* seconds */
static void __tape_do_irq (struct ccw_device *, unsigned long, struct irb *);
static void tape_delayed_next_request(struct work_struct *);
+static void tape_long_busy_timeout(unsigned long data);
/*
* One list to contain all tape devices of all disciplines, so
@@ -69,10 +71,12 @@ const char *tape_op_verbose[TO_SIZE] =
[TO_LOAD] = "LOA", [TO_READ_CONFIG] = "RCF",
[TO_READ_ATTMSG] = "RAT",
[TO_DIS] = "DIS", [TO_ASSIGN] = "ASS",
- [TO_UNASSIGN] = "UAS"
+ [TO_UNASSIGN] = "UAS", [TO_CRYPT_ON] = "CON",
+ [TO_CRYPT_OFF] = "COF", [TO_KEKL_SET] = "KLS",
+ [TO_KEKL_QUERY] = "KLQ",
};
-static inline int
+static int
busid_to_int(char *bus_id)
{
int dec;
@@ -252,7 +256,7 @@ tape_med_state_set(struct tape_device *device, enum tape_medium_state newstate)
/*
* Stop running ccw. Has to be called with the device lock held.
*/
-static inline int
+static int
__tape_cancel_io(struct tape_device *device, struct tape_request *request)
{
int retries;
@@ -346,6 +350,9 @@ tape_generic_online(struct tape_device *device,
return -EINVAL;
}
+ init_timer(&device->lb_timeout);
+ device->lb_timeout.function = tape_long_busy_timeout;
+
/* Let the discipline have a go at the device. */
device->discipline = discipline;
if (!try_module_get(discipline->owner)) {
@@ -385,7 +392,7 @@ out:
return rc;
}
-static inline void
+static void
tape_cleanup_device(struct tape_device *device)
{
tapeblock_cleanup_device(device);
@@ -563,7 +570,7 @@ tape_generic_probe(struct ccw_device *cdev)
return ret;
}
-static inline void
+static void
__tape_discard_requests(struct tape_device *device)
{
struct tape_request * request;
@@ -703,7 +710,7 @@ tape_free_request (struct tape_request * request)
kfree(request);
}
-static inline int
+static int
__tape_start_io(struct tape_device *device, struct tape_request *request)
{
int rc;
@@ -733,7 +740,7 @@ __tape_start_io(struct tape_device *device, struct tape_request *request)
return rc;
}
-static inline void
+static void
__tape_start_next_request(struct tape_device *device)
{
struct list_head *l, *n;
@@ -801,7 +808,23 @@ tape_delayed_next_request(struct work_struct *work)
spin_unlock_irq(get_ccwdev_lock(device->cdev));
}
-static inline void
+static void tape_long_busy_timeout(unsigned long data)
+{
+ struct tape_request *request;
+ struct tape_device *device;
+
+ device = (struct tape_device *) data;
+ spin_lock_irq(get_ccwdev_lock(device->cdev));
+ request = list_entry(device->req_queue.next, struct tape_request, list);
+ if (request->status != TAPE_REQUEST_LONG_BUSY)
+ BUG();
+ DBF_LH(6, "%08x: Long busy timeout.\n", device->cdev_id);
+ __tape_start_next_request(device);
+ device->lb_timeout.data = (unsigned long) tape_put_device(device);
+ spin_unlock_irq(get_ccwdev_lock(device->cdev));
+}
+
+static void
__tape_end_request(
struct tape_device * device,
struct tape_request * request,
@@ -878,7 +901,7 @@ tape_dump_sense_dbf(struct tape_device *device, struct tape_request *request,
* and starts it if the tape is idle. Has to be called with
* the device lock held.
*/
-static inline int
+static int
__tape_start_request(struct tape_device *device, struct tape_request *request)
{
int rc;
@@ -1094,7 +1117,22 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
/* May be an unsolicited irq */
if(request != NULL)
request->rescnt = irb->scsw.count;
-
+ else if ((irb->scsw.dstat == 0x85 || irb->scsw.dstat == 0x80) &&
+ !list_empty(&device->req_queue)) {
+ /* Not Ready to Ready after long busy ? */
+ struct tape_request *req;
+ req = list_entry(device->req_queue.next,
+ struct tape_request, list);
+ if (req->status == TAPE_REQUEST_LONG_BUSY) {
+ DBF_EVENT(3, "(%08x): del timer\n", device->cdev_id);
+ if (del_timer(&device->lb_timeout)) {
+ device->lb_timeout.data = (unsigned long)
+ tape_put_device(device);
+ __tape_start_next_request(device);
+ }
+ return;
+ }
+ }
if (irb->scsw.dstat != 0x0c) {
/* Set the 'ONLINE' flag depending on sense byte 1 */
if(*(((__u8 *) irb->ecw) + 1) & SENSE_DRIVE_ONLINE)
@@ -1142,6 +1180,15 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
break;
case TAPE_IO_PENDING:
break;
+ case TAPE_IO_LONG_BUSY:
+ device->lb_timeout.data =
+ (unsigned long)tape_get_device_reference(device);
+ device->lb_timeout.expires = jiffies +
+ LONG_BUSY_TIMEOUT * HZ;
+ DBF_EVENT(3, "(%08x): add timer\n", device->cdev_id);
+ add_timer(&device->lb_timeout);
+ request->status = TAPE_REQUEST_LONG_BUSY;
+ break;
case TAPE_IO_RETRY:
rc = __tape_start_io(device, request);
if (rc)
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
index 09844621edc..bc33068b9ce 100644
--- a/drivers/s390/char/tty3270.c
+++ b/drivers/s390/char/tty3270.c
@@ -36,7 +36,7 @@
struct tty_driver *tty3270_driver;
static int tty3270_max_index;
-struct raw3270_fn tty3270_fn;
+static struct raw3270_fn tty3270_fn;
struct tty3270_cell {
unsigned char character;
@@ -119,8 +119,7 @@ static void tty3270_update(struct tty3270 *);
/*
* Setup timeout for a device. On timeout trigger an update.
*/
-void
-tty3270_set_timer(struct tty3270 *tp, int expires)
+static void tty3270_set_timer(struct tty3270 *tp, int expires)
{
if (expires == 0) {
if (timer_pending(&tp->timer) && del_timer(&tp->timer))
@@ -841,7 +840,7 @@ tty3270_del_views(void)
}
}
-struct raw3270_fn tty3270_fn = {
+static struct raw3270_fn tty3270_fn = {
.activate = tty3270_activate,
.deactivate = tty3270_deactivate,
.intv = (void *) tty3270_irq,
@@ -1754,8 +1753,7 @@ static const struct tty_operations tty3270_ops = {
.set_termios = tty3270_set_termios
};
-void
-tty3270_notifier(int index, int active)
+static void tty3270_notifier(int index, int active)
{
if (active)
tty_register_device(tty3270_driver, index, NULL);
@@ -1767,8 +1765,7 @@ tty3270_notifier(int index, int active)
* 3270 tty registration code called from tty_init().
* Most kernel services (incl. kmalloc) are available at this poimt.
*/
-int __init
-tty3270_init(void)
+static int __init tty3270_init(void)
{
struct tty_driver *driver;
int ret;
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c
index 6cb23040954..8432a76b961 100644
--- a/drivers/s390/char/vmlogrdr.c
+++ b/drivers/s390/char/vmlogrdr.c
@@ -3,7 +3,7 @@
* character device driver for reading z/VM system service records
*
*
- * Copyright (C) 2004 IBM Corporation
+ * Copyright 2004 IBM Corporation
* character device driver for reading z/VM system service records,
* Version 1.0
* Author(s): Xenia Tkatschow <xenia@us.ibm.com>
@@ -21,7 +21,7 @@
#include <asm/cpcmd.h>
#include <asm/debug.h>
#include <asm/ebcdic.h>
-#include "../net/iucv.h"
+#include <net/iucv/iucv.h>
#include <linux/kmod.h>
#include <linux/cdev.h>
#include <linux/device.h>
@@ -60,12 +60,11 @@ struct vmlogrdr_priv_t {
char system_service[8];
char internal_name[8];
char recording_name[8];
- u16 pathid;
+ struct iucv_path *path;
int connection_established;
int iucv_path_severed;
- iucv_MessagePending local_interrupt_buffer;
+ struct iucv_message local_interrupt_buffer;
atomic_t receive_ready;
- iucv_handle_t iucv_handle;
int minor_num;
char * buffer;
char * current_position;
@@ -97,40 +96,21 @@ static struct file_operations vmlogrdr_fops = {
};
-static u8 iucvMagic[16] = {
- 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
- 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40
-};
+static void vmlogrdr_iucv_path_complete(struct iucv_path *, u8 ipuser[16]);
+static void vmlogrdr_iucv_path_severed(struct iucv_path *, u8 ipuser[16]);
+static void vmlogrdr_iucv_message_pending(struct iucv_path *,
+ struct iucv_message *);
-static u8 mask[] = {
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+static struct iucv_handler vmlogrdr_iucv_handler = {
+ .path_complete = vmlogrdr_iucv_path_complete,
+ .path_severed = vmlogrdr_iucv_path_severed,
+ .message_pending = vmlogrdr_iucv_message_pending,
};
-static u8 iucv_host[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-
-
-static void
-vmlogrdr_iucv_ConnectionComplete(iucv_ConnectionComplete *eib, void *pgm_data);
-static void
-vmlogrdr_iucv_ConnectionSevered(iucv_ConnectionSevered *eib, void *pgm_data);
-static void
-vmlogrdr_iucv_MessagePending(iucv_MessagePending *eib, void *pgm_data);
-
-
-static iucv_interrupt_ops_t vmlogrdr_iucvops = {
- .ConnectionComplete = vmlogrdr_iucv_ConnectionComplete,
- .ConnectionSevered = vmlogrdr_iucv_ConnectionSevered,
- .MessagePending = vmlogrdr_iucv_MessagePending,
-};
-
-
-DECLARE_WAIT_QUEUE_HEAD(conn_wait_queue);
-DECLARE_WAIT_QUEUE_HEAD(read_wait_queue);
+static DECLARE_WAIT_QUEUE_HEAD(conn_wait_queue);
+static DECLARE_WAIT_QUEUE_HEAD(read_wait_queue);
/*
* pointer to system service private structure
@@ -177,28 +157,29 @@ static struct cdev *vmlogrdr_cdev = NULL;
static int recording_class_AB;
-static void
-vmlogrdr_iucv_ConnectionComplete (iucv_ConnectionComplete * eib,
- void * pgm_data)
+static void vmlogrdr_iucv_path_complete(struct iucv_path *path, u8 ipuser[16])
{
- struct vmlogrdr_priv_t * logptr = pgm_data;
+ struct vmlogrdr_priv_t * logptr = path->private;
+
spin_lock(&logptr->priv_lock);
logptr->connection_established = 1;
spin_unlock(&logptr->priv_lock);
wake_up(&conn_wait_queue);
- return;
}
-static void
-vmlogrdr_iucv_ConnectionSevered (iucv_ConnectionSevered * eib, void * pgm_data)
+static void vmlogrdr_iucv_path_severed(struct iucv_path *path, u8 ipuser[16])
{
- u8 reason = (u8) eib->ipuser[8];
- struct vmlogrdr_priv_t * logptr = pgm_data;
+ struct vmlogrdr_priv_t * logptr = path->private;
+ u8 reason = (u8) ipuser[8];
printk (KERN_ERR "vmlogrdr: connection severed with"
" reason %i\n", reason);
+ iucv_path_sever(path, NULL);
+ kfree(path);
+ logptr->path = NULL;
+
spin_lock(&logptr->priv_lock);
logptr->connection_established = 0;
logptr->iucv_path_severed = 1;
@@ -210,10 +191,10 @@ vmlogrdr_iucv_ConnectionSevered (iucv_ConnectionSevered * eib, void * pgm_data)
}
-static void
-vmlogrdr_iucv_MessagePending (iucv_MessagePending * eib, void * pgm_data)
+static void vmlogrdr_iucv_message_pending(struct iucv_path *path,
+ struct iucv_message *msg)
{
- struct vmlogrdr_priv_t * logptr = pgm_data;
+ struct vmlogrdr_priv_t * logptr = path->private;
/*
* This function is the bottom half so it should be quick.
@@ -221,15 +202,15 @@ vmlogrdr_iucv_MessagePending (iucv_MessagePending * eib, void * pgm_data)
* the usage count
*/
spin_lock(&logptr->priv_lock);
- memcpy(&(logptr->local_interrupt_buffer), eib, sizeof(*eib));
+ memcpy(&logptr->local_interrupt_buffer, msg, sizeof(*msg));
atomic_inc(&logptr->receive_ready);
spin_unlock(&logptr->priv_lock);
wake_up_interruptible(&read_wait_queue);
}
-static int
-vmlogrdr_get_recording_class_AB(void) {
+static int vmlogrdr_get_recording_class_AB(void)
+{
char cp_command[]="QUERY COMMAND RECORDING ";
char cp_response[80];
char *tail;
@@ -259,8 +240,9 @@ vmlogrdr_get_recording_class_AB(void) {
}
-static int
-vmlogrdr_recording(struct vmlogrdr_priv_t * logptr, int action, int purge) {
+static int vmlogrdr_recording(struct vmlogrdr_priv_t * logptr,
+ int action, int purge)
+{
char cp_command[80];
char cp_response[160];
@@ -318,8 +300,7 @@ vmlogrdr_recording(struct vmlogrdr_priv_t * logptr, int action, int purge) {
}
-static int
-vmlogrdr_open (struct inode *inode, struct file *filp)
+static int vmlogrdr_open (struct inode *inode, struct file *filp)
{
int dev_num = 0;
struct vmlogrdr_priv_t * logptr = NULL;
@@ -329,10 +310,7 @@ vmlogrdr_open (struct inode *inode, struct file *filp)
dev_num = iminor(inode);
if (dev_num > MAXMINOR)
return -ENODEV;
-
logptr = &sys_ser[dev_num];
- if (logptr == NULL)
- return -ENODEV;
/*
* only allow for blocking reads to be open
@@ -345,52 +323,38 @@ vmlogrdr_open (struct inode *inode, struct file *filp)
if (logptr->dev_in_use) {
spin_unlock_bh(&logptr->priv_lock);
return -EBUSY;
- } else {
- logptr->dev_in_use = 1;
- spin_unlock_bh(&logptr->priv_lock);
}
-
+ logptr->dev_in_use = 1;
+ logptr->connection_established = 0;
+ logptr->iucv_path_severed = 0;
atomic_set(&logptr->receive_ready, 0);
logptr->buffer_free = 1;
+ spin_unlock_bh(&logptr->priv_lock);
/* set the file options */
filp->private_data = logptr;
filp->f_op = &vmlogrdr_fops;
/* start recording for this service*/
- ret=0;
- if (logptr->autorecording)
+ if (logptr->autorecording) {
ret = vmlogrdr_recording(logptr,1,logptr->autopurge);
- if (ret)
- printk (KERN_WARNING "vmlogrdr: failed to start "
- "recording automatically\n");
-
- /* Register with iucv driver */
- logptr->iucv_handle = iucv_register_program(iucvMagic,
- logptr->system_service, mask, &vmlogrdr_iucvops,
- logptr);
-
- if (logptr->iucv_handle == NULL) {
- printk (KERN_ERR "vmlogrdr: failed to register with"
- "iucv driver\n");
- goto not_registered;
+ if (ret)
+ printk (KERN_WARNING "vmlogrdr: failed to start "
+ "recording automatically\n");
}
/* create connection to the system service */
- spin_lock_bh(&logptr->priv_lock);
- logptr->connection_established = 0;
- logptr->iucv_path_severed = 0;
- spin_unlock_bh(&logptr->priv_lock);
-
- connect_rc = iucv_connect (&(logptr->pathid), 10, iucvMagic,
- logptr->system_service, iucv_host, 0,
- NULL, NULL,
- logptr->iucv_handle, NULL);
+ logptr->path = iucv_path_alloc(10, 0, GFP_KERNEL);
+ if (!logptr->path)
+ goto out_dev;
+ connect_rc = iucv_path_connect(logptr->path, &vmlogrdr_iucv_handler,
+ logptr->system_service, NULL, NULL,
+ logptr);
if (connect_rc) {
printk (KERN_ERR "vmlogrdr: iucv connection to %s "
"failed with rc %i \n", logptr->system_service,
connect_rc);
- goto not_connected;
+ goto out_path;
}
/* We've issued the connect and now we must wait for a
@@ -399,35 +363,28 @@ vmlogrdr_open (struct inode *inode, struct file *filp)
*/
wait_event(conn_wait_queue, (logptr->connection_established)
|| (logptr->iucv_path_severed));
- if (logptr->iucv_path_severed) {
- goto not_connected;
- }
-
+ if (logptr->iucv_path_severed)
+ goto out_record;
return nonseekable_open(inode, filp);
-not_connected:
- iucv_unregister_program(logptr->iucv_handle);
- logptr->iucv_handle = NULL;
-not_registered:
+out_record:
if (logptr->autorecording)
vmlogrdr_recording(logptr,0,logptr->autopurge);
+out_path:
+ kfree(logptr->path); /* kfree(NULL) is ok. */
+ logptr->path = NULL;
+out_dev:
logptr->dev_in_use = 0;
return -EIO;
-
-
}
-static int
-vmlogrdr_release (struct inode *inode, struct file *filp)
+static int vmlogrdr_release (struct inode *inode, struct file *filp)
{
int ret;
struct vmlogrdr_priv_t * logptr = filp->private_data;
- iucv_unregister_program(logptr->iucv_handle);
- logptr->iucv_handle = NULL;
-
if (logptr->autorecording) {
ret = vmlogrdr_recording(logptr,0,logptr->autopurge);
if (ret)
@@ -440,8 +397,8 @@ vmlogrdr_release (struct inode *inode, struct file *filp)
}
-static int
-vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) {
+static int vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv)
+{
int rc, *temp;
/* we need to keep track of two data sizes here:
* The number of bytes we need to receive from iucv and
@@ -462,8 +419,7 @@ vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) {
* We need to return the total length of the record
* + size of FENCE in the first 4 bytes of the buffer.
*/
- iucv_data_count =
- priv->local_interrupt_buffer.ln1msg2.ipbfln1f;
+ iucv_data_count = priv->local_interrupt_buffer.length;
user_data_count = sizeof(int);
temp = (int*)priv->buffer;
*temp= iucv_data_count + sizeof(FENCE);
@@ -475,14 +431,10 @@ vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) {
*/
if (iucv_data_count > NET_BUFFER_SIZE)
iucv_data_count = NET_BUFFER_SIZE;
- rc = iucv_receive(priv->pathid,
- priv->local_interrupt_buffer.ipmsgid,
- priv->local_interrupt_buffer.iptrgcls,
- buffer,
- iucv_data_count,
- NULL,
- NULL,
- &priv->residual_length);
+ rc = iucv_message_receive(priv->path,
+ &priv->local_interrupt_buffer,
+ 0, buffer, iucv_data_count,
+ &priv->residual_length);
spin_unlock_bh(&priv->priv_lock);
/* An rc of 5 indicates that the record was bigger then
* the buffer, which is OK for us. A 9 indicates that the
@@ -514,8 +466,8 @@ vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) {
}
-static ssize_t
-vmlogrdr_read(struct file *filp, char __user *data, size_t count, loff_t * ppos)
+static ssize_t vmlogrdr_read(struct file *filp, char __user *data,
+ size_t count, loff_t * ppos)
{
int rc;
struct vmlogrdr_priv_t * priv = filp->private_data;
@@ -547,8 +499,10 @@ vmlogrdr_read(struct file *filp, char __user *data, size_t count, loff_t * ppos)
return count;
}
-static ssize_t
-vmlogrdr_autopurge_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) {
+static ssize_t vmlogrdr_autopurge_store(struct device * dev,
+ struct device_attribute *attr,
+ const char * buf, size_t count)
+{
struct vmlogrdr_priv_t *priv = dev->driver_data;
ssize_t ret = count;
@@ -566,8 +520,10 @@ vmlogrdr_autopurge_store(struct device * dev, struct device_attribute *attr, con
}
-static ssize_t
-vmlogrdr_autopurge_show(struct device *dev, struct device_attribute *attr, char *buf) {
+static ssize_t vmlogrdr_autopurge_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
struct vmlogrdr_priv_t *priv = dev->driver_data;
return sprintf(buf, "%u\n", priv->autopurge);
}
@@ -577,8 +533,10 @@ static DEVICE_ATTR(autopurge, 0644, vmlogrdr_autopurge_show,
vmlogrdr_autopurge_store);
-static ssize_t
-vmlogrdr_purge_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) {
+static ssize_t vmlogrdr_purge_store(struct device * dev,
+ struct device_attribute *attr,
+ const char * buf, size_t count)
+{
char cp_command[80];
char cp_response[80];
@@ -618,9 +576,10 @@ vmlogrdr_purge_store(struct device * dev, struct device_attribute *attr, const c
static DEVICE_ATTR(purge, 0200, NULL, vmlogrdr_purge_store);
-static ssize_t
-vmlogrdr_autorecording_store(struct device *dev, struct device_attribute *attr, const char *buf,
- size_t count) {
+static ssize_t vmlogrdr_autorecording_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
struct vmlogrdr_priv_t *priv = dev->driver_data;
ssize_t ret = count;
@@ -638,8 +597,10 @@ vmlogrdr_autorecording_store(struct device *dev, struct device_attribute *attr,
}
-static ssize_t
-vmlogrdr_autorecording_show(struct device *dev, struct device_attribute *attr, char *buf) {
+static ssize_t vmlogrdr_autorecording_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
struct vmlogrdr_priv_t *priv = dev->driver_data;
return sprintf(buf, "%u\n", priv->autorecording);
}
@@ -649,9 +610,10 @@ static DEVICE_ATTR(autorecording, 0644, vmlogrdr_autorecording_show,
vmlogrdr_autorecording_store);
-static ssize_t
-vmlogrdr_recording_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) {
-
+static ssize_t vmlogrdr_recording_store(struct device * dev,
+ struct device_attribute *attr,
+ const char * buf, size_t count)
+{
struct vmlogrdr_priv_t *priv = dev->driver_data;
ssize_t ret;
@@ -676,8 +638,9 @@ vmlogrdr_recording_store(struct device * dev, struct device_attribute *attr, con
static DEVICE_ATTR(recording, 0200, NULL, vmlogrdr_recording_store);
-static ssize_t
-vmlogrdr_recording_status_show(struct device_driver *driver, char *buf) {
+static ssize_t vmlogrdr_recording_status_show(struct device_driver *driver,
+ char *buf)
+{
char cp_command[] = "QUERY RECORDING ";
int len;
@@ -710,52 +673,63 @@ static struct device_driver vmlogrdr_driver = {
};
-static int
-vmlogrdr_register_driver(void) {
+static int vmlogrdr_register_driver(void)
+{
int ret;
+ /* Register with iucv driver */
+ ret = iucv_register(&vmlogrdr_iucv_handler, 1);
+ if (ret) {
+ printk (KERN_ERR "vmlogrdr: failed to register with"
+ "iucv driver\n");
+ goto out;
+ }
+
ret = driver_register(&vmlogrdr_driver);
if (ret) {
printk(KERN_ERR "vmlogrdr: failed to register driver.\n");
- return ret;
+ goto out_iucv;
}
ret = driver_create_file(&vmlogrdr_driver,
&driver_attr_recording_status);
if (ret) {
printk(KERN_ERR "vmlogrdr: failed to add driver attribute.\n");
- goto unregdriver;
+ goto out_driver;
}
vmlogrdr_class = class_create(THIS_MODULE, "vmlogrdr");
if (IS_ERR(vmlogrdr_class)) {
printk(KERN_ERR "vmlogrdr: failed to create class.\n");
- ret=PTR_ERR(vmlogrdr_class);
- vmlogrdr_class=NULL;
- goto unregattr;
+ ret = PTR_ERR(vmlogrdr_class);
+ vmlogrdr_class = NULL;
+ goto out_attr;
}
return 0;
-unregattr:
+out_attr:
driver_remove_file(&vmlogrdr_driver, &driver_attr_recording_status);
-unregdriver:
+out_driver:
driver_unregister(&vmlogrdr_driver);
+out_iucv:
+ iucv_unregister(&vmlogrdr_iucv_handler, 1);
+out:
return ret;
}
-static void
-vmlogrdr_unregister_driver(void) {
+static void vmlogrdr_unregister_driver(void)
+{
class_destroy(vmlogrdr_class);
vmlogrdr_class = NULL;
driver_remove_file(&vmlogrdr_driver, &driver_attr_recording_status);
driver_unregister(&vmlogrdr_driver);
- return;
+ iucv_unregister(&vmlogrdr_iucv_handler, 1);
}
-static int
-vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) {
+static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv)
+{
struct device *dev;
int ret;
@@ -804,9 +778,10 @@ vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) {
}
-static int
-vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv ) {
- class_device_destroy(vmlogrdr_class, MKDEV(vmlogrdr_major, priv->minor_num));
+static int vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv)
+{
+ class_device_destroy(vmlogrdr_class,
+ MKDEV(vmlogrdr_major, priv->minor_num));
if (priv->device != NULL) {
sysfs_remove_group(&priv->device->kobj, &vmlogrdr_attr_group);
device_unregister(priv->device);
@@ -816,8 +791,8 @@ vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv ) {
}
-static int
-vmlogrdr_register_cdev(dev_t dev) {
+static int vmlogrdr_register_cdev(dev_t dev)
+{
int rc = 0;
vmlogrdr_cdev = cdev_alloc();
if (!vmlogrdr_cdev) {
@@ -837,9 +812,10 @@ vmlogrdr_register_cdev(dev_t dev) {
}
-static void
-vmlogrdr_cleanup(void) {
+static void vmlogrdr_cleanup(void)
+{
int i;
+
if (vmlogrdr_cdev) {
cdev_del(vmlogrdr_cdev);
vmlogrdr_cdev=NULL;
@@ -856,8 +832,7 @@ vmlogrdr_cleanup(void) {
}
-static int
-vmlogrdr_init(void)
+static int vmlogrdr_init(void)
{
int rc;
int i;
@@ -907,8 +882,7 @@ cleanup:
}
-static void
-vmlogrdr_exit(void)
+static void vmlogrdr_exit(void)
{
vmlogrdr_cleanup();
printk (KERN_INFO "vmlogrdr: driver unloaded\n");
diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c
index 12c2d6b746e..aa65df4dfce 100644
--- a/drivers/s390/cio/blacklist.c
+++ b/drivers/s390/cio/blacklist.c
@@ -43,7 +43,7 @@ typedef enum {add, free} range_action;
* Function: blacklist_range
* (Un-)blacklist the devices from-to
*/
-static inline void
+static void
blacklist_range (range_action action, unsigned int from, unsigned int to,
unsigned int ssid)
{
@@ -69,7 +69,7 @@ blacklist_range (range_action action, unsigned int from, unsigned int to,
* Get devno/busid from given string.
* Shamelessly grabbed from dasd_devmap.c.
*/
-static inline int
+static int
blacklist_busid(char **str, int *id0, int *ssid, int *devno)
{
int val, old_style;
@@ -123,10 +123,10 @@ confused:
return 1;
}
-static inline int
+static int
blacklist_parse_parameters (char *str, range_action action)
{
- unsigned int from, to, from_id0, to_id0, from_ssid, to_ssid;
+ int from, to, from_id0, to_id0, from_ssid, to_ssid;
while (*str != 0 && *str != '\n') {
range_action ra = action;
@@ -227,7 +227,7 @@ is_blacklisted (int ssid, int devno)
* Function: blacklist_parse_proc_parameters
* parse the stuff which is piped to /proc/cio_ignore
*/
-static inline void
+static void
blacklist_parse_proc_parameters (char *buf)
{
if (strncmp (buf, "free ", 5) == 0) {
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index 38954f5cd14..d48e3ca4752 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -53,7 +53,7 @@ ccwgroup_uevent (struct device *dev, char **envp, int num_envp, char *buffer,
static struct bus_type ccwgroup_bus_type;
-static inline void
+static void
__ccwgroup_remove_symlinks(struct ccwgroup_device *gdev)
{
int i;
@@ -104,7 +104,7 @@ ccwgroup_release (struct device *dev)
kfree(gdev);
}
-static inline int
+static int
__ccwgroup_create_symlinks(struct ccwgroup_device *gdev)
{
char str[8];
@@ -424,7 +424,7 @@ ccwgroup_probe_ccwdev(struct ccw_device *cdev)
return 0;
}
-static inline struct ccwgroup_device *
+static struct ccwgroup_device *
__ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev)
{
struct ccwgroup_device *gdev;
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index cbab8d2ce5c..6f05a44e381 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -93,7 +93,7 @@ chsc_get_sch_desc_irq(struct subchannel *sch, void *page)
u16 sch; /* subchannel */
u8 chpid[8]; /* chpids 0-7 */
u16 fla[8]; /* full link addresses 0-7 */
- } *ssd_area;
+ } __attribute__ ((packed)) *ssd_area;
ssd_area = page;
@@ -277,7 +277,7 @@ out_unreg:
return 0;
}
-static inline void
+static void
s390_set_chpid_offline( __u8 chpid)
{
char dbf_txt[15];
@@ -338,7 +338,7 @@ s390_process_res_acc_sch(struct res_acc_data *res_data, struct subchannel *sch)
return 0x80 >> chp;
}
-static inline int
+static int
s390_process_res_acc_new_sch(struct subchannel_id schid)
{
struct schib schib;
@@ -444,7 +444,7 @@ __get_chpid_from_lir(void *data)
u32 andesc[28];
/* incident-specific information */
u32 isinfo[28];
- } *lir;
+ } __attribute__ ((packed)) *lir;
lir = data;
if (!(lir->iq&0x80))
@@ -461,154 +461,146 @@ __get_chpid_from_lir(void *data)
return (u16) (lir->indesc[0]&0x000000ff);
}
-int
-chsc_process_crw(void)
+struct chsc_sei_area {
+ struct chsc_header request;
+ u32 reserved1;
+ u32 reserved2;
+ u32 reserved3;
+ struct chsc_header response;
+ u32 reserved4;
+ u8 flags;
+ u8 vf; /* validity flags */
+ u8 rs; /* reporting source */
+ u8 cc; /* content code */
+ u16 fla; /* full link address */
+ u16 rsid; /* reporting source id */
+ u32 reserved5;
+ u32 reserved6;
+ u8 ccdf[4096 - 16 - 24]; /* content-code dependent field */
+ /* ccdf has to be big enough for a link-incident record */
+} __attribute__ ((packed));
+
+static int chsc_process_sei_link_incident(struct chsc_sei_area *sei_area)
+{
+ int chpid;
+
+ CIO_CRW_EVENT(4, "chsc: link incident (rs=%02x, rs_id=%04x)\n",
+ sei_area->rs, sei_area->rsid);
+ if (sei_area->rs != 4)
+ return 0;
+ chpid = __get_chpid_from_lir(sei_area->ccdf);
+ if (chpid < 0)
+ CIO_CRW_EVENT(4, "chsc: link incident - invalid LIR\n");
+ else
+ s390_set_chpid_offline(chpid);
+
+ return 0;
+}
+
+static int chsc_process_sei_res_acc(struct chsc_sei_area *sei_area)
{
- int chpid, ret;
struct res_acc_data res_data;
- struct {
- struct chsc_header request;
- u32 reserved1;
- u32 reserved2;
- u32 reserved3;
- struct chsc_header response;
- u32 reserved4;
- u8 flags;
- u8 vf; /* validity flags */
- u8 rs; /* reporting source */
- u8 cc; /* content code */
- u16 fla; /* full link address */
- u16 rsid; /* reporting source id */
- u32 reserved5;
- u32 reserved6;
- u32 ccdf[96]; /* content-code dependent field */
- /* ccdf has to be big enough for a link-incident record */
- } *sei_area;
+ struct device *dev;
+ int status;
+ int rc;
+
+ CIO_CRW_EVENT(4, "chsc: resource accessibility event (rs=%02x, "
+ "rs_id=%04x)\n", sei_area->rs, sei_area->rsid);
+ if (sei_area->rs != 4)
+ return 0;
+ /* allocate a new channel path structure, if needed */
+ status = get_chp_status(sei_area->rsid);
+ if (status < 0)
+ new_channel_path(sei_area->rsid);
+ else if (!status)
+ return 0;
+ dev = get_device(&css[0]->chps[sei_area->rsid]->dev);
+ memset(&res_data, 0, sizeof(struct res_acc_data));
+ res_data.chp = to_channelpath(dev);
+ if ((sei_area->vf & 0xc0) != 0) {
+ res_data.fla = sei_area->fla;
+ if ((sei_area->vf & 0xc0) == 0xc0)
+ /* full link address */
+ res_data.fla_mask = 0xffff;
+ else
+ /* link address */
+ res_data.fla_mask = 0xff00;
+ }
+ rc = s390_process_res_acc(&res_data);
+ put_device(dev);
+
+ return rc;
+}
+
+static int chsc_process_sei(struct chsc_sei_area *sei_area)
+{
+ int rc;
+
+ /* Check if we might have lost some information. */
+ if (sei_area->flags & 0x40)
+ CIO_CRW_EVENT(2, "chsc: event overflow\n");
+ /* which kind of information was stored? */
+ rc = 0;
+ switch (sei_area->cc) {
+ case 1: /* link incident*/
+ rc = chsc_process_sei_link_incident(sei_area);
+ break;
+ case 2: /* i/o resource accessibiliy */
+ rc = chsc_process_sei_res_acc(sei_area);
+ break;
+ default: /* other stuff */
+ CIO_CRW_EVENT(4, "chsc: unhandled sei content code %d\n",
+ sei_area->cc);
+ break;
+ }
+
+ return rc;
+}
+
+int chsc_process_crw(void)
+{
+ struct chsc_sei_area *sei_area;
+ int ret;
+ int rc;
if (!sei_page)
return 0;
- /*
- * build the chsc request block for store event information
- * and do the call
- * This function is only called by the machine check handler thread,
- * so we don't need locking for the sei_page.
- */
+ /* Access to sei_page is serialized through machine check handler
+ * thread, so no need for locking. */
sei_area = sei_page;
CIO_TRACE_EVENT( 2, "prcss");
ret = 0;
do {
- int ccode, status;
- struct device *dev;
memset(sei_area, 0, sizeof(*sei_area));
- memset(&res_data, 0, sizeof(struct res_acc_data));
sei_area->request.length = 0x0010;
sei_area->request.code = 0x000e;
+ if (chsc(sei_area))
+ break;
- ccode = chsc(sei_area);
- if (ccode > 0)
- return 0;
-
- switch (sei_area->response.code) {
- /* for debug purposes, check for problems */
- case 0x0001:
- CIO_CRW_EVENT(4, "chsc_process_crw: event information "
- "successfully stored\n");
- break; /* everything ok */
- case 0x0002:
- CIO_CRW_EVENT(2,
- "chsc_process_crw: invalid command!\n");
- return 0;
- case 0x0003:
- CIO_CRW_EVENT(2, "chsc_process_crw: error in chsc "
- "request block!\n");
- return 0;
- case 0x0005:
- CIO_CRW_EVENT(2, "chsc_process_crw: no event "
- "information stored\n");
- return 0;
- default:
- CIO_CRW_EVENT(2, "chsc_process_crw: chsc response %d\n",
+ if (sei_area->response.code == 0x0001) {
+ CIO_CRW_EVENT(4, "chsc: sei successful\n");
+ rc = chsc_process_sei(sei_area);
+ if (rc)
+ ret = rc;
+ } else {
+ CIO_CRW_EVENT(2, "chsc: sei failed (rc=%04x)\n",
sei_area->response.code);
- return 0;
- }
-
- /* Check if we might have lost some information. */
- if (sei_area->flags & 0x40)
- CIO_CRW_EVENT(2, "chsc_process_crw: Event information "
- "has been lost due to overflow!\n");
-
- if (sei_area->rs != 4) {
- CIO_CRW_EVENT(2, "chsc_process_crw: reporting source "
- "(%04X) isn't a chpid!\n",
- sei_area->rsid);
- continue;
- }
-
- /* which kind of information was stored? */
- switch (sei_area->cc) {
- case 1: /* link incident*/
- CIO_CRW_EVENT(4, "chsc_process_crw: "
- "channel subsystem reports link incident,"
- " reporting source is chpid %x\n",
- sei_area->rsid);
- chpid = __get_chpid_from_lir(sei_area->ccdf);
- if (chpid < 0)
- CIO_CRW_EVENT(4, "%s: Invalid LIR, skipping\n",
- __FUNCTION__);
- else
- s390_set_chpid_offline(chpid);
- break;
-
- case 2: /* i/o resource accessibiliy */
- CIO_CRW_EVENT(4, "chsc_process_crw: "
- "channel subsystem reports some I/O "
- "devices may have become accessible\n");
- pr_debug("Data received after sei: \n");
- pr_debug("Validity flags: %x\n", sei_area->vf);
-
- /* allocate a new channel path structure, if needed */
- status = get_chp_status(sei_area->rsid);
- if (status < 0)
- new_channel_path(sei_area->rsid);
- else if (!status)
- break;
- dev = get_device(&css[0]->chps[sei_area->rsid]->dev);
- res_data.chp = to_channelpath(dev);
- pr_debug("chpid: %x", sei_area->rsid);
- if ((sei_area->vf & 0xc0) != 0) {
- res_data.fla = sei_area->fla;
- if ((sei_area->vf & 0xc0) == 0xc0) {
- pr_debug(" full link addr: %x",
- sei_area->fla);
- res_data.fla_mask = 0xffff;
- } else {
- pr_debug(" link addr: %x",
- sei_area->fla);
- res_data.fla_mask = 0xff00;
- }
- }
- ret = s390_process_res_acc(&res_data);
- pr_debug("\n\n");
- put_device(dev);
- break;
-
- default: /* other stuff */
- CIO_CRW_EVENT(4, "chsc_process_crw: event %d\n",
- sei_area->cc);
+ ret = 0;
break;
}
} while (sei_area->flags & 0x80);
+
return ret;
}
-static inline int
+static int
__chp_add_new_sch(struct subchannel_id schid)
{
struct schib schib;
int ret;
- if (stsch(schid, &schib))
+ if (stsch_err(schid, &schib))
/* We're through */
return need_rescan ? -EAGAIN : -ENXIO;
@@ -709,7 +701,7 @@ chp_process_crw(int chpid, int on)
return chp_add(chpid);
}
-static inline int check_for_io_on_path(struct subchannel *sch, int index)
+static int check_for_io_on_path(struct subchannel *sch, int index)
{
int cc;
@@ -741,7 +733,7 @@ static void terminate_internal_io(struct subchannel *sch)
sch->driver->termination(&sch->dev);
}
-static inline void
+static void
__s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on)
{
int chp, old_lpm;
@@ -967,8 +959,8 @@ static struct bin_attribute chp_measurement_attr = {
static void
chsc_remove_chp_cmg_attr(struct channel_path *chp)
{
- sysfs_remove_bin_file(&chp->dev.kobj, &chp_measurement_chars_attr);
- sysfs_remove_bin_file(&chp->dev.kobj, &chp_measurement_attr);
+ device_remove_bin_file(&chp->dev, &chp_measurement_chars_attr);
+ device_remove_bin_file(&chp->dev, &chp_measurement_attr);
}
static int
@@ -976,14 +968,12 @@ chsc_add_chp_cmg_attr(struct channel_path *chp)
{
int ret;
- ret = sysfs_create_bin_file(&chp->dev.kobj,
- &chp_measurement_chars_attr);
+ ret = device_create_bin_file(&chp->dev, &chp_measurement_chars_attr);
if (ret)
return ret;
- ret = sysfs_create_bin_file(&chp->dev.kobj, &chp_measurement_attr);
+ ret = device_create_bin_file(&chp->dev, &chp_measurement_attr);
if (ret)
- sysfs_remove_bin_file(&chp->dev.kobj,
- &chp_measurement_chars_attr);
+ device_remove_bin_file(&chp->dev, &chp_measurement_chars_attr);
return ret;
}
@@ -1042,7 +1032,7 @@ __chsc_do_secm(struct channel_subsystem *css, int enable, void *page)
u32 : 4;
u32 fmt : 4;
u32 : 16;
- } *secm_area;
+ } __attribute__ ((packed)) *secm_area;
int ret, ccode;
secm_area = page;
@@ -1253,7 +1243,7 @@ chsc_determine_channel_path_description(int chpid,
struct chsc_header response;
u32 zeroes2;
struct channel_path_desc desc;
- } *scpd_area;
+ } __attribute__ ((packed)) *scpd_area;
scpd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
if (!scpd_area)
@@ -1350,7 +1340,7 @@ chsc_get_channel_measurement_chars(struct channel_path *chp)
u32 cmg : 8;
u32 zeroes3;
u32 data[NR_MEASUREMENT_CHARS];
- } *scmc_area;
+ } __attribute__ ((packed)) *scmc_area;
scmc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
if (!scmc_area)
@@ -1517,7 +1507,7 @@ chsc_enable_facility(int operation_code)
u32 reserved5:4;
u32 format2:4;
u32 reserved6:24;
- } *sda_area;
+ } __attribute__ ((packed)) *sda_area;
sda_area = (void *)get_zeroed_page(GFP_KERNEL|GFP_DMA);
if (!sda_area)
@@ -1569,7 +1559,7 @@ chsc_determine_css_characteristics(void)
u32 reserved4;
u32 general_char[510];
u32 chsc_char[518];
- } *scsc_area;
+ } __attribute__ ((packed)) *scsc_area;
scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
if (!scsc_area) {
diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h
index a259245780a..0fb2b024208 100644
--- a/drivers/s390/cio/chsc.h
+++ b/drivers/s390/cio/chsc.h
@@ -10,17 +10,17 @@
struct chsc_header {
u16 length;
u16 code;
-};
+} __attribute__ ((packed));
#define NR_MEASUREMENT_CHARS 5
struct cmg_chars {
u32 values[NR_MEASUREMENT_CHARS];
-};
+} __attribute__ ((packed));
#define NR_MEASUREMENT_ENTRIES 8
struct cmg_entry {
u32 values[NR_MEASUREMENT_ENTRIES];
-};
+} __attribute__ ((packed));
struct channel_path_desc {
u8 flags;
@@ -31,7 +31,7 @@ struct channel_path_desc {
u8 zeroes;
u8 chla;
u8 chpp;
-};
+} __attribute__ ((packed));
struct channel_path {
int id;
@@ -47,6 +47,9 @@ struct channel_path {
extern void s390_process_css( void );
extern void chsc_validate_chpids(struct subchannel *);
extern void chpid_is_actually_online(int);
+extern int css_get_ssd_info(struct subchannel *);
+extern int chsc_process_crw(void);
+extern int chp_process_crw(int, int);
struct css_general_char {
u64 : 41;
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index ae1bf231d08..b3a56dc5f68 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -122,7 +122,7 @@ cio_get_options (struct subchannel *sch)
* Use tpi to get a pending interrupt, call the interrupt handler and
* return a pointer to the subchannel structure.
*/
-static inline int
+static int
cio_tpi(void)
{
struct tpi_info *tpi_info;
@@ -152,7 +152,7 @@ cio_tpi(void)
return 1;
}
-static inline int
+static int
cio_start_handle_notoper(struct subchannel *sch, __u8 lpm)
{
char dbf_text[15];
@@ -585,7 +585,7 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
* This device must not be known to Linux. So we simply
* say that there is no device and return ENODEV.
*/
- CIO_MSG_EVENT(0, "Blacklisted device detected "
+ CIO_MSG_EVENT(4, "Blacklisted device detected "
"at devno %04X, subchannel set %x\n",
sch->schib.pmcw.dev, sch->schid.ssid);
err = -ENODEV;
@@ -646,7 +646,7 @@ do_IRQ (struct pt_regs *regs)
* Make sure that the i/o interrupt did not "overtake"
* the last HZ timer interrupt.
*/
- account_ticks();
+ account_ticks(S390_lowcore.int_clock);
/*
* Get interrupt information from lowcore
*/
@@ -832,7 +832,7 @@ cio_get_console_subchannel(void)
}
#endif
-static inline int
+static int
__disable_subchannel_easy(struct subchannel_id schid, struct schib *schib)
{
int retry, cc;
@@ -850,7 +850,20 @@ __disable_subchannel_easy(struct subchannel_id schid, struct schib *schib)
return -EBUSY; /* uhm... */
}
-static inline int
+/* we can't use the normal udelay here, since it enables external interrupts */
+
+static void udelay_reset(unsigned long usecs)
+{
+ uint64_t start_cc, end_cc;
+
+ asm volatile ("STCK %0" : "=m" (start_cc));
+ do {
+ cpu_relax();
+ asm volatile ("STCK %0" : "=m" (end_cc));
+ } while (((end_cc - start_cc)/4096) < usecs);
+}
+
+static int
__clear_subchannel_easy(struct subchannel_id schid)
{
int retry;
@@ -865,7 +878,7 @@ __clear_subchannel_easy(struct subchannel_id schid)
if (schid_equal(&ti.schid, &schid))
return 0;
}
- udelay(100);
+ udelay_reset(100);
}
return -EBUSY;
}
@@ -882,11 +895,11 @@ static int stsch_reset(struct subchannel_id schid, volatile struct schib *addr)
int rc;
pgm_check_occured = 0;
- s390_reset_pgm_handler = cio_reset_pgm_check_handler;
+ s390_base_pgm_handler_fn = cio_reset_pgm_check_handler;
rc = stsch(schid, addr);
- s390_reset_pgm_handler = NULL;
+ s390_base_pgm_handler_fn = NULL;
- /* The program check handler could have changed pgm_check_occured */
+ /* The program check handler could have changed pgm_check_occured. */
barrier();
if (pgm_check_occured)
@@ -944,7 +957,7 @@ static void css_reset(void)
/* Reset subchannels. */
for_each_subchannel(__shutdown_subchannel_easy, NULL);
/* Reset channel paths. */
- s390_reset_mcck_handler = s390_reset_chpids_mcck_handler;
+ s390_base_mcck_handler_fn = s390_reset_chpids_mcck_handler;
/* Enable channel report machine checks. */
__ctl_set_bit(14, 28);
/* Temporarily reenable machine checks. */
@@ -969,7 +982,7 @@ static void css_reset(void)
local_mcck_disable();
/* Disable channel report machine checks. */
__ctl_clear_bit(14, 28);
- s390_reset_mcck_handler = NULL;
+ s390_base_mcck_handler_fn = NULL;
}
static struct reset_call css_reset_call = {
diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c
index 828b2d334f0..90b22faabbf 100644
--- a/drivers/s390/cio/cmf.c
+++ b/drivers/s390/cio/cmf.c
@@ -519,8 +519,8 @@ struct cmb {
/* insert a single device into the cmb_area list
* called with cmb_area.lock held from alloc_cmb
*/
-static inline int alloc_cmb_single (struct ccw_device *cdev,
- struct cmb_data *cmb_data)
+static int alloc_cmb_single(struct ccw_device *cdev,
+ struct cmb_data *cmb_data)
{
struct cmb *cmb;
struct ccw_device_private *node;
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 9d6c0244686..fe0ace7aece 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -30,7 +30,7 @@ struct channel_subsystem *css[__MAX_CSSID + 1];
int css_characteristics_avail = 0;
-inline int
+int
for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *data)
{
struct subchannel_id schid;
@@ -108,9 +108,6 @@ 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;
@@ -187,7 +184,7 @@ get_subchannel_by_schid(struct subchannel_id schid)
return dev ? to_subchannel(dev) : NULL;
}
-static inline int css_get_subchannel_status(struct subchannel *sch)
+static int css_get_subchannel_status(struct subchannel *sch)
{
struct schib schib;
@@ -299,7 +296,7 @@ static int css_evaluate_new_subchannel(struct subchannel_id schid, int slow)
/* Will be done on the slow path. */
return -EAGAIN;
}
- if (stsch(schid, &schib) || !schib.pmcw.dnv) {
+ if (stsch_err(schid, &schib) || !schib.pmcw.dnv) {
/* Unusable - ignore. */
return 0;
}
@@ -417,7 +414,7 @@ static void reprobe_all(struct work_struct *unused)
need_reprobe);
}
-DECLARE_WORK(css_reprobe_work, reprobe_all);
+static DECLARE_WORK(css_reprobe_work, reprobe_all);
/* Schedule reprobing of all unregistered subchannels. */
void css_schedule_reprobe(void)
@@ -578,7 +575,7 @@ css_cm_enable_store(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR(cm_enable, 0644, css_cm_enable_show, css_cm_enable_store);
-static inline int __init setup_css(int nr)
+static int __init setup_css(int nr)
{
u32 tod_high;
int ret;
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h
index 3464c5b875c..ca2bab932a8 100644
--- a/drivers/s390/cio/css.h
+++ b/drivers/s390/cio/css.h
@@ -143,6 +143,8 @@ 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 *);
+extern int css_process_crw(int, int);
+extern void css_reiterate_subchannels(void);
#define __MAX_SUBCHANNEL 65535
#define __MAX_SSID 3
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 803579053c2..e322111fb36 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -138,7 +138,6 @@ struct bus_type ccw_bus_type;
static int io_subchannel_probe (struct subchannel *);
static int io_subchannel_remove (struct subchannel *);
-void io_subchannel_irq (struct device *);
static int io_subchannel_notify(struct device *, int);
static void io_subchannel_verify(struct device *);
static void io_subchannel_ioterm(struct device *);
@@ -235,11 +234,8 @@ chpids_show (struct device * dev, struct device_attribute *attr, char * buf)
ssize_t ret = 0;
int chp;
- if (ssd)
- for (chp = 0; chp < 8; chp++)
- ret += sprintf (buf+ret, "%02x ", ssd->chpid[chp]);
- else
- ret += sprintf (buf, "n/a");
+ for (chp = 0; chp < 8; chp++)
+ ret += sprintf (buf+ret, "%02x ", ssd->chpid[chp]);
ret += sprintf (buf+ret, "\n");
return min((ssize_t)PAGE_SIZE, ret);
}
@@ -552,13 +548,13 @@ static struct attribute_group ccwdev_attr_group = {
.attrs = ccwdev_attrs,
};
-static inline int
+static int
device_add_files (struct device *dev)
{
return sysfs_create_group(&dev->kobj, &ccwdev_attr_group);
}
-static inline void
+static void
device_remove_files(struct device *dev)
{
sysfs_remove_group(&dev->kobj, &ccwdev_attr_group);
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h
index 29db6341d63..b66338b7657 100644
--- a/drivers/s390/cio/device.h
+++ b/drivers/s390/cio/device.h
@@ -74,6 +74,7 @@ extern struct workqueue_struct *ccw_device_notify_work;
extern wait_queue_head_t ccw_device_init_wq;
extern atomic_t ccw_device_init_count;
+void io_subchannel_irq (struct device *pdev);
void io_subchannel_recog_done(struct ccw_device *cdev);
int ccw_device_cancel_halt_clear(struct ccw_device *);
@@ -118,6 +119,7 @@ int ccw_device_stlck(struct ccw_device *);
/* qdio needs this. */
void ccw_device_set_timeout(struct ccw_device *, int);
extern struct subchannel_id ccw_device_get_subchannel_id(struct ccw_device *);
+extern struct bus_type ccw_bus_type;
/* Channel measurement facility related */
void retry_set_schib(struct ccw_device *cdev);
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index eed14572fc3..51238e7555b 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -206,7 +206,7 @@ ccw_device_handle_oper(struct ccw_device *cdev)
* been varied online on the SE so we have to find out by magic (i. e. driving
* the channel subsystem to device selection and updating our path masks).
*/
-static inline void
+static void
__recover_lost_chpids(struct subchannel *sch, int old_lpm)
{
int mask, i;
@@ -387,7 +387,7 @@ ccw_device_done(struct ccw_device *cdev, int state)
put_device (&cdev->dev);
}
-static inline int cmp_pgid(struct pgid *p1, struct pgid *p2)
+static int cmp_pgid(struct pgid *p1, struct pgid *p2)
{
char *c1;
char *c2;
@@ -842,6 +842,8 @@ ccw_device_irq(struct ccw_device *cdev, enum dev_event dev_event)
call_handler_unsol:
if (cdev->handler)
cdev->handler (cdev, 0, irb);
+ if (cdev->private->flags.doverify)
+ ccw_device_online_verify(cdev, 0);
return;
}
/* Accumulate status and find out if a basic sense is needed. */
@@ -892,7 +894,7 @@ ccw_device_online_timeout(struct ccw_device *cdev, enum dev_event dev_event)
/*
* Got an interrupt for a basic sense.
*/
-void
+static void
ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event)
{
struct irb *irb;
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
index d269607336e..d7b25b8f71d 100644
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -302,7 +302,7 @@ ccw_device_wake_up(struct ccw_device *cdev, unsigned long ip, struct irb *irb)
wake_up(&cdev->private->wait_q);
}
-static inline int
+static int
__ccw_device_retry_loop(struct ccw_device *cdev, struct ccw1 *ccw, long magic, __u8 lpm)
{
int ret;
diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c
index bdcf930f7be..6b1caea622e 100644
--- a/drivers/s390/cio/device_status.c
+++ b/drivers/s390/cio/device_status.c
@@ -25,7 +25,7 @@
* Check for any kind of channel or interface control check but don't
* issue the message for the console device
*/
-static inline void
+static void
ccw_device_msg_control_check(struct ccw_device *cdev, struct irb *irb)
{
if (!(irb->scsw.cstat & (SCHN_STAT_CHN_DATA_CHK |
@@ -72,7 +72,7 @@ ccw_device_path_notoper(struct ccw_device *cdev)
/*
* Copy valid bits from the extended control word to device irb.
*/
-static inline void
+static void
ccw_device_accumulate_ecw(struct ccw_device *cdev, struct irb *irb)
{
/*
@@ -94,7 +94,7 @@ ccw_device_accumulate_ecw(struct ccw_device *cdev, struct irb *irb)
/*
* Check if extended status word is valid.
*/
-static inline int
+static int
ccw_device_accumulate_esw_valid(struct irb *irb)
{
if (!irb->scsw.eswf && irb->scsw.stctl == SCSW_STCTL_STATUS_PEND)
@@ -109,7 +109,7 @@ ccw_device_accumulate_esw_valid(struct irb *irb)
/*
* Copy valid bits from the extended status word to device irb.
*/
-static inline void
+static void
ccw_device_accumulate_esw(struct ccw_device *cdev, struct irb *irb)
{
struct irb *cdev_irb;
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c
index 6fd1940842e..d726cd5777d 100644
--- a/drivers/s390/cio/qdio.c
+++ b/drivers/s390/cio/qdio.c
@@ -66,7 +66,6 @@ MODULE_LICENSE("GPL");
/******************** HERE WE GO ***********************************/
static const char version[] = "QDIO base support version 2";
-extern struct bus_type ccw_bus_type;
static int qdio_performance_stats = 0;
static int proc_perf_file_registration;
@@ -138,7 +137,7 @@ qdio_release_q(struct qdio_q *q)
}
/*check ccq */
-static inline int
+static int
qdio_check_ccq(struct qdio_q *q, unsigned int ccq)
{
char dbf_text[15];
@@ -153,7 +152,7 @@ qdio_check_ccq(struct qdio_q *q, unsigned int ccq)
return -EIO;
}
/* EQBS: extract buffer states */
-static inline int
+static int
qdio_do_eqbs(struct qdio_q *q, unsigned char *state,
unsigned int *start, unsigned int *cnt)
{
@@ -188,7 +187,7 @@ again:
}
/* SQBS: set buffer states */
-static inline int
+static int
qdio_do_sqbs(struct qdio_q *q, unsigned char state,
unsigned int *start, unsigned int *cnt)
{
@@ -315,7 +314,7 @@ __do_siga_output(struct qdio_q *q, unsigned int *busy_bit)
* returns QDIO_SIGA_ERROR_ACCESS_EXCEPTION as cc, when SIGA returns
* an access exception
*/
-static inline int
+static int
qdio_siga_output(struct qdio_q *q)
{
int cc;
@@ -349,7 +348,7 @@ qdio_siga_output(struct qdio_q *q)
return cc;
}
-static inline int
+static int
qdio_siga_input(struct qdio_q *q)
{
int cc;
@@ -421,7 +420,7 @@ tiqdio_sched_tl(void)
tasklet_hi_schedule(&tiqdio_tasklet);
}
-static inline void
+static void
qdio_mark_tiq(struct qdio_q *q)
{
unsigned long flags;
@@ -471,7 +470,7 @@ qdio_mark_q(struct qdio_q *q)
tasklet_schedule(&q->tasklet);
}
-static inline int
+static int
qdio_stop_polling(struct qdio_q *q)
{
#ifdef QDIO_USE_PROCESSING_STATE
@@ -525,7 +524,7 @@ qdio_stop_polling(struct qdio_q *q)
* sophisticated locking outside of unmark_q, so that we don't need to
* disable the interrupts :-)
*/
-static inline void
+static void
qdio_unmark_q(struct qdio_q *q)
{
unsigned long flags;
@@ -691,7 +690,7 @@ qdio_qebsm_get_inbound_buffer_frontier(struct qdio_q *q)
return q->first_to_check;
}
-static inline int
+static int
qdio_get_outbound_buffer_frontier(struct qdio_q *q)
{
struct qdio_irq *irq;
@@ -774,7 +773,7 @@ out:
}
/* all buffers are processed */
-static inline int
+static int
qdio_is_outbound_q_done(struct qdio_q *q)
{
int no_used;
@@ -796,7 +795,7 @@ qdio_is_outbound_q_done(struct qdio_q *q)
return (no_used==0);
}
-static inline int
+static int
qdio_has_outbound_q_moved(struct qdio_q *q)
{
int i;
@@ -816,7 +815,7 @@ qdio_has_outbound_q_moved(struct qdio_q *q)
}
}
-static inline void
+static void
qdio_kick_outbound_q(struct qdio_q *q)
{
int result;
@@ -905,7 +904,7 @@ qdio_kick_outbound_q(struct qdio_q *q)
}
}
-static inline void
+static void
qdio_kick_outbound_handler(struct qdio_q *q)
{
int start, end, real_end, count;
@@ -942,7 +941,7 @@ qdio_kick_outbound_handler(struct qdio_q *q)
q->error_status_flags=0;
}
-static inline void
+static void
__qdio_outbound_processing(struct qdio_q *q)
{
int siga_attempts;
@@ -1002,7 +1001,7 @@ qdio_outbound_processing(struct qdio_q *q)
/************************* INBOUND ROUTINES *******************************/
-static inline int
+static int
qdio_get_inbound_buffer_frontier(struct qdio_q *q)
{
struct qdio_irq *irq;
@@ -1133,7 +1132,7 @@ out:
return q->first_to_check;
}
-static inline int
+static int
qdio_has_inbound_q_moved(struct qdio_q *q)
{
int i;
@@ -1167,7 +1166,7 @@ qdio_has_inbound_q_moved(struct qdio_q *q)
}
/* means, no more buffers to be filled */
-static inline int
+static int
tiqdio_is_inbound_q_done(struct qdio_q *q)
{
int no_used;
@@ -1228,7 +1227,7 @@ tiqdio_is_inbound_q_done(struct qdio_q *q)
return 0;
}
-static inline int
+static int
qdio_is_inbound_q_done(struct qdio_q *q)
{
int no_used;
@@ -1296,7 +1295,7 @@ qdio_is_inbound_q_done(struct qdio_q *q)
}
}
-static inline void
+static void
qdio_kick_inbound_handler(struct qdio_q *q)
{
int count, start, end, real_end, i;
@@ -1343,7 +1342,7 @@ qdio_kick_inbound_handler(struct qdio_q *q)
}
}
-static inline void
+static void
__tiqdio_inbound_processing(struct qdio_q *q, int spare_ind_was_set)
{
struct qdio_irq *irq_ptr;
@@ -1442,7 +1441,7 @@ tiqdio_inbound_processing(struct qdio_q *q)
__tiqdio_inbound_processing(q, atomic_read(&spare_indicator_usecount));
}
-static inline void
+static void
__qdio_inbound_processing(struct qdio_q *q)
{
int q_laps=0;
@@ -1493,7 +1492,7 @@ qdio_inbound_processing(struct qdio_q *q)
/************************* MAIN ROUTINES *******************************/
#ifdef QDIO_USE_PROCESSING_STATE
-static inline int
+static int
tiqdio_reset_processing_state(struct qdio_q *q, int q_laps)
{
if (!q) {
@@ -1545,7 +1544,7 @@ tiqdio_reset_processing_state(struct qdio_q *q, int q_laps)
}
#endif /* QDIO_USE_PROCESSING_STATE */
-static inline void
+static void
tiqdio_inbound_checks(void)
{
struct qdio_q *q;
@@ -1949,7 +1948,7 @@ qdio_set_state(struct qdio_irq *irq_ptr, enum qdio_irq_states state)
mb();
}
-static inline void
+static void
qdio_irq_check_sense(struct subchannel_id schid, struct irb *irb)
{
char dbf_text[15];
@@ -1966,7 +1965,7 @@ qdio_irq_check_sense(struct subchannel_id schid, struct irb *irb)
}
-static inline void
+static void
qdio_handle_pci(struct qdio_irq *irq_ptr)
{
int i;
@@ -2002,7 +2001,7 @@ qdio_handle_pci(struct qdio_irq *irq_ptr)
static void qdio_establish_handle_irq(struct ccw_device*, int, int);
-static inline void
+static void
qdio_handle_activate_check(struct ccw_device *cdev, unsigned long intparm,
int cstat, int dstat)
{
@@ -2229,7 +2228,7 @@ qdio_synchronize(struct ccw_device *cdev, unsigned int flags,
return cc;
}
-static inline void
+static void
qdio_check_subchannel_qebsm(struct qdio_irq *irq_ptr, unsigned char qdioac,
unsigned long token)
{
@@ -2740,7 +2739,7 @@ qdio_free(struct ccw_device *cdev)
return 0;
}
-static inline void
+static void
qdio_allocate_do_dbf(struct qdio_initialize *init_data)
{
char dbf_text[20]; /* if a printf printed out more than 8 chars */
@@ -2773,7 +2772,7 @@ qdio_allocate_do_dbf(struct qdio_initialize *init_data)
QDIO_DBF_HEX0(0,setup,&init_data->output_sbal_addr_array,sizeof(void*));
}
-static inline void
+static void
qdio_allocate_fill_input_desc(struct qdio_irq *irq_ptr, int i, int iqfmt)
{
irq_ptr->input_qs[i]->is_iqdio_q = iqfmt;
@@ -2792,7 +2791,7 @@ qdio_allocate_fill_input_desc(struct qdio_irq *irq_ptr, int i, int iqfmt)
irq_ptr->qdr->qdf0[i].dkey=QDIO_STORAGE_KEY;
}
-static inline void
+static void
qdio_allocate_fill_output_desc(struct qdio_irq *irq_ptr, int i,
int j, int iqfmt)
{
@@ -2813,7 +2812,7 @@ qdio_allocate_fill_output_desc(struct qdio_irq *irq_ptr, int i,
}
-static inline void
+static void
qdio_initialize_set_siga_flags_input(struct qdio_irq *irq_ptr)
{
int i;
@@ -2839,7 +2838,7 @@ qdio_initialize_set_siga_flags_input(struct qdio_irq *irq_ptr)
}
}
-static inline void
+static void
qdio_initialize_set_siga_flags_output(struct qdio_irq *irq_ptr)
{
int i;
@@ -2865,7 +2864,7 @@ qdio_initialize_set_siga_flags_output(struct qdio_irq *irq_ptr)
}
}
-static inline int
+static int
qdio_establish_irq_check_for_errors(struct ccw_device *cdev, int cstat,
int dstat)
{
@@ -3014,7 +3013,7 @@ qdio_allocate(struct qdio_initialize *init_data)
return 0;
}
-int qdio_fill_irq(struct qdio_initialize *init_data)
+static int qdio_fill_irq(struct qdio_initialize *init_data)
{
int i;
char dbf_text[15];
@@ -3367,7 +3366,7 @@ qdio_activate(struct ccw_device *cdev, int flags)
}
/* buffers filled forwards again to make Rick happy */
-static inline void
+static void
qdio_do_qdio_fill_input(struct qdio_q *q, unsigned int qidx,
unsigned int count, struct qdio_buffer *buffers)
{
@@ -3386,7 +3385,7 @@ qdio_do_qdio_fill_input(struct qdio_q *q, unsigned int qidx,
}
}
-static inline void
+static void
qdio_do_qdio_fill_output(struct qdio_q *q, unsigned int qidx,
unsigned int count, struct qdio_buffer *buffers)
{
@@ -3407,7 +3406,7 @@ qdio_do_qdio_fill_output(struct qdio_q *q, unsigned int qidx,
}
}
-static inline void
+static void
do_qdio_handle_inbound(struct qdio_q *q, unsigned int callflags,
unsigned int qidx, unsigned int count,
struct qdio_buffer *buffers)
@@ -3443,7 +3442,7 @@ do_qdio_handle_inbound(struct qdio_q *q, unsigned int callflags,
qdio_mark_q(q);
}
-static inline void
+static void
do_qdio_handle_outbound(struct qdio_q *q, unsigned int callflags,
unsigned int qidx, unsigned int count,
struct qdio_buffer *buffers)
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index 81b5899f401..c7d1355237b 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -465,7 +465,7 @@ static int ap_device_probe(struct device *dev)
* Flush all requests from the request/pending queue of an AP device.
* @ap_dev: pointer to the AP device.
*/
-static inline void __ap_flush_queue(struct ap_device *ap_dev)
+static void __ap_flush_queue(struct ap_device *ap_dev)
{
struct ap_message *ap_msg, *next;
@@ -587,7 +587,7 @@ static struct bus_attribute *const ap_bus_attrs[] = {
/**
* Pick one of the 16 ap domains.
*/
-static inline int ap_select_domain(void)
+static int ap_select_domain(void)
{
int queue_depth, device_type, count, max_count, best_domain;
int rc, i, j;
@@ -825,7 +825,7 @@ static inline void ap_schedule_poll_timer(void)
* required, bit 2^1 is set if the poll timer needs to get armed
* Returns 0 if the device is still present, -ENODEV if not.
*/
-static inline int ap_poll_read(struct ap_device *ap_dev, unsigned long *flags)
+static int ap_poll_read(struct ap_device *ap_dev, unsigned long *flags)
{
struct ap_queue_status status;
struct ap_message *ap_msg;
@@ -872,7 +872,7 @@ static inline int ap_poll_read(struct ap_device *ap_dev, unsigned long *flags)
* required, bit 2^1 is set if the poll timer needs to get armed
* Returns 0 if the device is still present, -ENODEV if not.
*/
-static inline int ap_poll_write(struct ap_device *ap_dev, unsigned long *flags)
+static int ap_poll_write(struct ap_device *ap_dev, unsigned long *flags)
{
struct ap_queue_status status;
struct ap_message *ap_msg;
diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c
index 1edc10a7a6f..b9e59bc9435 100644
--- a/drivers/s390/crypto/zcrypt_api.c
+++ b/drivers/s390/crypto/zcrypt_api.c
@@ -791,7 +791,7 @@ static long trans_xcRB32(struct file *filp, unsigned int cmd,
return rc;
}
-long zcrypt_compat_ioctl(struct file *filp, unsigned int cmd,
+static long zcrypt_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
if (cmd == ICARSAMODEXPO)
@@ -833,8 +833,8 @@ static struct miscdevice zcrypt_misc_device = {
*/
static struct proc_dir_entry *zcrypt_entry;
-static inline int sprintcl(unsigned char *outaddr, unsigned char *addr,
- unsigned int len)
+static int sprintcl(unsigned char *outaddr, unsigned char *addr,
+ unsigned int len)
{
int hl, i;
@@ -845,8 +845,8 @@ static inline int sprintcl(unsigned char *outaddr, unsigned char *addr,
return hl;
}
-static inline int sprintrw(unsigned char *outaddr, unsigned char *addr,
- unsigned int len)
+static int sprintrw(unsigned char *outaddr, unsigned char *addr,
+ unsigned int len)
{
int hl, inl, c, cx;
@@ -865,8 +865,8 @@ static inline int sprintrw(unsigned char *outaddr, unsigned char *addr,
return hl;
}
-static inline int sprinthx(unsigned char *title, unsigned char *outaddr,
- unsigned char *addr, unsigned int len)
+static int sprinthx(unsigned char *title, unsigned char *outaddr,
+ unsigned char *addr, unsigned int len)
{
int hl, inl, r, rx;
@@ -885,8 +885,8 @@ static inline int sprinthx(unsigned char *title, unsigned char *outaddr,
return hl;
}
-static inline int sprinthx4(unsigned char *title, unsigned char *outaddr,
- unsigned int *array, unsigned int len)
+static int sprinthx4(unsigned char *title, unsigned char *outaddr,
+ unsigned int *array, unsigned int len)
{
int hl, r;
@@ -943,7 +943,7 @@ static int zcrypt_status_read(char *resp_buff, char **start, off_t offset,
zcrypt_qdepth_mask(workarea);
len += sprinthx("Waiting work element counts",
resp_buff+len, workarea, AP_DEVICES);
- zcrypt_perdev_reqcnt((unsigned int *) workarea);
+ zcrypt_perdev_reqcnt((int *) workarea);
len += sprinthx4("Per-device successfully completed request counts",
resp_buff+len,(unsigned int *) workarea, AP_DEVICES);
*eof = 1;
diff --git a/drivers/s390/crypto/zcrypt_pcica.c b/drivers/s390/crypto/zcrypt_pcica.c
index 32e37014345..818ffe05ac0 100644
--- a/drivers/s390/crypto/zcrypt_pcica.c
+++ b/drivers/s390/crypto/zcrypt_pcica.c
@@ -191,10 +191,10 @@ static int ICACRT_msg_to_type4CRT_msg(struct zcrypt_device *zdev,
*
* Returns 0 on success or -EFAULT.
*/
-static inline int convert_type84(struct zcrypt_device *zdev,
- struct ap_message *reply,
- char __user *outputdata,
- unsigned int outputdatalength)
+static int convert_type84(struct zcrypt_device *zdev,
+ struct ap_message *reply,
+ char __user *outputdata,
+ unsigned int outputdatalength)
{
struct type84_hdr *t84h = reply->message;
char *data;
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c
index b7153c1e15c..252443b6bd1 100644
--- a/drivers/s390/crypto/zcrypt_pcixcc.c
+++ b/drivers/s390/crypto/zcrypt_pcixcc.c
@@ -709,7 +709,8 @@ out_free:
* PCIXCC/CEX2C device to the request distributor
* @xcRB: pointer to the send_cprb request buffer
*/
-long zcrypt_pcixcc_send_cprb(struct zcrypt_device *zdev, struct ica_xcRB *xcRB)
+static long zcrypt_pcixcc_send_cprb(struct zcrypt_device *zdev,
+ struct ica_xcRB *xcRB)
{
struct ap_message ap_msg;
struct response_type resp_type = {
diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig
index 52625153a4f..f98fa465df0 100644
--- a/drivers/s390/net/Kconfig
+++ b/drivers/s390/net/Kconfig
@@ -22,13 +22,6 @@ config CTC
available. This option is also available as a module which will be
called ctc.ko. If you do not know what it is, it's safe to say "Y".
-config IUCV
- tristate "IUCV support (VM only)"
- help
- Select this option if you want to use inter-user communication
- under VM or VIF. If unsure, say "Y" to enable a fast communication
- link between VM guests.
-
config NETIUCV
tristate "IUCV network device support (VM only)"
depends on IUCV && NETDEVICES
diff --git a/drivers/s390/net/Makefile b/drivers/s390/net/Makefile
index 4777e36a922..bbe3ab2e93d 100644
--- a/drivers/s390/net/Makefile
+++ b/drivers/s390/net/Makefile
@@ -4,7 +4,6 @@
ctc-objs := ctcmain.o ctcdbug.o
-obj-$(CONFIG_IUCV) += iucv.o
obj-$(CONFIG_NETIUCV) += netiucv.o fsm.o
obj-$(CONFIG_SMSGIUCV) += smsgiucv.o
obj-$(CONFIG_CTC) += ctc.o fsm.o cu3088.o
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c
index 95f4e105cb9..7809a79feec 100644
--- a/drivers/s390/net/claw.c
+++ b/drivers/s390/net/claw.c
@@ -121,7 +121,7 @@ MODULE_LICENSE("GPL");
#define DEBUG
#endif
- char debug_buffer[255];
+static char debug_buffer[255];
/**
* Debug Facility Stuff
*/
@@ -223,16 +223,14 @@ static void claw_timer ( struct chbk * p_ch );
/* Functions */
static int add_claw_reads(struct net_device *dev,
struct ccwbk* p_first, struct ccwbk* p_last);
-static void inline ccw_check_return_code (struct ccw_device *cdev,
- int return_code);
-static void inline ccw_check_unit_check (struct chbk * p_ch,
- unsigned char sense );
+static void ccw_check_return_code (struct ccw_device *cdev, int return_code);
+static void ccw_check_unit_check (struct chbk * p_ch, unsigned char sense );
static int find_link(struct net_device *dev, char *host_name, char *ws_name );
static int claw_hw_tx(struct sk_buff *skb, struct net_device *dev, long linkid);
static int init_ccw_bk(struct net_device *dev);
static void probe_error( struct ccwgroup_device *cgdev);
static struct net_device_stats *claw_stats(struct net_device *dev);
-static int inline pages_to_order_of_mag(int num_of_pages);
+static int pages_to_order_of_mag(int num_of_pages);
static struct sk_buff *claw_pack_skb(struct claw_privbk *privptr);
#ifdef DEBUG
static void dumpit (char *buf, int len);
@@ -1310,7 +1308,7 @@ claw_timer ( struct chbk * p_ch )
* of magnitude get_free_pages() has an upper order of 9 *
*--------------------------------------------------------------------*/
-static int inline
+static int
pages_to_order_of_mag(int num_of_pages)
{
int order_of_mag=1; /* assume 2 pages */
@@ -1482,7 +1480,7 @@ add_claw_reads(struct net_device *dev, struct ccwbk* p_first,
* *
*-------------------------------------------------------------------*/
-static void inline
+static void
ccw_check_return_code(struct ccw_device *cdev, int return_code)
{
#ifdef FUNCTRACE
@@ -1529,7 +1527,7 @@ ccw_check_return_code(struct ccw_device *cdev, int return_code)
* ccw_check_unit_check *
*--------------------------------------------------------------------*/
-static void inline
+static void
ccw_check_unit_check(struct chbk * p_ch, unsigned char sense )
{
struct net_device *dev = p_ch->ndev;
diff --git a/drivers/s390/net/ctcmain.c b/drivers/s390/net/ctcmain.c
index 03cc263fe0d..5a84fbbc661 100644
--- a/drivers/s390/net/ctcmain.c
+++ b/drivers/s390/net/ctcmain.c
@@ -369,7 +369,7 @@ ctc_dump_skb(struct sk_buff *skb, int offset)
* @param ch The channel where this skb has been received.
* @param pskb The received skb.
*/
-static __inline__ void
+static void
ctc_unpack_skb(struct channel *ch, struct sk_buff *pskb)
{
struct net_device *dev = ch->netdev;
@@ -512,7 +512,7 @@ ctc_unpack_skb(struct channel *ch, struct sk_buff *pskb)
* @param ch The channel, the error belongs to.
* @param return_code The error code to inspect.
*/
-static void inline
+static void
ccw_check_return_code(struct channel *ch, int return_code, char *msg)
{
DBF_TEXT(trace, 5, __FUNCTION__);
@@ -547,7 +547,7 @@ ccw_check_return_code(struct channel *ch, int return_code, char *msg)
* @param ch The channel, the sense code belongs to.
* @param sense The sense code to inspect.
*/
-static void inline
+static void
ccw_unit_check(struct channel *ch, unsigned char sense)
{
DBF_TEXT(trace, 5, __FUNCTION__);
@@ -603,7 +603,7 @@ ctc_purge_skb_queue(struct sk_buff_head *q)
}
}
-static __inline__ int
+static int
ctc_checkalloc_buffer(struct channel *ch, int warn)
{
DBF_TEXT(trace, 5, __FUNCTION__);
diff --git a/drivers/s390/net/cu3088.c b/drivers/s390/net/cu3088.c
index e965f03a729..76728ae4b84 100644
--- a/drivers/s390/net/cu3088.c
+++ b/drivers/s390/net/cu3088.c
@@ -57,7 +57,7 @@ static struct ccw_device_id cu3088_ids[] = {
static struct ccw_driver cu3088_driver;
-struct device *cu3088_root_dev;
+static struct device *cu3088_root_dev;
static ssize_t
group_write(struct device_driver *drv, const char *buf, size_t count)
diff --git a/drivers/s390/net/iucv.c b/drivers/s390/net/iucv.c
deleted file mode 100644
index 229aeb5fc39..00000000000
--- a/drivers/s390/net/iucv.c
+++ /dev/null
@@ -1,2540 +0,0 @@
-/*
- * IUCV network driver
- *
- * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s):
- * Original source:
- * Alan Altmark (Alan_Altmark@us.ibm.com) Sept. 2000
- * Xenia Tkatschow (xenia@us.ibm.com)
- * 2Gb awareness and general cleanup:
- * Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com)
- *
- * Documentation used:
- * The original source
- * CP Programming Service, IBM document # SC24-5760
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-/* #define DEBUG */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-
-#include <linux/spinlock.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/device.h>
-#include <asm/atomic.h>
-#include "iucv.h"
-#include <asm/io.h>
-#include <asm/s390_ext.h>
-#include <asm/ebcdic.h>
-#include <asm/smp.h>
-#include <asm/s390_rdev.h>
-
-/* FLAGS:
- * All flags are defined in the field IPFLAGS1 of each function
- * and can be found in CP Programming Services.
- * IPSRCCLS - Indicates you have specified a source class
- * IPFGMCL - Indicates you have specified a target class
- * IPFGPID - Indicates you have specified a pathid
- * IPFGMID - Indicates you have specified a message ID
- * IPANSLST - Indicates that you are using an address list for
- * reply data
- * IPBUFLST - Indicates that you are using an address list for
- * message data
- */
-
-#define IPSRCCLS 0x01
-#define IPFGMCL 0x01
-#define IPFGPID 0x02
-#define IPFGMID 0x04
-#define IPANSLST 0x08
-#define IPBUFLST 0x40
-
-static int
-iucv_bus_match (struct device *dev, struct device_driver *drv)
-{
- return 0;
-}
-
-struct bus_type iucv_bus = {
- .name = "iucv",
- .match = iucv_bus_match,
-};
-
-struct device *iucv_root;
-
-/* General IUCV interrupt structure */
-typedef struct {
- __u16 ippathid;
- __u8 res1;
- __u8 iptype;
- __u32 res2;
- __u8 ipvmid[8];
- __u8 res3[24];
-} iucv_GeneralInterrupt;
-
-static iucv_GeneralInterrupt *iucv_external_int_buffer = NULL;
-
-/* Spin Lock declaration */
-
-static DEFINE_SPINLOCK(iucv_lock);
-
-static int messagesDisabled = 0;
-
-/***************INTERRUPT HANDLING ***************/
-
-typedef struct {
- struct list_head queue;
- iucv_GeneralInterrupt data;
-} iucv_irqdata;
-
-static struct list_head iucv_irq_queue;
-static DEFINE_SPINLOCK(iucv_irq_queue_lock);
-
-/*
- *Internal function prototypes
- */
-static void iucv_tasklet_handler(unsigned long);
-static void iucv_irq_handler(__u16);
-
-static DECLARE_TASKLET(iucv_tasklet,iucv_tasklet_handler,0);
-
-/************ FUNCTION ID'S ****************************/
-
-#define ACCEPT 10
-#define CONNECT 11
-#define DECLARE_BUFFER 12
-#define PURGE 9
-#define QUERY 0
-#define QUIESCE 13
-#define RECEIVE 5
-#define REJECT 8
-#define REPLY 6
-#define RESUME 14
-#define RETRIEVE_BUFFER 2
-#define SEND 4
-#define SETMASK 16
-#define SEVER 15
-
-/**
- * Structure: handler
- * members: list - list management.
- * structure: id
- * userid - 8 char array of machine identification
- * user_data - 16 char array for user identification
- * mask - 24 char array used to compare the 2 previous
- * interrupt_table - vector of interrupt functions.
- * pgm_data - ulong, application data that is passed
- * to the interrupt handlers
-*/
-typedef struct handler_t {
- struct list_head list;
- struct {
- __u8 userid[8];
- __u8 user_data[16];
- __u8 mask[24];
- } id;
- iucv_interrupt_ops_t *interrupt_table;
- void *pgm_data;
-} handler;
-
-/**
- * iucv_handler_table: List of registered handlers.
- */
-static struct list_head iucv_handler_table;
-
-/**
- * iucv_pathid_table: an array of *handler pointing into
- * iucv_handler_table for fast indexing by pathid;
- */
-static handler **iucv_pathid_table;
-
-static unsigned long max_connections;
-
-/**
- * iucv_cpuid: contains the logical cpu number of the cpu which
- * has declared the iucv buffer by issuing DECLARE_BUFFER.
- * If no cpu has done the initialization iucv_cpuid contains -1.
- */
-static int iucv_cpuid = -1;
-/**
- * register_flag: is 0 when external interrupt has not been registered
- */
-static int register_flag;
-
-/****************FIVE 40-BYTE PARAMETER STRUCTURES******************/
-/* Data struct 1: iparml_control
- * Used for iucv_accept
- * iucv_connect
- * iucv_quiesce
- * iucv_resume
- * iucv_sever
- * iucv_retrieve_buffer
- * Data struct 2: iparml_dpl (data in parameter list)
- * Used for iucv_send_prmmsg
- * iucv_send2way_prmmsg
- * iucv_send2way_prmmsg_array
- * iucv_reply_prmmsg
- * Data struct 3: iparml_db (data in a buffer)
- * Used for iucv_receive
- * iucv_receive_array
- * iucv_reject
- * iucv_reply
- * iucv_reply_array
- * iucv_send
- * iucv_send_array
- * iucv_send2way
- * iucv_send2way_array
- * iucv_declare_buffer
- * Data struct 4: iparml_purge
- * Used for iucv_purge
- * iucv_query
- * Data struct 5: iparml_set_mask
- * Used for iucv_set_mask
- */
-
-typedef struct {
- __u16 ippathid;
- __u8 ipflags1;
- __u8 iprcode;
- __u16 ipmsglim;
- __u16 res1;
- __u8 ipvmid[8];
- __u8 ipuser[16];
- __u8 iptarget[8];
-} iparml_control;
-
-typedef struct {
- __u16 ippathid;
- __u8 ipflags1;
- __u8 iprcode;
- __u32 ipmsgid;
- __u32 iptrgcls;
- __u8 iprmmsg[8];
- __u32 ipsrccls;
- __u32 ipmsgtag;
- __u32 ipbfadr2;
- __u32 ipbfln2f;
- __u32 res;
-} iparml_dpl;
-
-typedef struct {
- __u16 ippathid;
- __u8 ipflags1;
- __u8 iprcode;
- __u32 ipmsgid;
- __u32 iptrgcls;
- __u32 ipbfadr1;
- __u32 ipbfln1f;
- __u32 ipsrccls;
- __u32 ipmsgtag;
- __u32 ipbfadr2;
- __u32 ipbfln2f;
- __u32 res;
-} iparml_db;
-
-typedef struct {
- __u16 ippathid;
- __u8 ipflags1;
- __u8 iprcode;
- __u32 ipmsgid;
- __u8 ipaudit[3];
- __u8 res1[5];
- __u32 res2;
- __u32 ipsrccls;
- __u32 ipmsgtag;
- __u32 res3[3];
-} iparml_purge;
-
-typedef struct {
- __u8 ipmask;
- __u8 res1[2];
- __u8 iprcode;
- __u32 res2[9];
-} iparml_set_mask;
-
-typedef struct {
- union {
- iparml_control p_ctrl;
- iparml_dpl p_dpl;
- iparml_db p_db;
- iparml_purge p_purge;
- iparml_set_mask p_set_mask;
- } param;
- atomic_t in_use;
- __u32 res;
-} __attribute__ ((aligned(8))) iucv_param;
-#define PARAM_POOL_SIZE (PAGE_SIZE / sizeof(iucv_param))
-
-static iucv_param * iucv_param_pool;
-
-MODULE_AUTHOR("(C) 2001 IBM Corp. by Fritz Elfert (felfert@millenux.com)");
-MODULE_DESCRIPTION("Linux for S/390 IUCV lowlevel driver");
-MODULE_LICENSE("GPL");
-
-/*
- * Debugging stuff
- *******************************************************************************/
-
-
-#ifdef DEBUG
-static int debuglevel = 0;
-
-module_param(debuglevel, int, 0);
-MODULE_PARM_DESC(debuglevel,
- "Specifies the debug level (0=off ... 3=all)");
-
-static void
-iucv_dumpit(char *title, void *buf, int len)
-{
- int i;
- __u8 *p = (__u8 *)buf;
-
- if (debuglevel < 3)
- return;
-
- printk(KERN_DEBUG "%s\n", title);
- printk(" ");
- for (i = 0; i < len; i++) {
- if (!(i % 16) && i != 0)
- printk ("\n ");
- else if (!(i % 4) && i != 0)
- printk(" ");
- printk("%02X", *p++);
- }
- if (len % 16)
- printk ("\n");
- return;
-}
-#define iucv_debug(lvl, fmt, args...) \
-do { \
- if (debuglevel >= lvl) \
- printk(KERN_DEBUG "%s: " fmt "\n", __FUNCTION__ , ## args); \
-} while (0)
-
-#else
-
-#define iucv_debug(lvl, fmt, args...) do { } while (0)
-#define iucv_dumpit(title, buf, len) do { } while (0)
-
-#endif
-
-/*
- * Internal functions
- *******************************************************************************/
-
-/**
- * print start banner
- */
-static void
-iucv_banner(void)
-{
- printk(KERN_INFO "IUCV lowlevel driver initialized\n");
-}
-
-/**
- * iucv_init - Initialization
- *
- * Allocates and initializes various data structures.
- */
-static int
-iucv_init(void)
-{
- int ret;
-
- if (iucv_external_int_buffer)
- return 0;
-
- if (!MACHINE_IS_VM) {
- printk(KERN_ERR "IUCV: IUCV connection needs VM as base\n");
- return -EPROTONOSUPPORT;
- }
-
- ret = bus_register(&iucv_bus);
- if (ret) {
- printk(KERN_ERR "IUCV: failed to register bus.\n");
- return ret;
- }
-
- iucv_root = s390_root_dev_register("iucv");
- if (IS_ERR(iucv_root)) {
- printk(KERN_ERR "IUCV: failed to register iucv root.\n");
- bus_unregister(&iucv_bus);
- return PTR_ERR(iucv_root);
- }
-
- /* Note: GFP_DMA used used to get memory below 2G */
- iucv_external_int_buffer = kzalloc(sizeof(iucv_GeneralInterrupt),
- GFP_KERNEL|GFP_DMA);
- if (!iucv_external_int_buffer) {
- printk(KERN_WARNING
- "%s: Could not allocate external interrupt buffer\n",
- __FUNCTION__);
- s390_root_dev_unregister(iucv_root);
- bus_unregister(&iucv_bus);
- return -ENOMEM;
- }
-
- /* Initialize parameter pool */
- iucv_param_pool = kzalloc(sizeof(iucv_param) * PARAM_POOL_SIZE,
- GFP_KERNEL|GFP_DMA);
- if (!iucv_param_pool) {
- printk(KERN_WARNING "%s: Could not allocate param pool\n",
- __FUNCTION__);
- kfree(iucv_external_int_buffer);
- iucv_external_int_buffer = NULL;
- s390_root_dev_unregister(iucv_root);
- bus_unregister(&iucv_bus);
- return -ENOMEM;
- }
-
- /* Initialize irq queue */
- INIT_LIST_HEAD(&iucv_irq_queue);
-
- /* Initialize handler table */
- INIT_LIST_HEAD(&iucv_handler_table);
-
- iucv_banner();
- return 0;
-}
-
-/**
- * iucv_exit - De-Initialization
- *
- * Frees everything allocated from iucv_init.
- */
-static int iucv_retrieve_buffer (void);
-
-static void
-iucv_exit(void)
-{
- iucv_retrieve_buffer();
- kfree(iucv_external_int_buffer);
- iucv_external_int_buffer = NULL;
- kfree(iucv_param_pool);
- iucv_param_pool = NULL;
- s390_root_dev_unregister(iucv_root);
- bus_unregister(&iucv_bus);
- printk(KERN_INFO "IUCV lowlevel driver unloaded\n");
-}
-
-/**
- * grab_param: - Get a parameter buffer from the pre-allocated pool.
- *
- * This function searches for an unused element in the pre-allocated pool
- * of parameter buffers. If one is found, it marks it "in use" and returns
- * a pointer to it. The calling function is responsible for releasing it
- * when it has finished its usage.
- *
- * Returns: A pointer to iucv_param.
- */
-static __inline__ iucv_param *
-grab_param(void)
-{
- iucv_param *ptr;
- static int hint = 0;
-
- ptr = iucv_param_pool + hint;
- do {
- ptr++;
- if (ptr >= iucv_param_pool + PARAM_POOL_SIZE)
- ptr = iucv_param_pool;
- } while (atomic_cmpxchg(&ptr->in_use, 0, 1) != 0);
- hint = ptr - iucv_param_pool;
-
- memset(&ptr->param, 0, sizeof(ptr->param));
- return ptr;
-}
-
-/**
- * release_param - Release a parameter buffer.
- * @p: A pointer to a struct iucv_param, previously obtained by calling
- * grab_param().
- *
- * This function marks the specified parameter buffer "unused".
- */
-static __inline__ void
-release_param(void *p)
-{
- atomic_set(&((iucv_param *)p)->in_use, 0);
-}
-
-/**
- * iucv_add_handler: - Add a new handler
- * @new_handler: handle that is being entered into chain.
- *
- * Places new handle on iucv_handler_table, if identical handler is not
- * found.
- *
- * Returns: 0 on success, !0 on failure (handler already in chain).
- */
-static int
-iucv_add_handler (handler *new)
-{
- ulong flags;
-
- iucv_debug(1, "entering");
- iucv_dumpit("handler:", new, sizeof(handler));
-
- spin_lock_irqsave (&iucv_lock, flags);
- if (!list_empty(&iucv_handler_table)) {
- struct list_head *lh;
-
- /**
- * Search list for handler with identical id. If one
- * is found, the new handler is _not_ added.
- */
- list_for_each(lh, &iucv_handler_table) {
- handler *h = list_entry(lh, handler, list);
- if (!memcmp(&new->id, &h->id, sizeof(h->id))) {
- iucv_debug(1, "ret 1");
- spin_unlock_irqrestore (&iucv_lock, flags);
- return 1;
- }
- }
- }
- /**
- * If we get here, no handler was found.
- */
- INIT_LIST_HEAD(&new->list);
- list_add(&new->list, &iucv_handler_table);
- spin_unlock_irqrestore (&iucv_lock, flags);
-
- iucv_debug(1, "exiting");
- return 0;
-}
-
-/**
- * b2f0:
- * @code: identifier of IUCV call to CP.
- * @parm: pointer to 40 byte iparml area passed to CP
- *
- * Calls CP to execute IUCV commands.
- *
- * Returns: return code from CP's IUCV call
- */
-static inline ulong b2f0(__u32 code, void *parm)
-{
- register unsigned long reg0 asm ("0");
- register unsigned long reg1 asm ("1");
- iucv_dumpit("iparml before b2f0 call:", parm, sizeof(iucv_param));
-
- reg0 = code;
- reg1 = virt_to_phys(parm);
- asm volatile(".long 0xb2f01000" : : "d" (reg0), "a" (reg1));
-
- iucv_dumpit("iparml after b2f0 call:", parm, sizeof(iucv_param));
-
- return (unsigned long)*((__u8 *)(parm + 3));
-}
-
-/*
- * Name: iucv_add_pathid
- * Purpose: Adds a path id to the system.
- * Input: pathid - pathid that is going to be entered into system
- * handle - address of handler that the pathid will be associated
- * with.
- * pgm_data - token passed in by application.
- * Output: 0: successful addition of pathid
- * - EINVAL - pathid entry is being used by another application
- * - ENOMEM - storage allocation for a new pathid table failed
-*/
-static int
-__iucv_add_pathid(__u16 pathid, handler *handler)
-{
-
- iucv_debug(1, "entering");
-
- iucv_debug(1, "handler is pointing to %p", handler);
-
- if (pathid > (max_connections - 1))
- return -EINVAL;
-
- if (iucv_pathid_table[pathid]) {
- iucv_debug(1, "pathid entry is %p", iucv_pathid_table[pathid]);
- printk(KERN_WARNING
- "%s: Pathid being used, error.\n", __FUNCTION__);
- return -EINVAL;
- }
- iucv_pathid_table[pathid] = handler;
-
- iucv_debug(1, "exiting");
- return 0;
-} /* end of add_pathid function */
-
-static int
-iucv_add_pathid(__u16 pathid, handler *handler)
-{
- ulong flags;
- int rc;
-
- spin_lock_irqsave (&iucv_lock, flags);
- rc = __iucv_add_pathid(pathid, handler);
- spin_unlock_irqrestore (&iucv_lock, flags);
- return rc;
-}
-
-static void
-iucv_remove_pathid(__u16 pathid)
-{
- ulong flags;
-
- if (pathid > (max_connections - 1))
- return;
-
- spin_lock_irqsave (&iucv_lock, flags);
- iucv_pathid_table[pathid] = NULL;
- spin_unlock_irqrestore (&iucv_lock, flags);
-}
-
-/**
- * iucv_declare_buffer_cpuid
- * Register at VM for subsequent IUCV operations. This is executed
- * on the reserved CPU iucv_cpuid. Called from iucv_declare_buffer().
- */
-static void
-iucv_declare_buffer_cpuid (void *result)
-{
- iparml_db *parm;
-
- parm = (iparml_db *)grab_param();
- parm->ipbfadr1 = virt_to_phys(iucv_external_int_buffer);
- if ((*((ulong *)result) = b2f0(DECLARE_BUFFER, parm)) == 1)
- *((ulong *)result) = parm->iprcode;
- release_param(parm);
-}
-
-/**
- * iucv_retrieve_buffer_cpuid:
- * Unregister IUCV usage at VM. This is always executed on the same
- * cpu that registered the buffer to VM.
- * Called from iucv_retrieve_buffer().
- */
-static void
-iucv_retrieve_buffer_cpuid (void *cpu)
-{
- iparml_control *parm;
-
- parm = (iparml_control *)grab_param();
- b2f0(RETRIEVE_BUFFER, parm);
- release_param(parm);
-}
-
-/**
- * Name: iucv_declare_buffer
- * Purpose: Specifies the guests real address of an external
- * interrupt.
- * Input: void
- * Output: iprcode - return code from b2f0 call
- */
-static int
-iucv_declare_buffer (void)
-{
- unsigned long flags;
- ulong b2f0_result;
-
- iucv_debug(1, "entering");
- b2f0_result = -ENODEV;
- spin_lock_irqsave (&iucv_lock, flags);
- if (iucv_cpuid == -1) {
- /* Reserve any cpu for use by iucv. */
- iucv_cpuid = smp_get_cpu(CPU_MASK_ALL);
- spin_unlock_irqrestore (&iucv_lock, flags);
- smp_call_function_on(iucv_declare_buffer_cpuid,
- &b2f0_result, 0, 1, iucv_cpuid);
- if (b2f0_result) {
- smp_put_cpu(iucv_cpuid);
- iucv_cpuid = -1;
- }
- iucv_debug(1, "Address of EIB = %p", iucv_external_int_buffer);
- } else {
- spin_unlock_irqrestore (&iucv_lock, flags);
- b2f0_result = 0;
- }
- iucv_debug(1, "exiting");
- return b2f0_result;
-}
-
-/**
- * iucv_retrieve_buffer:
- *
- * Terminates all use of IUCV.
- * Returns: return code from CP
- */
-static int
-iucv_retrieve_buffer (void)
-{
- iucv_debug(1, "entering");
- if (iucv_cpuid != -1) {
- smp_call_function_on(iucv_retrieve_buffer_cpuid,
- NULL, 0, 1, iucv_cpuid);
- /* Release the cpu reserved by iucv_declare_buffer. */
- smp_put_cpu(iucv_cpuid);
- iucv_cpuid = -1;
- }
- iucv_debug(1, "exiting");
- return 0;
-}
-
-/**
- * iucv_remove_handler:
- * @users_handler: handler to be removed
- *
- * Remove handler when application unregisters.
- */
-static void
-iucv_remove_handler(handler *handler)
-{
- unsigned long flags;
-
- if ((!iucv_pathid_table) || (!handler))
- return;
-
- iucv_debug(1, "entering");
-
- spin_lock_irqsave (&iucv_lock, flags);
- list_del(&handler->list);
- if (list_empty(&iucv_handler_table)) {
- if (register_flag) {
- unregister_external_interrupt(0x4000, iucv_irq_handler);
- register_flag = 0;
- }
- }
- spin_unlock_irqrestore (&iucv_lock, flags);
-
- iucv_debug(1, "exiting");
- return;
-}
-
-/**
- * iucv_register_program:
- * @pgmname: user identification
- * @userid: machine identification
- * @pgmmask: Indicates which bits in the pgmname and userid combined will be
- * used to determine who is given control.
- * @ops: Address of interrupt handler table.
- * @pgm_data: Application data to be passed to interrupt handlers.
- *
- * Registers an application with IUCV.
- * Returns:
- * The address of handler, or NULL on failure.
- * NOTE on pgmmask:
- * If pgmname, userid and pgmmask are provided, pgmmask is entered into the
- * handler as is.
- * If pgmmask is NULL, the internal mask is set to all 0xff's
- * When userid is NULL, the first 8 bytes of the internal mask are forced
- * to 0x00.
- * If pgmmask and userid are NULL, the first 8 bytes of the internal mask
- * are forced to 0x00 and the last 16 bytes to 0xff.
- */
-
-iucv_handle_t
-iucv_register_program (__u8 pgmname[16],
- __u8 userid[8],
- __u8 pgmmask[24],
- iucv_interrupt_ops_t * ops, void *pgm_data)
-{
- ulong rc = 0; /* return code from function calls */
- handler *new_handler;
-
- iucv_debug(1, "entering");
-
- if (ops == NULL) {
- /* interrupt table is not defined */
- printk(KERN_WARNING "%s: Interrupt table is not defined, "
- "exiting\n", __FUNCTION__);
- return NULL;
- }
- if (!pgmname) {
- printk(KERN_WARNING "%s: pgmname not provided\n", __FUNCTION__);
- return NULL;
- }
-
- /* Allocate handler entry */
- new_handler = kmalloc(sizeof(handler), GFP_ATOMIC);
- if (new_handler == NULL) {
- printk(KERN_WARNING "%s: storage allocation for new handler "
- "failed.\n", __FUNCTION__);
- return NULL;
- }
-
- if (!iucv_pathid_table) {
- if (iucv_init()) {
- kfree(new_handler);
- return NULL;
- }
-
- max_connections = iucv_query_maxconn();
- iucv_pathid_table = kcalloc(max_connections, sizeof(handler *),
- GFP_ATOMIC);
- if (iucv_pathid_table == NULL) {
- printk(KERN_WARNING "%s: iucv_pathid_table storage "
- "allocation failed\n", __FUNCTION__);
- kfree(new_handler);
- return NULL;
- }
- }
- memset(new_handler, 0, sizeof (handler));
- memcpy(new_handler->id.user_data, pgmname,
- sizeof (new_handler->id.user_data));
- if (userid) {
- memcpy (new_handler->id.userid, userid,
- sizeof (new_handler->id.userid));
- ASCEBC (new_handler->id.userid,
- sizeof (new_handler->id.userid));
- EBC_TOUPPER (new_handler->id.userid,
- sizeof (new_handler->id.userid));
-
- if (pgmmask) {
- memcpy (new_handler->id.mask, pgmmask,
- sizeof (new_handler->id.mask));
- } else {
- memset (new_handler->id.mask, 0xFF,
- sizeof (new_handler->id.mask));
- }
- } else {
- if (pgmmask) {
- memcpy (new_handler->id.mask, pgmmask,
- sizeof (new_handler->id.mask));
- } else {
- memset (new_handler->id.mask, 0xFF,
- sizeof (new_handler->id.mask));
- }
- memset (new_handler->id.userid, 0x00,
- sizeof (new_handler->id.userid));
- }
- /* fill in the rest of handler */
- new_handler->pgm_data = pgm_data;
- new_handler->interrupt_table = ops;
-
- /*
- * Check if someone else is registered with same pgmname, userid
- * and mask. If someone is already registered with same pgmname,
- * userid and mask, registration will fail and NULL will be returned
- * to the application.
- * If identical handler not found, then handler is added to list.
- */
- rc = iucv_add_handler(new_handler);
- if (rc) {
- printk(KERN_WARNING "%s: Someone already registered with same "
- "pgmname, userid, pgmmask\n", __FUNCTION__);
- kfree (new_handler);
- return NULL;
- }
-
- rc = iucv_declare_buffer();
- if (rc) {
- char *err = "Unknown";
- iucv_remove_handler(new_handler);
- kfree(new_handler);
- switch(rc) {
- case 0x03:
- err = "Directory error";
- break;
- case 0x0a:
- err = "Invalid length";
- break;
- case 0x13:
- err = "Buffer already exists";
- break;
- case 0x3e:
- err = "Buffer overlap";
- break;
- case 0x5c:
- err = "Paging or storage error";
- break;
- }
- printk(KERN_WARNING "%s: iucv_declare_buffer "
- "returned error 0x%02lx (%s)\n", __FUNCTION__, rc, err);
- return NULL;
- }
- if (!register_flag) {
- /* request the 0x4000 external interrupt */
- rc = register_external_interrupt (0x4000, iucv_irq_handler);
- if (rc) {
- iucv_remove_handler(new_handler);
- kfree (new_handler);
- printk(KERN_WARNING "%s: "
- "register_external_interrupt returned %ld\n",
- __FUNCTION__, rc);
- return NULL;
-
- }
- register_flag = 1;
- }
- iucv_debug(1, "exiting");
- return new_handler;
-} /* end of register function */
-
-/**
- * iucv_unregister_program:
- * @handle: address of handler
- *
- * Unregister application with IUCV.
- * Returns:
- * 0 on success, -EINVAL, if specified handle is invalid.
- */
-
-int
-iucv_unregister_program (iucv_handle_t handle)
-{
- handler *h = NULL;
- struct list_head *lh;
- int i;
- ulong flags;
-
- iucv_debug(1, "entering");
- iucv_debug(1, "address of handler is %p", h);
-
- /* Checking if handle is valid */
- spin_lock_irqsave (&iucv_lock, flags);
- list_for_each(lh, &iucv_handler_table) {
- if ((handler *)handle == list_entry(lh, handler, list)) {
- h = (handler *)handle;
- break;
- }
- }
- if (!h) {
- spin_unlock_irqrestore (&iucv_lock, flags);
- if (handle)
- printk(KERN_WARNING
- "%s: Handler not found in iucv_handler_table.\n",
- __FUNCTION__);
- else
- printk(KERN_WARNING
- "%s: NULL handle passed by application.\n",
- __FUNCTION__);
- return -EINVAL;
- }
-
- /**
- * First, walk thru iucv_pathid_table and sever any pathid which is
- * still pointing to the handler to be removed.
- */
- for (i = 0; i < max_connections; i++)
- if (iucv_pathid_table[i] == h) {
- spin_unlock_irqrestore (&iucv_lock, flags);
- iucv_sever(i, h->id.user_data);
- spin_lock_irqsave(&iucv_lock, flags);
- }
- spin_unlock_irqrestore (&iucv_lock, flags);
-
- iucv_remove_handler(h);
- kfree(h);
-
- iucv_debug(1, "exiting");
- return 0;
-}
-
-/**
- * iucv_accept:
- * @pathid: Path identification number
- * @msglim_reqstd: The number of outstanding messages requested.
- * @user_data: Data specified by the iucv_connect function.
- * @flags1: Contains options for this path.
- * - IPPRTY (0x20) Specifies if you want to send priority message.
- * - IPRMDATA (0x80) Specifies whether your program can handle a message
- * in the parameter list.
- * - IPQUSCE (0x40) Specifies whether you want to quiesce the path being
- * established.
- * @handle: Address of handler.
- * @pgm_data: Application data passed to interrupt handlers.
- * @flags1_out: Pointer to an int. If not NULL, on return the options for
- * the path are stored at the given location:
- * - IPPRTY (0x20) Indicates you may send a priority message.
- * @msglim: Pointer to an __u16. If not NULL, on return the maximum
- * number of outstanding messages is stored at the given
- * location.
- *
- * This function is issued after the user receives a Connection Pending external
- * interrupt and now wishes to complete the IUCV communication path.
- * Returns:
- * return code from CP
- */
-int
-iucv_accept(__u16 pathid, __u16 msglim_reqstd,
- __u8 user_data[16], int flags1,
- iucv_handle_t handle, void *pgm_data,
- int *flags1_out, __u16 * msglim)
-{
- ulong b2f0_result = 0;
- ulong flags;
- struct list_head *lh;
- handler *h = NULL;
- iparml_control *parm;
-
- iucv_debug(1, "entering");
- iucv_debug(1, "pathid = %d", pathid);
-
- /* Checking if handle is valid */
- spin_lock_irqsave (&iucv_lock, flags);
- list_for_each(lh, &iucv_handler_table) {
- if ((handler *)handle == list_entry(lh, handler, list)) {
- h = (handler *)handle;
- break;
- }
- }
- spin_unlock_irqrestore (&iucv_lock, flags);
-
- if (!h) {
- if (handle)
- printk(KERN_WARNING
- "%s: Handler not found in iucv_handler_table.\n",
- __FUNCTION__);
- else
- printk(KERN_WARNING
- "%s: NULL handle passed by application.\n",
- __FUNCTION__);
- return -EINVAL;
- }
-
- parm = (iparml_control *)grab_param();
-
- parm->ippathid = pathid;
- parm->ipmsglim = msglim_reqstd;
- if (user_data)
- memcpy(parm->ipuser, user_data, sizeof(parm->ipuser));
-
- parm->ipflags1 = (__u8)flags1;
- b2f0_result = b2f0(ACCEPT, parm);
-
- if (!b2f0_result) {
- if (msglim)
- *msglim = parm->ipmsglim;
- if (pgm_data)
- h->pgm_data = pgm_data;
- if (flags1_out)
- *flags1_out = (parm->ipflags1 & IPPRTY) ? IPPRTY : 0;
- }
- release_param(parm);
-
- iucv_debug(1, "exiting");
- return b2f0_result;
-}
-
-/**
- * iucv_connect:
- * @pathid: Path identification number
- * @msglim_reqstd: Number of outstanding messages requested
- * @user_data: 16-byte user data
- * @userid: 8-byte of user identification
- * @system_name: 8-byte identifying the system name
- * @flags1: Specifies options for this path:
- * - IPPRTY (0x20) Specifies if you want to send priority message.
- * - IPRMDATA (0x80) Specifies whether your program can handle a message
- * in the parameter list.
- * - IPQUSCE (0x40) Specifies whether you want to quiesce the path being
- * established.
- * - IPLOCAL (0x01) Allows an application to force the partner to be on the
- * local system. If local is specified then target class
- * cannot be specified.
- * @flags1_out: Pointer to an int. If not NULL, on return the options for
- * the path are stored at the given location:
- * - IPPRTY (0x20) Indicates you may send a priority message.
- * @msglim: Pointer to an __u16. If not NULL, on return the maximum
- * number of outstanding messages is stored at the given
- * location.
- * @handle: Address of handler.
- * @pgm_data: Application data to be passed to interrupt handlers.
- *
- * This function establishes an IUCV path. Although the connect may complete
- * successfully, you are not able to use the path until you receive an IUCV
- * Connection Complete external interrupt.
- * Returns: return code from CP, or one of the following
- * - ENOMEM
- * - return code from iucv_declare_buffer
- * - EINVAL - invalid handle passed by application
- * - EINVAL - pathid address is NULL
- * - ENOMEM - pathid table storage allocation failed
- * - return code from internal function add_pathid
- */
-int
-iucv_connect (__u16 *pathid, __u16 msglim_reqstd,
- __u8 user_data[16], __u8 userid[8],
- __u8 system_name[8], int flags1,
- int *flags1_out, __u16 * msglim,
- iucv_handle_t handle, void *pgm_data)
-{
- iparml_control *parm;
- iparml_control local_parm;
- struct list_head *lh;
- ulong b2f0_result = 0;
- ulong flags;
- int add_pathid_result = 0;
- handler *h = NULL;
- __u8 no_memory[16] = "NO MEMORY";
-
- iucv_debug(1, "entering");
-
- /* Checking if handle is valid */
- spin_lock_irqsave (&iucv_lock, flags);
- list_for_each(lh, &iucv_handler_table) {
- if ((handler *)handle == list_entry(lh, handler, list)) {
- h = (handler *)handle;
- break;
- }
- }
- spin_unlock_irqrestore (&iucv_lock, flags);
-
- if (!h) {
- if (handle)
- printk(KERN_WARNING
- "%s: Handler not found in iucv_handler_table.\n",
- __FUNCTION__);
- else
- printk(KERN_WARNING
- "%s: NULL handle passed by application.\n",
- __FUNCTION__);
- return -EINVAL;
- }
-
- if (pathid == NULL) {
- printk(KERN_WARNING "%s: NULL pathid pointer\n",
- __FUNCTION__);
- return -EINVAL;
- }
-
- parm = (iparml_control *)grab_param();
-
- parm->ipmsglim = msglim_reqstd;
-
- if (user_data)
- memcpy(parm->ipuser, user_data, sizeof(parm->ipuser));
-
- if (userid) {
- memcpy(parm->ipvmid, userid, sizeof(parm->ipvmid));
- ASCEBC(parm->ipvmid, sizeof(parm->ipvmid));
- EBC_TOUPPER(parm->ipvmid, sizeof(parm->ipvmid));
- }
-
- if (system_name) {
- memcpy(parm->iptarget, system_name, sizeof(parm->iptarget));
- ASCEBC(parm->iptarget, sizeof(parm->iptarget));
- EBC_TOUPPER(parm->iptarget, sizeof(parm->iptarget));
- }
-
- /* In order to establish an IUCV connection, the procedure is:
- *
- * b2f0(CONNECT)
- * take the ippathid from the b2f0 call
- * register the handler to the ippathid
- *
- * Unfortunately, the ConnectionEstablished message gets sent after the
- * b2f0(CONNECT) call but before the register is handled.
- *
- * In order for this race condition to be eliminated, the IUCV Control
- * Interrupts must be disabled for the above procedure.
- *
- * David Kennedy <dkennedy@linuxcare.com>
- */
-
- /* Enable everything but IUCV Control messages */
- iucv_setmask(~(AllInterrupts));
- messagesDisabled = 1;
-
- spin_lock_irqsave (&iucv_lock, flags);
- parm->ipflags1 = (__u8)flags1;
- b2f0_result = b2f0(CONNECT, parm);
- memcpy(&local_parm, parm, sizeof(local_parm));
- release_param(parm);
- parm = &local_parm;
- if (!b2f0_result)
- add_pathid_result = __iucv_add_pathid(parm->ippathid, h);
- spin_unlock_irqrestore (&iucv_lock, flags);
-
- if (b2f0_result) {
- iucv_setmask(~0);
- messagesDisabled = 0;
- return b2f0_result;
- }
-
- *pathid = parm->ippathid;
-
- /* Enable everything again */
- iucv_setmask(IUCVControlInterruptsFlag);
-
- if (msglim)
- *msglim = parm->ipmsglim;
- if (flags1_out)
- *flags1_out = (parm->ipflags1 & IPPRTY) ? IPPRTY : 0;
-
- if (add_pathid_result) {
- iucv_sever(*pathid, no_memory);
- printk(KERN_WARNING "%s: add_pathid failed with rc ="
- " %d\n", __FUNCTION__, add_pathid_result);
- return(add_pathid_result);
- }
-
- iucv_debug(1, "exiting");
- return b2f0_result;
-}
-
-/**
- * iucv_purge:
- * @pathid: Path identification number
- * @msgid: Message ID of message to purge.
- * @srccls: Message class of the message to purge.
- * @audit: Pointer to an __u32. If not NULL, on return, information about
- * asynchronous errors that may have affected the normal completion
- * of this message ist stored at the given location.
- *
- * Cancels a message you have sent.
- * Returns: return code from CP
- */
-int
-iucv_purge (__u16 pathid, __u32 msgid, __u32 srccls, __u32 *audit)
-{
- iparml_purge *parm;
- ulong b2f0_result = 0;
-
- iucv_debug(1, "entering");
- iucv_debug(1, "pathid = %d", pathid);
-
- parm = (iparml_purge *)grab_param();
-
- parm->ipmsgid = msgid;
- parm->ippathid = pathid;
- parm->ipsrccls = srccls;
- parm->ipflags1 |= (IPSRCCLS | IPFGMID | IPFGPID);
- b2f0_result = b2f0(PURGE, parm);
-
- if (!b2f0_result && audit) {
- memcpy(audit, parm->ipaudit, sizeof(parm->ipaudit));
- /* parm->ipaudit has only 3 bytes */
- *audit >>= 8;
- }
-
- release_param(parm);
-
- iucv_debug(1, "b2f0_result = %ld", b2f0_result);
- iucv_debug(1, "exiting");
- return b2f0_result;
-}
-
-/**
- * iucv_query_generic:
- * @want_maxconn: Flag, describing which value is to be returned.
- *
- * Helper function for iucv_query_maxconn() and iucv_query_bufsize().
- *
- * Returns: The buffersize, if want_maxconn is 0; the maximum number of
- * connections, if want_maxconn is 1 or an error-code < 0 on failure.
- */
-static int
-iucv_query_generic(int want_maxconn)
-{
- register unsigned long reg0 asm ("0");
- register unsigned long reg1 asm ("1");
- iparml_purge *parm = (iparml_purge *)grab_param();
- int bufsize, maxconn;
- int ccode;
-
- /**
- * Call b2f0 and store R0 (max buffer size),
- * R1 (max connections) and CC.
- */
- reg0 = QUERY;
- reg1 = virt_to_phys(parm);
- asm volatile(
- " .long 0xb2f01000\n"
- " ipm %0\n"
- " srl %0,28\n"
- : "=d" (ccode), "+d" (reg0), "+d" (reg1) : : "cc");
- bufsize = reg0;
- maxconn = reg1;
- release_param(parm);
-
- if (ccode)
- return -EPERM;
- if (want_maxconn)
- return maxconn;
- return bufsize;
-}
-
-/**
- * iucv_query_maxconn:
- *
- * Determines the maximum number of connections thay may be established.
- *
- * Returns: Maximum number of connections that can be.
- */
-ulong
-iucv_query_maxconn(void)
-{
- return iucv_query_generic(1);
-}
-
-/**
- * iucv_query_bufsize:
- *
- * Determines the size of the external interrupt buffer.
- *
- * Returns: Size of external interrupt buffer.
- */
-ulong
-iucv_query_bufsize (void)
-{
- return iucv_query_generic(0);
-}
-
-/**
- * iucv_quiesce:
- * @pathid: Path identification number
- * @user_data: 16-byte user data
- *
- * Temporarily suspends incoming messages on an IUCV path.
- * You can later reactivate the path by invoking the iucv_resume function.
- * Returns: return code from CP
- */
-int
-iucv_quiesce (__u16 pathid, __u8 user_data[16])
-{
- iparml_control *parm;
- ulong b2f0_result = 0;
-
- iucv_debug(1, "entering");
- iucv_debug(1, "pathid = %d", pathid);
-
- parm = (iparml_control *)grab_param();
-
- memcpy(parm->ipuser, user_data, sizeof(parm->ipuser));
- parm->ippathid = pathid;
-
- b2f0_result = b2f0(QUIESCE, parm);
- release_param(parm);
-
- iucv_debug(1, "b2f0_result = %ld", b2f0_result);
- iucv_debug(1, "exiting");
-
- return b2f0_result;
-}
-
-/**
- * iucv_receive:
- * @pathid: Path identification number.
- * @buffer: Address of buffer to receive. Must be below 2G.
- * @buflen: Length of buffer to receive.
- * @msgid: Specifies the message ID.
- * @trgcls: Specifies target class.
- * @flags1_out: Receives options for path on return.
- * - IPNORPY (0x10) Specifies whether a reply is required
- * - IPPRTY (0x20) Specifies if you want to send priority message
- * - IPRMDATA (0x80) Specifies the data is contained in the parameter list
- * @residual_buffer: Receives the address of buffer updated by the number
- * of bytes you have received on return.
- * @residual_length: On return, receives one of the following values:
- * - 0 If the receive buffer is the same length as
- * the message.
- * - Remaining bytes in buffer If the receive buffer is longer than the
- * message.
- * - Remaining bytes in message If the receive buffer is shorter than the
- * message.
- *
- * This function receives messages that are being sent to you over established
- * paths.
- * Returns: return code from CP IUCV call; If the receive buffer is shorter
- * than the message, always 5
- * -EINVAL - buffer address is pointing to NULL
- */
-int
-iucv_receive (__u16 pathid, __u32 msgid, __u32 trgcls,
- void *buffer, ulong buflen,
- int *flags1_out, ulong * residual_buffer, ulong * residual_length)
-{
- iparml_db *parm;
- ulong b2f0_result;
- int moved = 0; /* number of bytes moved from parmlist to buffer */
-
- iucv_debug(2, "entering");
-
- if (!buffer)
- return -EINVAL;
-
- parm = (iparml_db *)grab_param();
-
- parm->ipbfadr1 = (__u32) (addr_t) buffer;
- parm->ipbfln1f = (__u32) ((ulong) buflen);
- parm->ipmsgid = msgid;
- parm->ippathid = pathid;
- parm->iptrgcls = trgcls;
- parm->ipflags1 = (IPFGPID | IPFGMID | IPFGMCL);
-
- b2f0_result = b2f0(RECEIVE, parm);
-
- if (!b2f0_result || b2f0_result == 5) {
- if (flags1_out) {
- iucv_debug(2, "*flags1_out = %d", *flags1_out);
- *flags1_out = (parm->ipflags1 & (~0x07));
- iucv_debug(2, "*flags1_out = %d", *flags1_out);
- }
-
- if (!(parm->ipflags1 & IPRMDATA)) { /*msg not in parmlist */
- if (residual_length)
- *residual_length = parm->ipbfln1f;
-
- if (residual_buffer)
- *residual_buffer = parm->ipbfadr1;
- } else {
- moved = min_t (unsigned long, buflen, 8);
-
- memcpy ((char *) buffer,
- (char *) &parm->ipbfadr1, moved);
-
- if (buflen < 8)
- b2f0_result = 5;
-
- if (residual_length)
- *residual_length = abs (buflen - 8);
-
- if (residual_buffer)
- *residual_buffer = (ulong) (buffer + moved);
- }
- }
- release_param(parm);
-
- iucv_debug(2, "exiting");
- return b2f0_result;
-}
-
-/*
- * Name: iucv_receive_array
- * Purpose: This function receives messages that are being sent to you
- * over established paths.
- * Input: pathid - path identification number
- * buffer - address of array of buffers
- * buflen - total length of buffers
- * msgid - specifies the message ID.
- * trgcls - specifies target class
- * Output:
- * flags1_out: Options for path.
- * IPNORPY - 0x10 specifies whether a reply is required
- * IPPRTY - 0x20 specifies if you want to send priority message
- * IPRMDATA - 0x80 specifies the data is contained in the parameter list
- * residual_buffer - address points to the current list entry IUCV
- * is working on.
- * residual_length -
- * Contains one of the following values, if the receive buffer is:
- * The same length as the message, this field is zero.
- * Longer than the message, this field contains the number of
- * bytes remaining in the buffer.
- * Shorter than the message, this field contains the residual
- * count (that is, the number of bytes remaining in the
- * message that does not fit into the buffer. In this case
- * b2f0_result = 5.
- * Return: b2f0_result - return code from CP
- * (-EINVAL) - buffer address is NULL
- */
-int
-iucv_receive_array (__u16 pathid,
- __u32 msgid, __u32 trgcls,
- iucv_array_t * buffer, ulong buflen,
- int *flags1_out,
- ulong * residual_buffer, ulong * residual_length)
-{
- iparml_db *parm;
- ulong b2f0_result;
- int i = 0, moved = 0, need_to_move = 8, dyn_len;
-
- iucv_debug(2, "entering");
-
- if (!buffer)
- return -EINVAL;
-
- parm = (iparml_db *)grab_param();
-
- parm->ipbfadr1 = (__u32) ((ulong) buffer);
- parm->ipbfln1f = (__u32) buflen;
- parm->ipmsgid = msgid;
- parm->ippathid = pathid;
- parm->iptrgcls = trgcls;
- parm->ipflags1 = (IPBUFLST | IPFGPID | IPFGMID | IPFGMCL);
-
- b2f0_result = b2f0(RECEIVE, parm);
-
- if (!b2f0_result || b2f0_result == 5) {
-
- if (flags1_out) {
- iucv_debug(2, "*flags1_out = %d", *flags1_out);
- *flags1_out = (parm->ipflags1 & (~0x07));
- iucv_debug(2, "*flags1_out = %d", *flags1_out);
- }
-
- if (!(parm->ipflags1 & IPRMDATA)) { /*msg not in parmlist */
-
- if (residual_length)
- *residual_length = parm->ipbfln1f;
-
- if (residual_buffer)
- *residual_buffer = parm->ipbfadr1;
-
- } else {
- /* copy msg from parmlist to users array. */
-
- while ((moved < 8) && (moved < buflen)) {
- dyn_len =
- min_t (unsigned int,
- (buffer + i)->length, need_to_move);
-
- memcpy ((char *)((ulong)((buffer + i)->address)),
- ((char *) &parm->ipbfadr1) + moved,
- dyn_len);
-
- moved += dyn_len;
- need_to_move -= dyn_len;
-
- (buffer + i)->address =
- (__u32)
- ((ulong)(__u8 *) ((ulong)(buffer + i)->address)
- + dyn_len);
-
- (buffer + i)->length -= dyn_len;
- i++;
- }
-
- if (need_to_move) /* buflen < 8 bytes */
- b2f0_result = 5;
-
- if (residual_length)
- *residual_length = abs (buflen - 8);
-
- if (residual_buffer) {
- if (!moved)
- *residual_buffer = (ulong) buffer;
- else
- *residual_buffer =
- (ulong) (buffer + (i - 1));
- }
-
- }
- }
- release_param(parm);
-
- iucv_debug(2, "exiting");
- return b2f0_result;
-}
-
-/**
- * iucv_reject:
- * @pathid: Path identification number.
- * @msgid: Message ID of the message to reject.
- * @trgcls: Target class of the message to reject.
- * Returns: return code from CP
- *
- * Refuses a specified message. Between the time you are notified of a
- * message and the time that you complete the message, the message may
- * be rejected.
- */
-int
-iucv_reject (__u16 pathid, __u32 msgid, __u32 trgcls)
-{
- iparml_db *parm;
- ulong b2f0_result = 0;
-
- iucv_debug(1, "entering");
- iucv_debug(1, "pathid = %d", pathid);
-
- parm = (iparml_db *)grab_param();
-
- parm->ippathid = pathid;
- parm->ipmsgid = msgid;
- parm->iptrgcls = trgcls;
- parm->ipflags1 = (IPFGMCL | IPFGMID | IPFGPID);
-
- b2f0_result = b2f0(REJECT, parm);
- release_param(parm);
-
- iucv_debug(1, "b2f0_result = %ld", b2f0_result);
- iucv_debug(1, "exiting");
-
- return b2f0_result;
-}
-
-/*
- * Name: iucv_reply
- * Purpose: This function responds to the two-way messages that you
- * receive. You must identify completely the message to
- * which you wish to reply. ie, pathid, msgid, and trgcls.
- * Input: pathid - path identification number
- * msgid - specifies the message ID.
- * trgcls - specifies target class
- * flags1 - option for path
- * IPPRTY- 0x20 - specifies if you want to send priority message
- * buffer - address of reply buffer
- * buflen - length of reply buffer
- * Output: ipbfadr2 - Address of buffer updated by the number
- * of bytes you have moved.
- * ipbfln2f - Contains one of the following values:
- * If the answer buffer is the same length as the reply, this field
- * contains zero.
- * If the answer buffer is longer than the reply, this field contains
- * the number of bytes remaining in the buffer.
- * If the answer buffer is shorter than the reply, this field contains
- * a residual count (that is, the number of bytes remianing in the
- * reply that does not fit into the buffer. In this
- * case b2f0_result = 5.
- * Return: b2f0_result - return code from CP
- * (-EINVAL) - buffer address is NULL
- */
-int
-iucv_reply (__u16 pathid,
- __u32 msgid, __u32 trgcls,
- int flags1,
- void *buffer, ulong buflen, ulong * ipbfadr2, ulong * ipbfln2f)
-{
- iparml_db *parm;
- ulong b2f0_result;
-
- iucv_debug(2, "entering");
-
- if (!buffer)
- return -EINVAL;
-
- parm = (iparml_db *)grab_param();
-
- parm->ipbfadr2 = (__u32) ((ulong) buffer);
- parm->ipbfln2f = (__u32) buflen; /* length of message */
- parm->ippathid = pathid;
- parm->ipmsgid = msgid;
- parm->iptrgcls = trgcls;
- parm->ipflags1 = (__u8) flags1; /* priority message */
-
- b2f0_result = b2f0(REPLY, parm);
-
- if ((!b2f0_result) || (b2f0_result == 5)) {
- if (ipbfadr2)
- *ipbfadr2 = parm->ipbfadr2;
- if (ipbfln2f)
- *ipbfln2f = parm->ipbfln2f;
- }
- release_param(parm);
-
- iucv_debug(2, "exiting");
-
- return b2f0_result;
-}
-
-/*
- * Name: iucv_reply_array
- * Purpose: This function responds to the two-way messages that you
- * receive. You must identify completely the message to
- * which you wish to reply. ie, pathid, msgid, and trgcls.
- * The array identifies a list of addresses and lengths of
- * discontiguous buffers that contains the reply data.
- * Input: pathid - path identification number
- * msgid - specifies the message ID.
- * trgcls - specifies target class
- * flags1 - option for path
- * IPPRTY- specifies if you want to send priority message
- * buffer - address of array of reply buffers
- * buflen - total length of reply buffers
- * Output: ipbfadr2 - Address of buffer which IUCV is currently working on.
- * ipbfln2f - Contains one of the following values:
- * If the answer buffer is the same length as the reply, this field
- * contains zero.
- * If the answer buffer is longer than the reply, this field contains
- * the number of bytes remaining in the buffer.
- * If the answer buffer is shorter than the reply, this field contains
- * a residual count (that is, the number of bytes remianing in the
- * reply that does not fit into the buffer. In this
- * case b2f0_result = 5.
- * Return: b2f0_result - return code from CP
- * (-EINVAL) - buffer address is NULL
-*/
-int
-iucv_reply_array (__u16 pathid,
- __u32 msgid, __u32 trgcls,
- int flags1,
- iucv_array_t * buffer,
- ulong buflen, ulong * ipbfadr2, ulong * ipbfln2f)
-{
- iparml_db *parm;
- ulong b2f0_result;
-
- iucv_debug(2, "entering");
-
- if (!buffer)
- return -EINVAL;
-
- parm = (iparml_db *)grab_param();
-
- parm->ipbfadr2 = (__u32) ((ulong) buffer);
- parm->ipbfln2f = buflen; /* length of message */
- parm->ippathid = pathid;
- parm->ipmsgid = msgid;
- parm->iptrgcls = trgcls;
- parm->ipflags1 = (IPANSLST | flags1);
-
- b2f0_result = b2f0(REPLY, parm);
-
- if ((!b2f0_result) || (b2f0_result == 5)) {
-
- if (ipbfadr2)
- *ipbfadr2 = parm->ipbfadr2;
- if (ipbfln2f)
- *ipbfln2f = parm->ipbfln2f;
- }
- release_param(parm);
-
- iucv_debug(2, "exiting");
-
- return b2f0_result;
-}
-
-/*
- * Name: iucv_reply_prmmsg
- * Purpose: This function responds to the two-way messages that you
- * receive. You must identify completely the message to
- * which you wish to reply. ie, pathid, msgid, and trgcls.
- * Prmmsg signifies the data is moved into the
- * parameter list.
- * Input: pathid - path identification number
- * msgid - specifies the message ID.
- * trgcls - specifies target class
- * flags1 - option for path
- * IPPRTY- specifies if you want to send priority message
- * prmmsg - 8-bytes of data to be placed into the parameter
- * list.
- * Output: NA
- * Return: b2f0_result - return code from CP
-*/
-int
-iucv_reply_prmmsg (__u16 pathid,
- __u32 msgid, __u32 trgcls, int flags1, __u8 prmmsg[8])
-{
- iparml_dpl *parm;
- ulong b2f0_result;
-
- iucv_debug(2, "entering");
-
- parm = (iparml_dpl *)grab_param();
-
- parm->ippathid = pathid;
- parm->ipmsgid = msgid;
- parm->iptrgcls = trgcls;
- memcpy(parm->iprmmsg, prmmsg, sizeof (parm->iprmmsg));
- parm->ipflags1 = (IPRMDATA | flags1);
-
- b2f0_result = b2f0(REPLY, parm);
- release_param(parm);
-
- iucv_debug(2, "exiting");
-
- return b2f0_result;
-}
-
-/**
- * iucv_resume:
- * @pathid: Path identification number
- * @user_data: 16-byte of user data
- *
- * This function restores communication over a quiesced path.
- * Returns: return code from CP
- */
-int
-iucv_resume (__u16 pathid, __u8 user_data[16])
-{
- iparml_control *parm;
- ulong b2f0_result = 0;
-
- iucv_debug(1, "entering");
- iucv_debug(1, "pathid = %d", pathid);
-
- parm = (iparml_control *)grab_param();
-
- memcpy (parm->ipuser, user_data, sizeof (*user_data));
- parm->ippathid = pathid;
-
- b2f0_result = b2f0(RESUME, parm);
- release_param(parm);
-
- iucv_debug(1, "exiting");
-
- return b2f0_result;
-}
-
-/*
- * Name: iucv_send
- * Purpose: sends messages
- * Input: pathid - ushort, pathid
- * msgid - ulong *, id of message returned to caller
- * trgcls - ulong, target message class
- * srccls - ulong, source message class
- * msgtag - ulong, message tag
- * flags1 - Contains options for this path.
- * IPPRTY - Ox20 - specifies if you want to send a priority message.
- * buffer - pointer to buffer
- * buflen - ulong, length of buffer
- * Output: b2f0_result - return code from b2f0 call
- * msgid - returns message id
- */
-int
-iucv_send (__u16 pathid, __u32 * msgid,
- __u32 trgcls, __u32 srccls,
- __u32 msgtag, int flags1, void *buffer, ulong buflen)
-{
- iparml_db *parm;
- ulong b2f0_result;
-
- iucv_debug(2, "entering");
-
- if (!buffer)
- return -EINVAL;
-
- parm = (iparml_db *)grab_param();
-
- parm->ipbfadr1 = (__u32) ((ulong) buffer);
- parm->ippathid = pathid;
- parm->iptrgcls = trgcls;
- parm->ipbfln1f = (__u32) buflen; /* length of message */
- parm->ipsrccls = srccls;
- parm->ipmsgtag = msgtag;
- parm->ipflags1 = (IPNORPY | flags1); /* one way priority message */
-
- b2f0_result = b2f0(SEND, parm);
-
- if ((!b2f0_result) && (msgid))
- *msgid = parm->ipmsgid;
- release_param(parm);
-
- iucv_debug(2, "exiting");
-
- return b2f0_result;
-}
-
-/*
- * Name: iucv_send_array
- * Purpose: This function transmits data to another application.
- * The contents of buffer is the address of the array of
- * addresses and lengths of discontiguous buffers that hold
- * the message text. This is a one-way message and the
- * receiver will not reply to the message.
- * Input: pathid - path identification number
- * trgcls - specifies target class
- * srccls - specifies the source message class
- * msgtag - specifies a tag to be associated witht the message
- * flags1 - option for path
- * IPPRTY- specifies if you want to send priority message
- * buffer - address of array of send buffers
- * buflen - total length of send buffers
- * Output: msgid - specifies the message ID.
- * Return: b2f0_result - return code from CP
- * (-EINVAL) - buffer address is NULL
- */
-int
-iucv_send_array (__u16 pathid,
- __u32 * msgid,
- __u32 trgcls,
- __u32 srccls,
- __u32 msgtag, int flags1, iucv_array_t * buffer, ulong buflen)
-{
- iparml_db *parm;
- ulong b2f0_result;
-
- iucv_debug(2, "entering");
-
- if (!buffer)
- return -EINVAL;
-
- parm = (iparml_db *)grab_param();
-
- parm->ippathid = pathid;
- parm->iptrgcls = trgcls;
- parm->ipbfadr1 = (__u32) ((ulong) buffer);
- parm->ipbfln1f = (__u32) buflen; /* length of message */
- parm->ipsrccls = srccls;
- parm->ipmsgtag = msgtag;
- parm->ipflags1 = (IPNORPY | IPBUFLST | flags1);
- b2f0_result = b2f0(SEND, parm);
-
- if ((!b2f0_result) && (msgid))
- *msgid = parm->ipmsgid;
- release_param(parm);
-
- iucv_debug(2, "exiting");
- return b2f0_result;
-}
-
-/*
- * Name: iucv_send_prmmsg
- * Purpose: This function transmits data to another application.
- * Prmmsg specifies that the 8-bytes of data are to be moved
- * into the parameter list. This is a one-way message and the
- * receiver will not reply to the message.
- * Input: pathid - path identification number
- * trgcls - specifies target class
- * srccls - specifies the source message class
- * msgtag - specifies a tag to be associated with the message
- * flags1 - option for path
- * IPPRTY- specifies if you want to send priority message
- * prmmsg - 8-bytes of data to be placed into parameter list
- * Output: msgid - specifies the message ID.
- * Return: b2f0_result - return code from CP
-*/
-int
-iucv_send_prmmsg (__u16 pathid,
- __u32 * msgid,
- __u32 trgcls,
- __u32 srccls, __u32 msgtag, int flags1, __u8 prmmsg[8])
-{
- iparml_dpl *parm;
- ulong b2f0_result;
-
- iucv_debug(2, "entering");
-
- parm = (iparml_dpl *)grab_param();
-
- parm->ippathid = pathid;
- parm->iptrgcls = trgcls;
- parm->ipsrccls = srccls;
- parm->ipmsgtag = msgtag;
- parm->ipflags1 = (IPRMDATA | IPNORPY | flags1);
- memcpy(parm->iprmmsg, prmmsg, sizeof(parm->iprmmsg));
-
- b2f0_result = b2f0(SEND, parm);
-
- if ((!b2f0_result) && (msgid))
- *msgid = parm->ipmsgid;
- release_param(parm);
-
- iucv_debug(2, "exiting");
-
- return b2f0_result;
-}
-
-/*
- * Name: iucv_send2way
- * Purpose: This function transmits data to another application.
- * Data to be transmitted is in a buffer. The receiver
- * of the send is expected to reply to the message and
- * a buffer is provided into which IUCV moves the reply
- * to this message.
- * Input: pathid - path identification number
- * trgcls - specifies target class
- * srccls - specifies the source message class
- * msgtag - specifies a tag associated with the message
- * flags1 - option for path
- * IPPRTY- specifies if you want to send priority message
- * buffer - address of send buffer
- * buflen - length of send buffer
- * ansbuf - address of buffer to reply with
- * anslen - length of buffer to reply with
- * Output: msgid - specifies the message ID.
- * Return: b2f0_result - return code from CP
- * (-EINVAL) - buffer or ansbuf address is NULL
- */
-int
-iucv_send2way (__u16 pathid,
- __u32 * msgid,
- __u32 trgcls,
- __u32 srccls,
- __u32 msgtag,
- int flags1,
- void *buffer, ulong buflen, void *ansbuf, ulong anslen)
-{
- iparml_db *parm;
- ulong b2f0_result;
-
- iucv_debug(2, "entering");
-
- if (!buffer || !ansbuf)
- return -EINVAL;
-
- parm = (iparml_db *)grab_param();
-
- parm->ippathid = pathid;
- parm->iptrgcls = trgcls;
- parm->ipbfadr1 = (__u32) ((ulong) buffer);
- parm->ipbfln1f = (__u32) buflen; /* length of message */
- parm->ipbfadr2 = (__u32) ((ulong) ansbuf);
- parm->ipbfln2f = (__u32) anslen;
- parm->ipsrccls = srccls;
- parm->ipmsgtag = msgtag;
- parm->ipflags1 = flags1; /* priority message */
-
- b2f0_result = b2f0(SEND, parm);
-
- if ((!b2f0_result) && (msgid))
- *msgid = parm->ipmsgid;
- release_param(parm);
-
- iucv_debug(2, "exiting");
-
- return b2f0_result;
-}
-
-/*
- * Name: iucv_send2way_array
- * Purpose: This function transmits data to another application.
- * The contents of buffer is the address of the array of
- * addresses and lengths of discontiguous buffers that hold
- * the message text. The receiver of the send is expected to
- * reply to the message and a buffer is provided into which
- * IUCV moves the reply to this message.
- * Input: pathid - path identification number
- * trgcls - specifies target class
- * srccls - specifies the source message class
- * msgtag - spcifies a tag to be associated with the message
- * flags1 - option for path
- * IPPRTY- specifies if you want to send priority message
- * buffer - address of array of send buffers
- * buflen - total length of send buffers
- * ansbuf - address of buffer to reply with
- * anslen - length of buffer to reply with
- * Output: msgid - specifies the message ID.
- * Return: b2f0_result - return code from CP
- * (-EINVAL) - buffer address is NULL
- */
-int
-iucv_send2way_array (__u16 pathid,
- __u32 * msgid,
- __u32 trgcls,
- __u32 srccls,
- __u32 msgtag,
- int flags1,
- iucv_array_t * buffer,
- ulong buflen, iucv_array_t * ansbuf, ulong anslen)
-{
- iparml_db *parm;
- ulong b2f0_result;
-
- iucv_debug(2, "entering");
-
- if (!buffer || !ansbuf)
- return -EINVAL;
-
- parm = (iparml_db *)grab_param();
-
- parm->ippathid = pathid;
- parm->iptrgcls = trgcls;
- parm->ipbfadr1 = (__u32) ((ulong) buffer);
- parm->ipbfln1f = (__u32) buflen; /* length of message */
- parm->ipbfadr2 = (__u32) ((ulong) ansbuf);
- parm->ipbfln2f = (__u32) anslen;
- parm->ipsrccls = srccls;
- parm->ipmsgtag = msgtag;
- parm->ipflags1 = (IPBUFLST | IPANSLST | flags1);
- b2f0_result = b2f0(SEND, parm);
- if ((!b2f0_result) && (msgid))
- *msgid = parm->ipmsgid;
- release_param(parm);
-
- iucv_debug(2, "exiting");
- return b2f0_result;
-}
-
-/*
- * Name: iucv_send2way_prmmsg
- * Purpose: This function transmits data to another application.
- * Prmmsg specifies that the 8-bytes of data are to be moved
- * into the parameter list. This is a two-way message and the
- * receiver of the message is expected to reply. A buffer
- * is provided into which IUCV moves the reply to this
- * message.
- * Input: pathid - path identification number
- * trgcls - specifies target class
- * srccls - specifies the source message class
- * msgtag - specifies a tag to be associated with the message
- * flags1 - option for path
- * IPPRTY- specifies if you want to send priority message
- * prmmsg - 8-bytes of data to be placed in parameter list
- * ansbuf - address of buffer to reply with
- * anslen - length of buffer to reply with
- * Output: msgid - specifies the message ID.
- * Return: b2f0_result - return code from CP
- * (-EINVAL) - buffer address is NULL
-*/
-int
-iucv_send2way_prmmsg (__u16 pathid,
- __u32 * msgid,
- __u32 trgcls,
- __u32 srccls,
- __u32 msgtag,
- ulong flags1, __u8 prmmsg[8], void *ansbuf, ulong anslen)
-{
- iparml_dpl *parm;
- ulong b2f0_result;
-
- iucv_debug(2, "entering");
-
- if (!ansbuf)
- return -EINVAL;
-
- parm = (iparml_dpl *)grab_param();
-
- parm->ippathid = pathid;
- parm->iptrgcls = trgcls;
- parm->ipsrccls = srccls;
- parm->ipmsgtag = msgtag;
- parm->ipbfadr2 = (__u32) ((ulong) ansbuf);
- parm->ipbfln2f = (__u32) anslen;
- parm->ipflags1 = (IPRMDATA | flags1); /* message in prmlist */
- memcpy(parm->iprmmsg, prmmsg, sizeof(parm->iprmmsg));
-
- b2f0_result = b2f0(SEND, parm);
-
- if ((!b2f0_result) && (msgid))
- *msgid = parm->ipmsgid;
- release_param(parm);
-
- iucv_debug(2, "exiting");
-
- return b2f0_result;
-}
-
-/*
- * Name: iucv_send2way_prmmsg_array
- * Purpose: This function transmits data to another application.
- * Prmmsg specifies that the 8-bytes of data are to be moved
- * into the parameter list. This is a two-way message and the
- * receiver of the message is expected to reply. A buffer
- * is provided into which IUCV moves the reply to this
- * message. The contents of ansbuf is the address of the
- * array of addresses and lengths of discontiguous buffers
- * that contain the reply.
- * Input: pathid - path identification number
- * trgcls - specifies target class
- * srccls - specifies the source message class
- * msgtag - specifies a tag to be associated with the message
- * flags1 - option for path
- * IPPRTY- specifies if you want to send priority message
- * prmmsg - 8-bytes of data to be placed into the parameter list
- * ansbuf - address of buffer to reply with
- * anslen - length of buffer to reply with
- * Output: msgid - specifies the message ID.
- * Return: b2f0_result - return code from CP
- * (-EINVAL) - ansbuf address is NULL
- */
-int
-iucv_send2way_prmmsg_array (__u16 pathid,
- __u32 * msgid,
- __u32 trgcls,
- __u32 srccls,
- __u32 msgtag,
- int flags1,
- __u8 prmmsg[8],
- iucv_array_t * ansbuf, ulong anslen)
-{
- iparml_dpl *parm;
- ulong b2f0_result;
-
- iucv_debug(2, "entering");
-
- if (!ansbuf)
- return -EINVAL;
-
- parm = (iparml_dpl *)grab_param();
-
- parm->ippathid = pathid;
- parm->iptrgcls = trgcls;
- parm->ipsrccls = srccls;
- parm->ipmsgtag = msgtag;
- parm->ipbfadr2 = (__u32) ((ulong) ansbuf);
- parm->ipbfln2f = (__u32) anslen;
- parm->ipflags1 = (IPRMDATA | IPANSLST | flags1);
- memcpy(parm->iprmmsg, prmmsg, sizeof(parm->iprmmsg));
- b2f0_result = b2f0(SEND, parm);
- if ((!b2f0_result) && (msgid))
- *msgid = parm->ipmsgid;
- release_param(parm);
-
- iucv_debug(2, "exiting");
- return b2f0_result;
-}
-
-void
-iucv_setmask_cpuid (void *result)
-{
- iparml_set_mask *parm;
-
- iucv_debug(1, "entering");
- parm = (iparml_set_mask *)grab_param();
- parm->ipmask = *((__u8*)result);
- *((ulong *)result) = b2f0(SETMASK, parm);
- release_param(parm);
-
- iucv_debug(1, "b2f0_result = %ld", *((ulong *)result));
- iucv_debug(1, "exiting");
-}
-
-/*
- * Name: iucv_setmask
- * Purpose: This function enables or disables the following IUCV
- * external interruptions: Nonpriority and priority message
- * interrupts, nonpriority and priority reply interrupts.
- * Input: SetMaskFlag - options for interrupts
- * 0x80 - Nonpriority_MessagePendingInterruptsFlag
- * 0x40 - Priority_MessagePendingInterruptsFlag
- * 0x20 - Nonpriority_MessageCompletionInterruptsFlag
- * 0x10 - Priority_MessageCompletionInterruptsFlag
- * 0x08 - IUCVControlInterruptsFlag
- * Output: NA
- * Return: b2f0_result - return code from CP
-*/
-int
-iucv_setmask (int SetMaskFlag)
-{
- union {
- ulong result;
- __u8 param;
- } u;
- int cpu;
-
- u.param = SetMaskFlag;
- cpu = get_cpu();
- smp_call_function_on(iucv_setmask_cpuid, &u, 0, 1, iucv_cpuid);
- put_cpu();
-
- return u.result;
-}
-
-/**
- * iucv_sever:
- * @pathid: Path identification number
- * @user_data: 16-byte of user data
- *
- * This function terminates an iucv path.
- * Returns: return code from CP
- */
-int
-iucv_sever(__u16 pathid, __u8 user_data[16])
-{
- iparml_control *parm;
- ulong b2f0_result = 0;
-
- iucv_debug(1, "entering");
- parm = (iparml_control *)grab_param();
-
- memcpy(parm->ipuser, user_data, sizeof(parm->ipuser));
- parm->ippathid = pathid;
-
- b2f0_result = b2f0(SEVER, parm);
-
- if (!b2f0_result)
- iucv_remove_pathid(pathid);
- release_param(parm);
-
- iucv_debug(1, "exiting");
- return b2f0_result;
-}
-
-/*
- * Interrupt Handlers
- *******************************************************************************/
-
-/**
- * iucv_irq_handler:
- * @regs: Current registers
- * @code: irq code
- *
- * Handles external interrupts coming in from CP.
- * Places the interrupt buffer on a queue and schedules iucv_tasklet_handler().
- */
-static void
-iucv_irq_handler(__u16 code)
-{
- iucv_irqdata *irqdata;
-
- irqdata = kmalloc(sizeof(iucv_irqdata), GFP_ATOMIC);
- if (!irqdata) {
- printk(KERN_WARNING "%s: out of memory\n", __FUNCTION__);
- return;
- }
-
- memcpy(&irqdata->data, iucv_external_int_buffer,
- sizeof(iucv_GeneralInterrupt));
-
- spin_lock(&iucv_irq_queue_lock);
- list_add_tail(&irqdata->queue, &iucv_irq_queue);
- spin_unlock(&iucv_irq_queue_lock);
-
- tasklet_schedule(&iucv_tasklet);
-}
-
-/**
- * iucv_do_int:
- * @int_buf: Pointer to copy of external interrupt buffer
- *
- * The workhorse for handling interrupts queued by iucv_irq_handler().
- * This function is called from the bottom half iucv_tasklet_handler().
- */
-static void
-iucv_do_int(iucv_GeneralInterrupt * int_buf)
-{
- handler *h = NULL;
- struct list_head *lh;
- ulong flags;
- iucv_interrupt_ops_t *interrupt = NULL; /* interrupt addresses */
- __u8 temp_buff1[24], temp_buff2[24]; /* masked handler id. */
- int rc = 0, j = 0;
- __u8 no_listener[16] = "NO LISTENER";
-
- iucv_debug(2, "entering, pathid %d, type %02X",
- int_buf->ippathid, int_buf->iptype);
- iucv_dumpit("External Interrupt Buffer:",
- int_buf, sizeof(iucv_GeneralInterrupt));
-
- ASCEBC (no_listener, 16);
-
- if (int_buf->iptype != 01) {
- if ((int_buf->ippathid) > (max_connections - 1)) {
- printk(KERN_WARNING "%s: Got interrupt with pathid %d"
- " > max_connections (%ld)\n", __FUNCTION__,
- int_buf->ippathid, max_connections - 1);
- } else {
- h = iucv_pathid_table[int_buf->ippathid];
- interrupt = h->interrupt_table;
- iucv_dumpit("Handler:", h, sizeof(handler));
- }
- }
-
- /* end of if statement */
- switch (int_buf->iptype) {
- case 0x01: /* connection pending */
- if (messagesDisabled) {
- iucv_setmask(~0);
- messagesDisabled = 0;
- }
- spin_lock_irqsave(&iucv_lock, flags);
- list_for_each(lh, &iucv_handler_table) {
- h = list_entry(lh, handler, list);
- memcpy(temp_buff1, &(int_buf->ipvmid), 24);
- memcpy(temp_buff2, &(h->id.userid), 24);
- for (j = 0; j < 24; j++) {
- temp_buff1[j] &= (h->id.mask)[j];
- temp_buff2[j] &= (h->id.mask)[j];
- }
-
- iucv_dumpit("temp_buff1:",
- temp_buff1, sizeof(temp_buff1));
- iucv_dumpit("temp_buff2",
- temp_buff2, sizeof(temp_buff2));
-
- if (!memcmp (temp_buff1, temp_buff2, 24)) {
-
- iucv_debug(2,
- "found a matching handler");
- break;
- } else
- h = NULL;
- }
- spin_unlock_irqrestore (&iucv_lock, flags);
- if (h) {
- /* ADD PATH TO PATHID TABLE */
- rc = iucv_add_pathid(int_buf->ippathid, h);
- if (rc) {
- iucv_sever (int_buf->ippathid,
- no_listener);
- iucv_debug(1,
- "add_pathid failed, rc = %d",
- rc);
- } else {
- interrupt = h->interrupt_table;
- if (interrupt->ConnectionPending) {
- EBCASC (int_buf->ipvmid, 8);
- interrupt->ConnectionPending(
- (iucv_ConnectionPending *)int_buf,
- h->pgm_data);
- } else
- iucv_sever(int_buf->ippathid,
- no_listener);
- }
- } else
- iucv_sever(int_buf->ippathid, no_listener);
- break;
-
- case 0x02: /*connection complete */
- if (messagesDisabled) {
- iucv_setmask(~0);
- messagesDisabled = 0;
- }
- if (h) {
- if (interrupt->ConnectionComplete)
- {
- interrupt->ConnectionComplete(
- (iucv_ConnectionComplete *)int_buf,
- h->pgm_data);
- }
- else
- iucv_debug(1,
- "ConnectionComplete not called");
- } else
- iucv_sever(int_buf->ippathid, no_listener);
- break;
-
- case 0x03: /* connection severed */
- if (messagesDisabled) {
- iucv_setmask(~0);
- messagesDisabled = 0;
- }
- if (h) {
- if (interrupt->ConnectionSevered)
- interrupt->ConnectionSevered(
- (iucv_ConnectionSevered *)int_buf,
- h->pgm_data);
-
- else
- iucv_sever (int_buf->ippathid, no_listener);
- } else
- iucv_sever(int_buf->ippathid, no_listener);
- break;
-
- case 0x04: /* connection quiesced */
- if (messagesDisabled) {
- iucv_setmask(~0);
- messagesDisabled = 0;
- }
- if (h) {
- if (interrupt->ConnectionQuiesced)
- interrupt->ConnectionQuiesced(
- (iucv_ConnectionQuiesced *)int_buf,
- h->pgm_data);
- else
- iucv_debug(1,
- "ConnectionQuiesced not called");
- }
- break;
-
- case 0x05: /* connection resumed */
- if (messagesDisabled) {
- iucv_setmask(~0);
- messagesDisabled = 0;
- }
- if (h) {
- if (interrupt->ConnectionResumed)
- interrupt->ConnectionResumed(
- (iucv_ConnectionResumed *)int_buf,
- h->pgm_data);
- else
- iucv_debug(1,
- "ConnectionResumed not called");
- }
- break;
-
- case 0x06: /* priority message complete */
- case 0x07: /* nonpriority message complete */
- if (h) {
- if (interrupt->MessageComplete)
- interrupt->MessageComplete(
- (iucv_MessageComplete *)int_buf,
- h->pgm_data);
- else
- iucv_debug(2,
- "MessageComplete not called");
- }
- break;
-
- case 0x08: /* priority message pending */
- case 0x09: /* nonpriority message pending */
- if (h) {
- if (interrupt->MessagePending)
- interrupt->MessagePending(
- (iucv_MessagePending *) int_buf,
- h->pgm_data);
- else
- iucv_debug(2,
- "MessagePending not called");
- }
- break;
- default: /* unknown iucv type */
- printk(KERN_WARNING "%s: unknown iucv interrupt\n",
- __FUNCTION__);
- break;
- } /* end switch */
-
- iucv_debug(2, "exiting pathid %d, type %02X",
- int_buf->ippathid, int_buf->iptype);
-
- return;
-}
-
-/**
- * iucv_tasklet_handler:
- *
- * This function loops over the queue of irq buffers and runs iucv_do_int()
- * on every queue element.
- */
-static void
-iucv_tasklet_handler(unsigned long ignored)
-{
- struct list_head head;
- struct list_head *next;
- ulong flags;
-
- spin_lock_irqsave(&iucv_irq_queue_lock, flags);
- list_add(&head, &iucv_irq_queue);
- list_del_init(&iucv_irq_queue);
- spin_unlock_irqrestore (&iucv_irq_queue_lock, flags);
-
- next = head.next;
- while (next != &head) {
- iucv_irqdata *p = list_entry(next, iucv_irqdata, queue);
-
- next = next->next;
- iucv_do_int(&p->data);
- kfree(p);
- }
-
- return;
-}
-
-subsys_initcall(iucv_init);
-module_exit(iucv_exit);
-
-/**
- * Export all public stuff
- */
-EXPORT_SYMBOL (iucv_bus);
-EXPORT_SYMBOL (iucv_root);
-EXPORT_SYMBOL (iucv_accept);
-EXPORT_SYMBOL (iucv_connect);
-#if 0
-EXPORT_SYMBOL (iucv_purge);
-EXPORT_SYMBOL (iucv_query_maxconn);
-EXPORT_SYMBOL (iucv_query_bufsize);
-EXPORT_SYMBOL (iucv_quiesce);
-#endif
-EXPORT_SYMBOL (iucv_receive);
-#if 0
-EXPORT_SYMBOL (iucv_receive_array);
-#endif
-EXPORT_SYMBOL (iucv_reject);
-#if 0
-EXPORT_SYMBOL (iucv_reply);
-EXPORT_SYMBOL (iucv_reply_array);
-EXPORT_SYMBOL (iucv_resume);
-#endif
-EXPORT_SYMBOL (iucv_reply_prmmsg);
-EXPORT_SYMBOL (iucv_send);
-EXPORT_SYMBOL (iucv_send2way);
-EXPORT_SYMBOL (iucv_send2way_array);
-EXPORT_SYMBOL (iucv_send2way_prmmsg);
-EXPORT_SYMBOL (iucv_send2way_prmmsg_array);
-#if 0
-EXPORT_SYMBOL (iucv_send_array);
-EXPORT_SYMBOL (iucv_send_prmmsg);
-EXPORT_SYMBOL (iucv_setmask);
-#endif
-EXPORT_SYMBOL (iucv_sever);
-EXPORT_SYMBOL (iucv_register_program);
-EXPORT_SYMBOL (iucv_unregister_program);
diff --git a/drivers/s390/net/iucv.h b/drivers/s390/net/iucv.h
deleted file mode 100644
index 5b6b1b7241c..00000000000
--- a/drivers/s390/net/iucv.h
+++ /dev/null
@@ -1,849 +0,0 @@
-/*
- * drivers/s390/net/iucv.h
- * IUCV base support.
- *
- * S390 version
- * Copyright (C) 2000 IBM Corporation
- * Author(s):Alan Altmark (Alan_Altmark@us.ibm.com)
- * Xenia Tkatschow (xenia@us.ibm.com)
- *
- *
- * Functionality:
- * To explore any of the IUCV functions, one must first register
- * their program using iucv_register_program(). Once your program has
- * successfully completed a register, it can exploit the other functions.
- * For furthur reference on all IUCV functionality, refer to the
- * CP Programming Services book, also available on the web
- * thru www.ibm.com/s390/vm/pubs, manual # SC24-5760
- *
- * Definition of Return Codes
- * -All positive return codes including zero are reflected back
- * from CP except for iucv_register_program. The definition of each
- * return code can be found in CP Programming Services book.
- * Also available on the web thru www.ibm.com/s390/vm/pubs, manual # SC24-5760
- * - Return Code of:
- * (-EINVAL) Invalid value
- * (-ENOMEM) storage allocation failed
- * pgmask defined in iucv_register_program will be set depending on input
- * paramters.
- *
- */
-
-#include <linux/types.h>
-#include <asm/debug.h>
-
-/**
- * Debug Facility stuff
- */
-#define IUCV_DBF_SETUP_NAME "iucv_setup"
-#define IUCV_DBF_SETUP_LEN 32
-#define IUCV_DBF_SETUP_PAGES 2
-#define IUCV_DBF_SETUP_NR_AREAS 1
-#define IUCV_DBF_SETUP_LEVEL 3
-
-#define IUCV_DBF_DATA_NAME "iucv_data"
-#define IUCV_DBF_DATA_LEN 128
-#define IUCV_DBF_DATA_PAGES 2
-#define IUCV_DBF_DATA_NR_AREAS 1
-#define IUCV_DBF_DATA_LEVEL 2
-
-#define IUCV_DBF_TRACE_NAME "iucv_trace"
-#define IUCV_DBF_TRACE_LEN 16
-#define IUCV_DBF_TRACE_PAGES 4
-#define IUCV_DBF_TRACE_NR_AREAS 1
-#define IUCV_DBF_TRACE_LEVEL 3
-
-#define IUCV_DBF_TEXT(name,level,text) \
- do { \
- debug_text_event(iucv_dbf_##name,level,text); \
- } while (0)
-
-#define IUCV_DBF_HEX(name,level,addr,len) \
- do { \
- debug_event(iucv_dbf_##name,level,(void*)(addr),len); \
- } while (0)
-
-DECLARE_PER_CPU(char[256], iucv_dbf_txt_buf);
-
-#define IUCV_DBF_TEXT_(name,level,text...) \
- do { \
- char* iucv_dbf_txt_buf = get_cpu_var(iucv_dbf_txt_buf); \
- sprintf(iucv_dbf_txt_buf, text); \
- debug_text_event(iucv_dbf_##name,level,iucv_dbf_txt_buf); \
- put_cpu_var(iucv_dbf_txt_buf); \
- } while (0)
-
-#define IUCV_DBF_SPRINTF(name,level,text...) \
- do { \
- debug_sprintf_event(iucv_dbf_trace, level, ##text ); \
- debug_sprintf_event(iucv_dbf_trace, level, text ); \
- } while (0)
-
-/**
- * some more debug stuff
- */
-#define IUCV_HEXDUMP16(importance,header,ptr) \
-PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \
- "%02x %02x %02x %02x %02x %02x %02x %02x\n", \
- *(((char*)ptr)),*(((char*)ptr)+1),*(((char*)ptr)+2), \
- *(((char*)ptr)+3),*(((char*)ptr)+4),*(((char*)ptr)+5), \
- *(((char*)ptr)+6),*(((char*)ptr)+7),*(((char*)ptr)+8), \
- *(((char*)ptr)+9),*(((char*)ptr)+10),*(((char*)ptr)+11), \
- *(((char*)ptr)+12),*(((char*)ptr)+13), \
- *(((char*)ptr)+14),*(((char*)ptr)+15)); \
-PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \
- "%02x %02x %02x %02x %02x %02x %02x %02x\n", \
- *(((char*)ptr)+16),*(((char*)ptr)+17), \
- *(((char*)ptr)+18),*(((char*)ptr)+19), \
- *(((char*)ptr)+20),*(((char*)ptr)+21), \
- *(((char*)ptr)+22),*(((char*)ptr)+23), \
- *(((char*)ptr)+24),*(((char*)ptr)+25), \
- *(((char*)ptr)+26),*(((char*)ptr)+27), \
- *(((char*)ptr)+28),*(((char*)ptr)+29), \
- *(((char*)ptr)+30),*(((char*)ptr)+31));
-
-static inline void
-iucv_hex_dump(unsigned char *buf, size_t len)
-{
- size_t i;
-
- for (i = 0; i < len; i++) {
- if (i && !(i % 16))
- printk("\n");
- printk("%02x ", *(buf + i));
- }
- printk("\n");
-}
-/**
- * end of debug stuff
- */
-
-#define uchar unsigned char
-#define ushort unsigned short
-#define ulong unsigned long
-#define iucv_handle_t void *
-
-/* flags1:
- * All flags are defined in the field IPFLAGS1 of each function
- * and can be found in CP Programming Services.
- * IPLOCAL - Indicates the connect can only be satisfied on the
- * local system
- * IPPRTY - Indicates a priority message
- * IPQUSCE - Indicates you do not want to receive messages on a
- * path until an iucv_resume is issued
- * IPRMDATA - Indicates that the message is in the parameter list
- */
-#define IPLOCAL 0x01
-#define IPPRTY 0x20
-#define IPQUSCE 0x40
-#define IPRMDATA 0x80
-
-/* flags1_out:
- * All flags are defined in the output field of IPFLAGS1 for each function
- * and can be found in CP Programming Services.
- * IPNORPY - Specifies this is a one-way message and no reply is expected.
- * IPPRTY - Indicates a priority message is permitted. Defined in flags1.
- */
-#define IPNORPY 0x10
-
-#define Nonpriority_MessagePendingInterruptsFlag 0x80
-#define Priority_MessagePendingInterruptsFlag 0x40
-#define Nonpriority_MessageCompletionInterruptsFlag 0x20
-#define Priority_MessageCompletionInterruptsFlag 0x10
-#define IUCVControlInterruptsFlag 0x08
-#define AllInterrupts 0xf8
-/*
- * Mapping of external interrupt buffers should be used with the corresponding
- * interrupt types.
- * Names: iucv_ConnectionPending -> connection pending
- * iucv_ConnectionComplete -> connection complete
- * iucv_ConnectionSevered -> connection severed
- * iucv_ConnectionQuiesced -> connection quiesced
- * iucv_ConnectionResumed -> connection resumed
- * iucv_MessagePending -> message pending
- * iucv_MessageComplete -> message complete
- */
-typedef struct {
- u16 ippathid;
- uchar ipflags1;
- uchar iptype;
- u16 ipmsglim;
- u16 res1;
- uchar ipvmid[8];
- uchar ipuser[16];
- u32 res3;
- uchar ippollfg;
- uchar res4[3];
-} iucv_ConnectionPending;
-
-typedef struct {
- u16 ippathid;
- uchar ipflags1;
- uchar iptype;
- u16 ipmsglim;
- u16 res1;
- uchar res2[8];
- uchar ipuser[16];
- u32 res3;
- uchar ippollfg;
- uchar res4[3];
-} iucv_ConnectionComplete;
-
-typedef struct {
- u16 ippathid;
- uchar res1;
- uchar iptype;
- u32 res2;
- uchar res3[8];
- uchar ipuser[16];
- u32 res4;
- uchar ippollfg;
- uchar res5[3];
-} iucv_ConnectionSevered;
-
-typedef struct {
- u16 ippathid;
- uchar res1;
- uchar iptype;
- u32 res2;
- uchar res3[8];
- uchar ipuser[16];
- u32 res4;
- uchar ippollfg;
- uchar res5[3];
-} iucv_ConnectionQuiesced;
-
-typedef struct {
- u16 ippathid;
- uchar res1;
- uchar iptype;
- u32 res2;
- uchar res3[8];
- uchar ipuser[16];
- u32 res4;
- uchar ippollfg;
- uchar res5[3];
-} iucv_ConnectionResumed;
-
-typedef struct {
- u16 ippathid;
- uchar ipflags1;
- uchar iptype;
- u32 ipmsgid;
- u32 iptrgcls;
- union u2 {
- u32 iprmmsg1_u32;
- uchar iprmmsg1[4];
- } ln1msg1;
- union u1 {
- u32 ipbfln1f;
- uchar iprmmsg2[4];
- } ln1msg2;
- u32 res1[3];
- u32 ipbfln2f;
- uchar ippollfg;
- uchar res2[3];
-} iucv_MessagePending;
-
-typedef struct {
- u16 ippathid;
- uchar ipflags1;
- uchar iptype;
- u32 ipmsgid;
- u32 ipaudit;
- uchar iprmmsg[8];
- u32 ipsrccls;
- u32 ipmsgtag;
- u32 res;
- u32 ipbfln2f;
- uchar ippollfg;
- uchar res2[3];
-} iucv_MessageComplete;
-
-/*
- * iucv_interrupt_ops_t: Is a vector of functions that handle
- * IUCV interrupts.
- * Parameter list:
- * eib - is a pointer to a 40-byte area described
- * with one of the structures above.
- * pgm_data - this data is strictly for the
- * interrupt handler that is passed by
- * the application. This may be an address
- * or token.
-*/
-typedef struct {
- void (*ConnectionPending) (iucv_ConnectionPending * eib,
- void *pgm_data);
- void (*ConnectionComplete) (iucv_ConnectionComplete * eib,
- void *pgm_data);
- void (*ConnectionSevered) (iucv_ConnectionSevered * eib,
- void *pgm_data);
- void (*ConnectionQuiesced) (iucv_ConnectionQuiesced * eib,
- void *pgm_data);
- void (*ConnectionResumed) (iucv_ConnectionResumed * eib,
- void *pgm_data);
- void (*MessagePending) (iucv_MessagePending * eib, void *pgm_data);
- void (*MessageComplete) (iucv_MessageComplete * eib, void *pgm_data);
-} iucv_interrupt_ops_t;
-
-/*
- *iucv_array_t : Defines buffer array.
- * Inside the array may be 31- bit addresses and 31-bit lengths.
-*/
-typedef struct {
- u32 address;
- u32 length;
-} iucv_array_t __attribute__ ((aligned (8)));
-
-extern struct bus_type iucv_bus;
-extern struct device *iucv_root;
-
-/* -prototypes- */
-/*
- * Name: iucv_register_program
- * Purpose: Registers an application with IUCV
- * Input: prmname - user identification
- * userid - machine identification
- * pgmmask - indicates which bits in the prmname and userid combined will be
- * used to determine who is given control
- * ops - address of vector of interrupt handlers
- * pgm_data- application data passed to interrupt handlers
- * Output: NA
- * Return: address of handler
- * (0) - Error occurred, registration not completed.
- * NOTE: Exact cause of failure will be recorded in syslog.
-*/
-iucv_handle_t iucv_register_program (uchar pgmname[16],
- uchar userid[8],
- uchar pgmmask[24],
- iucv_interrupt_ops_t * ops,
- void *pgm_data);
-
-/*
- * Name: iucv_unregister_program
- * Purpose: Unregister application with IUCV
- * Input: address of handler
- * Output: NA
- * Return: (0) - Normal return
- * (-EINVAL) - Internal error, wild pointer
-*/
-int iucv_unregister_program (iucv_handle_t handle);
-
-/*
- * Name: iucv_accept
- * Purpose: This function is issued after the user receives a Connection Pending external
- * interrupt and now wishes to complete the IUCV communication path.
- * Input: pathid - u16 , Path identification number
- * msglim_reqstd - u16, The number of outstanding messages requested.
- * user_data - uchar[16], Data specified by the iucv_connect function.
- * flags1 - int, Contains options for this path.
- * -IPPRTY - 0x20- Specifies if you want to send priority message.
- * -IPRMDATA - 0x80, Specifies whether your program can handle a message
- * in the parameter list.
- * -IPQUSCE - 0x40, Specifies whether you want to quiesce the path being
- * established.
- * handle - iucv_handle_t, Address of handler.
- * pgm_data - void *, Application data passed to interrupt handlers.
- * flags1_out - int * Contains information about the path
- * - IPPRTY - 0x20, Indicates you may send priority messages.
- * msglim - *u16, Number of outstanding messages.
- * Output: return code from CP IUCV call.
-*/
-
-int iucv_accept (u16 pathid,
- u16 msglim_reqstd,
- uchar user_data[16],
- int flags1,
- iucv_handle_t handle,
- void *pgm_data, int *flags1_out, u16 * msglim);
-
-/*
- * Name: iucv_connect
- * Purpose: This function establishes an IUCV path. Although the connect may complete
- * successfully, you are not able to use the path until you receive an IUCV
- * Connection Complete external interrupt.
- * Input: pathid - u16 *, Path identification number
- * msglim_reqstd - u16, Number of outstanding messages requested
- * user_data - uchar[16], 16-byte user data
- * userid - uchar[8], User identification
- * system_name - uchar[8], 8-byte identifying the system name
- * flags1 - int, Contains options for this path.
- * -IPPRTY - 0x20, Specifies if you want to send priority message.
- * -IPRMDATA - 0x80, Specifies whether your program can handle a message
- * in the parameter list.
- * -IPQUSCE - 0x40, Specifies whether you want to quiesce the path being
- * established.
- * -IPLOCAL - 0X01, Allows an application to force the partner to be on
- * the local system. If local is specified then target class cannot be
- * specified.
- * flags1_out - int * Contains information about the path
- * - IPPRTY - 0x20, Indicates you may send priority messages.
- * msglim - * u16, Number of outstanding messages
- * handle - iucv_handle_t, Address of handler
- * pgm_data - void *, Application data passed to interrupt handlers
- * Output: return code from CP IUCV call
- * rc - return code from iucv_declare_buffer
- * -EINVAL - Invalid handle passed by application
- * -EINVAL - Pathid address is NULL
- * add_pathid_result - Return code from internal function add_pathid
-*/
-int
- iucv_connect (u16 * pathid,
- u16 msglim_reqstd,
- uchar user_data[16],
- uchar userid[8],
- uchar system_name[8],
- int flags1,
- int *flags1_out,
- u16 * msglim, iucv_handle_t handle, void *pgm_data);
-
-/*
- * Name: iucv_purge
- * Purpose: This function cancels a message that you have sent.
- * Input: pathid - Path identification number.
- * msgid - Specifies the message ID of the message to be purged.
- * srccls - Specifies the source message class.
- * Output: audit - Contains information about asynchronous error
- * that may have affected the normal completion
- * of this message.
- * Return: Return code from CP IUCV call.
-*/
-int iucv_purge (u16 pathid, u32 msgid, u32 srccls, __u32 *audit);
-/*
- * Name: iucv_query_maxconn
- * Purpose: This function determines the maximum number of communication paths you
- * may establish.
- * Return: maxconn - ulong, Maximum number of connection the virtual machine may
- * establish.
-*/
-ulong iucv_query_maxconn (void);
-
-/*
- * Name: iucv_query_bufsize
- * Purpose: This function determines how large an external interrupt
- * buffer IUCV requires to store information.
- * Return: bufsize - ulong, Size of external interrupt buffer.
- */
-ulong iucv_query_bufsize (void);
-
-/*
- * Name: iucv_quiesce
- * Purpose: This function temporarily suspends incoming messages on an
- * IUCV path. You can later reactivate the path by invoking
- * the iucv_resume function.
- * Input: pathid - Path identification number
- * user_data - 16-bytes of user data
- * Output: NA
- * Return: Return code from CP IUCV call.
-*/
-int iucv_quiesce (u16 pathid, uchar user_data[16]);
-
-/*
- * Name: iucv_receive
- * Purpose: This function receives messages that are being sent to you
- * over established paths. Data will be returned in buffer for length of
- * buflen.
- * Input:
- * pathid - Path identification number.
- * buffer - Address of buffer to receive.
- * buflen - Length of buffer to receive.
- * msgid - Specifies the message ID.
- * trgcls - Specifies target class.
- * Output:
- * flags1_out: int *, Contains information about this path.
- * IPNORPY - 0x10 Specifies this is a one-way message and no reply is
- * expected.
- * IPPRTY - 0x20 Specifies if you want to send priority message.
- * IPRMDATA - 0x80 specifies the data is contained in the parameter list
- * residual_buffer - address of buffer updated by the number
- * of bytes you have received.
- * residual_length -
- * Contains one of the following values, if the receive buffer is:
- * The same length as the message, this field is zero.
- * Longer than the message, this field contains the number of
- * bytes remaining in the buffer.
- * Shorter than the message, this field contains the residual
- * count (that is, the number of bytes remaining in the
- * message that does not fit into the buffer. In this
- * case b2f0_result = 5.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - buffer address is pointing to NULL
-*/
-int iucv_receive (u16 pathid,
- u32 msgid,
- u32 trgcls,
- void *buffer,
- ulong buflen,
- int *flags1_out,
- ulong * residual_buffer, ulong * residual_length);
-
- /*
- * Name: iucv_receive_array
- * Purpose: This function receives messages that are being sent to you
- * over established paths. Data will be returned in first buffer for
- * length of first buffer.
- * Input: pathid - Path identification number.
- * msgid - specifies the message ID.
- * trgcls - Specifies target class.
- * buffer - Address of array of buffers.
- * buflen - Total length of buffers.
- * Output:
- * flags1_out: int *, Contains information about this path.
- * IPNORPY - 0x10 Specifies this is a one-way message and no reply is
- * expected.
- * IPPRTY - 0x20 Specifies if you want to send priority message.
- * IPRMDATA - 0x80 specifies the data is contained in the parameter list
- * residual_buffer - address points to the current list entry IUCV
- * is working on.
- * residual_length -
- * Contains one of the following values, if the receive buffer is:
- * The same length as the message, this field is zero.
- * Longer than the message, this field contains the number of
- * bytes remaining in the buffer.
- * Shorter than the message, this field contains the residual
- * count (that is, the number of bytes remaining in the
- * message that does not fit into the buffer. In this
- * case b2f0_result = 5.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Buffer address is NULL.
- */
-int iucv_receive_array (u16 pathid,
- u32 msgid,
- u32 trgcls,
- iucv_array_t * buffer,
- ulong buflen,
- int *flags1_out,
- ulong * residual_buffer, ulong * residual_length);
-
-/*
- * Name: iucv_reject
- * Purpose: The reject function refuses a specified message. Between the
- * time you are notified of a message and the time that you
- * complete the message, the message may be rejected.
- * Input: pathid - Path identification number.
- * msgid - Specifies the message ID.
- * trgcls - Specifies target class.
- * Output: NA
- * Return: Return code from CP IUCV call.
-*/
-int iucv_reject (u16 pathid, u32 msgid, u32 trgcls);
-
-/*
- * Name: iucv_reply
- * Purpose: This function responds to the two-way messages that you
- * receive. You must identify completely the message to
- * which you wish to reply. ie, pathid, msgid, and trgcls.
- * Input: pathid - Path identification number.
- * msgid - Specifies the message ID.
- * trgcls - Specifies target class.
- * flags1 - Option for path.
- * IPPRTY- 0x20, Specifies if you want to send priority message.
- * buffer - Address of reply buffer.
- * buflen - Length of reply buffer.
- * Output: residual_buffer - Address of buffer updated by the number
- * of bytes you have moved.
- * residual_length - Contains one of the following values:
- * If the answer buffer is the same length as the reply, this field
- * contains zero.
- * If the answer buffer is longer than the reply, this field contains
- * the number of bytes remaining in the buffer.
- * If the answer buffer is shorter than the reply, this field contains
- * a residual count (that is, the number of bytes remianing in the
- * reply that does not fit into the buffer. In this
- * case b2f0_result = 5.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Buffer address is NULL.
-*/
-int iucv_reply (u16 pathid,
- u32 msgid,
- u32 trgcls,
- int flags1,
- void *buffer, ulong buflen, ulong * residual_buffer,
- ulong * residual_length);
-
-/*
- * Name: iucv_reply_array
- * Purpose: This function responds to the two-way messages that you
- * receive. You must identify completely the message to
- * which you wish to reply. ie, pathid, msgid, and trgcls.
- * The array identifies a list of addresses and lengths of
- * discontiguous buffers that contains the reply data.
- * Input: pathid - Path identification number
- * msgid - Specifies the message ID.
- * trgcls - Specifies target class.
- * flags1 - Option for path.
- * IPPRTY- 0x20, Specifies if you want to send priority message.
- * buffer - Address of array of reply buffers.
- * buflen - Total length of reply buffers.
- * Output: residual_buffer - Address of buffer which IUCV is currently working on.
- * residual_length - Contains one of the following values:
- * If the answer buffer is the same length as the reply, this field
- * contains zero.
- * If the answer buffer is longer than the reply, this field contains
- * the number of bytes remaining in the buffer.
- * If the answer buffer is shorter than the reply, this field contains
- * a residual count (that is, the number of bytes remianing in the
- * reply that does not fit into the buffer. In this
- * case b2f0_result = 5.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Buffer address is NULL.
-*/
-int iucv_reply_array (u16 pathid,
- u32 msgid,
- u32 trgcls,
- int flags1,
- iucv_array_t * buffer,
- ulong buflen, ulong * residual_address,
- ulong * residual_length);
-
-/*
- * Name: iucv_reply_prmmsg
- * Purpose: This function responds to the two-way messages that you
- * receive. You must identify completely the message to
- * which you wish to reply. ie, pathid, msgid, and trgcls.
- * Prmmsg signifies the data is moved into the
- * parameter list.
- * Input: pathid - Path identification number.
- * msgid - Specifies the message ID.
- * trgcls - Specifies target class.
- * flags1 - Option for path.
- * IPPRTY- 0x20 Specifies if you want to send priority message.
- * prmmsg - 8-bytes of data to be placed into the parameter.
- * list.
- * Output: NA
- * Return: Return code from CP IUCV call.
-*/
-int iucv_reply_prmmsg (u16 pathid,
- u32 msgid, u32 trgcls, int flags1, uchar prmmsg[8]);
-
-/*
- * Name: iucv_resume
- * Purpose: This function restores communications over a quiesced path
- * Input: pathid - Path identification number.
- * user_data - 16-bytes of user data.
- * Output: NA
- * Return: Return code from CP IUCV call.
-*/
-int iucv_resume (u16 pathid, uchar user_data[16]);
-
-/*
- * Name: iucv_send
- * Purpose: This function transmits data to another application.
- * Data to be transmitted is in a buffer and this is a
- * one-way message and the receiver will not reply to the
- * message.
- * Input: pathid - Path identification number.
- * trgcls - Specifies target class.
- * srccls - Specifies the source message class.
- * msgtag - Specifies a tag to be associated with the message.
- * flags1 - Option for path.
- * IPPRTY- 0x20 Specifies if you want to send priority message.
- * buffer - Address of send buffer.
- * buflen - Length of send buffer.
- * Output: msgid - Specifies the message ID.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Buffer address is NULL.
-*/
-int iucv_send (u16 pathid,
- u32 * msgid,
- u32 trgcls,
- u32 srccls, u32 msgtag, int flags1, void *buffer, ulong buflen);
-
-/*
- * Name: iucv_send_array
- * Purpose: This function transmits data to another application.
- * The contents of buffer is the address of the array of
- * addresses and lengths of discontiguous buffers that hold
- * the message text. This is a one-way message and the
- * receiver will not reply to the message.
- * Input: pathid - Path identification number.
- * trgcls - Specifies target class.
- * srccls - Specifies the source message class.
- * msgtag - Specifies a tag to be associated witht the message.
- * flags1 - Option for path.
- * IPPRTY- specifies if you want to send priority message.
- * buffer - Address of array of send buffers.
- * buflen - Total length of send buffers.
- * Output: msgid - Specifies the message ID.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Buffer address is NULL.
-*/
-int iucv_send_array (u16 pathid,
- u32 * msgid,
- u32 trgcls,
- u32 srccls,
- u32 msgtag,
- int flags1, iucv_array_t * buffer, ulong buflen);
-
-/*
- * Name: iucv_send_prmmsg
- * Purpose: This function transmits data to another application.
- * Prmmsg specifies that the 8-bytes of data are to be moved
- * into the parameter list. This is a one-way message and the
- * receiver will not reply to the message.
- * Input: pathid - Path identification number.
- * trgcls - Specifies target class.
- * srccls - Specifies the source message class.
- * msgtag - Specifies a tag to be associated with the message.
- * flags1 - Option for path.
- * IPPRTY- 0x20 specifies if you want to send priority message.
- * prmmsg - 8-bytes of data to be placed into parameter list.
- * Output: msgid - Specifies the message ID.
- * Return: Return code from CP IUCV call.
-*/
-int iucv_send_prmmsg (u16 pathid,
- u32 * msgid,
- u32 trgcls,
- u32 srccls, u32 msgtag, int flags1, uchar prmmsg[8]);
-
-/*
- * Name: iucv_send2way
- * Purpose: This function transmits data to another application.
- * Data to be transmitted is in a buffer. The receiver
- * of the send is expected to reply to the message and
- * a buffer is provided into which IUCV moves the reply
- * to this message.
- * Input: pathid - Path identification number.
- * trgcls - Specifies target class.
- * srccls - Specifies the source message class.
- * msgtag - Specifies a tag associated with the message.
- * flags1 - Option for path.
- * IPPRTY- 0x20 Specifies if you want to send priority message.
- * buffer - Address of send buffer.
- * buflen - Length of send buffer.
- * ansbuf - Address of buffer into which IUCV moves the reply of
- * this message.
- * anslen - Address of length of buffer.
- * Output: msgid - Specifies the message ID.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Buffer or ansbuf address is NULL.
-*/
-int iucv_send2way (u16 pathid,
- u32 * msgid,
- u32 trgcls,
- u32 srccls,
- u32 msgtag,
- int flags1,
- void *buffer, ulong buflen, void *ansbuf, ulong anslen);
-
-/*
- * Name: iucv_send2way_array
- * Purpose: This function transmits data to another application.
- * The contents of buffer is the address of the array of
- * addresses and lengths of discontiguous buffers that hold
- * the message text. The receiver of the send is expected to
- * reply to the message and a buffer is provided into which
- * IUCV moves the reply to this message.
- * Input: pathid - Path identification number.
- * trgcls - Specifies target class.
- * srccls - Specifies the source message class.
- * msgtag - Specifies a tag to be associated with the message.
- * flags1 - Option for path.
- * IPPRTY- 0x20 Specifies if you want to send priority message.
- * buffer - Sddress of array of send buffers.
- * buflen - Total length of send buffers.
- * ansbuf - Address of array of buffer into which IUCV moves the reply
- * of this message.
- * anslen - Address of length reply buffers.
- * Output: msgid - Specifies the message ID.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Buffer address is NULL.
-*/
-int iucv_send2way_array (u16 pathid,
- u32 * msgid,
- u32 trgcls,
- u32 srccls,
- u32 msgtag,
- int flags1,
- iucv_array_t * buffer,
- ulong buflen, iucv_array_t * ansbuf, ulong anslen);
-
-/*
- * Name: iucv_send2way_prmmsg
- * Purpose: This function transmits data to another application.
- * Prmmsg specifies that the 8-bytes of data are to be moved
- * into the parameter list. This is a two-way message and the
- * receiver of the message is expected to reply. A buffer
- * is provided into which IUCV moves the reply to this
- * message.
- * Input: pathid - Rath identification number.
- * trgcls - Specifies target class.
- * srccls - Specifies the source message class.
- * msgtag - Specifies a tag to be associated with the message.
- * flags1 - Option for path.
- * IPPRTY- 0x20 Specifies if you want to send priority message.
- * prmmsg - 8-bytes of data to be placed in parameter list.
- * ansbuf - Address of buffer into which IUCV moves the reply of
- * this message.
- * anslen - Address of length of buffer.
- * Output: msgid - Specifies the message ID.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Buffer address is NULL.
-*/
-int iucv_send2way_prmmsg (u16 pathid,
- u32 * msgid,
- u32 trgcls,
- u32 srccls,
- u32 msgtag,
- ulong flags1,
- uchar prmmsg[8], void *ansbuf, ulong anslen);
-
-/*
- * Name: iucv_send2way_prmmsg_array
- * Purpose: This function transmits data to another application.
- * Prmmsg specifies that the 8-bytes of data are to be moved
- * into the parameter list. This is a two-way message and the
- * receiver of the message is expected to reply. A buffer
- * is provided into which IUCV moves the reply to this
- * message. The contents of ansbuf is the address of the
- * array of addresses and lengths of discontiguous buffers
- * that contain the reply.
- * Input: pathid - Path identification number.
- * trgcls - Specifies target class.
- * srccls - Specifies the source message class.
- * msgtag - Specifies a tag to be associated with the message.
- * flags1 - Option for path.
- * IPPRTY- 0x20 specifies if you want to send priority message.
- * prmmsg - 8-bytes of data to be placed into the parameter list.
- * ansbuf - Address of array of buffer into which IUCV moves the reply
- * of this message.
- * anslen - Address of length of reply buffers.
- * Output: msgid - Specifies the message ID.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Ansbuf address is NULL.
-*/
-int iucv_send2way_prmmsg_array (u16 pathid,
- u32 * msgid,
- u32 trgcls,
- u32 srccls,
- u32 msgtag,
- int flags1,
- uchar prmmsg[8],
- iucv_array_t * ansbuf, ulong anslen);
-
-/*
- * Name: iucv_setmask
- * Purpose: This function enables or disables the following IUCV
- * external interruptions: Nonpriority and priority message
- * interrupts, nonpriority and priority reply interrupts.
- * Input: SetMaskFlag - options for interrupts
- * 0x80 - Nonpriority_MessagePendingInterruptsFlag
- * 0x40 - Priority_MessagePendingInterruptsFlag
- * 0x20 - Nonpriority_MessageCompletionInterruptsFlag
- * 0x10 - Priority_MessageCompletionInterruptsFlag
- * 0x08 - IUCVControlInterruptsFlag
- * Output: NA
- * Return: Return code from CP IUCV call.
-*/
-int iucv_setmask (int SetMaskFlag);
-
-/*
- * Name: iucv_sever
- * Purpose: This function terminates an IUCV path.
- * Input: pathid - Path identification number.
- * user_data - 16-bytes of user data.
- * Output: NA
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Interal error, wild pointer.
-*/
-int iucv_sever (u16 pathid, uchar user_data[16]);
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index e5665b6743a..b97dd15bdb9 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -828,7 +828,7 @@ lcs_notify_lancmd_waiters(struct lcs_card *card, struct lcs_cmd *cmd)
/**
* Emit buffer of a lan comand.
*/
-void
+static void
lcs_lancmd_timeout(unsigned long data)
{
struct lcs_reply *reply, *list_reply, *r;
@@ -1360,7 +1360,7 @@ lcs_get_problem(struct ccw_device *cdev, struct irb *irb)
return 0;
}
-void
+static void
lcs_schedule_recovery(struct lcs_card *card)
{
LCS_DBF_TEXT(2, trace, "startrec");
@@ -1990,7 +1990,7 @@ lcs_timeout_store (struct device *dev, struct device_attribute *attr, const char
}
-DEVICE_ATTR(lancmd_timeout, 0644, lcs_timeout_show, lcs_timeout_store);
+static DEVICE_ATTR(lancmd_timeout, 0644, lcs_timeout_show, lcs_timeout_store);
static ssize_t
lcs_dev_recover_store(struct device *dev, struct device_attribute *attr,
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c
index d7d1cc0a5c8..6387b483f2b 100644
--- a/drivers/s390/net/netiucv.c
+++ b/drivers/s390/net/netiucv.c
@@ -1,7 +1,7 @@
/*
* IUCV network driver
*
- * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com)
*
* Sysfs integration and all bugs therein by Cornelia Huck
@@ -58,13 +58,94 @@
#include <asm/io.h>
#include <asm/uaccess.h>
-#include "iucv.h"
+#include <net/iucv/iucv.h>
#include "fsm.h"
MODULE_AUTHOR
("(C) 2001 IBM Corporation by Fritz Elfert (felfert@millenux.com)");
MODULE_DESCRIPTION ("Linux for S/390 IUCV network driver");
+/**
+ * Debug Facility stuff
+ */
+#define IUCV_DBF_SETUP_NAME "iucv_setup"
+#define IUCV_DBF_SETUP_LEN 32
+#define IUCV_DBF_SETUP_PAGES 2
+#define IUCV_DBF_SETUP_NR_AREAS 1
+#define IUCV_DBF_SETUP_LEVEL 3
+
+#define IUCV_DBF_DATA_NAME "iucv_data"
+#define IUCV_DBF_DATA_LEN 128
+#define IUCV_DBF_DATA_PAGES 2
+#define IUCV_DBF_DATA_NR_AREAS 1
+#define IUCV_DBF_DATA_LEVEL 2
+
+#define IUCV_DBF_TRACE_NAME "iucv_trace"
+#define IUCV_DBF_TRACE_LEN 16
+#define IUCV_DBF_TRACE_PAGES 4
+#define IUCV_DBF_TRACE_NR_AREAS 1
+#define IUCV_DBF_TRACE_LEVEL 3
+
+#define IUCV_DBF_TEXT(name,level,text) \
+ do { \
+ debug_text_event(iucv_dbf_##name,level,text); \
+ } while (0)
+
+#define IUCV_DBF_HEX(name,level,addr,len) \
+ do { \
+ debug_event(iucv_dbf_##name,level,(void*)(addr),len); \
+ } while (0)
+
+DECLARE_PER_CPU(char[256], iucv_dbf_txt_buf);
+
+#define IUCV_DBF_TEXT_(name,level,text...) \
+ do { \
+ char* iucv_dbf_txt_buf = get_cpu_var(iucv_dbf_txt_buf); \
+ sprintf(iucv_dbf_txt_buf, text); \
+ debug_text_event(iucv_dbf_##name,level,iucv_dbf_txt_buf); \
+ put_cpu_var(iucv_dbf_txt_buf); \
+ } while (0)
+
+#define IUCV_DBF_SPRINTF(name,level,text...) \
+ do { \
+ debug_sprintf_event(iucv_dbf_trace, level, ##text ); \
+ debug_sprintf_event(iucv_dbf_trace, level, text ); \
+ } while (0)
+
+/**
+ * some more debug stuff
+ */
+#define IUCV_HEXDUMP16(importance,header,ptr) \
+PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \
+ "%02x %02x %02x %02x %02x %02x %02x %02x\n", \
+ *(((char*)ptr)),*(((char*)ptr)+1),*(((char*)ptr)+2), \
+ *(((char*)ptr)+3),*(((char*)ptr)+4),*(((char*)ptr)+5), \
+ *(((char*)ptr)+6),*(((char*)ptr)+7),*(((char*)ptr)+8), \
+ *(((char*)ptr)+9),*(((char*)ptr)+10),*(((char*)ptr)+11), \
+ *(((char*)ptr)+12),*(((char*)ptr)+13), \
+ *(((char*)ptr)+14),*(((char*)ptr)+15)); \
+PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \
+ "%02x %02x %02x %02x %02x %02x %02x %02x\n", \
+ *(((char*)ptr)+16),*(((char*)ptr)+17), \
+ *(((char*)ptr)+18),*(((char*)ptr)+19), \
+ *(((char*)ptr)+20),*(((char*)ptr)+21), \
+ *(((char*)ptr)+22),*(((char*)ptr)+23), \
+ *(((char*)ptr)+24),*(((char*)ptr)+25), \
+ *(((char*)ptr)+26),*(((char*)ptr)+27), \
+ *(((char*)ptr)+28),*(((char*)ptr)+29), \
+ *(((char*)ptr)+30),*(((char*)ptr)+31));
+
+static inline void iucv_hex_dump(unsigned char *buf, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ if (i && !(i % 16))
+ printk("\n");
+ printk("%02x ", *(buf + i));
+ }
+ printk("\n");
+}
#define PRINTK_HEADER " iucv: " /* for debugging */
@@ -73,6 +154,25 @@ static struct device_driver netiucv_driver = {
.bus = &iucv_bus,
};
+static int netiucv_callback_connreq(struct iucv_path *,
+ u8 ipvmid[8], u8 ipuser[16]);
+static void netiucv_callback_connack(struct iucv_path *, u8 ipuser[16]);
+static void netiucv_callback_connrej(struct iucv_path *, u8 ipuser[16]);
+static void netiucv_callback_connsusp(struct iucv_path *, u8 ipuser[16]);
+static void netiucv_callback_connres(struct iucv_path *, u8 ipuser[16]);
+static void netiucv_callback_rx(struct iucv_path *, struct iucv_message *);
+static void netiucv_callback_txdone(struct iucv_path *, struct iucv_message *);
+
+static struct iucv_handler netiucv_handler = {
+ .path_pending = netiucv_callback_connreq,
+ .path_complete = netiucv_callback_connack,
+ .path_severed = netiucv_callback_connrej,
+ .path_quiesced = netiucv_callback_connsusp,
+ .path_resumed = netiucv_callback_connres,
+ .message_pending = netiucv_callback_rx,
+ .message_complete = netiucv_callback_txdone
+};
+
/**
* Per connection profiling data
*/
@@ -92,9 +192,8 @@ struct connection_profile {
* Representation of one iucv connection
*/
struct iucv_connection {
- struct iucv_connection *next;
- iucv_handle_t handle;
- __u16 pathid;
+ struct list_head list;
+ struct iucv_path *path;
struct sk_buff *rx_buff;
struct sk_buff *tx_buff;
struct sk_buff_head collect_queue;
@@ -112,12 +211,9 @@ struct iucv_connection {
/**
* Linked list of all connection structs.
*/
-struct iucv_connection_struct {
- struct iucv_connection *iucv_connections;
- rwlock_t iucv_rwlock;
-};
-
-static struct iucv_connection_struct iucv_conns;
+static struct list_head iucv_connection_list =
+ LIST_HEAD_INIT(iucv_connection_list);
+static rwlock_t iucv_connection_rwlock = RW_LOCK_UNLOCKED;
/**
* Representation of event-data for the
@@ -142,11 +238,11 @@ struct netiucv_priv {
/**
* Link level header for a packet.
*/
-typedef struct ll_header_t {
- __u16 next;
-} ll_header;
+struct ll_header {
+ u16 next;
+};
-#define NETIUCV_HDRLEN (sizeof(ll_header))
+#define NETIUCV_HDRLEN (sizeof(struct ll_header))
#define NETIUCV_BUFSIZE_MAX 32768
#define NETIUCV_BUFSIZE_DEFAULT NETIUCV_BUFSIZE_MAX
#define NETIUCV_MTU_MAX (NETIUCV_BUFSIZE_MAX - NETIUCV_HDRLEN)
@@ -158,36 +254,26 @@ typedef struct ll_header_t {
* Compatibility macros for busy handling
* of network devices.
*/
-static __inline__ void netiucv_clear_busy(struct net_device *dev)
+static inline void netiucv_clear_busy(struct net_device *dev)
{
- clear_bit(0, &(((struct netiucv_priv *)dev->priv)->tbusy));
+ struct netiucv_priv *priv = netdev_priv(dev);
+ clear_bit(0, &priv->tbusy);
netif_wake_queue(dev);
}
-static __inline__ int netiucv_test_and_set_busy(struct net_device *dev)
+static inline int netiucv_test_and_set_busy(struct net_device *dev)
{
+ struct netiucv_priv *priv = netdev_priv(dev);
netif_stop_queue(dev);
- return test_and_set_bit(0, &((struct netiucv_priv *)dev->priv)->tbusy);
+ return test_and_set_bit(0, &priv->tbusy);
}
-static __u8 iucv_host[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-static __u8 iucvMagic[16] = {
+static u8 iucvMagic[16] = {
0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40
};
/**
- * This mask means the 16-byte IUCV "magic" and the origin userid must
- * match exactly as specified in order to give connection_pending()
- * control.
- */
-static __u8 netiucv_mask[] = {
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
-};
-
-/**
* Convert an iucv userId to its printable
* form (strip whitespace at end).
*
@@ -195,8 +281,7 @@ static __u8 netiucv_mask[] = {
*
* @returns The printable string (static data!!)
*/
-static __inline__ char *
-netiucv_printname(char *name)
+static inline char *netiucv_printname(char *name)
{
static char tmp[9];
char *p = tmp;
@@ -379,8 +464,7 @@ static debug_info_t *iucv_dbf_trace = NULL;
DEFINE_PER_CPU(char[256], iucv_dbf_txt_buf);
-static void
-iucv_unregister_dbf_views(void)
+static void iucv_unregister_dbf_views(void)
{
if (iucv_dbf_setup)
debug_unregister(iucv_dbf_setup);
@@ -389,8 +473,7 @@ iucv_unregister_dbf_views(void)
if (iucv_dbf_trace)
debug_unregister(iucv_dbf_trace);
}
-static int
-iucv_register_dbf_views(void)
+static int iucv_register_dbf_views(void)
{
iucv_dbf_setup = debug_register(IUCV_DBF_SETUP_NAME,
IUCV_DBF_SETUP_PAGES,
@@ -422,125 +505,111 @@ iucv_register_dbf_views(void)
return 0;
}
-/**
+/*
* Callback-wrappers, called from lowlevel iucv layer.
- *****************************************************************************/
+ */
-static void
-netiucv_callback_rx(iucv_MessagePending *eib, void *pgm_data)
+static void netiucv_callback_rx(struct iucv_path *path,
+ struct iucv_message *msg)
{
- struct iucv_connection *conn = (struct iucv_connection *)pgm_data;
+ struct iucv_connection *conn = path->private;
struct iucv_event ev;
ev.conn = conn;
- ev.data = (void *)eib;
-
+ ev.data = msg;
fsm_event(conn->fsm, CONN_EVENT_RX, &ev);
}
-static void
-netiucv_callback_txdone(iucv_MessageComplete *eib, void *pgm_data)
+static void netiucv_callback_txdone(struct iucv_path *path,
+ struct iucv_message *msg)
{
- struct iucv_connection *conn = (struct iucv_connection *)pgm_data;
+ struct iucv_connection *conn = path->private;
struct iucv_event ev;
ev.conn = conn;
- ev.data = (void *)eib;
+ ev.data = msg;
fsm_event(conn->fsm, CONN_EVENT_TXDONE, &ev);
}
-static void
-netiucv_callback_connack(iucv_ConnectionComplete *eib, void *pgm_data)
+static void netiucv_callback_connack(struct iucv_path *path, u8 ipuser[16])
{
- struct iucv_connection *conn = (struct iucv_connection *)pgm_data;
- struct iucv_event ev;
+ struct iucv_connection *conn = path->private;
- ev.conn = conn;
- ev.data = (void *)eib;
- fsm_event(conn->fsm, CONN_EVENT_CONN_ACK, &ev);
+ fsm_event(conn->fsm, CONN_EVENT_CONN_ACK, conn);
}
-static void
-netiucv_callback_connreq(iucv_ConnectionPending *eib, void *pgm_data)
+static int netiucv_callback_connreq(struct iucv_path *path,
+ u8 ipvmid[8], u8 ipuser[16])
{
- struct iucv_connection *conn = (struct iucv_connection *)pgm_data;
+ struct iucv_connection *conn = path->private;
struct iucv_event ev;
+ int rc;
- ev.conn = conn;
- ev.data = (void *)eib;
- fsm_event(conn->fsm, CONN_EVENT_CONN_REQ, &ev);
+ if (memcmp(iucvMagic, ipuser, sizeof(ipuser)))
+ /* ipuser must match iucvMagic. */
+ return -EINVAL;
+ rc = -EINVAL;
+ read_lock_bh(&iucv_connection_rwlock);
+ list_for_each_entry(conn, &iucv_connection_list, list) {
+ if (strncmp(ipvmid, conn->userid, 8))
+ continue;
+ /* Found a matching connection for this path. */
+ conn->path = path;
+ ev.conn = conn;
+ ev.data = path;
+ fsm_event(conn->fsm, CONN_EVENT_CONN_REQ, &ev);
+ rc = 0;
+ }
+ read_unlock_bh(&iucv_connection_rwlock);
+ return rc;
}
-static void
-netiucv_callback_connrej(iucv_ConnectionSevered *eib, void *pgm_data)
+static void netiucv_callback_connrej(struct iucv_path *path, u8 ipuser[16])
{
- struct iucv_connection *conn = (struct iucv_connection *)pgm_data;
- struct iucv_event ev;
+ struct iucv_connection *conn = path->private;
- ev.conn = conn;
- ev.data = (void *)eib;
- fsm_event(conn->fsm, CONN_EVENT_CONN_REJ, &ev);
+ fsm_event(conn->fsm, CONN_EVENT_CONN_REJ, conn);
}
-static void
-netiucv_callback_connsusp(iucv_ConnectionQuiesced *eib, void *pgm_data)
+static void netiucv_callback_connsusp(struct iucv_path *path, u8 ipuser[16])
{
- struct iucv_connection *conn = (struct iucv_connection *)pgm_data;
- struct iucv_event ev;
+ struct iucv_connection *conn = path->private;
- ev.conn = conn;
- ev.data = (void *)eib;
- fsm_event(conn->fsm, CONN_EVENT_CONN_SUS, &ev);
+ fsm_event(conn->fsm, CONN_EVENT_CONN_SUS, conn);
}
-static void
-netiucv_callback_connres(iucv_ConnectionResumed *eib, void *pgm_data)
+static void netiucv_callback_connres(struct iucv_path *path, u8 ipuser[16])
{
- struct iucv_connection *conn = (struct iucv_connection *)pgm_data;
- struct iucv_event ev;
+ struct iucv_connection *conn = path->private;
- ev.conn = conn;
- ev.data = (void *)eib;
- fsm_event(conn->fsm, CONN_EVENT_CONN_RES, &ev);
-}
-
-static iucv_interrupt_ops_t netiucv_ops = {
- .ConnectionPending = netiucv_callback_connreq,
- .ConnectionComplete = netiucv_callback_connack,
- .ConnectionSevered = netiucv_callback_connrej,
- .ConnectionQuiesced = netiucv_callback_connsusp,
- .ConnectionResumed = netiucv_callback_connres,
- .MessagePending = netiucv_callback_rx,
- .MessageComplete = netiucv_callback_txdone
-};
+ fsm_event(conn->fsm, CONN_EVENT_CONN_RES, conn);
+}
/**
* Dummy NOP action for all statemachines
*/
-static void
-fsm_action_nop(fsm_instance *fi, int event, void *arg)
+static void fsm_action_nop(fsm_instance *fi, int event, void *arg)
{
}
-/**
+/*
* Actions of the connection statemachine
- *****************************************************************************/
+ */
/**
- * Helper function for conn_action_rx()
- * Unpack a just received skb and hand it over to
- * upper layers.
+ * netiucv_unpack_skb
+ * @conn: The connection where this skb has been received.
+ * @pskb: The received skb.
*
- * @param conn The connection where this skb has been received.
- * @param pskb The received skb.
+ * Unpack a just received skb and hand it over to upper layers.
+ * Helper function for conn_action_rx.
*/
-//static __inline__ void
-static void
-netiucv_unpack_skb(struct iucv_connection *conn, struct sk_buff *pskb)
+static void netiucv_unpack_skb(struct iucv_connection *conn,
+ struct sk_buff *pskb)
{
struct net_device *dev = conn->netdev;
- struct netiucv_priv *privptr = dev->priv;
- __u16 offset = 0;
+ struct netiucv_priv *privptr = netdev_priv(dev);
+ u16 offset = 0;
skb_put(pskb, NETIUCV_HDRLEN);
pskb->dev = dev;
@@ -549,7 +618,7 @@ netiucv_unpack_skb(struct iucv_connection *conn, struct sk_buff *pskb)
while (1) {
struct sk_buff *skb;
- ll_header *header = (ll_header *)pskb->data;
+ struct ll_header *header = (struct ll_header *) pskb->data;
if (!header->next)
break;
@@ -595,40 +664,37 @@ netiucv_unpack_skb(struct iucv_connection *conn, struct sk_buff *pskb)
}
}
-static void
-conn_action_rx(fsm_instance *fi, int event, void *arg)
+static void conn_action_rx(fsm_instance *fi, int event, void *arg)
{
- struct iucv_event *ev = (struct iucv_event *)arg;
+ struct iucv_event *ev = arg;
struct iucv_connection *conn = ev->conn;
- iucv_MessagePending *eib = (iucv_MessagePending *)ev->data;
- struct netiucv_priv *privptr =(struct netiucv_priv *)conn->netdev->priv;
-
- __u32 msglen = eib->ln1msg2.ipbfln1f;
+ struct iucv_message *msg = ev->data;
+ struct netiucv_priv *privptr = netdev_priv(conn->netdev);
int rc;
IUCV_DBF_TEXT(trace, 4, __FUNCTION__);
if (!conn->netdev) {
- /* FRITZ: How to tell iucv LL to drop the msg? */
+ iucv_message_reject(conn->path, msg);
PRINT_WARN("Received data for unlinked connection\n");
IUCV_DBF_TEXT(data, 2,
- "Received data for unlinked connection\n");
+ "Received data for unlinked connection\n");
return;
}
- if (msglen > conn->max_buffsize) {
- /* FRITZ: How to tell iucv LL to drop the msg? */
+ if (msg->length > conn->max_buffsize) {
+ iucv_message_reject(conn->path, msg);
privptr->stats.rx_dropped++;
PRINT_WARN("msglen %d > max_buffsize %d\n",
- msglen, conn->max_buffsize);
+ msg->length, conn->max_buffsize);
IUCV_DBF_TEXT_(data, 2, "msglen %d > max_buffsize %d\n",
- msglen, conn->max_buffsize);
+ msg->length, conn->max_buffsize);
return;
}
conn->rx_buff->data = conn->rx_buff->tail = conn->rx_buff->head;
conn->rx_buff->len = 0;
- rc = iucv_receive(conn->pathid, eib->ipmsgid, eib->iptrgcls,
- conn->rx_buff->data, msglen, NULL, NULL, NULL);
- if (rc || msglen < 5) {
+ rc = iucv_message_receive(conn->path, msg, 0, conn->rx_buff->data,
+ msg->length, NULL);
+ if (rc || msg->length < 5) {
privptr->stats.rx_errors++;
PRINT_WARN("iucv_receive returned %08x\n", rc);
IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_receive\n", rc);
@@ -637,26 +703,26 @@ conn_action_rx(fsm_instance *fi, int event, void *arg)
netiucv_unpack_skb(conn, conn->rx_buff);
}
-static void
-conn_action_txdone(fsm_instance *fi, int event, void *arg)
+static void conn_action_txdone(fsm_instance *fi, int event, void *arg)
{
- struct iucv_event *ev = (struct iucv_event *)arg;
+ struct iucv_event *ev = arg;
struct iucv_connection *conn = ev->conn;
- iucv_MessageComplete *eib = (iucv_MessageComplete *)ev->data;
+ struct iucv_message *msg = ev->data;
+ struct iucv_message txmsg;
struct netiucv_priv *privptr = NULL;
- /* Shut up, gcc! skb is always below 2G. */
- __u32 single_flag = eib->ipmsgtag;
- __u32 txbytes = 0;
- __u32 txpackets = 0;
- __u32 stat_maxcq = 0;
+ u32 single_flag = msg->tag;
+ u32 txbytes = 0;
+ u32 txpackets = 0;
+ u32 stat_maxcq = 0;
struct sk_buff *skb;
unsigned long saveflags;
- ll_header header;
+ struct ll_header header;
+ int rc;
IUCV_DBF_TEXT(trace, 4, __FUNCTION__);
- if (conn && conn->netdev && conn->netdev->priv)
- privptr = (struct netiucv_priv *)conn->netdev->priv;
+ if (conn && conn->netdev)
+ privptr = netdev_priv(conn->netdev);
conn->prof.tx_pending--;
if (single_flag) {
if ((skb = skb_dequeue(&conn->commit_queue))) {
@@ -688,56 +754,55 @@ conn_action_txdone(fsm_instance *fi, int event, void *arg)
conn->prof.maxmulti = conn->collect_len;
conn->collect_len = 0;
spin_unlock_irqrestore(&conn->collect_lock, saveflags);
- if (conn->tx_buff->len) {
- int rc;
-
- header.next = 0;
- memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header,
- NETIUCV_HDRLEN);
+ if (conn->tx_buff->len == 0) {
+ fsm_newstate(fi, CONN_STATE_IDLE);
+ return;
+ }
- conn->prof.send_stamp = xtime;
- rc = iucv_send(conn->pathid, NULL, 0, 0, 0, 0,
+ header.next = 0;
+ memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header, NETIUCV_HDRLEN);
+ conn->prof.send_stamp = xtime;
+ txmsg.class = 0;
+ txmsg.tag = 0;
+ rc = iucv_message_send(conn->path, &txmsg, 0, 0,
conn->tx_buff->data, conn->tx_buff->len);
- conn->prof.doios_multi++;
- conn->prof.txlen += conn->tx_buff->len;
- conn->prof.tx_pending++;
- if (conn->prof.tx_pending > conn->prof.tx_max_pending)
- conn->prof.tx_max_pending = conn->prof.tx_pending;
- if (rc) {
- conn->prof.tx_pending--;
- fsm_newstate(fi, CONN_STATE_IDLE);
- if (privptr)
- privptr->stats.tx_errors += txpackets;
- PRINT_WARN("iucv_send returned %08x\n", rc);
- IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_send\n", rc);
- } else {
- if (privptr) {
- privptr->stats.tx_packets += txpackets;
- privptr->stats.tx_bytes += txbytes;
- }
- if (stat_maxcq > conn->prof.maxcqueue)
- conn->prof.maxcqueue = stat_maxcq;
- }
- } else
+ conn->prof.doios_multi++;
+ conn->prof.txlen += conn->tx_buff->len;
+ conn->prof.tx_pending++;
+ if (conn->prof.tx_pending > conn->prof.tx_max_pending)
+ conn->prof.tx_max_pending = conn->prof.tx_pending;
+ if (rc) {
+ conn->prof.tx_pending--;
fsm_newstate(fi, CONN_STATE_IDLE);
+ if (privptr)
+ privptr->stats.tx_errors += txpackets;
+ PRINT_WARN("iucv_send returned %08x\n", rc);
+ IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_send\n", rc);
+ } else {
+ if (privptr) {
+ privptr->stats.tx_packets += txpackets;
+ privptr->stats.tx_bytes += txbytes;
+ }
+ if (stat_maxcq > conn->prof.maxcqueue)
+ conn->prof.maxcqueue = stat_maxcq;
+ }
}
-static void
-conn_action_connaccept(fsm_instance *fi, int event, void *arg)
+static void conn_action_connaccept(fsm_instance *fi, int event, void *arg)
{
- struct iucv_event *ev = (struct iucv_event *)arg;
+ struct iucv_event *ev = arg;
struct iucv_connection *conn = ev->conn;
- iucv_ConnectionPending *eib = (iucv_ConnectionPending *)ev->data;
+ struct iucv_path *path = ev->data;
struct net_device *netdev = conn->netdev;
- struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv;
+ struct netiucv_priv *privptr = netdev_priv(netdev);
int rc;
- __u16 msglimit;
- __u8 udata[16];
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
- rc = iucv_accept(eib->ippathid, NETIUCV_QUEUELEN_DEFAULT, udata, 0,
- conn->handle, conn, NULL, &msglimit);
+ conn->path = path;
+ path->msglim = NETIUCV_QUEUELEN_DEFAULT;
+ path->flags = 0;
+ rc = iucv_path_accept(path, &netiucv_handler, NULL, conn);
if (rc) {
PRINT_WARN("%s: IUCV accept failed with error %d\n",
netdev->name, rc);
@@ -745,183 +810,126 @@ conn_action_connaccept(fsm_instance *fi, int event, void *arg)
return;
}
fsm_newstate(fi, CONN_STATE_IDLE);
- conn->pathid = eib->ippathid;
- netdev->tx_queue_len = msglimit;
+ netdev->tx_queue_len = conn->path->msglim;
fsm_event(privptr->fsm, DEV_EVENT_CONUP, netdev);
}
-static void
-conn_action_connreject(fsm_instance *fi, int event, void *arg)
+static void conn_action_connreject(fsm_instance *fi, int event, void *arg)
{
- struct iucv_event *ev = (struct iucv_event *)arg;
- struct iucv_connection *conn = ev->conn;
- struct net_device *netdev = conn->netdev;
- iucv_ConnectionPending *eib = (iucv_ConnectionPending *)ev->data;
- __u8 udata[16];
+ struct iucv_event *ev = arg;
+ struct iucv_path *path = ev->data;
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
-
- iucv_sever(eib->ippathid, udata);
- if (eib->ippathid != conn->pathid) {
- PRINT_INFO("%s: IR Connection Pending; "
- "pathid %d does not match original pathid %d\n",
- netdev->name, eib->ippathid, conn->pathid);
- IUCV_DBF_TEXT_(data, 2,
- "connreject: IR pathid %d, conn. pathid %d\n",
- eib->ippathid, conn->pathid);
- iucv_sever(conn->pathid, udata);
- }
+ iucv_path_sever(path, NULL);
}
-static void
-conn_action_connack(fsm_instance *fi, int event, void *arg)
+static void conn_action_connack(fsm_instance *fi, int event, void *arg)
{
- struct iucv_event *ev = (struct iucv_event *)arg;
- struct iucv_connection *conn = ev->conn;
- iucv_ConnectionComplete *eib = (iucv_ConnectionComplete *)ev->data;
+ struct iucv_connection *conn = arg;
struct net_device *netdev = conn->netdev;
- struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv;
+ struct netiucv_priv *privptr = netdev_priv(netdev);
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
-
fsm_deltimer(&conn->timer);
fsm_newstate(fi, CONN_STATE_IDLE);
- if (eib->ippathid != conn->pathid) {
- PRINT_INFO("%s: IR Connection Complete; "
- "pathid %d does not match original pathid %d\n",
- netdev->name, eib->ippathid, conn->pathid);
- IUCV_DBF_TEXT_(data, 2,
- "connack: IR pathid %d, conn. pathid %d\n",
- eib->ippathid, conn->pathid);
- conn->pathid = eib->ippathid;
- }
- netdev->tx_queue_len = eib->ipmsglim;
+ netdev->tx_queue_len = conn->path->msglim;
fsm_event(privptr->fsm, DEV_EVENT_CONUP, netdev);
}
-static void
-conn_action_conntimsev(fsm_instance *fi, int event, void *arg)
+static void conn_action_conntimsev(fsm_instance *fi, int event, void *arg)
{
- struct iucv_connection *conn = (struct iucv_connection *)arg;
- __u8 udata[16];
+ struct iucv_connection *conn = arg;
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
-
fsm_deltimer(&conn->timer);
- iucv_sever(conn->pathid, udata);
+ iucv_path_sever(conn->path, NULL);
fsm_newstate(fi, CONN_STATE_STARTWAIT);
}
-static void
-conn_action_connsever(fsm_instance *fi, int event, void *arg)
+static void conn_action_connsever(fsm_instance *fi, int event, void *arg)
{
- struct iucv_event *ev = (struct iucv_event *)arg;
- struct iucv_connection *conn = ev->conn;
+ struct iucv_connection *conn = arg;
struct net_device *netdev = conn->netdev;
- struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv;
- __u8 udata[16];
+ struct netiucv_priv *privptr = netdev_priv(netdev);
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
fsm_deltimer(&conn->timer);
- iucv_sever(conn->pathid, udata);
+ iucv_path_sever(conn->path, NULL);
PRINT_INFO("%s: Remote dropped connection\n", netdev->name);
IUCV_DBF_TEXT(data, 2,
- "conn_action_connsever: Remote dropped connection\n");
+ "conn_action_connsever: Remote dropped connection\n");
fsm_newstate(fi, CONN_STATE_STARTWAIT);
fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev);
}
-static void
-conn_action_start(fsm_instance *fi, int event, void *arg)
+static void conn_action_start(fsm_instance *fi, int event, void *arg)
{
- struct iucv_event *ev = (struct iucv_event *)arg;
- struct iucv_connection *conn = ev->conn;
- __u16 msglimit;
+ struct iucv_connection *conn = arg;
int rc;
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
- if (!conn->handle) {
- IUCV_DBF_TEXT(trace, 5, "calling iucv_register_program\n");
- conn->handle =
- iucv_register_program(iucvMagic, conn->userid,
- netiucv_mask,
- &netiucv_ops, conn);
- fsm_newstate(fi, CONN_STATE_STARTWAIT);
- if (!conn->handle) {
- fsm_newstate(fi, CONN_STATE_REGERR);
- conn->handle = NULL;
- IUCV_DBF_TEXT(setup, 2,
- "NULL from iucv_register_program\n");
- return;
- }
-
- PRINT_DEBUG("%s('%s'): registered successfully\n",
- conn->netdev->name, conn->userid);
- }
-
+ fsm_newstate(fi, CONN_STATE_STARTWAIT);
PRINT_DEBUG("%s('%s'): connecting ...\n",
- conn->netdev->name, conn->userid);
+ conn->netdev->name, conn->userid);
- /* We must set the state before calling iucv_connect because the callback
- * handler could be called at any point after the connection request is
- * sent */
+ /*
+ * We must set the state before calling iucv_connect because the
+ * callback handler could be called at any point after the connection
+ * request is sent
+ */
fsm_newstate(fi, CONN_STATE_SETUPWAIT);
- rc = iucv_connect(&(conn->pathid), NETIUCV_QUEUELEN_DEFAULT, iucvMagic,
- conn->userid, iucv_host, 0, NULL, &msglimit,
- conn->handle, conn);
+ conn->path = iucv_path_alloc(NETIUCV_QUEUELEN_DEFAULT, 0, GFP_KERNEL);
+ rc = iucv_path_connect(conn->path, &netiucv_handler, conn->userid,
+ NULL, iucvMagic, conn);
switch (rc) {
- case 0:
- conn->netdev->tx_queue_len = msglimit;
- fsm_addtimer(&conn->timer, NETIUCV_TIMEOUT_5SEC,
- CONN_EVENT_TIMER, conn);
- return;
- case 11:
- PRINT_INFO("%s: User %s is currently not available.\n",
- conn->netdev->name,
- netiucv_printname(conn->userid));
- fsm_newstate(fi, CONN_STATE_STARTWAIT);
- return;
- case 12:
- PRINT_INFO("%s: User %s is currently not ready.\n",
- conn->netdev->name,
- netiucv_printname(conn->userid));
- fsm_newstate(fi, CONN_STATE_STARTWAIT);
- return;
- case 13:
- PRINT_WARN("%s: Too many IUCV connections.\n",
- conn->netdev->name);
- fsm_newstate(fi, CONN_STATE_CONNERR);
- break;
- case 14:
- PRINT_WARN(
- "%s: User %s has too many IUCV connections.\n",
- conn->netdev->name,
- netiucv_printname(conn->userid));
- fsm_newstate(fi, CONN_STATE_CONNERR);
- break;
- case 15:
- PRINT_WARN(
- "%s: No IUCV authorization in CP directory.\n",
- conn->netdev->name);
- fsm_newstate(fi, CONN_STATE_CONNERR);
- break;
- default:
- PRINT_WARN("%s: iucv_connect returned error %d\n",
- conn->netdev->name, rc);
- fsm_newstate(fi, CONN_STATE_CONNERR);
- break;
+ case 0:
+ conn->netdev->tx_queue_len = conn->path->msglim;
+ fsm_addtimer(&conn->timer, NETIUCV_TIMEOUT_5SEC,
+ CONN_EVENT_TIMER, conn);
+ return;
+ case 11:
+ PRINT_INFO("%s: User %s is currently not available.\n",
+ conn->netdev->name,
+ netiucv_printname(conn->userid));
+ fsm_newstate(fi, CONN_STATE_STARTWAIT);
+ break;
+ case 12:
+ PRINT_INFO("%s: User %s is currently not ready.\n",
+ conn->netdev->name,
+ netiucv_printname(conn->userid));
+ fsm_newstate(fi, CONN_STATE_STARTWAIT);
+ break;
+ case 13:
+ PRINT_WARN("%s: Too many IUCV connections.\n",
+ conn->netdev->name);
+ fsm_newstate(fi, CONN_STATE_CONNERR);
+ break;
+ case 14:
+ PRINT_WARN("%s: User %s has too many IUCV connections.\n",
+ conn->netdev->name,
+ netiucv_printname(conn->userid));
+ fsm_newstate(fi, CONN_STATE_CONNERR);
+ break;
+ case 15:
+ PRINT_WARN("%s: No IUCV authorization in CP directory.\n",
+ conn->netdev->name);
+ fsm_newstate(fi, CONN_STATE_CONNERR);
+ break;
+ default:
+ PRINT_WARN("%s: iucv_connect returned error %d\n",
+ conn->netdev->name, rc);
+ fsm_newstate(fi, CONN_STATE_CONNERR);
+ break;
}
IUCV_DBF_TEXT_(setup, 5, "iucv_connect rc is %d\n", rc);
- IUCV_DBF_TEXT(trace, 5, "calling iucv_unregister_program\n");
- iucv_unregister_program(conn->handle);
- conn->handle = NULL;
+ kfree(conn->path);
+ conn->path = NULL;
}
-static void
-netiucv_purge_skb_queue(struct sk_buff_head *q)
+static void netiucv_purge_skb_queue(struct sk_buff_head *q)
{
struct sk_buff *skb;
@@ -931,36 +939,34 @@ netiucv_purge_skb_queue(struct sk_buff_head *q)
}
}
-static void
-conn_action_stop(fsm_instance *fi, int event, void *arg)
+static void conn_action_stop(fsm_instance *fi, int event, void *arg)
{
- struct iucv_event *ev = (struct iucv_event *)arg;
+ struct iucv_event *ev = arg;
struct iucv_connection *conn = ev->conn;
struct net_device *netdev = conn->netdev;
- struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv;
+ struct netiucv_priv *privptr = netdev_priv(netdev);
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
fsm_deltimer(&conn->timer);
fsm_newstate(fi, CONN_STATE_STOPPED);
netiucv_purge_skb_queue(&conn->collect_queue);
- if (conn->handle)
- IUCV_DBF_TEXT(trace, 5, "calling iucv_unregister_program\n");
- iucv_unregister_program(conn->handle);
- conn->handle = NULL;
+ if (conn->path) {
+ IUCV_DBF_TEXT(trace, 5, "calling iucv_path_sever\n");
+ iucv_path_sever(conn->path, iucvMagic);
+ kfree(conn->path);
+ conn->path = NULL;
+ }
netiucv_purge_skb_queue(&conn->commit_queue);
fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev);
}
-static void
-conn_action_inval(fsm_instance *fi, int event, void *arg)
+static void conn_action_inval(fsm_instance *fi, int event, void *arg)
{
- struct iucv_event *ev = (struct iucv_event *)arg;
- struct iucv_connection *conn = ev->conn;
+ struct iucv_connection *conn = arg;
struct net_device *netdev = conn->netdev;
- PRINT_WARN("%s: Cannot connect without username\n",
- netdev->name);
+ PRINT_WARN("%s: Cannot connect without username\n", netdev->name);
IUCV_DBF_TEXT(data, 2, "conn_action_inval called\n");
}
@@ -999,29 +1005,27 @@ static const fsm_node conn_fsm[] = {
static const int CONN_FSM_LEN = sizeof(conn_fsm) / sizeof(fsm_node);
-/**
+/*
* Actions for interface - statemachine.
- *****************************************************************************/
+ */
/**
- * Startup connection by sending CONN_EVENT_START to it.
+ * dev_action_start
+ * @fi: An instance of an interface statemachine.
+ * @event: The event, just happened.
+ * @arg: Generic pointer, casted from struct net_device * upon call.
*
- * @param fi An instance of an interface statemachine.
- * @param event The event, just happened.
- * @param arg Generic pointer, casted from struct net_device * upon call.
+ * Startup connection by sending CONN_EVENT_START to it.
*/
-static void
-dev_action_start(fsm_instance *fi, int event, void *arg)
+static void dev_action_start(fsm_instance *fi, int event, void *arg)
{
- struct net_device *dev = (struct net_device *)arg;
- struct netiucv_priv *privptr = dev->priv;
- struct iucv_event ev;
+ struct net_device *dev = arg;
+ struct netiucv_priv *privptr = netdev_priv(dev);
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
- ev.conn = privptr->conn;
fsm_newstate(fi, DEV_STATE_STARTWAIT);
- fsm_event(privptr->conn->fsm, CONN_EVENT_START, &ev);
+ fsm_event(privptr->conn->fsm, CONN_EVENT_START, privptr->conn);
}
/**
@@ -1034,8 +1038,8 @@ dev_action_start(fsm_instance *fi, int event, void *arg)
static void
dev_action_stop(fsm_instance *fi, int event, void *arg)
{
- struct net_device *dev = (struct net_device *)arg;
- struct netiucv_priv *privptr = dev->priv;
+ struct net_device *dev = arg;
+ struct netiucv_priv *privptr = netdev_priv(dev);
struct iucv_event ev;
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
@@ -1057,8 +1061,8 @@ dev_action_stop(fsm_instance *fi, int event, void *arg)
static void
dev_action_connup(fsm_instance *fi, int event, void *arg)
{
- struct net_device *dev = (struct net_device *)arg;
- struct netiucv_priv *privptr = dev->priv;
+ struct net_device *dev = arg;
+ struct netiucv_priv *privptr = netdev_priv(dev);
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
@@ -1131,11 +1135,13 @@ static const int DEV_FSM_LEN = sizeof(dev_fsm) / sizeof(fsm_node);
*
* @return 0 on success, -ERRNO on failure. (Never fails.)
*/
-static int
-netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) {
+static int netiucv_transmit_skb(struct iucv_connection *conn,
+ struct sk_buff *skb)
+{
+ struct iucv_message msg;
unsigned long saveflags;
- ll_header header;
- int rc = 0;
+ struct ll_header header;
+ int rc;
if (fsm_getstate(conn->fsm) != CONN_STATE_IDLE) {
int l = skb->len + NETIUCV_HDRLEN;
@@ -1145,11 +1151,12 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) {
(conn->max_buffsize - NETIUCV_HDRLEN)) {
rc = -EBUSY;
IUCV_DBF_TEXT(data, 2,
- "EBUSY from netiucv_transmit_skb\n");
+ "EBUSY from netiucv_transmit_skb\n");
} else {
atomic_inc(&skb->users);
skb_queue_tail(&conn->collect_queue, skb);
conn->collect_len += l;
+ rc = 0;
}
spin_unlock_irqrestore(&conn->collect_lock, saveflags);
} else {
@@ -1188,9 +1195,10 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) {
fsm_newstate(conn->fsm, CONN_STATE_TX);
conn->prof.send_stamp = xtime;
- rc = iucv_send(conn->pathid, NULL, 0, 0, 1 /* single_flag */,
- 0, nskb->data, nskb->len);
- /* Shut up, gcc! nskb is always below 2G. */
+ msg.tag = 1;
+ msg.class = 0;
+ rc = iucv_message_send(conn->path, &msg, 0, 0,
+ nskb->data, nskb->len);
conn->prof.doios_single++;
conn->prof.txlen += skb->len;
conn->prof.tx_pending++;
@@ -1200,7 +1208,7 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) {
struct netiucv_priv *privptr;
fsm_newstate(conn->fsm, CONN_STATE_IDLE);
conn->prof.tx_pending--;
- privptr = (struct netiucv_priv *)conn->netdev->priv;
+ privptr = netdev_priv(conn->netdev);
if (privptr)
privptr->stats.tx_errors++;
if (copied)
@@ -1226,9 +1234,9 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) {
return rc;
}
-/**
+/*
* Interface API for upper network layers
- *****************************************************************************/
+ */
/**
* Open an interface.
@@ -1238,9 +1246,11 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) {
*
* @return 0 on success, -ERRNO on failure. (Never fails.)
*/
-static int
-netiucv_open(struct net_device *dev) {
- fsm_event(((struct netiucv_priv *)dev->priv)->fsm, DEV_EVENT_START,dev);
+static int netiucv_open(struct net_device *dev)
+{
+ struct netiucv_priv *priv = netdev_priv(dev);
+
+ fsm_event(priv->fsm, DEV_EVENT_START, dev);
return 0;
}
@@ -1252,9 +1262,11 @@ netiucv_open(struct net_device *dev) {
*
* @return 0 on success, -ERRNO on failure. (Never fails.)
*/
-static int
-netiucv_close(struct net_device *dev) {
- fsm_event(((struct netiucv_priv *)dev->priv)->fsm, DEV_EVENT_STOP, dev);
+static int netiucv_close(struct net_device *dev)
+{
+ struct netiucv_priv *priv = netdev_priv(dev);
+
+ fsm_event(priv->fsm, DEV_EVENT_STOP, dev);
return 0;
}
@@ -1271,8 +1283,8 @@ netiucv_close(struct net_device *dev) {
*/
static int netiucv_tx(struct sk_buff *skb, struct net_device *dev)
{
- int rc = 0;
- struct netiucv_priv *privptr = dev->priv;
+ struct netiucv_priv *privptr = netdev_priv(dev);
+ int rc;
IUCV_DBF_TEXT(trace, 4, __FUNCTION__);
/**
@@ -1312,40 +1324,41 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev)
return -EBUSY;
}
dev->trans_start = jiffies;
- if (netiucv_transmit_skb(privptr->conn, skb))
- rc = 1;
+ rc = netiucv_transmit_skb(privptr->conn, skb) != 0;
netiucv_clear_busy(dev);
return rc;
}
/**
- * Returns interface statistics of a device.
+ * netiucv_stats
+ * @dev: Pointer to interface struct.
*
- * @param dev Pointer to interface struct.
+ * Returns interface statistics of a device.
*
- * @return Pointer to stats struct of this interface.
+ * Returns pointer to stats struct of this interface.
*/
-static struct net_device_stats *
-netiucv_stats (struct net_device * dev)
+static struct net_device_stats *netiucv_stats (struct net_device * dev)
{
+ struct netiucv_priv *priv = netdev_priv(dev);
+
IUCV_DBF_TEXT(trace, 5, __FUNCTION__);
- return &((struct netiucv_priv *)dev->priv)->stats;
+ return &priv->stats;
}
/**
- * Sets MTU of an interface.
+ * netiucv_change_mtu
+ * @dev: Pointer to interface struct.
+ * @new_mtu: The new MTU to use for this interface.
*
- * @param dev Pointer to interface struct.
- * @param new_mtu The new MTU to use for this interface.
+ * Sets MTU of an interface.
*
- * @return 0 on success, -EINVAL if MTU is out of valid range.
+ * Returns 0 on success, -EINVAL if MTU is out of valid range.
* (valid range is 576 .. NETIUCV_MTU_MAX).
*/
-static int
-netiucv_change_mtu (struct net_device * dev, int new_mtu)
+static int netiucv_change_mtu(struct net_device * dev, int new_mtu)
{
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
- if ((new_mtu < 576) || (new_mtu > NETIUCV_MTU_MAX)) {
+ if (new_mtu < 576 || new_mtu > NETIUCV_MTU_MAX) {
IUCV_DBF_TEXT(setup, 2, "given MTU out of valid range\n");
return -EINVAL;
}
@@ -1353,12 +1366,12 @@ netiucv_change_mtu (struct net_device * dev, int new_mtu)
return 0;
}
-/**
+/*
* attributes in sysfs
- *****************************************************************************/
+ */
-static ssize_t
-user_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t user_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1366,8 +1379,8 @@ user_show (struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%s\n", netiucv_printname(priv->conn->userid));
}
-static ssize_t
-user_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t user_write(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
struct net_device *ndev = priv->conn->netdev;
@@ -1375,80 +1388,70 @@ user_write (struct device *dev, struct device_attribute *attr, const char *buf,
char *tmp;
char username[9];
int i;
- struct iucv_connection **clist = &iucv_conns.iucv_connections;
- unsigned long flags;
+ struct iucv_connection *cp;
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
- if (count>9) {
- PRINT_WARN("netiucv: username too long (%d)!\n", (int)count);
+ if (count > 9) {
+ PRINT_WARN("netiucv: username too long (%d)!\n", (int) count);
IUCV_DBF_TEXT_(setup, 2,
- "%d is length of username\n", (int)count);
+ "%d is length of username\n", (int) count);
return -EINVAL;
}
tmp = strsep((char **) &buf, "\n");
- for (i=0, p=tmp; i<8 && *p; i++, p++) {
- if (isalnum(*p) || (*p == '$'))
+ for (i = 0, p = tmp; i < 8 && *p; i++, p++) {
+ if (isalnum(*p) || (*p == '$')) {
username[i]= toupper(*p);
- else if (*p == '\n') {
+ continue;
+ }
+ if (*p == '\n') {
/* trailing lf, grr */
break;
- } else {
- PRINT_WARN("netiucv: Invalid char %c in username!\n",
- *p);
- IUCV_DBF_TEXT_(setup, 2,
- "username: invalid character %c\n",
- *p);
- return -EINVAL;
}
+ PRINT_WARN("netiucv: Invalid char %c in username!\n", *p);
+ IUCV_DBF_TEXT_(setup, 2,
+ "username: invalid character %c\n", *p);
+ return -EINVAL;
}
- while (i<8)
+ while (i < 8)
username[i++] = ' ';
username[8] = '\0';
- if (memcmp(username, priv->conn->userid, 9)) {
- /* username changed */
- if (ndev->flags & (IFF_UP | IFF_RUNNING)) {
- PRINT_WARN(
- "netiucv: device %s active, connected to %s\n",
- dev->bus_id, priv->conn->userid);
- PRINT_WARN("netiucv: user cannot be updated\n");
- IUCV_DBF_TEXT(setup, 2, "user_write: device active\n");
- return -EBUSY;
+ if (memcmp(username, priv->conn->userid, 9) &&
+ (ndev->flags & (IFF_UP | IFF_RUNNING))) {
+ /* username changed while the interface is active. */
+ PRINT_WARN("netiucv: device %s active, connected to %s\n",
+ dev->bus_id, priv->conn->userid);
+ PRINT_WARN("netiucv: user cannot be updated\n");
+ IUCV_DBF_TEXT(setup, 2, "user_write: device active\n");
+ return -EBUSY;
+ }
+ read_lock_bh(&iucv_connection_rwlock);
+ list_for_each_entry(cp, &iucv_connection_list, list) {
+ if (!strncmp(username, cp->userid, 9) && cp->netdev != ndev) {
+ read_unlock_bh(&iucv_connection_rwlock);
+ PRINT_WARN("netiucv: Connection to %s already "
+ "exists\n", username);
+ return -EEXIST;
}
}
- read_lock_irqsave(&iucv_conns.iucv_rwlock, flags);
- while (*clist) {
- if (!strncmp(username, (*clist)->userid, 9) ||
- ((*clist)->netdev != ndev))
- break;
- clist = &((*clist)->next);
- }
- read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
- if (*clist) {
- PRINT_WARN("netiucv: Connection to %s already exists\n",
- username);
- return -EEXIST;
- }
+ read_unlock_bh(&iucv_connection_rwlock);
memcpy(priv->conn->userid, username, 9);
-
return count;
-
}
static DEVICE_ATTR(user, 0644, user_show, user_write);
-static ssize_t
-buffer_show (struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct netiucv_priv *priv = dev->driver_data;
+static ssize_t buffer_show (struct device *dev, struct device_attribute *attr,
+ char *buf)
+{ struct netiucv_priv *priv = dev->driver_data;
IUCV_DBF_TEXT(trace, 5, __FUNCTION__);
return sprintf(buf, "%d\n", priv->conn->max_buffsize);
}
-static ssize_t
-buffer_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t buffer_write (struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
struct net_device *ndev = priv->conn->netdev;
@@ -1502,8 +1505,8 @@ buffer_write (struct device *dev, struct device_attribute *attr, const char *buf
static DEVICE_ATTR(buffer, 0644, buffer_show, buffer_write);
-static ssize_t
-dev_fsm_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t dev_fsm_show (struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1513,8 +1516,8 @@ dev_fsm_show (struct device *dev, struct device_attribute *attr, char *buf)
static DEVICE_ATTR(device_fsm_state, 0444, dev_fsm_show, NULL);
-static ssize_t
-conn_fsm_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t conn_fsm_show (struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1524,8 +1527,8 @@ conn_fsm_show (struct device *dev, struct device_attribute *attr, char *buf)
static DEVICE_ATTR(connection_fsm_state, 0444, conn_fsm_show, NULL);
-static ssize_t
-maxmulti_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t maxmulti_show (struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1533,8 +1536,9 @@ maxmulti_show (struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%ld\n", priv->conn->prof.maxmulti);
}
-static ssize_t
-maxmulti_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t maxmulti_write (struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1545,8 +1549,8 @@ maxmulti_write (struct device *dev, struct device_attribute *attr, const char *b
static DEVICE_ATTR(max_tx_buffer_used, 0644, maxmulti_show, maxmulti_write);
-static ssize_t
-maxcq_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t maxcq_show (struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1554,8 +1558,8 @@ maxcq_show (struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%ld\n", priv->conn->prof.maxcqueue);
}
-static ssize_t
-maxcq_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t maxcq_write (struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1566,8 +1570,8 @@ maxcq_write (struct device *dev, struct device_attribute *attr, const char *buf,
static DEVICE_ATTR(max_chained_skbs, 0644, maxcq_show, maxcq_write);
-static ssize_t
-sdoio_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t sdoio_show (struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1575,8 +1579,8 @@ sdoio_show (struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%ld\n", priv->conn->prof.doios_single);
}
-static ssize_t
-sdoio_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t sdoio_write (struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1587,8 +1591,8 @@ sdoio_write (struct device *dev, struct device_attribute *attr, const char *buf,
static DEVICE_ATTR(tx_single_write_ops, 0644, sdoio_show, sdoio_write);
-static ssize_t
-mdoio_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t mdoio_show (struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1596,8 +1600,8 @@ mdoio_show (struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%ld\n", priv->conn->prof.doios_multi);
}
-static ssize_t
-mdoio_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t mdoio_write (struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1608,8 +1612,8 @@ mdoio_write (struct device *dev, struct device_attribute *attr, const char *buf,
static DEVICE_ATTR(tx_multi_write_ops, 0644, mdoio_show, mdoio_write);
-static ssize_t
-txlen_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t txlen_show (struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1617,8 +1621,8 @@ txlen_show (struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%ld\n", priv->conn->prof.txlen);
}
-static ssize_t
-txlen_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t txlen_write (struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1629,8 +1633,8 @@ txlen_write (struct device *dev, struct device_attribute *attr, const char *buf,
static DEVICE_ATTR(netto_bytes, 0644, txlen_show, txlen_write);
-static ssize_t
-txtime_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t txtime_show (struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1638,8 +1642,8 @@ txtime_show (struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%ld\n", priv->conn->prof.tx_time);
}
-static ssize_t
-txtime_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t txtime_write (struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1650,8 +1654,8 @@ txtime_write (struct device *dev, struct device_attribute *attr, const char *buf
static DEVICE_ATTR(max_tx_io_time, 0644, txtime_show, txtime_write);
-static ssize_t
-txpend_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t txpend_show (struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1659,8 +1663,8 @@ txpend_show (struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%ld\n", priv->conn->prof.tx_pending);
}
-static ssize_t
-txpend_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t txpend_write (struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1671,8 +1675,8 @@ txpend_write (struct device *dev, struct device_attribute *attr, const char *buf
static DEVICE_ATTR(tx_pending, 0644, txpend_show, txpend_write);
-static ssize_t
-txmpnd_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t txmpnd_show (struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1680,8 +1684,8 @@ txmpnd_show (struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%ld\n", priv->conn->prof.tx_max_pending);
}
-static ssize_t
-txmpnd_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t txmpnd_write (struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1721,8 +1725,7 @@ static struct attribute_group netiucv_stat_attr_group = {
.attrs = netiucv_stat_attrs,
};
-static inline int
-netiucv_add_files(struct device *dev)
+static inline int netiucv_add_files(struct device *dev)
{
int ret;
@@ -1736,18 +1739,16 @@ netiucv_add_files(struct device *dev)
return ret;
}
-static inline void
-netiucv_remove_files(struct device *dev)
+static inline void netiucv_remove_files(struct device *dev)
{
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
sysfs_remove_group(&dev->kobj, &netiucv_stat_attr_group);
sysfs_remove_group(&dev->kobj, &netiucv_attr_group);
}
-static int
-netiucv_register_device(struct net_device *ndev)
+static int netiucv_register_device(struct net_device *ndev)
{
- struct netiucv_priv *priv = ndev->priv;
+ struct netiucv_priv *priv = netdev_priv(ndev);
struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL);
int ret;
@@ -1786,8 +1787,7 @@ out_unreg:
return ret;
}
-static void
-netiucv_unregister_device(struct device *dev)
+static void netiucv_unregister_device(struct device *dev)
{
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
netiucv_remove_files(dev);
@@ -1798,107 +1798,89 @@ netiucv_unregister_device(struct device *dev)
* Allocate and initialize a new connection structure.
* Add it to the list of netiucv connections;
*/
-static struct iucv_connection *
-netiucv_new_connection(struct net_device *dev, char *username)
-{
- unsigned long flags;
- struct iucv_connection **clist = &iucv_conns.iucv_connections;
- struct iucv_connection *conn =
- kzalloc(sizeof(struct iucv_connection), GFP_KERNEL);
-
- if (conn) {
- skb_queue_head_init(&conn->collect_queue);
- skb_queue_head_init(&conn->commit_queue);
- spin_lock_init(&conn->collect_lock);
- conn->max_buffsize = NETIUCV_BUFSIZE_DEFAULT;
- conn->netdev = dev;
-
- conn->rx_buff = alloc_skb(NETIUCV_BUFSIZE_DEFAULT,
- GFP_KERNEL | GFP_DMA);
- if (!conn->rx_buff) {
- kfree(conn);
- return NULL;
- }
- conn->tx_buff = alloc_skb(NETIUCV_BUFSIZE_DEFAULT,
- GFP_KERNEL | GFP_DMA);
- if (!conn->tx_buff) {
- kfree_skb(conn->rx_buff);
- kfree(conn);
- return NULL;
- }
- conn->fsm = init_fsm("netiucvconn", conn_state_names,
- conn_event_names, NR_CONN_STATES,
- NR_CONN_EVENTS, conn_fsm, CONN_FSM_LEN,
- GFP_KERNEL);
- if (!conn->fsm) {
- kfree_skb(conn->tx_buff);
- kfree_skb(conn->rx_buff);
- kfree(conn);
- return NULL;
- }
- fsm_settimer(conn->fsm, &conn->timer);
- fsm_newstate(conn->fsm, CONN_STATE_INVALID);
-
- if (username) {
- memcpy(conn->userid, username, 9);
- fsm_newstate(conn->fsm, CONN_STATE_STOPPED);
- }
+static struct iucv_connection *netiucv_new_connection(struct net_device *dev,
+ char *username)
+{
+ struct iucv_connection *conn;
- write_lock_irqsave(&iucv_conns.iucv_rwlock, flags);
- conn->next = *clist;
- *clist = conn;
- write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
+ conn = kzalloc(sizeof(*conn), GFP_KERNEL);
+ if (!conn)
+ goto out;
+ skb_queue_head_init(&conn->collect_queue);
+ skb_queue_head_init(&conn->commit_queue);
+ spin_lock_init(&conn->collect_lock);
+ conn->max_buffsize = NETIUCV_BUFSIZE_DEFAULT;
+ conn->netdev = dev;
+
+ conn->rx_buff = alloc_skb(conn->max_buffsize, GFP_KERNEL | GFP_DMA);
+ if (!conn->rx_buff)
+ goto out_conn;
+ conn->tx_buff = alloc_skb(conn->max_buffsize, GFP_KERNEL | GFP_DMA);
+ if (!conn->tx_buff)
+ goto out_rx;
+ conn->fsm = init_fsm("netiucvconn", conn_state_names,
+ conn_event_names, NR_CONN_STATES,
+ NR_CONN_EVENTS, conn_fsm, CONN_FSM_LEN,
+ GFP_KERNEL);
+ if (!conn->fsm)
+ goto out_tx;
+
+ fsm_settimer(conn->fsm, &conn->timer);
+ fsm_newstate(conn->fsm, CONN_STATE_INVALID);
+
+ if (username) {
+ memcpy(conn->userid, username, 9);
+ fsm_newstate(conn->fsm, CONN_STATE_STOPPED);
}
+
+ write_lock_bh(&iucv_connection_rwlock);
+ list_add_tail(&conn->list, &iucv_connection_list);
+ write_unlock_bh(&iucv_connection_rwlock);
return conn;
+
+out_tx:
+ kfree_skb(conn->tx_buff);
+out_rx:
+ kfree_skb(conn->rx_buff);
+out_conn:
+ kfree(conn);
+out:
+ return NULL;
}
/**
* Release a connection structure and remove it from the
* list of netiucv connections.
*/
-static void
-netiucv_remove_connection(struct iucv_connection *conn)
+static void netiucv_remove_connection(struct iucv_connection *conn)
{
- struct iucv_connection **clist = &iucv_conns.iucv_connections;
- unsigned long flags;
-
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
- if (conn == NULL)
- return;
- write_lock_irqsave(&iucv_conns.iucv_rwlock, flags);
- while (*clist) {
- if (*clist == conn) {
- *clist = conn->next;
- write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
- if (conn->handle) {
- iucv_unregister_program(conn->handle);
- conn->handle = NULL;
- }
- fsm_deltimer(&conn->timer);
- kfree_fsm(conn->fsm);
- kfree_skb(conn->rx_buff);
- kfree_skb(conn->tx_buff);
- return;
- }
- clist = &((*clist)->next);
+ write_lock_bh(&iucv_connection_rwlock);
+ list_del_init(&conn->list);
+ write_unlock_bh(&iucv_connection_rwlock);
+ if (conn->path) {
+ iucv_path_sever(conn->path, iucvMagic);
+ kfree(conn->path);
+ conn->path = NULL;
}
- write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
+ fsm_deltimer(&conn->timer);
+ kfree_fsm(conn->fsm);
+ kfree_skb(conn->rx_buff);
+ kfree_skb(conn->tx_buff);
}
/**
* Release everything of a net device.
*/
-static void
-netiucv_free_netdevice(struct net_device *dev)
+static void netiucv_free_netdevice(struct net_device *dev)
{
- struct netiucv_priv *privptr;
+ struct netiucv_priv *privptr = netdev_priv(dev);
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
if (!dev)
return;
- privptr = (struct netiucv_priv *)dev->priv;
if (privptr) {
if (privptr->conn)
netiucv_remove_connection(privptr->conn);
@@ -1913,11 +1895,8 @@ netiucv_free_netdevice(struct net_device *dev)
/**
* Initialize a net device. (Called from kernel in alloc_netdev())
*/
-static void
-netiucv_setup_netdevice(struct net_device *dev)
+static void netiucv_setup_netdevice(struct net_device *dev)
{
- memset(dev->priv, 0, sizeof(struct netiucv_priv));
-
dev->mtu = NETIUCV_MTU_DEFAULT;
dev->hard_start_xmit = netiucv_tx;
dev->open = netiucv_open;
@@ -1936,8 +1915,7 @@ netiucv_setup_netdevice(struct net_device *dev)
/**
* Allocate and initialize everything of a net device.
*/
-static struct net_device *
-netiucv_init_netdevice(char *username)
+static struct net_device *netiucv_init_netdevice(char *username)
{
struct netiucv_priv *privptr;
struct net_device *dev;
@@ -1946,40 +1924,40 @@ netiucv_init_netdevice(char *username)
netiucv_setup_netdevice);
if (!dev)
return NULL;
- if (dev_alloc_name(dev, dev->name) < 0) {
- free_netdev(dev);
- return NULL;
- }
+ if (dev_alloc_name(dev, dev->name) < 0)
+ goto out_netdev;
- privptr = (struct netiucv_priv *)dev->priv;
+ privptr = netdev_priv(dev);
privptr->fsm = init_fsm("netiucvdev", dev_state_names,
dev_event_names, NR_DEV_STATES, NR_DEV_EVENTS,
dev_fsm, DEV_FSM_LEN, GFP_KERNEL);
- if (!privptr->fsm) {
- free_netdev(dev);
- return NULL;
- }
+ if (!privptr->fsm)
+ goto out_netdev;
+
privptr->conn = netiucv_new_connection(dev, username);
if (!privptr->conn) {
- kfree_fsm(privptr->fsm);
- free_netdev(dev);
IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_new_connection\n");
- return NULL;
+ goto out_fsm;
}
fsm_newstate(privptr->fsm, DEV_STATE_STOPPED);
-
return dev;
+
+out_fsm:
+ kfree_fsm(privptr->fsm);
+out_netdev:
+ free_netdev(dev);
+ return NULL;
}
-static ssize_t
-conn_write(struct device_driver *drv, const char *buf, size_t count)
+static ssize_t conn_write(struct device_driver *drv,
+ const char *buf, size_t count)
{
- char *p;
+ const char *p;
char username[9];
- int i, ret;
+ int i, rc;
struct net_device *dev;
- struct iucv_connection **clist = &iucv_conns.iucv_connections;
- unsigned long flags;
+ struct netiucv_priv *priv;
+ struct iucv_connection *cp;
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
if (count>9) {
@@ -1988,83 +1966,82 @@ conn_write(struct device_driver *drv, const char *buf, size_t count)
return -EINVAL;
}
- for (i=0, p=(char *)buf; i<8 && *p; i++, p++) {
- if (isalnum(*p) || (*p == '$'))
- username[i]= toupper(*p);
- else if (*p == '\n') {
+ for (i = 0, p = buf; i < 8 && *p; i++, p++) {
+ if (isalnum(*p) || *p == '$') {
+ username[i] = toupper(*p);
+ continue;
+ }
+ if (*p == '\n')
/* trailing lf, grr */
break;
- } else {
- PRINT_WARN("netiucv: Invalid character in username!\n");
- IUCV_DBF_TEXT_(setup, 2,
- "conn_write: invalid character %c\n", *p);
- return -EINVAL;
- }
+ PRINT_WARN("netiucv: Invalid character in username!\n");
+ IUCV_DBF_TEXT_(setup, 2,
+ "conn_write: invalid character %c\n", *p);
+ return -EINVAL;
}
- while (i<8)
+ while (i < 8)
username[i++] = ' ';
username[8] = '\0';
- read_lock_irqsave(&iucv_conns.iucv_rwlock, flags);
- while (*clist) {
- if (!strncmp(username, (*clist)->userid, 9))
- break;
- clist = &((*clist)->next);
- }
- read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
- if (*clist) {
- PRINT_WARN("netiucv: Connection to %s already exists\n",
- username);
- return -EEXIST;
+ read_lock_bh(&iucv_connection_rwlock);
+ list_for_each_entry(cp, &iucv_connection_list, list) {
+ if (!strncmp(username, cp->userid, 9)) {
+ read_unlock_bh(&iucv_connection_rwlock);
+ PRINT_WARN("netiucv: Connection to %s already "
+ "exists\n", username);
+ return -EEXIST;
+ }
}
+ read_unlock_bh(&iucv_connection_rwlock);
+
dev = netiucv_init_netdevice(username);
if (!dev) {
- PRINT_WARN(
- "netiucv: Could not allocate network device structure "
- "for user '%s'\n", netiucv_printname(username));
+ PRINT_WARN("netiucv: Could not allocate network device "
+ "structure for user '%s'\n",
+ netiucv_printname(username));
IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_init_netdevice\n");
return -ENODEV;
}
- if ((ret = netiucv_register_device(dev))) {
+ rc = netiucv_register_device(dev);
+ if (rc) {
IUCV_DBF_TEXT_(setup, 2,
- "ret %d from netiucv_register_device\n", ret);
+ "ret %d from netiucv_register_device\n", rc);
goto out_free_ndev;
}
/* sysfs magic */
- SET_NETDEV_DEV(dev,
- (struct device*)((struct netiucv_priv*)dev->priv)->dev);
+ priv = netdev_priv(dev);
+ SET_NETDEV_DEV(dev, priv->dev);
- if ((ret = register_netdev(dev))) {
- netiucv_unregister_device((struct device*)
- ((struct netiucv_priv*)dev->priv)->dev);
- goto out_free_ndev;
- }
+ rc = register_netdev(dev);
+ if (rc)
+ goto out_unreg;
PRINT_INFO("%s: '%s'\n", dev->name, netiucv_printname(username));
return count;
+out_unreg:
+ netiucv_unregister_device(priv->dev);
out_free_ndev:
PRINT_WARN("netiucv: Could not register '%s'\n", dev->name);
IUCV_DBF_TEXT(setup, 2, "conn_write: could not register\n");
netiucv_free_netdevice(dev);
- return ret;
+ return rc;
}
-DRIVER_ATTR(connection, 0200, NULL, conn_write);
+static DRIVER_ATTR(connection, 0200, NULL, conn_write);
-static ssize_t
-remove_write (struct device_driver *drv, const char *buf, size_t count)
+static ssize_t remove_write (struct device_driver *drv,
+ const char *buf, size_t count)
{
- struct iucv_connection **clist = &iucv_conns.iucv_connections;
- unsigned long flags;
+ struct iucv_connection *cp;
struct net_device *ndev;
struct netiucv_priv *priv;
struct device *dev;
char name[IFNAMSIZ];
- char *p;
+ const char *p;
int i;
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
@@ -2072,33 +2049,27 @@ remove_write (struct device_driver *drv, const char *buf, size_t count)
if (count >= IFNAMSIZ)
count = IFNAMSIZ - 1;;
- for (i=0, p=(char *)buf; i<count && *p; i++, p++) {
- if ((*p == '\n') || (*p == ' ')) {
+ for (i = 0, p = buf; i < count && *p; i++, p++) {
+ if (*p == '\n' || *p == ' ')
/* trailing lf, grr */
break;
- } else {
- name[i]=*p;
- }
+ name[i] = *p;
}
name[i] = '\0';
- read_lock_irqsave(&iucv_conns.iucv_rwlock, flags);
- while (*clist) {
- ndev = (*clist)->netdev;
- priv = (struct netiucv_priv*)ndev->priv;
+ read_lock_bh(&iucv_connection_rwlock);
+ list_for_each_entry(cp, &iucv_connection_list, list) {
+ ndev = cp->netdev;
+ priv = netdev_priv(ndev);
dev = priv->dev;
-
- if (strncmp(name, ndev->name, count)) {
- clist = &((*clist)->next);
- continue;
- }
- read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
+ if (strncmp(name, ndev->name, count))
+ continue;
+ read_unlock_bh(&iucv_connection_rwlock);
if (ndev->flags & (IFF_UP | IFF_RUNNING)) {
- PRINT_WARN(
- "netiucv: net device %s active with peer %s\n",
- ndev->name, priv->conn->userid);
+ PRINT_WARN("netiucv: net device %s active with peer "
+ "%s\n", ndev->name, priv->conn->userid);
PRINT_WARN("netiucv: %s cannot be removed\n",
- ndev->name);
+ ndev->name);
IUCV_DBF_TEXT(data, 2, "remove_write: still active\n");
return -EBUSY;
}
@@ -2106,75 +2077,94 @@ remove_write (struct device_driver *drv, const char *buf, size_t count)
netiucv_unregister_device(dev);
return count;
}
- read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
+ read_unlock_bh(&iucv_connection_rwlock);
PRINT_WARN("netiucv: net device %s unknown\n", name);
IUCV_DBF_TEXT(data, 2, "remove_write: unknown device\n");
return -EINVAL;
}
-DRIVER_ATTR(remove, 0200, NULL, remove_write);
+static DRIVER_ATTR(remove, 0200, NULL, remove_write);
-static void
-netiucv_banner(void)
+static struct attribute * netiucv_drv_attrs[] = {
+ &driver_attr_connection.attr,
+ &driver_attr_remove.attr,
+ NULL,
+};
+
+static struct attribute_group netiucv_drv_attr_group = {
+ .attrs = netiucv_drv_attrs,
+};
+
+static void netiucv_banner(void)
{
PRINT_INFO("NETIUCV driver initialized\n");
}
-static void __exit
-netiucv_exit(void)
+static void __exit netiucv_exit(void)
{
+ struct iucv_connection *cp;
+ struct net_device *ndev;
+ struct netiucv_priv *priv;
+ struct device *dev;
+
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
- while (iucv_conns.iucv_connections) {
- struct net_device *ndev = iucv_conns.iucv_connections->netdev;
- struct netiucv_priv *priv = (struct netiucv_priv*)ndev->priv;
- struct device *dev = priv->dev;
+ while (!list_empty(&iucv_connection_list)) {
+ cp = list_entry(iucv_connection_list.next,
+ struct iucv_connection, list);
+ list_del(&cp->list);
+ ndev = cp->netdev;
+ priv = netdev_priv(ndev);
+ dev = priv->dev;
unregister_netdev(ndev);
netiucv_unregister_device(dev);
}
- driver_remove_file(&netiucv_driver, &driver_attr_connection);
- driver_remove_file(&netiucv_driver, &driver_attr_remove);
+ sysfs_remove_group(&netiucv_driver.kobj, &netiucv_drv_attr_group);
driver_unregister(&netiucv_driver);
+ iucv_unregister(&netiucv_handler, 1);
iucv_unregister_dbf_views();
PRINT_INFO("NETIUCV driver unloaded\n");
return;
}
-static int __init
-netiucv_init(void)
+static int __init netiucv_init(void)
{
- int ret;
+ int rc;
- ret = iucv_register_dbf_views();
- if (ret) {
- PRINT_WARN("netiucv_init failed, "
- "iucv_register_dbf_views rc = %d\n", ret);
- return ret;
- }
+ rc = iucv_register_dbf_views();
+ if (rc)
+ goto out;
+ rc = iucv_register(&netiucv_handler, 1);
+ if (rc)
+ goto out_dbf;
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
- ret = driver_register(&netiucv_driver);
- if (ret) {
+ rc = driver_register(&netiucv_driver);
+ if (rc) {
PRINT_ERR("NETIUCV: failed to register driver.\n");
- IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_register\n", ret);
- iucv_unregister_dbf_views();
- return ret;
+ IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_register\n", rc);
+ goto out_iucv;
}
- /* Add entry for specifying connections. */
- ret = driver_create_file(&netiucv_driver, &driver_attr_connection);
- if (!ret) {
- ret = driver_create_file(&netiucv_driver, &driver_attr_remove);
- netiucv_banner();
- rwlock_init(&iucv_conns.iucv_rwlock);
- } else {
- PRINT_ERR("NETIUCV: failed to add driver attribute.\n");
- IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_create_file\n", ret);
- driver_unregister(&netiucv_driver);
- iucv_unregister_dbf_views();
+ rc = sysfs_create_group(&netiucv_driver.kobj, &netiucv_drv_attr_group);
+ if (rc) {
+ PRINT_ERR("NETIUCV: failed to add driver attributes.\n");
+ IUCV_DBF_TEXT_(setup, 2,
+ "ret %d - netiucv_drv_attr_group\n", rc);
+ goto out_driver;
}
- return ret;
+ netiucv_banner();
+ return rc;
+
+out_driver:
+ driver_unregister(&netiucv_driver);
+out_iucv:
+ iucv_unregister(&netiucv_handler, 1);
+out_dbf:
+ iucv_unregister_dbf_views();
+out:
+ return rc;
}
module_init(netiucv_init);
diff --git a/drivers/s390/net/qeth_eddp.c b/drivers/s390/net/qeth_eddp.c
index 6bb558a9a03..7c735e1fe06 100644
--- a/drivers/s390/net/qeth_eddp.c
+++ b/drivers/s390/net/qeth_eddp.c
@@ -49,7 +49,7 @@ qeth_eddp_check_buffers_for_context(struct qeth_qdio_out_q *queue,
return buffers_needed;
}
-static inline void
+static void
qeth_eddp_free_context(struct qeth_eddp_context *ctx)
{
int i;
@@ -91,7 +91,7 @@ qeth_eddp_buf_release_contexts(struct qeth_qdio_out_buffer *buf)
}
}
-static inline int
+static int
qeth_eddp_buf_ref_context(struct qeth_qdio_out_buffer *buf,
struct qeth_eddp_context *ctx)
{
@@ -196,7 +196,7 @@ out:
return flush_cnt;
}
-static inline void
+static void
qeth_eddp_create_segment_hdrs(struct qeth_eddp_context *ctx,
struct qeth_eddp_data *eddp, int data_len)
{
@@ -256,7 +256,7 @@ qeth_eddp_create_segment_hdrs(struct qeth_eddp_context *ctx,
ctx->offset += eddp->thl;
}
-static inline void
+static void
qeth_eddp_copy_data_tcp(char *dst, struct qeth_eddp_data *eddp, int len,
__wsum *hcsum)
{
@@ -302,7 +302,7 @@ qeth_eddp_copy_data_tcp(char *dst, struct qeth_eddp_data *eddp, int len,
}
}
-static inline void
+static void
qeth_eddp_create_segment_data_tcp(struct qeth_eddp_context *ctx,
struct qeth_eddp_data *eddp, int data_len,
__wsum hcsum)
@@ -349,7 +349,7 @@ qeth_eddp_create_segment_data_tcp(struct qeth_eddp_context *ctx,
((struct tcphdr *)eddp->th_in_ctx)->check = csum_fold(hcsum);
}
-static inline __wsum
+static __wsum
qeth_eddp_check_tcp4_hdr(struct qeth_eddp_data *eddp, int data_len)
{
__wsum phcsum; /* pseudo header checksum */
@@ -363,7 +363,7 @@ qeth_eddp_check_tcp4_hdr(struct qeth_eddp_data *eddp, int data_len)
return csum_partial((u8 *)&eddp->th, eddp->thl, phcsum);
}
-static inline __wsum
+static __wsum
qeth_eddp_check_tcp6_hdr(struct qeth_eddp_data *eddp, int data_len)
{
__be32 proto;
@@ -381,7 +381,7 @@ qeth_eddp_check_tcp6_hdr(struct qeth_eddp_data *eddp, int data_len)
return phcsum;
}
-static inline struct qeth_eddp_data *
+static struct qeth_eddp_data *
qeth_eddp_create_eddp_data(struct qeth_hdr *qh, u8 *nh, u8 nhl, u8 *th, u8 thl)
{
struct qeth_eddp_data *eddp;
@@ -399,7 +399,7 @@ qeth_eddp_create_eddp_data(struct qeth_hdr *qh, u8 *nh, u8 nhl, u8 *th, u8 thl)
return eddp;
}
-static inline void
+static void
__qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
struct qeth_eddp_data *eddp)
{
@@ -464,7 +464,7 @@ __qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
}
}
-static inline int
+static int
qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
struct sk_buff *skb, struct qeth_hdr *qhdr)
{
@@ -505,7 +505,7 @@ qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
return 0;
}
-static inline void
+static void
qeth_eddp_calc_num_pages(struct qeth_eddp_context *ctx, struct sk_buff *skb,
int hdr_len)
{
@@ -529,7 +529,7 @@ qeth_eddp_calc_num_pages(struct qeth_eddp_context *ctx, struct sk_buff *skb,
(skb_shinfo(skb)->gso_segs + 1);
}
-static inline struct qeth_eddp_context *
+static struct qeth_eddp_context *
qeth_eddp_create_context_generic(struct qeth_card *card, struct sk_buff *skb,
int hdr_len)
{
@@ -581,7 +581,7 @@ qeth_eddp_create_context_generic(struct qeth_card *card, struct sk_buff *skb,
return ctx;
}
-static inline struct qeth_eddp_context *
+static struct qeth_eddp_context *
qeth_eddp_create_context_tcp(struct qeth_card *card, struct sk_buff *skb,
struct qeth_hdr *qhdr)
{
@@ -625,5 +625,3 @@ qeth_eddp_create_context(struct qeth_card *card, struct sk_buff *skb,
}
return NULL;
}
-
-
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
index d2efa5ff125..2257e45594b 100644
--- a/drivers/s390/net/qeth_main.c
+++ b/drivers/s390/net/qeth_main.c
@@ -651,7 +651,7 @@ __qeth_ref_ip_on_card(struct qeth_card *card, struct qeth_ipaddr *todo,
return 0;
}
-static inline int
+static int
__qeth_address_exists_in_list(struct list_head *list, struct qeth_ipaddr *addr,
int same_type)
{
@@ -795,7 +795,7 @@ qeth_add_ip(struct qeth_card *card, struct qeth_ipaddr *addr)
return rc;
}
-static inline void
+static void
__qeth_delete_all_mc(struct qeth_card *card, unsigned long *flags)
{
struct qeth_ipaddr *addr, *tmp;
@@ -882,7 +882,7 @@ static void qeth_layer2_add_multicast(struct qeth_card *);
static void qeth_add_multicast_ipv6(struct qeth_card *);
#endif
-static inline int
+static int
qeth_set_thread_start_bit(struct qeth_card *card, unsigned long thread)
{
unsigned long flags;
@@ -920,7 +920,7 @@ qeth_clear_thread_running_bit(struct qeth_card *card, unsigned long thread)
wake_up(&card->wait_q);
}
-static inline int
+static int
__qeth_do_run_thread(struct qeth_card *card, unsigned long thread)
{
unsigned long flags;
@@ -1764,9 +1764,9 @@ out:
qeth_release_buffer(channel,iob);
}
-static inline void
+static void
qeth_prepare_control_data(struct qeth_card *card, int len,
-struct qeth_cmd_buffer *iob)
+ struct qeth_cmd_buffer *iob)
{
qeth_setup_ccw(&card->write,iob->data,len);
iob->callback = qeth_release_buffer;
@@ -2160,7 +2160,7 @@ qeth_check_qdio_errors(struct qdio_buffer *buf, unsigned int qdio_error,
return 0;
}
-static inline struct sk_buff *
+static struct sk_buff *
qeth_get_skb(unsigned int length, struct qeth_hdr *hdr)
{
struct sk_buff* skb;
@@ -2179,7 +2179,7 @@ qeth_get_skb(unsigned int length, struct qeth_hdr *hdr)
return skb;
}
-static inline struct sk_buff *
+static struct sk_buff *
qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer,
struct qdio_buffer_element **__element, int *__offset,
struct qeth_hdr **hdr)
@@ -2264,7 +2264,7 @@ no_mem:
return NULL;
}
-static inline __be16
+static __be16
qeth_type_trans(struct sk_buff *skb, struct net_device *dev)
{
struct qeth_card *card;
@@ -2297,7 +2297,7 @@ qeth_type_trans(struct sk_buff *skb, struct net_device *dev)
return htons(ETH_P_802_2);
}
-static inline void
+static void
qeth_rebuild_skb_fake_ll_tr(struct qeth_card *card, struct sk_buff *skb,
struct qeth_hdr *hdr)
{
@@ -2351,7 +2351,7 @@ qeth_rebuild_skb_fake_ll_tr(struct qeth_card *card, struct sk_buff *skb,
fake_llc->ethertype = ETH_P_IP;
}
-static inline void
+static void
qeth_rebuild_skb_fake_ll_eth(struct qeth_card *card, struct sk_buff *skb,
struct qeth_hdr *hdr)
{
@@ -2420,7 +2420,7 @@ qeth_layer2_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
*((__u32 *)skb->cb) = ++card->seqno.pkt_seqno;
}
-static inline __u16
+static __u16
qeth_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
struct qeth_hdr *hdr)
{
@@ -2476,7 +2476,7 @@ qeth_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
return vlan_id;
}
-static inline void
+static void
qeth_process_inbound_buffer(struct qeth_card *card,
struct qeth_qdio_buffer *buf, int index)
{
@@ -2528,7 +2528,7 @@ qeth_process_inbound_buffer(struct qeth_card *card,
}
}
-static inline struct qeth_buffer_pool_entry *
+static struct qeth_buffer_pool_entry *
qeth_get_buffer_pool_entry(struct qeth_card *card)
{
struct qeth_buffer_pool_entry *entry;
@@ -2543,7 +2543,7 @@ qeth_get_buffer_pool_entry(struct qeth_card *card)
return NULL;
}
-static inline void
+static void
qeth_init_input_buffer(struct qeth_card *card, struct qeth_qdio_buffer *buf)
{
struct qeth_buffer_pool_entry *pool_entry;
@@ -2570,7 +2570,7 @@ qeth_init_input_buffer(struct qeth_card *card, struct qeth_qdio_buffer *buf)
buf->state = QETH_QDIO_BUF_EMPTY;
}
-static inline void
+static void
qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
struct qeth_qdio_out_buffer *buf)
{
@@ -2595,7 +2595,7 @@ qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
atomic_set(&buf->state, QETH_QDIO_BUF_EMPTY);
}
-static inline void
+static void
qeth_queue_input_buffer(struct qeth_card *card, int index)
{
struct qeth_qdio_q *queue = card->qdio.in_q;
@@ -2699,7 +2699,7 @@ qeth_qdio_input_handler(struct ccw_device * ccwdev, unsigned int status,
card->perf_stats.inbound_start_time;
}
-static inline int
+static int
qeth_handle_send_error(struct qeth_card *card,
struct qeth_qdio_out_buffer *buffer,
unsigned int qdio_err, unsigned int siga_err)
@@ -2821,7 +2821,7 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int,
* Switched to packing state if the number of used buffers on a queue
* reaches a certain limit.
*/
-static inline void
+static void
qeth_switch_to_packing_if_needed(struct qeth_qdio_out_q *queue)
{
if (!queue->do_pack) {
@@ -2842,7 +2842,7 @@ qeth_switch_to_packing_if_needed(struct qeth_qdio_out_q *queue)
* In that case 1 is returned to inform the caller. If no buffer
* has to be flushed, zero is returned.
*/
-static inline int
+static int
qeth_switch_to_nonpacking_if_needed(struct qeth_qdio_out_q *queue)
{
struct qeth_qdio_out_buffer *buffer;
@@ -2877,7 +2877,7 @@ qeth_switch_to_nonpacking_if_needed(struct qeth_qdio_out_q *queue)
* Checks if there is a packing buffer and prepares it to be flushed.
* In that case returns 1, otherwise zero.
*/
-static inline int
+static int
qeth_flush_buffers_on_no_pci(struct qeth_qdio_out_q *queue)
{
struct qeth_qdio_out_buffer *buffer;
@@ -2894,7 +2894,7 @@ qeth_flush_buffers_on_no_pci(struct qeth_qdio_out_q *queue)
return 0;
}
-static inline void
+static void
qeth_check_outbound_queue(struct qeth_qdio_out_q *queue)
{
int index;
@@ -3594,7 +3594,7 @@ qeth_fake_header(struct sk_buff *skb, struct net_device *dev,
}
}
-static inline int
+static int
qeth_send_packet(struct qeth_card *, struct sk_buff *);
static int
@@ -3759,7 +3759,7 @@ qeth_stop(struct net_device *dev)
return 0;
}
-static inline int
+static int
qeth_get_cast_type(struct qeth_card *card, struct sk_buff *skb)
{
int cast_type = RTN_UNSPEC;
@@ -3806,7 +3806,7 @@ qeth_get_cast_type(struct qeth_card *card, struct sk_buff *skb)
return cast_type;
}
-static inline int
+static int
qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb,
int ipv, int cast_type)
{
@@ -3853,7 +3853,7 @@ qeth_get_ip_version(struct sk_buff *skb)
}
}
-static inline struct qeth_hdr *
+static struct qeth_hdr *
__qeth_prepare_skb(struct qeth_card *card, struct sk_buff *skb, int ipv)
{
#ifdef CONFIG_QETH_VLAN
@@ -3882,14 +3882,14 @@ __qeth_prepare_skb(struct qeth_card *card, struct sk_buff *skb, int ipv)
qeth_push_skb(card, skb, sizeof(struct qeth_hdr)));
}
-static inline void
+static void
__qeth_free_new_skb(struct sk_buff *orig_skb, struct sk_buff *new_skb)
{
if (orig_skb != new_skb)
dev_kfree_skb_any(new_skb);
}
-static inline struct sk_buff *
+static struct sk_buff *
qeth_prepare_skb(struct qeth_card *card, struct sk_buff *skb,
struct qeth_hdr **hdr, int ipv)
{
@@ -3940,7 +3940,7 @@ qeth_get_qeth_hdr_flags6(int cast_type)
return ct | QETH_CAST_UNICAST;
}
-static inline void
+static void
qeth_layer2_get_packet_type(struct qeth_card *card, struct qeth_hdr *hdr,
struct sk_buff *skb)
{
@@ -3977,7 +3977,7 @@ qeth_layer2_get_packet_type(struct qeth_card *card, struct qeth_hdr *hdr,
}
}
-static inline void
+static void
qeth_layer2_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
struct sk_buff *skb, int cast_type)
{
@@ -4068,7 +4068,7 @@ qeth_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
}
}
-static inline void
+static void
__qeth_fill_buffer(struct sk_buff *skb, struct qdio_buffer *buffer,
int is_tso, int *next_element_to_fill)
{
@@ -4112,7 +4112,7 @@ __qeth_fill_buffer(struct sk_buff *skb, struct qdio_buffer *buffer,
*next_element_to_fill = element;
}
-static inline int
+static int
qeth_fill_buffer(struct qeth_qdio_out_q *queue,
struct qeth_qdio_out_buffer *buf,
struct sk_buff *skb)
@@ -4171,7 +4171,7 @@ qeth_fill_buffer(struct qeth_qdio_out_q *queue,
return flush_cnt;
}
-static inline int
+static int
qeth_do_send_packet_fast(struct qeth_card *card, struct qeth_qdio_out_q *queue,
struct sk_buff *skb, struct qeth_hdr *hdr,
int elements_needed,
@@ -4222,7 +4222,7 @@ out:
return -EBUSY;
}
-static inline int
+static int
qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
struct sk_buff *skb, struct qeth_hdr *hdr,
int elements_needed, struct qeth_eddp_context *ctx)
@@ -4328,7 +4328,7 @@ out:
return rc;
}
-static inline int
+static int
qeth_get_elements_no(struct qeth_card *card, void *hdr,
struct sk_buff *skb, int elems)
{
@@ -4349,7 +4349,7 @@ qeth_get_elements_no(struct qeth_card *card, void *hdr,
}
-static inline int
+static int
qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
{
int ipv = 0;
@@ -4536,7 +4536,7 @@ qeth_mdio_read(struct net_device *dev, int phy_id, int regnum)
}
-static inline const char *
+static const char *
qeth_arp_get_error_cause(int *rc)
{
switch (*rc) {
@@ -4597,7 +4597,7 @@ qeth_arp_set_no_entries(struct qeth_card *card, int no_entries)
return rc;
}
-static inline void
+static void
qeth_copy_arp_entries_stripped(struct qeth_arp_query_info *qinfo,
struct qeth_arp_query_data *qdata,
int entry_size, int uentry_size)
@@ -5214,7 +5214,7 @@ qeth_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
spin_unlock_irqrestore(&card->vlanlock, flags);
}
-static inline void
+static void
qeth_free_vlan_buffer(struct qeth_card *card, struct qeth_qdio_out_buffer *buf,
unsigned short vid)
{
@@ -5625,7 +5625,7 @@ qeth_delete_mc_addresses(struct qeth_card *card)
spin_unlock_irqrestore(&card->ip_lock, flags);
}
-static inline void
+static void
qeth_add_mc(struct qeth_card *card, struct in_device *in4_dev)
{
struct qeth_ipaddr *ipm;
@@ -5711,7 +5711,7 @@ qeth_layer2_add_multicast(struct qeth_card *card)
}
#ifdef CONFIG_QETH_IPV6
-static inline void
+static void
qeth_add_mc6(struct qeth_card *card, struct inet6_dev *in6_dev)
{
struct qeth_ipaddr *ipm;
@@ -6022,7 +6022,7 @@ qeth_send_setdelmc(struct qeth_card *card, struct qeth_ipaddr *addr, int ipacmd)
return rc;
}
-static inline void
+static void
qeth_fill_netmask(u8 *netmask, unsigned int len)
{
int i,j;
@@ -6626,7 +6626,7 @@ qeth_send_setadp_mode(struct qeth_card *card, __u32 command, __u32 mode)
return rc;
}
-static inline int
+static int
qeth_setadapter_hstr(struct qeth_card *card)
{
int rc;
@@ -6889,7 +6889,7 @@ qeth_send_simple_setassparms(struct qeth_card *card,
return rc;
}
-static inline int
+static int
qeth_start_ipa_arp_processing(struct qeth_card *card)
{
int rc;
@@ -7529,7 +7529,7 @@ qeth_set_allowed_threads(struct qeth_card *card, unsigned long threads,
wake_up(&card->wait_q);
}
-static inline int
+static int
qeth_threads_running(struct qeth_card *card, unsigned long threads)
{
unsigned long flags;
@@ -8118,7 +8118,7 @@ qeth_del_ipato_entry(struct qeth_card *card, enum qeth_prot_versions proto,
spin_unlock_irqrestore(&card->ip_lock, flags);
}
-static inline void
+static void
qeth_convert_addr_to_bits(u8 *addr, u8 *bits, int len)
{
int i, j;
diff --git a/drivers/s390/net/qeth_sys.c b/drivers/s390/net/qeth_sys.c
index 5836737ac58..d518419cd0c 100644
--- a/drivers/s390/net/qeth_sys.c
+++ b/drivers/s390/net/qeth_sys.c
@@ -328,7 +328,7 @@ qeth_dev_bufcnt_store(struct device *dev, struct device_attribute *attr, const c
static DEVICE_ATTR(buffer_count, 0644, qeth_dev_bufcnt_show,
qeth_dev_bufcnt_store);
-static inline ssize_t
+static ssize_t
qeth_dev_route_show(struct qeth_card *card, struct qeth_routing_info *route,
char *buf)
{
@@ -368,7 +368,7 @@ qeth_dev_route4_show(struct device *dev, struct device_attribute *attr, char *bu
return qeth_dev_route_show(card, &card->options.route4, buf);
}
-static inline ssize_t
+static ssize_t
qeth_dev_route_store(struct qeth_card *card, struct qeth_routing_info *route,
enum qeth_prot_versions prot, const char *buf, size_t count)
{
@@ -998,7 +998,7 @@ struct device_attribute dev_attr_##_id = { \
.store = _store, \
};
-int
+static int
qeth_check_layer2(struct qeth_card *card)
{
if (card->options.layer2)
@@ -1100,7 +1100,7 @@ static QETH_DEVICE_ATTR(ipato_invert4, invert4, 0644,
qeth_dev_ipato_invert4_show,
qeth_dev_ipato_invert4_store);
-static inline ssize_t
+static ssize_t
qeth_dev_ipato_add_show(char *buf, struct qeth_card *card,
enum qeth_prot_versions proto)
{
@@ -1146,7 +1146,7 @@ qeth_dev_ipato_add4_show(struct device *dev, struct device_attribute *attr, char
return qeth_dev_ipato_add_show(buf, card, QETH_PROT_IPV4);
}
-static inline int
+static int
qeth_parse_ipatoe(const char* buf, enum qeth_prot_versions proto,
u8 *addr, int *mask_bits)
{
@@ -1178,7 +1178,7 @@ qeth_parse_ipatoe(const char* buf, enum qeth_prot_versions proto,
return 0;
}
-static inline ssize_t
+static ssize_t
qeth_dev_ipato_add_store(const char *buf, size_t count,
struct qeth_card *card, enum qeth_prot_versions proto)
{
@@ -1223,7 +1223,7 @@ static QETH_DEVICE_ATTR(ipato_add4, add4, 0644,
qeth_dev_ipato_add4_show,
qeth_dev_ipato_add4_store);
-static inline ssize_t
+static ssize_t
qeth_dev_ipato_del_store(const char *buf, size_t count,
struct qeth_card *card, enum qeth_prot_versions proto)
{
@@ -1361,7 +1361,7 @@ static struct attribute_group qeth_device_ipato_group = {
.attrs = (struct attribute **)qeth_ipato_device_attrs,
};
-static inline ssize_t
+static ssize_t
qeth_dev_vipa_add_show(char *buf, struct qeth_card *card,
enum qeth_prot_versions proto)
{
@@ -1407,7 +1407,7 @@ qeth_dev_vipa_add4_show(struct device *dev, struct device_attribute *attr, char
return qeth_dev_vipa_add_show(buf, card, QETH_PROT_IPV4);
}
-static inline int
+static int
qeth_parse_vipae(const char* buf, enum qeth_prot_versions proto,
u8 *addr)
{
@@ -1418,7 +1418,7 @@ qeth_parse_vipae(const char* buf, enum qeth_prot_versions proto,
return 0;
}
-static inline ssize_t
+static ssize_t
qeth_dev_vipa_add_store(const char *buf, size_t count,
struct qeth_card *card, enum qeth_prot_versions proto)
{
@@ -1451,7 +1451,7 @@ static QETH_DEVICE_ATTR(vipa_add4, add4, 0644,
qeth_dev_vipa_add4_show,
qeth_dev_vipa_add4_store);
-static inline ssize_t
+static ssize_t
qeth_dev_vipa_del_store(const char *buf, size_t count,
struct qeth_card *card, enum qeth_prot_versions proto)
{
@@ -1542,7 +1542,7 @@ static struct attribute_group qeth_device_vipa_group = {
.attrs = (struct attribute **)qeth_vipa_device_attrs,
};
-static inline ssize_t
+static ssize_t
qeth_dev_rxip_add_show(char *buf, struct qeth_card *card,
enum qeth_prot_versions proto)
{
@@ -1588,7 +1588,7 @@ qeth_dev_rxip_add4_show(struct device *dev, struct device_attribute *attr, char
return qeth_dev_rxip_add_show(buf, card, QETH_PROT_IPV4);
}
-static inline int
+static int
qeth_parse_rxipe(const char* buf, enum qeth_prot_versions proto,
u8 *addr)
{
@@ -1599,7 +1599,7 @@ qeth_parse_rxipe(const char* buf, enum qeth_prot_versions proto,
return 0;
}
-static inline ssize_t
+static ssize_t
qeth_dev_rxip_add_store(const char *buf, size_t count,
struct qeth_card *card, enum qeth_prot_versions proto)
{
@@ -1632,7 +1632,7 @@ static QETH_DEVICE_ATTR(rxip_add4, add4, 0644,
qeth_dev_rxip_add4_show,
qeth_dev_rxip_add4_store);
-static inline ssize_t
+static ssize_t
qeth_dev_rxip_del_store(const char *buf, size_t count,
struct qeth_card *card, enum qeth_prot_versions proto)
{
diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c
index b8179c27ceb..3ccca5871fd 100644
--- a/drivers/s390/net/smsgiucv.c
+++ b/drivers/s390/net/smsgiucv.c
@@ -1,7 +1,7 @@
/*
* IUCV special message driver
*
- * Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
*
* This program is free software; you can redistribute it and/or modify
@@ -23,10 +23,10 @@
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/device.h>
+#include <net/iucv/iucv.h>
#include <asm/cpcmd.h>
#include <asm/ebcdic.h>
-
-#include "iucv.h"
+#include "smsgiucv.h"
struct smsg_callback {
struct list_head list;
@@ -39,38 +39,46 @@ MODULE_AUTHOR
("(C) 2003 IBM Corporation by Martin Schwidefsky (schwidefsky@de.ibm.com)");
MODULE_DESCRIPTION ("Linux for S/390 IUCV special message driver");
-static iucv_handle_t smsg_handle;
-static unsigned short smsg_pathid;
+static struct iucv_path *smsg_path;
+
static DEFINE_SPINLOCK(smsg_list_lock);
static struct list_head smsg_list = LIST_HEAD_INIT(smsg_list);
-static void
-smsg_connection_complete(iucv_ConnectionComplete *eib, void *pgm_data)
+static int smsg_path_pending(struct iucv_path *, u8 ipvmid[8], u8 ipuser[16]);
+static void smsg_message_pending(struct iucv_path *, struct iucv_message *);
+
+static struct iucv_handler smsg_handler = {
+ .path_pending = smsg_path_pending,
+ .message_pending = smsg_message_pending,
+};
+
+static int smsg_path_pending(struct iucv_path *path, u8 ipvmid[8],
+ u8 ipuser[16])
{
+ if (strncmp(ipvmid, "*MSG ", sizeof(ipvmid)) != 0)
+ return -EINVAL;
+ /* Path pending from *MSG. */
+ return iucv_path_accept(path, &smsg_handler, "SMSGIUCV ", NULL);
}
-
-static void
-smsg_message_pending(iucv_MessagePending *eib, void *pgm_data)
+static void smsg_message_pending(struct iucv_path *path,
+ struct iucv_message *msg)
{
struct smsg_callback *cb;
- unsigned char *msg;
+ unsigned char *buffer;
unsigned char sender[9];
- unsigned short len;
int rc, i;
- len = eib->ln1msg2.ipbfln1f;
- msg = kmalloc(len + 1, GFP_ATOMIC|GFP_DMA);
- if (!msg) {
- iucv_reject(eib->ippathid, eib->ipmsgid, eib->iptrgcls);
+ buffer = kmalloc(msg->length + 1, GFP_ATOMIC | GFP_DMA);
+ if (!buffer) {
+ iucv_message_reject(path, msg);
return;
}
- rc = iucv_receive(eib->ippathid, eib->ipmsgid, eib->iptrgcls,
- msg, len, NULL, NULL, NULL);
+ rc = iucv_message_receive(path, msg, 0, buffer, msg->length, NULL);
if (rc == 0) {
- msg[len] = 0;
- EBCASC(msg, len);
- memcpy(sender, msg, 8);
+ buffer[msg->length] = 0;
+ EBCASC(buffer, msg->length);
+ memcpy(sender, buffer, 8);
sender[8] = 0;
/* Remove trailing whitespace from the sender name. */
for (i = 7; i >= 0; i--) {
@@ -80,27 +88,17 @@ smsg_message_pending(iucv_MessagePending *eib, void *pgm_data)
}
spin_lock(&smsg_list_lock);
list_for_each_entry(cb, &smsg_list, list)
- if (strncmp(msg + 8, cb->prefix, cb->len) == 0) {
- cb->callback(sender, msg + 8);
+ if (strncmp(buffer + 8, cb->prefix, cb->len) == 0) {
+ cb->callback(sender, buffer + 8);
break;
}
spin_unlock(&smsg_list_lock);
}
- kfree(msg);
+ kfree(buffer);
}
-static iucv_interrupt_ops_t smsg_ops = {
- .ConnectionComplete = smsg_connection_complete,
- .MessagePending = smsg_message_pending,
-};
-
-static struct device_driver smsg_driver = {
- .name = "SMSGIUCV",
- .bus = &iucv_bus,
-};
-
-int
-smsg_register_callback(char *prefix, void (*callback)(char *from, char *str))
+int smsg_register_callback(char *prefix,
+ void (*callback)(char *from, char *str))
{
struct smsg_callback *cb;
@@ -110,18 +108,18 @@ smsg_register_callback(char *prefix, void (*callback)(char *from, char *str))
cb->prefix = prefix;
cb->len = strlen(prefix);
cb->callback = callback;
- spin_lock(&smsg_list_lock);
+ spin_lock_bh(&smsg_list_lock);
list_add_tail(&cb->list, &smsg_list);
- spin_unlock(&smsg_list_lock);
+ spin_unlock_bh(&smsg_list_lock);
return 0;
}
-void
-smsg_unregister_callback(char *prefix, void (*callback)(char *from, char *str))
+void smsg_unregister_callback(char *prefix,
+ void (*callback)(char *from, char *str))
{
struct smsg_callback *cb, *tmp;
- spin_lock(&smsg_list_lock);
+ spin_lock_bh(&smsg_list_lock);
cb = NULL;
list_for_each_entry(tmp, &smsg_list, list)
if (tmp->callback == callback &&
@@ -130,55 +128,58 @@ smsg_unregister_callback(char *prefix, void (*callback)(char *from, char *str))
list_del(&cb->list);
break;
}
- spin_unlock(&smsg_list_lock);
+ spin_unlock_bh(&smsg_list_lock);
kfree(cb);
}
-static void __exit
-smsg_exit(void)
+static struct device_driver smsg_driver = {
+ .name = "SMSGIUCV",
+ .bus = &iucv_bus,
+};
+
+static void __exit smsg_exit(void)
{
- if (smsg_handle > 0) {
- cpcmd("SET SMSG OFF", NULL, 0, NULL);
- iucv_sever(smsg_pathid, NULL);
- iucv_unregister_program(smsg_handle);
- driver_unregister(&smsg_driver);
- }
- return;
+ cpcmd("SET SMSG IUCV", NULL, 0, NULL);
+ iucv_unregister(&smsg_handler, 1);
+ driver_unregister(&smsg_driver);
}
-static int __init
-smsg_init(void)
+static int __init smsg_init(void)
{
- static unsigned char pgmmask[24] = {
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
- };
int rc;
rc = driver_register(&smsg_driver);
- if (rc != 0) {
- printk(KERN_ERR "SMSGIUCV: failed to register driver.\n");
- return rc;
- }
- smsg_handle = iucv_register_program("SMSGIUCV ", "*MSG ",
- pgmmask, &smsg_ops, NULL);
- if (!smsg_handle) {
+ if (rc != 0)
+ goto out;
+ rc = iucv_register(&smsg_handler, 1);
+ if (rc) {
printk(KERN_ERR "SMSGIUCV: failed to register to iucv");
- driver_unregister(&smsg_driver);
- return -EIO; /* better errno ? */
+ rc = -EIO; /* better errno ? */
+ goto out_driver;
+ }
+ smsg_path = iucv_path_alloc(255, 0, GFP_KERNEL);
+ if (!smsg_path) {
+ rc = -ENOMEM;
+ goto out_register;
}
- rc = iucv_connect (&smsg_pathid, 255, NULL, "*MSG ", NULL, 0,
- NULL, NULL, smsg_handle, NULL);
+ rc = iucv_path_connect(smsg_path, &smsg_handler, "*MSG ",
+ NULL, NULL, NULL);
if (rc) {
printk(KERN_ERR "SMSGIUCV: failed to connect to *MSG");
- iucv_unregister_program(smsg_handle);
- driver_unregister(&smsg_driver);
- smsg_handle = NULL;
- return -EIO;
+ rc = -EIO; /* better errno ? */
+ goto out_free;
}
cpcmd("SET SMSG IUCV", NULL, 0, NULL);
return 0;
+
+out_free:
+ iucv_path_free(smsg_path);
+out_register:
+ iucv_unregister(&smsg_handler, 1);
+out_driver:
+ driver_unregister(&smsg_driver);
+out:
+ return rc;
}
module_init(smsg_init);
diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c
index e088b5e2871..806bb1a921e 100644
--- a/drivers/s390/s390mach.c
+++ b/drivers/s390/s390mach.c
@@ -13,22 +13,18 @@
#include <linux/errno.h>
#include <linux/workqueue.h>
#include <linux/time.h>
+#include <linux/device.h>
#include <linux/kthread.h>
-
+#include <asm/etr.h>
#include <asm/lowcore.h>
-
+#include <asm/cio.h>
+#include "cio/cio.h"
+#include "cio/chsc.h"
+#include "cio/css.h"
#include "s390mach.h"
static struct semaphore m_sem;
-extern int css_process_crw(int, int);
-extern int chsc_process_crw(void);
-extern int chp_process_crw(int, int);
-extern void css_reiterate_subchannels(void);
-
-extern struct workqueue_struct *slow_path_wq;
-extern struct work_struct slow_path_work;
-
static NORET_TYPE void
s390_handle_damage(char *msg)
{
@@ -470,6 +466,19 @@ s390_do_machine_check(struct pt_regs *regs)
s390_handle_damage("unable to revalidate registers.");
}
+ if (mci->cd) {
+ /* Timing facility damage */
+ s390_handle_damage("TOD clock damaged");
+ }
+
+ if (mci->ed && mci->ec) {
+ /* External damage */
+ if (S390_lowcore.external_damage_code & (1U << ED_ETR_SYNC))
+ etr_sync_check();
+ if (S390_lowcore.external_damage_code & (1U << ED_ETR_SWITCH))
+ etr_switch_to_local();
+ }
+
if (mci->se)
/* Storage error uncorrected */
s390_handle_damage("received storage error uncorrected "
@@ -508,7 +517,7 @@ static int
machine_check_init(void)
{
init_MUTEX_LOCKED(&m_sem);
- ctl_clear_bit(14, 25); /* disable external damage MCH */
+ ctl_set_bit(14, 25); /* enable external damage MCH */
ctl_set_bit(14, 27); /* enable system recovery MCH */
#ifdef CONFIG_MACHCHK_WARNING
ctl_set_bit(14, 24); /* enable warning MCH */
@@ -529,7 +538,11 @@ arch_initcall(machine_check_init);
static int __init
machine_check_crw_init (void)
{
- kthread_run(s390_collect_crw_info, &m_sem, "kmcheck");
+ struct task_struct *task;
+
+ task = kthread_run(s390_collect_crw_info, &m_sem, "kmcheck");
+ if (IS_ERR(task))
+ return PTR_ERR(task);
ctl_set_bit(14, 28); /* enable channel report MCH */
return 0;
}
diff --git a/drivers/s390/s390mach.h b/drivers/s390/s390mach.h
index 7abb42a09ae..d3ca4281a49 100644
--- a/drivers/s390/s390mach.h
+++ b/drivers/s390/s390mach.h
@@ -102,4 +102,7 @@ static inline int stcrw(struct crw *pcrw )
return ccode;
}
+#define ED_ETR_SYNC 12 /* External damage ETR sync check */
+#define ED_ETR_SWITCH 13 /* External damage ETR switch to local */
+
#endif /* __s390mach */
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index 85093b71f9f..39a88526679 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -47,13 +47,12 @@ static int __init zfcp_module_init(void);
static void zfcp_ns_gid_pn_handler(unsigned long);
/* miscellaneous */
-static inline int zfcp_sg_list_alloc(struct zfcp_sg_list *, size_t);
-static inline void zfcp_sg_list_free(struct zfcp_sg_list *);
-static inline int zfcp_sg_list_copy_from_user(struct zfcp_sg_list *,
- void __user *, size_t);
-static inline int zfcp_sg_list_copy_to_user(void __user *,
- struct zfcp_sg_list *, size_t);
-
+static int zfcp_sg_list_alloc(struct zfcp_sg_list *, size_t);
+static void zfcp_sg_list_free(struct zfcp_sg_list *);
+static int zfcp_sg_list_copy_from_user(struct zfcp_sg_list *,
+ void __user *, size_t);
+static int zfcp_sg_list_copy_to_user(void __user *,
+ struct zfcp_sg_list *, size_t);
static long zfcp_cfdc_dev_ioctl(struct file *, unsigned int, unsigned long);
#define ZFCP_CFDC_IOC_MAGIC 0xDD
@@ -605,7 +604,7 @@ zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command,
* elements of the scatter-gather list. The maximum size of a single element
* in the scatter-gather list is PAGE_SIZE.
*/
-static inline int
+static int
zfcp_sg_list_alloc(struct zfcp_sg_list *sg_list, size_t size)
{
struct scatterlist *sg;
@@ -652,7 +651,7 @@ zfcp_sg_list_alloc(struct zfcp_sg_list *sg_list, size_t size)
* Memory for each element in the scatter-gather list is freed.
* Finally sg_list->sg is freed itself and sg_list->count is reset.
*/
-static inline void
+static void
zfcp_sg_list_free(struct zfcp_sg_list *sg_list)
{
struct scatterlist *sg;
@@ -697,7 +696,7 @@ zfcp_sg_size(struct scatterlist *sg, unsigned int sg_count)
* @size: number of bytes to be copied
* Return: 0 on success, -EFAULT if copy_from_user fails.
*/
-static inline int
+static int
zfcp_sg_list_copy_from_user(struct zfcp_sg_list *sg_list,
void __user *user_buffer,
size_t size)
@@ -735,7 +734,7 @@ zfcp_sg_list_copy_from_user(struct zfcp_sg_list *sg_list,
* @size: number of bytes to be copied
* Return: 0 on success, -EFAULT if copy_to_user fails
*/
-static inline int
+static int
zfcp_sg_list_copy_to_user(void __user *user_buffer,
struct zfcp_sg_list *sg_list,
size_t size)
@@ -1799,7 +1798,7 @@ static const struct zfcp_rc_entry zfcp_p_rjt_rc[] = {
* @code: reason code
* @rc_table: table of reason codes and descriptions
*/
-static inline const char *
+static const char *
zfcp_rc_description(u8 code, const struct zfcp_rc_entry *rc_table)
{
const char *descr = "unknown reason code";
@@ -1847,7 +1846,7 @@ zfcp_check_ct_response(struct ct_hdr *rjt)
* @rjt_par: reject parameter acc. to FC-PH/FC-FS
* @rc_table: table of reason codes and descriptions
*/
-static inline void
+static void
zfcp_print_els_rjt(struct zfcp_ls_rjt_par *rjt_par,
const struct zfcp_rc_entry *rc_table)
{
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c
index 0aa3b1ac76a..d8191d115c1 100644
--- a/drivers/s390/scsi/zfcp_dbf.c
+++ b/drivers/s390/scsi/zfcp_dbf.c
@@ -31,7 +31,7 @@ MODULE_PARM_DESC(dbfsize,
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_OTHER
-static inline int
+static int
zfcp_dbf_stck(char *out_buf, const char *label, unsigned long long stck)
{
unsigned long long sec;
@@ -106,7 +106,7 @@ zfcp_dbf_view_dump(char *out_buf, const char *label,
return len;
}
-static inline int
+static int
zfcp_dbf_view_header(debug_info_t * id, struct debug_view *view, int area,
debug_entry_t * entry, char *out_buf)
{
@@ -130,7 +130,7 @@ zfcp_dbf_view_header(debug_info_t * id, struct debug_view *view, int area,
return len;
}
-inline void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req)
+void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req)
{
struct zfcp_adapter *adapter = fsf_req->adapter;
struct fsf_qtcb *qtcb = fsf_req->qtcb;
@@ -241,7 +241,7 @@ inline void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req)
spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags);
}
-inline void
+void
zfcp_hba_dbf_event_fsf_unsol(const char *tag, struct zfcp_adapter *adapter,
struct fsf_status_read_buffer *status_buffer)
{
@@ -295,7 +295,7 @@ zfcp_hba_dbf_event_fsf_unsol(const char *tag, struct zfcp_adapter *adapter,
spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags);
}
-inline void
+void
zfcp_hba_dbf_event_qdio(struct zfcp_adapter *adapter, unsigned int status,
unsigned int qdio_error, unsigned int siga_error,
int sbal_index, int sbal_count)
@@ -316,7 +316,7 @@ zfcp_hba_dbf_event_qdio(struct zfcp_adapter *adapter, unsigned int status,
spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags);
}
-static inline int
+static int
zfcp_hba_dbf_view_response(char *out_buf,
struct zfcp_hba_dbf_record_response *rec)
{
@@ -403,7 +403,7 @@ zfcp_hba_dbf_view_response(char *out_buf,
return len;
}
-static inline int
+static int
zfcp_hba_dbf_view_status(char *out_buf, struct zfcp_hba_dbf_record_status *rec)
{
int len = 0;
@@ -424,7 +424,7 @@ zfcp_hba_dbf_view_status(char *out_buf, struct zfcp_hba_dbf_record_status *rec)
return len;
}
-static inline int
+static int
zfcp_hba_dbf_view_qdio(char *out_buf, struct zfcp_hba_dbf_record_qdio *rec)
{
int len = 0;
@@ -469,7 +469,7 @@ zfcp_hba_dbf_view_format(debug_info_t * id, struct debug_view *view,
return len;
}
-struct debug_view zfcp_hba_dbf_view = {
+static struct debug_view zfcp_hba_dbf_view = {
"structured",
NULL,
&zfcp_dbf_view_header,
@@ -478,7 +478,7 @@ struct debug_view zfcp_hba_dbf_view = {
NULL
};
-inline void
+void
_zfcp_san_dbf_event_common_ct(const char *tag, struct zfcp_fsf_req *fsf_req,
u32 s_id, u32 d_id, void *buffer, int buflen)
{
@@ -519,7 +519,7 @@ _zfcp_san_dbf_event_common_ct(const char *tag, struct zfcp_fsf_req *fsf_req,
spin_unlock_irqrestore(&adapter->san_dbf_lock, flags);
}
-inline void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req)
+void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req)
{
struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data;
struct zfcp_port *port = ct->port;
@@ -531,7 +531,7 @@ inline void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req)
ct->req->length);
}
-inline void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req)
+void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req)
{
struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data;
struct zfcp_port *port = ct->port;
@@ -543,7 +543,7 @@ inline void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req)
ct->resp->length);
}
-static inline void
+static void
_zfcp_san_dbf_event_common_els(const char *tag, int level,
struct zfcp_fsf_req *fsf_req, u32 s_id,
u32 d_id, u8 ls_code, void *buffer, int buflen)
@@ -585,7 +585,7 @@ _zfcp_san_dbf_event_common_els(const char *tag, int level,
spin_unlock_irqrestore(&adapter->san_dbf_lock, flags);
}
-inline void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *fsf_req)
+void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *fsf_req)
{
struct zfcp_send_els *els = (struct zfcp_send_els *)fsf_req->data;
@@ -597,7 +597,7 @@ inline void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *fsf_req)
els->req->length);
}
-inline void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *fsf_req)
+void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *fsf_req)
{
struct zfcp_send_els *els = (struct zfcp_send_els *)fsf_req->data;
@@ -608,7 +608,7 @@ inline void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *fsf_req)
els->resp->length);
}
-inline void zfcp_san_dbf_event_incoming_els(struct zfcp_fsf_req *fsf_req)
+void zfcp_san_dbf_event_incoming_els(struct zfcp_fsf_req *fsf_req)
{
struct zfcp_adapter *adapter = fsf_req->adapter;
struct fsf_status_read_buffer *status_buffer =
@@ -693,7 +693,7 @@ zfcp_san_dbf_view_format(debug_info_t * id, struct debug_view *view,
return len;
}
-struct debug_view zfcp_san_dbf_view = {
+static struct debug_view zfcp_san_dbf_view = {
"structured",
NULL,
&zfcp_dbf_view_header,
@@ -702,7 +702,7 @@ struct debug_view zfcp_san_dbf_view = {
NULL
};
-static inline void
+static void
_zfcp_scsi_dbf_event_common(const char *tag, const char *tag2, int level,
struct zfcp_adapter *adapter,
struct scsi_cmnd *scsi_cmnd,
@@ -786,7 +786,7 @@ _zfcp_scsi_dbf_event_common(const char *tag, const char *tag2, int level,
spin_unlock_irqrestore(&adapter->scsi_dbf_lock, flags);
}
-inline void
+void
zfcp_scsi_dbf_event_result(const char *tag, int level,
struct zfcp_adapter *adapter,
struct scsi_cmnd *scsi_cmnd,
@@ -796,7 +796,7 @@ zfcp_scsi_dbf_event_result(const char *tag, int level,
adapter, scsi_cmnd, fsf_req, 0);
}
-inline void
+void
zfcp_scsi_dbf_event_abort(const char *tag, struct zfcp_adapter *adapter,
struct scsi_cmnd *scsi_cmnd,
struct zfcp_fsf_req *new_fsf_req,
@@ -806,7 +806,7 @@ zfcp_scsi_dbf_event_abort(const char *tag, struct zfcp_adapter *adapter,
adapter, scsi_cmnd, new_fsf_req, old_req_id);
}
-inline void
+void
zfcp_scsi_dbf_event_devreset(const char *tag, u8 flag, struct zfcp_unit *unit,
struct scsi_cmnd *scsi_cmnd)
{
@@ -884,7 +884,7 @@ zfcp_scsi_dbf_view_format(debug_info_t * id, struct debug_view *view,
return len;
}
-struct debug_view zfcp_scsi_dbf_view = {
+static struct debug_view zfcp_scsi_dbf_view = {
"structured",
NULL,
&zfcp_dbf_view_header,
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index c88babce9bc..88642dec080 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -200,7 +200,7 @@ void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req, unsigned long timeout)
* returns: 0 - initiated action successfully
* <0 - failed to initiate action
*/
-int
+static int
zfcp_erp_adapter_reopen_internal(struct zfcp_adapter *adapter, int clear_mask)
{
int retval;
@@ -295,7 +295,7 @@ zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear_mask)
* zfcp_erp_adisc - send ADISC ELS command
* @port: port structure
*/
-int
+static int
zfcp_erp_adisc(struct zfcp_port *port)
{
struct zfcp_adapter *adapter = port->adapter;
@@ -380,7 +380,7 @@ zfcp_erp_adisc(struct zfcp_port *port)
*
* If ADISC failed (LS_RJT or timed out) forced reopen of the port is triggered.
*/
-void
+static void
zfcp_erp_adisc_handler(unsigned long data)
{
struct zfcp_send_els *send_els;
@@ -3141,7 +3141,6 @@ zfcp_erp_action_cleanup(int action, struct zfcp_adapter *adapter,
break;
case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
if (result != ZFCP_ERP_SUCCEEDED) {
- struct zfcp_port *port;
list_for_each_entry(port, &adapter->port_list_head, list)
if (port->rport &&
!atomic_test_mask(ZFCP_STATUS_PORT_WKA,
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
index b8794d77285..cda0cc095ad 100644
--- a/drivers/s390/scsi/zfcp_ext.h
+++ b/drivers/s390/scsi/zfcp_ext.h
@@ -119,8 +119,8 @@ extern int zfcp_adapter_scsi_register(struct zfcp_adapter *);
extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *);
extern void zfcp_set_fcp_dl(struct fcp_cmnd_iu *, fcp_dl_t);
extern char *zfcp_get_fcp_rsp_info_ptr(struct fcp_rsp_iu *);
-extern void set_host_byte(u32 *, char);
-extern void set_driver_byte(u32 *, char);
+extern void set_host_byte(int *, char);
+extern void set_driver_byte(int *, char);
extern char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *);
extern fcp_dl_t zfcp_get_fcp_dl(struct fcp_cmnd_iu *);
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 067f1519eb0..4b3ae3f22e7 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -4563,7 +4563,7 @@ zfcp_fsf_req_sbal_check(unsigned long *flags,
/*
* set qtcb pointer in fsf_req and initialize QTCB
*/
-static inline void
+static void
zfcp_fsf_req_qtcb_init(struct zfcp_fsf_req *fsf_req)
{
if (likely(fsf_req->qtcb != NULL)) {
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c
index dbd9f48e863..1e12a78e8ed 100644
--- a/drivers/s390/scsi/zfcp_qdio.c
+++ b/drivers/s390/scsi/zfcp_qdio.c
@@ -21,22 +21,22 @@
#include "zfcp_ext.h"
-static inline void zfcp_qdio_sbal_limit(struct zfcp_fsf_req *, int);
+static void zfcp_qdio_sbal_limit(struct zfcp_fsf_req *, int);
static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_get
(struct zfcp_qdio_queue *, int, int);
static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_resp
(struct zfcp_fsf_req *, int, int);
-static inline volatile struct qdio_buffer_element *zfcp_qdio_sbal_chain
+static volatile struct qdio_buffer_element *zfcp_qdio_sbal_chain
(struct zfcp_fsf_req *, unsigned long);
-static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_next
+static volatile struct qdio_buffer_element *zfcp_qdio_sbale_next
(struct zfcp_fsf_req *, unsigned long);
-static inline int zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *, int, int);
+static int zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *, int, int);
static inline int zfcp_qdio_sbals_wipe(struct zfcp_fsf_req *);
-static inline void zfcp_qdio_sbale_fill
+static void zfcp_qdio_sbale_fill
(struct zfcp_fsf_req *, unsigned long, void *, int);
-static inline int zfcp_qdio_sbals_from_segment
+static int zfcp_qdio_sbals_from_segment
(struct zfcp_fsf_req *, unsigned long, void *, unsigned long);
-static inline int zfcp_qdio_sbals_from_buffer
+static int zfcp_qdio_sbals_from_buffer
(struct zfcp_fsf_req *, unsigned long, void *, unsigned long, int);
static qdio_handler_t zfcp_qdio_request_handler;
@@ -201,7 +201,7 @@ zfcp_qdio_allocate(struct zfcp_adapter *adapter)
* returns: error flag
*
*/
-static inline int
+static int
zfcp_qdio_handler_error_check(struct zfcp_adapter *adapter, unsigned int status,
unsigned int qdio_error, unsigned int siga_error,
int first_element, int elements_processed)
@@ -462,7 +462,7 @@ zfcp_qdio_sbale_get(struct zfcp_qdio_queue *queue, int sbal, int sbale)
* zfcp_qdio_sbale_req - return pointer to SBALE of request_queue for
* a struct zfcp_fsf_req
*/
-inline volatile struct qdio_buffer_element *
+volatile struct qdio_buffer_element *
zfcp_qdio_sbale_req(struct zfcp_fsf_req *fsf_req, int sbal, int sbale)
{
return zfcp_qdio_sbale_get(&fsf_req->adapter->request_queue,
@@ -484,7 +484,7 @@ zfcp_qdio_sbale_resp(struct zfcp_fsf_req *fsf_req, int sbal, int sbale)
* zfcp_qdio_sbale_curr - return current SBALE on request_queue for
* a struct zfcp_fsf_req
*/
-inline volatile struct qdio_buffer_element *
+volatile struct qdio_buffer_element *
zfcp_qdio_sbale_curr(struct zfcp_fsf_req *fsf_req)
{
return zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr,
@@ -499,7 +499,7 @@ zfcp_qdio_sbale_curr(struct zfcp_fsf_req *fsf_req)
*
* Note: We can assume at least one free SBAL in the request_queue when called.
*/
-static inline void
+static void
zfcp_qdio_sbal_limit(struct zfcp_fsf_req *fsf_req, int max_sbals)
{
int count = atomic_read(&fsf_req->adapter->request_queue.free_count);
@@ -517,7 +517,7 @@ zfcp_qdio_sbal_limit(struct zfcp_fsf_req *fsf_req, int max_sbals)
*
* This function changes sbal_curr, sbale_curr, sbal_number of fsf_req.
*/
-static inline volatile struct qdio_buffer_element *
+static volatile struct qdio_buffer_element *
zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype)
{
volatile struct qdio_buffer_element *sbale;
@@ -554,7 +554,7 @@ zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype)
/**
* zfcp_qdio_sbale_next - switch to next SBALE, chain SBALs if needed
*/
-static inline volatile struct qdio_buffer_element *
+static volatile struct qdio_buffer_element *
zfcp_qdio_sbale_next(struct zfcp_fsf_req *fsf_req, unsigned long sbtype)
{
if (fsf_req->sbale_curr == ZFCP_LAST_SBALE_PER_SBAL)
@@ -569,7 +569,7 @@ zfcp_qdio_sbale_next(struct zfcp_fsf_req *fsf_req, unsigned long sbtype)
* zfcp_qdio_sbals_zero - initialize SBALs between first and last in queue
* with zero from
*/
-static inline int
+static int
zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *queue, int first, int last)
{
struct qdio_buffer **buf = queue->buffer;
@@ -603,7 +603,7 @@ zfcp_qdio_sbals_wipe(struct zfcp_fsf_req *fsf_req)
* zfcp_qdio_sbale_fill - set address and lenght in current SBALE
* on request_queue
*/
-static inline void
+static void
zfcp_qdio_sbale_fill(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
void *addr, int length)
{
@@ -624,7 +624,7 @@ zfcp_qdio_sbale_fill(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
* Alignment and length of the segment determine how many SBALEs are needed
* for the memory segment.
*/
-static inline int
+static int
zfcp_qdio_sbals_from_segment(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
void *start_addr, unsigned long total_length)
{
@@ -659,7 +659,7 @@ zfcp_qdio_sbals_from_segment(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
* @sg_count: number of elements in scatter-gather list
* @max_sbals: upper bound for number of SBALs to be used
*/
-inline int
+int
zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
struct scatterlist *sg, int sg_count, int max_sbals)
{
@@ -707,7 +707,7 @@ out:
* @length: length of buffer
* @max_sbals: upper bound for number of SBALs to be used
*/
-static inline int
+static int
zfcp_qdio_sbals_from_buffer(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
void *buffer, unsigned long length, int max_sbals)
{
@@ -728,7 +728,7 @@ zfcp_qdio_sbals_from_buffer(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
* @scsi_cmnd: either scatter-gather list or buffer contained herein is used
* to fill SBALs
*/
-inline int
+int
zfcp_qdio_sbals_from_scsicmnd(struct zfcp_fsf_req *fsf_req,
unsigned long sbtype, struct scsi_cmnd *scsi_cmnd)
{
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index 452d96f92a1..99db02062c3 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -90,7 +90,7 @@ zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *fcp_rsp_iu)
return fcp_sns_info_ptr;
}
-fcp_dl_t *
+static fcp_dl_t *
zfcp_get_fcp_dl_ptr(struct fcp_cmnd_iu * fcp_cmd)
{
int additional_length = fcp_cmd->add_fcp_cdb_length << 2;
@@ -124,19 +124,19 @@ zfcp_set_fcp_dl(struct fcp_cmnd_iu *fcp_cmd, fcp_dl_t fcp_dl)
* regarding the specified byte
*/
static inline void
-set_byte(u32 * result, char status, char pos)
+set_byte(int *result, char status, char pos)
{
*result |= status << (pos * 8);
}
void
-set_host_byte(u32 * result, char status)
+set_host_byte(int *result, char status)
{
set_byte(result, status, 2);
}
void
-set_driver_byte(u32 * result, char status)
+set_driver_byte(int *result, char status)
{
set_byte(result, status, 3);
}
@@ -280,7 +280,7 @@ out:
return retval;
}
-void
+static void
zfcp_scsi_command_sync_handler(struct scsi_cmnd *scpnt)
{
struct completion *wait = (struct completion *) scpnt->SCp.ptr;
@@ -324,7 +324,7 @@ zfcp_scsi_command_sync(struct zfcp_unit *unit, struct scsi_cmnd *scpnt,
* returns: 0 - success, SCSI command enqueued
* !0 - failure
*/
-int
+static int
zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
void (*done) (struct scsi_cmnd *))
{
@@ -380,7 +380,7 @@ zfcp_unit_lookup(struct zfcp_adapter *adapter, int channel, unsigned int id,
* will handle late commands. (Usually, the normal completion of late
* commands is ignored with respect to the running abort operation.)
*/
-int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
+static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
{
struct Scsi_Host *scsi_host;
struct zfcp_adapter *adapter;
@@ -445,7 +445,7 @@ int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
return retval;
}
-int
+static int
zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt)
{
int retval;
@@ -541,7 +541,7 @@ zfcp_task_management_function(struct zfcp_unit *unit, u8 tm_flags,
/**
* zfcp_scsi_eh_host_reset_handler - handler for host and bus reset
*/
-int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
+static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
{
struct zfcp_unit *unit;
struct zfcp_adapter *adapter;
diff --git a/drivers/s390/sysinfo.c b/drivers/s390/sysinfo.c
index 1e788e815ce..090743d2f91 100644
--- a/drivers/s390/sysinfo.c
+++ b/drivers/s390/sysinfo.c
@@ -9,8 +9,14 @@
#include <linux/mm.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
+#include <linux/delay.h>
#include <asm/ebcdic.h>
+/* Sigh, math-emu. Don't ask. */
+#include <asm/sfp-util.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/single.h>
+
struct sysinfo_1_1_1 {
char reserved_0[32];
char manufacturer[16];
@@ -198,7 +204,7 @@ static int stsi_1_2_2(struct sysinfo_1_2_2 *info, char *page, int len)
* if the higher order 8 bits are not zero. Printing
* a floating point number in the kernel is a no-no,
* always print the number as 32 bit unsigned integer.
- * The user-space needs to know about the stange
+ * The user-space needs to know about the strange
* encoding of the alternate cpu capability.
*/
len += sprintf(page + len, "Capability: %u %u\n",
@@ -351,3 +357,58 @@ static __init int create_proc_sysinfo(void)
__initcall(create_proc_sysinfo);
+/*
+ * CPU capability might have changed. Therefore recalculate loops_per_jiffy.
+ */
+void s390_adjust_jiffies(void)
+{
+ struct sysinfo_1_2_2 *info;
+ const unsigned int fmil = 0x4b189680; /* 1e7 as 32-bit float. */
+ FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
+ FP_DECL_EX;
+ unsigned int capability;
+
+ info = (void *) get_zeroed_page(GFP_KERNEL);
+ if (!info)
+ return;
+
+ if (stsi(info, 1, 2, 2) != -ENOSYS) {
+ /*
+ * Major sigh. The cpu capability encoding is "special".
+ * If the first 9 bits of info->capability are 0 then it
+ * is a 32 bit unsigned integer in the range 0 .. 2^23.
+ * If the first 9 bits are != 0 then it is a 32 bit float.
+ * In addition a lower value indicates a proportionally
+ * higher cpu capacity. Bogomips are the other way round.
+ * To get to a halfway suitable number we divide 1e7
+ * by the cpu capability number. Yes, that means a floating
+ * point division .. math-emu here we come :-)
+ */
+ FP_UNPACK_SP(SA, &fmil);
+ if ((info->capability >> 23) == 0)
+ FP_FROM_INT_S(SB, info->capability, 32, int);
+ else
+ FP_UNPACK_SP(SB, &info->capability);
+ FP_DIV_S(SR, SA, SB);
+ FP_TO_INT_S(capability, SR, 32, 0);
+ } else
+ /*
+ * Really old machine without stsi block for basic
+ * cpu information. Report 42.0 bogomips.
+ */
+ capability = 42;
+ loops_per_jiffy = capability * (500000/HZ);
+ free_page((unsigned long) info);
+}
+
+/*
+ * calibrate the delay loop
+ */
+void __init calibrate_delay(void)
+{
+ s390_adjust_jiffies();
+ /* Print the good old Bogomips line .. */
+ printk(KERN_DEBUG "Calibrating delay loop (skipped)... "
+ "%lu.%02lu BogoMIPS preset\n", loops_per_jiffy/(500000/HZ),
+ (loops_per_jiffy/(5000/HZ)) % 100);
+}
diff --git a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c
index 3c912ee29da..8b5334c56f0 100644
--- a/drivers/scsi/NCR53C9x.c
+++ b/drivers/scsi/NCR53C9x.c
@@ -528,12 +528,16 @@ void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs)
/* Allocate structure and insert basic data such as SCSI chip frequency
* data and a pointer to the device
*/
-struct NCR_ESP* esp_allocate(struct scsi_host_template *tpnt, void *esp_dev)
+struct NCR_ESP* esp_allocate(struct scsi_host_template *tpnt, void *esp_dev,
+ int hotplug)
{
struct NCR_ESP *esp, *elink;
struct Scsi_Host *esp_host;
- esp_host = scsi_register(tpnt, sizeof(struct NCR_ESP));
+ if (hotplug)
+ esp_host = scsi_host_alloc(tpnt, sizeof(struct NCR_ESP));
+ else
+ esp_host = scsi_register(tpnt, sizeof(struct NCR_ESP));
if(!esp_host)
panic("Cannot register ESP SCSI host");
esp = (struct NCR_ESP *) esp_host->hostdata;
diff --git a/drivers/scsi/NCR53C9x.h b/drivers/scsi/NCR53C9x.h
index 521e3f842cf..d85cb73a9f6 100644
--- a/drivers/scsi/NCR53C9x.h
+++ b/drivers/scsi/NCR53C9x.h
@@ -652,7 +652,7 @@ extern int nesps, esps_in_use, esps_running;
/* External functions */
extern void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs);
-extern struct NCR_ESP *esp_allocate(struct scsi_host_template *, void *);
+extern struct NCR_ESP *esp_allocate(struct scsi_host_template *, void *, int);
extern void esp_deallocate(struct NCR_ESP *);
extern void esp_release(void);
extern void esp_initialize(struct NCR_ESP *);
diff --git a/drivers/scsi/blz1230.c b/drivers/scsi/blz1230.c
index 329a8f297b3..23f7c24ab80 100644
--- a/drivers/scsi/blz1230.c
+++ b/drivers/scsi/blz1230.c
@@ -121,7 +121,8 @@ int __init blz1230_esp_detect(struct scsi_host_template *tpnt)
*/
address = ZTWO_VADDR(board);
eregs = (struct ESP_regs *)(address + REAL_BLZ1230_ESP_ADDR);
- esp = esp_allocate(tpnt, (void *)board+REAL_BLZ1230_ESP_ADDR);
+ esp = esp_allocate(tpnt, (void *)board + REAL_BLZ1230_ESP_ADDR,
+ 0);
esp_write(eregs->esp_cfg1, (ESP_CONFIG1_PENABLE | 7));
udelay(5);
diff --git a/drivers/scsi/blz2060.c b/drivers/scsi/blz2060.c
index b6c137b9735..b6203ec0096 100644
--- a/drivers/scsi/blz2060.c
+++ b/drivers/scsi/blz2060.c
@@ -100,7 +100,7 @@ int __init blz2060_esp_detect(struct scsi_host_template *tpnt)
unsigned long board = z->resource.start;
if (request_mem_region(board+BLZ2060_ESP_ADDR,
sizeof(struct ESP_regs), "NCR53C9x")) {
- esp = esp_allocate(tpnt, (void *)board+BLZ2060_ESP_ADDR);
+ esp = esp_allocate(tpnt, (void *)board + BLZ2060_ESP_ADDR, 0);
/* Do command transfer with programmed I/O */
esp->do_pio_cmds = 1;
diff --git a/drivers/scsi/cyberstorm.c b/drivers/scsi/cyberstorm.c
index 7c7cfb54e89..c6b98a42e89 100644
--- a/drivers/scsi/cyberstorm.c
+++ b/drivers/scsi/cyberstorm.c
@@ -126,7 +126,7 @@ int __init cyber_esp_detect(struct scsi_host_template *tpnt)
sizeof(struct ESP_regs));
return 0;
}
- esp = esp_allocate(tpnt, (void *)board+CYBER_ESP_ADDR);
+ esp = esp_allocate(tpnt, (void *)board + CYBER_ESP_ADDR, 0);
/* Do command transfer with programmed I/O */
esp->do_pio_cmds = 1;
diff --git a/drivers/scsi/cyberstormII.c b/drivers/scsi/cyberstormII.c
index d88cb9cf091..e336e853e66 100644
--- a/drivers/scsi/cyberstormII.c
+++ b/drivers/scsi/cyberstormII.c
@@ -98,7 +98,7 @@ int __init cyberII_esp_detect(struct scsi_host_template *tpnt)
address = (unsigned long)ZTWO_VADDR(board);
eregs = (struct ESP_regs *)(address + CYBERII_ESP_ADDR);
- esp = esp_allocate(tpnt, (void *)board+CYBERII_ESP_ADDR);
+ esp = esp_allocate(tpnt, (void *)board + CYBERII_ESP_ADDR, 0);
esp_write(eregs->esp_cfg1, (ESP_CONFIG1_PENABLE | 7));
udelay(5);
diff --git a/drivers/scsi/dec_esp.c b/drivers/scsi/dec_esp.c
index c29ccbc4469..d42ad663ffe 100644
--- a/drivers/scsi/dec_esp.c
+++ b/drivers/scsi/dec_esp.c
@@ -18,7 +18,7 @@
* 20001005 - Initialization fixes for 2.4.0-test9
* Florian Lohoff <flo@rfc822.org>
*
- * Copyright (C) 2002, 2003, 2005 Maciej W. Rozycki
+ * Copyright (C) 2002, 2003, 2005, 2006 Maciej W. Rozycki
*/
#include <linux/kernel.h>
@@ -30,6 +30,7 @@
#include <linux/proc_fs.h>
#include <linux/spinlock.h>
#include <linux/stat.h>
+#include <linux/tc.h>
#include <asm/dma.h>
#include <asm/irq.h>
@@ -42,7 +43,6 @@
#include <asm/dec/ioasic_ints.h>
#include <asm/dec/machtype.h>
#include <asm/dec/system.h>
-#include <asm/dec/tc.h>
#define DEC_SCSI_SREG 0
#define DEC_SCSI_DMAREG 0x40000
@@ -98,51 +98,33 @@ static irqreturn_t scsi_dma_merr_int(int, void *);
static irqreturn_t scsi_dma_err_int(int, void *);
static irqreturn_t scsi_dma_int(int, void *);
-static int dec_esp_detect(struct scsi_host_template * tpnt);
-
-static int dec_esp_release(struct Scsi_Host *shost)
-{
- if (shost->irq)
- free_irq(shost->irq, NULL);
- if (shost->io_port && shost->n_io_port)
- release_region(shost->io_port, shost->n_io_port);
- scsi_unregister(shost);
- return 0;
-}
-
-static struct scsi_host_template driver_template = {
- .proc_name = "dec_esp",
- .proc_info = esp_proc_info,
+static struct scsi_host_template dec_esp_template = {
+ .module = THIS_MODULE,
.name = "NCR53C94",
- .detect = dec_esp_detect,
- .slave_alloc = esp_slave_alloc,
- .slave_destroy = esp_slave_destroy,
- .release = dec_esp_release,
.info = esp_info,
.queuecommand = esp_queue,
.eh_abort_handler = esp_abort,
.eh_bus_reset_handler = esp_reset,
+ .slave_alloc = esp_slave_alloc,
+ .slave_destroy = esp_slave_destroy,
+ .proc_info = esp_proc_info,
+ .proc_name = "dec_esp",
.can_queue = 7,
- .this_id = 7,
.sg_tablesize = SG_ALL,
.cmd_per_lun = 1,
.use_clustering = DISABLE_CLUSTERING,
};
-
-#include "scsi_module.c"
+static struct NCR_ESP *dec_esp_platform;
/***************************************************************** Detection */
-static int dec_esp_detect(struct scsi_host_template * tpnt)
+static int dec_esp_platform_probe(void)
{
struct NCR_ESP *esp;
- struct ConfigDev *esp_dev;
- int slot;
- unsigned long mem_start;
+ int err = 0;
if (IOASIC) {
- esp_dev = 0;
- esp = esp_allocate(tpnt, (void *) esp_dev);
+ esp = esp_allocate(&dec_esp_template, NULL, 1);
/* Do command transfer with programmed I/O */
esp->do_pio_cmds = 1;
@@ -200,112 +182,175 @@ static int dec_esp_detect(struct scsi_host_template * tpnt)
/* Check for differential SCSI-bus */
esp->diff = 0;
+ err = request_irq(esp->irq, esp_intr, IRQF_DISABLED,
+ "ncr53c94", esp->ehost);
+ if (err)
+ goto err_alloc;
+ err = request_irq(dec_interrupt[DEC_IRQ_ASC_MERR],
+ scsi_dma_merr_int, IRQF_DISABLED,
+ "ncr53c94 error", esp->ehost);
+ if (err)
+ goto err_irq;
+ err = request_irq(dec_interrupt[DEC_IRQ_ASC_ERR],
+ scsi_dma_err_int, IRQF_DISABLED,
+ "ncr53c94 overrun", esp->ehost);
+ if (err)
+ goto err_irq_merr;
+ err = request_irq(dec_interrupt[DEC_IRQ_ASC_DMA], scsi_dma_int,
+ IRQF_DISABLED, "ncr53c94 dma", esp->ehost);
+ if (err)
+ goto err_irq_err;
+
esp_initialize(esp);
- if (request_irq(esp->irq, esp_intr, IRQF_DISABLED,
- "ncr53c94", esp->ehost))
- goto err_dealloc;
- if (request_irq(dec_interrupt[DEC_IRQ_ASC_MERR],
- scsi_dma_merr_int, IRQF_DISABLED,
- "ncr53c94 error", esp->ehost))
- goto err_free_irq;
- if (request_irq(dec_interrupt[DEC_IRQ_ASC_ERR],
- scsi_dma_err_int, IRQF_DISABLED,
- "ncr53c94 overrun", esp->ehost))
- goto err_free_irq_merr;
- if (request_irq(dec_interrupt[DEC_IRQ_ASC_DMA],
- scsi_dma_int, IRQF_DISABLED,
- "ncr53c94 dma", esp->ehost))
- goto err_free_irq_err;
+ err = scsi_add_host(esp->ehost, NULL);
+ if (err) {
+ printk(KERN_ERR "ESP: Unable to register adapter\n");
+ goto err_irq_dma;
+ }
+
+ scsi_scan_host(esp->ehost);
+ dec_esp_platform = esp;
}
- if (TURBOCHANNEL) {
- while ((slot = search_tc_card("PMAZ-AA")) >= 0) {
- claim_tc_card(slot);
-
- esp_dev = 0;
- esp = esp_allocate(tpnt, (void *) esp_dev);
-
- mem_start = get_tc_base_addr(slot);
-
- /* Store base addr into esp struct */
- esp->slot = CPHYSADDR(mem_start);
-
- esp->dregs = 0;
- esp->eregs = (void *)CKSEG1ADDR(mem_start +
- DEC_SCSI_SREG);
- esp->do_pio_cmds = 1;
-
- /* Set the command buffer */
- esp->esp_command = (volatile unsigned char *) pmaz_cmd_buffer;
-
- /* get virtual dma address for command buffer */
- esp->esp_command_dvma = virt_to_phys(pmaz_cmd_buffer);
-
- esp->cfreq = get_tc_speed();
-
- esp->irq = get_tc_irq_nr(slot);
-
- /* Required functions */
- esp->dma_bytes_sent = &dma_bytes_sent;
- esp->dma_can_transfer = &dma_can_transfer;
- esp->dma_dump_state = &dma_dump_state;
- esp->dma_init_read = &pmaz_dma_init_read;
- esp->dma_init_write = &pmaz_dma_init_write;
- esp->dma_ints_off = &pmaz_dma_ints_off;
- esp->dma_ints_on = &pmaz_dma_ints_on;
- esp->dma_irq_p = &dma_irq_p;
- esp->dma_ports_p = &dma_ports_p;
- esp->dma_setup = &pmaz_dma_setup;
-
- /* Optional functions */
- esp->dma_barrier = 0;
- esp->dma_drain = &pmaz_dma_drain;
- esp->dma_invalidate = 0;
- esp->dma_irq_entry = 0;
- esp->dma_irq_exit = 0;
- esp->dma_poll = 0;
- esp->dma_reset = 0;
- esp->dma_led_off = 0;
- esp->dma_led_on = 0;
-
- esp->dma_mmu_get_scsi_one = pmaz_dma_mmu_get_scsi_one;
- esp->dma_mmu_get_scsi_sgl = 0;
- esp->dma_mmu_release_scsi_one = 0;
- esp->dma_mmu_release_scsi_sgl = 0;
- esp->dma_advance_sg = 0;
-
- if (request_irq(esp->irq, esp_intr, IRQF_DISABLED,
- "PMAZ_AA", esp->ehost)) {
- esp_deallocate(esp);
- release_tc_card(slot);
- continue;
- }
- esp->scsi_id = 7;
- esp->diff = 0;
- esp_initialize(esp);
- }
+ return 0;
+
+err_irq_dma:
+ free_irq(dec_interrupt[DEC_IRQ_ASC_DMA], esp->ehost);
+err_irq_err:
+ free_irq(dec_interrupt[DEC_IRQ_ASC_ERR], esp->ehost);
+err_irq_merr:
+ free_irq(dec_interrupt[DEC_IRQ_ASC_MERR], esp->ehost);
+err_irq:
+ free_irq(esp->irq, esp->ehost);
+err_alloc:
+ esp_deallocate(esp);
+ scsi_host_put(esp->ehost);
+ return err;
+}
+
+static int __init dec_esp_probe(struct device *dev)
+{
+ struct NCR_ESP *esp;
+ resource_size_t start, len;
+ int err;
+
+ esp = esp_allocate(&dec_esp_template, NULL, 1);
+
+ dev_set_drvdata(dev, esp);
+
+ start = to_tc_dev(dev)->resource.start;
+ len = to_tc_dev(dev)->resource.end - start + 1;
+
+ if (!request_mem_region(start, len, dev->bus_id)) {
+ printk(KERN_ERR "%s: Unable to reserve MMIO resource\n",
+ dev->bus_id);
+ err = -EBUSY;
+ goto err_alloc;
}
- if(nesps) {
- printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use);
- esps_running = esps_in_use;
- return esps_in_use;
+ /* Store base addr into esp struct. */
+ esp->slot = start;
+
+ esp->dregs = 0;
+ esp->eregs = (void *)CKSEG1ADDR(start + DEC_SCSI_SREG);
+ esp->do_pio_cmds = 1;
+
+ /* Set the command buffer. */
+ esp->esp_command = (volatile unsigned char *)pmaz_cmd_buffer;
+
+ /* Get virtual dma address for command buffer. */
+ esp->esp_command_dvma = virt_to_phys(pmaz_cmd_buffer);
+
+ esp->cfreq = tc_get_speed(to_tc_dev(dev)->bus);
+
+ esp->irq = to_tc_dev(dev)->interrupt;
+
+ /* Required functions. */
+ esp->dma_bytes_sent = &dma_bytes_sent;
+ esp->dma_can_transfer = &dma_can_transfer;
+ esp->dma_dump_state = &dma_dump_state;
+ esp->dma_init_read = &pmaz_dma_init_read;
+ esp->dma_init_write = &pmaz_dma_init_write;
+ esp->dma_ints_off = &pmaz_dma_ints_off;
+ esp->dma_ints_on = &pmaz_dma_ints_on;
+ esp->dma_irq_p = &dma_irq_p;
+ esp->dma_ports_p = &dma_ports_p;
+ esp->dma_setup = &pmaz_dma_setup;
+
+ /* Optional functions. */
+ esp->dma_barrier = 0;
+ esp->dma_drain = &pmaz_dma_drain;
+ esp->dma_invalidate = 0;
+ esp->dma_irq_entry = 0;
+ esp->dma_irq_exit = 0;
+ esp->dma_poll = 0;
+ esp->dma_reset = 0;
+ esp->dma_led_off = 0;
+ esp->dma_led_on = 0;
+
+ esp->dma_mmu_get_scsi_one = pmaz_dma_mmu_get_scsi_one;
+ esp->dma_mmu_get_scsi_sgl = 0;
+ esp->dma_mmu_release_scsi_one = 0;
+ esp->dma_mmu_release_scsi_sgl = 0;
+ esp->dma_advance_sg = 0;
+
+ err = request_irq(esp->irq, esp_intr, IRQF_DISABLED, "PMAZ_AA",
+ esp->ehost);
+ if (err) {
+ printk(KERN_ERR "%s: Unable to get IRQ %d\n",
+ dev->bus_id, esp->irq);
+ goto err_resource;
+ }
+
+ esp->scsi_id = 7;
+ esp->diff = 0;
+ esp_initialize(esp);
+
+ err = scsi_add_host(esp->ehost, dev);
+ if (err) {
+ printk(KERN_ERR "%s: Unable to register adapter\n",
+ dev->bus_id);
+ goto err_irq;
}
+
+ scsi_scan_host(esp->ehost);
+
return 0;
-err_free_irq_err:
- free_irq(dec_interrupt[DEC_IRQ_ASC_ERR], scsi_dma_err_int);
-err_free_irq_merr:
- free_irq(dec_interrupt[DEC_IRQ_ASC_MERR], scsi_dma_merr_int);
-err_free_irq:
- free_irq(esp->irq, esp_intr);
-err_dealloc:
+err_irq:
+ free_irq(esp->irq, esp->ehost);
+
+err_resource:
+ release_mem_region(start, len);
+
+err_alloc:
esp_deallocate(esp);
- return 0;
+ scsi_host_put(esp->ehost);
+ return err;
+}
+
+static void __exit dec_esp_platform_remove(void)
+{
+ struct NCR_ESP *esp = dec_esp_platform;
+
+ free_irq(esp->irq, esp->ehost);
+ esp_deallocate(esp);
+ scsi_host_put(esp->ehost);
+ dec_esp_platform = NULL;
}
+static void __exit dec_esp_remove(struct device *dev)
+{
+ struct NCR_ESP *esp = dev_get_drvdata(dev);
+
+ free_irq(esp->irq, esp->ehost);
+ esp_deallocate(esp);
+ scsi_host_put(esp->ehost);
+}
+
+
/************************************************************* DMA Functions */
static irqreturn_t scsi_dma_merr_int(int irq, void *dev_id)
{
@@ -576,3 +621,67 @@ static void pmaz_dma_mmu_get_scsi_one(struct NCR_ESP *esp, struct scsi_cmnd * sp
{
sp->SCp.ptr = (char *)virt_to_phys(sp->request_buffer);
}
+
+
+#ifdef CONFIG_TC
+static int __init dec_esp_tc_probe(struct device *dev);
+static int __exit dec_esp_tc_remove(struct device *dev);
+
+static const struct tc_device_id dec_esp_tc_table[] = {
+ { "DEC ", "PMAZ-AA " },
+ { }
+};
+MODULE_DEVICE_TABLE(tc, dec_esp_tc_table);
+
+static struct tc_driver dec_esp_tc_driver = {
+ .id_table = dec_esp_tc_table,
+ .driver = {
+ .name = "dec_esp",
+ .bus = &tc_bus_type,
+ .probe = dec_esp_tc_probe,
+ .remove = __exit_p(dec_esp_tc_remove),
+ },
+};
+
+static int __init dec_esp_tc_probe(struct device *dev)
+{
+ int status = dec_esp_probe(dev);
+ if (!status)
+ get_device(dev);
+ return status;
+}
+
+static int __exit dec_esp_tc_remove(struct device *dev)
+{
+ put_device(dev);
+ dec_esp_remove(dev);
+ return 0;
+}
+#endif
+
+static int __init dec_esp_init(void)
+{
+ int status;
+
+ status = tc_register_driver(&dec_esp_tc_driver);
+ if (!status)
+ dec_esp_platform_probe();
+
+ if (nesps) {
+ pr_info("ESP: Total of %d ESP hosts found, "
+ "%d actually in use.\n", nesps, esps_in_use);
+ esps_running = esps_in_use;
+ }
+
+ return status;
+}
+
+static void __exit dec_esp_exit(void)
+{
+ dec_esp_platform_remove();
+ tc_unregister_driver(&dec_esp_tc_driver);
+}
+
+
+module_init(dec_esp_init);
+module_exit(dec_esp_exit);
diff --git a/drivers/scsi/fastlane.c b/drivers/scsi/fastlane.c
index 2a1c5c22b9e..4266a2139b5 100644
--- a/drivers/scsi/fastlane.c
+++ b/drivers/scsi/fastlane.c
@@ -142,7 +142,7 @@ int __init fastlane_esp_detect(struct scsi_host_template *tpnt)
if (board < 0x1000000) {
goto err_release;
}
- esp = esp_allocate(tpnt, (void *)board+FASTLANE_ESP_ADDR);
+ esp = esp_allocate(tpnt, (void *)board + FASTLANE_ESP_ADDR, 0);
/* Do command transfer with programmed I/O */
esp->do_pio_cmds = 1;
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index b318500785e..821386c7b57 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -7558,9 +7558,6 @@ static struct pci_device_id ipr_pci_table[] __devinitdata = {
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C,
0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
- { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
- PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B8,
- 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E,
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B7,
0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index 43768408437..8f55e143143 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -1375,7 +1375,7 @@ iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
}
BUG_ON(tcp_mtask->xmstate != XMSTATE_IDLE);
- if (mtask->hdr->itt == cpu_to_be32(ISCSI_RESERVED_TAG)) {
+ if (mtask->hdr->itt == RESERVED_ITT) {
struct iscsi_session *session = conn->session;
spin_lock_bh(&session->lock);
diff --git a/drivers/scsi/jazz_esp.c b/drivers/scsi/jazz_esp.c
index bfac4441d89..19dd4b962e1 100644
--- a/drivers/scsi/jazz_esp.c
+++ b/drivers/scsi/jazz_esp.c
@@ -75,7 +75,7 @@ static int jazz_esp_detect(struct scsi_host_template *tpnt)
*/
if (1) {
esp_dev = NULL;
- esp = esp_allocate(tpnt, (void *) esp_dev);
+ esp = esp_allocate(tpnt, esp_dev, 0);
/* Do command transfer with programmed I/O */
esp->do_pio_cmds = 1;
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index d37048c96ea..7c75771c77f 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -113,8 +113,7 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
hdr->opcode = ISCSI_OP_SCSI_CMD;
hdr->flags = ISCSI_ATTR_SIMPLE;
int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
- hdr->itt = ctask->itt | (conn->id << ISCSI_CID_SHIFT) |
- (session->age << ISCSI_AGE_SHIFT);
+ hdr->itt = build_itt(ctask->itt, conn->id, session->age);
hdr->data_length = cpu_to_be32(sc->request_bufflen);
hdr->cmdsn = cpu_to_be32(session->cmdsn);
session->cmdsn++;
@@ -270,7 +269,7 @@ invalid_datalen:
goto out;
}
- senselen = be16_to_cpu(*(uint16_t *)data);
+ senselen = be16_to_cpu(*(__be16 *)data);
if (datalen < senselen)
goto invalid_datalen;
@@ -338,7 +337,7 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
if (ntoh24(reject->dlength) >= sizeof(struct iscsi_hdr)) {
memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr));
- itt = rejected_pdu.itt & ISCSI_ITT_MASK;
+ itt = get_itt(rejected_pdu.itt);
printk(KERN_ERR "itt 0x%x had pdu (op 0x%x) rejected "
"due to DataDigest error.\n", itt,
rejected_pdu.opcode);
@@ -367,10 +366,10 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
struct iscsi_mgmt_task *mtask;
uint32_t itt;
- if (hdr->itt != cpu_to_be32(ISCSI_RESERVED_TAG))
- itt = hdr->itt & ISCSI_ITT_MASK;
+ if (hdr->itt != RESERVED_ITT)
+ itt = get_itt(hdr->itt);
else
- itt = hdr->itt;
+ itt = ~0U;
if (itt < session->cmds_max) {
ctask = session->cmds[itt];
@@ -440,7 +439,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
iscsi_tmf_rsp(conn, hdr);
break;
case ISCSI_OP_NOOP_IN:
- if (hdr->ttt != ISCSI_RESERVED_TAG || datalen) {
+ if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) || datalen) {
rc = ISCSI_ERR_PROTO;
break;
}
@@ -457,7 +456,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
rc = ISCSI_ERR_BAD_OPCODE;
break;
}
- } else if (itt == ISCSI_RESERVED_TAG) {
+ } else if (itt == ~0U) {
rc = iscsi_check_assign_cmdsn(session,
(struct iscsi_nopin*)hdr);
if (rc)
@@ -470,7 +469,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
break;
}
- if (hdr->ttt == ISCSI_RESERVED_TAG)
+ if (hdr->ttt == cpu_to_be32(ISCSI_RESERVED_TAG))
break;
if (iscsi_recv_pdu(conn->cls_conn, hdr, NULL, 0))
@@ -516,24 +515,24 @@ int iscsi_verify_itt(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
struct iscsi_cmd_task *ctask;
uint32_t itt;
- if (hdr->itt != cpu_to_be32(ISCSI_RESERVED_TAG)) {
- if ((hdr->itt & ISCSI_AGE_MASK) !=
+ if (hdr->itt != RESERVED_ITT) {
+ if (((__force u32)hdr->itt & ISCSI_AGE_MASK) !=
(session->age << ISCSI_AGE_SHIFT)) {
printk(KERN_ERR "iscsi: received itt %x expected "
- "session age (%x)\n", hdr->itt,
+ "session age (%x)\n", (__force u32)hdr->itt,
session->age & ISCSI_AGE_MASK);
return ISCSI_ERR_BAD_ITT;
}
- if ((hdr->itt & ISCSI_CID_MASK) !=
+ if (((__force u32)hdr->itt & ISCSI_CID_MASK) !=
(conn->id << ISCSI_CID_SHIFT)) {
printk(KERN_ERR "iscsi: received itt %x, expected "
- "CID (%x)\n", hdr->itt, conn->id);
+ "CID (%x)\n", (__force u32)hdr->itt, conn->id);
return ISCSI_ERR_BAD_ITT;
}
- itt = hdr->itt & ISCSI_ITT_MASK;
+ itt = get_itt(hdr->itt);
} else
- itt = hdr->itt;
+ itt = ~0U;
if (itt < session->cmds_max) {
ctask = session->cmds[itt];
@@ -896,9 +895,8 @@ iscsi_conn_send_generic(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
/*
* pre-format CmdSN for outgoing PDU.
*/
- if (hdr->itt != cpu_to_be32(ISCSI_RESERVED_TAG)) {
- hdr->itt = mtask->itt | (conn->id << ISCSI_CID_SHIFT) |
- (session->age << ISCSI_AGE_SHIFT);
+ if (hdr->itt != RESERVED_ITT) {
+ hdr->itt = build_itt(mtask->itt, conn->id, session->age);
nop->cmdsn = cpu_to_be32(session->cmdsn);
if (conn->c_stage == ISCSI_CONN_STARTED &&
!(hdr->opcode & ISCSI_OP_IMMEDIATE))
@@ -1064,7 +1062,7 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc,
spin_lock_bh(&session->lock);
ctask->mtask = (struct iscsi_mgmt_task *)
- session->mgmt_cmds[(hdr->itt & ISCSI_ITT_MASK) -
+ session->mgmt_cmds[get_itt(hdr->itt) -
ISCSI_MGMT_ITT_OFFSET];
if (conn->tmabort_state == TMABORT_INITIAL) {
diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c
index 3586fac9be9..bcb49021b7e 100644
--- a/drivers/scsi/mac_esp.c
+++ b/drivers/scsi/mac_esp.c
@@ -351,7 +351,7 @@ int mac_esp_detect(struct scsi_host_template * tpnt)
for (chipnum = 0; chipnum < chipspresent; chipnum ++) {
struct NCR_ESP * esp;
- esp = esp_allocate(tpnt, (void *) NULL);
+ esp = esp_allocate(tpnt, NULL, 0);
esp->eregs = (struct ESP_regs *) get_base(chipnum);
esp->dma_irq_p = &esp_dafb_dma_irq_p;
diff --git a/drivers/scsi/mca_53c9x.c b/drivers/scsi/mca_53c9x.c
index 998a8bbc1a4..d693d0f2139 100644
--- a/drivers/scsi/mca_53c9x.c
+++ b/drivers/scsi/mca_53c9x.c
@@ -122,7 +122,7 @@ static int mca_esp_detect(struct scsi_host_template *tpnt)
if ((slot = mca_find_adapter(*id_to_check, 0)) !=
MCA_NOTFOUND)
{
- esp = esp_allocate(tpnt, (void *) NULL);
+ esp = esp_allocate(tpnt, NULL, 0);
pos[0] = mca_read_stored_pos(slot, 2);
pos[1] = mca_read_stored_pos(slot, 3);
diff --git a/drivers/scsi/oktagon_esp.c b/drivers/scsi/oktagon_esp.c
index c116a6ae3c5..26a6d55faf3 100644
--- a/drivers/scsi/oktagon_esp.c
+++ b/drivers/scsi/oktagon_esp.c
@@ -133,7 +133,7 @@ int oktagon_esp_detect(struct scsi_host_template *tpnt)
eregs = (struct ESP_regs *)(address + OKTAGON_ESP_ADDR);
/* This line was 5 lines lower */
- esp = esp_allocate(tpnt, (void *)board+OKTAGON_ESP_ADDR);
+ esp = esp_allocate(tpnt, (void *)board + OKTAGON_ESP_ADDR, 0);
/* we have to shift the registers only one bit for oktagon */
esp->shift = 1;
diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c
index 7d231106790..bd6bbf61adb 100644
--- a/drivers/scsi/osst.c
+++ b/drivers/scsi/osst.c
@@ -521,10 +521,10 @@ static void osst_init_aux(struct osst_tape * STp, int frame_type, int frame_seq_
break;
default: ; /* probably FILL */
}
- aux->filemark_cnt = ntohl(STp->filemark_cnt);
- aux->phys_fm = ntohl(0xffffffff);
- aux->last_mark_ppos = ntohl(STp->last_mark_ppos);
- aux->last_mark_lbn = ntohl(STp->last_mark_lbn);
+ aux->filemark_cnt = htonl(STp->filemark_cnt);
+ aux->phys_fm = htonl(0xffffffff);
+ aux->last_mark_ppos = htonl(STp->last_mark_ppos);
+ aux->last_mark_lbn = htonl(STp->last_mark_lbn);
}
/*
diff --git a/drivers/scsi/osst.h b/drivers/scsi/osst.h
index 1e426f5d0ed..2cc7b5a1606 100644
--- a/drivers/scsi/osst.h
+++ b/drivers/scsi/osst.h
@@ -288,11 +288,11 @@ typedef struct {
#else
#error "Please fix <asm/byteorder.h>"
#endif
- u16 max_speed; /* Maximum speed supported in KBps */
+ __be16 max_speed; /* Maximum speed supported in KBps */
u8 reserved10, reserved11;
- u16 ctl; /* Continuous Transfer Limit in blocks */
- u16 speed; /* Current Speed, in KBps */
- u16 buffer_size; /* Buffer Size, in 512 bytes */
+ __be16 ctl; /* Continuous Transfer Limit in blocks */
+ __be16 speed; /* Current Speed, in KBps */
+ __be16 buffer_size; /* Buffer Size, in 512 bytes */
u8 reserved18, reserved19;
} osst_capabilities_page_t;
@@ -352,8 +352,8 @@ typedef struct {
u8 reserved2;
u8 density;
u8 reserved3,reserved4;
- u16 segtrk;
- u16 trks;
+ __be16 segtrk;
+ __be16 trks;
u8 reserved5,reserved6,reserved7,reserved8,reserved9,reserved10;
} osst_tape_paramtr_page_t;
@@ -369,18 +369,18 @@ typedef struct {
typedef struct os_partition_s {
__u8 partition_num;
__u8 par_desc_ver;
- __u16 wrt_pass_cntr;
- __u32 first_frame_ppos;
- __u32 last_frame_ppos;
- __u32 eod_frame_ppos;
+ __be16 wrt_pass_cntr;
+ __be32 first_frame_ppos;
+ __be32 last_frame_ppos;
+ __be32 eod_frame_ppos;
} os_partition_t;
/*
* DAT entry
*/
typedef struct os_dat_entry_s {
- __u32 blk_sz;
- __u16 blk_cnt;
+ __be32 blk_sz;
+ __be16 blk_cnt;
__u8 flags;
__u8 reserved;
} os_dat_entry_t;
@@ -412,23 +412,23 @@ typedef struct os_dat_s {
* AUX
*/
typedef struct os_aux_s {
- __u32 format_id; /* hardware compability AUX is based on */
+ __be32 format_id; /* hardware compability AUX is based on */
char application_sig[4]; /* driver used to write this media */
- __u32 hdwr; /* reserved */
- __u32 update_frame_cntr; /* for configuration frame */
+ __be32 hdwr; /* reserved */
+ __be32 update_frame_cntr; /* for configuration frame */
__u8 frame_type;
__u8 frame_type_reserved;
__u8 reserved_18_19[2];
os_partition_t partition;
__u8 reserved_36_43[8];
- __u32 frame_seq_num;
- __u32 logical_blk_num_high;
- __u32 logical_blk_num;
+ __be32 frame_seq_num;
+ __be32 logical_blk_num_high;
+ __be32 logical_blk_num;
os_dat_t dat;
__u8 reserved188_191[4];
- __u32 filemark_cnt;
- __u32 phys_fm;
- __u32 last_mark_ppos;
+ __be32 filemark_cnt;
+ __be32 phys_fm;
+ __be32 last_mark_ppos;
__u8 reserved204_223[20];
/*
@@ -436,8 +436,8 @@ typedef struct os_aux_s {
*
* Linux specific fields:
*/
- __u32 next_mark_ppos; /* when known, points to next marker */
- __u32 last_mark_lbn; /* storing log_blk_num of last mark is extends ADR spec */
+ __be32 next_mark_ppos; /* when known, points to next marker */
+ __be32 last_mark_lbn; /* storing log_blk_num of last mark is extends ADR spec */
__u8 linux_specific[24];
__u8 reserved_256_511[256];
@@ -450,19 +450,19 @@ typedef struct os_fm_tab_s {
__u8 reserved_1;
__u8 fm_tab_ent_sz;
__u8 reserved_3;
- __u16 fm_tab_ent_cnt;
+ __be16 fm_tab_ent_cnt;
__u8 reserved6_15[10];
- __u32 fm_tab_ent[OS_FM_TAB_MAX];
+ __be32 fm_tab_ent[OS_FM_TAB_MAX];
} os_fm_tab_t;
typedef struct os_ext_trk_ey_s {
__u8 et_part_num;
__u8 fmt;
- __u16 fm_tab_off;
+ __be16 fm_tab_off;
__u8 reserved4_7[4];
- __u32 last_hlb_hi;
- __u32 last_hlb;
- __u32 last_pp;
+ __be32 last_hlb_hi;
+ __be32 last_hlb;
+ __be32 last_pp;
__u8 reserved20_31[12];
} os_ext_trk_ey_t;
@@ -479,17 +479,17 @@ typedef struct os_header_s {
char ident_str[8];
__u8 major_rev;
__u8 minor_rev;
- __u16 ext_trk_tb_off;
+ __be16 ext_trk_tb_off;
__u8 reserved12_15[4];
__u8 pt_par_num;
__u8 pt_reserved1_3[3];
os_partition_t partition[16];
- __u32 cfg_col_width;
- __u32 dat_col_width;
- __u32 qfa_col_width;
+ __be32 cfg_col_width;
+ __be32 dat_col_width;
+ __be32 qfa_col_width;
__u8 cartridge[16];
__u8 reserved304_511[208];
- __u32 old_filemark_list[16680/4]; /* in ADR 1.4 __u8 track_table[16680] */
+ __be32 old_filemark_list[16680/4]; /* in ADR 1.4 __u8 track_table[16680] */
os_ext_trk_tb_t ext_track_tb;
__u8 reserved17272_17735[464];
os_fm_tab_t dat_fm_tab;
diff --git a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c
index 6b60536ac92..80fb3f88af2 100644
--- a/drivers/scsi/sun3x_esp.c
+++ b/drivers/scsi/sun3x_esp.c
@@ -53,7 +53,7 @@ int sun3x_esp_detect(struct scsi_host_template *tpnt)
struct ConfigDev *esp_dev;
esp_dev = 0;
- esp = esp_allocate(tpnt, (void *) esp_dev);
+ esp = esp_allocate(tpnt, esp_dev, 0);
/* Do command transfer with DMA */
esp->do_pio_cmds = 0;
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/serial/cpm_uart/cpm_uart_cpm1.c
index 08e55fdc882..925fb607d8c 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm1.c
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.c
@@ -40,6 +40,7 @@
#include <asm/io.h>
#include <asm/irq.h>
+#include <asm/fs_pd.h>
#include <linux/serial_core.h>
#include <linux/kernel.h>
@@ -145,7 +146,7 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
/* was hostalloc but changed cause it blows away the */
/* large tlb mapping when pinning the kernel area */
mem_addr = (u8 *) cpm_dpram_addr(cpm_dpalloc(memsz, 8));
- dma_addr = (u32)mem_addr;
+ dma_addr = (u32)cpm_dpram_phys(mem_addr);
} else
mem_addr = dma_alloc_coherent(NULL, memsz, &dma_addr,
GFP_KERNEL);
@@ -205,7 +206,7 @@ int __init cpm_uart_init_portdesc(void)
(unsigned long)&cpmp->cp_smc[0];
cpm_uart_ports[UART_SMC1].smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
cpm_uart_ports[UART_SMC1].smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
- cpm_uart_ports[UART_SMC1].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+ cpm_uart_ports[UART_SMC1].port.uartclk = uart_clock();
cpm_uart_port_map[cpm_uart_nr++] = UART_SMC1;
#endif
@@ -217,7 +218,7 @@ int __init cpm_uart_init_portdesc(void)
(unsigned long)&cpmp->cp_smc[1];
cpm_uart_ports[UART_SMC2].smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
cpm_uart_ports[UART_SMC2].smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
- cpm_uart_ports[UART_SMC2].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+ cpm_uart_ports[UART_SMC2].port.uartclk = uart_clock();
cpm_uart_port_map[cpm_uart_nr++] = UART_SMC2;
#endif
@@ -231,7 +232,7 @@ int __init cpm_uart_init_portdesc(void)
~(UART_SCCM_TX | UART_SCCM_RX);
cpm_uart_ports[UART_SCC1].sccp->scc_gsmrl &=
~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
- cpm_uart_ports[UART_SCC1].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+ cpm_uart_ports[UART_SCC1].port.uartclk = uart_clock();
cpm_uart_port_map[cpm_uart_nr++] = UART_SCC1;
#endif
@@ -245,7 +246,7 @@ int __init cpm_uart_init_portdesc(void)
~(UART_SCCM_TX | UART_SCCM_RX);
cpm_uart_ports[UART_SCC2].sccp->scc_gsmrl &=
~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
- cpm_uart_ports[UART_SCC2].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+ cpm_uart_ports[UART_SCC2].port.uartclk = uart_clock();
cpm_uart_port_map[cpm_uart_nr++] = UART_SCC2;
#endif
@@ -259,7 +260,7 @@ int __init cpm_uart_init_portdesc(void)
~(UART_SCCM_TX | UART_SCCM_RX);
cpm_uart_ports[UART_SCC3].sccp->scc_gsmrl &=
~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
- cpm_uart_ports[UART_SCC3].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+ cpm_uart_ports[UART_SCC3].port.uartclk = uart_clock();
cpm_uart_port_map[cpm_uart_nr++] = UART_SCC3;
#endif
@@ -273,7 +274,7 @@ int __init cpm_uart_init_portdesc(void)
~(UART_SCCM_TX | UART_SCCM_RX);
cpm_uart_ports[UART_SCC4].sccp->scc_gsmrl &=
~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
- cpm_uart_ports[UART_SCC4].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+ cpm_uart_ports[UART_SCC4].port.uartclk = uart_clock();
cpm_uart_port_map[cpm_uart_nr++] = UART_SCC4;
#endif
return 0;
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.h b/drivers/serial/cpm_uart/cpm_uart_cpm1.h
index 5eb49ea63bf..a99e45e2b6d 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm1.h
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.h
@@ -20,9 +20,6 @@
#define SCC3_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC3)
#define SCC4_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC4)
-/* the CPM address */
-#define CPM_ADDR IMAP_ADDR
-
static inline void cpm_set_brg(int brg, int baud)
{
cpm_setbrg(brg, baud);
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.h b/drivers/serial/cpm_uart/cpm_uart_cpm2.h
index 4b779111eaf..1b3219f56c8 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm2.h
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.h
@@ -20,9 +20,6 @@
#define SCC3_IRQ SIU_INT_SCC3
#define SCC4_IRQ SIU_INT_SCC4
-/* the CPM address */
-#define CPM_ADDR CPM_MAP_ADDR
-
static inline void cpm_set_brg(int brg, int baud)
{
cpm_setbrg(brg, baud);
diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c
index db8607e3d53..f5051cf1a0c 100644
--- a/drivers/serial/uartlite.c
+++ b/drivers/serial/uartlite.c
@@ -256,7 +256,7 @@ static void ulite_release_port(struct uart_port *port)
{
release_mem_region(port->mapbase, ULITE_REGION);
iounmap(port->membase);
- port->membase = 0;
+ port->membase = NULL;
}
static int ulite_request_port(struct uart_port *port)
@@ -438,7 +438,7 @@ static int __devinit ulite_probe(struct platform_device *pdev)
port->iotype = UPIO_MEM;
port->iobase = 1; /* mark port in use */
port->mapbase = res->start;
- port->membase = 0;
+ port->membase = NULL;
port->ops = &ulite_ops;
port->irq = res2->start;
port->flags = UPF_BOOT_AUTOCONF;
@@ -462,7 +462,7 @@ static int ulite_remove(struct platform_device *pdev)
uart_remove_one_port(&ulite_uart_driver, port);
/* mark port as free */
- port->membase = 0;
+ port->membase = NULL;
return 0;
}
diff --git a/drivers/tc/Makefile b/drivers/tc/Makefile
index 83b5bd75ce2..96734269221 100644
--- a/drivers/tc/Makefile
+++ b/drivers/tc/Makefile
@@ -4,7 +4,7 @@
# Object file lists.
-obj-$(CONFIG_TC) += tc.o
+obj-$(CONFIG_TC) += tc.o tc-driver.o
obj-$(CONFIG_ZS) += zs.o
obj-$(CONFIG_VT) += lk201.o lk201-map.o lk201-remap.o
diff --git a/drivers/tc/tc-driver.c b/drivers/tc/tc-driver.c
new file mode 100644
index 00000000000..16b5bae63c7
--- /dev/null
+++ b/drivers/tc/tc-driver.c
@@ -0,0 +1,110 @@
+/*
+ * TURBOchannel driver services.
+ *
+ * Copyright (c) 2005 James Simmons
+ * Copyright (c) 2006 Maciej W. Rozycki
+ *
+ * Loosely based on drivers/dio/dio-driver.c and
+ * drivers/pci/pci-driver.c.
+ *
+ * This file is subject to the terms and conditions of the GNU
+ * General Public License. See the file "COPYING" in the main
+ * directory of this archive for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/tc.h>
+
+/**
+ * tc_register_driver - register a new TC driver
+ * @drv: the driver structure to register
+ *
+ * Adds the driver structure to the list of registered drivers
+ * Returns a negative value on error, otherwise 0.
+ * If no error occurred, the driver remains registered even if
+ * no device was claimed during registration.
+ */
+int tc_register_driver(struct tc_driver *tdrv)
+{
+ return driver_register(&tdrv->driver);
+}
+EXPORT_SYMBOL(tc_register_driver);
+
+/**
+ * tc_unregister_driver - unregister a TC driver
+ * @drv: the driver structure to unregister
+ *
+ * Deletes the driver structure from the list of registered TC drivers,
+ * gives it a chance to clean up by calling its remove() function for
+ * each device it was responsible for, and marks those devices as
+ * driverless.
+ */
+void tc_unregister_driver(struct tc_driver *tdrv)
+{
+ driver_unregister(&tdrv->driver);
+}
+EXPORT_SYMBOL(tc_unregister_driver);
+
+/**
+ * tc_match_device - tell if a TC device structure has a matching
+ * TC device ID structure
+ * @tdrv: the TC driver to earch for matching TC device ID strings
+ * @tdev: the TC device structure to match against
+ *
+ * Used by a driver to check whether a TC device present in the
+ * system is in its list of supported devices. Returns the matching
+ * tc_device_id structure or %NULL if there is no match.
+ */
+const struct tc_device_id *tc_match_device(struct tc_driver *tdrv,
+ struct tc_dev *tdev)
+{
+ const struct tc_device_id *id = tdrv->id_table;
+
+ if (id) {
+ while (id->name[0] || id->vendor[0]) {
+ if (strcmp(tdev->name, id->name) == 0 &&
+ strcmp(tdev->vendor, id->vendor) == 0)
+ return id;
+ id++;
+ }
+ }
+ return NULL;
+}
+EXPORT_SYMBOL(tc_match_device);
+
+/**
+ * tc_bus_match - Tell if a device structure has a matching
+ * TC device ID structure
+ * @dev: the device structure to match against
+ * @drv: the device driver to search for matching TC device ID strings
+ *
+ * Used by a driver to check whether a TC device present in the
+ * system is in its list of supported devices. Returns 1 if there
+ * is a match or 0 otherwise.
+ */
+static int tc_bus_match(struct device *dev, struct device_driver *drv)
+{
+ struct tc_dev *tdev = to_tc_dev(dev);
+ struct tc_driver *tdrv = to_tc_driver(drv);
+ const struct tc_device_id *id;
+
+ id = tc_match_device(tdrv, tdev);
+ if (id)
+ return 1;
+
+ return 0;
+}
+
+struct bus_type tc_bus_type = {
+ .name = "tc",
+ .match = tc_bus_match,
+};
+EXPORT_SYMBOL(tc_bus_type);
+
+static int __init tc_driver_init(void)
+{
+ return bus_register(&tc_bus_type);
+}
+
+postcore_initcall(tc_driver_init);
diff --git a/drivers/tc/tc.c b/drivers/tc/tc.c
index 4a51e56f85b..f77f62a4b32 100644
--- a/drivers/tc/tc.c
+++ b/drivers/tc/tc.c
@@ -1,254 +1,193 @@
/*
- * tc-init: We assume the TURBOchannel to be up and running so
- * just probe for Modules and fill in the global data structure
- * tc_bus.
+ * TURBOchannel bus services.
*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
+ * Copyright (c) Harald Koerfgen, 1998
+ * Copyright (c) 2001, 2003, 2005, 2006 Maciej W. Rozycki
+ * Copyright (c) 2005 James Simmons
*
- * Copyright (c) Harald Koerfgen, 1998
- * Copyright (c) 2001, 2003, 2005 Maciej W. Rozycki
+ * This file is subject to the terms and conditions of the GNU
+ * General Public License. See the file "COPYING" in the main
+ * directory of this archive for more details.
*/
+#include <linux/compiler.h>
+#include <linux/errno.h>
#include <linux/init.h>
+#include <linux/ioport.h>
#include <linux/kernel.h>
+#include <linux/list.h>
#include <linux/module.h>
#include <linux/string.h>
+#include <linux/tc.h>
#include <linux/types.h>
-#include <asm/addrspace.h>
-#include <asm/errno.h>
#include <asm/io.h>
-#include <asm/paccess.h>
-#include <asm/dec/machtype.h>
-#include <asm/dec/prom.h>
-#include <asm/dec/tcinfo.h>
-#include <asm/dec/tcmodule.h>
-#include <asm/dec/interrupts.h>
-
-MODULE_LICENSE("GPL");
-slot_info tc_bus[MAX_SLOT];
-static int num_tcslots;
-static tcinfo *info;
+static struct tc_bus tc_bus = {
+ .name = "TURBOchannel",
+};
/*
- * Interface to the world. Read comment in include/asm-mips/tc.h.
+ * Probing for TURBOchannel modules.
*/
-
-int search_tc_card(const char *name)
-{
- int slot;
- slot_info *sip;
-
- for (slot = 0; slot < num_tcslots; slot++) {
- sip = &tc_bus[slot];
- if ((sip->flags & FREE) &&
- (strncmp(sip->name, name, strlen(name)) == 0)) {
- return slot;
- }
- }
-
- return -ENODEV;
-}
-
-void claim_tc_card(int slot)
-{
- if (tc_bus[slot].flags & IN_USE) {
- printk("claim_tc_card: attempting to claim a card already in use\n");
- return;
- }
- tc_bus[slot].flags &= ~FREE;
- tc_bus[slot].flags |= IN_USE;
-}
-
-void release_tc_card(int slot)
+static void __init tc_bus_add_devices(struct tc_bus *tbus)
{
- if (tc_bus[slot].flags & FREE) {
- printk("release_tc_card: "
- "attempting to release a card already free\n");
- return;
- }
- tc_bus[slot].flags &= ~IN_USE;
- tc_bus[slot].flags |= FREE;
-}
-
-unsigned long get_tc_base_addr(int slot)
-{
- return tc_bus[slot].base_addr;
-}
-
-unsigned long get_tc_irq_nr(int slot)
-{
- return tc_bus[slot].interrupt;
-}
-
-unsigned long get_tc_speed(void)
-{
- return 100000 * (10000 / (unsigned long)info->clk_period);
-}
-
-/*
- * Probing for TURBOchannel modules
- */
-static void __init tc_probe(unsigned long startaddr, unsigned long size,
- int slots)
-{
- unsigned long slotaddr;
+ resource_size_t slotsize = tbus->info.slot_size << 20;
+ resource_size_t extslotsize = tbus->ext_slot_size;
+ resource_size_t slotaddr;
+ resource_size_t extslotaddr;
+ resource_size_t devsize;
+ void __iomem *module;
+ struct tc_dev *tdev;
int i, slot, err;
- long offset;
u8 pattern[4];
- volatile u8 *module;
+ long offset;
- for (slot = 0; slot < slots; slot++) {
- slotaddr = startaddr + slot * size;
- module = ioremap_nocache(slotaddr, size);
+ for (slot = 0; slot < tbus->num_tcslots; slot++) {
+ slotaddr = tbus->slot_base + slot * slotsize;
+ extslotaddr = tbus->ext_slot_base + slot * extslotsize;
+ module = ioremap_nocache(slotaddr, slotsize);
BUG_ON(!module);
- offset = OLDCARD;
+ offset = TC_OLDCARD;
err = 0;
- err |= get_dbe(pattern[0], module + OLDCARD + TC_PATTERN0);
- err |= get_dbe(pattern[1], module + OLDCARD + TC_PATTERN1);
- err |= get_dbe(pattern[2], module + OLDCARD + TC_PATTERN2);
- err |= get_dbe(pattern[3], module + OLDCARD + TC_PATTERN3);
- if (err) {
- iounmap(module);
- continue;
- }
+ err |= tc_preadb(pattern + 0, module + offset + TC_PATTERN0);
+ err |= tc_preadb(pattern + 1, module + offset + TC_PATTERN1);
+ err |= tc_preadb(pattern + 2, module + offset + TC_PATTERN2);
+ err |= tc_preadb(pattern + 3, module + offset + TC_PATTERN3);
+ if (err)
+ goto out_err;
if (pattern[0] != 0x55 || pattern[1] != 0x00 ||
pattern[2] != 0xaa || pattern[3] != 0xff) {
- offset = NEWCARD;
+ offset = TC_NEWCARD;
err = 0;
- err |= get_dbe(pattern[0], module + TC_PATTERN0);
- err |= get_dbe(pattern[1], module + TC_PATTERN1);
- err |= get_dbe(pattern[2], module + TC_PATTERN2);
- err |= get_dbe(pattern[3], module + TC_PATTERN3);
- if (err) {
- iounmap(module);
- continue;
- }
+ err |= tc_preadb(pattern + 0,
+ module + offset + TC_PATTERN0);
+ err |= tc_preadb(pattern + 1,
+ module + offset + TC_PATTERN1);
+ err |= tc_preadb(pattern + 2,
+ module + offset + TC_PATTERN2);
+ err |= tc_preadb(pattern + 3,
+ module + offset + TC_PATTERN3);
+ if (err)
+ goto out_err;
}
if (pattern[0] != 0x55 || pattern[1] != 0x00 ||
- pattern[2] != 0xaa || pattern[3] != 0xff) {
- iounmap(module);
- continue;
+ pattern[2] != 0xaa || pattern[3] != 0xff)
+ goto out_err;
+
+ /* Found a board, allocate it an entry in the list */
+ tdev = kzalloc(sizeof(*tdev), GFP_KERNEL);
+ if (!tdev) {
+ printk(KERN_ERR "tc%x: unable to allocate tc_dev\n",
+ slot);
+ goto out_err;
}
+ sprintf(tdev->dev.bus_id, "tc%x", slot);
+ tdev->bus = tbus;
+ tdev->dev.parent = &tbus->dev;
+ tdev->dev.bus = &tc_bus_type;
+ tdev->slot = slot;
- tc_bus[slot].base_addr = slotaddr;
for (i = 0; i < 8; i++) {
- tc_bus[slot].firmware[i] =
- module[TC_FIRM_VER + offset + 4 * i];
- tc_bus[slot].vendor[i] =
- module[TC_VENDOR + offset + 4 * i];
- tc_bus[slot].name[i] =
- module[TC_MODULE + offset + 4 * i];
+ tdev->firmware[i] =
+ readb(module + offset + TC_FIRM_VER + 4 * i);
+ tdev->vendor[i] =
+ readb(module + offset + TC_VENDOR + 4 * i);
+ tdev->name[i] =
+ readb(module + offset + TC_MODULE + 4 * i);
}
- tc_bus[slot].firmware[8] = 0;
- tc_bus[slot].vendor[8] = 0;
- tc_bus[slot].name[8] = 0;
- /*
- * Looks unneccesary, but we may change
- * TC? in the future
- */
- switch (slot) {
- case 0:
- tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC0];
- break;
- case 1:
- tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC1];
- break;
- case 2:
- tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC2];
- break;
- /*
- * Yuck! DS5000/200 onboard devices
- */
- case 5:
- tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC5];
- break;
- case 6:
- tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC6];
- break;
- default:
- tc_bus[slot].interrupt = -1;
- break;
+ tdev->firmware[8] = 0;
+ tdev->vendor[8] = 0;
+ tdev->name[8] = 0;
+
+ pr_info("%s: %s %s %s\n", tdev->dev.bus_id, tdev->vendor,
+ tdev->name, tdev->firmware);
+
+ devsize = readb(module + offset + TC_SLOT_SIZE);
+ devsize <<= 22;
+ if (devsize <= slotsize) {
+ tdev->resource.start = slotaddr;
+ tdev->resource.end = slotaddr + devsize - 1;
+ } else if (devsize <= extslotsize) {
+ tdev->resource.start = extslotaddr;
+ tdev->resource.end = extslotaddr + devsize - 1;
+ } else {
+ printk(KERN_ERR "%s: Cannot provide slot space "
+ "(%dMiB required, up to %dMiB supported)\n",
+ tdev->dev.bus_id, devsize >> 20,
+ max(slotsize, extslotsize) >> 20);
+ kfree(tdev);
+ goto out_err;
}
+ tdev->resource.name = tdev->name;
+ tdev->resource.flags = IORESOURCE_MEM;
+
+ tc_device_get_irq(tdev);
+ device_register(&tdev->dev);
+ list_add_tail(&tdev->node, &tbus->devices);
+
+out_err:
iounmap(module);
}
}
/*
- * the main entry
+ * The main entry.
*/
static int __init tc_init(void)
{
- int tc_clock;
- int i;
- unsigned long slot0addr;
- unsigned long slot_size;
-
- if (!TURBOCHANNEL)
+ /* Initialize the TURBOchannel bus */
+ if (tc_bus_get_info(&tc_bus))
return 0;
- for (i = 0; i < MAX_SLOT; i++) {
- tc_bus[i].base_addr = 0;
- tc_bus[i].name[0] = 0;
- tc_bus[i].vendor[0] = 0;
- tc_bus[i].firmware[0] = 0;
- tc_bus[i].interrupt = -1;
- tc_bus[i].flags = FREE;
- }
-
- info = rex_gettcinfo();
- slot0addr = CPHYSADDR((long)rex_slot_address(0));
-
- switch (mips_machtype) {
- case MACH_DS5000_200:
- num_tcslots = 7;
- break;
- case MACH_DS5000_1XX:
- case MACH_DS5000_2X0:
- case MACH_DS5900:
- num_tcslots = 3;
- break;
- case MACH_DS5000_XX:
- default:
- num_tcslots = 2;
- break;
- }
-
- tc_clock = 10000 / info->clk_period;
-
- if (info->slot_size && slot0addr) {
- pr_info("TURBOchannel rev. %d at %d.%d MHz (with%s parity)\n",
- info->revision, tc_clock / 10, tc_clock % 10,
- info->parity ? "" : "out");
-
- slot_size = info->slot_size << 20;
-
- tc_probe(slot0addr, slot_size, num_tcslots);
-
- for (i = 0; i < num_tcslots; i++) {
- if (!tc_bus[i].base_addr)
- continue;
- pr_info(" slot %d: %s %s %s\n", i, tc_bus[i].vendor,
- tc_bus[i].name, tc_bus[i].firmware);
+ INIT_LIST_HEAD(&tc_bus.devices);
+ strcpy(tc_bus.dev.bus_id, "tc");
+ device_register(&tc_bus.dev);
+
+ if (tc_bus.info.slot_size) {
+ unsigned int tc_clock = tc_get_speed(&tc_bus) / 100000;
+
+ pr_info("tc: TURBOchannel rev. %d at %d.%d MHz "
+ "(with%s parity)\n", tc_bus.info.revision,
+ tc_clock / 10, tc_clock % 10,
+ tc_bus.info.parity ? "" : "out");
+
+ tc_bus.resource[0].start = tc_bus.slot_base;
+ tc_bus.resource[0].end = tc_bus.slot_base +
+ (tc_bus.info.slot_size << 20) *
+ tc_bus.num_tcslots - 1;
+ tc_bus.resource[0].name = tc_bus.name;
+ tc_bus.resource[0].flags = IORESOURCE_MEM;
+ if (request_resource(&iomem_resource,
+ &tc_bus.resource[0]) < 0) {
+ printk(KERN_ERR "tc: Cannot reserve resource\n");
+ return 0;
+ }
+ if (tc_bus.ext_slot_size) {
+ tc_bus.resource[1].start = tc_bus.ext_slot_base;
+ tc_bus.resource[1].end = tc_bus.ext_slot_base +
+ tc_bus.ext_slot_size *
+ tc_bus.num_tcslots - 1;
+ tc_bus.resource[1].name = tc_bus.name;
+ tc_bus.resource[1].flags = IORESOURCE_MEM;
+ if (request_resource(&iomem_resource,
+ &tc_bus.resource[1]) < 0) {
+ printk(KERN_ERR
+ "tc: Cannot reserve resource\n");
+ release_resource(&tc_bus.resource[0]);
+ return 0;
+ }
}
+
+ tc_bus_add_devices(&tc_bus);
}
return 0;
}
subsys_initcall(tc_init);
-
-EXPORT_SYMBOL(search_tc_card);
-EXPORT_SYMBOL(claim_tc_card);
-EXPORT_SYMBOL(release_tc_card);
-EXPORT_SYMBOL(get_tc_base_addr);
-EXPORT_SYMBOL(get_tc_irq_nr);
-EXPORT_SYMBOL(get_tc_speed);
diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c
index 8ed6c75adf0..638b8009b3b 100644
--- a/drivers/usb/atm/speedtch.c
+++ b/drivers/usb/atm/speedtch.c
@@ -36,7 +36,7 @@
#include <linux/stat.h>
#include <linux/timer.h>
#include <linux/types.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/workqueue.h>
#include "usbatm.h"
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
index 6377db1b446..63e50a1f139 100644
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -398,6 +398,9 @@ static int usblp_open(struct inode *inode, struct file *file)
retval = 0;
#endif
+ retval = usb_autopm_get_interface(intf);
+ if (retval < 0)
+ goto out;
usblp->used = 1;
file->private_data = usblp;
@@ -442,6 +445,7 @@ static int usblp_release(struct inode *inode, struct file *file)
usblp->used = 0;
if (usblp->present) {
usblp_unlink_urbs(usblp);
+ usb_autopm_put_interface(usblp->intf);
} else /* finish cleanup from disconnect */
usblp_cleanup (usblp);
mutex_unlock (&usblp_mutex);
@@ -1203,14 +1207,9 @@ static int usblp_suspend (struct usb_interface *intf, pm_message_t message)
{
struct usblp *usblp = usb_get_intfdata (intf);
- /* this races against normal access and open */
- mutex_lock (&usblp_mutex);
- mutex_lock (&usblp->mut);
/* we take no more IO */
usblp->sleeping = 1;
usblp_unlink_urbs(usblp);
- mutex_unlock (&usblp->mut);
- mutex_unlock (&usblp_mutex);
return 0;
}
@@ -1220,15 +1219,9 @@ static int usblp_resume (struct usb_interface *intf)
struct usblp *usblp = usb_get_intfdata (intf);
int r;
- mutex_lock (&usblp_mutex);
- mutex_lock (&usblp->mut);
-
usblp->sleeping = 0;
r = handle_bidir (usblp);
- mutex_unlock (&usblp->mut);
- mutex_unlock (&usblp_mutex);
-
return r;
}
@@ -1251,6 +1244,7 @@ static struct usb_driver usblp_driver = {
.suspend = usblp_suspend,
.resume = usblp_resume,
.id_table = usblp_ids,
+ .supports_autosuspend = 1,
};
static int __init usblp_init(void)
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index 3e66b2a9974..2fc0f88a3d8 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -33,19 +33,6 @@ config USB_DEVICEFS
Most users want to say Y here.
-config USB_BANDWIDTH
- bool "Enforce USB bandwidth allocation (EXPERIMENTAL)"
- depends on USB && EXPERIMENTAL
- help
- If you say Y here, the USB subsystem enforces USB bandwidth
- allocation and will prevent some device opens from succeeding
- if they would cause USB bandwidth usage to go above 90% of
- the bus bandwidth.
-
- If you say N here, these conditions will cause warning messages
- about USB bandwidth usage to be logged and some devices or
- drivers may not work correctly.
-
config USB_DYNAMIC_MINORS
bool "Dynamic USB minor allocation (EXPERIMENTAL)"
depends on USB && EXPERIMENTAL
diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c
index c3915dc2860..ead2475406b 100644
--- a/drivers/usb/core/buffer.c
+++ b/drivers/usb/core/buffer.c
@@ -49,9 +49,9 @@ static const size_t pool_max [HCD_BUFFER_POOLS] = {
*
* Call hcd_buffer_destroy() to clean up after using those pools.
*/
-int hcd_buffer_create (struct usb_hcd *hcd)
+int hcd_buffer_create(struct usb_hcd *hcd)
{
- char name [16];
+ char name[16];
int i, size;
if (!hcd->self.controller->dma_mask)
@@ -60,11 +60,11 @@ int hcd_buffer_create (struct usb_hcd *hcd)
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
if (!(size = pool_max [i]))
continue;
- snprintf (name, sizeof name, "buffer-%d", size);
- hcd->pool [i] = dma_pool_create (name, hcd->self.controller,
+ snprintf(name, sizeof name, "buffer-%d", size);
+ hcd->pool[i] = dma_pool_create(name, hcd->self.controller,
size, size, 0);
if (!hcd->pool [i]) {
- hcd_buffer_destroy (hcd);
+ hcd_buffer_destroy(hcd);
return -ENOMEM;
}
}
@@ -79,14 +79,14 @@ int hcd_buffer_create (struct usb_hcd *hcd)
*
* This frees the buffer pools created by hcd_buffer_create().
*/
-void hcd_buffer_destroy (struct usb_hcd *hcd)
+void hcd_buffer_destroy(struct usb_hcd *hcd)
{
int i;
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
- struct dma_pool *pool = hcd->pool [i];
+ struct dma_pool *pool = hcd->pool[i];
if (pool) {
- dma_pool_destroy (pool);
+ dma_pool_destroy(pool);
hcd->pool[i] = NULL;
}
}
@@ -97,8 +97,8 @@ void hcd_buffer_destroy (struct usb_hcd *hcd)
* better sharing and to leverage mm/slab.c intelligence.
*/
-void *hcd_buffer_alloc (
- struct usb_bus *bus,
+void *hcd_buffer_alloc(
+ struct usb_bus *bus,
size_t size,
gfp_t mem_flags,
dma_addr_t *dma
@@ -110,18 +110,18 @@ void *hcd_buffer_alloc (
/* some USB hosts just use PIO */
if (!bus->controller->dma_mask) {
*dma = ~(dma_addr_t) 0;
- return kmalloc (size, mem_flags);
+ return kmalloc(size, mem_flags);
}
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
if (size <= pool_max [i])
- return dma_pool_alloc (hcd->pool [i], mem_flags, dma);
+ return dma_pool_alloc(hcd->pool [i], mem_flags, dma);
}
- return dma_alloc_coherent (hcd->self.controller, size, dma, 0);
+ return dma_alloc_coherent(hcd->self.controller, size, dma, 0);
}
-void hcd_buffer_free (
- struct usb_bus *bus,
+void hcd_buffer_free(
+ struct usb_bus *bus,
size_t size,
void *addr,
dma_addr_t dma
@@ -134,15 +134,15 @@ void hcd_buffer_free (
return;
if (!bus->controller->dma_mask) {
- kfree (addr);
+ kfree(addr);
return;
}
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
if (size <= pool_max [i]) {
- dma_pool_free (hcd->pool [i], addr, dma);
+ dma_pool_free(hcd->pool [i], addr, dma);
return;
}
}
- dma_free_coherent (hcd->self.controller, size, addr, dma);
+ dma_free_coherent(hcd->self.controller, size, addr, dma);
}
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
index ea398e5d50a..a47c30b2d76 100644
--- a/drivers/usb/core/devices.c
+++ b/drivers/usb/core/devices.c
@@ -104,7 +104,7 @@ static const char *format_config =
static const char *format_iface =
/* I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=xxxx*/
- "I: If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n";
+ "I:%c If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n";
static const char *format_endpt =
/* E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=D?s */
@@ -164,10 +164,10 @@ static const char *class_decode(const int class)
for (ix = 0; clas_info[ix].class != -1; ix++)
if (clas_info[ix].class == class)
break;
- return (clas_info[ix].class_name);
+ return clas_info[ix].class_name;
}
-static char *usb_dump_endpoint_descriptor (
+static char *usb_dump_endpoint_descriptor(
int speed,
char *start,
char *end,
@@ -212,9 +212,9 @@ static char *usb_dump_endpoint_descriptor (
break;
case USB_ENDPOINT_XFER_INT:
type = "Int.";
- if (speed == USB_SPEED_HIGH) {
+ if (speed == USB_SPEED_HIGH)
interval = 1 << (desc->bInterval - 1);
- } else
+ else
interval = desc->bInterval;
break;
default: /* "can't happen" */
@@ -242,15 +242,19 @@ static char *usb_dump_interface_descriptor(char *start, char *end,
{
const struct usb_interface_descriptor *desc = &intfc->altsetting[setno].desc;
const char *driver_name = "";
+ int active = 0;
if (start > end)
return start;
down_read(&usb_bus_type.subsys.rwsem);
- if (iface)
+ if (iface) {
driver_name = (iface->dev.driver
? iface->dev.driver->name
: "(none)");
+ active = (desc == &iface->cur_altsetting->desc);
+ }
start += sprintf(start, format_iface,
+ active ? '*' : ' ', /* mark active altsetting */
desc->bInterfaceNumber,
desc->bAlternateSetting,
desc->bNumEndpoints,
@@ -343,7 +347,7 @@ static char *usb_dump_device_descriptor(char *start, char *end, const struct usb
if (start > end)
return start;
- start += sprintf (start, format_device1,
+ start += sprintf(start, format_device1,
bcdUSB >> 8, bcdUSB & 0xff,
desc->bDeviceClass,
class_decode (desc->bDeviceClass),
@@ -363,7 +367,7 @@ static char *usb_dump_device_descriptor(char *start, char *end, const struct usb
/*
* Dump the different strings that this device holds.
*/
-static char *usb_dump_device_strings (char *start, char *end, struct usb_device *dev)
+static char *usb_dump_device_strings(char *start, char *end, struct usb_device *dev)
{
if (start > end)
return start;
@@ -395,7 +399,7 @@ static char *usb_dump_desc(char *start, char *end, struct usb_device *dev)
if (start > end)
return start;
- start = usb_dump_device_strings (start, end, dev);
+ start = usb_dump_device_strings(start, end, dev);
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
if (start > end)
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 4b3a6ab29bd..2087766f9e8 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -522,19 +522,19 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig
static struct usb_device *usbdev_lookup_minor(int minor)
{
- struct class_device *class_dev;
- struct usb_device *dev = NULL;
+ struct device *device;
+ struct usb_device *udev = NULL;
down(&usb_device_class->sem);
- 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;
+ list_for_each_entry(device, &usb_device_class->devices, node) {
+ if (device->devt == MKDEV(USB_DEVICE_MAJOR, minor)) {
+ udev = device->platform_data;
break;
}
}
up(&usb_device_class->sem);
- return dev;
+ return udev;
};
/*
@@ -570,6 +570,7 @@ static int usbdev_open(struct inode *inode, struct file *file)
ps->dev = dev;
ps->file = file;
spin_lock_init(&ps->lock);
+ INIT_LIST_HEAD(&ps->list);
INIT_LIST_HEAD(&ps->async_pending);
INIT_LIST_HEAD(&ps->async_completed);
init_waitqueue_head(&ps->wait);
@@ -1596,19 +1597,19 @@ static int usbdev_add(struct usb_device *dev)
{
int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1);
- dev->class_dev = class_device_create(usb_device_class, NULL,
- MKDEV(USB_DEVICE_MAJOR, minor), &dev->dev,
+ dev->usbfs_dev = device_create(usb_device_class, &dev->dev,
+ MKDEV(USB_DEVICE_MAJOR, minor),
"usbdev%d.%d", dev->bus->busnum, dev->devnum);
- if (IS_ERR(dev->class_dev))
- return PTR_ERR(dev->class_dev);
+ if (IS_ERR(dev->usbfs_dev))
+ return PTR_ERR(dev->usbfs_dev);
- dev->class_dev->class_data = dev;
+ dev->usbfs_dev->platform_data = dev;
return 0;
}
static void usbdev_remove(struct usb_device *dev)
{
- class_device_unregister(dev->class_dev);
+ device_unregister(dev->usbfs_dev);
}
static int usbdev_notify(struct notifier_block *self, unsigned long action,
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index d6eb5ce1dd1..600d1bc8272 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -28,24 +28,16 @@
#include "hcd.h"
#include "usb.h"
-static int usb_match_one_id(struct usb_interface *interface,
- const struct usb_device_id *id);
-
-struct usb_dynid {
- struct list_head node;
- struct usb_device_id id;
-};
-
#ifdef CONFIG_HOTPLUG
/*
* Adds a new dynamic USBdevice ID to this driver,
* and cause the driver to probe for all devices again.
*/
-static ssize_t store_new_id(struct device_driver *driver,
- const char *buf, size_t count)
+ssize_t usb_store_new_id(struct usb_dynids *dynids,
+ struct device_driver *driver,
+ const char *buf, size_t count)
{
- struct usb_driver *usb_drv = to_usb_driver(driver);
struct usb_dynid *dynid;
u32 idVendor = 0;
u32 idProduct = 0;
@@ -65,9 +57,9 @@ static ssize_t store_new_id(struct device_driver *driver,
dynid->id.idProduct = idProduct;
dynid->id.match_flags = USB_DEVICE_ID_MATCH_DEVICE;
- spin_lock(&usb_drv->dynids.lock);
- list_add_tail(&usb_drv->dynids.list, &dynid->node);
- spin_unlock(&usb_drv->dynids.lock);
+ spin_lock(&dynids->lock);
+ list_add_tail(&dynids->list, &dynid->node);
+ spin_unlock(&dynids->lock);
if (get_driver(driver)) {
retval = driver_attach(driver);
@@ -78,6 +70,15 @@ static ssize_t store_new_id(struct device_driver *driver,
return retval;
return count;
}
+EXPORT_SYMBOL_GPL(usb_store_new_id);
+
+static ssize_t store_new_id(struct device_driver *driver,
+ const char *buf, size_t count)
+{
+ struct usb_driver *usb_drv = to_usb_driver(driver);
+
+ return usb_store_new_id(&usb_drv->dynids, driver, buf, count);
+}
static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
static int usb_create_newid_file(struct usb_driver *usb_drv)
@@ -365,8 +366,8 @@ void usb_driver_release_interface(struct usb_driver *driver,
EXPORT_SYMBOL(usb_driver_release_interface);
/* returns 0 if no match, 1 if match */
-static int usb_match_one_id(struct usb_interface *interface,
- const struct usb_device_id *id)
+int usb_match_one_id(struct usb_interface *interface,
+ const struct usb_device_id *id)
{
struct usb_host_interface *intf;
struct usb_device *dev;
@@ -432,6 +433,8 @@ static int usb_match_one_id(struct usb_interface *interface,
return 1;
}
+EXPORT_SYMBOL_GPL(usb_match_one_id);
+
/**
* usb_match_id - find first usb_device_id matching device or interface
* @interface: the interface of interest
@@ -750,7 +753,8 @@ EXPORT_SYMBOL_GPL(usb_deregister_device_driver);
* usb_register_dev() to enable that functionality. This function no longer
* takes care of that.
*/
-int usb_register_driver(struct usb_driver *new_driver, struct module *owner)
+int usb_register_driver(struct usb_driver *new_driver, struct module *owner,
+ const char *mod_name)
{
int retval = 0;
@@ -763,6 +767,7 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner)
new_driver->drvwrap.driver.probe = usb_probe_interface;
new_driver->drvwrap.driver.remove = usb_unbind_interface;
new_driver->drvwrap.driver.owner = owner;
+ new_driver->drvwrap.driver.mod_name = mod_name;
spin_lock_init(&new_driver->dynids.lock);
INIT_LIST_HEAD(&new_driver->dynids.list);
diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c
index f794f07cfb3..01c857ac27a 100644
--- a/drivers/usb/core/file.c
+++ b/drivers/usb/core/file.c
@@ -194,14 +194,13 @@ int usb_register_dev(struct usb_interface *intf,
++temp;
else
temp = name;
- intf->class_dev = class_device_create(usb_class->class, NULL,
- MKDEV(USB_MAJOR, minor),
- &intf->dev, "%s", temp);
- if (IS_ERR(intf->class_dev)) {
+ intf->usb_dev = device_create(usb_class->class, &intf->dev,
+ MKDEV(USB_MAJOR, minor), "%s", temp);
+ if (IS_ERR(intf->usb_dev)) {
spin_lock (&minor_lock);
usb_minors[intf->minor] = NULL;
spin_unlock (&minor_lock);
- retval = PTR_ERR(intf->class_dev);
+ retval = PTR_ERR(intf->usb_dev);
}
exit:
return retval;
@@ -242,8 +241,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);
- class_device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
- intf->class_dev = NULL;
+ device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
+ intf->usb_dev = NULL;
intf->minor = -1;
destroy_usb_class();
}
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index ebb20ff7ac5..b531a4fd30c 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -25,6 +25,20 @@ static inline const char *plural(int n)
return (n == 1 ? "" : "s");
}
+static int is_rndis(struct usb_interface_descriptor *desc)
+{
+ return desc->bInterfaceClass == USB_CLASS_COMM
+ && desc->bInterfaceSubClass == 2
+ && desc->bInterfaceProtocol == 0xff;
+}
+
+static int is_activesync(struct usb_interface_descriptor *desc)
+{
+ return desc->bInterfaceClass == USB_CLASS_MISC
+ && desc->bInterfaceSubClass == 1
+ && desc->bInterfaceProtocol == 1;
+}
+
static int choose_configuration(struct usb_device *udev)
{
int i;
@@ -87,14 +101,12 @@ static int choose_configuration(struct usb_device *udev)
continue;
}
- /* If the first config's first interface is COMM/2/0xff
- * (MSFT RNDIS), rule it out unless Linux has host-side
- * RNDIS support. */
- if (i == 0 && desc
- && desc->bInterfaceClass == USB_CLASS_COMM
- && desc->bInterfaceSubClass == 2
- && desc->bInterfaceProtocol == 0xff) {
-#ifndef CONFIG_USB_NET_RNDIS_HOST
+ /* When the first config's first interface is one of Microsoft's
+ * pet nonstandard Ethernet-over-USB protocols, ignore it unless
+ * this kernel has enabled the necessary host side driver.
+ */
+ if (i == 0 && desc && (is_rndis(desc) || is_activesync(desc))) {
+#if !defined(CONFIG_USB_NET_RNDIS_HOST) && !defined(CONFIG_USB_NET_RNDIS_HOST_MODULE)
continue;
#else
best = c;
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 10064af65d1..b26c19e8d19 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -45,8 +45,6 @@
#include "hub.h"
-// #define USB_BANDWIDTH_MESSAGES
-
/*-------------------------------------------------------------------------*/
/*
@@ -891,136 +889,6 @@ long usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount)
}
EXPORT_SYMBOL (usb_calc_bus_time);
-/*
- * usb_check_bandwidth():
- *
- * old_alloc is from host_controller->bandwidth_allocated in microseconds;
- * bustime is from calc_bus_time(), but converted to microseconds.
- *
- * returns <bustime in us> if successful,
- * or -ENOSPC if bandwidth request fails.
- *
- * FIXME:
- * This initial implementation does not use Endpoint.bInterval
- * in managing bandwidth allocation.
- * It probably needs to be expanded to use Endpoint.bInterval.
- * This can be done as a later enhancement (correction).
- *
- * This will also probably require some kind of
- * frame allocation tracking...meaning, for example,
- * that if multiple drivers request interrupts every 10 USB frames,
- * they don't all have to be allocated at
- * frame numbers N, N+10, N+20, etc. Some of them could be at
- * N+11, N+21, N+31, etc., and others at
- * N+12, N+22, N+32, etc.
- *
- * Similarly for isochronous transfers...
- *
- * Individual HCDs can schedule more directly ... this logic
- * is not correct for high speed transfers.
- */
-int usb_check_bandwidth (struct usb_device *dev, struct urb *urb)
-{
- unsigned int pipe = urb->pipe;
- long bustime;
- int is_in = usb_pipein (pipe);
- int is_iso = usb_pipeisoc (pipe);
- int old_alloc = dev->bus->bandwidth_allocated;
- int new_alloc;
-
-
- bustime = NS_TO_US (usb_calc_bus_time (dev->speed, is_in, is_iso,
- usb_maxpacket (dev, pipe, !is_in)));
- if (is_iso)
- bustime /= urb->number_of_packets;
-
- new_alloc = old_alloc + (int) bustime;
- if (new_alloc > FRAME_TIME_MAX_USECS_ALLOC) {
-#ifdef DEBUG
- char *mode =
-#ifdef CONFIG_USB_BANDWIDTH
- "";
-#else
- "would have ";
-#endif
- dev_dbg (&dev->dev, "usb_check_bandwidth %sFAILED: %d + %ld = %d usec\n",
- mode, old_alloc, bustime, new_alloc);
-#endif
-#ifdef CONFIG_USB_BANDWIDTH
- bustime = -ENOSPC; /* report error */
-#endif
- }
-
- return bustime;
-}
-EXPORT_SYMBOL (usb_check_bandwidth);
-
-
-/**
- * usb_claim_bandwidth - records bandwidth for a periodic transfer
- * @dev: source/target of request
- * @urb: request (urb->dev == dev)
- * @bustime: bandwidth consumed, in (average) microseconds per frame
- * @isoc: true iff the request is isochronous
- *
- * Bus bandwidth reservations are recorded purely for diagnostic purposes.
- * HCDs are expected not to overcommit periodic bandwidth, and to record such
- * reservations whenever endpoints are added to the periodic schedule.
- *
- * FIXME averaging per-frame is suboptimal. Better to sum over the HCD's
- * entire periodic schedule ... 32 frames for OHCI, 1024 for UHCI, settable
- * for EHCI (256/512/1024 frames, default 1024) and have the bus expose how
- * large its periodic schedule is.
- */
-void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, int bustime, int isoc)
-{
- dev->bus->bandwidth_allocated += bustime;
- if (isoc)
- dev->bus->bandwidth_isoc_reqs++;
- else
- dev->bus->bandwidth_int_reqs++;
- urb->bandwidth = bustime;
-
-#ifdef USB_BANDWIDTH_MESSAGES
- dev_dbg (&dev->dev, "bandwidth alloc increased by %d (%s) to %d for %d requesters\n",
- bustime,
- isoc ? "ISOC" : "INTR",
- dev->bus->bandwidth_allocated,
- dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);
-#endif
-}
-EXPORT_SYMBOL (usb_claim_bandwidth);
-
-
-/**
- * usb_release_bandwidth - reverses effect of usb_claim_bandwidth()
- * @dev: source/target of request
- * @urb: request (urb->dev == dev)
- * @isoc: true iff the request is isochronous
- *
- * This records that previously allocated bandwidth has been released.
- * Bandwidth is released when endpoints are removed from the host controller's
- * periodic schedule.
- */
-void usb_release_bandwidth (struct usb_device *dev, struct urb *urb, int isoc)
-{
- dev->bus->bandwidth_allocated -= urb->bandwidth;
- if (isoc)
- dev->bus->bandwidth_isoc_reqs--;
- else
- dev->bus->bandwidth_int_reqs--;
-
-#ifdef USB_BANDWIDTH_MESSAGES
- dev_dbg (&dev->dev, "bandwidth alloc reduced by %d (%s) to %d for %d requesters\n",
- urb->bandwidth,
- isoc ? "ISOC" : "INTR",
- dev->bus->bandwidth_allocated,
- dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);
-#endif
- urb->bandwidth = 0;
-}
-EXPORT_SYMBOL (usb_release_bandwidth);
-
/*-------------------------------------------------------------------------*/
@@ -1034,11 +902,6 @@ static void urb_unlink (struct urb *urb)
{
unsigned long flags;
- /* Release any periodic transfer bandwidth */
- if (urb->bandwidth)
- usb_release_bandwidth (urb->dev, urb,
- usb_pipeisoc (urb->pipe));
-
/* clear all state linking urb to this dev (and hcd) */
spin_lock_irqsave (&hcd_data_lock, flags);
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index 8f8df0d4382..2a269ca2051 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -308,10 +308,6 @@ extern void usb_destroy_configuration(struct usb_device *dev);
#define NS_TO_US(ns) ((ns + 500L) / 1000L)
/* convert & round nanoseconds to microseconds */
-extern void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb,
- int bustime, int isoc);
-extern void usb_release_bandwidth (struct usb_device *dev, struct urb *urb,
- int isoc);
/*
* Full/low speed bandwidth allocation constants/support.
@@ -324,8 +320,6 @@ extern void usb_release_bandwidth (struct usb_device *dev, struct urb *urb,
#define FRAME_TIME_MAX_BITS_ALLOC (90L * FRAME_TIME_BITS / 100L)
#define FRAME_TIME_MAX_USECS_ALLOC (90L * FRAME_TIME_USECS / 100L)
-extern int usb_check_bandwidth (struct usb_device *dev, struct urb *urb);
-
/*
* Ceiling [nano/micro]seconds (typical) for that many bytes at high speed
* ISO is a bit less, no ACK ... from USB 2.0 spec, 5.11.3 (and needed
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 1988224b362..590ec82d051 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -87,9 +87,6 @@ static DECLARE_WAIT_QUEUE_HEAD(khubd_wait);
static struct task_struct *khubd_task;
-/* multithreaded probe logic */
-static int multithread_probe = 0;
-
/* cycle leds on hubs that aren't blinking for attention */
static int blinkenlights = 0;
module_param (blinkenlights, bool, S_IRUGO);
@@ -1256,9 +1253,28 @@ static inline void show_string(struct usb_device *udev, char *id, char *string)
static int __usb_port_suspend(struct usb_device *, int port1);
#endif
-static int __usb_new_device(void *void_data)
+/**
+ * usb_new_device - perform initial device setup (usbcore-internal)
+ * @udev: newly addressed device (in ADDRESS state)
+ *
+ * This is called with devices which have been enumerated, but not yet
+ * configured. The device descriptor is available, but not descriptors
+ * for any device configuration. The caller must have locked either
+ * the parent hub (if udev is a normal device) or else the
+ * usb_bus_list_lock (if udev is a root hub). The parent's pointer to
+ * udev has already been installed, but udev is not yet visible through
+ * sysfs or other filesystem code.
+ *
+ * It will return if the device is configured properly or not. Zero if
+ * the interface was registered with the driver core; else a negative
+ * errno value.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ *
+ * Only the hub driver or root-hub registrar should ever call this.
+ */
+int usb_new_device(struct usb_device *udev)
{
- struct usb_device *udev = void_data;
int err;
/* Lock ourself into memory in order to keep a probe sequence
@@ -1375,44 +1391,6 @@ fail:
goto exit;
}
-/**
- * usb_new_device - perform initial device setup (usbcore-internal)
- * @udev: newly addressed device (in ADDRESS state)
- *
- * This is called with devices which have been enumerated, but not yet
- * configured. The device descriptor is available, but not descriptors
- * for any device configuration. The caller must have locked either
- * the parent hub (if udev is a normal device) or else the
- * usb_bus_list_lock (if udev is a root hub). The parent's pointer to
- * udev has already been installed, but udev is not yet visible through
- * sysfs or other filesystem code.
- *
- * The return value for this function depends on if the
- * multithread_probe variable is set or not. If it's set, it will
- * return a if the probe thread was successfully created or not. If the
- * variable is not set, it will return if the device is configured
- * properly or not. interfaces, in sysfs); else a negative errno value.
- *
- * This call is synchronous, and may not be used in an interrupt context.
- *
- * Only the hub driver or root-hub registrar should ever call this.
- */
-int usb_new_device(struct usb_device *udev)
-{
- struct task_struct *probe_task;
- int ret = 0;
-
- if (multithread_probe) {
- probe_task = kthread_run(__usb_new_device, udev,
- "usb-probe-%s", udev->devnum);
- if (IS_ERR(probe_task))
- ret = PTR_ERR(probe_task);
- } else
- ret = __usb_new_device(udev);
-
- return ret;
-}
-
static int hub_port_status(struct usb_hub *hub, int port1,
u16 *status, u16 *change)
{
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 149aa8bfb1f..8aca3574c2b 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -1545,11 +1545,7 @@ int usb_driver_set_configuration(struct usb_device *udev, int config)
INIT_WORK(&req->work, driver_set_config_work);
usb_get_dev(udev);
- if (!schedule_work(&req->work)) {
- usb_put_dev(udev);
- kfree(req);
- return -EINVAL;
- }
+ schedule_work(&req->work);
return 0;
}
EXPORT_SYMBOL_GPL(usb_driver_set_configuration);
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 55d8f575206..4eaa0ee8e72 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -16,16 +16,16 @@
/* Active configuration fields */
#define usb_actconfig_show(field, multiplier, format_string) \
-static ssize_t show_##field (struct device *dev, \
+static ssize_t show_##field(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
struct usb_device *udev; \
struct usb_host_config *actconfig; \
\
- udev = to_usb_device (dev); \
+ udev = to_usb_device(dev); \
actconfig = udev->actconfig; \
if (actconfig) \
- return sprintf (buf, format_string, \
+ return sprintf(buf, format_string, \
actconfig->desc.field * multiplier); \
else \
return 0; \
@@ -35,9 +35,9 @@ static ssize_t show_##field (struct device *dev, \
usb_actconfig_show(field, multiplier, format_string) \
static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
-usb_actconfig_attr (bNumInterfaces, 1, "%2d\n")
-usb_actconfig_attr (bmAttributes, 1, "%2x\n")
-usb_actconfig_attr (bMaxPower, 2, "%3dmA\n")
+usb_actconfig_attr(bNumInterfaces, 1, "%2d\n")
+usb_actconfig_attr(bmAttributes, 1, "%2x\n")
+usb_actconfig_attr(bMaxPower, 2, "%3dmA\n")
static ssize_t show_configuration_string(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -45,7 +45,7 @@ static ssize_t show_configuration_string(struct device *dev,
struct usb_device *udev;
struct usb_host_config *actconfig;
- udev = to_usb_device (dev);
+ udev = to_usb_device(dev);
actconfig = udev->actconfig;
if ((!actconfig) || (!actconfig->string))
return 0;
@@ -57,16 +57,16 @@ static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL);
usb_actconfig_show(bConfigurationValue, 1, "%u\n");
static ssize_t
-set_bConfigurationValue (struct device *dev, struct device_attribute *attr,
+set_bConfigurationValue(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct usb_device *udev = to_usb_device (dev);
+ struct usb_device *udev = to_usb_device(dev);
int config, value;
- if (sscanf (buf, "%u", &config) != 1 || config > 255)
+ if (sscanf(buf, "%u", &config) != 1 || config > 255)
return -EINVAL;
usb_lock_device(udev);
- value = usb_set_configuration (udev, config);
+ value = usb_set_configuration(udev, config);
usb_unlock_device(udev);
return (value < 0) ? value : count;
}
@@ -81,7 +81,7 @@ static ssize_t show_##name(struct device *dev, \
{ \
struct usb_device *udev; \
\
- udev = to_usb_device (dev); \
+ udev = to_usb_device(dev); \
return sprintf(buf, "%s\n", udev->name); \
} \
static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
@@ -91,12 +91,12 @@ usb_string_attr(manufacturer);
usb_string_attr(serial);
static ssize_t
-show_speed (struct device *dev, struct device_attribute *attr, char *buf)
+show_speed(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_device *udev;
char *speed;
- udev = to_usb_device (dev);
+ udev = to_usb_device(dev);
switch (udev->speed) {
case USB_SPEED_LOW:
@@ -112,22 +112,22 @@ show_speed (struct device *dev, struct device_attribute *attr, char *buf)
default:
speed = "unknown";
}
- return sprintf (buf, "%s\n", speed);
+ return sprintf(buf, "%s\n", speed);
}
static DEVICE_ATTR(speed, S_IRUGO, show_speed, NULL);
static ssize_t
-show_devnum (struct device *dev, struct device_attribute *attr, char *buf)
+show_devnum(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_device *udev;
- udev = to_usb_device (dev);
- return sprintf (buf, "%d\n", udev->devnum);
+ udev = to_usb_device(dev);
+ return sprintf(buf, "%d\n", udev->devnum);
}
static DEVICE_ATTR(devnum, S_IRUGO, show_devnum, NULL);
static ssize_t
-show_version (struct device *dev, struct device_attribute *attr, char *buf)
+show_version(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_device *udev;
u16 bcdUSB;
@@ -139,25 +139,25 @@ show_version (struct device *dev, struct device_attribute *attr, char *buf)
static DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
static ssize_t
-show_maxchild (struct device *dev, struct device_attribute *attr, char *buf)
+show_maxchild(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_device *udev;
- udev = to_usb_device (dev);
- return sprintf (buf, "%d\n", udev->maxchild);
+ udev = to_usb_device(dev);
+ return sprintf(buf, "%d\n", udev->maxchild);
}
static DEVICE_ATTR(maxchild, S_IRUGO, show_maxchild, NULL);
/* Descriptor fields */
#define usb_descriptor_attr_le16(field, format_string) \
static ssize_t \
-show_##field (struct device *dev, struct device_attribute *attr, \
+show_##field(struct device *dev, struct device_attribute *attr, \
char *buf) \
{ \
struct usb_device *udev; \
\
- udev = to_usb_device (dev); \
- return sprintf (buf, format_string, \
+ udev = to_usb_device(dev); \
+ return sprintf(buf, format_string, \
le16_to_cpu(udev->descriptor.field)); \
} \
static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
@@ -168,21 +168,21 @@ usb_descriptor_attr_le16(bcdDevice, "%04x\n")
#define usb_descriptor_attr(field, format_string) \
static ssize_t \
-show_##field (struct device *dev, struct device_attribute *attr, \
+show_##field(struct device *dev, struct device_attribute *attr, \
char *buf) \
{ \
struct usb_device *udev; \
\
- udev = to_usb_device (dev); \
- return sprintf (buf, format_string, udev->descriptor.field); \
+ udev = to_usb_device(dev); \
+ return sprintf(buf, format_string, udev->descriptor.field); \
} \
static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
-usb_descriptor_attr (bDeviceClass, "%02x\n")
-usb_descriptor_attr (bDeviceSubClass, "%02x\n")
-usb_descriptor_attr (bDeviceProtocol, "%02x\n")
-usb_descriptor_attr (bNumConfigurations, "%d\n")
-usb_descriptor_attr (bMaxPacketSize0, "%d\n")
+usb_descriptor_attr(bDeviceClass, "%02x\n")
+usb_descriptor_attr(bDeviceSubClass, "%02x\n")
+usb_descriptor_attr(bDeviceProtocol, "%02x\n")
+usb_descriptor_attr(bNumConfigurations, "%d\n")
+usb_descriptor_attr(bMaxPacketSize0, "%d\n")
static struct attribute *dev_attrs[] = {
/* current configuration's attributes */
@@ -220,17 +220,17 @@ int usb_create_sysfs_dev_files(struct usb_device *udev)
return retval;
if (udev->manufacturer) {
- retval = device_create_file (dev, &dev_attr_manufacturer);
+ retval = device_create_file(dev, &dev_attr_manufacturer);
if (retval)
goto error;
}
if (udev->product) {
- retval = device_create_file (dev, &dev_attr_product);
+ retval = device_create_file(dev, &dev_attr_product);
if (retval)
goto error;
}
if (udev->serial) {
- retval = device_create_file (dev, &dev_attr_serial);
+ retval = device_create_file(dev, &dev_attr_serial);
if (retval)
goto error;
}
@@ -246,7 +246,7 @@ error:
return retval;
}
-void usb_remove_sysfs_dev_files (struct usb_device *udev)
+void usb_remove_sysfs_dev_files(struct usb_device *udev)
{
struct device *dev = &udev->dev;
@@ -264,22 +264,22 @@ void usb_remove_sysfs_dev_files (struct usb_device *udev)
/* Interface fields */
#define usb_intf_attr(field, format_string) \
static ssize_t \
-show_##field (struct device *dev, struct device_attribute *attr, \
+show_##field(struct device *dev, struct device_attribute *attr, \
char *buf) \
{ \
- struct usb_interface *intf = to_usb_interface (dev); \
+ struct usb_interface *intf = to_usb_interface(dev); \
\
- return sprintf (buf, format_string, \
+ return sprintf(buf, format_string, \
intf->cur_altsetting->desc.field); \
} \
static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
-usb_intf_attr (bInterfaceNumber, "%02x\n")
-usb_intf_attr (bAlternateSetting, "%2d\n")
-usb_intf_attr (bNumEndpoints, "%02x\n")
-usb_intf_attr (bInterfaceClass, "%02x\n")
-usb_intf_attr (bInterfaceSubClass, "%02x\n")
-usb_intf_attr (bInterfaceProtocol, "%02x\n")
+usb_intf_attr(bInterfaceNumber, "%02x\n")
+usb_intf_attr(bAlternateSetting, "%2d\n")
+usb_intf_attr(bNumEndpoints, "%02x\n")
+usb_intf_attr(bInterfaceClass, "%02x\n")
+usb_intf_attr(bInterfaceSubClass, "%02x\n")
+usb_intf_attr(bInterfaceProtocol, "%02x\n")
static ssize_t show_interface_string(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -288,8 +288,8 @@ static ssize_t show_interface_string(struct device *dev,
struct usb_device *udev;
int len;
- intf = to_usb_interface (dev);
- udev = interface_to_usbdev (intf);
+ intf = to_usb_interface(dev);
+ udev = interface_to_usbdev(intf);
len = snprintf(buf, 256, "%s", intf->cur_altsetting->string);
if (len < 0)
return 0;
@@ -384,7 +384,7 @@ error:
return retval;
}
-void usb_remove_sysfs_intf_files (struct usb_interface *intf)
+void usb_remove_sysfs_intf_files(struct usb_interface *intf)
{
usb_remove_intf_ep_files(intf);
sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp);
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index 9801d08edac..94ea9727ff5 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -235,16 +235,15 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
urb->status = -EINPROGRESS;
urb->actual_length = 0;
- urb->bandwidth = 0;
/* Lots of sanity checks, so HCDs can rely on clean data
* and don't need to duplicate tests
*/
pipe = urb->pipe;
- temp = usb_pipetype (pipe);
- is_out = usb_pipeout (pipe);
+ temp = usb_pipetype(pipe);
+ is_out = usb_pipeout(pipe);
- if (!usb_pipecontrol (pipe) && dev->state < USB_STATE_CONFIGURED)
+ if (!usb_pipecontrol(pipe) && dev->state < USB_STATE_CONFIGURED)
return -ENODEV;
/* FIXME there should be a sharable lock protecting us against
@@ -253,11 +252,11 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
* checks get made.)
*/
- max = usb_maxpacket (dev, pipe, is_out);
+ max = usb_maxpacket(dev, pipe, is_out);
if (max <= 0) {
dev_dbg(&dev->dev,
"bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",
- usb_pipeendpoint (pipe), is_out ? "out" : "in",
+ usb_pipeendpoint(pipe), is_out ? "out" : "in",
__FUNCTION__, max);
return -EMSGSIZE;
}
@@ -279,11 +278,11 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
if (urb->number_of_packets <= 0)
return -EINVAL;
for (n = 0; n < urb->number_of_packets; n++) {
- len = urb->iso_frame_desc [n].length;
+ len = urb->iso_frame_desc[n].length;
if (len < 0 || len > max)
return -EMSGSIZE;
- urb->iso_frame_desc [n].status = -EXDEV;
- urb->iso_frame_desc [n].actual_length = 0;
+ urb->iso_frame_desc[n].status = -EXDEV;
+ urb->iso_frame_desc[n].actual_length = 0;
}
}
@@ -322,7 +321,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
/* fail if submitter gave bogus flags */
if (urb->transfer_flags != orig_flags) {
- err ("BOGUS urb flags, %x --> %x",
+ err("BOGUS urb flags, %x --> %x",
orig_flags, urb->transfer_flags);
return -EINVAL;
}
@@ -373,7 +372,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
urb->interval = temp;
}
- return usb_hcd_submit_urb (urb, mem_flags);
+ return usb_hcd_submit_urb(urb, mem_flags);
}
/*-------------------------------------------------------------------*/
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 02426d0b9a3..3db721cd557 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -233,7 +233,7 @@ static void usb_autosuspend_work(struct work_struct *work)
* @parent: hub to which device is connected; null to allocate a root hub
* @bus: bus used to access the device
* @port1: one-based index of port; ignored for root hubs
- * Context: !in_interrupt ()
+ * Context: !in_interrupt()
*
* Only hub drivers (including virtual root hub drivers for host
* controllers) should ever call this.
@@ -277,22 +277,22 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
* as stable: bus->busnum changes easily from modprobe order,
* cardbus or pci hotplugging, and so on.
*/
- if (unlikely (!parent)) {
- dev->devpath [0] = '0';
+ if (unlikely(!parent)) {
+ dev->devpath[0] = '0';
dev->dev.parent = bus->controller;
- sprintf (&dev->dev.bus_id[0], "usb%d", bus->busnum);
+ sprintf(&dev->dev.bus_id[0], "usb%d", bus->busnum);
} else {
/* match any labeling on the hubs; it's one-based */
- if (parent->devpath [0] == '0')
- snprintf (dev->devpath, sizeof dev->devpath,
+ if (parent->devpath[0] == '0')
+ snprintf(dev->devpath, sizeof dev->devpath,
"%d", port1);
else
- snprintf (dev->devpath, sizeof dev->devpath,
+ snprintf(dev->devpath, sizeof dev->devpath,
"%s.%d", parent->devpath, port1);
dev->dev.parent = &parent->dev;
- sprintf (&dev->dev.bus_id[0], "%d-%s",
+ sprintf(&dev->dev.bus_id[0], "%d-%s",
bus->busnum, dev->devpath);
/* hub driver sets up TT records */
@@ -463,7 +463,7 @@ static struct usb_device *match_device(struct usb_device *dev,
/* see if this device matches */
if ((vendor_id == le16_to_cpu(dev->descriptor.idVendor)) &&
(product_id == le16_to_cpu(dev->descriptor.idProduct))) {
- dev_dbg (&dev->dev, "matched this device!\n");
+ dev_dbg(&dev->dev, "matched this device!\n");
ret_dev = usb_get_dev(dev);
goto exit;
}
@@ -535,7 +535,7 @@ exit:
*/
int usb_get_current_frame_number(struct usb_device *dev)
{
- return usb_hcd_get_frame_number (dev);
+ return usb_hcd_get_frame_number(dev);
}
/*-------------------------------------------------------------------*/
@@ -593,7 +593,7 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size,
*
* When the buffer is no longer used, free it with usb_buffer_free().
*/
-void *usb_buffer_alloc (
+void *usb_buffer_alloc(
struct usb_device *dev,
size_t size,
gfp_t mem_flags,
@@ -602,7 +602,7 @@ void *usb_buffer_alloc (
{
if (!dev || !dev->bus)
return NULL;
- return hcd_buffer_alloc (dev->bus, size, mem_flags, dma);
+ return hcd_buffer_alloc(dev->bus, size, mem_flags, dma);
}
/**
@@ -616,7 +616,7 @@ void *usb_buffer_alloc (
* been allocated using usb_buffer_alloc(), and the parameters must match
* those provided in that allocation request.
*/
-void usb_buffer_free (
+void usb_buffer_free(
struct usb_device *dev,
size_t size,
void *addr,
@@ -627,7 +627,7 @@ void usb_buffer_free (
return;
if (!addr)
return;
- hcd_buffer_free (dev->bus, size, addr, dma);
+ hcd_buffer_free(dev->bus, size, addr, dma);
}
/**
@@ -647,7 +647,7 @@ void usb_buffer_free (
* Reverse the effect of this call with usb_buffer_unmap().
*/
#if 0
-struct urb *usb_buffer_map (struct urb *urb)
+struct urb *usb_buffer_map(struct urb *urb)
{
struct usb_bus *bus;
struct device *controller;
@@ -659,14 +659,14 @@ struct urb *usb_buffer_map (struct urb *urb)
return NULL;
if (controller->dma_mask) {
- urb->transfer_dma = dma_map_single (controller,
+ urb->transfer_dma = dma_map_single(controller,
urb->transfer_buffer, urb->transfer_buffer_length,
- usb_pipein (urb->pipe)
+ usb_pipein(urb->pipe)
? DMA_FROM_DEVICE : DMA_TO_DEVICE);
- if (usb_pipecontrol (urb->pipe))
- urb->setup_dma = dma_map_single (controller,
+ if (usb_pipecontrol(urb->pipe))
+ urb->setup_dma = dma_map_single(controller,
urb->setup_packet,
- sizeof (struct usb_ctrlrequest),
+ sizeof(struct usb_ctrlrequest),
DMA_TO_DEVICE);
// FIXME generic api broken like pci, can't report errors
// if (urb->transfer_dma == DMA_ADDR_INVALID) return 0;
@@ -689,7 +689,7 @@ struct urb *usb_buffer_map (struct urb *urb)
* usb_buffer_dmasync - synchronize DMA and CPU view of buffer(s)
* @urb: urb whose transfer_buffer/setup_packet will be synchronized
*/
-void usb_buffer_dmasync (struct urb *urb)
+void usb_buffer_dmasync(struct urb *urb)
{
struct usb_bus *bus;
struct device *controller;
@@ -702,14 +702,14 @@ void usb_buffer_dmasync (struct urb *urb)
return;
if (controller->dma_mask) {
- dma_sync_single (controller,
+ dma_sync_single(controller,
urb->transfer_dma, urb->transfer_buffer_length,
- usb_pipein (urb->pipe)
+ usb_pipein(urb->pipe)
? DMA_FROM_DEVICE : DMA_TO_DEVICE);
- if (usb_pipecontrol (urb->pipe))
- dma_sync_single (controller,
+ if (usb_pipecontrol(urb->pipe))
+ dma_sync_single(controller,
urb->setup_dma,
- sizeof (struct usb_ctrlrequest),
+ sizeof(struct usb_ctrlrequest),
DMA_TO_DEVICE);
}
}
@@ -722,7 +722,7 @@ void usb_buffer_dmasync (struct urb *urb)
* Reverses the effect of usb_buffer_map().
*/
#if 0
-void usb_buffer_unmap (struct urb *urb)
+void usb_buffer_unmap(struct urb *urb)
{
struct usb_bus *bus;
struct device *controller;
@@ -735,14 +735,14 @@ void usb_buffer_unmap (struct urb *urb)
return;
if (controller->dma_mask) {
- dma_unmap_single (controller,
+ dma_unmap_single(controller,
urb->transfer_dma, urb->transfer_buffer_length,
- usb_pipein (urb->pipe)
+ usb_pipein(urb->pipe)
? DMA_FROM_DEVICE : DMA_TO_DEVICE);
- if (usb_pipecontrol (urb->pipe))
- dma_unmap_single (controller,
+ if (usb_pipecontrol(urb->pipe))
+ dma_unmap_single(controller,
urb->setup_dma,
- sizeof (struct usb_ctrlrequest),
+ sizeof(struct usb_ctrlrequest),
DMA_TO_DEVICE);
}
urb->transfer_flags &= ~(URB_NO_TRANSFER_DMA_MAP
@@ -783,15 +783,15 @@ int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
struct device *controller;
if (!dev
- || usb_pipecontrol (pipe)
+ || usb_pipecontrol(pipe)
|| !(bus = dev->bus)
|| !(controller = bus->controller)
|| !controller->dma_mask)
return -1;
// FIXME generic api broken like pci, can't report errors
- return dma_map_sg (controller, sg, nents,
- usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ return dma_map_sg(controller, sg, nents,
+ usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
/* XXX DISABLED, no users currently. If you wish to re-enable this
@@ -823,8 +823,8 @@ void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe,
|| !controller->dma_mask)
return;
- dma_sync_sg (controller, sg, n_hw_ents,
- usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ dma_sync_sg(controller, sg, n_hw_ents,
+ usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
#endif
@@ -849,8 +849,8 @@ void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe,
|| !controller->dma_mask)
return;
- dma_unmap_sg (controller, sg, n_hw_ents,
- usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ dma_unmap_sg(controller, sg, n_hw_ents,
+ usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
/* format to disable USB on kernel command line is: nousb */
@@ -871,7 +871,7 @@ static int __init usb_init(void)
{
int retval;
if (nousb) {
- pr_info ("%s: USB support disabled\n", usbcore_name);
+ pr_info("%s: USB support disabled\n", usbcore_name);
return 0;
}
@@ -971,19 +971,19 @@ EXPORT_SYMBOL(__usb_get_extra_descriptor);
EXPORT_SYMBOL(usb_find_device);
EXPORT_SYMBOL(usb_get_current_frame_number);
-EXPORT_SYMBOL (usb_buffer_alloc);
-EXPORT_SYMBOL (usb_buffer_free);
+EXPORT_SYMBOL(usb_buffer_alloc);
+EXPORT_SYMBOL(usb_buffer_free);
#if 0
-EXPORT_SYMBOL (usb_buffer_map);
-EXPORT_SYMBOL (usb_buffer_dmasync);
-EXPORT_SYMBOL (usb_buffer_unmap);
+EXPORT_SYMBOL(usb_buffer_map);
+EXPORT_SYMBOL(usb_buffer_dmasync);
+EXPORT_SYMBOL(usb_buffer_unmap);
#endif
-EXPORT_SYMBOL (usb_buffer_map_sg);
+EXPORT_SYMBOL(usb_buffer_map_sg);
#if 0
-EXPORT_SYMBOL (usb_buffer_dmasync_sg);
+EXPORT_SYMBOL(usb_buffer_dmasync_sg);
#endif
-EXPORT_SYMBOL (usb_buffer_unmap_sg);
+EXPORT_SYMBOL(usb_buffer_unmap_sg);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index 812c733ba8c..f39050145f1 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -39,7 +39,7 @@
#include <linux/interrupt.h>
#include <linux/proc_fs.h>
#include <linux/clk.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <asm/byteorder.h>
@@ -1807,16 +1807,13 @@ static int at91udc_suspend(struct platform_device *pdev, pm_message_t mesg)
|| !wake
|| at91_suspend_entering_slow_clock()) {
pullup(udc, 0);
- disable_irq_wake(udc->udp_irq);
+ wake = 0;
} 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);
- }
+ udc->active_suspend = wake;
+ if (udc->board.vbus_pin > 0 && wake)
+ enable_irq_wake(udc->board.vbus_pin);
return 0;
}
@@ -1824,8 +1821,14 @@ static int at91udc_resume(struct platform_device *pdev)
{
struct at91_udc *udc = platform_get_drvdata(pdev);
+ if (udc->board.vbus_pin > 0 && udc->active_suspend)
+ disable_irq_wake(udc->board.vbus_pin);
+
/* maybe reconnect to host; if so, clocks on */
- pullup(udc, 1);
+ if (udc->active_suspend)
+ disable_irq_wake(udc->udp_irq);
+ else
+ pullup(udc, 1);
return 0;
}
#else
diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h
index 677089baa59..7e34e2f864f 100644
--- a/drivers/usb/gadget/at91_udc.h
+++ b/drivers/usb/gadget/at91_udc.h
@@ -136,6 +136,7 @@ struct at91_udc {
unsigned wait_for_addr_ack:1;
unsigned wait_for_config_ack:1;
unsigned selfpowered:1;
+ unsigned active_suspend:1;
u8 addr;
struct at91_udc_data board;
struct clk *iclk, *fclk;
diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c
index 83b4866df9a..d18901b92cd 100644
--- a/drivers/usb/gadget/config.c
+++ b/drivers/usb/gadget/config.c
@@ -24,7 +24,7 @@
#include <linux/string.h>
#include <linux/device.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index 53d584589c2..f28af06905a 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -27,7 +27,7 @@
#include <linux/ctype.h>
#include <linux/string.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include "gadget_chips.h"
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index d15bf22b9a0..22e3c944364 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -47,7 +47,7 @@
#include <asm/uaccess.h>
#include <asm/unaligned.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb/cdc.h>
#include <linux/usb_gadget.h>
@@ -72,9 +72,18 @@
*
* There's some hardware that can't talk CDC. We make that hardware
* implement a "minimalist" vendor-agnostic CDC core: same framing, but
- * link-level setup only requires activating the configuration.
- * Linux supports it, but other host operating systems may not.
- * (This is a subset of CDC Ethernet.)
+ * link-level setup only requires activating the configuration. Only the
+ * endpoint descriptors, and product/vendor IDs, are relevant; no control
+ * operations are available. Linux supports it, but other host operating
+ * systems may not. (This is a subset of CDC Ethernet.)
+ *
+ * It turns out that if you add a few descriptors to that "CDC Subset",
+ * (Windows) host side drivers from MCCI can treat it as one submode of
+ * a proprietary scheme called "SAFE" ... without needing to know about
+ * specific product/vendor IDs. So we do that, making it easier to use
+ * those MS-Windows drivers. Those added descriptors make it resemble a
+ * CDC MDLM device, but they don't change device behavior at all. (See
+ * MCCI Engineering report 950198 "SAFE Networking Functions".)
*
* A third option is also in use. Rather than CDC Ethernet, or something
* simpler, Microsoft pushes their own approach: RNDIS. The published
@@ -254,6 +263,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
#define DEV_CONFIG_CDC
#endif
+#ifdef CONFIG_USB_GADGET_S3C2410
+#define DEV_CONFIG_CDC
+#endif
+
#ifdef CONFIG_USB_GADGET_AT91
#define DEV_CONFIG_CDC
#endif
@@ -266,6 +279,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
#define DEV_CONFIG_CDC
#endif
+#ifdef CONFIG_USB_GADGET_HUSB2DEV
+#define DEV_CONFIG_CDC
+#endif
+
/* For CDC-incapable hardware, choose the simple cdc subset.
* Anything that talks bulk (without notable bugs) can do this.
@@ -283,9 +300,6 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
#define DEV_CONFIG_SUBSET
#endif
-#ifdef CONFIG_USB_GADGET_S3C2410
-#define DEV_CONFIG_CDC
-#endif
/*-------------------------------------------------------------------------*/
@@ -487,8 +501,17 @@ rndis_config = {
* endpoint. Both have a "data" interface and two bulk endpoints.
* There are also differences in how control requests are handled.
*
- * RNDIS shares a lot with CDC-Ethernet, since it's a variant of
- * the CDC-ACM (modem) spec.
+ * RNDIS shares a lot with CDC-Ethernet, since it's a variant of the
+ * CDC-ACM (modem) spec. Unfortunately MSFT's RNDIS driver is buggy; it
+ * may hang or oops. Since bugfixes (or accurate specs, letting Linux
+ * work around those bugs) are unlikely to ever come from MSFT, you may
+ * wish to avoid using RNDIS.
+ *
+ * MCCI offers an alternative to RNDIS if you need to connect to Windows
+ * but have hardware that can't support CDC Ethernet. We add descriptors
+ * to present the CDC Subset as a (nonconformant) CDC MDLM variant called
+ * "SAFE". That borrows from both CDC Ethernet and CDC MDLM. You can
+ * get those drivers from MCCI, or bundled with various products.
*/
#ifdef DEV_CONFIG_CDC
@@ -522,8 +545,6 @@ rndis_control_intf = {
};
#endif
-#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
-
static const struct usb_cdc_header_desc header_desc = {
.bLength = sizeof header_desc,
.bDescriptorType = USB_DT_CS_INTERFACE,
@@ -532,6 +553,8 @@ static const struct usb_cdc_header_desc header_desc = {
.bcdCDC = __constant_cpu_to_le16 (0x0110),
};
+#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
+
static const struct usb_cdc_union_desc union_desc = {
.bLength = sizeof union_desc,
.bDescriptorType = USB_DT_CS_INTERFACE,
@@ -564,7 +587,40 @@ static const struct usb_cdc_acm_descriptor acm_descriptor = {
#endif
-#ifdef DEV_CONFIG_CDC
+#ifndef DEV_CONFIG_CDC
+
+/* "SAFE" loosely follows CDC WMC MDLM, violating the spec in various
+ * ways: data endpoints live in the control interface, there's no data
+ * interface, and it's not used to talk to a cell phone radio.
+ */
+
+static const struct usb_cdc_mdlm_desc mdlm_desc = {
+ .bLength = sizeof mdlm_desc,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubType = USB_CDC_MDLM_TYPE,
+
+ .bcdVersion = __constant_cpu_to_le16(0x0100),
+ .bGUID = {
+ 0x5d, 0x34, 0xcf, 0x66, 0x11, 0x18, 0x11, 0xd6,
+ 0xa2, 0x1a, 0x00, 0x01, 0x02, 0xca, 0x9a, 0x7f,
+ },
+};
+
+/* since "usb_cdc_mdlm_detail_desc" is a variable length structure, we
+ * can't really use its struct. All we do here is say that we're using
+ * the submode of "SAFE" which directly matches the CDC Subset.
+ */
+static const u8 mdlm_detail_desc[] = {
+ 6,
+ USB_DT_CS_INTERFACE,
+ USB_CDC_MDLM_DETAIL_TYPE,
+
+ 0, /* "SAFE" */
+ 0, /* network control capabilities (none) */
+ 0, /* network data capabilities ("raw" encapsulation) */
+};
+
+#endif
static const struct usb_cdc_ether_desc ether_desc = {
.bLength = sizeof ether_desc,
@@ -579,7 +635,6 @@ static const struct usb_cdc_ether_desc ether_desc = {
.bNumberPowerFilters = 0,
};
-#endif
#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
@@ -672,6 +727,9 @@ rndis_data_intf = {
/*
* "Simple" CDC-subset option is a simple vendor-neutral model that most
* full speed controllers can handle: one interface, two bulk endpoints.
+ *
+ * To assist host side drivers, we fancy it up a bit, and add descriptors
+ * so some host side drivers will understand it as a "SAFE" variant.
*/
static const struct usb_interface_descriptor
@@ -682,8 +740,8 @@ subset_data_intf = {
.bInterfaceNumber = 0,
.bAlternateSetting = 0,
.bNumEndpoints = 2,
- .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
- .bInterfaceSubClass = 0,
+ .bInterfaceClass = USB_CLASS_COMM,
+ .bInterfaceSubClass = USB_CDC_SUBCLASS_MDLM,
.bInterfaceProtocol = 0,
.iInterface = STRING_DATA,
};
@@ -731,10 +789,15 @@ static const struct usb_descriptor_header *fs_eth_function [11] = {
static inline void __init fs_subset_descriptors(void)
{
#ifdef DEV_CONFIG_SUBSET
+ /* behavior is "CDC Subset"; extra descriptors say "SAFE" */
fs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf;
- fs_eth_function[2] = (struct usb_descriptor_header *) &fs_source_desc;
- fs_eth_function[3] = (struct usb_descriptor_header *) &fs_sink_desc;
- fs_eth_function[4] = NULL;
+ fs_eth_function[2] = (struct usb_descriptor_header *) &header_desc;
+ fs_eth_function[3] = (struct usb_descriptor_header *) &mdlm_desc;
+ fs_eth_function[4] = (struct usb_descriptor_header *) &mdlm_detail_desc;
+ fs_eth_function[5] = (struct usb_descriptor_header *) &ether_desc;
+ fs_eth_function[6] = (struct usb_descriptor_header *) &fs_source_desc;
+ fs_eth_function[7] = (struct usb_descriptor_header *) &fs_sink_desc;
+ fs_eth_function[8] = NULL;
#else
fs_eth_function[1] = NULL;
#endif
@@ -828,10 +891,15 @@ static const struct usb_descriptor_header *hs_eth_function [11] = {
static inline void __init hs_subset_descriptors(void)
{
#ifdef DEV_CONFIG_SUBSET
+ /* behavior is "CDC Subset"; extra descriptors say "SAFE" */
hs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf;
- hs_eth_function[2] = (struct usb_descriptor_header *) &fs_source_desc;
- hs_eth_function[3] = (struct usb_descriptor_header *) &fs_sink_desc;
- hs_eth_function[4] = NULL;
+ hs_eth_function[2] = (struct usb_descriptor_header *) &header_desc;
+ hs_eth_function[3] = (struct usb_descriptor_header *) &mdlm_desc;
+ hs_eth_function[4] = (struct usb_descriptor_header *) &mdlm_detail_desc;
+ hs_eth_function[5] = (struct usb_descriptor_header *) &ether_desc;
+ hs_eth_function[6] = (struct usb_descriptor_header *) &hs_source_desc;
+ hs_eth_function[7] = (struct usb_descriptor_header *) &hs_sink_desc;
+ hs_eth_function[8] = NULL;
#else
hs_eth_function[1] = NULL;
#endif
@@ -878,10 +946,8 @@ static char manufacturer [50];
static char product_desc [40] = DRIVER_DESC;
static char serial_number [20];
-#ifdef DEV_CONFIG_CDC
/* address that the host will use ... usually assigned at random */
static char ethaddr [2 * ETH_ALEN + 1];
-#endif
/* static strings, in UTF-8 */
static struct usb_string strings [] = {
@@ -889,9 +955,9 @@ static struct usb_string strings [] = {
{ STRING_PRODUCT, product_desc, },
{ STRING_SERIALNUMBER, serial_number, },
{ STRING_DATA, "Ethernet Data", },
+ { STRING_ETHADDR, ethaddr, },
#ifdef DEV_CONFIG_CDC
{ STRING_CDC, "CDC Ethernet", },
- { STRING_ETHADDR, ethaddr, },
{ STRING_CONTROL, "CDC Communications Control", },
#endif
#ifdef DEV_CONFIG_SUBSET
@@ -986,10 +1052,10 @@ set_ether_config (struct eth_dev *dev, gfp_t gfp_flags)
}
#endif
- dev->in = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc);
+ dev->in = ep_desc(gadget, &hs_source_desc, &fs_source_desc);
dev->in_ep->driver_data = dev;
- dev->out = ep_desc (dev->gadget, &hs_sink_desc, &fs_sink_desc);
+ dev->out = ep_desc(gadget, &hs_sink_desc, &fs_sink_desc);
dev->out_ep->driver_data = dev;
/* With CDC, the host isn't allowed to use these two data
@@ -2278,10 +2344,10 @@ eth_bind (struct usb_gadget *gadget)
"RNDIS/%s", driver_desc);
/* CDC subset ... recognized by Linux since 2.4.10, but Windows
- * drivers aren't widely available.
+ * drivers aren't widely available. (That may be improved by
+ * supporting one submode of the "SAFE" variant of MDLM.)
*/
} else if (!cdc) {
- device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC;
device_desc.idVendor =
__constant_cpu_to_le16(SIMPLE_VENDOR_NUM);
device_desc.idProduct =
@@ -2352,6 +2418,10 @@ autoconf_fail:
if (!cdc) {
eth_config.bNumInterfaces = 1;
eth_config.iConfiguration = STRING_SUBSET;
+
+ /* use functions to set these up, in case we're built to work
+ * with multiple controllers and must override CDC Ethernet.
+ */
fs_subset_descriptors();
hs_subset_descriptors();
}
@@ -2415,22 +2485,20 @@ autoconf_fail:
/* Module params for these addresses should come from ID proms.
* The host side address is used with CDC and RNDIS, and commonly
- * ends up in a persistent config database.
+ * ends up in a persistent config database. It's not clear if
+ * host side code for the SAFE thing cares -- its original BLAN
+ * thing didn't, Sharp never assigned those addresses on Zaurii.
*/
if (get_ether_addr(dev_addr, net->dev_addr))
dev_warn(&gadget->dev,
"using random %s ethernet address\n", "self");
- if (cdc || rndis) {
- if (get_ether_addr(host_addr, dev->host_mac))
- dev_warn(&gadget->dev,
- "using random %s ethernet address\n", "host");
-#ifdef DEV_CONFIG_CDC
- snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X",
- dev->host_mac [0], dev->host_mac [1],
- dev->host_mac [2], dev->host_mac [3],
- dev->host_mac [4], dev->host_mac [5]);
-#endif
- }
+ if (get_ether_addr(host_addr, dev->host_mac))
+ dev_warn(&gadget->dev,
+ "using random %s ethernet address\n", "host");
+ snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X",
+ dev->host_mac [0], dev->host_mac [1],
+ dev->host_mac [2], dev->host_mac [3],
+ dev->host_mac [4], dev->host_mac [5]);
if (rndis) {
status = rndis_init();
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index 72f2ae96fbf..f04a29a4664 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -253,7 +253,7 @@
#include <linux/freezer.h>
#include <linux/utsname.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include "gadget_chips.h"
@@ -1148,7 +1148,7 @@ static int ep0_queue(struct fsg_dev *fsg)
static void ep0_complete(struct usb_ep *ep, struct usb_request *req)
{
- struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data;
+ struct fsg_dev *fsg = ep->driver_data;
if (req->actual > 0)
dump_msg(fsg, fsg->ep0req_name, req->buf, req->actual);
@@ -1170,8 +1170,8 @@ static void ep0_complete(struct usb_ep *ep, struct usb_request *req)
static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req)
{
- struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data;
- struct fsg_buffhd *bh = (struct fsg_buffhd *) req->context;
+ struct fsg_dev *fsg = ep->driver_data;
+ struct fsg_buffhd *bh = req->context;
if (req->status || req->actual != req->length)
DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__,
@@ -1190,8 +1190,8 @@ static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req)
static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
{
- struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data;
- struct fsg_buffhd *bh = (struct fsg_buffhd *) req->context;
+ struct fsg_dev *fsg = ep->driver_data;
+ struct fsg_buffhd *bh = req->context;
dump_msg(fsg, "bulk-out", req->buf, req->actual);
if (req->status || req->actual != bh->bulk_out_intended_length)
@@ -1214,8 +1214,8 @@ static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
#ifdef CONFIG_USB_FILE_STORAGE_TEST
static void intr_in_complete(struct usb_ep *ep, struct usb_request *req)
{
- struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data;
- struct fsg_buffhd *bh = (struct fsg_buffhd *) req->context;
+ struct fsg_dev *fsg = ep->driver_data;
+ struct fsg_buffhd *bh = req->context;
if (req->status || req->actual != req->length)
DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__,
@@ -2577,7 +2577,7 @@ static int send_status(struct fsg_dev *fsg)
}
if (transport_is_bbb()) {
- struct bulk_cs_wrap *csw = (struct bulk_cs_wrap *) bh->buf;
+ struct bulk_cs_wrap *csw = bh->buf;
/* Store and send the Bulk-only CSW */
csw->Signature = __constant_cpu_to_le32(USB_BULK_CS_SIG);
@@ -2596,8 +2596,7 @@ static int send_status(struct fsg_dev *fsg)
return 0;
} else { // USB_PR_CBI
- struct interrupt_data *buf = (struct interrupt_data *)
- bh->buf;
+ struct interrupt_data *buf = bh->buf;
/* Store and send the Interrupt data. UFI sends the ASC
* and ASCQ bytes. Everything else sends a Type (which
@@ -2982,7 +2981,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
{
struct usb_request *req = bh->outreq;
- struct bulk_cb_wrap *cbw = (struct bulk_cb_wrap *) req->buf;
+ struct bulk_cb_wrap *cbw = req->buf;
/* Was this a real packet? */
if (req->status)
@@ -3428,7 +3427,7 @@ static void handle_exception(struct fsg_dev *fsg)
static int fsg_main_thread(void *fsg_)
{
- struct fsg_dev *fsg = (struct fsg_dev *) fsg_;
+ struct fsg_dev *fsg = fsg_;
/* Allow the thread to be killed by a signal, but set the signal mask
* to block everything but INT, TERM, KILL, and USR1. */
@@ -3600,7 +3599,7 @@ static ssize_t show_ro(struct device *dev, struct device_attribute *attr, char *
static ssize_t show_file(struct device *dev, struct device_attribute *attr, char *buf)
{
struct lun *curlun = dev_to_lun(dev);
- struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev);
+ struct fsg_dev *fsg = dev_get_drvdata(dev);
char *p;
ssize_t rc;
@@ -3629,7 +3628,7 @@ static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const
{
ssize_t rc = count;
struct lun *curlun = dev_to_lun(dev);
- struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev);
+ struct fsg_dev *fsg = dev_get_drvdata(dev);
int i;
if (sscanf(buf, "%d", &i) != 1)
@@ -3652,7 +3651,7 @@ static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const
static ssize_t store_file(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct lun *curlun = dev_to_lun(dev);
- struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev);
+ struct fsg_dev *fsg = dev_get_drvdata(dev);
int rc = 0;
if (curlun->prevent_medium_removal && backing_file_is_open(curlun)) {
@@ -3700,7 +3699,7 @@ static void fsg_release(struct kref *ref)
static void lun_release(struct device *dev)
{
- struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev);
+ struct fsg_dev *fsg = dev_get_drvdata(dev);
kref_put(&fsg->ref, fsg_release);
}
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index aa80f091072..2e3d6620d21 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -75,6 +75,12 @@
#define gadget_is_pxa27x(g) 0
#endif
+#ifdef CONFIG_USB_GADGET_HUSB2DEV
+#define gadget_is_husb2dev(g) !strcmp("husb2_udc", (g)->name)
+#else
+#define gadget_is_husb2dev(g) 0
+#endif
+
#ifdef CONFIG_USB_GADGET_S3C2410
#define gadget_is_s3c2410(g) !strcmp("s3c2410_udc", (g)->name)
#else
@@ -169,5 +175,7 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
return 0x16;
else if (gadget_is_mpc8272(gadget))
return 0x17;
+ else if (gadget_is_husb2dev(gadget))
+ return 0x18;
return -ENOENT;
}
diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c
index f1a679656c9..d08a8d0e642 100644
--- a/drivers/usb/gadget/gmidi.c
+++ b/drivers/usb/gadget/gmidi.c
@@ -35,7 +35,7 @@
#include <sound/initval.h>
#include <sound/rawmidi.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <linux/usb/audio.h>
#include <linux/usb/midi.h>
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index d0ef1d6b3fa..e873cf48824 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -39,7 +39,7 @@
#include <linux/interrupt.h>
#include <linux/proc_fs.h>
#include <linux/device.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <asm/byteorder.h>
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index 3fb1044a4db..34296e79edc 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -20,7 +20,7 @@
*/
-// #define DEBUG /* data to help fault diagnosis */
+// #define DEBUG /* data to help fault diagnosis */
// #define VERBOSE /* extra debug messages (success too) */
#include <linux/init.h>
@@ -59,11 +59,11 @@
* may serve as a source of device events, used to handle all control
* requests other than basic enumeration.
*
- * - Then either immediately, or after a SET_CONFIGURATION control request,
- * ep_config() is called when each /dev/gadget/ep* file is configured
- * (by writing endpoint descriptors). Afterwards these files are used
- * to write() IN data or to read() OUT data. To halt the endpoint, a
- * "wrong direction" request is issued (like reading an IN endpoint).
+ * - Then, after a SET_CONFIGURATION control request, ep_config() is
+ * called when each /dev/gadget/ep* file is configured (by writing
+ * endpoint descriptors). Afterwards these files are used to write()
+ * IN data or to read() OUT data. To halt the endpoint, a "wrong
+ * direction" request is issued (like reading an IN endpoint).
*
* Unlike "usbfs" the only ioctl()s are for things that are rare, and maybe
* not possible on all hardware. For example, precise fault handling with
@@ -98,16 +98,16 @@ enum ep0_state {
* must always write descriptors to initialize the device, then
* the device becomes UNCONNECTED until enumeration.
*/
- STATE_OPENED,
+ STATE_DEV_OPENED,
/* From then on, ep0 fd is in either of two basic modes:
* - (UN)CONNECTED: read usb_gadgetfs_event(s) from it
* - SETUP: read/write will transfer control data and succeed;
* or if "wrong direction", performs protocol stall
*/
- STATE_UNCONNECTED,
- STATE_CONNECTED,
- STATE_SETUP,
+ STATE_DEV_UNCONNECTED,
+ STATE_DEV_CONNECTED,
+ STATE_DEV_SETUP,
/* UNBOUND means the driver closed ep0, so the device won't be
* accessible again (DEV_DISABLED) until all fds are closed.
@@ -121,7 +121,7 @@ enum ep0_state {
struct dev_data {
spinlock_t lock;
atomic_t count;
- enum ep0_state state;
+ enum ep0_state state; /* P: lock */
struct usb_gadgetfs_event event [N_EVENT];
unsigned ev_next;
struct fasync_struct *fasync;
@@ -188,7 +188,6 @@ static struct dev_data *dev_new (void)
enum ep_state {
STATE_EP_DISABLED = 0,
STATE_EP_READY,
- STATE_EP_DEFER_ENABLE,
STATE_EP_ENABLED,
STATE_EP_UNBOUND,
};
@@ -313,18 +312,10 @@ nonblock:
if ((val = down_interruptible (&epdata->lock)) < 0)
return val;
-newstate:
+
switch (epdata->state) {
case STATE_EP_ENABLED:
break;
- case STATE_EP_DEFER_ENABLE:
- DBG (epdata->dev, "%s wait for host\n", epdata->name);
- if ((val = wait_event_interruptible (epdata->wait,
- epdata->state != STATE_EP_DEFER_ENABLE
- || epdata->dev->state == STATE_DEV_UNBOUND
- )) < 0)
- goto fail;
- goto newstate;
// case STATE_EP_DISABLED: /* "can't happen" */
// case STATE_EP_READY: /* "can't happen" */
default: /* error! */
@@ -333,7 +324,6 @@ newstate:
// FALLTHROUGH
case STATE_EP_UNBOUND: /* clean disconnect */
val = -ENODEV;
-fail:
up (&epdata->lock);
}
return val;
@@ -565,29 +555,28 @@ static ssize_t ep_aio_read_retry(struct kiocb *iocb)
ssize_t len, total;
int i;
- /* we "retry" to get the right mm context for this: */
-
- /* copy stuff into user buffers */
- total = priv->actual;
- len = 0;
- for (i=0; i < priv->nr_segs; i++) {
- ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total);
-
- if (copy_to_user(priv->iv[i].iov_base, priv->buf, this)) {
- if (len == 0)
- len = -EFAULT;
- break;
- }
-
- total -= this;
- len += this;
- if (total == 0)
- break;
- }
- kfree(priv->buf);
- kfree(priv);
- aio_put_req(iocb);
- return len;
+ /* we "retry" to get the right mm context for this: */
+
+ /* copy stuff into user buffers */
+ total = priv->actual;
+ len = 0;
+ for (i=0; i < priv->nr_segs; i++) {
+ ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total);
+
+ if (copy_to_user(priv->iv[i].iov_base, priv->buf, this)) {
+ if (len == 0)
+ len = -EFAULT;
+ break;
+ }
+
+ total -= this;
+ len += this;
+ if (total == 0)
+ break;
+ }
+ kfree(priv->buf);
+ kfree(priv);
+ return len;
}
static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
@@ -600,18 +589,17 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
spin_lock(&epdata->dev->lock);
priv->req = NULL;
priv->epdata = NULL;
- if (priv->iv == NULL
- || unlikely(req->actual == 0)
- || unlikely(kiocbIsCancelled(iocb))) {
+
+ /* if this was a write or a read returning no data then we
+ * don't need to copy anything to userspace, so we can
+ * complete the aio request immediately.
+ */
+ if (priv->iv == NULL || unlikely(req->actual == 0)) {
kfree(req->buf);
kfree(priv);
iocb->private = NULL;
/* aio_complete() reports bytes-transferred _and_ faults */
- if (unlikely(kiocbIsCancelled(iocb)))
- aio_put_req(iocb);
- else
- aio_complete(iocb,
- req->actual ? req->actual : req->status,
+ aio_complete(iocb, req->actual ? req->actual : req->status,
req->status);
} else {
/* retry() won't report both; so we hide some faults */
@@ -636,7 +624,7 @@ ep_aio_rwtail(
size_t len,
struct ep_data *epdata,
const struct iovec *iv,
- unsigned long nr_segs
+ unsigned long nr_segs
)
{
struct kiocb_priv *priv;
@@ -852,9 +840,9 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
break;
#endif
default:
- DBG (data->dev, "unconnected, %s init deferred\n",
+ DBG(data->dev, "unconnected, %s init abandoned\n",
data->name);
- data->state = STATE_EP_DEFER_ENABLE;
+ value = -EINVAL;
}
if (value == 0) {
fd->f_op = &ep_io_operations;
@@ -943,22 +931,24 @@ static void clean_req (struct usb_ep *ep, struct usb_request *req)
static void ep0_complete (struct usb_ep *ep, struct usb_request *req)
{
struct dev_data *dev = ep->driver_data;
+ unsigned long flags;
int free = 1;
/* for control OUT, data must still get to userspace */
+ spin_lock_irqsave(&dev->lock, flags);
if (!dev->setup_in) {
dev->setup_out_error = (req->status != 0);
if (!dev->setup_out_error)
free = 0;
dev->setup_out_ready = 1;
ep0_readable (dev);
- } else if (dev->state == STATE_SETUP)
- dev->state = STATE_CONNECTED;
+ }
/* clean up as appropriate */
if (free && req->buf != &dev->rbuf)
clean_req (ep, req);
req->complete = epio_complete;
+ spin_unlock_irqrestore(&dev->lock, flags);
}
static int setup_req (struct usb_ep *ep, struct usb_request *req, u16 len)
@@ -998,13 +988,13 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
}
/* control DATA stage */
- if ((state = dev->state) == STATE_SETUP) {
+ if ((state = dev->state) == STATE_DEV_SETUP) {
if (dev->setup_in) { /* stall IN */
VDEBUG(dev, "ep0in stall\n");
(void) usb_ep_set_halt (dev->gadget->ep0);
retval = -EL2HLT;
- dev->state = STATE_CONNECTED;
+ dev->state = STATE_DEV_CONNECTED;
} else if (len == 0) { /* ack SET_CONFIGURATION etc */
struct usb_ep *ep = dev->gadget->ep0;
@@ -1012,7 +1002,7 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
if ((retval = setup_req (ep, req, 0)) == 0)
retval = usb_ep_queue (ep, req, GFP_ATOMIC);
- dev->state = STATE_CONNECTED;
+ dev->state = STATE_DEV_CONNECTED;
/* assume that was SET_CONFIGURATION */
if (dev->current_config) {
@@ -1040,6 +1030,13 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
spin_lock_irq (&dev->lock);
if (retval)
goto done;
+
+ if (dev->state != STATE_DEV_SETUP) {
+ retval = -ECANCELED;
+ goto done;
+ }
+ dev->state = STATE_DEV_CONNECTED;
+
if (dev->setup_out_error)
retval = -EIO;
else {
@@ -1066,39 +1063,36 @@ scan:
/* return queued events right away */
if (dev->ev_next != 0) {
unsigned i, n;
- int tmp = dev->ev_next;
- len = min (len, tmp * sizeof (struct usb_gadgetfs_event));
n = len / sizeof (struct usb_gadgetfs_event);
+ if (dev->ev_next < n)
+ n = dev->ev_next;
- /* ep0 can't deliver events when STATE_SETUP */
+ /* ep0 i/o has special semantics during STATE_DEV_SETUP */
for (i = 0; i < n; i++) {
if (dev->event [i].type == GADGETFS_SETUP) {
- len = i + 1;
- len *= sizeof (struct usb_gadgetfs_event);
- n = 0;
+ dev->state = STATE_DEV_SETUP;
+ n = i + 1;
break;
}
}
spin_unlock_irq (&dev->lock);
+ len = n * sizeof (struct usb_gadgetfs_event);
if (copy_to_user (buf, &dev->event, len))
retval = -EFAULT;
else
retval = len;
if (len > 0) {
- len /= sizeof (struct usb_gadgetfs_event);
-
/* NOTE this doesn't guard against broken drivers;
* concurrent ep0 readers may lose events.
*/
spin_lock_irq (&dev->lock);
- dev->ev_next -= len;
- if (dev->ev_next != 0)
- memmove (&dev->event, &dev->event [len],
+ if (dev->ev_next > n) {
+ memmove(&dev->event[0], &dev->event[n],
sizeof (struct usb_gadgetfs_event)
- * (tmp - len));
- if (n == 0)
- dev->state = STATE_SETUP;
+ * (dev->ev_next - n));
+ }
+ dev->ev_next -= n;
spin_unlock_irq (&dev->lock);
}
return retval;
@@ -1113,8 +1107,8 @@ scan:
DBG (dev, "fail %s, state %d\n", __FUNCTION__, state);
retval = -ESRCH;
break;
- case STATE_UNCONNECTED:
- case STATE_CONNECTED:
+ case STATE_DEV_UNCONNECTED:
+ case STATE_DEV_CONNECTED:
spin_unlock_irq (&dev->lock);
DBG (dev, "%s wait\n", __FUNCTION__);
@@ -1141,7 +1135,7 @@ next_event (struct dev_data *dev, enum usb_gadgetfs_event_type type)
switch (type) {
/* these events purge the queue */
case GADGETFS_DISCONNECT:
- if (dev->state == STATE_SETUP)
+ if (dev->state == STATE_DEV_SETUP)
dev->setup_abort = 1;
// FALL THROUGH
case GADGETFS_CONNECT:
@@ -1153,7 +1147,7 @@ next_event (struct dev_data *dev, enum usb_gadgetfs_event_type type)
for (i = 0; i != dev->ev_next; i++) {
if (dev->event [i].type != type)
continue;
- DBG (dev, "discard old event %d\n", type);
+ DBG(dev, "discard old event[%d] %d\n", i, type);
dev->ev_next--;
if (i == dev->ev_next)
break;
@@ -1166,9 +1160,9 @@ next_event (struct dev_data *dev, enum usb_gadgetfs_event_type type)
default:
BUG ();
}
+ VDEBUG(dev, "event[%d] = %d\n", dev->ev_next, type);
event = &dev->event [dev->ev_next++];
BUG_ON (dev->ev_next > N_EVENT);
- VDEBUG (dev, "ev %d, next %d\n", type, dev->ev_next);
memset (event, 0, sizeof *event);
event->type = type;
return event;
@@ -1188,12 +1182,13 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
retval = -EIDRM;
/* data and/or status stage for control request */
- } else if (dev->state == STATE_SETUP) {
+ } else if (dev->state == STATE_DEV_SETUP) {
/* IN DATA+STATUS caller makes len <= wLength */
if (dev->setup_in) {
retval = setup_req (dev->gadget->ep0, dev->req, len);
if (retval == 0) {
+ dev->state = STATE_DEV_CONNECTED;
spin_unlock_irq (&dev->lock);
if (copy_from_user (dev->req->buf, buf, len))
retval = -EFAULT;
@@ -1219,7 +1214,7 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
VDEBUG(dev, "ep0out stall\n");
(void) usb_ep_set_halt (dev->gadget->ep0);
retval = -EL2HLT;
- dev->state = STATE_CONNECTED;
+ dev->state = STATE_DEV_CONNECTED;
} else {
DBG(dev, "bogus ep0out stall!\n");
}
@@ -1261,7 +1256,9 @@ dev_release (struct inode *inode, struct file *fd)
put_dev (dev);
/* other endpoints were all decoupled from this device */
+ spin_lock_irq(&dev->lock);
dev->state = STATE_DEV_DISABLED;
+ spin_unlock_irq(&dev->lock);
return 0;
}
@@ -1282,7 +1279,7 @@ ep0_poll (struct file *fd, poll_table *wait)
goto out;
}
- if (dev->state == STATE_SETUP) {
+ if (dev->state == STATE_DEV_SETUP) {
if (dev->setup_in || dev->setup_can_stall)
mask = POLLOUT;
} else {
@@ -1392,52 +1389,29 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
spin_lock (&dev->lock);
dev->setup_abort = 0;
- if (dev->state == STATE_UNCONNECTED) {
- struct usb_ep *ep;
- struct ep_data *data;
-
- dev->state = STATE_CONNECTED;
- dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket;
-
+ if (dev->state == STATE_DEV_UNCONNECTED) {
#ifdef CONFIG_USB_GADGET_DUALSPEED
if (gadget->speed == USB_SPEED_HIGH && dev->hs_config == 0) {
+ spin_unlock(&dev->lock);
ERROR (dev, "no high speed config??\n");
return -EINVAL;
}
#endif /* CONFIG_USB_GADGET_DUALSPEED */
+ dev->state = STATE_DEV_CONNECTED;
+ dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket;
+
INFO (dev, "connected\n");
event = next_event (dev, GADGETFS_CONNECT);
event->u.speed = gadget->speed;
ep0_readable (dev);
- list_for_each_entry (ep, &gadget->ep_list, ep_list) {
- data = ep->driver_data;
- /* ... down_trylock (&data->lock) ... */
- if (data->state != STATE_EP_DEFER_ENABLE)
- continue;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- if (gadget->speed == USB_SPEED_HIGH)
- value = usb_ep_enable (ep, &data->hs_desc);
- else
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
- value = usb_ep_enable (ep, &data->desc);
- if (value) {
- ERROR (dev, "deferred %s enable --> %d\n",
- data->name, value);
- continue;
- }
- data->state = STATE_EP_ENABLED;
- wake_up (&data->wait);
- DBG (dev, "woke up %s waiters\n", data->name);
- }
-
/* host may have given up waiting for response. we can miss control
* requests handled lower down (device/endpoint status and features);
* then ep0_{read,write} will report the wrong status. controller
* driver will have aborted pending i/o.
*/
- } else if (dev->state == STATE_SETUP)
+ } else if (dev->state == STATE_DEV_SETUP)
dev->setup_abort = 1;
req->buf = dev->rbuf;
@@ -1583,7 +1557,7 @@ delegate:
}
/* proceed with data transfer and status phases? */
- if (value >= 0 && dev->state != STATE_SETUP) {
+ if (value >= 0 && dev->state != STATE_DEV_SETUP) {
req->length = value;
req->zero = value < w_length;
value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
@@ -1747,7 +1721,9 @@ gadgetfs_bind (struct usb_gadget *gadget)
goto enomem;
INFO (dev, "bound to %s driver\n", gadget->name);
- dev->state = STATE_UNCONNECTED;
+ spin_lock_irq(&dev->lock);
+ dev->state = STATE_DEV_UNCONNECTED;
+ spin_unlock_irq(&dev->lock);
get_dev (dev);
return 0;
@@ -1762,11 +1738,9 @@ gadgetfs_disconnect (struct usb_gadget *gadget)
struct dev_data *dev = get_gadget_data (gadget);
spin_lock (&dev->lock);
- if (dev->state == STATE_UNCONNECTED) {
- DBG (dev, "already unconnected\n");
+ if (dev->state == STATE_DEV_UNCONNECTED)
goto exit;
- }
- dev->state = STATE_UNCONNECTED;
+ dev->state = STATE_DEV_UNCONNECTED;
INFO (dev, "disconnected\n");
next_event (dev, GADGETFS_DISCONNECT);
@@ -1783,9 +1757,9 @@ gadgetfs_suspend (struct usb_gadget *gadget)
INFO (dev, "suspended from state %d\n", dev->state);
spin_lock (&dev->lock);
switch (dev->state) {
- case STATE_SETUP: // VERY odd... host died??
- case STATE_CONNECTED:
- case STATE_UNCONNECTED:
+ case STATE_DEV_SETUP: // VERY odd... host died??
+ case STATE_DEV_CONNECTED:
+ case STATE_DEV_UNCONNECTED:
next_event (dev, GADGETFS_SUSPEND);
ep0_readable (dev);
/* FALLTHROUGH */
@@ -1808,7 +1782,7 @@ static struct usb_gadget_driver gadgetfs_driver = {
.disconnect = gadgetfs_disconnect,
.suspend = gadgetfs_suspend,
- .driver = {
+ .driver = {
.name = (char *) shortname,
},
};
@@ -1829,7 +1803,7 @@ static struct usb_gadget_driver probe_driver = {
.unbind = gadgetfs_nop,
.setup = (void *)gadgetfs_nop,
.disconnect = gadgetfs_nop,
- .driver = {
+ .driver = {
.name = "nop",
},
};
@@ -1849,19 +1823,16 @@ static struct usb_gadget_driver probe_driver = {
* . full/low speed config ... all wTotalLength bytes (with interface,
* class, altsetting, endpoint, and other descriptors)
* . high speed config ... all descriptors, for high speed operation;
- * this one's optional except for high-speed hardware
+ * this one's optional except for high-speed hardware
* . device descriptor
*
- * Endpoints are not yet enabled. Drivers may want to immediately
- * initialize them, using the /dev/gadget/ep* files that are available
- * as soon as the kernel sees the configuration, or they can wait
- * until device configuration and interface altsetting changes create
+ * Endpoints are not yet enabled. Drivers must wait until device
+ * configuration and interface altsetting changes create
* the need to configure (or unconfigure) them.
*
* After initialization, the device stays active for as long as that
- * $CHIP file is open. Events may then be read from that descriptor,
- * such as configuration notifications. More complex drivers will handle
- * some control requests in user space.
+ * $CHIP file is open. Events must then be read from that descriptor,
+ * such as configuration notifications.
*/
static int is_valid_config (struct usb_config_descriptor *config)
@@ -1884,9 +1855,6 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
u32 tag;
char *kbuf;
- if (dev->state != STATE_OPENED)
- return -EEXIST;
-
if (len < (USB_DT_CONFIG_SIZE + USB_DT_DEVICE_SIZE + 4))
return -EINVAL;
@@ -1978,13 +1946,15 @@ dev_open (struct inode *inode, struct file *fd)
struct dev_data *dev = inode->i_private;
int value = -EBUSY;
+ spin_lock_irq(&dev->lock);
if (dev->state == STATE_DEV_DISABLED) {
dev->ev_next = 0;
- dev->state = STATE_OPENED;
+ dev->state = STATE_DEV_OPENED;
fd->private_data = dev;
get_dev (dev);
value = 0;
}
+ spin_unlock_irq(&dev->lock);
return value;
}
diff --git a/drivers/usb/gadget/lh7a40x_udc.h b/drivers/usb/gadget/lh7a40x_udc.h
index e3bb78524c8..b3fe197e1ee 100644
--- a/drivers/usb/gadget/lh7a40x_udc.h
+++ b/drivers/usb/gadget/lh7a40x_udc.h
@@ -49,7 +49,7 @@
#include <asm/unaligned.h>
#include <asm/hardware.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
/*
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index 569eb8ccf23..7617ff7bd5a 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -63,7 +63,7 @@
#include <linux/interrupt.h>
#include <linux/moduleparam.h>
#include <linux/device.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <asm/byteorder.h>
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index cdcfd42843d..140104341db 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -38,7 +38,7 @@
#include <linux/mm.h>
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <linux/usb/otg.h>
#include <linux/dma-mapping.h>
diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
index b78de969466..0d225369847 100644
--- a/drivers/usb/gadget/pxa2xx_udc.c
+++ b/drivers/usb/gadget/pxa2xx_udc.c
@@ -56,7 +56,7 @@
#include <asm/arch/pxa-regs.h>
#endif
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <asm/arch/udc.h>
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index f8a3ec64635..6c742a90922 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -43,7 +43,7 @@
#include <asm/unaligned.h>
#include <asm/uaccess.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb/cdc.h>
#include <linux/usb_gadget.h>
diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c
index b1735767660..3459ea6c6c0 100644
--- a/drivers/usb/gadget/usbstring.c
+++ b/drivers/usb/gadget/usbstring.c
@@ -14,7 +14,7 @@
#include <linux/device.h>
#include <linux/init.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <asm/unaligned.h>
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
index 40710ea1b49..ebe04e0d287 100644
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -84,7 +84,7 @@
#include <asm/system.h>
#include <asm/unaligned.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include "gadget_chips.h"
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index cc60759083b..62711870f8e 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -67,6 +67,11 @@ config USB_EHCI_TT_NEWSCHED
If unsure, say N.
+config USB_EHCI_BIG_ENDIAN_MMIO
+ bool
+ depends on USB_EHCI_HCD
+ default n
+
config USB_ISP116X_HCD
tristate "ISP116X HCD support"
depends on USB
@@ -101,21 +106,48 @@ config USB_OHCI_HCD_PPC_SOC
bool "OHCI support for on-chip PPC USB controller"
depends on USB_OHCI_HCD && (STB03xxx || PPC_MPC52xx)
default y
- select USB_OHCI_BIG_ENDIAN
+ select USB_OHCI_BIG_ENDIAN_DESC
+ select USB_OHCI_BIG_ENDIAN_MMIO
---help---
Enables support for the USB controller on the MPC52xx or
STB03xxx processor chip. If unsure, say Y.
+config USB_OHCI_HCD_PPC_OF
+ bool "OHCI support for PPC USB controller on OF platform bus"
+ depends on USB_OHCI_HCD && PPC_OF
+ default y
+ ---help---
+ Enables support for the USB controller PowerPC present on the
+ OpenFirmware platform bus.
+
+config USB_OHCI_HCD_PPC_OF_BE
+ bool "Support big endian HC"
+ depends on USB_OHCI_HCD_PPC_OF
+ default y
+ select USB_OHCI_BIG_ENDIAN_DESC
+ select USB_OHCI_BIG_ENDIAN_MMIO
+
+config USB_OHCI_HCD_PPC_OF_LE
+ bool "Support little endian HC"
+ depends on USB_OHCI_HCD_PPC_OF
+ default n
+ select USB_OHCI_LITTLE_ENDIAN
+
config USB_OHCI_HCD_PCI
bool "OHCI support for PCI-bus USB controllers"
- depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx)
+ depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx || USB_OHCI_HCD_PPC_OF)
default y
select USB_OHCI_LITTLE_ENDIAN
---help---
Enables support for PCI-bus plug-in USB controller cards.
If unsure, say Y.
-config USB_OHCI_BIG_ENDIAN
+config USB_OHCI_BIG_ENDIAN_DESC
+ bool
+ depends on USB_OHCI_HCD
+ default n
+
+config USB_OHCI_BIG_ENDIAN_MMIO
bool
depends on USB_OHCI_HCD
default n
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index 56349d21e6e..246afea9e83 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -43,7 +43,7 @@
*/
static void dbg_hcs_params (struct ehci_hcd *ehci, char *label)
{
- u32 params = readl (&ehci->caps->hcs_params);
+ u32 params = ehci_readl(ehci, &ehci->caps->hcs_params);
ehci_dbg (ehci,
"%s hcs_params 0x%x dbg=%d%s cc=%d pcc=%d%s%s ports=%d\n",
@@ -87,7 +87,7 @@ static inline void dbg_hcs_params (struct ehci_hcd *ehci, char *label) {}
* */
static void dbg_hcc_params (struct ehci_hcd *ehci, char *label)
{
- u32 params = readl (&ehci->caps->hcc_params);
+ u32 params = ehci_readl(ehci, &ehci->caps->hcc_params);
if (HCC_ISOC_CACHE (params)) {
ehci_dbg (ehci,
@@ -653,7 +653,7 @@ show_registers (struct class_device *class_dev, char *buf)
}
/* Capability Registers */
- i = HC_VERSION(readl (&ehci->caps->hc_capbase));
+ i = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
temp = scnprintf (next, size,
"bus %s, device %s (driver " DRIVER_VERSION ")\n"
"%s\n"
@@ -673,7 +673,7 @@ show_registers (struct class_device *class_dev, char *buf)
unsigned count = 256/4;
pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller);
- offset = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params));
+ offset = HCC_EXT_CAPS (ehci_readl(ehci, &ehci->caps->hcc_params));
while (offset && count--) {
pci_read_config_dword (pdev, offset, &cap);
switch (cap & 0xff) {
@@ -704,50 +704,50 @@ show_registers (struct class_device *class_dev, char *buf)
#endif
// FIXME interpret both types of params
- i = readl (&ehci->caps->hcs_params);
+ i = ehci_readl(ehci, &ehci->caps->hcs_params);
temp = scnprintf (next, size, "structural params 0x%08x\n", i);
size -= temp;
next += temp;
- i = readl (&ehci->caps->hcc_params);
+ i = ehci_readl(ehci, &ehci->caps->hcc_params);
temp = scnprintf (next, size, "capability params 0x%08x\n", i);
size -= temp;
next += temp;
/* Operational Registers */
temp = dbg_status_buf (scratch, sizeof scratch, label,
- readl (&ehci->regs->status));
+ ehci_readl(ehci, &ehci->regs->status));
temp = scnprintf (next, size, fmt, temp, scratch);
size -= temp;
next += temp;
temp = dbg_command_buf (scratch, sizeof scratch, label,
- readl (&ehci->regs->command));
+ ehci_readl(ehci, &ehci->regs->command));
temp = scnprintf (next, size, fmt, temp, scratch);
size -= temp;
next += temp;
temp = dbg_intr_buf (scratch, sizeof scratch, label,
- readl (&ehci->regs->intr_enable));
+ ehci_readl(ehci, &ehci->regs->intr_enable));
temp = scnprintf (next, size, fmt, temp, scratch);
size -= temp;
next += temp;
temp = scnprintf (next, size, "uframe %04x\n",
- readl (&ehci->regs->frame_index));
+ ehci_readl(ehci, &ehci->regs->frame_index));
size -= temp;
next += temp;
for (i = 1; i <= HCS_N_PORTS (ehci->hcs_params); i++) {
temp = dbg_port_buf (scratch, sizeof scratch, label, i,
- readl (&ehci->regs->port_status [i - 1]));
+ ehci_readl(ehci, &ehci->regs->port_status [i - 1]));
temp = scnprintf (next, size, fmt, temp, scratch);
size -= temp;
next += temp;
if (i == HCS_DEBUG_PORT(ehci->hcs_params) && ehci->debug) {
temp = scnprintf (next, size,
" debug control %08x\n",
- readl (&ehci->debug->control));
+ ehci_readl(ehci, &ehci->debug->control));
size -= temp;
next += temp;
}
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index 1a915e982c1..a52480505f7 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -177,7 +177,7 @@ static void mpc83xx_setup_phy(struct ehci_hcd *ehci,
case FSL_USB2_PHY_NONE:
break;
}
- writel(portsc, &ehci->regs->port_status[port_offset]);
+ ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]);
}
static void mpc83xx_usb_setup(struct usb_hcd *hcd)
@@ -214,7 +214,7 @@ static void mpc83xx_usb_setup(struct usb_hcd *hcd)
}
/* put controller in host mode. */
- writel(0x00000003, non_ehci + FSL_SOC_USB_USBMODE);
+ ehci_writel(ehci, 0x00000003, non_ehci + FSL_SOC_USB_USBMODE);
out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c);
out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040);
out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
@@ -238,12 +238,12 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
/* EHCI registers start at offset 0x100 */
ehci->caps = hcd->regs + 0x100;
ehci->regs = hcd->regs + 0x100 +
- HC_LENGTH(readl(&ehci->caps->hc_capbase));
+ HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
dbg_hcs_params(ehci, "reset");
dbg_hcc_params(ehci, "reset");
/* cache this readonly data; minimize chip reads */
- ehci->hcs_params = readl(&ehci->caps->hcs_params);
+ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
retval = ehci_halt(ehci);
if (retval)
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 025d3331368..185721dba42 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -157,12 +157,13 @@ MODULE_PARM_DESC (ignore_oc, "ignore bogus hardware overcurrent indications");
* before driver shutdown. But it also seems to be caused by bugs in cardbus
* bridge shutdown: shutting down the bridge before the devices using it.
*/
-static int handshake (void __iomem *ptr, u32 mask, u32 done, int usec)
+static int handshake (struct ehci_hcd *ehci, void __iomem *ptr,
+ u32 mask, u32 done, int usec)
{
u32 result;
do {
- result = readl (ptr);
+ result = ehci_readl(ehci, ptr);
if (result == ~(u32)0) /* card removed */
return -ENODEV;
result &= mask;
@@ -177,18 +178,19 @@ static int handshake (void __iomem *ptr, u32 mask, u32 done, int usec)
/* force HC to halt state from unknown (EHCI spec section 2.3) */
static int ehci_halt (struct ehci_hcd *ehci)
{
- u32 temp = readl (&ehci->regs->status);
+ u32 temp = ehci_readl(ehci, &ehci->regs->status);
/* disable any irqs left enabled by previous code */
- writel (0, &ehci->regs->intr_enable);
+ ehci_writel(ehci, 0, &ehci->regs->intr_enable);
if ((temp & STS_HALT) != 0)
return 0;
- temp = readl (&ehci->regs->command);
+ temp = ehci_readl(ehci, &ehci->regs->command);
temp &= ~CMD_RUN;
- writel (temp, &ehci->regs->command);
- return handshake (&ehci->regs->status, STS_HALT, STS_HALT, 16 * 125);
+ ehci_writel(ehci, temp, &ehci->regs->command);
+ return handshake (ehci, &ehci->regs->status,
+ STS_HALT, STS_HALT, 16 * 125);
}
/* put TDI/ARC silicon into EHCI mode */
@@ -198,23 +200,24 @@ static void tdi_reset (struct ehci_hcd *ehci)
u32 tmp;
reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + 0x68);
- tmp = readl (reg_ptr);
+ tmp = ehci_readl(ehci, reg_ptr);
tmp |= 0x3;
- writel (tmp, reg_ptr);
+ ehci_writel(ehci, tmp, reg_ptr);
}
/* reset a non-running (STS_HALT == 1) controller */
static int ehci_reset (struct ehci_hcd *ehci)
{
int retval;
- u32 command = readl (&ehci->regs->command);
+ u32 command = ehci_readl(ehci, &ehci->regs->command);
command |= CMD_RESET;
dbg_cmd (ehci, "reset", command);
- writel (command, &ehci->regs->command);
+ ehci_writel(ehci, command, &ehci->regs->command);
ehci_to_hcd(ehci)->state = HC_STATE_HALT;
ehci->next_statechange = jiffies;
- retval = handshake (&ehci->regs->command, CMD_RESET, 0, 250 * 1000);
+ retval = handshake (ehci, &ehci->regs->command,
+ CMD_RESET, 0, 250 * 1000);
if (retval)
return retval;
@@ -236,21 +239,21 @@ static void ehci_quiesce (struct ehci_hcd *ehci)
#endif
/* wait for any schedule enables/disables to take effect */
- temp = readl (&ehci->regs->command) << 10;
+ temp = ehci_readl(ehci, &ehci->regs->command) << 10;
temp &= STS_ASS | STS_PSS;
- if (handshake (&ehci->regs->status, STS_ASS | STS_PSS,
+ if (handshake (ehci, &ehci->regs->status, STS_ASS | STS_PSS,
temp, 16 * 125) != 0) {
ehci_to_hcd(ehci)->state = HC_STATE_HALT;
return;
}
/* then disable anything that's still active */
- temp = readl (&ehci->regs->command);
+ temp = ehci_readl(ehci, &ehci->regs->command);
temp &= ~(CMD_ASE | CMD_IAAD | CMD_PSE);
- writel (temp, &ehci->regs->command);
+ ehci_writel(ehci, temp, &ehci->regs->command);
/* hardware can take 16 microframes to turn off ... */
- if (handshake (&ehci->regs->status, STS_ASS | STS_PSS,
+ if (handshake (ehci, &ehci->regs->status, STS_ASS | STS_PSS,
0, 16 * 125) != 0) {
ehci_to_hcd(ehci)->state = HC_STATE_HALT;
return;
@@ -277,11 +280,11 @@ static void ehci_watchdog (unsigned long param)
/* lost IAA irqs wedge things badly; seen with a vt8235 */
if (ehci->reclaim) {
- u32 status = readl (&ehci->regs->status);
+ u32 status = ehci_readl(ehci, &ehci->regs->status);
if (status & STS_IAA) {
ehci_vdbg (ehci, "lost IAA\n");
COUNT (ehci->stats.lost_iaa);
- writel (STS_IAA, &ehci->regs->status);
+ ehci_writel(ehci, STS_IAA, &ehci->regs->status);
ehci->reclaim_ready = 1;
}
}
@@ -309,7 +312,7 @@ ehci_shutdown (struct usb_hcd *hcd)
(void) ehci_halt (ehci);
/* make BIOS/etc use companion controller during reboot */
- writel (0, &ehci->regs->configured_flag);
+ ehci_writel(ehci, 0, &ehci->regs->configured_flag);
}
static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
@@ -379,12 +382,13 @@ static void ehci_stop (struct usb_hcd *hcd)
ehci_quiesce (ehci);
ehci_reset (ehci);
- writel (0, &ehci->regs->intr_enable);
+ ehci_writel(ehci, 0, &ehci->regs->intr_enable);
spin_unlock_irq(&ehci->lock);
/* let companion controllers work when we aren't */
- writel (0, &ehci->regs->configured_flag);
+ ehci_writel(ehci, 0, &ehci->regs->configured_flag);
+ remove_companion_file(ehci);
remove_debug_files (ehci);
/* root hub is shut down separately (first, when possible) */
@@ -402,7 +406,8 @@ static void ehci_stop (struct usb_hcd *hcd)
ehci->stats.complete, ehci->stats.unlink);
#endif
- dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status));
+ dbg_status (ehci, "ehci_stop completed",
+ ehci_readl(ehci, &ehci->regs->status));
}
/* one-time init, only for memory state */
@@ -428,7 +433,7 @@ static int ehci_init(struct usb_hcd *hcd)
return retval;
/* controllers may cache some of the periodic schedule ... */
- hcc_params = readl(&ehci->caps->hcc_params);
+ hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params);
if (HCC_ISOC_CACHE(hcc_params)) // full frame cache
ehci->i_thresh = 8;
else // N microframes cached
@@ -496,13 +501,16 @@ static int ehci_run (struct usb_hcd *hcd)
u32 temp;
u32 hcc_params;
+ hcd->uses_new_polling = 1;
+ hcd->poll_rh = 0;
+
/* EHCI spec section 4.1 */
if ((retval = ehci_reset(ehci)) != 0) {
ehci_mem_cleanup(ehci);
return retval;
}
- writel(ehci->periodic_dma, &ehci->regs->frame_list);
- writel((u32)ehci->async->qh_dma, &ehci->regs->async_next);
+ ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);
+ ehci_writel(ehci, (u32)ehci->async->qh_dma, &ehci->regs->async_next);
/*
* hcc_params controls whether ehci->regs->segment must (!!!)
@@ -516,9 +524,9 @@ static int ehci_run (struct usb_hcd *hcd)
* Scsi_Host.highmem_io, and so forth. It's readonly to all
* host side drivers though.
*/
- hcc_params = readl(&ehci->caps->hcc_params);
+ hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params);
if (HCC_64BIT_ADDR(hcc_params)) {
- writel(0, &ehci->regs->segment);
+ ehci_writel(ehci, 0, &ehci->regs->segment);
#if 0
// this is deeply broken on almost all architectures
if (!dma_set_mask(hcd->self.controller, DMA_64BIT_MASK))
@@ -531,7 +539,7 @@ static int ehci_run (struct usb_hcd *hcd)
// root hub will detect new devices (why?); NEC doesn't
ehci->command &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);
ehci->command |= CMD_RUN;
- writel (ehci->command, &ehci->regs->command);
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
dbg_cmd (ehci, "init", ehci->command);
/*
@@ -541,23 +549,25 @@ static int ehci_run (struct usb_hcd *hcd)
* and there's no companion controller unless maybe for USB OTG.)
*/
hcd->state = HC_STATE_RUNNING;
- writel (FLAG_CF, &ehci->regs->configured_flag);
- readl (&ehci->regs->command); /* unblock posted writes */
+ ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
+ ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
- temp = HC_VERSION(readl (&ehci->caps->hc_capbase));
+ temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
ehci_info (ehci,
"USB %x.%x started, EHCI %x.%02x, driver %s%s\n",
((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f),
temp >> 8, temp & 0xff, DRIVER_VERSION,
ignore_oc ? ", overcurrent ignored" : "");
- writel (INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */
+ ehci_writel(ehci, INTR_MASK,
+ &ehci->regs->intr_enable); /* Turn On Interrupts */
/* GRR this is run-once init(), being done every time the HC starts.
* So long as they're part of class devices, we can't do it init()
* since the class device isn't created that early.
*/
create_debug_files(ehci);
+ create_companion_file(ehci);
return 0;
}
@@ -567,12 +577,12 @@ static int ehci_run (struct usb_hcd *hcd)
static irqreturn_t ehci_irq (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
- u32 status;
+ u32 status, pcd_status = 0;
int bh;
spin_lock (&ehci->lock);
- status = readl (&ehci->regs->status);
+ status = ehci_readl(ehci, &ehci->regs->status);
/* e.g. cardbus physical eject */
if (status == ~(u32) 0) {
@@ -587,8 +597,8 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
}
/* clear (just) interrupts */
- writel (status, &ehci->regs->status);
- readl (&ehci->regs->command); /* unblock posted write */
+ ehci_writel(ehci, status, &ehci->regs->status);
+ ehci_readl(ehci, &ehci->regs->command); /* unblock posted write */
bh = 0;
#ifdef EHCI_VERBOSE_DEBUG
@@ -617,13 +627,15 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
/* remote wakeup [4.3.1] */
if (status & STS_PCD) {
unsigned i = HCS_N_PORTS (ehci->hcs_params);
+ pcd_status = status;
/* resume root hub? */
- if (!(readl(&ehci->regs->command) & CMD_RUN))
+ if (!(ehci_readl(ehci, &ehci->regs->command) & CMD_RUN))
usb_hcd_resume_root_hub(hcd);
while (i--) {
- int pstatus = readl (&ehci->regs->port_status [i]);
+ int pstatus = ehci_readl(ehci,
+ &ehci->regs->port_status [i]);
if (pstatus & PORT_OWNER)
continue;
@@ -643,14 +655,15 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
/* PCI errors [4.15.2.4] */
if (unlikely ((status & STS_FATAL) != 0)) {
/* bogus "fatal" IRQs appear on some chips... why? */
- status = readl (&ehci->regs->status);
- dbg_cmd (ehci, "fatal", readl (&ehci->regs->command));
+ status = ehci_readl(ehci, &ehci->regs->status);
+ dbg_cmd (ehci, "fatal", ehci_readl(ehci,
+ &ehci->regs->command));
dbg_status (ehci, "fatal", status);
if (status & STS_HALT) {
ehci_err (ehci, "fatal error\n");
dead:
ehci_reset (ehci);
- writel (0, &ehci->regs->configured_flag);
+ ehci_writel(ehci, 0, &ehci->regs->configured_flag);
/* generic layer kills/unlinks all urbs, then
* uses ehci_stop to clean up the rest
*/
@@ -661,6 +674,8 @@ dead:
if (bh)
ehci_work (ehci);
spin_unlock (&ehci->lock);
+ if (pcd_status & STS_PCD)
+ usb_hcd_poll_rh_status(hcd);
return IRQ_HANDLED;
}
@@ -873,7 +888,8 @@ done:
static int ehci_get_frame (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
- return (readl (&ehci->regs->frame_index) >> 3) % ehci->periodic_size;
+ return (ehci_readl(ehci, &ehci->regs->frame_index) >> 3) %
+ ehci->periodic_size;
}
/*-------------------------------------------------------------------------*/
@@ -899,7 +915,13 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ehci_hcd_au1xxx_driver
#endif
-#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER)
+#ifdef CONFIG_PPC_PS3
+#include "ehci-ps3.c"
+#define PS3_SYSTEM_BUS_DRIVER ps3_ehci_sb_driver
+#endif
+
+#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
+ !defined(PS3_SYSTEM_BUS_DRIVER)
#error "missing bus glue for ehci-hcd"
#endif
@@ -924,6 +946,20 @@ static int __init ehci_hcd_init(void)
#ifdef PLATFORM_DRIVER
platform_driver_unregister(&PLATFORM_DRIVER);
#endif
+ return retval;
+ }
+#endif
+
+#ifdef PS3_SYSTEM_BUS_DRIVER
+ retval = ps3_system_bus_driver_register(&PS3_SYSTEM_BUS_DRIVER);
+ if (retval < 0) {
+#ifdef PLATFORM_DRIVER
+ platform_driver_unregister(&PLATFORM_DRIVER);
+#endif
+#ifdef PCI_DRIVER
+ pci_unregister_driver(&PCI_DRIVER);
+#endif
+ return retval;
}
#endif
@@ -939,6 +975,9 @@ static void __exit ehci_hcd_cleanup(void)
#ifdef PCI_DRIVER
pci_unregister_driver(&PCI_DRIVER);
#endif
+#ifdef PS3_SYSTEM_BUS_DRIVER
+ ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+#endif
}
module_exit(ehci_hcd_cleanup);
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index bfe5f307cba..0d83c6df1a3 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -47,7 +47,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
ehci_quiesce (ehci);
hcd->state = HC_STATE_QUIESCING;
}
- ehci->command = readl (&ehci->regs->command);
+ ehci->command = ehci_readl(ehci, &ehci->regs->command);
if (ehci->reclaim)
ehci->reclaim_ready = 1;
ehci_work(ehci);
@@ -60,7 +60,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
ehci->bus_suspended = 0;
while (port--) {
u32 __iomem *reg = &ehci->regs->port_status [port];
- u32 t1 = readl (reg) & ~PORT_RWC_BITS;
+ u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
u32 t2 = t1;
/* keep track of which ports we suspend */
@@ -79,7 +79,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
if (t1 != t2) {
ehci_vdbg (ehci, "port %d, %08x -> %08x\n",
port + 1, t1, t2);
- writel (t2, reg);
+ ehci_writel(ehci, t2, reg);
}
}
@@ -92,8 +92,8 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
mask = INTR_MASK;
if (!device_may_wakeup(&hcd->self.root_hub->dev))
mask &= ~STS_PCD;
- writel(mask, &ehci->regs->intr_enable);
- readl(&ehci->regs->intr_enable);
+ ehci_writel(ehci, mask, &ehci->regs->intr_enable);
+ ehci_readl(ehci, &ehci->regs->intr_enable);
ehci->next_statechange = jiffies + msecs_to_jiffies(10);
spin_unlock_irq (&ehci->lock);
@@ -118,26 +118,26 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
* the last user of the controller, not reset/pm hardware keeping
* state we gave to it.
*/
- temp = readl(&ehci->regs->intr_enable);
+ temp = ehci_readl(ehci, &ehci->regs->intr_enable);
ehci_dbg(ehci, "resume root hub%s\n", temp ? "" : " after power loss");
/* at least some APM implementations will try to deliver
* IRQs right away, so delay them until we're ready.
*/
- writel(0, &ehci->regs->intr_enable);
+ ehci_writel(ehci, 0, &ehci->regs->intr_enable);
/* re-init operational registers */
- writel(0, &ehci->regs->segment);
- writel(ehci->periodic_dma, &ehci->regs->frame_list);
- writel((u32) ehci->async->qh_dma, &ehci->regs->async_next);
+ ehci_writel(ehci, 0, &ehci->regs->segment);
+ ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);
+ ehci_writel(ehci, (u32) ehci->async->qh_dma, &ehci->regs->async_next);
/* restore CMD_RUN, framelist size, and irq threshold */
- writel (ehci->command, &ehci->regs->command);
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
/* manually resume the ports we suspended during bus_suspend() */
i = HCS_N_PORTS (ehci->hcs_params);
while (i--) {
- temp = readl (&ehci->regs->port_status [i]);
+ temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
temp &= ~(PORT_RWC_BITS
| PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E);
if (test_bit(i, &ehci->bus_suspended) &&
@@ -145,20 +145,20 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
ehci->reset_done [i] = jiffies + msecs_to_jiffies (20);
temp |= PORT_RESUME;
}
- writel (temp, &ehci->regs->port_status [i]);
+ ehci_writel(ehci, temp, &ehci->regs->port_status [i]);
}
i = HCS_N_PORTS (ehci->hcs_params);
mdelay (20);
while (i--) {
- temp = readl (&ehci->regs->port_status [i]);
+ temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
if (test_bit(i, &ehci->bus_suspended) &&
(temp & PORT_SUSPEND)) {
temp &= ~(PORT_RWC_BITS | PORT_RESUME);
- writel (temp, &ehci->regs->port_status [i]);
+ ehci_writel(ehci, temp, &ehci->regs->port_status [i]);
ehci_vdbg (ehci, "resumed port %d\n", i + 1);
}
}
- (void) readl (&ehci->regs->command);
+ (void) ehci_readl(ehci, &ehci->regs->command);
/* maybe re-activate the schedule(s) */
temp = 0;
@@ -168,14 +168,14 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
temp |= CMD_PSE;
if (temp) {
ehci->command |= temp;
- writel (ehci->command, &ehci->regs->command);
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
}
ehci->next_statechange = jiffies + msecs_to_jiffies(5);
hcd->state = HC_STATE_RUNNING;
/* Now we can safely re-enable irqs */
- writel(INTR_MASK, &ehci->regs->intr_enable);
+ ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable);
spin_unlock_irq (&ehci->lock);
return 0;
@@ -190,9 +190,107 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
/*-------------------------------------------------------------------------*/
+/* Display the ports dedicated to the companion controller */
+static ssize_t show_companion(struct class_device *class_dev, char *buf)
+{
+ struct ehci_hcd *ehci;
+ int nports, index, n;
+ int count = PAGE_SIZE;
+ char *ptr = buf;
+
+ ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev)));
+ nports = HCS_N_PORTS(ehci->hcs_params);
+
+ for (index = 0; index < nports; ++index) {
+ if (test_bit(index, &ehci->companion_ports)) {
+ n = scnprintf(ptr, count, "%d\n", index + 1);
+ ptr += n;
+ count -= n;
+ }
+ }
+ return ptr - buf;
+}
+
+/*
+ * Dedicate or undedicate a port to the companion controller.
+ * Syntax is "[-]portnum", where a leading '-' sign means
+ * return control of the port to the EHCI controller.
+ */
+static ssize_t store_companion(struct class_device *class_dev,
+ const char *buf, size_t count)
+{
+ struct ehci_hcd *ehci;
+ int portnum, new_owner, try;
+ u32 __iomem *status_reg;
+ u32 port_status;
+
+ ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev)));
+ new_owner = PORT_OWNER; /* Owned by companion */
+ if (sscanf(buf, "%d", &portnum) != 1)
+ return -EINVAL;
+ if (portnum < 0) {
+ portnum = - portnum;
+ new_owner = 0; /* Owned by EHCI */
+ }
+ if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params))
+ return -ENOENT;
+ status_reg = &ehci->regs->port_status[--portnum];
+ if (new_owner)
+ set_bit(portnum, &ehci->companion_ports);
+ else
+ clear_bit(portnum, &ehci->companion_ports);
+
+ /*
+ * The controller won't set the OWNER bit if the port is
+ * enabled, so this loop will sometimes require at least two
+ * iterations: one to disable the port and one to set OWNER.
+ */
+
+ for (try = 4; try > 0; --try) {
+ spin_lock_irq(&ehci->lock);
+ port_status = ehci_readl(ehci, status_reg);
+ if ((port_status & PORT_OWNER) == new_owner
+ || (port_status & (PORT_OWNER | PORT_CONNECT))
+ == 0)
+ try = 0;
+ else {
+ port_status ^= PORT_OWNER;
+ port_status &= ~(PORT_PE | PORT_RWC_BITS);
+ ehci_writel(ehci, port_status, status_reg);
+ }
+ spin_unlock_irq(&ehci->lock);
+ if (try > 1)
+ msleep(5);
+ }
+ return count;
+}
+static CLASS_DEVICE_ATTR(companion, 0644, show_companion, store_companion);
+
+static inline void create_companion_file(struct ehci_hcd *ehci)
+{
+ int i;
+
+ /* with integrated TT there is no companion! */
+ if (!ehci_is_TDI(ehci))
+ i = class_device_create_file(ehci_to_hcd(ehci)->self.class_dev,
+ &class_device_attr_companion);
+}
+
+static inline void remove_companion_file(struct ehci_hcd *ehci)
+{
+ /* with integrated TT there is no companion! */
+ if (!ehci_is_TDI(ehci))
+ class_device_remove_file(ehci_to_hcd(ehci)->self.class_dev,
+ &class_device_attr_companion);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
static int check_reset_complete (
struct ehci_hcd *ehci,
int index,
+ u32 __iomem *status_reg,
int port_status
) {
if (!(port_status & PORT_CONNECT)) {
@@ -217,7 +315,7 @@ static int check_reset_complete (
// what happens if HCS_N_CC(params) == 0 ?
port_status |= PORT_OWNER;
port_status &= ~PORT_RWC_BITS;
- writel (port_status, &ehci->regs->port_status [index]);
+ ehci_writel(ehci, port_status, status_reg);
} else
ehci_dbg (ehci, "port %d high speed\n", index + 1);
@@ -268,22 +366,21 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
/* port N changes (bit N)? */
spin_lock_irqsave (&ehci->lock, flags);
for (i = 0; i < ports; i++) {
- temp = readl (&ehci->regs->port_status [i]);
- if (temp & PORT_OWNER) {
- /* don't report this in GetPortStatus */
- if (temp & PORT_CSC) {
- temp &= ~PORT_RWC_BITS;
- temp |= PORT_CSC;
- writel (temp, &ehci->regs->port_status [i]);
- }
- continue;
- }
+ temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
+
+ /*
+ * Return status information even for ports with OWNER set.
+ * Otherwise khubd wouldn't see the disconnect event when a
+ * high-speed device is switched over to the companion
+ * controller by the user.
+ */
+
if (!(temp & PORT_CONNECT))
ehci->reset_done [i] = 0;
if ((temp & mask) != 0
|| ((temp & PORT_RESUME) != 0
- && time_after (jiffies,
- ehci->reset_done [i]))) {
+ && time_after_eq(jiffies,
+ ehci->reset_done[i]))) {
if (i < 7)
buf [0] |= 1 << (i + 1);
else
@@ -345,6 +442,7 @@ static int ehci_hub_control (
) {
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
int ports = HCS_N_PORTS (ehci->hcs_params);
+ u32 __iomem *status_reg = &ehci->regs->port_status[wIndex - 1];
u32 temp, status;
unsigned long flags;
int retval = 0;
@@ -373,18 +471,22 @@ static int ehci_hub_control (
if (!wIndex || wIndex > ports)
goto error;
wIndex--;
- temp = readl (&ehci->regs->port_status [wIndex]);
- if (temp & PORT_OWNER)
- break;
+ temp = ehci_readl(ehci, status_reg);
+
+ /*
+ * Even if OWNER is set, so the port is owned by the
+ * companion controller, khubd needs to be able to clear
+ * the port-change status bits (especially
+ * USB_PORT_FEAT_C_CONNECTION).
+ */
switch (wValue) {
case USB_PORT_FEAT_ENABLE:
- writel (temp & ~PORT_PE,
- &ehci->regs->port_status [wIndex]);
+ ehci_writel(ehci, temp & ~PORT_PE, status_reg);
break;
case USB_PORT_FEAT_C_ENABLE:
- writel((temp & ~PORT_RWC_BITS) | PORT_PEC,
- &ehci->regs->port_status [wIndex]);
+ ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_PEC,
+ status_reg);
break;
case USB_PORT_FEAT_SUSPEND:
if (temp & PORT_RESET)
@@ -396,8 +498,8 @@ static int ehci_hub_control (
goto error;
/* resume signaling for 20 msec */
temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
- writel (temp | PORT_RESUME,
- &ehci->regs->port_status [wIndex]);
+ ehci_writel(ehci, temp | PORT_RESUME,
+ status_reg);
ehci->reset_done [wIndex] = jiffies
+ msecs_to_jiffies (20);
}
@@ -407,16 +509,17 @@ static int ehci_hub_control (
break;
case USB_PORT_FEAT_POWER:
if (HCS_PPC (ehci->hcs_params))
- writel (temp & ~(PORT_RWC_BITS | PORT_POWER),
- &ehci->regs->port_status [wIndex]);
+ ehci_writel(ehci,
+ temp & ~(PORT_RWC_BITS | PORT_POWER),
+ status_reg);
break;
case USB_PORT_FEAT_C_CONNECTION:
- writel((temp & ~PORT_RWC_BITS) | PORT_CSC,
- &ehci->regs->port_status [wIndex]);
+ ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_CSC,
+ status_reg);
break;
case USB_PORT_FEAT_C_OVER_CURRENT:
- writel((temp & ~PORT_RWC_BITS) | PORT_OCC,
- &ehci->regs->port_status [wIndex]);
+ ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_OCC,
+ status_reg);
break;
case USB_PORT_FEAT_C_RESET:
/* GetPortStatus clears reset */
@@ -424,7 +527,7 @@ static int ehci_hub_control (
default:
goto error;
}
- readl (&ehci->regs->command); /* unblock posted write */
+ ehci_readl(ehci, &ehci->regs->command); /* unblock posted write */
break;
case GetHubDescriptor:
ehci_hub_descriptor (ehci, (struct usb_hub_descriptor *)
@@ -440,7 +543,7 @@ static int ehci_hub_control (
goto error;
wIndex--;
status = 0;
- temp = readl (&ehci->regs->port_status [wIndex]);
+ temp = ehci_readl(ehci, status_reg);
// wPortChange bits
if (temp & PORT_CSC)
@@ -451,42 +554,55 @@ static int ehci_hub_control (
status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;
/* whoever resumes must GetPortStatus to complete it!! */
- if ((temp & PORT_RESUME)
- && time_after (jiffies,
- ehci->reset_done [wIndex])) {
- status |= 1 << USB_PORT_FEAT_C_SUSPEND;
- ehci->reset_done [wIndex] = 0;
+ if (temp & PORT_RESUME) {
- /* stop resume signaling */
- temp = readl (&ehci->regs->port_status [wIndex]);
- writel (temp & ~(PORT_RWC_BITS | PORT_RESUME),
- &ehci->regs->port_status [wIndex]);
- retval = handshake (
- &ehci->regs->port_status [wIndex],
- PORT_RESUME, 0, 2000 /* 2msec */);
- if (retval != 0) {
- ehci_err (ehci, "port %d resume error %d\n",
- wIndex + 1, retval);
- goto error;
+ /* Remote Wakeup received? */
+ if (!ehci->reset_done[wIndex]) {
+ /* resume signaling for 20 msec */
+ ehci->reset_done[wIndex] = jiffies
+ + msecs_to_jiffies(20);
+ /* check the port again */
+ mod_timer(&ehci_to_hcd(ehci)->rh_timer,
+ ehci->reset_done[wIndex]);
+ }
+
+ /* resume completed? */
+ else if (time_after_eq(jiffies,
+ ehci->reset_done[wIndex])) {
+ status |= 1 << USB_PORT_FEAT_C_SUSPEND;
+ ehci->reset_done[wIndex] = 0;
+
+ /* stop resume signaling */
+ temp = ehci_readl(ehci, status_reg);
+ ehci_writel(ehci,
+ temp & ~(PORT_RWC_BITS | PORT_RESUME),
+ status_reg);
+ retval = handshake(ehci, status_reg,
+ PORT_RESUME, 0, 2000 /* 2msec */);
+ if (retval != 0) {
+ ehci_err(ehci,
+ "port %d resume error %d\n",
+ wIndex + 1, retval);
+ goto error;
+ }
+ temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
}
- temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
}
/* whoever resets must GetPortStatus to complete it!! */
if ((temp & PORT_RESET)
- && time_after (jiffies,
- ehci->reset_done [wIndex])) {
+ && time_after_eq(jiffies,
+ ehci->reset_done[wIndex])) {
status |= 1 << USB_PORT_FEAT_C_RESET;
ehci->reset_done [wIndex] = 0;
/* force reset to complete */
- writel (temp & ~(PORT_RWC_BITS | PORT_RESET),
- &ehci->regs->port_status [wIndex]);
+ ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_RESET),
+ status_reg);
/* REVISIT: some hardware needs 550+ usec to clear
* this bit; seems too long to spin routinely...
*/
- retval = handshake (
- &ehci->regs->port_status [wIndex],
+ retval = handshake(ehci, status_reg,
PORT_RESET, 0, 750);
if (retval != 0) {
ehci_err (ehci, "port %d reset error %d\n",
@@ -495,28 +611,41 @@ static int ehci_hub_control (
}
/* see what we found out */
- temp = check_reset_complete (ehci, wIndex,
- readl (&ehci->regs->port_status [wIndex]));
+ temp = check_reset_complete (ehci, wIndex, status_reg,
+ ehci_readl(ehci, status_reg));
}
- // don't show wPortStatus if it's owned by a companion hc
- if (!(temp & PORT_OWNER)) {
- if (temp & PORT_CONNECT) {
- status |= 1 << USB_PORT_FEAT_CONNECTION;
- // status may be from integrated TT
- status |= ehci_port_speed(ehci, temp);
- }
- if (temp & PORT_PE)
- status |= 1 << USB_PORT_FEAT_ENABLE;
- if (temp & (PORT_SUSPEND|PORT_RESUME))
- status |= 1 << USB_PORT_FEAT_SUSPEND;
- if (temp & PORT_OC)
- status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
- if (temp & PORT_RESET)
- status |= 1 << USB_PORT_FEAT_RESET;
- if (temp & PORT_POWER)
- status |= 1 << USB_PORT_FEAT_POWER;
+ /* transfer dedicated ports to the companion hc */
+ if ((temp & PORT_CONNECT) &&
+ test_bit(wIndex, &ehci->companion_ports)) {
+ temp &= ~PORT_RWC_BITS;
+ temp |= PORT_OWNER;
+ ehci_writel(ehci, temp, status_reg);
+ ehci_dbg(ehci, "port %d --> companion\n", wIndex + 1);
+ temp = ehci_readl(ehci, status_reg);
+ }
+
+ /*
+ * Even if OWNER is set, there's no harm letting khubd
+ * see the wPortStatus values (they should all be 0 except
+ * for PORT_POWER anyway).
+ */
+
+ if (temp & PORT_CONNECT) {
+ status |= 1 << USB_PORT_FEAT_CONNECTION;
+ // status may be from integrated TT
+ status |= ehci_port_speed(ehci, temp);
}
+ if (temp & PORT_PE)
+ status |= 1 << USB_PORT_FEAT_ENABLE;
+ if (temp & (PORT_SUSPEND|PORT_RESUME))
+ status |= 1 << USB_PORT_FEAT_SUSPEND;
+ if (temp & PORT_OC)
+ status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
+ if (temp & PORT_RESET)
+ status |= 1 << USB_PORT_FEAT_RESET;
+ if (temp & PORT_POWER)
+ status |= 1 << USB_PORT_FEAT_POWER;
#ifndef EHCI_VERBOSE_DEBUG
if (status & ~0xffff) /* only if wPortChange is interesting */
@@ -541,7 +670,7 @@ static int ehci_hub_control (
if (!wIndex || wIndex > ports)
goto error;
wIndex--;
- temp = readl (&ehci->regs->port_status [wIndex]);
+ temp = ehci_readl(ehci, status_reg);
if (temp & PORT_OWNER)
break;
@@ -555,13 +684,12 @@ static int ehci_hub_control (
goto error;
if (device_may_wakeup(&hcd->self.root_hub->dev))
temp |= PORT_WAKE_BITS;
- writel (temp | PORT_SUSPEND,
- &ehci->regs->port_status [wIndex]);
+ ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
break;
case USB_PORT_FEAT_POWER:
if (HCS_PPC (ehci->hcs_params))
- writel (temp | PORT_POWER,
- &ehci->regs->port_status [wIndex]);
+ ehci_writel(ehci, temp | PORT_POWER,
+ status_reg);
break;
case USB_PORT_FEAT_RESET:
if (temp & PORT_RESUME)
@@ -589,7 +717,7 @@ static int ehci_hub_control (
ehci->reset_done [wIndex] = jiffies
+ msecs_to_jiffies (50);
}
- writel (temp, &ehci->regs->port_status [wIndex]);
+ ehci_writel(ehci, temp, status_reg);
break;
/* For downstream facing ports (these): one hub port is put
@@ -604,13 +732,13 @@ static int ehci_hub_control (
ehci_quiesce(ehci);
ehci_halt(ehci);
temp |= selector << 16;
- writel (temp, &ehci->regs->port_status [wIndex]);
+ ehci_writel(ehci, temp, status_reg);
break;
default:
goto error;
}
- readl (&ehci->regs->command); /* unblock posted writes */
+ ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
break;
default:
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 4bc7970ba3e..12edc723ec7 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -38,7 +38,7 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)
if ((temp & (3 << 13)) == (1 << 13)) {
temp &= 0x1fff;
ehci->debug = ehci_to_hcd(ehci)->regs + temp;
- temp = readl(&ehci->debug->control);
+ temp = ehci_readl(ehci, &ehci->debug->control);
ehci_info(ehci, "debug port %d%s\n",
HCS_DEBUG_PORT(ehci->hcs_params),
(temp & DBGP_ENABLED)
@@ -71,8 +71,24 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
u32 temp;
int retval;
+ switch (pdev->vendor) {
+ case PCI_VENDOR_ID_TOSHIBA_2:
+ /* celleb's companion chip */
+ if (pdev->device == 0x01b5) {
+#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+ ehci->big_endian_mmio = 1;
+#else
+ ehci_warn(ehci,
+ "unsupported big endian Toshiba quirk\n");
+#endif
+ }
+ break;
+ }
+
ehci->caps = hcd->regs;
- ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase));
+ ehci->regs = hcd->regs +
+ HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+
dbg_hcs_params(ehci, "reset");
dbg_hcc_params(ehci, "reset");
@@ -101,7 +117,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
}
/* cache this readonly data; minimize chip reads */
- ehci->hcs_params = readl(&ehci->caps->hcs_params);
+ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
retval = ehci_halt(ehci);
if (retval)
@@ -235,8 +251,8 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
rc = -EINVAL;
goto bail;
}
- writel (0, &ehci->regs->intr_enable);
- (void)readl(&ehci->regs->intr_enable);
+ ehci_writel(ehci, 0, &ehci->regs->intr_enable);
+ (void)ehci_readl(ehci, &ehci->regs->intr_enable);
/* make sure snapshot being resumed re-enumerates everything */
if (message.event == PM_EVENT_PRETHAW) {
@@ -270,13 +286,13 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
/* If CF is still set, we maintained PCI Vaux power.
* Just undo the effect of ehci_pci_suspend().
*/
- if (readl(&ehci->regs->configured_flag) == FLAG_CF) {
+ if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
int mask = INTR_MASK;
if (!device_may_wakeup(&hcd->self.root_hub->dev))
mask &= ~STS_PCD;
- writel(mask, &ehci->regs->intr_enable);
- readl(&ehci->regs->intr_enable);
+ ehci_writel(ehci, mask, &ehci->regs->intr_enable);
+ ehci_readl(ehci, &ehci->regs->intr_enable);
return 0;
}
@@ -300,9 +316,9 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
/* here we "know" root ports should always stay powered */
ehci_port_power(ehci, 1);
- writel(ehci->command, &ehci->regs->command);
- writel(FLAG_CF, &ehci->regs->configured_flag);
- readl(&ehci->regs->command); /* unblock posted writes */
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
+ ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
+ ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
hcd->state = HC_STATE_SUSPENDED;
return 0;
diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c
new file mode 100644
index 00000000000..4d781a2a980
--- /dev/null
+++ b/drivers/usb/host/ehci-ps3.c
@@ -0,0 +1,193 @@
+/*
+ * PS3 EHCI Host Controller driver
+ *
+ * Copyright (C) 2006 Sony Computer Entertainment Inc.
+ * Copyright 2006 Sony Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <asm/ps3.h>
+
+static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
+{
+ int result;
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+
+ ehci->big_endian_mmio = 1;
+
+ ehci->caps = hcd->regs;
+ ehci->regs = hcd->regs + HC_LENGTH(ehci_readl(ehci,
+ &ehci->caps->hc_capbase));
+
+ dbg_hcs_params(ehci, "reset");
+ dbg_hcc_params(ehci, "reset");
+
+ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+
+ result = ehci_halt(ehci);
+
+ if (result)
+ return result;
+
+ result = ehci_init(hcd);
+
+ if (result)
+ return result;
+
+ ehci_port_power(ehci, 0);
+
+ return result;
+}
+
+static const struct hc_driver ps3_ehci_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "PS3 EHCI Host Controller",
+ .hcd_priv_size = sizeof(struct ehci_hcd),
+ .irq = ehci_irq,
+ .flags = HCD_MEMORY | HCD_USB2,
+ .reset = ps3_ehci_hc_reset,
+ .start = ehci_run,
+ .stop = ehci_stop,
+ .shutdown = ehci_shutdown,
+ .urb_enqueue = ehci_urb_enqueue,
+ .urb_dequeue = ehci_urb_dequeue,
+ .endpoint_disable = ehci_endpoint_disable,
+ .get_frame_number = ehci_get_frame,
+ .hub_status_data = ehci_hub_status_data,
+ .hub_control = ehci_hub_control,
+#if defined(CONFIG_PM)
+ .bus_suspend = ehci_bus_suspend,
+ .bus_resume = ehci_bus_resume,
+#endif
+};
+
+#if !defined(DEBUG)
+#undef dev_dbg
+static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg(
+ const struct device *_dev, const char *fmt, ...) {return 0;}
+#endif
+
+
+static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev)
+{
+ int result;
+ struct usb_hcd *hcd;
+ unsigned int virq;
+ static u64 dummy_mask = DMA_32BIT_MASK;
+
+ if (usb_disabled()) {
+ result = -ENODEV;
+ goto fail_start;
+ }
+
+ result = ps3_mmio_region_create(dev->m_region);
+
+ if (result) {
+ dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n",
+ __func__, __LINE__);
+ result = -EPERM;
+ goto fail_mmio;
+ }
+
+ dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
+ __LINE__, dev->m_region->lpar_addr);
+
+ result = ps3_alloc_io_irq(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq);
+
+ if (result) {
+ dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n",
+ __func__, __LINE__, virq);
+ result = -EPERM;
+ goto fail_irq;
+ }
+
+ dev->core.power.power_state = PMSG_ON;
+ dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */
+
+ hcd = usb_create_hcd(&ps3_ehci_hc_driver, &dev->core, dev->core.bus_id);
+
+ if (!hcd) {
+ dev_dbg(&dev->core, "%s:%d: usb_create_hcd failed\n", __func__,
+ __LINE__);
+ result = -ENOMEM;
+ goto fail_create_hcd;
+ }
+
+ hcd->rsrc_start = dev->m_region->lpar_addr;
+ hcd->rsrc_len = dev->m_region->len;
+ hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len);
+
+ if (!hcd->regs) {
+ dev_dbg(&dev->core, "%s:%d: ioremap failed\n", __func__,
+ __LINE__);
+ result = -EPERM;
+ goto fail_ioremap;
+ }
+
+ dev_dbg(&dev->core, "%s:%d: hcd->rsrc_start %lxh\n", __func__, __LINE__,
+ (unsigned long)hcd->rsrc_start);
+ dev_dbg(&dev->core, "%s:%d: hcd->rsrc_len %lxh\n", __func__, __LINE__,
+ (unsigned long)hcd->rsrc_len);
+ dev_dbg(&dev->core, "%s:%d: hcd->regs %lxh\n", __func__, __LINE__,
+ (unsigned long)hcd->regs);
+ dev_dbg(&dev->core, "%s:%d: virq %lu\n", __func__, __LINE__,
+ (unsigned long)virq);
+
+ ps3_system_bus_set_driver_data(dev, hcd);
+
+ result = usb_add_hcd(hcd, virq, IRQF_DISABLED);
+
+ if (result) {
+ dev_dbg(&dev->core, "%s:%d: usb_add_hcd failed (%d)\n",
+ __func__, __LINE__, result);
+ goto fail_add_hcd;
+ }
+
+ return result;
+
+fail_add_hcd:
+ iounmap(hcd->regs);
+fail_ioremap:
+ usb_put_hcd(hcd);
+fail_create_hcd:
+ ps3_free_io_irq(virq);
+fail_irq:
+ ps3_free_mmio_region(dev->m_region);
+fail_mmio:
+fail_start:
+ return result;
+}
+
+static int ps3_ehci_sb_remove(struct ps3_system_bus_device *dev)
+{
+ struct usb_hcd *hcd =
+ (struct usb_hcd *)ps3_system_bus_get_driver_data(dev);
+
+ usb_put_hcd(hcd);
+ ps3_system_bus_set_driver_data(dev, NULL);
+
+ return 0;
+}
+
+MODULE_ALIAS("ps3-ehci");
+
+static struct ps3_system_bus_driver ps3_ehci_sb_driver = {
+ .match_id = PS3_MATCH_ID_EHCI,
+ .core = {
+ .name = "ps3-ehci-driver",
+ },
+ .probe = ps3_ehci_sb_probe,
+ .remove = ps3_ehci_sb_remove,
+};
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 62e46dc60e8..e7fbbd00e7c 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -789,13 +789,14 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
head = ehci->async;
timer_action_done (ehci, TIMER_ASYNC_OFF);
if (!head->qh_next.qh) {
- u32 cmd = readl (&ehci->regs->command);
+ u32 cmd = ehci_readl(ehci, &ehci->regs->command);
if (!(cmd & CMD_ASE)) {
/* in case a clear of CMD_ASE didn't take yet */
- (void) handshake (&ehci->regs->status, STS_ASS, 0, 150);
+ (void)handshake(ehci, &ehci->regs->status,
+ STS_ASS, 0, 150);
cmd |= CMD_ASE | CMD_RUN;
- writel (cmd, &ehci->regs->command);
+ ehci_writel(ehci, cmd, &ehci->regs->command);
ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
/* posted write need not be known to HC yet ... */
}
@@ -1007,7 +1008,7 @@ static void end_unlink_async (struct ehci_hcd *ehci)
static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
{
- int cmd = readl (&ehci->regs->command);
+ int cmd = ehci_readl(ehci, &ehci->regs->command);
struct ehci_qh *prev;
#ifdef DEBUG
@@ -1025,7 +1026,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
if (ehci_to_hcd(ehci)->state != HC_STATE_HALT
&& !ehci->reclaim) {
/* ... and CMD_IAAD clear */
- writel (cmd & ~CMD_ASE, &ehci->regs->command);
+ ehci_writel(ehci, cmd & ~CMD_ASE,
+ &ehci->regs->command);
wmb ();
// handshake later, if we need to
timer_action_done (ehci, TIMER_ASYNC_OFF);
@@ -1054,8 +1056,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
ehci->reclaim_ready = 0;
cmd |= CMD_IAAD;
- writel (cmd, &ehci->regs->command);
- (void) readl (&ehci->regs->command);
+ ehci_writel(ehci, cmd, &ehci->regs->command);
+ (void)ehci_readl(ehci, &ehci->regs->command);
timer_action (ehci, TIMER_IAA_WATCHDOG);
}
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 65c402a0fa7..7b5ae7111f2 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -433,20 +433,20 @@ static int enable_periodic (struct ehci_hcd *ehci)
/* did clearing PSE did take effect yet?
* takes effect only at frame boundaries...
*/
- status = handshake (&ehci->regs->status, STS_PSS, 0, 9 * 125);
+ status = handshake(ehci, &ehci->regs->status, STS_PSS, 0, 9 * 125);
if (status != 0) {
ehci_to_hcd(ehci)->state = HC_STATE_HALT;
return status;
}
- cmd = readl (&ehci->regs->command) | CMD_PSE;
- writel (cmd, &ehci->regs->command);
+ cmd = ehci_readl(ehci, &ehci->regs->command) | CMD_PSE;
+ ehci_writel(ehci, cmd, &ehci->regs->command);
/* posted write ... PSS happens later */
ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
/* make sure ehci_work scans these */
- ehci->next_uframe = readl (&ehci->regs->frame_index)
- % (ehci->periodic_size << 3);
+ ehci->next_uframe = ehci_readl(ehci, &ehci->regs->frame_index)
+ % (ehci->periodic_size << 3);
return 0;
}
@@ -458,14 +458,14 @@ static int disable_periodic (struct ehci_hcd *ehci)
/* did setting PSE not take effect yet?
* takes effect only at frame boundaries...
*/
- status = handshake (&ehci->regs->status, STS_PSS, STS_PSS, 9 * 125);
+ status = handshake(ehci, &ehci->regs->status, STS_PSS, STS_PSS, 9 * 125);
if (status != 0) {
ehci_to_hcd(ehci)->state = HC_STATE_HALT;
return status;
}
- cmd = readl (&ehci->regs->command) & ~CMD_PSE;
- writel (cmd, &ehci->regs->command);
+ cmd = ehci_readl(ehci, &ehci->regs->command) & ~CMD_PSE;
+ ehci_writel(ehci, cmd, &ehci->regs->command);
/* posted write ... */
ehci->next_uframe = -1;
@@ -1336,7 +1336,7 @@ iso_stream_schedule (
goto fail;
}
- now = readl (&ehci->regs->frame_index) % mod;
+ now = ehci_readl(ehci, &ehci->regs->frame_index) % mod;
/* when's the last uframe this urb could start? */
max = now + mod;
@@ -2088,7 +2088,7 @@ scan_periodic (struct ehci_hcd *ehci)
*/
now_uframe = ehci->next_uframe;
if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
- clock = readl (&ehci->regs->frame_index);
+ clock = ehci_readl(ehci, &ehci->regs->frame_index);
else
clock = now_uframe + mod - 1;
clock %= mod;
@@ -2213,7 +2213,7 @@ restart:
if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
break;
ehci->next_uframe = now_uframe;
- now = readl (&ehci->regs->frame_index) % mod;
+ now = ehci_readl(ehci, &ehci->regs->frame_index) % mod;
if (now_uframe == now)
break;
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 74dbc6c8228..46fa57a520d 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -74,7 +74,11 @@ struct ehci_hcd { /* one per controller */
/* per root hub port */
unsigned long reset_done [EHCI_MAX_ROOT_PORTS];
- unsigned long bus_suspended;
+ /* bit vectors (one bit per port) */
+ unsigned long bus_suspended; /* which ports were
+ already suspended at the start of a bus suspend */
+ unsigned long companion_ports; /* which ports are
+ dedicated to the companion controller */
/* per-HC memory pools (could be per-bus, but ...) */
struct dma_pool *qh_pool; /* qh per active urb */
@@ -92,6 +96,7 @@ struct ehci_hcd { /* one per controller */
unsigned is_tdi_rh_tt:1; /* TDI roothub with TT */
unsigned no_selective_suspend:1;
unsigned has_fsl_port_bug:1; /* FreeScale */
+ unsigned big_endian_mmio:1;
u8 sbrn; /* packed release number */
@@ -651,6 +656,45 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
#define ehci_has_fsl_portno_bug(e) (0)
#endif
+/*
+ * While most USB host controllers implement their registers in
+ * little-endian format, a minority (celleb companion chip) implement
+ * them in big endian format.
+ *
+ * This attempts to support either format at compile time without a
+ * runtime penalty, or both formats with the additional overhead
+ * of checking a flag bit.
+ */
+
+#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+#define ehci_big_endian_mmio(e) ((e)->big_endian_mmio)
+#else
+#define ehci_big_endian_mmio(e) 0
+#endif
+
+static inline unsigned int ehci_readl (const struct ehci_hcd *ehci,
+ __u32 __iomem * regs)
+{
+#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+ return ehci_big_endian_mmio(ehci) ?
+ readl_be(regs) :
+ readl(regs);
+#else
+ return readl(regs);
+#endif
+}
+
+static inline void ehci_writel (const struct ehci_hcd *ehci,
+ const unsigned int val, __u32 __iomem *regs)
+{
+#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+ ehci_big_endian_mmio(ehci) ?
+ writel_be(val, regs) :
+ writel(val, regs);
+#else
+ writel(val, regs);
+#endif
+}
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index cc405512fa1..93034648727 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -170,7 +170,6 @@ static int usb_hcd_at91_remove(struct usb_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);
@@ -271,8 +270,6 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg)
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,
@@ -293,6 +290,11 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg)
static int ohci_hcd_at91_drv_resume(struct platform_device *pdev)
{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+ if (device_may_wakeup(&pdev->dev))
+ disable_irq_wake(hcd->irq);
+
if (!clocked) {
clk_enable(iclk);
clk_enable(fclk);
@@ -320,18 +322,3 @@ static struct platform_driver ohci_hcd_at91_driver = {
},
};
-static int __init ohci_hcd_at91_init (void)
-{
- if (usb_disabled())
- return -ENODEV;
-
- return platform_driver_register(&ohci_hcd_at91_driver);
-}
-
-static void __exit ohci_hcd_at91_cleanup (void)
-{
- platform_driver_unregister(&ohci_hcd_at91_driver);
-}
-
-module_init (ohci_hcd_at91_init);
-module_exit (ohci_hcd_at91_cleanup);
diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c
index e70b2430e2a..663a0600b6e 100644
--- a/drivers/usb/host/ohci-au1xxx.c
+++ b/drivers/usb/host/ohci-au1xxx.c
@@ -345,19 +345,3 @@ static struct platform_driver ohci_hcd_au1xxx_driver = {
},
};
-static int __init ohci_hcd_au1xxx_init (void)
-{
- pr_debug (DRIVER_INFO " (Au1xxx)");
- pr_debug ("block sizes: ed %d td %d\n",
- sizeof (struct ed), sizeof (struct td));
-
- return platform_driver_register(&ohci_hcd_au1xxx_driver);
-}
-
-static void __exit ohci_hcd_au1xxx_cleanup (void)
-{
- platform_driver_unregister(&ohci_hcd_au1xxx_driver);
-}
-
-module_init (ohci_hcd_au1xxx_init);
-module_exit (ohci_hcd_au1xxx_cleanup);
diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c
index 3348b07f0fe..44c60fba76e 100644
--- a/drivers/usb/host/ohci-ep93xx.c
+++ b/drivers/usb/host/ohci-ep93xx.c
@@ -214,15 +214,3 @@ static struct platform_driver ohci_hcd_ep93xx_driver = {
},
};
-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 c1c1d871aba..fa6a7ceaa0d 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -855,63 +855,167 @@ MODULE_LICENSE ("GPL");
#ifdef CONFIG_PCI
#include "ohci-pci.c"
+#define PCI_DRIVER ohci_pci_driver
#endif
#ifdef CONFIG_SA1111
#include "ohci-sa1111.c"
+#define SA1111_DRIVER ohci_hcd_sa1111_driver
#endif
#ifdef CONFIG_ARCH_S3C2410
#include "ohci-s3c2410.c"
+#define PLATFORM_DRIVER ohci_hcd_s3c2410_driver
#endif
#ifdef CONFIG_ARCH_OMAP
#include "ohci-omap.c"
+#define PLATFORM_DRIVER ohci_hcd_omap_driver
#endif
#ifdef CONFIG_ARCH_LH7A404
#include "ohci-lh7a404.c"
+#define PLATFORM_DRIVER ohci_hcd_lh7a404_driver
#endif
#ifdef CONFIG_PXA27x
#include "ohci-pxa27x.c"
+#define PLATFORM_DRIVER ohci_hcd_pxa27x_driver
#endif
#ifdef CONFIG_ARCH_EP93XX
#include "ohci-ep93xx.c"
+#define PLATFORM_DRIVER ohci_hcd_ep93xx_driver
#endif
#ifdef CONFIG_SOC_AU1X00
#include "ohci-au1xxx.c"
+#define PLATFORM_DRIVER ohci_hcd_au1xxx_driver
#endif
#ifdef CONFIG_PNX8550
#include "ohci-pnx8550.c"
+#define PLATFORM_DRIVER ohci_hcd_pnx8550_driver
#endif
#ifdef CONFIG_USB_OHCI_HCD_PPC_SOC
#include "ohci-ppc-soc.c"
+#define PLATFORM_DRIVER ohci_hcd_ppc_soc_driver
#endif
#ifdef CONFIG_ARCH_AT91
#include "ohci-at91.c"
+#define PLATFORM_DRIVER ohci_hcd_at91_driver
#endif
#ifdef CONFIG_ARCH_PNX4008
#include "ohci-pnx4008.c"
+#define PLATFORM_DRIVER usb_hcd_pnx4008_driver
#endif
-#if !(defined(CONFIG_PCI) \
- || defined(CONFIG_SA1111) \
- || defined(CONFIG_ARCH_S3C2410) \
- || 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_AT91) \
- || defined (CONFIG_ARCH_PNX4008) \
- )
+
+#ifdef CONFIG_USB_OHCI_HCD_PPC_OF
+#include "ohci-ppc-of.c"
+#define OF_PLATFORM_DRIVER ohci_hcd_ppc_of_driver
+#endif
+
+#ifdef CONFIG_PPC_PS3
+#include "ohci-ps3.c"
+#define PS3_SYSTEM_BUS_DRIVER ps3_ohci_sb_driver
+#endif
+
+#if !defined(PCI_DRIVER) && \
+ !defined(PLATFORM_DRIVER) && \
+ !defined(OF_PLATFORM_DRIVER) && \
+ !defined(SA1111_DRIVER) && \
+ !defined(PS3_SYSTEM_BUS_DRIVER)
#error "missing bus glue for ohci-hcd"
#endif
+
+static int __init ohci_hcd_mod_init(void)
+{
+ int retval = 0;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ printk (KERN_DEBUG "%s: " DRIVER_INFO "\n", hcd_name);
+ pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
+ sizeof (struct ed), sizeof (struct td));
+
+#ifdef PS3_SYSTEM_BUS_DRIVER
+ retval = ps3_system_bus_driver_register(&PS3_SYSTEM_BUS_DRIVER);
+ if (retval < 0)
+ goto error_ps3;
+#endif
+
+#ifdef PLATFORM_DRIVER
+ retval = platform_driver_register(&PLATFORM_DRIVER);
+ if (retval < 0)
+ goto error_platform;
+#endif
+
+#ifdef OF_PLATFORM_DRIVER
+ retval = of_register_platform_driver(&OF_PLATFORM_DRIVER);
+ if (retval < 0)
+ goto error_of_platform;
+#endif
+
+#ifdef SA1111_DRIVER
+ retval = sa1111_driver_register(&SA1111_DRIVER);
+ if (retval < 0)
+ goto error_sa1111;
+#endif
+
+#ifdef PCI_DRIVER
+ retval = pci_register_driver(&PCI_DRIVER);
+ if (retval < 0)
+ goto error_pci;
+#endif
+
+ return retval;
+
+ /* Error path */
+#ifdef PCI_DRIVER
+ error_pci:
+#endif
+#ifdef SA1111_DRIVER
+ sa1111_driver_unregister(&SA1111_DRIVER);
+ error_sa1111:
+#endif
+#ifdef OF_PLATFORM_DRIVER
+ of_unregister_platform_driver(&OF_PLATFORM_DRIVER);
+ error_of_platform:
+#endif
+#ifdef PLATFORM_DRIVER
+ platform_driver_unregister(&PLATFORM_DRIVER);
+ error_platform:
+#endif
+#ifdef PS3_SYSTEM_BUS_DRIVER
+ ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+ error_ps3:
+#endif
+ return retval;
+}
+module_init(ohci_hcd_mod_init);
+
+static void __exit ohci_hcd_mod_exit(void)
+{
+#ifdef PCI_DRIVER
+ pci_unregister_driver(&PCI_DRIVER);
+#endif
+#ifdef SA1111_DRIVER
+ sa1111_driver_unregister(&SA1111_DRIVER);
+#endif
+#ifdef OF_PLATFORM_DRIVER
+ of_unregister_platform_driver(&OF_PLATFORM_DRIVER);
+#endif
+#ifdef PLATFORM_DRIVER
+ platform_driver_unregister(&PLATFORM_DRIVER);
+#endif
+#ifdef PS3_SYSTEM_BUS_DRIVER
+ ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+#endif
+}
+module_exit(ohci_hcd_mod_exit);
+
diff --git a/drivers/usb/host/ohci-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c
index e9807cf73a2..4a043abd85e 100644
--- a/drivers/usb/host/ohci-lh7a404.c
+++ b/drivers/usb/host/ohci-lh7a404.c
@@ -251,19 +251,3 @@ static struct platform_driver ohci_hcd_lh7a404_driver = {
},
};
-static int __init ohci_hcd_lh7a404_init (void)
-{
- pr_debug (DRIVER_INFO " (LH7A404)");
- pr_debug ("block sizes: ed %d td %d\n",
- sizeof (struct ed), sizeof (struct td));
-
- return platform_driver_register(&ohci_hcd_lh7a404_driver);
-}
-
-static void __exit ohci_hcd_lh7a404_cleanup (void)
-{
- platform_driver_unregister(&ohci_hcd_lh7a404_driver);
-}
-
-module_init (ohci_hcd_lh7a404_init);
-module_exit (ohci_hcd_lh7a404_cleanup);
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index 27be1f93688..5cfa3d1c441 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -544,22 +544,3 @@ static struct platform_driver ohci_hcd_omap_driver = {
},
};
-static int __init ohci_hcd_omap_init (void)
-{
- printk (KERN_DEBUG "%s: " DRIVER_INFO " (OMAP)\n", hcd_name);
- if (usb_disabled())
- return -ENODEV;
-
- pr_debug("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
- sizeof (struct ed), sizeof (struct td));
-
- return platform_driver_register(&ohci_hcd_omap_driver);
-}
-
-static void __exit ohci_hcd_omap_cleanup (void)
-{
- platform_driver_unregister(&ohci_hcd_omap_driver);
-}
-
-module_init (ohci_hcd_omap_init);
-module_exit (ohci_hcd_omap_cleanup);
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index 596e0b41e60..b331ac4d0d6 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -20,79 +20,154 @@
/*-------------------------------------------------------------------------*/
-static int
-ohci_pci_reset (struct usb_hcd *hcd)
+/* AMD 756, for most chips (early revs), corrupts register
+ * values on read ... so enable the vendor workaround.
+ */
+static int __devinit ohci_quirk_amd756(struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
- ohci_hcd_init (ohci);
- return ohci_init (ohci);
+ ohci->flags = OHCI_QUIRK_AMD756;
+ ohci_dbg (ohci, "AMD756 erratum 4 workaround\n");
+
+ /* also erratum 10 (suspend/resume issues) */
+ device_init_wakeup(&hcd->self.root_hub->dev, 0);
+
+ return 0;
}
-static int __devinit
-ohci_pci_start (struct usb_hcd *hcd)
+/* Apple's OHCI driver has a lot of bizarre workarounds
+ * for this chip. Evidently control and bulk lists
+ * can get confused. (B&W G3 models, and ...)
+ */
+static int __devinit ohci_quirk_opti(struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
- int ret;
- /* REVISIT this whole block should move to reset(), which handles
- * all the other one-time init.
+ ohci_dbg (ohci, "WARNING: OPTi workarounds unavailable\n");
+
+ return 0;
+}
+
+/* Check for NSC87560. We have to look at the bridge (fn1) to
+ * identify the USB (fn2). This quirk might apply to more or
+ * even all NSC stuff.
+ */
+static int __devinit ohci_quirk_ns(struct usb_hcd *hcd)
+{
+ struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
+ struct pci_dev *b;
+
+ b = pci_get_slot (pdev->bus, PCI_DEVFN (PCI_SLOT (pdev->devfn), 1));
+ if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO
+ && b->vendor == PCI_VENDOR_ID_NS) {
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+
+ ohci->flags |= OHCI_QUIRK_SUPERIO;
+ ohci_dbg (ohci, "Using NSC SuperIO setup\n");
+ }
+ pci_dev_put(b);
+
+ return 0;
+}
+
+/* Check for Compaq's ZFMicro chipset, which needs short
+ * delays before control or bulk queues get re-activated
+ * in finish_unlinks()
+ */
+static int __devinit ohci_quirk_zfmicro(struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+
+ ohci->flags |= OHCI_QUIRK_ZFMICRO;
+ ohci_dbg (ohci, "enabled Compaq ZFMicro chipset quirk\n");
+
+ return 0;
+}
+
+/* Check for Toshiba SCC OHCI which has big endian registers
+ * and little endian in memory data structures
+ */
+static int __devinit ohci_quirk_toshiba_scc(struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+
+ /* That chip is only present in the southbridge of some
+ * cell based platforms which are supposed to select
+ * CONFIG_USB_OHCI_BIG_ENDIAN_MMIO. We verify here if
+ * that was the case though.
+ */
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
+ ohci->flags |= OHCI_QUIRK_BE_MMIO;
+ ohci_dbg (ohci, "enabled big endian Toshiba quirk\n");
+ return 0;
+#else
+ ohci_err (ohci, "unsupported big endian Toshiba quirk\n");
+ return -ENXIO;
+#endif
+}
+
+/* List of quirks for OHCI */
+static const struct pci_device_id ohci_pci_quirks[] = {
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x740c),
+ .driver_data = (unsigned long)ohci_quirk_amd756,
+ },
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_OPTI, 0xc861),
+ .driver_data = (unsigned long)ohci_quirk_opti,
+ },
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_ANY_ID),
+ .driver_data = (unsigned long)ohci_quirk_ns,
+ },
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xa0f8),
+ .driver_data = (unsigned long)ohci_quirk_zfmicro,
+ },
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, 0x01b6),
+ .driver_data = (unsigned long)ohci_quirk_toshiba_scc,
+ },
+ /* FIXME for some of the early AMD 760 southbridges, OHCI
+ * won't work at all. blacklist them.
*/
+
+ {},
+};
+
+static int ohci_pci_reset (struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+ int ret = 0;
+
if (hcd->self.controller) {
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
+ const struct pci_device_id *quirk_id;
- /* AMD 756, for most chips (early revs), corrupts register
- * values on read ... so enable the vendor workaround.
- */
- if (pdev->vendor == PCI_VENDOR_ID_AMD
- && pdev->device == 0x740c) {
- ohci->flags = OHCI_QUIRK_AMD756;
- ohci_dbg (ohci, "AMD756 erratum 4 workaround\n");
- /* also erratum 10 (suspend/resume issues) */
- device_init_wakeup(&hcd->self.root_hub->dev, 0);
+ quirk_id = pci_match_id(ohci_pci_quirks, pdev);
+ if (quirk_id != NULL) {
+ int (*quirk)(struct usb_hcd *ohci);
+ quirk = (void *)quirk_id->driver_data;
+ ret = quirk(hcd);
}
+ }
+ if (ret == 0) {
+ ohci_hcd_init (ohci);
+ return ohci_init (ohci);
+ }
+ return ret;
+}
- /* FIXME for some of the early AMD 760 southbridges, OHCI
- * won't work at all. blacklist them.
- */
-
- /* Apple's OHCI driver has a lot of bizarre workarounds
- * for this chip. Evidently control and bulk lists
- * can get confused. (B&W G3 models, and ...)
- */
- else if (pdev->vendor == PCI_VENDOR_ID_OPTI
- && pdev->device == 0xc861) {
- ohci_dbg (ohci,
- "WARNING: OPTi workarounds unavailable\n");
- }
- /* Check for NSC87560. We have to look at the bridge (fn1) to
- * identify the USB (fn2). This quirk might apply to more or
- * even all NSC stuff.
- */
- else if (pdev->vendor == PCI_VENDOR_ID_NS) {
- struct pci_dev *b;
-
- b = pci_get_slot (pdev->bus,
- PCI_DEVFN (PCI_SLOT (pdev->devfn), 1));
- if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO
- && b->vendor == PCI_VENDOR_ID_NS) {
- ohci->flags |= OHCI_QUIRK_SUPERIO;
- ohci_dbg (ohci, "Using NSC SuperIO setup\n");
- }
- pci_dev_put(b);
- }
+static int __devinit ohci_pci_start (struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+ int ret;
- /* Check for Compaq's ZFMicro chipset, which needs short
- * delays before control or bulk queues get re-activated
- * in finish_unlinks()
- */
- else if (pdev->vendor == PCI_VENDOR_ID_COMPAQ
- && pdev->device == 0xa0f8) {
- ohci->flags |= OHCI_QUIRK_ZFMICRO;
- ohci_dbg (ohci,
- "enabled Compaq ZFMicro chipset quirk\n");
- }
+#ifdef CONFIG_PM /* avoid warnings about unused pdev */
+ if (hcd->self.controller) {
+ struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
/* RWC may not be set for add-in PCI cards, since boot
* firmware probably ignored them. This transfers PCI
@@ -101,16 +176,14 @@ ohci_pci_start (struct usb_hcd *hcd)
if (device_may_wakeup(&pdev->dev))
ohci->hc_control |= OHCI_CTRL_RWC;
}
+#endif /* CONFIG_PM */
- /* NOTE: there may have already been a first reset, to
- * keep bios/smm irqs from making trouble
- */
- if ((ret = ohci_run (ohci)) < 0) {
+ ret = ohci_run (ohci);
+ if (ret < 0) {
ohci_err (ohci, "can't start\n");
ohci_stop (hcd);
- return ret;
}
- return 0;
+ return ret;
}
#ifdef CONFIG_PM
@@ -238,23 +311,3 @@ static struct pci_driver ohci_pci_driver = {
.shutdown = usb_hcd_pci_shutdown,
};
-
-static int __init ohci_hcd_pci_init (void)
-{
- printk (KERN_DEBUG "%s: " DRIVER_INFO " (PCI)\n", hcd_name);
- if (usb_disabled())
- return -ENODEV;
-
- pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
- sizeof (struct ed), sizeof (struct td));
- return pci_register_driver (&ohci_pci_driver);
-}
-module_init (ohci_hcd_pci_init);
-
-/*-------------------------------------------------------------------------*/
-
-static void __exit ohci_hcd_pci_cleanup (void)
-{
- pci_unregister_driver (&ohci_pci_driver);
-}
-module_exit (ohci_hcd_pci_cleanup);
diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c
index 3a8cbfb6905..893b172384d 100644
--- a/drivers/usb/host/ohci-pnx4008.c
+++ b/drivers/usb/host/ohci-pnx4008.c
@@ -465,15 +465,3 @@ static struct platform_driver usb_hcd_pnx4008_driver = {
.remove = usb_hcd_pnx4008_remove,
};
-static int __init usb_hcd_pnx4008_init(void)
-{
- return platform_driver_register(&usb_hcd_pnx4008_driver);
-}
-
-static void __exit usb_hcd_pnx4008_cleanup(void)
-{
- return platform_driver_unregister(&usb_hcd_pnx4008_driver);
-}
-
-module_init(usb_hcd_pnx4008_init);
-module_exit(usb_hcd_pnx4008_cleanup);
diff --git a/drivers/usb/host/ohci-pnx8550.c b/drivers/usb/host/ohci-pnx8550.c
index 6922b91b170..de45eb0051a 100644
--- a/drivers/usb/host/ohci-pnx8550.c
+++ b/drivers/usb/host/ohci-pnx8550.c
@@ -240,19 +240,3 @@ static struct platform_driver ohci_hcd_pnx8550_driver = {
.remove = ohci_hcd_pnx8550_drv_remove,
};
-static int __init ohci_hcd_pnx8550_init (void)
-{
- pr_debug (DRIVER_INFO " (pnx8550)");
- pr_debug ("block sizes: ed %d td %d\n",
- sizeof (struct ed), sizeof (struct td));
-
- return platform_driver_register(&ohci_hcd_pnx8550_driver);
-}
-
-static void __exit ohci_hcd_pnx8550_cleanup (void)
-{
- platform_driver_unregister(&ohci_hcd_pnx8550_driver);
-}
-
-module_init (ohci_hcd_pnx8550_init);
-module_exit (ohci_hcd_pnx8550_cleanup);
diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
new file mode 100644
index 00000000000..08e237c7bc4
--- /dev/null
+++ b/drivers/usb/host/ohci-ppc-of.c
@@ -0,0 +1,232 @@
+/*
+ * 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
+ * (C) Copyright 2006 Sylvain Munaut <tnt@246tNt.com>
+ *
+ * Bus glue for OHCI HC on the of_platform bus
+ *
+ * Modified for of_platform bus from ohci-sa1111.c
+ *
+ * This file is licenced under the GPL.
+ */
+
+#include <linux/signal.h>
+
+#include <asm/of_platform.h>
+#include <asm/prom.h>
+
+
+static int __devinit
+ohci_ppc_of_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", ohci_to_hcd(ohci)->self.bus_name);
+ ohci_stop(hcd);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct hc_driver ohci_ppc_of_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "OF OHCI",
+ .hcd_priv_size = sizeof(struct ohci_hcd),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ohci_irq,
+ .flags = HCD_USB11 | HCD_MEMORY,
+
+ /*
+ * basic lifecycle operations
+ */
+ .start = ohci_ppc_of_start,
+ .stop = ohci_stop,
+ .shutdown = ohci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = ohci_urb_enqueue,
+ .urb_dequeue = ohci_urb_dequeue,
+ .endpoint_disable = ohci_endpoint_disable,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = ohci_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = ohci_hub_status_data,
+ .hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
+#ifdef CONFIG_PM
+ .bus_suspend = ohci_bus_suspend,
+ .bus_resume = ohci_bus_resume,
+#endif
+ .start_port_reset = ohci_start_port_reset,
+};
+
+
+static int __devinit
+ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
+{
+ struct device_node *dn = op->node;
+ struct usb_hcd *hcd;
+ struct ohci_hcd *ohci;
+ struct resource res;
+ int irq;
+
+ int rv;
+ int is_bigendian;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ is_bigendian =
+ device_is_compatible(dn, "ohci-bigendian") ||
+ device_is_compatible(dn, "ohci-be");
+
+ dev_dbg(&op->dev, "initializing PPC-OF USB Controller\n");
+
+ rv = of_address_to_resource(dn, 0, &res);
+ if (rv)
+ return rv;
+
+ hcd = usb_create_hcd(&ohci_ppc_of_hc_driver, &op->dev, "PPC-OF USB");
+ if (!hcd)
+ return -ENOMEM;
+
+ hcd->rsrc_start = res.start;
+ hcd->rsrc_len = res.end - res.start + 1;
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+ printk(KERN_ERR __FILE__ ": request_mem_region failed\n");
+ rv = -EBUSY;
+ goto err_rmr;
+ }
+
+ irq = irq_of_parse_and_map(dn, 0);
+ if (irq == NO_IRQ) {
+ printk(KERN_ERR __FILE__ ": irq_of_parse_and_map failed\n");
+ rv = -EBUSY;
+ goto err_irq;
+ }
+
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs) {
+ printk(KERN_ERR __FILE__ ": ioremap failed\n");
+ rv = -ENOMEM;
+ goto err_ioremap;
+ }
+
+ ohci = hcd_to_ohci(hcd);
+ if (is_bigendian)
+ ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
+
+ ohci_hcd_init(ohci);
+
+ rv = usb_add_hcd(hcd, irq, 0);
+ if (rv == 0)
+ return 0;
+
+ iounmap(hcd->regs);
+err_ioremap:
+ irq_dispose_mapping(irq);
+err_irq:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err_rmr:
+ usb_put_hcd(hcd);
+
+ return rv;
+}
+
+static int ohci_hcd_ppc_of_remove(struct of_device *op)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
+ dev_set_drvdata(&op->dev, NULL);
+
+ dev_dbg(&op->dev, "stopping PPC-OF USB Controller\n");
+
+ usb_remove_hcd(hcd);
+
+ iounmap(hcd->regs);
+ irq_dispose_mapping(hcd->irq);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+
+ usb_put_hcd(hcd);
+
+ return 0;
+}
+
+static int ohci_hcd_ppc_of_shutdown(struct of_device *op)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
+
+ if (hcd->driver->shutdown)
+ hcd->driver->shutdown(hcd);
+
+ return 0;
+}
+
+
+static struct of_device_id ohci_hcd_ppc_of_match[] = {
+#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_BE
+ {
+ .name = "usb",
+ .compatible = "ohci-bigendian",
+ },
+ {
+ .name = "usb",
+ .compatible = "ohci-be",
+ },
+#endif
+#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_LE
+ {
+ .name = "usb",
+ .compatible = "ohci-littledian",
+ },
+ {
+ .name = "usb",
+ .compatible = "ohci-le",
+ },
+#endif
+ {},
+};
+MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_match);
+
+#if !defined(CONFIG_USB_OHCI_HCD_PPC_OF_BE) && \
+ !defined(CONFIG_USB_OHCI_HCD_PPC_OF_LE)
+#error "No endianess selected for ppc-of-ohci"
+#endif
+
+
+static struct of_platform_driver ohci_hcd_ppc_of_driver = {
+ .name = "ppc-of-ohci",
+ .match_table = ohci_hcd_ppc_of_match,
+ .probe = ohci_hcd_ppc_of_probe,
+ .remove = ohci_hcd_ppc_of_remove,
+ .shutdown = ohci_hcd_ppc_of_shutdown,
+#ifdef CONFIG_PM
+ /*.suspend = ohci_hcd_ppc_soc_drv_suspend,*/
+ /*.resume = ohci_hcd_ppc_soc_drv_resume,*/
+#endif
+ .driver = {
+ .name = "ppc-of-ohci",
+ .owner = THIS_MODULE,
+ },
+};
+
diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c
index e1a7eb81731..1a2e1777ca6 100644
--- a/drivers/usb/host/ohci-ppc-soc.c
+++ b/drivers/usb/host/ohci-ppc-soc.c
@@ -72,7 +72,7 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
}
ohci = hcd_to_ohci(hcd);
- ohci->flags |= OHCI_BIG_ENDIAN;
+ ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
ohci_hcd_init(ohci);
retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
@@ -208,19 +208,3 @@ static struct platform_driver ohci_hcd_ppc_soc_driver = {
},
};
-static int __init ohci_hcd_ppc_soc_init(void)
-{
- pr_debug(DRIVER_INFO " (PPC SOC)\n");
- pr_debug("block sizes: ed %d td %d\n", sizeof(struct ed),
- sizeof(struct td));
-
- return platform_driver_register(&ohci_hcd_ppc_soc_driver);
-}
-
-static void __exit ohci_hcd_ppc_soc_cleanup(void)
-{
- platform_driver_unregister(&ohci_hcd_ppc_soc_driver);
-}
-
-module_init(ohci_hcd_ppc_soc_init);
-module_exit(ohci_hcd_ppc_soc_cleanup);
diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c
new file mode 100644
index 00000000000..62283a3926d
--- /dev/null
+++ b/drivers/usb/host/ohci-ps3.c
@@ -0,0 +1,196 @@
+/*
+ * PS3 OHCI Host Controller driver
+ *
+ * Copyright (C) 2006 Sony Computer Entertainment Inc.
+ * Copyright 2006 Sony Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <asm/ps3.h>
+
+static int ps3_ohci_hc_reset(struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+
+ ohci->flags |= OHCI_QUIRK_BE_MMIO;
+ ohci_hcd_init(ohci);
+ return ohci_init(ohci);
+}
+
+static int __devinit ps3_ohci_hc_start(struct usb_hcd *hcd)
+{
+ int result;
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+
+ /* Handle root hub init quirk in spider south bridge. */
+ /* Also set PwrOn2PwrGood to 0x7f (254ms). */
+
+ ohci_writel(ohci, 0x7f000000 | RH_A_PSM | RH_A_OCPM,
+ &ohci->regs->roothub.a);
+ ohci_writel(ohci, 0x00060000, &ohci->regs->roothub.b);
+
+ result = ohci_run(ohci);
+
+ if (result < 0) {
+ err("can't start %s", hcd->self.bus_name);
+ ohci_stop(hcd);
+ }
+
+ return result;
+}
+
+static const struct hc_driver ps3_ohci_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "PS3 OHCI Host Controller",
+ .hcd_priv_size = sizeof(struct ohci_hcd),
+ .irq = ohci_irq,
+ .flags = HCD_MEMORY | HCD_USB11,
+ .reset = ps3_ohci_hc_reset,
+ .start = ps3_ohci_hc_start,
+ .stop = ohci_stop,
+ .shutdown = ohci_shutdown,
+ .urb_enqueue = ohci_urb_enqueue,
+ .urb_dequeue = ohci_urb_dequeue,
+ .endpoint_disable = ohci_endpoint_disable,
+ .get_frame_number = ohci_get_frame,
+ .hub_status_data = ohci_hub_status_data,
+ .hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
+ .start_port_reset = ohci_start_port_reset,
+#if defined(CONFIG_PM)
+ .bus_suspend = ohci_bus_suspend,
+ .bus_resume = ohci_bus_resume,
+#endif
+};
+
+/* redefine dev_dbg to do a syntax check */
+
+#if !defined(DEBUG)
+#undef dev_dbg
+static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg(
+ const struct device *_dev, const char *fmt, ...) {return 0;}
+#endif
+
+static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev)
+{
+ int result;
+ struct usb_hcd *hcd;
+ unsigned int virq;
+ static u64 dummy_mask = DMA_32BIT_MASK;
+
+ if (usb_disabled()) {
+ result = -ENODEV;
+ goto fail_start;
+ }
+
+ result = ps3_mmio_region_create(dev->m_region);
+
+ if (result) {
+ dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n",
+ __func__, __LINE__);
+ result = -EPERM;
+ goto fail_mmio;
+ }
+
+ dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
+ __LINE__, dev->m_region->lpar_addr);
+
+ result = ps3_alloc_io_irq(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq);
+
+ if (result) {
+ dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n",
+ __func__, __LINE__, virq);
+ result = -EPERM;
+ goto fail_irq;
+ }
+
+ dev->core.power.power_state = PMSG_ON;
+ dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */
+
+ hcd = usb_create_hcd(&ps3_ohci_hc_driver, &dev->core, dev->core.bus_id);
+
+ if (!hcd) {
+ dev_dbg(&dev->core, "%s:%d: usb_create_hcd failed\n", __func__,
+ __LINE__);
+ result = -ENOMEM;
+ goto fail_create_hcd;
+ }
+
+ hcd->rsrc_start = dev->m_region->lpar_addr;
+ hcd->rsrc_len = dev->m_region->len;
+ hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len);
+
+ if (!hcd->regs) {
+ dev_dbg(&dev->core, "%s:%d: ioremap failed\n", __func__,
+ __LINE__);
+ result = -EPERM;
+ goto fail_ioremap;
+ }
+
+ dev_dbg(&dev->core, "%s:%d: hcd->rsrc_start %lxh\n", __func__, __LINE__,
+ (unsigned long)hcd->rsrc_start);
+ dev_dbg(&dev->core, "%s:%d: hcd->rsrc_len %lxh\n", __func__, __LINE__,
+ (unsigned long)hcd->rsrc_len);
+ dev_dbg(&dev->core, "%s:%d: hcd->regs %lxh\n", __func__, __LINE__,
+ (unsigned long)hcd->regs);
+ dev_dbg(&dev->core, "%s:%d: virq %lu\n", __func__, __LINE__,
+ (unsigned long)virq);
+
+ ps3_system_bus_set_driver_data(dev, hcd);
+
+ result = usb_add_hcd(hcd, virq, IRQF_DISABLED);
+
+ if (result) {
+ dev_dbg(&dev->core, "%s:%d: usb_add_hcd failed (%d)\n",
+ __func__, __LINE__, result);
+ goto fail_add_hcd;
+ }
+
+ return result;
+
+fail_add_hcd:
+ iounmap(hcd->regs);
+fail_ioremap:
+ usb_put_hcd(hcd);
+fail_create_hcd:
+ ps3_free_io_irq(virq);
+fail_irq:
+ ps3_free_mmio_region(dev->m_region);
+fail_mmio:
+fail_start:
+ return result;
+}
+
+static int ps3_ohci_sb_remove (struct ps3_system_bus_device *dev)
+{
+ struct usb_hcd *hcd =
+ (struct usb_hcd *)ps3_system_bus_get_driver_data(dev);
+
+ usb_put_hcd(hcd);
+ ps3_system_bus_set_driver_data(dev, NULL);
+
+ return 0;
+}
+
+MODULE_ALIAS("ps3-ohci");
+
+static struct ps3_system_bus_driver ps3_ohci_sb_driver = {
+ .match_id = PS3_MATCH_ID_OHCI,
+ .core = {
+ .name = "ps3-ohci-driver",
+ },
+ .probe = ps3_ohci_sb_probe,
+ .remove = ps3_ohci_sb_remove,
+};
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index 3bbea844a9e..f1563dc319d 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -369,19 +369,3 @@ static struct platform_driver ohci_hcd_pxa27x_driver = {
},
};
-static int __init ohci_hcd_pxa27x_init (void)
-{
- pr_debug (DRIVER_INFO " (pxa27x)");
- pr_debug ("block sizes: ed %d td %d\n",
- sizeof (struct ed), sizeof (struct td));
-
- return platform_driver_register(&ohci_hcd_pxa27x_driver);
-}
-
-static void __exit ohci_hcd_pxa27x_cleanup (void)
-{
- platform_driver_unregister(&ohci_hcd_pxa27x_driver);
-}
-
-module_init (ohci_hcd_pxa27x_init);
-module_exit (ohci_hcd_pxa27x_cleanup);
diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
index b350d45033e..6829814b7aa 100644
--- a/drivers/usb/host/ohci-s3c2410.c
+++ b/drivers/usb/host/ohci-s3c2410.c
@@ -501,15 +501,3 @@ static struct platform_driver ohci_hcd_s3c2410_driver = {
},
};
-static int __init ohci_hcd_s3c2410_init (void)
-{
- return platform_driver_register(&ohci_hcd_s3c2410_driver);
-}
-
-static void __exit ohci_hcd_s3c2410_cleanup (void)
-{
- platform_driver_unregister(&ohci_hcd_s3c2410_driver);
-}
-
-module_init (ohci_hcd_s3c2410_init);
-module_exit (ohci_hcd_s3c2410_cleanup);
diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
index fe0090e3367..0f48f2d9922 100644
--- a/drivers/usb/host/ohci-sa1111.c
+++ b/drivers/usb/host/ohci-sa1111.c
@@ -269,19 +269,3 @@ static struct sa1111_driver ohci_hcd_sa1111_driver = {
.remove = ohci_hcd_sa1111_drv_remove,
};
-static int __init ohci_hcd_sa1111_init (void)
-{
- dbg (DRIVER_INFO " (SA-1111)");
- dbg ("block sizes: ed %d td %d",
- sizeof (struct ed), sizeof (struct td));
-
- return sa1111_driver_register(&ohci_hcd_sa1111_driver);
-}
-
-static void __exit ohci_hcd_sa1111_cleanup (void)
-{
- sa1111_driver_unregister(&ohci_hcd_sa1111_driver);
-}
-
-module_init (ohci_hcd_sa1111_init);
-module_exit (ohci_hcd_sa1111_cleanup);
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index 405257f3e85..c2b5ecfe5e9 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -394,8 +394,9 @@ struct ohci_hcd {
#define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */
#define OHCI_QUIRK_SUPERIO 0x02 /* natsemi */
#define OHCI_QUIRK_INITRESET 0x04 /* SiS, OPTi, ... */
-#define OHCI_BIG_ENDIAN 0x08 /* big endian HC */
-#define OHCI_QUIRK_ZFMICRO 0x10 /* Compaq ZFMicro chipset*/
+#define OHCI_QUIRK_BE_DESC 0x08 /* BE descriptors */
+#define OHCI_QUIRK_BE_MMIO 0x10 /* BE registers */
+#define OHCI_QUIRK_ZFMICRO 0x20 /* Compaq ZFMicro chipset*/
// there are also chip quirks/bugs in init logic
};
@@ -439,117 +440,164 @@ static inline struct usb_hcd *ohci_to_hcd (const struct ohci_hcd *ohci)
* a minority (notably the IBM STB04XXX and the Motorola MPC5200
* processors) implement them in big endian format.
*
+ * In addition some more exotic implementations like the Toshiba
+ * Spider (aka SCC) cell southbridge are "mixed" endian, that is,
+ * they have a different endianness for registers vs. in-memory
+ * descriptors.
+ *
* This attempts to support either format at compile time without a
* runtime penalty, or both formats with the additional overhead
* of checking a flag bit.
+ *
+ * That leads to some tricky Kconfig rules howevber. There are
+ * different defaults based on some arch/ppc platforms, though
+ * the basic rules are:
+ *
+ * Controller type Kconfig options needed
+ * --------------- ----------------------
+ * little endian CONFIG_USB_OHCI_LITTLE_ENDIAN
+ *
+ * fully big endian CONFIG_USB_OHCI_BIG_ENDIAN_DESC _and_
+ * CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
+ *
+ * mixed endian CONFIG_USB_OHCI_LITTLE_ENDIAN _and_
+ * CONFIG_USB_OHCI_BIG_ENDIAN_{MMIO,DESC}
+ *
+ * (If you have a mixed endian controller, you -must- also define
+ * CONFIG_USB_OHCI_LITTLE_ENDIAN or things will not work when building
+ * both your mixed endian and a fully big endian controller support in
+ * the same kernel image).
*/
-#ifdef CONFIG_USB_OHCI_BIG_ENDIAN
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_DESC
+#ifdef CONFIG_USB_OHCI_LITTLE_ENDIAN
+#define big_endian_desc(ohci) (ohci->flags & OHCI_QUIRK_BE_DESC)
+#else
+#define big_endian_desc(ohci) 1 /* only big endian */
+#endif
+#else
+#define big_endian_desc(ohci) 0 /* only little endian */
+#endif
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
#ifdef CONFIG_USB_OHCI_LITTLE_ENDIAN
-#define big_endian(ohci) (ohci->flags & OHCI_BIG_ENDIAN) /* either */
+#define big_endian_mmio(ohci) (ohci->flags & OHCI_QUIRK_BE_MMIO)
#else
-#define big_endian(ohci) 1 /* only big endian */
+#define big_endian_mmio(ohci) 1 /* only big endian */
+#endif
+#else
+#define big_endian_mmio(ohci) 0 /* only little endian */
#endif
/*
* Big-endian read/write functions are arch-specific.
* Other arches can be added if/when they're needed.
+ *
+ * REVISIT: arch/powerpc now has readl/writel_be, so the
+ * definition below can die once the STB04xxx support is
+ * finally ported over.
*/
-#if defined(CONFIG_PPC)
+#if defined(CONFIG_PPC) && !defined(CONFIG_PPC_MERGE)
#define readl_be(addr) in_be32((__force unsigned *)addr)
#define writel_be(val, addr) out_be32((__force unsigned *)addr, val)
#endif
-static inline unsigned int ohci_readl (const struct ohci_hcd *ohci,
- __hc32 __iomem * regs)
+static inline unsigned int _ohci_readl (const struct ohci_hcd *ohci,
+ __hc32 __iomem * regs)
{
- return big_endian(ohci) ? readl_be (regs) : readl ((__force u32 *)regs);
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
+ return big_endian_mmio(ohci) ?
+ readl_be (regs) :
+ readl (regs);
+#else
+ return readl (regs);
+#endif
}
-static inline void ohci_writel (const struct ohci_hcd *ohci,
- const unsigned int val, __hc32 __iomem *regs)
+static inline void _ohci_writel (const struct ohci_hcd *ohci,
+ const unsigned int val, __hc32 __iomem *regs)
{
- big_endian(ohci) ? writel_be (val, regs) :
- writel (val, (__force u32 *)regs);
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
+ big_endian_mmio(ohci) ?
+ writel_be (val, regs) :
+ writel (val, regs);
+#else
+ writel (val, regs);
+#endif
}
-#else /* !CONFIG_USB_OHCI_BIG_ENDIAN */
-
-#define big_endian(ohci) 0 /* only little endian */
-
#ifdef CONFIG_ARCH_LH7A404
- /* Marc Singer: at the time this code was written, the LH7A404
- * had a problem reading the USB host registers. This
- * implementation of the ohci_readl function performs the read
- * twice as a work-around.
- */
-static inline unsigned int
-ohci_readl (const struct ohci_hcd *ohci, const __hc32 *regs)
-{
- *(volatile __force unsigned int*) regs;
- return *(volatile __force unsigned int*) regs;
-}
+/* Marc Singer: at the time this code was written, the LH7A404
+ * had a problem reading the USB host registers. This
+ * implementation of the ohci_readl function performs the read
+ * twice as a work-around.
+ */
+#define ohci_readl(o,r) (_ohci_readl(o,r),_ohci_readl(o,r))
+#define ohci_writel(o,v,r) _ohci_writel(o,v,r)
#else
- /* Standard version of ohci_readl uses standard, platform
- * specific implementation. */
-static inline unsigned int
-ohci_readl (const struct ohci_hcd *ohci, __hc32 __iomem * regs)
-{
- return readl(regs);
-}
+#define ohci_readl(o,r) _ohci_readl(o,r)
+#define ohci_writel(o,v,r) _ohci_writel(o,v,r)
#endif
-static inline void ohci_writel (const struct ohci_hcd *ohci,
- const unsigned int val, __hc32 __iomem *regs)
-{
- writel (val, regs);
-}
-
-#endif /* !CONFIG_USB_OHCI_BIG_ENDIAN */
/*-------------------------------------------------------------------------*/
/* cpu to ohci */
static inline __hc16 cpu_to_hc16 (const struct ohci_hcd *ohci, const u16 x)
{
- return big_endian(ohci) ? (__force __hc16)cpu_to_be16(x) : (__force __hc16)cpu_to_le16(x);
+ return big_endian_desc(ohci) ?
+ (__force __hc16)cpu_to_be16(x) :
+ (__force __hc16)cpu_to_le16(x);
}
static inline __hc16 cpu_to_hc16p (const struct ohci_hcd *ohci, const u16 *x)
{
- return big_endian(ohci) ? cpu_to_be16p(x) : cpu_to_le16p(x);
+ return big_endian_desc(ohci) ?
+ cpu_to_be16p(x) :
+ cpu_to_le16p(x);
}
static inline __hc32 cpu_to_hc32 (const struct ohci_hcd *ohci, const u32 x)
{
- return big_endian(ohci) ? (__force __hc32)cpu_to_be32(x) : (__force __hc32)cpu_to_le32(x);
+ return big_endian_desc(ohci) ?
+ (__force __hc32)cpu_to_be32(x) :
+ (__force __hc32)cpu_to_le32(x);
}
static inline __hc32 cpu_to_hc32p (const struct ohci_hcd *ohci, const u32 *x)
{
- return big_endian(ohci) ? cpu_to_be32p(x) : cpu_to_le32p(x);
+ return big_endian_desc(ohci) ?
+ cpu_to_be32p(x) :
+ cpu_to_le32p(x);
}
/* ohci to cpu */
static inline u16 hc16_to_cpu (const struct ohci_hcd *ohci, const __hc16 x)
{
- return big_endian(ohci) ? be16_to_cpu((__force __be16)x) : le16_to_cpu((__force __le16)x);
+ return big_endian_desc(ohci) ?
+ be16_to_cpu((__force __be16)x) :
+ le16_to_cpu((__force __le16)x);
}
static inline u16 hc16_to_cpup (const struct ohci_hcd *ohci, const __hc16 *x)
{
- return big_endian(ohci) ? be16_to_cpup((__force __be16 *)x) : le16_to_cpup((__force __le16 *)x);
+ return big_endian_desc(ohci) ?
+ be16_to_cpup((__force __be16 *)x) :
+ le16_to_cpup((__force __le16 *)x);
}
static inline u32 hc32_to_cpu (const struct ohci_hcd *ohci, const __hc32 x)
{
- return big_endian(ohci) ? be32_to_cpu((__force __be32)x) : le32_to_cpu((__force __le32)x);
+ return big_endian_desc(ohci) ?
+ be32_to_cpu((__force __be32)x) :
+ le32_to_cpu((__force __le32)x);
}
static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
{
- return big_endian(ohci) ? be32_to_cpup((__force __be32 *)x) : le32_to_cpup((__force __le32 *)x);
+ return big_endian_desc(ohci) ?
+ be32_to_cpup((__force __be32 *)x) :
+ le32_to_cpup((__force __le32 *)x);
}
/*-------------------------------------------------------------------------*/
@@ -557,6 +605,9 @@ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
/* HCCA frame number is 16 bits, but is accessed as 32 bits since not all
* hardware handles 16 bit reads. That creates a different confusion on
* some big-endian SOC implementations. Same thing happens with PSW access.
+ *
+ * FIXME: Deal with that as a runtime quirk when STB03xxx is ported over
+ * to arch/powerpc
*/
#ifdef CONFIG_STB03xxx
@@ -568,7 +619,7 @@ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
{
u32 tmp;
- if (big_endian(ohci)) {
+ if (big_endian_desc(ohci)) {
tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no);
tmp >>= OHCI_BE_FRAME_NO_SHIFT;
} else
@@ -580,7 +631,7 @@ static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
static inline __hc16 *ohci_hwPSWp(const struct ohci_hcd *ohci,
const struct td *td, int index)
{
- return (__hc16 *)(big_endian(ohci) ?
+ return (__hc16 *)(big_endian_desc(ohci) ?
&td->hwPSW[index ^ 1] : &td->hwPSW[index]);
}
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c
index e345f15b7d8..5d6c06bc452 100644
--- a/drivers/usb/host/uhci-debug.c
+++ b/drivers/usb/host/uhci-debug.c
@@ -168,9 +168,13 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
space, "", qh, qtype,
le32_to_cpu(qh->link), le32_to_cpu(element));
if (qh->type == USB_ENDPOINT_XFER_ISOC)
- out += sprintf(out, "%*s period %d frame %x desc [%p]\n",
- space, "", qh->period, qh->iso_frame,
- qh->iso_packet_desc);
+ out += sprintf(out, "%*s period %d phase %d load %d us, "
+ "frame %x desc [%p]\n",
+ space, "", qh->period, qh->phase, qh->load,
+ qh->iso_frame, qh->iso_packet_desc);
+ else if (qh->type == USB_ENDPOINT_XFER_INT)
+ out += sprintf(out, "%*s period %d phase %d load %d us\n",
+ space, "", qh->period, qh->phase, qh->load);
if (element & UHCI_PTR_QH)
out += sprintf(out, "%*s Element points to QH (bug?)\n", space, "");
@@ -208,7 +212,7 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
space, "", nurbs);
}
- if (qh->udev) {
+ if (qh->dummy_td) {
out += sprintf(out, "%*s Dummy TD\n", space, "");
out += uhci_show_td(qh->dummy_td, out, len - (out - buf), 0);
}
@@ -347,31 +351,80 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
struct uhci_qh *qh;
struct uhci_td *td;
struct list_head *tmp, *head;
+ int nframes, nerrs;
out += uhci_show_root_hub_state(uhci, out, len - (out - buf));
out += sprintf(out, "HC status\n");
out += uhci_show_status(uhci, out, len - (out - buf));
+
+ out += sprintf(out, "Periodic load table\n");
+ for (i = 0; i < MAX_PHASE; ++i) {
+ out += sprintf(out, "\t%d", uhci->load[i]);
+ if (i % 8 == 7)
+ *out++ = '\n';
+ }
+ out += sprintf(out, "Total: %d, #INT: %d, #ISO: %d\n",
+ uhci->total_load,
+ uhci_to_hcd(uhci)->self.bandwidth_int_reqs,
+ uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs);
if (debug <= 1)
return out - buf;
out += sprintf(out, "Frame List\n");
+ nframes = 10;
+ nerrs = 0;
for (i = 0; i < UHCI_NUMFRAMES; ++i) {
+ __le32 link, qh_dma;
+
+ j = 0;
td = uhci->frame_cpu[i];
+ link = uhci->frame[i];
if (!td)
- continue;
+ goto check_link;
- out += sprintf(out, "- Frame %d\n", i); \
- if (td->dma_handle != (dma_addr_t)uhci->frame[i])
- out += sprintf(out, " frame list does not match td->dma_handle!\n");
+ if (nframes > 0) {
+ out += sprintf(out, "- Frame %d -> (%08x)\n",
+ i, le32_to_cpu(link));
+ j = 1;
+ }
head = &td->fl_list;
tmp = head;
do {
td = list_entry(tmp, struct uhci_td, fl_list);
tmp = tmp->next;
- out += uhci_show_td(td, out, len - (out - buf), 4);
+ if (cpu_to_le32(td->dma_handle) != link) {
+ if (nframes > 0)
+ out += sprintf(out, " link does "
+ "not match list entry!\n");
+ else
+ ++nerrs;
+ }
+ if (nframes > 0)
+ out += uhci_show_td(td, out,
+ len - (out - buf), 4);
+ link = td->link;
} while (tmp != head);
+
+check_link:
+ qh_dma = uhci_frame_skel_link(uhci, i);
+ if (link != qh_dma) {
+ if (nframes > 0) {
+ if (!j) {
+ out += sprintf(out,
+ "- Frame %d -> (%08x)\n",
+ i, le32_to_cpu(link));
+ j = 1;
+ }
+ out += sprintf(out, " link does not match "
+ "QH (%08x)!\n", le32_to_cpu(qh_dma));
+ } else
+ ++nerrs;
+ }
+ nframes -= j;
}
+ if (nerrs > 0)
+ out += sprintf(out, "Skipped %d bad links\n", nerrs);
out += sprintf(out, "Skeleton QHs\n");
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index e0d4c2358b3..49b9d390b95 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -92,6 +92,34 @@ static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state);
static void wakeup_rh(struct uhci_hcd *uhci);
static void uhci_get_current_frame_number(struct uhci_hcd *uhci);
+/*
+ * Calculate the link pointer DMA value for the first Skeleton QH in a frame.
+ */
+static __le32 uhci_frame_skel_link(struct uhci_hcd *uhci, int frame)
+{
+ int skelnum;
+
+ /*
+ * The interrupt queues will be interleaved as evenly as possible.
+ * There's not much to be done about period-1 interrupts; they have
+ * to occur in every frame. But we can schedule period-2 interrupts
+ * in odd-numbered frames, period-4 interrupts in frames congruent
+ * to 2 (mod 4), and so on. This way each frame only has two
+ * interrupt QHs, which will help spread out bandwidth utilization.
+ *
+ * ffs (Find First bit Set) does exactly what we need:
+ * 1,3,5,... => ffs = 0 => use skel_int2_qh = skelqh[8],
+ * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[7], etc.
+ * ffs >= 7 => not on any high-period queue, so use
+ * skel_int1_qh = skelqh[9].
+ * Add in UHCI_NUMFRAMES to insure at least one bit is set.
+ */
+ skelnum = 8 - (int) __ffs(frame | UHCI_NUMFRAMES);
+ if (skelnum <= 1)
+ skelnum = 9;
+ return UHCI_PTR_QH | cpu_to_le32(uhci->skelqh[skelnum]->dma_handle);
+}
+
#include "uhci-debug.c"
#include "uhci-q.c"
#include "uhci-hub.c"
@@ -631,32 +659,11 @@ static int uhci_start(struct usb_hcd *hcd)
/*
* Fill the frame list: make all entries point to the proper
* interrupt queue.
- *
- * The interrupt queues will be interleaved as evenly as possible.
- * There's not much to be done about period-1 interrupts; they have
- * to occur in every frame. But we can schedule period-2 interrupts
- * in odd-numbered frames, period-4 interrupts in frames congruent
- * to 2 (mod 4), and so on. This way each frame only has two
- * interrupt QHs, which will help spread out bandwidth utilization.
*/
for (i = 0; i < UHCI_NUMFRAMES; i++) {
- int irq;
-
- /*
- * ffs (Find First bit Set) does exactly what we need:
- * 1,3,5,... => ffs = 0 => use skel_int2_qh = skelqh[8],
- * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[7], etc.
- * ffs >= 7 => not on any high-period queue, so use
- * skel_int1_qh = skelqh[9].
- * Add UHCI_NUMFRAMES to insure at least one bit is set.
- */
- irq = 8 - (int) __ffs(i + UHCI_NUMFRAMES);
- if (irq <= 1)
- irq = 9;
/* Only place we don't use the frame list routines */
- uhci->frame[i] = UHCI_PTR_QH |
- cpu_to_le32(uhci->skelqh[irq]->dma_handle);
+ uhci->frame[i] = uhci_frame_skel_link(uhci, i);
}
/*
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
index 108e3de2dc2..74469b5bcb6 100644
--- a/drivers/usb/host/uhci-hcd.h
+++ b/drivers/usb/host/uhci-hcd.h
@@ -83,6 +83,7 @@
#define UHCI_MAX_SOF_NUMBER 2047 /* in an SOF packet */
#define CAN_SCHEDULE_FRAMES 1000 /* how far in the future frames
* can be scheduled */
+#define MAX_PHASE 32 /* Periodic scheduling length */
/* When no queues need Full-Speed Bandwidth Reclamation,
* delay this long before turning FSBR off */
@@ -141,6 +142,8 @@ struct uhci_qh {
unsigned long advance_jiffies; /* Time of last queue advance */
unsigned int unlink_frame; /* When the QH was unlinked */
unsigned int period; /* For Interrupt and Isochronous QHs */
+ short phase; /* Between 0 and period-1 */
+ short load; /* Periodic time requirement, in us */
unsigned int iso_frame; /* Frame # for iso_packet_desc */
int iso_status; /* Status for Isochronous URBs */
@@ -153,6 +156,8 @@ struct uhci_qh {
unsigned int needs_fixup:1; /* Must fix the TD toggle values */
unsigned int is_stopped:1; /* Queue was stopped by error/unlink */
unsigned int wait_expired:1; /* QH_WAIT_TIMEOUT has expired */
+ unsigned int bandwidth_reserved:1; /* Periodic bandwidth has
+ * been allocated */
} __attribute__((aligned(16)));
/*
@@ -414,6 +419,9 @@ struct uhci_hcd {
wait_queue_head_t waitqh; /* endpoint_disable waiters */
int num_waiting; /* Number of waiters */
+
+ int total_load; /* Sum of array values */
+ short load[MAX_PHASE]; /* Periodic allocations */
};
/* Convert between a usb_hcd pointer and the corresponding uhci_hcd */
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index 30b88459ac7..2cbb239e63f 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -248,16 +248,26 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci,
INIT_LIST_HEAD(&qh->node);
if (udev) { /* Normal QH */
- qh->dummy_td = uhci_alloc_td(uhci);
- if (!qh->dummy_td) {
- dma_pool_free(uhci->qh_pool, qh, dma_handle);
- return NULL;
+ qh->type = hep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+ if (qh->type != USB_ENDPOINT_XFER_ISOC) {
+ qh->dummy_td = uhci_alloc_td(uhci);
+ if (!qh->dummy_td) {
+ dma_pool_free(uhci->qh_pool, qh, dma_handle);
+ return NULL;
+ }
}
qh->state = QH_STATE_IDLE;
qh->hep = hep;
qh->udev = udev;
hep->hcpriv = qh;
- qh->type = hep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+ if (qh->type == USB_ENDPOINT_XFER_INT ||
+ qh->type == USB_ENDPOINT_XFER_ISOC)
+ qh->load = usb_calc_bus_time(udev->speed,
+ usb_endpoint_dir_in(&hep->desc),
+ qh->type == USB_ENDPOINT_XFER_ISOC,
+ le16_to_cpu(hep->desc.wMaxPacketSize))
+ / 1000 + 1;
} else { /* Skeleton QH */
qh->state = QH_STATE_ACTIVE;
@@ -275,7 +285,8 @@ static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
list_del(&qh->node);
if (qh->udev) {
qh->hep->hcpriv = NULL;
- uhci_free_td(uhci, qh->dummy_td);
+ if (qh->dummy_td)
+ uhci_free_td(uhci, qh->dummy_td);
}
dma_pool_free(uhci->qh_pool, qh, qh->dma_handle);
}
@@ -327,7 +338,7 @@ static int uhci_cleanup_queue(struct uhci_hcd *uhci, struct uhci_qh *qh,
goto done;
qh->element = UHCI_PTR_TERM;
- /* Control pipes have to worry about toggles */
+ /* Control pipes don't have to worry about toggles */
if (qh->type == USB_ENDPOINT_XFER_CONTROL)
goto done;
@@ -493,6 +504,121 @@ static void uhci_make_qh_idle(struct uhci_hcd *uhci, struct uhci_qh *qh)
wake_up_all(&uhci->waitqh);
}
+/*
+ * Find the highest existing bandwidth load for a given phase and period.
+ */
+static int uhci_highest_load(struct uhci_hcd *uhci, int phase, int period)
+{
+ int highest_load = uhci->load[phase];
+
+ for (phase += period; phase < MAX_PHASE; phase += period)
+ highest_load = max_t(int, highest_load, uhci->load[phase]);
+ return highest_load;
+}
+
+/*
+ * Set qh->phase to the optimal phase for a periodic transfer and
+ * check whether the bandwidth requirement is acceptable.
+ */
+static int uhci_check_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+ int minimax_load;
+
+ /* Find the optimal phase (unless it is already set) and get
+ * its load value. */
+ if (qh->phase >= 0)
+ minimax_load = uhci_highest_load(uhci, qh->phase, qh->period);
+ else {
+ int phase, load;
+ int max_phase = min_t(int, MAX_PHASE, qh->period);
+
+ qh->phase = 0;
+ minimax_load = uhci_highest_load(uhci, qh->phase, qh->period);
+ for (phase = 1; phase < max_phase; ++phase) {
+ load = uhci_highest_load(uhci, phase, qh->period);
+ if (load < minimax_load) {
+ minimax_load = load;
+ qh->phase = phase;
+ }
+ }
+ }
+
+ /* Maximum allowable periodic bandwidth is 90%, or 900 us per frame */
+ if (minimax_load + qh->load > 900) {
+ dev_dbg(uhci_dev(uhci), "bandwidth allocation failed: "
+ "period %d, phase %d, %d + %d us\n",
+ qh->period, qh->phase, minimax_load, qh->load);
+ return -ENOSPC;
+ }
+ return 0;
+}
+
+/*
+ * Reserve a periodic QH's bandwidth in the schedule
+ */
+static void uhci_reserve_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+ int i;
+ int load = qh->load;
+ char *p = "??";
+
+ for (i = qh->phase; i < MAX_PHASE; i += qh->period) {
+ uhci->load[i] += load;
+ uhci->total_load += load;
+ }
+ uhci_to_hcd(uhci)->self.bandwidth_allocated =
+ uhci->total_load / MAX_PHASE;
+ switch (qh->type) {
+ case USB_ENDPOINT_XFER_INT:
+ ++uhci_to_hcd(uhci)->self.bandwidth_int_reqs;
+ p = "INT";
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ ++uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs;
+ p = "ISO";
+ break;
+ }
+ qh->bandwidth_reserved = 1;
+ dev_dbg(uhci_dev(uhci),
+ "%s dev %d ep%02x-%s, period %d, phase %d, %d us\n",
+ "reserve", qh->udev->devnum,
+ qh->hep->desc.bEndpointAddress, p,
+ qh->period, qh->phase, load);
+}
+
+/*
+ * Release a periodic QH's bandwidth reservation
+ */
+static void uhci_release_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+ int i;
+ int load = qh->load;
+ char *p = "??";
+
+ for (i = qh->phase; i < MAX_PHASE; i += qh->period) {
+ uhci->load[i] -= load;
+ uhci->total_load -= load;
+ }
+ uhci_to_hcd(uhci)->self.bandwidth_allocated =
+ uhci->total_load / MAX_PHASE;
+ switch (qh->type) {
+ case USB_ENDPOINT_XFER_INT:
+ --uhci_to_hcd(uhci)->self.bandwidth_int_reqs;
+ p = "INT";
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ --uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs;
+ p = "ISO";
+ break;
+ }
+ qh->bandwidth_reserved = 0;
+ dev_dbg(uhci_dev(uhci),
+ "%s dev %d ep%02x-%s, period %d, phase %d, %d us\n",
+ "release", qh->udev->devnum,
+ qh->hep->desc.bEndpointAddress, p,
+ qh->period, qh->phase, load);
+}
+
static inline struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci,
struct urb *urb)
{
@@ -796,7 +922,6 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
wmb();
qh->dummy_td->status |= __constant_cpu_to_le32(TD_CTRL_ACTIVE);
qh->dummy_td = td;
- qh->period = urb->interval;
usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
usb_pipeout(urb->pipe), toggle);
@@ -827,28 +952,42 @@ static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb,
static int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb,
struct uhci_qh *qh)
{
- int exponent;
+ int ret;
/* USB 1.1 interrupt transfers only involve one packet per interval.
* Drivers can submit URBs of any length, but longer ones will need
* multiple intervals to complete.
*/
- /* Figure out which power-of-two queue to use */
- for (exponent = 7; exponent >= 0; --exponent) {
- if ((1 << exponent) <= urb->interval)
- break;
- }
- if (exponent < 0)
- return -EINVAL;
- urb->interval = 1 << exponent;
+ if (!qh->bandwidth_reserved) {
+ int exponent;
- if (qh->period == 0)
+ /* Figure out which power-of-two queue to use */
+ for (exponent = 7; exponent >= 0; --exponent) {
+ if ((1 << exponent) <= urb->interval)
+ break;
+ }
+ if (exponent < 0)
+ return -EINVAL;
+ qh->period = 1 << exponent;
qh->skel = uhci->skelqh[UHCI_SKEL_INDEX(exponent)];
- else if (qh->period != urb->interval)
- return -EINVAL; /* Can't change the period */
- return uhci_submit_common(uhci, urb, qh);
+ /* For now, interrupt phase is fixed by the layout
+ * of the QH lists. */
+ qh->phase = (qh->period / 2) & (MAX_PHASE - 1);
+ ret = uhci_check_bandwidth(uhci, qh);
+ if (ret)
+ return ret;
+ } else if (qh->period > urb->interval)
+ return -EINVAL; /* Can't decrease the period */
+
+ ret = uhci_submit_common(uhci, urb, qh);
+ if (ret == 0) {
+ urb->interval = qh->period;
+ if (!qh->bandwidth_reserved)
+ uhci_reserve_bandwidth(uhci, qh);
+ }
+ return ret;
}
/*
@@ -995,15 +1134,32 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
return -EFBIG;
/* Check the period and figure out the starting frame number */
- if (qh->period == 0) {
+ if (!qh->bandwidth_reserved) {
+ qh->period = urb->interval;
if (urb->transfer_flags & URB_ISO_ASAP) {
+ qh->phase = -1; /* Find the best phase */
+ i = uhci_check_bandwidth(uhci, qh);
+ if (i)
+ return i;
+
+ /* Allow a little time to allocate the TDs */
uhci_get_current_frame_number(uhci);
- urb->start_frame = uhci->frame_number + 10;
+ frame = uhci->frame_number + 10;
+
+ /* Move forward to the first frame having the
+ * correct phase */
+ urb->start_frame = frame + ((qh->phase - frame) &
+ (qh->period - 1));
} else {
i = urb->start_frame - uhci->last_iso_frame;
if (i <= 0 || i >= UHCI_NUMFRAMES)
return -EINVAL;
+ qh->phase = urb->start_frame & (qh->period - 1);
+ i = uhci_check_bandwidth(uhci, qh);
+ if (i)
+ return i;
}
+
} else if (qh->period != urb->interval) {
return -EINVAL; /* Can't change the period */
@@ -1049,9 +1205,6 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
/* Set the interrupt-on-completion flag on the last packet. */
td->status |= __constant_cpu_to_le32(TD_CTRL_IOC);
- qh->skel = uhci->skel_iso_qh;
- qh->period = urb->interval;
-
/* Add the TDs to the frame list */
frame = urb->start_frame;
list_for_each_entry(td, &urbp->td_list, list) {
@@ -1065,6 +1218,9 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
qh->iso_status = 0;
}
+ qh->skel = uhci->skel_iso_qh;
+ if (!qh->bandwidth_reserved)
+ uhci_reserve_bandwidth(uhci, qh);
return 0;
}
@@ -1119,7 +1275,6 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
unsigned long flags;
struct urb_priv *urbp;
struct uhci_qh *qh;
- int bustime;
spin_lock_irqsave(&uhci->lock, flags);
@@ -1149,35 +1304,11 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
ret = uhci_submit_bulk(uhci, urb, qh);
break;
case USB_ENDPOINT_XFER_INT:
- if (list_empty(&qh->queue)) {
- bustime = usb_check_bandwidth(urb->dev, urb);
- if (bustime < 0)
- ret = bustime;
- else {
- ret = uhci_submit_interrupt(uhci, urb, qh);
- if (ret == 0)
- usb_claim_bandwidth(urb->dev, urb, bustime, 0);
- }
- } else { /* inherit from parent */
- struct urb_priv *eurbp;
-
- eurbp = list_entry(qh->queue.prev, struct urb_priv,
- node);
- urb->bandwidth = eurbp->urb->bandwidth;
- ret = uhci_submit_interrupt(uhci, urb, qh);
- }
+ ret = uhci_submit_interrupt(uhci, urb, qh);
break;
case USB_ENDPOINT_XFER_ISOC:
urb->error_count = 0;
- bustime = usb_check_bandwidth(urb->dev, urb);
- if (bustime < 0) {
- ret = bustime;
- break;
- }
-
ret = uhci_submit_isochronous(uhci, urb, qh);
- if (ret == 0)
- usb_claim_bandwidth(urb->dev, urb, bustime, 1);
break;
}
if (ret != 0)
@@ -1274,24 +1405,6 @@ __acquires(uhci->lock)
uhci_free_urb_priv(uhci, urbp);
- switch (qh->type) {
- case USB_ENDPOINT_XFER_ISOC:
- /* Release bandwidth for Interrupt or Isoc. transfers */
- if (urb->bandwidth)
- usb_release_bandwidth(urb->dev, urb, 1);
- break;
- case USB_ENDPOINT_XFER_INT:
- /* Release bandwidth for Interrupt or Isoc. transfers */
- /* Make sure we don't release if we have a queued URB */
- if (list_empty(&qh->queue) && urb->bandwidth)
- usb_release_bandwidth(urb->dev, urb, 0);
- else
- /* bandwidth was passed on to queued URB, */
- /* so don't let usb_unlink_urb() release it */
- urb->bandwidth = 0;
- break;
- }
-
spin_unlock(&uhci->lock);
usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb);
spin_lock(&uhci->lock);
@@ -1300,9 +1413,8 @@ __acquires(uhci->lock)
* reserved bandwidth. */
if (list_empty(&qh->queue)) {
uhci_unlink_qh(uhci, qh);
-
- /* Bandwidth stuff not yet implemented */
- qh->period = 0;
+ if (qh->bandwidth_reserved)
+ uhci_release_bandwidth(uhci, qh);
}
}
diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c
index 63a84bbc310..d308afd0693 100644
--- a/drivers/usb/image/mdc800.c
+++ b/drivers/usb/image/mdc800.c
@@ -565,11 +565,15 @@ static void mdc800_usb_disconnect (struct usb_interface *intf)
usb_deregister_dev(intf, &mdc800_class);
+ /* must be under lock to make sure no URB
+ is submitted after usb_kill_urb() */
+ mutex_lock(&mdc800->io_lock);
mdc800->state=NOT_CONNECTED;
usb_kill_urb(mdc800->irq_urb);
usb_kill_urb(mdc800->write_urb);
usb_kill_urb(mdc800->download_urb);
+ mutex_unlock(&mdc800->io_lock);
mdc800->dev = NULL;
usb_set_intfdata(intf, NULL);
diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig
index c7d887540d8..2e71d3cca19 100644
--- a/drivers/usb/input/Kconfig
+++ b/drivers/usb/input/Kconfig
@@ -69,6 +69,14 @@ config LOGITECH_FF
Note: if you say N here, this device will still be supported, but without
force feedback.
+config PANTHERLORD_FF
+ bool "PantherLord USB/PS2 2in1 Adapter support"
+ depends on HID_FF
+ select INPUT_FF_MEMLESS if USB_HID
+ help
+ Say Y here if you have a PantherLord USB/PS2 2in1 Adapter and want
+ to enable force feedback support for it.
+
config THRUSTMASTER_FF
bool "ThrustMaster FireStorm Dual Power 2 support (EXPERIMENTAL)"
depends on HID_FF && EXPERIMENTAL
@@ -344,3 +352,15 @@ config USB_APPLETOUCH
To compile this driver as a module, choose M here: the
module will be called appletouch.
+
+config USB_GTCO
+ tristate "GTCO CalComp/InterWrite USB Support"
+ depends on USB && INPUT
+ ---help---
+ Say Y here if you want to use the USB version of the GTCO
+ CalComp/InterWrite Tablet. Make sure to say Y to "Mouse support"
+ (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
+ (CONFIG_INPUT_EVDEV) as well.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gtco.
diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile
index 1a24b5bfa05..a9d206c945e 100644
--- a/drivers/usb/input/Makefile
+++ b/drivers/usb/input/Makefile
@@ -17,6 +17,9 @@ endif
ifeq ($(CONFIG_LOGITECH_FF),y)
usbhid-objs += hid-lgff.o
endif
+ifeq ($(CONFIG_PANTHERLORD_FF),y)
+ usbhid-objs += hid-plff.o
+endif
ifeq ($(CONFIG_THRUSTMASTER_FF),y)
usbhid-objs += hid-tmff.o
endif
@@ -45,6 +48,7 @@ obj-$(CONFIG_USB_ACECAD) += acecad.o
obj-$(CONFIG_USB_YEALINK) += yealink.o
obj-$(CONFIG_USB_XPAD) += xpad.o
obj-$(CONFIG_USB_APPLETOUCH) += appletouch.o
+obj-$(CONFIG_USB_GTCO) += gtco.o
ifeq ($(CONFIG_USB_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/usb/input/gtco.c b/drivers/usb/input/gtco.c
new file mode 100644
index 00000000000..203cdc1bbba
--- /dev/null
+++ b/drivers/usb/input/gtco.c
@@ -0,0 +1,1104 @@
+/* -*- linux-c -*-
+
+GTCO digitizer USB driver
+
+Use the err(), dbg() and info() macros from usb.h for system logging
+
+TO CHECK: Is pressure done right on report 5?
+
+Copyright (C) 2006 GTCO CalComp
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of GTCO-CalComp not be used in advertising
+or publicity pertaining to distribution of the software without specific,
+written prior permission. GTCO-CalComp makes no representations about the
+suitability of this software for any purpose. It is provided "as is"
+without express or implied warranty.
+
+GTCO-CALCOMP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+EVENT SHALL GTCO-CALCOMP BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+TORTIOUS ACTIONS, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+
+GTCO CalComp, Inc.
+7125 Riverwood Drive
+Columbia, MD 21046
+
+Jeremy Roberson jroberson@gtcocalcomp.com
+Scott Hill shill@gtcocalcomp.com
+*/
+
+
+
+/*#define DEBUG*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <asm/uaccess.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+
+
+#include <linux/version.h>
+#include <linux/usb/input.h>
+
+/* Version with a Major number of 2 is for kernel inclusion only. */
+#define GTCO_VERSION "2.00.0006"
+
+
+/* MACROS */
+
+#define VENDOR_ID_GTCO 0x078C
+#define PID_400 0x400
+#define PID_401 0x401
+#define PID_1000 0x1000
+#define PID_1001 0x1001
+#define PID_1002 0x1002
+
+/* Max size of a single report */
+#define REPORT_MAX_SIZE 10
+
+
+/* Bitmask whether pen is in range */
+#define MASK_INRANGE 0x20
+#define MASK_BUTTON 0x01F
+
+#define PATHLENGTH 64
+
+/* DATA STRUCTURES */
+
+/* Device table */
+static struct usb_device_id gtco_usbid_table [] = {
+ { USB_DEVICE(VENDOR_ID_GTCO, PID_400) },
+ { USB_DEVICE(VENDOR_ID_GTCO, PID_401) },
+ { USB_DEVICE(VENDOR_ID_GTCO, PID_1000) },
+ { USB_DEVICE(VENDOR_ID_GTCO, PID_1001) },
+ { USB_DEVICE(VENDOR_ID_GTCO, PID_1002) },
+ { }
+};
+MODULE_DEVICE_TABLE (usb, gtco_usbid_table);
+
+
+/* Structure to hold all of our device specific stuff */
+struct gtco {
+
+ struct input_dev *inputdevice; /* input device struct pointer */
+ struct usb_device *usbdev; /* the usb device for this device */
+ struct urb *urbinfo; /* urb for incoming reports */
+ dma_addr_t buf_dma; /* dma addr of the data buffer*/
+ unsigned char * buffer; /* databuffer for reports */
+
+ char usbpath[PATHLENGTH];
+ int openCount;
+
+ /* Information pulled from Report Descriptor */
+ u32 usage;
+ u32 min_X;
+ u32 max_X;
+ u32 min_Y;
+ u32 max_Y;
+ s8 mintilt_X;
+ s8 maxtilt_X;
+ s8 mintilt_Y;
+ s8 maxtilt_Y;
+ u32 maxpressure;
+ u32 minpressure;
+};
+
+
+
+/* Code for parsing the HID REPORT DESCRIPTOR */
+
+/* From HID1.11 spec */
+struct hid_descriptor
+{
+ struct usb_descriptor_header header;
+ __le16 bcdHID;
+ u8 bCountryCode;
+ u8 bNumDescriptors;
+ u8 bDescriptorType;
+ __le16 wDescriptorLength;
+} __attribute__ ((packed));
+
+
+#define HID_DESCRIPTOR_SIZE 9
+#define HID_DEVICE_TYPE 33
+#define REPORT_DEVICE_TYPE 34
+
+
+#define PREF_TAG(x) ((x)>>4)
+#define PREF_TYPE(x) ((x>>2)&0x03)
+#define PREF_SIZE(x) ((x)&0x03)
+
+#define TYPE_MAIN 0
+#define TYPE_GLOBAL 1
+#define TYPE_LOCAL 2
+#define TYPE_RESERVED 3
+
+#define TAG_MAIN_INPUT 0x8
+#define TAG_MAIN_OUTPUT 0x9
+#define TAG_MAIN_FEATURE 0xB
+#define TAG_MAIN_COL_START 0xA
+#define TAG_MAIN_COL_END 0xC
+
+#define TAG_GLOB_USAGE 0
+#define TAG_GLOB_LOG_MIN 1
+#define TAG_GLOB_LOG_MAX 2
+#define TAG_GLOB_PHYS_MIN 3
+#define TAG_GLOB_PHYS_MAX 4
+#define TAG_GLOB_UNIT_EXP 5
+#define TAG_GLOB_UNIT 6
+#define TAG_GLOB_REPORT_SZ 7
+#define TAG_GLOB_REPORT_ID 8
+#define TAG_GLOB_REPORT_CNT 9
+#define TAG_GLOB_PUSH 10
+#define TAG_GLOB_POP 11
+
+#define TAG_GLOB_MAX 12
+
+#define DIGITIZER_USAGE_TIP_PRESSURE 0x30
+#define DIGITIZER_USAGE_TILT_X 0x3D
+#define DIGITIZER_USAGE_TILT_Y 0x3E
+
+
+/*
+ *
+ * This is an abbreviated parser for the HID Report Descriptor. We
+ * know what devices we are talking to, so this is by no means meant
+ * to be generic. We can make some safe assumptions:
+ *
+ * - We know there are no LONG tags, all short
+ * - We know that we have no MAIN Feature and MAIN Output items
+ * - We know what the IRQ reports are supposed to look like.
+ *
+ * The main purpose of this is to use the HID report desc to figure
+ * out the mins and maxs of the fields in the IRQ reports. The IRQ
+ * reports for 400/401 change slightly if the max X is bigger than 64K.
+ *
+ */
+static void parse_hid_report_descriptor(struct gtco *device, char * report,
+ int length)
+{
+ int x,i=0;
+
+ /* Tag primitive vars */
+ __u8 prefix;
+ __u8 size;
+ __u8 tag;
+ __u8 type;
+ __u8 data = 0;
+ __u16 data16 = 0;
+ __u32 data32 = 0;
+
+
+ /* For parsing logic */
+ int inputnum = 0;
+ __u32 usage = 0;
+
+ /* Global Values, indexed by TAG */
+ __u32 globalval[TAG_GLOB_MAX];
+ __u32 oldval[TAG_GLOB_MAX];
+
+ /* Debug stuff */
+ char maintype='x';
+ char globtype[12];
+ int indent=0;
+ char indentstr[10]="";
+
+
+
+ dbg("======>>>>>>PARSE<<<<<<======");
+
+ /* Walk this report and pull out the info we need */
+ while (i<length){
+ prefix=report[i];
+
+ /* Skip over prefix */
+ i++;
+
+ /* Determine data size and save the data in the proper variable */
+ size = PREF_SIZE(prefix);
+ switch(size){
+ case 1:
+ data = report[i];
+ break;
+ case 2:
+ data16 = le16_to_cpu(get_unaligned((__le16*)(&(report[i]))));
+ break;
+ case 3:
+ size = 4;
+ data32 = le32_to_cpu(get_unaligned((__le32*)(&(report[i]))));
+ }
+
+ /* Skip size of data */
+ i+=size;
+
+ /* What we do depends on the tag type */
+ tag = PREF_TAG(prefix);
+ type = PREF_TYPE(prefix);
+ switch(type){
+ case TYPE_MAIN:
+ strcpy(globtype,"");
+ switch(tag){
+
+ case TAG_MAIN_INPUT:
+ /*
+ * The INPUT MAIN tag signifies this is
+ * information from a report. We need to
+ * figure out what it is and store the
+ * min/max values
+ */
+
+ maintype='I';
+ if (data==2){
+ strcpy(globtype,"Variable");
+ }
+ if (data==3){
+ strcpy(globtype,"Var|Const");
+ }
+
+ dbg("::::: Saving Report: %d input #%d Max: 0x%X(%d) Min:0x%X(%d) of %d bits",
+ globalval[TAG_GLOB_REPORT_ID],inputnum,
+ globalval[TAG_GLOB_LOG_MAX],globalval[TAG_GLOB_LOG_MAX],
+ globalval[TAG_GLOB_LOG_MIN],globalval[TAG_GLOB_LOG_MIN],
+ (globalval[TAG_GLOB_REPORT_SZ] * globalval[TAG_GLOB_REPORT_CNT]));
+
+
+ /*
+ We can assume that the first two input items
+ are always the X and Y coordinates. After
+ that, we look for everything else by
+ local usage value
+ */
+ switch (inputnum){
+ case 0: /* X coord */
+ dbg("GER: X Usage: 0x%x",usage);
+ if (device->max_X == 0){
+ device->max_X = globalval[TAG_GLOB_LOG_MAX];
+ device->min_X = globalval[TAG_GLOB_LOG_MIN];
+ }
+
+ break;
+ case 1: /* Y coord */
+ dbg("GER: Y Usage: 0x%x",usage);
+ if (device->max_Y == 0){
+ device->max_Y = globalval[TAG_GLOB_LOG_MAX];
+ device->min_Y = globalval[TAG_GLOB_LOG_MIN];
+ }
+ break;
+ default:
+ /* Tilt X */
+ if (usage == DIGITIZER_USAGE_TILT_X){
+ if (device->maxtilt_X == 0){
+ device->maxtilt_X = globalval[TAG_GLOB_LOG_MAX];
+ device->mintilt_X = globalval[TAG_GLOB_LOG_MIN];
+ }
+ }
+
+ /* Tilt Y */
+ if (usage == DIGITIZER_USAGE_TILT_Y){
+ if (device->maxtilt_Y == 0){
+ device->maxtilt_Y = globalval[TAG_GLOB_LOG_MAX];
+ device->mintilt_Y = globalval[TAG_GLOB_LOG_MIN];
+ }
+ }
+
+
+ /* Pressure */
+ if (usage == DIGITIZER_USAGE_TIP_PRESSURE){
+ if (device->maxpressure == 0){
+ device->maxpressure = globalval[TAG_GLOB_LOG_MAX];
+ device->minpressure = globalval[TAG_GLOB_LOG_MIN];
+ }
+ }
+
+ break;
+ }
+
+ inputnum++;
+
+
+ break;
+ case TAG_MAIN_OUTPUT:
+ maintype='O';
+ break;
+ case TAG_MAIN_FEATURE:
+ maintype='F';
+ break;
+ case TAG_MAIN_COL_START:
+ maintype='S';
+
+ if (data==0){
+ dbg("======>>>>>> Physical");
+ strcpy(globtype,"Physical");
+ }else{
+ dbg("======>>>>>>");
+ }
+
+ /* Indent the debug output */
+ indent++;
+ for (x=0;x<indent;x++){
+ indentstr[x]='-';
+ }
+ indentstr[x]=0;
+
+ /* Save global tags */
+ for (x=0;x<TAG_GLOB_MAX;x++){
+ oldval[x] = globalval[x];
+ }
+
+ break;
+ case TAG_MAIN_COL_END:
+ dbg("<<<<<<======");
+ maintype='E';
+ indent--;
+ for (x=0;x<indent;x++){
+ indentstr[x]='-';
+ }
+ indentstr[x]=0;
+
+ /* Copy global tags back */
+ for (x=0;x<TAG_GLOB_MAX;x++){
+ globalval[x] = oldval[x];
+ }
+
+ break;
+ }
+
+ switch (size){
+ case 1:
+ dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
+ indentstr,tag,maintype,size,globtype,data);
+ break;
+ case 2:
+ dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
+ indentstr,tag,maintype,size,globtype, data16);
+ break;
+ case 4:
+ dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
+ indentstr,tag,maintype,size,globtype,data32);
+ break;
+ }
+ break;
+ case TYPE_GLOBAL:
+ switch(tag){
+ case TAG_GLOB_USAGE:
+ /*
+ * First time we hit the global usage tag,
+ * it should tell us the type of device
+ */
+ if (device->usage == 0){
+ device->usage = data;
+ }
+ strcpy(globtype,"USAGE");
+ break;
+ case TAG_GLOB_LOG_MIN :
+ strcpy(globtype,"LOG_MIN");
+ break;
+ case TAG_GLOB_LOG_MAX :
+ strcpy(globtype,"LOG_MAX");
+ break;
+ case TAG_GLOB_PHYS_MIN :
+ strcpy(globtype,"PHYS_MIN");
+ break;
+ case TAG_GLOB_PHYS_MAX :
+ strcpy(globtype,"PHYS_MAX");
+ break;
+ case TAG_GLOB_UNIT_EXP :
+ strcpy(globtype,"EXP");
+ break;
+ case TAG_GLOB_UNIT :
+ strcpy(globtype,"UNIT");
+ break;
+ case TAG_GLOB_REPORT_SZ :
+ strcpy(globtype,"REPORT_SZ");
+ break;
+ case TAG_GLOB_REPORT_ID :
+ strcpy(globtype,"REPORT_ID");
+ /* New report, restart numbering */
+ inputnum=0;
+ break;
+ case TAG_GLOB_REPORT_CNT:
+ strcpy(globtype,"REPORT_CNT");
+ break;
+ case TAG_GLOB_PUSH :
+ strcpy(globtype,"PUSH");
+ break;
+ case TAG_GLOB_POP:
+ strcpy(globtype,"POP");
+ break;
+ }
+
+
+ /* Check to make sure we have a good tag number
+ so we don't overflow array */
+ if (tag < TAG_GLOB_MAX){
+ switch (size){
+ case 1:
+ dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data);
+ globalval[tag]=data;
+ break;
+ case 2:
+ dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data16);
+ globalval[tag]=data16;
+ break;
+ case 4:
+ dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data32);
+ globalval[tag]=data32;
+ break;
+ }
+ }else{
+ dbg("%sGLOBALTAG: ILLEGAL TAG:%d SIZE: %d ",
+ indentstr,tag,size);
+ }
+
+
+ break;
+
+ case TYPE_LOCAL:
+ switch(tag){
+ case TAG_GLOB_USAGE:
+ strcpy(globtype,"USAGE");
+ /* Always 1 byte */
+ usage = data;
+ break;
+ case TAG_GLOB_LOG_MIN :
+ strcpy(globtype,"MIN");
+ break;
+ case TAG_GLOB_LOG_MAX :
+ strcpy(globtype,"MAX");
+ break;
+ default:
+ strcpy(globtype,"UNKNOWN");
+ }
+
+ switch (size){
+ case 1:
+ dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
+ indentstr,tag,globtype,size,data);
+ break;
+ case 2:
+ dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
+ indentstr,tag,globtype,size,data16);
+ break;
+ case 4:
+ dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
+ indentstr,tag,globtype,size,data32);
+ break;
+ }
+
+ break;
+ }
+
+ }
+
+}
+
+
+
+/* INPUT DRIVER Routines */
+
+
+/*
+ * Called when opening the input device. This will submit the URB to
+ * the usb system so we start getting reports
+ */
+static int gtco_input_open(struct input_dev *inputdev)
+{
+ struct gtco *device;
+ device = inputdev->private;
+
+ device->urbinfo->dev = device->usbdev;
+ if (usb_submit_urb(device->urbinfo, GFP_KERNEL)) {
+ return -EIO;
+ }
+ return 0;
+}
+
+/**
+ Called when closing the input device. This will unlink the URB
+*/
+static void gtco_input_close(struct input_dev *inputdev)
+{
+ struct gtco *device = inputdev->private;
+
+ usb_kill_urb(device->urbinfo);
+
+}
+
+
+/*
+ * Setup input device capabilities. Tell the input system what this
+ * device is capable of generating.
+ *
+ * This information is based on what is read from the HID report and
+ * placed in the struct gtco structure
+ *
+ */
+static void gtco_setup_caps(struct input_dev *inputdev)
+{
+ struct gtco *device = inputdev->private;
+
+
+ /* Which events */
+ inputdev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_MSC);
+
+
+ /* Misc event menu block */
+ inputdev->mscbit[0] = BIT(MSC_SCAN)|BIT(MSC_SERIAL)|BIT(MSC_RAW) ;
+
+
+ /* Absolute values based on HID report info */
+ input_set_abs_params(inputdev, ABS_X, device->min_X, device->max_X,
+ 0, 0);
+ input_set_abs_params(inputdev, ABS_Y, device->min_Y, device->max_Y,
+ 0, 0);
+
+ /* Proximity */
+ input_set_abs_params(inputdev, ABS_DISTANCE, 0, 1, 0, 0);
+
+ /* Tilt & pressure */
+ input_set_abs_params(inputdev, ABS_TILT_X, device->mintilt_X,
+ device->maxtilt_X, 0, 0);
+ input_set_abs_params(inputdev, ABS_TILT_Y, device->mintilt_Y,
+ device->maxtilt_Y, 0, 0);
+ input_set_abs_params(inputdev, ABS_PRESSURE, device->minpressure,
+ device->maxpressure, 0, 0);
+
+
+ /* Transducer */
+ input_set_abs_params(inputdev, ABS_MISC, 0,0xFF, 0, 0);
+
+}
+
+
+
+/* USB Routines */
+
+
+/*
+ * URB callback routine. Called when we get IRQ reports from the
+ * digitizer.
+ *
+ * This bridges the USB and input device worlds. It generates events
+ * on the input device based on the USB reports.
+ */
+static void gtco_urb_callback(struct urb *urbinfo)
+{
+
+
+ struct gtco *device = urbinfo->context;
+ struct input_dev *inputdev;
+ int rc;
+ u32 val = 0;
+ s8 valsigned = 0;
+ char le_buffer[2];
+
+ inputdev = device->inputdevice;
+
+
+ /* Was callback OK? */
+ if ((urbinfo->status == -ECONNRESET ) ||
+ (urbinfo->status == -ENOENT ) ||
+ (urbinfo->status == -ESHUTDOWN )){
+
+ /* Shutdown is occurring. Return and don't queue up any more */
+ return;
+ }
+
+ if (urbinfo->status != 0 ) {
+ /* Some unknown error. Hopefully temporary. Just go and */
+ /* requeue an URB */
+ goto resubmit;
+ }
+
+ /*
+ * Good URB, now process
+ */
+
+ /* PID dependent when we interpret the report */
+ if ((inputdev->id.product == PID_1000 )||
+ (inputdev->id.product == PID_1001 )||
+ (inputdev->id.product == PID_1002 ))
+ {
+
+ /*
+ * Switch on the report ID
+ * Conveniently, the reports have more information, the higher
+ * the report number. We can just fall through the case
+ * statements if we start with the highest number report
+ */
+ switch(device->buffer[0]){
+ case 5:
+ /* Pressure is 9 bits */
+ val = ((u16)(device->buffer[8]) << 1);
+ val |= (u16)(device->buffer[7] >> 7);
+ input_report_abs(inputdev, ABS_PRESSURE,
+ device->buffer[8]);
+
+ /* Mask out the Y tilt value used for pressure */
+ device->buffer[7] = (u8)((device->buffer[7]) & 0x7F);
+
+
+ /* Fall thru */
+ case 4:
+ /* Tilt */
+
+ /* Sign extend these 7 bit numbers. */
+ if (device->buffer[6] & 0x40)
+ device->buffer[6] |= 0x80;
+
+ if (device->buffer[7] & 0x40)
+ device->buffer[7] |= 0x80;
+
+
+ valsigned = (device->buffer[6]);
+ input_report_abs(inputdev, ABS_TILT_X, (s32)valsigned);
+
+ valsigned = (device->buffer[7]);
+ input_report_abs(inputdev, ABS_TILT_Y, (s32)valsigned);
+
+ /* Fall thru */
+
+ case 2:
+ case 3:
+ /* Convert buttons, only 5 bits possible */
+ val = (device->buffer[5])&MASK_BUTTON;
+
+ /* We don't apply any meaning to the bitmask,
+ just report */
+ input_event(inputdev, EV_MSC, MSC_SERIAL, val);
+
+ /* Fall thru */
+ case 1:
+
+ /* All reports have X and Y coords in the same place */
+ val = le16_to_cpu(get_unaligned((__le16 *) &(device->buffer[1])));
+ input_report_abs(inputdev, ABS_X, val);
+
+ val = le16_to_cpu(get_unaligned((__le16 *) &(device->buffer[3])));
+ input_report_abs(inputdev, ABS_Y, val);
+
+
+ /* Ditto for proximity bit */
+ if (device->buffer[5]& MASK_INRANGE){
+ val = 1;
+ }else{
+ val=0;
+ }
+ input_report_abs(inputdev, ABS_DISTANCE, val);
+
+
+ /* Report 1 is an exception to how we handle buttons */
+ /* Buttons are an index, not a bitmask */
+ if (device->buffer[0] == 1){
+
+ /* Convert buttons, 5 bit index */
+ /* Report value of index set as one,
+ the rest as 0 */
+ val = device->buffer[5]& MASK_BUTTON;
+ dbg("======>>>>>>REPORT 1: val 0x%X(%d)",
+ val,val);
+
+ /*
+ * We don't apply any meaning to the button
+ * index, just report it
+ */
+ input_event(inputdev, EV_MSC, MSC_SERIAL, val);
+
+
+ }
+
+ break;
+ case 7:
+ /* Menu blocks */
+ input_event(inputdev, EV_MSC, MSC_SCAN,
+ device->buffer[1]);
+
+
+ break;
+
+ }
+
+
+ }
+ /* Other pid class */
+ if ((inputdev->id.product == PID_400 )||
+ (inputdev->id.product == PID_401 ))
+ {
+
+ /* Report 2 */
+ if (device->buffer[0] == 2){
+ /* Menu blocks */
+ input_event(inputdev, EV_MSC, MSC_SCAN,
+ device->buffer[1]);
+ }
+
+ /* Report 1 */
+ if (device->buffer[0] == 1){
+ char buttonbyte;
+
+
+ /* IF X max > 64K, we still a bit from the y report */
+ if (device->max_X > 0x10000){
+
+ val = (u16)(((u16)(device->buffer[2]<<8))|((u8)(device->buffer[1])));
+ val |= (u32)(((u8)device->buffer[3]&0x1)<< 16);
+
+ input_report_abs(inputdev, ABS_X, val);
+
+ le_buffer[0] = (u8)((u8)(device->buffer[3])>>1);
+ le_buffer[0] |= (u8)((device->buffer[3]&0x1)<<7);
+
+ le_buffer[1] = (u8)(device->buffer[4]>>1);
+ le_buffer[1] |= (u8)((device->buffer[5]&0x1)<<7);
+
+ val = le16_to_cpu(get_unaligned((__le16 *)(le_buffer)));
+
+ input_report_abs(inputdev, ABS_Y, val);
+
+
+ /*
+ * Shift the button byte right by one to
+ * make it look like the standard report
+ */
+ buttonbyte = (device->buffer[5])>>1;
+ }else{
+
+ val = le16_to_cpu(get_unaligned((__le16 *) (&(device->buffer[1]))));
+ input_report_abs(inputdev, ABS_X, val);
+
+ val = le16_to_cpu(get_unaligned((__le16 *) (&(device->buffer[3]))));
+ input_report_abs(inputdev, ABS_Y, val);
+
+ buttonbyte = device->buffer[5];
+
+ }
+
+
+ /* BUTTONS and PROXIMITY */
+ if (buttonbyte& MASK_INRANGE){
+ val = 1;
+ }else{
+ val=0;
+ }
+ input_report_abs(inputdev, ABS_DISTANCE, val);
+
+ /* Convert buttons, only 4 bits possible */
+ val = buttonbyte&0x0F;
+#ifdef USE_BUTTONS
+ for ( i=0;i<5;i++){
+ input_report_key(inputdev, BTN_DIGI+i,val&(1<<i));
+ }
+#else
+ /* We don't apply any meaning to the bitmask, just report */
+ input_event(inputdev, EV_MSC, MSC_SERIAL, val);
+#endif
+ /* TRANSDUCER */
+ input_report_abs(inputdev, ABS_MISC, device->buffer[6]);
+
+ }
+ }
+
+ /* Everybody gets report ID's */
+ input_event(inputdev, EV_MSC, MSC_RAW, device->buffer[0]);
+
+ /* Sync it up */
+ input_sync(inputdev);
+
+ resubmit:
+ rc = usb_submit_urb(urbinfo, GFP_ATOMIC);
+ if (rc != 0) {
+ err("usb_submit_urb failed rc=0x%x",rc);
+ }
+
+}
+
+/*
+ * The probe routine. This is called when the kernel find the matching USB
+ * vendor/product. We do the following:
+ *
+ * - Allocate mem for a local structure to manage the device
+ * - Request a HID Report Descriptor from the device and parse it to
+ * find out the device parameters
+ * - Create an input device and assign it attributes
+ * - Allocate an URB so the device can talk to us when the input
+ * queue is open
+ */
+static int gtco_probe(struct usb_interface *usbinterface,
+ const struct usb_device_id *id)
+{
+
+ struct gtco *device = NULL;
+ char path[PATHLENGTH];
+ struct input_dev *inputdev;
+ struct hid_descriptor *hid_desc;
+ char *report;
+ int result=0, retry;
+ struct usb_endpoint_descriptor *endpoint;
+
+ /* Allocate memory for device structure */
+ device = kzalloc(sizeof(struct gtco), GFP_KERNEL);
+ if (device == NULL) {
+ err("No more memory");
+ return -ENOMEM;
+ }
+
+
+ device->inputdevice = input_allocate_device();
+ if (!device->inputdevice){
+ kfree(device);
+ err("No more memory");
+ return -ENOMEM;
+ }
+
+ /* Get pointer to the input device */
+ inputdev = device->inputdevice;
+
+ /* Save interface information */
+ device->usbdev = usb_get_dev(interface_to_usbdev(usbinterface));
+
+
+ /* Allocate some data for incoming reports */
+ device->buffer = usb_buffer_alloc(device->usbdev, REPORT_MAX_SIZE,
+ GFP_KERNEL, &(device->buf_dma));
+ if (!device->buffer){
+ input_free_device(device->inputdevice);
+ kfree(device);
+ err("No more memory");
+ return -ENOMEM;
+ }
+
+ /* Allocate URB for reports */
+ device->urbinfo = usb_alloc_urb(0, GFP_KERNEL);
+ if (!device->urbinfo) {
+ usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+ device->buffer, device->buf_dma);
+ input_free_device(device->inputdevice);
+ kfree(device);
+ err("No more memory");
+ return -ENOMEM;
+ }
+
+
+ /*
+ * The endpoint is always altsetting 0, we know this since we know
+ * this device only has one interrupt endpoint
+ */
+ endpoint = &usbinterface->altsetting[0].endpoint[0].desc;
+
+ /* Some debug */
+ dbg("gtco # interfaces: %d",usbinterface->num_altsetting);
+ dbg("num endpoints: %d",usbinterface->cur_altsetting->desc.bNumEndpoints);
+ dbg("interface class: %d",usbinterface->cur_altsetting->desc.bInterfaceClass);
+ dbg("endpoint: attribute:0x%x type:0x%x",endpoint->bmAttributes,endpoint->bDescriptorType);
+ if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)
+ dbg("endpoint: we have interrupt endpoint\n");
+
+ dbg("endpoint extra len:%d ",usbinterface->altsetting[0].extralen);
+
+
+
+ /*
+ * Find the HID descriptor so we can find out the size of the
+ * HID report descriptor
+ */
+ if (usb_get_extra_descriptor(usbinterface->cur_altsetting,
+ HID_DEVICE_TYPE,&hid_desc) != 0){
+ err("Can't retrieve exta USB descriptor to get hid report descriptor length");
+ usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+ device->buffer, device->buf_dma);
+ input_free_device(device->inputdevice);
+ kfree(device);
+ return -EIO;
+ }
+
+ dbg("Extra descriptor success: type:%d len:%d",
+ hid_desc->bDescriptorType, hid_desc->wDescriptorLength);
+
+ if (!(report = kzalloc(hid_desc->wDescriptorLength, GFP_KERNEL))) {
+ usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+ device->buffer, device->buf_dma);
+
+ input_free_device(device->inputdevice);
+ kfree(device);
+ err("No more memory");
+ return -ENOMEM;
+ }
+
+ /* Couple of tries to get reply */
+ for (retry=0;retry<3;retry++) {
+ result = usb_control_msg(device->usbdev,
+ usb_rcvctrlpipe(device->usbdev, 0),
+ USB_REQ_GET_DESCRIPTOR,
+ USB_RECIP_INTERFACE | USB_DIR_IN,
+ (REPORT_DEVICE_TYPE << 8),
+ 0, /* interface */
+ report,
+ hid_desc->wDescriptorLength,
+ 5000); /* 5 secs */
+
+ if (result == hid_desc->wDescriptorLength)
+ break;
+ }
+
+ /* If we didn't get the report, fail */
+ dbg("usb_control_msg result: :%d", result);
+ if (result != hid_desc->wDescriptorLength){
+ kfree(report);
+ usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+ device->buffer, device->buf_dma);
+ input_free_device(device->inputdevice);
+ kfree(device);
+ err("Failed to get HID Report Descriptor of size: %d",
+ hid_desc->wDescriptorLength);
+ return -EIO;
+ }
+
+
+ /* Now we parse the report */
+ parse_hid_report_descriptor(device,report,result);
+
+ /* Now we delete it */
+ kfree(report);
+
+ /* Create a device file node */
+ usb_make_path(device->usbdev, path, PATHLENGTH);
+ sprintf(device->usbpath, "%s/input0", path);
+
+
+ /* Set Input device functions */
+ inputdev->open = gtco_input_open;
+ inputdev->close = gtco_input_close;
+
+ /* Set input device information */
+ inputdev->name = "GTCO_CalComp";
+ inputdev->phys = device->usbpath;
+ inputdev->private = device;
+
+
+ /* Now set up all the input device capabilities */
+ gtco_setup_caps(inputdev);
+
+ /* Set input device required ID information */
+ usb_to_input_id(device->usbdev, &device->inputdevice->id);
+ inputdev->cdev.dev = &usbinterface->dev;
+
+ /* Setup the URB, it will be posted later on open of input device */
+ endpoint = &usbinterface->altsetting[0].endpoint[0].desc;
+
+ usb_fill_int_urb(device->urbinfo,
+ device->usbdev,
+ usb_rcvintpipe(device->usbdev,
+ endpoint->bEndpointAddress),
+ device->buffer,
+ REPORT_MAX_SIZE,
+ gtco_urb_callback,
+ device,
+ endpoint->bInterval);
+
+ device->urbinfo->transfer_dma = device->buf_dma;
+ device->urbinfo->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+
+ /* Save device pointer in USB interface device */
+ usb_set_intfdata(usbinterface, device);
+
+ /* All done, now register the input device */
+ input_register_device(inputdev);
+
+ info( "gtco driver created usb: %s\n", path);
+ return 0;
+
+}
+
+/*
+ * This function is a standard USB function called when the USB device
+ * is disconnected. We will get rid of the URV, de-register the input
+ * device, and free up allocated memory
+ */
+static void gtco_disconnect(struct usb_interface *interface)
+{
+
+ /* Grab private device ptr */
+ struct gtco *device = usb_get_intfdata (interface);
+ struct input_dev *inputdev;
+
+ inputdev = device->inputdevice;
+
+ /* Now reverse all the registration stuff */
+ if (device) {
+ input_unregister_device(inputdev);
+ usb_kill_urb(device->urbinfo);
+ usb_free_urb(device->urbinfo);
+ usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+ device->buffer, device->buf_dma);
+ kfree(device);
+ }
+
+ info("gtco driver disconnected");
+}
+
+
+/* STANDARD MODULE LOAD ROUTINES */
+
+static struct usb_driver gtco_driverinfo_table = {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16))
+ .owner = THIS_MODULE,
+#endif
+ .name = "gtco",
+ .id_table = gtco_usbid_table,
+ .probe = gtco_probe,
+ .disconnect = gtco_disconnect,
+};
+/*
+ * Register this module with the USB subsystem
+ */
+static int __init gtco_init(void)
+{
+ int rc;
+ rc = usb_register(&gtco_driverinfo_table);
+ if (rc) {
+ err("usb_register() failed rc=0x%x", rc);
+ }
+ printk("GTCO usb driver version: %s",GTCO_VERSION);
+ return rc;
+}
+
+/*
+ * Deregister this module with the USB subsystem
+ */
+static void __exit gtco_exit(void)
+{
+ usb_deregister(&gtco_driverinfo_table);
+}
+
+module_init (gtco_init);
+module_exit (gtco_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
index c6c9e72e5fd..84983d1b716 100644
--- a/drivers/usb/input/hid-core.c
+++ b/drivers/usb/input/hid-core.c
@@ -35,6 +35,7 @@
#include <linux/hid.h>
#include <linux/hiddev.h>
+#include <linux/hid-debug.h>
#include "usbhid.h"
/*
@@ -220,23 +221,6 @@ static void hid_irq_in(struct urb *urb)
}
}
-/*
- * Find a report field with a specified HID usage.
- */
-#if 0
-struct hid_field *hid_find_field_by_usage(struct hid_device *hid, __u32 wanted_usage, int type)
-{
- struct hid_report *report;
- int i;
-
- list_for_each_entry(report, &hid->report_enum[type].report_list, list)
- for (i = 0; i < report->maxfield; i++)
- if (report->field[i]->logical == wanted_usage)
- return report->field[i];
- return NULL;
-}
-#endif /* 0 */
-
static int hid_submit_out(struct hid_device *hid)
{
struct hid_report *report;
@@ -501,7 +485,7 @@ static int hid_get_class_descriptor(struct usb_device *dev, int ifnum,
{
int result, retries = 4;
- memset(buf,0,size); // Make sure we parse really received data
+ memset(buf, 0, size);
do {
result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
@@ -528,18 +512,6 @@ void usbhid_close(struct hid_device *hid)
usb_kill_urb(usbhid->urbin);
}
-static int hidinput_open(struct input_dev *dev)
-{
- struct hid_device *hid = dev->private;
- return usbhid_open(hid);
-}
-
-static void hidinput_close(struct input_dev *dev)
-{
- struct hid_device *hid = dev->private;
- usbhid_close(hid);
-}
-
#define USB_VENDOR_ID_PANJIT 0x134c
#define USB_VENDOR_ID_TURBOX 0x062a
@@ -770,6 +742,7 @@ void usbhid_init_reports(struct hid_device *hid)
#define USB_DEVICE_ID_APPLE_GEYSER4_JIS 0x021c
#define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a
#define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b
+#define USB_DEVICE_ID_APPLE_IR 0x8240
#define USB_VENDOR_ID_CHERRY 0x046a
#define USB_DEVICE_ID_CHERRY_CYMOTION 0x0023
@@ -792,6 +765,12 @@ void usbhid_init_reports(struct hid_device *hid)
#define USB_VENDOR_ID_IMATION 0x0718
#define USB_DEVICE_ID_DISC_STAKKA 0xd000
+#define USB_VENDOR_ID_PANTHERLORD 0x0810
+#define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK 0x0001
+
+#define USB_VENDOR_ID_SONY 0x054c
+#define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268
+
/*
* Alphabetically sorted blacklist by quirk type.
*/
@@ -946,19 +925,21 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION, HID_QUIRK_CYMOTION },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_POWERBOOK_HAS_FN },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_POWERBOOK_HAS_FN },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_POWERBOOK_HAS_FN },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_POWERBOOK_HAS_FN },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_POWERBOOK_HAS_FN },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_POWERBOOK_HAS_FN },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_POWERBOOK_HAS_FN },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_POWERBOOK_HAS_FN },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IR, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_PANJIT, 0x0001, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_PANJIT, 0x0002, HID_QUIRK_IGNORE },
@@ -969,6 +950,10 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_USB_RECEIVER, HID_QUIRK_BAD_RELATIVE_KEYS },
+ { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
+
+ { USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER, HID_QUIRK_SONY_PS3_CONTROLLER },
+
{ 0, 0 }
};
@@ -1033,6 +1018,32 @@ static void hid_fixup_cymotion_descriptor(char *rdesc, int rsize)
}
}
+/*
+ * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller
+ * to "operational". Without this, the ps3 controller will not report any
+ * events.
+ */
+static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum)
+{
+ int result;
+ char *buf = kmalloc(18, GFP_KERNEL);
+
+ if (!buf)
+ return;
+
+ result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ HID_REQ_GET_REPORT,
+ USB_DIR_IN | USB_TYPE_CLASS |
+ USB_RECIP_INTERFACE,
+ (3 << 8) | 0xf2, ifnum, buf, 17,
+ USB_CTRL_GET_TIMEOUT);
+
+ if (result < 0)
+ err("%s failed: %d\n", __func__, result);
+
+ kfree(buf);
+}
+
static struct hid_device *usb_hid_configure(struct usb_interface *intf)
{
struct usb_host_interface *interface = intf->cur_altsetting;
@@ -1064,6 +1075,11 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
if (quirks & HID_QUIRK_IGNORE)
return NULL;
+ if ((quirks & HID_QUIRK_IGNORE_MOUSE) &&
+ (interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE))
+ return NULL;
+
+
if (usb_get_extra_descriptor(interface, HID_DT_HID, &hdesc) &&
(!interface->desc.bNumEndpoints ||
usb_get_extra_descriptor(&interface->endpoint[0], HID_DT_HID, &hdesc))) {
@@ -1235,8 +1251,8 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma;
usbhid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
hid->hidinput_input_event = usb_hidinput_input_event;
- hid->hidinput_open = hidinput_open;
- hid->hidinput_close = hidinput_close;
+ hid->hid_open = usbhid_open;
+ hid->hid_close = usbhid_close;
#ifdef CONFIG_USB_HIDDEV
hid->hiddev_hid_event = hiddev_hid_event;
hid->hiddev_report_event = hiddev_report_event;
@@ -1315,13 +1331,13 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
return -ENODEV;
}
- /* This only gets called when we are a single-input (most of the
- * time). IOW, not a HID_QUIRK_MULTI_INPUT. The hid_ff_init() is
- * only useful in this case, and not for multi-input quirks. */
- if ((hid->claimed & HID_CLAIMED_INPUT) &&
- !(hid->quirks & HID_QUIRK_MULTI_INPUT))
+ if ((hid->claimed & HID_CLAIMED_INPUT))
hid_ff_init(hid);
+ if (hid->quirks & HID_QUIRK_SONY_PS3_CONTROLLER)
+ hid_fixup_sony_ps3_controller(interface_to_usbdev(intf),
+ intf->cur_altsetting->desc.bInterfaceNumber);
+
printk(KERN_INFO);
if (hid->claimed & HID_CLAIMED_INPUT)
diff --git a/drivers/usb/input/hid-ff.c b/drivers/usb/input/hid-ff.c
index 59ed65e7a62..5d145058a5c 100644
--- a/drivers/usb/input/hid-ff.c
+++ b/drivers/usb/input/hid-ff.c
@@ -58,6 +58,9 @@ static struct hid_ff_initializer inits[] = {
{ 0x46d, 0xc295, hid_lgff_init }, /* Logitech MOMO force wheel */
{ 0x46d, 0xc219, hid_lgff_init }, /* Logitech Cordless rumble pad 2 */
#endif
+#ifdef CONFIG_PANTHERLORD_FF
+ { 0x810, 0x0001, hid_plff_init },
+#endif
#ifdef CONFIG_THRUSTMASTER_FF
{ 0x44f, 0xb304, hid_tmff_init },
#endif
diff --git a/drivers/usb/input/hid-lgff.c b/drivers/usb/input/hid-lgff.c
index e4746626856..4f4fc3be192 100644
--- a/drivers/usb/input/hid-lgff.c
+++ b/drivers/usb/input/hid-lgff.c
@@ -32,7 +32,7 @@
#include <linux/hid.h>
#include "usbhid.h"
-struct device_type {
+struct dev_type {
u16 idVendor;
u16 idProduct;
const signed short *ff;
@@ -48,7 +48,7 @@ static const signed short ff_joystick[] = {
-1
};
-static const struct device_type devices[] = {
+static const struct dev_type devices[] = {
{ 0x046d, 0xc211, ff_rumble },
{ 0x046d, 0xc219, ff_rumble },
{ 0x046d, 0xc283, ff_joystick },
diff --git a/drivers/usb/input/hid-plff.c b/drivers/usb/input/hid-plff.c
new file mode 100644
index 00000000000..76d2e6e14db
--- /dev/null
+++ b/drivers/usb/input/hid-plff.c
@@ -0,0 +1,129 @@
+/*
+ * Force feedback support for PantherLord USB/PS2 2in1 Adapter devices
+ *
+ * Copyright (c) 2007 Anssi Hannula <anssi.hannula@gmail.com>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/* #define DEBUG */
+
+#define debug(format, arg...) pr_debug("hid-plff: " format "\n" , ## arg)
+
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/hid.h>
+#include "usbhid.h"
+
+struct plff_device {
+ struct hid_report *report;
+};
+
+static int hid_plff_play(struct input_dev *dev, void *data,
+ struct ff_effect *effect)
+{
+ struct hid_device *hid = dev->private;
+ struct plff_device *plff = data;
+ int left, right;
+
+ left = effect->u.rumble.strong_magnitude;
+ right = effect->u.rumble.weak_magnitude;
+ debug("called with 0x%04x 0x%04x", left, right);
+
+ left = left * 0x7f / 0xffff;
+ right = right * 0x7f / 0xffff;
+
+ plff->report->field[0]->value[2] = left;
+ plff->report->field[0]->value[3] = right;
+ debug("running with 0x%02x 0x%02x", left, right);
+ usbhid_submit_report(hid, plff->report, USB_DIR_OUT);
+
+ return 0;
+}
+
+int hid_plff_init(struct hid_device *hid)
+{
+ struct plff_device *plff;
+ struct hid_report *report;
+ struct hid_input *hidinput;
+ struct list_head *report_list =
+ &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+ struct list_head *report_ptr = report_list;
+ struct input_dev *dev;
+ int error;
+
+ /* The device contains 2 output reports (one for each
+ HID_QUIRK_MULTI_INPUT device), both containing 1 field, which
+ contains 4 ff00.0002 usages and 4 16bit absolute values.
+
+ The 2 input reports also contain a field which contains
+ 8 ff00.0001 usages and 8 boolean values. Their meaning is
+ currently unknown. */
+
+ if (list_empty(report_list)) {
+ printk(KERN_ERR "hid-plff: no output reports found\n");
+ return -ENODEV;
+ }
+
+ list_for_each_entry(hidinput, &hid->inputs, list) {
+
+ report_ptr = report_ptr->next;
+
+ if (report_ptr == report_list) {
+ printk(KERN_ERR "hid-plff: required output report is missing\n");
+ return -ENODEV;
+ }
+
+ report = list_entry(report_ptr, struct hid_report, list);
+ if (report->maxfield < 1) {
+ printk(KERN_ERR "hid-plff: no fields in the report\n");
+ return -ENODEV;
+ }
+
+ if (report->field[0]->report_count < 4) {
+ printk(KERN_ERR "hid-plff: not enough values in the field\n");
+ return -ENODEV;
+ }
+
+ plff = kzalloc(sizeof(struct plff_device), GFP_KERNEL);
+ if (!plff)
+ return -ENOMEM;
+
+ dev = hidinput->input;
+
+ set_bit(FF_RUMBLE, dev->ffbit);
+
+ error = input_ff_create_memless(dev, plff, hid_plff_play);
+ if (error) {
+ kfree(plff);
+ return error;
+ }
+
+ plff->report = report;
+ plff->report->field[0]->value[0] = 0x00;
+ plff->report->field[0]->value[1] = 0x00;
+ plff->report->field[0]->value[2] = 0x00;
+ plff->report->field[0]->value[3] = 0x00;
+ usbhid_submit_report(hid, plff->report, USB_DIR_OUT);
+ }
+
+ printk(KERN_INFO "hid-plff: Force feedback for PantherLord USB/PS2 "
+ "2in1 Adapters by Anssi Hannula <anssi.hannula@gmail.com>\n");
+
+ return 0;
+}
diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c
index c9418535bef..15c70bd048c 100644
--- a/drivers/usb/misc/idmouse.c
+++ b/drivers/usb/misc/idmouse.c
@@ -269,7 +269,7 @@ static int idmouse_release(struct inode *inode, struct file *file)
/* prevent a race condition with open() */
mutex_lock(&disconnect_mutex);
- dev = (struct usb_idmouse *) file->private_data;
+ dev = file->private_data;
if (dev == NULL) {
mutex_unlock(&disconnect_mutex);
@@ -304,17 +304,15 @@ static int idmouse_release(struct inode *inode, struct file *file)
static ssize_t idmouse_read(struct file *file, char __user *buffer, size_t count,
loff_t * ppos)
{
- struct usb_idmouse *dev;
+ struct usb_idmouse *dev = file->private_data;
int result;
- dev = (struct usb_idmouse *) file->private_data;
-
/* lock this object */
- down (&dev->sem);
+ down(&dev->sem);
/* verify that the device wasn't unplugged */
if (!dev->present) {
- up (&dev->sem);
+ up(&dev->sem);
return -ENODEV;
}
diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c
index 384fa376980..fdf68479a16 100644
--- a/drivers/usb/misc/rio500.c
+++ b/drivers/usb/misc/rio500.c
@@ -69,7 +69,7 @@ struct rio_usb_data {
char *obuf, *ibuf; /* transfer buffers */
char bulk_in_ep, bulk_out_ep; /* Endpoint assignments */
wait_queue_head_t wait_q; /* for timeouts */
- struct semaphore lock; /* general race avoidance */
+ struct mutex lock; /* general race avoidance */
};
static struct rio_usb_data rio_instance;
@@ -78,17 +78,17 @@ static int open_rio(struct inode *inode, struct file *file)
{
struct rio_usb_data *rio = &rio_instance;
- down(&(rio->lock));
+ mutex_lock(&(rio->lock));
if (rio->isopen || !rio->present) {
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return -EBUSY;
}
rio->isopen = 1;
init_waitqueue_head(&rio->wait_q);
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
info("Rio opened.");
@@ -117,7 +117,7 @@ ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd,
int retries;
int retval=0;
- down(&(rio->lock));
+ mutex_lock(&(rio->lock));
/* Sanity check to make sure rio is connected, powered, etc */
if ( rio == NULL ||
rio->present == 0 ||
@@ -257,7 +257,7 @@ ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd,
err_out:
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return retval;
}
@@ -275,14 +275,17 @@ write_rio(struct file *file, const char __user *buffer,
int result = 0;
int maxretry;
int errn = 0;
+ int intr;
- down(&(rio->lock));
+ intr = mutex_lock_interruptible(&(rio->lock));
+ if (intr)
+ return -EINTR;
/* Sanity check to make sure rio is connected, powered, etc */
if ( rio == NULL ||
rio->present == 0 ||
rio->rio_dev == NULL )
{
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return -ENODEV;
}
@@ -305,7 +308,7 @@ write_rio(struct file *file, const char __user *buffer,
goto error;
}
if (signal_pending(current)) {
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return bytes_written ? bytes_written : -EINTR;
}
@@ -341,12 +344,12 @@ write_rio(struct file *file, const char __user *buffer,
buffer += copy_size;
} while (count > 0);
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return bytes_written ? bytes_written : -EIO;
error:
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return errn;
}
@@ -361,14 +364,17 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
int result;
int maxretry = 10;
char *ibuf;
+ int intr;
- down(&(rio->lock));
+ intr = mutex_lock_interruptible(&(rio->lock));
+ if (intr)
+ return -EINTR;
/* Sanity check to make sure rio is connected, powered, etc */
if ( rio == NULL ||
rio->present == 0 ||
rio->rio_dev == NULL )
{
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return -ENODEV;
}
@@ -379,11 +385,11 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
while (count > 0) {
if (signal_pending(current)) {
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return read_count ? read_count : -EINTR;
}
if (!rio->rio_dev) {
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return -ENODEV;
}
this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count;
@@ -400,7 +406,7 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
count = this_read = partial;
} else if (result == -ETIMEDOUT || result == 15) { /* FIXME: 15 ??? */
if (!maxretry--) {
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
err("read_rio: maxretry timeout");
return -ETIME;
}
@@ -409,18 +415,18 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
finish_wait(&rio->wait_q, &wait);
continue;
} else if (result != -EREMOTEIO) {
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
err("Read Whoops - result:%u partial:%u this_read:%u",
result, partial, this_read);
return -EIO;
} else {
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return (0);
}
if (this_read) {
if (copy_to_user(buffer, ibuf, this_read)) {
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return -EFAULT;
}
count -= this_read;
@@ -428,7 +434,7 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
buffer += this_read;
}
}
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return read_count;
}
@@ -480,7 +486,7 @@ static int probe_rio(struct usb_interface *intf,
}
dbg("probe_rio: ibuf address:%p", rio->ibuf);
- init_MUTEX(&(rio->lock));
+ mutex_init(&(rio->lock));
usb_set_intfdata (intf, rio);
rio->present = 1;
@@ -496,12 +502,12 @@ static void disconnect_rio(struct usb_interface *intf)
if (rio) {
usb_deregister_dev(intf, &usb_rio_class);
- down(&(rio->lock));
+ mutex_lock(&(rio->lock));
if (rio->isopen) {
rio->isopen = 0;
/* better let it finish - the release will do whats needed */
rio->rio_dev = NULL;
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return;
}
kfree(rio->ibuf);
@@ -510,7 +516,7 @@ static void disconnect_rio(struct usb_interface *intf)
info("USB Rio disconnected.");
rio->present = 0;
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
}
}
diff --git a/drivers/usb/mon/Makefile b/drivers/usb/mon/Makefile
index 3cf3ea3a88e..90c59535778 100644
--- a/drivers/usb/mon/Makefile
+++ b/drivers/usb/mon/Makefile
@@ -2,7 +2,7 @@
# Makefile for USB Core files and filesystem
#
-usbmon-objs := mon_main.o mon_stat.o mon_text.o mon_dma.o
+usbmon-objs := mon_main.o mon_stat.o mon_text.o mon_bin.o mon_dma.o
# This does not use CONFIG_USB_MON because we want this to use a tristate.
obj-$(CONFIG_USB) += usbmon.o
diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c
new file mode 100644
index 00000000000..c01dfe60367
--- /dev/null
+++ b/drivers/usb/mon/mon_bin.c
@@ -0,0 +1,1172 @@
+/*
+ * The USB Monitor, inspired by Dave Harding's USBMon.
+ *
+ * This is a binary format reader.
+ *
+ * Copyright (C) 2006 Paolo Abeni (paolo.abeni@email.it)
+ * Copyright (C) 2006 Pete Zaitcev (zaitcev@redhat.com)
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/usb.h>
+#include <linux/poll.h>
+#include <linux/compat.h>
+#include <linux/mm.h>
+
+#include <asm/uaccess.h>
+
+#include "usb_mon.h"
+
+/*
+ * Defined by USB 2.0 clause 9.3, table 9.2.
+ */
+#define SETUP_LEN 8
+
+/* ioctl macros */
+#define MON_IOC_MAGIC 0x92
+
+#define MON_IOCQ_URB_LEN _IO(MON_IOC_MAGIC, 1)
+/* #2 used to be MON_IOCX_URB, removed before it got into Linus tree */
+#define MON_IOCG_STATS _IOR(MON_IOC_MAGIC, 3, struct mon_bin_stats)
+#define MON_IOCT_RING_SIZE _IO(MON_IOC_MAGIC, 4)
+#define MON_IOCQ_RING_SIZE _IO(MON_IOC_MAGIC, 5)
+#define MON_IOCX_GET _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get)
+#define MON_IOCX_MFETCH _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch)
+#define MON_IOCH_MFLUSH _IO(MON_IOC_MAGIC, 8)
+#ifdef CONFIG_COMPAT
+#define MON_IOCX_GET32 _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get32)
+#define MON_IOCX_MFETCH32 _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch32)
+#endif
+
+/*
+ * Some architectures have enormous basic pages (16KB for ia64, 64KB for ppc).
+ * But it's all right. Just use a simple way to make sure the chunk is never
+ * smaller than a page.
+ *
+ * N.B. An application does not know our chunk size.
+ *
+ * Woops, get_zeroed_page() returns a single page. I guess we're stuck with
+ * page-sized chunks for the time being.
+ */
+#define CHUNK_SIZE PAGE_SIZE
+#define CHUNK_ALIGN(x) (((x)+CHUNK_SIZE-1) & ~(CHUNK_SIZE-1))
+
+/*
+ * The magic limit was calculated so that it allows the monitoring
+ * application to pick data once in two ticks. This way, another application,
+ * which presumably drives the bus, gets to hog CPU, yet we collect our data.
+ * If HZ is 100, a 480 mbit/s bus drives 614 KB every jiffy. USB has an
+ * enormous overhead built into the bus protocol, so we need about 1000 KB.
+ *
+ * This is still too much for most cases, where we just snoop a few
+ * descriptor fetches for enumeration. So, the default is a "reasonable"
+ * amount for systems with HZ=250 and incomplete bus saturation.
+ *
+ * XXX What about multi-megabyte URBs which take minutes to transfer?
+ */
+#define BUFF_MAX CHUNK_ALIGN(1200*1024)
+#define BUFF_DFL CHUNK_ALIGN(300*1024)
+#define BUFF_MIN CHUNK_ALIGN(8*1024)
+
+/*
+ * The per-event API header (2 per URB).
+ *
+ * This structure is seen in userland as defined by the documentation.
+ */
+struct mon_bin_hdr {
+ u64 id; /* URB ID - from submission to callback */
+ unsigned char type; /* Same as in text API; extensible. */
+ unsigned char xfer_type; /* ISO, Intr, Control, Bulk */
+ unsigned char epnum; /* Endpoint number and transfer direction */
+ unsigned char devnum; /* Device address */
+ unsigned short busnum; /* Bus number */
+ char flag_setup;
+ char flag_data;
+ s64 ts_sec; /* gettimeofday */
+ s32 ts_usec; /* gettimeofday */
+ int status;
+ unsigned int len_urb; /* Length of data (submitted or actual) */
+ unsigned int len_cap; /* Delivered length */
+ unsigned char setup[SETUP_LEN]; /* Only for Control S-type */
+};
+
+/* per file statistic */
+struct mon_bin_stats {
+ u32 queued;
+ u32 dropped;
+};
+
+struct mon_bin_get {
+ struct mon_bin_hdr __user *hdr; /* Only 48 bytes, not 64. */
+ void __user *data;
+ size_t alloc; /* Length of data (can be zero) */
+};
+
+struct mon_bin_mfetch {
+ u32 __user *offvec; /* Vector of events fetched */
+ u32 nfetch; /* Number of events to fetch (out: fetched) */
+ u32 nflush; /* Number of events to flush */
+};
+
+#ifdef CONFIG_COMPAT
+struct mon_bin_get32 {
+ u32 hdr32;
+ u32 data32;
+ u32 alloc32;
+};
+
+struct mon_bin_mfetch32 {
+ u32 offvec32;
+ u32 nfetch32;
+ u32 nflush32;
+};
+#endif
+
+/* Having these two values same prevents wrapping of the mon_bin_hdr */
+#define PKT_ALIGN 64
+#define PKT_SIZE 64
+
+/* max number of USB bus supported */
+#define MON_BIN_MAX_MINOR 128
+
+/*
+ * The buffer: map of used pages.
+ */
+struct mon_pgmap {
+ struct page *pg;
+ unsigned char *ptr; /* XXX just use page_to_virt everywhere? */
+};
+
+/*
+ * This gets associated with an open file struct.
+ */
+struct mon_reader_bin {
+ /* The buffer: one per open. */
+ spinlock_t b_lock; /* Protect b_cnt, b_in */
+ unsigned int b_size; /* Current size of the buffer - bytes */
+ unsigned int b_cnt; /* Bytes used */
+ unsigned int b_in, b_out; /* Offsets into buffer - bytes */
+ unsigned int b_read; /* Amount of read data in curr. pkt. */
+ struct mon_pgmap *b_vec; /* The map array */
+ wait_queue_head_t b_wait; /* Wait for data here */
+
+ struct mutex fetch_lock; /* Protect b_read, b_out */
+ int mmap_active;
+
+ /* A list of these is needed for "bus 0". Some time later. */
+ struct mon_reader r;
+
+ /* Stats */
+ unsigned int cnt_lost;
+};
+
+static inline struct mon_bin_hdr *MON_OFF2HDR(const struct mon_reader_bin *rp,
+ unsigned int offset)
+{
+ return (struct mon_bin_hdr *)
+ (rp->b_vec[offset / CHUNK_SIZE].ptr + offset % CHUNK_SIZE);
+}
+
+#define MON_RING_EMPTY(rp) ((rp)->b_cnt == 0)
+
+static dev_t mon_bin_dev0;
+static struct cdev mon_bin_cdev;
+
+static void mon_buff_area_fill(const struct mon_reader_bin *rp,
+ unsigned int offset, unsigned int size);
+static int mon_bin_wait_event(struct file *file, struct mon_reader_bin *rp);
+static int mon_alloc_buff(struct mon_pgmap *map, int npages);
+static void mon_free_buff(struct mon_pgmap *map, int npages);
+
+/*
+ * This is a "chunked memcpy". It does not manipulate any counters.
+ * But it returns the new offset for repeated application.
+ */
+unsigned int mon_copy_to_buff(const struct mon_reader_bin *this,
+ unsigned int off, const unsigned char *from, unsigned int length)
+{
+ unsigned int step_len;
+ unsigned char *buf;
+ unsigned int in_page;
+
+ while (length) {
+ /*
+ * Determine step_len.
+ */
+ step_len = length;
+ in_page = CHUNK_SIZE - (off & (CHUNK_SIZE-1));
+ if (in_page < step_len)
+ step_len = in_page;
+
+ /*
+ * Copy data and advance pointers.
+ */
+ buf = this->b_vec[off / CHUNK_SIZE].ptr + off % CHUNK_SIZE;
+ memcpy(buf, from, step_len);
+ if ((off += step_len) >= this->b_size) off = 0;
+ from += step_len;
+ length -= step_len;
+ }
+ return off;
+}
+
+/*
+ * This is a little worse than the above because it's "chunked copy_to_user".
+ * The return value is an error code, not an offset.
+ */
+static int copy_from_buf(const struct mon_reader_bin *this, unsigned int off,
+ char __user *to, int length)
+{
+ unsigned int step_len;
+ unsigned char *buf;
+ unsigned int in_page;
+
+ while (length) {
+ /*
+ * Determine step_len.
+ */
+ step_len = length;
+ in_page = CHUNK_SIZE - (off & (CHUNK_SIZE-1));
+ if (in_page < step_len)
+ step_len = in_page;
+
+ /*
+ * Copy data and advance pointers.
+ */
+ buf = this->b_vec[off / CHUNK_SIZE].ptr + off % CHUNK_SIZE;
+ if (copy_to_user(to, buf, step_len))
+ return -EINVAL;
+ if ((off += step_len) >= this->b_size) off = 0;
+ to += step_len;
+ length -= step_len;
+ }
+ return 0;
+}
+
+/*
+ * Allocate an (aligned) area in the buffer.
+ * This is called under b_lock.
+ * Returns ~0 on failure.
+ */
+static unsigned int mon_buff_area_alloc(struct mon_reader_bin *rp,
+ unsigned int size)
+{
+ unsigned int offset;
+
+ size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+ if (rp->b_cnt + size > rp->b_size)
+ return ~0;
+ offset = rp->b_in;
+ rp->b_cnt += size;
+ if ((rp->b_in += size) >= rp->b_size)
+ rp->b_in -= rp->b_size;
+ return offset;
+}
+
+/*
+ * This is the same thing as mon_buff_area_alloc, only it does not allow
+ * buffers to wrap. This is needed by applications which pass references
+ * into mmap-ed buffers up their stacks (libpcap can do that).
+ *
+ * Currently, we always have the header stuck with the data, although
+ * it is not strictly speaking necessary.
+ *
+ * When a buffer would wrap, we place a filler packet to mark the space.
+ */
+static unsigned int mon_buff_area_alloc_contiguous(struct mon_reader_bin *rp,
+ unsigned int size)
+{
+ unsigned int offset;
+ unsigned int fill_size;
+
+ size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+ if (rp->b_cnt + size > rp->b_size)
+ return ~0;
+ if (rp->b_in + size > rp->b_size) {
+ /*
+ * This would wrap. Find if we still have space after
+ * skipping to the end of the buffer. If we do, place
+ * a filler packet and allocate a new packet.
+ */
+ fill_size = rp->b_size - rp->b_in;
+ if (rp->b_cnt + size + fill_size > rp->b_size)
+ return ~0;
+ mon_buff_area_fill(rp, rp->b_in, fill_size);
+
+ offset = 0;
+ rp->b_in = size;
+ rp->b_cnt += size + fill_size;
+ } else if (rp->b_in + size == rp->b_size) {
+ offset = rp->b_in;
+ rp->b_in = 0;
+ rp->b_cnt += size;
+ } else {
+ offset = rp->b_in;
+ rp->b_in += size;
+ rp->b_cnt += size;
+ }
+ return offset;
+}
+
+/*
+ * Return a few (kilo-)bytes to the head of the buffer.
+ * This is used if a DMA fetch fails.
+ */
+static void mon_buff_area_shrink(struct mon_reader_bin *rp, unsigned int size)
+{
+
+ size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+ rp->b_cnt -= size;
+ if (rp->b_in < size)
+ rp->b_in += rp->b_size;
+ rp->b_in -= size;
+}
+
+/*
+ * This has to be called under both b_lock and fetch_lock, because
+ * it accesses both b_cnt and b_out.
+ */
+static void mon_buff_area_free(struct mon_reader_bin *rp, unsigned int size)
+{
+
+ size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+ rp->b_cnt -= size;
+ if ((rp->b_out += size) >= rp->b_size)
+ rp->b_out -= rp->b_size;
+}
+
+static void mon_buff_area_fill(const struct mon_reader_bin *rp,
+ unsigned int offset, unsigned int size)
+{
+ struct mon_bin_hdr *ep;
+
+ ep = MON_OFF2HDR(rp, offset);
+ memset(ep, 0, PKT_SIZE);
+ ep->type = '@';
+ ep->len_cap = size - PKT_SIZE;
+}
+
+static inline char mon_bin_get_setup(unsigned char *setupb,
+ const struct urb *urb, char ev_type)
+{
+
+ if (!usb_pipecontrol(urb->pipe) || ev_type != 'S')
+ return '-';
+
+ if (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)
+ return mon_dmapeek(setupb, urb->setup_dma, SETUP_LEN);
+ if (urb->setup_packet == NULL)
+ return 'Z';
+
+ memcpy(setupb, urb->setup_packet, SETUP_LEN);
+ return 0;
+}
+
+static char mon_bin_get_data(const struct mon_reader_bin *rp,
+ unsigned int offset, struct urb *urb, unsigned int length)
+{
+
+ if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) {
+ mon_dmapeek_vec(rp, offset, urb->transfer_dma, length);
+ return 0;
+ }
+
+ if (urb->transfer_buffer == NULL)
+ return 'Z';
+
+ mon_copy_to_buff(rp, offset, urb->transfer_buffer, length);
+ return 0;
+}
+
+static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
+ char ev_type)
+{
+ unsigned long flags;
+ struct timeval ts;
+ unsigned int urb_length;
+ unsigned int offset;
+ unsigned int length;
+ struct mon_bin_hdr *ep;
+ char data_tag = 0;
+
+ do_gettimeofday(&ts);
+
+ spin_lock_irqsave(&rp->b_lock, flags);
+
+ /*
+ * Find the maximum allowable length, then allocate space.
+ */
+ urb_length = (ev_type == 'S') ?
+ urb->transfer_buffer_length : urb->actual_length;
+ length = urb_length;
+
+ if (length >= rp->b_size/5)
+ length = rp->b_size/5;
+
+ if (usb_pipein(urb->pipe)) {
+ if (ev_type == 'S') {
+ length = 0;
+ data_tag = '<';
+ }
+ } else {
+ if (ev_type == 'C') {
+ length = 0;
+ data_tag = '>';
+ }
+ }
+
+ if (rp->mmap_active)
+ offset = mon_buff_area_alloc_contiguous(rp, length + PKT_SIZE);
+ else
+ offset = mon_buff_area_alloc(rp, length + PKT_SIZE);
+ if (offset == ~0) {
+ rp->cnt_lost++;
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+ return;
+ }
+
+ ep = MON_OFF2HDR(rp, offset);
+ if ((offset += PKT_SIZE) >= rp->b_size) offset = 0;
+
+ /*
+ * Fill the allocated area.
+ */
+ memset(ep, 0, PKT_SIZE);
+ ep->type = ev_type;
+ ep->xfer_type = usb_pipetype(urb->pipe);
+ /* We use the fact that usb_pipein() returns 0x80 */
+ ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe);
+ ep->devnum = usb_pipedevice(urb->pipe);
+ ep->busnum = rp->r.m_bus->u_bus->busnum;
+ ep->id = (unsigned long) urb;
+ ep->ts_sec = ts.tv_sec;
+ ep->ts_usec = ts.tv_usec;
+ ep->status = urb->status;
+ ep->len_urb = urb_length;
+ ep->len_cap = length;
+
+ ep->flag_setup = mon_bin_get_setup(ep->setup, urb, ev_type);
+ if (length != 0) {
+ ep->flag_data = mon_bin_get_data(rp, offset, urb, length);
+ if (ep->flag_data != 0) { /* Yes, it's 0x00, not '0' */
+ ep->len_cap = 0;
+ mon_buff_area_shrink(rp, length);
+ }
+ } else {
+ ep->flag_data = data_tag;
+ }
+
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+
+ wake_up(&rp->b_wait);
+}
+
+static void mon_bin_submit(void *data, struct urb *urb)
+{
+ struct mon_reader_bin *rp = data;
+ mon_bin_event(rp, urb, 'S');
+}
+
+static void mon_bin_complete(void *data, struct urb *urb)
+{
+ struct mon_reader_bin *rp = data;
+ mon_bin_event(rp, urb, 'C');
+}
+
+static void mon_bin_error(void *data, struct urb *urb, int error)
+{
+ struct mon_reader_bin *rp = data;
+ unsigned long flags;
+ unsigned int offset;
+ struct mon_bin_hdr *ep;
+
+ spin_lock_irqsave(&rp->b_lock, flags);
+
+ offset = mon_buff_area_alloc(rp, PKT_SIZE);
+ if (offset == ~0) {
+ /* Not incrementing cnt_lost. Just because. */
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+ return;
+ }
+
+ ep = MON_OFF2HDR(rp, offset);
+
+ memset(ep, 0, PKT_SIZE);
+ ep->type = 'E';
+ ep->xfer_type = usb_pipetype(urb->pipe);
+ /* We use the fact that usb_pipein() returns 0x80 */
+ ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe);
+ ep->devnum = usb_pipedevice(urb->pipe);
+ ep->busnum = rp->r.m_bus->u_bus->busnum;
+ ep->id = (unsigned long) urb;
+ ep->status = error;
+
+ ep->flag_setup = '-';
+ ep->flag_data = 'E';
+
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+
+ wake_up(&rp->b_wait);
+}
+
+static int mon_bin_open(struct inode *inode, struct file *file)
+{
+ struct mon_bus *mbus;
+ struct usb_bus *ubus;
+ struct mon_reader_bin *rp;
+ size_t size;
+ int rc;
+
+ mutex_lock(&mon_lock);
+ if ((mbus = mon_bus_lookup(iminor(inode))) == NULL) {
+ mutex_unlock(&mon_lock);
+ return -ENODEV;
+ }
+ if ((ubus = mbus->u_bus) == NULL) {
+ printk(KERN_ERR TAG ": consistency error on open\n");
+ mutex_unlock(&mon_lock);
+ return -ENODEV;
+ }
+
+ rp = kzalloc(sizeof(struct mon_reader_bin), GFP_KERNEL);
+ if (rp == NULL) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ spin_lock_init(&rp->b_lock);
+ init_waitqueue_head(&rp->b_wait);
+ mutex_init(&rp->fetch_lock);
+
+ rp->b_size = BUFF_DFL;
+
+ size = sizeof(struct mon_pgmap) * (rp->b_size/CHUNK_SIZE);
+ if ((rp->b_vec = kzalloc(size, GFP_KERNEL)) == NULL) {
+ rc = -ENOMEM;
+ goto err_allocvec;
+ }
+
+ if ((rc = mon_alloc_buff(rp->b_vec, rp->b_size/CHUNK_SIZE)) < 0)
+ goto err_allocbuff;
+
+ rp->r.m_bus = mbus;
+ rp->r.r_data = rp;
+ rp->r.rnf_submit = mon_bin_submit;
+ rp->r.rnf_error = mon_bin_error;
+ rp->r.rnf_complete = mon_bin_complete;
+
+ mon_reader_add(mbus, &rp->r);
+
+ file->private_data = rp;
+ mutex_unlock(&mon_lock);
+ return 0;
+
+err_allocbuff:
+ kfree(rp->b_vec);
+err_allocvec:
+ kfree(rp);
+err_alloc:
+ mutex_unlock(&mon_lock);
+ return rc;
+}
+
+/*
+ * Extract an event from buffer and copy it to user space.
+ * Wait if there is no event ready.
+ * Returns zero or error.
+ */
+static int mon_bin_get_event(struct file *file, struct mon_reader_bin *rp,
+ struct mon_bin_hdr __user *hdr, void __user *data, unsigned int nbytes)
+{
+ unsigned long flags;
+ struct mon_bin_hdr *ep;
+ size_t step_len;
+ unsigned int offset;
+ int rc;
+
+ mutex_lock(&rp->fetch_lock);
+
+ if ((rc = mon_bin_wait_event(file, rp)) < 0) {
+ mutex_unlock(&rp->fetch_lock);
+ return rc;
+ }
+
+ ep = MON_OFF2HDR(rp, rp->b_out);
+
+ if (copy_to_user(hdr, ep, sizeof(struct mon_bin_hdr))) {
+ mutex_unlock(&rp->fetch_lock);
+ return -EFAULT;
+ }
+
+ step_len = min(ep->len_cap, nbytes);
+ if ((offset = rp->b_out + PKT_SIZE) >= rp->b_size) offset = 0;
+
+ if (copy_from_buf(rp, offset, data, step_len)) {
+ mutex_unlock(&rp->fetch_lock);
+ return -EFAULT;
+ }
+
+ spin_lock_irqsave(&rp->b_lock, flags);
+ mon_buff_area_free(rp, PKT_SIZE + ep->len_cap);
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+ rp->b_read = 0;
+
+ mutex_unlock(&rp->fetch_lock);
+ return 0;
+}
+
+static int mon_bin_release(struct inode *inode, struct file *file)
+{
+ struct mon_reader_bin *rp = file->private_data;
+ struct mon_bus* mbus = rp->r.m_bus;
+
+ mutex_lock(&mon_lock);
+
+ if (mbus->nreaders <= 0) {
+ printk(KERN_ERR TAG ": consistency error on close\n");
+ mutex_unlock(&mon_lock);
+ return 0;
+ }
+ mon_reader_del(mbus, &rp->r);
+
+ mon_free_buff(rp->b_vec, rp->b_size/CHUNK_SIZE);
+ kfree(rp->b_vec);
+ kfree(rp);
+
+ mutex_unlock(&mon_lock);
+ return 0;
+}
+
+static ssize_t mon_bin_read(struct file *file, char __user *buf,
+ size_t nbytes, loff_t *ppos)
+{
+ struct mon_reader_bin *rp = file->private_data;
+ unsigned long flags;
+ struct mon_bin_hdr *ep;
+ unsigned int offset;
+ size_t step_len;
+ char *ptr;
+ ssize_t done = 0;
+ int rc;
+
+ mutex_lock(&rp->fetch_lock);
+
+ if ((rc = mon_bin_wait_event(file, rp)) < 0) {
+ mutex_unlock(&rp->fetch_lock);
+ return rc;
+ }
+
+ ep = MON_OFF2HDR(rp, rp->b_out);
+
+ if (rp->b_read < sizeof(struct mon_bin_hdr)) {
+ step_len = min(nbytes, sizeof(struct mon_bin_hdr) - rp->b_read);
+ ptr = ((char *)ep) + rp->b_read;
+ if (step_len && copy_to_user(buf, ptr, step_len)) {
+ mutex_unlock(&rp->fetch_lock);
+ return -EFAULT;
+ }
+ nbytes -= step_len;
+ buf += step_len;
+ rp->b_read += step_len;
+ done += step_len;
+ }
+
+ if (rp->b_read >= sizeof(struct mon_bin_hdr)) {
+ step_len = min(nbytes, (size_t)ep->len_cap);
+ offset = rp->b_out + PKT_SIZE;
+ offset += rp->b_read - sizeof(struct mon_bin_hdr);
+ if (offset >= rp->b_size)
+ offset -= rp->b_size;
+ if (copy_from_buf(rp, offset, buf, step_len)) {
+ mutex_unlock(&rp->fetch_lock);
+ return -EFAULT;
+ }
+ nbytes -= step_len;
+ buf += step_len;
+ rp->b_read += step_len;
+ done += step_len;
+ }
+
+ /*
+ * Check if whole packet was read, and if so, jump to the next one.
+ */
+ if (rp->b_read >= sizeof(struct mon_bin_hdr) + ep->len_cap) {
+ spin_lock_irqsave(&rp->b_lock, flags);
+ mon_buff_area_free(rp, PKT_SIZE + ep->len_cap);
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+ rp->b_read = 0;
+ }
+
+ mutex_unlock(&rp->fetch_lock);
+ return done;
+}
+
+/*
+ * Remove at most nevents from chunked buffer.
+ * Returns the number of removed events.
+ */
+static int mon_bin_flush(struct mon_reader_bin *rp, unsigned nevents)
+{
+ unsigned long flags;
+ struct mon_bin_hdr *ep;
+ int i;
+
+ mutex_lock(&rp->fetch_lock);
+ spin_lock_irqsave(&rp->b_lock, flags);
+ for (i = 0; i < nevents; ++i) {
+ if (MON_RING_EMPTY(rp))
+ break;
+
+ ep = MON_OFF2HDR(rp, rp->b_out);
+ mon_buff_area_free(rp, PKT_SIZE + ep->len_cap);
+ }
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+ rp->b_read = 0;
+ mutex_unlock(&rp->fetch_lock);
+ return i;
+}
+
+/*
+ * Fetch at most max event offsets into the buffer and put them into vec.
+ * The events are usually freed later with mon_bin_flush.
+ * Return the effective number of events fetched.
+ */
+static int mon_bin_fetch(struct file *file, struct mon_reader_bin *rp,
+ u32 __user *vec, unsigned int max)
+{
+ unsigned int cur_out;
+ unsigned int bytes, avail;
+ unsigned int size;
+ unsigned int nevents;
+ struct mon_bin_hdr *ep;
+ unsigned long flags;
+ int rc;
+
+ mutex_lock(&rp->fetch_lock);
+
+ if ((rc = mon_bin_wait_event(file, rp)) < 0) {
+ mutex_unlock(&rp->fetch_lock);
+ return rc;
+ }
+
+ spin_lock_irqsave(&rp->b_lock, flags);
+ avail = rp->b_cnt;
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+
+ cur_out = rp->b_out;
+ nevents = 0;
+ bytes = 0;
+ while (bytes < avail) {
+ if (nevents >= max)
+ break;
+
+ ep = MON_OFF2HDR(rp, cur_out);
+ if (put_user(cur_out, &vec[nevents])) {
+ mutex_unlock(&rp->fetch_lock);
+ return -EFAULT;
+ }
+
+ nevents++;
+ size = ep->len_cap + PKT_SIZE;
+ size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+ if ((cur_out += size) >= rp->b_size)
+ cur_out -= rp->b_size;
+ bytes += size;
+ }
+
+ mutex_unlock(&rp->fetch_lock);
+ return nevents;
+}
+
+/*
+ * Count events. This is almost the same as the above mon_bin_fetch,
+ * only we do not store offsets into user vector, and we have no limit.
+ */
+static int mon_bin_queued(struct mon_reader_bin *rp)
+{
+ unsigned int cur_out;
+ unsigned int bytes, avail;
+ unsigned int size;
+ unsigned int nevents;
+ struct mon_bin_hdr *ep;
+ unsigned long flags;
+
+ mutex_lock(&rp->fetch_lock);
+
+ spin_lock_irqsave(&rp->b_lock, flags);
+ avail = rp->b_cnt;
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+
+ cur_out = rp->b_out;
+ nevents = 0;
+ bytes = 0;
+ while (bytes < avail) {
+ ep = MON_OFF2HDR(rp, cur_out);
+
+ nevents++;
+ size = ep->len_cap + PKT_SIZE;
+ size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+ if ((cur_out += size) >= rp->b_size)
+ cur_out -= rp->b_size;
+ bytes += size;
+ }
+
+ mutex_unlock(&rp->fetch_lock);
+ return nevents;
+}
+
+/*
+ */
+static int mon_bin_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct mon_reader_bin *rp = file->private_data;
+ // struct mon_bus* mbus = rp->r.m_bus;
+ int ret = 0;
+ struct mon_bin_hdr *ep;
+ unsigned long flags;
+
+ switch (cmd) {
+
+ case MON_IOCQ_URB_LEN:
+ /*
+ * N.B. This only returns the size of data, without the header.
+ */
+ spin_lock_irqsave(&rp->b_lock, flags);
+ if (!MON_RING_EMPTY(rp)) {
+ ep = MON_OFF2HDR(rp, rp->b_out);
+ ret = ep->len_cap;
+ }
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+ break;
+
+ case MON_IOCQ_RING_SIZE:
+ ret = rp->b_size;
+ break;
+
+ case MON_IOCT_RING_SIZE:
+ /*
+ * Changing the buffer size will flush it's contents; the new
+ * buffer is allocated before releasing the old one to be sure
+ * the device will stay functional also in case of memory
+ * pressure.
+ */
+ {
+ int size;
+ struct mon_pgmap *vec;
+
+ if (arg < BUFF_MIN || arg > BUFF_MAX)
+ return -EINVAL;
+
+ size = CHUNK_ALIGN(arg);
+ if ((vec = kzalloc(sizeof(struct mon_pgmap) * (size/CHUNK_SIZE),
+ GFP_KERNEL)) == NULL) {
+ ret = -ENOMEM;
+ break;
+ }
+
+ ret = mon_alloc_buff(vec, size/CHUNK_SIZE);
+ if (ret < 0) {
+ kfree(vec);
+ break;
+ }
+
+ mutex_lock(&rp->fetch_lock);
+ spin_lock_irqsave(&rp->b_lock, flags);
+ mon_free_buff(rp->b_vec, size/CHUNK_SIZE);
+ kfree(rp->b_vec);
+ rp->b_vec = vec;
+ rp->b_size = size;
+ rp->b_read = rp->b_in = rp->b_out = rp->b_cnt = 0;
+ rp->cnt_lost = 0;
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+ mutex_unlock(&rp->fetch_lock);
+ }
+ break;
+
+ case MON_IOCH_MFLUSH:
+ ret = mon_bin_flush(rp, arg);
+ break;
+
+ case MON_IOCX_GET:
+ {
+ struct mon_bin_get getb;
+
+ if (copy_from_user(&getb, (void __user *)arg,
+ sizeof(struct mon_bin_get)))
+ return -EFAULT;
+
+ if (getb.alloc > 0x10000000) /* Want to cast to u32 */
+ return -EINVAL;
+ ret = mon_bin_get_event(file, rp,
+ getb.hdr, getb.data, (unsigned int)getb.alloc);
+ }
+ break;
+
+#ifdef CONFIG_COMPAT
+ case MON_IOCX_GET32: {
+ struct mon_bin_get32 getb;
+
+ if (copy_from_user(&getb, (void __user *)arg,
+ sizeof(struct mon_bin_get32)))
+ return -EFAULT;
+
+ ret = mon_bin_get_event(file, rp,
+ compat_ptr(getb.hdr32), compat_ptr(getb.data32),
+ getb.alloc32);
+ }
+ break;
+#endif
+
+ case MON_IOCX_MFETCH:
+ {
+ struct mon_bin_mfetch mfetch;
+ struct mon_bin_mfetch __user *uptr;
+
+ uptr = (struct mon_bin_mfetch __user *)arg;
+
+ if (copy_from_user(&mfetch, uptr, sizeof(mfetch)))
+ return -EFAULT;
+
+ if (mfetch.nflush) {
+ ret = mon_bin_flush(rp, mfetch.nflush);
+ if (ret < 0)
+ return ret;
+ if (put_user(ret, &uptr->nflush))
+ return -EFAULT;
+ }
+ ret = mon_bin_fetch(file, rp, mfetch.offvec, mfetch.nfetch);
+ if (ret < 0)
+ return ret;
+ if (put_user(ret, &uptr->nfetch))
+ return -EFAULT;
+ ret = 0;
+ }
+ break;
+
+#ifdef CONFIG_COMPAT
+ case MON_IOCX_MFETCH32:
+ {
+ struct mon_bin_mfetch32 mfetch;
+ struct mon_bin_mfetch32 __user *uptr;
+
+ uptr = (struct mon_bin_mfetch32 __user *) compat_ptr(arg);
+
+ if (copy_from_user(&mfetch, uptr, sizeof(mfetch)))
+ return -EFAULT;
+
+ if (mfetch.nflush32) {
+ ret = mon_bin_flush(rp, mfetch.nflush32);
+ if (ret < 0)
+ return ret;
+ if (put_user(ret, &uptr->nflush32))
+ return -EFAULT;
+ }
+ ret = mon_bin_fetch(file, rp, compat_ptr(mfetch.offvec32),
+ mfetch.nfetch32);
+ if (ret < 0)
+ return ret;
+ if (put_user(ret, &uptr->nfetch32))
+ return -EFAULT;
+ ret = 0;
+ }
+ break;
+#endif
+
+ case MON_IOCG_STATS: {
+ struct mon_bin_stats __user *sp;
+ unsigned int nevents;
+ unsigned int ndropped;
+
+ spin_lock_irqsave(&rp->b_lock, flags);
+ ndropped = rp->cnt_lost;
+ rp->cnt_lost = 0;
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+ nevents = mon_bin_queued(rp);
+
+ sp = (struct mon_bin_stats __user *)arg;
+ if (put_user(rp->cnt_lost, &sp->dropped))
+ return -EFAULT;
+ if (put_user(nevents, &sp->queued))
+ return -EFAULT;
+
+ }
+ break;
+
+ default:
+ return -ENOTTY;
+ }
+
+ return ret;
+}
+
+static unsigned int
+mon_bin_poll(struct file *file, struct poll_table_struct *wait)
+{
+ struct mon_reader_bin *rp = file->private_data;
+ unsigned int mask = 0;
+ unsigned long flags;
+
+ if (file->f_mode & FMODE_READ)
+ poll_wait(file, &rp->b_wait, wait);
+
+ spin_lock_irqsave(&rp->b_lock, flags);
+ if (!MON_RING_EMPTY(rp))
+ mask |= POLLIN | POLLRDNORM; /* readable */
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+ return mask;
+}
+
+/*
+ * open and close: just keep track of how many times the device is
+ * mapped, to use the proper memory allocation function.
+ */
+static void mon_bin_vma_open(struct vm_area_struct *vma)
+{
+ struct mon_reader_bin *rp = vma->vm_private_data;
+ rp->mmap_active++;
+}
+
+static void mon_bin_vma_close(struct vm_area_struct *vma)
+{
+ struct mon_reader_bin *rp = vma->vm_private_data;
+ rp->mmap_active--;
+}
+
+/*
+ * Map ring pages to user space.
+ */
+struct page *mon_bin_vma_nopage(struct vm_area_struct *vma,
+ unsigned long address, int *type)
+{
+ struct mon_reader_bin *rp = vma->vm_private_data;
+ unsigned long offset, chunk_idx;
+ struct page *pageptr;
+
+ offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
+ if (offset >= rp->b_size)
+ return NOPAGE_SIGBUS;
+ chunk_idx = offset / CHUNK_SIZE;
+ pageptr = rp->b_vec[chunk_idx].pg;
+ get_page(pageptr);
+ if (type)
+ *type = VM_FAULT_MINOR;
+ return pageptr;
+}
+
+struct vm_operations_struct mon_bin_vm_ops = {
+ .open = mon_bin_vma_open,
+ .close = mon_bin_vma_close,
+ .nopage = mon_bin_vma_nopage,
+};
+
+int mon_bin_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ /* don't do anything here: "nopage" will set up page table entries */
+ vma->vm_ops = &mon_bin_vm_ops;
+ vma->vm_flags |= VM_RESERVED;
+ vma->vm_private_data = filp->private_data;
+ mon_bin_vma_open(vma);
+ return 0;
+}
+
+struct file_operations mon_fops_binary = {
+ .owner = THIS_MODULE,
+ .open = mon_bin_open,
+ .llseek = no_llseek,
+ .read = mon_bin_read,
+ /* .write = mon_text_write, */
+ .poll = mon_bin_poll,
+ .ioctl = mon_bin_ioctl,
+ .release = mon_bin_release,
+};
+
+static int mon_bin_wait_event(struct file *file, struct mon_reader_bin *rp)
+{
+ DECLARE_WAITQUEUE(waita, current);
+ unsigned long flags;
+
+ add_wait_queue(&rp->b_wait, &waita);
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ spin_lock_irqsave(&rp->b_lock, flags);
+ while (MON_RING_EMPTY(rp)) {
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+
+ if (file->f_flags & O_NONBLOCK) {
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&rp->b_wait, &waita);
+ return -EWOULDBLOCK; /* Same as EAGAIN in Linux */
+ }
+ schedule();
+ if (signal_pending(current)) {
+ remove_wait_queue(&rp->b_wait, &waita);
+ return -EINTR;
+ }
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ spin_lock_irqsave(&rp->b_lock, flags);
+ }
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&rp->b_wait, &waita);
+ return 0;
+}
+
+static int mon_alloc_buff(struct mon_pgmap *map, int npages)
+{
+ int n;
+ unsigned long vaddr;
+
+ for (n = 0; n < npages; n++) {
+ vaddr = get_zeroed_page(GFP_KERNEL);
+ if (vaddr == 0) {
+ while (n-- != 0)
+ free_page((unsigned long) map[n].ptr);
+ return -ENOMEM;
+ }
+ map[n].ptr = (unsigned char *) vaddr;
+ map[n].pg = virt_to_page(vaddr);
+ }
+ return 0;
+}
+
+static void mon_free_buff(struct mon_pgmap *map, int npages)
+{
+ int n;
+
+ for (n = 0; n < npages; n++)
+ free_page((unsigned long) map[n].ptr);
+}
+
+int __init mon_bin_init(void)
+{
+ int rc;
+
+ rc = alloc_chrdev_region(&mon_bin_dev0, 0, MON_BIN_MAX_MINOR, "usbmon");
+ if (rc < 0)
+ goto err_dev;
+
+ cdev_init(&mon_bin_cdev, &mon_fops_binary);
+ mon_bin_cdev.owner = THIS_MODULE;
+
+ rc = cdev_add(&mon_bin_cdev, mon_bin_dev0, MON_BIN_MAX_MINOR);
+ if (rc < 0)
+ goto err_add;
+
+ return 0;
+
+err_add:
+ unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR);
+err_dev:
+ return rc;
+}
+
+void __exit mon_bin_exit(void)
+{
+ cdev_del(&mon_bin_cdev);
+ unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR);
+}
diff --git a/drivers/usb/mon/mon_dma.c b/drivers/usb/mon/mon_dma.c
index ddcfc01e77a..140cc80bd2b 100644
--- a/drivers/usb/mon/mon_dma.c
+++ b/drivers/usb/mon/mon_dma.c
@@ -48,6 +48,36 @@ char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len)
local_irq_restore(flags);
return 0;
}
+
+void mon_dmapeek_vec(const struct mon_reader_bin *rp,
+ unsigned int offset, dma_addr_t dma_addr, unsigned int length)
+{
+ unsigned long flags;
+ unsigned int step_len;
+ struct page *pg;
+ unsigned char *map;
+ unsigned long page_off, page_len;
+
+ local_irq_save(flags);
+ while (length) {
+ /* compute number of bytes we are going to copy in this page */
+ step_len = length;
+ page_off = dma_addr & (PAGE_SIZE-1);
+ page_len = PAGE_SIZE - page_off;
+ if (page_len < step_len)
+ step_len = page_len;
+
+ /* copy data and advance pointers */
+ pg = phys_to_page(dma_addr);
+ map = kmap_atomic(pg, KM_IRQ0);
+ offset = mon_copy_to_buff(rp, offset, map + page_off, step_len);
+ kunmap_atomic(map, KM_IRQ0);
+ dma_addr += step_len;
+ length -= step_len;
+ }
+ local_irq_restore(flags);
+}
+
#endif /* __i386__ */
#ifndef MON_HAS_UNMAP
@@ -55,4 +85,11 @@ char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len)
{
return 'D';
}
-#endif
+
+void mon_dmapeek_vec(const struct mon_reader_bin *rp,
+ unsigned int offset, dma_addr_t dma_addr, unsigned int length)
+{
+ ;
+}
+
+#endif /* MON_HAS_UNMAP */
diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c
index 394bbf2f68d..c9739e7b35e 100644
--- a/drivers/usb/mon/mon_main.c
+++ b/drivers/usb/mon/mon_main.c
@@ -9,7 +9,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/usb.h>
-#include <linux/debugfs.h>
#include <linux/smp_lock.h>
#include <linux/notifier.h>
#include <linux/mutex.h>
@@ -22,11 +21,10 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb);
static void mon_stop(struct mon_bus *mbus);
static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus);
static void mon_bus_drop(struct kref *r);
-static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus);
+static void mon_bus_init(struct usb_bus *ubus);
DEFINE_MUTEX(mon_lock);
-static struct dentry *mon_dir; /* /dbg/usbmon */
static LIST_HEAD(mon_buses); /* All buses we know: struct mon_bus */
/*
@@ -200,7 +198,7 @@ static void mon_stop(struct mon_bus *mbus)
*/
static void mon_bus_add(struct usb_bus *ubus)
{
- mon_bus_init(mon_dir, ubus);
+ mon_bus_init(ubus);
}
/*
@@ -212,8 +210,8 @@ static void mon_bus_remove(struct usb_bus *ubus)
mutex_lock(&mon_lock);
list_del(&mbus->bus_link);
- debugfs_remove(mbus->dent_t);
- debugfs_remove(mbus->dent_s);
+ if (mbus->text_inited)
+ mon_text_del(mbus);
mon_dissolve(mbus, ubus);
kref_put(&mbus->ref, mon_bus_drop);
@@ -281,13 +279,9 @@ static void mon_bus_drop(struct kref *r)
* - refcount USB bus struct
* - link
*/
-static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus)
+static void mon_bus_init(struct usb_bus *ubus)
{
- struct dentry *d;
struct mon_bus *mbus;
- enum { NAMESZ = 10 };
- char name[NAMESZ];
- int rc;
if ((mbus = kzalloc(sizeof(struct mon_bus), GFP_KERNEL)) == NULL)
goto err_alloc;
@@ -303,57 +297,54 @@ static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus)
ubus->mon_bus = mbus;
mbus->uses_dma = ubus->uses_dma;
- rc = snprintf(name, NAMESZ, "%dt", ubus->busnum);
- if (rc <= 0 || rc >= NAMESZ)
- goto err_print_t;
- d = debugfs_create_file(name, 0600, mondir, mbus, &mon_fops_text);
- if (d == NULL)
- goto err_create_t;
- mbus->dent_t = d;
-
- rc = snprintf(name, NAMESZ, "%ds", ubus->busnum);
- if (rc <= 0 || rc >= NAMESZ)
- goto err_print_s;
- d = debugfs_create_file(name, 0600, mondir, mbus, &mon_fops_stat);
- if (d == NULL)
- goto err_create_s;
- mbus->dent_s = d;
+ mbus->text_inited = mon_text_add(mbus, ubus);
+ // mon_bin_add(...)
mutex_lock(&mon_lock);
list_add_tail(&mbus->bus_link, &mon_buses);
mutex_unlock(&mon_lock);
return;
-err_create_s:
-err_print_s:
- debugfs_remove(mbus->dent_t);
-err_create_t:
-err_print_t:
- kfree(mbus);
err_alloc:
return;
}
+/*
+ * Search a USB bus by number. Notice that USB bus numbers start from one,
+ * which we may later use to identify "all" with zero.
+ *
+ * This function must be called with mon_lock held.
+ *
+ * This is obviously inefficient and may be revised in the future.
+ */
+struct mon_bus *mon_bus_lookup(unsigned int num)
+{
+ struct list_head *p;
+ struct mon_bus *mbus;
+
+ list_for_each (p, &mon_buses) {
+ mbus = list_entry(p, struct mon_bus, bus_link);
+ if (mbus->u_bus->busnum == num) {
+ return mbus;
+ }
+ }
+ return NULL;
+}
+
static int __init mon_init(void)
{
struct usb_bus *ubus;
- struct dentry *mondir;
+ int rc;
- mondir = debugfs_create_dir("usbmon", NULL);
- if (IS_ERR(mondir)) {
- printk(KERN_NOTICE TAG ": debugfs is not available\n");
- return -ENODEV;
- }
- if (mondir == NULL) {
- printk(KERN_NOTICE TAG ": unable to create usbmon directory\n");
- return -ENODEV;
- }
- mon_dir = mondir;
+ if ((rc = mon_text_init()) != 0)
+ goto err_text;
+ if ((rc = mon_bin_init()) != 0)
+ goto err_bin;
if (usb_mon_register(&mon_ops_0) != 0) {
printk(KERN_NOTICE TAG ": unable to register with the core\n");
- debugfs_remove(mondir);
- return -ENODEV;
+ rc = -ENODEV;
+ goto err_reg;
}
// MOD_INC_USE_COUNT(which_module?);
@@ -361,10 +352,17 @@ static int __init mon_init(void)
mutex_lock(&usb_bus_list_lock);
list_for_each_entry (ubus, &usb_bus_list, bus_list) {
- mon_bus_init(mondir, ubus);
+ mon_bus_init(ubus);
}
mutex_unlock(&usb_bus_list_lock);
return 0;
+
+err_reg:
+ mon_bin_exit();
+err_bin:
+ mon_text_exit();
+err_text:
+ return rc;
}
static void __exit mon_exit(void)
@@ -381,8 +379,8 @@ static void __exit mon_exit(void)
mbus = list_entry(p, struct mon_bus, bus_link);
list_del(p);
- debugfs_remove(mbus->dent_t);
- debugfs_remove(mbus->dent_s);
+ if (mbus->text_inited)
+ mon_text_del(mbus);
/*
* This never happens, because the open/close paths in
@@ -401,7 +399,8 @@ static void __exit mon_exit(void)
}
mutex_unlock(&mon_lock);
- debugfs_remove(mon_dir);
+ mon_text_exit();
+ mon_bin_exit();
}
module_init(mon_init);
diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c
index 05cf2c9a8f8..d38a1279d9d 100644
--- a/drivers/usb/mon/mon_text.c
+++ b/drivers/usb/mon/mon_text.c
@@ -9,6 +9,7 @@
#include <linux/usb.h>
#include <linux/time.h>
#include <linux/mutex.h>
+#include <linux/debugfs.h>
#include <asm/uaccess.h>
#include "usb_mon.h"
@@ -63,6 +64,8 @@ struct mon_reader_text {
char slab_name[SLAB_NAME_SZ];
};
+static struct dentry *mon_dir; /* Usually /sys/kernel/debug/usbmon */
+
static void mon_text_ctor(void *, struct kmem_cache *, unsigned long);
/*
@@ -436,7 +439,7 @@ static int mon_text_release(struct inode *inode, struct file *file)
return 0;
}
-const struct file_operations mon_fops_text = {
+static const struct file_operations mon_fops_text = {
.owner = THIS_MODULE,
.open = mon_text_open,
.llseek = no_llseek,
@@ -447,6 +450,47 @@ const struct file_operations mon_fops_text = {
.release = mon_text_release,
};
+int mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus)
+{
+ struct dentry *d;
+ enum { NAMESZ = 10 };
+ char name[NAMESZ];
+ int rc;
+
+ rc = snprintf(name, NAMESZ, "%dt", ubus->busnum);
+ if (rc <= 0 || rc >= NAMESZ)
+ goto err_print_t;
+ d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_text);
+ if (d == NULL)
+ goto err_create_t;
+ mbus->dent_t = d;
+
+ /* XXX The stats do not belong to here (text API), but oh well... */
+ rc = snprintf(name, NAMESZ, "%ds", ubus->busnum);
+ if (rc <= 0 || rc >= NAMESZ)
+ goto err_print_s;
+ d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_stat);
+ if (d == NULL)
+ goto err_create_s;
+ mbus->dent_s = d;
+
+ return 1;
+
+err_create_s:
+err_print_s:
+ debugfs_remove(mbus->dent_t);
+ mbus->dent_t = NULL;
+err_create_t:
+err_print_t:
+ return 0;
+}
+
+void mon_text_del(struct mon_bus *mbus)
+{
+ debugfs_remove(mbus->dent_t);
+ debugfs_remove(mbus->dent_s);
+}
+
/*
* Slab interface: constructor.
*/
@@ -459,3 +503,24 @@ static void mon_text_ctor(void *mem, struct kmem_cache *slab, unsigned long sfla
memset(mem, 0xe5, sizeof(struct mon_event_text));
}
+int __init mon_text_init(void)
+{
+ struct dentry *mondir;
+
+ mondir = debugfs_create_dir("usbmon", NULL);
+ if (IS_ERR(mondir)) {
+ printk(KERN_NOTICE TAG ": debugfs is not available\n");
+ return -ENODEV;
+ }
+ if (mondir == NULL) {
+ printk(KERN_NOTICE TAG ": unable to create usbmon directory\n");
+ return -ENODEV;
+ }
+ mon_dir = mondir;
+ return 0;
+}
+
+void __exit mon_text_exit(void)
+{
+ debugfs_remove(mon_dir);
+}
diff --git a/drivers/usb/mon/usb_mon.h b/drivers/usb/mon/usb_mon.h
index ab9d02d5df7..4f949ce8a7f 100644
--- a/drivers/usb/mon/usb_mon.h
+++ b/drivers/usb/mon/usb_mon.h
@@ -17,9 +17,11 @@
struct mon_bus {
struct list_head bus_link;
spinlock_t lock;
+ struct usb_bus *u_bus;
+
+ int text_inited;
struct dentry *dent_s; /* Debugging file */
struct dentry *dent_t; /* Text interface file */
- struct usb_bus *u_bus;
int uses_dma;
/* Ref */
@@ -48,13 +50,35 @@ struct mon_reader {
void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r);
void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r);
+struct mon_bus *mon_bus_lookup(unsigned int num);
+
+int /*bool*/ mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus);
+void mon_text_del(struct mon_bus *mbus);
+// void mon_bin_add(struct mon_bus *);
+
+int __init mon_text_init(void);
+void __exit mon_text_exit(void);
+int __init mon_bin_init(void);
+void __exit mon_bin_exit(void);
+
/*
- */
+ * DMA interface.
+ *
+ * XXX The vectored side needs a serious re-thinking. Abstracting vectors,
+ * like in Paolo's original patch, produces a double pkmap. We need an idea.
+*/
extern char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len);
+struct mon_reader_bin;
+extern void mon_dmapeek_vec(const struct mon_reader_bin *rp,
+ unsigned int offset, dma_addr_t dma_addr, unsigned int len);
+extern unsigned int mon_copy_to_buff(const struct mon_reader_bin *rp,
+ unsigned int offset, const unsigned char *from, unsigned int len);
+
+/*
+ */
extern struct mutex mon_lock;
-extern const struct file_operations mon_fops_text;
extern const struct file_operations mon_fops_stat;
#endif /* __USB_MON_H */
diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig
index e081836014a..a2b94ef512b 100644
--- a/drivers/usb/net/Kconfig
+++ b/drivers/usb/net/Kconfig
@@ -222,13 +222,15 @@ config USB_NET_MCS7830
adapters marketed under the DeLOCK brand.
config USB_NET_RNDIS_HOST
- tristate "Host for RNDIS devices (EXPERIMENTAL)"
+ tristate "Host for RNDIS and ActiveSync devices (EXPERIMENTAL)"
depends on USB_USBNET && EXPERIMENTAL
select USB_NET_CDCETHER
help
This option enables hosting "Remote NDIS" USB networking links,
as encouraged by Microsoft (instead of CDC Ethernet!) for use in
- various devices that may only support this protocol.
+ various devices that may only support this protocol. A variant
+ of this protocol (with even less public documentation) seems to
+ be at the root of Microsoft's "ActiveSync" too.
Avoid using this protocol unless you have no better options.
The protocol specification is incomplete, and is controlled by
diff --git a/drivers/usb/net/asix.c b/drivers/usb/net/asix.c
index 896449f0cf8..4206df2d61b 100644
--- a/drivers/usb/net/asix.c
+++ b/drivers/usb/net/asix.c
@@ -1449,6 +1449,10 @@ static const struct usb_device_id products [] = {
// Linksys USB1000
USB_DEVICE (0x1737, 0x0039),
.driver_info = (unsigned long) &ax88178_info,
+}, {
+ // IO-DATA ETG-US2
+ USB_DEVICE (0x04bb, 0x0930),
+ .driver_info = (unsigned long) &ax88178_info,
},
{ }, // END
};
diff --git a/drivers/usb/net/cdc_ether.c b/drivers/usb/net/cdc_ether.c
index 44a91547146..e5cdafa258d 100644
--- a/drivers/usb/net/cdc_ether.c
+++ b/drivers/usb/net/cdc_ether.c
@@ -1,6 +1,7 @@
/*
* CDC Ethernet based networking peripherals
* Copyright (C) 2003-2005 by David Brownell
+ * Copyright (C) 2006 by Ole Andre Vadla Ravnas (ActiveSync)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -35,6 +36,29 @@
#include "usbnet.h"
+#if defined(CONFIG_USB_NET_RNDIS_HOST) || defined(CONFIG_USB_NET_RNDIS_HOST_MODULE)
+
+static int is_rndis(struct usb_interface_descriptor *desc)
+{
+ return desc->bInterfaceClass == USB_CLASS_COMM
+ && desc->bInterfaceSubClass == 2
+ && desc->bInterfaceProtocol == 0xff;
+}
+
+static int is_activesync(struct usb_interface_descriptor *desc)
+{
+ return desc->bInterfaceClass == USB_CLASS_MISC
+ && desc->bInterfaceSubClass == 1
+ && desc->bInterfaceProtocol == 1;
+}
+
+#else
+
+#define is_rndis(desc) 0
+#define is_activesync(desc) 0
+
+#endif
+
/*
* probes control interface, claims data interface, collects the bulk
* endpoints, activates data interface (if needed), maybe sets MTU.
@@ -71,7 +95,8 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
/* this assumes that if there's a non-RNDIS vendor variant
* of cdc-acm, it'll fail RNDIS requests cleanly.
*/
- rndis = (intf->cur_altsetting->desc.bInterfaceProtocol == 0xff);
+ rndis = is_rndis(&intf->cur_altsetting->desc)
+ || is_activesync(&intf->cur_altsetting->desc);
memset(info, 0, sizeof *info);
info->control = intf;
@@ -99,6 +124,23 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
goto bad_desc;
}
break;
+ case USB_CDC_ACM_TYPE:
+ /* paranoia: disambiguate a "real" vendor-specific
+ * modem interface from an RNDIS non-modem.
+ */
+ if (rndis) {
+ struct usb_cdc_acm_descriptor *d;
+
+ d = (void *) buf;
+ if (d->bmCapabilities) {
+ dev_dbg(&intf->dev,
+ "ACM capabilities %02x, "
+ "not really RNDIS?\n",
+ d->bmCapabilities);
+ goto bad_desc;
+ }
+ }
+ break;
case USB_CDC_UNION_TYPE:
if (info->u) {
dev_dbg(&intf->dev, "extra CDC union\n");
@@ -171,7 +213,21 @@ next_desc:
buf += buf [0];
}
- if (!info->header || !info->u || (!rndis && !info->ether)) {
+ /* Microsoft ActiveSync based RNDIS devices lack the CDC descriptors,
+ * so we'll hard-wire the interfaces and not check for descriptors.
+ */
+ if (is_activesync(&intf->cur_altsetting->desc) && !info->u) {
+ info->control = usb_ifnum_to_if(dev->udev, 0);
+ info->data = usb_ifnum_to_if(dev->udev, 1);
+ if (!info->control || !info->data) {
+ dev_dbg(&intf->dev,
+ "activesync: master #0/%p slave #1/%p\n",
+ info->control,
+ info->data);
+ goto bad_desc;
+ }
+
+ } else if (!info->header || !info->u || (!rndis && !info->ether)) {
dev_dbg(&intf->dev, "missing cdc %s%s%sdescriptor\n",
info->header ? "" : "header ",
info->u ? "" : "union ",
diff --git a/drivers/usb/net/gl620a.c b/drivers/usb/net/gl620a.c
index a6f0f4d934d..31e5fe363fd 100644
--- a/drivers/usb/net/gl620a.c
+++ b/drivers/usb/net/gl620a.c
@@ -70,12 +70,12 @@
(((GL_MAX_PACKET_LEN + 4) * GL_MAX_TRANSMIT_PACKETS) + 4)
struct gl_packet {
- u32 packet_length;
+ __le32 packet_length;
char packet_data [1];
};
struct gl_header {
- u32 packet_count;
+ __le32 packet_count;
struct gl_packet packets;
};
@@ -85,15 +85,14 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
struct gl_packet *packet;
struct sk_buff *gl_skb;
u32 size;
+ u32 count;
header = (struct gl_header *) skb->data;
// get the packet count of the received skb
- le32_to_cpus(&header->packet_count);
- if ((header->packet_count > GL_MAX_TRANSMIT_PACKETS)
- || (header->packet_count < 0)) {
- dbg("genelink: invalid received packet count %d",
- header->packet_count);
+ count = le32_to_cpu(header->packet_count);
+ if (count > GL_MAX_TRANSMIT_PACKETS) {
+ dbg("genelink: invalid received packet count %u", count);
return 0;
}
@@ -103,7 +102,7 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
// decrement the length for the packet count size 4 bytes
skb_pull(skb, 4);
- while (header->packet_count > 1) {
+ while (count > 1) {
// get the packet length
size = le32_to_cpu(packet->packet_length);
@@ -124,9 +123,8 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
}
// advance to the next packet
- packet = (struct gl_packet *)
- &packet->packet_data [size];
- header->packet_count--;
+ packet = (struct gl_packet *)&packet->packet_data[size];
+ count--;
// shift the data pointer to the next gl_packet
skb_pull(skb, size + 4);
@@ -149,8 +147,8 @@ genelink_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
int length = skb->len;
int headroom = skb_headroom(skb);
int tailroom = skb_tailroom(skb);
- u32 *packet_count;
- u32 *packet_len;
+ __le32 *packet_count;
+ __le32 *packet_len;
// FIXME: magic numbers, bleech
padlen = ((skb->len + (4 + 4*1)) % 64) ? 0 : 1;
@@ -172,7 +170,7 @@ genelink_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
}
// attach the packet count to the header
- packet_count = (u32 *) skb_push(skb, (4 + 4*1));
+ packet_count = (__le32 *) skb_push(skb, (4 + 4*1));
packet_len = packet_count + 1;
*packet_count = cpu_to_le32(1);
diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c
index fa78326d0bf..36a989160a6 100644
--- a/drivers/usb/net/kaweth.c
+++ b/drivers/usb/net/kaweth.c
@@ -179,6 +179,7 @@ static struct usb_driver kaweth_driver = {
.suspend = kaweth_suspend,
.resume = kaweth_resume,
.id_table = usb_klsi_table,
+ .supports_autosuspend = 1,
};
typedef __u8 eth_addr_t[6];
@@ -225,6 +226,7 @@ struct kaweth_device
struct delayed_work lowmem_work;
struct usb_device *dev;
+ struct usb_interface *intf;
struct net_device *net;
wait_queue_head_t term_wait;
@@ -662,9 +664,14 @@ static int kaweth_open(struct net_device *net)
dbg("Opening network device.");
+ res = usb_autopm_get_interface(kaweth->intf);
+ if (res) {
+ err("Interface cannot be resumed.");
+ return -EIO;
+ }
res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL);
if (res)
- return -EIO;
+ goto err_out;
usb_fill_int_urb(
kaweth->irq_urb,
@@ -681,7 +688,7 @@ static int kaweth_open(struct net_device *net)
res = usb_submit_urb(kaweth->irq_urb, GFP_KERNEL);
if (res) {
usb_kill_urb(kaweth->rx_urb);
- return -EIO;
+ goto err_out;
}
kaweth->opened = 1;
@@ -689,10 +696,14 @@ static int kaweth_open(struct net_device *net)
kaweth_async_set_rx_mode(kaweth);
return 0;
+
+err_out:
+ usb_autopm_enable(kaweth->intf);
+ return -EIO;
}
/****************************************************************
- * kaweth_close
+ * kaweth_kill_urbs
****************************************************************/
static void kaweth_kill_urbs(struct kaweth_device *kaweth)
{
@@ -724,17 +735,29 @@ static int kaweth_close(struct net_device *net)
kaweth->status &= ~KAWETH_STATUS_CLOSING;
+ usb_autopm_enable(kaweth->intf);
+
return 0;
}
static void kaweth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
+ struct kaweth_device *kaweth = netdev_priv(dev);
strlcpy(info->driver, driver_name, sizeof(info->driver));
+ usb_make_path(kaweth->dev, info->bus_info, sizeof (info->bus_info));
+}
+
+static u32 kaweth_get_link(struct net_device *dev)
+{
+ struct kaweth_device *kaweth = netdev_priv(dev);
+
+ return kaweth->linkstate;
}
static struct ethtool_ops ops = {
- .get_drvinfo = kaweth_get_drvinfo
+ .get_drvinfo = kaweth_get_drvinfo,
+ .get_link = kaweth_get_link
};
/****************************************************************
@@ -908,6 +931,7 @@ static int kaweth_suspend(struct usb_interface *intf, pm_message_t message)
struct kaweth_device *kaweth = usb_get_intfdata(intf);
unsigned long flags;
+ dbg("Suspending device");
spin_lock_irqsave(&kaweth->device_lock, flags);
kaweth->status |= KAWETH_STATUS_SUSPENDING;
spin_unlock_irqrestore(&kaweth->device_lock, flags);
@@ -924,6 +948,7 @@ static int kaweth_resume(struct usb_interface *intf)
struct kaweth_device *kaweth = usb_get_intfdata(intf);
unsigned long flags;
+ dbg("Resuming device");
spin_lock_irqsave(&kaweth->device_lock, flags);
kaweth->status &= ~KAWETH_STATUS_SUSPENDING;
spin_unlock_irqrestore(&kaweth->device_lock, flags);
@@ -1086,6 +1111,8 @@ err_fw:
dbg("Initializing net device.");
+ kaweth->intf = intf;
+
kaweth->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!kaweth->tx_urb)
goto err_free_netdev;
@@ -1265,7 +1292,7 @@ static int kaweth_internal_control_msg(struct usb_device *usb_dev,
{
struct urb *urb;
int retv;
- int length;
+ int length = 0; /* shut up GCC */
urb = usb_alloc_urb(0, GFP_NOIO);
if (!urb)
diff --git a/drivers/usb/net/pegasus.h b/drivers/usb/net/pegasus.h
index 98f6898cae1..c7467823cd1 100644
--- a/drivers/usb/net/pegasus.h
+++ b/drivers/usb/net/pegasus.h
@@ -214,9 +214,9 @@ PEGASUS_DEV( "Billionton USBEL-100", VENDOR_BILLIONTON, 0x0988,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "Billionton USBE-100", VENDOR_BILLIONTON, 0x8511,
DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "Corega FEter USB-TX", VENDOR_COREGA, 0x0004,
+PEGASUS_DEV( "Corega FEther USB-TX", VENDOR_COREGA, 0x0004,
DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "Corega FEter USB-TXS", VENDOR_COREGA, 0x000d,
+PEGASUS_DEV( "Corega FEther USB-TXS", VENDOR_COREGA, 0x000d,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4001,
DEFAULT_GPIO_RESET )
diff --git a/drivers/usb/net/rndis_host.c b/drivers/usb/net/rndis_host.c
index a322a16d9cf..be888d2d813 100644
--- a/drivers/usb/net/rndis_host.c
+++ b/drivers/usb/net/rndis_host.c
@@ -49,6 +49,8 @@
* - In some cases, MS-Windows will emit undocumented requests; this
* matters more to peripheral implementations than host ones.
*
+ * Moreover there's a no-open-specs variant of RNDIS called "ActiveSync".
+ *
* For these reasons and others, ** USE OF RNDIS IS STRONGLY DISCOURAGED ** in
* favor of such non-proprietary alternatives as CDC Ethernet or the newer (and
* currently rare) "Ethernet Emulation Model" (EEM).
@@ -61,6 +63,9 @@
* - control-in: GET_ENCAPSULATED
*
* We'll try to ignore the RESPONSE_AVAILABLE notifications.
+ *
+ * REVISIT some RNDIS implementations seem to have curious issues still
+ * to be resolved.
*/
struct rndis_msg_hdr {
__le32 msg_type; /* RNDIS_MSG_* */
@@ -71,8 +76,14 @@ struct rndis_msg_hdr {
// ... and more
} __attribute__ ((packed));
-/* RNDIS defines this (absurdly huge) control timeout */
-#define RNDIS_CONTROL_TIMEOUT_MS (10 * 1000)
+/* MS-Windows uses this strange size, but RNDIS spec says 1024 minimum */
+#define CONTROL_BUFFER_SIZE 1025
+
+/* RNDIS defines an (absurdly huge) 10 second control timeout,
+ * but ActiveSync seems to use a more usual 5 second timeout
+ * (which matches the USB 2.0 spec).
+ */
+#define RNDIS_CONTROL_TIMEOUT_MS (5 * 1000)
#define ccpu2 __constant_cpu_to_le32
@@ -270,6 +281,7 @@ static void rndis_status(struct usbnet *dev, struct urb *urb)
static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
{
struct cdc_state *info = (void *) &dev->data;
+ int master_ifnum;
int retval;
unsigned count;
__le32 rsp;
@@ -279,7 +291,7 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
* disconnect(): either serialize, or dispatch responses on xid
*/
- /* Issue the request; don't bother byteswapping our xid */
+ /* Issue the request; xid is unique, don't bother byteswapping it */
if (likely(buf->msg_type != RNDIS_MSG_HALT
&& buf->msg_type != RNDIS_MSG_RESET)) {
xid = dev->xid++;
@@ -287,11 +299,12 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
xid = dev->xid++;
buf->request_id = (__force __le32) xid;
}
+ master_ifnum = info->control->cur_altsetting->desc.bInterfaceNumber;
retval = usb_control_msg(dev->udev,
usb_sndctrlpipe(dev->udev, 0),
USB_CDC_SEND_ENCAPSULATED_COMMAND,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- 0, info->u->bMasterInterface0,
+ 0, master_ifnum,
buf, le32_to_cpu(buf->msg_len),
RNDIS_CONTROL_TIMEOUT_MS);
if (unlikely(retval < 0 || xid == 0))
@@ -306,13 +319,13 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
*/
rsp = buf->msg_type | RNDIS_MSG_COMPLETION;
for (count = 0; count < 10; count++) {
- memset(buf, 0, 1024);
+ memset(buf, 0, CONTROL_BUFFER_SIZE);
retval = usb_control_msg(dev->udev,
usb_rcvctrlpipe(dev->udev, 0),
USB_CDC_GET_ENCAPSULATED_RESPONSE,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- 0, info->u->bMasterInterface0,
- buf, 1024,
+ 0, master_ifnum,
+ buf, CONTROL_BUFFER_SIZE,
RNDIS_CONTROL_TIMEOUT_MS);
if (likely(retval >= 8)) {
msg_len = le32_to_cpu(buf->msg_len);
@@ -350,7 +363,7 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
usb_sndctrlpipe(dev->udev, 0),
USB_CDC_SEND_ENCAPSULATED_COMMAND,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- 0, info->u->bMasterInterface0,
+ 0, master_ifnum,
msg, sizeof *msg,
RNDIS_CONTROL_TIMEOUT_MS);
if (unlikely(retval < 0))
@@ -393,38 +406,64 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
u32 tmp;
/* we can't rely on i/o from stack working, or stack allocation */
- u.buf = kmalloc(1024, GFP_KERNEL);
+ u.buf = kmalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL);
if (!u.buf)
return -ENOMEM;
retval = usbnet_generic_cdc_bind(dev, intf);
if (retval < 0)
goto fail;
- net->hard_header_len += sizeof (struct rndis_data_hdr);
-
- /* initialize; max transfer is 16KB at full speed */
u.init->msg_type = RNDIS_MSG_INIT;
u.init->msg_len = ccpu2(sizeof *u.init);
u.init->major_version = ccpu2(1);
u.init->minor_version = ccpu2(0);
- u.init->max_transfer_size = ccpu2(net->mtu + net->hard_header_len);
+ /* max transfer (in spec) is 0x4000 at full speed, but for
+ * TX we'll stick to one Ethernet packet plus RNDIS framing.
+ * For RX we handle drivers that zero-pad to end-of-packet.
+ * Don't let userspace change these settings.
+ */
+ net->hard_header_len += sizeof (struct rndis_data_hdr);
+ dev->hard_mtu = net->mtu + net->hard_header_len;
+
+ dev->rx_urb_size = dev->hard_mtu + (dev->maxpacket + 1);
+ dev->rx_urb_size &= ~(dev->maxpacket - 1);
+ u.init->max_transfer_size = cpu_to_le32(dev->rx_urb_size);
+
+ net->change_mtu = NULL;
retval = rndis_command(dev, u.header);
if (unlikely(retval < 0)) {
/* it might not even be an RNDIS device!! */
dev_err(&intf->dev, "RNDIS init failed, %d\n", retval);
+ goto fail_and_release;
+ }
+ tmp = le32_to_cpu(u.init_c->max_transfer_size);
+ if (tmp < dev->hard_mtu) {
+ dev_err(&intf->dev,
+ "dev can't take %u byte packets (max %u)\n",
+ dev->hard_mtu, tmp);
goto fail_and_release;
}
- dev->hard_mtu = le32_to_cpu(u.init_c->max_transfer_size);
+
/* REVISIT: peripheral "alignment" request is ignored ... */
- dev_dbg(&intf->dev, "hard mtu %u, align %d\n", dev->hard_mtu,
+ dev_dbg(&intf->dev,
+ "hard mtu %u (%u from dev), rx buflen %Zu, align %d\n",
+ dev->hard_mtu, tmp, dev->rx_urb_size,
1 << le32_to_cpu(u.init_c->packet_alignment));
- /* get designated host ethernet address */
- memset(u.get, 0, sizeof *u.get);
+ /* Get designated host ethernet address.
+ *
+ * Adding a payload exactly the same size as the expected response
+ * payload is an evident requirement MSFT added for ActiveSync.
+ * This undocumented (and nonsensical) issue was found by sniffing
+ * protocol requests from the ActiveSync 4.1 Windows driver.
+ */
+ memset(u.get, 0, sizeof *u.get + 48);
u.get->msg_type = RNDIS_MSG_QUERY;
- u.get->msg_len = ccpu2(sizeof *u.get);
+ u.get->msg_len = ccpu2(sizeof *u.get + 48);
u.get->oid = OID_802_3_PERMANENT_ADDRESS;
+ u.get->len = ccpu2(48);
+ u.get->offset = ccpu2(20);
retval = rndis_command(dev, u.header);
if (unlikely(retval < 0)) {
@@ -432,7 +471,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
goto fail_and_release;
}
tmp = le32_to_cpu(u.get_c->offset);
- if (unlikely((tmp + 8) > (1024 - ETH_ALEN)
+ if (unlikely((tmp + 8) > (CONTROL_BUFFER_SIZE - ETH_ALEN)
|| u.get_c->len != ccpu2(ETH_ALEN))) {
dev_err(&intf->dev, "rndis ethaddr off %d len %d ?\n",
tmp, le32_to_cpu(u.get_c->len));
@@ -598,6 +637,10 @@ static const struct usb_device_id products [] = {
/* RNDIS is MSFT's un-official variant of CDC ACM */
USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff),
.driver_info = (unsigned long) &rndis_info,
+}, {
+ /* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */
+ USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1),
+ .driver_info = (unsigned long) &rndis_info,
},
{ }, // END
};
diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c
index 86bcf63b6ba..11dad42c3c6 100644
--- a/drivers/usb/serial/aircable.c
+++ b/drivers/usb/serial/aircable.c
@@ -572,8 +572,20 @@ static void aircable_unthrottle(struct usb_serial_port *port)
schedule_work(&priv->rx_work);
}
+static struct usb_driver aircable_driver = {
+ .name = "aircable",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = id_table,
+ .no_dynamic_id = 1,
+};
+
static struct usb_serial_driver aircable_device = {
- .description = "aircable",
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "aircable",
+ },
+ .usb_driver = &aircable_driver,
.id_table = id_table,
.num_ports = 1,
.attach = aircable_attach,
@@ -587,13 +599,6 @@ static struct usb_serial_driver aircable_device = {
.unthrottle = aircable_unthrottle,
};
-static struct usb_driver aircable_driver = {
- .name = "aircable",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
static int __init aircable_init (void)
{
int retval;
diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c
index f2ca76a9cba..0af42e32fa0 100644
--- a/drivers/usb/serial/airprime.c
+++ b/drivers/usb/serial/airprime.c
@@ -277,6 +277,7 @@ static struct usb_serial_driver airprime_device = {
.owner = THIS_MODULE,
.name = "airprime",
},
+ .usb_driver = &airprime_driver,
.id_table = id_table,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index 5261cd22ee6..edd685791a6 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -444,6 +444,7 @@ static struct usb_driver ark3116_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
+ .no_dynamic_id = 1,
};
static struct usb_serial_driver ark3116_device = {
@@ -452,6 +453,7 @@ static struct usb_serial_driver ark3116_device = {
.name = "ark3116",
},
.id_table = id_table,
+ .usb_driver = &ark3116_driver,
.num_interrupt_in = 1,
.num_bulk_in = 1,
.num_bulk_out = 1,
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
index 38b4dae319e..3b800d277c4 100644
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -126,6 +126,7 @@ static struct usb_serial_driver belkin_device = {
.name = "belkin",
},
.description = "Belkin / Peracom / GoHubs USB Serial Adapter",
+ .usb_driver = &belkin_driver,
.id_table = id_table_combined,
.num_interrupt_in = 1,
.num_bulk_in = 1,
diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c
index 6542f220468..c08a38402b9 100644
--- a/drivers/usb/serial/bus.c
+++ b/drivers/usb/serial/bus.c
@@ -103,11 +103,52 @@ exit:
return retval;
}
+#ifdef CONFIG_HOTPLUG
+static ssize_t store_new_id(struct device_driver *driver,
+ const char *buf, size_t count)
+{
+ struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver);
+ ssize_t retval = usb_store_new_id(&usb_drv->dynids, driver, buf, count);
+
+ if (retval >= 0 && usb_drv->usb_driver != NULL)
+ retval = usb_store_new_id(&usb_drv->usb_driver->dynids,
+ &usb_drv->usb_driver->drvwrap.driver,
+ buf, count);
+ return retval;
+}
+
+static struct driver_attribute drv_attrs[] = {
+ __ATTR(new_id, S_IWUSR, NULL, store_new_id),
+ __ATTR_NULL,
+};
+
+static void free_dynids(struct usb_serial_driver *drv)
+{
+ struct usb_dynid *dynid, *n;
+
+ spin_lock(&drv->dynids.lock);
+ list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) {
+ list_del(&dynid->node);
+ kfree(dynid);
+ }
+ spin_unlock(&drv->dynids.lock);
+}
+
+#else
+static struct driver_attribute drv_attrs[] = {
+ __ATTR_NULL,
+};
+static inline void free_dynids(struct usb_driver *drv)
+{
+}
+#endif
+
struct bus_type usb_serial_bus_type = {
.name = "usb-serial",
.match = usb_serial_device_match,
.probe = usb_serial_device_probe,
.remove = usb_serial_device_remove,
+ .drv_attrs = drv_attrs,
};
int usb_serial_bus_register(struct usb_serial_driver *driver)
@@ -115,6 +156,9 @@ int usb_serial_bus_register(struct usb_serial_driver *driver)
int retval;
driver->driver.bus = &usb_serial_bus_type;
+ spin_lock_init(&driver->dynids.lock);
+ INIT_LIST_HEAD(&driver->dynids.list);
+
retval = driver_register(&driver->driver);
return retval;
@@ -122,6 +166,7 @@ int usb_serial_bus_register(struct usb_serial_driver *driver)
void usb_serial_bus_deregister(struct usb_serial_driver *driver)
{
+ free_dynids(driver);
driver_unregister(&driver->driver);
}
diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c
index 7ebaffd6ed8..3ec24870bca 100644
--- a/drivers/usb/serial/cp2101.c
+++ b/drivers/usb/serial/cp2101.c
@@ -89,6 +89,7 @@ static struct usb_serial_driver cp2101_device = {
.owner = THIS_MODULE,
.name = "cp2101",
},
+ .usb_driver = &cp2101_driver,
.id_table = id_table,
.num_interrupt_in = 0,
.num_bulk_in = 0,
@@ -169,13 +170,13 @@ static int cp2101_get_config(struct usb_serial_port* port, u8 request,
unsigned int *data, int size)
{
struct usb_serial *serial = port->serial;
- u32 *buf;
+ __le32 *buf;
int result, i, length;
/* Number of integers required to contain the array */
length = (((size - 1) | 3) + 1)/4;
- buf = kcalloc(length, sizeof(u32), GFP_KERNEL);
+ buf = kcalloc(length, sizeof(__le32), GFP_KERNEL);
if (!buf) {
dev_err(&port->dev, "%s - out of memory.\n", __FUNCTION__);
return -ENOMEM;
@@ -215,13 +216,13 @@ static int cp2101_set_config(struct usb_serial_port* port, u8 request,
unsigned int *data, int size)
{
struct usb_serial *serial = port->serial;
- u32 *buf;
+ __le32 *buf;
int result, i, length;
/* Number of integers required to contain the array */
length = (((size - 1) | 3) + 1)/4;
- buf = kmalloc(length * sizeof(u32), GFP_KERNEL);
+ buf = kmalloc(length * sizeof(__le32), GFP_KERNEL);
if (!buf) {
dev_err(&port->dev, "%s - out of memory.\n",
__FUNCTION__);
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index a63c3286caa..4167753ed31 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -88,6 +88,7 @@ static struct usb_serial_driver cyberjack_device = {
.name = "cyberjack",
},
.description = "Reiner SCT Cyberjack USB card reader",
+ .usb_driver = &cyberjack_driver,
.id_table = id_table,
.num_interrupt_in = 1,
.num_bulk_in = 1,
@@ -98,7 +99,7 @@ static struct usb_serial_driver cyberjack_device = {
.open = cyberjack_open,
.close = cyberjack_close,
.write = cyberjack_write,
- .write_room = cyberjack_write_room,
+ .write_room = cyberjack_write_room,
.read_int_callback = cyberjack_read_int_callback,
.read_bulk_callback = cyberjack_read_bulk_callback,
.write_bulk_callback = cyberjack_write_bulk_callback,
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index 6bc1f404e18..57b8e27285f 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -193,6 +193,7 @@ static struct usb_serial_driver cypress_earthmate_device = {
.name = "earthmate",
},
.description = "DeLorme Earthmate USB",
+ .usb_driver = &cypress_driver,
.id_table = id_table_earthmate,
.num_interrupt_in = 1,
.num_interrupt_out = 1,
@@ -222,6 +223,7 @@ static struct usb_serial_driver cypress_hidcom_device = {
.name = "cyphidcom",
},
.description = "HID->COM RS232 Adapter",
+ .usb_driver = &cypress_driver,
.id_table = id_table_cyphidcomrs232,
.num_interrupt_in = 1,
.num_interrupt_out = 1,
@@ -251,6 +253,7 @@ static struct usb_serial_driver cypress_ca42v2_device = {
.name = "nokiaca42v2",
},
.description = "Nokia CA-42 V2 Adapter",
+ .usb_driver = &cypress_driver,
.id_table = id_table_nokiaca42v2,
.num_interrupt_in = 1,
.num_interrupt_out = 1,
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index efd9ce3f931..0b0fb51bad3 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -509,6 +509,7 @@ static struct usb_serial_driver digi_acceleport_2_device = {
.name = "digi_2",
},
.description = "Digi 2 port USB adapter",
+ .usb_driver = &digi_driver,
.id_table = id_table_2,
.num_interrupt_in = 0,
.num_bulk_in = 4,
@@ -538,6 +539,7 @@ static struct usb_serial_driver digi_acceleport_4_device = {
.name = "digi_4",
},
.description = "Digi 4 port USB adapter",
+ .usb_driver = &digi_driver,
.id_table = id_table_4,
.num_interrupt_in = 0,
.num_bulk_in = 5,
diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
index 92beeb19795..4703c8f8538 100644
--- a/drivers/usb/serial/empeg.c
+++ b/drivers/usb/serial/empeg.c
@@ -117,6 +117,7 @@ static struct usb_serial_driver empeg_device = {
.name = "empeg",
},
.id_table = id_table,
+ .usb_driver = &empeg_driver,
.num_interrupt_in = 0,
.num_bulk_in = 1,
.num_bulk_out = 1,
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 6986e756f7c..4695952b647 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -464,7 +464,6 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) },
{ USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) },
{ USB_DEVICE(FTDI_VID, EVER_ECO_PRO_CDS) },
- { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_0_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) },
{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_0_PID) },
@@ -615,6 +614,7 @@ static struct usb_serial_driver ftdi_sio_device = {
.name = "ftdi_sio",
},
.description = "FTDI USB Serial Device",
+ .usb_driver = &ftdi_driver ,
.id_table = id_table_combined,
.num_interrupt_in = 0,
.num_bulk_in = 1,
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index 40dd394de58..7eff1c03ba8 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -364,7 +364,6 @@
* USB-TTY activ, USB-TTY passiv. Some PIDs are used by several devices
* and I'm not entirely sure which are used by which.
*/
-#define FTDI_4N_GALAXY_DE_0_PID 0x8372
#define FTDI_4N_GALAXY_DE_1_PID 0xF3C0
#define FTDI_4N_GALAXY_DE_2_PID 0xF3C1
diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c
index 2bebd63d5ed..4092f6dc9ef 100644
--- a/drivers/usb/serial/funsoft.c
+++ b/drivers/usb/serial/funsoft.c
@@ -58,6 +58,7 @@ static struct usb_serial_driver funsoft_device = {
.name = "funsoft",
},
.id_table = id_table,
+ .usb_driver = &funsoft_driver,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
.num_bulk_out = NUM_DONT_CARE,
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
index 6530d391ebe..74660a3aa67 100644
--- a/drivers/usb/serial/garmin_gps.c
+++ b/drivers/usb/serial/garmin_gps.c
@@ -1566,6 +1566,7 @@ static struct usb_serial_driver garmin_device = {
.name = "garmin_gps",
},
.description = "Garmin GPS usb/tty",
+ .usb_driver = &garmin_driver,
.id_table = id_table,
.num_interrupt_in = 1,
.num_bulk_in = 1,
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index 36042937e77..601e0648dec 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -20,6 +20,10 @@
#include <linux/usb/serial.h>
#include <asm/uaccess.h>
+static int generic_probe(struct usb_interface *interface,
+ const struct usb_device_id *id);
+
+
static int debug;
#ifdef CONFIG_USB_SERIAL_GENERIC
@@ -34,6 +38,21 @@ MODULE_PARM_DESC(product, "User specified USB idProduct");
static struct usb_device_id generic_device_ids[2]; /* Initially all zeroes. */
+/* we want to look at all devices, as the vendor/product id can change
+ * depending on the command line argument */
+static struct usb_device_id generic_serial_ids[] = {
+ {.driver_info = 42},
+ {}
+};
+
+static struct usb_driver generic_driver = {
+ .name = "usbserial_generic",
+ .probe = generic_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = generic_serial_ids,
+ .no_dynamic_id = 1,
+};
+
/* All of the device info needed for the Generic Serial Converter */
struct usb_serial_driver usb_serial_generic_device = {
.driver = {
@@ -41,6 +60,7 @@ struct usb_serial_driver usb_serial_generic_device = {
.name = "generic",
},
.id_table = generic_device_ids,
+ .usb_driver = &generic_driver,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
.num_bulk_out = NUM_DONT_CARE,
@@ -48,13 +68,6 @@ struct usb_serial_driver usb_serial_generic_device = {
.shutdown = usb_serial_generic_shutdown,
};
-/* we want to look at all devices, as the vendor/product id can change
- * depending on the command line argument */
-static struct usb_device_id generic_serial_ids[] = {
- {.driver_info = 42},
- {}
-};
-
static int generic_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
@@ -65,14 +78,6 @@ static int generic_probe(struct usb_interface *interface,
return usb_serial_probe(interface, id);
return -ENODEV;
}
-
-static struct usb_driver generic_driver = {
- .name = "usbserial_generic",
- .probe = generic_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = generic_serial_ids,
- .no_dynamic_id = 1,
-};
#endif
int usb_serial_generic_register (int _debug)
diff --git a/drivers/usb/serial/hp4x.c b/drivers/usb/serial/hp4x.c
index ebcac701b06..6c6ebae741c 100644
--- a/drivers/usb/serial/hp4x.c
+++ b/drivers/usb/serial/hp4x.c
@@ -49,6 +49,7 @@ static struct usb_serial_driver hp49gp_device = {
.name = "hp4X",
},
.id_table = id_table,
+ .usb_driver = &hp49gp_driver,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
.num_bulk_out = NUM_DONT_CARE,
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index f623d58370a..6a26a2e683a 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -146,6 +146,8 @@ struct edgeport_serial {
struct edge_manuf_descriptor manuf_descriptor; /* the manufacturer descriptor */
struct edge_boot_descriptor boot_descriptor; /* the boot firmware descriptor */
struct edgeport_product_info product_info; /* Product Info */
+ struct edge_compatibility_descriptor epic_descriptor; /* Edgeport compatible descriptor */
+ int is_epic; /* flag if EPiC device or not */
__u8 interrupt_in_endpoint; /* the interrupt endpoint handle */
unsigned char * interrupt_in_buffer; /* the buffer we use for the interrupt endpoint */
@@ -240,14 +242,6 @@ static void edge_shutdown (struct usb_serial *serial);
#include "io_tables.h" /* all of the devices that this driver supports */
-static struct usb_driver io_driver = {
- .name = "io_edgeport",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table_combined,
- .no_dynamic_id = 1,
-};
-
/* function prototypes for all of our local functions */
static void process_rcvd_data (struct edgeport_serial *edge_serial, unsigned char *buffer, __u16 bufferLength);
static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2, __u8 byte3);
@@ -397,6 +391,7 @@ static int get_string (struct usb_device *dev, int Id, char *string, int buflen)
unicode_to_ascii(string, buflen, pStringDesc->wData, pStringDesc->bLength/2);
kfree(pStringDesc);
+ dbg("%s - USB String %s", __FUNCTION__, string);
return strlen(string);
}
@@ -434,6 +429,34 @@ static int get_string_desc (struct usb_device *dev, int Id, struct usb_string_de
}
#endif
+static void dump_product_info(struct edgeport_product_info *product_info)
+{
+ // Dump Product Info structure
+ dbg("**Product Information:");
+ dbg(" ProductId %x", product_info->ProductId );
+ dbg(" NumPorts %d", product_info->NumPorts );
+ dbg(" ProdInfoVer %d", product_info->ProdInfoVer );
+ dbg(" IsServer %d", product_info->IsServer);
+ dbg(" IsRS232 %d", product_info->IsRS232 );
+ dbg(" IsRS422 %d", product_info->IsRS422 );
+ dbg(" IsRS485 %d", product_info->IsRS485 );
+ dbg(" RomSize %d", product_info->RomSize );
+ dbg(" RamSize %d", product_info->RamSize );
+ dbg(" CpuRev %x", product_info->CpuRev );
+ dbg(" BoardRev %x", product_info->BoardRev);
+ dbg(" BootMajorVersion %d.%d.%d", product_info->BootMajorVersion,
+ product_info->BootMinorVersion,
+ le16_to_cpu(product_info->BootBuildNumber));
+ dbg(" FirmwareMajorVersion %d.%d.%d", product_info->FirmwareMajorVersion,
+ product_info->FirmwareMinorVersion,
+ le16_to_cpu(product_info->FirmwareBuildNumber));
+ dbg(" ManufactureDescDate %d/%d/%d", product_info->ManufactureDescDate[0],
+ product_info->ManufactureDescDate[1],
+ product_info->ManufactureDescDate[2]+1900);
+ dbg(" iDownloadFile 0x%x", product_info->iDownloadFile);
+ dbg(" EpicVer %d", product_info->EpicVer);
+}
+
static void get_product_info(struct edgeport_serial *edge_serial)
{
struct edgeport_product_info *product_info = &edge_serial->product_info;
@@ -495,30 +518,60 @@ static void get_product_info(struct edgeport_serial *edge_serial)
break;
}
- // Dump Product Info structure
- dbg("**Product Information:");
- dbg(" ProductId %x", product_info->ProductId );
- dbg(" NumPorts %d", product_info->NumPorts );
- dbg(" ProdInfoVer %d", product_info->ProdInfoVer );
- dbg(" IsServer %d", product_info->IsServer);
- dbg(" IsRS232 %d", product_info->IsRS232 );
- dbg(" IsRS422 %d", product_info->IsRS422 );
- dbg(" IsRS485 %d", product_info->IsRS485 );
- dbg(" RomSize %d", product_info->RomSize );
- dbg(" RamSize %d", product_info->RamSize );
- dbg(" CpuRev %x", product_info->CpuRev );
- dbg(" BoardRev %x", product_info->BoardRev);
- dbg(" BootMajorVersion %d.%d.%d", product_info->BootMajorVersion,
- product_info->BootMinorVersion,
- le16_to_cpu(product_info->BootBuildNumber));
- dbg(" FirmwareMajorVersion %d.%d.%d", product_info->FirmwareMajorVersion,
- product_info->FirmwareMinorVersion,
- le16_to_cpu(product_info->FirmwareBuildNumber));
- dbg(" ManufactureDescDate %d/%d/%d", product_info->ManufactureDescDate[0],
- product_info->ManufactureDescDate[1],
- product_info->ManufactureDescDate[2]+1900);
- dbg(" iDownloadFile 0x%x", product_info->iDownloadFile);
+ dump_product_info(product_info);
+}
+static int get_epic_descriptor(struct edgeport_serial *ep)
+{
+ int result;
+ struct usb_serial *serial = ep->serial;
+ struct edgeport_product_info *product_info = &ep->product_info;
+ struct edge_compatibility_descriptor *epic = &ep->epic_descriptor;
+ struct edge_compatibility_bits *bits;
+
+ ep->is_epic = 0;
+ result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+ USB_REQUEST_ION_GET_EPIC_DESC,
+ 0xC0, 0x00, 0x00,
+ &ep->epic_descriptor,
+ sizeof(struct edge_compatibility_descriptor),
+ 300);
+
+ dbg("%s result = %d", __FUNCTION__, result);
+
+ if (result > 0) {
+ ep->is_epic = 1;
+ memset(product_info, 0, sizeof(struct edgeport_product_info));
+
+ product_info->NumPorts = epic->NumPorts;
+ product_info->ProdInfoVer = 0;
+ product_info->FirmwareMajorVersion = epic->MajorVersion;
+ product_info->FirmwareMinorVersion = epic->MinorVersion;
+ product_info->FirmwareBuildNumber = epic->BuildNumber;
+ product_info->iDownloadFile = epic->iDownloadFile;
+ product_info->EpicVer = epic->EpicVer;
+ product_info->Epic = epic->Supports;
+ product_info->ProductId = ION_DEVICE_ID_EDGEPORT_COMPATIBLE;
+ dump_product_info(product_info);
+
+ bits = &ep->epic_descriptor.Supports;
+ dbg("**EPIC descriptor:");
+ dbg(" VendEnableSuspend: %s", bits->VendEnableSuspend ? "TRUE": "FALSE");
+ dbg(" IOSPOpen : %s", bits->IOSPOpen ? "TRUE": "FALSE" );
+ dbg(" IOSPClose : %s", bits->IOSPClose ? "TRUE": "FALSE" );
+ dbg(" IOSPChase : %s", bits->IOSPChase ? "TRUE": "FALSE" );
+ dbg(" IOSPSetRxFlow : %s", bits->IOSPSetRxFlow ? "TRUE": "FALSE" );
+ dbg(" IOSPSetTxFlow : %s", bits->IOSPSetTxFlow ? "TRUE": "FALSE" );
+ dbg(" IOSPSetXChar : %s", bits->IOSPSetXChar ? "TRUE": "FALSE" );
+ dbg(" IOSPRxCheck : %s", bits->IOSPRxCheck ? "TRUE": "FALSE" );
+ dbg(" IOSPSetClrBreak : %s", bits->IOSPSetClrBreak ? "TRUE": "FALSE" );
+ dbg(" IOSPWriteMCR : %s", bits->IOSPWriteMCR ? "TRUE": "FALSE" );
+ dbg(" IOSPWriteLCR : %s", bits->IOSPWriteLCR ? "TRUE": "FALSE" );
+ dbg(" IOSPSetBaudRate : %s", bits->IOSPSetBaudRate ? "TRUE": "FALSE" );
+ dbg(" TrueEdgeport : %s", bits->TrueEdgeport ? "TRUE": "FALSE" );
+ }
+
+ return result;
}
@@ -1017,21 +1070,29 @@ static void edge_close (struct usb_serial_port *port, struct file * filp)
edge_port->closePending = TRUE;
- /* flush and chase */
- edge_port->chaseResponsePending = TRUE;
-
- dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__);
- status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
- if (status == 0) {
- // block until chase finished
- block_until_chase_response(edge_port);
- } else {
- edge_port->chaseResponsePending = FALSE;
+ if ((!edge_serial->is_epic) ||
+ ((edge_serial->is_epic) &&
+ (edge_serial->epic_descriptor.Supports.IOSPChase))) {
+ /* flush and chase */
+ edge_port->chaseResponsePending = TRUE;
+
+ dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__);
+ status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
+ if (status == 0) {
+ // block until chase finished
+ block_until_chase_response(edge_port);
+ } else {
+ edge_port->chaseResponsePending = FALSE;
+ }
}
- /* close the port */
- dbg("%s - Sending IOSP_CMD_CLOSE_PORT", __FUNCTION__);
- send_iosp_ext_cmd (edge_port, IOSP_CMD_CLOSE_PORT, 0);
+ if ((!edge_serial->is_epic) ||
+ ((edge_serial->is_epic) &&
+ (edge_serial->epic_descriptor.Supports.IOSPClose))) {
+ /* close the port */
+ dbg("%s - Sending IOSP_CMD_CLOSE_PORT", __FUNCTION__);
+ send_iosp_ext_cmd (edge_port, IOSP_CMD_CLOSE_PORT, 0);
+ }
//port->close = TRUE;
edge_port->closePending = FALSE;
@@ -1694,29 +1755,38 @@ static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned
static void edge_break (struct usb_serial_port *port, int break_state)
{
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+ struct edgeport_serial *edge_serial = usb_get_serial_data(port->serial);
int status;
- /* flush and chase */
- edge_port->chaseResponsePending = TRUE;
-
- dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__);
- status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
- if (status == 0) {
- // block until chase finished
- block_until_chase_response(edge_port);
- } else {
- edge_port->chaseResponsePending = FALSE;
+ if ((!edge_serial->is_epic) ||
+ ((edge_serial->is_epic) &&
+ (edge_serial->epic_descriptor.Supports.IOSPChase))) {
+ /* flush and chase */
+ edge_port->chaseResponsePending = TRUE;
+
+ dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__);
+ status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
+ if (status == 0) {
+ // block until chase finished
+ block_until_chase_response(edge_port);
+ } else {
+ edge_port->chaseResponsePending = FALSE;
+ }
}
- if (break_state == -1) {
- dbg("%s - Sending IOSP_CMD_SET_BREAK", __FUNCTION__);
- status = send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_BREAK, 0);
- } else {
- dbg("%s - Sending IOSP_CMD_CLEAR_BREAK", __FUNCTION__);
- status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CLEAR_BREAK, 0);
- }
- if (status) {
- dbg("%s - error sending break set/clear command.", __FUNCTION__);
+ if ((!edge_serial->is_epic) ||
+ ((edge_serial->is_epic) &&
+ (edge_serial->epic_descriptor.Supports.IOSPSetClrBreak))) {
+ if (break_state == -1) {
+ dbg("%s - Sending IOSP_CMD_SET_BREAK", __FUNCTION__);
+ status = send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_BREAK, 0);
+ } else {
+ dbg("%s - Sending IOSP_CMD_CLEAR_BREAK", __FUNCTION__);
+ status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CLEAR_BREAK, 0);
+ }
+ if (status) {
+ dbg("%s - error sending break set/clear command.", __FUNCTION__);
+ }
}
return;
@@ -2288,6 +2358,7 @@ static int write_cmd_usb (struct edgeport_port *edge_port, unsigned char *buffer
*****************************************************************************/
static int send_cmd_write_baud_rate (struct edgeport_port *edge_port, int baudRate)
{
+ struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial);
unsigned char *cmdBuffer;
unsigned char *currCmd;
int cmdLen = 0;
@@ -2295,6 +2366,14 @@ static int send_cmd_write_baud_rate (struct edgeport_port *edge_port, int baudRa
int status;
unsigned char number = edge_port->port->number - edge_port->port->serial->minor;
+ if ((!edge_serial->is_epic) ||
+ ((edge_serial->is_epic) &&
+ (!edge_serial->epic_descriptor.Supports.IOSPSetBaudRate))) {
+ dbg("SendCmdWriteBaudRate - NOT Setting baud rate for port = %d, baud = %d",
+ edge_port->port->number, baudRate);
+ return 0;
+ }
+
dbg("%s - port = %d, baud = %d", __FUNCTION__, edge_port->port->number, baudRate);
status = calc_baud_rate_divisor (baudRate, &divisor);
@@ -2374,6 +2453,7 @@ static int calc_baud_rate_divisor (int baudrate, int *divisor)
*****************************************************************************/
static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 regNum, __u8 regValue)
{
+ struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial);
unsigned char *cmdBuffer;
unsigned char *currCmd;
unsigned long cmdLen = 0;
@@ -2381,6 +2461,22 @@ static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 r
dbg("%s - write to %s register 0x%02x", (regNum == MCR) ? "MCR" : "LCR", __FUNCTION__, regValue);
+ if ((!edge_serial->is_epic) ||
+ ((edge_serial->is_epic) &&
+ (!edge_serial->epic_descriptor.Supports.IOSPWriteMCR) &&
+ (regNum == MCR))) {
+ dbg("SendCmdWriteUartReg - Not writting to MCR Register");
+ return 0;
+ }
+
+ if ((!edge_serial->is_epic) ||
+ ((edge_serial->is_epic) &&
+ (!edge_serial->epic_descriptor.Supports.IOSPWriteLCR) &&
+ (regNum == LCR))) {
+ dbg ("SendCmdWriteUartReg - Not writting to LCR Register");
+ return 0;
+ }
+
// Alloc memory for the string of commands.
cmdBuffer = kmalloc (0x10, GFP_ATOMIC);
if (cmdBuffer == NULL ) {
@@ -2414,6 +2510,7 @@ static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 r
#endif
static void change_port_settings (struct edgeport_port *edge_port, struct ktermios *old_termios)
{
+ struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial);
struct tty_struct *tty;
int baud;
unsigned cflag;
@@ -2494,8 +2591,12 @@ static void change_port_settings (struct edgeport_port *edge_port, struct ktermi
unsigned char stop_char = STOP_CHAR(tty);
unsigned char start_char = START_CHAR(tty);
- send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_XON_CHAR, start_char);
- send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_XOFF_CHAR, stop_char);
+ if ((!edge_serial->is_epic) ||
+ ((edge_serial->is_epic) &&
+ (edge_serial->epic_descriptor.Supports.IOSPSetXChar))) {
+ send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_XON_CHAR, start_char);
+ send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_XOFF_CHAR, stop_char);
+ }
/* if we are implementing INBOUND XON/XOFF */
if (I_IXOFF(tty)) {
@@ -2515,8 +2616,14 @@ static void change_port_settings (struct edgeport_port *edge_port, struct ktermi
}
/* Set flow control to the configured value */
- send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_RX_FLOW, rxFlow);
- send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_TX_FLOW, txFlow);
+ if ((!edge_serial->is_epic) ||
+ ((edge_serial->is_epic) &&
+ (edge_serial->epic_descriptor.Supports.IOSPSetRxFlow)))
+ send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_RX_FLOW, rxFlow);
+ if ((!edge_serial->is_epic) ||
+ ((edge_serial->is_epic) &&
+ (edge_serial->epic_descriptor.Supports.IOSPSetTxFlow)))
+ send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_TX_FLOW, txFlow);
edge_port->shadowLCR &= ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK);
@@ -2728,6 +2835,13 @@ static int edge_startup (struct usb_serial *serial)
struct edgeport_port *edge_port;
struct usb_device *dev;
int i, j;
+ int response;
+ int interrupt_in_found;
+ int bulk_in_found;
+ int bulk_out_found;
+ static __u32 descriptor[3] = { EDGE_COMPATIBILITY_MASK0,
+ EDGE_COMPATIBILITY_MASK1,
+ EDGE_COMPATIBILITY_MASK2 };
dev = serial->dev;
@@ -2750,38 +2864,50 @@ static int edge_startup (struct usb_serial *serial)
dev_info(&serial->dev->dev, "%s detected\n", edge_serial->name);
- /* get the manufacturing descriptor for this device */
- get_manufacturing_desc (edge_serial);
+ /* Read the epic descriptor */
+ if (get_epic_descriptor(edge_serial) <= 0) {
+ /* memcpy descriptor to Supports structures */
+ memcpy(&edge_serial->epic_descriptor.Supports, descriptor,
+ sizeof(struct edge_compatibility_bits));
+
+ /* get the manufacturing descriptor for this device */
+ get_manufacturing_desc (edge_serial);
- /* get the boot descriptor */
- get_boot_desc (edge_serial);
+ /* get the boot descriptor */
+ get_boot_desc (edge_serial);
- get_product_info(edge_serial);
+ get_product_info(edge_serial);
+ }
/* set the number of ports from the manufacturing description */
/* serial->num_ports = serial->product_info.NumPorts; */
- if (edge_serial->product_info.NumPorts != serial->num_ports) {
- warn("%s - Device Reported %d serial ports vs core "
- "thinking we have %d ports, email greg@kroah.com this info.",
- __FUNCTION__, edge_serial->product_info.NumPorts,
- serial->num_ports);
+ if ((!edge_serial->is_epic) &&
+ (edge_serial->product_info.NumPorts != serial->num_ports)) {
+ dev_warn(&serial->dev->dev, "Device Reported %d serial ports "
+ "vs. core thinking we have %d ports, email "
+ "greg@kroah.com this information.",
+ edge_serial->product_info.NumPorts,
+ serial->num_ports);
}
dbg("%s - time 1 %ld", __FUNCTION__, jiffies);
- /* now load the application firmware into this device */
- load_application_firmware (edge_serial);
+ /* If not an EPiC device */
+ if (!edge_serial->is_epic) {
+ /* now load the application firmware into this device */
+ load_application_firmware (edge_serial);
- dbg("%s - time 2 %ld", __FUNCTION__, jiffies);
+ dbg("%s - time 2 %ld", __FUNCTION__, jiffies);
- /* Check current Edgeport EEPROM and update if necessary */
- update_edgeport_E2PROM (edge_serial);
-
- dbg("%s - time 3 %ld", __FUNCTION__, jiffies);
+ /* Check current Edgeport EEPROM and update if necessary */
+ update_edgeport_E2PROM (edge_serial);
- /* set the configuration to use #1 */
-// dbg("set_configuration 1");
-// usb_set_configuration (dev, 1);
+ dbg("%s - time 3 %ld", __FUNCTION__, jiffies);
+
+ /* set the configuration to use #1 */
+// dbg("set_configuration 1");
+// usb_set_configuration (dev, 1);
+ }
/* we set up the pointers to the endpoints in the edge_open function,
* as the structures aren't created yet. */
@@ -2804,8 +2930,101 @@ static int edge_startup (struct usb_serial *serial)
edge_port->port = serial->port[i];
usb_set_serial_port_data(serial->port[i], edge_port);
}
-
- return 0;
+
+ response = 0;
+
+ if (edge_serial->is_epic) {
+ /* EPIC thing, set up our interrupt polling now and our read urb, so
+ * that the device knows it really is connected. */
+ interrupt_in_found = bulk_in_found = bulk_out_found = FALSE;
+ for (i = 0; i < serial->interface->altsetting[0].desc.bNumEndpoints; ++i) {
+ struct usb_endpoint_descriptor *endpoint;
+ int buffer_size;
+
+ endpoint = &serial->interface->altsetting[0].endpoint[i].desc;
+ buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+ if ((!interrupt_in_found) &&
+ (usb_endpoint_is_int_in(endpoint))) {
+ /* we found a interrupt in endpoint */
+ dbg("found interrupt in");
+
+ /* not set up yet, so do it now */
+ edge_serial->interrupt_read_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!edge_serial->interrupt_read_urb) {
+ err("out of memory");
+ return -ENOMEM;
+ }
+ edge_serial->interrupt_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
+ if (!edge_serial->interrupt_in_buffer) {
+ err("out of memory");
+ usb_free_urb(edge_serial->interrupt_read_urb);
+ return -ENOMEM;
+ }
+ edge_serial->interrupt_in_endpoint = endpoint->bEndpointAddress;
+
+ /* set up our interrupt urb */
+ usb_fill_int_urb(edge_serial->interrupt_read_urb,
+ dev,
+ usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+ edge_serial->interrupt_in_buffer,
+ buffer_size,
+ edge_interrupt_callback,
+ edge_serial,
+ endpoint->bInterval);
+
+ interrupt_in_found = TRUE;
+ }
+
+ if ((!bulk_in_found) &&
+ (usb_endpoint_is_bulk_in(endpoint))) {
+ /* we found a bulk in endpoint */
+ dbg("found bulk in");
+
+ /* not set up yet, so do it now */
+ edge_serial->read_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!edge_serial->read_urb) {
+ err("out of memory");
+ return -ENOMEM;
+ }
+ edge_serial->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
+ if (!edge_serial->bulk_in_buffer) {
+ err ("out of memory");
+ usb_free_urb(edge_serial->read_urb);
+ return -ENOMEM;
+ }
+ edge_serial->bulk_in_endpoint = endpoint->bEndpointAddress;
+
+ /* set up our bulk in urb */
+ usb_fill_bulk_urb(edge_serial->read_urb, dev,
+ usb_rcvbulkpipe(dev, endpoint->bEndpointAddress),
+ edge_serial->bulk_in_buffer,
+ endpoint->wMaxPacketSize,
+ edge_bulk_in_callback,
+ edge_serial);
+ bulk_in_found = TRUE;
+ }
+
+ if ((!bulk_out_found) &&
+ (usb_endpoint_is_bulk_out(endpoint))) {
+ /* we found a bulk out endpoint */
+ dbg("found bulk out");
+ edge_serial->bulk_out_endpoint = endpoint->bEndpointAddress;
+ bulk_out_found = TRUE;
+ }
+ }
+
+ if ((!interrupt_in_found) || (!bulk_in_found) || (!bulk_out_found)) {
+ err ("Error - the proper endpoints were not found!");
+ return -ENODEV;
+ }
+
+ /* start interrupt read for this edgeport this interrupt will
+ * continue as long as the edgeport is connected */
+ response = usb_submit_urb(edge_serial->interrupt_read_urb, GFP_KERNEL);
+ if (response)
+ err("%s - Error %d submitting control urb", __FUNCTION__, response);
+ }
+ return response;
}
@@ -2815,6 +3034,7 @@ static int edge_startup (struct usb_serial *serial)
****************************************************************************/
static void edge_shutdown (struct usb_serial *serial)
{
+ struct edgeport_serial *edge_serial = usb_get_serial_data(serial);
int i;
dbg("%s", __FUNCTION__);
@@ -2824,7 +3044,18 @@ static void edge_shutdown (struct usb_serial *serial)
kfree (usb_get_serial_port_data(serial->port[i]));
usb_set_serial_port_data(serial->port[i], NULL);
}
- kfree (usb_get_serial_data(serial));
+ /* free up our endpoint stuff */
+ if (edge_serial->is_epic) {
+ usb_unlink_urb(edge_serial->interrupt_read_urb);
+ usb_free_urb(edge_serial->interrupt_read_urb);
+ kfree(edge_serial->interrupt_in_buffer);
+
+ usb_unlink_urb(edge_serial->read_urb);
+ usb_free_urb(edge_serial->read_urb);
+ kfree(edge_serial->bulk_in_buffer);
+ }
+
+ kfree(edge_serial);
usb_set_serial_data(serial, NULL);
}
@@ -2846,6 +3077,9 @@ static int __init edgeport_init(void)
retval = usb_serial_register(&edgeport_8port_device);
if (retval)
goto failed_8port_device_register;
+ retval = usb_serial_register(&epic_device);
+ if (retval)
+ goto failed_epic_device_register;
retval = usb_register(&io_driver);
if (retval)
goto failed_usb_register;
@@ -2853,6 +3087,8 @@ static int __init edgeport_init(void)
return 0;
failed_usb_register:
+ usb_serial_deregister(&epic_device);
+failed_epic_device_register:
usb_serial_deregister(&edgeport_8port_device);
failed_8port_device_register:
usb_serial_deregister(&edgeport_4port_device);
@@ -2873,6 +3109,7 @@ static void __exit edgeport_exit (void)
usb_serial_deregister (&edgeport_2port_device);
usb_serial_deregister (&edgeport_4port_device);
usb_serial_deregister (&edgeport_8port_device);
+ usb_serial_deregister (&epic_device);
}
module_init(edgeport_init);
diff --git a/drivers/usb/serial/io_edgeport.h b/drivers/usb/serial/io_edgeport.h
index 123fa8a904e..29a913a6dac 100644
--- a/drivers/usb/serial/io_edgeport.h
+++ b/drivers/usb/serial/io_edgeport.h
@@ -111,10 +111,12 @@ struct edgeport_product_info {
__le16 FirmwareBuildNumber; /* zzzz (LE format) */
__u8 ManufactureDescDate[3]; /* MM/DD/YY when descriptor template was compiled */
- __u8 Unused1[1]; /* Available */
+ __u8 HardwareType;
__u8 iDownloadFile; /* What to download to EPiC device */
- __u8 Unused2[2]; /* Available */
+ __u8 EpicVer; /* What version of EPiC spec this device supports */
+
+ struct edge_compatibility_bits Epic;
};
/*
diff --git a/drivers/usb/serial/io_tables.h b/drivers/usb/serial/io_tables.h
index fad561c04c7..6d300877254 100644
--- a/drivers/usb/serial/io_tables.h
+++ b/drivers/usb/serial/io_tables.h
@@ -47,6 +47,18 @@ static struct usb_device_id edgeport_8port_id_table [] = {
{ }
};
+static struct usb_device_id Epic_port_id_table [] = {
+ { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0202) },
+ { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0203) },
+ { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0310) },
+ { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0311) },
+ { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0312) },
+ { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A758) },
+ { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A794) },
+ { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A225) },
+ { }
+};
+
/* Devices that this driver supports */
static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4) },
@@ -70,17 +82,34 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8R) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8RR) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_8) },
+ { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0202) },
+ { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0203) },
+ { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0310) },
+ { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0311) },
+ { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0312) },
+ { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A758) },
+ { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A794) },
+ { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A225) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, id_table_combined);
+static struct usb_driver io_driver = {
+ .name = "io_edgeport",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = id_table_combined,
+ .no_dynamic_id = 1,
+};
+
static struct usb_serial_driver edgeport_2port_device = {
.driver = {
.owner = THIS_MODULE,
.name = "edgeport_2",
},
.description = "Edgeport 2 port adapter",
+ .usb_driver = &io_driver,
.id_table = edgeport_2port_id_table,
.num_interrupt_in = 1,
.num_bulk_in = 1,
@@ -111,6 +140,7 @@ static struct usb_serial_driver edgeport_4port_device = {
.name = "edgeport_4",
},
.description = "Edgeport 4 port adapter",
+ .usb_driver = &io_driver,
.id_table = edgeport_4port_id_table,
.num_interrupt_in = 1,
.num_bulk_in = 1,
@@ -141,6 +171,7 @@ static struct usb_serial_driver edgeport_8port_device = {
.name = "edgeport_8",
},
.description = "Edgeport 8 port adapter",
+ .usb_driver = &io_driver,
.id_table = edgeport_8port_id_table,
.num_interrupt_in = 1,
.num_bulk_in = 1,
@@ -165,5 +196,35 @@ static struct usb_serial_driver edgeport_8port_device = {
.write_bulk_callback = edge_bulk_out_data_callback,
};
+static struct usb_serial_driver epic_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "epic",
+ },
+ .description = "EPiC device",
+ .id_table = Epic_port_id_table,
+ .num_interrupt_in = 1,
+ .num_bulk_in = 1,
+ .num_bulk_out = 1,
+ .num_ports = 1,
+ .open = edge_open,
+ .close = edge_close,
+ .throttle = edge_throttle,
+ .unthrottle = edge_unthrottle,
+ .attach = edge_startup,
+ .shutdown = edge_shutdown,
+ .ioctl = edge_ioctl,
+ .set_termios = edge_set_termios,
+ .tiocmget = edge_tiocmget,
+ .tiocmset = edge_tiocmset,
+ .write = edge_write,
+ .write_room = edge_write_room,
+ .chars_in_buffer = edge_chars_in_buffer,
+ .break_ctl = edge_break,
+ .read_int_callback = edge_interrupt_callback,
+ .read_bulk_callback = edge_bulk_in_callback,
+ .write_bulk_callback = edge_bulk_out_data_callback,
+};
+
#endif
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index 980285c0233..544098d2b77 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -2979,6 +2979,7 @@ static struct usb_serial_driver edgeport_1port_device = {
.name = "edgeport_ti_1",
},
.description = "Edgeport TI 1 port adapter",
+ .usb_driver = &io_driver,
.id_table = edgeport_1port_id_table,
.num_interrupt_in = 1,
.num_bulk_in = 1,
@@ -3009,6 +3010,7 @@ static struct usb_serial_driver edgeport_2port_device = {
.name = "edgeport_ti_2",
},
.description = "Edgeport TI 2 port adapter",
+ .usb_driver = &io_driver,
.id_table = edgeport_2port_id_table,
.num_interrupt_in = 1,
.num_bulk_in = 2,
diff --git a/drivers/usb/serial/io_usbvend.h b/drivers/usb/serial/io_usbvend.h
index f1804fd5a3d..e57fa117e48 100644
--- a/drivers/usb/serial/io_usbvend.h
+++ b/drivers/usb/serial/io_usbvend.h
@@ -30,6 +30,7 @@
#define USB_VENDOR_ID_ION 0x1608 // Our VID
#define USB_VENDOR_ID_TI 0x0451 // TI VID
+#define USB_VENDOR_ID_AXIOHM 0x05D9 /* Axiohm VID */
//
// Definitions of USB product IDs (PID)
@@ -334,6 +335,10 @@ struct edge_compatibility_bits
};
+#define EDGE_COMPATIBILITY_MASK0 0x0001
+#define EDGE_COMPATIBILITY_MASK1 0x3FFF
+#define EDGE_COMPATIBILITY_MASK2 0x0001
+
struct edge_compatibility_descriptor
{
__u8 Length; // Descriptor Length (per USB spec)
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index 42f757a5b87..a408184334e 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -563,6 +563,7 @@ static struct usb_serial_driver ipaq_device = {
.name = "ipaq",
},
.description = "PocketPC PDA",
+ .usb_driver = &ipaq_driver,
.id_table = ipaq_id_table,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = 1,
diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c
index d3b9a351cef..1bc586064c7 100644
--- a/drivers/usb/serial/ipw.c
+++ b/drivers/usb/serial/ipw.c
@@ -442,6 +442,7 @@ static struct usb_serial_driver ipw_device = {
.name = "ipw",
},
.description = "IPWireless converter",
+ .usb_driver = &usb_ipw_driver,
.id_table = usb_ipw_ids,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = 1,
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index 8fdf486e346..9d847f69291 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -138,6 +138,7 @@ static struct usb_serial_driver ir_device = {
.name = "ir-usb",
},
.description = "IR Dongle",
+ .usb_driver = &ir_driver,
.id_table = id_table,
.num_interrupt_in = 1,
.num_bulk_in = 1,
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index 9d2fdfd6865..e6966f12ed5 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -1275,11 +1275,31 @@ static int keyspan_fake_startup (struct usb_serial *serial)
}
/* Helper functions used by keyspan_setup_urbs */
+static struct usb_endpoint_descriptor const *find_ep(struct usb_serial const *serial,
+ int endpoint)
+{
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *ep;
+ int i;
+
+ iface_desc = serial->interface->cur_altsetting;
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+ ep = &iface_desc->endpoint[i].desc;
+ if (ep->bEndpointAddress == endpoint)
+ return ep;
+ }
+ dev_warn(&serial->interface->dev, "found no endpoint descriptor for "
+ "endpoint %x\n", endpoint);
+ return NULL;
+}
+
static struct urb *keyspan_setup_urb (struct usb_serial *serial, int endpoint,
int dir, void *ctx, char *buf, int len,
void (*callback)(struct urb *))
{
struct urb *urb;
+ struct usb_endpoint_descriptor const *ep_desc;
+ char const *ep_type_name;
if (endpoint == -1)
return NULL; /* endpoint not needed */
@@ -1291,11 +1311,32 @@ static struct urb *keyspan_setup_urb (struct usb_serial *serial, int endpoint,
return NULL;
}
- /* Fill URB using supplied data. */
- usb_fill_bulk_urb(urb, serial->dev,
- usb_sndbulkpipe(serial->dev, endpoint) | dir,
- buf, len, callback, ctx);
+ ep_desc = find_ep(serial, endpoint);
+ if (!ep_desc) {
+ /* leak the urb, something's wrong and the callers don't care */
+ return urb;
+ }
+ if (usb_endpoint_xfer_int(ep_desc)) {
+ ep_type_name = "INT";
+ usb_fill_int_urb(urb, serial->dev,
+ usb_sndintpipe(serial->dev, endpoint) | dir,
+ buf, len, callback, ctx,
+ ep_desc->bInterval);
+ } else if (usb_endpoint_xfer_bulk(ep_desc)) {
+ ep_type_name = "BULK";
+ usb_fill_bulk_urb(urb, serial->dev,
+ usb_sndbulkpipe(serial->dev, endpoint) | dir,
+ buf, len, callback, ctx);
+ } else {
+ dev_warn(&serial->interface->dev,
+ "unsupported endpoint type %x\n",
+ ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
+ usb_free_urb(urb);
+ return NULL;
+ }
+ dbg("%s - using urb %p for %s endpoint %x",
+ __func__, urb, ep_type_name, endpoint);
return urb;
}
diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h
index 6413d73c139..c6830cbdc6d 100644
--- a/drivers/usb/serial/keyspan.h
+++ b/drivers/usb/serial/keyspan.h
@@ -229,7 +229,6 @@ struct ezusb_hex_record {
#define keyspan_usa28_product_id 0x010f
#define keyspan_usa28x_product_id 0x0110
#define keyspan_usa28xa_product_id 0x0115
-#define keyspan_usa28xb_product_id 0x0110
#define keyspan_usa49w_product_id 0x010a
#define keyspan_usa49wlc_product_id 0x012a
@@ -511,7 +510,6 @@ static struct usb_device_id keyspan_ids_combined[] = {
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) },
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) },
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) },
- { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_product_id) },
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id)},
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_product_id)},
{ } /* Terminating entry */
@@ -559,7 +557,6 @@ static struct usb_device_id keyspan_2port_ids[] = {
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) },
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) },
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) },
- { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_product_id) },
{ } /* Terminating entry */
};
@@ -576,6 +573,7 @@ static struct usb_serial_driver keyspan_pre_device = {
.name = "keyspan_no_firm",
},
.description = "Keyspan - (without firmware)",
+ .usb_driver = &keyspan_driver,
.id_table = keyspan_pre_ids,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
@@ -590,6 +588,7 @@ static struct usb_serial_driver keyspan_1port_device = {
.name = "keyspan_1",
},
.description = "Keyspan 1 port adapter",
+ .usb_driver = &keyspan_driver,
.id_table = keyspan_1port_ids,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
@@ -617,6 +616,7 @@ static struct usb_serial_driver keyspan_2port_device = {
.name = "keyspan_2",
},
.description = "Keyspan 2 port adapter",
+ .usb_driver = &keyspan_driver,
.id_table = keyspan_2port_ids,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
@@ -644,6 +644,7 @@ static struct usb_serial_driver keyspan_4port_device = {
.name = "keyspan_4",
},
.description = "Keyspan 4 port adapter",
+ .usb_driver = &keyspan_driver,
.id_table = keyspan_4port_ids,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = 5,
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index 126b9703bba..da514cb785b 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -793,6 +793,7 @@ static struct usb_serial_driver keyspan_pda_fake_device = {
.name = "keyspan_pda_pre",
},
.description = "Keyspan PDA - (prerenumeration)",
+ .usb_driver = &keyspan_pda_driver,
.id_table = id_table_fake,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
@@ -809,6 +810,7 @@ static struct usb_serial_driver xircom_pgs_fake_device = {
.name = "xircom_no_firm",
},
.description = "Xircom / Entregra PGS - (prerenumeration)",
+ .usb_driver = &keyspan_pda_driver,
.id_table = id_table_fake_xircom,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
@@ -824,6 +826,7 @@ static struct usb_serial_driver keyspan_pda_device = {
.name = "keyspan_pda",
},
.description = "Keyspan PDA",
+ .usb_driver = &keyspan_pda_driver,
.id_table = id_table_std,
.num_interrupt_in = 1,
.num_bulk_in = 0,
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index 5c4b06a99ac..b2097c45a23 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -124,6 +124,7 @@ static struct usb_serial_driver kl5kusb105d_device = {
.name = "kl5kusb105d",
},
.description = "KL5KUSB105D / PalmConnect",
+ .usb_driver = &kl5kusb105d_driver,
.id_table = id_table,
.num_interrupt_in = 1,
.num_bulk_in = 1,
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index 62bea0c923b..0683b51f093 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -110,6 +110,7 @@ static struct usb_serial_driver kobil_device = {
.name = "kobil",
},
.description = "KOBIL USB smart card terminal",
+ .usb_driver = &kobil_driver,
.id_table = id_table,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = 0,
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index 38b1d17e06e..4cd839b1407 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -137,6 +137,7 @@ static struct usb_serial_driver mct_u232_device = {
.name = "mct_u232",
},
.description = "MCT U232",
+ .usb_driver = &mct_u232_driver,
.id_table = id_table_combined,
.num_interrupt_in = 2,
.num_bulk_in = 0,
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index e55f4ed81d7..6109c6704a7 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -1605,12 +1605,21 @@ static void mos7720_shutdown(struct usb_serial *serial)
usb_set_serial_data(serial, NULL);
}
+static struct usb_driver usb_driver = {
+ .name = "moschip7720",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = moschip_port_id_table,
+ .no_dynamic_id = 1,
+};
+
static struct usb_serial_driver moschip7720_2port_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "moschip7720",
},
.description = "Moschip 2 port adapter",
+ .usb_driver = &usb_driver,
.id_table = moschip_port_id_table,
.num_interrupt_in = 1,
.num_bulk_in = 2,
@@ -1631,13 +1640,6 @@ static struct usb_serial_driver moschip7720_2port_driver = {
.read_bulk_callback = mos7720_bulk_in_callback,
};
-static struct usb_driver usb_driver = {
- .name = "moschip7720",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = moschip_port_id_table,
-};
-
static int __init moschip7720_init(void)
{
int retval;
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 83f661403ba..b2264a87617 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -2834,12 +2834,21 @@ static void mos7840_shutdown(struct usb_serial *serial)
}
+static struct usb_driver io_driver = {
+ .name = "mos7840",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = moschip_id_table_combined,
+ .no_dynamic_id = 1,
+};
+
static struct usb_serial_driver moschip7840_4port_device = {
.driver = {
.owner = THIS_MODULE,
.name = "mos7840",
},
.description = DRIVER_DESC,
+ .usb_driver = &io_driver,
.id_table = moschip_port_id_table,
.num_interrupt_in = 1, //NUM_DONT_CARE,//1,
#ifdef check
@@ -2869,13 +2878,6 @@ static struct usb_serial_driver moschip7840_4port_device = {
.read_int_callback = mos7840_interrupt_callback,
};
-static struct usb_driver io_driver = {
- .name = "mos7840",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = moschip_id_table_combined,
-};
-
/****************************************************************************
* moschip7840_init
* This is called by the module subsystem, or on startup to initialize us
diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c
index 054abee8165..90701111d74 100644
--- a/drivers/usb/serial/navman.c
+++ b/drivers/usb/serial/navman.c
@@ -119,6 +119,7 @@ static struct usb_serial_driver navman_device = {
.name = "navman",
},
.id_table = id_table,
+ .usb_driver = &navman_driver,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
.num_bulk_out = NUM_DONT_CARE,
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index bc91d3b726f..0216ac12a27 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -93,6 +93,7 @@ static struct usb_serial_driver zyxel_omninet_device = {
.name = "omninet",
},
.description = "ZyXEL - omni.net lcd plus usb",
+ .usb_driver = &omninet_driver,
.id_table = id_table,
.num_interrupt_in = 1,
.num_bulk_in = 1,
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 0fed43a9687..ced9f32b29d 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -135,6 +135,7 @@ static struct usb_serial_driver option_1port_device = {
.name = "option1",
},
.description = "GSM modem (1-port)",
+ .usb_driver = &option_driver,
.id_table = option_ids1,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 5dc2ac9afa9..6c083d4e2c9 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -1118,6 +1118,7 @@ static struct usb_serial_driver pl2303_device = {
.name = "pl2303",
},
.id_table = id_table,
+ .usb_driver = &pl2303_driver,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = 1,
.num_bulk_out = 1,
diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
index 30b7ebc8d45..5a03a3fc938 100644
--- a/drivers/usb/serial/safe_serial.c
+++ b/drivers/usb/serial/safe_serial.c
@@ -402,6 +402,7 @@ static struct usb_serial_driver safe_device = {
.name = "safe_serial",
},
.id_table = id_table,
+ .usb_driver = &safe_driver,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
.num_bulk_out = NUM_DONT_CARE,
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index 6d8e91e00ec..ecedd833818 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -13,10 +13,9 @@
Portions based on the option driver by Matthias Urlichs <smurf@smurf.noris.de>
Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org>
- History:
*/
-#define DRIVER_VERSION "v.1.0.5"
+#define DRIVER_VERSION "v.1.0.6"
#define DRIVER_AUTHOR "Kevin Lloyd <linux@sierrawireless.com>"
#define DRIVER_DESC "USB Driver for Sierra Wireless USB modems"
@@ -31,14 +30,15 @@
static struct usb_device_id id_table [] = {
+ { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
{ USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
+ { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
{ USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
- { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
{ USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
- { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
+ { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */
{ USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
+ { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */
{ USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
- { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 for Europe */
{ USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */
{ USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
@@ -55,14 +55,15 @@ static struct usb_device_id id_table_1port [] = {
};
static struct usb_device_id id_table_3port [] = {
+ { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
{ USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
+ { USB_DEVICE(0x1199, 0x0218) }, /* 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, 0x0218) }, /* Sierra Wireless MC5720 */
+ { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */
{ USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
+ { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */
{ USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
- { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 for Europe */
{ USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */
{ USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
{ }
@@ -81,7 +82,7 @@ static int debug;
/* per port private data */
#define N_IN_URB 4
-#define N_OUT_URB 1
+#define N_OUT_URB 4
#define IN_BUFLEN 4096
#define OUT_BUFLEN 128
@@ -396,6 +397,8 @@ static int sierra_open(struct usb_serial_port *port, struct file *filp)
struct usb_serial *serial = port->serial;
int i, err;
struct urb *urb;
+ int result;
+ __u16 set_mode_dzero = 0x0000;
portdata = usb_get_serial_port_data(port);
@@ -442,6 +445,12 @@ static int sierra_open(struct usb_serial_port *port, struct file *filp)
port->tty->low_latency = 1;
+ /* set mode to D0 */
+ result = usb_control_msg(serial->dev,
+ usb_rcvctrlpipe(serial->dev, 0),
+ 0x00, 0x40, set_mode_dzero, 0, NULL,
+ 0, USB_CTRL_SET_TIMEOUT);
+
sierra_send_setup(port);
return (0);
@@ -614,6 +623,7 @@ static struct usb_serial_driver sierra_1port_device = {
},
.description = "Sierra USB modem (1 port)",
.id_table = id_table_1port,
+ .usb_driver = &sierra_driver,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = 1,
.num_bulk_out = 1,
@@ -642,6 +652,7 @@ static struct usb_serial_driver sierra_3port_device = {
},
.description = "Sierra USB modem (3 port)",
.id_table = id_table_3port,
+ .usb_driver = &sierra_driver,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = 3,
.num_bulk_out = 3,
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index 83189005c6f..4203e2b1a76 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -262,6 +262,7 @@ static struct usb_serial_driver ti_1port_device = {
.name = "ti_usb_3410_5052_1",
},
.description = "TI USB 3410 1 port adapter",
+ .usb_driver = &ti_usb_driver,
.id_table = ti_id_table_3410,
.num_interrupt_in = 1,
.num_bulk_in = 1,
@@ -292,6 +293,7 @@ static struct usb_serial_driver ti_2port_device = {
.name = "ti_usb_3410_5052_2",
},
.description = "TI USB 5052 2 port adapter",
+ .usb_driver = &ti_usb_driver,
.id_table = ti_id_table_5052,
.num_interrupt_in = 1,
.num_bulk_in = 2,
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 716f6806cc8..6bf22a28adb 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -59,14 +59,19 @@ static struct usb_driver usb_serial_driver = {
static int debug;
static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */
+static spinlock_t table_lock;
static LIST_HEAD(usb_serial_driver_list);
struct usb_serial *usb_serial_get_by_index(unsigned index)
{
- struct usb_serial *serial = serial_table[index];
+ struct usb_serial *serial;
+
+ spin_lock(&table_lock);
+ serial = serial_table[index];
if (serial)
kref_get(&serial->kref);
+ spin_unlock(&table_lock);
return serial;
}
@@ -78,6 +83,7 @@ static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_po
dbg("%s %d", __FUNCTION__, num_ports);
*minor = 0;
+ spin_lock(&table_lock);
for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
if (serial_table[i])
continue;
@@ -96,8 +102,10 @@ static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_po
dbg("%s - minor base = %d", __FUNCTION__, *minor);
for (i = *minor; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i)
serial_table[i] = serial;
+ spin_unlock(&table_lock);
return serial;
}
+ spin_unlock(&table_lock);
return NULL;
}
@@ -110,9 +118,11 @@ static void return_serial(struct usb_serial *serial)
if (serial == NULL)
return;
+ spin_lock(&table_lock);
for (i = 0; i < serial->num_ports; ++i) {
serial_table[serial->minor + i] = NULL;
}
+ spin_unlock(&table_lock);
}
static void destroy_serial(struct kref *kref)
@@ -271,7 +281,7 @@ static void serial_close(struct tty_struct *tty, struct file * filp)
static int serial_write (struct tty_struct * tty, const unsigned char *buf, int count)
{
struct usb_serial_port *port = tty->driver_data;
- int retval = -EINVAL;
+ int retval = -ENODEV;
if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED)
goto exit;
@@ -279,6 +289,7 @@ static int serial_write (struct tty_struct * tty, const unsigned char *buf, int
dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count);
if (!port->open_count) {
+ retval = -EINVAL;
dbg("%s - port not opened", __FUNCTION__);
goto exit;
}
@@ -559,15 +570,20 @@ static void port_release(struct device *dev)
port_free(port);
}
-static void port_free(struct usb_serial_port *port)
+static void kill_traffic(struct usb_serial_port *port)
{
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);
+}
+
+static void port_free(struct usb_serial_port *port)
+{
+ kill_traffic(port);
+ usb_free_urb(port->read_urb);
+ usb_free_urb(port->write_urb);
+ usb_free_urb(port->interrupt_in_urb);
usb_free_urb(port->interrupt_out_urb);
kfree(port->bulk_in_buffer);
kfree(port->bulk_out_buffer);
@@ -596,6 +612,39 @@ static struct usb_serial * create_serial (struct usb_device *dev,
return serial;
}
+static const struct usb_device_id *match_dynamic_id(struct usb_interface *intf,
+ struct usb_serial_driver *drv)
+{
+ struct usb_dynid *dynid;
+
+ spin_lock(&drv->dynids.lock);
+ list_for_each_entry(dynid, &drv->dynids.list, node) {
+ if (usb_match_one_id(intf, &dynid->id)) {
+ spin_unlock(&drv->dynids.lock);
+ return &dynid->id;
+ }
+ }
+ spin_unlock(&drv->dynids.lock);
+ return NULL;
+}
+
+static const struct usb_device_id *get_iface_id(struct usb_serial_driver *drv,
+ struct usb_interface *intf)
+{
+ const struct usb_device_id *id;
+
+ id = usb_match_id(intf, drv->id_table);
+ if (id) {
+ dbg("static descriptor matches");
+ goto exit;
+ }
+ id = match_dynamic_id(intf, drv);
+ if (id)
+ dbg("dynamic descriptor matches");
+exit:
+ return id;
+}
+
static struct usb_serial_driver *search_serial_device(struct usb_interface *iface)
{
struct list_head *p;
@@ -605,11 +654,9 @@ static struct usb_serial_driver *search_serial_device(struct usb_interface *ifac
/* Check if the usb id matches a known device */
list_for_each(p, &usb_serial_driver_list) {
t = list_entry(p, struct usb_serial_driver, driver_list);
- id = usb_match_id(iface, t->id_table);
- if (id != NULL) {
- dbg("descriptor matches");
+ id = get_iface_id(t, iface);
+ if (id)
return t;
- }
}
return NULL;
@@ -639,14 +686,17 @@ int usb_serial_probe(struct usb_interface *interface,
int num_ports = 0;
int max_endpoints;
+ lock_kernel(); /* guard against unloading a serial driver module */
type = search_serial_device(interface);
if (!type) {
+ unlock_kernel();
dbg("none matched");
return -ENODEV;
}
serial = create_serial (dev, interface, type);
if (!serial) {
+ unlock_kernel();
dev_err(&interface->dev, "%s - out of memory\n", __FUNCTION__);
return -ENOMEM;
}
@@ -656,16 +706,18 @@ int usb_serial_probe(struct usb_interface *interface,
const struct usb_device_id *id;
if (!try_module_get(type->driver.owner)) {
+ unlock_kernel();
dev_err(&interface->dev, "module get failed, exiting\n");
kfree (serial);
return -EIO;
}
- id = usb_match_id(interface, type->id_table);
+ id = get_iface_id(type, interface);
retval = type->probe(serial, id);
module_put(type->driver.owner);
if (retval) {
+ unlock_kernel();
dbg ("sub driver rejected device");
kfree (serial);
return retval;
@@ -735,6 +787,7 @@ int usb_serial_probe(struct usb_interface *interface,
* properly during a later invocation of usb_serial_probe
*/
if (num_bulk_in == 0 || num_bulk_out == 0) {
+ unlock_kernel();
dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n");
kfree (serial);
return -ENODEV;
@@ -750,6 +803,7 @@ int usb_serial_probe(struct usb_interface *interface,
if (type == &usb_serial_generic_device) {
num_ports = num_bulk_out;
if (num_ports == 0) {
+ unlock_kernel();
dev_err(&interface->dev, "Generic device with no bulk out, not allowed.\n");
kfree (serial);
return -EIO;
@@ -760,6 +814,7 @@ int usb_serial_probe(struct usb_interface *interface,
/* if this device type has a calc_num_ports function, call it */
if (type->calc_num_ports) {
if (!try_module_get(type->driver.owner)) {
+ unlock_kernel();
dev_err(&interface->dev, "module get failed, exiting\n");
kfree (serial);
return -EIO;
@@ -771,12 +826,6 @@ int usb_serial_probe(struct usb_interface *interface,
num_ports = type->num_ports;
}
- if (get_free_serial (serial, num_ports, &minor) == NULL) {
- dev_err(&interface->dev, "No more free serial devices\n");
- kfree (serial);
- return -ENOMEM;
- }
-
serial->minor = minor;
serial->num_ports = num_ports;
serial->num_bulk_in = num_bulk_in;
@@ -791,6 +840,8 @@ int usb_serial_probe(struct usb_interface *interface,
max_endpoints = max(max_endpoints, num_interrupt_out);
max_endpoints = max(max_endpoints, (int)serial->num_ports);
serial->num_port_pointers = max_endpoints;
+ unlock_kernel();
+
dbg("%s - setting up %d port structures for this device", __FUNCTION__, max_endpoints);
for (i = 0; i < max_endpoints; ++i) {
port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
@@ -925,6 +976,11 @@ int usb_serial_probe(struct usb_interface *interface,
}
}
+ if (get_free_serial (serial, num_ports, &minor) == NULL) {
+ dev_err(&interface->dev, "No more free serial devices\n");
+ goto probe_error;
+ }
+
/* register all of the individual ports with the driver core */
for (i = 0; i < num_ports; ++i) {
port = serial->port[i];
@@ -1002,8 +1058,11 @@ void usb_serial_disconnect(struct usb_interface *interface)
if (serial) {
for (i = 0; i < serial->num_ports; ++i) {
port = serial->port[i];
- if (port && port->tty)
- tty_hangup(port->tty);
+ if (port) {
+ if (port->tty)
+ tty_hangup(port->tty);
+ kill_traffic(port);
+ }
}
/* let the last holder of this object
* cause it to be cleaned up */
@@ -1040,6 +1099,7 @@ static int __init usb_serial_init(void)
return -ENOMEM;
/* Initialize our global data */
+ spin_lock_init(&table_lock);
for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
serial_table[i] = NULL;
}
@@ -1138,7 +1198,7 @@ static void fixup_generic(struct usb_serial_driver *device)
set_to_generic_if_null(device, shutdown);
}
-int usb_serial_register(struct usb_serial_driver *driver)
+int usb_serial_register(struct usb_serial_driver *driver) /* must be called with BKL held */
{
int retval;
@@ -1162,7 +1222,7 @@ int usb_serial_register(struct usb_serial_driver *driver)
}
-void usb_serial_deregister(struct usb_serial_driver *device)
+void usb_serial_deregister(struct usb_serial_driver *device) /* must be called with BKL held */
{
info("USB Serial deregistering driver %s", device->description);
list_del(&device->driver_list);
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index b09f0609605..2f59ff226e2 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -90,8 +90,6 @@ static struct usb_device_id id_table [] = {
.driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID),
.driver_info = (kernel_ulong_t)&palm_os_4_probe },
- { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE31_ID),
- .driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID),
.driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID),
@@ -151,7 +149,6 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_T_ID) },
{ USB_DEVICE(PALM_VENDOR_ID, PALM_TREO_650) },
{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID) },
- { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE31_ID) },
{ USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID) },
{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) },
{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) },
@@ -189,6 +186,7 @@ static struct usb_serial_driver handspring_device = {
.name = "visor",
},
.description = "Handspring Visor / Palm OS",
+ .usb_driver = &visor_driver,
.id_table = id_table,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = 2,
@@ -219,6 +217,7 @@ static struct usb_serial_driver clie_5_device = {
.name = "clie_5",
},
.description = "Sony Clie 5.0",
+ .usb_driver = &visor_driver,
.id_table = clie_id_5_table,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = 2,
@@ -249,6 +248,7 @@ static struct usb_serial_driver clie_3_5_device = {
.name = "clie_3.5",
},
.description = "Sony Clie 3.5",
+ .usb_driver = &visor_driver,
.id_table = clie_id_3_5_table,
.num_interrupt_in = 0,
.num_bulk_in = 1,
diff --git a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h
index 765118d83fb..4ce6f62a6f3 100644
--- a/drivers/usb/serial/visor.h
+++ b/drivers/usb/serial/visor.h
@@ -32,7 +32,6 @@
#define PALM_TUNGSTEN_T_ID 0x0060
#define PALM_TREO_650 0x0061
#define PALM_TUNGSTEN_Z_ID 0x0031
-#define PALM_ZIRE31_ID 0x0061
#define PALM_ZIRE_ID 0x0070
#define PALM_M100_ID 0x0080
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index 5483d8564c1..bf16e9e1d84 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -161,6 +161,7 @@ static struct usb_serial_driver whiteheat_fake_device = {
.name = "whiteheatnofirm",
},
.description = "Connect Tech - WhiteHEAT - (prerenumeration)",
+ .usb_driver = &whiteheat_driver,
.id_table = id_table_prerenumeration,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
@@ -176,6 +177,7 @@ static struct usb_serial_driver whiteheat_device = {
.name = "whiteheat",
},
.description = "Connect Tech - WhiteHEAT",
+ .usb_driver = &whiteheat_driver,
.id_table = id_table_std,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c
index e565d3d2ab2..6d3dad3d1da 100644
--- a/drivers/usb/storage/onetouch.c
+++ b/drivers/usb/storage/onetouch.c
@@ -33,7 +33,6 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
-#include <linux/usb_ch9.h>
#include <linux/usb/input.h>
#include "usb.h"
#include "onetouch.h"
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index e1072d52d64..70234f5dbee 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -110,23 +110,6 @@ static int slave_configure(struct scsi_device *sdev)
* the end, scatter-gather buffers follow page boundaries. */
blk_queue_dma_alignment(sdev->request_queue, (512 - 1));
- /* Set the SCSI level to at least 2. We'll leave it at 3 if that's
- * what is originally reported. We need this to avoid confusing
- * the SCSI layer with devices that report 0 or 1, but need 10-byte
- * commands (ala ATAPI devices behind certain bridges, or devices
- * which simply have broken INQUIRY data).
- *
- * NOTE: This means /dev/sg programs (ala cdrecord) will get the
- * actual information. This seems to be the preference for
- * programs like that.
- *
- * NOTE: This also means that /proc/scsi/scsi and sysfs may report
- * the actual value or the modified one, depending on where the
- * data comes from.
- */
- if (sdev->scsi_level < SCSI_2)
- sdev->scsi_level = sdev->sdev_target->scsi_level = SCSI_2;
-
/* 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).
@@ -176,7 +159,9 @@ static int slave_configure(struct scsi_device *sdev)
* a Get-Max-LUN request, we won't lose much by setting the
* revision level down to 2. The only devices that would be
* affected are those with sparse LUNs. */
- sdev->scsi_level = sdev->sdev_target->scsi_level = SCSI_2;
+ if (sdev->scsi_level > SCSI_2)
+ sdev->sdev_target->scsi_level =
+ sdev->scsi_level = SCSI_2;
/* USB-IDE bridges tend to report SK = 0x04 (Non-recoverable
* Hardware Error) when any low-level error occurs,
@@ -194,6 +179,16 @@ static int slave_configure(struct scsi_device *sdev)
sdev->use_10_for_ms = 1;
}
+ /* The CB and CBI transports have no way to pass LUN values
+ * other than the bits in the second byte of a CDB. But those
+ * bits don't get set to the LUN value if the device reports
+ * scsi_level == 0 (UNKNOWN). Hence such devices must necessarily
+ * be single-LUN.
+ */
+ if ((us->protocol == US_PR_CB || us->protocol == US_PR_CBI) &&
+ sdev->scsi_level == SCSI_UNKNOWN)
+ us->max_lun = 0;
+
/* Some devices choke when they receive a PREVENT-ALLOW MEDIUM
* REMOVAL command, so suppress those commands. */
if (us->flags & US_FL_NOT_LOCKABLE)
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index b49f2a78189..f49a62fc32d 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -573,7 +573,7 @@ UNUSUAL_DEV( 0x054c, 0x002b, 0x0100, 0x0110,
#endif
/* Submitted by Olaf Hering, <olh@suse.de> SuSE Bugzilla #49049 */
-UNUSUAL_DEV( 0x054c, 0x002c, 0x0501, 0x0501,
+UNUSUAL_DEV( 0x054c, 0x002c, 0x0501, 0x2000,
"Sony",
"USB Floppy Drive",
US_SC_DEVICE, US_PR_DEVICE, NULL,
@@ -1325,13 +1325,6 @@ UNUSUAL_DEV( 0x0fce, 0xe031, 0x0000, 0x0000,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_CAPACITY ),
-/* Reported by Jan Mate <mate@fiit.stuba.sk> */
-UNUSUAL_DEV( 0x0fce, 0xe030, 0x0000, 0x0000,
- "Sony Ericsson",
- "P990i",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_CAPACITY ),
-
/* Reported by Kevin Cernekee <kpc-usbdev@gelato.uiuc.edu>
* Tested on hardware version 1.10.
* Entry is needed only for the initializer function override.
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 70644506651..7e7ec29782f 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -731,26 +731,27 @@ static int get_pipes(struct us_data *us)
struct usb_endpoint_descriptor *ep_int = NULL;
/*
- * Find the endpoints we need.
+ * Find the first endpoint of each type we need.
* We are expecting a minimum of 2 endpoints - in and out (bulk).
- * An optional interrupt is OK (necessary for CBI protocol).
+ * An optional interrupt-in is OK (necessary for CBI protocol).
* We will ignore any others.
*/
for (i = 0; i < altsetting->desc.bNumEndpoints; i++) {
ep = &altsetting->endpoint[i].desc;
- /* Is it a BULK endpoint? */
if (usb_endpoint_xfer_bulk(ep)) {
- /* BULK in or out? */
- if (usb_endpoint_dir_in(ep))
- ep_in = ep;
- else
- ep_out = ep;
+ if (usb_endpoint_dir_in(ep)) {
+ if (!ep_in)
+ ep_in = ep;
+ } else {
+ if (!ep_out)
+ ep_out = ep;
+ }
}
- /* Is it an interrupt endpoint? */
- else if (usb_endpoint_xfer_int(ep)) {
- ep_int = ep;
+ else if (usb_endpoint_is_int_in(ep)) {
+ if (!ep_int)
+ ep_int = ep;
}
}
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 4e83f01e894..45fe65d8d7a 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1444,8 +1444,8 @@ config FB_PMAG_AA
used mainly in the MIPS-based DECstation series.
config FB_PMAG_BA
- bool "PMAG-BA TURBOchannel framebuffer support"
- depends on (FB = y) && TC
+ tristate "PMAG-BA TURBOchannel framebuffer support"
+ depends on FB && TC
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -1454,8 +1454,8 @@ config FB_PMAG_BA
used mainly in the MIPS-based DECstation series.
config FB_PMAGB_B
- bool "PMAGB-B TURBOchannel framebuffer support"
- depends on (FB = y) && TC
+ tristate "PMAGB-B TURBOchannel framebuffer support"
+ depends on TC
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
diff --git a/drivers/video/output.c b/drivers/video/output.c
new file mode 100644
index 00000000000..1473f2c892d
--- /dev/null
+++ b/drivers/video/output.c
@@ -0,0 +1,129 @@
+/*
+ * output.c - Display Output Switch driver
+ *
+ * Copyright (C) 2006 Luming Yu <luming.yu@intel.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <linux/module.h>
+#include <linux/video_output.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+
+
+MODULE_DESCRIPTION("Display Output Switcher Lowlevel Control Abstraction");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Luming Yu <luming.yu@intel.com>");
+
+static ssize_t video_output_show_state(struct class_device *dev,char *buf)
+{
+ ssize_t ret_size = 0;
+ struct output_device *od = to_output_device(dev);
+ if (od->props)
+ ret_size = sprintf(buf,"%.8x\n",od->props->get_status(od));
+ return ret_size;
+}
+
+static ssize_t video_output_store_state(struct class_device *dev,
+ const char *buf,size_t count)
+{
+ char *endp;
+ struct output_device *od = to_output_device(dev);
+ int request_state = simple_strtoul(buf,&endp,0);
+ size_t size = endp - buf;
+
+ if (*endp && isspace(*endp))
+ size++;
+ if (size != count)
+ return -EINVAL;
+
+ if (od->props) {
+ od->request_state = request_state;
+ od->props->set_state(od);
+ }
+ return count;
+}
+
+static void video_output_class_release(struct class_device *dev)
+{
+ struct output_device *od = to_output_device(dev);
+ kfree(od);
+}
+
+static struct class_device_attribute video_output_attributes[] = {
+ __ATTR(state, 0644, video_output_show_state, video_output_store_state),
+ __ATTR_NULL,
+};
+
+static struct class video_output_class = {
+ .name = "video_output",
+ .release = video_output_class_release,
+ .class_dev_attrs = video_output_attributes,
+};
+
+struct output_device *video_output_register(const char *name,
+ struct device *dev,
+ void *devdata,
+ struct output_properties *op)
+{
+ struct output_device *new_dev;
+ int ret_code = 0;
+
+ new_dev = kzalloc(sizeof(struct output_device),GFP_KERNEL);
+ if (!new_dev) {
+ ret_code = -ENOMEM;
+ goto error_return;
+ }
+ new_dev->props = op;
+ new_dev->class_dev.class = &video_output_class;
+ new_dev->class_dev.dev = dev;
+ strlcpy(new_dev->class_dev.class_id,name,KOBJ_NAME_LEN);
+ class_set_devdata(&new_dev->class_dev,devdata);
+ ret_code = class_device_register(&new_dev->class_dev);
+ if (ret_code) {
+ kfree(new_dev);
+ goto error_return;
+ }
+ return new_dev;
+
+error_return:
+ return ERR_PTR(ret_code);
+}
+EXPORT_SYMBOL(video_output_register);
+
+void video_output_unregister(struct output_device *dev)
+{
+ if (!dev)
+ return;
+ class_device_unregister(&dev->class_dev);
+}
+EXPORT_SYMBOL(video_output_unregister);
+
+static void __exit video_output_class_exit(void)
+{
+ class_unregister(&video_output_class);
+}
+
+static int __init video_output_class_init(void)
+{
+ return class_register(&video_output_class);
+}
+
+postcore_initcall(video_output_class_init);
+module_exit(video_output_class_exit);
diff --git a/drivers/video/pmag-ba-fb.c b/drivers/video/pmag-ba-fb.c
index f5361cd8ccc..264d37243fa 100644
--- a/drivers/video/pmag-ba-fb.c
+++ b/drivers/video/pmag-ba-fb.c
@@ -15,7 +15,8 @@
* Michael Engel <engel@unix-ag.org>,
* Karsten Merker <merker@linuxtag.org> and
* Harald Koerfgen.
- * Copyright (c) 2005 Maciej W. Rozycki
+ * Copyright (c) 2005, 2006 Maciej W. Rozycki
+ * Copyright (c) 2005 James Simmons
*
* 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
@@ -28,26 +29,21 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/tc.h>
#include <linux/types.h>
#include <asm/io.h>
#include <asm/system.h>
-#include <asm/dec/tc.h>
-
#include <video/pmag-ba-fb.h>
struct pmagbafb_par {
- struct fb_info *next;
volatile void __iomem *mmio;
volatile u32 __iomem *dac;
- int slot;
};
-static struct fb_info *root_pmagbafb_dev;
-
static struct fb_var_screeninfo pmagbafb_defined __initdata = {
.xres = 1024,
.yres = 864,
@@ -145,24 +141,19 @@ static void __init pmagbafb_erase_cursor(struct fb_info *info)
}
-static int __init pmagbafb_init_one(int slot)
+static int __init pmagbafb_probe(struct device *dev)
{
+ struct tc_dev *tdev = to_tc_dev(dev);
+ resource_size_t start, len;
struct fb_info *info;
struct pmagbafb_par *par;
- unsigned long base_addr;
- info = framebuffer_alloc(sizeof(struct pmagbafb_par), NULL);
+ info = framebuffer_alloc(sizeof(struct pmagbafb_par), dev);
if (!info)
return -ENOMEM;
par = info->par;
- par->slot = slot;
- claim_tc_card(par->slot);
-
- base_addr = get_tc_base_addr(par->slot);
-
- par->next = root_pmagbafb_dev;
- root_pmagbafb_dev = info;
+ dev_set_drvdata(dev, info);
if (fb_alloc_cmap(&info->cmap, 256, 0) < 0)
goto err_alloc;
@@ -172,15 +163,21 @@ static int __init pmagbafb_init_one(int slot)
info->var = pmagbafb_defined;
info->flags = FBINFO_DEFAULT;
+ /* Request the I/O MEM resource. */
+ start = tdev->resource.start;
+ len = tdev->resource.end - start + 1;
+ if (!request_mem_region(start, len, dev->bus_id))
+ goto err_cmap;
+
/* MMIO mapping setup. */
- info->fix.mmio_start = base_addr;
+ info->fix.mmio_start = start;
par->mmio = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
if (!par->mmio)
- goto err_cmap;
+ goto err_resource;
par->dac = par->mmio + PMAG_BA_BT459;
/* Frame buffer mapping setup. */
- info->fix.smem_start = base_addr + PMAG_BA_FBMEM;
+ info->fix.smem_start = start + PMAG_BA_FBMEM;
info->screen_base = ioremap_nocache(info->fix.smem_start,
info->fix.smem_len);
if (!info->screen_base)
@@ -192,8 +189,10 @@ static int __init pmagbafb_init_one(int slot)
if (register_framebuffer(info) < 0)
goto err_smem_map;
- pr_info("fb%d: %s frame buffer device in slot %d\n",
- info->node, info->fix.id, par->slot);
+ get_device(dev);
+
+ pr_info("fb%d: %s frame buffer device at %s\n",
+ info->node, info->fix.id, dev->bus_id);
return 0;
@@ -204,54 +203,68 @@ err_smem_map:
err_mmio_map:
iounmap(par->mmio);
+err_resource:
+ release_mem_region(start, len);
+
err_cmap:
fb_dealloc_cmap(&info->cmap);
err_alloc:
- root_pmagbafb_dev = par->next;
- release_tc_card(par->slot);
framebuffer_release(info);
return -ENXIO;
}
-static void __exit pmagbafb_exit_one(void)
+static int __exit pmagbafb_remove(struct device *dev)
{
- struct fb_info *info = root_pmagbafb_dev;
+ struct tc_dev *tdev = to_tc_dev(dev);
+ struct fb_info *info = dev_get_drvdata(dev);
struct pmagbafb_par *par = info->par;
+ resource_size_t start, len;
+ put_device(dev);
unregister_framebuffer(info);
iounmap(info->screen_base);
iounmap(par->mmio);
+ start = tdev->resource.start;
+ len = tdev->resource.end - start + 1;
+ release_mem_region(start, len);
fb_dealloc_cmap(&info->cmap);
- root_pmagbafb_dev = par->next;
- release_tc_card(par->slot);
framebuffer_release(info);
+ return 0;
}
/*
- * Initialise the framebuffer.
+ * Initialize the framebuffer.
*/
+static const struct tc_device_id pmagbafb_tc_table[] = {
+ { "DEC ", "PMAG-BA " },
+ { }
+};
+MODULE_DEVICE_TABLE(tc, pmagbafb_tc_table);
+
+static struct tc_driver pmagbafb_driver = {
+ .id_table = pmagbafb_tc_table,
+ .driver = {
+ .name = "pmagbafb",
+ .bus = &tc_bus_type,
+ .probe = pmagbafb_probe,
+ .remove = __exit_p(pmagbafb_remove),
+ },
+};
+
static int __init pmagbafb_init(void)
{
- int count = 0;
- int slot;
-
+#ifndef MODULE
if (fb_get_options("pmagbafb", NULL))
return -ENXIO;
-
- while ((slot = search_tc_card("PMAG-BA")) >= 0) {
- if (pmagbafb_init_one(slot) < 0)
- break;
- count++;
- }
- return (count > 0) ? 0 : -ENXIO;
+#endif
+ return tc_register_driver(&pmagbafb_driver);
}
static void __exit pmagbafb_exit(void)
{
- while (root_pmagbafb_dev)
- pmagbafb_exit_one();
+ tc_unregister_driver(&pmagbafb_driver);
}
diff --git a/drivers/video/pmagb-b-fb.c b/drivers/video/pmagb-b-fb.c
index a06a064ad75..7a0ce7d5af6 100644
--- a/drivers/video/pmagb-b-fb.c
+++ b/drivers/video/pmagb-b-fb.c
@@ -11,7 +11,7 @@
* Michael Engel <engel@unix-ag.org>,
* Karsten Merker <merker@linuxtag.org> and
* Harald Koerfgen.
- * Copyright (c) 2005 Maciej W. Rozycki
+ * Copyright (c) 2005, 2006 Maciej W. Rozycki
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file COPYING in the main directory of this
@@ -25,18 +25,16 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/tc.h>
#include <linux/types.h>
#include <asm/io.h>
#include <asm/system.h>
-#include <asm/dec/tc.h>
-
#include <video/pmagb-b-fb.h>
struct pmagbbfb_par {
- struct fb_info *next;
volatile void __iomem *mmio;
volatile void __iomem *smem;
volatile u32 __iomem *sfb;
@@ -47,8 +45,6 @@ struct pmagbbfb_par {
};
-static struct fb_info *root_pmagbbfb_dev;
-
static struct fb_var_screeninfo pmagbbfb_defined __initdata = {
.bits_per_pixel = 8,
.red.length = 8,
@@ -190,8 +186,9 @@ static void __init pmagbbfb_osc_setup(struct fb_info *info)
69197, 66000, 65000, 50350, 36000, 32000, 25175
};
struct pmagbbfb_par *par = info->par;
+ struct tc_bus *tbus = to_tc_dev(info->device)->bus;
u32 count0 = 8, count1 = 8, counttc = 16 * 256 + 8;
- u32 freq0, freq1, freqtc = get_tc_speed() / 250;
+ u32 freq0, freq1, freqtc = tc_get_speed(tbus) / 250;
int i, j;
gp0_write(par, 0); /* select Osc0 */
@@ -249,26 +246,21 @@ static void __init pmagbbfb_osc_setup(struct fb_info *info)
};
-static int __init pmagbbfb_init_one(int slot)
+static int __init pmagbbfb_probe(struct device *dev)
{
- char freq0[12], freq1[12];
+ struct tc_dev *tdev = to_tc_dev(dev);
+ resource_size_t start, len;
struct fb_info *info;
struct pmagbbfb_par *par;
- unsigned long base_addr;
+ char freq0[12], freq1[12];
u32 vid_base;
- info = framebuffer_alloc(sizeof(struct pmagbbfb_par), NULL);
+ info = framebuffer_alloc(sizeof(struct pmagbbfb_par), dev);
if (!info)
return -ENOMEM;
par = info->par;
- par->slot = slot;
- claim_tc_card(par->slot);
-
- base_addr = get_tc_base_addr(par->slot);
-
- par->next = root_pmagbbfb_dev;
- root_pmagbbfb_dev = info;
+ dev_set_drvdata(dev, info);
if (fb_alloc_cmap(&info->cmap, 256, 0) < 0)
goto err_alloc;
@@ -278,16 +270,22 @@ static int __init pmagbbfb_init_one(int slot)
info->var = pmagbbfb_defined;
info->flags = FBINFO_DEFAULT;
+ /* Request the I/O MEM resource. */
+ start = tdev->resource.start;
+ len = tdev->resource.end - start + 1;
+ if (!request_mem_region(start, len, dev->bus_id))
+ goto err_cmap;
+
/* MMIO mapping setup. */
- info->fix.mmio_start = base_addr;
+ info->fix.mmio_start = start;
par->mmio = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
if (!par->mmio)
- goto err_cmap;
+ goto err_resource;
par->sfb = par->mmio + PMAGB_B_SFB;
par->dac = par->mmio + PMAGB_B_BT459;
/* Frame buffer mapping setup. */
- info->fix.smem_start = base_addr + PMAGB_B_FBMEM;
+ info->fix.smem_start = start + PMAGB_B_FBMEM;
par->smem = ioremap_nocache(info->fix.smem_start, info->fix.smem_len);
if (!par->smem)
goto err_mmio_map;
@@ -302,13 +300,15 @@ static int __init pmagbbfb_init_one(int slot)
if (register_framebuffer(info) < 0)
goto err_smem_map;
+ get_device(dev);
+
snprintf(freq0, sizeof(freq0), "%u.%03uMHz",
par->osc0 / 1000, par->osc0 % 1000);
snprintf(freq1, sizeof(freq1), "%u.%03uMHz",
par->osc1 / 1000, par->osc1 % 1000);
- pr_info("fb%d: %s frame buffer device in slot %d\n",
- info->node, info->fix.id, par->slot);
+ pr_info("fb%d: %s frame buffer device at %s\n",
+ info->node, info->fix.id, dev->bus_id);
pr_info("fb%d: Osc0: %s, Osc1: %s, Osc%u selected\n",
info->node, freq0, par->osc1 ? freq1 : "disabled",
par->osc1 != 0);
@@ -322,54 +322,68 @@ err_smem_map:
err_mmio_map:
iounmap(par->mmio);
+err_resource:
+ release_mem_region(start, len);
+
err_cmap:
fb_dealloc_cmap(&info->cmap);
err_alloc:
- root_pmagbbfb_dev = par->next;
- release_tc_card(par->slot);
framebuffer_release(info);
return -ENXIO;
}
-static void __exit pmagbbfb_exit_one(void)
+static int __exit pmagbbfb_remove(struct device *dev)
{
- struct fb_info *info = root_pmagbbfb_dev;
+ struct tc_dev *tdev = to_tc_dev(dev);
+ struct fb_info *info = dev_get_drvdata(dev);
struct pmagbbfb_par *par = info->par;
+ resource_size_t start, len;
+ put_device(dev);
unregister_framebuffer(info);
iounmap(par->smem);
iounmap(par->mmio);
+ start = tdev->resource.start;
+ len = tdev->resource.end - start + 1;
+ release_mem_region(start, len);
fb_dealloc_cmap(&info->cmap);
- root_pmagbbfb_dev = par->next;
- release_tc_card(par->slot);
framebuffer_release(info);
+ return 0;
}
/*
- * Initialise the framebuffer.
+ * Initialize the framebuffer.
*/
+static const struct tc_device_id pmagbbfb_tc_table[] = {
+ { "DEC ", "PMAGB-BA" },
+ { }
+};
+MODULE_DEVICE_TABLE(tc, pmagbbfb_tc_table);
+
+static struct tc_driver pmagbbfb_driver = {
+ .id_table = pmagbbfb_tc_table,
+ .driver = {
+ .name = "pmagbbfb",
+ .bus = &tc_bus_type,
+ .probe = pmagbbfb_probe,
+ .remove = __exit_p(pmagbbfb_remove),
+ },
+};
+
static int __init pmagbbfb_init(void)
{
- int count = 0;
- int slot;
-
+#ifndef MODULE
if (fb_get_options("pmagbbfb", NULL))
return -ENXIO;
-
- while ((slot = search_tc_card("PMAGB-BA")) >= 0) {
- if (pmagbbfb_init_one(slot) < 0)
- break;
- count++;
- }
- return (count > 0) ? 0 : -ENXIO;
+#endif
+ return tc_register_driver(&pmagbbfb_driver);
}
static void __exit pmagbbfb_exit(void)
{
- while (root_pmagbbfb_dev)
- pmagbbfb_exit_one();
+ tc_unregister_driver(&pmagbbfb_driver);
}