# This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2004/08/14 13:50:37-03:00 zaitcev@redhat.com # [PATCH] David Brownell: Fix uhci-hcd oops # # The attached ought to fix Nick up (no way to tell about Kai because his # report had no data). It consists of two things. First, it fixes the # oops in the scan_async. Second, it prevents the oops from happening by # ignoring the handoff failure (as the old code did, in effect). Either # one should be sufficient, but this is why I use both. The if around # scan_async is the right fix, so it's there on merit. However, it yields # a non-working EHCI if your BIOS is buggy. # TAG: MailDone # # drivers/usb/host/ehci-hcd.c # 2004/07/30 20:21:12-03:00 zaitcev@redhat.com +4 -2 # David Brownell: Fix uhci-hcd oops # # ChangeSet # 2004/08/14 13:48:21-03:00 castor@3pardata.com # [PATCH] Add 3PARdata InServ Virtual Volume to SCSI device list # # This patch adds Sparse LUN and LARGE support for our storage server. # # drivers/scsi/scsi_scan.c # 2004/08/13 16:00:25-03:00 castor@3pardata.com +1 -0 # Add 3PARdata InServ Virtual Volume to SCSI device list # # ChangeSet # 2004/08/14 13:37:29-03:00 sezeroz@ttnet.net.tr # [PATCH] amd76xrom.c unused warning # # # drivers/mtd/maps/amd76xrom.c # 2004/08/07 08:09:39-03:00 sezeroz@ttnet.net.tr +1 -1 # amd76xrom.c unused warning # # ChangeSet # 2004/08/14 13:33:00-03:00 sezeroz@ttnet.net.tr # [PATCH] trivial: various "unused" warnings # # # drivers/video/sstfb.c # 2004/08/07 08:09:39-03:00 sezeroz@ttnet.net.tr +3 -2 # trivial: various "unused" warnings # # drivers/video/riva/fbdev.c # 2004/08/07 08:09:39-03:00 sezeroz@ttnet.net.tr +0 -1 # trivial: various "unused" warnings # # drivers/video/matrox/matroxfb_g450.c # 2004/08/07 08:09:39-03:00 sezeroz@ttnet.net.tr +1 -1 # trivial: various "unused" warnings # # drivers/usb/storage/sddr09.c # 2004/08/07 08:09:39-03:00 sezeroz@ttnet.net.tr +2 -1 # trivial: various "unused" warnings # # ChangeSet # 2004/08/14 13:23:13-03:00 sezeroz@ttnet.net.tr # [PATCH] backport applicom 2.6 fixes # # Leak and copy*user in cli fixes from 2.6 # (by akpm iirc). # # drivers/char/applicom.c # 2004/08/07 09:52:02-03:00 sezeroz@ttnet.net.tr +25 -28 # backport applicom 2.6 fixes # # ChangeSet # 2004/08/14 13:17:07-03:00 sezeroz@ttnet.net.tr # [PATCH] trivial nwflash.c missing -EFAULT retcode # # missing -EFAULT retcode in nwflash.c, from 2.6 # # drivers/char/nwflash.c # 2004/08/07 08:18:04-03:00 sezeroz@ttnet.net.tr +2 -1 # trivial nwflash.c missing -EFAULT retcode # # ChangeSet # 2004/08/14 13:14:08-03:00 sezeroz@ttnet.net.tr # [PATCH] trivial iph5526.c fixes from 2.6 # # unreached code, rx/tx typo, etc. # # drivers/net/fc/iph5526.c # 2004/08/07 08:09:39-03:00 sezeroz@ttnet.net.tr +7 -5 # trivial iph5526.c fixes from 2.6 # # ChangeSet # 2004/08/14 13:04:58-03:00 sezeroz@ttnet.net.tr # [PATCH] warning fixes: befs trivial # # various befs fixes. one is unused xattr code. # the other is unreached code fixed the same way in 2.6. # # fs/befs/linuxvfs.c # 2004/08/07 08:09:39-03:00 sezeroz@ttnet.net.tr +1 -37 # warning fixes: befs trivial # # ChangeSet # 2004/08/14 13:00:10-03:00 sezeroz@ttnet.net.tr # [PATCH] warning fixes: ULL-fixes # # Various ULL modifiers. Also cures compiler warnings. # Most, if not all, are from 2.6. Please apply. # # fs/partitions/ldm.h # 2003/08/20 14:21:47-03:00 sezeroz@ttnet.net.tr +2 -2 # warning fixes: ULL-fixes # # fs/befs/btree.c # 2004/08/07 08:09:39-03:00 sezeroz@ttnet.net.tr +1 -1 # warning fixes: ULL-fixes # # drivers/scsi/qlogicfc.c # 2003/08/18 21:00:37-03:00 sezeroz@ttnet.net.tr +1 -1 # warning fixes: ULL-fixes # # drivers/net/sungem.h # 2003/08/20 05:30:43-03:00 sezeroz@ttnet.net.tr +15 -15 # warning fixes: ULL-fixes # # drivers/net/sungem.c # 2004/08/07 15:08:12-03:00 sezeroz@ttnet.net.tr +1 -1 # warning fixes: ULL-fixes # # drivers/char/agp/agpgart_be.c # 2004/08/07 15:58:49-03:00 sezeroz@ttnet.net.tr +3 -3 # warning fixes: ULL-fixes # # drivers/block/cciss.c # 2004/08/07 15:18:41-03:00 sezeroz@ttnet.net.tr +1 -1 # warning fixes: ULL-fixes # # ChangeSet # 2004/08/14 12:53:03-03:00 marcelo@logos.cnet # Herbert Xu: delete zero sized files from BK repository # # BitKeeper/deleted/.del-Makefile~31e6be7698cbac7 # 2004/08/14 12:52:03-03:00 marcelo@logos.cnet +0 -0 # Delete: drivers/scsi/aic79xx/aicasm/Makefile # # BitKeeper/deleted/.del-aicasm_symbol.h~71000b8c8af4c69 # 2004/08/14 12:52:02-03:00 marcelo@logos.cnet +0 -0 # Delete: drivers/scsi/aic79xx/aicasm/aicasm_symbol.h # # BitKeeper/deleted/.del-aicasm_symbol.c~79e36b1b8b55a240 # 2004/08/14 12:52:02-03:00 marcelo@logos.cnet +0 -0 # Delete: drivers/scsi/aic79xx/aicasm/aicasm_symbol.c # # BitKeeper/deleted/.del-aicasm_scan.l~470977a4781bde28 # 2004/08/14 12:52:02-03:00 marcelo@logos.cnet +0 -0 # Delete: drivers/scsi/aic79xx/aicasm/aicasm_scan.l # # BitKeeper/deleted/.del-aicasm_macro_scan.l~28655286f58e38ce # 2004/08/14 12:52:02-03:00 marcelo@logos.cnet +0 -0 # Delete: drivers/scsi/aic79xx/aicasm/aicasm_macro_scan.l # # BitKeeper/deleted/.del-aicasm_macro_gram.y~caf8a842ab45773a # 2004/08/14 12:52:02-03:00 marcelo@logos.cnet +0 -0 # Delete: drivers/scsi/aic79xx/aicasm/aicasm_macro_gram.y # # BitKeeper/deleted/.del-aicasm_insformat.h~bc2a6f47d84d8cac # 2004/08/14 12:52:02-03:00 marcelo@logos.cnet +0 -0 # Delete: drivers/scsi/aic79xx/aicasm/aicasm_insformat.h # # BitKeeper/deleted/.del-aicasm_gram.y~753aaa8c7df605c5 # 2004/08/14 12:52:02-03:00 marcelo@logos.cnet +0 -0 # Delete: drivers/scsi/aic79xx/aicasm/aicasm_gram.y # # BitKeeper/deleted/.del-aicasm.h~782cd4c68b2aea5a # 2004/08/14 12:52:02-03:00 marcelo@logos.cnet +0 -0 # Delete: drivers/scsi/aic79xx/aicasm/aicasm.h # # BitKeeper/deleted/.del-aicasm.c~ecf6cb765fe62209 # 2004/08/14 12:52:02-03:00 marcelo@logos.cnet +0 -0 # Delete: drivers/scsi/aic79xx/aicasm/aicasm.c # # BitKeeper/deleted/.del-check-gas-for-hint.S~2ff19955c1eac46c # 2004/08/14 12:51:42-03:00 marcelo@logos.cnet +0 -0 # Delete: arch/ia64/scripts/check-gas-for-hint.S # # BitKeeper/deleted/.del-sisfb.txt~fbf4ec412a892367 # 2004/08/14 12:50:35-03:00 marcelo@logos.cnet +0 -0 # Delete: Documentation/fb/sisfb.txt # # ChangeSet # 2004/08/13 20:37:32-04:00 mcgrof@ruslug.rutgers.edu # [wireless] add new prism54 driver # # drivers/net/wireless/Makefile # 2004/08/13 20:37:30-04:00 mcgrof@ruslug.rutgers.edu +5 -0 # [wireless] add new prism54 driver # # drivers/net/wireless/Config.in # 2004/08/13 20:37:30-04:00 mcgrof@ruslug.rutgers.edu +9 -0 # [wireless] add new prism54 driver # # Documentation/Configure.help # 2004/08/13 20:37:30-04:00 mcgrof@ruslug.rutgers.edu +43 -0 # [wireless] add new prism54 driver # # drivers/net/wireless/prism54/Makefile # 2004/08/13 20:36:53-04:00 jgarzik@pobox.com +12 -0 # # drivers/net/wireless/prism54/Makefile # 2004/08/13 20:36:53-04:00 jgarzik@pobox.com +0 -0 # BitKeeper file /spare/repo/net-drivers-2.4/drivers/net/wireless/prism54/Makefile # # drivers/net/wireless/prism54/prismcompat24.h # 2004/08/13 20:36:33-04:00 jgarzik@pobox.com +72 -0 # # drivers/net/wireless/prism54/prismcompat.h # 2004/08/13 20:36:33-04:00 jgarzik@pobox.com +46 -0 # # drivers/net/wireless/prism54/oid_mgt.h # 2004/08/13 20:36:33-04:00 jgarzik@pobox.com +58 -0 # # drivers/net/wireless/prism54/oid_mgt.c # 2004/08/13 20:36:33-04:00 jgarzik@pobox.com +807 -0 # # drivers/net/wireless/prism54/islpci_mgt.h # 2004/08/13 20:36:33-04:00 jgarzik@pobox.com +162 -0 # # drivers/net/wireless/prism54/islpci_mgt.c # 2004/08/13 20:36:33-04:00 jgarzik@pobox.com +510 -0 # # drivers/net/wireless/prism54/islpci_hotplug.c # 2004/08/13 20:36:33-04:00 jgarzik@pobox.com +494 -0 # # drivers/net/wireless/prism54/islpci_eth.h # 2004/08/13 20:36:33-04:00 jgarzik@pobox.com +73 -0 # # drivers/net/wireless/prism54/islpci_eth.c # 2004/08/13 20:36:33-04:00 jgarzik@pobox.com +518 -0 # # drivers/net/wireless/prism54/islpci_dev.h # 2004/08/13 20:36:33-04:00 jgarzik@pobox.com +215 -0 # # drivers/net/wireless/prism54/islpci_dev.c # 2004/08/13 20:36:33-04:00 jgarzik@pobox.com +931 -0 # # drivers/net/wireless/prism54/isl_oid.h # 2004/08/13 20:36:33-04:00 jgarzik@pobox.com +498 -0 # # drivers/net/wireless/prism54/isl_ioctl.h # 2004/08/13 20:36:33-04:00 jgarzik@pobox.com +54 -0 # # drivers/net/wireless/prism54/isl_ioctl.c # 2004/08/13 20:36:33-04:00 jgarzik@pobox.com +2261 -0 # # drivers/net/wireless/prism54/prismcompat24.h # 2004/08/13 20:36:33-04:00 jgarzik@pobox.com +0 -0 # BitKeeper file /spare/repo/net-drivers-2.4/drivers/net/wireless/prism54/prismcompat24.h # # drivers/net/wireless/prism54/prismcompat.h # 2004/08/13 20:36:33-04:00 jgarzik@pobox.com +0 -0 # BitKeeper file /spare/repo/net-drivers-2.4/drivers/net/wireless/prism54/prismcompat.h # # drivers/net/wireless/prism54/oid_mgt.h # 2004/08/13 20:36:33-04:00 jgarzik@pobox.com +0 -0 # BitKeeper file /spare/repo/net-drivers-2.4/drivers/net/wireless/prism54/oid_mgt.h # # drivers/net/wireless/prism54/oid_mgt.c # 2004/08/13 20:36:33-04:00 jgarzik@pobox.com +0 -0 # BitKeeper file /spare/repo/net-drivers-2.4/drivers/net/wireless/prism54/oid_mgt.c # # drivers/net/wireless/prism54/islpci_mgt.h # 2004/08/13 20:36:33-04:00 jgarzik@pobox.com +0 -0 # BitKeeper file /spare/repo/net-drivers-2.4/drivers/net/wireless/prism54/islpci_mgt.h # # drivers/net/wireless/prism54/islpci_mgt.c # 2004/08/13 20:36:33-04:00 jgarzik@pobox.com +0 -0 # BitKeeper file /spare/repo/net-drivers-2.4/drivers/net/wireless/prism54/islpci_mgt.c # # drivers/net/wireless/prism54/islpci_hotplug.c # 2004/08/13 20:36:33-04:00 jgarzik@pobox.com +0 -0 # BitKeeper file /spare/repo/net-drivers-2.4/drivers/net/wireless/prism54/islpci_hotplug.c # # drivers/net/wireless/prism54/islpci_eth.h # 2004/08/13 20:36:33-04:00 jgarzik@pobox.com +0 -0 # BitKeeper file /spare/repo/net-drivers-2.4/drivers/net/wireless/prism54/islpci_eth.h # # drivers/net/wireless/prism54/islpci_eth.c # 2004/08/13 20:36:33-04:00 jgarzik@pobox.com +0 -0 # BitKeeper file /spare/repo/net-drivers-2.4/drivers/net/wireless/prism54/islpci_eth.c # # drivers/net/wireless/prism54/islpci_dev.h # 2004/08/13 20:36:33-04:00 jgarzik@pobox.com +0 -0 # BitKeeper file /spare/repo/net-drivers-2.4/drivers/net/wireless/prism54/islpci_dev.h # # drivers/net/wireless/prism54/islpci_dev.c # 2004/08/13 20:36:33-04:00 jgarzik@pobox.com +0 -0 # BitKeeper file /spare/repo/net-drivers-2.4/drivers/net/wireless/prism54/islpci_dev.c # # drivers/net/wireless/prism54/isl_oid.h # 2004/08/13 20:36:33-04:00 jgarzik@pobox.com +0 -0 # BitKeeper file /spare/repo/net-drivers-2.4/drivers/net/wireless/prism54/isl_oid.h # # drivers/net/wireless/prism54/isl_ioctl.h # 2004/08/13 20:36:33-04:00 jgarzik@pobox.com +0 -0 # BitKeeper file /spare/repo/net-drivers-2.4/drivers/net/wireless/prism54/isl_ioctl.h # # drivers/net/wireless/prism54/isl_ioctl.c # 2004/08/13 20:36:33-04:00 jgarzik@pobox.com +0 -0 # BitKeeper file /spare/repo/net-drivers-2.4/drivers/net/wireless/prism54/isl_ioctl.c # # drivers/net/wireless/prism54/isl_38xx.h # 2004/08/13 20:36:32-04:00 jgarzik@pobox.com +169 -0 # # drivers/net/wireless/prism54/isl_38xx.c # 2004/08/13 20:36:32-04:00 jgarzik@pobox.com +267 -0 # # drivers/net/wireless/prism54/isl_38xx.h # 2004/08/13 20:36:32-04:00 jgarzik@pobox.com +0 -0 # BitKeeper file /spare/repo/net-drivers-2.4/drivers/net/wireless/prism54/isl_38xx.h # # drivers/net/wireless/prism54/isl_38xx.c # 2004/08/13 20:36:32-04:00 jgarzik@pobox.com +0 -0 # BitKeeper file /spare/repo/net-drivers-2.4/drivers/net/wireless/prism54/isl_38xx.c # # ChangeSet # 2004/08/13 11:17:26-03:00 ha505@hszk.bme.hu # [PATCH] Redefination before undefination in fore200e.c # # Just for staying close to standards... # TAG: MailDone # # drivers/atm/fore200e.c # 2004/08/11 16:37:48-03:00 ha505@hszk.bme.hu +1 -0 # Redefination before undefination in fore200e.c # # ChangeSet # 2004/08/13 11:16:18-03:00 ha505@hszk.bme.hu # [PATCH] Redefinition before undefinition in pci-pc.c # # # arch/i386/kernel/pci-pc.c # 2004/08/11 18:11:49-03:00 ha505@hszk.bme.hu +1 -0 # Redefinition before undefinition in pci-pc.c # # ChangeSet # 2004/08/13 11:14:06-03:00 ha505@hszk.bme.hu # [PATCH] Missing enforced type conversion in pc300_tty.c # # # drivers/net/wan/pc300_tty.c # 2004/08/11 17:05:57-03:00 ha505@hszk.bme.hu +1 -1 # Missing enforced type conversion in pc300_tty.c # # ChangeSet # 2004/08/13 10:20:03-03:00 ha505@hszk.bme.hu # [PATCH] Extra tokens at #undef in ma600.c # # ma600.c:51:22: warning: extra tokens at end of #undef directive # # drivers/net/irda/ma600.c # 2004/08/11 16:26:58-03:00 ha505@hszk.bme.hu +1 -1 # Extra tokens at #undef in ma600.c # # ChangeSet # 2004/08/13 10:18:10-03:00 ha505@hszk.bme.hu # [PATCH] Fix i2o_pci.c warning # # Fix i2o_pci.c "no newline at end of file" warning # # drivers/message/i2o/i2o_pci.c # 2004/08/11 16:46:01-03:00 ha505@hszk.bme.hu +0 -1 # Fix i2o_pci.c warning # # ChangeSet # 2004/08/13 09:31:22-03:00 wli@holomorphy.com # [PATCH] OOM killer: make jiffies comparison wrap safe # # Incremental atop the mm reference patch: # # out_of_memory() attempts to determine whether one jiffies-valued # variable refers to a point in time preceding another jiffies-valued # variable, but does not do so in a jiffies wrap -safe fashion. The # following patch corrects this by using the expansion of the 2.6 # macro time_after() to check this condition. # TAG: MailDone # # mm/oom_kill.c # 2004/06/23 23:50:59-03:00 wli@holomorphy.com +1 -1 # OOM killer: make jiffies comparison wrap safe # # ChangeSet # 2004/08/13 09:27:19-03:00 wli@holomorphy.com # [PATCH] Fix OOM killer issues: kill all threads of a process and ignore kernel threads # # This patch by nature corrects two apparent bugs which are really one # bug. p->mm can become NULL while traversing the tasklist. The two # effects are first that kernel threads appear to be killed. The second # is that the OOM killing process fails to actually shoot down all threads # of the chosen process, and so fails to reclaim the memory it intended to. # oom_kill_task() consists primarily of the expansion of the 2.6 inline # function get_task_mm(). # # mm/oom_kill.c # 2004/06/23 23:52:25-03:00 wli@holomorphy.com +31 -5 # Fix OOM killer issues: kill all threads of a process and ignore kernel threads # # ChangeSet # 2004/08/13 08:38:23-03:00 sezeroz@ttnet.net.tr # [PATCH] agpgart: Missing chipset enum entry for i915 # # # include/linux/agp_backend.h # 2004/08/13 07:58:57-03:00 sezeroz@ttnet.net.tr +1 -0 # agpgart: Missing chipset enum entry for i915 # # ChangeSet # 2004/08/13 00:34:32-07:00 davem@kernel.bkbits.net # Merge davem@nuts.davemloft.net:/disk1/BK/net-2.4 # into kernel.bkbits.net:/home/davem/net-2.4 # # Documentation/Configure.help # 2004/08/13 00:34:30-07:00 davem@kernel.bkbits.net +0 -0 # Auto merged # # ChangeSet # 2004/08/12 18:45:04-03:00 chrisw@osdl.org # [PATCH] fix possible buffer overflow in panic() # # Minor issue here with the static buffer in 2.4 kernel's panic() function. # This has already been fixed in 2.6. # # [PATCH] fix possible buffer overflow in panic() # # ===== kernel/panic.c 1.12 vs edited ===== # TAG: MailDone # # kernel/panic.c # 2004/04/15 07:33:32-03:00 chrisw@osdl.org +1 -1 # fix possible buffer overflow in panic() # # ChangeSet # 2004/08/12 14:15:26-07:00 sri@us.ibm.com # [SCTP] Mark chunks as ineligible for fast retransmit after they are # retransmitted. Also mark any chunks that could not be fit in the # PMTU sized packet as ineligible for fast retransmit. # # net/sctp/outqueue.c # 2004/08/12 14:15:20-07:00 sri@us.ibm.com +20 -2 # [SCTP] Mark chunks as ineligible for fast retransmit after they are # retransmitted. Also mark any chunks that could not be fit in the # PMTU sized packet as ineligible for fast retransmit. # # ChangeSet # 2004/08/12 14:14:29-07:00 sri@us.ibm.com # [SCTP] Fix missing '+' in the computation of sack chunk size in # sctp_sm_pull_sack(). # # net/sctp/sm_statefuns.c # 2004/08/12 14:14:23-07:00 sri@us.ibm.com +1 -1 # [SCTP] Fix missing '+' in the computation of sack chunk size in # sctp_sm_pull_sack(). # # ChangeSet # 2004/08/12 14:13:23-07:00 sri@us.ibm.com # [SCTP] Fix issues with handling stale cookie error over multihoming # associations. # # net/sctp/sm_statefuns.c # 2004/08/12 14:13:17-07:00 sri@us.ibm.com +24 -12 # [SCTP] Fix issues with handling stale cookie error over multihoming # associations. # # net/sctp/sm_sideeffect.c # 2004/08/12 14:13:17-07:00 sri@us.ibm.com +71 -0 # [SCTP] Fix issues with handling stale cookie error over multihoming # associations. # # include/net/sctp/command.h # 2004/08/12 14:13:17-07:00 sri@us.ibm.com +3 -0 # [SCTP] Fix issues with handling stale cookie error over multihoming # associations. # # ChangeSet # 2004/08/12 14:12:00-07:00 sri@us.ibm.com # [SCTP] Fix data not being delivered to user in SHUTDOWN_SENT state. # # Also cleaned up sctp_sf_eat_data_6_2() and sctp_sf_eat_data_fast_4_4() # as they have a lot of common code. # # net/sctp/sm_statefuns.c # 2004/08/12 14:11:53-07:00 sri@us.ibm.com +200 -259 # [SCTP] Fix data not being delivered to user in SHUTDOWN_SENT state. # # Also cleaned up sctp_sf_eat_data_6_2() and sctp_sf_eat_data_fast_4_4() # as they have a lot of common code. # # net/sctp/associola.c # 2004/08/12 14:11:53-07:00 sri@us.ibm.com +1 -0 # [SCTP] Fix data not being delivered to user in SHUTDOWN_SENT state. # # Also cleaned up sctp_sf_eat_data_6_2() and sctp_sf_eat_data_fast_4_4() # as they have a lot of common code. # # include/net/sctp/sm.h # 2004/08/12 14:11:53-07:00 sri@us.ibm.com +3 -0 # [SCTP] Fix data not being delivered to user in SHUTDOWN_SENT state. # # Also cleaned up sctp_sf_eat_data_6_2() and sctp_sf_eat_data_fast_4_4() # as they have a lot of common code. # # include/net/sctp/constants.h # 2004/08/12 14:11:53-07:00 sri@us.ibm.com +4 -0 # [SCTP] Fix data not being delivered to user in SHUTDOWN_SENT state. # # Also cleaned up sctp_sf_eat_data_6_2() and sctp_sf_eat_data_fast_4_4() # as they have a lot of common code. # # ChangeSet # 2004/08/12 14:08:40-07:00 sri@us.ibm.com # [SCTP] Set/Get default SCTP_PEER_ADDR_PARAMS for endpoint when associd # and peer address are 0. # # net/sctp/socket.c # 2004/08/12 14:08:31-07:00 sri@us.ibm.com +38 -0 # [SCTP] Set/Get default SCTP_PEER_ADDR_PARAMS for endpoint when associd # and peer address are 0. # # ChangeSet # 2004/08/12 12:25:45-07:00 sri@us.ibm.com # [SCTP] SPARSE cleanup backported from 2.6 # # net/sctp/ulpqueue.c # 2004/08/12 12:25:34-07:00 sri@us.ibm.com +12 -12 # [SCTP] SPARSE cleanup backported from 2.6 # # net/sctp/ulpevent.c # 2004/08/12 12:25:34-07:00 sri@us.ibm.com +37 -40 # [SCTP] SPARSE cleanup backported from 2.6 # # net/sctp/socket.c # 2004/08/12 12:25:34-07:00 sri@us.ibm.com +61 -62 # [SCTP] SPARSE cleanup backported from 2.6 # # net/sctp/sm_statefuns.c # 2004/08/12 12:25:34-07:00 sri@us.ibm.com +1 -1 # [SCTP] SPARSE cleanup backported from 2.6 # # net/sctp/protocol.c # 2004/08/12 12:25:34-07:00 sri@us.ibm.com +1 -1 # [SCTP] SPARSE cleanup backported from 2.6 # # net/sctp/outqueue.c # 2004/08/12 12:25:34-07:00 sri@us.ibm.com +6 -6 # [SCTP] SPARSE cleanup backported from 2.6 # # net/sctp/output.c # 2004/08/12 12:25:34-07:00 sri@us.ibm.com +3 -3 # [SCTP] SPARSE cleanup backported from 2.6 # # net/sctp/inqueue.c # 2004/08/12 12:25:34-07:00 sri@us.ibm.com +1 -1 # [SCTP] SPARSE cleanup backported from 2.6 # # ChangeSet # 2004/08/12 14:58:02-03:00 marcelo@logos.cnet # Merge bk://kernel.bkbits.net/jgarzik/libata-upstream-2.4 # into logos.cnet:/home/marcelo/bk/linux-2.4 # TAG: MailDone # # Documentation/Configure.help # 2004/08/12 14:57:59-03:00 marcelo@logos.cnet +0 -0 # Auto merged # # ChangeSet # 2004/08/12 13:38:15-04:00 achew@nvidia.com # [libata] unmap MMIO region _after_ last possible usage # # drivers/scsi/libata-core.c # 2004/08/12 13:38:12-04:00 achew@nvidia.com +2 -2 # [libata] unmap MMIO region _after_ last possible usage # # ChangeSet # 2004/08/12 14:18:08-03:00 rbh00@utsglobal.com # [PATCH] UTS Global Cisco CLAW driver: Fix 64-bit handling # # This patch fixes 64-bit bugs in c7000.c so the driver will work for # both 31-bit and 64-bit kernels. This is the third of three patches. # TAG: MailDone # # drivers/s390/net/c7000.c # 2004/08/03 18:30:20-03:00 rbh00@utsglobal.com +31 -33 # UTS Global Cisco CLAW driver: Fix 64-bit handling # # ChangeSet # 2004/08/12 14:16:49-03:00 rbh00@utsglobal.com # [PATCH] UTS Global Cisco CLAW driver: remove old ifdefs and adds GPL header # # This patch to c7000.c removes old kernel-version ifdefs and adds # standard GPL license text. This is patch 2 of 3 for c7000.c. # # drivers/s390/net/c7000.c # 2004/08/03 18:43:54-03:00 rbh00@utsglobal.com +33 -96 # UTS Global Cisco CLAW driver: remove old ifdefs and adds GPL header # # ChangeSet # 2004/08/12 14:11:41-03:00 rbh00@utsglobal.com # [PATCH] UTS Global Cisco CLAW driver: avoid packets from being lost under heavy load # # This patch fixes a c7000.c bug where packets can be lost under heavy # workload. Two more c7000.c patches are to come; this is patch 1 of 3. # # drivers/s390/net/c7000.c # 2004/08/03 18:43:27-03:00 rbh00@utsglobal.com +2 -1 # UTS Global Cisco CLAW driver: avoid packets from being lost under heavy load # # ChangeSet # 2004/08/12 14:09:31-03:00 rbh00@utsglobal.com # [PATCH] s390x: enable ioctl's for UTS global 3270 # # Here are two patches that allow operation of ned, the (31-bit) UTS # Global full-screen 3270 editor, on 64-bit zSeries machines. Each patch # changes arch/s390x/kernel/ioctl32.c to enable processing of the 3270 # ioctl commands. # # For other 2.4 kernen versions, one or the other patch will probably # apply with only offsets; in any case, interpolation should be easy. # # arch/s390x/kernel/ioctl32.c # 2004/08/05 22:14:56-03:00 rbh00@utsglobal.com +7 -0 # s390x: enable octl's for UTS global 3270 # # ChangeSet # 2004/08/12 13:41:54-03:00 bunk@fs.tum.de # [PATCH] update email address of Pedro Roque Marques # # I tried to send a Cc of a patch in a file in the Linux kernel that is # credited to Pedro Roque Marques, but the email bounced. # # The patch below (already ACK'ed by Pedro Roque Marques) updates his # email address. It applies against both 2.4 and 2.6 . # # diffstat output: # Documentation/isdn/CREDITS | 2 +- # Documentation/isdn/README.pcbit | 2 +- # drivers/isdn/pcbit/callbacks.c | 2 +- # drivers/isdn/pcbit/callbacks.h | 2 +- # drivers/isdn/pcbit/capi.c | 2 +- # drivers/isdn/pcbit/capi.h | 2 +- # drivers/isdn/pcbit/drv.c | 2 +- # drivers/isdn/pcbit/edss1.c | 2 +- # drivers/isdn/pcbit/edss1.h | 2 +- # drivers/isdn/pcbit/layer2.c | 2 +- # drivers/isdn/pcbit/layer2.h | 2 +- # drivers/isdn/pcbit/module.c | 2 +- # drivers/isdn/pcbit/pcbit.h | 2 +- # include/linux/in6.h | 2 +- # include/linux/ipv6_route.h | 2 +- # include/net/if_inet6.h | 2 +- # include/net/ip6_fib.h | 2 +- # include/net/ipv6.h | 2 +- # include/net/neighbour.h | 2 +- # net/core/neighbour.c | 2 +- # net/ipv6/addrconf.c | 2 +- # net/ipv6/af_inet6.c | 2 +- # net/ipv6/datagram.c | 2 +- # net/ipv6/exthdrs.c | 2 +- # net/ipv6/icmp.c | 2 +- # net/ipv6/ip6_fib.c | 2 +- # net/ipv6/ip6_input.c | 2 +- # net/ipv6/ip6_output.c | 2 +- # net/ipv6/ipv6_sockglue.c | 2 +- # net/ipv6/mcast.c | 2 +- # net/ipv6/ndisc.c | 2 +- # net/ipv6/protocol.c | 2 +- # net/ipv6/raw.c | 2 +- # net/ipv6/reassembly.c | 2 +- # net/ipv6/route.c | 2 +- # net/ipv6/sit.c | 2 +- # net/ipv6/tcp_ipv6.c | 2 +- # net/ipv6/udp.c | 2 +- # 38 files changed, 38 insertions(+), 38 deletions(-) # # # # Signed-off-by: Adrian Bunk # TAG: MailDone # # net/ipv6/udp.c # 2004/07/15 17:33:03-03:00 bunk@fs.tum.de +1 -1 # update email address of Pedro Roque Marques # # net/ipv6/tcp_ipv6.c # 2004/07/15 17:33:03-03:00 bunk@fs.tum.de +1 -1 # update email address of Pedro Roque Marques # # net/ipv6/sit.c # 2004/07/15 17:33:03-03:00 bunk@fs.tum.de +1 -1 # update email address of Pedro Roque Marques # # net/ipv6/route.c # 2004/07/15 17:33:03-03:00 bunk@fs.tum.de +1 -1 # update email address of Pedro Roque Marques # # net/ipv6/reassembly.c # 2004/07/15 17:33:03-03:00 bunk@fs.tum.de +1 -1 # update email address of Pedro Roque Marques # # net/ipv6/raw.c # 2004/07/15 17:33:03-03:00 bunk@fs.tum.de +1 -1 # update email address of Pedro Roque Marques # # net/ipv6/protocol.c # 2004/07/15 17:33:03-03:00 bunk@fs.tum.de +1 -1 # update email address of Pedro Roque Marques # # net/ipv6/ndisc.c # 2004/07/15 17:33:03-03:00 bunk@fs.tum.de +1 -1 # update email address of Pedro Roque Marques # # net/ipv6/mcast.c # 2004/07/15 17:33:03-03:00 bunk@fs.tum.de +1 -1 # update email address of Pedro Roque Marques # # net/ipv6/ipv6_sockglue.c # 2004/07/15 17:33:03-03:00 bunk@fs.tum.de +1 -1 # update email address of Pedro Roque Marques # # net/ipv6/ip6_output.c # 2004/07/15 17:33:03-03:00 bunk@fs.tum.de +1 -1 # update email address of Pedro Roque Marques # # net/ipv6/ip6_input.c # 2004/07/15 17:33:03-03:00 bunk@fs.tum.de +1 -1 # update email address of Pedro Roque Marques # # net/ipv6/ip6_fib.c # 2004/07/15 17:33:03-03:00 bunk@fs.tum.de +1 -1 # update email address of Pedro Roque Marques # # net/ipv6/icmp.c # 2004/07/15 17:33:03-03:00 bunk@fs.tum.de +1 -1 # update email address of Pedro Roque Marques # # net/ipv6/exthdrs.c # 2004/07/15 17:33:03-03:00 bunk@fs.tum.de +1 -1 # update email address of Pedro Roque Marques # # net/ipv6/datagram.c # 2004/07/15 17:33:03-03:00 bunk@fs.tum.de +1 -1 # update email address of Pedro Roque Marques # # net/ipv6/af_inet6.c # 2004/07/15 17:33:03-03:00 bunk@fs.tum.de +1 -1 # update email address of Pedro Roque Marques # # net/ipv6/addrconf.c # 2004/07/15 17:33:03-03:00 bunk@fs.tum.de +1 -1 # update email address of Pedro Roque Marques # # net/core/neighbour.c # 2004/07/15 17:33:03-03:00 bunk@fs.tum.de +1 -1 # update email address of Pedro Roque Marques # # include/net/neighbour.h # 2004/07/15 17:33:03-03:00 bunk@fs.tum.de +1 -1 # update email address of Pedro Roque Marques # # include/net/ipv6.h # 2004/07/15 17:33:03-03:00 bunk@fs.tum.de +1 -1 # update email address of Pedro Roque Marques # # include/net/ip6_fib.h # 2004/07/15 17:33:03-03:00 bunk@fs.tum.de +1 -1 # update email address of Pedro Roque Marques # # include/net/if_inet6.h # 2004/07/15 17:33:03-03:00 bunk@fs.tum.de +1 -1 # update email address of Pedro Roque Marques # # include/linux/ipv6_route.h # 2004/07/15 17:33:03-03:00 bunk@fs.tum.de +1 -1 # update email address of Pedro Roque Marques # # include/linux/in6.h # 2004/07/15 17:33:03-03:00 bunk@fs.tum.de +1 -1 # update email address of Pedro Roque Marques # # drivers/isdn/pcbit/pcbit.h # 2004/07/15 17:33:03-03:00 bunk@fs.tum.de +1 -1 # update email address of Pedro Roque Marques # # drivers/isdn/pcbit/module.c # 2004/07/15 17:33:03-03:00 bunk@fs.tum.de +1 -1 # update email address of Pedro Roque Marques # # drivers/isdn/pcbit/layer2.h # 2004/07/15 17:33:03-03:00 bunk@fs.tum.de +1 -1 # update email address of Pedro Roque Marques # # drivers/isdn/pcbit/layer2.c # 2004/07/15 17:33:03-03:00 bunk@fs.tum.de +1 -1 # update email address of Pedro Roque Marques # # drivers/isdn/pcbit/edss1.h # 2004/07/15 17:33:03-03:00 bunk@fs.tum.de +1 -1 # update email address of Pedro Roque Marques # # drivers/isdn/pcbit/edss1.c # 2004/07/15 17:33:03-03:00 bunk@fs.tum.de +1 -1 # update email address of Pedro Roque Marques # # drivers/isdn/pcbit/drv.c # 2004/07/15 17:33:03-03:00 bunk@fs.tum.de +1 -1 # update email address of Pedro Roque Marques # # drivers/isdn/pcbit/capi.h # 2004/07/15 17:33:03-03:00 bunk@fs.tum.de +1 -1 # update email address of Pedro Roque Marques # # drivers/isdn/pcbit/capi.c # 2004/07/15 17:33:03-03:00 bunk@fs.tum.de +1 -1 # update email address of Pedro Roque Marques # # drivers/isdn/pcbit/callbacks.h # 2004/07/15 17:33:03-03:00 bunk@fs.tum.de +1 -1 # update email address of Pedro Roque Marques # # drivers/isdn/pcbit/callbacks.c # 2004/07/15 17:33:03-03:00 bunk@fs.tum.de +1 -1 # update email address of Pedro Roque Marques # # Documentation/isdn/README.pcbit # 2004/07/15 17:33:03-03:00 bunk@fs.tum.de +1 -1 # update email address of Pedro Roque Marques # # Documentation/isdn/CREDITS # 2004/07/15 17:33:03-03:00 bunk@fs.tum.de +1 -1 # update email address of Pedro Roque Marques # # ChangeSet # 2004/08/12 13:39:55-03:00 Frank_Borich@us.xyratex.com # [PATCH] Add Xyratex 4200 to SCSI blacklist # # The patch simply adds our FC-SATA # RAID to scsi_scan.c's blacklist. # # drivers/scsi/scsi_scan.c # 2004/08/12 13:38:26-03:00 Frank_Borich@us.xyratex.com +1 -0 # Add Xyratex 4200 to SCSI blacklist # # ChangeSet # 2004/08/12 13:32:01-03:00 alanh@fairlite.demon.co.uk # [PATCH] AGPgart update: Intel i915G support # # Intel i915G support # * Support for ARGB full color cursors for X which requires 4 physical pages, # (this supports all Intel chipsets from i810 onward) # * Fix a problem with 64M apertures which where picking up the 128M offsets. # # drivers/char/agp/agpgart_be.c # 2004/06/10 19:20:16-03:00 alanh@fairlite.demon.co.uk +228 -42 # AGPgart update: Intel i915G support # # drivers/char/agp/agp.h # 2004/06/03 11:59:15-03:00 alanh@fairlite.demon.co.uk +12 -0 # AGPgart update: Intel i915G support # # ChangeSet # 2004/08/10 18:33:11-07:00 jmorris@redhat.com # [CRYPTO]: Typo in crypto/tcrypt.h # # From Nicolas Kaiser # # Signed-off-by: James Morris # Signed-off-by: David S. Miller # # crypto/tcrypt.h # 2004/08/10 18:33:06-07:00 jmorris@redhat.com +1 -1 # [CRYPTO]: Typo in crypto/tcrypt.h # # From Nicolas Kaiser # # Signed-off-by: James Morris # Signed-off-by: David S. Miller # # ChangeSet # 2004/08/10 18:32:52-07:00 jmorris@redhat.com # [CRYPTO]: Typo in crypto/blowfish.c # # From Nicolas Kaiser # # Signed-off-by: James Morris # Signed-off-by: David S. Miller # # crypto/blowfish.c # 2004/08/10 18:32:48-07:00 jmorris@redhat.com +3 -3 # [CRYPTO]: Typo in crypto/blowfish.c # # From Nicolas Kaiser # # Signed-off-by: James Morris # Signed-off-by: David S. Miller # # ChangeSet # 2004/08/10 18:32:38-07:00 jmorris@redhat.com # [CRYPTO]: Typo in crypto/scatterwalk.c # # From Nicolas Kaiser # # Signed-off-by: James Morris # Signed-off-by: David S. Miller # # crypto/scatterwalk.c # 2004/08/10 18:32:34-07:00 jmorris@redhat.com +1 -1 # [CRYPTO]: Typo in crypto/scatterwalk.c # # From Nicolas Kaiser # # Signed-off-by: James Morris # Signed-off-by: David S. Miller # # ChangeSet # 2004/08/10 18:32:25-07:00 jmorris@redhat.com # [CRYPTO]: Typo in crypto/aes.c # # From Nicolas Kaiser # # Signed-off-by: James Morris # Signed-off-by: David S. Miller # # crypto/aes.c # 2004/08/10 18:32:20-07:00 jmorris@redhat.com +1 -1 # [CRYPTO]: Typo in crypto/aes.c # # From Nicolas Kaiser # # Signed-off-by: James Morris # Signed-off-by: David S. Miller # # ChangeSet # 2004/08/10 18:32:07-07:00 jmorris@redhat.com # [CRYPTO]: Typo in crypto/twofish.c # # From Nicolas Kaiser # # Signed-off-by: James Morris # Signed-off-by: David S. Miller # # crypto/twofish.c # 2004/08/10 18:32:03-07:00 jmorris@redhat.com +2 -2 # [CRYPTO]: Typo in crypto/twofish.c # # From Nicolas Kaiser # # Signed-off-by: James Morris # Signed-off-by: David S. Miller # # ChangeSet # 2004/08/10 18:31:37-07:00 jmorris@redhat.com # [CRYPTO]: Typo in Documentation/Configure.help # # From Nicolas Kaiser # # Signed-off-by: James Morris # Signed-off-by: David S. Miller # # Documentation/Configure.help # 2004/08/10 18:31:21-07:00 jmorris@redhat.com +1 -1 # [CRYPTO]: Typo in Documentation/Configure.help # # From Nicolas Kaiser # # Signed-off-by: James Morris # Signed-off-by: David S. Miller # # ChangeSet # 2004/08/10 18:29:18-07:00 jon@oberheide.org # [CRYPTO]: Email update in crypto/arc4.c # # crypto/arc4.c # 2004/08/10 18:29:14-07:00 jon@oberheide.org +2 -2 # [CRYPTO]: Email update in crypto/arc4.c # # ChangeSet # 2004/08/10 18:27:54-07:00 ajgrothe@yahoo.com # [CRYPTO]: Add Khazad algorithm. # # Signed-off-by: Aaron Grothe # Signed-off-by: James Morris # Signed-off-by: David S. Miller # # crypto/tcrypt.h # 2004/08/10 18:27:14-07:00 ajgrothe@yahoo.com +96 -0 # [CRYPTO]: Add Khazad algorithm. # # crypto/tcrypt.c # 2004/08/10 18:27:14-07:00 ajgrothe@yahoo.com +9 -0 # [CRYPTO]: Add Khazad algorithm. # # crypto/Makefile # 2004/08/10 18:27:14-07:00 ajgrothe@yahoo.com +1 -0 # [CRYPTO]: Add Khazad algorithm. # # crypto/Config.in # 2004/08/10 18:27:14-07:00 ajgrothe@yahoo.com +1 -0 # [CRYPTO]: Add Khazad algorithm. # # Documentation/crypto/api-intro.txt # 2004/08/10 18:27:14-07:00 ajgrothe@yahoo.com +6 -0 # [CRYPTO]: Add Khazad algorithm. # # Documentation/Configure.help # 2004/08/10 18:27:13-07:00 ajgrothe@yahoo.com +10 -0 # [CRYPTO]: Add Khazad algorithm. # # crypto/khazad.c # 2004/08/10 18:27:07-07:00 ajgrothe@yahoo.com +915 -0 # [CRYPTO]: Add Khazad algorithm. # # crypto/khazad.c # 2004/08/10 18:27:07-07:00 ajgrothe@yahoo.com +0 -0 # BitKeeper file /disk1/BK/net-2.4/crypto/khazad.c # # ChangeSet # 2004/08/10 17:16:39-03:00 riel@redhat.com # [PATCH] reserved buffers only for PF_MEMALLOC # # The buffer allocation path in 2.4 has a long standing bug, # where non-PF_MEMALLOC tasks can dig into the reserved pool # in get_unused_buffer_head(). The following patch makes the # reserved pool only accessible to PF_MEMALLOC tasks. # # Other processes will loop in create_buffers() - the only # function that calls get_unused_buffer_head() - and will call # try_to_free_pages(GFP_NOIO), freeing any buffer heads that # have become freeable due to IO completion. # # Note that PF_MEMALLOC tasks will NOT do anything inside # try_to_free_pages(), so it is needed that they are able to # dig into the reserved buffer heads while other tasks are # not. # # Signed-off-by: Rik van Riel # # fs/buffer.c # 2004/08/10 12:34:54-03:00 riel@redhat.com +2 -1 # reserved buffers only for PF_MEMALLOC # # ChangeSet # 2004/08/09 16:50:52-07:00 devik@cdi.cz # [PKT_SCHED]: Fix borrowing fairness in htb. # # net/sched/sch_htb.c # 2004/08/09 16:50:48-07:00 devik@cdi.cz +53 -8 # [PKT_SCHED]: Fix borrowing fairness in htb. # # ChangeSet # 2004/08/09 16:09:47-07:00 davem@nuts.davemloft.net # [SPARC64]: More entropy in add_timer_randomness. # # Based upon a patch from Richard Mortimer. # # Signed-off-by: David S. Miller # # drivers/char/random.c # 2004/08/09 16:09:10-07:00 davem@nuts.davemloft.net +5 -0 # [SPARC64]: More entropy in add_timer_randomness. # # ChangeSet # 2004/08/09 18:50:28-03:00 Liam.Girdwood@wolfsonmicro.com # [PATCH] Fix unsafe reset in ac97_codec.c, support WM9713, more fixes # # o Added support for WM9713 # o Added support for codecs that power down when register reset. # o Moved the codec specific inits after the mixer setup as some init # settings were being clobbered. # o Checking reg 0 bit 15 after register reset. # o Added extra check so that default_digital_ops doesn't overwrite a # valid codec_ops. (SPDIF) # TAG: MailDone # # include/linux/ac97_codec.h # 2004/08/04 12:10:43-03:00 Liam.Girdwood@wolfsonmicro.com +1 -0 # Fix unsafe reset in ac97_codec.c, support WM9713, more fixes # # drivers/sound/ac97_codec.c # 2004/08/04 13:07:52-03:00 Liam.Girdwood@wolfsonmicro.com +58 -29 # Fix unsafe reset in ac97_codec.c, support WM9713, more fixes # # ChangeSet # 2004/08/09 18:45:29-03:00 daniel.ritz@gmx.ch # [PATCH] PCI: fix irq routing on acer travelmate 360 laptop # # v2.4 version of the following v2.6 patch: # Fixes interrupt routing on acer travelmate 360 notebooks. it looks like # the bios assigned the wrong pirq value for the cardbus bridge. just # assigning irq 10 to all devices with pirq 0x63 would break second usb port. # pirq 0x68 seems to be right one for cardbus. # # Signed-off-by: Daniel Ritz # Signed-off-by: Andrew Morton # Signed-off-by: Greg Kroah-Hartman # # arch/i386/kernel/pci-irq.c # 2004/05/31 20:01:54-03:00 daniel.ritz@gmx.ch +9 -0 # PCI: fix irq routing on acer travelmate 360 laptop # # arch/i386/kernel/dmi_scan.c # 2004/05/31 20:00:20-03:00 daniel.ritz@gmx.ch +29 -0 # PCI: fix irq routing on acer travelmate 360 laptop # # ChangeSet # 2004/08/02 19:02:08-07:00 davem@nuts.davemloft.net # Merge nuts.davemloft.net:/disk1/BK/sparcwork-2.4 # into nuts.davemloft.net:/disk1/BK/sparc-2.4 # # MAINTAINERS # 2004/08/02 19:02:06-07:00 davem@nuts.davemloft.net +0 -0 # Auto merged # # ChangeSet # 2004/08/02 18:59:35-07:00 joshk@triplehelix.org # [SPARC]: Add missing GPL module license tags to drivers. # # drivers/scsi/qlogicpti.c # 2004/08/02 18:59:26-07:00 joshk@triplehelix.org +1 -1 # [SPARC]: Add missing GPL module license tags to drivers. # # drivers/scsi/pluto.c # 2004/08/02 18:59:26-07:00 joshk@triplehelix.org +1 -1 # [SPARC]: Add missing GPL module license tags to drivers. # # drivers/scsi/fcal.c # 2004/08/02 18:59:26-07:00 joshk@triplehelix.org +1 -1 # [SPARC]: Add missing GPL module license tags to drivers. # # drivers/scsi/esp.c # 2004/08/02 18:59:26-07:00 joshk@triplehelix.org +1 -1 # [SPARC]: Add missing GPL module license tags to drivers. # # drivers/sbus/char/vfc_dev.c # 2004/08/02 18:59:26-07:00 joshk@triplehelix.org +1 -1 # [SPARC]: Add missing GPL module license tags to drivers. # # drivers/sbus/char/bpp.c # 2004/08/02 18:59:26-07:00 joshk@triplehelix.org +2 -0 # [SPARC]: Add missing GPL module license tags to drivers. # # drivers/fc4/fc.c # 2004/08/02 18:59:26-07:00 joshk@triplehelix.org +2 -0 # [SPARC]: Add missing GPL module license tags to drivers. # # ChangeSet # 2004/07/29 16:30:16-07:00 davem@nuts.davemloft.net # [SPARC64]: Simplify and optimize ultra3 memory copies. # # - Use one unrolled loop instead of two # - Improve performance for well aligned # copies smaller than 256 bytes # - Use better named local label names so # that diffing between the various instances # is much easier to read # - Reverify exception handling # # arch/sparc64/lib/U3memcpy.S # 2004/07/29 16:29:51-07:00 davem@nuts.davemloft.net +244 -339 # [SPARC64]: Simplify and optimize ultra3 memory copies. # # - Use one unrolled loop instead of two # - Improve performance for well aligned # copies smaller than 256 bytes # - Use better named local label names so # that diffing between the various instances # is much easier to read # - Reverify exception handling # # arch/sparc64/lib/U3copy_to_user.S # 2004/07/29 16:29:51-07:00 davem@nuts.davemloft.net +250 -364 # [SPARC64]: Simplify and optimize ultra3 memory copies. # # - Use one unrolled loop instead of two # - Improve performance for well aligned # copies smaller than 256 bytes # - Use better named local label names so # that diffing between the various instances # is much easier to read # - Reverify exception handling # # arch/sparc64/lib/U3copy_in_user.S # 2004/07/29 16:29:51-07:00 davem@nuts.davemloft.net +78 -469 # [SPARC64]: Simplify and optimize ultra3 memory copies. # # - Use one unrolled loop instead of two # - Improve performance for well aligned # copies smaller than 256 bytes # - Use better named local label names so # that diffing between the various instances # is much easier to read # - Reverify exception handling # # arch/sparc64/lib/U3copy_from_user.S # 2004/07/29 16:29:51-07:00 davem@nuts.davemloft.net +271 -360 # [SPARC64]: Simplify and optimize ultra3 memory copies. # # - Use one unrolled loop instead of two # - Improve performance for well aligned # copies smaller than 256 bytes # - Use better named local label names so # that diffing between the various instances # is much easier to read # - Reverify exception handling # # ChangeSet # 2004/07/28 13:18:00-04:00 achew@nvidia.com # [ata] fix reversed bit definitions in linux/ata.h # # The macros ata_id_has_lba() and ata_id_has_dma() seem to have their bits # reversed. LBA support is bit 9 of word 49 in the identify page, whereas # DMA support is bit 8 of word 49 in the identify page. # # include/linux/ata.h # 2004/07/28 13:17:56-04:00 achew@nvidia.com +2 -2 # [ata] fix reversed bit definitions in linux/ata.h # # The macros ata_id_has_lba() and ata_id_has_dma() seem to have their bits # reversed. LBA support is bit 9 of word 49 in the identify page, whereas # DMA support is bit 8 of word 49 in the identify page. # # ChangeSet # 2004/07/28 13:16:26-04:00 p.lavarre@ieee.org # [PATCH] SATAPI despite no data # # I see we lost this source line in the changes since 2.6.7. But if I try # SATAPI expecting no data without this source line, then my ata_piix.ko # promptly dies with such complaints as: # # kernel: irq 18: nobody cared! # # With this source line, I find I can expect no data, though I still have # to add auto sense to overcome: # # kernel: ata2: BUG: timeout without command # # drivers/scsi/libata-core.c # 2004/07/28 13:16:16-04:00 p.lavarre@ieee.org +1 -0 # [PATCH] SATAPI despite no data # # I see we lost this source line in the changes since 2.6.7. But if I try # SATAPI expecting no data without this source line, then my ata_piix.ko # promptly dies with such complaints as: # # kernel: irq 18: nobody cared! # # With this source line, I find I can expect no data, though I still have # to add auto sense to overcome: # # kernel: ata2: BUG: timeout without command # # ChangeSet # 2004/07/27 13:08:54-07:00 davem@nuts.davemloft.net # [SPARC64]: Kill all this silly inline memcpy handling. # # GCC does this well enough. # # Signed-off-by: David S. Miller # # include/asm-sparc64/string.h # 2004/07/27 13:08:37-07:00 davem@nuts.davemloft.net +1 -25 # [SPARC64]: Kill all this silly inline memcpy handling. # # GCC does this well enough. # # Signed-off-by: David S. Miller # # include/asm-sparc64/page.h # 2004/07/27 13:08:37-07:00 davem@nuts.davemloft.net +1 -1 # [SPARC64]: Kill all this silly inline memcpy handling. # # GCC does this well enough. # # Signed-off-by: David S. Miller # # arch/sparc64/lib/VIScopy.S # 2004/07/27 13:08:37-07:00 davem@nuts.davemloft.net +0 -4 # [SPARC64]: Kill all this silly inline memcpy handling. # # GCC does this well enough. # # Signed-off-by: David S. Miller # # arch/sparc64/kernel/sparc64_ksyms.c # 2004/07/27 13:08:37-07:00 davem@nuts.davemloft.net +0 -1 # [SPARC64]: Kill all this silly inline memcpy handling. # # GCC does this well enough. # # Signed-off-by: David S. Miller # # ChangeSet # 2004/07/21 14:27:25-07:00 wli@holomorphy.com # [SPARC32]: Mark William Lee Irwin III as maintainer. # # MAINTAINERS # 2004/07/21 14:27:16-07:00 wli@holomorphy.com +2 -2 # [SPARC32]: Mark William Lee Irwin III as maintainer. # # ChangeSet # 2004/07/21 13:42:33-07:00 tcallawa@redhat.com # [SPARC]: Fix copy_user.S with gcc 3.3 # # Signed-off-by: Tom Callaway # Signed-off-by: David S. Miller # # arch/sparc/lib/copy_user.S # 2004/07/21 13:42:25-07:00 tcallawa@redhat.com +38 -38 # [SPARC]: Fix copy_user.S with gcc 3.3 # # Signed-off-by: Tom Callaway # Signed-off-by: David S. Miller # # ChangeSet # 2004/07/21 13:27:59-07:00 dave@thedillows.org # [SPARC64]: Handle SBUS dma allocations larger than 1MB. # # Signed-off-by: David Dillow # Signed-off-by: David S. Miller # # arch/sparc64/kernel/sbus.c # 2004/07/21 13:27:54-07:00 dave@thedillows.org +50 -17 # [SPARC64]: Handle SBUS dma allocations larger than 1MB. # # Signed-off-by: David Dillow # Signed-off-by: David S. Miller # # ChangeSet # 2004/07/14 16:38:22-04:00 Sergio.Gelato@astro.su.se # [PATCH] libata: fix kunmap() of incorrect page, in PIO data xfer # # Obvious bug. Fixes highmem oops. # # drivers/scsi/libata-core.c # 2004/07/14 16:38:11-04:00 Sergio.Gelato@astro.su.se +4 -2 # [PATCH] libata: fix kunmap() of incorrect page, in PIO data xfer # # Obvious bug. Fixes highmem oops. # # ChangeSet # 2004/07/11 17:25:34-07:00 davem@nuts.davemloft.net # [SPARC64]: Add CMT register defines. # # include/asm-sparc64/asi.h # 2004/07/11 17:25:27-07:00 davem@nuts.davemloft.net +130 -117 # [SPARC64]: Add CMT register defines. # # include/asm-sparc64/cmt.h # 2004/07/11 17:25:25-07:00 davem@nuts.davemloft.net +59 -0 # [SPARC64]: Add CMT register defines. # # include/asm-sparc64/cmt.h # 2004/07/11 17:25:25-07:00 davem@nuts.davemloft.net +0 -0 # BitKeeper file /disk1/BK/sparc-2.4/include/asm-sparc64/cmt.h # # ChangeSet # 2004/07/10 12:53:38-04:00 jgarzik@pobox.com # [libata] fix a 2.6-ism that snuck in # # drivers/scsi/libata-core.c # 2004/07/10 12:53:37-04:00 jgarzik@pobox.com +1 -1 # [libata] fix a 2.6-ism that snuck in # # ChangeSet # 2004/07/10 12:50:05-04:00 jgarzik@pobox.com # [libata] ATAPI work - cdb len, new taskfile protocol, cleanups # # * new helper atapi_cdb_len() in linux/ata.h, use it after # IDENTIFY PACKET DEVICE command completes # * add new taskfile protocol ATA_PROT_ATAPI_NODATA # * store scsi cdb in ata_queued_cmd. This removes another dependence # on the scsi layer, and enables us to issue an internal REQUEST SENSE. # * store cdb len in ata_port # * new constant ATAPI_CDB_LEN for max cdb length # * move ATA taskfile and SCSI cdb near the top of ata_queued_cmd, for # better cacheline friendliness. # # include/linux/libata.h # 2004/07/10 12:50:00-04:00 jgarzik@pobox.com +4 -1 # [libata] ATAPI work - cdb len, new taskfile protocol, cleanups # # * new helper atapi_cdb_len() in linux/ata.h, use it after # IDENTIFY PACKET DEVICE command completes # * add new taskfile protocol ATA_PROT_ATAPI_NODATA # * store scsi cdb in ata_queued_cmd. This removes another dependence # on the scsi layer, and enables us to issue an internal REQUEST SENSE. # * store cdb len in ata_port # * new constant ATAPI_CDB_LEN for max cdb length # * move ATA taskfile and SCSI cdb near the top of ata_queued_cmd, for # better cacheline friendliness. # # include/linux/ata.h # 2004/07/10 12:50:00-04:00 jgarzik@pobox.com +14 -1 # [libata] ATAPI work - cdb len, new taskfile protocol, cleanups # # * new helper atapi_cdb_len() in linux/ata.h, use it after # IDENTIFY PACKET DEVICE command completes # * add new taskfile protocol ATA_PROT_ATAPI_NODATA # * store scsi cdb in ata_queued_cmd. This removes another dependence # on the scsi layer, and enables us to issue an internal REQUEST SENSE. # * store cdb len in ata_port # * new constant ATAPI_CDB_LEN for max cdb length # * move ATA taskfile and SCSI cdb near the top of ata_queued_cmd, for # better cacheline friendliness. # # drivers/scsi/libata-scsi.c # 2004/07/10 12:50:00-04:00 jgarzik@pobox.com +11 -8 # [libata] ATAPI work - cdb len, new taskfile protocol, cleanups # # * new helper atapi_cdb_len() in linux/ata.h, use it after # IDENTIFY PACKET DEVICE command completes # * add new taskfile protocol ATA_PROT_ATAPI_NODATA # * store scsi cdb in ata_queued_cmd. This removes another dependence # on the scsi layer, and enables us to issue an internal REQUEST SENSE. # * store cdb len in ata_port # * new constant ATAPI_CDB_LEN for max cdb length # * move ATA taskfile and SCSI cdb near the top of ata_queued_cmd, for # better cacheline friendliness. # # drivers/scsi/libata-core.c # 2004/07/10 12:50:00-04:00 jgarzik@pobox.com +17 -8 # [libata] ATAPI work - cdb len, new taskfile protocol, cleanups # # * new helper atapi_cdb_len() in linux/ata.h, use it after # IDENTIFY PACKET DEVICE command completes # * add new taskfile protocol ATA_PROT_ATAPI_NODATA # * store scsi cdb in ata_queued_cmd. This removes another dependence # on the scsi layer, and enables us to issue an internal REQUEST SENSE. # * store cdb len in ata_port # * new constant ATAPI_CDB_LEN for max cdb length # * move ATA taskfile and SCSI cdb near the top of ata_queued_cmd, for # better cacheline friendliness. # # ChangeSet # 2004/07/10 12:49:43-04:00 jgarzik@pobox.com # [libata] flags cleanup # # Remove unused/redundant flags ATA_DFLAG_{MASTER,WCACHE} # # include/linux/libata.h # 2004/07/10 12:49:35-04:00 jgarzik@pobox.com +1 -4 # [libata] flags cleanup # # Remove unused/redundant flags ATA_DFLAG_{MASTER,WCACHE} # # drivers/scsi/libata-core.c # 2004/07/10 12:49:35-04:00 jgarzik@pobox.com +0 -1 # [libata] flags cleanup # # Remove unused/redundant flags ATA_DFLAG_{MASTER,WCACHE} # # drivers/scsi/ata_piix.c # 2004/07/10 12:49:35-04:00 jgarzik@pobox.com +1 -1 # [libata] flags cleanup # # Remove unused/redundant flags ATA_DFLAG_{MASTER,WCACHE} # # ChangeSet # 2004/07/10 11:03:24-04:00 jgarzik@pobox.com # [libata ata_piix] make sure AHCI is disabled, if h/w is used by this driver # # AHCI must be disabled if we are to have access to taskfile registers. # # drivers/scsi/ata_piix.c # 2004/07/10 11:03:13-04:00 jgarzik@pobox.com +58 -6 # [libata ata_piix] make sure AHCI is disabled, if h/w is used by this driver # # AHCI must be disabled if we are to have access to taskfile registers. # # ChangeSet # 2004/07/09 23:20:47-04:00 jgarzik@pobox.com # [libata] ATAPI work - PIO xfer, completion function # # Move hand-coded ATA Data register I/O from ata_pio_sector() to its # own function ata_data_xfer(), so that it may also be used to send the # ATAPI packet to hardware. # # Use ata_data_xfer() in ATAPI packet send. # # Separate ATA and ATAPI completion functions. # # drivers/scsi/libata-scsi.c # 2004/07/09 23:20:36-04:00 jgarzik@pobox.com +30 -7 # [libata] ATAPI work - PIO xfer, completion function # # Move hand-coded ATA Data register I/O from ata_pio_sector() to its # own function ata_data_xfer(), so that it may also be used to send the # ATAPI packet to hardware. # # Use ata_data_xfer() in ATAPI packet send. # # Separate ATA and ATAPI completion functions. # # drivers/scsi/libata-core.c # 2004/07/09 23:20:36-04:00 jgarzik@pobox.com +41 -22 # [libata] ATAPI work - PIO xfer, completion function # # Move hand-coded ATA Data register I/O from ata_pio_sector() to its # own function ata_data_xfer(), so that it may also be used to send the # ATAPI packet to hardware. # # Use ata_data_xfer() in ATAPI packet send. # # Separate ATA and ATAPI completion functions. # # ChangeSet # 2004/07/07 19:45:31-04:00 jgarzik@pobox.com # [libata] export msleep for use in libata drivers # # include/linux/libata.h # 2004/07/07 19:45:30-04:00 jgarzik@pobox.com +1 -0 # [libata] export msleep for use in libata drivers # # drivers/scsi/sata_promise.c # 2004/07/07 19:45:30-04:00 jgarzik@pobox.com +1 -0 # [libata] export msleep for use in libata drivers # # drivers/scsi/libata-core.c # 2004/07/07 19:45:30-04:00 jgarzik@pobox.com +6 -0 # [libata] export msleep for use in libata drivers # # ChangeSet # 2004/07/07 19:39:33-04:00 jgarzik@pobox.com # [libata] update IDENTIFY DEVICE path to use ata_queued_cmd # # rather than hand-rolling our own taskfile call (which won't work at # all on newer SATA controllers). # # Individual changes: # * use ata_qc_issue to issue identify-device command # * implement MMIO path for PIO data xfer # * implement PIO error handling path # # drivers/scsi/libata-core.c # 2004/07/07 19:39:30-04:00 jgarzik@pobox.com +72 -62 # [libata] update IDENTIFY DEVICE path to use ata_queued_cmd # # rather than hand-rolling our own taskfile call (which won't work at # all on newer SATA controllers). # # Individual changes: # * use ata_qc_issue to issue identify-device command # * implement MMIO path for PIO data xfer # * implement PIO error handling path # # ChangeSet # 2004/07/07 19:39:02-04:00 jgarzik@pobox.com # [libata sata_sx4] deliver non-data taskfiles using Promise packet format # # drivers/scsi/sata_sx4.c # 2004/07/07 19:38:58-04:00 jgarzik@pobox.com +97 -64 # [libata sata_sx4] deliver non-data taskfiles using Promise packet format # # drivers/scsi/sata_promise.c # 2004/07/07 19:38:58-04:00 jgarzik@pobox.com +1 -1 # [libata sata_sx4] deliver non-data taskfiles using Promise packet format # # ChangeSet # 2004/07/07 19:38:51-04:00 jgarzik@pobox.com # [libata sata_promise] convert to using packets for non-data taskfiles # # drivers/scsi/sata_promise.c # 2004/07/07 19:38:47-04:00 jgarzik@pobox.com +27 -41 # [libata sata_promise] convert to using packets for non-data taskfiles # # ChangeSet # 2004/07/07 19:38:04-04:00 jgarzik@pobox.com # [libata] convert set-xfer-mode operation to use ata_queued_cmd # # drivers/scsi/libata-core.c # 2004/07/07 19:37:54-04:00 jgarzik@pobox.com +27 -17 # [libata] convert set-xfer-mode operation to use ata_queued_cmd # # ChangeSet # 2004/07/07 15:57:00-04:00 jgarzik@pobox.com # [libata] pio/dma flag bug fix, and cleanup # # In the transfer-mode cleanup recently, the code that set flag # ATA_DFLAG_PIO disappeared. Resurrect it. # # Remove ATA_QCFLAG_DMA, it isn't needed. # # Always set polling in the ->qc_issue function, rather than force # the user to do it when setting up an ata_queued_cmd. This gives # maximum flexibility to the driver, letting the driver choose # whether or not to poll. # # include/linux/libata.h # 2004/07/07 15:56:50-04:00 jgarzik@pobox.com +0 -2 # [libata] pio/dma flag bug fix, and cleanup # # In the transfer-mode cleanup recently, the code that set flag # ATA_DFLAG_PIO disappeared. Resurrect it. # # Remove ATA_QCFLAG_DMA, it isn't needed. # # Always set polling in the ->qc_issue function, rather than force # the user to do it when setting up an ata_queued_cmd. This gives # maximum flexibility to the driver, letting the driver choose # whether or not to poll. # # drivers/scsi/libata-scsi.c # 2004/07/07 15:56:50-04:00 jgarzik@pobox.com +5 -4 # [libata] pio/dma flag bug fix, and cleanup # # In the transfer-mode cleanup recently, the code that set flag # ATA_DFLAG_PIO disappeared. Resurrect it. # # Remove ATA_QCFLAG_DMA, it isn't needed. # # Always set polling in the ->qc_issue function, rather than force # the user to do it when setting up an ata_queued_cmd. This gives # maximum flexibility to the driver, letting the driver choose # whether or not to poll. # # drivers/scsi/libata-core.c # 2004/07/07 15:56:50-04:00 jgarzik@pobox.com +4 -2 # [libata] pio/dma flag bug fix, and cleanup # # In the transfer-mode cleanup recently, the code that set flag # ATA_DFLAG_PIO disappeared. Resurrect it. # # Remove ATA_QCFLAG_DMA, it isn't needed. # # Always set polling in the ->qc_issue function, rather than force # the user to do it when setting up an ata_queued_cmd. This gives # maximum flexibility to the driver, letting the driver choose # whether or not to poll. # # ChangeSet # 2004/07/04 23:42:24-04:00 jgarzik@pobox.com # [libata] transfer mode bug fixes and type cleanup # # Fix two bugs that causes the recently-added transfer mode code # to break on 64-bit platforms. Make associated code more type-correct # in the process. # # include/linux/libata.h # 2004/07/04 23:42:20-04:00 jgarzik@pobox.com +3 -3 # [libata] transfer mode bug fixes and type cleanup # # Fix two bugs that causes the recently-added transfer mode code # to break on 64-bit platforms. Make associated code more type-correct # in the process. # # drivers/scsi/libata-core.c # 2004/07/04 23:42:20-04:00 jgarzik@pobox.com +33 -21 # [libata] transfer mode bug fixes and type cleanup # # Fix two bugs that causes the recently-added transfer mode code # to break on 64-bit platforms. Make associated code more type-correct # in the process. # # ChangeSet # 2004/07/04 23:41:48-04:00 jgarzik@pobox.com # [libata] fix completion bug, better debug output # # When using a completion, we need to clear the entry, and furthermore # clear the entry before we call the completion. # # Make debugging output a bit more explicit. # # drivers/scsi/libata-core.c # 2004/07/04 23:41:37-04:00 jgarzik@pobox.com +10 -4 # [libata] fix completion bug, better debug output # # When using a completion, we need to clear the entry, and furthermore # clear the entry before we call the completion. # # Make debugging output a bit more explicit. # # ChangeSet # 2004/07/04 17:42:35-04:00 jgarzik@pobox.com # [libata] transfer mode cleanup # # Add MWDMA support, and rework pio/mwdma/udma mode setup. # # In the lone test case for PATA support, ata_piix, MWDMA mode setting # does not appear to work here. UDMA and PIO continue to work, so nobody # will really notice. But beware. Probably a driver problem, not # a bug in the core. # # Also, doesn't bother writing to dummy timing registers on ICH5/6 SATA # anymore. # # include/linux/libata.h # 2004/07/04 17:42:24-04:00 jgarzik@pobox.com +15 -6 # [libata] transfer mode cleanup # # Add MWDMA support, and rework pio/mwdma/udma mode setup. # # In the lone test case for PATA support, ata_piix, MWDMA mode setting # does not appear to work here. UDMA and PIO continue to work, so nobody # will really notice. But beware. Probably a driver problem, not # a bug in the core. # # Also, doesn't bother writing to dummy timing registers on ICH5/6 SATA # anymore. # # include/linux/ata.h # 2004/07/04 17:42:24-04:00 jgarzik@pobox.com +7 -0 # [libata] transfer mode cleanup # # Add MWDMA support, and rework pio/mwdma/udma mode setup. # # In the lone test case for PATA support, ata_piix, MWDMA mode setting # does not appear to work here. UDMA and PIO continue to work, so nobody # will really notice. But beware. Probably a driver problem, not # a bug in the core. # # Also, doesn't bother writing to dummy timing registers on ICH5/6 SATA # anymore. # # drivers/scsi/sata_vsc.c # 2004/07/04 17:42:24-04:00 jgarzik@pobox.com +1 -0 # [libata] transfer mode cleanup # # Add MWDMA support, and rework pio/mwdma/udma mode setup. # # In the lone test case for PATA support, ata_piix, MWDMA mode setting # does not appear to work here. UDMA and PIO continue to work, so nobody # will really notice. But beware. Probably a driver problem, not # a bug in the core. # # Also, doesn't bother writing to dummy timing registers on ICH5/6 SATA # anymore. # # drivers/scsi/sata_via.c # 2004/07/04 17:42:24-04:00 jgarzik@pobox.com +1 -0 # [libata] transfer mode cleanup # # Add MWDMA support, and rework pio/mwdma/udma mode setup. # # In the lone test case for PATA support, ata_piix, MWDMA mode setting # does not appear to work here. UDMA and PIO continue to work, so nobody # will really notice. But beware. Probably a driver problem, not # a bug in the core. # # Also, doesn't bother writing to dummy timing registers on ICH5/6 SATA # anymore. # # drivers/scsi/sata_sx4.c # 2004/07/04 17:42:24-04:00 jgarzik@pobox.com +3 -1 # [libata] transfer mode cleanup # # Add MWDMA support, and rework pio/mwdma/udma mode setup. # # In the lone test case for PATA support, ata_piix, MWDMA mode setting # does not appear to work here. UDMA and PIO continue to work, so nobody # will really notice. But beware. Probably a driver problem, not # a bug in the core. # # Also, doesn't bother writing to dummy timing registers on ICH5/6 SATA # anymore. # # drivers/scsi/sata_svw.c # 2004/07/04 17:42:24-04:00 jgarzik@pobox.com +1 -0 # [libata] transfer mode cleanup # # Add MWDMA support, and rework pio/mwdma/udma mode setup. # # In the lone test case for PATA support, ata_piix, MWDMA mode setting # does not appear to work here. UDMA and PIO continue to work, so nobody # will really notice. But beware. Probably a driver problem, not # a bug in the core. # # Also, doesn't bother writing to dummy timing registers on ICH5/6 SATA # anymore. # # drivers/scsi/sata_sis.c # 2004/07/04 17:42:24-04:00 jgarzik@pobox.com +2 -1 # [libata] transfer mode cleanup # # Add MWDMA support, and rework pio/mwdma/udma mode setup. # # In the lone test case for PATA support, ata_piix, MWDMA mode setting # does not appear to work here. UDMA and PIO continue to work, so nobody # will really notice. But beware. Probably a driver problem, not # a bug in the core. # # Also, doesn't bother writing to dummy timing registers on ICH5/6 SATA # anymore. # # drivers/scsi/sata_sil.c # 2004/07/04 17:42:24-04:00 jgarzik@pobox.com +5 -2 # [libata] transfer mode cleanup # # Add MWDMA support, and rework pio/mwdma/udma mode setup. # # In the lone test case for PATA support, ata_piix, MWDMA mode setting # does not appear to work here. UDMA and PIO continue to work, so nobody # will really notice. But beware. Probably a driver problem, not # a bug in the core. # # Also, doesn't bother writing to dummy timing registers on ICH5/6 SATA # anymore. # # drivers/scsi/sata_promise.c # 2004/07/04 17:42:24-04:00 jgarzik@pobox.com +5 -2 # [libata] transfer mode cleanup # # Add MWDMA support, and rework pio/mwdma/udma mode setup. # # In the lone test case for PATA support, ata_piix, MWDMA mode setting # does not appear to work here. UDMA and PIO continue to work, so nobody # will really notice. But beware. Probably a driver problem, not # a bug in the core. # # Also, doesn't bother writing to dummy timing registers on ICH5/6 SATA # anymore. # # drivers/scsi/sata_nv.c # 2004/07/04 17:42:24-04:00 jgarzik@pobox.com +2 -0 # [libata] transfer mode cleanup # # Add MWDMA support, and rework pio/mwdma/udma mode setup. # # In the lone test case for PATA support, ata_piix, MWDMA mode setting # does not appear to work here. UDMA and PIO continue to work, so nobody # will really notice. But beware. Probably a driver problem, not # a bug in the core. # # Also, doesn't bother writing to dummy timing registers on ICH5/6 SATA # anymore. # # drivers/scsi/libata-core.c # 2004/07/04 17:42:24-04:00 jgarzik@pobox.com +224 -181 # [libata] transfer mode cleanup # # Add MWDMA support, and rework pio/mwdma/udma mode setup. # # In the lone test case for PATA support, ata_piix, MWDMA mode setting # does not appear to work here. UDMA and PIO continue to work, so nobody # will really notice. But beware. Probably a driver problem, not # a bug in the core. # # Also, doesn't bother writing to dummy timing registers on ICH5/6 SATA # anymore. # # drivers/scsi/ata_piix.c # 2004/07/04 17:42:24-04:00 jgarzik@pobox.com +51 -30 # [libata] transfer mode cleanup # # Add MWDMA support, and rework pio/mwdma/udma mode setup. # # In the lone test case for PATA support, ata_piix, MWDMA mode setting # does not appear to work here. UDMA and PIO continue to work, so nobody # will really notice. But beware. Probably a driver problem, not # a bug in the core. # # Also, doesn't bother writing to dummy timing registers on ICH5/6 SATA # anymore. # # ChangeSet # 2004/07/04 02:13:42-04:00 jgarzik@pobox.com # [libata sata_promise] update driver to use new ->qc_issue hook # # The ->qc_issue hook was designed to allow drivers to override some # or all of the actual delivery of the taskfile to hardware. # # In the case of Promise, the hardware has its own packet format when doing # read/write DMA commands, but uses traditional ATA taskfile registers # for other types of commands. # # drivers/scsi/sata_promise.c # 2004/07/04 02:13:31-04:00 jgarzik@pobox.com +25 -15 # [libata sata_promise] update driver to use new ->qc_issue hook # # The ->qc_issue hook was designed to allow drivers to override some # or all of the actual delivery of the taskfile to hardware. # # In the case of Promise, the hardware has its own packet format when doing # read/write DMA commands, but uses traditional ATA taskfile registers # for other types of commands. # # ChangeSet # 2004/07/04 00:57:58-04:00 jgarzik@pobox.com # [libata] create, and use aga_sg_init[_one] helpers # # Move more SCSI-specific code out of libata core. # # include/linux/libata.h # 2004/07/04 00:57:56-04:00 jgarzik@pobox.com +5 -0 # [libata] create, and use aga_sg_init[_one] helpers # # Move more SCSI-specific code out of libata core. # # drivers/scsi/libata-scsi.c # 2004/07/04 00:57:56-04:00 jgarzik@pobox.com +3 -2 # [libata] create, and use aga_sg_init[_one] helpers # # Move more SCSI-specific code out of libata core. # # drivers/scsi/libata-core.c # 2004/07/04 00:57:56-04:00 jgarzik@pobox.com +34 -18 # [libata] create, and use aga_sg_init[_one] helpers # # Move more SCSI-specific code out of libata core. # # ChangeSet # 2004/07/04 00:26:54-04:00 jgarzik@pobox.com # [libata] split ATA_QCFLAG_SG into ATA_QCFLAG_{SG,SINGLE} # # In part of the effort to remove SCSI specifics from the libata # internals, remove references to cmd->use_sg. cmd->use_sg # becomes ATA_QCFLAG_SG, and !cmd->use_sg becomes ATA_QCFLAG_SINGLE. # # Convenience constant ATA_QCFLAG_DMAMAP is created when the programmer # wishes to refer collectively to ATA_QCFLAG_{SG,SINGLE}. # # include/linux/libata.h # 2004/07/04 00:26:50-04:00 jgarzik@pobox.com +7 -1 # [libata] split ATA_QCFLAG_SG into ATA_QCFLAG_{SG,SINGLE} # # In part of the effort to remove SCSI specifics from the libata # internals, remove references to cmd->use_sg. cmd->use_sg # becomes ATA_QCFLAG_SG, and !cmd->use_sg becomes ATA_QCFLAG_SINGLE. # # Convenience constant ATA_QCFLAG_DMAMAP is created when the programmer # wishes to refer collectively to ATA_QCFLAG_{SG,SINGLE}. # # drivers/scsi/sata_sx4.c # 2004/07/04 00:26:50-04:00 jgarzik@pobox.com +1 -1 # [libata] split ATA_QCFLAG_SG into ATA_QCFLAG_{SG,SINGLE} # # In part of the effort to remove SCSI specifics from the libata # internals, remove references to cmd->use_sg. cmd->use_sg # becomes ATA_QCFLAG_SG, and !cmd->use_sg becomes ATA_QCFLAG_SINGLE. # # Convenience constant ATA_QCFLAG_DMAMAP is created when the programmer # wishes to refer collectively to ATA_QCFLAG_{SG,SINGLE}. # # drivers/scsi/libata-scsi.c # 2004/07/04 00:26:50-04:00 jgarzik@pobox.com +7 -1 # [libata] split ATA_QCFLAG_SG into ATA_QCFLAG_{SG,SINGLE} # # In part of the effort to remove SCSI specifics from the libata # internals, remove references to cmd->use_sg. cmd->use_sg # becomes ATA_QCFLAG_SG, and !cmd->use_sg becomes ATA_QCFLAG_SINGLE. # # Convenience constant ATA_QCFLAG_DMAMAP is created when the programmer # wishes to refer collectively to ATA_QCFLAG_{SG,SINGLE}. # # drivers/scsi/libata-core.c # 2004/07/04 00:26:50-04:00 jgarzik@pobox.com +17 -23 # [libata] split ATA_QCFLAG_SG into ATA_QCFLAG_{SG,SINGLE} # # In part of the effort to remove SCSI specifics from the libata # internals, remove references to cmd->use_sg. cmd->use_sg # becomes ATA_QCFLAG_SG, and !cmd->use_sg becomes ATA_QCFLAG_SINGLE. # # Convenience constant ATA_QCFLAG_DMAMAP is created when the programmer # wishes to refer collectively to ATA_QCFLAG_{SG,SINGLE}. # # ChangeSet # 2004/07/03 22:42:52-04:00 jgarzik@pobox.com # [ata] add ata_ok() inlined helper, and ATA_{DRDY,DF} bit to linux/ata.h # # include/linux/ata.h # 2004/07/03 22:42:50-04:00 jgarzik@pobox.com +9 -1 # [ata] add ata_ok() inlined helper, and ATA_{DRDY,DF} bit to linux/ata.h # # ChangeSet # 2004/07/03 22:41:38-04:00 jgarzik@pobox.com # [libata] create, and use, ->irq_clear hook # # This is more conservative in general, and so applies to multiple # controllers. Specifically it attempts to address irq-related issues # on the Intel ICH5/6 hardware. On Intel ICH5/6, the BMDMA 'interrupt' # status bit will be set even on non-DMA commands, which software # (and I) did not expect. # # This change clears pending interrupts once upon initialization, # and then each time ata_irq_on() is called. # # include/linux/libata.h # 2004/07/03 22:41:33-04:00 jgarzik@pobox.com +9 -1 # [libata] create, and use, ->irq_clear hook # # This is more conservative in general, and so applies to multiple # controllers. Specifically it attempts to address irq-related issues # on the Intel ICH5/6 hardware. On Intel ICH5/6, the BMDMA 'interrupt' # status bit will be set even on non-DMA commands, which software # (and I) did not expect. # # This change clears pending interrupts once upon initialization, # and then each time ata_irq_on() is called. # # drivers/scsi/sata_vsc.c # 2004/07/03 22:41:33-04:00 jgarzik@pobox.com +1 -0 # [libata] create, and use, ->irq_clear hook # # This is more conservative in general, and so applies to multiple # controllers. Specifically it attempts to address irq-related issues # on the Intel ICH5/6 hardware. On Intel ICH5/6, the BMDMA 'interrupt' # status bit will be set even on non-DMA commands, which software # (and I) did not expect. # # This change clears pending interrupts once upon initialization, # and then each time ata_irq_on() is called. # # drivers/scsi/sata_via.c # 2004/07/03 22:41:33-04:00 jgarzik@pobox.com +1 -0 # [libata] create, and use, ->irq_clear hook # # This is more conservative in general, and so applies to multiple # controllers. Specifically it attempts to address irq-related issues # on the Intel ICH5/6 hardware. On Intel ICH5/6, the BMDMA 'interrupt' # status bit will be set even on non-DMA commands, which software # (and I) did not expect. # # This change clears pending interrupts once upon initialization, # and then each time ata_irq_on() is called. # # drivers/scsi/sata_sx4.c # 2004/07/03 22:41:33-04:00 jgarzik@pobox.com +12 -0 # [libata] create, and use, ->irq_clear hook # # This is more conservative in general, and so applies to multiple # controllers. Specifically it attempts to address irq-related issues # on the Intel ICH5/6 hardware. On Intel ICH5/6, the BMDMA 'interrupt' # status bit will be set even on non-DMA commands, which software # (and I) did not expect. # # This change clears pending interrupts once upon initialization, # and then each time ata_irq_on() is called. # # drivers/scsi/sata_svw.c # 2004/07/03 22:41:33-04:00 jgarzik@pobox.com +1 -0 # [libata] create, and use, ->irq_clear hook # # This is more conservative in general, and so applies to multiple # controllers. Specifically it attempts to address irq-related issues # on the Intel ICH5/6 hardware. On Intel ICH5/6, the BMDMA 'interrupt' # status bit will be set even on non-DMA commands, which software # (and I) did not expect. # # This change clears pending interrupts once upon initialization, # and then each time ata_irq_on() is called. # # drivers/scsi/sata_sis.c # 2004/07/03 22:41:33-04:00 jgarzik@pobox.com +1 -0 # [libata] create, and use, ->irq_clear hook # # This is more conservative in general, and so applies to multiple # controllers. Specifically it attempts to address irq-related issues # on the Intel ICH5/6 hardware. On Intel ICH5/6, the BMDMA 'interrupt' # status bit will be set even on non-DMA commands, which software # (and I) did not expect. # # This change clears pending interrupts once upon initialization, # and then each time ata_irq_on() is called. # # drivers/scsi/sata_sil.c # 2004/07/03 22:41:33-04:00 jgarzik@pobox.com +1 -0 # [libata] create, and use, ->irq_clear hook # # This is more conservative in general, and so applies to multiple # controllers. Specifically it attempts to address irq-related issues # on the Intel ICH5/6 hardware. On Intel ICH5/6, the BMDMA 'interrupt' # status bit will be set even on non-DMA commands, which software # (and I) did not expect. # # This change clears pending interrupts once upon initialization, # and then each time ata_irq_on() is called. # # drivers/scsi/sata_promise.c # 2004/07/03 22:41:33-04:00 jgarzik@pobox.com +10 -0 # [libata] create, and use, ->irq_clear hook # # This is more conservative in general, and so applies to multiple # controllers. Specifically it attempts to address irq-related issues # on the Intel ICH5/6 hardware. On Intel ICH5/6, the BMDMA 'interrupt' # status bit will be set even on non-DMA commands, which software # (and I) did not expect. # # This change clears pending interrupts once upon initialization, # and then each time ata_irq_on() is called. # # drivers/scsi/sata_nv.c # 2004/07/03 22:41:33-04:00 jgarzik@pobox.com +1 -0 # [libata] create, and use, ->irq_clear hook # # This is more conservative in general, and so applies to multiple # controllers. Specifically it attempts to address irq-related issues # on the Intel ICH5/6 hardware. On Intel ICH5/6, the BMDMA 'interrupt' # status bit will be set even on non-DMA commands, which software # (and I) did not expect. # # This change clears pending interrupts once upon initialization, # and then each time ata_irq_on() is called. # # drivers/scsi/libata-core.c # 2004/07/03 22:41:33-04:00 jgarzik@pobox.com +11 -6 # [libata] create, and use, ->irq_clear hook # # This is more conservative in general, and so applies to multiple # controllers. Specifically it attempts to address irq-related issues # on the Intel ICH5/6 hardware. On Intel ICH5/6, the BMDMA 'interrupt' # status bit will be set even on non-DMA commands, which software # (and I) did not expect. # # This change clears pending interrupts once upon initialization, # and then each time ata_irq_on() is called. # # drivers/scsi/ata_piix.c # 2004/07/03 22:41:33-04:00 jgarzik@pobox.com +2 -0 # [libata] create, and use, ->irq_clear hook # # This is more conservative in general, and so applies to multiple # controllers. Specifically it attempts to address irq-related issues # on the Intel ICH5/6 hardware. On Intel ICH5/6, the BMDMA 'interrupt' # status bit will be set even on non-DMA commands, which software # (and I) did not expect. # # This change clears pending interrupts once upon initialization, # and then each time ata_irq_on() is called. # # ChangeSet # 2004/07/03 02:20:08-04:00 jfbeam@bluetronic.net # [libata sata_sil] add drive to mod15write quirk list # # drivers/scsi/sata_sil.c # 2004/07/03 02:20:04-04:00 jfbeam@bluetronic.net +1 -0 # [libata sata_sil] add drive to mod15write quirk list # # ChangeSet # 2004/07/03 00:24:01-04:00 jgarzik@pobox.com # [libata] add ata_queued_cmd completion hook # # include/linux/libata.h # 2004/07/03 00:23:59-04:00 jgarzik@pobox.com +2 -2 # [libata] add ata_queued_cmd completion hook # # drivers/scsi/libata-scsi.c # 2004/07/03 00:23:59-04:00 jgarzik@pobox.com +20 -0 # [libata] add ata_queued_cmd completion hook # # drivers/scsi/libata-core.c # 2004/07/03 00:23:59-04:00 jgarzik@pobox.com +8 -12 # [libata] add ata_queued_cmd completion hook # # ChangeSet # 2004/07/03 00:08:50-04:00 jgarzik@pobox.com # [libata] add ->qc_issue hook # # This hook is used when an ATA controller wishes to use # hardware-specific methods of taskfile delivery, rather # than the standard method of bitbanging the ATA shadow # registers. # # include/linux/libata.h # 2004/07/03 00:08:47-04:00 jgarzik@pobox.com +4 -0 # [libata] add ->qc_issue hook # # This hook is used when an ATA controller wishes to use # hardware-specific methods of taskfile delivery, rather # than the standard method of bitbanging the ATA shadow # registers. # # drivers/scsi/sata_vsc.c # 2004/07/03 00:08:47-04:00 jgarzik@pobox.com +1 -0 # [libata] add ->qc_issue hook # # This hook is used when an ATA controller wishes to use # hardware-specific methods of taskfile delivery, rather # than the standard method of bitbanging the ATA shadow # registers. # # drivers/scsi/sata_via.c # 2004/07/03 00:08:47-04:00 jgarzik@pobox.com +2 -0 # [libata] add ->qc_issue hook # # This hook is used when an ATA controller wishes to use # hardware-specific methods of taskfile delivery, rather # than the standard method of bitbanging the ATA shadow # registers. # # drivers/scsi/sata_sx4.c # 2004/07/03 00:08:47-04:00 jgarzik@pobox.com +1 -0 # [libata] add ->qc_issue hook # # This hook is used when an ATA controller wishes to use # hardware-specific methods of taskfile delivery, rather # than the standard method of bitbanging the ATA shadow # registers. # # drivers/scsi/sata_svw.c # 2004/07/03 00:08:47-04:00 jgarzik@pobox.com +1 -0 # [libata] add ->qc_issue hook # # This hook is used when an ATA controller wishes to use # hardware-specific methods of taskfile delivery, rather # than the standard method of bitbanging the ATA shadow # registers. # # drivers/scsi/sata_sis.c # 2004/07/03 00:08:47-04:00 jgarzik@pobox.com +1 -0 # [libata] add ->qc_issue hook # # This hook is used when an ATA controller wishes to use # hardware-specific methods of taskfile delivery, rather # than the standard method of bitbanging the ATA shadow # registers. # # drivers/scsi/sata_sil.c # 2004/07/03 00:08:47-04:00 jgarzik@pobox.com +1 -0 # [libata] add ->qc_issue hook # # This hook is used when an ATA controller wishes to use # hardware-specific methods of taskfile delivery, rather # than the standard method of bitbanging the ATA shadow # registers. # # drivers/scsi/sata_promise.c # 2004/07/03 00:08:47-04:00 jgarzik@pobox.com +1 -0 # [libata] add ->qc_issue hook # # This hook is used when an ATA controller wishes to use # hardware-specific methods of taskfile delivery, rather # than the standard method of bitbanging the ATA shadow # registers. # # drivers/scsi/sata_nv.c # 2004/07/03 00:08:47-04:00 jgarzik@pobox.com +1 -0 # [libata] add ->qc_issue hook # # This hook is used when an ATA controller wishes to use # hardware-specific methods of taskfile delivery, rather # than the standard method of bitbanging the ATA shadow # registers. # # drivers/scsi/libata-core.c # 2004/07/03 00:08:47-04:00 jgarzik@pobox.com +3 -3 # [libata] add ->qc_issue hook # # This hook is used when an ATA controller wishes to use # hardware-specific methods of taskfile delivery, rather # than the standard method of bitbanging the ATA shadow # registers. # # drivers/scsi/ata_piix.c # 2004/07/03 00:08:47-04:00 jgarzik@pobox.com +4 -0 # [libata] add ->qc_issue hook # # This hook is used when an ATA controller wishes to use # hardware-specific methods of taskfile delivery, rather # than the standard method of bitbanging the ATA shadow # registers. # # ChangeSet # 2004/07/02 23:51:35-04:00 jgarzik@pobox.com # Merge pobox.com:/spare/repo/linux-2.4 # into pobox.com:/spare/repo/libata-upstream-2.4 # # Documentation/Configure.help # 2004/07/02 23:51:34-04:00 jgarzik@pobox.com +0 -0 # Auto merged # # ChangeSet # 2004/07/01 13:56:38-07:00 davem@nuts.davemloft.net # [SPARC64]: Duh, s/_PAGE_FILE/_PAGE_EXEC/. # # include/asm-sparc64/pgtable.h # 2004/07/01 13:56:30-07:00 davem@nuts.davemloft.net +1 -1 # [SPARC64]: Duh, s/_PAGE_FILE/_PAGE_EXEC/. # # ChangeSet # 2004/07/01 00:51:09-07:00 davem@nuts.davemloft.net # [SPARC64]: Non-executable page support. # # Based upon the PAX patches. # # Signed-off-by: David S. Miller # # include/asm-sparc64/pgtable.h # 2004/07/01 00:50:57-07:00 davem@nuts.davemloft.net +21 -10 # [SPARC64]: Non-executable page support. # # Based upon the PAX patches. # # Signed-off-by: David S. Miller # # arch/sparc64/mm/fault.c # 2004/07/01 00:50:57-07:00 davem@nuts.davemloft.net +11 -1 # [SPARC64]: Non-executable page support. # # Based upon the PAX patches. # # Signed-off-by: David S. Miller # # arch/sparc64/kernel/itlb_base.S # 2004/07/01 00:50:57-07:00 davem@nuts.davemloft.net +3 -4 # [SPARC64]: Non-executable page support. # # Based upon the PAX patches. # # Signed-off-by: David S. Miller # # ChangeSet # 2004/07/01 00:46:27-07:00 davem@nuts.davemloft.net # [SPARC64]: Reserve a software PTE bit for _PAGE_EXEC. # # Based upon the PAX sparc64 patches. Also, format # the comments here so the lines fit in 80 columns. # # Signed-off-by: David S. Miller # # include/asm-sparc64/pgtable.h # 2004/07/01 00:46:13-07:00 davem@nuts.davemloft.net +28 -27 # [SPARC64]: Reserve a software PTE bit for _PAGE_EXEC. # # Based upon the PAX sparc64 patches. Also, format # the comments here so the lines fit in 80 columns. # # Signed-off-by: David S. Miller # # ChangeSet # 2004/06/30 20:26:04-07:00 davem@nuts.davemloft.net # [SPARC64]: Document reserved and soft2 bits in PTE. # # include/asm-sparc64/pgtable.h # 2004/06/30 20:25:58-07:00 davem@nuts.davemloft.net +3 -0 # [SPARC64]: Document reserved and soft2 bits in PTE. # # ChangeSet # 2004/06/30 19:45:39-04:00 jgarzik@pobox.com # [libata sata_sil] Re-fix mod15write bug # # (note: this bug was not present in 2.4) # # Certain early SATA drives have problems with write requests whose # length satisfy the equation "sectors % 15 == 1", on the SiI 3112. # Other drives, and other SiI controllers, are not affected. # # The fix for this problem is to avoid such requests, in one of three # ways, for the affect drive+controller combos: # 1) Limit all writes to 15 sectors # 2) Use block layer features to avoid creating requests whose # length satisfies the above equation. # 3) When a request satisfies the above equation, split the request # into two writes, neither of which satisfies the equation. # # I chose fix #1, the most simple to implement. After discussion with # Silicon Image and others regarding the impact of this fix, I have # decided to remain with fix #1, and will not be implementing a # "better fix". This means that the affected SATA drives will see # decreased performance, but set of affected drives is small and will # never grow larger. # # Further, the complexity of implementing solution #2 or # solution #3 is rather large. # # When implementing lba48 'large request' support, I unintentionally # broke the fix for these affected drives. Kudos to Ricky Beam for # noticing this. # # This change restores the fix, by adding a flag ATA_DFLAG_LOCK_SECTORS # to indicate that the max_sectors value set by the low-level driver # should never be changed. # # include/linux/libata.h # 2004/06/30 19:45:38-04:00 jgarzik@pobox.com +1 -0 # [libata sata_sil] Re-fix mod15write bug # # Certain early SATA drives have problems with write requests whose # length satisfy the equation "sectors % 15 == 1", on the SiI 3112. # Other drives, and other SiI controllers, are not affected. # # The fix for this problem is to avoid such requests, in one of three # ways, for the affect drive+controller combos: # 1) Limit all writes to 15 sectors # 2) Use block layer features to avoid creating requests whose # length satisfies the above equation. # 3) When a request satisfies the above equation, split the request # into two writes, neither of which satisfies the equation. # # I chose fix #1, the most simple to implement. After discussion with # Silicon Image and others regarding the impact of this fix, I have # decided to remain with fix #1, and will not be implementing a # "better fix". This means that the affected SATA drives will see # decreased performance, but set of affected drives is small and will # never grow larger. # # Further, the complexity of implementing solution #2 or # solution #3 is rather large. # # When implementing lba48 'large request' support, I unintentionally # broke the fix for these affected drives. Kudos to Ricky Beam for # noticing this. # # This change restores the fix, by adding a flag ATA_DFLAG_LOCK_SECTORS # to indicate that the max_sectors value set by the low-level driver # should never be changed. # # drivers/scsi/sata_sil.c # 2004/06/30 19:45:38-04:00 jgarzik@pobox.com +1 -0 # [libata sata_sil] Re-fix mod15write bug # # Certain early SATA drives have problems with write requests whose # length satisfy the equation "sectors % 15 == 1", on the SiI 3112. # Other drives, and other SiI controllers, are not affected. # # The fix for this problem is to avoid such requests, in one of three # ways, for the affect drive+controller combos: # 1) Limit all writes to 15 sectors # 2) Use block layer features to avoid creating requests whose # length satisfies the above equation. # 3) When a request satisfies the above equation, split the request # into two writes, neither of which satisfies the equation. # # I chose fix #1, the most simple to implement. After discussion with # Silicon Image and others regarding the impact of this fix, I have # decided to remain with fix #1, and will not be implementing a # "better fix". This means that the affected SATA drives will see # decreased performance, but set of affected drives is small and will # never grow larger. # # Further, the complexity of implementing solution #2 or # solution #3 is rather large. # # When implementing lba48 'large request' support, I unintentionally # broke the fix for these affected drives. Kudos to Ricky Beam for # noticing this. # # This change restores the fix, by adding a flag ATA_DFLAG_LOCK_SECTORS # to indicate that the max_sectors value set by the low-level driver # should never be changed. # # ChangeSet # 2004/06/22 02:12:56-04:00 jgarzik@pobox.com # [libata ata_piix] combined mode bug fix; improved ICH6 support # # drivers/scsi/ata_piix.c # 2004/06/22 02:12:44-04:00 jgarzik@pobox.com +14 -11 # [libata ata_piix] combined mode bug fix; improved ICH6 support # # ChangeSet # 2004/06/22 00:55:46-04:00 jgarzik@pobox.com # [libata] fix build error, minor cleanups # # include/linux/libata.h # 2004/06/22 00:55:35-04:00 jgarzik@pobox.com +0 -5 # [libata] fix build error, minor cleanups # # drivers/scsi/libata-core.c # 2004/06/22 00:55:35-04:00 jgarzik@pobox.com +2 -3 # [libata] fix build error, minor cleanups # # ChangeSet # 2004/06/22 00:36:38-04:00 jgarzik@pobox.com # [libata] move some code around # # Split ata_eng_timeout into the main part (ata_qc_timeout) # and the part called by the SCSI layer (ata_eng_timeout). # # Zero behavior changes. # # drivers/scsi/libata-core.c # 2004/06/22 00:36:26-04:00 jgarzik@pobox.com +42 -12 # [libata] move some code around # # Split ata_eng_timeout into the main part (ata_qc_timeout) # and the part called by the SCSI layer (ata_eng_timeout). # # Zero behavior changes. # # ChangeSet # 2004/06/21 23:47:40-04:00 bunk@fs.tum.de # [PATCH] 2.6.7-mm1: drivers/scsi/hosts.h -> scsi/scsi_host.h # # On Sun, Jun 20, 2004 at 05:46:32PM -0700, Andrew Morton wrote: # >... # > All 226 patches: # >... # > bk-libata.patch # >... # # drivers/scsi/hosts.h is obsolete, use scsi/scsi_host.h. # # Please apply # Adrian # # drivers/scsi/sata_nv.c # 2004/06/21 23:47:28-04:00 bunk@fs.tum.de +1 -1 # [PATCH] 2.6.7-mm1: drivers/scsi/hosts.h -> scsi/scsi_host.h # # On Sun, Jun 20, 2004 at 05:46:32PM -0700, Andrew Morton wrote: # >... # > All 226 patches: # >... # > bk-libata.patch # >... # # drivers/scsi/hosts.h is obsolete, use scsi/scsi_host.h. # # Please apply # Adrian # # ChangeSet # 2004/06/17 00:26:49-04:00 jgarzik@pobox.com # [libata/IDE nvidia] shuffle pci ids # # * Mark conflicting PCI ids with CONFIG_BLK_DEV_IDE_SATA # * Move not-yet-released PCI ids to libata sata_nv driver # # drivers/scsi/sata_nv.c # 2004/06/17 00:26:48-04:00 jgarzik@pobox.com +11 -3 # [libata/IDE nvidia] shuffle pci ids # # * Mark conflicting PCI ids with CONFIG_BLK_DEV_IDE_SATA # * Move not-yet-released PCI ids to libata sata_nv driver # # drivers/ide/pci/amd74xx.h # 2004/06/17 00:26:48-04:00 jgarzik@pobox.com +0 -44 # [libata/IDE nvidia] shuffle pci ids # # * Mark conflicting PCI ids with CONFIG_BLK_DEV_IDE_SATA # * Move not-yet-released PCI ids to libata sata_nv driver # # drivers/ide/pci/amd74xx.c # 2004/06/17 00:26:48-04:00 jgarzik@pobox.com +5 -9 # [libata/IDE nvidia] shuffle pci ids # # * Mark conflicting PCI ids with CONFIG_BLK_DEV_IDE_SATA # * Move not-yet-released PCI ids to libata sata_nv driver # # ChangeSet # 2004/06/17 00:11:00-04:00 B.Zolnierkiewicz@elka.pw.edu.pl # [PATCH] DMA mode setup fixes for piix.c/ata_piix.c # # From: Go Taniguchi (Turbolinx Inc.) # # Change reg48 and reg54 in 8bit access and remove unused reg44. # # Jeff acked ata_piix.c part. # # Signed-off-by: Bartlomiej Zolnierkiewicz # Signed-off-by: Linus Torvalds # # drivers/scsi/ata_piix.c # 2004/06/17 00:10:59-04:00 B.Zolnierkiewicz@elka.pw.edu.pl +11 -16 # [PATCH] DMA mode setup fixes for piix.c/ata_piix.c # # From: Go Taniguchi (Turbolinx Inc.) # # Change reg48 and reg54 in 8bit access and remove unused reg44. # # Jeff acked ata_piix.c part. # # Signed-off-by: Bartlomiej Zolnierkiewicz # Signed-off-by: Linus Torvalds # # drivers/ide/pci/piix.c # 2004/06/17 00:10:59-04:00 B.Zolnierkiewicz@elka.pw.edu.pl +15 -20 # [PATCH] DMA mode setup fixes for piix.c/ata_piix.c # # From: Go Taniguchi (Turbolinx Inc.) # # Change reg48 and reg54 in 8bit access and remove unused reg44. # # Jeff acked ata_piix.c part. # # Signed-off-by: Bartlomiej Zolnierkiewicz # Signed-off-by: Linus Torvalds # # ChangeSet # 2004/06/16 23:54:16-04:00 jgarzik@pobox.com # [libata ata_piix] disable combined mode # # 2.4.x kernels do not have the nasty PCI/resource gunk necessary to make # combined mode work, so support for it is disabled in the driver. # # drivers/scsi/ata_piix.c # 2004/06/16 23:54:15-04:00 jgarzik@pobox.com +2 -1 # [libata ata_piix] disable combined mode # # 2.4.x kernels do not have the nasty PCI/resource gunk necessary to make # combined mode work, so support for it is disabled in the driver. # # ChangeSet # 2004/06/16 23:51:54-04:00 achew@nvidia.com # [libata] Add NVIDIA SATA driver. # # drivers/scsi/sata_nv.c # 2004/06/16 23:51:52-04:00 achew@nvidia.com +20 -12 # [libata] Add NVIDIA SATA driver. # # drivers/scsi/Makefile # 2004/06/16 23:51:52-04:00 achew@nvidia.com +1 -0 # [libata] Add NVIDIA SATA driver. # # drivers/scsi/Config.in # 2004/06/16 23:51:52-04:00 achew@nvidia.com +1 -0 # [libata] Add NVIDIA SATA driver. # # drivers/scsi/sata_nv.c # 2004/06/16 23:46:47-04:00 jgarzik@pobox.com +345 -0 # # drivers/scsi/sata_nv.c # 2004/06/16 23:46:47-04:00 jgarzik@pobox.com +0 -0 # BitKeeper file /spare/repo/libata-upstream-2.4/drivers/scsi/sata_nv.c # # ChangeSet # 2004/06/16 23:36:35-04:00 jgarzik@pobox.com # [IDE] Introduce SATA enable/disable config option # # This config option is introduced to help reduce user confusion, # and eliminate conflicts between the IDE driver (which is often # built into user kernels) and the new libata SATA driver. # # drivers/ide/pci/siimage.c # 2004/06/16 23:36:34-04:00 jgarzik@pobox.com +2 -0 # [IDE] Introduce SATA enable/disable config option # # This config option is introduced to help reduce user confusion, # and eliminate conflicts between the IDE driver (which is often # built into user kernels) and the new libata SATA driver. # # drivers/ide/pci/piix.c # 2004/06/16 23:36:33-04:00 jgarzik@pobox.com +2 -0 # [IDE] Introduce SATA enable/disable config option # # This config option is introduced to help reduce user confusion, # and eliminate conflicts between the IDE driver (which is often # built into user kernels) and the new libata SATA driver. # # drivers/ide/Config.in # 2004/06/16 23:36:33-04:00 jgarzik@pobox.com +1 -0 # [IDE] Introduce SATA enable/disable config option # # This config option is introduced to help reduce user confusion, # and eliminate conflicts between the IDE driver (which is often # built into user kernels) and the new libata SATA driver. # # Documentation/Configure.help # 2004/06/16 23:36:33-04:00 jgarzik@pobox.com +18 -0 # [IDE] Introduce SATA enable/disable config option # # This config option is introduced to help reduce user confusion, # and eliminate conflicts between the IDE driver (which is often # built into user kernels) and the new libata SATA driver. # # ChangeSet # 2004/06/16 23:17:00-04:00 jgarzik@pobox.com # [libata] Add Intel ICH5/6 driver # # drivers/scsi/Makefile # 2004/06/16 23:16:59-04:00 jgarzik@pobox.com +1 -0 # [libata] Add Intel ICH5/6 driver # # drivers/scsi/Config.in # 2004/06/16 23:16:59-04:00 jgarzik@pobox.com +1 -0 # [libata] Add Intel ICH5/6 driver # # drivers/scsi/ata_piix.c # 2004/06/16 23:16:15-04:00 jgarzik@pobox.com +597 -0 # # drivers/scsi/ata_piix.c # 2004/06/16 23:16:15-04:00 jgarzik@pobox.com +0 -0 # BitKeeper file /spare/repo/libata-upstream-2.4/drivers/scsi/ata_piix.c # # ChangeSet # 2004/06/15 00:30:33-04:00 jgarzik@pobox.com # [libata] ->qc_prep hook # # Rename ->fill_sg hook to ->qc_prep, and call it unconditionally # (as opposed to ->fill_sg, which was called only when the # flag ATA_QCFLAG_SG was set). # # include/linux/libata.h # 2004/06/15 00:30:32-04:00 jgarzik@pobox.com +2 -2 # [libata] ->qc_prep hook # # Rename ->fill_sg hook to ->qc_prep, and call it unconditionally # (as opposed to ->fill_sg, which was called only when the # flag ATA_QCFLAG_SG was set). # # drivers/scsi/sata_vsc.c # 2004/06/15 00:30:32-04:00 jgarzik@pobox.com +1 -1 # [libata] ->qc_prep hook # # Rename ->fill_sg hook to ->qc_prep, and call it unconditionally # (as opposed to ->fill_sg, which was called only when the # flag ATA_QCFLAG_SG was set). # # drivers/scsi/sata_via.c # 2004/06/15 00:30:32-04:00 jgarzik@pobox.com +1 -1 # [libata] ->qc_prep hook # # Rename ->fill_sg hook to ->qc_prep, and call it unconditionally # (as opposed to ->fill_sg, which was called only when the # flag ATA_QCFLAG_SG was set). # # drivers/scsi/sata_sx4.c # 2004/06/15 00:30:32-04:00 jgarzik@pobox.com +6 -3 # [libata] ->qc_prep hook # # Rename ->fill_sg hook to ->qc_prep, and call it unconditionally # (as opposed to ->fill_sg, which was called only when the # flag ATA_QCFLAG_SG was set). # # drivers/scsi/sata_svw.c # 2004/06/15 00:30:32-04:00 jgarzik@pobox.com +1 -1 # [libata] ->qc_prep hook # # Rename ->fill_sg hook to ->qc_prep, and call it unconditionally # (as opposed to ->fill_sg, which was called only when the # flag ATA_QCFLAG_SG was set). # # drivers/scsi/sata_sis.c # 2004/06/15 00:30:32-04:00 jgarzik@pobox.com +1 -1 # [libata] ->qc_prep hook # # Rename ->fill_sg hook to ->qc_prep, and call it unconditionally # (as opposed to ->fill_sg, which was called only when the # flag ATA_QCFLAG_SG was set). # # drivers/scsi/sata_sil.c # 2004/06/15 00:30:32-04:00 jgarzik@pobox.com +1 -1 # [libata] ->qc_prep hook # # Rename ->fill_sg hook to ->qc_prep, and call it unconditionally # (as opposed to ->fill_sg, which was called only when the # flag ATA_QCFLAG_SG was set). # # drivers/scsi/sata_promise.c # 2004/06/15 00:30:32-04:00 jgarzik@pobox.com +4 -4 # [libata] ->qc_prep hook # # Rename ->fill_sg hook to ->qc_prep, and call it unconditionally # (as opposed to ->fill_sg, which was called only when the # flag ATA_QCFLAG_SG was set). # # drivers/scsi/libata-core.c # 2004/06/15 00:30:32-04:00 jgarzik@pobox.com +29 -21 # [libata] ->qc_prep hook # # Rename ->fill_sg hook to ->qc_prep, and call it unconditionally # (as opposed to ->fill_sg, which was called only when the # flag ATA_QCFLAG_SG was set). # # ChangeSet # 2004/06/14 23:54:47-04:00 jgarzik@pobox.com # [libata] PCI IDE command-end/irq-acknowledge cleanup # # Restruct default irq handler (used for many PCI IDE-like SATA # controllers) to obtain device status and acknowledge interrupts # a bit differently. # # In an attempt to better attack the "ich5 screaming interrupt" problem, # acknowledge and clear the device's INTRQ by reading the Status register # _before_ ack'ing the controller's irq status. This is a deviation # from how the Linux IDE driver acknowledges interrupts, but it may # be the best method, since the ICH5 appears to continue to assert # the interrupt bit in the BMDMA until the device INTRQ line is cleared. # # Of course, SATA has no INTRQ line per se, so ICH5 essentially has # new interrupt behavior not seen before in the PCI IDE world, while # pretending that it's compatible with PCI IDE. Sigh. # # This change affects all SATA controllers (for which there are libata # drivers) except for sata_promise and sata_sx4. # # drivers/scsi/libata-core.c # 2004/06/14 23:54:44-04:00 jgarzik@pobox.com +57 -83 # [libata] PCI IDE command-end/irq-acknowledge cleanup # # Restruct default irq handler (used for many PCI IDE-like SATA # controllers) to obtain device status and acknowledge interrupts # a bit differently. # # In an attempt to better attack the "ich5 screaming interrupt" problem, # acknowledge and clear the device's INTRQ by reading the Status register # _before_ ack'ing the controller's irq status. This is a deviation # from how the Linux IDE driver acknowledges interrupts, but it may # be the best method, since the ICH5 appears to continue to assert # the interrupt bit in the BMDMA until the device INTRQ line is cleared. # # Of course, SATA has no INTRQ line per se, so ICH5 essentially has # new interrupt behavior not seen before in the PCI IDE world, while # pretending that it's compatible with PCI IDE. Sigh. # # This change affects all SATA controllers (for which there are libata # drivers) except for sata_promise and sata_sx4. # # ChangeSet # 2004/06/14 22:41:34-04:00 jgarzik@pobox.com # [libata] PCI IDE DMA code shuffling # # PCI IDE DMA standard (or "bmdma") helper routines ata_bmdma_stop, # ata_bmdma_ack_irq, and ata_bmdma_status are added to linux/libata.h, # and used in libata-core. # # There is a minor behavior change, such that, the Alt Status register # is read before acknowledging the bmdma interrupt. This should be ok, # and furthermore there will be more significant behavior changes # in this area coming soon. # # include/linux/libata.h # 2004/06/14 22:41:30-04:00 jgarzik@pobox.com +40 -0 # [libata] PCI IDE DMA code shuffling # # PCI IDE DMA standard (or "bmdma") helper routines ata_bmdma_stop, # ata_bmdma_ack_irq, and ata_bmdma_status are added to linux/libata.h, # and used in libata-core. # # There is a minor behavior change, such that, the Alt Status register # is read before acknowledging the bmdma interrupt. This should be ok, # and furthermore there will be more significant behavior changes # in this area coming soon. # # drivers/scsi/libata-core.c # 2004/06/14 22:41:30-04:00 jgarzik@pobox.com +4 -41 # [libata] PCI IDE DMA code shuffling # # PCI IDE DMA standard (or "bmdma") helper routines ata_bmdma_stop, # ata_bmdma_ack_irq, and ata_bmdma_status are added to linux/libata.h, # and used in libata-core. # # There is a minor behavior change, such that, the Alt Status register # is read before acknowledging the bmdma interrupt. This should be ok, # and furthermore there will be more significant behavior changes # in this area coming soon. # # ChangeSet # 2004/06/14 16:27:52-04:00 jgarzik@pobox.com # [libata] don't probe from workqueue # # Since we want the probe phase to call other workqueues, this is # required to eliminate future deadlocks. # # Other methods would include starting a single-shot thread just for # probing, but overall, using a separate thread for probing is pointless # since we are already in process context when we probe. # # So, we simply call ata_bus_probe directly. # # include/linux/libata.h # 2004/06/14 16:27:51-04:00 jgarzik@pobox.com +0 -15 # [libata] don't probe from workqueue # # Since we want the probe phase to call other workqueues, this is # required to eliminate future deadlocks. # # Other methods would include starting a single-shot thread just for # probing, but overall, using a separate thread for probing is pointless # since we are already in process context when we probe. # # So, we simply call ata_bus_probe directly. # # drivers/scsi/libata-core.c # 2004/06/14 16:27:51-04:00 jgarzik@pobox.com +19 -120 # [libata] don't probe from workqueue # # Since we want the probe phase to call other workqueues, this is # required to eliminate future deadlocks. # # Other methods would include starting a single-shot thread just for # probing, but overall, using a separate thread for probing is pointless # since we are already in process context when we probe. # # So, we simply call ata_bus_probe directly. # # ChangeSet # 2004/06/02 22:03:37-04:00 p.lavarre@ieee.org # [PATCH] ata_check_bmdma # # Move hand-coded BMDMA status check into separate function. # # drivers/scsi/libata-core.c # 2004/06/02 22:03:35-04:00 p.lavarre@ieee.org +18 -10 # [PATCH] ata_check_bmdma # # Move hand-coded BMDMA status check into separate function. # diff -Nru a/Documentation/Configure.help b/Documentation/Configure.help --- a/Documentation/Configure.help 2004-08-14 12:02:30 -07:00 +++ b/Documentation/Configure.help 2004-08-14 12:02:30 -07:00 @@ -696,6 +696,24 @@ could say N here, and select the "Old hard disk driver" below instead to save about 13 KB of memory in the kernel. +Support for SATA (deprecated; conflicts with libata SATA driver) +CONFIG_BLK_DEV_IDE_SATA + There are two drivers for Serial ATA controllers. + + The main driver, "libata", exists inside the SCSI subsystem + and supports most modern SATA controllers. + + The IDE driver (which you are currently configuring) supports + a few first-generation SATA controllers. + + In order to eliminate conflicts between the two subsystems, + this config option enables the IDE driver's SATA support. + Normally this is disabled, as it is preferred that libata + supports SATA controllers, and this (IDE) driver supports + PATA controllers. + + If unsure, say N. + Old hard disk (MFM/RLL/IDE) driver CONFIG_BLK_DEV_HD_ONLY There are two drivers for MFM/RLL/IDE hard disks. Most people use @@ -10077,6 +10095,49 @@ compile it as a module, say M here and read . +Intersil 802.11(a/b/g) Prism GT/Duette/Indigo support +CONFIG_PRISM54 + Enable PCI and Cardbus support for the following chipset based cards: + + ISL3880 - Prism GT 802.11 b/g + ISL3877 - Prism Indigo 802.11 a + ISL3890 - Prism Duette 802.11 a/b/g + + For a complete list of supported cards visit . + Here is the latest confirmed list of supported cards: + + 3com OfficeConnect 11g Cardbus Card aka 3CRWE154G72 + Allnet ALL0271 PCI Card + Compex WL54G Cardbus Card + Corega CG-WLCB54GT Cardbus Card + D-Link Air Plus Xtreme G A1 Cardbus Card aka DWL-g650 + I-O Data WN-G54/CB Cardbus Card + Kobishi XG-300 aka Z-Com Cardbus Card + Netgear WG511 Cardbus Card + Ovislink WL-5400PCI PCI Card + Peabird WLG-PCI PCI Card + Sitecom WL-100i Cardbus Card + Sitecom WL-110i PCI Card + SMC2802W - EZ Connect g 2.4GHz 54 Mbps Wireless PCI Card + SMC2835W - EZ Connect g 2.4GHz 54 Mbps Wireless Cardbus Card + Z-Com XG-900 PCI Card + Zyxel G-100 Cardbus Card + + If you enable this, you require a firmware file as well. + You will need to copy this to /usr/lib/hotplug/firmware/isl3890. + You can get this non-GPL'd firmware file from the Prism54 project page: + . + You will also need the /etc/hotplug/firmware.agent script from + a current hotplug package. + + + Note: You need a motherboard with DMA support to use any of these cards + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read . The module + will be called prism54.o. + Aironet 4500/4800 PROC interface CONFIG_AIRONET4500_PROC If you say Y here (and to the "/proc file system" below), you will @@ -28932,7 +28993,7 @@ many rounds for security. It is very fast and uses little memory. - Xtendend Tiny Encryption Algorithm is a modifcation to + Xtendend Tiny Encryption Algorithm is a modification to the TEA algorithm to address a potential key weakness in the TEA algorithm. @@ -28943,6 +29004,16 @@ bits in length. This algorithm is required for driver-based WEP, but it should not be for other purposes because of the weakness of the algorithm. + +CONFIG_CRYPTO_KHAZAD + Khazad cipher algorithm. + + Khazad was a finalist in the initial NESSIE competition. It is + an algorithm optimized for 64-bit processors with good performance + on 32-bit processors. Khazad uses an 128 bit key size. + + See also: + http://planeta.terra.com.br/informatica/paulobarreto/KhazadPage.html CONFIG_CRYPTO_DEFLATE This is the Deflate algorithm (RFC1951), specified for use in diff -Nru a/Documentation/crypto/api-intro.txt b/Documentation/crypto/api-intro.txt --- a/Documentation/crypto/api-intro.txt 2004-08-14 12:02:31 -07:00 +++ b/Documentation/crypto/api-intro.txt 2004-08-14 12:02:31 -07:00 @@ -219,6 +219,12 @@ CAST5/CAST6 algorithm contributors: Kartikey Mahendra Bhatt (original developers unknown, FSF copyright). +TEA/XTEA algorithm contributors: + Aaron Grothe + +Khazad algorithm contributors: + Aaron Grothe + Generic scatterwalk code by Adam J. Richter Please send any credits updates or corrections to: diff -Nru a/Documentation/isdn/CREDITS b/Documentation/isdn/CREDITS --- a/Documentation/isdn/CREDITS 2004-08-14 12:02:30 -07:00 +++ b/Documentation/isdn/CREDITS 2004-08-14 12:02:30 -07:00 @@ -37,7 +37,7 @@ Andreas Kool (akool@Kool.f.EUnet.de) For contribution of the isdnlog/isdnrep-tool -Pedro Roque Marques (roque@di.fc.ul.pt) +Pedro Roque Marques (pedro_m@yahoo.com) For lot of new ideas and the pcbit driver. Eberhard Moenkeberg (emoenke@gwdg.de) diff -Nru a/Documentation/isdn/README.pcbit b/Documentation/isdn/README.pcbit --- a/Documentation/isdn/README.pcbit 2004-08-14 12:02:30 -07:00 +++ b/Documentation/isdn/README.pcbit 2004-08-14 12:02:30 -07:00 @@ -37,4 +37,4 @@ regards, Pedro. - + diff -Nru a/MAINTAINERS b/MAINTAINERS --- a/MAINTAINERS 2004-08-14 12:02:30 -07:00 +++ b/MAINTAINERS 2004-08-14 12:02:30 -07:00 @@ -1735,8 +1735,8 @@ S: Maintained SPARC (sparc32): -P: Keith M. Wesolowski -M: wesolows@foobazco.org +P: William L. Irwin +M: wli@holomorphy.com L: sparclinux@vger.kernel.org S: Maintained diff -Nru a/arch/i386/kernel/dmi_scan.c b/arch/i386/kernel/dmi_scan.c --- a/arch/i386/kernel/dmi_scan.c 2004-08-14 12:02:30 -07:00 +++ b/arch/i386/kernel/dmi_scan.c 2004-08-14 12:02:30 -07:00 @@ -459,6 +459,22 @@ } /* + * Work around broken Acer TravelMate 360 Notebooks which assign Cardbus to + * IRQ 11 even though it is actually wired to IRQ 10 + */ +static __init int fix_acer_tm360_irqrouting(struct dmi_blacklist *d) +{ +#ifdef CONFIG_PCI + extern int acer_tm360_irqrouting; + if (acer_tm360_irqrouting == 0) { + acer_tm360_irqrouting = 1; + printk(KERN_INFO "%s detected - fixing broken IRQ routing\n", d->ident); + } +#endif + return 0; +} + +/* * Exploding PnPBIOS. Don't yet know if its the BIOS or us for * some entries */ @@ -820,6 +836,12 @@ MATCH(DMI_BOARD_VERSION, "OmniBook N32N-736") } }, + { fix_acer_tm360_irqrouting, "Acer TravelMate 36x Laptop", { + MATCH(DMI_SYS_VENDOR, "Acer"), + MATCH(DMI_PRODUCT_NAME, "TravelMate 360"), + NO_MATCH, NO_MATCH + } }, + /* * Generic per vendor APM settings */ @@ -935,6 +957,13 @@ /* newer BIOS, Revision 1011, does work */ MATCH(DMI_BIOS_VERSION, "ASUS A7V ACPI BIOS Revision 1007"), NO_MATCH }}, + + { disable_acpi_pci, "Acer TravelMate 36x Laptop", { + MATCH(DMI_SYS_VENDOR, "Acer"), + MATCH(DMI_PRODUCT_NAME, "TravelMate 360"), + NO_MATCH, NO_MATCH + } }, + #endif /* CONFIG_ACPI_PCI */ { NULL, } diff -Nru a/arch/i386/kernel/pci-irq.c b/arch/i386/kernel/pci-irq.c --- a/arch/i386/kernel/pci-irq.c 2004-08-14 12:02:31 -07:00 +++ b/arch/i386/kernel/pci-irq.c 2004-08-14 12:02:31 -07:00 @@ -23,6 +23,7 @@ #define PIRQ_VERSION 0x0100 int broken_hp_bios_irq9; +int acer_tm360_irqrouting; static struct irq_routing_table *pirq_table; @@ -893,6 +894,14 @@ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 11); r->set(pirq_router_dev, dev, pirq, 11); } + + /* same for Acer Travelmate 360, but with CB and irq 11 -> 10 */ + if (acer_tm360_irqrouting && dev->irq == 11 && dev->vendor == PCI_VENDOR_ID_O2) { + pirq = 0x68; + mask = 0x400; + dev->irq = r->get(pirq_router_dev, dev, pirq); + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); + } /* * Find the best IRQ to assign: use the one diff -Nru a/arch/i386/kernel/pci-pc.c b/arch/i386/kernel/pci-pc.c --- a/arch/i386/kernel/pci-pc.c 2004-08-14 12:02:30 -07:00 +++ b/arch/i386/kernel/pci-pc.c 2004-08-14 12:02:30 -07:00 @@ -177,6 +177,7 @@ }; #endif /* !CONFIG_MULTIQUAD */ +#undef PCI_CONF1_ADDRESS #define PCI_CONF1_ADDRESS(bus, dev, fn, reg) \ (0x80000000 | (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~3)) diff -Nru a/arch/s390x/kernel/ioctl32.c b/arch/s390x/kernel/ioctl32.c --- a/arch/s390x/kernel/ioctl32.c 2004-08-14 12:02:30 -07:00 +++ b/arch/s390x/kernel/ioctl32.c 2004-08-14 12:02:30 -07:00 @@ -34,6 +34,7 @@ #include #include #include +#include "../../../drivers/s390/char/tubio.h" #include "linux32.h" @@ -535,6 +536,12 @@ IOCTL32_HANDLER(HDIO_GETGEO, hd_geometry_ioctl), + IOCTL32_DEFAULT(TUBICMD), + IOCTL32_DEFAULT(TUBOCMD), + IOCTL32_DEFAULT(TUBGETI), + IOCTL32_DEFAULT(TUBGETO), + IOCTL32_DEFAULT(TUBSETMOD), + IOCTL32_DEFAULT(TUBGETMOD), IOCTL32_DEFAULT(TCGETA), IOCTL32_DEFAULT(TCSETA), IOCTL32_DEFAULT(TCSETAW), diff -Nru a/arch/sparc/lib/copy_user.S b/arch/sparc/lib/copy_user.S --- a/arch/sparc/lib/copy_user.S 2004-08-14 12:02:30 -07:00 +++ b/arch/sparc/lib/copy_user.S 2004-08-14 12:02:30 -07:00 @@ -65,52 +65,52 @@ /* Both these macros have to start with exactly the same insn */ #define MOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \ - ldd [%src + offset + 0x00], %t0; \ - ldd [%src + offset + 0x08], %t2; \ - ldd [%src + offset + 0x10], %t4; \ - ldd [%src + offset + 0x18], %t6; \ - st %t0, [%dst + offset + 0x00]; \ - st %t1, [%dst + offset + 0x04]; \ - st %t2, [%dst + offset + 0x08]; \ - st %t3, [%dst + offset + 0x0c]; \ - st %t4, [%dst + offset + 0x10]; \ - st %t5, [%dst + offset + 0x14]; \ - st %t6, [%dst + offset + 0x18]; \ - st %t7, [%dst + offset + 0x1c]; + ldd [%src + (offset) + 0x00], %t0; \ + ldd [%src + (offset) + 0x08], %t2; \ + ldd [%src + (offset) + 0x10], %t4; \ + ldd [%src + (offset) + 0x18], %t6; \ + st %t0, [%dst + (offset) + 0x00]; \ + st %t1, [%dst + (offset) + 0x04]; \ + st %t2, [%dst + (offset) + 0x08]; \ + st %t3, [%dst + (offset) + 0x0c]; \ + st %t4, [%dst + (offset) + 0x10]; \ + st %t5, [%dst + (offset) + 0x14]; \ + st %t6, [%dst + (offset) + 0x18]; \ + st %t7, [%dst + (offset) + 0x1c]; #define MOVE_BIGALIGNCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \ - ldd [%src + offset + 0x00], %t0; \ - ldd [%src + offset + 0x08], %t2; \ - ldd [%src + offset + 0x10], %t4; \ - ldd [%src + offset + 0x18], %t6; \ - std %t0, [%dst + offset + 0x00]; \ - std %t2, [%dst + offset + 0x08]; \ - std %t4, [%dst + offset + 0x10]; \ - std %t6, [%dst + offset + 0x18]; + ldd [%src + (offset) + 0x00], %t0; \ + ldd [%src + (offset) + 0x08], %t2; \ + ldd [%src + (offset) + 0x10], %t4; \ + ldd [%src + (offset) + 0x18], %t6; \ + std %t0, [%dst + (offset) + 0x00]; \ + std %t2, [%dst + (offset) + 0x08]; \ + std %t4, [%dst + (offset) + 0x10]; \ + std %t6, [%dst + (offset) + 0x18]; #define MOVE_LASTCHUNK(src, dst, offset, t0, t1, t2, t3) \ - ldd [%src - offset - 0x10], %t0; \ - ldd [%src - offset - 0x08], %t2; \ - st %t0, [%dst - offset - 0x10]; \ - st %t1, [%dst - offset - 0x0c]; \ - st %t2, [%dst - offset - 0x08]; \ - st %t3, [%dst - offset - 0x04]; + ldd [%src - (offset) - 0x10], %t0; \ + ldd [%src - (offset) - 0x08], %t2; \ + st %t0, [%dst - (offset) - 0x10]; \ + st %t1, [%dst - (offset) - 0x0c]; \ + st %t2, [%dst - (offset) - 0x08]; \ + st %t3, [%dst - (offset) - 0x04]; #define MOVE_HALFCHUNK(src, dst, offset, t0, t1, t2, t3) \ - lduh [%src + offset + 0x00], %t0; \ - lduh [%src + offset + 0x02], %t1; \ - lduh [%src + offset + 0x04], %t2; \ - lduh [%src + offset + 0x06], %t3; \ - sth %t0, [%dst + offset + 0x00]; \ - sth %t1, [%dst + offset + 0x02]; \ - sth %t2, [%dst + offset + 0x04]; \ - sth %t3, [%dst + offset + 0x06]; + lduh [%src + (offset) + 0x00], %t0; \ + lduh [%src + (offset) + 0x02], %t1; \ + lduh [%src + (offset) + 0x04], %t2; \ + lduh [%src + (offset) + 0x06], %t3; \ + sth %t0, [%dst + (offset) + 0x00]; \ + sth %t1, [%dst + (offset) + 0x02]; \ + sth %t2, [%dst + (offset) + 0x04]; \ + sth %t3, [%dst + (offset) + 0x06]; #define MOVE_SHORTCHUNK(src, dst, offset, t0, t1) \ - ldub [%src - offset - 0x02], %t0; \ - ldub [%src - offset - 0x01], %t1; \ - stb %t0, [%dst - offset - 0x02]; \ - stb %t1, [%dst - offset - 0x01]; + ldub [%src - (offset) - 0x02], %t0; \ + ldub [%src - (offset) - 0x01], %t1; \ + stb %t0, [%dst - (offset) - 0x02]; \ + stb %t1, [%dst - (offset) - 0x01]; .text .align 4 diff -Nru a/arch/sparc64/kernel/itlb_base.S b/arch/sparc64/kernel/itlb_base.S --- a/arch/sparc64/kernel/itlb_base.S 2004-08-14 12:02:30 -07:00 +++ b/arch/sparc64/kernel/itlb_base.S 2004-08-14 12:02:30 -07:00 @@ -41,7 +41,9 @@ CREATE_VPTE_OFFSET2(%g4, %g6) ! Create VPTE offset ldxa [%g3 + %g6] ASI_P, %g5 ! Load VPTE 1: brgez,pn %g5, 3f ! Not valid, branch out - nop ! Delay-slot + sethi %hi(_PAGE_EXEC), %g4 ! Delay-slot + andcc %g5, %g4, %g0 ! Executable? + be,pn %xcc, 3f ! Nope, branch. 2: stxa %g5, [%g0] ASI_ITLB_DATA_IN ! Load PTE into TLB retry ! Trap return 3: rdpr %pstate, %g4 ! Move into alternate globals @@ -69,9 +71,6 @@ done ! Do it to it /* ITLB ** ICACHE line 4: Unused... */ - nop - nop - nop nop nop nop diff -Nru a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c --- a/arch/sparc64/kernel/sbus.c 2004-08-14 12:02:31 -07:00 +++ b/arch/sparc64/kernel/sbus.c 2004-08-14 12:02:31 -07:00 @@ -27,10 +27,10 @@ * * On SYSIO, using an 8K page size we have 1GB of SBUS * DMA space mapped. We divide this space into equally - * sized clusters. Currently we allow clusters up to a - * size of 1MB. If anything begins to generate DMA - * mapping requests larger than this we will need to - * increase things a bit. + * sized clusters. We allocate a DMA mapping from the + * cluster that matches the order of the allocation, or + * if the order is greater than the number of clusters, + * we try to allocate from the last cluster. */ #define NCLUSTERS 8UL @@ -133,12 +133,17 @@ static iopte_t *alloc_streaming_cluster(struct sbus_iommu *iommu, unsigned long npages) { - iopte_t *iopte, *limit, *first; - unsigned long cnum, ent, flush_point; + iopte_t *iopte, *limit, *first, *cluster; + unsigned long cnum, ent, nent, flush_point, found; cnum = 0; + nent = 1; while ((1UL << cnum) < npages) cnum++; + if(cnum >= NCLUSTERS) { + nent = 1UL << (cnum - NCLUSTERS); + cnum = NCLUSTERS - 1; + } iopte = iommu->page_table + (cnum * CLUSTER_NPAGES); if (cnum == 0) @@ -151,22 +156,31 @@ flush_point = iommu->alloc_info[cnum].flush; first = iopte; + cluster = NULL; + found = 0; for (;;) { if (iopte_val(*iopte) == 0UL) { - if ((iopte + (1 << cnum)) >= limit) - ent = 0; - else - ent = ent + 1; - iommu->alloc_info[cnum].next = ent; - if (ent == flush_point) - __iommu_flushall(iommu); - break; + found++; + if (!cluster) + cluster = iopte; + } else { + /* Used cluster in the way */ + cluster = NULL; + found = 0; } + + if (found == nent) + break; + iopte += (1 << cnum); ent++; if (iopte >= limit) { iopte = (iommu->page_table + (cnum * CLUSTER_NPAGES)); ent = 0; + + /* Multiple cluster allocations must not wrap */ + cluster = NULL; + found = 0; } if (ent == flush_point) __iommu_flushall(iommu); @@ -174,8 +188,19 @@ goto bad; } + /* ent/iopte points to the last cluster entry we're going to use, + * so save our place for the next allocation. + */ + if ((iopte + (1 << cnum)) >= limit) + ent = 0; + else + ent = ent + 1; + iommu->alloc_info[cnum].next = ent; + if (ent == flush_point) + __iommu_flushall(iommu); + /* I've got your streaming cluster right here buddy boy... */ - return iopte; + return cluster; bad: printk(KERN_EMERG "sbus: alloc_streaming_cluster of npages(%ld) failed!\n", @@ -185,15 +210,23 @@ static void free_streaming_cluster(struct sbus_iommu *iommu, u32 base, unsigned long npages) { - unsigned long cnum, ent; + unsigned long cnum, ent, nent; iopte_t *iopte; cnum = 0; + nent = 1; while ((1UL << cnum) < npages) cnum++; + if(cnum >= NCLUSTERS) { + nent = 1UL << (cnum - NCLUSTERS); + cnum = NCLUSTERS - 1; + } ent = (base & CLUSTER_MASK) >> (IO_PAGE_SHIFT + cnum); iopte = iommu->page_table + ((base - MAP_BASE) >> IO_PAGE_SHIFT); - iopte_val(*iopte) = 0UL; + do { + iopte_val(*iopte) = 0UL; + iopte += 1 << cnum; + } while(--nent); /* If the global flush might not have caught this entry, * adjust the flush point such that we will flush before diff -Nru a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c --- a/arch/sparc64/kernel/sparc64_ksyms.c 2004-08-14 12:02:30 -07:00 +++ b/arch/sparc64/kernel/sparc64_ksyms.c 2004-08-14 12:02:30 -07:00 @@ -324,7 +324,6 @@ #endif /* Special internal versions of library functions. */ -EXPORT_SYMBOL(__memcpy); EXPORT_SYMBOL(__memset); EXPORT_SYMBOL(_clear_page); EXPORT_SYMBOL(clear_user_page); diff -Nru a/arch/sparc64/lib/U3copy_from_user.S b/arch/sparc64/lib/U3copy_from_user.S --- a/arch/sparc64/lib/U3copy_from_user.S 2004-08-14 12:02:30 -07:00 +++ b/arch/sparc64/lib/U3copy_from_user.S 2004-08-14 12:02:30 -07:00 @@ -1,20 +1,31 @@ -/* $Id: U3copy_from_user.S,v 1.3.2.1 2002/01/15 07:17:47 davem Exp $ - * U3memcpy.S: UltraSparc-III optimized copy from userspace. +/* U3copy_from_user.S: UltraSparc-III optimized copy from userspace. * - * Copyright (C) 1999, 2000 David S. Miller (davem@redhat.com) + * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com) */ -#ifdef __KERNEL__ #include #include #include #include -#undef SMALL_COPY_USES_FPU + +#define XCC xcc + +#define EXNV_RAW(x,y,a,b) \ +98: x,y; \ + .section .fixup; \ + .align 4; \ +99: ba U3cfu_fixup; \ + a, b, %o1; \ + .section __ex_table; \ + .align 4; \ + .word 98b, 99b; \ + .text; \ + .align 4; #define EXNV(x,y,a,b) \ 98: x,y; \ .section .fixup; \ .align 4; \ -99: VISExitHalf; \ +99: add %o1, %o3, %o0; \ ba U3cfu_fixup; \ a, b, %o1; \ .section __ex_table; \ @@ -22,6 +33,32 @@ .word 98b, 99b; \ .text; \ .align 4; +#define EXNV4(x,y,a,b) \ +98: x,y; \ + .section .fixup; \ + .align 4; \ +99: add %o1, %o3, %o0; \ + a, b, %o1; \ + ba U3cfu_fixup; \ + add %o1, 4, %o1; \ + .section __ex_table; \ + .align 4; \ + .word 98b, 99b; \ + .text; \ + .align 4; +#define EXNV8(x,y,a,b) \ +98: x,y; \ + .section .fixup; \ + .align 4; \ +99: add %o1, %o3, %o0; \ + a, b, %o1; \ + ba U3cfu_fixup; \ + add %o1, 8, %o1; \ + .section __ex_table; \ + .align 4; \ + .word 98b, 99b; \ + .text; \ + .align 4; #define EX(x,y,a,b) \ 98: x,y; \ .section .fixup; \ @@ -77,18 +114,9 @@ .word 98b, 99b; \ .text; \ .align 4; -#else -#define ASI_BLK_P 0xf0 -#define FPRS_FEF 0x04 -#define VISEntryHalf rd %fprs, %o5; wr %g0, FPRS_FEF, %fprs -#define VISExitHalf and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs -#define SMALL_COPY_USES_FPU -#define EXNV(x,y,a,b) x,y; -#define EX(x,y,a,b) x,y; -#define EX2(x,y) x,y; -#define EX3(x,y) x,y; -#define EX4(x,y) x,y; -#endif + + .register %g2,#scratch + .register %g3,#scratch /* Special/non-trivial issues of this code: * @@ -109,81 +137,55 @@ * of up to 2.4GB per second. */ - .globl U3copy_from_user -U3copy_from_user: /* %o0=dst, %o1=src, %o2=len */ -#ifndef __KERNEL__ - /* Save away original 'dst' for memcpy return value. */ - mov %o0, %g3 ! A0 Group -#endif - /* Anything to copy at all? */ - cmp %o2, 0 ! A1 - ble,pn %icc, U3copy_from_user_short_ret! BR - - /* Extremely small copy? */ - cmp %o2, 31 ! A0 Group - ble,pn %icc, U3copy_from_user_short ! BR - - /* Large enough to use unrolled prefetch loops? */ - cmp %o2, 0x100 ! A1 - bge,a,pt %icc, U3copy_from_user_enter ! BR Group - andcc %o0, 0x3f, %g2 ! A0 - - ba,pt %xcc, U3copy_from_user_toosmall ! BR Group - andcc %o0, 0x7, %g2 ! A0 - - .align 32 -U3copy_from_user_short: - /* Copy %o2 bytes from src to dst, one byte at a time. */ - EXNV(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g0)! MS Group - add %o1, 0x1, %o1 ! A0 - add %o0, 0x1, %o0 ! A1 - subcc %o2, 1, %o2 ! A0 Group - - bg,pt %icc, U3copy_from_user_short ! BR - stb %o3, [%o0 + -1] ! MS Group (1-cycle stall) - -U3copy_from_user_short_ret: -#ifdef __KERNEL__ - retl ! BR Group (0-4 cycle stall) - clr %o0 ! A0 -#else - retl ! BR Group (0-4 cycle stall) - mov %g3, %o0 ! A0 -#endif + .globl U3copy_from_user +U3copy_from_user: /* %o0=dst, %o1=src, %o2=len */ + cmp %o2, 0 + be,pn %XCC, out + or %o0, %o1, %o3 + cmp %o2, 16 + bleu,a,pn %XCC, small_copy + or %o3, %o2, %o3 + + cmp %o2, 256 + blu,pt %XCC, medium_copy + andcc %o3, 0x7, %g0 - /* Here len >= (6 * 64) and condition codes reflect execution + ba,pt %xcc, enter + andcc %o0, 0x3f, %g2 + + /* Here len >= 256 and condition codes reflect execution * of "andcc %o0, 0x7, %g2", done by caller. */ .align 64 -U3copy_from_user_enter: +enter: /* Is 'dst' already aligned on an 64-byte boundary? */ - be,pt %xcc, 2f ! BR + be,pt %XCC, 2f /* Compute abs((dst & 0x3f) - 0x40) into %g2. This is the number * of bytes to copy to make 'dst' 64-byte aligned. We pre- * subtract this from 'len'. */ - sub %g2, 0x40, %g2 ! A0 Group - sub %g0, %g2, %g2 ! A0 Group - sub %o2, %g2, %o2 ! A0 Group + sub %g2, 0x40, %g2 + sub %g0, %g2, %g2 + sub %o2, %g2, %o2 /* Copy %g2 bytes from src to dst, one byte at a time. */ -1: EXNV(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g2)! MS (Group) - add %o1, 0x1, %o1 ! A1 - add %o0, 0x1, %o0 ! A0 Group - subcc %g2, 0x1, %g2 ! A1 - - bg,pt %icc, 1b ! BR Group - stb %o3, [%o0 + -1] ! MS Group - -2: VISEntryHalf ! MS+MS - and %o1, 0x7, %g1 ! A1 - ba,pt %xcc, U3copy_from_user_begin ! BR - alignaddr %o1, %g0, %o1 ! MS (Break-after) +1: EXNV_RAW(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g2) + add %o1, 0x1, %o1 + add %o0, 0x1, %o0 + subcc %g2, 0x1, %g2 + + bg,pt %XCC, 1b + stb %o3, [%o0 + -1] + +2: VISEntryHalf + and %o1, 0x7, %g1 + ba,pt %xcc, begin + alignaddr %o1, %g0, %o1 .align 64 -U3copy_from_user_begin: -#ifdef __KERNEL__ +begin: + .globl U3copy_from_user_nop_1_6 U3copy_from_user_nop_1_6: ldxa [%g0] ASI_DCU_CONTROL_REG, %g3 @@ -192,315 +194,225 @@ or %g3, %o3, %o3 stxa %o3, [%g0] ASI_DCU_CONTROL_REG ! Enable P-cache membar #Sync -#endif - prefetcha [%o1 + 0x000] %asi, #one_read ! MS Group1 - prefetcha [%o1 + 0x040] %asi, #one_read ! MS Group2 - andn %o2, (0x40 - 1), %o4 ! A0 - prefetcha [%o1 + 0x080] %asi, #one_read ! MS Group3 - cmp %o4, 0x140 ! A0 - prefetcha [%o1 + 0x0c0] %asi, #one_read ! MS Group4 - EX(ldda [%o1 + 0x000] %asi, %f0, add %o2, %g0) ! MS Group5 (%f0 results at G8) - bge,a,pt %icc, 1f ! BR - - prefetcha [%o1 + 0x100] %asi, #one_read ! MS Group6 -1: EX(ldda [%o1 + 0x008] %asi, %f2, add %o2, %g0) ! AX (%f2 results at G9) - cmp %o4, 0x180 ! A1 - bge,a,pt %icc, 1f ! BR - prefetcha [%o1 + 0x140] %asi, #one_read ! MS Group7 -1: EX(ldda [%o1 + 0x010] %asi, %f4, add %o2, %g0) ! AX (%f4 results at G10) - cmp %o4, 0x1c0 ! A1 - bge,a,pt %icc, 1f ! BR - - prefetcha [%o1 + 0x180] %asi, #one_read ! MS Group8 -1: faligndata %f0, %f2, %f16 ! FGA Group9 (%f16 at G12) - EX(ldda [%o1 + 0x018] %asi, %f6, add %o2, %g0) ! AX (%f6 results at G12) - faligndata %f2, %f4, %f18 ! FGA Group10 (%f18 results at G13) - EX(ldda [%o1 + 0x020] %asi, %f8, add %o2, %g0) ! MS (%f8 results at G13) - faligndata %f4, %f6, %f20 ! FGA Group12 (1-cycle stall,%f20 at G15) - EX(ldda [%o1 + 0x028] %asi, %f10, add %o2, %g0) ! MS (%f10 results at G15) - faligndata %f6, %f8, %f22 ! FGA Group13 (%f22 results at G16) - - EX(ldda [%o1 + 0x030] %asi, %f12, add %o2, %g0) ! MS (%f12 results at G16) - faligndata %f8, %f10, %f24 ! FGA Group15 (1-cycle stall,%f24 at G18) - EX(ldda [%o1 + 0x038] %asi, %f14, add %o2, %g0) ! MS (%f14 results at G18) - faligndata %f10, %f12, %f26 ! FGA Group16 (%f26 results at G19) - EX(ldda [%o1 + 0x040] %asi, %f0, add %o2, %g0) ! MS (%f0 results at G19) - - /* We only use the first loop if len > (7 * 64). */ - subcc %o4, 0x1c0, %o4 ! A0 Group17 - bg,pt %icc, U3copy_from_user_loop1 ! BR - add %o1, 0x40, %o1 ! A1 - - add %o4, 0x140, %o4 ! A0 Group18 - ba,pt %xcc, U3copy_from_user_loop2 ! BR - srl %o4, 6, %o3 ! A0 Group19 - nop - nop - nop - nop - nop - - nop - nop - - /* This loop performs the copy and queues new prefetches. - * We drop into the second loop when len <= (5 * 64). Note - * that this (5 * 64) factor has been subtracted from len - * already. - */ -U3copy_from_user_loop1: - EX2(ldda [%o1 + 0x008] %asi, %f2) ! MS Group2 (%f2 results at G5) - faligndata %f12, %f14, %f28 ! FGA (%f28 results at G5) - EX2(ldda [%o1 + 0x010] %asi, %f4) ! MS Group3 (%f4 results at G6) - faligndata %f14, %f0, %f30 ! FGA Group4 (1-cycle stall, %f30 at G7) - stda %f16, [%o0] ASI_BLK_P ! MS - EX2(ldda [%o1 + 0x018] %asi, %f6) ! AX (%f6 results at G7) - - faligndata %f0, %f2, %f16 ! FGA Group12 (7-cycle stall) - EX2(ldda [%o1 + 0x020] %asi, %f8) ! MS (%f8 results at G15) - faligndata %f2, %f4, %f18 ! FGA Group13 (%f18 results at G16) - EX2(ldda [%o1 + 0x028] %asi, %f10) ! MS (%f10 results at G16) - faligndata %f4, %f6, %f20 ! FGA Group14 (%f20 results at G17) - EX2(ldda [%o1 + 0x030] %asi, %f12) ! MS (%f12 results at G17) - faligndata %f6, %f8, %f22 ! FGA Group15 (%f22 results at G18) - EX2(ldda [%o1 + 0x038] %asi, %f14) ! MS (%f14 results at G18) - - faligndata %f8, %f10, %f24 ! FGA Group16 (%f24 results at G19) - EX2(ldda [%o1 + 0x040] %asi, %f0) ! AX (%f0 results at G19) - prefetcha [%o1 + 0x180] %asi, #one_read ! MS - faligndata %f10, %f12, %f26 ! FGA Group17 (%f26 results at G20) - subcc %o4, 0x40, %o4 ! A0 - add %o1, 0x40, %o1 ! A1 - bg,pt %xcc, U3copy_from_user_loop1 ! BR - add %o0, 0x40, %o0 ! A0 Group18 - -U3copy_from_user_loop2_enter: - mov 5, %o3 ! A1 - - /* This loop performs on the copy, no new prefetches are - * queued. We do things this way so that we do not perform - * any spurious prefetches past the end of the src buffer. - */ -U3copy_from_user_loop2: - EX3(ldda [%o1 + 0x008] %asi, %f2) ! MS - faligndata %f12, %f14, %f28 ! FGA Group2 - EX3(ldda [%o1 + 0x010] %asi, %f4) ! MS - faligndata %f14, %f0, %f30 ! FGA Group4 (1-cycle stall) - stda %f16, [%o0] ASI_BLK_P ! MS - EX3(ldda [%o1 + 0x018] %asi, %f6) ! AX - faligndata %f0, %f2, %f16 ! FGA Group12 (7-cycle stall) - - EX3(ldda [%o1 + 0x020] %asi, %f8) ! MS - faligndata %f2, %f4, %f18 ! FGA Group13 - EX3(ldda [%o1 + 0x028] %asi, %f10) ! MS - faligndata %f4, %f6, %f20 ! FGA Group14 - EX3(ldda [%o1 + 0x030] %asi, %f12) ! MS - faligndata %f6, %f8, %f22 ! FGA Group15 - EX3(ldda [%o1 + 0x038] %asi, %f14) ! MS - faligndata %f8, %f10, %f24 ! FGA Group16 - - EX3(ldda [%o1 + 0x040] %asi, %f0) ! AX - faligndata %f10, %f12, %f26 ! FGA Group17 - subcc %o3, 0x01, %o3 ! A0 - add %o1, 0x40, %o1 ! A1 - bg,pt %xcc, U3copy_from_user_loop2 ! BR - add %o0, 0x40, %o0 ! A0 Group18 + + prefetcha [%o1 + 0x000] %asi, #one_read + prefetcha [%o1 + 0x040] %asi, #one_read + andn %o2, (0x40 - 1), %o4 + prefetcha [%o1 + 0x080] %asi, #one_read + prefetcha [%o1 + 0x0c0] %asi, #one_read + EX(ldda [%o1 + 0x000] %asi, %f0, add %o2, %g0) + prefetcha [%o1 + 0x100] %asi, #one_read + EX(ldda [%o1 + 0x008] %asi, %f2, add %o2, %g0) + prefetcha [%o1 + 0x140] %asi, #one_read + EX(ldda [%o1 + 0x010] %asi, %f4, add %o2, %g0) + prefetcha [%o1 + 0x180] %asi, #one_read + faligndata %f0, %f2, %f16 + EX(ldda [%o1 + 0x018] %asi, %f6, add %o2, %g0) + faligndata %f2, %f4, %f18 + EX(ldda [%o1 + 0x020] %asi, %f8, add %o2, %g0) + faligndata %f4, %f6, %f20 + EX(ldda [%o1 + 0x028] %asi, %f10, add %o2, %g0) + faligndata %f6, %f8, %f22 + + EX(ldda [%o1 + 0x030] %asi, %f12, add %o2, %g0) + faligndata %f8, %f10, %f24 + EX(ldda [%o1 + 0x038] %asi, %f14, add %o2, %g0) + faligndata %f10, %f12, %f26 + EX(ldda [%o1 + 0x040] %asi, %f0, add %o2, %g0) + + sub %o4, 0x80, %o4 + add %o1, 0x40, %o1 + ba,pt %xcc, loop + srl %o4, 6, %o3 + + .align 64 +loop: + EX3(ldda [%o1 + 0x008] %asi, %f2) + faligndata %f12, %f14, %f28 + EX3(ldda [%o1 + 0x010] %asi, %f4) + faligndata %f14, %f0, %f30 + stda %f16, [%o0] ASI_BLK_P + EX3(ldda [%o1 + 0x018] %asi, %f6) + faligndata %f0, %f2, %f16 + + EX3(ldda [%o1 + 0x020] %asi, %f8) + faligndata %f2, %f4, %f18 + EX3(ldda [%o1 + 0x028] %asi, %f10) + faligndata %f4, %f6, %f20 + EX3(ldda [%o1 + 0x030] %asi, %f12) + faligndata %f6, %f8, %f22 + EX3(ldda [%o1 + 0x038] %asi, %f14) + faligndata %f8, %f10, %f24 + + EX3(ldda [%o1 + 0x040] %asi, %f0) + prefetcha [%o1 + 0x180] %asi, #one_read + faligndata %f10, %f12, %f26 + subcc %o3, 0x01, %o3 + add %o1, 0x40, %o1 + bg,pt %XCC, loop + add %o0, 0x40, %o0 /* Finally we copy the last full 64-byte block. */ -U3copy_from_user_loopfini: - EX3(ldda [%o1 + 0x008] %asi, %f2) ! MS - faligndata %f12, %f14, %f28 ! FGA - EX3(ldda [%o1 + 0x010] %asi, %f4) ! MS Group19 - faligndata %f14, %f0, %f30 ! FGA - stda %f16, [%o0] ASI_BLK_P ! MS Group20 - EX3(ldda [%o1 + 0x018] %asi, %f6) ! AX - faligndata %f0, %f2, %f16 ! FGA Group11 (7-cycle stall) - EX3(ldda [%o1 + 0x020] %asi, %f8) ! MS - faligndata %f2, %f4, %f18 ! FGA Group12 - EX3(ldda [%o1 + 0x028] %asi, %f10) ! MS - faligndata %f4, %f6, %f20 ! FGA Group13 - EX3(ldda [%o1 + 0x030] %asi, %f12) ! MS - faligndata %f6, %f8, %f22 ! FGA Group14 - EX3(ldda [%o1 + 0x038] %asi, %f14) ! MS - faligndata %f8, %f10, %f24 ! FGA Group15 - cmp %g1, 0 ! A0 - be,pt %icc, 1f ! BR - add %o0, 0x40, %o0 ! A1 - EX4(ldda [%o1 + 0x040] %asi, %f0) ! MS -1: faligndata %f10, %f12, %f26 ! FGA Group16 - faligndata %f12, %f14, %f28 ! FGA Group17 - faligndata %f14, %f0, %f30 ! FGA Group18 - stda %f16, [%o0] ASI_BLK_P ! MS - add %o0, 0x40, %o0 ! A0 - add %o1, 0x40, %o1 ! A1 -#ifdef __KERNEL__ +loopfini: + EX3(ldda [%o1 + 0x008] %asi, %f2) + faligndata %f12, %f14, %f28 + EX3(ldda [%o1 + 0x010] %asi, %f4) + faligndata %f14, %f0, %f30 + stda %f16, [%o0] ASI_BLK_P + EX3(ldda [%o1 + 0x018] %asi, %f6) + faligndata %f0, %f2, %f16 + EX3(ldda [%o1 + 0x020] %asi, %f8) + faligndata %f2, %f4, %f18 + EX3(ldda [%o1 + 0x028] %asi, %f10) + faligndata %f4, %f6, %f20 + EX3(ldda [%o1 + 0x030] %asi, %f12) + faligndata %f6, %f8, %f22 + EX3(ldda [%o1 + 0x038] %asi, %f14) + faligndata %f8, %f10, %f24 + cmp %g1, 0 + be,pt %XCC, 1f + add %o0, 0x40, %o0 + EX4(ldda [%o1 + 0x040] %asi, %f0) +1: faligndata %f10, %f12, %f26 + faligndata %f12, %f14, %f28 + faligndata %f14, %f0, %f30 + stda %f16, [%o0] ASI_BLK_P + add %o0, 0x40, %o0 + add %o1, 0x40, %o1 + .globl U3copy_from_user_nop_2_3 U3copy_from_user_nop_2_3: mov PRIMARY_CONTEXT, %o3 stxa %g0, [%o3] ASI_DMMU ! Flush P-cache stxa %g3, [%g0] ASI_DCU_CONTROL_REG ! Disable P-cache -#endif - membar #Sync ! MS Group26 (7-cycle stall) + + membar #Sync /* Now we copy the (len modulo 64) bytes at the end. * Note how we borrow the %f0 loaded above. * * Also notice how this code is careful not to perform a - * load past the end of the src buffer just like similar - * code found in U3copy_from_user_toosmall processing. + * load past the end of the src buffer. */ -U3copy_from_user_loopend: - and %o2, 0x3f, %o2 ! A0 Group - andcc %o2, 0x38, %g2 ! A0 Group - be,pn %icc, U3copy_from_user_endcruft ! BR - subcc %g2, 0x8, %g2 ! A1 - be,pn %icc, U3copy_from_user_endcruft ! BR Group - cmp %g1, 0 ! A0 - - be,a,pt %icc, 1f ! BR Group - EX(ldda [%o1 + 0x00] %asi, %f0, add %o2, %g0) ! MS - -1: EX(ldda [%o1 + 0x08] %asi, %f2, add %o2, %g0) ! MS Group - add %o1, 0x8, %o1 ! A0 - sub %o2, 0x8, %o2 ! A1 - subcc %g2, 0x8, %g2 ! A0 Group - faligndata %f0, %f2, %f8 ! FGA Group - std %f8, [%o0 + 0x00] ! MS (XXX does it stall here? XXX) - be,pn %icc, U3copy_from_user_endcruft ! BR - add %o0, 0x8, %o0 ! A0 - EX(ldda [%o1 + 0x08] %asi, %f0, add %o2, %g0) ! MS Group - add %o1, 0x8, %o1 ! A0 - sub %o2, 0x8, %o2 ! A1 - subcc %g2, 0x8, %g2 ! A0 Group - faligndata %f2, %f0, %f8 ! FGA - std %f8, [%o0 + 0x00] ! MS (XXX does it stall here? XXX) - bne,pn %icc, 1b ! BR - add %o0, 0x8, %o0 ! A0 Group +loopend: + and %o2, 0x3f, %o2 + andcc %o2, 0x38, %g2 + be,pn %XCC, endcruft + subcc %g2, 0x8, %g2 + be,pn %XCC, endcruft + cmp %g1, 0 + + be,a,pt %XCC, 1f + EX(ldda [%o1 + 0x00] %asi, %f0, add %o2, %g0) + +1: EX(ldda [%o1 + 0x08] %asi, %f2, add %o2, %g0) + add %o1, 0x8, %o1 + sub %o2, 0x8, %o2 + subcc %g2, 0x8, %g2 + faligndata %f0, %f2, %f8 + std %f8, [%o0 + 0x00] + be,pn %XCC, endcruft + add %o0, 0x8, %o0 + EX(ldda [%o1 + 0x08] %asi, %f0, add %o2, %g0) + add %o1, 0x8, %o1 + sub %o2, 0x8, %o2 + subcc %g2, 0x8, %g2 + faligndata %f2, %f0, %f8 + std %f8, [%o0 + 0x00] + bne,pn %XCC, 1b + add %o0, 0x8, %o0 /* If anything is left, we copy it one byte at a time. * Note that %g1 is (src & 0x3) saved above before the * alignaddr was performed. */ -U3copy_from_user_endcruft: +endcruft: cmp %o2, 0 add %o1, %g1, %o1 VISExitHalf - be,pn %icc, U3copy_from_user_short_ret - nop - ba,a,pt %xcc, U3copy_from_user_short + be,pn %XCC, out + sub %o0, %o1, %o3 - /* If we get here, then 32 <= len < (6 * 64) */ -U3copy_from_user_toosmall: - -#ifdef SMALL_COPY_USES_FPU - - /* Is 'dst' already aligned on an 8-byte boundary? */ - be,pt %xcc, 2f ! BR Group - - /* Compute abs((dst & 7) - 8) into %g2. This is the number - * of bytes to copy to make 'dst' 8-byte aligned. We pre- - * subtract this from 'len'. - */ - sub %g2, 0x8, %g2 ! A0 - sub %g0, %g2, %g2 ! A0 Group (reg-dep) - sub %o2, %g2, %o2 ! A0 Group (reg-dep) - - /* Copy %g2 bytes from src to dst, one byte at a time. */ -1: EXNV(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g2)! MS (Group) (%o3 in 3 cycles) - add %o1, 0x1, %o1 ! A1 - add %o0, 0x1, %o0 ! A0 Group - subcc %g2, 0x1, %g2 ! A1 - - bg,pt %icc, 1b ! BR Group - stb %o3, [%o0 + -1] ! MS Group - -2: VISEntryHalf ! MS+MS - - /* Compute (len - (len % 8)) into %g2. This is guarenteed - * to be nonzero. - */ - andn %o2, 0x7, %g2 ! A0 Group - - /* You may read this and believe that it allows reading - * one 8-byte longword past the end of src. It actually - * does not, as %g2 is subtracted as loads are done from - * src, so we always stop before running off the end. - * Also, we are guarenteed to have at least 0x10 bytes - * to move here. - */ - sub %g2, 0x8, %g2 ! A0 Group (reg-dep) - alignaddr %o1, %g0, %g1 ! MS (Break-after) - EX(ldda [%g1 + 0x00] %asi, %f0, add %o2, %g0) ! MS Group (1-cycle stall) - add %g1, 0x8, %g1 ! A0 - -1: EX(ldda [%g1 + 0x00] %asi, %f2, add %o2, %g0) ! MS Group - add %g1, 0x8, %g1 ! A0 - sub %o2, 0x8, %o2 ! A1 - subcc %g2, 0x8, %g2 ! A0 Group - - faligndata %f0, %f2, %f8 ! FGA Group (1-cycle stall) - std %f8, [%o0 + 0x00] ! MS Group (2-cycle stall) - add %o1, 0x8, %o1 ! A0 - be,pn %icc, 2f ! BR - - add %o0, 0x8, %o0 ! A1 - EX(ldda [%g1 + 0x00] %asi, %f0, add %o2, %g0) ! MS Group - add %g1, 0x8, %g1 ! A0 - sub %o2, 0x8, %o2 ! A1 - - subcc %g2, 0x8, %g2 ! A0 Group - faligndata %f2, %f0, %f8 ! FGA Group (1-cycle stall) - std %f8, [%o0 + 0x00] ! MS Group (2-cycle stall) - add %o1, 0x8, %o1 ! A0 - - bne,pn %icc, 1b ! BR - add %o0, 0x8, %o0 ! A1 - - /* Nothing left to copy? */ -2: cmp %o2, 0 ! A0 Group - VISExitHalf ! A0+MS - be,pn %icc, U3copy_from_user_short_ret! BR Group - nop ! A0 - ba,a,pt %xcc, U3copy_from_user_short ! BR Group - -#else /* !(SMALL_COPY_USES_FPU) */ - - xor %o1, %o0, %g2 - andcc %g2, 0x7, %g0 - bne,pn %icc, U3copy_from_user_short - andcc %o1, 0x7, %g2 + andcc %g1, 0x7, %g0 + bne,pn %icc, small_copy_unaligned + andcc %o2, 0x8, %g0 + be,pt %icc, 1f + nop + EXNV(ldxa [%o1] %asi, %o5, add %o2, %g0) + stx %o5, [%o1 + %o3] + add %o1, 0x8, %o1 - be,pt %xcc, 2f - sub %g2, 0x8, %g2 - sub %g0, %g2, %g2 - sub %o2, %g2, %o2 +1: andcc %o2, 0x4, %g0 + be,pt %icc, 1f + nop + EXNV(lduwa [%o1] %asi, %o5, and %o2, 0x7) + stw %o5, [%o1 + %o3] + add %o1, 0x4, %o1 -1: EXNV(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g2) - add %o1, 0x1, %o1 - add %o0, 0x1, %o0 - subcc %g2, 0x1, %g2 - bg,pt %icc, 1b - stb %o3, [%o0 + -1] +1: andcc %o2, 0x2, %g0 + be,pt %icc, 1f + nop + EXNV(lduha [%o1] %asi, %o5, and %o2, 0x3) + sth %o5, [%o1 + %o3] + add %o1, 0x2, %o1 -2: andn %o2, 0x7, %g2 - sub %o2, %g2, %o2 +1: andcc %o2, 0x1, %g0 + be,pt %icc, out + nop + EXNV(lduba [%o1] %asi, %o5, and %o2, 0x1) + ba,pt %xcc, out + stb %o5, [%o1 + %o3] + +medium_copy: /* 16 < len <= 64 */ + bne,pn %XCC, small_copy_unaligned + sub %o0, %o1, %o3 + +medium_copy_aligned: + andn %o2, 0x7, %o4 + and %o2, 0x7, %o2 +1: subcc %o4, 0x8, %o4 + EXNV8(ldxa [%o1] %asi, %o5, add %o2, %o4) + stx %o5, [%o1 + %o3] + bgu,pt %XCC, 1b + add %o1, 0x8, %o1 + andcc %o2, 0x4, %g0 + be,pt %XCC, 1f + nop + sub %o2, 0x4, %o2 + EXNV4(lduwa [%o1] %asi, %o5, add %o2, %g0) + stw %o5, [%o1 + %o3] + add %o1, 0x4, %o1 +1: cmp %o2, 0 + be,pt %XCC, out + nop + ba,pt %xcc, small_copy_unaligned + nop -3: EXNV(ldxa [%o1 + 0x00] %asi, %o3, add %o2, %g2) - add %o1, 0x8, %o1 - add %o0, 0x8, %o0 - subcc %g2, 0x8, %g2 - bg,pt %icc, 3b - stx %o3, [%o0 + -8] +small_copy: /* 0 < len <= 16 */ + andcc %o3, 0x3, %g0 + bne,pn %XCC, small_copy_unaligned + sub %o0, %o1, %o3 + +small_copy_aligned: + subcc %o2, 4, %o2 + EXNV(lduwa [%o1] %asi, %g1, add %o2, %g0) + stw %g1, [%o1 + %o3] + bgu,pt %XCC, small_copy_aligned + add %o1, 4, %o1 - cmp %o2, 0 - bne,pn %icc, U3copy_from_user_short - nop - ba,a,pt %xcc, U3copy_from_user_short_ret +out: retl + clr %o0 -#endif /* !(SMALL_COPY_USES_FPU) */ + .align 32 +small_copy_unaligned: + subcc %o2, 1, %o2 + EXNV(lduba [%o1] %asi, %g1, add %o2, %g0) + stb %g1, [%o1 + %o3] + bgu,pt %XCC, small_copy_unaligned + add %o1, 1, %o1 + retl + clr %o0 -#ifdef __KERNEL__ - .globl U3cfu_fixup U3cfu_fixup: /* Since this is copy_from_user(), zero out the rest of the * kernel buffer. @@ -516,4 +428,3 @@ 2: retl mov %o1, %o0 -#endif diff -Nru a/arch/sparc64/lib/U3copy_in_user.S b/arch/sparc64/lib/U3copy_in_user.S --- a/arch/sparc64/lib/U3copy_in_user.S 2004-08-14 12:02:30 -07:00 +++ b/arch/sparc64/lib/U3copy_in_user.S 2004-08-14 12:02:30 -07:00 @@ -1,13 +1,15 @@ -/* $Id: U3copy_in_user.S,v 1.4 2001/03/21 05:58:47 davem Exp $ - * U3memcpy.S: UltraSparc-III optimized copy within userspace. +/* U3copy_in_user.S: UltraSparc-III optimized memcpy. * - * Copyright (C) 1999, 2000 David S. Miller (davem@redhat.com) + * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com) */ -#ifdef __KERNEL__ #include #include -#undef SMALL_COPY_USES_FPU +#include +#include + +#define XCC xcc + #define EXNV(x,y,a,b) \ 98: x,y; \ .section .fixup; \ @@ -19,7 +21,7 @@ .word 98b, 99b; \ .text; \ .align 4; -#define EXNV2(x,y,a,b) \ +#define EXNV1(x,y,a,b) \ 98: x,y; \ .section .fixup; \ .align 4; \ @@ -31,501 +33,108 @@ .word 98b, 99b; \ .text; \ .align 4; -#define EXNV3(x,y,a,b) \ +#define EXNV4(x,y,a,b) \ 98: x,y; \ .section .fixup; \ .align 4; \ 99: a, b, %o0; \ retl; \ - add %o0, 8, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EX(x,y,a,b) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: VISExitHalf; \ - retl; \ - a, b, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXBLK1(x,y) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: VISExitHalf; \ - add %o4, 0x1c0, %o1; \ - and %o2, (0x40 - 1), %o2; \ - retl; \ - add %o1, %o2, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXBLK2(x,y) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: VISExitHalf; \ - sll %o3, 6, %o3; \ - and %o2, (0x40 - 1), %o2; \ - add %o3, 0x80, %o1; \ - retl; \ - add %o1, %o2, %o0; \ - .section __ex_table; \ - .align 4; \ - .word 98b, 99b; \ - .text; \ - .align 4; -#define EXBLK3(x,y) \ -98: x,y; \ - .section .fixup; \ - .align 4; \ -99: VISExitHalf; \ - and %o2, (0x40 - 1), %o2; \ - retl; \ - add %o2, 0x80, %o0; \ + add %o0, 4, %o0; \ .section __ex_table; \ .align 4; \ .word 98b, 99b; \ .text; \ .align 4; -#define EXBLK4(x,y) \ +#define EXNV8(x,y,a,b) \ 98: x,y; \ .section .fixup; \ .align 4; \ -99: VISExitHalf; \ - and %o2, (0x40 - 1), %o2; \ +99: a, b, %o0; \ retl; \ - add %o2, 0x40, %o0; \ + add %o0, 8, %o0; \ .section __ex_table; \ .align 4; \ .word 98b, 99b; \ .text; \ .align 4; -#else -#define ASI_AIUS 0x80 -#define ASI_BLK_AIUS 0xf0 -#define FPRS_FEF 0x04 -#define VISEntryHalf rd %fprs, %o5; wr %g0, FPRS_FEF, %fprs -#define VISExitHalf and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs -#define SMALL_COPY_USES_FPU -#define EXNV(x,y,a,b) x,y; -#define EXNV2(x,y,a,b) x,y; -#define EXNV3(x,y,a,b) x,y; -#define EX(x,y,a,b) x,y; -#define EXBLK1(x,y) x,y; -#define EXBLK2(x,y) x,y; -#define EXBLK3(x,y) x,y; -#define EXBLK4(x,y) x,y; -#endif - - /* Special/non-trivial issues of this code: - * - * 1) %o5 is preserved from VISEntryHalf to VISExitHalf - * 2) Only low 32 FPU registers are used so that only the - * lower half of the FPU register set is dirtied by this - * code. This is especially important in the kernel. - * 3) This code never prefetches cachelines past the end - * of the source buffer. - * - * XXX Actually, Cheetah can buffer up to 8 concurrent - * XXX prefetches, revisit this... - */ + + .register %g2,#scratch + .register %g3,#scratch .text .align 32 - /* The cheetah's flexible spine, oversized liver, enlarged heart, - * slender muscular body, and claws make it the swiftest hunter - * in Africa and the fastest animal on land. Can reach speeds - * of up to 2.4GB per second. + /* Don't try to get too fancy here, just nice and + * simple. This is predominantly used for well aligned + * small copies in the compat layer. It is also used + * to copy register windows around during thread cloning. */ - .globl U3copy_in_user -U3copy_in_user: /* %o0=dst, %o1=src, %o2=len */ + .globl U3copy_in_user +U3copy_in_user: /* %o0=dst, %o1=src, %o2=len */ /* Writing to %asi is _expensive_ so we hardcode it. * Reading %asi to check for KERNEL_DS is comparatively * cheap. */ - rd %asi, %g1 ! MS Group (4 cycles) - cmp %g1, ASI_AIUS ! A0 Group - bne U3memcpy ! BR - nop ! A1 -#ifndef __KERNEL__ - /* Save away original 'dst' for memcpy return value. */ - mov %o0, %g3 ! A0 Group -#endif - /* Anything to copy at all? */ - cmp %o2, 0 ! A1 - ble,pn %icc, U3copy_in_user_short_ret ! BR - - /* Extremely small copy? */ - cmp %o2, 31 ! A0 Group - ble,pn %icc, U3copy_in_user_short ! BR - - /* Large enough to use unrolled prefetch loops? */ - cmp %o2, 0x100 ! A1 - bge,a,pt %icc, U3copy_in_user_enter ! BR Group - andcc %o0, 0x3f, %g2 ! A0 - - ba,pt %xcc, U3copy_in_user_toosmall ! BR Group - andcc %o0, 0x7, %g2 ! A0 - - .align 32 -U3copy_in_user_short: - /* Copy %o2 bytes from src to dst, one byte at a time. */ - EXNV(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g0)! MS Group - add %o1, 0x1, %o1 ! A0 - add %o0, 0x1, %o0 ! A1 - subcc %o2, 1, %o2 ! A0 Group - - bg,pt %icc, U3copy_in_user_short ! BR - EXNV(stba %o3, [%o0 + -1] %asi, add %o2, 1) ! MS Group (1-cycle stall) - -U3copy_in_user_short_ret: -#ifdef __KERNEL__ - retl ! BR Group (0-4 cycle stall) - clr %o0 ! A0 -#else - retl ! BR Group (0-4 cycle stall) - mov %g3, %o0 ! A0 -#endif + rd %asi, %g1 + cmp %g1, ASI_AIUS + bne,pn %icc, U3memcpy_user_stub + nop - /* Here len >= (6 * 64) and condition codes reflect execution - * of "andcc %o0, 0x7, %g2", done by caller. - */ - .align 64 -U3copy_in_user_enter: - /* Is 'dst' already aligned on an 64-byte boundary? */ - be,pt %xcc, 2f ! BR - - /* Compute abs((dst & 0x3f) - 0x40) into %g2. This is the number - * of bytes to copy to make 'dst' 64-byte aligned. We pre- - * subtract this from 'len'. - */ - sub %g2, 0x40, %g2 ! A0 Group - sub %g0, %g2, %g2 ! A0 Group - sub %o2, %g2, %o2 ! A0 Group - - /* Copy %g2 bytes from src to dst, one byte at a time. */ -1: EXNV(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g2)! MS (Group) - add %o1, 0x1, %o1 ! A1 - add %o0, 0x1, %o0 ! A0 Group - subcc %g2, 0x1, %g2 ! A1 - - bg,pt %icc, 1b ! BR Group - EXNV2(stba %o3, [%o0 + -1] %asi, add %o2, %g2) ! MS Group - -2: VISEntryHalf ! MS+MS - and %o1, 0x7, %g1 ! A1 - ba,pt %xcc, U3copy_in_user_begin ! BR - alignaddr %o1, %g0, %o1 ! MS (Break-after) - - .align 64 -U3copy_in_user_begin: - prefetcha [%o1 + 0x000] %asi, #one_read ! MS Group1 - prefetcha [%o1 + 0x040] %asi, #one_read ! MS Group2 - andn %o2, (0x40 - 1), %o4 ! A0 - prefetcha [%o1 + 0x080] %asi, #one_read ! MS Group3 - cmp %o4, 0x140 ! A0 - prefetcha [%o1 + 0x0c0] %asi, #one_read ! MS Group4 - EX(ldda [%o1 + 0x000] %asi, %f0, add %o2, %g0) ! MS Group5 (%f0 results at G8) - bge,a,pt %icc, 1f ! BR - - prefetcha [%o1 + 0x100] %asi, #one_read ! MS Group6 -1: EX(ldda [%o1 + 0x008] %asi, %f2, add %o2, %g0) ! AX (%f2 results at G9) - cmp %o4, 0x180 ! A1 - bge,a,pt %icc, 1f ! BR - prefetcha [%o1 + 0x140] %asi, #one_read ! MS Group7 -1: EX(ldda [%o1 + 0x010] %asi, %f4, add %o2, %g0) ! AX (%f4 results at G10) - cmp %o4, 0x1c0 ! A1 - bge,a,pt %icc, 1f ! BR - - prefetcha [%o1 + 0x180] %asi, #one_read ! MS Group8 -1: faligndata %f0, %f2, %f16 ! FGA Group9 (%f16 at G12) - EX(ldda [%o1 + 0x018] %asi, %f6, add %o2, %g0) ! AX (%f6 results at G12) - faligndata %f2, %f4, %f18 ! FGA Group10 (%f18 results at G13) - EX(ldda [%o1 + 0x020] %asi, %f8, add %o2, %g0) ! MS (%f8 results at G13) - faligndata %f4, %f6, %f20 ! FGA Group12 (1-cycle stall,%f20 at G15) - EX(ldda [%o1 + 0x028] %asi, %f10, add %o2, %g0) ! MS (%f10 results at G15) - faligndata %f6, %f8, %f22 ! FGA Group13 (%f22 results at G16) - - EX(ldda [%o1 + 0x030] %asi, %f12, add %o2, %g0) ! MS (%f12 results at G16) - faligndata %f8, %f10, %f24 ! FGA Group15 (1-cycle stall,%f24 at G18) - EX(ldda [%o1 + 0x038] %asi, %f14, add %o2, %g0) ! MS (%f14 results at G18) - faligndata %f10, %f12, %f26 ! FGA Group16 (%f26 results at G19) - EX(ldda [%o1 + 0x040] %asi, %f0, add %o2, %g0) ! MS (%f0 results at G19) - - /* We only use the first loop if len > (7 * 64). */ - subcc %o4, 0x1c0, %o4 ! A0 Group17 - bg,pt %icc, U3copy_in_user_loop1 ! BR - add %o1, 0x40, %o1 ! A1 - - add %o4, 0x140, %o4 ! A0 Group18 - ba,pt %xcc, U3copy_in_user_loop2 ! BR - srl %o4, 6, %o3 ! A0 Group19 - nop - nop - nop - nop - nop - - nop - nop - - /* This loop performs the copy and queues new prefetches. - * We drop into the second loop when len <= (5 * 64). Note - * that this (5 * 64) factor has been subtracted from len - * already. - */ -U3copy_in_user_loop1: - EXBLK1(ldda [%o1 + 0x008] %asi, %f2) ! MS Group2 (%f2 results at G5) - faligndata %f12, %f14, %f28 ! FGA (%f28 results at G5) - EXBLK1(ldda [%o1 + 0x010] %asi, %f4) ! MS Group3 (%f4 results at G6) - faligndata %f14, %f0, %f30 ! FGA Group4 (1-cycle stall, %f30 at G7) - EXBLK1(stda %f16, [%o0] ASI_BLK_AIUS) ! MS - EXBLK1(ldda [%o1 + 0x018] %asi, %f6) ! AX (%f6 results at G7) - - faligndata %f0, %f2, %f16 ! FGA Group12 (7-cycle stall) - EXBLK1(ldda [%o1 + 0x020] %asi, %f8) ! MS (%f8 results at G15) - faligndata %f2, %f4, %f18 ! FGA Group13 (%f18 results at G16) - EXBLK1(ldda [%o1 + 0x028] %asi, %f10) ! MS (%f10 results at G16) - faligndata %f4, %f6, %f20 ! FGA Group14 (%f20 results at G17) - EXBLK1(ldda [%o1 + 0x030] %asi, %f12) ! MS (%f12 results at G17) - faligndata %f6, %f8, %f22 ! FGA Group15 (%f22 results at G18) - EXBLK1(ldda [%o1 + 0x038] %asi, %f14) ! MS (%f14 results at G18) - - faligndata %f8, %f10, %f24 ! FGA Group16 (%f24 results at G19) - EXBLK1(ldda [%o1 + 0x040] %asi, %f0) ! AX (%f0 results at G19) - prefetcha [%o1 + 0x180] %asi, #one_read ! MS - faligndata %f10, %f12, %f26 ! FGA Group17 (%f26 results at G20) - subcc %o4, 0x40, %o4 ! A0 - add %o1, 0x40, %o1 ! A1 - bg,pt %xcc, U3copy_in_user_loop1 ! BR - add %o0, 0x40, %o0 ! A0 Group18 - -U3copy_in_user_loop2_enter: - mov 5, %o3 ! A1 - - /* This loop performs on the copy, no new prefetches are - * queued. We do things this way so that we do not perform - * any spurious prefetches past the end of the src buffer. - */ -U3copy_in_user_loop2: - EXBLK2(ldda [%o1 + 0x008] %asi, %f2) ! MS - faligndata %f12, %f14, %f28 ! FGA Group2 - EXBLK2(ldda [%o1 + 0x010] %asi, %f4) ! MS - faligndata %f14, %f0, %f30 ! FGA Group4 (1-cycle stall) - EXBLK2(stda %f16, [%o0] ASI_BLK_AIUS) ! MS - EXBLK2(ldda [%o1 + 0x018] %asi, %f6) ! AX - faligndata %f0, %f2, %f16 ! FGA Group12 (7-cycle stall) - - EXBLK2(ldda [%o1 + 0x020] %asi, %f8) ! MS - faligndata %f2, %f4, %f18 ! FGA Group13 - EXBLK2(ldda [%o1 + 0x028] %asi, %f10) ! MS - faligndata %f4, %f6, %f20 ! FGA Group14 - EXBLK2(ldda [%o1 + 0x030] %asi, %f12) ! MS - faligndata %f6, %f8, %f22 ! FGA Group15 - EXBLK2(ldda [%o1 + 0x038] %asi, %f14) ! MS - faligndata %f8, %f10, %f24 ! FGA Group16 - - EXBLK2(ldda [%o1 + 0x040] %asi, %f0) ! AX - faligndata %f10, %f12, %f26 ! FGA Group17 - subcc %o3, 0x01, %o3 ! A0 - add %o1, 0x40, %o1 ! A1 - bg,pt %xcc, U3copy_in_user_loop2 ! BR - add %o0, 0x40, %o0 ! A0 Group18 - - /* Finally we copy the last full 64-byte block. */ -U3copy_in_user_loopfini: - EXBLK3(ldda [%o1 + 0x008] %asi, %f2) ! MS - faligndata %f12, %f14, %f28 ! FGA - EXBLK3(ldda [%o1 + 0x010] %asi, %f4) ! MS Group19 - faligndata %f14, %f0, %f30 ! FGA - EXBLK3(stda %f16, [%o0] ASI_BLK_AIUS) ! MS Group20 - EXBLK4(ldda [%o1 + 0x018] %asi, %f6) ! AX - faligndata %f0, %f2, %f16 ! FGA Group11 (7-cycle stall) - EXBLK4(ldda [%o1 + 0x020] %asi, %f8) ! MS - faligndata %f2, %f4, %f18 ! FGA Group12 - EXBLK4(ldda [%o1 + 0x028] %asi, %f10) ! MS - faligndata %f4, %f6, %f20 ! FGA Group13 - EXBLK4(ldda [%o1 + 0x030] %asi, %f12) ! MS - faligndata %f6, %f8, %f22 ! FGA Group14 - EXBLK4(ldda [%o1 + 0x038] %asi, %f14) ! MS - faligndata %f8, %f10, %f24 ! FGA Group15 - cmp %g1, 0 ! A0 - be,pt %icc, 1f ! BR - add %o0, 0x40, %o0 ! A1 - EXBLK4(ldda [%o1 + 0x040] %asi, %f0) ! MS -1: faligndata %f10, %f12, %f26 ! FGA Group16 - faligndata %f12, %f14, %f28 ! FGA Group17 - faligndata %f14, %f0, %f30 ! FGA Group18 - EXBLK4(stda %f16, [%o0] ASI_BLK_AIUS) ! MS - add %o0, 0x40, %o0 ! A0 - add %o1, 0x40, %o1 ! A1 - membar #Sync ! MS Group26 (7-cycle stall) - - /* Now we copy the (len modulo 64) bytes at the end. - * Note how we borrow the %f0 loaded above. - * - * Also notice how this code is careful not to perform a - * load past the end of the src buffer just like similar - * code found in U3copy_in_user_toosmall processing. - */ -U3copy_in_user_loopend: - and %o2, 0x3f, %o2 ! A0 Group - andcc %o2, 0x38, %g2 ! A0 Group - be,pn %icc, U3copy_in_user_endcruft ! BR - subcc %g2, 0x8, %g2 ! A1 - be,pn %icc, U3copy_in_user_endcruft ! BR Group - cmp %g1, 0 ! A0 - - be,a,pt %icc, 1f ! BR Group - EX(ldda [%o1 + 0x00] %asi, %f0, add %o2, %g0) ! MS - -1: EX(ldda [%o1 + 0x08] %asi, %f2, add %o2, %g0) ! MS Group - add %o1, 0x8, %o1 ! A0 - sub %o2, 0x8, %o2 ! A1 - subcc %g2, 0x8, %g2 ! A0 Group - faligndata %f0, %f2, %f8 ! FGA Group - EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8) ! MS (XXX does it stall here? XXX) - be,pn %icc, U3copy_in_user_endcruft ! BR - add %o0, 0x8, %o0 ! A0 - EX(ldda [%o1 + 0x08] %asi, %f0, add %o2, %g0) ! MS Group - add %o1, 0x8, %o1 ! A0 - sub %o2, 0x8, %o2 ! A1 - subcc %g2, 0x8, %g2 ! A0 Group - faligndata %f2, %f0, %f8 ! FGA - EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8) ! MS (XXX does it stall here? XXX) - bne,pn %icc, 1b ! BR - add %o0, 0x8, %o0 ! A0 Group - - /* If anything is left, we copy it one byte at a time. - * Note that %g1 is (src & 0x3) saved above before the - * alignaddr was performed. - */ -U3copy_in_user_endcruft: cmp %o2, 0 - add %o1, %g1, %o1 - VISExitHalf - be,pn %icc, U3copy_in_user_short_ret + be,pn %XCC, out + or %o0, %o1, %o3 + cmp %o2, 16 + bleu,a,pn %XCC, small_copy + or %o3, %o2, %o3 + +medium_copy: /* 16 < len <= 64 */ + andcc %o3, 0x7, %g0 + bne,pn %XCC, small_copy_unaligned + sub %o0, %o1, %o3 + +medium_copy_aligned: + andn %o2, 0x7, %o4 + and %o2, 0x7, %o2 +1: subcc %o4, 0x8, %o4 + EXNV8(ldxa [%o1] %asi, %o5, add %o4, %o2) + EXNV8(stxa %o5, [%o1 + %o3] ASI_AIUS, add %o4, %o2) + bgu,pt %XCC, 1b + add %o1, 0x8, %o1 + andcc %o2, 0x4, %g0 + be,pt %XCC, 1f + nop + sub %o2, 0x4, %o2 + EXNV4(lduwa [%o1] %asi, %o5, add %o4, %o2) + EXNV4(stwa %o5, [%o1 + %o3] ASI_AIUS, add %o4, %o2) + add %o1, 0x4, %o1 +1: cmp %o2, 0 + be,pt %XCC, out + nop + ba,pt %xcc, small_copy_unaligned nop - ba,a,pt %xcc, U3copy_in_user_short - - /* If we get here, then 32 <= len < (6 * 64) */ -U3copy_in_user_toosmall: - -#ifdef SMALL_COPY_USES_FPU - - /* Is 'dst' already aligned on an 8-byte boundary? */ - be,pt %xcc, 2f ! BR Group - - /* Compute abs((dst & 7) - 8) into %g2. This is the number - * of bytes to copy to make 'dst' 8-byte aligned. We pre- - * subtract this from 'len'. - */ - sub %g2, 0x8, %g2 ! A0 - sub %g0, %g2, %g2 ! A0 Group (reg-dep) - sub %o2, %g2, %o2 ! A0 Group (reg-dep) - - /* Copy %g2 bytes from src to dst, one byte at a time. */ -1: EXNV2(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g2)! MS (Group) (%o3 in 3 cycles) - add %o1, 0x1, %o1 ! A1 - add %o0, 0x1, %o0 ! A0 Group - subcc %g2, 0x1, %g2 ! A1 - - bg,pt %icc, 1b ! BR Group - EXNV2(stba %o3, [%o0 + -1] %asi, add %o2, %g2) ! MS Group - -2: VISEntryHalf ! MS+MS - - /* Compute (len - (len % 8)) into %g2. This is guarenteed - * to be nonzero. - */ - andn %o2, 0x7, %g2 ! A0 Group - /* You may read this and believe that it allows reading - * one 8-byte longword past the end of src. It actually - * does not, as %g2 is subtracted as loads are done from - * src, so we always stop before running off the end. - * Also, we are guarenteed to have at least 0x10 bytes - * to move here. - */ - sub %g2, 0x8, %g2 ! A0 Group (reg-dep) - alignaddr %o1, %g0, %g1 ! MS (Break-after) - EX(ldda [%g1 + 0x00] %asi, %f0, add %o2, %g0) ! MS Group (1-cycle stall) - add %g1, 0x8, %g1 ! A0 - -1: EX(ldda [%g1 + 0x00] %asi, %f2, add %o2, %g0) ! MS Group - add %g1, 0x8, %g1 ! A0 - sub %o2, 0x8, %o2 ! A1 - subcc %g2, 0x8, %g2 ! A0 Group - - faligndata %f0, %f2, %f8 ! FGA Group (1-cycle stall) - EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8) ! MS Group (2-cycle stall) - add %o1, 0x8, %o1 ! A0 - be,pn %icc, 2f ! BR - - add %o0, 0x8, %o0 ! A1 - EX(ldda [%g1 + 0x00] %asi, %f0, add %o2, %g0) ! MS Group - add %g1, 0x8, %g1 ! A0 - sub %o2, 0x8, %o2 ! A1 - - subcc %g2, 0x8, %g2 ! A0 Group - faligndata %f2, %f0, %f8 ! FGA Group (1-cycle stall) - EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8) ! MS Group (2-cycle stall) - add %o1, 0x8, %o1 ! A0 - - bne,pn %icc, 1b ! BR - add %o0, 0x8, %o0 ! A1 - - /* Nothing left to copy? */ -2: cmp %o2, 0 ! A0 Group - VISExitHalf ! A0+MS - be,pn %icc, U3copy_in_user_short_ret ! BR Group - nop ! A0 - ba,a,pt %xcc, U3copy_in_user_short ! BR Group - -#else /* !(SMALL_COPY_USES_FPU) */ - - xor %o1, %o0, %g2 - andcc %g2, 0x7, %g0 - bne,pn %icc, U3copy_in_user_short - andcc %o1, 0x7, %g2 - - be,pt %xcc, 2f - sub %g2, 0x8, %g2 - sub %g0, %g2, %g2 - sub %o2, %g2, %o2 - -1: EXNV2(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g2) - add %o1, 0x1, %o1 - add %o0, 0x1, %o0 - subcc %g2, 0x1, %g2 - bg,pt %icc, 1b - EXNV2(stba %o3, [%o0 + -1] %asi, add %o2, %g2) - -2: andn %o2, 0x7, %g2 - sub %o2, %g2, %o2 - -3: EXNV3(ldxa [%o1 + 0x00] %asi, %o3, add %o2, %g2) - add %o1, 0x8, %o1 - add %o0, 0x8, %o0 - subcc %g2, 0x8, %g2 - bg,pt %icc, 3b - EXNV3(stxa %o3, [%o0 + -8] %asi, add %o2, %g2) +small_copy: /* 0 < len <= 16 */ + andcc %o3, 0x3, %g0 + bne,pn %XCC, small_copy_unaligned + sub %o0, %o1, %o3 + +small_copy_aligned: + subcc %o2, 4, %o2 + EXNV4(lduwa [%o1] %asi, %g1, add %o2, %g0) + EXNV4(stwa %g1, [%o1 + %o3] ASI_AIUS, add %o2, %g0) + bgu,pt %XCC, small_copy_aligned + add %o1, 4, %o1 - cmp %o2, 0 - bne,pn %icc, U3copy_in_user_short - nop - ba,a,pt %xcc, U3copy_in_user_short_ret +out: retl + clr %o0 -#endif /* !(SMALL_COPY_USES_FPU) */ + .align 32 +small_copy_unaligned: + subcc %o2, 1, %o2 + EXNV1(lduba [%o1] %asi, %g1, add %o2, %g0) + EXNV1(stba %g1, [%o1 + %o3] ASI_AIUS, add %o2, %g0) + bgu,pt %XCC, small_copy_unaligned + add %o1, 1, %o1 + retl + clr %o0 diff -Nru a/arch/sparc64/lib/U3copy_to_user.S b/arch/sparc64/lib/U3copy_to_user.S --- a/arch/sparc64/lib/U3copy_to_user.S 2004-08-14 12:02:30 -07:00 +++ b/arch/sparc64/lib/U3copy_to_user.S 2004-08-14 12:02:30 -07:00 @@ -1,15 +1,15 @@ -/* $Id: U3copy_to_user.S,v 1.3 2000/11/01 09:29:19 davem Exp $ - * U3memcpy.S: UltraSparc-III optimized copy to userspace. +/* U3copy_to_user.S: UltraSparc-III optimized memcpy. * - * Copyright (C) 1999, 2000 David S. Miller (davem@redhat.com) + * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com) */ -#ifdef __KERNEL__ #include #include #include #include -#undef SMALL_COPY_USES_FPU + +#define XCC xcc + #define EXNV(x,y,a,b) \ 98: x,y; \ .section .fixup; \ @@ -39,6 +39,18 @@ .align 4; \ 99: a, b, %o0; \ retl; \ + add %o0, 4, %o0; \ + .section __ex_table; \ + .align 4; \ + .word 98b, 99b; \ + .text; \ + .align 4; +#define EXNV4(x,y,a,b) \ +98: x,y; \ + .section .fixup; \ + .align 4; \ +99: a, b, %o0; \ + retl; \ add %o0, 8, %o0; \ .section __ex_table; \ .align 4; \ @@ -112,22 +124,9 @@ .word 98b, 99b; \ .text; \ .align 4; -#else -#define ASI_AIUS 0x80 -#define ASI_BLK_AIUS 0xf0 -#define FPRS_FEF 0x04 -#define VISEntryHalf rd %fprs, %o5; wr %g0, FPRS_FEF, %fprs -#define VISExitHalf and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs -#define SMALL_COPY_USES_FPU -#define EXNV(x,y,a,b) x,y; -#define EXNV2(x,y,a,b) x,y; -#define EXNV3(x,y,a,b) x,y; -#define EX(x,y,a,b) x,y; -#define EXBLK1(x,y) x,y; -#define EXBLK2(x,y) x,y; -#define EXBLK3(x,y) x,y; -#define EXBLK4(x,y) x,y; -#endif + + .register %g2,#scratch + .register %g3,#scratch /* Special/non-trivial issues of this code: * @@ -148,89 +147,64 @@ * of up to 2.4GB per second. */ - .globl U3copy_to_user -U3copy_to_user: /* %o0=dst, %o1=src, %o2=len */ + .globl U3copy_to_user +U3copy_to_user: /* %o0=dst, %o1=src, %o2=len */ /* Writing to %asi is _expensive_ so we hardcode it. * Reading %asi to check for KERNEL_DS is comparatively * cheap. */ - rd %asi, %g1 ! MS Group (4 cycles) - cmp %g1, ASI_AIUS ! A0 Group - bne U3memcpy ! BR - nop ! A1 -#ifndef __KERNEL__ - /* Save away original 'dst' for memcpy return value. */ - mov %o0, %g3 ! A0 Group -#endif - /* Anything to copy at all? */ - cmp %o2, 0 ! A1 - ble,pn %icc, U3copy_to_user_short_ret ! BR - - /* Extremely small copy? */ - cmp %o2, 31 ! A0 Group - ble,pn %icc, U3copy_to_user_short ! BR - - /* Large enough to use unrolled prefetch loops? */ - cmp %o2, 0x100 ! A1 - bge,a,pt %icc, U3copy_to_user_enter ! BR Group - andcc %o0, 0x3f, %g2 ! A0 - - ba,pt %xcc, U3copy_to_user_toosmall ! BR Group - andcc %o0, 0x7, %g2 ! A0 - - .align 32 -U3copy_to_user_short: - /* Copy %o2 bytes from src to dst, one byte at a time. */ - ldub [%o1 + 0x00], %o3 ! MS Group - add %o1, 0x1, %o1 ! A0 - add %o0, 0x1, %o0 ! A1 - subcc %o2, 1, %o2 ! A0 Group - - bg,pt %icc, U3copy_to_user_short ! BR - EXNV(stba %o3, [%o0 + -1] %asi, add %o2, 1) ! MS Group (1-cycle stall) - -U3copy_to_user_short_ret: -#ifdef __KERNEL__ - retl ! BR Group (0-4 cycle stall) - clr %o0 ! A0 -#else - retl ! BR Group (0-4 cycle stall) - mov %g3, %o0 ! A0 -#endif + rd %asi, %g1 + cmp %g1, ASI_AIUS + bne,pn %icc, U3memcpy_user_stub + nop - /* Here len >= (6 * 64) and condition codes reflect execution + cmp %o2, 0 + be,pn %XCC, out + or %o0, %o1, %o3 + cmp %o2, 16 + bleu,a,pn %XCC, small_copy + or %o3, %o2, %o3 + + cmp %o2, 256 + blu,pt %XCC, medium_copy + andcc %o3, 0x7, %g0 + + ba,pt %xcc, enter + andcc %o0, 0x3f, %g2 + + /* Here len >= 256 and condition codes reflect execution * of "andcc %o0, 0x7, %g2", done by caller. */ .align 64 -U3copy_to_user_enter: +enter: /* Is 'dst' already aligned on an 64-byte boundary? */ - be,pt %xcc, 2f ! BR + be,pt %XCC, 2f /* Compute abs((dst & 0x3f) - 0x40) into %g2. This is the number * of bytes to copy to make 'dst' 64-byte aligned. We pre- * subtract this from 'len'. */ - sub %g2, 0x40, %g2 ! A0 Group - sub %g0, %g2, %g2 ! A0 Group - sub %o2, %g2, %o2 ! A0 Group + sub %g2, 0x40, %g2 + sub %g0, %g2, %g2 + sub %o2, %g2, %o2 /* Copy %g2 bytes from src to dst, one byte at a time. */ -1: ldub [%o1 + 0x00], %o3 ! MS (Group) - add %o1, 0x1, %o1 ! A1 - add %o0, 0x1, %o0 ! A0 Group - subcc %g2, 0x1, %g2 ! A1 - - bg,pt %icc, 1b ! BR Group - EXNV2(stba %o3, [%o0 + -1] %asi, add %o2, %g2) ! MS Group - -2: VISEntryHalf ! MS+MS - and %o1, 0x7, %g1 ! A1 - ba,pt %xcc, U3copy_to_user_begin ! BR - alignaddr %o1, %g0, %o1 ! MS (Break-after) +1: ldub [%o1 + 0x00], %o3 + add %o1, 0x1, %o1 + add %o0, 0x1, %o0 + subcc %g2, 0x1, %g2 + + bg,pt %XCC, 1b + EXNV2(stba %o3, [%o0 + -1] %asi, add %o2, %g2) + +2: VISEntryHalf + and %o1, 0x7, %g1 + ba,pt %xcc, begin + alignaddr %o1, %g0, %o1 .align 64 -U3copy_to_user_begin: -#ifdef __KERNEL__ +begin: + .globl U3copy_to_user_nop_1_6 U3copy_to_user_nop_1_6: ldxa [%g0] ASI_DCU_CONTROL_REG, %g3 @@ -239,309 +213,221 @@ or %g3, %o3, %o3 stxa %o3, [%g0] ASI_DCU_CONTROL_REG ! Enable P-cache membar #Sync -#endif - prefetch [%o1 + 0x000], #one_read ! MS Group1 - prefetch [%o1 + 0x040], #one_read ! MS Group2 - andn %o2, (0x40 - 1), %o4 ! A0 - prefetch [%o1 + 0x080], #one_read ! MS Group3 - cmp %o4, 0x140 ! A0 - prefetch [%o1 + 0x0c0], #one_read ! MS Group4 - ldd [%o1 + 0x000], %f0 ! MS Group5 (%f0 results at G8) - bge,a,pt %icc, 1f ! BR - - prefetch [%o1 + 0x100], #one_read ! MS Group6 -1: ldd [%o1 + 0x008], %f2 ! AX (%f2 results at G9) - cmp %o4, 0x180 ! A1 - bge,a,pt %icc, 1f ! BR - prefetch [%o1 + 0x140], #one_read ! MS Group7 -1: ldd [%o1 + 0x010], %f4 ! AX (%f4 results at G10) - cmp %o4, 0x1c0 ! A1 - bge,a,pt %icc, 1f ! BR - - prefetch [%o1 + 0x180], #one_read ! MS Group8 -1: faligndata %f0, %f2, %f16 ! FGA Group9 (%f16 at G12) - ldd [%o1 + 0x018], %f6 ! AX (%f6 results at G12) - faligndata %f2, %f4, %f18 ! FGA Group10 (%f18 results at G13) - ldd [%o1 + 0x020], %f8 ! MS (%f8 results at G13) - faligndata %f4, %f6, %f20 ! FGA Group12 (1-cycle stall,%f20 at G15) - ldd [%o1 + 0x028], %f10 ! MS (%f10 results at G15) - faligndata %f6, %f8, %f22 ! FGA Group13 (%f22 results at G16) - - ldd [%o1 + 0x030], %f12 ! MS (%f12 results at G16) - faligndata %f8, %f10, %f24 ! FGA Group15 (1-cycle stall,%f24 at G18) - ldd [%o1 + 0x038], %f14 ! MS (%f14 results at G18) - faligndata %f10, %f12, %f26 ! FGA Group16 (%f26 results at G19) - ldd [%o1 + 0x040], %f0 ! MS (%f0 results at G19) - - /* We only use the first loop if len > (7 * 64). */ - subcc %o4, 0x1c0, %o4 ! A0 Group17 - bg,pt %icc, U3copy_to_user_loop1 ! BR - add %o1, 0x40, %o1 ! A1 - - add %o4, 0x140, %o4 ! A0 Group18 - ba,pt %xcc, U3copy_to_user_loop2 ! BR - srl %o4, 6, %o3 ! A0 Group19 - nop - nop - nop - nop - nop - - nop - nop - - /* This loop performs the copy and queues new prefetches. - * We drop into the second loop when len <= (5 * 64). Note - * that this (5 * 64) factor has been subtracted from len - * already. - */ -U3copy_to_user_loop1: - ldd [%o1 + 0x008], %f2 ! MS Group2 (%f2 results at G5) - faligndata %f12, %f14, %f28 ! FGA (%f28 results at G5) - ldd [%o1 + 0x010], %f4 ! MS Group3 (%f4 results at G6) - faligndata %f14, %f0, %f30 ! FGA Group4 (1-cycle stall, %f30 at G7) - EXBLK1(stda %f16, [%o0] ASI_BLK_AIUS) ! MS - ldd [%o1 + 0x018], %f6 ! AX (%f6 results at G7) - - faligndata %f0, %f2, %f16 ! FGA Group12 (7-cycle stall) - ldd [%o1 + 0x020], %f8 ! MS (%f8 results at G15) - faligndata %f2, %f4, %f18 ! FGA Group13 (%f18 results at G16) - ldd [%o1 + 0x028], %f10 ! MS (%f10 results at G16) - faligndata %f4, %f6, %f20 ! FGA Group14 (%f20 results at G17) - ldd [%o1 + 0x030], %f12 ! MS (%f12 results at G17) - faligndata %f6, %f8, %f22 ! FGA Group15 (%f22 results at G18) - ldd [%o1 + 0x038], %f14 ! MS (%f14 results at G18) - - faligndata %f8, %f10, %f24 ! FGA Group16 (%f24 results at G19) - ldd [%o1 + 0x040], %f0 ! AX (%f0 results at G19) - prefetch [%o1 + 0x180], #one_read ! MS - faligndata %f10, %f12, %f26 ! FGA Group17 (%f26 results at G20) - subcc %o4, 0x40, %o4 ! A0 - add %o1, 0x40, %o1 ! A1 - bg,pt %xcc, U3copy_to_user_loop1 ! BR - add %o0, 0x40, %o0 ! A0 Group18 - -U3copy_to_user_loop2_enter: - mov 5, %o3 ! A1 - - /* This loop performs on the copy, no new prefetches are - * queued. We do things this way so that we do not perform - * any spurious prefetches past the end of the src buffer. - */ -U3copy_to_user_loop2: - ldd [%o1 + 0x008], %f2 ! MS - faligndata %f12, %f14, %f28 ! FGA Group2 - ldd [%o1 + 0x010], %f4 ! MS - faligndata %f14, %f0, %f30 ! FGA Group4 (1-cycle stall) - EXBLK2(stda %f16, [%o0] ASI_BLK_AIUS) ! MS - ldd [%o1 + 0x018], %f6 ! AX - faligndata %f0, %f2, %f16 ! FGA Group12 (7-cycle stall) - - ldd [%o1 + 0x020], %f8 ! MS - faligndata %f2, %f4, %f18 ! FGA Group13 - ldd [%o1 + 0x028], %f10 ! MS - faligndata %f4, %f6, %f20 ! FGA Group14 - ldd [%o1 + 0x030], %f12 ! MS - faligndata %f6, %f8, %f22 ! FGA Group15 - ldd [%o1 + 0x038], %f14 ! MS - faligndata %f8, %f10, %f24 ! FGA Group16 - - ldd [%o1 + 0x040], %f0 ! AX - faligndata %f10, %f12, %f26 ! FGA Group17 - subcc %o3, 0x01, %o3 ! A0 - add %o1, 0x40, %o1 ! A1 - bg,pt %xcc, U3copy_to_user_loop2 ! BR - add %o0, 0x40, %o0 ! A0 Group18 + + prefetch [%o1 + 0x000], #one_read + prefetch [%o1 + 0x040], #one_read + andn %o2, (0x40 - 1), %o4 + prefetch [%o1 + 0x080], #one_read + prefetch [%o1 + 0x0c0], #one_read + ldd [%o1 + 0x000], %f0 + prefetch [%o1 + 0x100], #one_read + ldd [%o1 + 0x008], %f2 + prefetch [%o1 + 0x140], #one_read + ldd [%o1 + 0x010], %f4 + prefetch [%o1 + 0x180], #one_read + faligndata %f0, %f2, %f16 + ldd [%o1 + 0x018], %f6 + faligndata %f2, %f4, %f18 + ldd [%o1 + 0x020], %f8 + faligndata %f4, %f6, %f20 + ldd [%o1 + 0x028], %f10 + faligndata %f6, %f8, %f22 + + ldd [%o1 + 0x030], %f12 + faligndata %f8, %f10, %f24 + ldd [%o1 + 0x038], %f14 + faligndata %f10, %f12, %f26 + ldd [%o1 + 0x040], %f0 + + sub %o4, 0x80, %o4 + add %o1, 0x40, %o1 + ba,pt %xcc, loop + srl %o4, 6, %o3 + + .align 64 +loop: + ldd [%o1 + 0x008], %f2 + faligndata %f12, %f14, %f28 + ldd [%o1 + 0x010], %f4 + faligndata %f14, %f0, %f30 + EXBLK2(stda %f16, [%o0] ASI_BLK_AIUS) + ldd [%o1 + 0x018], %f6 + faligndata %f0, %f2, %f16 + + ldd [%o1 + 0x020], %f8 + faligndata %f2, %f4, %f18 + ldd [%o1 + 0x028], %f10 + faligndata %f4, %f6, %f20 + ldd [%o1 + 0x030], %f12 + faligndata %f6, %f8, %f22 + ldd [%o1 + 0x038], %f14 + faligndata %f8, %f10, %f24 + + ldd [%o1 + 0x040], %f0 + prefetch [%o1 + 0x180], #one_read + faligndata %f10, %f12, %f26 + subcc %o3, 0x01, %o3 + add %o1, 0x40, %o1 + bg,pt %XCC, loop + add %o0, 0x40, %o0 /* Finally we copy the last full 64-byte block. */ -U3copy_to_user_loopfini: - ldd [%o1 + 0x008], %f2 ! MS - faligndata %f12, %f14, %f28 ! FGA - ldd [%o1 + 0x010], %f4 ! MS Group19 - faligndata %f14, %f0, %f30 ! FGA - EXBLK3(stda %f16, [%o0] ASI_BLK_AIUS) ! MS Group20 - ldd [%o1 + 0x018], %f6 ! AX - faligndata %f0, %f2, %f16 ! FGA Group11 (7-cycle stall) - ldd [%o1 + 0x020], %f8 ! MS - faligndata %f2, %f4, %f18 ! FGA Group12 - ldd [%o1 + 0x028], %f10 ! MS - faligndata %f4, %f6, %f20 ! FGA Group13 - ldd [%o1 + 0x030], %f12 ! MS - faligndata %f6, %f8, %f22 ! FGA Group14 - ldd [%o1 + 0x038], %f14 ! MS - faligndata %f8, %f10, %f24 ! FGA Group15 - cmp %g1, 0 ! A0 - be,pt %icc, 1f ! BR - add %o0, 0x40, %o0 ! A1 - ldd [%o1 + 0x040], %f0 ! MS -1: faligndata %f10, %f12, %f26 ! FGA Group16 - faligndata %f12, %f14, %f28 ! FGA Group17 - faligndata %f14, %f0, %f30 ! FGA Group18 - EXBLK4(stda %f16, [%o0] ASI_BLK_AIUS) ! MS - add %o0, 0x40, %o0 ! A0 - add %o1, 0x40, %o1 ! A1 -#ifdef __KERNEL__ +loopfini: + ldd [%o1 + 0x008], %f2 + faligndata %f12, %f14, %f28 + ldd [%o1 + 0x010], %f4 + faligndata %f14, %f0, %f30 + EXBLK3(stda %f16, [%o0] ASI_BLK_AIUS) + ldd [%o1 + 0x018], %f6 + faligndata %f0, %f2, %f16 + ldd [%o1 + 0x020], %f8 + faligndata %f2, %f4, %f18 + ldd [%o1 + 0x028], %f10 + faligndata %f4, %f6, %f20 + ldd [%o1 + 0x030], %f12 + faligndata %f6, %f8, %f22 + ldd [%o1 + 0x038], %f14 + faligndata %f8, %f10, %f24 + cmp %g1, 0 + be,pt %XCC, 1f + add %o0, 0x40, %o0 + ldd [%o1 + 0x040], %f0 +1: faligndata %f10, %f12, %f26 + faligndata %f12, %f14, %f28 + faligndata %f14, %f0, %f30 + EXBLK4(stda %f16, [%o0] ASI_BLK_AIUS) + add %o0, 0x40, %o0 + add %o1, 0x40, %o1 + .globl U3copy_to_user_nop_2_3 U3copy_to_user_nop_2_3: mov PRIMARY_CONTEXT, %o3 stxa %g0, [%o3] ASI_DMMU ! Flush P-cache stxa %g3, [%g0] ASI_DCU_CONTROL_REG ! Disable P-cache -#endif - membar #Sync ! MS Group26 (7-cycle stall) + + membar #Sync /* Now we copy the (len modulo 64) bytes at the end. * Note how we borrow the %f0 loaded above. * * Also notice how this code is careful not to perform a - * load past the end of the src buffer just like similar - * code found in U3copy_to_user_toosmall processing. + * load past the end of the src buffer. */ -U3copy_to_user_loopend: - and %o2, 0x3f, %o2 ! A0 Group - andcc %o2, 0x38, %g2 ! A0 Group - be,pn %icc, U3copy_to_user_endcruft ! BR - subcc %g2, 0x8, %g2 ! A1 - be,pn %icc, U3copy_to_user_endcruft ! BR Group - cmp %g1, 0 ! A0 - - be,a,pt %icc, 1f ! BR Group - ldd [%o1 + 0x00], %f0 ! MS - -1: ldd [%o1 + 0x08], %f2 ! MS Group - add %o1, 0x8, %o1 ! A0 - sub %o2, 0x8, %o2 ! A1 - subcc %g2, 0x8, %g2 ! A0 Group - faligndata %f0, %f2, %f8 ! FGA Group - EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8) ! MS (XXX does it stall here? XXX) - be,pn %icc, U3copy_to_user_endcruft ! BR - add %o0, 0x8, %o0 ! A0 - ldd [%o1 + 0x08], %f0 ! MS Group - add %o1, 0x8, %o1 ! A0 - sub %o2, 0x8, %o2 ! A1 - subcc %g2, 0x8, %g2 ! A0 Group - faligndata %f2, %f0, %f8 ! FGA - EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8) ! MS (XXX does it stall here? XXX) - bne,pn %icc, 1b ! BR - add %o0, 0x8, %o0 ! A0 Group +loopend: + and %o2, 0x3f, %o2 + andcc %o2, 0x38, %g2 + be,pn %XCC, endcruft + subcc %g2, 0x8, %g2 + be,pn %XCC, endcruft + cmp %g1, 0 + + be,a,pt %XCC, 1f + ldd [%o1 + 0x00], %f0 + +1: ldd [%o1 + 0x08], %f2 + add %o1, 0x8, %o1 + sub %o2, 0x8, %o2 + subcc %g2, 0x8, %g2 + faligndata %f0, %f2, %f8 + EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8) + be,pn %XCC, endcruft + add %o0, 0x8, %o0 + ldd [%o1 + 0x08], %f0 + add %o1, 0x8, %o1 + sub %o2, 0x8, %o2 + subcc %g2, 0x8, %g2 + faligndata %f2, %f0, %f8 + EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8) + bne,pn %XCC, 1b + add %o0, 0x8, %o0 /* If anything is left, we copy it one byte at a time. * Note that %g1 is (src & 0x3) saved above before the * alignaddr was performed. */ -U3copy_to_user_endcruft: +endcruft: cmp %o2, 0 add %o1, %g1, %o1 VISExitHalf - be,pn %icc, U3copy_to_user_short_ret - nop - ba,a,pt %xcc, U3copy_to_user_short - - /* If we get here, then 32 <= len < (6 * 64) */ -U3copy_to_user_toosmall: - -#ifdef SMALL_COPY_USES_FPU - - /* Is 'dst' already aligned on an 8-byte boundary? */ - be,pt %xcc, 2f ! BR Group - - /* Compute abs((dst & 7) - 8) into %g2. This is the number - * of bytes to copy to make 'dst' 8-byte aligned. We pre- - * subtract this from 'len'. - */ - sub %g2, 0x8, %g2 ! A0 - sub %g0, %g2, %g2 ! A0 Group (reg-dep) - sub %o2, %g2, %o2 ! A0 Group (reg-dep) + be,pn %XCC, out + sub %o0, %o1, %o3 - /* Copy %g2 bytes from src to dst, one byte at a time. */ -1: ldub [%o1 + 0x00], %o3 ! MS (Group) (%o3 in 3 cycles) - add %o1, 0x1, %o1 ! A1 - add %o0, 0x1, %o0 ! A0 Group - subcc %g2, 0x1, %g2 ! A1 - - bg,pt %icc, 1b ! BR Group - EXNV2(stba %o3, [%o0 + -1] %asi, add %o2, %g2) ! MS Group - -2: VISEntryHalf ! MS+MS - - /* Compute (len - (len % 8)) into %g2. This is guarenteed - * to be nonzero. - */ - andn %o2, 0x7, %g2 ! A0 Group - - /* You may read this and believe that it allows reading - * one 8-byte longword past the end of src. It actually - * does not, as %g2 is subtracted as loads are done from - * src, so we always stop before running off the end. - * Also, we are guarenteed to have at least 0x10 bytes - * to move here. - */ - sub %g2, 0x8, %g2 ! A0 Group (reg-dep) - alignaddr %o1, %g0, %g1 ! MS (Break-after) - ldd [%g1 + 0x00], %f0 ! MS Group (1-cycle stall) - add %g1, 0x8, %g1 ! A0 - -1: ldd [%g1 + 0x00], %f2 ! MS Group - add %g1, 0x8, %g1 ! A0 - sub %o2, 0x8, %o2 ! A1 - subcc %g2, 0x8, %g2 ! A0 Group - - faligndata %f0, %f2, %f8 ! FGA Group (1-cycle stall) - EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8) ! MS Group (2-cycle stall) - add %o1, 0x8, %o1 ! A0 - be,pn %icc, 2f ! BR - - add %o0, 0x8, %o0 ! A1 - ldd [%g1 + 0x00], %f0 ! MS Group - add %g1, 0x8, %g1 ! A0 - sub %o2, 0x8, %o2 ! A1 - - subcc %g2, 0x8, %g2 ! A0 Group - faligndata %f2, %f0, %f8 ! FGA Group (1-cycle stall) - EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8) ! MS Group (2-cycle stall) - add %o1, 0x8, %o1 ! A0 - - bne,pn %icc, 1b ! BR - add %o0, 0x8, %o0 ! A1 - - /* Nothing left to copy? */ -2: cmp %o2, 0 ! A0 Group - VISExitHalf ! A0+MS - be,pn %icc, U3copy_to_user_short_ret ! BR Group - nop ! A0 - ba,a,pt %xcc, U3copy_to_user_short ! BR Group - -#else /* !(SMALL_COPY_USES_FPU) */ - - xor %o1, %o0, %g2 - andcc %g2, 0x7, %g0 - bne,pn %icc, U3copy_to_user_short - andcc %o1, 0x7, %g2 + andcc %g1, 0x7, %g0 + bne,pn %icc, small_copy_unaligned + andcc %o2, 0x8, %g0 + be,pt %icc, 1f + nop + ldx [%o1], %o5 + EXNV(stxa %o5, [%o1 + %o3] ASI_AIUS, add %o2, %g0) + add %o1, 0x8, %o1 - be,pt %xcc, 2f - sub %g2, 0x8, %g2 - sub %g0, %g2, %g2 - sub %o2, %g2, %o2 +1: andcc %o2, 0x4, %g0 + be,pt %icc, 1f + nop + lduw [%o1], %o5 + EXNV(stwa %o5, [%o1 + %o3] ASI_AIUS, and %o2, 0x7) + add %o1, 0x4, %o1 -1: ldub [%o1 + 0x00], %o3 - add %o1, 0x1, %o1 - add %o0, 0x1, %o0 - subcc %g2, 0x1, %g2 - bg,pt %icc, 1b - EXNV2(stba %o3, [%o0 + -1] %asi, add %o2, %g2) +1: andcc %o2, 0x2, %g0 + be,pt %icc, 1f + nop + lduh [%o1], %o5 + EXNV(stha %o5, [%o1 + %o3] ASI_AIUS, and %o2, 0x3) + add %o1, 0x2, %o1 -2: andn %o2, 0x7, %g2 - sub %o2, %g2, %o2 +1: andcc %o2, 0x1, %g0 + be,pt %icc, out + nop + ldub [%o1], %o5 + ba,pt %xcc, out + EXNV(stba %o5, [%o1 + %o3] ASI_AIUS, and %o2, 0x1) + +medium_copy: /* 16 < len <= 64 */ + bne,pn %XCC, small_copy_unaligned + sub %o0, %o1, %o3 + +medium_copy_aligned: + andn %o2, 0x7, %o4 + and %o2, 0x7, %o2 +1: subcc %o4, 0x8, %o4 + ldx [%o1], %o5 + EXNV4(stxa %o5, [%o1 + %o3] ASI_AIUS, add %o2, %o4) + bgu,pt %XCC, 1b + add %o1, 0x8, %o1 + andcc %o2, 0x4, %g0 + be,pt %XCC, 1f + nop + sub %o2, 0x4, %o2 + lduw [%o1], %o5 + EXNV3(stwa %o5, [%o1 + %o3] ASI_AIUS, add %o2, %g0) + add %o1, 0x4, %o1 +1: cmp %o2, 0 + be,pt %XCC, out + nop + ba,pt %xcc, small_copy_unaligned + nop -3: ldx [%o1 + 0x00], %o3 - add %o1, 0x8, %o1 - add %o0, 0x8, %o0 - subcc %g2, 0x8, %g2 - bg,pt %icc, 3b - EXNV3(stxa %o3, [%o0 + -8] %asi, add %o2, %g2) +small_copy: /* 0 < len <= 16 */ + andcc %o3, 0x3, %g0 + bne,pn %XCC, small_copy_unaligned + sub %o0, %o1, %o3 + +small_copy_aligned: + subcc %o2, 4, %o2 + lduw [%o1], %g1 + EXNV3(stwa %g1, [%o1 + %o3] ASI_AIUS, add %o2, %g0) + bgu,pt %XCC, small_copy_aligned + add %o1, 4, %o1 - cmp %o2, 0 - bne,pn %icc, U3copy_to_user_short - nop - ba,a,pt %xcc, U3copy_to_user_short_ret +out: retl + clr %o0 -#endif /* !(SMALL_COPY_USES_FPU) */ + .align 32 +small_copy_unaligned: + subcc %o2, 1, %o2 + ldub [%o1], %g1 + EXNV2(stba %g1, [%o1 + %o3] ASI_AIUS, add %o2, %g0) + bgu,pt %XCC, small_copy_unaligned + add %o1, 1, %o1 + retl + clr %o0 diff -Nru a/arch/sparc64/lib/U3memcpy.S b/arch/sparc64/lib/U3memcpy.S --- a/arch/sparc64/lib/U3memcpy.S 2004-08-14 12:02:31 -07:00 +++ b/arch/sparc64/lib/U3memcpy.S 2004-08-14 12:02:31 -07:00 @@ -1,7 +1,6 @@ -/* $Id: U3memcpy.S,v 1.2 2000/11/01 09:29:19 davem Exp $ - * U3memcpy.S: UltraSparc-III optimized memcpy. +/* U3memcpy.S: UltraSparc-III optimized memcpy. * - * Copyright (C) 1999, 2000 David S. Miller (davem@redhat.com) + * Copyright (C) 1999, 2000, 2004 David S. Miller (davem@redhat.com) */ #ifdef __KERNEL__ @@ -9,15 +8,20 @@ #include #include #include -#undef SMALL_COPY_USES_FPU #else #define ASI_BLK_P 0xf0 #define FPRS_FEF 0x04 #define VISEntryHalf rd %fprs, %o5; wr %g0, FPRS_FEF, %fprs #define VISExitHalf and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs -#define SMALL_COPY_USES_FPU #endif +#ifndef XCC +#define XCC xcc +#endif + + .register %g2,#scratch + .register %g3,#scratch + /* Special/non-trivial issues of this code: * * 1) %o5 is preserved from VISEntryHalf to VISExitHalf @@ -37,80 +41,55 @@ * of up to 2.4GB per second. */ - .globl U3memcpy -U3memcpy: /* %o0=dst, %o1=src, %o2=len */ -#ifndef __KERNEL__ - /* Save away original 'dst' for memcpy return value. */ - mov %o0, %g3 ! A0 Group -#endif - /* Anything to copy at all? */ - cmp %o2, 0 ! A1 - ble,pn %icc, U3memcpy_short_ret ! BR - - /* Extremely small copy? */ - cmp %o2, 31 ! A0 Group - ble,pn %icc, U3memcpy_short ! BR - - /* Large enough to use unrolled prefetch loops? */ - cmp %o2, 0x100 ! A1 - bge,a,pt %icc, U3memcpy_enter ! BR Group - andcc %o0, 0x3f, %g2 ! A0 - - ba,pt %xcc, U3memcpy_toosmall ! BR Group - andcc %o0, 0x7, %g2 ! A0 - - .align 32 -U3memcpy_short: - /* Copy %o2 bytes from src to dst, one byte at a time. */ - ldub [%o1 + 0x00], %o3 ! MS Group - add %o1, 0x1, %o1 ! A0 - add %o0, 0x1, %o0 ! A1 - subcc %o2, 1, %o2 ! A0 Group - - bg,pt %icc, U3memcpy_short ! BR - stb %o3, [%o0 + -1] ! MS Group (1-cycle stall) + .globl U3memcpy +U3memcpy: /* %o0=dst, %o1=src, %o2=len */ + mov %o0, %g5 + cmp %o2, 0 + be,pn %XCC, out + or %o0, %o1, %o3 + cmp %o2, 16 + bleu,a,pn %XCC, small_copy + or %o3, %o2, %o3 + + cmp %o2, 256 + blu,pt %XCC, medium_copy + andcc %o3, 0x7, %g0 -U3memcpy_short_ret: -#ifdef __KERNEL__ - retl ! BR Group (0-4 cycle stall) - clr %o0 ! A0 -#else - retl ! BR Group (0-4 cycle stall) - mov %g3, %o0 ! A0 -#endif + ba,pt %xcc, enter + andcc %o0, 0x3f, %g2 - /* Here len >= (6 * 64) and condition codes reflect execution + /* Here len >= 256 and condition codes reflect execution * of "andcc %o0, 0x7, %g2", done by caller. */ .align 64 -U3memcpy_enter: +enter: /* Is 'dst' already aligned on an 64-byte boundary? */ - be,pt %xcc, 2f ! BR + be,pt %XCC, 2f /* Compute abs((dst & 0x3f) - 0x40) into %g2. This is the number * of bytes to copy to make 'dst' 64-byte aligned. We pre- * subtract this from 'len'. */ - sub %g2, 0x40, %g2 ! A0 Group - sub %g0, %g2, %g2 ! A0 Group - sub %o2, %g2, %o2 ! A0 Group + sub %g2, 0x40, %g2 + sub %g0, %g2, %g2 + sub %o2, %g2, %o2 /* Copy %g2 bytes from src to dst, one byte at a time. */ -1: ldub [%o1 + 0x00], %o3 ! MS (Group) - add %o1, 0x1, %o1 ! A1 - add %o0, 0x1, %o0 ! A0 Group - subcc %g2, 0x1, %g2 ! A1 - - bg,pt %icc, 1b ! BR Group - stb %o3, [%o0 + -1] ! MS Group - -2: VISEntryHalf ! MS+MS - and %o1, 0x7, %g1 ! A1 - ba,pt %xcc, U3memcpy_begin ! BR - alignaddr %o1, %g0, %o1 ! MS (Break-after) +1: ldub [%o1 + 0x00], %o3 + add %o1, 0x1, %o1 + add %o0, 0x1, %o0 + subcc %g2, 0x1, %g2 + + bg,pt %XCC, 1b + stb %o3, [%o0 + -1] + +2: VISEntryHalf + and %o1, 0x7, %g1 + ba,pt %xcc, begin + alignaddr %o1, %g0, %o1 .align 64 -U3memcpy_begin: +begin: #ifdef __KERNEL__ .globl U3memcpy_nop_1_6 U3memcpy_nop_1_6: @@ -121,146 +100,90 @@ stxa %o3, [%g0] ASI_DCU_CONTROL_REG ! Enable P-cache membar #Sync #endif - prefetch [%o1 + 0x000], #one_read ! MS Group1 - prefetch [%o1 + 0x040], #one_read ! MS Group2 - andn %o2, (0x40 - 1), %o4 ! A0 - prefetch [%o1 + 0x080], #one_read ! MS Group3 - cmp %o4, 0x140 ! A0 - prefetch [%o1 + 0x0c0], #one_read ! MS Group4 - ldd [%o1 + 0x000], %f0 ! MS Group5 (%f0 results at G8) - bge,a,pt %icc, 1f ! BR - - prefetch [%o1 + 0x100], #one_read ! MS Group6 -1: ldd [%o1 + 0x008], %f2 ! AX (%f2 results at G9) - cmp %o4, 0x180 ! A1 - bge,a,pt %icc, 1f ! BR - prefetch [%o1 + 0x140], #one_read ! MS Group7 -1: ldd [%o1 + 0x010], %f4 ! AX (%f4 results at G10) - cmp %o4, 0x1c0 ! A1 - bge,a,pt %icc, 1f ! BR - - prefetch [%o1 + 0x180], #one_read ! MS Group8 -1: faligndata %f0, %f2, %f16 ! FGA Group9 (%f16 at G12) - ldd [%o1 + 0x018], %f6 ! AX (%f6 results at G12) - faligndata %f2, %f4, %f18 ! FGA Group10 (%f18 results at G13) - ldd [%o1 + 0x020], %f8 ! MS (%f8 results at G13) - faligndata %f4, %f6, %f20 ! FGA Group12 (1-cycle stall,%f20 at G15) - ldd [%o1 + 0x028], %f10 ! MS (%f10 results at G15) - faligndata %f6, %f8, %f22 ! FGA Group13 (%f22 results at G16) - - ldd [%o1 + 0x030], %f12 ! MS (%f12 results at G16) - faligndata %f8, %f10, %f24 ! FGA Group15 (1-cycle stall,%f24 at G18) - ldd [%o1 + 0x038], %f14 ! MS (%f14 results at G18) - faligndata %f10, %f12, %f26 ! FGA Group16 (%f26 results at G19) - ldd [%o1 + 0x040], %f0 ! MS (%f0 results at G19) - - /* We only use the first loop if len > (7 * 64). */ - subcc %o4, 0x1c0, %o4 ! A0 Group17 - bg,pt %icc, U3memcpy_loop1 ! BR - add %o1, 0x40, %o1 ! A1 - - add %o4, 0x140, %o4 ! A0 Group18 - ba,pt %xcc, U3memcpy_loop2 ! BR - srl %o4, 6, %o3 ! A0 Group19 - nop - nop - nop - nop - nop - - nop - nop - - /* This loop performs the copy and queues new prefetches. - * We drop into the second loop when len <= (5 * 64). Note - * that this (5 * 64) factor has been subtracted from len - * already. - */ -U3memcpy_loop1: - ldd [%o1 + 0x008], %f2 ! MS Group2 (%f2 results at G5) - faligndata %f12, %f14, %f28 ! FGA (%f28 results at G5) - ldd [%o1 + 0x010], %f4 ! MS Group3 (%f4 results at G6) - faligndata %f14, %f0, %f30 ! FGA Group4 (1-cycle stall, %f30 at G7) - stda %f16, [%o0] ASI_BLK_P ! MS - ldd [%o1 + 0x018], %f6 ! AX (%f6 results at G7) - - faligndata %f0, %f2, %f16 ! FGA Group12 (7-cycle stall) - ldd [%o1 + 0x020], %f8 ! MS (%f8 results at G15) - faligndata %f2, %f4, %f18 ! FGA Group13 (%f18 results at G16) - ldd [%o1 + 0x028], %f10 ! MS (%f10 results at G16) - faligndata %f4, %f6, %f20 ! FGA Group14 (%f20 results at G17) - ldd [%o1 + 0x030], %f12 ! MS (%f12 results at G17) - faligndata %f6, %f8, %f22 ! FGA Group15 (%f22 results at G18) - ldd [%o1 + 0x038], %f14 ! MS (%f14 results at G18) - - faligndata %f8, %f10, %f24 ! FGA Group16 (%f24 results at G19) - ldd [%o1 + 0x040], %f0 ! AX (%f0 results at G19) - prefetch [%o1 + 0x180], #one_read ! MS - faligndata %f10, %f12, %f26 ! FGA Group17 (%f26 results at G20) - subcc %o4, 0x40, %o4 ! A0 - add %o1, 0x40, %o1 ! A1 - bg,pt %xcc, U3memcpy_loop1 ! BR - add %o0, 0x40, %o0 ! A0 Group18 - -U3memcpy_loop2_enter: - mov 5, %o3 ! A1 - - /* This loop performs on the copy, no new prefetches are - * queued. We do things this way so that we do not perform - * any spurious prefetches past the end of the src buffer. - */ -U3memcpy_loop2: - ldd [%o1 + 0x008], %f2 ! MS - faligndata %f12, %f14, %f28 ! FGA Group2 - ldd [%o1 + 0x010], %f4 ! MS - faligndata %f14, %f0, %f30 ! FGA Group4 (1-cycle stall) - stda %f16, [%o0] ASI_BLK_P ! MS - ldd [%o1 + 0x018], %f6 ! AX - faligndata %f0, %f2, %f16 ! FGA Group12 (7-cycle stall) - - ldd [%o1 + 0x020], %f8 ! MS - faligndata %f2, %f4, %f18 ! FGA Group13 - ldd [%o1 + 0x028], %f10 ! MS - faligndata %f4, %f6, %f20 ! FGA Group14 - ldd [%o1 + 0x030], %f12 ! MS - faligndata %f6, %f8, %f22 ! FGA Group15 - ldd [%o1 + 0x038], %f14 ! MS - faligndata %f8, %f10, %f24 ! FGA Group16 - - ldd [%o1 + 0x040], %f0 ! AX - faligndata %f10, %f12, %f26 ! FGA Group17 - subcc %o3, 0x01, %o3 ! A0 - add %o1, 0x40, %o1 ! A1 - bg,pt %xcc, U3memcpy_loop2 ! BR - add %o0, 0x40, %o0 ! A0 Group18 + prefetch [%o1 + 0x000], #one_read + prefetch [%o1 + 0x040], #one_read + andn %o2, (0x40 - 1), %o4 + prefetch [%o1 + 0x080], #one_read + prefetch [%o1 + 0x0c0], #one_read + ldd [%o1 + 0x000], %f0 + prefetch [%o1 + 0x100], #one_read + ldd [%o1 + 0x008], %f2 + prefetch [%o1 + 0x140], #one_read + ldd [%o1 + 0x010], %f4 + prefetch [%o1 + 0x180], #one_read + faligndata %f0, %f2, %f16 + ldd [%o1 + 0x018], %f6 + faligndata %f2, %f4, %f18 + ldd [%o1 + 0x020], %f8 + faligndata %f4, %f6, %f20 + ldd [%o1 + 0x028], %f10 + faligndata %f6, %f8, %f22 + + ldd [%o1 + 0x030], %f12 + faligndata %f8, %f10, %f24 + ldd [%o1 + 0x038], %f14 + faligndata %f10, %f12, %f26 + ldd [%o1 + 0x040], %f0 + + sub %o4, 0x80, %o4 + add %o1, 0x40, %o1 + ba,pt %xcc, loop + srl %o4, 6, %o3 + + .align 64 +loop: + ldd [%o1 + 0x008], %f2 + faligndata %f12, %f14, %f28 + ldd [%o1 + 0x010], %f4 + faligndata %f14, %f0, %f30 + stda %f16, [%o0] ASI_BLK_P + ldd [%o1 + 0x018], %f6 + faligndata %f0, %f2, %f16 + + ldd [%o1 + 0x020], %f8 + faligndata %f2, %f4, %f18 + ldd [%o1 + 0x028], %f10 + faligndata %f4, %f6, %f20 + ldd [%o1 + 0x030], %f12 + faligndata %f6, %f8, %f22 + ldd [%o1 + 0x038], %f14 + faligndata %f8, %f10, %f24 + + ldd [%o1 + 0x040], %f0 + prefetch [%o1 + 0x180], #one_read + faligndata %f10, %f12, %f26 + subcc %o3, 0x01, %o3 + add %o1, 0x40, %o1 + bg,pt %XCC, loop + add %o0, 0x40, %o0 /* Finally we copy the last full 64-byte block. */ -U3memcpy_loopfini: - ldd [%o1 + 0x008], %f2 ! MS - faligndata %f12, %f14, %f28 ! FGA - ldd [%o1 + 0x010], %f4 ! MS Group19 - faligndata %f14, %f0, %f30 ! FGA - stda %f16, [%o0] ASI_BLK_P ! MS Group20 - ldd [%o1 + 0x018], %f6 ! AX - faligndata %f0, %f2, %f16 ! FGA Group11 (7-cycle stall) - ldd [%o1 + 0x020], %f8 ! MS - faligndata %f2, %f4, %f18 ! FGA Group12 - ldd [%o1 + 0x028], %f10 ! MS - faligndata %f4, %f6, %f20 ! FGA Group13 - ldd [%o1 + 0x030], %f12 ! MS - faligndata %f6, %f8, %f22 ! FGA Group14 - ldd [%o1 + 0x038], %f14 ! MS - faligndata %f8, %f10, %f24 ! FGA Group15 - cmp %g1, 0 ! A0 - be,pt %icc, 1f ! BR - add %o0, 0x40, %o0 ! A1 - ldd [%o1 + 0x040], %f0 ! MS -1: faligndata %f10, %f12, %f26 ! FGA Group16 - faligndata %f12, %f14, %f28 ! FGA Group17 - faligndata %f14, %f0, %f30 ! FGA Group18 - stda %f16, [%o0] ASI_BLK_P ! MS - add %o0, 0x40, %o0 ! A0 - add %o1, 0x40, %o1 ! A1 +loopfini: + ldd [%o1 + 0x008], %f2 + faligndata %f12, %f14, %f28 + ldd [%o1 + 0x010], %f4 + faligndata %f14, %f0, %f30 + stda %f16, [%o0] ASI_BLK_P + ldd [%o1 + 0x018], %f6 + faligndata %f0, %f2, %f16 + ldd [%o1 + 0x020], %f8 + faligndata %f2, %f4, %f18 + ldd [%o1 + 0x028], %f10 + faligndata %f4, %f6, %f20 + ldd [%o1 + 0x030], %f12 + faligndata %f6, %f8, %f22 + ldd [%o1 + 0x038], %f14 + faligndata %f8, %f10, %f24 + cmp %g1, 0 + be,pt %XCC, 1f + add %o0, 0x40, %o0 + ldd [%o1 + 0x040], %f0 +1: faligndata %f10, %f12, %f26 + faligndata %f12, %f14, %f28 + faligndata %f14, %f0, %f30 + stda %f16, [%o0] ASI_BLK_P + add %o0, 0x40, %o0 + add %o1, 0x40, %o1 #ifdef __KERNEL__ .globl U3memcpy_nop_2_3 U3memcpy_nop_2_3: @@ -268,161 +191,143 @@ stxa %g0, [%o3] ASI_DMMU ! Flush P-cache stxa %g3, [%g0] ASI_DCU_CONTROL_REG ! Disable P-cache #endif - membar #Sync ! MS Group26 (7-cycle stall) + membar #Sync /* Now we copy the (len modulo 64) bytes at the end. * Note how we borrow the %f0 loaded above. * * Also notice how this code is careful not to perform a - * load past the end of the src buffer just like similar - * code found in U3memcpy_toosmall processing. + * load past the end of the src buffer. */ -U3memcpy_loopend: - and %o2, 0x3f, %o2 ! A0 Group - andcc %o2, 0x38, %g2 ! A0 Group - be,pn %icc, U3memcpy_endcruft ! BR - subcc %g2, 0x8, %g2 ! A1 - be,pn %icc, U3memcpy_endcruft ! BR Group - cmp %g1, 0 ! A0 - - be,a,pt %icc, 1f ! BR Group - ldd [%o1 + 0x00], %f0 ! MS - -1: ldd [%o1 + 0x08], %f2 ! MS Group - add %o1, 0x8, %o1 ! A0 - sub %o2, 0x8, %o2 ! A1 - subcc %g2, 0x8, %g2 ! A0 Group - faligndata %f0, %f2, %f8 ! FGA Group - std %f8, [%o0 + 0x00] ! MS (XXX does it stall here? XXX) - be,pn %icc, U3memcpy_endcruft ! BR - add %o0, 0x8, %o0 ! A0 - ldd [%o1 + 0x08], %f0 ! MS Group - add %o1, 0x8, %o1 ! A0 - sub %o2, 0x8, %o2 ! A1 - subcc %g2, 0x8, %g2 ! A0 Group - faligndata %f2, %f0, %f8 ! FGA - std %f8, [%o0 + 0x00] ! MS (XXX does it stall here? XXX) - bne,pn %icc, 1b ! BR - add %o0, 0x8, %o0 ! A0 Group +loopend: + and %o2, 0x3f, %o2 + andcc %o2, 0x38, %g2 + be,pn %XCC, endcruft + subcc %g2, 0x8, %g2 + be,pn %XCC, endcruft + cmp %g1, 0 + + be,a,pt %XCC, 1f + ldd [%o1 + 0x00], %f0 + +1: ldd [%o1 + 0x08], %f2 + add %o1, 0x8, %o1 + sub %o2, 0x8, %o2 + subcc %g2, 0x8, %g2 + faligndata %f0, %f2, %f8 + std %f8, [%o0 + 0x00] + be,pn %XCC, endcruft + add %o0, 0x8, %o0 + ldd [%o1 + 0x08], %f0 + add %o1, 0x8, %o1 + sub %o2, 0x8, %o2 + subcc %g2, 0x8, %g2 + faligndata %f2, %f0, %f8 + std %f8, [%o0 + 0x00] + bne,pn %XCC, 1b + add %o0, 0x8, %o0 /* If anything is left, we copy it one byte at a time. * Note that %g1 is (src & 0x3) saved above before the * alignaddr was performed. */ -U3memcpy_endcruft: +endcruft: cmp %o2, 0 add %o1, %g1, %o1 VISExitHalf - be,pn %icc, U3memcpy_short_ret - nop - ba,a,pt %xcc, U3memcpy_short - - /* If we get here, then 32 <= len < (6 * 64) */ -U3memcpy_toosmall: - -#ifdef SMALL_COPY_USES_FPU + be,pn %XCC, out + sub %o0, %o1, %o3 - /* Is 'dst' already aligned on an 8-byte boundary? */ - be,pt %xcc, 2f ! BR Group - - /* Compute abs((dst & 7) - 8) into %g2. This is the number - * of bytes to copy to make 'dst' 8-byte aligned. We pre- - * subtract this from 'len'. - */ - sub %g2, 0x8, %g2 ! A0 - sub %g0, %g2, %g2 ! A0 Group (reg-dep) - sub %o2, %g2, %o2 ! A0 Group (reg-dep) - - /* Copy %g2 bytes from src to dst, one byte at a time. */ -1: ldub [%o1 + 0x00], %o3 ! MS (Group) (%o3 in 3 cycles) - add %o1, 0x1, %o1 ! A1 - add %o0, 0x1, %o0 ! A0 Group - subcc %g2, 0x1, %g2 ! A1 - - bg,pt %icc, 1b ! BR Group - stb %o3, [%o0 + -1] ! MS Group - -2: VISEntryHalf ! MS+MS - - /* Compute (len - (len % 8)) into %g2. This is guarenteed - * to be nonzero. - */ - andn %o2, 0x7, %g2 ! A0 Group - - /* You may read this and believe that it allows reading - * one 8-byte longword past the end of src. It actually - * does not, as %g2 is subtracted as loads are done from - * src, so we always stop before running off the end. - * Also, we are guarenteed to have at least 0x10 bytes - * to move here. - */ - sub %g2, 0x8, %g2 ! A0 Group (reg-dep) - alignaddr %o1, %g0, %g1 ! MS (Break-after) - ldd [%g1 + 0x00], %f0 ! MS Group (1-cycle stall) - add %g1, 0x8, %g1 ! A0 - -1: ldd [%g1 + 0x00], %f2 ! MS Group - add %g1, 0x8, %g1 ! A0 - sub %o2, 0x8, %o2 ! A1 - subcc %g2, 0x8, %g2 ! A0 Group - - faligndata %f0, %f2, %f8 ! FGA Group (1-cycle stall) - std %f8, [%o0 + 0x00] ! MS Group (2-cycle stall) - add %o1, 0x8, %o1 ! A0 - be,pn %icc, 2f ! BR - - add %o0, 0x8, %o0 ! A1 - ldd [%g1 + 0x00], %f0 ! MS Group - add %g1, 0x8, %g1 ! A0 - sub %o2, 0x8, %o2 ! A1 - - subcc %g2, 0x8, %g2 ! A0 Group - faligndata %f2, %f0, %f8 ! FGA Group (1-cycle stall) - std %f8, [%o0 + 0x00] ! MS Group (2-cycle stall) - add %o1, 0x8, %o1 ! A0 - - bne,pn %icc, 1b ! BR - add %o0, 0x8, %o0 ! A1 - - /* Nothing left to copy? */ -2: cmp %o2, 0 ! A0 Group - VISExitHalf ! A0+MS - be,pn %icc, U3memcpy_short_ret ! BR Group - nop ! A0 - ba,a,pt %xcc, U3memcpy_short ! BR Group - -#else /* !(SMALL_COPY_USES_FPU) */ - - xor %o1, %o0, %g2 - andcc %g2, 0x7, %g0 - bne,pn %icc, U3memcpy_short - andcc %o1, 0x7, %g2 + andcc %g1, 0x7, %g0 + bne,pn %icc, small_copy_unaligned + andcc %o2, 0x8, %g0 + be,pt %icc, 1f + nop + ldx [%o1], %o5 + stx %o5, [%o1 + %o3] + add %o1, 0x8, %o1 - be,pt %xcc, 2f - sub %g2, 0x8, %g2 - sub %g0, %g2, %g2 - sub %o2, %g2, %o2 +1: andcc %o2, 0x4, %g0 + be,pt %icc, 1f + nop + lduw [%o1], %o5 + stw %o5, [%o1 + %o3] + add %o1, 0x4, %o1 -1: ldub [%o1 + 0x00], %o3 - add %o1, 0x1, %o1 - add %o0, 0x1, %o0 - subcc %g2, 0x1, %g2 - bg,pt %icc, 1b - stb %o3, [%o0 + -1] +1: andcc %o2, 0x2, %g0 + be,pt %icc, 1f + nop + lduh [%o1], %o5 + sth %o5, [%o1 + %o3] + add %o1, 0x2, %o1 -2: andn %o2, 0x7, %g2 - sub %o2, %g2, %o2 +1: andcc %o2, 0x1, %g0 + be,pt %icc, out + nop + ldub [%o1], %o5 + ba,pt %xcc, out + stb %o5, [%o1 + %o3] + +medium_copy: /* 16 < len <= 64 */ + bne,pn %XCC, small_copy_unaligned + sub %o0, %o1, %o3 + +medium_copy_aligned: + andn %o2, 0x7, %o4 + and %o2, 0x7, %o2 +1: subcc %o4, 0x8, %o4 + ldx [%o1], %o5 + stx %o5, [%o1 + %o3] + bgu,pt %XCC, 1b + add %o1, 0x8, %o1 + andcc %o2, 0x4, %g0 + be,pt %XCC, 1f + nop + sub %o2, 0x4, %o2 + lduw [%o1], %o5 + stw %o5, [%o1 + %o3] + add %o1, 0x4, %o1 +1: cmp %o2, 0 + be,pt %XCC, out + nop + ba,pt %xcc, small_copy_unaligned + nop -3: ldx [%o1 + 0x00], %o3 - add %o1, 0x8, %o1 - add %o0, 0x8, %o0 - subcc %g2, 0x8, %g2 - bg,pt %icc, 3b - stx %o3, [%o0 + -8] +small_copy: /* 0 < len <= 16 */ + andcc %o3, 0x3, %g0 + bne,pn %XCC, small_copy_unaligned + sub %o0, %o1, %o3 + +small_copy_aligned: + subcc %o2, 4, %o2 + lduw [%o1], %g1 + stw %g1, [%o1 + %o3] + bgu,pt %XCC, small_copy_aligned + add %o1, 4, %o1 - cmp %o2, 0 - bne,pn %icc, U3memcpy_short - nop - ba,a,pt %xcc, U3memcpy_short_ret +out: retl + mov %g5, %o0 -#endif /* !(SMALL_COPY_USES_FPU) */ + .align 32 +small_copy_unaligned: + subcc %o2, 1, %o2 + ldub [%o1], %g1 + stb %g1, [%o1 + %o3] + bgu,pt %XCC, small_copy_unaligned + add %o1, 1, %o1 + retl + mov %g5, %o0 + + /* Act like copy_{to,in}_user(), ie. return zero instead + * of original destination pointer. This is invoked when + * copy_{to,in}_user() finds that %asi is kernel space. + */ + .globl U3memcpy_user_stub +U3memcpy_user_stub: + save %sp, -192, %sp + mov %i0, %o0 + mov %i1, %o1 + call U3memcpy + mov %i2, %o2 + ret + restore %g0, %g0, %o0 diff -Nru a/arch/sparc64/lib/VIScopy.S b/arch/sparc64/lib/VIScopy.S --- a/arch/sparc64/lib/VIScopy.S 2004-08-14 12:02:30 -07:00 +++ b/arch/sparc64/lib/VIScopy.S 2004-08-14 12:02:30 -07:00 @@ -306,11 +306,7 @@ .globl __memcpy_begin __memcpy_begin: - .globl __memcpy - .type __memcpy,@function - memcpy_private: -__memcpy: memcpy: mov ASI_P, asi_src ! IEU0 Group brnz,pt %o2, __memcpy_entry ! CTI mov ASI_P, asi_dest ! IEU1 diff -Nru a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c --- a/arch/sparc64/mm/fault.c 2004-08-14 12:02:31 -07:00 +++ b/arch/sparc64/mm/fault.c 2004-08-14 12:02:31 -07:00 @@ -253,7 +253,7 @@ * in that case. */ - if (!(fault_code & FAULT_CODE_WRITE) && + if (!(fault_code & (FAULT_CODE_WRITE|FAULT_CODE_ITLB)) && (insn & 0xc0800000) == 0xc0800000) { if (insn & 0x2000) asi = (regs->tstate >> 24); @@ -404,6 +404,16 @@ */ good_area: si_code = SEGV_ACCERR; + + /* If we took a ITLB miss on a non-executable page, catch + * that here. + */ + if ((fault_code & FAULT_CODE_ITLB) && !(vma->vm_flags & VM_EXEC)) { + BUG_ON(address != regs->tpc); + BUG_ON(regs->tstate & TSTATE_PRIV); + goto bad_area; + } + if (fault_code & FAULT_CODE_WRITE) { if (!(vma->vm_flags & VM_WRITE)) goto bad_area; diff -Nru a/crypto/Config.in b/crypto/Config.in --- a/crypto/Config.in 2004-08-14 12:02:30 -07:00 +++ b/crypto/Config.in 2004-08-14 12:02:30 -07:00 @@ -73,6 +73,7 @@ tristate ' CAST5 (CAST-128) cipher algorithm' CONFIG_CRYPTO_CAST5 tristate ' CAST6 (CAST-256) cipher algorithm' CONFIG_CRYPTO_CAST6 tristate ' TEA and XTEA cipher algorithms' CONFIG_CRYPTO_TEA + tristate ' Khazad cipher algorithm' CONFIG_CRYPTO_KHAZAD tristate ' ARC4 cipher algorithm' CONFIG_CRYPTO_ARC4 if [ "$CONFIG_INET_IPCOMP" = "y" -o \ "$CONFIG_INET_IPCOMP" = "m" -o \ diff -Nru a/crypto/Makefile b/crypto/Makefile --- a/crypto/Makefile 2004-08-14 12:02:30 -07:00 +++ b/crypto/Makefile 2004-08-14 12:02:30 -07:00 @@ -28,6 +28,7 @@ obj-$(CONFIG_CRYPTO_CAST6) += cast6.o obj-$(CONFIG_CRYPTO_ARC4) += arc4.o obj-$(CONFIG_CRYPTO_TEA) += tea.o +obj-$(CONFIG_CRYPTO_KHAZAD) += khazad.o obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o diff -Nru a/crypto/aes.c b/crypto/aes.c --- a/crypto/aes.c 2004-08-14 12:02:30 -07:00 +++ b/crypto/aes.c 2004-08-14 12:02:30 -07:00 @@ -160,7 +160,7 @@ u8 p, q; /* log and power tables for GF(2**8) finite field with - 0x011b as modular polynomial - the simplest prmitive + 0x011b as modular polynomial - the simplest primitive root is 0x03, used here to generate the tables */ for (i = 0, p = 1; i < 256; ++i) { diff -Nru a/crypto/arc4.c b/crypto/arc4.c --- a/crypto/arc4.c 2004-08-14 12:02:30 -07:00 +++ b/crypto/arc4.c 2004-08-14 12:02:30 -07:00 @@ -3,7 +3,7 @@ * * ARC4 Cipher Algorithm * - * Jon Oberheide + * Jon Oberheide * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -100,4 +100,4 @@ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("ARC4 Cipher Algorithm"); -MODULE_AUTHOR("Jon Oberheide "); +MODULE_AUTHOR("Jon Oberheide "); diff -Nru a/crypto/blowfish.c b/crypto/blowfish.c --- a/crypto/blowfish.c 2004-08-14 12:02:30 -07:00 +++ b/crypto/blowfish.c 2004-08-14 12:02:30 -07:00 @@ -3,9 +3,9 @@ * * Blowfish Cipher Algorithm, by Bruce Schneier. * http://www.counterpane.com/blowfish.html - * - * Adapated from Kerneli implementation. - * + * + * Adapted from Kerneli implementation. + * * Copyright (c) Herbert Valerio Riedel * Copyright (c) Kyle McMartin * Copyright (c) 2002 James Morris diff -Nru a/crypto/khazad.c b/crypto/khazad.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/crypto/khazad.c 2004-08-14 12:02:31 -07:00 @@ -0,0 +1,915 @@ +/* + * Cryptographic API. + * + * Khazad Algorithm + * + * The Khazad algorithm was developed by Paulo S. L. M. Barreto and + * Vincent Rijmen. It was a finalist in the NESSIE encryption contest. + * + * The original authors have disclaimed all copyright interest in this + * code and thus put it in the public domain. The subsequent authors + * have put this under the GNU General Public License. + * + * By Aaron Grothe ajgrothe@yahoo.com, August 1, 2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include + +#define KHAZAD_KEY_SIZE 16 +#define KHAZAD_BLOCK_SIZE 8 +#define KHAZAD_ROUNDS 8 + +struct khazad_ctx { + u64 E[KHAZAD_ROUNDS + 1]; + u64 D[KHAZAD_ROUNDS + 1]; +}; + +static const u64 T0[256] = { + 0xbad3d268bbb96a01ULL, 0x54fc4d19e59a66b1ULL, 0x2f71bc93e26514cdULL, + 0x749ccdb925871b51ULL, 0x53f55102f7a257a4ULL, 0xd3686bb8d0d6be03ULL, + 0xd26b6fbdd6deb504ULL, 0x4dd72964b35285feULL, 0x50f05d0dfdba4aadULL, + 0xace98a26cf09e063ULL, 0x8d8a0e83091c9684ULL, 0xbfdcc679a5914d1aULL, + 0x7090ddad3da7374dULL, 0x52f65507f1aa5ca3ULL, 0x9ab352c87ba417e1ULL, + 0x4cd42d61b55a8ef9ULL, 0xea238f65460320acULL, 0xd56273a6c4e68411ULL, + 0x97a466f155cc68c2ULL, 0xd16e63b2dcc6a80dULL, 0x3355ccffaa85d099ULL, + 0x51f35908fbb241aaULL, 0x5bed712ac7e20f9cULL, 0xa6f7a204f359ae55ULL, + 0xde7f5f81febec120ULL, 0x48d83d75ad7aa2e5ULL, 0xa8e59a32d729cc7fULL, + 0x99b65ec771bc0ae8ULL, 0xdb704b90e096e63bULL, 0x3256c8faac8ddb9eULL, + 0xb7c4e65195d11522ULL, 0xfc19d72b32b3aaceULL, 0xe338ab48704b7393ULL, + 0x9ebf42dc63843bfdULL, 0x91ae7eef41fc52d0ULL, 0x9bb056cd7dac1ce6ULL, + 0xe23baf4d76437894ULL, 0xbbd0d66dbdb16106ULL, 0x41c319589b32f1daULL, + 0x6eb2a5cb7957e517ULL, 0xa5f2ae0bf941b35cULL, 0xcb400bc08016564bULL, + 0x6bbdb1da677fc20cULL, 0x95a26efb59dc7eccULL, 0xa1febe1fe1619f40ULL, + 0xf308eb1810cbc3e3ULL, 0xb1cefe4f81e12f30ULL, 0x0206080a0c10160eULL, + 0xcc4917db922e675eULL, 0xc45137f3a26e3f66ULL, 0x1d2774694ee8cf53ULL, + 0x143c504478a09c6cULL, 0xc3582be8b0560e73ULL, 0x63a591f2573f9a34ULL, + 0xda734f95e69eed3cULL, 0x5de76934d3d2358eULL, 0x5fe1613edfc22380ULL, + 0xdc79578bf2aed72eULL, 0x7d87e99413cf486eULL, 0xcd4a13de94266c59ULL, + 0x7f81e19e1fdf5e60ULL, 0x5aee752fc1ea049bULL, 0x6cb4adc17547f319ULL, + 0x5ce46d31d5da3e89ULL, 0xf704fb0c08ebefffULL, 0x266a98bed42d47f2ULL, + 0xff1cdb2438abb7c7ULL, 0xed2a937e543b11b9ULL, 0xe825876f4a1336a2ULL, + 0x9dba4ed3699c26f4ULL, 0x6fb1a1ce7f5fee10ULL, 0x8e8f028c03048b8dULL, + 0x192b647d56c8e34fULL, 0xa0fdba1ae7699447ULL, 0xf00de7171ad3deeaULL, + 0x89861e97113cba98ULL, 0x0f113c332278692dULL, 0x07091c1b12383115ULL, + 0xafec8629c511fd6aULL, 0xfb10cb30208b9bdbULL, 0x0818202830405838ULL, + 0x153f54417ea8976bULL, 0x0d1734392e687f23ULL, 0x040c101418202c1cULL, + 0x0103040506080b07ULL, 0x64ac8de94507ab21ULL, 0xdf7c5b84f8b6ca27ULL, + 0x769ac5b329970d5fULL, 0x798bf9800bef6472ULL, 0xdd7a538ef4a6dc29ULL, + 0x3d47f4c98ef5b2b3ULL, 0x163a584e74b08a62ULL, 0x3f41fcc382e5a4bdULL, + 0x3759dcebb2a5fc85ULL, 0x6db7a9c4734ff81eULL, 0x3848e0d890dd95a8ULL, + 0xb9d6de67b1a17708ULL, 0x7395d1a237bf2a44ULL, 0xe926836a4c1b3da5ULL, + 0x355fd4e1beb5ea8bULL, 0x55ff491ce3926db6ULL, 0x7193d9a83baf3c4aULL, + 0x7b8df18a07ff727cULL, 0x8c890a860f149d83ULL, 0x7296d5a731b72143ULL, + 0x88851a921734b19fULL, 0xf607ff090ee3e4f8ULL, 0x2a7ea882fc4d33d6ULL, + 0x3e42f8c684edafbaULL, 0x5ee2653bd9ca2887ULL, 0x27699cbbd2254cf5ULL, + 0x46ca0543890ac0cfULL, 0x0c14303c28607424ULL, 0x65af89ec430fa026ULL, + 0x68b8bdd56d67df05ULL, 0x61a399f85b2f8c3aULL, 0x03050c0f0a181d09ULL, + 0xc15e23e2bc46187dULL, 0x57f94116ef827bb8ULL, 0xd6677fa9cefe9918ULL, + 0xd976439aec86f035ULL, 0x58e87d25cdfa1295ULL, 0xd875479fea8efb32ULL, + 0x66aa85e34917bd2fULL, 0xd7647bacc8f6921fULL, 0x3a4ee8d29ccd83a6ULL, + 0xc84507cf8a0e4b42ULL, 0x3c44f0cc88fdb9b4ULL, 0xfa13cf35268390dcULL, + 0x96a762f453c463c5ULL, 0xa7f4a601f551a552ULL, 0x98b55ac277b401efULL, + 0xec29977b52331abeULL, 0xb8d5da62b7a97c0fULL, 0xc7543bfca876226fULL, + 0xaeef822cc319f66dULL, 0x69bbb9d06b6fd402ULL, 0x4bdd317aa762bfecULL, + 0xabe0963ddd31d176ULL, 0xa9e69e37d121c778ULL, 0x67a981e64f1fb628ULL, + 0x0a1e28223c504e36ULL, 0x47c901468f02cbc8ULL, 0xf20bef1d16c3c8e4ULL, + 0xb5c2ee5b99c1032cULL, 0x226688aacc0d6beeULL, 0xe532b356647b4981ULL, + 0xee2f9f715e230cb0ULL, 0xbedfc27ca399461dULL, 0x2b7dac87fa4538d1ULL, + 0x819e3ebf217ce2a0ULL, 0x1236485a6c90a67eULL, 0x839836b52d6cf4aeULL, + 0x1b2d6c775ad8f541ULL, 0x0e1238362470622aULL, 0x23658cafca0560e9ULL, + 0xf502f30604fbf9f1ULL, 0x45cf094c8312ddc6ULL, 0x216384a5c61576e7ULL, + 0xce4f1fd19e3e7150ULL, 0x49db3970ab72a9e2ULL, 0x2c74b09ce87d09c4ULL, + 0xf916c33a2c9b8dd5ULL, 0xe637bf596e635488ULL, 0xb6c7e25493d91e25ULL, + 0x2878a088f05d25d8ULL, 0x17395c4b72b88165ULL, 0x829b32b02b64ffa9ULL, + 0x1a2e68725cd0fe46ULL, 0x8b80169d1d2cac96ULL, 0xfe1fdf213ea3bcc0ULL, + 0x8a8312981b24a791ULL, 0x091b242d3648533fULL, 0xc94603ca8c064045ULL, + 0x879426a1354cd8b2ULL, 0x4ed2256bb94a98f7ULL, 0xe13ea3427c5b659dULL, + 0x2e72b896e46d1fcaULL, 0xe431b75362734286ULL, 0xe03da7477a536e9aULL, + 0xeb208b60400b2babULL, 0x90ad7aea47f459d7ULL, 0xa4f1aa0eff49b85bULL, + 0x1e22786644f0d25aULL, 0x85922eab395ccebcULL, 0x60a09dfd5d27873dULL, + 0x0000000000000000ULL, 0x256f94b1de355afbULL, 0xf401f70302f3f2f6ULL, + 0xf10ee3121cdbd5edULL, 0x94a16afe5fd475cbULL, 0x0b1d2c273a584531ULL, + 0xe734bb5c686b5f8fULL, 0x759fc9bc238f1056ULL, 0xef2c9b74582b07b7ULL, + 0x345cd0e4b8bde18cULL, 0x3153c4f5a695c697ULL, 0xd46177a3c2ee8f16ULL, + 0xd06d67b7dacea30aULL, 0x869722a43344d3b5ULL, 0x7e82e59b19d75567ULL, + 0xadea8e23c901eb64ULL, 0xfd1ad32e34bba1c9ULL, 0x297ba48df6552edfULL, + 0x3050c0f0a09dcd90ULL, 0x3b4decd79ac588a1ULL, 0x9fbc46d9658c30faULL, + 0xf815c73f2a9386d2ULL, 0xc6573ff9ae7e2968ULL, 0x13354c5f6a98ad79ULL, + 0x060a181e14303a12ULL, 0x050f14111e28271bULL, 0xc55233f6a4663461ULL, + 0x113344556688bb77ULL, 0x7799c1b62f9f0658ULL, 0x7c84ed9115c74369ULL, + 0x7a8ef58f01f7797bULL, 0x7888fd850de76f75ULL, 0x365ad8eeb4adf782ULL, + 0x1c24706c48e0c454ULL, 0x394be4dd96d59eafULL, 0x59eb7920cbf21992ULL, + 0x1828607850c0e848ULL, 0x56fa4513e98a70bfULL, 0xb3c8f6458df1393eULL, + 0xb0cdfa4a87e92437ULL, 0x246c90b4d83d51fcULL, 0x206080a0c01d7de0ULL, + 0xb2cbf2408bf93239ULL, 0x92ab72e04be44fd9ULL, 0xa3f8b615ed71894eULL, + 0xc05d27e7ba4e137aULL, 0x44cc0d49851ad6c1ULL, 0x62a695f751379133ULL, + 0x103040506080b070ULL, 0xb4c1ea5e9fc9082bULL, 0x84912aae3f54c5bbULL, + 0x43c511529722e7d4ULL, 0x93a876e54dec44deULL, 0xc25b2fedb65e0574ULL, + 0x4ade357fa16ab4ebULL, 0xbddace73a9815b14ULL, 0x8f8c0689050c808aULL, + 0x2d77b499ee7502c3ULL, 0xbcd9ca76af895013ULL, 0x9cb94ad66f942df3ULL, + 0x6abeb5df6177c90bULL, 0x40c01d5d9d3afaddULL, 0xcf4c1bd498367a57ULL, + 0xa2fbb210eb798249ULL, 0x809d3aba2774e9a7ULL, 0x4fd1216ebf4293f0ULL, + 0x1f217c6342f8d95dULL, 0xca430fc5861e5d4cULL, 0xaae39238db39da71ULL, + 0x42c61557912aecd3ULL +}; + +static const u64 T1[256] = { + 0xd3ba68d2b9bb016aULL, 0xfc54194d9ae5b166ULL, 0x712f93bc65e2cd14ULL, + 0x9c74b9cd8725511bULL, 0xf5530251a2f7a457ULL, 0x68d3b86bd6d003beULL, + 0x6bd2bd6fded604b5ULL, 0xd74d642952b3fe85ULL, 0xf0500d5dbafdad4aULL, + 0xe9ac268a09cf63e0ULL, 0x8a8d830e1c098496ULL, 0xdcbf79c691a51a4dULL, + 0x9070addda73d4d37ULL, 0xf6520755aaf1a35cULL, 0xb39ac852a47be117ULL, + 0xd44c612d5ab5f98eULL, 0x23ea658f0346ac20ULL, 0x62d5a673e6c41184ULL, + 0xa497f166cc55c268ULL, 0x6ed1b263c6dc0da8ULL, 0x5533ffcc85aa99d0ULL, + 0xf3510859b2fbaa41ULL, 0xed5b2a71e2c79c0fULL, 0xf7a604a259f355aeULL, + 0x7fde815fbefe20c1ULL, 0xd848753d7aade5a2ULL, 0xe5a8329a29d77fccULL, + 0xb699c75ebc71e80aULL, 0x70db904b96e03be6ULL, 0x5632fac88dac9edbULL, + 0xc4b751e6d1952215ULL, 0x19fc2bd7b332ceaaULL, 0x38e348ab4b709373ULL, + 0xbf9edc428463fd3bULL, 0xae91ef7efc41d052ULL, 0xb09bcd56ac7de61cULL, + 0x3be24daf43769478ULL, 0xd0bb6dd6b1bd0661ULL, 0xc3415819329bdaf1ULL, + 0xb26ecba5577917e5ULL, 0xf2a50bae41f95cb3ULL, 0x40cbc00b16804b56ULL, + 0xbd6bdab17f670cc2ULL, 0xa295fb6edc59cc7eULL, 0xfea11fbe61e1409fULL, + 0x08f318ebcb10e3c3ULL, 0xceb14ffee181302fULL, 0x06020a08100c0e16ULL, + 0x49ccdb172e925e67ULL, 0x51c4f3376ea2663fULL, 0x271d6974e84e53cfULL, + 0x3c144450a0786c9cULL, 0x58c3e82b56b0730eULL, 0xa563f2913f57349aULL, + 0x73da954f9ee63cedULL, 0xe75d3469d2d38e35ULL, 0xe15f3e61c2df8023ULL, + 0x79dc8b57aef22ed7ULL, 0x877d94e9cf136e48ULL, 0x4acdde132694596cULL, + 0x817f9ee1df1f605eULL, 0xee5a2f75eac19b04ULL, 0xb46cc1ad477519f3ULL, + 0xe45c316ddad5893eULL, 0x04f70cfbeb08ffefULL, 0x6a26be982dd4f247ULL, + 0x1cff24dbab38c7b7ULL, 0x2aed7e933b54b911ULL, 0x25e86f87134aa236ULL, + 0xba9dd34e9c69f426ULL, 0xb16fcea15f7f10eeULL, 0x8f8e8c0204038d8bULL, + 0x2b197d64c8564fe3ULL, 0xfda01aba69e74794ULL, 0x0df017e7d31aeadeULL, + 0x8689971e3c1198baULL, 0x110f333c78222d69ULL, 0x09071b1c38121531ULL, + 0xecaf298611c56afdULL, 0x10fb30cb8b20db9bULL, 0x1808282040303858ULL, + 0x3f154154a87e6b97ULL, 0x170d3934682e237fULL, 0x0c04141020181c2cULL, + 0x030105040806070bULL, 0xac64e98d074521abULL, 0x7cdf845bb6f827caULL, + 0x9a76b3c597295f0dULL, 0x8b7980f9ef0b7264ULL, 0x7add8e53a6f429dcULL, + 0x473dc9f4f58eb3b2ULL, 0x3a164e58b074628aULL, 0x413fc3fce582bda4ULL, + 0x5937ebdca5b285fcULL, 0xb76dc4a94f731ef8ULL, 0x4838d8e0dd90a895ULL, + 0xd6b967dea1b10877ULL, 0x9573a2d1bf37442aULL, 0x26e96a831b4ca53dULL, + 0x5f35e1d4b5be8beaULL, 0xff551c4992e3b66dULL, 0x9371a8d9af3b4a3cULL, + 0x8d7b8af1ff077c72ULL, 0x898c860a140f839dULL, 0x9672a7d5b7314321ULL, + 0x8588921a34179fb1ULL, 0x07f609ffe30ef8e4ULL, 0x7e2a82a84dfcd633ULL, + 0x423ec6f8ed84baafULL, 0xe25e3b65cad98728ULL, 0x6927bb9c25d2f54cULL, + 0xca4643050a89cfc0ULL, 0x140c3c3060282474ULL, 0xaf65ec890f4326a0ULL, + 0xb868d5bd676d05dfULL, 0xa361f8992f5b3a8cULL, 0x05030f0c180a091dULL, + 0x5ec1e22346bc7d18ULL, 0xf957164182efb87bULL, 0x67d6a97ffece1899ULL, + 0x76d99a4386ec35f0ULL, 0xe858257dfacd9512ULL, 0x75d89f478eea32fbULL, + 0xaa66e38517492fbdULL, 0x64d7ac7bf6c81f92ULL, 0x4e3ad2e8cd9ca683ULL, + 0x45c8cf070e8a424bULL, 0x443cccf0fd88b4b9ULL, 0x13fa35cf8326dc90ULL, + 0xa796f462c453c563ULL, 0xf4a701a651f552a5ULL, 0xb598c25ab477ef01ULL, + 0x29ec7b973352be1aULL, 0xd5b862daa9b70f7cULL, 0x54c7fc3b76a86f22ULL, + 0xefae2c8219c36df6ULL, 0xbb69d0b96f6b02d4ULL, 0xdd4b7a3162a7ecbfULL, + 0xe0ab3d9631dd76d1ULL, 0xe6a9379e21d178c7ULL, 0xa967e6811f4f28b6ULL, + 0x1e0a2228503c364eULL, 0xc9474601028fc8cbULL, 0x0bf21defc316e4c8ULL, + 0xc2b55beec1992c03ULL, 0x6622aa880dccee6bULL, 0x32e556b37b648149ULL, + 0x2fee719f235eb00cULL, 0xdfbe7cc299a31d46ULL, 0x7d2b87ac45fad138ULL, + 0x9e81bf3e7c21a0e2ULL, 0x36125a48906c7ea6ULL, 0x9883b5366c2daef4ULL, + 0x2d1b776cd85a41f5ULL, 0x120e363870242a62ULL, 0x6523af8c05cae960ULL, + 0x02f506f3fb04f1f9ULL, 0xcf454c091283c6ddULL, 0x6321a58415c6e776ULL, + 0x4fced11f3e9e5071ULL, 0xdb49703972abe2a9ULL, 0x742c9cb07de8c409ULL, + 0x16f93ac39b2cd58dULL, 0x37e659bf636e8854ULL, 0xc7b654e2d993251eULL, + 0x782888a05df0d825ULL, 0x39174b5cb8726581ULL, 0x9b82b032642ba9ffULL, + 0x2e1a7268d05c46feULL, 0x808b9d162c1d96acULL, 0x1ffe21dfa33ec0bcULL, + 0x838a9812241b91a7ULL, 0x1b092d2448363f53ULL, 0x46c9ca03068c4540ULL, + 0x9487a1264c35b2d8ULL, 0xd24e6b254ab9f798ULL, 0x3ee142a35b7c9d65ULL, + 0x722e96b86de4ca1fULL, 0x31e453b773628642ULL, 0x3de047a7537a9a6eULL, + 0x20eb608b0b40ab2bULL, 0xad90ea7af447d759ULL, 0xf1a40eaa49ff5bb8ULL, + 0x221e6678f0445ad2ULL, 0x9285ab2e5c39bcceULL, 0xa060fd9d275d3d87ULL, + 0x0000000000000000ULL, 0x6f25b19435defb5aULL, 0x01f403f7f302f6f2ULL, + 0x0ef112e3db1cedd5ULL, 0xa194fe6ad45fcb75ULL, 0x1d0b272c583a3145ULL, + 0x34e75cbb6b688f5fULL, 0x9f75bcc98f235610ULL, 0x2cef749b2b58b707ULL, + 0x5c34e4d0bdb88ce1ULL, 0x5331f5c495a697c6ULL, 0x61d4a377eec2168fULL, + 0x6dd0b767ceda0aa3ULL, 0x9786a4224433b5d3ULL, 0x827e9be5d7196755ULL, + 0xeaad238e01c964ebULL, 0x1afd2ed3bb34c9a1ULL, 0x7b298da455f6df2eULL, + 0x5030f0c09da090cdULL, 0x4d3bd7ecc59aa188ULL, 0xbc9fd9468c65fa30ULL, + 0x15f83fc7932ad286ULL, 0x57c6f93f7eae6829ULL, 0x35135f4c986a79adULL, + 0x0a061e183014123aULL, 0x0f051114281e1b27ULL, 0x52c5f63366a46134ULL, + 0x33115544886677bbULL, 0x9977b6c19f2f5806ULL, 0x847c91edc7156943ULL, + 0x8e7a8ff5f7017b79ULL, 0x887885fde70d756fULL, 0x5a36eed8adb482f7ULL, + 0x241c6c70e04854c4ULL, 0x4b39dde4d596af9eULL, 0xeb592079f2cb9219ULL, + 0x28187860c05048e8ULL, 0xfa5613458ae9bf70ULL, 0xc8b345f6f18d3e39ULL, + 0xcdb04afae9873724ULL, 0x6c24b4903dd8fc51ULL, 0x6020a0801dc0e07dULL, + 0xcbb240f2f98b3932ULL, 0xab92e072e44bd94fULL, 0xf8a315b671ed4e89ULL, + 0x5dc0e7274eba7a13ULL, 0xcc44490d1a85c1d6ULL, 0xa662f79537513391ULL, + 0x30105040806070b0ULL, 0xc1b45eeac99f2b08ULL, 0x9184ae2a543fbbc5ULL, + 0xc54352112297d4e7ULL, 0xa893e576ec4dde44ULL, 0x5bc2ed2f5eb67405ULL, + 0xde4a7f356aa1ebb4ULL, 0xdabd73ce81a9145bULL, 0x8c8f89060c058a80ULL, + 0x772d99b475eec302ULL, 0xd9bc76ca89af1350ULL, 0xb99cd64a946ff32dULL, + 0xbe6adfb577610bc9ULL, 0xc0405d1d3a9dddfaULL, 0x4ccfd41b3698577aULL, + 0xfba210b279eb4982ULL, 0x9d80ba3a7427a7e9ULL, 0xd14f6e2142bff093ULL, + 0x211f637cf8425dd9ULL, 0x43cac50f1e864c5dULL, 0xe3aa389239db71daULL, + 0xc64257152a91d3ecULL +}; + +static const u64 T2[256] = { + 0xd268bad36a01bbb9ULL, 0x4d1954fc66b1e59aULL, 0xbc932f7114cde265ULL, + 0xcdb9749c1b512587ULL, 0x510253f557a4f7a2ULL, 0x6bb8d368be03d0d6ULL, + 0x6fbdd26bb504d6deULL, 0x29644dd785feb352ULL, 0x5d0d50f04aadfdbaULL, + 0x8a26ace9e063cf09ULL, 0x0e838d8a9684091cULL, 0xc679bfdc4d1aa591ULL, + 0xddad7090374d3da7ULL, 0x550752f65ca3f1aaULL, 0x52c89ab317e17ba4ULL, + 0x2d614cd48ef9b55aULL, 0x8f65ea2320ac4603ULL, 0x73a6d5628411c4e6ULL, + 0x66f197a468c255ccULL, 0x63b2d16ea80ddcc6ULL, 0xccff3355d099aa85ULL, + 0x590851f341aafbb2ULL, 0x712a5bed0f9cc7e2ULL, 0xa204a6f7ae55f359ULL, + 0x5f81de7fc120febeULL, 0x3d7548d8a2e5ad7aULL, 0x9a32a8e5cc7fd729ULL, + 0x5ec799b60ae871bcULL, 0x4b90db70e63be096ULL, 0xc8fa3256db9eac8dULL, + 0xe651b7c4152295d1ULL, 0xd72bfc19aace32b3ULL, 0xab48e3387393704bULL, + 0x42dc9ebf3bfd6384ULL, 0x7eef91ae52d041fcULL, 0x56cd9bb01ce67dacULL, + 0xaf4de23b78947643ULL, 0xd66dbbd06106bdb1ULL, 0x195841c3f1da9b32ULL, + 0xa5cb6eb2e5177957ULL, 0xae0ba5f2b35cf941ULL, 0x0bc0cb40564b8016ULL, + 0xb1da6bbdc20c677fULL, 0x6efb95a27ecc59dcULL, 0xbe1fa1fe9f40e161ULL, + 0xeb18f308c3e310cbULL, 0xfe4fb1ce2f3081e1ULL, 0x080a0206160e0c10ULL, + 0x17dbcc49675e922eULL, 0x37f3c4513f66a26eULL, 0x74691d27cf534ee8ULL, + 0x5044143c9c6c78a0ULL, 0x2be8c3580e73b056ULL, 0x91f263a59a34573fULL, + 0x4f95da73ed3ce69eULL, 0x69345de7358ed3d2ULL, 0x613e5fe12380dfc2ULL, + 0x578bdc79d72ef2aeULL, 0xe9947d87486e13cfULL, 0x13decd4a6c599426ULL, + 0xe19e7f815e601fdfULL, 0x752f5aee049bc1eaULL, 0xadc16cb4f3197547ULL, + 0x6d315ce43e89d5daULL, 0xfb0cf704efff08ebULL, 0x98be266a47f2d42dULL, + 0xdb24ff1cb7c738abULL, 0x937eed2a11b9543bULL, 0x876fe82536a24a13ULL, + 0x4ed39dba26f4699cULL, 0xa1ce6fb1ee107f5fULL, 0x028c8e8f8b8d0304ULL, + 0x647d192be34f56c8ULL, 0xba1aa0fd9447e769ULL, 0xe717f00ddeea1ad3ULL, + 0x1e978986ba98113cULL, 0x3c330f11692d2278ULL, 0x1c1b070931151238ULL, + 0x8629afecfd6ac511ULL, 0xcb30fb109bdb208bULL, 0x2028081858383040ULL, + 0x5441153f976b7ea8ULL, 0x34390d177f232e68ULL, 0x1014040c2c1c1820ULL, + 0x040501030b070608ULL, 0x8de964acab214507ULL, 0x5b84df7cca27f8b6ULL, + 0xc5b3769a0d5f2997ULL, 0xf980798b64720befULL, 0x538edd7adc29f4a6ULL, + 0xf4c93d47b2b38ef5ULL, 0x584e163a8a6274b0ULL, 0xfcc33f41a4bd82e5ULL, + 0xdceb3759fc85b2a5ULL, 0xa9c46db7f81e734fULL, 0xe0d8384895a890ddULL, + 0xde67b9d67708b1a1ULL, 0xd1a273952a4437bfULL, 0x836ae9263da54c1bULL, + 0xd4e1355fea8bbeb5ULL, 0x491c55ff6db6e392ULL, 0xd9a871933c4a3bafULL, + 0xf18a7b8d727c07ffULL, 0x0a868c899d830f14ULL, 0xd5a77296214331b7ULL, + 0x1a928885b19f1734ULL, 0xff09f607e4f80ee3ULL, 0xa8822a7e33d6fc4dULL, + 0xf8c63e42afba84edULL, 0x653b5ee22887d9caULL, 0x9cbb27694cf5d225ULL, + 0x054346cac0cf890aULL, 0x303c0c1474242860ULL, 0x89ec65afa026430fULL, + 0xbdd568b8df056d67ULL, 0x99f861a38c3a5b2fULL, 0x0c0f03051d090a18ULL, + 0x23e2c15e187dbc46ULL, 0x411657f97bb8ef82ULL, 0x7fa9d6679918cefeULL, + 0x439ad976f035ec86ULL, 0x7d2558e81295cdfaULL, 0x479fd875fb32ea8eULL, + 0x85e366aabd2f4917ULL, 0x7bacd764921fc8f6ULL, 0xe8d23a4e83a69ccdULL, + 0x07cfc8454b428a0eULL, 0xf0cc3c44b9b488fdULL, 0xcf35fa1390dc2683ULL, + 0x62f496a763c553c4ULL, 0xa601a7f4a552f551ULL, 0x5ac298b501ef77b4ULL, + 0x977bec291abe5233ULL, 0xda62b8d57c0fb7a9ULL, 0x3bfcc754226fa876ULL, + 0x822caeeff66dc319ULL, 0xb9d069bbd4026b6fULL, 0x317a4bddbfeca762ULL, + 0x963dabe0d176dd31ULL, 0x9e37a9e6c778d121ULL, 0x81e667a9b6284f1fULL, + 0x28220a1e4e363c50ULL, 0x014647c9cbc88f02ULL, 0xef1df20bc8e416c3ULL, + 0xee5bb5c2032c99c1ULL, 0x88aa22666beecc0dULL, 0xb356e5324981647bULL, + 0x9f71ee2f0cb05e23ULL, 0xc27cbedf461da399ULL, 0xac872b7d38d1fa45ULL, + 0x3ebf819ee2a0217cULL, 0x485a1236a67e6c90ULL, 0x36b58398f4ae2d6cULL, + 0x6c771b2df5415ad8ULL, 0x38360e12622a2470ULL, 0x8caf236560e9ca05ULL, + 0xf306f502f9f104fbULL, 0x094c45cfddc68312ULL, 0x84a5216376e7c615ULL, + 0x1fd1ce4f71509e3eULL, 0x397049dba9e2ab72ULL, 0xb09c2c7409c4e87dULL, + 0xc33af9168dd52c9bULL, 0xbf59e63754886e63ULL, 0xe254b6c71e2593d9ULL, + 0xa088287825d8f05dULL, 0x5c4b1739816572b8ULL, 0x32b0829bffa92b64ULL, + 0x68721a2efe465cd0ULL, 0x169d8b80ac961d2cULL, 0xdf21fe1fbcc03ea3ULL, + 0x12988a83a7911b24ULL, 0x242d091b533f3648ULL, 0x03cac94640458c06ULL, + 0x26a18794d8b2354cULL, 0x256b4ed298f7b94aULL, 0xa342e13e659d7c5bULL, + 0xb8962e721fcae46dULL, 0xb753e43142866273ULL, 0xa747e03d6e9a7a53ULL, + 0x8b60eb202bab400bULL, 0x7aea90ad59d747f4ULL, 0xaa0ea4f1b85bff49ULL, + 0x78661e22d25a44f0ULL, 0x2eab8592cebc395cULL, 0x9dfd60a0873d5d27ULL, + 0x0000000000000000ULL, 0x94b1256f5afbde35ULL, 0xf703f401f2f602f3ULL, + 0xe312f10ed5ed1cdbULL, 0x6afe94a175cb5fd4ULL, 0x2c270b1d45313a58ULL, + 0xbb5ce7345f8f686bULL, 0xc9bc759f1056238fULL, 0x9b74ef2c07b7582bULL, + 0xd0e4345ce18cb8bdULL, 0xc4f53153c697a695ULL, 0x77a3d4618f16c2eeULL, + 0x67b7d06da30adaceULL, 0x22a48697d3b53344ULL, 0xe59b7e82556719d7ULL, + 0x8e23adeaeb64c901ULL, 0xd32efd1aa1c934bbULL, 0xa48d297b2edff655ULL, + 0xc0f03050cd90a09dULL, 0xecd73b4d88a19ac5ULL, 0x46d99fbc30fa658cULL, + 0xc73ff81586d22a93ULL, 0x3ff9c6572968ae7eULL, 0x4c5f1335ad796a98ULL, + 0x181e060a3a121430ULL, 0x1411050f271b1e28ULL, 0x33f6c5523461a466ULL, + 0x44551133bb776688ULL, 0xc1b6779906582f9fULL, 0xed917c84436915c7ULL, + 0xf58f7a8e797b01f7ULL, 0xfd8578886f750de7ULL, 0xd8ee365af782b4adULL, + 0x706c1c24c45448e0ULL, 0xe4dd394b9eaf96d5ULL, 0x792059eb1992cbf2ULL, + 0x60781828e84850c0ULL, 0x451356fa70bfe98aULL, 0xf645b3c8393e8df1ULL, + 0xfa4ab0cd243787e9ULL, 0x90b4246c51fcd83dULL, 0x80a020607de0c01dULL, + 0xf240b2cb32398bf9ULL, 0x72e092ab4fd94be4ULL, 0xb615a3f8894eed71ULL, + 0x27e7c05d137aba4eULL, 0x0d4944ccd6c1851aULL, 0x95f762a691335137ULL, + 0x40501030b0706080ULL, 0xea5eb4c1082b9fc9ULL, 0x2aae8491c5bb3f54ULL, + 0x115243c5e7d49722ULL, 0x76e593a844de4decULL, 0x2fedc25b0574b65eULL, + 0x357f4adeb4eba16aULL, 0xce73bdda5b14a981ULL, 0x06898f8c808a050cULL, + 0xb4992d7702c3ee75ULL, 0xca76bcd95013af89ULL, 0x4ad69cb92df36f94ULL, + 0xb5df6abec90b6177ULL, 0x1d5d40c0fadd9d3aULL, 0x1bd4cf4c7a579836ULL, + 0xb210a2fb8249eb79ULL, 0x3aba809de9a72774ULL, 0x216e4fd193f0bf42ULL, + 0x7c631f21d95d42f8ULL, 0x0fc5ca435d4c861eULL, 0x9238aae3da71db39ULL, + 0x155742c6ecd3912aULL +}; + +static const u64 T3[256] = { + 0x68d2d3ba016ab9bbULL, 0x194dfc54b1669ae5ULL, 0x93bc712fcd1465e2ULL, + 0xb9cd9c74511b8725ULL, 0x0251f553a457a2f7ULL, 0xb86b68d303bed6d0ULL, + 0xbd6f6bd204b5ded6ULL, 0x6429d74dfe8552b3ULL, 0x0d5df050ad4abafdULL, + 0x268ae9ac63e009cfULL, 0x830e8a8d84961c09ULL, 0x79c6dcbf1a4d91a5ULL, + 0xaddd90704d37a73dULL, 0x0755f652a35caaf1ULL, 0xc852b39ae117a47bULL, + 0x612dd44cf98e5ab5ULL, 0x658f23eaac200346ULL, 0xa67362d51184e6c4ULL, + 0xf166a497c268cc55ULL, 0xb2636ed10da8c6dcULL, 0xffcc553399d085aaULL, + 0x0859f351aa41b2fbULL, 0x2a71ed5b9c0fe2c7ULL, 0x04a2f7a655ae59f3ULL, + 0x815f7fde20c1befeULL, 0x753dd848e5a27aadULL, 0x329ae5a87fcc29d7ULL, + 0xc75eb699e80abc71ULL, 0x904b70db3be696e0ULL, 0xfac856329edb8dacULL, + 0x51e6c4b72215d195ULL, 0x2bd719fcceaab332ULL, 0x48ab38e393734b70ULL, + 0xdc42bf9efd3b8463ULL, 0xef7eae91d052fc41ULL, 0xcd56b09be61cac7dULL, + 0x4daf3be294784376ULL, 0x6dd6d0bb0661b1bdULL, 0x5819c341daf1329bULL, + 0xcba5b26e17e55779ULL, 0x0baef2a55cb341f9ULL, 0xc00b40cb4b561680ULL, + 0xdab1bd6b0cc27f67ULL, 0xfb6ea295cc7edc59ULL, 0x1fbefea1409f61e1ULL, + 0x18eb08f3e3c3cb10ULL, 0x4ffeceb1302fe181ULL, 0x0a0806020e16100cULL, + 0xdb1749cc5e672e92ULL, 0xf33751c4663f6ea2ULL, 0x6974271d53cfe84eULL, + 0x44503c146c9ca078ULL, 0xe82b58c3730e56b0ULL, 0xf291a563349a3f57ULL, + 0x954f73da3ced9ee6ULL, 0x3469e75d8e35d2d3ULL, 0x3e61e15f8023c2dfULL, + 0x8b5779dc2ed7aef2ULL, 0x94e9877d6e48cf13ULL, 0xde134acd596c2694ULL, + 0x9ee1817f605edf1fULL, 0x2f75ee5a9b04eac1ULL, 0xc1adb46c19f34775ULL, + 0x316de45c893edad5ULL, 0x0cfb04f7ffefeb08ULL, 0xbe986a26f2472dd4ULL, + 0x24db1cffc7b7ab38ULL, 0x7e932aedb9113b54ULL, 0x6f8725e8a236134aULL, + 0xd34eba9df4269c69ULL, 0xcea1b16f10ee5f7fULL, 0x8c028f8e8d8b0403ULL, + 0x7d642b194fe3c856ULL, 0x1abafda0479469e7ULL, 0x17e70df0eaded31aULL, + 0x971e868998ba3c11ULL, 0x333c110f2d697822ULL, 0x1b1c090715313812ULL, + 0x2986ecaf6afd11c5ULL, 0x30cb10fbdb9b8b20ULL, 0x2820180838584030ULL, + 0x41543f156b97a87eULL, 0x3934170d237f682eULL, 0x14100c041c2c2018ULL, + 0x05040301070b0806ULL, 0xe98dac6421ab0745ULL, 0x845b7cdf27cab6f8ULL, + 0xb3c59a765f0d9729ULL, 0x80f98b797264ef0bULL, 0x8e537add29dca6f4ULL, + 0xc9f4473db3b2f58eULL, 0x4e583a16628ab074ULL, 0xc3fc413fbda4e582ULL, + 0xebdc593785fca5b2ULL, 0xc4a9b76d1ef84f73ULL, 0xd8e04838a895dd90ULL, + 0x67ded6b90877a1b1ULL, 0xa2d19573442abf37ULL, 0x6a8326e9a53d1b4cULL, + 0xe1d45f358beab5beULL, 0x1c49ff55b66d92e3ULL, 0xa8d993714a3caf3bULL, + 0x8af18d7b7c72ff07ULL, 0x860a898c839d140fULL, 0xa7d596724321b731ULL, + 0x921a85889fb13417ULL, 0x09ff07f6f8e4e30eULL, 0x82a87e2ad6334dfcULL, + 0xc6f8423ebaafed84ULL, 0x3b65e25e8728cad9ULL, 0xbb9c6927f54c25d2ULL, + 0x4305ca46cfc00a89ULL, 0x3c30140c24746028ULL, 0xec89af6526a00f43ULL, + 0xd5bdb86805df676dULL, 0xf899a3613a8c2f5bULL, 0x0f0c0503091d180aULL, + 0xe2235ec17d1846bcULL, 0x1641f957b87b82efULL, 0xa97f67d61899feceULL, + 0x9a4376d935f086ecULL, 0x257de8589512facdULL, 0x9f4775d832fb8eeaULL, + 0xe385aa662fbd1749ULL, 0xac7b64d71f92f6c8ULL, 0xd2e84e3aa683cd9cULL, + 0xcf0745c8424b0e8aULL, 0xccf0443cb4b9fd88ULL, 0x35cf13fadc908326ULL, + 0xf462a796c563c453ULL, 0x01a6f4a752a551f5ULL, 0xc25ab598ef01b477ULL, + 0x7b9729ecbe1a3352ULL, 0x62dad5b80f7ca9b7ULL, 0xfc3b54c76f2276a8ULL, + 0x2c82efae6df619c3ULL, 0xd0b9bb6902d46f6bULL, 0x7a31dd4becbf62a7ULL, + 0x3d96e0ab76d131ddULL, 0x379ee6a978c721d1ULL, 0xe681a96728b61f4fULL, + 0x22281e0a364e503cULL, 0x4601c947c8cb028fULL, 0x1def0bf2e4c8c316ULL, + 0x5beec2b52c03c199ULL, 0xaa886622ee6b0dccULL, 0x56b332e581497b64ULL, + 0x719f2feeb00c235eULL, 0x7cc2dfbe1d4699a3ULL, 0x87ac7d2bd13845faULL, + 0xbf3e9e81a0e27c21ULL, 0x5a4836127ea6906cULL, 0xb5369883aef46c2dULL, + 0x776c2d1b41f5d85aULL, 0x3638120e2a627024ULL, 0xaf8c6523e96005caULL, + 0x06f302f5f1f9fb04ULL, 0x4c09cf45c6dd1283ULL, 0xa5846321e77615c6ULL, + 0xd11f4fce50713e9eULL, 0x7039db49e2a972abULL, 0x9cb0742cc4097de8ULL, + 0x3ac316f9d58d9b2cULL, 0x59bf37e68854636eULL, 0x54e2c7b6251ed993ULL, + 0x88a07828d8255df0ULL, 0x4b5c39176581b872ULL, 0xb0329b82a9ff642bULL, + 0x72682e1a46fed05cULL, 0x9d16808b96ac2c1dULL, 0x21df1ffec0bca33eULL, + 0x9812838a91a7241bULL, 0x2d241b093f534836ULL, 0xca0346c94540068cULL, + 0xa1269487b2d84c35ULL, 0x6b25d24ef7984ab9ULL, 0x42a33ee19d655b7cULL, + 0x96b8722eca1f6de4ULL, 0x53b731e486427362ULL, 0x47a73de09a6e537aULL, + 0x608b20ebab2b0b40ULL, 0xea7aad90d759f447ULL, 0x0eaaf1a45bb849ffULL, + 0x6678221e5ad2f044ULL, 0xab2e9285bcce5c39ULL, 0xfd9da0603d87275dULL, + 0x0000000000000000ULL, 0xb1946f25fb5a35deULL, 0x03f701f4f6f2f302ULL, + 0x12e30ef1edd5db1cULL, 0xfe6aa194cb75d45fULL, 0x272c1d0b3145583aULL, + 0x5cbb34e78f5f6b68ULL, 0xbcc99f7556108f23ULL, 0x749b2cefb7072b58ULL, + 0xe4d05c348ce1bdb8ULL, 0xf5c4533197c695a6ULL, 0xa37761d4168feec2ULL, + 0xb7676dd00aa3cedaULL, 0xa4229786b5d34433ULL, 0x9be5827e6755d719ULL, + 0x238eeaad64eb01c9ULL, 0x2ed31afdc9a1bb34ULL, 0x8da47b29df2e55f6ULL, + 0xf0c0503090cd9da0ULL, 0xd7ec4d3ba188c59aULL, 0xd946bc9ffa308c65ULL, + 0x3fc715f8d286932aULL, 0xf93f57c668297eaeULL, 0x5f4c351379ad986aULL, + 0x1e180a06123a3014ULL, 0x11140f051b27281eULL, 0xf63352c5613466a4ULL, + 0x5544331177bb8866ULL, 0xb6c1997758069f2fULL, 0x91ed847c6943c715ULL, + 0x8ff58e7a7b79f701ULL, 0x85fd8878756fe70dULL, 0xeed85a3682f7adb4ULL, + 0x6c70241c54c4e048ULL, 0xdde44b39af9ed596ULL, 0x2079eb599219f2cbULL, + 0x7860281848e8c050ULL, 0x1345fa56bf708ae9ULL, 0x45f6c8b33e39f18dULL, + 0x4afacdb03724e987ULL, 0xb4906c24fc513dd8ULL, 0xa0806020e07d1dc0ULL, + 0x40f2cbb23932f98bULL, 0xe072ab92d94fe44bULL, 0x15b6f8a34e8971edULL, + 0xe7275dc07a134ebaULL, 0x490dcc44c1d61a85ULL, 0xf795a66233913751ULL, + 0x5040301070b08060ULL, 0x5eeac1b42b08c99fULL, 0xae2a9184bbc5543fULL, + 0x5211c543d4e72297ULL, 0xe576a893de44ec4dULL, 0xed2f5bc274055eb6ULL, + 0x7f35de4aebb46aa1ULL, 0x73cedabd145b81a9ULL, 0x89068c8f8a800c05ULL, + 0x99b4772dc30275eeULL, 0x76cad9bc135089afULL, 0xd64ab99cf32d946fULL, + 0xdfb5be6a0bc97761ULL, 0x5d1dc040ddfa3a9dULL, 0xd41b4ccf577a3698ULL, + 0x10b2fba2498279ebULL, 0xba3a9d80a7e97427ULL, 0x6e21d14ff09342bfULL, + 0x637c211f5dd9f842ULL, 0xc50f43ca4c5d1e86ULL, 0x3892e3aa71da39dbULL, + 0x5715c642d3ec2a91ULL +}; + +static const u64 T4[256] = { + 0xbbb96a01bad3d268ULL, 0xe59a66b154fc4d19ULL, 0xe26514cd2f71bc93ULL, + 0x25871b51749ccdb9ULL, 0xf7a257a453f55102ULL, 0xd0d6be03d3686bb8ULL, + 0xd6deb504d26b6fbdULL, 0xb35285fe4dd72964ULL, 0xfdba4aad50f05d0dULL, + 0xcf09e063ace98a26ULL, 0x091c96848d8a0e83ULL, 0xa5914d1abfdcc679ULL, + 0x3da7374d7090ddadULL, 0xf1aa5ca352f65507ULL, 0x7ba417e19ab352c8ULL, + 0xb55a8ef94cd42d61ULL, 0x460320acea238f65ULL, 0xc4e68411d56273a6ULL, + 0x55cc68c297a466f1ULL, 0xdcc6a80dd16e63b2ULL, 0xaa85d0993355ccffULL, + 0xfbb241aa51f35908ULL, 0xc7e20f9c5bed712aULL, 0xf359ae55a6f7a204ULL, + 0xfebec120de7f5f81ULL, 0xad7aa2e548d83d75ULL, 0xd729cc7fa8e59a32ULL, + 0x71bc0ae899b65ec7ULL, 0xe096e63bdb704b90ULL, 0xac8ddb9e3256c8faULL, + 0x95d11522b7c4e651ULL, 0x32b3aacefc19d72bULL, 0x704b7393e338ab48ULL, + 0x63843bfd9ebf42dcULL, 0x41fc52d091ae7eefULL, 0x7dac1ce69bb056cdULL, + 0x76437894e23baf4dULL, 0xbdb16106bbd0d66dULL, 0x9b32f1da41c31958ULL, + 0x7957e5176eb2a5cbULL, 0xf941b35ca5f2ae0bULL, 0x8016564bcb400bc0ULL, + 0x677fc20c6bbdb1daULL, 0x59dc7ecc95a26efbULL, 0xe1619f40a1febe1fULL, + 0x10cbc3e3f308eb18ULL, 0x81e12f30b1cefe4fULL, 0x0c10160e0206080aULL, + 0x922e675ecc4917dbULL, 0xa26e3f66c45137f3ULL, 0x4ee8cf531d277469ULL, + 0x78a09c6c143c5044ULL, 0xb0560e73c3582be8ULL, 0x573f9a3463a591f2ULL, + 0xe69eed3cda734f95ULL, 0xd3d2358e5de76934ULL, 0xdfc223805fe1613eULL, + 0xf2aed72edc79578bULL, 0x13cf486e7d87e994ULL, 0x94266c59cd4a13deULL, + 0x1fdf5e607f81e19eULL, 0xc1ea049b5aee752fULL, 0x7547f3196cb4adc1ULL, + 0xd5da3e895ce46d31ULL, 0x08ebeffff704fb0cULL, 0xd42d47f2266a98beULL, + 0x38abb7c7ff1cdb24ULL, 0x543b11b9ed2a937eULL, 0x4a1336a2e825876fULL, + 0x699c26f49dba4ed3ULL, 0x7f5fee106fb1a1ceULL, 0x03048b8d8e8f028cULL, + 0x56c8e34f192b647dULL, 0xe7699447a0fdba1aULL, 0x1ad3deeaf00de717ULL, + 0x113cba9889861e97ULL, 0x2278692d0f113c33ULL, 0x1238311507091c1bULL, + 0xc511fd6aafec8629ULL, 0x208b9bdbfb10cb30ULL, 0x3040583808182028ULL, + 0x7ea8976b153f5441ULL, 0x2e687f230d173439ULL, 0x18202c1c040c1014ULL, + 0x06080b0701030405ULL, 0x4507ab2164ac8de9ULL, 0xf8b6ca27df7c5b84ULL, + 0x29970d5f769ac5b3ULL, 0x0bef6472798bf980ULL, 0xf4a6dc29dd7a538eULL, + 0x8ef5b2b33d47f4c9ULL, 0x74b08a62163a584eULL, 0x82e5a4bd3f41fcc3ULL, + 0xb2a5fc853759dcebULL, 0x734ff81e6db7a9c4ULL, 0x90dd95a83848e0d8ULL, + 0xb1a17708b9d6de67ULL, 0x37bf2a447395d1a2ULL, 0x4c1b3da5e926836aULL, + 0xbeb5ea8b355fd4e1ULL, 0xe3926db655ff491cULL, 0x3baf3c4a7193d9a8ULL, + 0x07ff727c7b8df18aULL, 0x0f149d838c890a86ULL, 0x31b721437296d5a7ULL, + 0x1734b19f88851a92ULL, 0x0ee3e4f8f607ff09ULL, 0xfc4d33d62a7ea882ULL, + 0x84edafba3e42f8c6ULL, 0xd9ca28875ee2653bULL, 0xd2254cf527699cbbULL, + 0x890ac0cf46ca0543ULL, 0x286074240c14303cULL, 0x430fa02665af89ecULL, + 0x6d67df0568b8bdd5ULL, 0x5b2f8c3a61a399f8ULL, 0x0a181d0903050c0fULL, + 0xbc46187dc15e23e2ULL, 0xef827bb857f94116ULL, 0xcefe9918d6677fa9ULL, + 0xec86f035d976439aULL, 0xcdfa129558e87d25ULL, 0xea8efb32d875479fULL, + 0x4917bd2f66aa85e3ULL, 0xc8f6921fd7647bacULL, 0x9ccd83a63a4ee8d2ULL, + 0x8a0e4b42c84507cfULL, 0x88fdb9b43c44f0ccULL, 0x268390dcfa13cf35ULL, + 0x53c463c596a762f4ULL, 0xf551a552a7f4a601ULL, 0x77b401ef98b55ac2ULL, + 0x52331abeec29977bULL, 0xb7a97c0fb8d5da62ULL, 0xa876226fc7543bfcULL, + 0xc319f66daeef822cULL, 0x6b6fd40269bbb9d0ULL, 0xa762bfec4bdd317aULL, + 0xdd31d176abe0963dULL, 0xd121c778a9e69e37ULL, 0x4f1fb62867a981e6ULL, + 0x3c504e360a1e2822ULL, 0x8f02cbc847c90146ULL, 0x16c3c8e4f20bef1dULL, + 0x99c1032cb5c2ee5bULL, 0xcc0d6bee226688aaULL, 0x647b4981e532b356ULL, + 0x5e230cb0ee2f9f71ULL, 0xa399461dbedfc27cULL, 0xfa4538d12b7dac87ULL, + 0x217ce2a0819e3ebfULL, 0x6c90a67e1236485aULL, 0x2d6cf4ae839836b5ULL, + 0x5ad8f5411b2d6c77ULL, 0x2470622a0e123836ULL, 0xca0560e923658cafULL, + 0x04fbf9f1f502f306ULL, 0x8312ddc645cf094cULL, 0xc61576e7216384a5ULL, + 0x9e3e7150ce4f1fd1ULL, 0xab72a9e249db3970ULL, 0xe87d09c42c74b09cULL, + 0x2c9b8dd5f916c33aULL, 0x6e635488e637bf59ULL, 0x93d91e25b6c7e254ULL, + 0xf05d25d82878a088ULL, 0x72b8816517395c4bULL, 0x2b64ffa9829b32b0ULL, + 0x5cd0fe461a2e6872ULL, 0x1d2cac968b80169dULL, 0x3ea3bcc0fe1fdf21ULL, + 0x1b24a7918a831298ULL, 0x3648533f091b242dULL, 0x8c064045c94603caULL, + 0x354cd8b2879426a1ULL, 0xb94a98f74ed2256bULL, 0x7c5b659de13ea342ULL, + 0xe46d1fca2e72b896ULL, 0x62734286e431b753ULL, 0x7a536e9ae03da747ULL, + 0x400b2babeb208b60ULL, 0x47f459d790ad7aeaULL, 0xff49b85ba4f1aa0eULL, + 0x44f0d25a1e227866ULL, 0x395ccebc85922eabULL, 0x5d27873d60a09dfdULL, + 0x0000000000000000ULL, 0xde355afb256f94b1ULL, 0x02f3f2f6f401f703ULL, + 0x1cdbd5edf10ee312ULL, 0x5fd475cb94a16afeULL, 0x3a5845310b1d2c27ULL, + 0x686b5f8fe734bb5cULL, 0x238f1056759fc9bcULL, 0x582b07b7ef2c9b74ULL, + 0xb8bde18c345cd0e4ULL, 0xa695c6973153c4f5ULL, 0xc2ee8f16d46177a3ULL, + 0xdacea30ad06d67b7ULL, 0x3344d3b5869722a4ULL, 0x19d755677e82e59bULL, + 0xc901eb64adea8e23ULL, 0x34bba1c9fd1ad32eULL, 0xf6552edf297ba48dULL, + 0xa09dcd903050c0f0ULL, 0x9ac588a13b4decd7ULL, 0x658c30fa9fbc46d9ULL, + 0x2a9386d2f815c73fULL, 0xae7e2968c6573ff9ULL, 0x6a98ad7913354c5fULL, + 0x14303a12060a181eULL, 0x1e28271b050f1411ULL, 0xa4663461c55233f6ULL, + 0x6688bb7711334455ULL, 0x2f9f06587799c1b6ULL, 0x15c743697c84ed91ULL, + 0x01f7797b7a8ef58fULL, 0x0de76f757888fd85ULL, 0xb4adf782365ad8eeULL, + 0x48e0c4541c24706cULL, 0x96d59eaf394be4ddULL, 0xcbf2199259eb7920ULL, + 0x50c0e84818286078ULL, 0xe98a70bf56fa4513ULL, 0x8df1393eb3c8f645ULL, + 0x87e92437b0cdfa4aULL, 0xd83d51fc246c90b4ULL, 0xc01d7de0206080a0ULL, + 0x8bf93239b2cbf240ULL, 0x4be44fd992ab72e0ULL, 0xed71894ea3f8b615ULL, + 0xba4e137ac05d27e7ULL, 0x851ad6c144cc0d49ULL, 0x5137913362a695f7ULL, + 0x6080b07010304050ULL, 0x9fc9082bb4c1ea5eULL, 0x3f54c5bb84912aaeULL, + 0x9722e7d443c51152ULL, 0x4dec44de93a876e5ULL, 0xb65e0574c25b2fedULL, + 0xa16ab4eb4ade357fULL, 0xa9815b14bddace73ULL, 0x050c808a8f8c0689ULL, + 0xee7502c32d77b499ULL, 0xaf895013bcd9ca76ULL, 0x6f942df39cb94ad6ULL, + 0x6177c90b6abeb5dfULL, 0x9d3afadd40c01d5dULL, 0x98367a57cf4c1bd4ULL, + 0xeb798249a2fbb210ULL, 0x2774e9a7809d3abaULL, 0xbf4293f04fd1216eULL, + 0x42f8d95d1f217c63ULL, 0x861e5d4cca430fc5ULL, 0xdb39da71aae39238ULL, + 0x912aecd342c61557ULL +}; + +static const u64 T5[256] = { + 0xb9bb016ad3ba68d2ULL, 0x9ae5b166fc54194dULL, 0x65e2cd14712f93bcULL, + 0x8725511b9c74b9cdULL, 0xa2f7a457f5530251ULL, 0xd6d003be68d3b86bULL, + 0xded604b56bd2bd6fULL, 0x52b3fe85d74d6429ULL, 0xbafdad4af0500d5dULL, + 0x09cf63e0e9ac268aULL, 0x1c0984968a8d830eULL, 0x91a51a4ddcbf79c6ULL, + 0xa73d4d379070adddULL, 0xaaf1a35cf6520755ULL, 0xa47be117b39ac852ULL, + 0x5ab5f98ed44c612dULL, 0x0346ac2023ea658fULL, 0xe6c4118462d5a673ULL, + 0xcc55c268a497f166ULL, 0xc6dc0da86ed1b263ULL, 0x85aa99d05533ffccULL, + 0xb2fbaa41f3510859ULL, 0xe2c79c0fed5b2a71ULL, 0x59f355aef7a604a2ULL, + 0xbefe20c17fde815fULL, 0x7aade5a2d848753dULL, 0x29d77fcce5a8329aULL, + 0xbc71e80ab699c75eULL, 0x96e03be670db904bULL, 0x8dac9edb5632fac8ULL, + 0xd1952215c4b751e6ULL, 0xb332ceaa19fc2bd7ULL, 0x4b70937338e348abULL, + 0x8463fd3bbf9edc42ULL, 0xfc41d052ae91ef7eULL, 0xac7de61cb09bcd56ULL, + 0x437694783be24dafULL, 0xb1bd0661d0bb6dd6ULL, 0x329bdaf1c3415819ULL, + 0x577917e5b26ecba5ULL, 0x41f95cb3f2a50baeULL, 0x16804b5640cbc00bULL, + 0x7f670cc2bd6bdab1ULL, 0xdc59cc7ea295fb6eULL, 0x61e1409ffea11fbeULL, + 0xcb10e3c308f318ebULL, 0xe181302fceb14ffeULL, 0x100c0e1606020a08ULL, + 0x2e925e6749ccdb17ULL, 0x6ea2663f51c4f337ULL, 0xe84e53cf271d6974ULL, + 0xa0786c9c3c144450ULL, 0x56b0730e58c3e82bULL, 0x3f57349aa563f291ULL, + 0x9ee63ced73da954fULL, 0xd2d38e35e75d3469ULL, 0xc2df8023e15f3e61ULL, + 0xaef22ed779dc8b57ULL, 0xcf136e48877d94e9ULL, 0x2694596c4acdde13ULL, + 0xdf1f605e817f9ee1ULL, 0xeac19b04ee5a2f75ULL, 0x477519f3b46cc1adULL, + 0xdad5893ee45c316dULL, 0xeb08ffef04f70cfbULL, 0x2dd4f2476a26be98ULL, + 0xab38c7b71cff24dbULL, 0x3b54b9112aed7e93ULL, 0x134aa23625e86f87ULL, + 0x9c69f426ba9dd34eULL, 0x5f7f10eeb16fcea1ULL, 0x04038d8b8f8e8c02ULL, + 0xc8564fe32b197d64ULL, 0x69e74794fda01abaULL, 0xd31aeade0df017e7ULL, + 0x3c1198ba8689971eULL, 0x78222d69110f333cULL, 0x3812153109071b1cULL, + 0x11c56afdecaf2986ULL, 0x8b20db9b10fb30cbULL, 0x4030385818082820ULL, + 0xa87e6b973f154154ULL, 0x682e237f170d3934ULL, 0x20181c2c0c041410ULL, + 0x0806070b03010504ULL, 0x074521abac64e98dULL, 0xb6f827ca7cdf845bULL, + 0x97295f0d9a76b3c5ULL, 0xef0b72648b7980f9ULL, 0xa6f429dc7add8e53ULL, + 0xf58eb3b2473dc9f4ULL, 0xb074628a3a164e58ULL, 0xe582bda4413fc3fcULL, + 0xa5b285fc5937ebdcULL, 0x4f731ef8b76dc4a9ULL, 0xdd90a8954838d8e0ULL, + 0xa1b10877d6b967deULL, 0xbf37442a9573a2d1ULL, 0x1b4ca53d26e96a83ULL, + 0xb5be8bea5f35e1d4ULL, 0x92e3b66dff551c49ULL, 0xaf3b4a3c9371a8d9ULL, + 0xff077c728d7b8af1ULL, 0x140f839d898c860aULL, 0xb73143219672a7d5ULL, + 0x34179fb18588921aULL, 0xe30ef8e407f609ffULL, 0x4dfcd6337e2a82a8ULL, + 0xed84baaf423ec6f8ULL, 0xcad98728e25e3b65ULL, 0x25d2f54c6927bb9cULL, + 0x0a89cfc0ca464305ULL, 0x60282474140c3c30ULL, 0x0f4326a0af65ec89ULL, + 0x676d05dfb868d5bdULL, 0x2f5b3a8ca361f899ULL, 0x180a091d05030f0cULL, + 0x46bc7d185ec1e223ULL, 0x82efb87bf9571641ULL, 0xfece189967d6a97fULL, + 0x86ec35f076d99a43ULL, 0xfacd9512e858257dULL, 0x8eea32fb75d89f47ULL, + 0x17492fbdaa66e385ULL, 0xf6c81f9264d7ac7bULL, 0xcd9ca6834e3ad2e8ULL, + 0x0e8a424b45c8cf07ULL, 0xfd88b4b9443cccf0ULL, 0x8326dc9013fa35cfULL, + 0xc453c563a796f462ULL, 0x51f552a5f4a701a6ULL, 0xb477ef01b598c25aULL, + 0x3352be1a29ec7b97ULL, 0xa9b70f7cd5b862daULL, 0x76a86f2254c7fc3bULL, + 0x19c36df6efae2c82ULL, 0x6f6b02d4bb69d0b9ULL, 0x62a7ecbfdd4b7a31ULL, + 0x31dd76d1e0ab3d96ULL, 0x21d178c7e6a9379eULL, 0x1f4f28b6a967e681ULL, + 0x503c364e1e0a2228ULL, 0x028fc8cbc9474601ULL, 0xc316e4c80bf21defULL, + 0xc1992c03c2b55beeULL, 0x0dccee6b6622aa88ULL, 0x7b64814932e556b3ULL, + 0x235eb00c2fee719fULL, 0x99a31d46dfbe7cc2ULL, 0x45fad1387d2b87acULL, + 0x7c21a0e29e81bf3eULL, 0x906c7ea636125a48ULL, 0x6c2daef49883b536ULL, + 0xd85a41f52d1b776cULL, 0x70242a62120e3638ULL, 0x05cae9606523af8cULL, + 0xfb04f1f902f506f3ULL, 0x1283c6ddcf454c09ULL, 0x15c6e7766321a584ULL, + 0x3e9e50714fced11fULL, 0x72abe2a9db497039ULL, 0x7de8c409742c9cb0ULL, + 0x9b2cd58d16f93ac3ULL, 0x636e885437e659bfULL, 0xd993251ec7b654e2ULL, + 0x5df0d825782888a0ULL, 0xb872658139174b5cULL, 0x642ba9ff9b82b032ULL, + 0xd05c46fe2e1a7268ULL, 0x2c1d96ac808b9d16ULL, 0xa33ec0bc1ffe21dfULL, + 0x241b91a7838a9812ULL, 0x48363f531b092d24ULL, 0x068c454046c9ca03ULL, + 0x4c35b2d89487a126ULL, 0x4ab9f798d24e6b25ULL, 0x5b7c9d653ee142a3ULL, + 0x6de4ca1f722e96b8ULL, 0x7362864231e453b7ULL, 0x537a9a6e3de047a7ULL, + 0x0b40ab2b20eb608bULL, 0xf447d759ad90ea7aULL, 0x49ff5bb8f1a40eaaULL, + 0xf0445ad2221e6678ULL, 0x5c39bcce9285ab2eULL, 0x275d3d87a060fd9dULL, + 0x0000000000000000ULL, 0x35defb5a6f25b194ULL, 0xf302f6f201f403f7ULL, + 0xdb1cedd50ef112e3ULL, 0xd45fcb75a194fe6aULL, 0x583a31451d0b272cULL, + 0x6b688f5f34e75cbbULL, 0x8f2356109f75bcc9ULL, 0x2b58b7072cef749bULL, + 0xbdb88ce15c34e4d0ULL, 0x95a697c65331f5c4ULL, 0xeec2168f61d4a377ULL, + 0xceda0aa36dd0b767ULL, 0x4433b5d39786a422ULL, 0xd7196755827e9be5ULL, + 0x01c964ebeaad238eULL, 0xbb34c9a11afd2ed3ULL, 0x55f6df2e7b298da4ULL, + 0x9da090cd5030f0c0ULL, 0xc59aa1884d3bd7ecULL, 0x8c65fa30bc9fd946ULL, + 0x932ad28615f83fc7ULL, 0x7eae682957c6f93fULL, 0x986a79ad35135f4cULL, + 0x3014123a0a061e18ULL, 0x281e1b270f051114ULL, 0x66a4613452c5f633ULL, + 0x886677bb33115544ULL, 0x9f2f58069977b6c1ULL, 0xc7156943847c91edULL, + 0xf7017b798e7a8ff5ULL, 0xe70d756f887885fdULL, 0xadb482f75a36eed8ULL, + 0xe04854c4241c6c70ULL, 0xd596af9e4b39dde4ULL, 0xf2cb9219eb592079ULL, + 0xc05048e828187860ULL, 0x8ae9bf70fa561345ULL, 0xf18d3e39c8b345f6ULL, + 0xe9873724cdb04afaULL, 0x3dd8fc516c24b490ULL, 0x1dc0e07d6020a080ULL, + 0xf98b3932cbb240f2ULL, 0xe44bd94fab92e072ULL, 0x71ed4e89f8a315b6ULL, + 0x4eba7a135dc0e727ULL, 0x1a85c1d6cc44490dULL, 0x37513391a662f795ULL, + 0x806070b030105040ULL, 0xc99f2b08c1b45eeaULL, 0x543fbbc59184ae2aULL, + 0x2297d4e7c5435211ULL, 0xec4dde44a893e576ULL, 0x5eb674055bc2ed2fULL, + 0x6aa1ebb4de4a7f35ULL, 0x81a9145bdabd73ceULL, 0x0c058a808c8f8906ULL, + 0x75eec302772d99b4ULL, 0x89af1350d9bc76caULL, 0x946ff32db99cd64aULL, + 0x77610bc9be6adfb5ULL, 0x3a9dddfac0405d1dULL, 0x3698577a4ccfd41bULL, + 0x79eb4982fba210b2ULL, 0x7427a7e99d80ba3aULL, 0x42bff093d14f6e21ULL, + 0xf8425dd9211f637cULL, 0x1e864c5d43cac50fULL, 0x39db71dae3aa3892ULL, + 0x2a91d3ecc6425715ULL +}; + +static const u64 T6[256] = { + 0x6a01bbb9d268bad3ULL, 0x66b1e59a4d1954fcULL, 0x14cde265bc932f71ULL, + 0x1b512587cdb9749cULL, 0x57a4f7a2510253f5ULL, 0xbe03d0d66bb8d368ULL, + 0xb504d6de6fbdd26bULL, 0x85feb35229644dd7ULL, 0x4aadfdba5d0d50f0ULL, + 0xe063cf098a26ace9ULL, 0x9684091c0e838d8aULL, 0x4d1aa591c679bfdcULL, + 0x374d3da7ddad7090ULL, 0x5ca3f1aa550752f6ULL, 0x17e17ba452c89ab3ULL, + 0x8ef9b55a2d614cd4ULL, 0x20ac46038f65ea23ULL, 0x8411c4e673a6d562ULL, + 0x68c255cc66f197a4ULL, 0xa80ddcc663b2d16eULL, 0xd099aa85ccff3355ULL, + 0x41aafbb2590851f3ULL, 0x0f9cc7e2712a5bedULL, 0xae55f359a204a6f7ULL, + 0xc120febe5f81de7fULL, 0xa2e5ad7a3d7548d8ULL, 0xcc7fd7299a32a8e5ULL, + 0x0ae871bc5ec799b6ULL, 0xe63be0964b90db70ULL, 0xdb9eac8dc8fa3256ULL, + 0x152295d1e651b7c4ULL, 0xaace32b3d72bfc19ULL, 0x7393704bab48e338ULL, + 0x3bfd638442dc9ebfULL, 0x52d041fc7eef91aeULL, 0x1ce67dac56cd9bb0ULL, + 0x78947643af4de23bULL, 0x6106bdb1d66dbbd0ULL, 0xf1da9b32195841c3ULL, + 0xe5177957a5cb6eb2ULL, 0xb35cf941ae0ba5f2ULL, 0x564b80160bc0cb40ULL, + 0xc20c677fb1da6bbdULL, 0x7ecc59dc6efb95a2ULL, 0x9f40e161be1fa1feULL, + 0xc3e310cbeb18f308ULL, 0x2f3081e1fe4fb1ceULL, 0x160e0c10080a0206ULL, + 0x675e922e17dbcc49ULL, 0x3f66a26e37f3c451ULL, 0xcf534ee874691d27ULL, + 0x9c6c78a05044143cULL, 0x0e73b0562be8c358ULL, 0x9a34573f91f263a5ULL, + 0xed3ce69e4f95da73ULL, 0x358ed3d269345de7ULL, 0x2380dfc2613e5fe1ULL, + 0xd72ef2ae578bdc79ULL, 0x486e13cfe9947d87ULL, 0x6c59942613decd4aULL, + 0x5e601fdfe19e7f81ULL, 0x049bc1ea752f5aeeULL, 0xf3197547adc16cb4ULL, + 0x3e89d5da6d315ce4ULL, 0xefff08ebfb0cf704ULL, 0x47f2d42d98be266aULL, + 0xb7c738abdb24ff1cULL, 0x11b9543b937eed2aULL, 0x36a24a13876fe825ULL, + 0x26f4699c4ed39dbaULL, 0xee107f5fa1ce6fb1ULL, 0x8b8d0304028c8e8fULL, + 0xe34f56c8647d192bULL, 0x9447e769ba1aa0fdULL, 0xdeea1ad3e717f00dULL, + 0xba98113c1e978986ULL, 0x692d22783c330f11ULL, 0x311512381c1b0709ULL, + 0xfd6ac5118629afecULL, 0x9bdb208bcb30fb10ULL, 0x5838304020280818ULL, + 0x976b7ea85441153fULL, 0x7f232e6834390d17ULL, 0x2c1c18201014040cULL, + 0x0b07060804050103ULL, 0xab2145078de964acULL, 0xca27f8b65b84df7cULL, + 0x0d5f2997c5b3769aULL, 0x64720beff980798bULL, 0xdc29f4a6538edd7aULL, + 0xb2b38ef5f4c93d47ULL, 0x8a6274b0584e163aULL, 0xa4bd82e5fcc33f41ULL, + 0xfc85b2a5dceb3759ULL, 0xf81e734fa9c46db7ULL, 0x95a890dde0d83848ULL, + 0x7708b1a1de67b9d6ULL, 0x2a4437bfd1a27395ULL, 0x3da54c1b836ae926ULL, + 0xea8bbeb5d4e1355fULL, 0x6db6e392491c55ffULL, 0x3c4a3bafd9a87193ULL, + 0x727c07fff18a7b8dULL, 0x9d830f140a868c89ULL, 0x214331b7d5a77296ULL, + 0xb19f17341a928885ULL, 0xe4f80ee3ff09f607ULL, 0x33d6fc4da8822a7eULL, + 0xafba84edf8c63e42ULL, 0x2887d9ca653b5ee2ULL, 0x4cf5d2259cbb2769ULL, + 0xc0cf890a054346caULL, 0x74242860303c0c14ULL, 0xa026430f89ec65afULL, + 0xdf056d67bdd568b8ULL, 0x8c3a5b2f99f861a3ULL, 0x1d090a180c0f0305ULL, + 0x187dbc4623e2c15eULL, 0x7bb8ef82411657f9ULL, 0x9918cefe7fa9d667ULL, + 0xf035ec86439ad976ULL, 0x1295cdfa7d2558e8ULL, 0xfb32ea8e479fd875ULL, + 0xbd2f491785e366aaULL, 0x921fc8f67bacd764ULL, 0x83a69ccde8d23a4eULL, + 0x4b428a0e07cfc845ULL, 0xb9b488fdf0cc3c44ULL, 0x90dc2683cf35fa13ULL, + 0x63c553c462f496a7ULL, 0xa552f551a601a7f4ULL, 0x01ef77b45ac298b5ULL, + 0x1abe5233977bec29ULL, 0x7c0fb7a9da62b8d5ULL, 0x226fa8763bfcc754ULL, + 0xf66dc319822caeefULL, 0xd4026b6fb9d069bbULL, 0xbfeca762317a4bddULL, + 0xd176dd31963dabe0ULL, 0xc778d1219e37a9e6ULL, 0xb6284f1f81e667a9ULL, + 0x4e363c5028220a1eULL, 0xcbc88f02014647c9ULL, 0xc8e416c3ef1df20bULL, + 0x032c99c1ee5bb5c2ULL, 0x6beecc0d88aa2266ULL, 0x4981647bb356e532ULL, + 0x0cb05e239f71ee2fULL, 0x461da399c27cbedfULL, 0x38d1fa45ac872b7dULL, + 0xe2a0217c3ebf819eULL, 0xa67e6c90485a1236ULL, 0xf4ae2d6c36b58398ULL, + 0xf5415ad86c771b2dULL, 0x622a247038360e12ULL, 0x60e9ca058caf2365ULL, + 0xf9f104fbf306f502ULL, 0xddc68312094c45cfULL, 0x76e7c61584a52163ULL, + 0x71509e3e1fd1ce4fULL, 0xa9e2ab72397049dbULL, 0x09c4e87db09c2c74ULL, + 0x8dd52c9bc33af916ULL, 0x54886e63bf59e637ULL, 0x1e2593d9e254b6c7ULL, + 0x25d8f05da0882878ULL, 0x816572b85c4b1739ULL, 0xffa92b6432b0829bULL, + 0xfe465cd068721a2eULL, 0xac961d2c169d8b80ULL, 0xbcc03ea3df21fe1fULL, + 0xa7911b2412988a83ULL, 0x533f3648242d091bULL, 0x40458c0603cac946ULL, + 0xd8b2354c26a18794ULL, 0x98f7b94a256b4ed2ULL, 0x659d7c5ba342e13eULL, + 0x1fcae46db8962e72ULL, 0x42866273b753e431ULL, 0x6e9a7a53a747e03dULL, + 0x2bab400b8b60eb20ULL, 0x59d747f47aea90adULL, 0xb85bff49aa0ea4f1ULL, + 0xd25a44f078661e22ULL, 0xcebc395c2eab8592ULL, 0x873d5d279dfd60a0ULL, + 0x0000000000000000ULL, 0x5afbde3594b1256fULL, 0xf2f602f3f703f401ULL, + 0xd5ed1cdbe312f10eULL, 0x75cb5fd46afe94a1ULL, 0x45313a582c270b1dULL, + 0x5f8f686bbb5ce734ULL, 0x1056238fc9bc759fULL, 0x07b7582b9b74ef2cULL, + 0xe18cb8bdd0e4345cULL, 0xc697a695c4f53153ULL, 0x8f16c2ee77a3d461ULL, + 0xa30adace67b7d06dULL, 0xd3b5334422a48697ULL, 0x556719d7e59b7e82ULL, + 0xeb64c9018e23adeaULL, 0xa1c934bbd32efd1aULL, 0x2edff655a48d297bULL, + 0xcd90a09dc0f03050ULL, 0x88a19ac5ecd73b4dULL, 0x30fa658c46d99fbcULL, + 0x86d22a93c73ff815ULL, 0x2968ae7e3ff9c657ULL, 0xad796a984c5f1335ULL, + 0x3a121430181e060aULL, 0x271b1e281411050fULL, 0x3461a46633f6c552ULL, + 0xbb77668844551133ULL, 0x06582f9fc1b67799ULL, 0x436915c7ed917c84ULL, + 0x797b01f7f58f7a8eULL, 0x6f750de7fd857888ULL, 0xf782b4add8ee365aULL, + 0xc45448e0706c1c24ULL, 0x9eaf96d5e4dd394bULL, 0x1992cbf2792059ebULL, + 0xe84850c060781828ULL, 0x70bfe98a451356faULL, 0x393e8df1f645b3c8ULL, + 0x243787e9fa4ab0cdULL, 0x51fcd83d90b4246cULL, 0x7de0c01d80a02060ULL, + 0x32398bf9f240b2cbULL, 0x4fd94be472e092abULL, 0x894eed71b615a3f8ULL, + 0x137aba4e27e7c05dULL, 0xd6c1851a0d4944ccULL, 0x9133513795f762a6ULL, + 0xb070608040501030ULL, 0x082b9fc9ea5eb4c1ULL, 0xc5bb3f542aae8491ULL, + 0xe7d49722115243c5ULL, 0x44de4dec76e593a8ULL, 0x0574b65e2fedc25bULL, + 0xb4eba16a357f4adeULL, 0x5b14a981ce73bddaULL, 0x808a050c06898f8cULL, + 0x02c3ee75b4992d77ULL, 0x5013af89ca76bcd9ULL, 0x2df36f944ad69cb9ULL, + 0xc90b6177b5df6abeULL, 0xfadd9d3a1d5d40c0ULL, 0x7a5798361bd4cf4cULL, + 0x8249eb79b210a2fbULL, 0xe9a727743aba809dULL, 0x93f0bf42216e4fd1ULL, + 0xd95d42f87c631f21ULL, 0x5d4c861e0fc5ca43ULL, 0xda71db399238aae3ULL, + 0xecd3912a155742c6ULL +}; + +static const u64 T7[256] = { + 0x016ab9bb68d2d3baULL, 0xb1669ae5194dfc54ULL, 0xcd1465e293bc712fULL, + 0x511b8725b9cd9c74ULL, 0xa457a2f70251f553ULL, 0x03bed6d0b86b68d3ULL, + 0x04b5ded6bd6f6bd2ULL, 0xfe8552b36429d74dULL, 0xad4abafd0d5df050ULL, + 0x63e009cf268ae9acULL, 0x84961c09830e8a8dULL, 0x1a4d91a579c6dcbfULL, + 0x4d37a73daddd9070ULL, 0xa35caaf10755f652ULL, 0xe117a47bc852b39aULL, + 0xf98e5ab5612dd44cULL, 0xac200346658f23eaULL, 0x1184e6c4a67362d5ULL, + 0xc268cc55f166a497ULL, 0x0da8c6dcb2636ed1ULL, 0x99d085aaffcc5533ULL, + 0xaa41b2fb0859f351ULL, 0x9c0fe2c72a71ed5bULL, 0x55ae59f304a2f7a6ULL, + 0x20c1befe815f7fdeULL, 0xe5a27aad753dd848ULL, 0x7fcc29d7329ae5a8ULL, + 0xe80abc71c75eb699ULL, 0x3be696e0904b70dbULL, 0x9edb8dacfac85632ULL, + 0x2215d19551e6c4b7ULL, 0xceaab3322bd719fcULL, 0x93734b7048ab38e3ULL, + 0xfd3b8463dc42bf9eULL, 0xd052fc41ef7eae91ULL, 0xe61cac7dcd56b09bULL, + 0x947843764daf3be2ULL, 0x0661b1bd6dd6d0bbULL, 0xdaf1329b5819c341ULL, + 0x17e55779cba5b26eULL, 0x5cb341f90baef2a5ULL, 0x4b561680c00b40cbULL, + 0x0cc27f67dab1bd6bULL, 0xcc7edc59fb6ea295ULL, 0x409f61e11fbefea1ULL, + 0xe3c3cb1018eb08f3ULL, 0x302fe1814ffeceb1ULL, 0x0e16100c0a080602ULL, + 0x5e672e92db1749ccULL, 0x663f6ea2f33751c4ULL, 0x53cfe84e6974271dULL, + 0x6c9ca07844503c14ULL, 0x730e56b0e82b58c3ULL, 0x349a3f57f291a563ULL, + 0x3ced9ee6954f73daULL, 0x8e35d2d33469e75dULL, 0x8023c2df3e61e15fULL, + 0x2ed7aef28b5779dcULL, 0x6e48cf1394e9877dULL, 0x596c2694de134acdULL, + 0x605edf1f9ee1817fULL, 0x9b04eac12f75ee5aULL, 0x19f34775c1adb46cULL, + 0x893edad5316de45cULL, 0xffefeb080cfb04f7ULL, 0xf2472dd4be986a26ULL, + 0xc7b7ab3824db1cffULL, 0xb9113b547e932aedULL, 0xa236134a6f8725e8ULL, + 0xf4269c69d34eba9dULL, 0x10ee5f7fcea1b16fULL, 0x8d8b04038c028f8eULL, + 0x4fe3c8567d642b19ULL, 0x479469e71abafda0ULL, 0xeaded31a17e70df0ULL, + 0x98ba3c11971e8689ULL, 0x2d697822333c110fULL, 0x153138121b1c0907ULL, + 0x6afd11c52986ecafULL, 0xdb9b8b2030cb10fbULL, 0x3858403028201808ULL, + 0x6b97a87e41543f15ULL, 0x237f682e3934170dULL, 0x1c2c201814100c04ULL, + 0x070b080605040301ULL, 0x21ab0745e98dac64ULL, 0x27cab6f8845b7cdfULL, + 0x5f0d9729b3c59a76ULL, 0x7264ef0b80f98b79ULL, 0x29dca6f48e537addULL, + 0xb3b2f58ec9f4473dULL, 0x628ab0744e583a16ULL, 0xbda4e582c3fc413fULL, + 0x85fca5b2ebdc5937ULL, 0x1ef84f73c4a9b76dULL, 0xa895dd90d8e04838ULL, + 0x0877a1b167ded6b9ULL, 0x442abf37a2d19573ULL, 0xa53d1b4c6a8326e9ULL, + 0x8beab5bee1d45f35ULL, 0xb66d92e31c49ff55ULL, 0x4a3caf3ba8d99371ULL, + 0x7c72ff078af18d7bULL, 0x839d140f860a898cULL, 0x4321b731a7d59672ULL, + 0x9fb13417921a8588ULL, 0xf8e4e30e09ff07f6ULL, 0xd6334dfc82a87e2aULL, + 0xbaafed84c6f8423eULL, 0x8728cad93b65e25eULL, 0xf54c25d2bb9c6927ULL, + 0xcfc00a894305ca46ULL, 0x247460283c30140cULL, 0x26a00f43ec89af65ULL, + 0x05df676dd5bdb868ULL, 0x3a8c2f5bf899a361ULL, 0x091d180a0f0c0503ULL, + 0x7d1846bce2235ec1ULL, 0xb87b82ef1641f957ULL, 0x1899fecea97f67d6ULL, + 0x35f086ec9a4376d9ULL, 0x9512facd257de858ULL, 0x32fb8eea9f4775d8ULL, + 0x2fbd1749e385aa66ULL, 0x1f92f6c8ac7b64d7ULL, 0xa683cd9cd2e84e3aULL, + 0x424b0e8acf0745c8ULL, 0xb4b9fd88ccf0443cULL, 0xdc90832635cf13faULL, + 0xc563c453f462a796ULL, 0x52a551f501a6f4a7ULL, 0xef01b477c25ab598ULL, + 0xbe1a33527b9729ecULL, 0x0f7ca9b762dad5b8ULL, 0x6f2276a8fc3b54c7ULL, + 0x6df619c32c82efaeULL, 0x02d46f6bd0b9bb69ULL, 0xecbf62a77a31dd4bULL, + 0x76d131dd3d96e0abULL, 0x78c721d1379ee6a9ULL, 0x28b61f4fe681a967ULL, + 0x364e503c22281e0aULL, 0xc8cb028f4601c947ULL, 0xe4c8c3161def0bf2ULL, + 0x2c03c1995beec2b5ULL, 0xee6b0dccaa886622ULL, 0x81497b6456b332e5ULL, + 0xb00c235e719f2feeULL, 0x1d4699a37cc2dfbeULL, 0xd13845fa87ac7d2bULL, + 0xa0e27c21bf3e9e81ULL, 0x7ea6906c5a483612ULL, 0xaef46c2db5369883ULL, + 0x41f5d85a776c2d1bULL, 0x2a6270243638120eULL, 0xe96005caaf8c6523ULL, + 0xf1f9fb0406f302f5ULL, 0xc6dd12834c09cf45ULL, 0xe77615c6a5846321ULL, + 0x50713e9ed11f4fceULL, 0xe2a972ab7039db49ULL, 0xc4097de89cb0742cULL, + 0xd58d9b2c3ac316f9ULL, 0x8854636e59bf37e6ULL, 0x251ed99354e2c7b6ULL, + 0xd8255df088a07828ULL, 0x6581b8724b5c3917ULL, 0xa9ff642bb0329b82ULL, + 0x46fed05c72682e1aULL, 0x96ac2c1d9d16808bULL, 0xc0bca33e21df1ffeULL, + 0x91a7241b9812838aULL, 0x3f5348362d241b09ULL, 0x4540068cca0346c9ULL, + 0xb2d84c35a1269487ULL, 0xf7984ab96b25d24eULL, 0x9d655b7c42a33ee1ULL, + 0xca1f6de496b8722eULL, 0x8642736253b731e4ULL, 0x9a6e537a47a73de0ULL, + 0xab2b0b40608b20ebULL, 0xd759f447ea7aad90ULL, 0x5bb849ff0eaaf1a4ULL, + 0x5ad2f0446678221eULL, 0xbcce5c39ab2e9285ULL, 0x3d87275dfd9da060ULL, + 0x0000000000000000ULL, 0xfb5a35deb1946f25ULL, 0xf6f2f30203f701f4ULL, + 0xedd5db1c12e30ef1ULL, 0xcb75d45ffe6aa194ULL, 0x3145583a272c1d0bULL, + 0x8f5f6b685cbb34e7ULL, 0x56108f23bcc99f75ULL, 0xb7072b58749b2cefULL, + 0x8ce1bdb8e4d05c34ULL, 0x97c695a6f5c45331ULL, 0x168feec2a37761d4ULL, + 0x0aa3cedab7676dd0ULL, 0xb5d34433a4229786ULL, 0x6755d7199be5827eULL, + 0x64eb01c9238eeaadULL, 0xc9a1bb342ed31afdULL, 0xdf2e55f68da47b29ULL, + 0x90cd9da0f0c05030ULL, 0xa188c59ad7ec4d3bULL, 0xfa308c65d946bc9fULL, + 0xd286932a3fc715f8ULL, 0x68297eaef93f57c6ULL, 0x79ad986a5f4c3513ULL, + 0x123a30141e180a06ULL, 0x1b27281e11140f05ULL, 0x613466a4f63352c5ULL, + 0x77bb886655443311ULL, 0x58069f2fb6c19977ULL, 0x6943c71591ed847cULL, + 0x7b79f7018ff58e7aULL, 0x756fe70d85fd8878ULL, 0x82f7adb4eed85a36ULL, + 0x54c4e0486c70241cULL, 0xaf9ed596dde44b39ULL, 0x9219f2cb2079eb59ULL, + 0x48e8c05078602818ULL, 0xbf708ae91345fa56ULL, 0x3e39f18d45f6c8b3ULL, + 0x3724e9874afacdb0ULL, 0xfc513dd8b4906c24ULL, 0xe07d1dc0a0806020ULL, + 0x3932f98b40f2cbb2ULL, 0xd94fe44be072ab92ULL, 0x4e8971ed15b6f8a3ULL, + 0x7a134ebae7275dc0ULL, 0xc1d61a85490dcc44ULL, 0x33913751f795a662ULL, + 0x70b0806050403010ULL, 0x2b08c99f5eeac1b4ULL, 0xbbc5543fae2a9184ULL, + 0xd4e722975211c543ULL, 0xde44ec4de576a893ULL, 0x74055eb6ed2f5bc2ULL, + 0xebb46aa17f35de4aULL, 0x145b81a973cedabdULL, 0x8a800c0589068c8fULL, + 0xc30275ee99b4772dULL, 0x135089af76cad9bcULL, 0xf32d946fd64ab99cULL, + 0x0bc97761dfb5be6aULL, 0xddfa3a9d5d1dc040ULL, 0x577a3698d41b4ccfULL, + 0x498279eb10b2fba2ULL, 0xa7e97427ba3a9d80ULL, 0xf09342bf6e21d14fULL, + 0x5dd9f842637c211fULL, 0x4c5d1e86c50f43caULL, 0x71da39db3892e3aaULL, + 0xd3ec2a915715c642ULL +}; + +static const u64 c[KHAZAD_ROUNDS + 1] = { + 0xba542f7453d3d24dULL, 0x50ac8dbf70529a4cULL, 0xead597d133515ba6ULL, + 0xde48a899db32b7fcULL, 0xe39e919be2bb416eULL, 0xa5cb6b95a1f3b102ULL, + 0xccc41d14c363da5dULL, 0x5fdc7dcd7f5a6c5cULL, 0xf726ffede89d6f8eULL +}; + +static int khazad_setkey(void *ctx_arg, const u8 *in_key, + unsigned int key_len, u32 *flags) +{ + + struct khazad_ctx *ctx = ctx_arg; + int r; + const u64 *S = T7; + u64 K2, K1; + + if (key_len != 16) + { + *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + + K2 = ((u64)in_key[ 0] << 56) ^ + ((u64)in_key[ 1] << 48) ^ + ((u64)in_key[ 2] << 40) ^ + ((u64)in_key[ 3] << 32) ^ + ((u64)in_key[ 4] << 24) ^ + ((u64)in_key[ 5] << 16) ^ + ((u64)in_key[ 6] << 8) ^ + ((u64)in_key[ 7] ); + K1 = ((u64)in_key[ 8] << 56) ^ + ((u64)in_key[ 9] << 48) ^ + ((u64)in_key[10] << 40) ^ + ((u64)in_key[11] << 32) ^ + ((u64)in_key[12] << 24) ^ + ((u64)in_key[13] << 16) ^ + ((u64)in_key[14] << 8) ^ + ((u64)in_key[15] ); + + /* setup the encrypt key */ + for (r = 0; r <= KHAZAD_ROUNDS; r++) { + ctx->E[r] = T0[(int)(K1 >> 56) ] ^ + T1[(int)(K1 >> 48) & 0xff] ^ + T2[(int)(K1 >> 40) & 0xff] ^ + T3[(int)(K1 >> 32) & 0xff] ^ + T4[(int)(K1 >> 24) & 0xff] ^ + T5[(int)(K1 >> 16) & 0xff] ^ + T6[(int)(K1 >> 8) & 0xff] ^ + T7[(int)(K1 ) & 0xff] ^ + c[r] ^ K2; + K2 = K1; + K1 = ctx->E[r]; + } + /* Setup the decrypt key */ + ctx->D[0] = ctx->E[KHAZAD_ROUNDS]; + for (r = 1; r < KHAZAD_ROUNDS; r++) { + K1 = ctx->E[KHAZAD_ROUNDS - r]; + ctx->D[r] = T0[(int)S[(int)(K1 >> 56) ] & 0xff] ^ + T1[(int)S[(int)(K1 >> 48) & 0xff] & 0xff] ^ + T2[(int)S[(int)(K1 >> 40) & 0xff] & 0xff] ^ + T3[(int)S[(int)(K1 >> 32) & 0xff] & 0xff] ^ + T4[(int)S[(int)(K1 >> 24) & 0xff] & 0xff] ^ + T5[(int)S[(int)(K1 >> 16) & 0xff] & 0xff] ^ + T6[(int)S[(int)(K1 >> 8) & 0xff] & 0xff] ^ + T7[(int)S[(int)(K1 ) & 0xff] & 0xff]; + } + ctx->D[KHAZAD_ROUNDS] = ctx->E[0]; + + return 0; + +} + +static void khazad_crypt(const u64 roundKey[KHAZAD_ROUNDS + 1], + u8 *ciphertext, const u8 *plaintext) +{ + + int r; + u64 state; + + state = ((u64)plaintext[0] << 56) ^ + ((u64)plaintext[1] << 48) ^ + ((u64)plaintext[2] << 40) ^ + ((u64)plaintext[3] << 32) ^ + ((u64)plaintext[4] << 24) ^ + ((u64)plaintext[5] << 16) ^ + ((u64)plaintext[6] << 8) ^ + ((u64)plaintext[7] ) ^ + roundKey[0]; + + for (r = 1; r < KHAZAD_ROUNDS; r++) { + state = T0[(int)(state >> 56) ] ^ + T1[(int)(state >> 48) & 0xff] ^ + T2[(int)(state >> 40) & 0xff] ^ + T3[(int)(state >> 32) & 0xff] ^ + T4[(int)(state >> 24) & 0xff] ^ + T5[(int)(state >> 16) & 0xff] ^ + T6[(int)(state >> 8) & 0xff] ^ + T7[(int)(state ) & 0xff] ^ + roundKey[r]; + } + + state = (T0[(int)(state >> 56) ] & 0xff00000000000000ULL) ^ + (T1[(int)(state >> 48) & 0xff] & 0x00ff000000000000ULL) ^ + (T2[(int)(state >> 40) & 0xff] & 0x0000ff0000000000ULL) ^ + (T3[(int)(state >> 32) & 0xff] & 0x000000ff00000000ULL) ^ + (T4[(int)(state >> 24) & 0xff] & 0x00000000ff000000ULL) ^ + (T5[(int)(state >> 16) & 0xff] & 0x0000000000ff0000ULL) ^ + (T6[(int)(state >> 8) & 0xff] & 0x000000000000ff00ULL) ^ + (T7[(int)(state ) & 0xff] & 0x00000000000000ffULL) ^ + roundKey[KHAZAD_ROUNDS]; + + ciphertext[0] = (u8)(state >> 56); + ciphertext[1] = (u8)(state >> 48); + ciphertext[2] = (u8)(state >> 40); + ciphertext[3] = (u8)(state >> 32); + ciphertext[4] = (u8)(state >> 24); + ciphertext[5] = (u8)(state >> 16); + ciphertext[6] = (u8)(state >> 8); + ciphertext[7] = (u8)(state ); + +} + +static void khazad_encrypt(void *ctx_arg, u8 *dst, const u8 *src) +{ + struct khazad_ctx *ctx = ctx_arg; + khazad_crypt(ctx->E, dst, src); +} + +static void khazad_decrypt(void *ctx_arg, u8 *dst, const u8 *src) +{ + struct khazad_ctx *ctx = ctx_arg; + khazad_crypt(ctx->D, dst, src); +} + +static struct crypto_alg khazad_alg = { + .cra_name = "khazad", + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = KHAZAD_BLOCK_SIZE, + .cra_ctxsize = sizeof (struct khazad_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(khazad_alg.cra_list), + .cra_u = { .cipher = { + .cia_min_keysize = KHAZAD_KEY_SIZE, + .cia_max_keysize = KHAZAD_KEY_SIZE, + .cia_setkey = khazad_setkey, + .cia_encrypt = khazad_encrypt, + .cia_decrypt = khazad_decrypt } } +}; + +static int __init init(void) +{ + int ret = 0; + + ret = crypto_register_alg(&khazad_alg); + return ret; +} + +static void __exit fini(void) +{ + crypto_unregister_alg(&khazad_alg); +} + + +module_init(init); +module_exit(fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Khazad Cryptographic Algorithm"); diff -Nru a/crypto/scatterwalk.c b/crypto/scatterwalk.c --- a/crypto/scatterwalk.c 2004-08-14 12:02:30 -07:00 +++ b/crypto/scatterwalk.c 2004-08-14 12:02:30 -07:00 @@ -70,7 +70,7 @@ { /* walk->data may be pointing the first byte of the next page; however, we know we transfered at least one byte. So, - walk->data - 1 will be a virutual address in the mapped page. */ + walk->data - 1 will be a virtual address in the mapped page. */ if (out) flush_dcache_page(walk->page); diff -Nru a/crypto/tcrypt.c b/crypto/tcrypt.c --- a/crypto/tcrypt.c 2004-08-14 12:02:30 -07:00 +++ b/crypto/tcrypt.c 2004-08-14 12:02:30 -07:00 @@ -575,6 +575,10 @@ test_cipher ("xtea", MODE_ECB, ENCRYPT, xtea_enc_tv_template, XTEA_ENC_TEST_VECTORS); test_cipher ("xtea", MODE_ECB, DECRYPT, xtea_dec_tv_template, XTEA_DEC_TEST_VECTORS); + //KHAZAD + test_cipher ("khazad", MODE_ECB, ENCRYPT, khazad_enc_tv_template, KHAZAD_ENC_TEST_VECTORS); + test_cipher ("khazad", MODE_ECB, DECRYPT, khazad_dec_tv_template, KHAZAD_DEC_TEST_VECTORS); + test_hash("sha384", sha384_tv_template, SHA384_TEST_VECTORS); test_hash("sha512", sha512_tv_template, SHA512_TEST_VECTORS); test_deflate(); @@ -676,6 +680,11 @@ case 20: test_cipher ("xtea", MODE_ECB, ENCRYPT, xtea_enc_tv_template, XTEA_ENC_TEST_VECTORS); test_cipher ("xtea", MODE_ECB, DECRYPT, xtea_dec_tv_template, XTEA_DEC_TEST_VECTORS); + break; + + case 21: + test_cipher ("khazad", MODE_ECB, ENCRYPT, khazad_enc_tv_template, KHAZAD_ENC_TEST_VECTORS); + test_cipher ("khazad", MODE_ECB, DECRYPT, khazad_dec_tv_template, KHAZAD_DEC_TEST_VECTORS); break; #ifdef CONFIG_CRYPTO_HMAC diff -Nru a/crypto/tcrypt.h b/crypto/tcrypt.h --- a/crypto/tcrypt.h 2004-08-14 12:02:31 -07:00 +++ b/crypto/tcrypt.h 2004-08-14 12:02:31 -07:00 @@ -1186,7 +1186,7 @@ /* * Serpent test vectors. These are backwards because Serpent writes - * octect sequences in right-to-left mode. + * octet sequences in right-to-left mode. */ #define SERPENT_ENC_TEST_VECTORS 4 #define SERPENT_DEC_TEST_VECTORS 4 @@ -1818,7 +1818,103 @@ } }; +/* + * KHAZAD test vectors. + */ +#define KHAZAD_ENC_TEST_VECTORS 5 +#define KHAZAD_DEC_TEST_VECTORS 5 + +struct cipher_testvec khazad_enc_tv_template[] = { + { + .key = { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .klen = 16, + .input = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .ilen = 8, + .result = { 0x49, 0xa4, 0xce, 0x32, 0xac, 0x19, 0x0e, 0x3f }, + .rlen = 8, + }, { + .key = { 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38 }, + .klen = 16, + .input = { 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38 }, + .ilen = 8, + .result = { 0x7e, 0x82, 0x12, 0xa1, 0Xd9, 0X5b, 0Xe4, 0Xf9 }, + .rlen = 8, + }, { + .key = { 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, + 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2 }, + .klen = 16, + .input = { 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2 }, + .ilen = 8, + .result = { 0Xaa, 0Xbe, 0Xc1, 0X95, 0Xc5, 0X94, 0X1a, 0X9c }, + .rlen = 8, + }, { + .key = { 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, + 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f }, + .klen = 16, + .input = { 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f }, + .ilen = 8, + .result = { 0X04, 0X74, 0Xf5, 0X70, 0X50, 0X16, 0Xd3, 0Xb8 }, + .rlen = 8, + }, { + .key = { 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, + 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f }, + .klen = 16, + .input = { 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f , + 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f }, + .ilen = 16, + .result = { 0X04, 0X74, 0Xf5, 0X70, 0X50, 0X16, 0Xd3, 0Xb8 , + 0X04, 0X74, 0Xf5, 0X70, 0X50, 0X16, 0Xd3, 0Xb8 }, + .rlen = 16, + }, +}; +struct cipher_testvec khazad_dec_tv_template[] = { + { + .key = { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .klen = 16, + .input = { 0X49, 0Xa4, 0Xce, 0X32, 0Xac, 0X19, 0X0e, 0X3f }, + .ilen = 8, + .result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .rlen = 8, + }, { + .key = { 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38 }, + .klen = 16, + .input = { 0X7e, 0X82, 0X12, 0Xa1, 0Xd9, 0X5b, 0Xe4, 0Xf9 }, + .ilen = 8, + .result = { 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38 }, + .rlen = 8, + }, { + .key = { 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, + 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2 }, + .klen = 16, + .input = { 0Xaa, 0Xbe, 0Xc1, 0X95, 0Xc5, 0X94, 0X1a, 0X9c }, + .ilen = 8, + .result = { 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2, 0Xa2 }, + .rlen = 8, + }, { + .key = { 0x2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, + 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f }, + .klen = 16, + .input = { 0X04, 0X74, 0Xf5, 0X70, 0X50, 0X16, 0Xd3, 0Xb8 }, + .ilen = 8, + .result = { 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f }, + .rlen = 8, + }, { + .key = { 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, + 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f }, + .klen = 16, + .input = { 0X04, 0X74, 0Xf5, 0X70, 0X50, 0X16, 0Xd3, 0Xb8 , + 0X04, 0X74, 0Xf5, 0X70, 0X50, 0X16, 0Xd3, 0Xb8 }, + .ilen = 16, + .result = { 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f , + 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f, 0X2f }, + .rlen = 16, + }, +}; /* * Compression stuff. diff -Nru a/crypto/twofish.c b/crypto/twofish.c --- a/crypto/twofish.c 2004-08-14 12:02:30 -07:00 +++ b/crypto/twofish.c 2004-08-14 12:02:30 -07:00 @@ -1,7 +1,7 @@ /* * Twofish for CryptoAPI * - * Originaly Twofish for GPG + * Originally Twofish for GPG * By Matthew Skala , July 26, 1998 * 256-bit key length added March 20, 1999 * Some modifications to reduce the text size by Werner Koch, April, 1998 @@ -514,7 +514,7 @@ * preprocessed through q0 and q1 respectively; for longer keys they are the * output of previous stages. j is the index of the first key byte to use. * CALC_K computes a pair of subkeys for 128-bit Twofish, by calling CALC_K_2 - * twice, doing the Psuedo-Hadamard Transform, and doing the necessary + * twice, doing the Pseudo-Hadamard Transform, and doing the necessary * rotations. Its parameters are: a, the array to write the results into, * j, the index of the first output entry, k and l, the preprocessed indices * for index 2i, and m and n, the preprocessed indices for index 2i+1. diff -Nru a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c --- a/drivers/atm/fore200e.c 2004-08-14 12:02:31 -07:00 +++ b/drivers/atm/fore200e.c 2004-08-14 12:02:31 -07:00 @@ -101,6 +101,7 @@ #if 1 +#undef ASSERT #define ASSERT(expr) if (!(expr)) { \ printk(FORE200E "assertion failed! %s[%d]: %s\n", \ __FUNCTION__, __LINE__, #expr); \ diff -Nru a/drivers/block/cciss.c b/drivers/block/cciss.c --- a/drivers/block/cciss.c 2004-08-14 12:02:31 -07:00 +++ b/drivers/block/cciss.c 2004-08-14 12:02:31 -07:00 @@ -125,7 +125,7 @@ /* Originally cciss driver only supports 8 major number */ #define MAX_CTLR_ORIG COMPAQ_CISS_MAJOR7 - COMPAQ_CISS_MAJOR + 1 -#define CCISS_DMA_MASK 0xFFFFFFFFFFFFFFFF /* 64 bit DMA */ +#define CCISS_DMA_MASK 0xFFFFFFFFFFFFFFFFULL /* 64 bit DMA */ #ifdef CONFIG_CISS_MONITOR_THREAD static int cciss_monitor(void *ctlr); diff -Nru a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h --- a/drivers/char/agp/agp.h 2004-08-14 12:02:30 -07:00 +++ b/drivers/char/agp/agp.h 2004-08-14 12:02:30 -07:00 @@ -211,6 +211,12 @@ #ifndef PCI_DEVICE_ID_INTEL_865_G_1 #define PCI_DEVICE_ID_INTEL_865_G_1 0x2572 #endif +#ifndef PCI_DEVICE_ID_INTEL_915_G_0 +#define PCI_DEVICE_ID_INTEL_915_G_0 0x2580 +#endif +#ifndef PCI_DEVICE_ID_INTEL_915_G_1 +#define PCI_DEVICE_ID_INTEL_915_G_1 0x2582 +#endif #ifndef PCI_DEVICE_ID_INTEL_820_0 #define PCI_DEVICE_ID_INTEL_820_0 0x2500 #endif @@ -441,6 +447,12 @@ #define I810_DRAM_ROW_0 0x00000001 #define I810_DRAM_ROW_0_SDRAM 0x00000001 +/* intel I915 registers */ +#define I915_GMADDR 0x18 +#define I915_MMADDR 0x10 +#define I915_PTEADDR 0x1C +#define I915_GMCH_GMS_STOLEN_48M (0x6 << 4) +#define I915_GMCH_GMS_STOLEN_64M (0x7 << 4) /* VIA register */ diff -Nru a/drivers/char/agp/agpgart_be.c b/drivers/char/agp/agpgart_be.c --- a/drivers/char/agp/agpgart_be.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/char/agp/agpgart_be.c 2004-08-14 12:02:30 -07:00 @@ -794,7 +794,29 @@ } #endif get_page(page); - LockPage(page); + set_bit(PG_locked, &page->flags); + atomic_inc(&agp_bridge.current_memory_agp); + return (unsigned long)page_address(page); +} + +/* Exists to support ARGB cursors */ +static unsigned long i830_alloc_pages(void) +{ + struct page * page; + + page = alloc_pages(GFP_KERNEL, 2); + if (page == NULL) { + return 0; + } + +#ifdef CONFIG_X86 + if (change_page_attr(page, 4, PAGE_KERNEL_NOCACHE) < 0) { + __free_page(page); + return 0; + } +#endif + get_page(page); + set_bit(PG_locked, &page->flags); atomic_inc(&agp_bridge.current_memory_agp); return (unsigned long)page_address(page); } @@ -818,6 +840,25 @@ atomic_dec(&agp_bridge.current_memory_agp); } +static void i830_destroy_pages(unsigned long addr) +{ + void *pt = (void *) addr; + struct page *page; + + if (pt == NULL) { + return; + } + + page = virt_to_page(pt); +#ifdef CONFIG_X86 + change_page_attr(page, 4, PAGE_KERNEL); +#endif + put_page(page); + UnlockPage(page); + free_pages((unsigned long) pt, 2); + atomic_dec(&agp_bridge.current_memory_agp); +} + /* End Basic Page Allocation Routines */ void agp_enable(u32 mode) @@ -1022,33 +1063,49 @@ return new; } if(type == AGP_PHYS_MEMORY) { + unsigned long physical; + /* The I810 requires a physical address to program * it's mouse pointer into hardware. However the * Xserver still writes to it through the agp * aperture */ - if (pg_count != 1) { - return NULL; - } - new = agp_create_memory(1); + if (pg_count != 1 && pg_count != 4) return(NULL); - if (new == NULL) { - return NULL; + new = agp_create_memory(pg_count); + + if (new == NULL) return(NULL); + + MOD_INC_USE_COUNT; + if (pg_count == 1) + new->memory[0] = agp_bridge.agp_alloc_page(); + else { + /* kludge to get 4 physical pages for ARGB cursor */ + new->memory[0] = i830_alloc_pages(); + new->memory[1] = new->memory[0] + PAGE_SIZE; + new->memory[2] = new->memory[1] + PAGE_SIZE; + new->memory[3] = new->memory[2] + PAGE_SIZE; } - MOD_INC_USE_COUNT; - new->memory[0] = agp_bridge.agp_alloc_page(); if (new->memory[0] == 0) { /* Free this structure */ agp_free_memory(new); return NULL; } + physical = new->memory[0]; + new->memory[0] = virt_to_phys((void *) new->memory[0]); - new->page_count = 1; - new->num_scratch_pages = 1; - new->type = AGP_PHYS_MEMORY; - new->physical = virt_to_phys((void *) new->memory[0]); - return new; + if (pg_count == 4) { + /* kludge to enable 4 physical pages for ARGB cursor */ + new->memory[1] = virt_to_phys((void *) new->memory[1]); + new->memory[2] = virt_to_phys((void *) new->memory[2]); + new->memory[3] = virt_to_phys((void *) new->memory[3]); + } + new->page_count = pg_count; + new->num_scratch_pages = pg_count; + new->type = AGP_PHYS_MEMORY; + new->physical = virt_to_phys((void *) physical); + return(new); } return NULL; @@ -1058,7 +1115,11 @@ { agp_free_key(curr->key); if(curr->type == AGP_PHYS_MEMORY) { - agp_bridge.agp_destroy_page((unsigned long) + if (curr->page_count == 4) + i830_destroy_pages((unsigned long) + phys_to_virt(curr->memory[0])); + else + agp_bridge.agp_destroy_page((unsigned long) phys_to_virt(curr->memory[0])); vfree(curr->memory); } @@ -1108,15 +1169,20 @@ { {128, 32768, 5}, /* The 64M mode still requires a 128k gatt */ - {64, 16384, 5} + {64, 16384, 5}, + /* For I915G */ + {256, 65536, 6} }; static struct _intel_i830_private { struct pci_dev *i830_dev; /* device one */ volatile u8 *registers; + volatile u32 *gtt; /* I915G */ int gtt_entries; } intel_i830_private; +static int intel_i830_fetch_size(void); + static void intel_i830_init_gtt_entries(void) { u16 gmch_ctrl; @@ -1124,26 +1190,47 @@ u8 rdct; int local = 0; static const int ddt[4] = { 0, 16, 32, 64 }; + int size; + pci_read_config_word(agp_bridge.dev,I830_GMCH_CTRL,&gmch_ctrl); + /* We obtain the size of the GTT, which is also stored (for some + * reason) at the top of stolen memory. Then we add 4KB to that + * for the video BIOS popup, which is also stored in there. */ + size = intel_i830_fetch_size() + 4; + if (agp_bridge.dev->device != PCI_DEVICE_ID_INTEL_830_M_0 && agp_bridge.dev->device != PCI_DEVICE_ID_INTEL_845_G_0) { switch (gmch_ctrl & I855_GMCH_GMS_MASK) { case I855_GMCH_GMS_STOLEN_1M: - gtt_entries = MB(1) - KB(132); + gtt_entries = MB(1) - KB(size); break; case I855_GMCH_GMS_STOLEN_4M: - gtt_entries = MB(4) - KB(132); + gtt_entries = MB(4) - KB(size); break; case I855_GMCH_GMS_STOLEN_8M: - gtt_entries = MB(8) - KB(132); + gtt_entries = MB(8) - KB(size); break; case I855_GMCH_GMS_STOLEN_16M: - gtt_entries = MB(16) - KB(132); + gtt_entries = MB(16) - KB(size); break; case I855_GMCH_GMS_STOLEN_32M: - gtt_entries = MB(32) - KB(132); + gtt_entries = MB(32) - KB(size); + break; + case I915_GMCH_GMS_STOLEN_48M: + /* Check it's really I915 */ + if (agp_bridge.dev->device == PCI_DEVICE_ID_INTEL_915_G_0) + gtt_entries = MB(48) - KB(size); + else + gtt_entries = 0; + break; + case I915_GMCH_GMS_STOLEN_64M: + /* Check it's really I915 */ + if (agp_bridge.dev->device == PCI_DEVICE_ID_INTEL_915_G_0) + gtt_entries = MB(64) - KB(size); + else + gtt_entries = 0; break; default: gtt_entries = 0; @@ -1153,13 +1240,13 @@ { switch (gmch_ctrl & I830_GMCH_GMS_MASK) { case I830_GMCH_GMS_STOLEN_512: - gtt_entries = KB(512) - KB(132); + gtt_entries = KB(512) - KB(size); break; case I830_GMCH_GMS_STOLEN_1024: - gtt_entries = MB(1) - KB(132); + gtt_entries = MB(1) - KB(size); break; case I830_GMCH_GMS_STOLEN_8192: - gtt_entries = MB(8) - KB(132); + gtt_entries = MB(8) - KB(size); break; case I830_GMCH_GMS_LOCAL: rdct = INREG8(intel_i830_private.registers, @@ -1193,14 +1280,24 @@ int page_order; aper_size_info_fixed *size; int num_entries; - u32 temp; + u32 temp, temp2; size = agp_bridge.current_size; page_order = size->page_order; num_entries = size->num_entries; agp_bridge.gatt_table_real = 0; - pci_read_config_dword(intel_i830_private.i830_dev,I810_MMADDR,&temp); + if (agp_bridge.dev->device == PCI_DEVICE_ID_INTEL_915_G_0) { + pci_read_config_dword(intel_i830_private.i830_dev, + I915_MMADDR,&temp); + pci_read_config_dword(intel_i830_private.i830_dev, + I915_PTEADDR,&temp2); + intel_i830_private.gtt = (volatile u32 *) ioremap(temp2, 256 * 1024); + if (!intel_i830_private.gtt) return (-ENOMEM); + } else + pci_read_config_dword(intel_i830_private.i830_dev, + I810_MMADDR,&temp); + temp &= 0xfff80000; intel_i830_private.registers = (volatile u8 *) ioremap(temp,128 * 4096); @@ -1234,6 +1331,20 @@ values = A_SIZE_FIX(agp_bridge.aperture_sizes); + if (agp_bridge.dev->device == PCI_DEVICE_ID_INTEL_915_G_0) { + u32 temp, offset = 0; + pci_read_config_dword(intel_i830_private.i830_dev, + I915_GMADDR,&temp); +#define I915_256MB_ADDRESS_MASK (1<<27) + if (temp & I915_256MB_ADDRESS_MASK) + offset = 0; /* 128MB aperture */ + else + offset = 2; /* 256MB aperture */ + agp_bridge.previous_size = agp_bridge.current_size = (void *)(values + offset); + agp_bridge.aperture_size_idx = offset; + return(values[offset].size); + } + if (agp_bridge.dev->device != PCI_DEVICE_ID_INTEL_830_M_0 && agp_bridge.dev->device != PCI_DEVICE_ID_INTEL_845_G_0) { agp_bridge.previous_size = agp_bridge.current_size = (void *) values; @@ -1247,7 +1358,7 @@ agp_bridge.aperture_size_idx = 0; return(values[0].size); } else { - agp_bridge.previous_size = agp_bridge.current_size = (void *) values; + agp_bridge.previous_size = agp_bridge.current_size = (void *)(values + 1); agp_bridge.aperture_size_idx = 1; return(values[1].size); } @@ -1264,7 +1375,13 @@ current_size = A_SIZE_FIX(agp_bridge.current_size); - pci_read_config_dword(intel_i830_private.i830_dev,I810_GMADDR,&temp); + if (agp_bridge.dev->device == PCI_DEVICE_ID_INTEL_915_G_0) + pci_read_config_dword(intel_i830_private.i830_dev, + I915_GMADDR,&temp); + else + pci_read_config_dword(intel_i830_private.i830_dev, + I810_GMADDR,&temp); + agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); pci_read_config_word(agp_bridge.dev,I830_GMCH_CTRL,&gmch_ctrl); @@ -1274,15 +1391,24 @@ OUTREG32(intel_i830_private.registers,I810_PGETBL_CTL,agp_bridge.gatt_bus_addr | I810_PGETBL_ENABLED); CACHE_FLUSH(); - if (agp_bridge.needs_scratch_page == TRUE) - for (i = intel_i830_private.gtt_entries; i < current_size->num_entries; i++) - OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge.scratch_page); + if (agp_bridge.needs_scratch_page == TRUE) { + if (agp_bridge.dev->device == PCI_DEVICE_ID_INTEL_915_G_0) { + for (i = intel_i830_private.gtt_entries; i < current_size->num_entries; i++) + OUTREG32(intel_i830_private.gtt, i, agp_bridge.scratch_page); + } else { + for (i = intel_i830_private.gtt_entries; i < current_size->num_entries; i++) + OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge.scratch_page); + } + } return (0); } static void intel_i830_cleanup(void) { + if (agp_bridge.dev->device == PCI_DEVICE_ID_INTEL_915_G_0) + iounmap((void *)intel_i830_private.gtt); + iounmap((void *) intel_i830_private.registers); } @@ -1315,9 +1441,13 @@ CACHE_FLUSH(); - for (i = 0, j = pg_start; i < mem->page_count; i++, j++) - OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (j * 4), - agp_bridge.mask_memory(mem->memory[i], mem->type)); + if (agp_bridge.dev->device == PCI_DEVICE_ID_INTEL_915_G_0) { + for (i = 0, j = pg_start; i < mem->page_count; i++, j++) + OUTREG32(intel_i830_private.gtt, j, agp_bridge.mask_memory(mem->memory[i], mem->type)); + } else { + for (i = 0, j = pg_start; i < mem->page_count; i++, j++) + OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (j * 4),agp_bridge.mask_memory(mem->memory[i], mem->type)); + } CACHE_FLUSH(); @@ -1337,8 +1467,13 @@ return (-EINVAL); } - for (i = pg_start; i < (mem->page_count + pg_start); i++) - OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge.scratch_page); + if (agp_bridge.dev->device == PCI_DEVICE_ID_INTEL_915_G_0) { + for (i = pg_start; i < (mem->page_count + pg_start); i++) + OUTREG32(intel_i830_private.gtt, i, agp_bridge.scratch_page); + } else { + for (i = pg_start; i < (mem->page_count + pg_start); i++) + OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge.scratch_page); + } CACHE_FLUSH(); @@ -1363,24 +1498,40 @@ * aperture */ - if (pg_count != 1) return(NULL); + if (pg_count != 1 && pg_count != 4) return(NULL); - nw = agp_create_memory(1); + nw = agp_create_memory(pg_count); if (nw == NULL) return(NULL); MOD_INC_USE_COUNT; - nw->memory[0] = agp_bridge.agp_alloc_page(); - physical = nw->memory[0]; + if (pg_count == 1) + nw->memory[0] = agp_bridge.agp_alloc_page(); + else { + /* kludge to get 4 physical pages for ARGB cursor */ + nw->memory[0] = i830_alloc_pages(); + nw->memory[1] = nw->memory[0] + PAGE_SIZE; + nw->memory[2] = nw->memory[1] + PAGE_SIZE; + nw->memory[3] = nw->memory[2] + PAGE_SIZE; + } + if (nw->memory[0] == 0) { /* free this structure */ agp_free_memory(nw); return(NULL); } + physical = nw->memory[0]; + nw->memory[0] = virt_to_phys((void *) nw->memory[0]); - nw->page_count = 1; - nw->num_scratch_pages = 1; + if (pg_count == 4) { + /* kludge to enable 4 physical pages for ARGB cursor */ + nw->memory[1] = virt_to_phys((void *) nw->memory[1]); + nw->memory[2] = virt_to_phys((void *) nw->memory[2]); + nw->memory[3] = virt_to_phys((void *) nw->memory[3]); + } + nw->page_count = pg_count; + nw->num_scratch_pages = pg_count; nw->type = AGP_PHYS_MEMORY; nw->physical = virt_to_phys((void *) physical); return(nw); @@ -3447,9 +3598,9 @@ for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { tmp = agp_bridge.mask_memory(mem->memory[i], mem->type); - BUG_ON(tmp & 0xffffff0000000ffc); - pte = (tmp & 0x000000ff00000000) >> 28; - pte |=(tmp & 0x00000000fffff000); + BUG_ON(tmp & 0xffffff0000000ffcULL); + pte = (tmp & 0x000000ff00000000ULL) >> 28; + pte |=(tmp & 0x00000000fffff000ULL); pte |= 1<<1|1<<0; agp_bridge.gatt_table[j] = pte; @@ -6112,6 +6263,13 @@ "865G", intel_845_setup }, + { PCI_DEVICE_ID_INTEL_915_G_0, + PCI_VENDOR_ID_INTEL, + INTEL_I915_G, + "Intel(R)", + "915G", + intel_845_setup }, + { PCI_DEVICE_ID_INTEL_840_0, PCI_VENDOR_ID_INTEL, INTEL_I840, @@ -6835,6 +6993,34 @@ "865G Chipset.\n"); agp_bridge.type = INTEL_I810; return intel_i830_setup(i810_dev); + + case PCI_DEVICE_ID_INTEL_915_G_0: + i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_915_G_1, NULL); + if(i810_dev && PCI_FUNC(i810_dev->devfn) != 0) { + i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_915_G_1, i810_dev); + } + + if (i810_dev == NULL) { + /* + * We probably have a 915G chipset + * with an external graphics + * card. It will be initialized later + */ + printk(KERN_ERR PFX "Detected an " + "Intel(R) 915G, but could not" + " find the" + " secondary device. Assuming a " + "non-integrated video card.\n"); + agp_bridge.type = INTEL_I915_G; + break; + } + printk(KERN_INFO PFX "Detected an Intel(R) " + "915G Chipset.\n"); + agp_bridge.type = INTEL_I810; + return intel_i830_setup(i810_dev); + default: break; } diff -Nru a/drivers/char/applicom.c b/drivers/char/applicom.c --- a/drivers/char/applicom.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/char/applicom.c 2004-08-14 12:02:30 -07:00 @@ -222,6 +222,7 @@ if (!RamIO) { printk(KERN_INFO "ac.o: Failed to ioremap PCI memory space at 0x%lx\n", PCI_BASE_ADDRESS(dev)); + pci_disable_device(dev); return -EIO; } @@ -233,12 +234,14 @@ (unsigned long)RamIO,0))) { printk(KERN_INFO "ac.o: PCI Applicom device doesn't have correct signature.\n"); iounmap(RamIO); + pci_disable_device(dev); continue; } if (request_irq(dev->irq, &ac_interrupt, SA_SHIRQ, "Applicom PCI", &dummy)) { printk(KERN_INFO "Could not allocate IRQ %d for PCI Applicom device.\n", dev->irq); iounmap(RamIO); + pci_disable_device(dev); apbs[boardno - 1].RamIO = 0; continue; } @@ -265,12 +268,6 @@ /* Now try the specified ISA cards */ -#warning "LEAK" - RamIO = ioremap(mem, LEN_RAM_IO * MAX_ISA_BOARD); - - if (!RamIO) - printk(KERN_INFO "ac.o: Failed to ioremap ISA memory space at 0x%lx\n", mem); - for (i = 0; i < MAX_ISA_BOARD; i++) { RamIO = ioremap(mem + (LEN_RAM_IO * i), LEN_RAM_IO); @@ -293,7 +290,8 @@ iounmap((void *) RamIO); apbs[boardno - 1].RamIO = 0; } - apbs[boardno - 1].irq = irq; + else + apbs[boardno - 1].irq = irq; } else apbs[boardno - 1].irq = 0; @@ -368,7 +366,7 @@ if (count != sizeof(struct st_ram_io) + sizeof(struct mailbox)) { static int warncount = 5; if (warncount) { - printk(KERN_INFO "Hmmm. write() of Applicom card, length %d != expected %d\n", + printk(KERN_INFO "Hmmm. write() of Applicom card, length %zd != expected %zd\n", count, sizeof(struct st_ram_io) + sizeof(struct mailbox)); warncount--; } @@ -476,18 +474,17 @@ return 0; } -static int do_ac_read(int IndexCard, char *buf) +static int do_ac_read(int IndexCard, char *buf, + struct st_ram_io *st_loc, struct mailbox *mailbox) { - struct st_ram_io st_loc; - struct mailbox tmpmailbox; /* bounce buffer - can't copy to user space with cli() */ unsigned long from = (unsigned long)apbs[IndexCard].RamIO + RAM_TO_PC; - unsigned char *to = (unsigned char *)&tmpmailbox; + unsigned char *to = (unsigned char *)&mailbox; #ifdef DEBUG int c; #endif - st_loc.tic_owner_to_pc = readb(apbs[IndexCard].RamIO + TIC_OWNER_TO_PC); - st_loc.numcard_owner_to_pc = readb(apbs[IndexCard].RamIO + NUMCARD_OWNER_TO_PC); + st_loc->tic_owner_to_pc = readb(apbs[IndexCard].RamIO + TIC_OWNER_TO_PC); + st_loc->numcard_owner_to_pc = readb(apbs[IndexCard].RamIO + NUMCARD_OWNER_TO_PC); { @@ -510,32 +507,24 @@ printk("Read from applicom card #%d. struct st_ram_io follows:", NumCard); for (c = 0; c < sizeof(struct st_ram_io);) { - printk("\n%5.5X: %2.2X", c, ((unsigned char *) &st_loc)[c]); + printk("\n%5.5X: %2.2X", c, ((unsigned char *)st_loc)[c]); for (c++; c % 8 && c < sizeof(struct st_ram_io); c++) { - printk(" %2.2X", ((unsigned char *) &st_loc)[c]); + printk(" %2.2X", ((unsigned char *)st_loc)[c]); } } printk("\nstruct mailbox follows:"); for (c = 0; c < sizeof(struct mailbox);) { - printk("\n%5.5X: %2.2X", c, ((unsigned char *) &tmpmailbox)[c]); + printk("\n%5.5X: %2.2X", c, ((unsigned char *)mailbox)[c]); for (c++; c % 8 && c < sizeof(struct mailbox); c++) { - printk(" %2.2X", ((unsigned char *) &tmpmailbox)[c]); + printk(" %2.2X", ((unsigned char *)mailbox)[c]); } } printk("\n"); #endif - -#warning "Je suis stupide. DW. - copy*user in cli" - - if (copy_to_user(buf, &st_loc, sizeof(struct st_ram_io))) - return -EFAULT; - if (copy_to_user(&buf[sizeof(struct st_ram_io)], &tmpmailbox, sizeof(struct mailbox))) - return -EFAULT; - return (sizeof(struct st_ram_io) + sizeof(struct mailbox)); } @@ -551,7 +540,7 @@ #endif /* No need to ratelimit this. Only root can trigger it anyway */ if (count != sizeof(struct st_ram_io) + sizeof(struct mailbox)) { - printk( KERN_WARNING "Hmmm. read() of Applicom card, length %d != expected %d\n", + printk( KERN_WARNING "Hmmm. read() of Applicom card, length %zd != expected %zd\n", count,sizeof(struct st_ram_io) + sizeof(struct mailbox)); return -EINVAL; } @@ -570,11 +559,19 @@ tmp = readb(apbs[i].RamIO + DATA_TO_PC_READY); if (tmp == 2) { + struct st_ram_io st_loc; + struct mailbox mailbox; + /* Got a packet for us */ - ret = do_ac_read(i, buf); + ret = do_ac_read(i, buf, &st_loc, &mailbox); spin_unlock_irqrestore(&apbs[i].mutex, flags); set_current_state(TASK_RUNNING); remove_wait_queue(&FlagSleepRec, &wait); + + if (copy_to_user(buf, &st_loc, sizeof(st_loc))) + return -EFAULT; + if (copy_to_user(buf + sizeof(st_loc), &mailbox, sizeof(mailbox))) + return -EFAULT; return tmp; } diff -Nru a/drivers/char/nwflash.c b/drivers/char/nwflash.c --- a/drivers/char/nwflash.c 2004-08-14 12:02:31 -07:00 +++ b/drivers/char/nwflash.c 2004-08-14 12:02:31 -07:00 @@ -159,7 +159,8 @@ if (ret == 0) { ret = count; *ppos = p + count; - } + } else + ret = -EFAULT; up(&nwflash_sem); } return ret; diff -Nru a/drivers/char/random.c b/drivers/char/random.c --- a/drivers/char/random.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/char/random.c 2004-08-14 12:02:30 -07:00 @@ -750,6 +750,11 @@ __u32 high; rdtsc(time, high); num ^= high; +#elif defined (__sparc_v9__) + unsigned long tick = tick_ops->get_tick(); + + time = (unsigned int) tick; + num ^= (tick >> 32UL); #else time = jiffies; #endif diff -Nru a/drivers/fc4/fc.c b/drivers/fc4/fc.c --- a/drivers/fc4/fc.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/fc4/fc.c 2004-08-14 12:02:30 -07:00 @@ -1155,3 +1155,5 @@ kfree(p); return status; } + +MODULE_LICENSE("GPL"); diff -Nru a/drivers/ide/Config.in b/drivers/ide/Config.in --- a/drivers/ide/Config.in 2004-08-14 12:02:30 -07:00 +++ b/drivers/ide/Config.in 2004-08-14 12:02:30 -07:00 @@ -12,6 +12,7 @@ dep_bool ' Use old disk-only driver on primary interface' CONFIG_BLK_DEV_HD_IDE $CONFIG_X86 define_bool CONFIG_BLK_DEV_HD $CONFIG_BLK_DEV_HD_IDE + dep_mbool ' Support for SATA (deprecated; conflicts with libata SATA driver)' CONFIG_BLK_DEV_IDE_SATA $CONFIG_BLK_DEV_IDE dep_tristate ' Include IDE/ATA-2 DISK support' CONFIG_BLK_DEV_IDEDISK $CONFIG_BLK_DEV_IDE dep_mbool ' Use multi-mode by default' CONFIG_IDEDISK_MULTI_MODE $CONFIG_BLK_DEV_IDEDISK dep_mbool ' Auto-Geometry Resizing support' CONFIG_IDEDISK_STROKE $CONFIG_BLK_DEV_IDEDISK diff -Nru a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c --- a/drivers/ide/pci/amd74xx.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/ide/pci/amd74xx.c 2004-08-14 12:02:30 -07:00 @@ -70,11 +70,7 @@ { PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA, 0x50, AMD_UDMA_133 }, { PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2, 0x50, AMD_UDMA_133 }, { PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, 0x50, AMD_UDMA_133 }, - { PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA, 0x50, AMD_UDMA_133 }, - { PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2, 0x50, AMD_UDMA_133 }, { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, 0x50, AMD_UDMA_133 }, - { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA, 0x50, AMD_UDMA_133 }, - { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2, 0x50, AMD_UDMA_133 }, { 0 } }; @@ -466,17 +462,17 @@ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7 }, +#ifdef CONFIG_BLK_DEV_IDE_SATA { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 }, +#endif { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10 }, +#ifdef CONFIG_BLK_DEV_IDE_SATA { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12 }, +#endif { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 17 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 18 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14 }, { 0, }, }; diff -Nru a/drivers/ide/pci/amd74xx.h b/drivers/ide/pci/amd74xx.h --- a/drivers/ide/pci/amd74xx.h 2004-08-14 12:02:30 -07:00 +++ b/drivers/ide/pci/amd74xx.h 2004-08-14 12:02:30 -07:00 @@ -188,52 +188,8 @@ }, { /* 14 */ .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA, - .name = "NFORCE-CK804-SATA", - .init_chipset = init_chipset_amd74xx, - .init_hwif = init_hwif_amd74xx, - .channels = 2, - .autodma = AUTODMA, - .enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, - .bootable = ON_BOARD, - }, - { /* 15 */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2, - .name = "NFORCE-CK804-SATA2", - .init_chipset = init_chipset_amd74xx, - .init_hwif = init_hwif_amd74xx, - .channels = 2, - .autodma = AUTODMA, - .enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, - .bootable = ON_BOARD, - }, - { /* 16 */ - .vendor = PCI_VENDOR_ID_NVIDIA, .device = PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, .name = "NFORCE-MCP04", - .init_chipset = init_chipset_amd74xx, - .init_hwif = init_hwif_amd74xx, - .channels = 2, - .autodma = AUTODMA, - .enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, - .bootable = ON_BOARD, - }, - { /* 17 */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA, - .name = "NFORCE-MCP04-SATA", - .init_chipset = init_chipset_amd74xx, - .init_hwif = init_hwif_amd74xx, - .channels = 2, - .autodma = AUTODMA, - .enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, - .bootable = ON_BOARD, - }, - { /* 18 */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2, - .name = "NFORCE-MCP04-SATA2", .init_chipset = init_chipset_amd74xx, .init_hwif = init_hwif_amd74xx, .channels = 2, diff -Nru a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c --- a/drivers/ide/pci/piix.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/ide/pci/piix.c 2004-08-14 12:02:30 -07:00 @@ -49,9 +49,9 @@ * pci_read_config_word(HWIF(drive)->pci_dev, 0x40, ®40); * pci_read_config_word(HWIF(drive)->pci_dev, 0x42, ®42); * pci_read_config_word(HWIF(drive)->pci_dev, 0x44, ®44); - * pci_read_config_word(HWIF(drive)->pci_dev, 0x48, ®48); + * pci_read_config_byte(HWIF(drive)->pci_dev, 0x48, ®48); * pci_read_config_word(HWIF(drive)->pci_dev, 0x4a, ®4a); - * pci_read_config_word(HWIF(drive)->pci_dev, 0x54, ®54); + * pci_read_config_byte(HWIF(drive)->pci_dev, 0x54, ®54); * * Documentation * Publically available from Intel web site. Errata documentation @@ -433,15 +433,14 @@ int w_flag = 0x10 << drive->dn; int u_speed = 0; int sitre; - u16 reg4042, reg44, reg48, reg4a, reg54; - u8 reg55; + u16 reg4042, reg4a; + u8 reg48, reg54, reg55; pci_read_config_word(dev, maslave, ®4042); sitre = (reg4042 & 0x4000) ? 1 : 0; - pci_read_config_word(dev, 0x44, ®44); - pci_read_config_word(dev, 0x48, ®48); + pci_read_config_byte(dev, 0x48, ®48); pci_read_config_word(dev, 0x4a, ®4a); - pci_read_config_word(dev, 0x54, ®54); + pci_read_config_byte(dev, 0x54, ®54); pci_read_config_byte(dev, 0x55, ®55); switch(speed) { @@ -463,30 +462,26 @@ if (speed >= XFER_UDMA_0) { if (!(reg48 & u_flag)) - pci_write_config_word(dev, 0x48, 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 & u_speed)) { - pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); - pci_write_config_word(dev, 0x4a, reg4a|u_speed); - } + 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_word(dev, 0x54, reg54|v_flag); - } - } else { - pci_write_config_word(dev, 0x54, reg54 & ~v_flag); - } + 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_word(dev, 0x48, 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_word(dev, 0x54, 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); } @@ -882,7 +877,9 @@ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_11,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15}, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_11, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16}, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_10,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 17}, +#ifdef CONFIG_BLK_DEV_IDE_SATA { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 18}, +#endif { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 19}, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 20}, { 0, }, diff -Nru a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c --- a/drivers/ide/pci/siimage.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/ide/pci/siimage.c 2004-08-14 12:02:30 -07:00 @@ -1194,8 +1194,10 @@ static struct pci_device_id siimage_pci_tbl[] __devinitdata = { { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_680, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, +#ifdef CONFIG_BLK_DEV_IDE_SATA { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_1210SA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, +#endif { 0, }, }; diff -Nru a/drivers/isdn/pcbit/callbacks.c b/drivers/isdn/pcbit/callbacks.c --- a/drivers/isdn/pcbit/callbacks.c 2004-08-14 12:02:31 -07:00 +++ b/drivers/isdn/pcbit/callbacks.c 2004-08-14 12:02:31 -07:00 @@ -3,7 +3,7 @@ * * Copyright (C) 1996 Universidade de Lisboa * - * Written by Pedro Roque Marques (roque@di.fc.ul.pt) + * Written by Pedro Roque Marques (pedro_m@yahoo.com) * * This software may be used and distributed according to the terms of * the GNU General Public License, incorporated herein by reference. diff -Nru a/drivers/isdn/pcbit/callbacks.h b/drivers/isdn/pcbit/callbacks.h --- a/drivers/isdn/pcbit/callbacks.h 2004-08-14 12:02:30 -07:00 +++ b/drivers/isdn/pcbit/callbacks.h 2004-08-14 12:02:30 -07:00 @@ -3,7 +3,7 @@ * * Copyright (C) 1996 Universidade de Lisboa * - * Written by Pedro Roque Marques (roque@di.fc.ul.pt) + * Written by Pedro Roque Marques (pedro_m@yahoo.com) * * This software may be used and distributed according to the terms of * the GNU General Public License, incorporated herein by reference. diff -Nru a/drivers/isdn/pcbit/capi.c b/drivers/isdn/pcbit/capi.c --- a/drivers/isdn/pcbit/capi.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/isdn/pcbit/capi.c 2004-08-14 12:02:30 -07:00 @@ -4,7 +4,7 @@ * * Copyright (C) 1996 Universidade de Lisboa * - * Written by Pedro Roque Marques (roque@di.fc.ul.pt) + * Written by Pedro Roque Marques (pedro_m@yahoo.com) * * This software may be used and distributed according to the terms of * the GNU General Public License, incorporated herein by reference. diff -Nru a/drivers/isdn/pcbit/capi.h b/drivers/isdn/pcbit/capi.h --- a/drivers/isdn/pcbit/capi.h 2004-08-14 12:02:30 -07:00 +++ b/drivers/isdn/pcbit/capi.h 2004-08-14 12:02:30 -07:00 @@ -3,7 +3,7 @@ * * Copyright (C) 1996 Universidade de Lisboa * - * Written by Pedro Roque Marques (roque@di.fc.ul.pt) + * Written by Pedro Roque Marques (pedro_m@yahoo.com) * * This software may be used and distributed according to the terms of * the GNU General Public License, incorporated herein by reference. diff -Nru a/drivers/isdn/pcbit/drv.c b/drivers/isdn/pcbit/drv.c --- a/drivers/isdn/pcbit/drv.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/isdn/pcbit/drv.c 2004-08-14 12:02:30 -07:00 @@ -3,7 +3,7 @@ * * Copyright (C) 1996 Universidade de Lisboa * - * Written by Pedro Roque Marques (roque@di.fc.ul.pt) + * Written by Pedro Roque Marques (pedro_m@yahoo.com) * * This software may be used and distributed according to the terms of * the GNU General Public License, incorporated herein by reference. diff -Nru a/drivers/isdn/pcbit/edss1.c b/drivers/isdn/pcbit/edss1.c --- a/drivers/isdn/pcbit/edss1.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/isdn/pcbit/edss1.c 2004-08-14 12:02:30 -07:00 @@ -4,7 +4,7 @@ * * Copyright (C) 1996 Universidade de Lisboa * - * Written by Pedro Roque Marques (roque@di.fc.ul.pt) + * Written by Pedro Roque Marques (pedro_m@yahoo.com) * * This software may be used and distributed according to the terms of * the GNU General Public License, incorporated herein by reference. diff -Nru a/drivers/isdn/pcbit/edss1.h b/drivers/isdn/pcbit/edss1.h --- a/drivers/isdn/pcbit/edss1.h 2004-08-14 12:02:30 -07:00 +++ b/drivers/isdn/pcbit/edss1.h 2004-08-14 12:02:30 -07:00 @@ -3,7 +3,7 @@ * * Copyright (C) 1996 Universidade de Lisboa * - * Written by Pedro Roque Marques (roque@di.fc.ul.pt) + * Written by Pedro Roque Marques (pedro_m@yahoo.com) * * This software may be used and distributed according to the terms of * the GNU General Public License, incorporated herein by reference. diff -Nru a/drivers/isdn/pcbit/layer2.c b/drivers/isdn/pcbit/layer2.c --- a/drivers/isdn/pcbit/layer2.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/isdn/pcbit/layer2.c 2004-08-14 12:02:30 -07:00 @@ -3,7 +3,7 @@ * * Copyright (C) 1996 Universidade de Lisboa * - * Written by Pedro Roque Marques (roque@di.fc.ul.pt) + * Written by Pedro Roque Marques (pedro_m@yahoo.com) * * This software may be used and distributed according to the terms of * the GNU General Public License, incorporated herein by reference. diff -Nru a/drivers/isdn/pcbit/layer2.h b/drivers/isdn/pcbit/layer2.h --- a/drivers/isdn/pcbit/layer2.h 2004-08-14 12:02:30 -07:00 +++ b/drivers/isdn/pcbit/layer2.h 2004-08-14 12:02:30 -07:00 @@ -3,7 +3,7 @@ * * Copyright (C) 1996 Universidade de Lisboa * - * Written by Pedro Roque Marques (roque@di.fc.ul.pt) + * Written by Pedro Roque Marques (pedro_m@yahoo.com) * * This software may be used and distributed according to the terms of * the GNU General Public License, incorporated herein by reference. diff -Nru a/drivers/isdn/pcbit/module.c b/drivers/isdn/pcbit/module.c --- a/drivers/isdn/pcbit/module.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/isdn/pcbit/module.c 2004-08-14 12:02:30 -07:00 @@ -3,7 +3,7 @@ * * Copyright (C) 1996 Universidade de Lisboa * - * Written by Pedro Roque Marques (roque@di.fc.ul.pt) + * Written by Pedro Roque Marques (pedro_m@yahoo.com) * * This software may be used and distributed according to the terms of * the GNU General Public License, incorporated herein by reference. diff -Nru a/drivers/isdn/pcbit/pcbit.h b/drivers/isdn/pcbit/pcbit.h --- a/drivers/isdn/pcbit/pcbit.h 2004-08-14 12:02:30 -07:00 +++ b/drivers/isdn/pcbit/pcbit.h 2004-08-14 12:02:30 -07:00 @@ -3,7 +3,7 @@ * * Copyright (C) 1996 Universidade de Lisboa * - * Written by Pedro Roque Marques (roque@di.fc.ul.pt) + * Written by Pedro Roque Marques (pedro_m@yahoo.com) * * This software may be used and distributed according to the terms of * the GNU General Public License, incorporated herein by reference. diff -Nru a/drivers/message/i2o/i2o_pci.c b/drivers/message/i2o/i2o_pci.c --- a/drivers/message/i2o/i2o_pci.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/message/i2o/i2o_pci.c 2004-08-14 12:02:30 -07:00 @@ -390,4 +390,3 @@ MODULE_PARM_DESC(dpt, "Set this if you want to drive DPT cards normally handled by dpt_i2o"); module_init(i2o_pci_core_attach); module_exit(i2o_pci_core_detach); - \ No newline at end of file diff -Nru a/drivers/mtd/maps/amd76xrom.c b/drivers/mtd/maps/amd76xrom.c --- a/drivers/mtd/maps/amd76xrom.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/mtd/maps/amd76xrom.c 2004-08-14 12:02:30 -07:00 @@ -178,7 +178,7 @@ iounmap((void *)(info->window_addr)); err_out_free_mmio_region: release_mem_region(window->start, window->size); -err_out_none: +//err_out_none: return -ENODEV; } diff -Nru a/drivers/net/fc/iph5526.c b/drivers/net/fc/iph5526.c --- a/drivers/net/fc/iph5526.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/net/fc/iph5526.c 2004-08-14 12:02:30 -07:00 @@ -689,8 +689,8 @@ prev_IMQ_index = current_IMQ_index; } } /*end of for loop*/ - return; LEAVE("tachyon_interrupt"); + return; } @@ -2933,7 +2933,7 @@ { struct fc_info *fi = (struct fc_info*)dev->priv; printk(KERN_WARNING "%s: timed out on send.\n", dev->name); - fi->fc_stats.rx_dropped++; + fi->fc_stats.tx_dropped++; dev->trans_start = jiffies; netif_wake_queue(dev); } @@ -2976,7 +2976,7 @@ fi->fc_stats.tx_packets++; } else - fi->fc_stats.rx_dropped++; + fi->fc_stats.tx_dropped++; dev->trans_start = jiffies; /* We free up the IP buffers in the OCI_interrupt handler. * status == 0 implies that the frame was not transmitted. So the @@ -3374,8 +3374,8 @@ q = q->next; } DPRINTK1("Port Name does not match. Txing LOGO."); - return 0; LEAVE("validate_login"); + return 0; } static void add_to_address_cache(struct fc_info *fi, u_int *base_ptr) @@ -3758,8 +3758,10 @@ sprintf(fi->name, "fc%d", count); host = scsi_register(tmpt, sizeof(struct iph5526_hostdata)); - if(host==NULL) + if(host==NULL) { + kfree(fc[count]); return no_of_hosts; + } hostdata = (struct iph5526_hostdata *)host->hostdata; memset(hostdata, 0 , sizeof(struct iph5526_hostdata)); diff -Nru a/drivers/net/irda/ma600.c b/drivers/net/irda/ma600.c --- a/drivers/net/irda/ma600.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/net/irda/ma600.c 2004-08-14 12:02:30 -07:00 @@ -48,7 +48,7 @@ #undef IRDA_DEBUG #define IRDA_DEBUG(n, args...) (printk(KERN_DEBUG args)) - #undef ASSERT(expr, func) + #undef ASSERT #define ASSERT(expr, func) \ if(!(expr)) { \ printk( "Assertion failed! %s,%s,%s,line=%d\n",\ diff -Nru a/drivers/net/sungem.c b/drivers/net/sungem.c --- a/drivers/net/sungem.c 2004-08-14 12:02:31 -07:00 +++ b/drivers/net/sungem.c 2004-08-14 12:02:31 -07:00 @@ -2920,7 +2920,7 @@ */ if (pdev->vendor == PCI_VENDOR_ID_SUN && pdev->device == PCI_DEVICE_ID_SUN_GEM && - !pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff)) { + !pci_set_dma_mask(pdev, (u64) 0xffffffffffffffffULL)) { pci_using_dac = 1; } else { err = pci_set_dma_mask(pdev, (u64) 0xffffffff); diff -Nru a/drivers/net/sungem.h b/drivers/net/sungem.h --- a/drivers/net/sungem.h 2004-08-14 12:02:30 -07:00 +++ b/drivers/net/sungem.h 2004-08-14 12:02:30 -07:00 @@ -805,14 +805,14 @@ u64 buffer; }; -#define TXDCTRL_BUFSZ 0x0000000000007fff /* Buffer Size */ -#define TXDCTRL_CSTART 0x00000000001f8000 /* CSUM Start Offset */ -#define TXDCTRL_COFF 0x000000001fe00000 /* CSUM Stuff Offset */ -#define TXDCTRL_CENAB 0x0000000020000000 /* CSUM Enable */ -#define TXDCTRL_EOF 0x0000000040000000 /* End of Frame */ -#define TXDCTRL_SOF 0x0000000080000000 /* Start of Frame */ -#define TXDCTRL_INTME 0x0000000100000000 /* "Interrupt Me" */ -#define TXDCTRL_NOCRC 0x0000000200000000 /* No CRC Present */ +#define TXDCTRL_BUFSZ 0x0000000000007fffULL /* Buffer Size */ +#define TXDCTRL_CSTART 0x00000000001f8000ULL /* CSUM Start Offset */ +#define TXDCTRL_COFF 0x000000001fe00000ULL /* CSUM Stuff Offset */ +#define TXDCTRL_CENAB 0x0000000020000000ULL /* CSUM Enable */ +#define TXDCTRL_EOF 0x0000000040000000ULL /* End of Frame */ +#define TXDCTRL_SOF 0x0000000080000000ULL /* Start of Frame */ +#define TXDCTRL_INTME 0x0000000100000000ULL /* "Interrupt Me" */ +#define TXDCTRL_NOCRC 0x0000000200000000ULL /* No CRC Present */ /* GEM requires that RX descriptors are provided four at a time, * aligned. Also, the RX ring may not wrap around. This means that @@ -840,13 +840,13 @@ u64 buffer; }; -#define RXDCTRL_TCPCSUM 0x000000000000ffff /* TCP Pseudo-CSUM */ -#define RXDCTRL_BUFSZ 0x000000007fff0000 /* Buffer Size */ -#define RXDCTRL_OWN 0x0000000080000000 /* GEM owns this entry */ -#define RXDCTRL_HASHVAL 0x0ffff00000000000 /* Hash Value */ -#define RXDCTRL_HPASS 0x1000000000000000 /* Passed Hash Filter */ -#define RXDCTRL_ALTMAC 0x2000000000000000 /* Matched ALT MAC */ -#define RXDCTRL_BAD 0x4000000000000000 /* Frame has bad CRC */ +#define RXDCTRL_TCPCSUM 0x000000000000ffffULL /* TCP Pseudo-CSUM */ +#define RXDCTRL_BUFSZ 0x000000007fff0000ULL /* Buffer Size */ +#define RXDCTRL_OWN 0x0000000080000000ULL /* GEM owns this entry */ +#define RXDCTRL_HASHVAL 0x0ffff00000000000ULL /* Hash Value */ +#define RXDCTRL_HPASS 0x1000000000000000ULL /* Passed Hash Filter */ +#define RXDCTRL_ALTMAC 0x2000000000000000ULL /* Matched ALT MAC */ +#define RXDCTRL_BAD 0x4000000000000000ULL /* Frame has bad CRC */ #define RXDCTRL_FRESH(gp) \ ((((RX_BUF_ALLOC_SIZE(gp) - RX_OFFSET) << 16) & RXDCTRL_BUFSZ) | \ diff -Nru a/drivers/net/wan/pc300_tty.c b/drivers/net/wan/pc300_tty.c --- a/drivers/net/wan/pc300_tty.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/net/wan/pc300_tty.c 2004-08-14 12:02:30 -07:00 @@ -702,7 +702,7 @@ if (cpc_tty->tty && (cpc_tty->tty->ldisc.receive_buf)) { CPC_TTY_DBG("%s: call line disc. receive_buf\n",cpc_tty->name); - cpc_tty->tty->ldisc.receive_buf(cpc_tty->tty, buf->data, + cpc_tty->tty->ldisc.receive_buf(cpc_tty->tty, (const unsigned char *)buf->data, &flags, buf->size); } cpc_tty->buf_rx.first = cpc_tty->buf_rx.first->next; diff -Nru a/drivers/net/wireless/Config.in b/drivers/net/wireless/Config.in --- a/drivers/net/wireless/Config.in 2004-08-14 12:02:30 -07:00 +++ b/drivers/net/wireless/Config.in 2004-08-14 12:02:30 -07:00 @@ -27,6 +27,15 @@ dep_tristate ' Atmel at76c502/at76c504 PCMCIA cards' CONFIG_PCMCIA_ATMEL $CONFIG_FW_LOADER fi +# If PCI enabled, allow for prism54 driver. CONFIG_FW_LOADER required +comment 'Prism54 PCI/PCMCIA GT/Duette Driver - 802.11(a/b/g)' +dep_tristate 'Intersil Prism GT/Duette/Indigo PCI/PCMCIA' CONFIG_PRISM54 $CONFIG_EXPERIMENTAL $CONFIG_PCI $CONFIG_HOTPLUG +if [ "$CONFIG_PRISM54" != "n" ]; then + if [ "$CONFIG_FW_LOADER" != "y" ]; then + define_tristate CONFIG_FW_LOADER $CONFIG_PRISM54 + fi +fi + # yes, this works even when no drivers are selected if [ "$CONFIG_ISA" = "y" -o "$CONFIG_PCI" = "y" -o \ "$CONFIG_ALL_PPC" = "y" -o "$CONFIG_PCMCIA" != "n" ]; then diff -Nru a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile --- a/drivers/net/wireless/Makefile 2004-08-14 12:02:31 -07:00 +++ b/drivers/net/wireless/Makefile 2004-08-14 12:02:31 -07:00 @@ -25,4 +25,9 @@ obj-$(CONFIG_AIRO_CS) += airo_cs.o airo.o obj-$(CONFIG_PCMCIA_ATMEL) += atmel_cs.o atmel.o +ifeq ($(CONFIG_PRISM54),y) +obj-$(CONFIG_PRISM54) += prism54/prism54.o +endif +subdir-$(CONFIG_PRISM54) += prism54 + include $(TOPDIR)/Rules.make diff -Nru a/drivers/net/wireless/prism54/Makefile b/drivers/net/wireless/prism54/Makefile --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/net/wireless/prism54/Makefile 2004-08-14 12:02:31 -07:00 @@ -0,0 +1,12 @@ + +O_TARGET := prism54.o + +EXTRA_CFLAGS += -DPRISM54_COMPAT24 + +obj-y := isl_38xx.o islpci_dev.o islpci_eth.o \ + islpci_mgt.o islpci_hotplug.o isl_ioctl.o \ + oid_mgt.o + +obj-m += prism54.o + +include $(TOPDIR)/Rules.make diff -Nru a/drivers/net/wireless/prism54/isl_38xx.c b/drivers/net/wireless/prism54/isl_38xx.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/net/wireless/prism54/isl_38xx.c 2004-08-14 12:02:31 -07:00 @@ -0,0 +1,267 @@ +/* + * + * Copyright (C) 2002 Intersil Americas Inc. + * Copyright (C) 2003-2004 Luis R. Rodriguez _ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#define __KERNEL_SYSCALLS__ + +#include +#include +#include +#include + +#include +#include + +#include "prismcompat.h" +#include "isl_38xx.h" +#include "islpci_dev.h" +#include "islpci_mgt.h" + +/****************************************************************************** + Device Interface & Control functions +******************************************************************************/ + +/** + * isl38xx_disable_interrupts - disable all interrupts + * @device: pci memory base address + * + * Instructs the device to disable all interrupt reporting by asserting + * the IRQ line. New events may still show up in the interrupt identification + * register located at offset %ISL38XX_INT_IDENT_REG. + */ +void +isl38xx_disable_interrupts(void *device) +{ + isl38xx_w32_flush(device, 0x00000000, ISL38XX_INT_EN_REG); + udelay(ISL38XX_WRITEIO_DELAY); +} + +void +isl38xx_handle_sleep_request(isl38xx_control_block *control_block, + int *powerstate, void *device_base) +{ + /* device requests to go into sleep mode + * check whether the transmit queues for data and management are empty */ + if (isl38xx_in_queue(control_block, ISL38XX_CB_TX_DATA_LQ)) + /* data tx queue not empty */ + return; + + if (isl38xx_in_queue(control_block, ISL38XX_CB_TX_MGMTQ)) + /* management tx queue not empty */ + return; + + /* check also whether received frames are pending */ + if (isl38xx_in_queue(control_block, ISL38XX_CB_RX_DATA_LQ)) + /* data rx queue not empty */ + return; + + if (isl38xx_in_queue(control_block, ISL38XX_CB_RX_MGMTQ)) + /* management rx queue not empty */ + return; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "Device going to sleep mode\n"); +#endif + + /* all queues are empty, allow the device to go into sleep mode */ + *powerstate = ISL38XX_PSM_POWERSAVE_STATE; + + /* assert the Sleep interrupt in the Device Interrupt Register */ + isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_SLEEP, + ISL38XX_DEV_INT_REG); + udelay(ISL38XX_WRITEIO_DELAY); +} + +void +isl38xx_handle_wakeup(isl38xx_control_block *control_block, + int *powerstate, void *device_base) +{ + /* device is in active state, update the powerstate flag */ + *powerstate = ISL38XX_PSM_ACTIVE_STATE; + + /* now check whether there are frames pending for the card */ + if (!isl38xx_in_queue(control_block, ISL38XX_CB_TX_DATA_LQ) + && !isl38xx_in_queue(control_block, ISL38XX_CB_TX_MGMTQ)) + return; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_ANYTHING, "Wake up handler trigger the device\n"); +#endif + + /* either data or management transmit queue has a frame pending + * trigger the device by setting the Update bit in the Device Int reg */ + isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_UPDATE, + ISL38XX_DEV_INT_REG); + udelay(ISL38XX_WRITEIO_DELAY); +} + +void +isl38xx_trigger_device(int asleep, void *device_base) +{ + struct timeval current_time; + u32 reg, counter = 0; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, "isl38xx trigger device\n"); +#endif + + /* check whether the device is in power save mode */ + if (asleep) { + /* device is in powersave, trigger the device for wakeup */ +#if VERBOSE > SHOW_ERROR_MESSAGES + do_gettimeofday(¤t_time); + DEBUG(SHOW_TRACING, "%08li.%08li Device wakeup triggered\n", + current_time.tv_sec, current_time.tv_usec); +#endif + + DEBUG(SHOW_TRACING, "%08li.%08li Device register read %08x\n", + current_time.tv_sec, current_time.tv_usec, + readl(device_base + ISL38XX_CTRL_STAT_REG)); + udelay(ISL38XX_WRITEIO_DELAY); + + if (reg = readl(device_base + ISL38XX_INT_IDENT_REG), + reg == 0xabadface) { +#if VERBOSE > SHOW_ERROR_MESSAGES + do_gettimeofday(¤t_time); + DEBUG(SHOW_TRACING, + "%08li.%08li Device register abadface\n", + current_time.tv_sec, current_time.tv_usec); +#endif + /* read the Device Status Register until Sleepmode bit is set */ + while (reg = readl(device_base + ISL38XX_CTRL_STAT_REG), + (reg & ISL38XX_CTRL_STAT_SLEEPMODE) == 0) { + udelay(ISL38XX_WRITEIO_DELAY); + counter++; + } + + DEBUG(SHOW_TRACING, + "%08li.%08li Device register read %08x\n", + current_time.tv_sec, current_time.tv_usec, + readl(device_base + ISL38XX_CTRL_STAT_REG)); + udelay(ISL38XX_WRITEIO_DELAY); + +#if VERBOSE > SHOW_ERROR_MESSAGES + do_gettimeofday(¤t_time); + DEBUG(SHOW_TRACING, + "%08li.%08li Device asleep counter %i\n", + current_time.tv_sec, current_time.tv_usec, + counter); +#endif + } + /* assert the Wakeup interrupt in the Device Interrupt Register */ + isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_WAKEUP, + ISL38XX_DEV_INT_REG); + udelay(ISL38XX_WRITEIO_DELAY); + + /* perform another read on the Device Status Register */ + reg = readl(device_base + ISL38XX_CTRL_STAT_REG); + udelay(ISL38XX_WRITEIO_DELAY); + +#if VERBOSE > SHOW_ERROR_MESSAGES + do_gettimeofday(¤t_time); + DEBUG(SHOW_TRACING, "%08li.%08li Device register read %08x\n", + current_time.tv_sec, current_time.tv_usec, reg); +#endif + } else { + /* device is (still) awake */ +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "Device is in active state\n"); +#endif + /* trigger the device by setting the Update bit in the Device Int reg */ + + isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_UPDATE, + ISL38XX_DEV_INT_REG); + udelay(ISL38XX_WRITEIO_DELAY); + } +} + +void +isl38xx_interface_reset(void *device_base, dma_addr_t host_address) +{ + u32 reg; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, "isl38xx_interface_reset \n"); +#endif + + /* load the address of the control block in the device */ + isl38xx_w32_flush(device_base, host_address, ISL38XX_CTRL_BLK_BASE_REG); + udelay(ISL38XX_WRITEIO_DELAY); + + /* set the reset bit in the Device Interrupt Register */ + isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_RESET, + ISL38XX_DEV_INT_REG); + udelay(ISL38XX_WRITEIO_DELAY); + + /* enable the interrupt for detecting initialization */ + + /* Note: Do not enable other interrupts here. We want the + * device to have come up first 100% before allowing any other + * interrupts. */ + reg = ISL38XX_INT_IDENT_INIT; + + isl38xx_w32_flush(device_base, reg, ISL38XX_INT_EN_REG); + udelay(ISL38XX_WRITEIO_DELAY); /* allow complete full reset */ +} + +void +isl38xx_enable_common_interrupts(void *device_base) { + u32 reg; + reg = ( ISL38XX_INT_IDENT_UPDATE | + ISL38XX_INT_IDENT_SLEEP | ISL38XX_INT_IDENT_WAKEUP); + isl38xx_w32_flush(device_base, reg, ISL38XX_INT_EN_REG); + udelay(ISL38XX_WRITEIO_DELAY); +} + +int +isl38xx_in_queue(isl38xx_control_block *cb, int queue) +{ + const s32 delta = (le32_to_cpu(cb->driver_curr_frag[queue]) - + le32_to_cpu(cb->device_curr_frag[queue])); + + /* determine the amount of fragments in the queue depending on the type + * of the queue, either transmit or receive */ + + BUG_ON(delta < 0); /* driver ptr must be ahead of device ptr */ + + switch (queue) { + /* send queues */ + case ISL38XX_CB_TX_MGMTQ: + BUG_ON(delta > ISL38XX_CB_MGMT_QSIZE); + case ISL38XX_CB_TX_DATA_LQ: + case ISL38XX_CB_TX_DATA_HQ: + BUG_ON(delta > ISL38XX_CB_TX_QSIZE); + return delta; + break; + + /* receive queues */ + case ISL38XX_CB_RX_MGMTQ: + BUG_ON(delta > ISL38XX_CB_MGMT_QSIZE); + return ISL38XX_CB_MGMT_QSIZE - delta; + break; + + case ISL38XX_CB_RX_DATA_LQ: + case ISL38XX_CB_RX_DATA_HQ: + BUG_ON(delta > ISL38XX_CB_RX_QSIZE); + return ISL38XX_CB_RX_QSIZE - delta; + break; + } + BUG(); + return 0; +} diff -Nru a/drivers/net/wireless/prism54/isl_38xx.h b/drivers/net/wireless/prism54/isl_38xx.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/net/wireless/prism54/isl_38xx.h 2004-08-14 12:02:31 -07:00 @@ -0,0 +1,169 @@ +/* + * + * Copyright (C) 2002 Intersil Americas Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License + * + * 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 _ISL_38XX_H +#define _ISL_38XX_H + +#include +#include +#include + +#define ISL38XX_CB_RX_QSIZE 8 +#define ISL38XX_CB_TX_QSIZE 32 + +/* ISL38XX Access Point Specific definitions */ +#define ISL38XX_MAX_WDS_LINKS 8 + +/* ISL38xx Client Specific definitions */ +#define ISL38XX_PSM_ACTIVE_STATE 0 +#define ISL38XX_PSM_POWERSAVE_STATE 1 + +/* ISL38XX Host Interface Definitions */ +#define ISL38XX_PCI_MEM_SIZE 0x02000 +#define ISL38XX_MEMORY_WINDOW_SIZE 0x01000 +#define ISL38XX_DEV_FIRMWARE_ADDRES 0x20000 +#define ISL38XX_WRITEIO_DELAY 10 /* in us */ +#define ISL38XX_RESET_DELAY 50 /* in ms */ +#define ISL38XX_WAIT_CYCLE 10 /* in 10ms */ +#define ISL38XX_MAX_WAIT_CYCLES 10 + +/* PCI Memory Area */ +#define ISL38XX_HARDWARE_REG 0x0000 +#define ISL38XX_CARDBUS_CIS 0x0800 +#define ISL38XX_DIRECT_MEM_WIN 0x1000 + +/* Hardware registers */ +#define ISL38XX_DEV_INT_REG 0x0000 +#define ISL38XX_INT_IDENT_REG 0x0010 +#define ISL38XX_INT_ACK_REG 0x0014 +#define ISL38XX_INT_EN_REG 0x0018 +#define ISL38XX_GEN_PURP_COM_REG_1 0x0020 +#define ISL38XX_GEN_PURP_COM_REG_2 0x0024 +#define ISL38XX_CTRL_BLK_BASE_REG ISL38XX_GEN_PURP_COM_REG_1 +#define ISL38XX_DIR_MEM_BASE_REG 0x0030 +#define ISL38XX_CTRL_STAT_REG 0x0078 + +/* High end mobos queue up pci writes, the following + * is used to "read" from after a write to force flush */ +#define ISL38XX_PCI_POSTING_FLUSH ISL38XX_INT_EN_REG + +/** + * isl38xx_w32_flush - PCI iomem write helper + * @base: (host) memory base address of the device + * @val: 32bit value (host order) to write + * @offset: byte offset into @base to write value to + * + * This helper takes care of writing a 32bit datum to the + * specified offset into the device's pci memory space, and making sure + * the pci memory buffers get flushed by performing one harmless read + * from the %ISL38XX_PCI_POSTING_FLUSH offset. + */ +static inline void +isl38xx_w32_flush(void *base, u32 val, unsigned long offset) +{ + writel(val, base + offset); + (void) readl(base + ISL38XX_PCI_POSTING_FLUSH); +} + +/* Device Interrupt register bits */ +#define ISL38XX_DEV_INT_RESET 0x0001 +#define ISL38XX_DEV_INT_UPDATE 0x0002 +#define ISL38XX_DEV_INT_WAKEUP 0x0008 +#define ISL38XX_DEV_INT_SLEEP 0x0010 + +/* Interrupt Identification/Acknowledge/Enable register bits */ +#define ISL38XX_INT_IDENT_UPDATE 0x0002 +#define ISL38XX_INT_IDENT_INIT 0x0004 +#define ISL38XX_INT_IDENT_WAKEUP 0x0008 +#define ISL38XX_INT_IDENT_SLEEP 0x0010 +#define ISL38XX_INT_SOURCES 0x001E + +/* Control/Status register bits */ +#define ISL38XX_CTRL_STAT_SLEEPMODE 0x00000200 +#define ISL38XX_CTRL_STAT_CLKRUN 0x00800000 +#define ISL38XX_CTRL_STAT_RESET 0x10000000 +#define ISL38XX_CTRL_STAT_RAMBOOT 0x20000000 +#define ISL38XX_CTRL_STAT_STARTHALTED 0x40000000 +#define ISL38XX_CTRL_STAT_HOST_OVERRIDE 0x80000000 + +/* Control Block definitions */ +#define ISL38XX_CB_RX_DATA_LQ 0 +#define ISL38XX_CB_TX_DATA_LQ 1 +#define ISL38XX_CB_RX_DATA_HQ 2 +#define ISL38XX_CB_TX_DATA_HQ 3 +#define ISL38XX_CB_RX_MGMTQ 4 +#define ISL38XX_CB_TX_MGMTQ 5 +#define ISL38XX_CB_QCOUNT 6 +#define ISL38XX_CB_MGMT_QSIZE 4 +#define ISL38XX_MIN_QTHRESHOLD 4 /* fragments */ + +/* Memory Manager definitions */ +#define MGMT_FRAME_SIZE 1500 /* >= size struct obj_bsslist */ +#define MGMT_TX_FRAME_COUNT 24 /* max 4 + spare 4 + 8 init */ +#define MGMT_RX_FRAME_COUNT 24 /* 4*4 + spare 8 */ +#define MGMT_FRAME_COUNT (MGMT_TX_FRAME_COUNT + MGMT_RX_FRAME_COUNT) +#define CONTROL_BLOCK_SIZE 1024 /* should be enough */ +#define PSM_FRAME_SIZE 1536 +#define PSM_MINIMAL_STATION_COUNT 64 +#define PSM_FRAME_COUNT PSM_MINIMAL_STATION_COUNT +#define PSM_BUFFER_SIZE PSM_FRAME_SIZE * PSM_FRAME_COUNT +#define MAX_TRAP_RX_QUEUE 4 +#define HOST_MEM_BLOCK CONTROL_BLOCK_SIZE + PSM_BUFFER_SIZE + +/* Fragment package definitions */ +#define FRAGMENT_FLAG_MF 0x0001 +#define MAX_FRAGMENT_SIZE 1536 + +/* In monitor mode frames have a header. I don't know exactly how big those + * frame can be but I've never seen any frame bigger than 1584... : + */ +#define MAX_FRAGMENT_SIZE_RX 1600 + +typedef struct { + u32 address; /* physical address on host */ + u16 size; /* packet size */ + u16 flags; /* set of bit-wise flags */ +} isl38xx_fragment; + +struct isl38xx_cb { + u32 driver_curr_frag[ISL38XX_CB_QCOUNT]; + u32 device_curr_frag[ISL38XX_CB_QCOUNT]; + isl38xx_fragment rx_data_low[ISL38XX_CB_RX_QSIZE]; + isl38xx_fragment tx_data_low[ISL38XX_CB_TX_QSIZE]; + isl38xx_fragment rx_data_high[ISL38XX_CB_RX_QSIZE]; + isl38xx_fragment tx_data_high[ISL38XX_CB_TX_QSIZE]; + isl38xx_fragment rx_data_mgmt[ISL38XX_CB_MGMT_QSIZE]; + isl38xx_fragment tx_data_mgmt[ISL38XX_CB_MGMT_QSIZE]; +}; + +typedef struct isl38xx_cb isl38xx_control_block; + +/* determine number of entries currently in queue */ +int isl38xx_in_queue(isl38xx_control_block *cb, int queue); + +void isl38xx_disable_interrupts(void *); +void isl38xx_enable_common_interrupts(void *); + +void isl38xx_handle_sleep_request(isl38xx_control_block *, int *, + void *); +void isl38xx_handle_wakeup(isl38xx_control_block *, int *, void *); +void isl38xx_trigger_device(int, void *); +void isl38xx_interface_reset(void *, dma_addr_t); + +#endif /* _ISL_38XX_H */ diff -Nru a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/net/wireless/prism54/isl_ioctl.c 2004-08-14 12:02:31 -07:00 @@ -0,0 +1,2261 @@ +/* + * + * Copyright (C) 2002 Intersil Americas Inc. + * (C) 2003,2004 Aurelien Alleaume + * (C) 2003 Herbert Valerio Riedel + * (C) 2003 Luis R. Rodriguez + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include + +#include + +#include "prismcompat.h" +#include "isl_ioctl.h" +#include "islpci_mgt.h" +#include "isl_oid.h" /* additional types and defs for isl38xx fw */ +#include "oid_mgt.h" + +#include /* New driver API */ + +static int init_mode = CARD_DEFAULT_IW_MODE; +static int init_channel = CARD_DEFAULT_CHANNEL; +static int init_wep = CARD_DEFAULT_WEP; +static int init_filter = CARD_DEFAULT_FILTER; +static int init_authen = CARD_DEFAULT_AUTHEN; +static int init_dot1x = CARD_DEFAULT_DOT1X; +static int init_conformance = CARD_DEFAULT_CONFORMANCE; +static int init_mlme = CARD_DEFAULT_MLME_MODE; + +module_param(init_mode, int, 0); +MODULE_PARM_DESC(init_mode, + "Set card mode:\n0: Auto\n1: Ad-Hoc\n2: Managed Client (Default)\n3: Master / Access Point\n4: Repeater (Not supported yet)\n5: Secondary (Not supported yet)\n6: Monitor"); + +module_param(init_channel, int, 0); +MODULE_PARM_DESC(init_channel, + "Check `iwpriv ethx channel` for available channels"); + +module_param(init_wep, int, 0); +module_param(init_filter, int, 0); + +module_param(init_authen, int, 0); +MODULE_PARM_DESC(init_authen, + "Authentication method. Can be of seven types:\n0 0x0000: None\n1 0x0001: DOT11_AUTH_OS (Default)\n2 0x0002: DOT11_AUTH_SK\n3 0x0003: DOT11_AUTH_BOTH"); + +module_param(init_dot1x, int, 0); +MODULE_PARM_DESC(init_dot1x, + "\n0: None/not set (Default)\n1: DOT11_DOT1X_AUTHENABLED\n2: DOT11_DOT1X_KEYTXENABLED"); + +module_param(init_mlme, int, 0); +MODULE_PARM_DESC(init_mlme, + "Sets the MAC layer management entity (MLME) mode of operation,\n0: DOT11_MLME_AUTO (Default)\n1: DOT11_MLME_INTERMEDIATE\n2: DOT11_MLME_EXTENDED"); + +/** + * prism54_mib_mode_helper - MIB change mode helper function + * @mib: the &struct islpci_mib object to modify + * @iw_mode: new mode (%IW_MODE_*) + * + * This is a helper function, hence it does not lock. Make sure + * caller deals with locking *if* necessary. This function sets the + * mode-dependent mib values and does the mapping of the Linux + * Wireless API modes to Device firmware modes. It also checks for + * correct valid Linux wireless modes. + */ +int +prism54_mib_mode_helper(islpci_private *priv, u32 iw_mode) +{ + u32 config = INL_CONFIG_MANUALRUN; + u32 mode, bsstype; + + /* For now, just catch early the Repeater and Secondary modes here */ + if (iw_mode == IW_MODE_REPEAT || iw_mode == IW_MODE_SECOND) { + printk(KERN_DEBUG + "%s(): Sorry, Repeater mode and Secondary mode " + "are not yet supported by this driver.\n", __FUNCTION__); + return -EINVAL; + } + + priv->iw_mode = iw_mode; + + switch (iw_mode) { + case IW_MODE_AUTO: + mode = INL_MODE_CLIENT; + bsstype = DOT11_BSSTYPE_ANY; + break; + case IW_MODE_ADHOC: + mode = INL_MODE_CLIENT; + bsstype = DOT11_BSSTYPE_IBSS; + break; + case IW_MODE_INFRA: + mode = INL_MODE_CLIENT; + bsstype = DOT11_BSSTYPE_INFRA; + break; + case IW_MODE_MASTER: + mode = INL_MODE_AP; + bsstype = DOT11_BSSTYPE_INFRA; + break; + case IW_MODE_MONITOR: + mode = INL_MODE_PROMISCUOUS; + bsstype = DOT11_BSSTYPE_ANY; + config |= INL_CONFIG_RXANNEX; + break; + default: + return -EINVAL; + } + + if (init_wds) + config |= INL_CONFIG_WDS; + mgt_set(priv, DOT11_OID_BSSTYPE, &bsstype); + mgt_set(priv, OID_INL_CONFIG, &config); + mgt_set(priv, OID_INL_MODE, &mode); + + return 0; +} + +/** + * prism54_mib_init - fill MIB cache with defaults + * + * this function initializes the struct given as @mib with defaults, + * of which many are retrieved from the global module parameter + * variables. + */ + +void +prism54_mib_init(islpci_private *priv) +{ + u32 t; + struct obj_buffer psm_buffer = { + .size = PSM_BUFFER_SIZE, + .addr = priv->device_psm_buffer + }; + + mgt_set(priv, DOT11_OID_CHANNEL, &init_channel); + mgt_set(priv, DOT11_OID_AUTHENABLE, &init_authen); + mgt_set(priv, DOT11_OID_PRIVACYINVOKED, &init_wep); + + mgt_set(priv, DOT11_OID_PSMBUFFER, &psm_buffer); + mgt_set(priv, DOT11_OID_EXUNENCRYPTED, &init_filter); + mgt_set(priv, DOT11_OID_DOT1XENABLE, &init_dot1x); + mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &init_mlme); + mgt_set(priv, OID_INL_DOT11D_CONFORMANCE, &init_conformance); + + t = 127; + mgt_set(priv, OID_INL_OUTPUTPOWER, &t); + + /* Important: we are setting a default wireless mode and we are + * forcing a valid one, so prism54_mib_mode_helper should just set + * mib values depending on what the wireless mode given is. No need + * for it save old values */ + if (init_mode > IW_MODE_MONITOR || init_mode < IW_MODE_AUTO) { + printk(KERN_DEBUG "%s(): You passed a non-valid init_mode. " + "Using default mode\n", __FUNCTION__); + init_mode = CARD_DEFAULT_IW_MODE; + } + /* This sets all of the mode-dependent values */ + prism54_mib_mode_helper(priv, init_mode); +} + +/* this will be executed outside of atomic context thanks to + * schedule_work(), thus we can as well use sleeping semaphore + * locking */ +void +prism54_update_stats(islpci_private *priv) +{ + char *data; + int j; + struct obj_bss bss, *bss2; + union oid_res_t r; + + if (down_interruptible(&priv->stats_sem)) + return; + +/* Noise floor. + * I'm not sure if the unit is dBm. + * Note : If we are not connected, this value seems to be irrelevant. */ + + mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r); + priv->local_iwstatistics.qual.noise = r.u; + +/* Get the rssi of the link. To do this we need to retrieve a bss. */ + + /* First get the MAC address of the AP we are associated with. */ + mgt_get_request(priv, DOT11_OID_BSSID, 0, NULL, &r); + data = r.ptr; + + /* copy this MAC to the bss */ + memcpy(bss.address, data, 6); + kfree(data); + + /* now ask for the corresponding bss */ + j = mgt_get_request(priv, DOT11_OID_BSSFIND, 0, (void *) &bss, &r); + bss2 = r.ptr; + /* report the rssi and use it to calculate + * link quality through a signal-noise + * ratio */ + priv->local_iwstatistics.qual.level = bss2->rssi; + priv->local_iwstatistics.qual.qual = + bss2->rssi - priv->iwstatistics.qual.noise; + + kfree(bss2); + + /* report that the stats are new */ + priv->local_iwstatistics.qual.updated = 0x7; + +/* Rx : unable to decrypt the MPDU */ + mgt_get_request(priv, DOT11_OID_PRIVRXFAILED, 0, NULL, &r); + priv->local_iwstatistics.discard.code = r.u; + +/* Tx : Max MAC retries num reached */ + mgt_get_request(priv, DOT11_OID_MPDUTXFAILED, 0, NULL, &r); + priv->local_iwstatistics.discard.retries = r.u; + + up(&priv->stats_sem); + + return; +} + +struct iw_statistics * +prism54_get_wireless_stats(struct net_device *ndev) +{ + islpci_private *priv = netdev_priv(ndev); + + /* If the stats are being updated return old data */ + if (down_trylock(&priv->stats_sem) == 0) { + memcpy(&priv->iwstatistics, &priv->local_iwstatistics, + sizeof (struct iw_statistics)); + /* They won't be marked updated for the next time */ + priv->local_iwstatistics.qual.updated = 0; + up(&priv->stats_sem); + } else + priv->iwstatistics.qual.updated = 0; + + /* Update our wireless stats, but do not schedule to often + * (max 1 HZ) */ + if ((priv->stats_timestamp == 0) || + time_after(jiffies, priv->stats_timestamp + 1 * HZ)) { + schedule_work(&priv->stats_work); + priv->stats_timestamp = jiffies; + } + + return &priv->iwstatistics; +} + +static int +prism54_commit(struct net_device *ndev, struct iw_request_info *info, + char *cwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + + /* simply re-set the last set SSID, this should commit most stuff */ + + /* Commit in Monitor mode is not necessary, also setting essid + * in Monitor mode does not make sense and isn't allowed for this + * device's firmware */ + if (priv->iw_mode != IW_MODE_MONITOR) + return mgt_set_request(priv, DOT11_OID_SSID, 0, NULL); + return 0; +} + +static int +prism54_get_name(struct net_device *ndev, struct iw_request_info *info, + char *cwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + char *capabilities; + union oid_res_t r; + int rvalue; + + if (islpci_get_state(priv) < PRV_STATE_INIT) { + strncpy(cwrq, "NOT READY!", IFNAMSIZ); + return 0; + } + rvalue = mgt_get_request(priv, OID_INL_PHYCAPABILITIES, 0, NULL, &r); + + switch (r.u) { + case INL_PHYCAP_5000MHZ: + capabilities = "IEEE 802.11a/b/g"; + break; + case INL_PHYCAP_FAA: + capabilities = "IEEE 802.11b/g - FAA Support"; + break; + case INL_PHYCAP_2400MHZ: + default: + capabilities = "IEEE 802.11b/g"; /* Default */ + break; + } + strncpy(cwrq, capabilities, IFNAMSIZ); + return rvalue; +} + +static int +prism54_set_freq(struct net_device *ndev, struct iw_request_info *info, + struct iw_freq *fwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + int rvalue; + u32 c; + + if (fwrq->m < 1000) + /* we have a channel number */ + c = fwrq->m; + else + c = (fwrq->e == 1) ? channel_of_freq(fwrq->m / 100000) : 0; + + rvalue = c ? mgt_set_request(priv, DOT11_OID_CHANNEL, 0, &c) : -EINVAL; + + /* Call commit handler */ + return (rvalue ? rvalue : -EINPROGRESS); +} + +static int +prism54_get_freq(struct net_device *ndev, struct iw_request_info *info, + struct iw_freq *fwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + union oid_res_t r; + int rvalue; + + rvalue = mgt_get_request(priv, DOT11_OID_CHANNEL, 0, NULL, &r); + + fwrq->m = r.u; + fwrq->e = 0; + + return rvalue; +} + +static int +prism54_set_mode(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + u32 mlmeautolevel = CARD_DEFAULT_MLME_MODE; + + /* Let's see if the user passed a valid Linux Wireless mode */ + if (*uwrq > IW_MODE_MONITOR || *uwrq < IW_MODE_AUTO) { + printk(KERN_DEBUG + "%s: %s() You passed a non-valid init_mode.\n", + priv->ndev->name, __FUNCTION__); + return -EINVAL; + } + + down_write(&priv->mib_sem); + + if (prism54_mib_mode_helper(priv, *uwrq)) { + up_write(&priv->mib_sem); + return -EOPNOTSUPP; + } + + /* the ACL code needs an intermediate mlmeautolevel. The wpa stuff an + * extended one. + */ + if ((*uwrq == IW_MODE_MASTER) && (priv->acl.policy != MAC_POLICY_OPEN)) + mlmeautolevel = DOT11_MLME_INTERMEDIATE; + if (priv->wpa) + mlmeautolevel = DOT11_MLME_EXTENDED; + + mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlmeautolevel); + + mgt_commit(priv); + priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR) + ? priv->monitor_type : ARPHRD_ETHER; + up_write(&priv->mib_sem); + + return 0; +} + +/* Use mib cache */ +static int +prism54_get_mode(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + + BUG_ON((priv->iw_mode < IW_MODE_AUTO) || (priv->iw_mode > + IW_MODE_MONITOR)); + *uwrq = priv->iw_mode; + + return 0; +} + +/* we use DOT11_OID_EDTHRESHOLD. From what I guess the card will not try to + * emit data if (sensitivity > rssi - noise) (in dBm). + * prism54_set_sens does not seem to work. + */ + +static int +prism54_set_sens(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + u32 sens; + + /* by default the card sets this to 20. */ + sens = vwrq->disabled ? 20 : vwrq->value; + + return mgt_set_request(priv, DOT11_OID_EDTHRESHOLD, 0, &sens); +} + +static int +prism54_get_sens(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + union oid_res_t r; + int rvalue; + + rvalue = mgt_get_request(priv, DOT11_OID_EDTHRESHOLD, 0, NULL, &r); + + vwrq->value = r.u; + vwrq->disabled = (vwrq->value == 0); + vwrq->fixed = 1; + + return rvalue; +} + +static int +prism54_get_range(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + struct iw_range *range = (struct iw_range *) extra; + islpci_private *priv = netdev_priv(ndev); + char *data; + int i, m, rvalue; + struct obj_frequencies *freq; + union oid_res_t r; + + memset(range, 0, sizeof (struct iw_range)); + dwrq->length = sizeof (struct iw_range); + + /* set the wireless extension version number */ + range->we_version_source = SUPPORTED_WIRELESS_EXT; + range->we_version_compiled = WIRELESS_EXT; + + /* Now the encoding capabilities */ + range->num_encoding_sizes = 3; + /* 64(40) bits WEP */ + range->encoding_size[0] = 5; + /* 128(104) bits WEP */ + range->encoding_size[1] = 13; + /* 256 bits for WPA-PSK */ + range->encoding_size[2] = 32; + /* 4 keys are allowed */ + range->max_encoding_tokens = 4; + + /* we don't know the quality range... */ + range->max_qual.level = 0; + range->max_qual.noise = 0; + range->max_qual.qual = 0; + /* these value describe an average quality. Needs more tweaking... */ + range->avg_qual.level = -80; /* -80 dBm */ + range->avg_qual.noise = 0; /* don't know what to put here */ + range->avg_qual.qual = 0; + + range->sensitivity = 200; + + /* retry limit capabilities */ + range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME; + range->retry_flags = IW_RETRY_LIMIT; + range->r_time_flags = IW_RETRY_LIFETIME; + + /* I don't know the range. Put stupid things here */ + range->min_retry = 1; + range->max_retry = 65535; + range->min_r_time = 1024; + range->max_r_time = 65535 * 1024; + + /* txpower is supported in dBm's */ + range->txpower_capa = IW_TXPOW_DBM; + + if (islpci_get_state(priv) < PRV_STATE_INIT) + return 0; + + /* Request the device for the supported frequencies + * not really relevant since some devices will report the 5 GHz band + * frequencies even if they don't support them. + */ + rvalue = + mgt_get_request(priv, DOT11_OID_SUPPORTEDFREQUENCIES, 0, NULL, &r); + freq = r.ptr; + + range->num_channels = freq->nr; + range->num_frequency = freq->nr; + + m = min(IW_MAX_FREQUENCIES, (int) freq->nr); + for (i = 0; i < m; i++) { + range->freq[i].m = freq->mhz[i]; + range->freq[i].e = 6; + range->freq[i].i = channel_of_freq(freq->mhz[i]); + } + kfree(freq); + + rvalue |= mgt_get_request(priv, DOT11_OID_SUPPORTEDRATES, 0, NULL, &r); + data = r.ptr; + + /* We got an array of char. It is NULL terminated. */ + i = 0; + while ((i < IW_MAX_BITRATES) && (*data != 0)) { + /* the result must be in bps. The card gives us 500Kbps */ + range->bitrate[i] = (__s32) (*data >> 1); + range->bitrate[i] *= 1000000; + i++; + data++; + } + range->num_bitrates = i; + kfree(r.ptr); + + return rvalue; +} + +/* Set AP address*/ + +static int +prism54_set_wap(struct net_device *ndev, struct iw_request_info *info, + struct sockaddr *awrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + char bssid[6]; + int rvalue; + + if (awrq->sa_family != ARPHRD_ETHER) + return -EINVAL; + + /* prepare the structure for the set object */ + memcpy(&bssid[0], awrq->sa_data, 6); + + /* set the bssid -- does this make sense when in AP mode? */ + rvalue = mgt_set_request(priv, DOT11_OID_BSSID, 0, &bssid); + + return (rvalue ? rvalue : -EINPROGRESS); /* Call commit handler */ +} + +/* get AP address*/ + +static int +prism54_get_wap(struct net_device *ndev, struct iw_request_info *info, + struct sockaddr *awrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + union oid_res_t r; + int rvalue; + + rvalue = mgt_get_request(priv, DOT11_OID_BSSID, 0, NULL, &r); + memcpy(awrq->sa_data, r.ptr, 6); + awrq->sa_family = ARPHRD_ETHER; + kfree(r.ptr); + + return rvalue; +} + +static int +prism54_set_scan(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + /* hehe the device does this automagicaly */ + return 0; +} + +/* a little helper that will translate our data into a card independent + * format that the Wireless Tools will understand. This was inspired by + * the "Aironet driver for 4500 and 4800 series cards" (GPL) + */ + +static char * +prism54_translate_bss(struct net_device *ndev, char *current_ev, + char *end_buf, struct obj_bss *bss, char noise) +{ + struct iw_event iwe; /* Temporary buffer */ + short cap; + islpci_private *priv = netdev_priv(ndev); + + /* The first entry must be the MAC address */ + memcpy(iwe.u.ap_addr.sa_data, bss->address, 6); + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + iwe.cmd = SIOCGIWAP; + current_ev = + iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN); + + /* The following entries will be displayed in the same order we give them */ + + /* The ESSID. */ + iwe.u.data.length = bss->ssid.length; + iwe.u.data.flags = 1; + iwe.cmd = SIOCGIWESSID; + current_ev = iwe_stream_add_point(current_ev, end_buf, + &iwe, bss->ssid.octets); + + /* Capabilities */ +#define CAP_ESS 0x01 +#define CAP_IBSS 0x02 +#define CAP_CRYPT 0x10 + + /* Mode */ + cap = bss->capinfo; + iwe.u.mode = 0; + if (cap & CAP_ESS) + iwe.u.mode = IW_MODE_MASTER; + else if (cap & CAP_IBSS) + iwe.u.mode = IW_MODE_ADHOC; + iwe.cmd = SIOCGIWMODE; + if (iwe.u.mode) + current_ev = + iwe_stream_add_event(current_ev, end_buf, &iwe, + IW_EV_UINT_LEN); + + /* Encryption capability */ + if (cap & CAP_CRYPT) + iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + else + iwe.u.data.flags = IW_ENCODE_DISABLED; + iwe.u.data.length = 0; + iwe.cmd = SIOCGIWENCODE; + current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, NULL); + + /* Add frequency. (short) bss->channel is the frequency in MHz */ + iwe.u.freq.m = channel_of_freq(bss->channel); + iwe.u.freq.e = 0; + iwe.cmd = SIOCGIWFREQ; + current_ev = + iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); + + /* Add quality statistics */ + iwe.u.qual.level = bss->rssi; + iwe.u.qual.noise = noise; + /* do a simple SNR for quality */ + iwe.u.qual.qual = bss->rssi - noise; + iwe.cmd = IWEVQUAL; + current_ev = + iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); + + if (priv->wpa) { + u8 wpa_ie[MAX_WPA_IE_LEN]; + char *buf, *p; + size_t wpa_ie_len; + int i; + + wpa_ie_len = prism54_wpa_ie_get(priv, bss->address, wpa_ie); + if (wpa_ie_len > 0 && + (buf = kmalloc(wpa_ie_len * 2 + 10, GFP_ATOMIC))) { + p = buf; + p += sprintf(p, "wpa_ie="); + for (i = 0; i < wpa_ie_len; i++) { + p += sprintf(p, "%02x", wpa_ie[i]); + } + memset(&iwe, 0, sizeof (iwe)); + iwe.cmd = IWEVCUSTOM; + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point(current_ev, end_buf, + &iwe, buf); + kfree(buf); + } + } + return current_ev; +} + +int +prism54_get_scan(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + int i, rvalue; + struct obj_bsslist *bsslist; + u32 noise = 0; + char *current_ev = extra; + union oid_res_t r; + + if (islpci_get_state(priv) < PRV_STATE_INIT) { + /* device is not ready, fail gently */ + dwrq->length = 0; + return 0; + } + + /* first get the noise value. We will use it to report the link quality */ + rvalue = mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r); + noise = r.u; + + /* Ask the device for a list of known bss. We can report at most + * IW_MAX_AP=64 to the range struct. But the device won't repport anything + * if you change the value of IWMAX_BSS=24. + */ + rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r); + bsslist = r.ptr; + + /* ok now, scan the list and translate its info */ + for (i = 0; i < min(IW_MAX_AP, (int) bsslist->nr); i++) + current_ev = prism54_translate_bss(ndev, current_ev, + extra + IW_SCAN_MAX_DATA, + &(bsslist->bsslist[i]), + noise); + kfree(bsslist); + dwrq->length = (current_ev - extra); + dwrq->flags = 0; /* todo */ + + return rvalue; +} + +static int +prism54_set_essid(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + struct obj_ssid essid; + + memset(essid.octets, 0, 33); + + /* Check if we were asked for `any' */ + if (dwrq->flags && dwrq->length) { + if (dwrq->length > min(33, IW_ESSID_MAX_SIZE + 1)) + return -E2BIG; + essid.length = dwrq->length - 1; + memcpy(essid.octets, extra, dwrq->length); + } else + essid.length = 0; + + if (priv->iw_mode != IW_MODE_MONITOR) + return mgt_set_request(priv, DOT11_OID_SSID, 0, &essid); + + /* If in monitor mode, just save to mib */ + mgt_set(priv, DOT11_OID_SSID, &essid); + return 0; + +} + +static int +prism54_get_essid(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + struct obj_ssid *essid; + union oid_res_t r; + int rvalue; + + rvalue = mgt_get_request(priv, DOT11_OID_SSID, 0, NULL, &r); + essid = r.ptr; + + if (essid->length) { + dwrq->flags = 1; /* set ESSID to ON for Wireless Extensions */ + /* if it is to big, trunk it */ + dwrq->length = min(IW_ESSID_MAX_SIZE, essid->length + 1); + } else { + dwrq->flags = 0; + dwrq->length = 0; + } + essid->octets[essid->length] = '\0'; + memcpy(extra, essid->octets, dwrq->length); + kfree(essid); + + return rvalue; +} + +/* Provides no functionality, just completes the ioctl. In essence this is a + * just a cosmetic ioctl. + */ +static int +prism54_set_nick(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + + if (dwrq->length > IW_ESSID_MAX_SIZE) + return -E2BIG; + + down_write(&priv->mib_sem); + memset(priv->nickname, 0, sizeof (priv->nickname)); + memcpy(priv->nickname, extra, dwrq->length); + up_write(&priv->mib_sem); + + return 0; +} + +static int +prism54_get_nick(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + + dwrq->length = 0; + + down_read(&priv->mib_sem); + dwrq->length = strlen(priv->nickname) + 1; + memcpy(extra, priv->nickname, dwrq->length); + up_read(&priv->mib_sem); + + return 0; +} + +/* Set the allowed Bitrates */ + +static int +prism54_set_rate(struct net_device *ndev, + struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + + islpci_private *priv = netdev_priv(ndev); + u32 rate, profile; + char *data; + int ret, i; + union oid_res_t r; + + if (vwrq->value == -1) { + /* auto mode. No limit. */ + profile = 1; + return mgt_set_request(priv, DOT11_OID_PROFILES, 0, &profile); + } + + if ((ret = + mgt_get_request(priv, DOT11_OID_SUPPORTEDRATES, 0, NULL, &r))) + return ret; + + rate = (u32) (vwrq->value / 500000); + data = r.ptr; + i = 0; + + while (data[i]) { + if (rate && (data[i] == rate)) { + break; + } + if (vwrq->value == i) { + break; + } + data[i] |= 0x80; + i++; + } + + if (!data[i]) { + return -EINVAL; + } + + data[i] |= 0x80; + data[i + 1] = 0; + + /* Now, check if we want a fixed or auto value */ + if (vwrq->fixed) { + data[0] = data[i]; + data[1] = 0; + } + +/* + i = 0; + printk("prism54 rate: "); + while(data[i]) { + printk("%u ", data[i]); + i++; + } + printk("0\n"); +*/ + profile = -1; + ret = mgt_set_request(priv, DOT11_OID_PROFILES, 0, &profile); + ret |= mgt_set_request(priv, DOT11_OID_EXTENDEDRATES, 0, data); + ret |= mgt_set_request(priv, DOT11_OID_RATES, 0, data); + + kfree(r.ptr); + + return ret; +} + +/* Get the current bit rate */ +static int +prism54_get_rate(struct net_device *ndev, + struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + int rvalue; + char *data; + union oid_res_t r; + + /* Get the current bit rate */ + if ((rvalue = mgt_get_request(priv, GEN_OID_LINKSTATE, 0, NULL, &r))) + return rvalue; + vwrq->value = r.u * 500000; + + /* request the device for the enabled rates */ + if ((rvalue = mgt_get_request(priv, DOT11_OID_RATES, 0, NULL, &r))) + return rvalue; + data = r.ptr; + vwrq->fixed = (data[0] != 0) && (data[1] == 0); + kfree(r.ptr); + + return 0; +} + +static int +prism54_set_rts(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + + return mgt_set_request(priv, DOT11_OID_RTSTHRESH, 0, &vwrq->value); +} + +static int +prism54_get_rts(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + union oid_res_t r; + int rvalue; + + /* get the rts threshold */ + rvalue = mgt_get_request(priv, DOT11_OID_RTSTHRESH, 0, NULL, &r); + vwrq->value = r.u; + + return rvalue; +} + +static int +prism54_set_frag(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + + return mgt_set_request(priv, DOT11_OID_FRAGTHRESH, 0, &vwrq->value); +} + +static int +prism54_get_frag(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + union oid_res_t r; + int rvalue; + + rvalue = mgt_get_request(priv, DOT11_OID_FRAGTHRESH, 0, NULL, &r); + vwrq->value = r.u; + + return rvalue; +} + +/* Here we have (min,max) = max retries for (small frames, big frames). Where + * big frame <=> bigger than the rts threshold + * small frame <=> smaller than the rts threshold + * This is not really the behavior expected by the wireless tool but it seems + * to be a common behavior in other drivers. + */ + +static int +prism54_set_retry(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + u32 slimit = 0, llimit = 0; /* short and long limit */ + u32 lifetime = 0; + int rvalue = 0; + + if (vwrq->disabled) + /* we cannot disable this feature */ + return -EINVAL; + + if (vwrq->flags & IW_RETRY_LIMIT) { + if (vwrq->flags & IW_RETRY_MIN) + slimit = vwrq->value; + else if (vwrq->flags & IW_RETRY_MAX) + llimit = vwrq->value; + else { + /* we are asked to set both */ + slimit = vwrq->value; + llimit = vwrq->value; + } + } + if (vwrq->flags & IW_RETRY_LIFETIME) + /* Wireless tools use us unit while the device uses 1024 us unit */ + lifetime = vwrq->value / 1024; + + /* now set what is requested */ + if (slimit) + rvalue = + mgt_set_request(priv, DOT11_OID_SHORTRETRIES, 0, &slimit); + if (llimit) + rvalue |= + mgt_set_request(priv, DOT11_OID_LONGRETRIES, 0, &llimit); + if (lifetime) + rvalue |= + mgt_set_request(priv, DOT11_OID_MAXTXLIFETIME, 0, + &lifetime); + return rvalue; +} + +static int +prism54_get_retry(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + union oid_res_t r; + int rvalue = 0; + vwrq->disabled = 0; /* It cannot be disabled */ + + if ((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { + /* we are asked for the life time */ + rvalue = + mgt_get_request(priv, DOT11_OID_MAXTXLIFETIME, 0, NULL, &r); + vwrq->value = r.u * 1024; + vwrq->flags = IW_RETRY_LIFETIME; + } else if ((vwrq->flags & IW_RETRY_MAX)) { + /* we are asked for the long retry limit */ + rvalue |= + mgt_get_request(priv, DOT11_OID_LONGRETRIES, 0, NULL, &r); + vwrq->value = r.u; + vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; + } else { + /* default. get the short retry limit */ + rvalue |= + mgt_get_request(priv, DOT11_OID_SHORTRETRIES, 0, NULL, &r); + vwrq->value = r.u; + vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MIN; + } + + return rvalue; +} + +static int +prism54_set_encode(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + int rvalue = 0, force = 0; + int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0; + union oid_res_t r; + + /* with the new API, it's impossible to get a NULL pointer. + * New version of iwconfig set the IW_ENCODE_NOKEY flag + * when no key is given, but older versions don't. */ + + if (dwrq->length > 0) { + /* we have a key to set */ + int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; + int current_index; + struct obj_key key = { DOT11_PRIV_WEP, 0, "" }; + + /* get the current key index */ + rvalue = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r); + current_index = r.u; + /* Verify that the key is not marked as invalid */ + if (!(dwrq->flags & IW_ENCODE_NOKEY)) { + key.length = dwrq->length > sizeof (key.key) ? + sizeof (key.key) : dwrq->length; + memcpy(key.key, extra, key.length); + if (key.length == 32) + /* we want WPA-PSK */ + key.type = DOT11_PRIV_TKIP; + if ((index < 0) || (index > 3)) + /* no index provided use the current one */ + index = current_index; + + /* now send the key to the card */ + rvalue |= + mgt_set_request(priv, DOT11_OID_DEFKEYX, index, + &key); + } + /* + * If a valid key is set, encryption should be enabled + * (user may turn it off later). + * This is also how "iwconfig ethX key on" works + */ + if ((index == current_index) && (key.length > 0)) + force = 1; + } else { + int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; + if ((index >= 0) && (index <= 3)) { + /* we want to set the key index */ + rvalue |= + mgt_set_request(priv, DOT11_OID_DEFKEYID, 0, + &index); + } else { + if (!dwrq->flags & IW_ENCODE_MODE) { + /* we cannot do anything. Complain. */ + return -EINVAL; + } + } + } + /* now read the flags */ + if (dwrq->flags & IW_ENCODE_DISABLED) { + /* Encoding disabled, + * authen = DOT11_AUTH_OS; + * invoke = 0; + * exunencrypt = 0; */ + } + if (dwrq->flags & IW_ENCODE_OPEN) + /* Encode but accept non-encoded packets. No auth */ + invoke = 1; + if ((dwrq->flags & IW_ENCODE_RESTRICTED) || force) { + /* Refuse non-encoded packets. Auth */ + authen = DOT11_AUTH_BOTH; + invoke = 1; + exunencrypt = 1; + } + /* do the change if requested */ + if ((dwrq->flags & IW_ENCODE_MODE) || force) { + rvalue |= + mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen); + rvalue |= + mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &invoke); + rvalue |= + mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, + &exunencrypt); + } + return rvalue; +} + +static int +prism54_get_encode(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + struct obj_key *key; + u32 devindex, index = (dwrq->flags & IW_ENCODE_INDEX) - 1; + u32 authen = 0, invoke = 0, exunencrypt = 0; + int rvalue; + union oid_res_t r; + + /* first get the flags */ + rvalue = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r); + authen = r.u; + rvalue |= mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r); + invoke = r.u; + rvalue |= mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r); + exunencrypt = r.u; + + if (invoke && (authen == DOT11_AUTH_BOTH) && exunencrypt) + dwrq->flags = IW_ENCODE_RESTRICTED; + else if ((authen == DOT11_AUTH_OS) && !exunencrypt) { + if (invoke) + dwrq->flags = IW_ENCODE_OPEN; + else + dwrq->flags = IW_ENCODE_DISABLED; + } else + /* The card should not work in this state */ + dwrq->flags = 0; + + /* get the current device key index */ + rvalue |= mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r); + devindex = r.u; + /* Now get the key, return it */ + if ((index < 0) || (index > 3)) + /* no index provided, use the current one */ + index = devindex; + rvalue |= mgt_get_request(priv, DOT11_OID_DEFKEYX, index, NULL, &r); + key = r.ptr; + dwrq->length = key->length; + memcpy(extra, key->key, dwrq->length); + kfree(key); + /* return the used key index */ + dwrq->flags |= devindex + 1; + + return rvalue; +} + +static int +prism54_get_txpower(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + union oid_res_t r; + int rvalue; + + rvalue = mgt_get_request(priv, OID_INL_OUTPUTPOWER, 0, NULL, &r); + /* intersil firmware operates in 0.25 dBm (1/4 dBm) */ + vwrq->value = (s32) r.u / 4; + vwrq->fixed = 1; + /* radio is not turned of + * btw: how is possible to turn off only the radio + */ + vwrq->disabled = 0; + + return rvalue; +} + +static int +prism54_set_txpower(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + s32 u = vwrq->value; + + /* intersil firmware operates in 0.25 dBm (1/4) */ + u *= 4; + if (vwrq->disabled) { + /* don't know how to disable radio */ + printk(KERN_DEBUG + "%s: %s() disabling radio is not yet supported.\n", + priv->ndev->name, __FUNCTION__); + return -ENOTSUPP; + } else if (vwrq->fixed) + /* currently only fixed value is supported */ + return mgt_set_request(priv, OID_INL_OUTPUTPOWER, 0, &u); + else { + printk(KERN_DEBUG + "%s: %s() auto power will be implemented later.\n", + priv->ndev->name, __FUNCTION__); + return -ENOTSUPP; + } +} + +static int +prism54_reset(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + islpci_reset(netdev_priv(ndev), 0); + + return 0; +} + +static int +prism54_get_oid(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + union oid_res_t r; + int rvalue; + enum oid_num_t n = dwrq->flags; + + rvalue = mgt_get_request((islpci_private *) ndev->priv, n, 0, NULL, &r); + dwrq->length = mgt_response_to_str(n, &r, extra); + if ((isl_oid[n].flags & OID_FLAG_TYPE) != OID_TYPE_U32) + kfree(r.ptr); + return rvalue; +} + +static int +prism54_set_u32(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + u32 oid = uwrq[0], u = uwrq[1]; + + return mgt_set_request((islpci_private *) ndev->priv, oid, 0, &u); +} + +static int +prism54_set_raw(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + u32 oid = dwrq->flags; + + return mgt_set_request((islpci_private *) ndev->priv, oid, 0, extra); +} + +void +prism54_acl_init(struct islpci_acl *acl) +{ + sema_init(&acl->sem, 1); + INIT_LIST_HEAD(&acl->mac_list); + acl->size = 0; + acl->policy = MAC_POLICY_OPEN; +} + +static void +prism54_clear_mac(struct islpci_acl *acl) +{ + struct list_head *ptr, *next; + struct mac_entry *entry; + + if (down_interruptible(&acl->sem)) + return; + + if (acl->size == 0) { + up(&acl->sem); + return; + } + + for (ptr = acl->mac_list.next, next = ptr->next; + ptr != &acl->mac_list; ptr = next, next = ptr->next) { + entry = list_entry(ptr, struct mac_entry, _list); + list_del(ptr); + kfree(entry); + } + acl->size = 0; + up(&acl->sem); +} + +void +prism54_acl_clean(struct islpci_acl *acl) +{ + prism54_clear_mac(acl); +} + +static int +prism54_add_mac(struct net_device *ndev, struct iw_request_info *info, + struct sockaddr *awrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + struct islpci_acl *acl = &priv->acl; + struct mac_entry *entry; + struct sockaddr *addr = (struct sockaddr *) extra; + + if (addr->sa_family != ARPHRD_ETHER) + return -EOPNOTSUPP; + + entry = kmalloc(sizeof (struct mac_entry), GFP_KERNEL); + if (entry == NULL) + return -ENOMEM; + + memcpy(entry->addr, addr->sa_data, ETH_ALEN); + + if (down_interruptible(&acl->sem)) { + kfree(entry); + return -ERESTARTSYS; + } + list_add_tail(&entry->_list, &acl->mac_list); + acl->size++; + up(&acl->sem); + + return 0; +} + +static int +prism54_del_mac(struct net_device *ndev, struct iw_request_info *info, + struct sockaddr *awrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + struct islpci_acl *acl = &priv->acl; + struct mac_entry *entry; + struct list_head *ptr; + struct sockaddr *addr = (struct sockaddr *) extra; + + if (addr->sa_family != ARPHRD_ETHER) + return -EOPNOTSUPP; + + if (down_interruptible(&acl->sem)) + return -ERESTARTSYS; + for (ptr = acl->mac_list.next; ptr != &acl->mac_list; ptr = ptr->next) { + entry = list_entry(ptr, struct mac_entry, _list); + + if (memcmp(entry->addr, addr->sa_data, ETH_ALEN) == 0) { + list_del(ptr); + acl->size--; + kfree(entry); + up(&acl->sem); + return 0; + } + } + up(&acl->sem); + return -EINVAL; +} + +static int +prism54_get_mac(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + struct islpci_acl *acl = &priv->acl; + struct mac_entry *entry; + struct list_head *ptr; + struct sockaddr *dst = (struct sockaddr *) extra; + + dwrq->length = 0; + + if (down_interruptible(&acl->sem)) + return -ERESTARTSYS; + + for (ptr = acl->mac_list.next; ptr != &acl->mac_list; ptr = ptr->next) { + entry = list_entry(ptr, struct mac_entry, _list); + + memcpy(dst->sa_data, entry->addr, ETH_ALEN); + dst->sa_family = ARPHRD_ETHER; + dwrq->length++; + dst++; + } + up(&acl->sem); + return 0; +} + +/* Setting policy also clears the MAC acl, even if we don't change the defaut + * policy + */ + +static int +prism54_set_policy(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + struct islpci_acl *acl = &priv->acl; + u32 mlmeautolevel; + + prism54_clear_mac(acl); + + if ((*uwrq < MAC_POLICY_OPEN) || (*uwrq > MAC_POLICY_REJECT)) + return -EINVAL; + + down_write(&priv->mib_sem); + + acl->policy = *uwrq; + + /* the ACL code needs an intermediate mlmeautolevel */ + if ((priv->iw_mode == IW_MODE_MASTER) && + (acl->policy != MAC_POLICY_OPEN)) + mlmeautolevel = DOT11_MLME_INTERMEDIATE; + else + mlmeautolevel = CARD_DEFAULT_MLME_MODE; + if (priv->wpa) + mlmeautolevel = DOT11_MLME_EXTENDED; + mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlmeautolevel); + /* restart the card with our new policy */ + mgt_commit(priv); + up_write(&priv->mib_sem); + + return 0; +} + +static int +prism54_get_policy(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + struct islpci_acl *acl = &priv->acl; + + *uwrq = acl->policy; + + return 0; +} + +/* Return 1 only if client should be accepted. */ + +static int +prism54_mac_accept(struct islpci_acl *acl, char *mac) +{ + struct list_head *ptr; + struct mac_entry *entry; + int res = 0; + + if (down_interruptible(&acl->sem)) + return -ERESTARTSYS; + + if (acl->policy == MAC_POLICY_OPEN) { + up(&acl->sem); + return 1; + } + + for (ptr = acl->mac_list.next; ptr != &acl->mac_list; ptr = ptr->next) { + entry = list_entry(ptr, struct mac_entry, _list); + if (memcmp(entry->addr, mac, ETH_ALEN) == 0) { + res = 1; + break; + } + } + res = (acl->policy == MAC_POLICY_ACCEPT) ? !res : res; + up(&acl->sem); + + return res; +} + +static int +prism54_kick_all(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + struct obj_mlme *mlme; + int rvalue; + + mlme = kmalloc(sizeof (struct obj_mlme), GFP_KERNEL); + if (mlme == NULL) + return -ENOMEM; + + /* Tell the card to kick every client */ + mlme->id = 0; + rvalue = + mgt_set_request(netdev_priv(ndev), DOT11_OID_DISASSOCIATE, 0, mlme); + kfree(mlme); + + return rvalue; +} + +static int +prism54_kick_mac(struct net_device *ndev, struct iw_request_info *info, + struct sockaddr *awrq, char *extra) +{ + struct obj_mlme *mlme; + struct sockaddr *addr = (struct sockaddr *) extra; + int rvalue; + + if (addr->sa_family != ARPHRD_ETHER) + return -EOPNOTSUPP; + + mlme = kmalloc(sizeof (struct obj_mlme), GFP_KERNEL); + if (mlme == NULL) + return -ENOMEM; + + /* Tell the card to only kick the corresponding bastard */ + memcpy(mlme->address, addr->sa_data, ETH_ALEN); + mlme->id = -1; + rvalue = + mgt_set_request(netdev_priv(ndev), DOT11_OID_DISASSOCIATE, 0, mlme); + + kfree(mlme); + + return rvalue; +} + +/* Translate a TRAP oid into a wireless event. Called in islpci_mgt_receive. */ + +static void +format_event(islpci_private *priv, char *dest, const char *str, + const struct obj_mlme *mlme, u16 *length, int error) +{ + const u8 *a = mlme->address; + int n = snprintf(dest, IW_CUSTOM_MAX, + "%s %s %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X %s (%2.2X)", + str, + ((priv->iw_mode == IW_MODE_MASTER) ? "from" : "to"), + a[0], a[1], a[2], a[3], a[4], a[5], + (error ? (mlme->code ? " : REJECTED " : " : ACCEPTED ") + : ""), mlme->code); + BUG_ON(n > IW_CUSTOM_MAX); + *length = n; +} + +static void +send_formatted_event(islpci_private *priv, const char *str, + const struct obj_mlme *mlme, int error) +{ + union iwreq_data wrqu; + + wrqu.data.pointer = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL); + if (!wrqu.data.pointer) + return; + wrqu.data.length = 0; + format_event(priv, wrqu.data.pointer, str, mlme, &wrqu.data.length, + error); + wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, wrqu.data.pointer); + kfree(wrqu.data.pointer); +} + +static void +send_simple_event(islpci_private *priv, const char *str) +{ + union iwreq_data wrqu; + int n = strlen(str); + + wrqu.data.pointer = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL); + if (!wrqu.data.pointer) + return; + BUG_ON(n > IW_CUSTOM_MAX); + wrqu.data.length = n; + strcpy(wrqu.data.pointer, str); + wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, wrqu.data.pointer); + kfree(wrqu.data.pointer); +} + +static void +link_changed(struct net_device *ndev, u32 bitrate) +{ + islpci_private *priv = netdev_priv(ndev); + + if (bitrate) { + if (priv->iw_mode == IW_MODE_INFRA) { + union iwreq_data uwrq; + prism54_get_wap(ndev, NULL, (struct sockaddr *) &uwrq, + NULL); + wireless_send_event(ndev, SIOCGIWAP, &uwrq, NULL); + } else + send_simple_event(netdev_priv(ndev), + "Link established"); + } else + send_simple_event(netdev_priv(ndev), "Link lost"); +} + +/* Beacon/ProbeResp payload header */ +struct ieee80211_beacon_phdr { + u8 timestamp[8]; + u16 beacon_int; + u16 capab_info; +} __attribute__ ((packed)); + +#define WLAN_EID_GENERIC 0xdd +static u8 wpa_oid[4] = { 0x00, 0x50, 0xf2, 1 }; + +#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] +#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" + +void +prism54_wpa_ie_add(islpci_private *priv, u8 *bssid, + u8 *wpa_ie, size_t wpa_ie_len) +{ + struct list_head *ptr; + struct islpci_bss_wpa_ie *bss = NULL; + + if (wpa_ie_len > MAX_WPA_IE_LEN) + wpa_ie_len = MAX_WPA_IE_LEN; + + if (down_interruptible(&priv->wpa_sem)) + return; + + /* try to use existing entry */ + list_for_each(ptr, &priv->bss_wpa_list) { + bss = list_entry(ptr, struct islpci_bss_wpa_ie, list); + if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0) { + list_move(&bss->list, &priv->bss_wpa_list); + break; + } + bss = NULL; + } + + if (bss == NULL) { + /* add a new BSS entry; if max number of entries is already + * reached, replace the least recently updated */ + if (priv->num_bss_wpa >= MAX_BSS_WPA_IE_COUNT) { + bss = list_entry(priv->bss_wpa_list.prev, + struct islpci_bss_wpa_ie, list); + list_del(&bss->list); + } else { + bss = kmalloc(sizeof (*bss), GFP_ATOMIC); + if (bss != NULL) { + priv->num_bss_wpa++; + memset(bss, 0, sizeof (*bss)); + } + } + if (bss != NULL) { + memcpy(bss->bssid, bssid, ETH_ALEN); + list_add(&bss->list, &priv->bss_wpa_list); + } + } + + if (bss != NULL) { + memcpy(bss->wpa_ie, wpa_ie, wpa_ie_len); + bss->wpa_ie_len = wpa_ie_len; + bss->last_update = jiffies; + } else { + printk(KERN_DEBUG "Failed to add BSS WPA entry for " MACSTR + "\n", MAC2STR(bssid)); + } + + /* expire old entries from WPA list */ + while (priv->num_bss_wpa > 0) { + bss = list_entry(priv->bss_wpa_list.prev, + struct islpci_bss_wpa_ie, list); + if (!time_after(jiffies, bss->last_update + 60 * HZ)) + break; + + list_del(&bss->list); + priv->num_bss_wpa--; + kfree(bss); + } + + up(&priv->wpa_sem); +} + +size_t +prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie) +{ + struct list_head *ptr; + struct islpci_bss_wpa_ie *bss = NULL; + size_t len = 0; + + if (down_interruptible(&priv->wpa_sem)) + return 0; + + list_for_each(ptr, &priv->bss_wpa_list) { + bss = list_entry(ptr, struct islpci_bss_wpa_ie, list); + if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0) + break; + bss = NULL; + } + if (bss) { + len = bss->wpa_ie_len; + memcpy(wpa_ie, bss->wpa_ie, len); + } + up(&priv->wpa_sem); + + return len; +} + +void +prism54_wpa_ie_init(islpci_private *priv) +{ + INIT_LIST_HEAD(&priv->bss_wpa_list); + sema_init(&priv->wpa_sem, 1); +} + +void +prism54_wpa_ie_clean(islpci_private *priv) +{ + struct list_head *ptr, *n; + + list_for_each_safe(ptr, n, &priv->bss_wpa_list) { + struct islpci_bss_wpa_ie *bss; + bss = list_entry(ptr, struct islpci_bss_wpa_ie, list); + kfree(bss); + } +} + +static void +prism54_process_bss_data(islpci_private *priv, u32 oid, u8 *addr, + u8 *payload, size_t len) +{ + struct ieee80211_beacon_phdr *hdr; + u8 *pos, *end; + + if (!priv->wpa) + return; + + hdr = (struct ieee80211_beacon_phdr *) payload; + pos = (u8 *) (hdr + 1); + end = payload + len; + while (pos < end) { + if (pos + 2 + pos[1] > end) { + printk(KERN_DEBUG "Parsing Beacon/ProbeResp failed " + "for " MACSTR "\n", MAC2STR(addr)); + return; + } + if (pos[0] == WLAN_EID_GENERIC && pos[1] >= 4 && + memcmp(pos + 2, wpa_oid, 4) == 0) { + prism54_wpa_ie_add(priv, addr, pos, pos[1] + 2); + return; + } + pos += 2 + pos[1]; + } +} + +static void +handle_request(islpci_private *priv, struct obj_mlme *mlme, enum oid_num_t oid) +{ + if (((mlme->state == DOT11_STATE_AUTHING) || + (mlme->state == DOT11_STATE_ASSOCING)) + && mgt_mlme_answer(priv)) { + /* Someone is requesting auth and we must respond. Just send back + * the trap with error code set accordingly. + */ + mlme->code = prism54_mac_accept(&priv->acl, + mlme->address) ? 0 : 1; + mgt_set_request(priv, oid, 0, mlme); + } +} + +int +prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid, + char *data) +{ + struct obj_mlme *mlme = (struct obj_mlme *) data; + size_t len; + u8 *payload, *pos = (u8 *) (mlme + 1); + + len = pos[0] | (pos[1] << 8); /* little endian data length */ + payload = pos + 2; + + /* I think all trapable objects are listed here. + * Some oids have a EX version. The difference is that they are emitted + * in DOT11_MLME_EXTENDED mode (set with DOT11_OID_MLMEAUTOLEVEL) + * with more info. + * The few events already defined by the wireless tools are not really + * suited. We use the more flexible custom event facility. + */ + + /* I fear prism54_process_bss_data won't work with big endian data */ + if ((oid == DOT11_OID_BEACON) || (oid == DOT11_OID_PROBE)) + prism54_process_bss_data(priv, oid, mlme->address, + payload, len); + + mgt_le_to_cpu(isl_oid[oid].flags & OID_FLAG_TYPE, (void *) mlme); + + switch (oid) { + + case GEN_OID_LINKSTATE: + link_changed(priv->ndev, (u32) *data); + break; + + case DOT11_OID_MICFAILURE: + send_simple_event(priv, "Mic failure"); + break; + + case DOT11_OID_DEAUTHENTICATE: + send_formatted_event(priv, "DeAuthenticate request", mlme, 0); + break; + + case DOT11_OID_AUTHENTICATE: + handle_request(priv, mlme, oid); + send_formatted_event(priv, "Authenticate request", mlme, 1); + break; + + case DOT11_OID_DISASSOCIATE: + send_formatted_event(priv, "Disassociate request", mlme, 0); + break; + + case DOT11_OID_ASSOCIATE: + handle_request(priv, mlme, oid); + send_formatted_event(priv, "Associate request", mlme, 1); + break; + + case DOT11_OID_REASSOCIATE: + handle_request(priv, mlme, oid); + send_formatted_event(priv, "ReAssociate request", mlme, 1); + break; + + case DOT11_OID_BEACON: + send_formatted_event(priv, + "Received a beacon from an unkown AP", + mlme, 0); + break; + + case DOT11_OID_PROBE: + /* we received a probe from a client. */ + send_formatted_event(priv, "Received a probe from client", mlme, + 0); + break; + + /* Note : "mlme" is actually a "struct obj_mlmeex *" here, but this + * is backward compatible layout-wise with "struct obj_mlme". + */ + + case DOT11_OID_DEAUTHENTICATEEX: + send_formatted_event(priv, "DeAuthenticate request", mlme, 0); + break; + + case DOT11_OID_AUTHENTICATEEX: + handle_request(priv, mlme, oid); + send_formatted_event(priv, "Authenticate request", mlme, 1); + break; + + case DOT11_OID_DISASSOCIATEEX: + send_formatted_event(priv, "Disassociate request", mlme, 0); + break; + + case DOT11_OID_ASSOCIATEEX: + handle_request(priv, mlme, oid); + send_formatted_event(priv, "Associate request", mlme, 1); + break; + + case DOT11_OID_REASSOCIATEEX: + handle_request(priv, mlme, oid); + send_formatted_event(priv, "Reassociate request", mlme, 1); + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* + * Process a device trap. This is called via schedule_work(), outside of + * interrupt context, no locks held. + */ +void +prism54_process_trap(void *data) +{ + struct islpci_mgmtframe *frame = data; + struct net_device *ndev = frame->ndev; + enum oid_num_t n = mgt_oidtonum(frame->header->oid); + + if (n != OID_NUM_LAST) + prism54_process_trap_helper(netdev_priv(ndev), n, frame->data); + islpci_mgt_release(frame); +} + +int +prism54_set_mac_address(struct net_device *ndev, void *addr) +{ + islpci_private *priv = netdev_priv(ndev); + int ret; + + if (ndev->addr_len != 6) + return -EINVAL; + ret = mgt_set_request(priv, GEN_OID_MACADDRESS, 0, + &((struct sockaddr *) addr)->sa_data); + if (!ret) + memcpy(priv->ndev->dev_addr, + &((struct sockaddr *) addr)->sa_data, 6); + + return ret; +} + +int +prism54_set_wpa(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + + down_write(&priv->mib_sem); + + priv->wpa = *uwrq; + if (priv->wpa) { + u32 l = DOT11_MLME_EXTENDED; + mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &l); + } + /* restart the card with new level. Needed ? */ + mgt_commit(priv); + up_write(&priv->mib_sem); + + return 0; +} + +int +prism54_get_wpa(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + *uwrq = priv->wpa; + return 0; +} + +int +prism54_set_prismhdr(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + priv->monitor_type = + (*uwrq ? ARPHRD_IEEE80211_PRISM : ARPHRD_IEEE80211); + if (priv->iw_mode == IW_MODE_MONITOR) + priv->ndev->type = priv->monitor_type; + + return 0; +} + +int +prism54_get_prismhdr(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + *uwrq = (priv->monitor_type == ARPHRD_IEEE80211_PRISM); + return 0; +} + +int +prism54_debug_oid(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + + priv->priv_oid = *uwrq; + printk("%s: oid 0x%08X\n", ndev->name, *uwrq); + + return 0; +} + +int +prism54_debug_get_oid(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + struct islpci_mgmtframe *response = NULL; + int ret = -EIO, response_op = PIMFOR_OP_ERROR; + + printk("%s: get_oid 0x%08X\n", ndev->name, priv->priv_oid); + data->length = 0; + + if (islpci_get_state(priv) >= PRV_STATE_INIT) { + ret = + islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET, + priv->priv_oid, extra, 256, + &response); + response_op = response->header->operation; + printk("%s: ret: %i\n", ndev->name, ret); + printk("%s: response_op: %i\n", ndev->name, response_op); + if (ret || !response + || response->header->operation == PIMFOR_OP_ERROR) { + if (response) { + islpci_mgt_release(response); + } + printk("%s: EIO\n", ndev->name); + ret = -EIO; + } + if (!ret) { + data->length = response->header->length; + memcpy(extra, response->data, data->length); + islpci_mgt_release(response); + printk("%s: len: %i\n", ndev->name, data->length); + } + } + + return ret; +} + +int +prism54_debug_set_oid(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + struct islpci_mgmtframe *response = NULL; + int ret = 0, response_op = PIMFOR_OP_ERROR; + + printk("%s: set_oid 0x%08X\tlen: %d\n", ndev->name, priv->priv_oid, + data->length); + + if (islpci_get_state(priv) >= PRV_STATE_INIT) { + ret = + islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, + priv->priv_oid, extra, data->length, + &response); + printk("%s: ret: %i\n", ndev->name, ret); + if (!ret) { + response_op = response->header->operation; + printk("%s: response_op: %i\n", ndev->name, + response_op); + islpci_mgt_release(response); + } + if (ret || response_op == PIMFOR_OP_ERROR) { + printk("%s: EIO\n", ndev->name); + ret = -EIO; + } + } + + return (ret ? ret : -EINPROGRESS); +} + +static int +prism54_set_spy(struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *uwrq, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + u32 u, oid = OID_INL_CONFIG; + + down_write(&priv->mib_sem); + mgt_get(priv, OID_INL_CONFIG, &u); + + if ((uwrq->data.length == 0) && (priv->spy_data.spy_number > 0)) + /* disable spy */ + u &= ~INL_CONFIG_RXANNEX; + else if ((uwrq->data.length > 0) && (priv->spy_data.spy_number == 0)) + /* enable spy */ + u |= INL_CONFIG_RXANNEX; + + mgt_set(priv, OID_INL_CONFIG, &u); + mgt_commit_list(priv, &oid, 1); + up_write(&priv->mib_sem); + + return iw_handler_set_spy(ndev, info, uwrq, extra); +} + +static const iw_handler prism54_handler[] = { + (iw_handler) prism54_commit, /* SIOCSIWCOMMIT */ + (iw_handler) prism54_get_name, /* SIOCGIWNAME */ + (iw_handler) NULL, /* SIOCSIWNWID */ + (iw_handler) NULL, /* SIOCGIWNWID */ + (iw_handler) prism54_set_freq, /* SIOCSIWFREQ */ + (iw_handler) prism54_get_freq, /* SIOCGIWFREQ */ + (iw_handler) prism54_set_mode, /* SIOCSIWMODE */ + (iw_handler) prism54_get_mode, /* SIOCGIWMODE */ + (iw_handler) prism54_set_sens, /* SIOCSIWSENS */ + (iw_handler) prism54_get_sens, /* SIOCGIWSENS */ + (iw_handler) NULL, /* SIOCSIWRANGE */ + (iw_handler) prism54_get_range, /* SIOCGIWRANGE */ + (iw_handler) NULL, /* SIOCSIWPRIV */ + (iw_handler) NULL, /* SIOCGIWPRIV */ + (iw_handler) NULL, /* SIOCSIWSTATS */ + (iw_handler) NULL, /* SIOCGIWSTATS */ + prism54_set_spy, /* SIOCSIWSPY */ + iw_handler_get_spy, /* SIOCGIWSPY */ + iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ + iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ + (iw_handler) prism54_set_wap, /* SIOCSIWAP */ + (iw_handler) prism54_get_wap, /* SIOCGIWAP */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* SIOCGIWAPLIST depreciated */ + (iw_handler) prism54_set_scan, /* SIOCSIWSCAN */ + (iw_handler) prism54_get_scan, /* SIOCGIWSCAN */ + (iw_handler) prism54_set_essid, /* SIOCSIWESSID */ + (iw_handler) prism54_get_essid, /* SIOCGIWESSID */ + (iw_handler) prism54_set_nick, /* SIOCSIWNICKN */ + (iw_handler) prism54_get_nick, /* SIOCGIWNICKN */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) prism54_set_rate, /* SIOCSIWRATE */ + (iw_handler) prism54_get_rate, /* SIOCGIWRATE */ + (iw_handler) prism54_set_rts, /* SIOCSIWRTS */ + (iw_handler) prism54_get_rts, /* SIOCGIWRTS */ + (iw_handler) prism54_set_frag, /* SIOCSIWFRAG */ + (iw_handler) prism54_get_frag, /* SIOCGIWFRAG */ + (iw_handler) prism54_set_txpower, /* SIOCSIWTXPOW */ + (iw_handler) prism54_get_txpower, /* SIOCGIWTXPOW */ + (iw_handler) prism54_set_retry, /* SIOCSIWRETRY */ + (iw_handler) prism54_get_retry, /* SIOCGIWRETRY */ + (iw_handler) prism54_set_encode, /* SIOCSIWENCODE */ + (iw_handler) prism54_get_encode, /* SIOCGIWENCODE */ + (iw_handler) NULL, /* SIOCSIWPOWER */ + (iw_handler) NULL, /* SIOCGIWPOWER */ +}; + +/* The low order bit identify a SET (0) or a GET (1) ioctl. */ + +#define PRISM54_RESET SIOCIWFIRSTPRIV +#define PRISM54_GET_POLICY SIOCIWFIRSTPRIV+1 +#define PRISM54_SET_POLICY SIOCIWFIRSTPRIV+2 +#define PRISM54_GET_MAC SIOCIWFIRSTPRIV+3 +#define PRISM54_ADD_MAC SIOCIWFIRSTPRIV+4 + +#define PRISM54_DEL_MAC SIOCIWFIRSTPRIV+6 + +#define PRISM54_KICK_MAC SIOCIWFIRSTPRIV+8 + +#define PRISM54_KICK_ALL SIOCIWFIRSTPRIV+10 + +#define PRISM54_GET_WPA SIOCIWFIRSTPRIV+11 +#define PRISM54_SET_WPA SIOCIWFIRSTPRIV+12 + +#define PRISM54_DBG_OID SIOCIWFIRSTPRIV+14 +#define PRISM54_DBG_GET_OID SIOCIWFIRSTPRIV+15 +#define PRISM54_DBG_SET_OID SIOCIWFIRSTPRIV+16 + +#define PRISM54_GET_OID SIOCIWFIRSTPRIV+17 +#define PRISM54_SET_OID_U32 SIOCIWFIRSTPRIV+18 +#define PRISM54_SET_OID_STR SIOCIWFIRSTPRIV+20 +#define PRISM54_SET_OID_ADDR SIOCIWFIRSTPRIV+22 + +#define PRISM54_GET_PRISMHDR SIOCIWFIRSTPRIV+23 +#define PRISM54_SET_PRISMHDR SIOCIWFIRSTPRIV+24 + +#define IWPRIV_SET_U32(n,x) { n, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x } +#define IWPRIV_SET_SSID(n,x) { n, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x } +#define IWPRIV_SET_ADDR(n,x) { n, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x } +#define IWPRIV_GET(n,x) { n, 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | PRIV_STR_SIZE, "g_"x } + +#define IWPRIV_U32(n,x) IWPRIV_SET_U32(n,x), IWPRIV_GET(n,x) +#define IWPRIV_SSID(n,x) IWPRIV_SET_SSID(n,x), IWPRIV_GET(n,x) +#define IWPRIV_ADDR(n,x) IWPRIV_SET_ADDR(n,x), IWPRIV_GET(n,x) + +/* Note : limited to 128 private ioctls (wireless tools 26) */ + +static const struct iw_priv_args prism54_private_args[] = { +/*{ cmd, set_args, get_args, name } */ + {PRISM54_RESET, 0, 0, "reset"}, + {PRISM54_GET_PRISMHDR, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_prismhdr"}, + {PRISM54_SET_PRISMHDR, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "set_prismhdr"}, + {PRISM54_GET_POLICY, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "getPolicy"}, + {PRISM54_SET_POLICY, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "setPolicy"}, + {PRISM54_GET_MAC, 0, IW_PRIV_TYPE_ADDR | 64, "getMac"}, + {PRISM54_ADD_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, + "addMac"}, + {PRISM54_DEL_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, + "delMac"}, + {PRISM54_KICK_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, + "kickMac"}, + {PRISM54_KICK_ALL, 0, 0, "kickAll"}, + {PRISM54_GET_WPA, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_wpa"}, + {PRISM54_SET_WPA, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "set_wpa"}, + {PRISM54_DBG_OID, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "dbg_oid"}, + {PRISM54_DBG_GET_OID, 0, IW_PRIV_TYPE_BYTE | 256, "dbg_get_oid"}, + {PRISM54_DBG_SET_OID, IW_PRIV_TYPE_BYTE | 256, 0, "dbg_set_oid"}, + /* --- sub-ioctls handlers --- */ + {PRISM54_GET_OID, + 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | PRIV_STR_SIZE, ""}, + {PRISM54_SET_OID_U32, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, ""}, + {PRISM54_SET_OID_STR, + IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 1, 0, ""}, + {PRISM54_SET_OID_ADDR, + IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, ""}, + /* --- sub-ioctls definitions --- */ + IWPRIV_ADDR(GEN_OID_MACADDRESS, "addr"), + IWPRIV_GET(GEN_OID_LINKSTATE, "linkstate"), + IWPRIV_U32(DOT11_OID_BSSTYPE, "bsstype"), + IWPRIV_ADDR(DOT11_OID_BSSID, "bssid"), + IWPRIV_U32(DOT11_OID_STATE, "state"), + IWPRIV_U32(DOT11_OID_AID, "aid"), + + IWPRIV_SSID(DOT11_OID_SSIDOVERRIDE, "ssidoverride"), + + IWPRIV_U32(DOT11_OID_MEDIUMLIMIT, "medlimit"), + IWPRIV_U32(DOT11_OID_BEACONPERIOD, "beacon"), + IWPRIV_U32(DOT11_OID_DTIMPERIOD, "dtimperiod"), + + IWPRIV_U32(DOT11_OID_AUTHENABLE, "authenable"), + IWPRIV_U32(DOT11_OID_PRIVACYINVOKED, "privinvok"), + IWPRIV_U32(DOT11_OID_EXUNENCRYPTED, "exunencrypt"), + + IWPRIV_U32(DOT11_OID_REKEYTHRESHOLD, "rekeythresh"), + + IWPRIV_U32(DOT11_OID_MAXTXLIFETIME, "maxtxlife"), + IWPRIV_U32(DOT11_OID_MAXRXLIFETIME, "maxrxlife"), + IWPRIV_U32(DOT11_OID_ALOFT_FIXEDRATE, "fixedrate"), + IWPRIV_U32(DOT11_OID_MAXFRAMEBURST, "frameburst"), + IWPRIV_U32(DOT11_OID_PSM, "psm"), + + IWPRIV_U32(DOT11_OID_BRIDGELOCAL, "bridge"), + IWPRIV_U32(DOT11_OID_CLIENTS, "clients"), + IWPRIV_U32(DOT11_OID_CLIENTSASSOCIATED, "clientassoc"), + IWPRIV_U32(DOT11_OID_DOT1XENABLE, "dot1xenable"), + IWPRIV_U32(DOT11_OID_ANTENNARX, "rxant"), + IWPRIV_U32(DOT11_OID_ANTENNATX, "txant"), + IWPRIV_U32(DOT11_OID_ANTENNADIVERSITY, "antdivers"), + IWPRIV_U32(DOT11_OID_EDTHRESHOLD, "edthresh"), + IWPRIV_U32(DOT11_OID_PREAMBLESETTINGS, "preamble"), + IWPRIV_GET(DOT11_OID_RATES, "rates"), + IWPRIV_U32(DOT11_OID_OUTPUTPOWER, ".11outpower"), + IWPRIV_GET(DOT11_OID_SUPPORTEDRATES, "supprates"), + IWPRIV_GET(DOT11_OID_SUPPORTEDFREQUENCIES, "suppfreq"), + + IWPRIV_U32(DOT11_OID_NOISEFLOOR, "noisefloor"), + IWPRIV_GET(DOT11_OID_FREQUENCYACTIVITY, "freqactivity"), + IWPRIV_U32(DOT11_OID_NONERPPROTECTION, "nonerpprotec"), + IWPRIV_U32(DOT11_OID_PROFILES, "profile"), + IWPRIV_GET(DOT11_OID_EXTENDEDRATES, "extrates"), + IWPRIV_U32(DOT11_OID_MLMEAUTOLEVEL, "mlmelevel"), + + IWPRIV_GET(DOT11_OID_BSSS, "bsss"), + IWPRIV_GET(DOT11_OID_BSSLIST, "bsslist"), + IWPRIV_U32(OID_INL_MODE, "mode"), + IWPRIV_U32(OID_INL_CONFIG, "config"), + IWPRIV_U32(OID_INL_DOT11D_CONFORMANCE, ".11dconform"), + IWPRIV_GET(OID_INL_PHYCAPABILITIES, "phycapa"), + IWPRIV_U32(OID_INL_OUTPUTPOWER, "outpower"), +}; + +static const iw_handler prism54_private_handler[] = { + (iw_handler) prism54_reset, + (iw_handler) prism54_get_policy, + (iw_handler) prism54_set_policy, + (iw_handler) prism54_get_mac, + (iw_handler) prism54_add_mac, + (iw_handler) NULL, + (iw_handler) prism54_del_mac, + (iw_handler) NULL, + (iw_handler) prism54_kick_mac, + (iw_handler) NULL, + (iw_handler) prism54_kick_all, + (iw_handler) prism54_get_wpa, + (iw_handler) prism54_set_wpa, + (iw_handler) NULL, + (iw_handler) prism54_debug_oid, + (iw_handler) prism54_debug_get_oid, + (iw_handler) prism54_debug_set_oid, + (iw_handler) prism54_get_oid, + (iw_handler) prism54_set_u32, + (iw_handler) NULL, + (iw_handler) prism54_set_raw, + (iw_handler) NULL, + (iw_handler) prism54_set_raw, + (iw_handler) prism54_get_prismhdr, + (iw_handler) prism54_set_prismhdr, +}; + +const struct iw_handler_def prism54_handler_def = { + .num_standard = sizeof (prism54_handler) / sizeof (iw_handler), + .num_private = sizeof (prism54_private_handler) / sizeof (iw_handler), + .num_private_args = + sizeof (prism54_private_args) / sizeof (struct iw_priv_args), + .standard = (iw_handler *) prism54_handler, + .private = (iw_handler *) prism54_private_handler, + .private_args = (struct iw_priv_args *) prism54_private_args, + .spy_offset = offsetof(islpci_private, spy_data), +}; + +/* For ioctls that don't work with the new API */ + +int +prism54_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) +{ + + return -EOPNOTSUPP; +} diff -Nru a/drivers/net/wireless/prism54/isl_ioctl.h b/drivers/net/wireless/prism54/isl_ioctl.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/net/wireless/prism54/isl_ioctl.h 2004-08-14 12:02:31 -07:00 @@ -0,0 +1,54 @@ +/* + * + * Copyright (C) 2002 Intersil Americas Inc. + * (C) 2003 Aurelien Alleaume + * (C) 2003 Luis R. Rodriguez + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _ISL_IOCTL_H +#define _ISL_IOCTL_H + +#include "islpci_mgt.h" +#include "islpci_dev.h" + +#include /* New driver API */ + +#define SUPPORTED_WIRELESS_EXT 16 + +void prism54_mib_init(islpci_private *); + +struct iw_statistics *prism54_get_wireless_stats(struct net_device *); +void prism54_update_stats(islpci_private *); + +void prism54_acl_init(struct islpci_acl *); +void prism54_acl_clean(struct islpci_acl *); + +void prism54_process_trap(void *); + +void prism54_wpa_ie_init(islpci_private *priv); +void prism54_wpa_ie_clean(islpci_private *priv); +void prism54_wpa_ie_add(islpci_private *priv, u8 *bssid, + u8 *wpa_ie, size_t wpa_ie_len); +size_t prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie); + +int prism54_set_mac_address(struct net_device *, void *); + +int prism54_ioctl(struct net_device *, struct ifreq *, int); + +extern const struct iw_handler_def prism54_handler_def; + +#endif /* _ISL_IOCTL_H */ diff -Nru a/drivers/net/wireless/prism54/isl_oid.h b/drivers/net/wireless/prism54/isl_oid.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/net/wireless/prism54/isl_oid.h 2004-08-14 12:02:31 -07:00 @@ -0,0 +1,498 @@ +/* + * + * + * Copyright (C) 2003 Herbert Valerio Riedel + * Copyright (C) 2004 Luis R. Rodriguez + * Copyright (C) 2004 Aurelien Alleaume + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#if !defined(_ISL_OID_H) +#define _ISL_OID_H + +/* + * MIB related constant and structure definitions for communicating + * with the device firmware + */ + +struct obj_ssid { + u8 length; + char octets[33]; +} __attribute__ ((packed)); + +struct obj_key { + u8 type; /* dot11_priv_t */ + u8 length; + char key[32]; +} __attribute__ ((packed)); + +struct obj_mlme { + u8 address[6]; + u16 id; + u16 state; + u16 code; +} __attribute__ ((packed)); + +struct obj_mlmeex { + u8 address[6]; + u16 id; + u16 state; + u16 code; + u16 size; + u8 data[0]; +} __attribute__ ((packed)); + +struct obj_buffer { + u32 size; + u32 addr; /* 32bit bus address */ +} __attribute__ ((packed)); + +struct obj_bss { + u8 address[6]; + int:16; /* padding */ + + char state; + char reserved; + short age; + + char quality; + char rssi; + + struct obj_ssid ssid; + short channel; + char beacon_period; + char dtim_period; + short capinfo; + short rates; + short basic_rates; + int:16; /* padding */ +} __attribute__ ((packed)); + +struct obj_bsslist { + u32 nr; + struct obj_bss bsslist[0]; +} __attribute__ ((packed)); + +struct obj_frequencies { + u16 nr; + u16 mhz[0]; +} __attribute__ ((packed)); + +/* + * in case everything's ok, the inlined function below will be + * optimized away by the compiler... + */ +static inline void +__bug_on_wrong_struct_sizes(void) +{ + BUG_ON(sizeof (struct obj_ssid) != 34); + BUG_ON(sizeof (struct obj_key) != 34); + BUG_ON(sizeof (struct obj_mlme) != 12); + BUG_ON(sizeof (struct obj_mlmeex) != 14); + BUG_ON(sizeof (struct obj_buffer) != 8); + BUG_ON(sizeof (struct obj_bss) != 60); + BUG_ON(sizeof (struct obj_bsslist) != 4); + BUG_ON(sizeof (struct obj_frequencies) != 2); +} + +enum dot11_state_t { + DOT11_STATE_NONE = 0, + DOT11_STATE_AUTHING = 1, + DOT11_STATE_AUTH = 2, + DOT11_STATE_ASSOCING = 3, + + DOT11_STATE_ASSOC = 5, + DOT11_STATE_IBSS = 6, + DOT11_STATE_WDS = 7 +}; + +enum dot11_bsstype_t { + DOT11_BSSTYPE_NONE = 0, + DOT11_BSSTYPE_INFRA = 1, + DOT11_BSSTYPE_IBSS = 2, + DOT11_BSSTYPE_ANY = 3 +}; + +enum dot11_auth_t { + DOT11_AUTH_NONE = 0, + DOT11_AUTH_OS = 1, + DOT11_AUTH_SK = 2, + DOT11_AUTH_BOTH = 3 +}; + +enum dot11_mlme_t { + DOT11_MLME_AUTO = 0, + DOT11_MLME_INTERMEDIATE = 1, + DOT11_MLME_EXTENDED = 2 +}; + +enum dot11_priv_t { + DOT11_PRIV_WEP = 0, + DOT11_PRIV_TKIP = 1 +}; + +/* Prism "Nitro" / Frameburst / "Packet Frame Grouping" + * Value is in microseconds. Represents the # microseconds + * the firmware will take to group frames before sending out then out + * together with a CSMA contention. Without this all frames are + * sent with a CSMA contention. + * Bibliography: + * http://www.hpl.hp.com/personal/Jean_Tourrilhes/Papers/Packet.Frame.Grouping.html + */ +enum dot11_maxframeburst_t { + /* Values for DOT11_OID_MAXFRAMEBURST */ + DOT11_MAXFRAMEBURST_OFF = 0, /* Card firmware default */ + DOT11_MAXFRAMEBURST_MIXED_SAFE = 650, /* 802.11 a,b,g safe */ + DOT11_MAXFRAMEBURST_IDEAL = 1300, /* Theoretical ideal level */ + DOT11_MAXFRAMEBURST_MAX = 5000, /* Use this as max, + * Note: firmware allows for greater values. This is a + * recommended max. I'll update this as I find + * out what the real MAX is. Also note that you don't necessarily + * get better results with a greater value here. + */ +}; + +/* Support for 802.11 long and short frame preambles. + * Long preamble uses 128-bit sync field, 8-bit CRC + * Short preamble uses 56-bit sync field, 16-bit CRC + * + * 802.11a -- not sure, both optionally ? + * 802.11b supports long and optionally short + * 802.11g supports both */ +enum dot11_preamblesettings_t { + DOT11_PREAMBLESETTING_LONG = 0, + /* Allows *only* long 802.11 preambles */ + DOT11_PREAMBLESETTING_SHORT = 1, + /* Allows *only* short 802.11 preambles */ + DOT11_PREAMBLESETTING_DYNAMIC = 2 + /* AutomatiGically set */ +}; + +/* Support for 802.11 slot timing (time between packets). + * + * Long uses 802.11a slot timing (9 usec ?) + * Short uses 802.11b slot timing (20 use ?) */ +enum dot11_slotsettings_t { + DOT11_SLOTSETTINGS_LONG = 0, + /* Allows *only* long 802.11b slot timing */ + DOT11_SLOTSETTINGS_SHORT = 1, + /* Allows *only* long 802.11a slot timing */ + DOT11_SLOTSETTINGS_DYNAMIC = 2 + /* AutomatiGically set */ +}; + +/* All you need to know, ERP is "Extended Rate PHY". + * An Extended Rate PHY (ERP) STA or AP shall support three different + * preamble and header formats: + * Long preamble (refer to above) + * Short preamble (refer to above) + * OFDM preamble ( ? ) + * + * I'm assuming here Protection tells the AP + * to be careful, a STA which cannot handle the long pre-amble + * has joined. + */ +enum do11_nonerpstatus_t { + DOT11_ERPSTAT_NONEPRESENT = 0, + DOT11_ERPSTAT_USEPROTECTION = 1 +}; + +/* (ERP is "Extended Rate PHY") Way to read NONERP is NON-ERP-* + * The key here is DOT11 NON ERP NEVER protects against + * NON ERP STA's. You *don't* want this unless + * you know what you are doing. It means you will only + * get Extended Rate capabilities */ +enum dot11_nonerpprotection_t { + DOT11_NONERP_NEVER = 0, + DOT11_NONERP_ALWAYS = 1, + DOT11_NONERP_DYNAMIC = 2 +}; + +/* Preset OID configuration for 802.11 modes + * Note: DOT11_OID_CW[MIN|MAX] hold the values of the + * DCS MIN|MAX backoff used */ +enum dot11_profile_t { /* And set/allowed values */ + /* Allowed values for DOT11_OID_PROFILES */ + DOT11_PROFILE_B_ONLY = 0, + /* DOT11_OID_RATES: 1, 2, 5.5, 11Mbps + * DOT11_OID_PREAMBLESETTINGS: DOT11_PREAMBLESETTING_DYNAMIC + * DOT11_OID_CWMIN: 31 + * DOT11_OID_NONEPROTECTION: DOT11_NOERP_DYNAMIC + * DOT11_OID_SLOTSETTINGS: DOT11_SLOTSETTINGS_LONG + */ + DOT11_PROFILE_MIXED_G_WIFI = 1, + /* DOT11_OID_RATES: 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54Mbs + * DOT11_OID_PREAMBLESETTINGS: DOT11_PREAMBLESETTING_DYNAMIC + * DOT11_OID_CWMIN: 15 + * DOT11_OID_NONEPROTECTION: DOT11_NOERP_DYNAMIC + * DOT11_OID_SLOTSETTINGS: DOT11_SLOTSETTINGS_DYNAMIC + */ + DOT11_PROFILE_MIXED_LONG = 2, /* "Long range" */ + /* Same as Profile MIXED_G_WIFI */ + DOT11_PROFILE_G_ONLY = 3, + /* Same as Profile MIXED_G_WIFI */ + DOT11_PROFILE_TEST = 4, + /* Same as Profile MIXED_G_WIFI except: + * DOT11_OID_PREAMBLESETTINGS: DOT11_PREAMBLESETTING_SHORT + * DOT11_OID_NONEPROTECTION: DOT11_NOERP_NEVER + * DOT11_OID_SLOTSETTINGS: DOT11_SLOTSETTINGS_SHORT + */ + DOT11_PROFILE_B_WIFI = 5, + /* Same as Profile B_ONLY */ + DOT11_PROFILE_A_ONLY = 6, + /* Same as Profile MIXED_G_WIFI except: + * DOT11_OID_RATES: 6, 9, 12, 18, 24, 36, 48, 54Mbs + */ + DOT11_PROFILE_MIXED_SHORT = 7 + /* Same as MIXED_G_WIFI */ +}; + + +/* The dot11d conformance level configures the 802.11d conformance levels. + * The following conformance levels exist:*/ +enum oid_inl_conformance_t { + OID_INL_CONFORMANCE_NONE = 0, /* Perform active scanning */ + OID_INL_CONFORMANCE_STRICT = 1, /* Strictly adhere to 802.11d */ + OID_INL_CONFORMANCE_FLEXIBLE = 2, /* Use passed 802.11d info to + * determine channel AND/OR just make assumption that active + * channels are valid channels */ +}; + +enum oid_inl_mode_t { + INL_MODE_NONE = -1, + INL_MODE_PROMISCUOUS = 0, + INL_MODE_CLIENT = 1, + INL_MODE_AP = 2, + INL_MODE_SNIFFER = 3 +}; + +enum oid_inl_config_t { + INL_CONFIG_NOTHING = 0x00, + INL_CONFIG_MANUALRUN = 0x01, + INL_CONFIG_FRAMETRAP = 0x02, + INL_CONFIG_RXANNEX = 0x04, + INL_CONFIG_TXANNEX = 0x08, + INL_CONFIG_WDS = 0x10 +}; + +enum oid_inl_phycap_t { + INL_PHYCAP_2400MHZ = 1, + INL_PHYCAP_5000MHZ = 2, + INL_PHYCAP_FAA = 0x80000000, /* Means card supports the FAA switch */ +}; + + +enum oid_num_t { + GEN_OID_MACADDRESS = 0, + GEN_OID_LINKSTATE, + GEN_OID_WATCHDOG, + GEN_OID_MIBOP, + GEN_OID_OPTIONS, + GEN_OID_LEDCONFIG, + + /* 802.11 */ + DOT11_OID_BSSTYPE, + DOT11_OID_BSSID, + DOT11_OID_SSID, + DOT11_OID_STATE, + DOT11_OID_AID, + DOT11_OID_COUNTRYSTRING, + DOT11_OID_SSIDOVERRIDE, + + DOT11_OID_MEDIUMLIMIT, + DOT11_OID_BEACONPERIOD, + DOT11_OID_DTIMPERIOD, + DOT11_OID_ATIMWINDOW, + DOT11_OID_LISTENINTERVAL, + DOT11_OID_CFPPERIOD, + DOT11_OID_CFPDURATION, + + DOT11_OID_AUTHENABLE, + DOT11_OID_PRIVACYINVOKED, + DOT11_OID_EXUNENCRYPTED, + DOT11_OID_DEFKEYID, + DOT11_OID_DEFKEYX, /* DOT11_OID_DEFKEY1,...DOT11_OID_DEFKEY4 */ + DOT11_OID_STAKEY, + DOT11_OID_REKEYTHRESHOLD, + DOT11_OID_STASC, + + DOT11_OID_PRIVTXREJECTED, + DOT11_OID_PRIVRXPLAIN, + DOT11_OID_PRIVRXFAILED, + DOT11_OID_PRIVRXNOKEY, + + DOT11_OID_RTSTHRESH, + DOT11_OID_FRAGTHRESH, + DOT11_OID_SHORTRETRIES, + DOT11_OID_LONGRETRIES, + DOT11_OID_MAXTXLIFETIME, + DOT11_OID_MAXRXLIFETIME, + DOT11_OID_AUTHRESPTIMEOUT, + DOT11_OID_ASSOCRESPTIMEOUT, + + DOT11_OID_ALOFT_TABLE, + DOT11_OID_ALOFT_CTRL_TABLE, + DOT11_OID_ALOFT_RETREAT, + DOT11_OID_ALOFT_PROGRESS, + DOT11_OID_ALOFT_FIXEDRATE, + DOT11_OID_ALOFT_RSSIGRAPH, + DOT11_OID_ALOFT_CONFIG, + + DOT11_OID_VDCFX, + DOT11_OID_MAXFRAMEBURST, + + DOT11_OID_PSM, + DOT11_OID_CAMTIMEOUT, + DOT11_OID_RECEIVEDTIMS, + DOT11_OID_ROAMPREFERENCE, + + DOT11_OID_BRIDGELOCAL, + DOT11_OID_CLIENTS, + DOT11_OID_CLIENTSASSOCIATED, + DOT11_OID_CLIENTX, /* DOT11_OID_CLIENTX,...DOT11_OID_CLIENT2007 */ + + DOT11_OID_CLIENTFIND, + DOT11_OID_WDSLINKADD, + DOT11_OID_WDSLINKREMOVE, + DOT11_OID_EAPAUTHSTA, + DOT11_OID_EAPUNAUTHSTA, + DOT11_OID_DOT1XENABLE, + DOT11_OID_MICFAILURE, + DOT11_OID_REKEYINDICATE, + + DOT11_OID_MPDUTXSUCCESSFUL, + DOT11_OID_MPDUTXONERETRY, + DOT11_OID_MPDUTXMULTIPLERETRIES, + DOT11_OID_MPDUTXFAILED, + DOT11_OID_MPDURXSUCCESSFUL, + DOT11_OID_MPDURXDUPS, + DOT11_OID_RTSSUCCESSFUL, + DOT11_OID_RTSFAILED, + DOT11_OID_ACKFAILED, + DOT11_OID_FRAMERECEIVES, + DOT11_OID_FRAMEERRORS, + DOT11_OID_FRAMEABORTS, + DOT11_OID_FRAMEABORTSPHY, + + DOT11_OID_SLOTTIME, + DOT11_OID_CWMIN, /* MIN DCS backoff */ + DOT11_OID_CWMAX, /* MAX DCS backoff */ + DOT11_OID_ACKWINDOW, + DOT11_OID_ANTENNARX, + DOT11_OID_ANTENNATX, + DOT11_OID_ANTENNADIVERSITY, + DOT11_OID_CHANNEL, + DOT11_OID_EDTHRESHOLD, + DOT11_OID_PREAMBLESETTINGS, + DOT11_OID_RATES, + DOT11_OID_CCAMODESUPPORTED, + DOT11_OID_CCAMODE, + DOT11_OID_RSSIVECTOR, + DOT11_OID_OUTPUTPOWERTABLE, + DOT11_OID_OUTPUTPOWER, + DOT11_OID_SUPPORTEDRATES, + DOT11_OID_FREQUENCY, + DOT11_OID_SUPPORTEDFREQUENCIES, + DOT11_OID_NOISEFLOOR, + DOT11_OID_FREQUENCYACTIVITY, + DOT11_OID_IQCALIBRATIONTABLE, + DOT11_OID_NONERPPROTECTION, + DOT11_OID_SLOTSETTINGS, + DOT11_OID_NONERPTIMEOUT, + DOT11_OID_PROFILES, + DOT11_OID_EXTENDEDRATES, + + DOT11_OID_DEAUTHENTICATE, + DOT11_OID_AUTHENTICATE, + DOT11_OID_DISASSOCIATE, + DOT11_OID_ASSOCIATE, + DOT11_OID_SCAN, + DOT11_OID_BEACON, + DOT11_OID_PROBE, + DOT11_OID_DEAUTHENTICATEEX, + DOT11_OID_AUTHENTICATEEX, + DOT11_OID_DISASSOCIATEEX, + DOT11_OID_ASSOCIATEEX, + DOT11_OID_REASSOCIATE, + DOT11_OID_REASSOCIATEEX, + + DOT11_OID_NONERPSTATUS, + + DOT11_OID_STATIMEOUT, + DOT11_OID_MLMEAUTOLEVEL, + DOT11_OID_BSSTIMEOUT, + DOT11_OID_ATTACHMENT, + DOT11_OID_PSMBUFFER, + + DOT11_OID_BSSS, + DOT11_OID_BSSX, /*DOT11_OID_BSS1,...,DOT11_OID_BSS64 */ + DOT11_OID_BSSFIND, + DOT11_OID_BSSLIST, + + OID_INL_TUNNEL, + OID_INL_MEMADDR, + OID_INL_MEMORY, + OID_INL_MODE, + OID_INL_COMPONENT_NR, + OID_INL_VERSION, + OID_INL_INTERFACE_ID, + OID_INL_COMPONENT_ID, + OID_INL_CONFIG, + OID_INL_DOT11D_CONFORMANCE, + OID_INL_PHYCAPABILITIES, + OID_INL_OUTPUTPOWER, + + OID_NUM_LAST +}; + +#define OID_FLAG_CACHED 0x80 +#define OID_FLAG_TYPE 0x7f + +#define OID_TYPE_U32 0x01 +#define OID_TYPE_SSID 0x02 +#define OID_TYPE_KEY 0x03 +#define OID_TYPE_BUFFER 0x04 +#define OID_TYPE_BSS 0x05 +#define OID_TYPE_BSSLIST 0x06 +#define OID_TYPE_FREQUENCIES 0x07 +#define OID_TYPE_MLME 0x08 +#define OID_TYPE_MLMEEX 0x09 +#define OID_TYPE_ADDR 0x0A +#define OID_TYPE_RAW 0x0B + +/* OID_TYPE_MLMEEX is special because of a variable size field when sending. + * Not yet implemented (not used in driver anyway). + */ + +struct oid_t { + enum oid_num_t oid; + short range; /* to define a range of oid */ + short size; /* max size of the associated data */ + char flags; +}; + +union oid_res_t { + void *ptr; + u32 u; +}; + +#define IWMAX_BITRATES 20 +#define IWMAX_BSS 24 +#define IWMAX_FREQ 30 +#define PRIV_STR_SIZE 1024 + +#endif /* !defined(_ISL_OID_H) */ +/* EOF */ diff -Nru a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/net/wireless/prism54/islpci_dev.c 2004-08-14 12:02:31 -07:00 @@ -0,0 +1,931 @@ +/* + * + * Copyright (C) 2002 Intersil Americas Inc. + * Copyright (C) 2003 Herbert Valerio Riedel + * Copyright (C) 2003 Luis R. Rodriguez + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "prismcompat.h" +#include "isl_38xx.h" +#include "isl_ioctl.h" +#include "islpci_dev.h" +#include "islpci_mgt.h" +#include "islpci_eth.h" +#include "oid_mgt.h" + +#define ISL3877_IMAGE_FILE "isl3877" +#define ISL3890_IMAGE_FILE "isl3890" + +static int prism54_bring_down(islpci_private *); +static int islpci_alloc_memory(islpci_private *); + +/* Temporary dummy MAC address to use until firmware is loaded. + * The idea there is that some tools (such as nameif) may query + * the MAC address before the netdev is 'open'. By using a valid + * OUI prefix, they can process the netdev properly. + * Of course, this is not the final/real MAC address. It doesn't + * matter, as you are suppose to be able to change it anytime via + * ndev->set_mac_address. Jean II */ +const unsigned char dummy_mac[6] = { 0x00, 0x30, 0xB4, 0x00, 0x00, 0x00 }; + +static int +isl_upload_firmware(islpci_private *priv) +{ + u32 reg, rc; + void *device_base = priv->device_base; + + /* clear the RAMBoot and the Reset bit */ + reg = readl(device_base + ISL38XX_CTRL_STAT_REG); + reg &= ~ISL38XX_CTRL_STAT_RESET; + reg &= ~ISL38XX_CTRL_STAT_RAMBOOT; + writel(reg, device_base + ISL38XX_CTRL_STAT_REG); + wmb(); + udelay(ISL38XX_WRITEIO_DELAY); + + /* set the Reset bit without reading the register ! */ + reg |= ISL38XX_CTRL_STAT_RESET; + writel(reg, device_base + ISL38XX_CTRL_STAT_REG); + wmb(); + udelay(ISL38XX_WRITEIO_DELAY); + + /* clear the Reset bit */ + reg &= ~ISL38XX_CTRL_STAT_RESET; + writel(reg, device_base + ISL38XX_CTRL_STAT_REG); + wmb(); + + /* wait a while for the device to reboot */ + mdelay(50); + + { + const struct firmware *fw_entry = 0; + long fw_len; + const u32 *fw_ptr; + + rc = request_firmware(&fw_entry, priv->firmware, PRISM_FW_PDEV); + if (rc) { + printk(KERN_ERR + "%s: request_firmware() failed for '%s'\n", + "prism54", priv->firmware); + return rc; + } + /* prepare the Direct Memory Base register */ + reg = ISL38XX_DEV_FIRMWARE_ADDRES; + + fw_ptr = (u32 *) fw_entry->data; + fw_len = fw_entry->size; + + if (fw_len % 4) { + printk(KERN_ERR + "%s: firmware '%s' size is not multiple of 32bit, aborting!\n", + "prism54", priv->firmware); + release_firmware(fw_entry); + return EILSEQ; /* Illegal byte sequence */; + } + + while (fw_len > 0) { + long _fw_len = + (fw_len > + ISL38XX_MEMORY_WINDOW_SIZE) ? + ISL38XX_MEMORY_WINDOW_SIZE : fw_len; + u32 *dev_fw_ptr = device_base + ISL38XX_DIRECT_MEM_WIN; + + /* set the cards base address for writting the data */ + isl38xx_w32_flush(device_base, reg, + ISL38XX_DIR_MEM_BASE_REG); + wmb(); /* be paranoid */ + + /* increment the write address for next iteration */ + reg += _fw_len; + fw_len -= _fw_len; + + /* write the data to the Direct Memory Window 32bit-wise */ + /* memcpy_toio() doesn't guarantee 32bit writes :-| */ + while (_fw_len > 0) { + /* use non-swapping writel() */ + __raw_writel(*fw_ptr, dev_fw_ptr); + fw_ptr++, dev_fw_ptr++; + _fw_len -= 4; + } + + /* flush PCI posting */ + (void) readl(device_base + ISL38XX_PCI_POSTING_FLUSH); + wmb(); /* be paranoid again */ + + BUG_ON(_fw_len != 0); + } + + BUG_ON(fw_len != 0); + + release_firmware(fw_entry); + } + + /* now reset the device + * clear the Reset & ClkRun bit, set the RAMBoot bit */ + reg = readl(device_base + ISL38XX_CTRL_STAT_REG); + reg &= ~ISL38XX_CTRL_STAT_CLKRUN; + reg &= ~ISL38XX_CTRL_STAT_RESET; + reg |= ISL38XX_CTRL_STAT_RAMBOOT; + isl38xx_w32_flush(device_base, reg, ISL38XX_CTRL_STAT_REG); + wmb(); + udelay(ISL38XX_WRITEIO_DELAY); + + /* set the reset bit latches the host override and RAMBoot bits + * into the device for operation when the reset bit is reset */ + reg |= ISL38XX_CTRL_STAT_RESET; + writel(reg, device_base + ISL38XX_CTRL_STAT_REG); + /* don't do flush PCI posting here! */ + wmb(); + udelay(ISL38XX_WRITEIO_DELAY); + + /* clear the reset bit should start the whole circus */ + reg &= ~ISL38XX_CTRL_STAT_RESET; + writel(reg, device_base + ISL38XX_CTRL_STAT_REG); + /* don't do flush PCI posting here! */ + wmb(); + udelay(ISL38XX_WRITEIO_DELAY); + + return 0; +} + +/****************************************************************************** + Device Interrupt Handler +******************************************************************************/ + +irqreturn_t +islpci_interrupt(int irq, void *config, struct pt_regs *regs) +{ + u32 reg; + islpci_private *priv = config; + struct net_device *ndev = priv->ndev; + void *device = priv->device_base; + int powerstate = ISL38XX_PSM_POWERSAVE_STATE; + + /* received an interrupt request on a shared IRQ line + * first check whether the device is in sleep mode */ + reg = readl(device + ISL38XX_CTRL_STAT_REG); + if (reg & ISL38XX_CTRL_STAT_SLEEPMODE) + /* device is in sleep mode, IRQ was generated by someone else */ + { +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "Assuming someone else called the IRQ\n"); +#endif + return IRQ_NONE; + } + + if (islpci_get_state(priv) != PRV_STATE_SLEEP) + powerstate = ISL38XX_PSM_ACTIVE_STATE; + + /* lock the interrupt handler */ + spin_lock(&priv->slock); + + /* check whether there is any source of interrupt on the device */ + reg = readl(device + ISL38XX_INT_IDENT_REG); + + /* also check the contents of the Interrupt Enable Register, because this + * will filter out interrupt sources from other devices on the same irq ! */ + reg &= readl(device + ISL38XX_INT_EN_REG); + reg &= ISL38XX_INT_SOURCES; + + if (reg != 0) { + /* reset the request bits in the Identification register */ + isl38xx_w32_flush(device, reg, ISL38XX_INT_ACK_REG); + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, + "IRQ: Identification register 0x%p 0x%x \n", device, reg); +#endif + + /* check for each bit in the register separately */ + if (reg & ISL38XX_INT_IDENT_UPDATE) { +#if VERBOSE > SHOW_ERROR_MESSAGES + /* Queue has been updated */ + DEBUG(SHOW_TRACING, "IRQ: Update flag \n"); + + DEBUG(SHOW_QUEUE_INDEXES, + "CB drv Qs: [%i][%i][%i][%i][%i][%i]\n", + le32_to_cpu(priv->control_block-> + driver_curr_frag[0]), + le32_to_cpu(priv->control_block-> + driver_curr_frag[1]), + le32_to_cpu(priv->control_block-> + driver_curr_frag[2]), + le32_to_cpu(priv->control_block-> + driver_curr_frag[3]), + le32_to_cpu(priv->control_block-> + driver_curr_frag[4]), + le32_to_cpu(priv->control_block-> + driver_curr_frag[5]) + ); + + DEBUG(SHOW_QUEUE_INDEXES, + "CB dev Qs: [%i][%i][%i][%i][%i][%i]\n", + le32_to_cpu(priv->control_block-> + device_curr_frag[0]), + le32_to_cpu(priv->control_block-> + device_curr_frag[1]), + le32_to_cpu(priv->control_block-> + device_curr_frag[2]), + le32_to_cpu(priv->control_block-> + device_curr_frag[3]), + le32_to_cpu(priv->control_block-> + device_curr_frag[4]), + le32_to_cpu(priv->control_block-> + device_curr_frag[5]) + ); +#endif + + /* cleanup the data low transmit queue */ + islpci_eth_cleanup_transmit(priv, priv->control_block); + + /* device is in active state, update the + * powerstate flag if necessary */ + powerstate = ISL38XX_PSM_ACTIVE_STATE; + + /* check all three queues in priority order + * call the PIMFOR receive function until the + * queue is empty */ + if (isl38xx_in_queue(priv->control_block, + ISL38XX_CB_RX_MGMTQ) != 0) { +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, + "Received frame in Management Queue\n"); +#endif + islpci_mgt_receive(ndev); + + islpci_mgt_cleanup_transmit(ndev); + + /* Refill slots in receive queue */ + islpci_mgmt_rx_fill(ndev); + + /* no need to trigger the device, next + islpci_mgt_transaction does it */ + } + + while (isl38xx_in_queue(priv->control_block, + ISL38XX_CB_RX_DATA_LQ) != 0) { +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, + "Received frame in Data Low Queue \n"); +#endif + islpci_eth_receive(priv); + } + + /* check whether the data transmit queues were full */ + if (priv->data_low_tx_full) { + /* check whether the transmit is not full anymore */ + if (ISL38XX_CB_TX_QSIZE - + isl38xx_in_queue(priv->control_block, + ISL38XX_CB_TX_DATA_LQ) >= + ISL38XX_MIN_QTHRESHOLD) { + /* nope, the driver is ready for more network frames */ + netif_wake_queue(priv->ndev); + + /* reset the full flag */ + priv->data_low_tx_full = 0; + } + } + } + + if (reg & ISL38XX_INT_IDENT_INIT) { + /* Device has been initialized */ +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, + "IRQ: Init flag, device initialized \n"); +#endif + wake_up(&priv->reset_done); + } + + if (reg & ISL38XX_INT_IDENT_SLEEP) { + /* Device intends to move to powersave state */ +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "IRQ: Sleep flag \n"); +#endif + isl38xx_handle_sleep_request(priv->control_block, + &powerstate, + priv->device_base); + } + + if (reg & ISL38XX_INT_IDENT_WAKEUP) { + /* Device has been woken up to active state */ +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "IRQ: Wakeup flag \n"); +#endif + + isl38xx_handle_wakeup(priv->control_block, + &powerstate, priv->device_base); + } + } + + /* sleep -> ready */ + if (islpci_get_state(priv) == PRV_STATE_SLEEP + && powerstate == ISL38XX_PSM_ACTIVE_STATE) + islpci_set_state(priv, PRV_STATE_READY); + + /* !sleep -> sleep */ + if (islpci_get_state(priv) != PRV_STATE_SLEEP + && powerstate == ISL38XX_PSM_POWERSAVE_STATE) + islpci_set_state(priv, PRV_STATE_SLEEP); + + /* unlock the interrupt handler */ + spin_unlock(&priv->slock); + + return IRQ_HANDLED; +} + +/****************************************************************************** + Network Interface Control & Statistical functions +******************************************************************************/ +static int +islpci_open(struct net_device *ndev) +{ + u32 rc; + islpci_private *priv = netdev_priv(ndev); + + printk(KERN_DEBUG "%s: islpci_open()\n", ndev->name); + + /* reset data structures, upload firmware and reset device */ + rc = islpci_reset(priv,1); + if (rc) { + prism54_bring_down(priv); + return rc; /* Returns informative message */ + } + + netif_start_queue(ndev); +/* netif_mark_up( ndev ); */ + + return 0; +} + +static int +islpci_close(struct net_device *ndev) +{ + islpci_private *priv = netdev_priv(ndev); + + printk(KERN_DEBUG "%s: islpci_close ()\n", ndev->name); + + netif_stop_queue(ndev); + + return prism54_bring_down(priv); +} + +static int +prism54_bring_down(islpci_private *priv) +{ + void *device_base = priv->device_base; + u32 reg; + /* we are going to shutdown the device */ + islpci_set_state(priv, PRV_STATE_PREBOOT); + + /* disable all device interrupts in case they weren't */ + isl38xx_disable_interrupts(priv->device_base); + + /* For safety reasons, we may want to ensure that no DMA transfer is + * currently in progress by emptying the TX and RX queues. */ + + /* wait until interrupts have finished executing on other CPUs */ + prism54_synchronize_irq(priv->pdev->irq); + + reg = readl(device_base + ISL38XX_CTRL_STAT_REG); + reg &= ~(ISL38XX_CTRL_STAT_RESET | ISL38XX_CTRL_STAT_RAMBOOT); + writel(reg, device_base + ISL38XX_CTRL_STAT_REG); + wmb(); + udelay(ISL38XX_WRITEIO_DELAY); + + reg |= ISL38XX_CTRL_STAT_RESET; + writel(reg, device_base + ISL38XX_CTRL_STAT_REG); + wmb(); + udelay(ISL38XX_WRITEIO_DELAY); + + /* clear the Reset bit */ + reg &= ~ISL38XX_CTRL_STAT_RESET; + writel(reg, device_base + ISL38XX_CTRL_STAT_REG); + wmb(); + + /* wait a while for the device to reset */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(50*HZ/1000); + + return 0; +} + +static int +islpci_upload_fw(islpci_private *priv) +{ + islpci_state_t old_state; + u32 rc; + + old_state = islpci_set_state(priv, PRV_STATE_BOOT); + + printk(KERN_DEBUG "%s: uploading firmware...\n", priv->ndev->name); + + rc = isl_upload_firmware(priv); + if (rc) { + /* error uploading the firmware */ + printk(KERN_ERR "%s: could not upload firmware ('%s')\n", + priv->ndev->name, priv->firmware); + + islpci_set_state(priv, old_state); + return rc; + } + + printk(KERN_DEBUG + "%s: firmware uploaded done, now triggering reset...\n", + priv->ndev->name); + + islpci_set_state(priv, PRV_STATE_POSTBOOT); + + return 0; +} + +static int +islpci_reset_if(islpci_private *priv) +{ + long remaining; + int result = -ETIME; + int count; + + DEFINE_WAIT(wait); + prepare_to_wait(&priv->reset_done, &wait, TASK_UNINTERRUPTIBLE); + + /* now the last step is to reset the interface */ + isl38xx_interface_reset(priv->device_base, priv->device_host_address); + islpci_set_state(priv, PRV_STATE_PREINIT); + + for(count = 0; count < 2 && result; count++) { + /* The software reset acknowledge needs about 220 msec here. + * Be conservative and wait for up to one second. */ + + remaining = schedule_timeout(HZ); + + if(remaining > 0) { + result = 0; + break; + } + + /* If we're here it's because our IRQ hasn't yet gone through. + * Retry a bit more... + */ + printk(KERN_ERR "%s: device soft reset timed out\n", + priv->ndev->name); + + } + + finish_wait(&priv->reset_done, &wait); + + if(result) + return result; + + islpci_set_state(priv, PRV_STATE_INIT); + + /* Now that the device is 100% up, let's allow + * for the other interrupts -- + * NOTE: this is not *yet* true since we've only allowed the + * INIT interrupt on the IRQ line. We can perhaps poll + * the IRQ line until we know for sure the reset went through */ + isl38xx_enable_common_interrupts(priv->device_base); + + down_write(&priv->mib_sem); + mgt_commit(priv); + up_write(&priv->mib_sem); + + islpci_set_state(priv, PRV_STATE_READY); + + return 0; +} + +int +islpci_reset(islpci_private *priv, int reload_firmware) +{ + isl38xx_control_block *cb = /* volatile not needed */ + (isl38xx_control_block *) priv->control_block; + unsigned counter; + int rc; + + if (reload_firmware) + islpci_set_state(priv, PRV_STATE_PREBOOT); + else + islpci_set_state(priv, PRV_STATE_POSTBOOT); + + printk(KERN_DEBUG "%s: resetting device...\n", priv->ndev->name); + + /* disable all device interrupts in case they weren't */ + isl38xx_disable_interrupts(priv->device_base); + + /* flush all management queues */ + priv->index_mgmt_tx = 0; + priv->index_mgmt_rx = 0; + + /* clear the indexes in the frame pointer */ + for (counter = 0; counter < ISL38XX_CB_QCOUNT; counter++) { + cb->driver_curr_frag[counter] = cpu_to_le32(0); + cb->device_curr_frag[counter] = cpu_to_le32(0); + } + + /* reset the mgmt receive queue */ + for (counter = 0; counter < ISL38XX_CB_MGMT_QSIZE; counter++) { + isl38xx_fragment *frag = &cb->rx_data_mgmt[counter]; + frag->size = cpu_to_le16(MGMT_FRAME_SIZE); + frag->flags = 0; + frag->address = cpu_to_le32(priv->mgmt_rx[counter].pci_addr); + } + + for (counter = 0; counter < ISL38XX_CB_RX_QSIZE; counter++) { + cb->rx_data_low[counter].address = + cpu_to_le32((u32) priv->pci_map_rx_address[counter]); + } + + /* since the receive queues are filled with empty fragments, now we can + * set the corresponding indexes in the Control Block */ + priv->control_block->driver_curr_frag[ISL38XX_CB_RX_DATA_LQ] = + cpu_to_le32(ISL38XX_CB_RX_QSIZE); + priv->control_block->driver_curr_frag[ISL38XX_CB_RX_MGMTQ] = + cpu_to_le32(ISL38XX_CB_MGMT_QSIZE); + + /* reset the remaining real index registers and full flags */ + priv->free_data_rx = 0; + priv->free_data_tx = 0; + priv->data_low_tx_full = 0; + + if (reload_firmware) { /* Should we load the firmware ? */ + /* now that the data structures are cleaned up, upload + * firmware and reset interface */ + rc = islpci_upload_fw(priv); + if (rc) + return rc; + } + + /* finally reset interface */ + rc = islpci_reset_if(priv); + if (!rc) /* If successful */ + return rc; + + printk(KERN_DEBUG "prism54: Your card/socket may be faulty, or IRQ line too busy :(\n"); + return rc; + +} + +struct net_device_stats * +islpci_statistics(struct net_device *ndev) +{ + islpci_private *priv = netdev_priv(ndev); + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, "islpci_statistics \n"); +#endif + + return &priv->statistics; +} + +/****************************************************************************** + Network device configuration functions +******************************************************************************/ +static int +islpci_alloc_memory(islpci_private *priv) +{ + int counter; + +#if VERBOSE > SHOW_ERROR_MESSAGES + printk(KERN_DEBUG "islpci_alloc_memory\n"); +#endif + + /* remap the PCI device base address to accessable */ + if (!(priv->device_base = + ioremap(pci_resource_start(priv->pdev, 0), + ISL38XX_PCI_MEM_SIZE))) { + /* error in remapping the PCI device memory address range */ + printk(KERN_ERR "PCI memory remapping failed \n"); + return -1; + } + + /* memory layout for consistent DMA region: + * + * Area 1: Control Block for the device interface + * Area 2: Power Save Mode Buffer for temporary frame storage. Be aware that + * the number of supported stations in the AP determines the minimal + * size of the buffer ! + */ + + /* perform the allocation */ + priv->driver_mem_address = pci_alloc_consistent(priv->pdev, + HOST_MEM_BLOCK, + &priv-> + device_host_address); + + if (!priv->driver_mem_address) { + /* error allocating the block of PCI memory */ + printk(KERN_ERR "%s: could not allocate DMA memory, aborting!", + "prism54"); + return -1; + } + + /* assign the Control Block to the first address of the allocated area */ + priv->control_block = + (isl38xx_control_block *) priv->driver_mem_address; + + /* set the Power Save Buffer pointer directly behind the CB */ + priv->device_psm_buffer = + priv->device_host_address + CONTROL_BLOCK_SIZE; + + /* make sure all buffer pointers are initialized */ + for (counter = 0; counter < ISL38XX_CB_QCOUNT; counter++) { + priv->control_block->driver_curr_frag[counter] = cpu_to_le32(0); + priv->control_block->device_curr_frag[counter] = cpu_to_le32(0); + } + + priv->index_mgmt_rx = 0; + memset(priv->mgmt_rx, 0, sizeof(priv->mgmt_rx)); + memset(priv->mgmt_tx, 0, sizeof(priv->mgmt_tx)); + + /* allocate rx queue for management frames */ + if (islpci_mgmt_rx_fill(priv->ndev) < 0) + goto out_free; + + /* now get the data rx skb's */ + memset(priv->data_low_rx, 0, sizeof (priv->data_low_rx)); + memset(priv->pci_map_rx_address, 0, sizeof (priv->pci_map_rx_address)); + + for (counter = 0; counter < ISL38XX_CB_RX_QSIZE; counter++) { + struct sk_buff *skb; + + /* allocate an sk_buff for received data frames storage + * each frame on receive size consists of 1 fragment + * include any required allignment operations */ + if (!(skb = dev_alloc_skb(MAX_FRAGMENT_SIZE_RX + 2))) { + /* error allocating an sk_buff structure elements */ + printk(KERN_ERR "Error allocating skb.\n"); + skb = NULL; + goto out_free; + } + skb_reserve(skb, (4 - (long) skb->data) & 0x03); + /* add the new allocated sk_buff to the buffer array */ + priv->data_low_rx[counter] = skb; + + /* map the allocated skb data area to pci */ + priv->pci_map_rx_address[counter] = + pci_map_single(priv->pdev, (void *) skb->data, + MAX_FRAGMENT_SIZE_RX + 2, + PCI_DMA_FROMDEVICE); + if (!priv->pci_map_rx_address[counter]) { + /* error mapping the buffer to device + accessable memory address */ + printk(KERN_ERR "failed to map skb DMA'able\n"); + goto out_free; + } + } + + prism54_acl_init(&priv->acl); + prism54_wpa_ie_init(priv); + if (mgt_init(priv)) + goto out_free; + + return 0; + out_free: + islpci_free_memory(priv); + return -1; +} + +int +islpci_free_memory(islpci_private *priv) +{ + int counter; + + if (priv->device_base) + iounmap(priv->device_base); + priv->device_base = 0; + + /* free consistent DMA area... */ + if (priv->driver_mem_address) + pci_free_consistent(priv->pdev, HOST_MEM_BLOCK, + priv->driver_mem_address, + priv->device_host_address); + + /* clear some dangling pointers */ + priv->driver_mem_address = 0; + priv->device_host_address = 0; + priv->device_psm_buffer = 0; + priv->control_block = 0; + + /* clean up mgmt rx buffers */ + for (counter = 0; counter < ISL38XX_CB_MGMT_QSIZE; counter++) { + struct islpci_membuf *buf = &priv->mgmt_rx[counter]; + if (buf->pci_addr) + pci_unmap_single(priv->pdev, buf->pci_addr, + buf->size, PCI_DMA_FROMDEVICE); + buf->pci_addr = 0; + if (buf->mem) + kfree(buf->mem); + buf->size = 0; + buf->mem = NULL; + } + + /* clean up data rx buffers */ + for (counter = 0; counter < ISL38XX_CB_RX_QSIZE; counter++) { + if (priv->pci_map_rx_address[counter]) + pci_unmap_single(priv->pdev, + priv->pci_map_rx_address[counter], + MAX_FRAGMENT_SIZE_RX + 2, + PCI_DMA_FROMDEVICE); + priv->pci_map_rx_address[counter] = 0; + + if (priv->data_low_rx[counter]) + dev_kfree_skb(priv->data_low_rx[counter]); + priv->data_low_rx[counter] = 0; + } + + /* Free the acces control list and the WPA list */ + prism54_acl_clean(&priv->acl); + prism54_wpa_ie_clean(priv); + mgt_clean(priv); + + return 0; +} + +#if 0 +static void +islpci_set_multicast_list(struct net_device *dev) +{ + /* put device into promisc mode and let network layer handle it */ +} +#endif + +struct net_device * +islpci_setup(struct pci_dev *pdev) +{ + islpci_private *priv; + struct net_device *ndev = alloc_etherdev(sizeof (islpci_private)); + + if (!ndev) + return ndev; + + SET_MODULE_OWNER(ndev); + pci_set_drvdata(pdev, ndev); +#if defined(SET_NETDEV_DEV) + SET_NETDEV_DEV(ndev, &pdev->dev); +#endif + + /* setup the structure members */ + ndev->base_addr = pci_resource_start(pdev, 0); + ndev->irq = pdev->irq; + + /* initialize the function pointers */ + ndev->open = &islpci_open; + ndev->stop = &islpci_close; + ndev->get_stats = &islpci_statistics; + ndev->get_wireless_stats = &prism54_get_wireless_stats; + ndev->do_ioctl = &prism54_ioctl; + ndev->wireless_handlers = + (struct iw_handler_def *) &prism54_handler_def; + + ndev->hard_start_xmit = &islpci_eth_transmit; + /* ndev->set_multicast_list = &islpci_set_multicast_list; */ + ndev->addr_len = ETH_ALEN; + ndev->set_mac_address = &prism54_set_mac_address; + /* Get a non-zero dummy MAC address for nameif. Jean II */ + memcpy(ndev->dev_addr, dummy_mac, 6); + +#ifdef HAVE_TX_TIMEOUT + ndev->watchdog_timeo = ISLPCI_TX_TIMEOUT; + ndev->tx_timeout = &islpci_eth_tx_timeout; +#endif + + /* allocate a private device structure to the network device */ + priv = netdev_priv(ndev); + priv->ndev = ndev; + priv->pdev = pdev; + priv->monitor_type = ARPHRD_IEEE80211; + priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR) ? + priv->monitor_type : ARPHRD_ETHER; + + /* save the start and end address of the PCI memory area */ + ndev->mem_start = (unsigned long) priv->device_base; + ndev->mem_end = ndev->mem_start + ISL38XX_PCI_MEM_SIZE; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "PCI Memory remapped to 0x%p\n", priv->device_base); +#endif + + init_waitqueue_head(&priv->reset_done); + + /* init the queue read locks, process wait counter */ + sema_init(&priv->mgmt_sem, 1); + priv->mgmt_received = NULL; + init_waitqueue_head(&priv->mgmt_wqueue); + sema_init(&priv->stats_sem, 1); + spin_lock_init(&priv->slock); + + /* init state machine with off#1 state */ + priv->state = PRV_STATE_OFF; + priv->state_off = 1; + + /* initialize workqueue's */ + INIT_WORK(&priv->stats_work, + (void (*)(void *)) prism54_update_stats, priv); + priv->stats_timestamp = 0; + + INIT_WORK(&priv->reset_task, islpci_do_reset_and_wake, priv); + priv->reset_task_pending = 0; + + /* allocate various memory areas */ + if (islpci_alloc_memory(priv)) + goto do_free_netdev; + + /* select the firmware file depending on the device id */ + switch (pdev->device) { + case PCIDEVICE_ISL3890: + case PCIDEVICE_3COM6001: + strcpy(priv->firmware, ISL3890_IMAGE_FILE); + break; + case PCIDEVICE_ISL3877: + strcpy(priv->firmware, ISL3877_IMAGE_FILE); + break; + + default: + strcpy(priv->firmware, ISL3890_IMAGE_FILE); + break; + } + + if (register_netdev(ndev)) { + DEBUG(SHOW_ERROR_MESSAGES, + "ERROR: register_netdev() failed \n"); + goto do_islpci_free_memory; + } + + return ndev; + + do_islpci_free_memory: + islpci_free_memory(priv); + do_free_netdev: + pci_set_drvdata(pdev, 0); + free_netdev(ndev); + priv = 0; + return NULL; +} + +islpci_state_t +islpci_set_state(islpci_private *priv, islpci_state_t new_state) +{ + islpci_state_t old_state; + + /* lock */ + old_state = priv->state; + + /* this means either a race condition or some serious error in + * the driver code */ + switch (new_state) { + case PRV_STATE_OFF: + priv->state_off++; + default: + priv->state = new_state; + break; + + case PRV_STATE_PREBOOT: + /* there are actually many off-states, enumerated by + * state_off */ + if (old_state == PRV_STATE_OFF) + priv->state_off--; + + /* only if hw_unavailable is zero now it means we either + * were in off#1 state, or came here from + * somewhere else */ + if (!priv->state_off) + priv->state = new_state; + break; + }; +#if 0 + printk(KERN_DEBUG "%s: state transition %d -> %d (off#%d)\n", + priv->ndev->name, old_state, new_state, priv->state_off); +#endif + + /* invariants */ + BUG_ON(priv->state_off < 0); + BUG_ON(priv->state_off && (priv->state != PRV_STATE_OFF)); + BUG_ON(!priv->state_off && (priv->state == PRV_STATE_OFF)); + + /* unlock */ + return old_state; +} diff -Nru a/drivers/net/wireless/prism54/islpci_dev.h b/drivers/net/wireless/prism54/islpci_dev.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/net/wireless/prism54/islpci_dev.h 2004-08-14 12:02:31 -07:00 @@ -0,0 +1,215 @@ +/* + * + * Copyright (C) 2002 Intersil Americas Inc. + * Copyright (C) 2003 Herbert Valerio Riedel + * Copyright (C) 2003 Luis R. Rodriguez + * Copyright (C) 2003 Aurelien Alleaume + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _ISLPCI_DEV_H +#define _ISLPCI_DEV_H + +#include +#include +#include +#include +#include + +#include "isl_38xx.h" +#include "isl_oid.h" +#include "islpci_mgt.h" + +/* some states might not be superflous and may be removed when + design is finalized (hvr) */ +typedef enum { + PRV_STATE_OFF = 0, /* this means hw_unavailable is != 0 */ + PRV_STATE_PREBOOT, /* we are in a pre-boot state (empty RAM) */ + PRV_STATE_BOOT, /* boot state (fw upload, run fw) */ + PRV_STATE_POSTBOOT, /* after boot state, need reset now */ + PRV_STATE_PREINIT, /* pre-init state */ + PRV_STATE_INIT, /* init state (restore MIB backup to device) */ + PRV_STATE_READY, /* driver&device are in operational state */ + PRV_STATE_SLEEP /* device in sleep mode */ +} islpci_state_t; + +/* ACL using MAC address */ +struct mac_entry { + struct list_head _list; + char addr[ETH_ALEN]; +}; + +struct islpci_acl { + enum { MAC_POLICY_OPEN=0, MAC_POLICY_ACCEPT=1, MAC_POLICY_REJECT=2 } policy; + struct list_head mac_list; /* a list of mac_entry */ + int size; /* size of queue */ + struct semaphore sem; /* accessed in ioctls and trap_work */ +}; + +struct islpci_membuf { + int size; /* size of memory */ + void *mem; /* address of memory as seen by CPU */ + dma_addr_t pci_addr; /* address of memory as seen by device */ +}; + +#define MAX_BSS_WPA_IE_COUNT 64 +#define MAX_WPA_IE_LEN 64 +struct islpci_bss_wpa_ie { + struct list_head list; + unsigned long last_update; + u8 bssid[ETH_ALEN]; + u8 wpa_ie[MAX_WPA_IE_LEN]; + size_t wpa_ie_len; + +}; + +typedef struct { + spinlock_t slock; /* generic spinlock; */ + + u32 priv_oid; + + /* our mib cache */ + u32 iw_mode; + struct rw_semaphore mib_sem; + void **mib; + char nickname[IW_ESSID_MAX_SIZE+1]; + + /* Take care of the wireless stats */ + struct work_struct stats_work; + struct semaphore stats_sem; + /* remember when we last updated the stats */ + unsigned long stats_timestamp; + /* The first is accessed under semaphore locking. + * The second is the clean one we return to iwconfig. + */ + struct iw_statistics local_iwstatistics; + struct iw_statistics iwstatistics; + + struct iw_spy_data spy_data; /* iwspy support */ + + int monitor_type; /* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_PRISM */ + + struct islpci_acl acl; + + /* PCI bus allocation & configuration members */ + struct pci_dev *pdev; /* PCI structure information */ + u32 pci_state[16]; /* used for suspend/resume */ + char firmware[33]; + + void *device_base; /* ioremapped device base address */ + + /* consistent DMA region */ + void *driver_mem_address; /* base DMA address */ + dma_addr_t device_host_address; /* base DMA address (bus address) */ + dma_addr_t device_psm_buffer; /* host memory for PSM buffering (bus address) */ + + /* our network_device structure */ + struct net_device *ndev; + + /* device queue interface members */ + struct isl38xx_cb *control_block; /* device control block + (== driver_mem_address!) */ + + /* Each queue has three indexes: + * free/index_mgmt/data_rx/tx (called index, see below), + * driver_curr_frag, and device_curr_frag (in the control block) + * All indexes are ever-increasing, but interpreted modulo the + * device queue size when used. + * index <= device_curr_frag <= driver_curr_frag at all times + * For rx queues, [index, device_curr_frag) contains fragments + * that the interrupt processing needs to handle (owned by driver). + * [device_curr_frag, driver_curr_frag) is the free space in the + * rx queue, waiting for data (owned by device). The driver + * increments driver_curr_frag to indicate to the device that more + * buffers are available. + * If device_curr_frag == driver_curr_frag, no more rx buffers are + * available, and the rx DMA engine of the device is halted. + * For tx queues, [index, device_curr_frag) contains fragments + * where tx is done; they need to be freed (owned by driver). + * [device_curr_frag, driver_curr_frag) contains the frames + * that are being transferred (owned by device). The driver + * increments driver_curr_frag to indicate that more tx work + * needs to be done. + */ + u32 index_mgmt_rx; /* real index mgmt rx queue */ + u32 index_mgmt_tx; /* read index mgmt tx queue */ + u32 free_data_rx; /* free pointer data rx queue */ + u32 free_data_tx; /* free pointer data tx queue */ + u32 data_low_tx_full; /* full detected flag */ + + /* frame memory buffers for the device queues */ + struct islpci_membuf mgmt_tx[ISL38XX_CB_MGMT_QSIZE]; + struct islpci_membuf mgmt_rx[ISL38XX_CB_MGMT_QSIZE]; + struct sk_buff *data_low_tx[ISL38XX_CB_TX_QSIZE]; + struct sk_buff *data_low_rx[ISL38XX_CB_RX_QSIZE]; + dma_addr_t pci_map_tx_address[ISL38XX_CB_TX_QSIZE]; + dma_addr_t pci_map_rx_address[ISL38XX_CB_RX_QSIZE]; + + /* driver network interface members */ + struct net_device_stats statistics; + + /* wait for a reset interrupt */ + wait_queue_head_t reset_done; + + /* used by islpci_mgt_transaction */ + struct semaphore mgmt_sem; /* serialize access to mailbox and wqueue */ + struct islpci_mgmtframe *mgmt_received; /* mbox for incoming frame */ + wait_queue_head_t mgmt_wqueue; /* waitqueue for mbox */ + + /* state machine */ + islpci_state_t state; + int state_off; /* enumeration of off-state, if 0 then + * we're not in any off-state */ + + /* WPA stuff */ + int wpa; /* WPA mode enabled */ + struct list_head bss_wpa_list; + int num_bss_wpa; + struct semaphore wpa_sem; + + struct work_struct reset_task; + int reset_task_pending; +} islpci_private; + +static inline islpci_state_t +islpci_get_state(islpci_private *priv) +{ + /* lock */ + return priv->state; + /* unlock */ +} + +islpci_state_t islpci_set_state(islpci_private *priv, islpci_state_t new_state); + +#define ISLPCI_TX_TIMEOUT (2*HZ) + +irqreturn_t islpci_interrupt(int, void *, struct pt_regs *); + +int prism54_post_setup(islpci_private *, int); +int islpci_reset(islpci_private *, int); + +static inline void +islpci_trigger(islpci_private *priv) +{ + isl38xx_trigger_device(islpci_get_state(priv) == PRV_STATE_SLEEP, + priv->device_base); +} + +struct net_device_stats *islpci_statistics(struct net_device *); + +int islpci_free_memory(islpci_private *); +struct net_device *islpci_setup(struct pci_dev *); +#endif /* _ISLPCI_DEV_H */ diff -Nru a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/net/wireless/prism54/islpci_eth.c 2004-08-14 12:02:31 -07:00 @@ -0,0 +1,518 @@ +/* + * + * Copyright (C) 2002 Intersil Americas Inc. + * Copyright (C) 2004 Aurelien Alleaume + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include "prismcompat.h" +#include "isl_38xx.h" +#include "islpci_eth.h" +#include "islpci_mgt.h" +#include "oid_mgt.h" + +/****************************************************************************** + Network Interface functions +******************************************************************************/ +void +islpci_eth_cleanup_transmit(islpci_private *priv, + isl38xx_control_block *control_block) +{ + struct sk_buff *skb; + u32 index; + + /* compare the control block read pointer with the free pointer */ + while (priv->free_data_tx != + le32_to_cpu(control_block-> + device_curr_frag[ISL38XX_CB_TX_DATA_LQ])) { + /* read the index of the first fragment to be freed */ + index = priv->free_data_tx % ISL38XX_CB_TX_QSIZE; + + /* check for holes in the arrays caused by multi fragment frames + * searching for the last fragment of a frame */ + if (priv->pci_map_tx_address[index] != (dma_addr_t) NULL) { + /* entry is the last fragment of a frame + * free the skb structure and unmap pci memory */ + skb = priv->data_low_tx[index]; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, + "cleanup skb %p skb->data %p skb->len %u truesize %u\n ", + skb, skb->data, skb->len, skb->truesize); +#endif + + pci_unmap_single(priv->pdev, + priv->pci_map_tx_address[index], + skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb_irq(skb); + skb = NULL; + } + /* increment the free data low queue pointer */ + priv->free_data_tx++; + } +} + +int +islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) +{ + islpci_private *priv = netdev_priv(ndev); + isl38xx_control_block *cb = priv->control_block; + u32 index; + dma_addr_t pci_map_address; + int frame_size; + isl38xx_fragment *fragment; + int offset; + struct sk_buff *newskb; + int newskb_offset; + unsigned long flags; + unsigned char wds_mac[6]; + u32 curr_frag; + int err = 0; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, "islpci_eth_transmit \n"); +#endif + + /* lock the driver code */ + spin_lock_irqsave(&priv->slock, flags); + + /* determine the amount of fragments needed to store the frame */ + + frame_size = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; + if (init_wds) + frame_size += 6; + + /* check whether the destination queue has enough fragments for the frame */ + curr_frag = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_TX_DATA_LQ]); + if (unlikely(curr_frag - priv->free_data_tx >= ISL38XX_CB_TX_QSIZE)) { + printk(KERN_ERR "%s: transmit device queue full when awake\n", + ndev->name); + netif_stop_queue(ndev); + + /* trigger the device */ + isl38xx_w32_flush(priv->device_base, ISL38XX_DEV_INT_UPDATE, + ISL38XX_DEV_INT_REG); + udelay(ISL38XX_WRITEIO_DELAY); + + err = -EBUSY; + goto drop_free; + } + /* Check alignment and WDS frame formatting. The start of the packet should + * be aligned on a 4-byte boundary. If WDS is enabled add another 6 bytes + * and add WDS address information */ + if (likely(((long) skb->data & 0x03) | init_wds)) { + /* get the number of bytes to add and re-allign */ + offset = (4 - (long) skb->data) & 0x03; + offset += init_wds ? 6 : 0; + + /* check whether the current skb can be used */ + if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) { + unsigned char *src = skb->data; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "skb offset %i wds %i\n", offset, + init_wds); +#endif + + /* align the buffer on 4-byte boundary */ + skb_reserve(skb, (4 - (long) skb->data) & 0x03); + if (init_wds) { + /* wds requires an additional address field of 6 bytes */ + skb_put(skb, 6); +#ifdef ISLPCI_ETH_DEBUG + printk("islpci_eth_transmit:wds_mac\n"); +#endif + memmove(skb->data + 6, src, skb->len); + memcpy(skb->data, wds_mac, 6); + } else { + memmove(skb->data, src, skb->len); + } + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "memmove %p %p %i \n", skb->data, + src, skb->len); +#endif + } else { + newskb = + dev_alloc_skb(init_wds ? skb->len + 6 : skb->len); + if (unlikely(newskb == NULL)) { + printk(KERN_ERR "%s: Cannot allocate skb\n", + ndev->name); + err = -ENOMEM; + goto drop_free; + } + newskb_offset = (4 - (long) newskb->data) & 0x03; + + /* Check if newskb->data is aligned */ + if (newskb_offset) + skb_reserve(newskb, newskb_offset); + + skb_put(newskb, init_wds ? skb->len + 6 : skb->len); + if (init_wds) { + memcpy(newskb->data + 6, skb->data, skb->len); + memcpy(newskb->data, wds_mac, 6); +#ifdef ISLPCI_ETH_DEBUG + printk("islpci_eth_transmit:wds_mac\n"); +#endif + } else + memcpy(newskb->data, skb->data, skb->len); + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "memcpy %p %p %i wds %i\n", + newskb->data, skb->data, skb->len, init_wds); +#endif + + newskb->dev = skb->dev; + dev_kfree_skb(skb); + skb = newskb; + } + } + /* display the buffer contents for debugging */ +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_BUFFER_CONTENTS, "\ntx %p ", skb->data); + display_buffer((char *) skb->data, skb->len); +#endif + + /* map the skb buffer to pci memory for DMA operation */ + pci_map_address = pci_map_single(priv->pdev, + (void *) skb->data, skb->len, + PCI_DMA_TODEVICE); + if (unlikely(pci_map_address == 0)) { + printk(KERN_WARNING "%s: cannot map buffer to PCI\n", + ndev->name); + + err = -EIO; + goto drop_free; + } + /* Place the fragment in the control block structure. */ + index = curr_frag % ISL38XX_CB_TX_QSIZE; + fragment = &cb->tx_data_low[index]; + + priv->pci_map_tx_address[index] = pci_map_address; + /* store the skb address for future freeing */ + priv->data_low_tx[index] = skb; + /* set the proper fragment start address and size information */ + fragment->size = cpu_to_le16(frame_size); + fragment->flags = cpu_to_le16(0); /* set to 1 if more fragments */ + fragment->address = cpu_to_le32(pci_map_address); + curr_frag++; + + /* The fragment address in the control block must have been + * written before announcing the frame buffer to device. */ + wmb(); + cb->driver_curr_frag[ISL38XX_CB_TX_DATA_LQ] = cpu_to_le32(curr_frag); + + if (curr_frag - priv->free_data_tx + ISL38XX_MIN_QTHRESHOLD + > ISL38XX_CB_TX_QSIZE) { + /* stop sends from upper layers */ + netif_stop_queue(ndev); + + /* set the full flag for the transmission queue */ + priv->data_low_tx_full = 1; + } + + /* trigger the device */ + islpci_trigger(priv); + + /* unlock the driver code */ + spin_unlock_irqrestore(&priv->slock, flags); + + /* set the transmission time */ + ndev->trans_start = jiffies; + priv->statistics.tx_packets++; + priv->statistics.tx_bytes += skb->len; + + return 0; + + drop_free: + /* free the skbuf structure before aborting */ + dev_kfree_skb(skb); + skb = NULL; + + priv->statistics.tx_dropped++; + spin_unlock_irqrestore(&priv->slock, flags); + return err; +} + +static inline int +islpci_monitor_rx(islpci_private *priv, struct sk_buff **skb) +{ + /* The card reports full 802.11 packets but with a 20 bytes + * header and without the FCS. But there a is a bit that + * indicates if the packet is corrupted :-) */ + struct rfmon_header *hdr = (struct rfmon_header *) (*skb)->data; + if (hdr->flags & 0x01) + /* This one is bad. Drop it ! */ + return -1; + if (priv->ndev->type == ARPHRD_IEEE80211_PRISM) { + struct avs_80211_1_header *avs; + /* extract the relevant data from the header */ + u32 clock = le32_to_cpu(hdr->clock); + u8 rate = hdr->rate; + u16 freq = le16_to_cpu(hdr->freq); + u8 rssi = hdr->rssi; + + skb_pull(*skb, sizeof (struct rfmon_header)); + + if (skb_headroom(*skb) < sizeof (struct avs_80211_1_header)) { + struct sk_buff *newskb = skb_copy_expand(*skb, + sizeof (struct + avs_80211_1_header), + 0, GFP_ATOMIC); + if (newskb) { + dev_kfree_skb_irq(*skb); + *skb = newskb; + } else + return -1; + /* This behavior is not very subtile... */ + } + + /* make room for the new header and fill it. */ + avs = + (struct avs_80211_1_header *) skb_push(*skb, + sizeof (struct + avs_80211_1_header)); + + avs->version = cpu_to_be32(P80211CAPTURE_VERSION); + avs->length = cpu_to_be32(sizeof (struct avs_80211_1_header)); + avs->mactime = cpu_to_be64(le64_to_cpu(clock)); + avs->hosttime = cpu_to_be64(jiffies); + avs->phytype = cpu_to_be32(6); /*OFDM: 6 for (g), 8 for (a) */ + avs->channel = cpu_to_be32(channel_of_freq(freq)); + avs->datarate = cpu_to_be32(rate * 5); + avs->antenna = cpu_to_be32(0); /*unknown */ + avs->priority = cpu_to_be32(0); /*unknown */ + avs->ssi_type = cpu_to_be32(3); /*2: dBm, 3: raw RSSI */ + avs->ssi_signal = cpu_to_be32(rssi & 0x7f); + avs->ssi_noise = cpu_to_be32(priv->local_iwstatistics.qual.noise); /*better than 'undefined', I assume */ + avs->preamble = cpu_to_be32(0); /*unknown */ + avs->encoding = cpu_to_be32(0); /*unknown */ + } else + skb_pull(*skb, sizeof (struct rfmon_header)); + + (*skb)->protocol = htons(ETH_P_802_2); + (*skb)->mac.raw = (*skb)->data; + (*skb)->pkt_type = PACKET_OTHERHOST; + + return 0; +} + +int +islpci_eth_receive(islpci_private *priv) +{ + struct net_device *ndev = priv->ndev; + isl38xx_control_block *control_block = priv->control_block; + struct sk_buff *skb; + u16 size; + u32 index, offset; + unsigned char *src; + int discard = 0; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, "islpci_eth_receive \n"); +#endif + + /* the device has written an Ethernet frame in the data area + * of the sk_buff without updating the structure, do it now */ + index = priv->free_data_rx % ISL38XX_CB_RX_QSIZE; + size = le16_to_cpu(control_block->rx_data_low[index].size); + skb = priv->data_low_rx[index]; + offset = ((unsigned long) + le32_to_cpu(control_block->rx_data_low[index].address) - + (unsigned long) skb->data) & 3; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, + "frq->addr %x skb->data %p skb->len %u offset %u truesize %u\n ", + control_block->rx_data_low[priv->free_data_rx].address, skb->data, + skb->len, offset, skb->truesize); +#endif + + /* delete the streaming DMA mapping before processing the skb */ + pci_unmap_single(priv->pdev, + priv->pci_map_rx_address[index], + MAX_FRAGMENT_SIZE_RX + 2, PCI_DMA_FROMDEVICE); + + /* update the skb structure and allign the buffer */ + skb_put(skb, size); + if (offset) { + /* shift the buffer allocation offset bytes to get the right frame */ + skb_pull(skb, 2); + skb_put(skb, 2); + } +#if VERBOSE > SHOW_ERROR_MESSAGES + /* display the buffer contents for debugging */ + DEBUG(SHOW_BUFFER_CONTENTS, "\nrx %p ", skb->data); + display_buffer((char *) skb->data, skb->len); +#endif + + /* check whether WDS is enabled and whether the data frame is a WDS frame */ + + if (init_wds) { + /* WDS enabled, check for the wds address on the first 6 bytes of the buffer */ + src = skb->data + 6; + memmove(skb->data, src, skb->len - 6); + skb_trim(skb, skb->len - 6); + } +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "Fragment size %i in skb at %p\n", size, skb); + DEBUG(SHOW_TRACING, "Skb data at %p, length %i\n", skb->data, skb->len); + + /* display the buffer contents for debugging */ + DEBUG(SHOW_BUFFER_CONTENTS, "\nrx %p ", skb->data); + display_buffer((char *) skb->data, skb->len); +#endif + + /* do some additional sk_buff and network layer parameters */ + skb->dev = ndev; + + /* take care of monitor mode and spy monitoring. */ + if (unlikely(priv->iw_mode == IW_MODE_MONITOR)) + discard = islpci_monitor_rx(priv, &skb); + else { + if (unlikely(skb->data[2 * ETH_ALEN] == 0)) { + /* The packet has a rx_annex. Read it for spy monitoring, Then + * remove it, while keeping the 2 leading MAC addr. + */ + struct iw_quality wstats; + struct rx_annex_header *annex = + (struct rx_annex_header *) skb->data; + wstats.level = annex->rfmon.rssi; + /* The noise value can be a bit outdated if nobody's + * reading wireless stats... */ + wstats.noise = priv->local_iwstatistics.qual.noise; + wstats.qual = wstats.level - wstats.noise; + wstats.updated = 0x07; + /* Update spy records */ + wireless_spy_update(ndev, annex->addr2, &wstats); + + memcpy(skb->data + sizeof (struct rfmon_header), + skb->data, 2 * ETH_ALEN); + skb_pull(skb, sizeof (struct rfmon_header)); + } + skb->protocol = eth_type_trans(skb, ndev); + } + skb->ip_summed = CHECKSUM_NONE; + priv->statistics.rx_packets++; + priv->statistics.rx_bytes += size; + + /* deliver the skb to the network layer */ +#ifdef ISLPCI_ETH_DEBUG + printk + ("islpci_eth_receive:netif_rx %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", + skb->data[0], skb->data[1], skb->data[2], skb->data[3], + skb->data[4], skb->data[5]); +#endif + if (unlikely(discard)) { + dev_kfree_skb_irq(skb); + skb = NULL; + } else + netif_rx(skb); + + /* increment the read index for the rx data low queue */ + priv->free_data_rx++; + + /* add one or more sk_buff structures */ + while (index = + le32_to_cpu(control_block-> + driver_curr_frag[ISL38XX_CB_RX_DATA_LQ]), + index - priv->free_data_rx < ISL38XX_CB_RX_QSIZE) { + /* allocate an sk_buff for received data frames storage + * include any required allignment operations */ + skb = dev_alloc_skb(MAX_FRAGMENT_SIZE_RX + 2); + if (unlikely(skb == NULL)) { + /* error allocating an sk_buff structure elements */ + DEBUG(SHOW_ERROR_MESSAGES, "Error allocating skb \n"); + break; + } + skb_reserve(skb, (4 - (long) skb->data) & 0x03); + /* store the new skb structure pointer */ + index = index % ISL38XX_CB_RX_QSIZE; + priv->data_low_rx[index] = skb; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, + "new alloc skb %p skb->data %p skb->len %u index %u truesize %u\n ", + skb, skb->data, skb->len, index, skb->truesize); +#endif + + /* set the streaming DMA mapping for proper PCI bus operation */ + priv->pci_map_rx_address[index] = + pci_map_single(priv->pdev, (void *) skb->data, + MAX_FRAGMENT_SIZE_RX + 2, + PCI_DMA_FROMDEVICE); + if (unlikely(priv->pci_map_rx_address[index] == (dma_addr_t) NULL)) { + /* error mapping the buffer to device accessable memory address */ + DEBUG(SHOW_ERROR_MESSAGES, + "Error mapping DMA address\n"); + + /* free the skbuf structure before aborting */ + dev_kfree_skb_irq((struct sk_buff *) skb); + skb = NULL; + break; + } + /* update the fragment address */ + control_block->rx_data_low[index].address = cpu_to_le32((u32) + priv-> + pci_map_rx_address + [index]); + wmb(); + + /* increment the driver read pointer */ + add_le32p((u32 *) &control_block-> + driver_curr_frag[ISL38XX_CB_RX_DATA_LQ], 1); + } + + /* trigger the device */ + islpci_trigger(priv); + + return 0; +} + +void +islpci_do_reset_and_wake(void *data) +{ + islpci_private *priv = (islpci_private *) data; + islpci_reset(priv, 1); + netif_wake_queue(priv->ndev); + priv->reset_task_pending = 0; +} + +void +islpci_eth_tx_timeout(struct net_device *ndev) +{ + islpci_private *priv = netdev_priv(ndev); + struct net_device_stats *statistics = &priv->statistics; + + /* increment the transmit error counter */ + statistics->tx_errors++; + + if (!priv->reset_task_pending) { + priv->reset_task_pending = 1; + netif_stop_queue(ndev); + schedule_work(&priv->reset_task); + } + + return; +} diff -Nru a/drivers/net/wireless/prism54/islpci_eth.h b/drivers/net/wireless/prism54/islpci_eth.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/net/wireless/prism54/islpci_eth.h 2004-08-14 12:02:31 -07:00 @@ -0,0 +1,73 @@ +/* + * + * Copyright (C) 2002 Intersil Americas Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License + * + * 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 _ISLPCI_ETH_H +#define _ISLPCI_ETH_H + +#include "isl_38xx.h" +#include "islpci_dev.h" + +struct rfmon_header { + u16 unk0; /* = 0x0000 */ + u16 length; /* = 0x1400 */ + u32 clock; /* 1MHz clock */ + u8 flags; + u8 unk1; + u8 rate; + u8 unk2; + u16 freq; + u16 unk3; + u8 rssi; + u8 padding[3]; +} __attribute__ ((packed)); + +struct rx_annex_header { + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + struct rfmon_header rfmon; +} __attribute__ ((packed)); + +/* wlan-ng (and hopefully others) AVS header, version one. Fields in + * network byte order. */ +#define P80211CAPTURE_VERSION 0x80211001 + +struct avs_80211_1_header { + uint32_t version; + uint32_t length; + uint64_t mactime; + uint64_t hosttime; + uint32_t phytype; + uint32_t channel; + uint32_t datarate; + uint32_t antenna; + uint32_t priority; + uint32_t ssi_type; + int32_t ssi_signal; + int32_t ssi_noise; + uint32_t preamble; + uint32_t encoding; +}; + +void islpci_eth_cleanup_transmit(islpci_private *, isl38xx_control_block *); +int islpci_eth_transmit(struct sk_buff *, struct net_device *); +int islpci_eth_receive(islpci_private *); +void islpci_eth_tx_timeout(struct net_device *); +void islpci_do_reset_and_wake(void *data); + +#endif /* _ISL_GEN_H */ diff -Nru a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/net/wireless/prism54/islpci_hotplug.c 2004-08-14 12:02:31 -07:00 @@ -0,0 +1,494 @@ +/* + * + * Copyright (C) 2002 Intersil Americas Inc. + * Copyright (C) 2003 Herbert Valerio Riedel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include /* For __init, __exit */ + +#include "prismcompat.h" +#include "islpci_dev.h" +#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 "); +MODULE_DESCRIPTION("The Prism54 802.11 Wireless LAN adapter"); +MODULE_LICENSE("GPL"); + +static int init_pcitm = 0; +module_param(init_pcitm, int, 0); + +/* In this order: vendor, device, subvendor, subdevice, class, class_mask, + * driver_data + * If you have an update for this please contact prism54-devel@prism54.org + * The latest list can be found at http://prism54.org/supported_cards.php */ +static const struct pci_device_id prism54_id_tbl[] = { + /* 3COM 3CRWE154G72 Wireless LAN adapter */ + { + PCIVENDOR_3COM, PCIDEVICE_3COM6001, + PCIVENDOR_3COM, PCIDEVICE_3COM6001, + 0, 0, 0 + }, + + /* D-Link Air Plus Xtreme G A1 - DWL-g650 A1 */ + { + PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890, + PCIVENDOR_DLINK, 0x3202UL, + 0, 0, 0 + }, + + /* I-O Data WN-G54/CB - WN-G54/CB */ + { + PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890, + PCIVENDOR_IODATA, 0xd019UL, + 0, 0, 0 + }, + + /* Netgear WG511 */ + { + PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890, + PCIVENDOR_NETGEAR, 0x4800UL, + 0, 0, 0 + }, + + /* Tekram Technology clones, Allnet, Netcomm, Zyxel */ + { + PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890, + PCIVENDOR_TTL, 0x1605UL, + 0, 0, 0 + }, + + /* SMC2802W */ + { + PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890, + PCIVENDOR_SMC, 0x2802UL, + 0, 0, 0 + }, + + /* SMC2835W */ + { + PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890, + PCIVENDOR_SMC, 0x2835UL, + 0, 0, 0 + }, + + /* Corega CG-WLCB54GT */ + { + PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890, + PCIVENDOR_ATI, 0xc104UL, + 0, 0, 0 + }, + + /* I4 Z-Com XG-600 */ + { + PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890, + PCIVENDOR_I4, 0x0014UL, + 0, 0, 0 + }, + + /* I4 Z-Com XG-900 and clones Macer, Ovislink, Planex, Peabird, */ + /* Sitecom, Xterasys */ + { + PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890, + PCIVENDOR_I4, 0x0020UL, + 0, 0, 0 + }, + + /* SMC 2802W V2 */ + { + PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890, + PCIVENDOR_ACCTON, 0xee03UL, + 0, 0, 0 + }, + + /* SMC 2835W V2 */ + { + PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890, + PCIVENDOR_SMC, 0xa835UL, + 0, 0, 0 + }, + + /* Intersil PRISM Indigo Wireless LAN adapter */ + { + PCIVENDOR_INTERSIL, PCIDEVICE_ISL3877, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, 0 + }, + + /* Intersil PRISM Duette/Prism GT Wireless LAN adapter */ + /* Default */ + { + PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, 0 + }, + + /* End of list */ + {0,0,0,0,0,0,0} +}; + +/* register the device with the Hotplug facilities of the kernel */ +MODULE_DEVICE_TABLE(pci, prism54_id_tbl); + +static int prism54_probe(struct pci_dev *, const struct pci_device_id *); +static void prism54_remove(struct pci_dev *); +static int prism54_suspend(struct pci_dev *, u32 state); +static int prism54_resume(struct pci_dev *); + +static struct pci_driver prism54_driver = { + .name = DRV_NAME, + .id_table = prism54_id_tbl, + .probe = prism54_probe, + .remove = prism54_remove, + .suspend = prism54_suspend, + .resume = prism54_resume, + /* .enable_wake ; we don't support this yet */ +}; + +static void +prism54_get_card_model(struct net_device *ndev) +{ + islpci_private *priv; + char *modelp; + int notwork = 0; + + priv = netdev_priv(ndev); + switch (priv->pdev->subsystem_device) { + case PCIDEVICE_ISL3877: + modelp = "PRISM Indigo"; + break; + case PCIDEVICE_ISL3886: + modelp = "PRISM Javelin / Xbow"; + break; + case PCIDEVICE_3COM6001: + modelp = "3COM 3CRWE154G72"; + break; + case 0x3202UL: + modelp = "D-Link DWL-g650 A1"; + break; + case 0xd019UL: + modelp = "WN-G54/CB"; + break; + case 0x4800UL: + modelp = "Netgear WG511"; + break; + case 0x2802UL: + modelp = "SMC2802W"; + break; + case 0xee03UL: + modelp = "SMC2802W V2"; + notwork = 1; + break; + case 0x2835UL: + modelp = "SMC2835W"; + break; + case 0xa835UL: + modelp = "SMC2835W V2"; + notwork = 1; + break; + case 0xc104UL: + modelp = "CG-WLCB54GT"; + break; + case 0x1605UL: + modelp = "Tekram Technology clone"; + break; + /* Let's leave this one out for now since it seems bogus/wrong + * Even if the manufacturer did use 0x0000UL it may not be correct + * by their part, therefore deserving no name ;) */ + /* case 0x0000UL: + * modelp = "SparkLAN WL-850F"; + * break;*/ + + /* We have two reported for the one below :( */ + case 0x0014UL: + modelp = "I4 Z-Com XG-600 and clones"; + break; + case 0x0020UL: + modelp = "I4 Z-Com XG-900 and clones"; + break; +/* Default it */ +/* + case PCIDEVICE_ISL3890: + modelp = "PRISM Duette/GT"; + break; +*/ + default: + modelp = "PRISM Duette/GT"; + } + printk(KERN_DEBUG "%s: %s driver detected card model: %s\n", + ndev->name, DRV_NAME, modelp); + if ( notwork ) { + printk(KERN_DEBUG "%s: %s Warning - This may not work\n", + ndev->name, DRV_NAME); + } + return; +} + +/****************************************************************************** + Module initialization functions +******************************************************************************/ + +int +prism54_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct net_device *ndev; + u8 latency_tmr; + u32 mem_addr; + islpci_private *priv; + int rvalue; + + /* TRACE(DRV_NAME); */ + + + /* Enable the pci device */ + if (pci_enable_device(pdev)) { + printk(KERN_ERR "%s: pci_enable_device() failed.\n", DRV_NAME); + return -ENODEV; + } + + /* check whether the latency timer is set correctly */ + pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency_tmr); +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "latency timer: %x\n", latency_tmr); +#endif + if (latency_tmr < PCIDEVICE_LATENCY_TIMER_MIN) { + /* set the latency timer */ + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, + PCIDEVICE_LATENCY_TIMER_VAL); + } + + /* enable PCI DMA */ + if (pci_set_dma_mask(pdev, 0xffffffff)) { + printk(KERN_ERR "%s: 32-bit PCI DMA not supported", DRV_NAME); + goto do_pci_disable_device; + } + + /* 0x40 is the programmable timer to configure the response timeout (TRDY_TIMEOUT) + * 0x41 is the programmable timer to configure the retry timeout (RETRY_TIMEOUT) + * The RETRY_TIMEOUT is used to set the number of retries that the core, as a + * Master, will perform before abandoning a cycle. The default value for + * RETRY_TIMEOUT is 0x80, which far exceeds the PCI 2.1 requirement for new + * devices. A write of zero to the RETRY_TIMEOUT register disables this + * function to allow use with any non-compliant legacy devices that may + * execute more retries. + * + * Writing zero to both these two registers will disable both timeouts and + * *can* solve problems caused by devices that are slow to respond. + * Make this configurable - MSW + */ + if ( init_pcitm >= 0 ) { + pci_write_config_byte(pdev, 0x40, (u8)init_pcitm); + pci_write_config_byte(pdev, 0x41, (u8)init_pcitm); + } else { + printk(KERN_INFO "PCI TRDY/RETRY unchanged\n"); + } + + /* request the pci device I/O regions */ + rvalue = pci_request_regions(pdev, DRV_NAME); + if (rvalue) { + printk(KERN_ERR "%s: pci_request_regions failure (rc=%d)\n", + DRV_NAME, rvalue); + goto do_pci_disable_device; + } + + /* check if the memory window is indeed set */ + rvalue = pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &mem_addr); + if (rvalue || !mem_addr) { + printk(KERN_ERR "%s: PCI device memory region not configured; fix your BIOS or CardBus bridge/drivers\n", + DRV_NAME); + goto do_pci_disable_device; + } + + /* enable PCI bus-mastering */ + DEBUG(SHOW_TRACING, "%s: pci_set_master(pdev)\n", DRV_NAME); + pci_set_master(pdev); + + /* enable MWI */ + pci_set_mwi(pdev); + + /* setup the network device interface and its structure */ + if (!(ndev = islpci_setup(pdev))) { + /* error configuring the driver as a network device */ + printk(KERN_ERR "%s: could not configure network device\n", + DRV_NAME); + goto do_pci_release_regions; + } + + priv = netdev_priv(ndev); + islpci_set_state(priv, PRV_STATE_PREBOOT); /* we are attempting to boot */ + + /* card is in unknown state yet, might have some interrupts pending */ + isl38xx_disable_interrupts(priv->device_base); + + /* request for the interrupt before uploading the firmware */ + rvalue = request_irq(pdev->irq, &islpci_interrupt, + SA_SHIRQ, ndev->name, priv); + + if (rvalue) { + /* error, could not hook the handler to the irq */ + printk(KERN_ERR "%s: could not install IRQ handler\n", + ndev->name); + goto do_unregister_netdev; + } + + /* firmware upload is triggered in islpci_open */ + + /* Pretty card model discovery output */ + prism54_get_card_model(ndev); + + return 0; + + do_unregister_netdev: + unregister_netdev(ndev); + islpci_free_memory(priv); + pci_set_drvdata(pdev, 0); + free_netdev(ndev); + priv = 0; + do_pci_release_regions: + pci_release_regions(pdev); + do_pci_disable_device: + pci_disable_device(pdev); + return -EIO; +} + +/* set by cleanup_module */ +static volatile int __in_cleanup_module = 0; + +/* this one removes one(!!) instance only */ +void +prism54_remove(struct pci_dev *pdev) +{ + struct net_device *ndev = pci_get_drvdata(pdev); + islpci_private *priv = ndev ? netdev_priv(ndev) : 0; + BUG_ON(!priv); + + if (!__in_cleanup_module) { + printk(KERN_DEBUG "%s: hot unplug detected\n", ndev->name); + islpci_set_state(priv, PRV_STATE_OFF); + } + + printk(KERN_DEBUG "%s: removing device\n", ndev->name); + + unregister_netdev(ndev); + + /* free the interrupt request */ + + if (islpci_get_state(priv) != PRV_STATE_OFF) { + isl38xx_disable_interrupts(priv->device_base); + islpci_set_state(priv, PRV_STATE_OFF); + /* This bellow causes a lockup at rmmod time. It might be + * because some interrupts still linger after rmmod time, + * see bug #17 */ + /* pci_set_power_state(pdev, 3);*/ /* try to power-off */ + } + + free_irq(pdev->irq, priv); + + /* free the PCI memory and unmap the remapped page */ + islpci_free_memory(priv); + + pci_set_drvdata(pdev, 0); + free_netdev(ndev); + priv = 0; + + pci_release_regions(pdev); + + pci_disable_device(pdev); +} + +int +prism54_suspend(struct pci_dev *pdev, u32 state) +{ + struct net_device *ndev = pci_get_drvdata(pdev); + islpci_private *priv = ndev ? netdev_priv(ndev) : 0; + BUG_ON(!priv); + + printk(KERN_NOTICE "%s: got suspend request (state %d)\n", + ndev->name, state); + + pci_save_state(pdev, priv->pci_state); + + /* tell the device not to trigger interrupts for now... */ + isl38xx_disable_interrupts(priv->device_base); + + /* from now on assume the hardware was already powered down + and don't touch it anymore */ + islpci_set_state(priv, PRV_STATE_OFF); + + netif_stop_queue(ndev); + netif_device_detach(ndev); + + return 0; +} + +int +prism54_resume(struct pci_dev *pdev) +{ + struct net_device *ndev = pci_get_drvdata(pdev); + islpci_private *priv = ndev ? netdev_priv(ndev) : 0; + BUG_ON(!priv); + + printk(KERN_NOTICE "%s: got resume request\n", ndev->name); + + pci_restore_state(pdev, priv->pci_state); + + /* alright let's go into the PREBOOT state */ + islpci_reset(priv, 1); + + netif_device_attach(ndev); + netif_start_queue(ndev); + + return 0; +} + +static int __init +prism54_module_init(void) +{ + printk(KERN_INFO "Loaded %s driver, version %s\n", + DRV_NAME, DRV_VERSION); + + __bug_on_wrong_struct_sizes (); + + return pci_module_init(&prism54_driver); +} + +/* by the time prism54_module_exit() terminates, as a postcondition + * all instances will have been destroyed by calls to + * prism54_remove() */ +static void __exit +prism54_module_exit(void) +{ + __in_cleanup_module = 1; + + pci_unregister_driver(&prism54_driver); + + printk(KERN_INFO "Unloaded %s driver\n", DRV_NAME); + + __in_cleanup_module = 0; +} + +/* register entry points */ +module_init(prism54_module_init); +module_exit(prism54_module_exit); +/* EOF */ diff -Nru a/drivers/net/wireless/prism54/islpci_mgt.c b/drivers/net/wireless/prism54/islpci_mgt.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/net/wireless/prism54/islpci_mgt.c 2004-08-14 12:02:31 -07:00 @@ -0,0 +1,510 @@ +/* + * + * Copyright (C) 2002 Intersil Americas Inc. + * Copyright 2004 Jens Maurer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include "prismcompat.h" +#include "isl_38xx.h" +#include "islpci_mgt.h" +#include "isl_oid.h" /* additional types and defs for isl38xx fw */ +#include "isl_ioctl.h" + +#include + +/****************************************************************************** + Global variable definition section +******************************************************************************/ +int pc_debug = VERBOSE; +module_param(pc_debug, int, 0); + +/****************************************************************************** + Driver general functions +******************************************************************************/ +void +display_buffer(char *buffer, int length) +{ + if ((pc_debug & SHOW_BUFFER_CONTENTS) == 0) + return; + + while (length > 0) { + printk("[%02x]", *buffer & 255); + length--; + buffer++; + } + + printk("\n"); +} + +/***************************************************************************** + Queue handling for management frames +******************************************************************************/ + +/* + * Helper function to create a PIMFOR management frame header. + */ +static void +pimfor_encode_header(int operation, u32 oid, u32 length, pimfor_header_t *h) +{ + h->version = PIMFOR_VERSION; + h->operation = operation; + h->device_id = PIMFOR_DEV_ID_MHLI_MIB; + h->flags = 0; + h->oid = cpu_to_be32(oid); + h->length = cpu_to_be32(length); +} + +/* + * Helper function to analyze a PIMFOR management frame header. + */ +static pimfor_header_t * +pimfor_decode_header(void *data, int len) +{ + pimfor_header_t *h = data; + + while ((void *) h < data + len) { + if (h->flags & PIMFOR_FLAG_LITTLE_ENDIAN) { + le32_to_cpus(&h->oid); + le32_to_cpus(&h->length); + } else { + be32_to_cpus(&h->oid); + be32_to_cpus(&h->length); + } + if (h->oid != OID_INL_TUNNEL) + return h; + h++; + } + return NULL; +} + +/* + * Fill the receive queue for management frames with fresh buffers. + */ +int +islpci_mgmt_rx_fill(struct net_device *ndev) +{ + islpci_private *priv = netdev_priv(ndev); + isl38xx_control_block *cb = /* volatile not needed */ + (isl38xx_control_block *) priv->control_block; + u32 curr = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_RX_MGMTQ]); + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgmt_rx_fill \n"); +#endif + + while (curr - priv->index_mgmt_rx < ISL38XX_CB_MGMT_QSIZE) { + u32 index = curr % ISL38XX_CB_MGMT_QSIZE; + struct islpci_membuf *buf = &priv->mgmt_rx[index]; + isl38xx_fragment *frag = &cb->rx_data_mgmt[index]; + + if (buf->mem == NULL) { + buf->mem = kmalloc(MGMT_FRAME_SIZE, GFP_ATOMIC); + if (!buf->mem) { + printk(KERN_WARNING + "Error allocating management frame.\n"); + return -ENOMEM; + } + buf->size = MGMT_FRAME_SIZE; + } + if (buf->pci_addr == 0) { + buf->pci_addr = pci_map_single(priv->pdev, buf->mem, + MGMT_FRAME_SIZE, + PCI_DMA_FROMDEVICE); + if (!buf->pci_addr) { + printk(KERN_WARNING + "Failed to make memory DMA'able\n."); + return -ENOMEM; + } + } + + /* be safe: always reset control block information */ + frag->size = cpu_to_le16(MGMT_FRAME_SIZE); + frag->flags = 0; + frag->address = cpu_to_le32(buf->pci_addr); + curr++; + + /* The fragment address in the control block must have + * been written before announcing the frame buffer to + * device */ + wmb(); + cb->driver_curr_frag[ISL38XX_CB_RX_MGMTQ] = cpu_to_le32(curr); + } + return 0; +} + +/* + * Create and transmit a management frame using "operation" and "oid", + * with arguments data/length. + * We either return an error and free the frame, or we return 0 and + * islpci_mgt_cleanup_transmit() frees the frame in the tx-done + * interrupt. + */ +static int +islpci_mgt_transmit(struct net_device *ndev, int operation, unsigned long oid, + void *data, int length) +{ + islpci_private *priv = netdev_priv(ndev); + isl38xx_control_block *cb = + (isl38xx_control_block *) priv->control_block; + void *p; + int err = -EINVAL; + unsigned long flags; + isl38xx_fragment *frag; + struct islpci_membuf buf; + u32 curr_frag; + int index; + int frag_len = length + PIMFOR_HEADER_SIZE; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgt_transmit\n"); +#endif + + if (frag_len > MGMT_FRAME_SIZE) { + printk(KERN_DEBUG "%s: mgmt frame too large %d\n", + ndev->name, frag_len); + goto error; + } + + err = -ENOMEM; + p = buf.mem = kmalloc(frag_len, GFP_KERNEL); + if (!buf.mem) { + printk(KERN_DEBUG "%s: cannot allocate mgmt frame\n", + ndev->name); + goto error; + } + buf.size = frag_len; + + /* create the header directly in the fragment data area */ + pimfor_encode_header(operation, oid, length, (pimfor_header_t *) p); + p += PIMFOR_HEADER_SIZE; + + if (data) + memcpy(p, data, length); + else + memset(p, 0, length); + +#if VERBOSE > SHOW_ERROR_MESSAGES + { + pimfor_header_t *h = buf.mem; + DEBUG(SHOW_PIMFOR_FRAMES, + "PIMFOR: op %i, oid 0x%08lx, device %i, flags 0x%x length 0x%x \n", + h->operation, oid, h->device_id, h->flags, length); + + /* display the buffer contents for debugging */ + display_buffer((char *) h, sizeof (pimfor_header_t)); + display_buffer(p, length); + } +#endif + + err = -ENOMEM; + buf.pci_addr = pci_map_single(priv->pdev, buf.mem, frag_len, + PCI_DMA_TODEVICE); + if (!buf.pci_addr) { + printk(KERN_WARNING "%s: cannot map PCI memory for mgmt\n", + ndev->name); + goto error_free; + } + + /* Protect the control block modifications against interrupts. */ + spin_lock_irqsave(&priv->slock, flags); + curr_frag = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_TX_MGMTQ]); + if (curr_frag - priv->index_mgmt_tx >= ISL38XX_CB_MGMT_QSIZE) { + printk(KERN_WARNING "%s: mgmt tx queue is still full\n", + ndev->name); + goto error_unlock; + } + + /* commit the frame to the tx device queue */ + index = curr_frag % ISL38XX_CB_MGMT_QSIZE; + priv->mgmt_tx[index] = buf; + frag = &cb->tx_data_mgmt[index]; + frag->size = cpu_to_le16(frag_len); + frag->flags = 0; /* for any other than the last fragment, set to 1 */ + frag->address = cpu_to_le32(buf.pci_addr); + + /* The fragment address in the control block must have + * been written before announcing the frame buffer to + * device */ + wmb(); + cb->driver_curr_frag[ISL38XX_CB_TX_MGMTQ] = cpu_to_le32(curr_frag + 1); + spin_unlock_irqrestore(&priv->slock, flags); + + /* trigger the device */ + islpci_trigger(priv); + return 0; + + error_unlock: + spin_unlock_irqrestore(&priv->slock, flags); + error_free: + kfree(buf.mem); + error: + return err; +} + +/* + * Receive a management frame from the device. + * This can be an arbitrary number of traps, and at most one response + * frame for a previous request sent via islpci_mgt_transmit(). + */ +int +islpci_mgt_receive(struct net_device *ndev) +{ + islpci_private *priv = netdev_priv(ndev); + isl38xx_control_block *cb = + (isl38xx_control_block *) priv->control_block; + u32 curr_frag; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgt_receive \n"); +#endif + + /* Only once per interrupt, determine fragment range to + * process. This avoids an endless loop (i.e. lockup) if + * frames come in faster than we can process them. */ + curr_frag = le32_to_cpu(cb->device_curr_frag[ISL38XX_CB_RX_MGMTQ]); + barrier(); + + for (; priv->index_mgmt_rx < curr_frag; priv->index_mgmt_rx++) { + pimfor_header_t *header; + u32 index = priv->index_mgmt_rx % ISL38XX_CB_MGMT_QSIZE; + struct islpci_membuf *buf = &priv->mgmt_rx[index]; + u16 frag_len; + int size; + struct islpci_mgmtframe *frame; + + /* I have no idea (and no documentation) if flags != 0 + * is possible. Drop the frame, reuse the buffer. */ + if (le16_to_cpu(cb->rx_data_mgmt[index].flags) != 0) { + printk(KERN_WARNING "%s: unknown flags 0x%04x\n", + ndev->name, + le16_to_cpu(cb->rx_data_mgmt[index].flags)); + continue; + } + + /* The device only returns the size of the header(s) here. */ + frag_len = le16_to_cpu(cb->rx_data_mgmt[index].size); + + /* + * We appear to have no way to tell the device the + * size of a receive buffer. Thus, if this check + * triggers, we likely have kernel heap corruption. */ + if (frag_len > MGMT_FRAME_SIZE) { + printk(KERN_WARNING + "%s: Bogus packet size of %d (%#x).\n", + ndev->name, frag_len, frag_len); + frag_len = MGMT_FRAME_SIZE; + } + + /* Ensure the results of device DMA are visible to the CPU. */ + pci_dma_sync_single(priv->pdev, buf->pci_addr, + buf->size, PCI_DMA_FROMDEVICE); + + /* Perform endianess conversion for PIMFOR header in-place. */ + header = pimfor_decode_header(buf->mem, frag_len); + if (!header) { + printk(KERN_WARNING "%s: no PIMFOR header found\n", + ndev->name); + continue; + } + + /* The device ID from the PIMFOR packet received from + * the MVC is always 0. We forward a sensible device_id. + * Not that anyone upstream would care... */ + header->device_id = priv->ndev->ifindex; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_PIMFOR_FRAMES, + "PIMFOR: op %i, oid 0x%08x, device %i, flags 0x%x length 0x%x \n", + header->operation, header->oid, header->device_id, + header->flags, header->length); + + /* display the buffer contents for debugging */ + display_buffer((char *) header, PIMFOR_HEADER_SIZE); + display_buffer((char *) header + PIMFOR_HEADER_SIZE, + header->length); +#endif + + /* nobody sends these */ + if (header->flags & PIMFOR_FLAG_APPLIC_ORIGIN) { + printk(KERN_DEBUG + "%s: errant PIMFOR application frame\n", + ndev->name); + continue; + } + + /* Determine frame size, skipping OID_INL_TUNNEL headers. */ + size = PIMFOR_HEADER_SIZE + header->length; + frame = kmalloc(sizeof (struct islpci_mgmtframe) + size, + GFP_ATOMIC); + if (!frame) { + printk(KERN_WARNING + "%s: Out of memory, cannot handle oid 0x%08x\n", + ndev->name, header->oid); + continue; + } + frame->ndev = ndev; + memcpy(&frame->buf, header, size); + frame->header = (pimfor_header_t *) frame->buf; + frame->data = frame->buf + PIMFOR_HEADER_SIZE; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_PIMFOR_FRAMES, + "frame: header: %p, data: %p, size: %d\n", + frame->header, frame->data, size); +#endif + + if (header->operation == PIMFOR_OP_TRAP) { +#if VERBOSE > SHOW_ERROR_MESSAGES + printk(KERN_DEBUG + "TRAP: oid 0x%x, device %i, flags 0x%x length %i\n", + header->oid, header->device_id, header->flags, + header->length); +#endif + + /* Create work to handle trap out of interrupt + * context. */ + INIT_WORK(&frame->ws, prism54_process_trap, frame); + schedule_work(&frame->ws); + + } else { + /* Signal the one waiting process that a response + * has been received. */ + if ((frame = xchg(&priv->mgmt_received, frame)) != NULL) { + printk(KERN_WARNING + "%s: mgmt response not collected\n", + ndev->name); + kfree(frame); + } +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "Wake up Mgmt Queue\n"); +#endif + wake_up(&priv->mgmt_wqueue); + } + + } + + return 0; +} + +/* + * Cleanup the transmit queue by freeing all frames handled by the device. + */ +void +islpci_mgt_cleanup_transmit(struct net_device *ndev) +{ + islpci_private *priv = netdev_priv(ndev); + isl38xx_control_block *cb = /* volatile not needed */ + (isl38xx_control_block *) priv->control_block; + u32 curr_frag; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgt_cleanup_transmit\n"); +#endif + + /* Only once per cleanup, determine fragment range to + * process. This avoids an endless loop (i.e. lockup) if + * the device became confused, incrementing device_curr_frag + * rapidly. */ + curr_frag = le32_to_cpu(cb->device_curr_frag[ISL38XX_CB_TX_MGMTQ]); + barrier(); + + for (; priv->index_mgmt_tx < curr_frag; priv->index_mgmt_tx++) { + int index = priv->index_mgmt_tx % ISL38XX_CB_MGMT_QSIZE; + struct islpci_membuf *buf = &priv->mgmt_tx[index]; + pci_unmap_single(priv->pdev, buf->pci_addr, buf->size, + PCI_DMA_TODEVICE); + buf->pci_addr = 0; + kfree(buf->mem); + buf->mem = NULL; + buf->size = 0; + } +} + +/* + * Perform one request-response transaction to the device. + */ +int +islpci_mgt_transaction(struct net_device *ndev, + int operation, unsigned long oid, + void *senddata, int sendlen, + struct islpci_mgmtframe **recvframe) +{ + islpci_private *priv = netdev_priv(ndev); + const long wait_cycle_jiffies = (ISL38XX_WAIT_CYCLE * 10 * HZ) / 1000; + long timeout_left = ISL38XX_MAX_WAIT_CYCLES * wait_cycle_jiffies; + int err; + DEFINE_WAIT(wait); + + *recvframe = NULL; + + if (down_interruptible(&priv->mgmt_sem)) + return -ERESTARTSYS; + + prepare_to_wait(&priv->mgmt_wqueue, &wait, TASK_UNINTERRUPTIBLE); + err = islpci_mgt_transmit(ndev, operation, oid, senddata, sendlen); + if (err) + goto out; + + err = -ETIMEDOUT; + while (timeout_left > 0) { + int timeleft; + struct islpci_mgmtframe *frame; + + timeleft = schedule_timeout(wait_cycle_jiffies); + frame = xchg(&priv->mgmt_received, NULL); + if (frame) { + if (frame->header->oid == oid) { + *recvframe = frame; + err = 0; + goto out; + } else { + printk(KERN_DEBUG + "%s: expecting oid 0x%x, received 0x%x.\n", + ndev->name, (unsigned int) oid, + frame->header->oid); + kfree(frame); + frame = NULL; + } + } + if (timeleft == 0) { + printk(KERN_DEBUG + "%s: timeout waiting for mgmt response %lu, " + "triggering device\n", + ndev->name, timeout_left); + islpci_trigger(priv); + } + timeout_left += timeleft - wait_cycle_jiffies; + } + printk(KERN_WARNING "%s: timeout waiting for mgmt response\n", + ndev->name); + + /* TODO: we should reset the device here */ + out: + finish_wait(&priv->mgmt_wqueue, &wait); + up(&priv->mgmt_sem); + return err; +} + diff -Nru a/drivers/net/wireless/prism54/islpci_mgt.h b/drivers/net/wireless/prism54/islpci_mgt.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/net/wireless/prism54/islpci_mgt.h 2004-08-14 12:02:31 -07:00 @@ -0,0 +1,162 @@ +/* + * + * Copyright (C) 2002 Intersil Americas Inc. + * Copyright (C) 2003 Luis R. Rodriguez + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _ISLPCI_MGT_H +#define _ISLPCI_MGT_H + +#include +#include + +/* + * Function definitions + */ + +#define K_DEBUG(f, m, args...) do { if(f & m) printk(KERN_DEBUG args); } while(0) +#define DEBUG(f, args...) K_DEBUG(f, pc_debug, args) + +#define TRACE(devname) K_DEBUG(SHOW_TRACING, VERBOSE, "%s: -> " __FUNCTION__ "()\n", devname) + +extern int pc_debug; +#define init_wds 0 /* help compiler optimize away dead code */ + + +/* General driver definitions */ +#define PCIVENDOR_INTERSIL 0x1260UL +#define PCIVENDOR_3COM 0x10b7UL +#define PCIVENDOR_DLINK 0x1186UL +#define PCIVENDOR_I4 0x17cfUL +#define PCIVENDOR_IODATA 0x10fcUL +#define PCIVENDOR_NETGEAR 0x1385UL +#define PCIVENDOR_SMC 0x10b8UL +#define PCIVENDOR_ACCTON 0x1113UL +#define PCIVENDOR_ATI 0x1259UL +#define PCIVENDOR_TTL 0x16a5UL + +#define PCIDEVICE_ISL3877 0x3877UL +#define PCIDEVICE_ISL3886 0x3886UL +#define PCIDEVICE_ISL3890 0x3890UL +#define PCIDEVICE_3COM6001 0x6001UL +#define PCIDEVICE_LATENCY_TIMER_MIN 0x40 +#define PCIDEVICE_LATENCY_TIMER_VAL 0x50 + +/* Debugging verbose definitions */ +#define SHOW_NOTHING 0x00 /* overrules everything */ +#define SHOW_ANYTHING 0xFF +#define SHOW_ERROR_MESSAGES 0x01 +#define SHOW_TRAPS 0x02 +#define SHOW_FUNCTION_CALLS 0x04 +#define SHOW_TRACING 0x08 +#define SHOW_QUEUE_INDEXES 0x10 +#define SHOW_PIMFOR_FRAMES 0x20 +#define SHOW_BUFFER_CONTENTS 0x40 +#define VERBOSE 0x01 + +/* Default card definitions */ +#define CARD_DEFAULT_CHANNEL 6 +#define CARD_DEFAULT_MODE INL_MODE_CLIENT +#define CARD_DEFAULT_IW_MODE IW_MODE_INFRA +#define CARD_DEFAULT_BSSTYPE DOT11_BSSTYPE_INFRA +#define CARD_DEFAULT_CLIENT_SSID "" +#define CARD_DEFAULT_AP_SSID "default" +#define CARD_DEFAULT_KEY1 "default_key_1" +#define CARD_DEFAULT_KEY2 "default_key_2" +#define CARD_DEFAULT_KEY3 "default_key_3" +#define CARD_DEFAULT_KEY4 "default_key_4" +#define CARD_DEFAULT_WEP 0 +#define CARD_DEFAULT_FILTER 0 +#define CARD_DEFAULT_WDS 0 +#define CARD_DEFAULT_AUTHEN DOT11_AUTH_OS +#define CARD_DEFAULT_DOT1X 0 +#define CARD_DEFAULT_MLME_MODE DOT11_MLME_AUTO +#define CARD_DEFAULT_CONFORMANCE OID_INL_CONFORMANCE_NONE +#define CARD_DEFAULT_PROFILE DOT11_PROFILE_MIXED_G_WIFI +#define CARD_DEFAULT_MAXFRAMEBURST DOT11_MAXFRAMEBURST_MIXED_SAFE + +/* PIMFOR package definitions */ +#define PIMFOR_ETHERTYPE 0x8828 +#define PIMFOR_HEADER_SIZE 12 +#define PIMFOR_VERSION 1 +#define PIMFOR_OP_GET 0 +#define PIMFOR_OP_SET 1 +#define PIMFOR_OP_RESPONSE 2 +#define PIMFOR_OP_ERROR 3 +#define PIMFOR_OP_TRAP 4 +#define PIMFOR_OP_RESERVED 5 /* till 255 */ +#define PIMFOR_DEV_ID_MHLI_MIB 0 +#define PIMFOR_FLAG_APPLIC_ORIGIN 0x01 +#define PIMFOR_FLAG_LITTLE_ENDIAN 0x02 + +static inline void +add_le32p(u32 * le_number, u32 add) +{ + *le_number = cpu_to_le32(le32_to_cpup(le_number) + add); +} + +void display_buffer(char *, int); + +/* + * Type definition section + * + * the structure defines only the header allowing copyless + * frame handling + */ +typedef struct { + u8 version; + u8 operation; + u32 oid; + u8 device_id; + u8 flags; + u32 length; +} __attribute__ ((packed)) +pimfor_header_t; + +/* A received and interrupt-processed management frame, either for + * schedule_work(prism54_process_trap) or for priv->mgmt_received, + * processed by islpci_mgt_transaction(). */ +struct islpci_mgmtframe { + struct net_device *ndev; /* pointer to network device */ + pimfor_header_t *header; /* payload header, points into buf */ + void *data; /* payload ex header, points into buf */ + struct work_struct ws; /* argument for schedule_work() */ + char buf[0]; /* fragment buffer */ +}; + +int +islpci_mgt_receive(struct net_device *ndev); + +int +islpci_mgmt_rx_fill(struct net_device *ndev); + +void +islpci_mgt_cleanup_transmit(struct net_device *ndev); + +int +islpci_mgt_transaction(struct net_device *ndev, + int operation, unsigned long oid, + void *senddata, int sendlen, + struct islpci_mgmtframe **recvframe); + +static inline void +islpci_mgt_release(struct islpci_mgmtframe *frame) +{ + kfree(frame); +} + +#endif /* _ISLPCI_MGT_H */ diff -Nru a/drivers/net/wireless/prism54/oid_mgt.c b/drivers/net/wireless/prism54/oid_mgt.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/net/wireless/prism54/oid_mgt.c 2004-08-14 12:02:31 -07:00 @@ -0,0 +1,807 @@ +/* + * Copyright (C) 2003,2004 Aurelien Alleaume + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "prismcompat.h" +#include "islpci_dev.h" +#include "islpci_mgt.h" +#include "isl_oid.h" +#include "oid_mgt.h" +#include "isl_ioctl.h" + +/* to convert between channel and freq */ +const int frequency_list_bg[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, + 2447, 2452, 2457, 2462, 2467, 2472, 2484 +}; + +int +channel_of_freq(int f) +{ + int c = 0; + + if ((f >= 2412) && (f <= 2484)) { + while ((c < 14) && (f != frequency_list_bg[c])) + c++; + return (c >= 14) ? 0 : ++c; + } else if ((f >= (int) 5000) && (f <= (int) 6000)) { + return ( (f - 5000) / 5 ); + } else + return 0; +} + +#define OID_STRUCT(name,oid,s,t) [name] = {oid, 0, sizeof(s), t} +#define OID_STRUCT_C(name,oid,s,t) OID_STRUCT(name,oid,s,t | OID_FLAG_CACHED) +#define OID_U32(name,oid) OID_STRUCT(name,oid,u32,OID_TYPE_U32) +#define OID_U32_C(name,oid) OID_STRUCT_C(name,oid,u32,OID_TYPE_U32) +#define OID_STRUCT_MLME(name,oid) OID_STRUCT(name,oid,struct obj_mlme,OID_TYPE_MLME) +#define OID_STRUCT_MLMEEX(name,oid) OID_STRUCT(name,oid,struct obj_mlmeex,OID_TYPE_MLMEEX) + +#define OID_UNKNOWN(name,oid) OID_STRUCT(name,oid,0,0) + +struct oid_t isl_oid[] = { + OID_STRUCT(GEN_OID_MACADDRESS, 0x00000000, u8[6], OID_TYPE_ADDR), + OID_U32(GEN_OID_LINKSTATE, 0x00000001), + OID_UNKNOWN(GEN_OID_WATCHDOG, 0x00000002), + OID_UNKNOWN(GEN_OID_MIBOP, 0x00000003), + OID_UNKNOWN(GEN_OID_OPTIONS, 0x00000004), + OID_UNKNOWN(GEN_OID_LEDCONFIG, 0x00000005), + + /* 802.11 */ + OID_U32_C(DOT11_OID_BSSTYPE, 0x10000000), + OID_STRUCT_C(DOT11_OID_BSSID, 0x10000001, u8[6], OID_TYPE_RAW), + OID_STRUCT_C(DOT11_OID_SSID, 0x10000002, struct obj_ssid, + OID_TYPE_SSID), + OID_U32(DOT11_OID_STATE, 0x10000003), + OID_U32(DOT11_OID_AID, 0x10000004), + OID_STRUCT(DOT11_OID_COUNTRYSTRING, 0x10000005, u8[4], OID_TYPE_RAW), + OID_STRUCT_C(DOT11_OID_SSIDOVERRIDE, 0x10000006, struct obj_ssid, + OID_TYPE_SSID), + + OID_U32(DOT11_OID_MEDIUMLIMIT, 0x11000000), + OID_U32_C(DOT11_OID_BEACONPERIOD, 0x11000001), + OID_U32(DOT11_OID_DTIMPERIOD, 0x11000002), + OID_U32(DOT11_OID_ATIMWINDOW, 0x11000003), + OID_U32(DOT11_OID_LISTENINTERVAL, 0x11000004), + OID_U32(DOT11_OID_CFPPERIOD, 0x11000005), + OID_U32(DOT11_OID_CFPDURATION, 0x11000006), + + OID_U32_C(DOT11_OID_AUTHENABLE, 0x12000000), + OID_U32_C(DOT11_OID_PRIVACYINVOKED, 0x12000001), + OID_U32_C(DOT11_OID_EXUNENCRYPTED, 0x12000002), + OID_U32_C(DOT11_OID_DEFKEYID, 0x12000003), + [DOT11_OID_DEFKEYX] = {0x12000004, 3, sizeof (struct obj_key), + OID_FLAG_CACHED | OID_TYPE_KEY}, /* DOT11_OID_DEFKEY1,...DOT11_OID_DEFKEY4 */ + OID_UNKNOWN(DOT11_OID_STAKEY, 0x12000008), + OID_U32(DOT11_OID_REKEYTHRESHOLD, 0x12000009), + OID_UNKNOWN(DOT11_OID_STASC, 0x1200000a), + + OID_U32(DOT11_OID_PRIVTXREJECTED, 0x1a000000), + OID_U32(DOT11_OID_PRIVRXPLAIN, 0x1a000001), + OID_U32(DOT11_OID_PRIVRXFAILED, 0x1a000002), + OID_U32(DOT11_OID_PRIVRXNOKEY, 0x1a000003), + + OID_U32_C(DOT11_OID_RTSTHRESH, 0x13000000), + OID_U32_C(DOT11_OID_FRAGTHRESH, 0x13000001), + OID_U32_C(DOT11_OID_SHORTRETRIES, 0x13000002), + OID_U32_C(DOT11_OID_LONGRETRIES, 0x13000003), + OID_U32_C(DOT11_OID_MAXTXLIFETIME, 0x13000004), + OID_U32(DOT11_OID_MAXRXLIFETIME, 0x13000005), + OID_U32(DOT11_OID_AUTHRESPTIMEOUT, 0x13000006), + OID_U32(DOT11_OID_ASSOCRESPTIMEOUT, 0x13000007), + + OID_UNKNOWN(DOT11_OID_ALOFT_TABLE, 0x1d000000), + OID_UNKNOWN(DOT11_OID_ALOFT_CTRL_TABLE, 0x1d000001), + OID_UNKNOWN(DOT11_OID_ALOFT_RETREAT, 0x1d000002), + OID_UNKNOWN(DOT11_OID_ALOFT_PROGRESS, 0x1d000003), + OID_U32(DOT11_OID_ALOFT_FIXEDRATE, 0x1d000004), + OID_UNKNOWN(DOT11_OID_ALOFT_RSSIGRAPH, 0x1d000005), + OID_UNKNOWN(DOT11_OID_ALOFT_CONFIG, 0x1d000006), + + [DOT11_OID_VDCFX] = {0x1b000000, 7, 0, 0}, + OID_U32(DOT11_OID_MAXFRAMEBURST, 0x1b000008), + + OID_U32(DOT11_OID_PSM, 0x14000000), + OID_U32(DOT11_OID_CAMTIMEOUT, 0x14000001), + OID_U32(DOT11_OID_RECEIVEDTIMS, 0x14000002), + OID_U32(DOT11_OID_ROAMPREFERENCE, 0x14000003), + + OID_U32(DOT11_OID_BRIDGELOCAL, 0x15000000), + OID_U32(DOT11_OID_CLIENTS, 0x15000001), + OID_U32(DOT11_OID_CLIENTSASSOCIATED, 0x15000002), + [DOT11_OID_CLIENTX] = {0x15000003, 2006, 0, 0}, /* DOT11_OID_CLIENTX,...DOT11_OID_CLIENT2007 */ + + OID_STRUCT(DOT11_OID_CLIENTFIND, 0x150007DB, u8[6], OID_TYPE_ADDR), + OID_STRUCT(DOT11_OID_WDSLINKADD, 0x150007DC, u8[6], OID_TYPE_ADDR), + OID_STRUCT(DOT11_OID_WDSLINKREMOVE, 0x150007DD, u8[6], OID_TYPE_ADDR), + OID_STRUCT(DOT11_OID_EAPAUTHSTA, 0x150007DE, u8[6], OID_TYPE_ADDR), + OID_STRUCT(DOT11_OID_EAPUNAUTHSTA, 0x150007DF, u8[6], OID_TYPE_ADDR), + OID_U32_C(DOT11_OID_DOT1XENABLE, 0x150007E0), + OID_UNKNOWN(DOT11_OID_MICFAILURE, 0x150007E1), + OID_UNKNOWN(DOT11_OID_REKEYINDICATE, 0x150007E2), + + OID_U32(DOT11_OID_MPDUTXSUCCESSFUL, 0x16000000), + OID_U32(DOT11_OID_MPDUTXONERETRY, 0x16000001), + OID_U32(DOT11_OID_MPDUTXMULTIPLERETRIES, 0x16000002), + OID_U32(DOT11_OID_MPDUTXFAILED, 0x16000003), + OID_U32(DOT11_OID_MPDURXSUCCESSFUL, 0x16000004), + OID_U32(DOT11_OID_MPDURXDUPS, 0x16000005), + OID_U32(DOT11_OID_RTSSUCCESSFUL, 0x16000006), + OID_U32(DOT11_OID_RTSFAILED, 0x16000007), + OID_U32(DOT11_OID_ACKFAILED, 0x16000008), + OID_U32(DOT11_OID_FRAMERECEIVES, 0x16000009), + OID_U32(DOT11_OID_FRAMEERRORS, 0x1600000A), + OID_U32(DOT11_OID_FRAMEABORTS, 0x1600000B), + OID_U32(DOT11_OID_FRAMEABORTSPHY, 0x1600000C), + + OID_U32(DOT11_OID_SLOTTIME, 0x17000000), + OID_U32(DOT11_OID_CWMIN, 0x17000001), + OID_U32(DOT11_OID_CWMAX, 0x17000002), + OID_U32(DOT11_OID_ACKWINDOW, 0x17000003), + OID_U32(DOT11_OID_ANTENNARX, 0x17000004), + OID_U32(DOT11_OID_ANTENNATX, 0x17000005), + OID_U32(DOT11_OID_ANTENNADIVERSITY, 0x17000006), + OID_U32_C(DOT11_OID_CHANNEL, 0x17000007), + OID_U32_C(DOT11_OID_EDTHRESHOLD, 0x17000008), + OID_U32(DOT11_OID_PREAMBLESETTINGS, 0x17000009), + OID_STRUCT(DOT11_OID_RATES, 0x1700000A, u8[IWMAX_BITRATES + 1], + OID_TYPE_RAW), + OID_U32(DOT11_OID_CCAMODESUPPORTED, 0x1700000B), + OID_U32(DOT11_OID_CCAMODE, 0x1700000C), + OID_UNKNOWN(DOT11_OID_RSSIVECTOR, 0x1700000D), + OID_UNKNOWN(DOT11_OID_OUTPUTPOWERTABLE, 0x1700000E), + OID_U32(DOT11_OID_OUTPUTPOWER, 0x1700000F), + OID_STRUCT(DOT11_OID_SUPPORTEDRATES, 0x17000010, + u8[IWMAX_BITRATES + 1], OID_TYPE_RAW), + OID_U32_C(DOT11_OID_FREQUENCY, 0x17000011), + [DOT11_OID_SUPPORTEDFREQUENCIES] = + {0x17000012, 0, sizeof (struct obj_frequencies) + + sizeof (u16) * IWMAX_FREQ, OID_TYPE_FREQUENCIES}, + + OID_U32(DOT11_OID_NOISEFLOOR, 0x17000013), + OID_STRUCT(DOT11_OID_FREQUENCYACTIVITY, 0x17000014, u8[IWMAX_FREQ + 1], + OID_TYPE_RAW), + OID_UNKNOWN(DOT11_OID_IQCALIBRATIONTABLE, 0x17000015), + OID_U32(DOT11_OID_NONERPPROTECTION, 0x17000016), + OID_U32(DOT11_OID_SLOTSETTINGS, 0x17000017), + OID_U32(DOT11_OID_NONERPTIMEOUT, 0x17000018), + OID_U32(DOT11_OID_PROFILES, 0x17000019), + OID_STRUCT(DOT11_OID_EXTENDEDRATES, 0x17000020, + u8[IWMAX_BITRATES + 1], OID_TYPE_RAW), + + OID_STRUCT_MLME(DOT11_OID_DEAUTHENTICATE, 0x18000000), + OID_STRUCT_MLME(DOT11_OID_AUTHENTICATE, 0x18000001), + OID_STRUCT_MLME(DOT11_OID_DISASSOCIATE, 0x18000002), + OID_STRUCT_MLME(DOT11_OID_ASSOCIATE, 0x18000003), + OID_UNKNOWN(DOT11_OID_SCAN, 0x18000004), + OID_STRUCT_MLMEEX(DOT11_OID_BEACON, 0x18000005), + OID_STRUCT_MLMEEX(DOT11_OID_PROBE, 0x18000006), + OID_STRUCT_MLMEEX(DOT11_OID_DEAUTHENTICATEEX, 0x18000007), + OID_STRUCT_MLMEEX(DOT11_OID_AUTHENTICATEEX, 0x18000008), + OID_STRUCT_MLMEEX(DOT11_OID_DISASSOCIATEEX, 0x18000009), + OID_STRUCT_MLMEEX(DOT11_OID_ASSOCIATEEX, 0x1800000A), + OID_STRUCT_MLMEEX(DOT11_OID_REASSOCIATE, 0x1800000B), + OID_STRUCT_MLMEEX(DOT11_OID_REASSOCIATEEX, 0x1800000C), + + OID_U32(DOT11_OID_NONERPSTATUS, 0x1E000000), + + OID_U32(DOT11_OID_STATIMEOUT, 0x19000000), + OID_U32_C(DOT11_OID_MLMEAUTOLEVEL, 0x19000001), + OID_U32(DOT11_OID_BSSTIMEOUT, 0x19000002), + OID_UNKNOWN(DOT11_OID_ATTACHMENT, 0x19000003), + OID_STRUCT_C(DOT11_OID_PSMBUFFER, 0x19000004, struct obj_buffer, + OID_TYPE_BUFFER), + + OID_U32(DOT11_OID_BSSS, 0x1C000000), + [DOT11_OID_BSSX] = {0x1C000001, 63, sizeof (struct obj_bss), + OID_TYPE_BSS}, /*DOT11_OID_BSS1,...,DOT11_OID_BSS64 */ + OID_STRUCT(DOT11_OID_BSSFIND, 0x1C000042, struct obj_bss, OID_TYPE_BSS), + [DOT11_OID_BSSLIST] = {0x1C000043, 0, sizeof (struct + obj_bsslist) + + sizeof (struct obj_bss[IWMAX_BSS]), + OID_TYPE_BSSLIST}, + + OID_UNKNOWN(OID_INL_TUNNEL, 0xFF020000), + OID_UNKNOWN(OID_INL_MEMADDR, 0xFF020001), + OID_UNKNOWN(OID_INL_MEMORY, 0xFF020002), + OID_U32_C(OID_INL_MODE, 0xFF020003), + OID_UNKNOWN(OID_INL_COMPONENT_NR, 0xFF020004), + OID_UNKNOWN(OID_INL_VERSION, 0xFF020005), + OID_UNKNOWN(OID_INL_INTERFACE_ID, 0xFF020006), + OID_UNKNOWN(OID_INL_COMPONENT_ID, 0xFF020007), + OID_U32_C(OID_INL_CONFIG, 0xFF020008), + OID_U32_C(OID_INL_DOT11D_CONFORMANCE, 0xFF02000C), + OID_U32(OID_INL_PHYCAPABILITIES, 0xFF02000D), + OID_U32_C(OID_INL_OUTPUTPOWER, 0xFF02000F), + +}; + +int +mgt_init(islpci_private *priv) +{ + int i; + + priv->mib = kmalloc(OID_NUM_LAST * sizeof (void *), GFP_KERNEL); + if (!priv->mib) + return -ENOMEM; + + memset(priv->mib, 0, OID_NUM_LAST * sizeof (void *)); + + /* Alloc the cache */ + for (i = 0; i < OID_NUM_LAST; i++) { + if (isl_oid[i].flags & OID_FLAG_CACHED) { + priv->mib[i] = kmalloc(isl_oid[i].size * + (isl_oid[i].range + 1), + GFP_KERNEL); + if (!priv->mib[i]) + return -ENOMEM; + memset(priv->mib[i], 0, + isl_oid[i].size * (isl_oid[i].range + 1)); + } else + priv->mib[i] = NULL; + } + + init_rwsem(&priv->mib_sem); + prism54_mib_init(priv); + + return 0; +} + +void +mgt_clean(islpci_private *priv) +{ + int i; + + if (!priv->mib) + return; + for (i = 0; i < OID_NUM_LAST; i++) + if (priv->mib[i]) { + kfree(priv->mib[i]); + priv->mib[i] = NULL; + } + kfree(priv->mib); + priv->mib = NULL; +} + +void +mgt_le_to_cpu(int type, void *data) +{ + switch (type) { + case OID_TYPE_U32: + *(u32 *) data = le32_to_cpu(*(u32 *) data); + break; + case OID_TYPE_BUFFER:{ + struct obj_buffer *buff = data; + buff->size = le32_to_cpu(buff->size); + buff->addr = le32_to_cpu(buff->addr); + break; + } + case OID_TYPE_BSS:{ + struct obj_bss *bss = data; + bss->age = le16_to_cpu(bss->age); + bss->channel = le16_to_cpu(bss->channel); + bss->capinfo = le16_to_cpu(bss->capinfo); + bss->rates = le16_to_cpu(bss->rates); + bss->basic_rates = le16_to_cpu(bss->basic_rates); + break; + } + case OID_TYPE_BSSLIST:{ + struct obj_bsslist *list = data; + int i; + list->nr = le32_to_cpu(list->nr); + for (i = 0; i < list->nr; i++) + mgt_le_to_cpu(OID_TYPE_BSS, &list->bsslist[i]); + break; + } + case OID_TYPE_FREQUENCIES:{ + struct obj_frequencies *freq = data; + int i; + freq->nr = le16_to_cpu(freq->nr); + for (i = 0; i < freq->nr; i++) + freq->mhz[i] = le16_to_cpu(freq->mhz[i]); + break; + } + case OID_TYPE_MLME:{ + struct obj_mlme *mlme = data; + mlme->id = le16_to_cpu(mlme->id); + mlme->state = le16_to_cpu(mlme->state); + mlme->code = le16_to_cpu(mlme->code); + break; + } + case OID_TYPE_MLMEEX:{ + struct obj_mlmeex *mlme = data; + mlme->id = le16_to_cpu(mlme->id); + mlme->state = le16_to_cpu(mlme->state); + mlme->code = le16_to_cpu(mlme->code); + mlme->size = le16_to_cpu(mlme->size); + break; + } + case OID_TYPE_SSID: + case OID_TYPE_KEY: + case OID_TYPE_ADDR: + case OID_TYPE_RAW: + break; + default: + BUG(); + } +} + +static void +mgt_cpu_to_le(int type, void *data) +{ + switch (type) { + case OID_TYPE_U32: + *(u32 *) data = cpu_to_le32(*(u32 *) data); + break; + case OID_TYPE_BUFFER:{ + struct obj_buffer *buff = data; + buff->size = cpu_to_le32(buff->size); + buff->addr = cpu_to_le32(buff->addr); + break; + } + case OID_TYPE_BSS:{ + struct obj_bss *bss = data; + bss->age = cpu_to_le16(bss->age); + bss->channel = cpu_to_le16(bss->channel); + bss->capinfo = cpu_to_le16(bss->capinfo); + bss->rates = cpu_to_le16(bss->rates); + bss->basic_rates = cpu_to_le16(bss->basic_rates); + break; + } + case OID_TYPE_BSSLIST:{ + struct obj_bsslist *list = data; + int i; + list->nr = cpu_to_le32(list->nr); + for (i = 0; i < list->nr; i++) + mgt_cpu_to_le(OID_TYPE_BSS, &list->bsslist[i]); + break; + } + case OID_TYPE_FREQUENCIES:{ + struct obj_frequencies *freq = data; + int i; + freq->nr = cpu_to_le16(freq->nr); + for (i = 0; i < freq->nr; i++) + freq->mhz[i] = cpu_to_le16(freq->mhz[i]); + break; + } + case OID_TYPE_MLME:{ + struct obj_mlme *mlme = data; + mlme->id = cpu_to_le16(mlme->id); + mlme->state = cpu_to_le16(mlme->state); + mlme->code = cpu_to_le16(mlme->code); + break; + } + case OID_TYPE_MLMEEX:{ + struct obj_mlmeex *mlme = data; + mlme->id = cpu_to_le16(mlme->id); + mlme->state = cpu_to_le16(mlme->state); + mlme->code = cpu_to_le16(mlme->code); + mlme->size = cpu_to_le16(mlme->size); + break; + } + case OID_TYPE_SSID: + case OID_TYPE_KEY: + case OID_TYPE_ADDR: + case OID_TYPE_RAW: + break; + default: + BUG(); + } +} + +/* Note : data is modified during this function */ + +int +mgt_set_request(islpci_private *priv, enum oid_num_t n, int extra, void *data) +{ + int ret = 0; + struct islpci_mgmtframe *response = NULL; + int response_op = PIMFOR_OP_ERROR; + int dlen; + void *cache, *_data = data; + u32 oid; + + BUG_ON(OID_NUM_LAST <= n); + BUG_ON(extra > isl_oid[n].range); + + if (!priv->mib) + /* memory has been freed */ + return -1; + + dlen = isl_oid[n].size; + cache = priv->mib[n]; + cache += (cache ? extra * dlen : 0); + oid = isl_oid[n].oid + extra; + + if (_data == NULL) + /* we are requested to re-set a cached value */ + _data = cache; + else + mgt_cpu_to_le(isl_oid[n].flags & OID_FLAG_TYPE, _data); + /* If we are going to write to the cache, we don't want anyone to read + * it -> acquire write lock. + * Else we could acquire a read lock to be sure we don't bother the + * commit process (which takes a write lock). But I'm not sure if it's + * needed. + */ + if (cache) + down_write(&priv->mib_sem); + + if (islpci_get_state(priv) >= PRV_STATE_READY) { + ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, oid, + _data, dlen, &response); + if (!ret) { + response_op = response->header->operation; + islpci_mgt_release(response); + } + if (ret || response_op == PIMFOR_OP_ERROR) + ret = -EIO; + } else if (!cache) + ret = -EIO; + + if (cache) { + if (!ret && data) + memcpy(cache, _data, dlen); + up_write(&priv->mib_sem); + } + + /* re-set given data to what it was */ + if (data) + mgt_le_to_cpu(isl_oid[n].flags & OID_FLAG_TYPE, data); + + return ret; +} + +int +mgt_get_request(islpci_private *priv, enum oid_num_t n, int extra, void *data, + union oid_res_t *res) +{ + + int ret = -EIO; + int reslen = 0; + struct islpci_mgmtframe *response = NULL; + + int dlen; + void *cache, *_res = NULL; + u32 oid; + + BUG_ON(OID_NUM_LAST <= n); + BUG_ON(extra > isl_oid[n].range); + + if (!priv->mib) + /* memory has been freed */ + return -1; + + dlen = isl_oid[n].size; + cache = priv->mib[n]; + cache += cache ? extra * dlen : 0; + oid = isl_oid[n].oid + extra; + reslen = dlen; + + if (cache) + down_read(&priv->mib_sem); + + if (islpci_get_state(priv) >= PRV_STATE_READY) { + ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET, + oid, data, dlen, &response); + if (ret || !response || + response->header->operation == PIMFOR_OP_ERROR) { + if (response) + islpci_mgt_release(response); + ret = -EIO; + } + if (!ret) { + _res = response->data; + reslen = response->header->length; + } + } else if (cache) { + _res = cache; + ret = 0; + } + if ((isl_oid[n].flags & OID_FLAG_TYPE) == OID_TYPE_U32) + res->u = ret ? 0 : le32_to_cpu(*(u32 *) _res); + else { + res->ptr = kmalloc(reslen, GFP_KERNEL); + BUG_ON(res->ptr == NULL); + if (ret) + memset(res->ptr, 0, reslen); + else { + memcpy(res->ptr, _res, reslen); + mgt_le_to_cpu(isl_oid[n].flags & OID_FLAG_TYPE, + res->ptr); + } + } + if (cache) + up_read(&priv->mib_sem); + + if (response && !ret) + islpci_mgt_release(response); + + if (reslen > isl_oid[n].size) + printk(KERN_DEBUG + "mgt_get_request(0x%x): received data length was bigger " + "than expected (%d > %d). Memory is probably corrupted...", + oid, reslen, isl_oid[n].size); + + return ret; +} + +/* lock outside */ +int +mgt_commit_list(islpci_private *priv, enum oid_num_t *l, int n) +{ + int i, ret = 0; + struct islpci_mgmtframe *response; + + for (i = 0; i < n; i++) { + struct oid_t *t = &(isl_oid[l[i]]); + void *data = priv->mib[l[i]]; + int j = 0; + u32 oid = t->oid; + BUG_ON(data == NULL); + while (j <= t->range) { + response = NULL; + ret |= islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, + oid, data, t->size, + &response); + if (response) { + ret |= (response->header->operation == + PIMFOR_OP_ERROR); + islpci_mgt_release(response); + } + j++; + oid++; + data += t->size; + } + } + return ret; +} + +/* Lock outside */ + +void +mgt_set(islpci_private *priv, enum oid_num_t n, void *data) +{ + BUG_ON(OID_NUM_LAST <= n); + BUG_ON(priv->mib[n] == NULL); + + memcpy(priv->mib[n], data, isl_oid[n].size); + mgt_cpu_to_le(isl_oid[n].flags & OID_FLAG_TYPE, priv->mib[n]); +} + +void +mgt_get(islpci_private *priv, enum oid_num_t n, void *res) +{ + BUG_ON(OID_NUM_LAST <= n); + BUG_ON(priv->mib[n] == NULL); + BUG_ON(res == NULL); + + memcpy(res, priv->mib[n], isl_oid[n].size); + mgt_le_to_cpu(isl_oid[n].flags & OID_FLAG_TYPE, res); +} + +/* Commits the cache. Lock outside. */ + +static enum oid_num_t commit_part1[] = { + OID_INL_CONFIG, + OID_INL_MODE, + DOT11_OID_BSSTYPE, + DOT11_OID_CHANNEL, + DOT11_OID_MLMEAUTOLEVEL +}; + +static enum oid_num_t commit_part2[] = { + DOT11_OID_SSID, + DOT11_OID_PSMBUFFER, + DOT11_OID_AUTHENABLE, + DOT11_OID_PRIVACYINVOKED, + DOT11_OID_EXUNENCRYPTED, + DOT11_OID_DEFKEYX, /* MULTIPLE */ + DOT11_OID_DEFKEYID, + DOT11_OID_DOT1XENABLE, + OID_INL_DOT11D_CONFORMANCE, + OID_INL_OUTPUTPOWER, +}; + +/* update the MAC addr. */ +static int +mgt_update_addr(islpci_private *priv) +{ + struct islpci_mgmtframe *res = NULL; + int ret; + + ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET, + isl_oid[GEN_OID_MACADDRESS].oid, NULL, + isl_oid[GEN_OID_MACADDRESS].size, &res); + + if ((ret == 0) && res && (res->header->operation != PIMFOR_OP_ERROR)) + memcpy(priv->ndev->dev_addr, res->data, 6); + else + ret = -EIO; + if (res) + islpci_mgt_release(res); + + return ret; +} + +void +mgt_commit(islpci_private *priv) +{ + int rvalue; + u32 u; + + if (islpci_get_state(priv) < PRV_STATE_INIT) + return; + + rvalue = mgt_commit_list(priv, commit_part1, + sizeof (commit_part1) / + sizeof (commit_part1[0])); + + if (priv->iw_mode != IW_MODE_MONITOR) + rvalue |= mgt_commit_list(priv, commit_part2, + sizeof (commit_part2) / + sizeof (commit_part2[0])); + + u = OID_INL_MODE; + rvalue |= mgt_commit_list(priv, &u, 1); + rvalue |= mgt_update_addr(priv); + + if (rvalue) { + /* some request have failed. The device might be in an + incoherent state. We should reset it ! */ + printk(KERN_DEBUG "%s: mgt_commit has failed. Restart the " + "device \n", priv->ndev->name); + } +} + +/* This will tell you if you are allowed to answer a mlme(ex) request .*/ + +int +mgt_mlme_answer(islpci_private *priv) +{ + u32 mlmeautolevel; + /* Acquire a read lock because if we are in a mode change, it's + * possible to answer true, while the card is leaving master to managed + * mode. Answering to a mlme in this situation could hang the card. + */ + down_read(&priv->mib_sem); + mlmeautolevel = + le32_to_cpu(*(u32 *) priv->mib[DOT11_OID_MLMEAUTOLEVEL]); + up_read(&priv->mib_sem); + + return ((priv->iw_mode == IW_MODE_MASTER) && + (mlmeautolevel >= DOT11_MLME_INTERMEDIATE)); +} + +enum oid_num_t +mgt_oidtonum(u32 oid) +{ + int i; + + for (i = 0; i < OID_NUM_LAST; i++) + if (isl_oid[i].oid == oid) + return i; + + printk(KERN_DEBUG "looking for an unknown oid 0x%x", oid); + + return OID_NUM_LAST; +} + +int +mgt_response_to_str(enum oid_num_t n, union oid_res_t *r, char *str) +{ + switch (isl_oid[n].flags & OID_FLAG_TYPE) { + case OID_TYPE_U32: + return snprintf(str, PRIV_STR_SIZE, "%u\n", r->u); + break; + case OID_TYPE_BUFFER:{ + struct obj_buffer *buff = r->ptr; + return snprintf(str, PRIV_STR_SIZE, + "size=%u\naddr=0x%X\n", buff->size, + buff->addr); + } + break; + case OID_TYPE_BSS:{ + struct obj_bss *bss = r->ptr; + return snprintf(str, PRIV_STR_SIZE, + "age=%u\nchannel=%u\n" + "capinfo=0x%X\nrates=0x%X\n" + "basic_rates=0x%X\n", bss->age, + bss->channel, bss->capinfo, + bss->rates, bss->basic_rates); + } + break; + case OID_TYPE_BSSLIST:{ + struct obj_bsslist *list = r->ptr; + int i, k; + k = snprintf(str, PRIV_STR_SIZE, "nr=%u\n", list->nr); + for (i = 0; i < list->nr; i++) + k += snprintf(str + k, PRIV_STR_SIZE - k, + "bss[%u] : \nage=%u\nchannel=%u\n" + "capinfo=0x%X\nrates=0x%X\n" + "basic_rates=0x%X\n", + i, list->bsslist[i].age, + list->bsslist[i].channel, + list->bsslist[i].capinfo, + list->bsslist[i].rates, + list->bsslist[i].basic_rates); + return k; + } + break; + case OID_TYPE_FREQUENCIES:{ + struct obj_frequencies *freq = r->ptr; + int i, t; + printk("nr : %u\n", freq->nr); + t = snprintf(str, PRIV_STR_SIZE, "nr=%u\n", freq->nr); + for (i = 0; i < freq->nr; i++) + t += snprintf(str + t, PRIV_STR_SIZE - t, + "mhz[%u]=%u\n", i, freq->mhz[i]); + return t; + } + break; + case OID_TYPE_MLME:{ + struct obj_mlme *mlme = r->ptr; + return snprintf(str, PRIV_STR_SIZE, + "id=0x%X\nstate=0x%X\ncode=0x%X\n", + mlme->id, mlme->state, mlme->code); + } + break; + case OID_TYPE_MLMEEX:{ + struct obj_mlmeex *mlme = r->ptr; + return snprintf(str, PRIV_STR_SIZE, + "id=0x%X\nstate=0x%X\n" + "code=0x%X\nsize=0x%X\n", mlme->id, + mlme->state, mlme->code, mlme->size); + } + break; + case OID_TYPE_SSID:{ + struct obj_ssid *ssid = r->ptr; + return snprintf(str, PRIV_STR_SIZE, + "length=%u\noctets=%.*s\n", + ssid->length, ssid->length, + ssid->octets); + } + break; + case OID_TYPE_KEY:{ + struct obj_key *key = r->ptr; + int t, i; + t = snprintf(str, PRIV_STR_SIZE, + "type=0x%X\nlength=0x%X\nkey=0x", + key->type, key->length); + for (i = 0; i < key->length; i++) + t += snprintf(str + t, PRIV_STR_SIZE - t, + "%02X:", key->key[i]); + t += snprintf(str + t, PRIV_STR_SIZE - t, "\n"); + return t; + } + break; + case OID_TYPE_RAW: + case OID_TYPE_ADDR:{ + unsigned char *buff = r->ptr; + int t, i; + t = snprintf(str, PRIV_STR_SIZE, "hex data="); + for (i = 0; i < isl_oid[n].size; i++) + t += snprintf(str + t, PRIV_STR_SIZE - t, + "%02X:", buff[i]); + t += snprintf(str + t, PRIV_STR_SIZE - t, "\n"); + return t; + } + break; + default: + BUG(); + } + return 0; +} diff -Nru a/drivers/net/wireless/prism54/oid_mgt.h b/drivers/net/wireless/prism54/oid_mgt.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/net/wireless/prism54/oid_mgt.h 2004-08-14 12:02:31 -07:00 @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2003 Aurelien Alleaume + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#if !defined(_OID_MGT_H) +#define _OID_MGT_H + +#include "isl_oid.h" +#include "islpci_dev.h" + +extern struct oid_t isl_oid[]; + +int mgt_init(islpci_private *); + +void mgt_clean(islpci_private *); + +/* I don't know where to put these 3 */ +extern const int frequency_list_bg[]; +extern const int frequency_list_a[]; +int channel_of_freq(int); + +void mgt_le_to_cpu(int, void *); + +int mgt_set_request(islpci_private *, enum oid_num_t, int, void *); + +int mgt_get_request(islpci_private *, enum oid_num_t, int, void *, + union oid_res_t *); + +int mgt_commit_list(islpci_private *, enum oid_num_t *, int); + +void mgt_set(islpci_private *, enum oid_num_t, void *); + +void mgt_get(islpci_private *, enum oid_num_t, void *); + +void mgt_commit(islpci_private *); + +int mgt_mlme_answer(islpci_private *); + +enum oid_num_t mgt_oidtonum(u32 oid); + +int mgt_response_to_str(enum oid_num_t, union oid_res_t *, char *); + +#endif /* !defined(_OID_MGT_H) */ +/* EOF */ diff -Nru a/drivers/net/wireless/prism54/prismcompat.h b/drivers/net/wireless/prism54/prismcompat.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/net/wireless/prism54/prismcompat.h 2004-08-14 12:02:31 -07:00 @@ -0,0 +1,46 @@ +/* + * (C) 2004 Margit Schubert-While + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* + * Compatibility header file to aid support of different kernel versions + */ + +#ifdef PRISM54_COMPAT24 +#include "prismcompat24.h" +#else /* PRISM54_COMPAT24 */ + +#ifndef _PRISM_COMPAT_H +#define _PRISM_COMPAT_H + +#include +#include +#include +#include +#include +#include + +#if !defined(CONFIG_FW_LOADER) && !defined(CONFIG_FW_LOADER_MODULE) +#error Firmware Loading is not configured in the kernel ! +#endif + +#define prism54_synchronize_irq(irq) synchronize_irq(irq) + +#define PRISM_FW_PDEV &priv->pdev->dev + +#endif /* _PRISM_COMPAT_H */ +#endif /* PRISM54_COMPAT24 */ diff -Nru a/drivers/net/wireless/prism54/prismcompat24.h b/drivers/net/wireless/prism54/prismcompat24.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/net/wireless/prism54/prismcompat24.h 2004-08-14 12:02:31 -07:00 @@ -0,0 +1,72 @@ +/* + * (C) 2004 Margit Schubert-While + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* + * Compatibility header file to aid support of different kernel versions + */ + +#ifndef _PRISM_COMPAT_H +#define _PRISM_COMPAT_H + +#include +#include +#include +#include +#include +#include +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,25) +#define module_param(x, y, z) MODULE_PARM(x, "i") +#else +#include +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,23) +#define free_netdev(x) kfree(x) +#define pci_name(x) x->slot_name +#define irqreturn_t void +#define IRQ_HANDLED +#define IRQ_NONE +#else +#include +#endif + +#define work_struct tq_struct +#define INIT_WORK INIT_TQUEUE +#define schedule_work schedule_task + +#if !defined(HAVE_NETDEV_PRIV) +#define netdev_priv(x) x->priv +#endif + +#if !defined(CONFIG_FW_LOADER) && !defined(CONFIG_FW_LOADER_MODULE) +#error Firmware Loading is not configured in the kernel ! +#endif + +#define prism54_synchronize_irq(irq) synchronize_irq() + +#define DEFINE_WAIT(y) DECLARE_WAITQUEUE(y, current) +#define prepare_to_wait(x, y, z) set_current_state(z); \ + add_wait_queue(x, y) +#define finish_wait(x, y) remove_wait_queue(x, y); \ + set_current_state(TASK_RUNNING) + +#define PRISM_FW_PDEV pci_name(priv->pdev) + +#endif /* _PRISM_COMPAT_H */ diff -Nru a/drivers/s390/net/c7000.c b/drivers/s390/net/c7000.c --- a/drivers/s390/net/c7000.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/s390/net/c7000.c 2004-08-14 12:02:30 -07:00 @@ -3,6 +3,20 @@ Author: Bob Scardapane (UTS Global LLC). Version: 3. + This 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. + To use this driver, run the LINUX command: insmod c7000 base0=0xYYYY lhost0=s1 uhost0=s2 lappl0=s3 uappl0=s4 dbg=x @@ -409,16 +423,7 @@ One device structure per controller. */ -/* RBH Try out the new code for 2.4.0 */ -#define NEWSTUFF - -#ifdef NEWSTUFF -#define STRUCT_NET_DEVICE struct net_device -#else -#define STRUCT_NET_DEVICE struct device -#endif - -STRUCT_NET_DEVICE c7000_devices[MAX_C7000]; +struct net_device c7000_devices[MAX_C7000]; /* Scratch variable filled in with controller name. @@ -432,6 +437,7 @@ MODULE_AUTHOR("Robert Scardapane (UTS Global)"); MODULE_DESCRIPTION("Network module for Cisco 7000 box."); +MODULE_LICENSE("GPL"); MODULE_PARM(base0, "1i"); MODULE_PARM_DESC(base0, "Base unit address for 1st C7000 box."); @@ -521,16 +527,12 @@ ccw1_t ccws[5]; /* control ccws */ int devno; /* device number */ int irq; /* subchannel number */ - int IO_active; /* IO activity flag */ + unsigned long IO_active; /* IO activity flag */ int state; /* fsm state */ int retries; /* retry counter */ unsigned long flag_a; /* bh activity flag */ devstat_t devstat; /* device status */ -#ifdef NEWSTUFF wait_queue_head_t wait; /* sleep q head */ -#else - struct wait_queue *wait; /* sleep q pointer */ -#endif struct c7000_controller *cntlp; /* controller pointer */ struct c7000_buffer *free; /* free buffer anchor */ struct c7000_buffer *proc_head; /* proc head */ @@ -551,7 +553,7 @@ struct c7000_controller { struct net_device_stats stats; /* statistics */ - STRUCT_NET_DEVICE *dev; /* -> device struct */ + struct net_device *dev; /* -> device struct */ unsigned int base_addr; /* base address */ char lappl[NAMLEN]; /* local appl */ char lhost[NAMLEN]; /* local host */ @@ -560,9 +562,7 @@ unsigned char version; /* version = 2 */ unsigned char linkid; /* link id */ struct c7000_unit cunits[NUNITS]; /* embedded units */ -#ifdef NEWSTUFF - int tbusy; -#endif + unsigned long tbusy; }; /* @@ -579,62 +579,29 @@ Set the device structure transmission busy flag. */ -#ifdef NEWSTUFF #define c7000_set_busy(dev) netif_stop_queue(dev) -#else -static __inline__ void -c7000_set_busy(STRUCT_NET_DEVICE *dev) -{ - dev->tbusy = 1; - eieio(); - return; -} -#endif /* Clear the device structure transmission busy flag. */ -#ifdef NEWSTUFF #define c7000_clear_busy(dev) netif_wake_queue(dev) -#else -static __inline__ void -c7000_clear_busy(STRUCT_NET_DEVICE *dev) -{ - dev->tbusy = 0; - eieio(); - return; -} -#endif /* Extract the device structure transmission busy flag. */ -#ifdef NEWSTUFF #define c7000_check_busy(dev) netif_queue_stopped(dev) -#else -static __inline__ int -c7000_check_busy(STRUCT_NET_DEVICE *dev) -{ - eieio(); - return(dev->tbusy); -} -#endif /* Set a bit in the device structure transmission busy flag. */ static __inline__ void -c7000_setbit_busy(int nr, STRUCT_NET_DEVICE *dev) +c7000_setbit_busy(int nr, struct net_device *dev) { -#ifdef NEWSTUFF netif_stop_queue(dev); test_and_set_bit(nr, &((struct c7000_controller *)dev->priv)->tbusy); -#else - set_bit(nr, (void *)&dev->tbusy); -#endif return; } @@ -643,14 +610,10 @@ */ static __inline__ void -c7000_clearbit_busy(int nr, STRUCT_NET_DEVICE *dev) +c7000_clearbit_busy(int nr, struct net_device *dev) { -#ifdef NEWSTUFF clear_bit(nr, &((struct c7000_controller *)dev->priv)->tbusy); netif_wake_queue(dev); -#else - clear_bit(nr, (void *)&dev->tbusy); -#endif return; } @@ -659,14 +622,10 @@ */ static __inline__ int -c7000_ts_busy(int nr, STRUCT_NET_DEVICE *dev) +c7000_ts_busy(int nr, struct net_device *dev) { -#ifdef NEWSTUFF netif_stop_queue(dev); return test_and_set_bit(nr, &((struct c7000_controller *)dev->priv)->tbusy); -#else - return(test_and_set_bit(nr, (void *)&dev->tbusy)); -#endif } /* @@ -678,7 +637,7 @@ { int i; struct c7000_unit *cup; - STRUCT_NET_DEVICE *dev = ccp->dev; + struct net_device *dev = ccp->dev; for (i = 0; i < NUNITS; i++) { cup = &ccp->cunits[i]; @@ -686,12 +645,8 @@ } if (dev != NULL) -#ifdef NEWSTUFF /* RBH XXX Should we be doing this? */ dev->state &= ~__LINK_STATE_START; -#else - dev->flags &= ~IFF_RUNNING; -#endif CPrintk(0, "c7000: c7000_error: base unit 0x%x is down\n", ccp->base_addr); return; @@ -759,9 +714,9 @@ static int c7000_haltio(struct c7000_unit *cup) { - __u32 parm; + unsigned long parm; __u8 flags = 0x00; - __u32 saveflags; + unsigned long saveflags; DECLARE_WAITQUEUE(wait, current); int rc; @@ -792,9 +747,9 @@ static int c7000_doio(struct c7000_unit *cup) { - __u32 parm; + unsigned long parm; __u8 flags = 0x00; - __u32 saveflags; + unsigned long saveflags; DECLARE_WAITQUEUE(wait, current); int rc; @@ -1013,7 +968,7 @@ */ static int -c7000_alloc_buffers(STRUCT_NET_DEVICE *dev) +c7000_alloc_buffers(struct net_device *dev) { int i; int j; @@ -1030,9 +985,10 @@ bufptr = kmalloc(sizeof(struct c7000_buffer), GFP_KERNEL); data = kmalloc(C7000_BUFSIZE, GFP_KERNEL); - if (bufptr == NULL) - { - if(data) + if (bufptr == NULL || data == NULL) { + if (bufptr) + kfree(bufptr); + if (data) kfree(data); return(-1); } @@ -1088,7 +1044,7 @@ */ static void -c7000_free_buffers(STRUCT_NET_DEVICE *dev) +c7000_free_buffers(struct net_device *dev) { int i; struct c7000_controller *ccp = (struct c7000_controller *) dev->priv; @@ -1328,12 +1284,12 @@ struct c7000_rd_header *head; struct sk_buff *skb; struct c7000_controller *ccp; - STRUCT_NET_DEVICE *dev; + struct net_device *dev; int rc; __u16 data_length; - __u32 parm; + unsigned long parm; __u8 flags = 0x00; - __u32 saveflags; + unsigned long saveflags; ccp = cup->cntlp; dev = ccp->dev; @@ -1385,6 +1341,7 @@ skb->ip_summed = CHECKSUM_UNNECESSARY; netif_rx(skb); ccp->stats.rx_packets++; + ccp->stats.rx_bytes += skb->len; } else { CPrintk(0, "c7000: c7000_irq_bh: can not allocate a skb for unit 0x%x\n", cup->devno); ccp->stats.rx_dropped++; @@ -1403,6 +1360,7 @@ Rechain the buffer on the running channel program. */ + buf->ccws[3].cda = buf->ccws[5].cda = (__u32)virt_to_phys(&buf->ccws[6]); if (pbuf != NULL) pbuf->ccws[3].cda = pbuf->ccws[5].cda = (__u32)virt_to_phys(&buf->ccws[0]); @@ -1422,7 +1380,7 @@ return; } - parm = (__u32)cup; + parm = (unsigned long)cup; cup->state = C7000_READ; if ((rc = do_IO(cup->irq, &cup->proc_head->ccws[0], parm, 0xff, flags)) != 0) { @@ -1979,7 +1937,7 @@ */ struct net_device_stats * -c7000_stats(STRUCT_NET_DEVICE *dev) +c7000_stats(struct net_device *dev) { struct c7000_controller *ccp = (struct c7000_controller *)dev->priv; @@ -1991,13 +1949,13 @@ */ static int -c7000_open(STRUCT_NET_DEVICE *dev) +c7000_open(struct net_device *dev) { int i; struct c7000_controller *ccp = (struct c7000_controller *)dev->priv; struct c7000_unit *cup; int rc; - __u32 parm; + unsigned long parm; __u8 flags = 0x00; c7000_set_busy(dev); @@ -2025,16 +1983,11 @@ half routine. */ -#ifndef NEWSTUFF - cup->tq.next = NULL; -#endif cup->tq.sync = 0; cup->tq.routine = (void *)(void *)c7000_irq_bh; cup->tq.data = cup; cup->state = C7000_HALT; -#ifdef NEWSTUFF init_waitqueue_head(&cup->wait); -#endif CPrintk(1, "c7000: c7000_open: issuing halt to unit 0x%x\n", cup->devno); /* @@ -2154,7 +2107,7 @@ */ cup->state = C7000_READ; - parm = (__u32) cup; + parm = (unsigned long)cup; set_bit(0, (void *)&cup->IO_active); if ((rc = do_IO(cup->irq, &cup->proc_head->ccws[0], parm, 0xff, flags)) != 0) { @@ -2165,11 +2118,7 @@ return(-EIO); } -#ifdef NEWSTUFF netif_start_queue(dev); -#else - dev->start = 1; -#endif CPrintk(0, "c7000: c7000_open: base unit 0x%lx is opened\n", dev->base_addr); c7000_clear_busy(dev); MOD_INC_USE_COUNT; /* increment module usage count */ @@ -2181,18 +2130,13 @@ */ static int -c7000_stop(STRUCT_NET_DEVICE *dev) +c7000_stop(struct net_device *dev) { int i; struct c7000_controller *ccp = (struct c7000_controller *)dev->priv; struct c7000_unit *cup; int rc; -#ifdef NEWSTUFF -/* nothing? */ -#else - dev->start = 0; -#endif c7000_set_busy(dev); /* @@ -2236,7 +2180,7 @@ */ static int -c7000_config(STRUCT_NET_DEVICE *dev, struct ifmap *map) +c7000_config(struct net_device *dev, struct ifmap *map) { CPrintk(1, "c7000: c7000_config: entered for base unit 0x%lx\n", dev->base_addr); return(0); @@ -2247,12 +2191,12 @@ */ static int -c7000_xmit(struct sk_buff *skb, STRUCT_NET_DEVICE *dev) +c7000_xmit(struct sk_buff *skb, struct net_device *dev) { struct c7000_controller *ccp = (struct c7000_controller *)dev->priv; struct c7000_unit *cup; - __u32 saveflags; - __u32 parm; + unsigned long saveflags; + unsigned long parm; __u8 flags = 0x00; struct c7000_buffer *buf, *pbuf; int rc; @@ -2350,7 +2294,7 @@ if (test_and_set_bit(0, (void *)&cup->IO_active) == 0) { CPrintk(1, "c7000: c7000_xmit: start IO for unit 0x%x\n", cup->devno); c7000_bld_wrt_chain(cup); - parm = (__u32) cup; + parm = (unsigned long)cup; cup->state = C7000_WRITE; if ((rc = do_IO(cup->irq, &cup->proc_head->ccws[0], parm, 0xff, flags)) != 0) { @@ -2385,7 +2329,7 @@ */ static int -c7000_ioctl(STRUCT_NET_DEVICE *dev, struct ifreq *ifr, int cmd) +c7000_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { CPrintk(1, "c7000: c7000_ioctl: entered for base unit 0x%lx with cmd %d\n", dev->base_addr, cmd); return(0); @@ -2461,7 +2405,7 @@ c7000_retry_io(struct c7000_unit *cup) { int rc; - __u32 parm; + unsigned long parm; __u8 flags = 0x00; ccw1_t *ccwp; @@ -2472,7 +2416,7 @@ } set_bit(0, (void *)&cup->IO_active); - parm = (__u32)cup; + parm = (unsigned long)cup; if (cup->state == C7000_READ || cup->state == C7000_WRITE) ccwp = &cup->proc_head->ccws[0]; @@ -2560,14 +2504,10 @@ */ buf = c7000_dequeue_buffer(cup); + ccp->stats.tx_bytes += buf->len; + ccp->stats.tx_packets++; c7000_release_buffer(cup, buf); num_write++; - - /* - Update transmitted packets statistic. - */ - - ccp->stats.tx_packets++; } CPrintk(1, "c7000: c7000_proc_wintr: %d buffers written for unit 0x%x\n", num_write, cup->devno); @@ -2584,8 +2524,8 @@ devstat_t *devstat = ((devstat_t *) initparm); struct c7000_unit *cup = NULL; struct c7000_controller *ccp = NULL; - STRUCT_NET_DEVICE *dev = NULL; - __u32 parm; + struct net_device *dev = NULL; + unsigned long parm; __u8 flags = 0x00; int rc; @@ -2618,14 +2558,14 @@ ccp = cup->cntlp; if (ccp == NULL) { - CPrintk(0, "c7000: c7000_intr: c7000_cntlp pointer is NULL in c7000_unit structure 0x%x for unit 0x%x\n", (int)cup, cup->devno); + CPrintk(0, "c7000: c7000_intr: c7000_cntlp pointer is NULL in c7000_unit structure %p for unit 0x%x\n", cup, cup->devno); return; } dev = ccp->dev; if (dev == NULL) { - CPrintk(0, "c7000: c7000_intr: device pointer is NULL in c7000_controller structure 0x%x for unit 0x%x\n", (int)ccp, cup->devno); + CPrintk(0, "c7000: c7000_intr: device pointer is NULL in c7000_controller structure %p for unit 0x%x\n", ccp, cup->devno); return; } @@ -2777,7 +2717,7 @@ if ((devstat->flag & DEVSTAT_FINAL_STATUS) && (cup->free != NULL)) { c7000_bld_read_chain(cup); - parm = (__u32)cup; + parm = (unsigned long)cup; set_bit(0, (void *)&cup->IO_active); if ((rc = do_IO(cup->irq, &cup->proc_head->ccws[0], parm, 0xff, flags)) != 0) { @@ -2834,7 +2774,7 @@ if (cup->proc_head != NULL) { c7000_bld_wrt_chain(cup); - parm = (__u32)cup; + parm = (unsigned long)cup; set_bit(0, (void *)&cup->IO_active); if ((rc = do_IO(cup->irq, &cup->proc_head->ccws[0], parm, 0xff, flags)) != 0) { @@ -2932,7 +2872,7 @@ */ static int -c7000_init(STRUCT_NET_DEVICE *dev) +c7000_init(struct net_device *dev) { struct c7000_controller *ccp; int i; @@ -2970,7 +2910,7 @@ dev->addr_len = 0; dev->type = ARPHRD_SLIP; dev->tx_queue_len = C7000_TXQUEUE_LEN; - dev->flags = IFF_NOARP; + dev->flags = IFF_BROADCAST|IFF_MULTICAST|IFF_NOARP; dev->open = c7000_open; dev->stop = c7000_stop; dev->set_config = c7000_config; @@ -2987,7 +2927,7 @@ return(-ENOMEM); } - CPrintk(1, "c7000: c7000_init: allocated a c7000_controller structure at address 0x%x\n", (int)ccp); + CPrintk(1, "c7000: c7000_init: allocated a c7000_controller structure at address %p\n", ccp); memset(ccp, '\0', sizeof(struct c7000_controller)); ccp->dev = dev; ccp->base_addr = dev->base_addr; @@ -3217,12 +3157,8 @@ Initialize the device structure. */ - memset(&c7000_devices[i], '\0', sizeof(STRUCT_NET_DEVICE)); -#ifdef NEWSTUFF + memset(&c7000_devices[i], '\0', sizeof(struct net_device)); strcpy(c7000_devices[i].name, ifnames[i]); -#else - c7000_devices[i].name = &ifnames[i][0]; -#endif c7000_devices[i].base_addr = bases[i]; c7000_devices[i].init = c7000_init; @@ -3278,7 +3214,7 @@ free_irq(ccp->cunits[j].irq, &ccp->cunits[j].devstat); } - CPrintk(1, "c7000: clean_module: free a c7000_controller structure at address 0x%x\n", (int)ccp); + CPrintk(1, "c7000: clean_module: free a c7000_controller structure at address %p\n", ccp); kfree(ccp); } diff -Nru a/drivers/sbus/char/bpp.c b/drivers/sbus/char/bpp.c --- a/drivers/sbus/char/bpp.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/sbus/char/bpp.c 2004-08-14 12:02:30 -07:00 @@ -1073,3 +1073,5 @@ module_init(bpp_init); module_exit(bpp_cleanup); + +MODULE_LICENSE("GPL"); diff -Nru a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c --- a/drivers/sbus/char/vfc_dev.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/sbus/char/vfc_dev.c 2004-08-14 12:02:30 -07:00 @@ -743,4 +743,4 @@ } #endif - +MODULE_LICENSE("GPL"); diff -Nru a/drivers/scsi/Config.in b/drivers/scsi/Config.in --- a/drivers/scsi/Config.in 2004-08-14 12:02:30 -07:00 +++ b/drivers/scsi/Config.in 2004-08-14 12:02:30 -07:00 @@ -70,6 +70,8 @@ dep_tristate 'AMI MegaRAID2 support' CONFIG_SCSI_MEGARAID2 $CONFIG_SCSI dep_mbool 'Serial ATA (SATA) support' CONFIG_SCSI_SATA $CONFIG_SCSI dep_tristate ' ServerWorks Frodo / Apple K2 SATA support (EXPERIMENTAL)' CONFIG_SCSI_SATA_SVW $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL +dep_tristate ' Intel PIIX/ICH SATA support' CONFIG_SCSI_ATA_PIIX $CONFIG_SCSI_SATA $CONFIG_PCI +dep_tristate ' NVIDIA SATA support (EXPERIMENTAL)' CONFIG_SCSI_SATA_NV $CONFIG_SCSI_SATA $CONFIG_PCI dep_tristate ' Promise SATA TX2/TX4 support (EXPERIMENTAL)' CONFIG_SCSI_SATA_PROMISE $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL dep_tristate ' Promise SATA SX4 support (EXPERIMENTAL)' CONFIG_SCSI_SATA_SX4 $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL dep_tristate ' Silicon Image SATA support (EXPERIMENTAL)' CONFIG_SCSI_SATA_SIL $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL diff -Nru a/drivers/scsi/Makefile b/drivers/scsi/Makefile --- a/drivers/scsi/Makefile 2004-08-14 12:02:30 -07:00 +++ b/drivers/scsi/Makefile 2004-08-14 12:02:30 -07:00 @@ -131,12 +131,14 @@ obj-$(CONFIG_SCSI_LASI700) += lasi700.o 53c700.o obj-$(CONFIG_SCSI_NSP32) += nsp32.o obj-$(CONFIG_SCSI_SATA_SVW) += libata.o sata_svw.o +obj-$(CONFIG_SCSI_ATA_PIIX) += libata.o ata_piix.o obj-$(CONFIG_SCSI_SATA_PROMISE) += libata.o sata_promise.o obj-$(CONFIG_SCSI_SATA_SIL) += libata.o sata_sil.o obj-$(CONFIG_SCSI_SATA_VIA) += libata.o sata_via.o obj-$(CONFIG_SCSI_SATA_VITESSE) += libata.o sata_vsc.o obj-$(CONFIG_SCSI_SATA_SIS) += libata.o sata_sis.o obj-$(CONFIG_SCSI_SATA_SX4) += libata.o sata_sx4.o +obj-$(CONFIG_SCSI_SATA_NV) += libata.o sata_nv.o subdir-$(CONFIG_ARCH_ACORN) += ../acorn/scsi obj-$(CONFIG_ARCH_ACORN) += ../acorn/scsi/acorn-scsi.o diff -Nru a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/scsi/ata_piix.c 2004-08-14 12:02:31 -07:00 @@ -0,0 +1,675 @@ +/* + + ata_piix.c - Intel PATA/SATA controllers + + + Copyright 2003-2004 Red Hat Inc + Copyright 2003-2004 Jeff Garzik + + + Copyright header from piix.c: + + Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer + Copyright (C) 1998-2000 Andre Hedrick + Copyright (C) 2003 Red Hat Inc + + May be copied or modified under the terms of the GNU General Public License + + */ + +#include +#include +#include +#include +#include +#include +#include "scsi.h" +#include +#include + +#define DRV_NAME "ata_piix" +#define DRV_VERSION "1.02" + +enum { + PIIX_IOCFG = 0x54, /* IDE I/O configuration register */ + ICH5_PMR = 0x90, /* port mapping register */ + ICH5_PCS = 0x92, /* port control and status */ + + PIIX_FLAG_AHCI = (1 << 28), /* AHCI possible */ + PIIX_FLAG_CHECKINTR = (1 << 29), /* make sure PCI INTx enabled */ + PIIX_FLAG_COMBINED = (1 << 30), /* combined mode possible */ + + /* combined mode. if set, PATA is channel 0. + * if clear, PATA is channel 1. + */ + PIIX_COMB_PATA_P0 = (1 << 1), + PIIX_COMB = (1 << 2), /* combined mode enabled? */ + + PIIX_PORT_PRESENT = (1 << 0), + PIIX_PORT_ENABLED = (1 << 4), + + PIIX_80C_PRI = (1 << 5) | (1 << 4), + PIIX_80C_SEC = (1 << 7) | (1 << 6), + + ich5_pata = 0, + ich5_sata = 1, + piix4_pata = 2, + ich6_sata = 3, + ich6_sata_rm = 4, +}; + +static int piix_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent); + +static void piix_pata_phy_reset(struct ata_port *ap); +static void piix_sata_phy_reset(struct ata_port *ap); +static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev); +static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev); + +static unsigned int in_module_init = 1; + +static struct pci_device_id piix_pci_tbl[] = { +#ifdef ATA_ENABLE_PATA + { 0x8086, 0x7111, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix4_pata }, + { 0x8086, 0x24db, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_pata }, + { 0x8086, 0x25a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_pata }, +#endif + + /* NOTE: The following PCI ids must be kept in sync with the + * list in drivers/pci/quirks.c. + */ + + { 0x8086, 0x24d1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata }, + { 0x8086, 0x24df, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata }, + { 0x8086, 0x25a3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata }, + { 0x8086, 0x25b0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata }, + { 0x8086, 0x2651, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata }, + { 0x8086, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_rm }, + { 0x8086, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_rm }, + + { } /* terminate list */ +}; + +static struct pci_driver piix_pci_driver = { + .name = DRV_NAME, + .id_table = piix_pci_tbl, + .probe = piix_init_one, + .remove = ata_pci_remove_one, +}; + +static Scsi_Host_Template piix_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .detect = ata_scsi_detect, + .release = ata_scsi_release, + .queuecommand = ata_scsi_queuecmd, + .eh_strategy_handler = ata_scsi_error, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = LIBATA_MAX_PRD, + .max_sectors = ATA_MAX_SECTORS, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .use_new_eh_code = ATA_SHT_NEW_EH_CODE, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .bios_param = ata_std_bios_param, +}; + +static struct ata_port_operations piix_pata_ops = { + .port_disable = ata_port_disable, + .set_piomode = piix_set_piomode, + .set_dmamode = piix_set_dmamode, + + .tf_load = ata_tf_load_pio, + .tf_read = ata_tf_read_pio, + .check_status = ata_check_status_pio, + .exec_command = ata_exec_command_pio, + + .phy_reset = piix_pata_phy_reset, + + .bmdma_setup = ata_bmdma_setup_pio, + .bmdma_start = ata_bmdma_start_pio, + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + + .eng_timeout = ata_eng_timeout, + + .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, + + .port_start = ata_port_start, + .port_stop = ata_port_stop, +}; + +static struct ata_port_operations piix_sata_ops = { + .port_disable = ata_port_disable, + + .tf_load = ata_tf_load_pio, + .tf_read = ata_tf_read_pio, + .check_status = ata_check_status_pio, + .exec_command = ata_exec_command_pio, + + .phy_reset = piix_sata_phy_reset, + + .bmdma_setup = ata_bmdma_setup_pio, + .bmdma_start = ata_bmdma_start_pio, + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + + .eng_timeout = ata_eng_timeout, + + .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, + + .port_start = ata_port_start, + .port_stop = ata_port_stop, +}; + +static struct ata_port_info piix_port_info[] = { + /* ich5_pata */ + { + .sht = &piix_sht, + .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | + PIIX_FLAG_CHECKINTR, + .pio_mask = 0x1f, /* pio0-4 */ +#if 0 + .mwdma_mask = 0x06, /* mwdma1-2 */ +#else + .mwdma_mask = 0x00, /* mwdma broken */ +#endif + .udma_mask = ATA_UDMA_MASK_40C, /* FIXME: cbl det */ + .port_ops = &piix_pata_ops, + }, + + /* ich5_sata */ + { + .sht = &piix_sht, + .host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST | + PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x7f, /* udma0-6 */ + .port_ops = &piix_sata_ops, + }, + + /* piix4_pata */ + { + .sht = &piix_sht, + .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .pio_mask = 0x1f, /* pio0-4 */ +#if 0 + .mwdma_mask = 0x06, /* mwdma1-2 */ +#else + .mwdma_mask = 0x00, /* mwdma broken */ +#endif + .udma_mask = ATA_UDMA_MASK_40C, /* FIXME: cbl det */ + .port_ops = &piix_pata_ops, + }, + + /* ich6_sata */ + { + .sht = &piix_sht, + .host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST | + PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR | + ATA_FLAG_SLAVE_POSS, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x7f, /* udma0-6 */ + .port_ops = &piix_sata_ops, + }, + + /* ich6_sata_rm */ + { + .sht = &piix_sht, + .host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST | + PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR | + ATA_FLAG_SLAVE_POSS | PIIX_FLAG_AHCI, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x7f, /* udma0-6 */ + .port_ops = &piix_sata_ops, + }, +}; + +static struct pci_bits piix_enable_bits[] = { + { 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */ + { 0x43U, 1U, 0x80UL, 0x80UL }, /* port 1 */ +}; + +MODULE_AUTHOR("Andre Hedrick, Alan Cox, Andrzej Krzysztofowicz, Jeff Garzik"); +MODULE_DESCRIPTION("SCSI low-level driver for Intel PIIX/ICH ATA controllers"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, piix_pci_tbl); + +/** + * piix_pata_cbl_detect - Probe host controller cable detect info + * @ap: Port for which cable detect info is desired + * + * Read 80c cable indicator from SATA PCI device's PCI config + * register. This register is normally set by firmware (BIOS). + * + * LOCKING: + * None (inherited from caller). + */ +static void piix_pata_cbl_detect(struct ata_port *ap) +{ + struct pci_dev *pdev = ap->host_set->pdev; + u8 tmp, mask; + + /* no 80c support in host controller? */ + if ((ap->udma_mask & ~ATA_UDMA_MASK_40C) == 0) + goto cbl40; + + /* check BIOS cable detect results */ + mask = ap->port_no == 0 ? PIIX_80C_PRI : PIIX_80C_SEC; + pci_read_config_byte(pdev, PIIX_IOCFG, &tmp); + if ((tmp & mask) == 0) + goto cbl40; + + ap->cbl = ATA_CBL_PATA80; + return; + +cbl40: + ap->cbl = ATA_CBL_PATA40; + ap->udma_mask &= ATA_UDMA_MASK_40C; +} + +/** + * piix_pata_phy_reset - Probe specified port on PATA host controller + * @ap: Port to probe + * + * Probe PATA phy. + * + * LOCKING: + * None (inherited from caller). + */ + +static void piix_pata_phy_reset(struct ata_port *ap) +{ + if (!pci_test_config_bits(ap->host_set->pdev, + &piix_enable_bits[ap->port_no])) { + ata_port_disable(ap); + printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id); + return; + } + + piix_pata_cbl_detect(ap); + + ata_port_probe(ap); + + ata_bus_reset(ap); +} + +/** + * piix_sata_probe - Probe PCI device for present SATA devices + * @ap: Port associated with the PCI device we wish to probe + * + * Reads SATA PCI device's PCI config register Port Configuration + * and Status (PCS) to determine port and device availability. + * + * LOCKING: + * None (inherited from caller). + * + * RETURNS: + * Non-zero if device detected, zero otherwise. + */ +static int piix_sata_probe (struct ata_port *ap) +{ + struct pci_dev *pdev = ap->host_set->pdev; + int combined = (ap->flags & ATA_FLAG_SLAVE_POSS); + int orig_mask, mask, i; + u8 pcs; + + mask = (PIIX_PORT_PRESENT << ap->port_no) | + (PIIX_PORT_ENABLED << ap->port_no); + + pci_read_config_byte(pdev, ICH5_PCS, &pcs); + orig_mask = (int) pcs & 0xff; + + /* TODO: this is vaguely wrong for ICH6 combined mode, + * where only two of the four SATA ports are mapped + * onto a single ATA channel. It is also vaguely inaccurate + * for ICH5, which has only two ports. However, this is ok, + * as further device presence detection code will handle + * any false positives produced here. + */ + + for (i = 0; i < 4; i++) { + mask = (PIIX_PORT_PRESENT << i) | (PIIX_PORT_ENABLED << i); + + if ((orig_mask & mask) == mask) + if (combined || (i == ap->port_no)) + return 1; + } + + return 0; +} + +/** + * piix_sata_phy_reset - Probe specified port on SATA host controller + * @ap: Port to probe + * + * Probe SATA phy. + * + * LOCKING: + * None (inherited from caller). + */ + +static void piix_sata_phy_reset(struct ata_port *ap) +{ + if (!piix_sata_probe(ap)) { + ata_port_disable(ap); + printk(KERN_INFO "ata%u: SATA port has no device.\n", ap->id); + return; + } + + ap->cbl = ATA_CBL_SATA; + + ata_port_probe(ap); + + ata_bus_reset(ap); +} + +/** + * piix_set_piomode - Initialize host controller PATA PIO timings + * @ap: Port whose timings we are configuring + * @adev: um + * @pio: PIO mode, 0 - 4 + * + * Set PIO mode for device, in host controller PCI config space. + * + * LOCKING: + * None (inherited from caller). + */ + +static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev) +{ + unsigned int pio = adev->pio_mode; + struct pci_dev *dev = ap->host_set->pdev; + unsigned int is_slave = (adev->devno != 0); + unsigned int master_port= ap->port_no ? 0x42 : 0x40; + unsigned int slave_port = 0x44; + u16 master_data; + u8 slave_data; + + static const /* ISP RTC */ + u8 timings[][2] = { { 0, 0 }, + { 0, 0 }, + { 1, 0 }, + { 2, 1 }, + { 2, 3 }, }; + + pci_read_config_word(dev, master_port, &master_data); + if (is_slave) { + master_data |= 0x4000; + /* enable PPE, IE and TIME */ + master_data |= 0x0070; + pci_read_config_byte(dev, slave_port, &slave_data); + slave_data &= (ap->port_no ? 0x0f : 0xf0); + slave_data |= + (timings[pio][0] << 2) | + (timings[pio][1] << (ap->port_no ? 4 : 0)); + } else { + master_data &= 0xccf8; + /* enable PPE, IE and TIME */ + master_data |= 0x0007; + 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); +} + +/** + * piix_set_dmamode - Initialize host controller PATA PIO timings + * @ap: Port whose timings we are configuring + * @adev: um + * @udma: udma mode, 0 - 6 + * + * Set UDMA mode for device, in host controller PCI config space. + * + * LOCKING: + * None (inherited from caller). + */ + +static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev) +{ + unsigned int udma = adev->dma_mode; /* FIXME: MWDMA too */ + struct pci_dev *dev = ap->host_set->pdev; + u8 maslave = ap->port_no ? 0x42 : 0x40; + u8 speed = udma; + unsigned int drive_dn = (ap->port_no ? 2 : 0) + adev->devno; + 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; + int sitre; + u16 reg4042, reg4a; + u8 reg48, reg54, reg55; + + pci_read_config_word(dev, maslave, ®4042); + DPRINTK("reg4042 = 0x%04x\n", reg4042); + sitre = (reg4042 & 0x4000) ? 1 : 0; + pci_read_config_byte(dev, 0x48, ®48); + pci_read_config_word(dev, 0x4a, ®4a); + pci_read_config_byte(dev, 0x54, ®54); + pci_read_config_byte(dev, 0x55, ®55); + + switch(speed) { + case XFER_UDMA_4: + case XFER_UDMA_2: u_speed = 2 << (drive_dn * 4); break; + case XFER_UDMA_6: + 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; + case XFER_MW_DMA_2: + case XFER_MW_DMA_1: break; + default: + BUG(); + return; + } + + 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); + } +} + +/* move to PCI layer, integrate w/ MSI stuff */ +static void pci_enable_intx(struct pci_dev *pdev) +{ + u16 pci_command; + + pci_read_config_word(pdev, PCI_COMMAND, &pci_command); + if (pci_command & PCI_COMMAND_INTX_DISABLE) { + pci_command &= ~PCI_COMMAND_INTX_DISABLE; + pci_write_config_word(pdev, PCI_COMMAND, pci_command); + } +} + +#define AHCI_PCI_BAR 5 +#define AHCI_GLOBAL_CTL 0x04 +#define AHCI_ENABLE (1 << 31) +static int piix_disable_ahci(struct pci_dev *pdev) +{ + void *mmio; + unsigned long addr; + u32 tmp; + int rc = 0; + + /* BUG: pci_enable_device has not yet been called. This + * works because this device is usually set up by BIOS. + */ + + addr = pci_resource_start(pdev, AHCI_PCI_BAR); + if (!addr || !pci_resource_len(pdev, AHCI_PCI_BAR)) + return 0; + + mmio = ioremap(addr, 64); + if (!mmio) + return -ENOMEM; + + tmp = readl(mmio + AHCI_GLOBAL_CTL); + if (tmp & AHCI_ENABLE) { + tmp &= ~AHCI_ENABLE; + writel(tmp, mmio + AHCI_GLOBAL_CTL); + + tmp = readl(mmio + AHCI_GLOBAL_CTL); + if (tmp & AHCI_ENABLE) + rc = -EIO; + } + + iounmap(mmio); + return rc; +} + +/** + * piix_init_one - Register PIIX ATA PCI device with kernel services + * @pdev: PCI device to register + * @ent: Entry in piix_pci_tbl matching with @pdev + * + * Called from kernel PCI layer. We probe for combined mode (sigh), + * and then hand over control to libata, for it to do the rest. + * + * LOCKING: + * Inherited from PCI layer (may sleep). + * + * RETURNS: + * Zero on success, or -ERRNO value. + */ + +static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) +{ + static int printed_version; + struct ata_port_info *port_info[2]; + unsigned int combined = 0, n_ports = 1; + unsigned int pata_chan = 0, sata_chan = 0; + + if (!printed_version++) + printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + + /* no hotplugging support (FIXME) */ + if (!in_module_init) + return -ENODEV; + + port_info[0] = &piix_port_info[ent->driver_data]; + port_info[1] = NULL; + + if (port_info[0]->host_flags & PIIX_FLAG_AHCI) { + int rc = piix_disable_ahci(pdev); + if (rc) + return rc; + } + + if (port_info[0]->host_flags & PIIX_FLAG_COMBINED) { + u8 tmp; + pci_read_config_byte(pdev, ICH5_PMR, &tmp); + + if (tmp & PIIX_COMB) { + combined = 1; + if (tmp & PIIX_COMB_PATA_P0) + sata_chan = 1; + else + pata_chan = 1; + } + } + + /* On ICH5, some BIOSen disable the interrupt using the + * PCI_COMMAND_INTX_DISABLE bit added in PCI 2.3. + * On ICH6, this bit has the same effect, but only when + * MSI is disabled (and it is disabled, as we don't use + * message-signalled interrupts currently). + */ + if (port_info[0]->host_flags & PIIX_FLAG_CHECKINTR) + pci_enable_intx(pdev); + + if (combined) { + port_info[sata_chan] = &piix_port_info[ent->driver_data]; + port_info[sata_chan]->host_flags |= ATA_FLAG_SLAVE_POSS; + port_info[pata_chan] = &piix_port_info[ich5_pata]; + n_ports++; + + printk(KERN_ERR DRV_NAME ": combined mode not supported\n"); + return -ENODEV; + } + + return ata_pci_init_one(pdev, port_info, n_ports); +} + +/** + * piix_init - + * + * LOCKING: + * + * RETURNS: + * + */ + +static int __init piix_init(void) +{ + int rc; + + DPRINTK("pci_module_init\n"); + rc = pci_module_init(&piix_pci_driver); + if (rc) + return rc; + + in_module_init = 0; + + DPRINTK("scsi_register_host\n"); + rc = scsi_register_module(MODULE_SCSI_HA, &piix_sht); + if (rc) { + rc = -ENODEV; + goto err_out; + } + + DPRINTK("done\n"); + return 0; + +err_out: + pci_unregister_driver(&piix_pci_driver); + return rc; +} + +/** + * piix_exit - + * + * LOCKING: + * + */ + +static void __exit piix_exit(void) +{ + scsi_unregister_module(MODULE_SCSI_HA, &piix_sht); + pci_unregister_driver(&piix_pci_driver); +} + +module_init(piix_init); +module_exit(piix_exit); + diff -Nru a/drivers/scsi/esp.c b/drivers/scsi/esp.c --- a/drivers/scsi/esp.c 2004-08-14 12:02:31 -07:00 +++ b/drivers/scsi/esp.c 2004-08-14 12:02:31 -07:00 @@ -4368,4 +4368,4 @@ #include "scsi_module.c" -EXPORT_NO_SYMBOLS; +MODULE_LICENSE("GPL"); diff -Nru a/drivers/scsi/fcal.c b/drivers/scsi/fcal.c --- a/drivers/scsi/fcal.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/scsi/fcal.c 2004-08-14 12:02:30 -07:00 @@ -300,4 +300,4 @@ #include "scsi_module.c" -EXPORT_NO_SYMBOLS; +MODULE_LICENSE("GPL"); diff -Nru a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c --- a/drivers/scsi/libata-core.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/scsi/libata-core.c 2004-08-14 12:02:30 -07:00 @@ -49,13 +49,14 @@ unsigned long tmout_pat, unsigned long tmout); static void __ata_dev_select (struct ata_port *ap, unsigned int device); -static void ata_dma_complete(struct ata_queued_cmd *qc, u8 host_stat); -static void ata_host_set_pio(struct ata_port *ap); -static void ata_host_set_udma(struct ata_port *ap); -static void ata_dev_set_pio(struct ata_port *ap, unsigned int device); -static void ata_dev_set_udma(struct ata_port *ap, unsigned int device); static void ata_set_mode(struct ata_port *ap); -static int ata_qc_issue_prot(struct ata_queued_cmd *qc); +static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev); +static unsigned int ata_get_mode_mask(struct ata_port *ap, int shift); +static int fgb(u32 bitmap); +static int ata_choose_xfer_mode(struct ata_port *ap, + u8 *xfer_mode_out, + unsigned int *xfer_shift_out); +static int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat); static unsigned int ata_unique_id = 1; static LIST_HEAD(ata_probe_list); @@ -65,37 +66,6 @@ MODULE_DESCRIPTION("Library module for ATA devices"); MODULE_LICENSE("GPL"); -static const char * thr_state_name[] = { - "THR_UNKNOWN", - "THR_PORT_RESET", - "THR_AWAIT_DEATH", - "THR_PROBE_FAILED", - "THR_IDLE", - "THR_PROBE_SUCCESS", - "THR_PROBE_START", -}; - -/** - * ata_thr_state_name - convert thread state enum to string - * @thr_state: thread state to be converted to string - * - * Converts the specified thread state id to a constant C string. - * - * LOCKING: - * None. - * - * RETURNS: - * The THR_xxx-prefixed string naming the specified thread - * state id, or the string "". - */ - -static const char *ata_thr_state_name(unsigned int thr_state) -{ - if (thr_state < ARRAY_SIZE(thr_state_name)) - return thr_state_name[thr_state]; - return ""; -} - /** * msleep - sleep for a number of milliseconds * @msecs: number of milliseconds to sleep @@ -113,6 +83,11 @@ schedule_timeout(msecs_to_jiffies(msecs) + 1); } +void libata_msleep(unsigned long msecs) +{ + msleep(msecs); +} + /** * ata_tf_load_pio - send taskfile registers to host controller * @ap: Port to which output is sent @@ -574,7 +549,7 @@ dev->write_cmd = (cmd >> 8) & 0xff; } -static const char * udma_str[] = { +static const char * xfer_mode_str[] = { "UDMA/16", "UDMA/25", "UDMA/33", @@ -583,6 +558,14 @@ "UDMA/100", "UDMA/133", "UDMA7", + "MWDMA0", + "MWDMA1", + "MWDMA2", + "PIO0", + "PIO1", + "PIO2", + "PIO3", + "PIO4", }; /** @@ -600,16 +583,24 @@ * @udma_mask, or the constant C string "". */ -static const char *ata_udma_string(unsigned int udma_mask) +static const char *ata_mode_string(unsigned int mask) { int i; - for (i = 7; i >= 0; i--) { - if (udma_mask & (1 << i)) - return udma_str[i]; - } + for (i = 7; i >= 0; i--) + if (mask & (1 << i)) + goto out; + for (i = ATA_SHIFT_MWDMA + 2; i >= ATA_SHIFT_MWDMA; i--) + if (mask & (1 << i)) + goto out; + for (i = ATA_SHIFT_PIO + 4; i >= ATA_SHIFT_PIO; i--) + if (mask & (1 << i)) + goto out; return ""; + +out: + return xfer_mode_str[i]; } /** @@ -980,10 +971,14 @@ { struct ata_device *dev = &ap->device[device]; unsigned int i; - u16 tmp, udma_modes; + u16 tmp; + unsigned long xfer_modes; u8 status; - struct ata_taskfile tf; unsigned int using_edd; + DECLARE_COMPLETION(wait); + struct ata_queued_cmd *qc; + unsigned long flags; + int rc; if (!ata_dev_present(dev)) { DPRINTK("ENTER/EXIT (host %u, dev %u) -- nodev\n", @@ -1003,27 +998,34 @@ ata_dev_select(ap, device, 1, 1); /* select device 0/1 */ -retry: - ata_tf_init(ap, &tf, device); - tf.ctl |= ATA_NIEN; - tf.protocol = ATA_PROT_PIO; + qc = ata_qc_new_init(ap, dev); + BUG_ON(qc == NULL); + ata_sg_init_one(qc, dev->id, sizeof(dev->id)); + qc->pci_dma_dir = PCI_DMA_FROMDEVICE; + qc->tf.protocol = ATA_PROT_PIO; + qc->nsect = 1; + +retry: if (dev->class == ATA_DEV_ATA) { - tf.command = ATA_CMD_ID_ATA; + qc->tf.command = ATA_CMD_ID_ATA; DPRINTK("do ATA identify\n"); } else { - tf.command = ATA_CMD_ID_ATAPI; + qc->tf.command = ATA_CMD_ID_ATAPI; DPRINTK("do ATAPI identify\n"); } - ata_tf_to_host(ap, &tf); + qc->waiting = &wait; + qc->complete_fn = ata_qc_complete_noop; - /* crazy ATAPI devices... */ - if (dev->class == ATA_DEV_ATAPI) - msleep(150); + spin_lock_irqsave(&ap->host_set->lock, flags); + rc = ata_qc_issue(qc); + spin_unlock_irqrestore(&ap->host_set->lock, flags); - if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) + if (rc) goto err_out; + else + wait_for_completion(&wait); status = ata_chk_status(ap); if (status & ATA_ERR) { @@ -1038,45 +1040,20 @@ * ATA software reset (SRST, the default) does not appear * to have this problem. */ - if ((using_edd) && (tf.command == ATA_CMD_ID_ATA)) { + if ((using_edd) && (qc->tf.command == ATA_CMD_ID_ATA)) { u8 err = ata_chk_err(ap); if (err & ATA_ABORTED) { dev->class = ATA_DEV_ATAPI; + qc->cursg = 0; + qc->cursg_ofs = 0; + qc->cursect = 0; + qc->nsect = 1; goto retry; } } goto err_out; } - /* make sure we have BSY=0, DRQ=1 */ - if ((status & ATA_DRQ) == 0) { - printk(KERN_WARNING "ata%u: dev %u (ATA%s?) not returning id page (0x%x)\n", - ap->id, device, - dev->class == ATA_DEV_ATA ? "" : "PI", - status); - goto err_out; - } - - /* read IDENTIFY [X] DEVICE page */ - if (ap->flags & ATA_FLAG_MMIO) { - for (i = 0; i < ATA_ID_WORDS; i++) - dev->id[i] = readw((void *)ap->ioaddr.data_addr); - } else - for (i = 0; i < ATA_ID_WORDS; i++) - dev->id[i] = inw(ap->ioaddr.data_addr); - - /* wait for host_idle */ - status = ata_wait_idle(ap); - if (status & (ATA_BUSY | ATA_DRQ)) { - printk(KERN_WARNING "ata%u: dev %u (ATA%s?) error after id page (0x%x)\n", - ap->id, device, - dev->class == ATA_DEV_ATA ? "" : "PI", - status); - goto err_out; - } - - ata_irq_on(ap); /* re-enable interrupts */ - /* print device capabilities */ printk(KERN_DEBUG "ata%u: dev %u cfg " "49:%04x 82:%04x 83:%04x 84:%04x 85:%04x 86:%04x 87:%04x 88:%04x\n", @@ -1095,12 +1072,13 @@ goto err_out_nosup; } - /* we require UDMA support */ - udma_modes = - tmp = dev->id[ATA_ID_UDMA_MODES]; - if ((tmp & 0xff) == 0) { - printk(KERN_DEBUG "ata%u: no udma\n", ap->id); - goto err_out_nosup; + /* quick-n-dirty find max transfer mode; for printk only */ + xfer_modes = dev->id[ATA_ID_UDMA_MODES]; + if (!xfer_modes) + xfer_modes = (dev->id[ATA_ID_MWDMA_MODES]) << ATA_SHIFT_MWDMA; + if (!xfer_modes) { + xfer_modes = (dev->id[ATA_ID_PIO_MODES]) << (ATA_SHIFT_PIO + 3); + xfer_modes |= (0x7 << ATA_SHIFT_PIO); } ata_dump_id(dev); @@ -1133,7 +1111,7 @@ /* print device info to dmesg */ printk(KERN_INFO "ata%u: dev %u ATA, max %s, %Lu sectors:%s\n", ap->id, device, - ata_udma_string(udma_modes), + ata_mode_string(xfer_modes), (unsigned long long)dev->n_sectors, dev->flags & ATA_DFLAG_LBA48 ? " lba48" : ""); } @@ -1143,15 +1121,18 @@ if (ata_id_is_ata(dev)) /* sanity check */ goto err_out_nosup; - /* see if 16-byte commands supported */ - tmp = dev->id[0] & 0x3; - if (tmp == 1) - ap->host->max_cmd_len = 16; + rc = atapi_cdb_len(dev->id); + if ((rc < 12) || (rc > ATAPI_CDB_LEN)) { + printk(KERN_WARNING "ata%u: unsupported CDB len\n", ap->id); + goto err_out_nosup; + } + ap->cdb_len = (unsigned int) rc; + ap->host->max_cmd_len = (unsigned char) ap->cdb_len; /* print device info to dmesg */ printk(KERN_INFO "ata%u: dev %u ATAPI, max %s\n", ap->id, device, - ata_udma_string(udma_modes)); + ata_mode_string(xfer_modes)); } DPRINTK("EXIT, drv_stat = 0x%x\n", ata_chk_status(ap)); @@ -1167,13 +1148,16 @@ } /** - * ata_port_reset - - * @ap: + * ata_bus_probe - Reset and probe ATA bus + * @ap: Bus to probe * * LOCKING: + * + * RETURNS: + * Zero on success, non-zero on error. */ -static void ata_port_reset(struct ata_port *ap) +static int ata_bus_probe(struct ata_port *ap) { unsigned int i, found = 0; @@ -1197,14 +1181,12 @@ if (ap->flags & ATA_FLAG_PORT_DISABLED) goto err_out_disable; - ap->thr_state = THR_PROBE_SUCCESS; - - return; + return 0; err_out_disable: ap->ops->port_disable(ap); err_out: - ap->thr_state = THR_PROBE_FAILED; + return -1; } /** @@ -1281,6 +1263,101 @@ ap->flags |= ATA_FLAG_PORT_DISABLED; } +static struct { + unsigned int shift; + u8 base; +} xfer_mode_classes[] = { + { ATA_SHIFT_UDMA, XFER_UDMA_0 }, + { ATA_SHIFT_MWDMA, XFER_MW_DMA_0 }, + { ATA_SHIFT_PIO, XFER_PIO_0 }, +}; + +static inline u8 base_from_shift(unsigned int shift) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(xfer_mode_classes); i++) + if (xfer_mode_classes[i].shift == shift) + return xfer_mode_classes[i].base; + + return 0xff; +} + +static void ata_dev_set_mode(struct ata_port *ap, struct ata_device *dev) +{ + int ofs, idx; + u8 base; + + if (!ata_dev_present(dev) || (ap->flags & ATA_FLAG_PORT_DISABLED)) + return; + + if (dev->xfer_shift == ATA_SHIFT_PIO) + dev->flags |= ATA_DFLAG_PIO; + + ata_dev_set_xfermode(ap, dev); + + base = base_from_shift(dev->xfer_shift); + ofs = dev->xfer_mode - base; + idx = ofs + dev->xfer_shift; + WARN_ON(idx >= ARRAY_SIZE(xfer_mode_str)); + + DPRINTK("idx=%d xfer_shift=%u, xfer_mode=0x%x, base=0x%x, offset=%d\n", + idx, dev->xfer_shift, (int)dev->xfer_mode, (int)base, ofs); + + printk(KERN_INFO "ata%u: dev %u configured for %s\n", + ap->id, dev->devno, xfer_mode_str[idx]); +} + +static int ata_host_set_pio(struct ata_port *ap) +{ + unsigned int mask; + int x, i; + u8 base, xfer_mode; + + mask = ata_get_mode_mask(ap, ATA_SHIFT_PIO); + x = fgb(mask); + if (x < 0) { + printk(KERN_WARNING "ata%u: no PIO support\n", ap->id); + return -1; + } + + base = base_from_shift(ATA_SHIFT_PIO); + xfer_mode = base + x; + + DPRINTK("base 0x%x xfer_mode 0x%x mask 0x%x x %d\n", + (int)base, (int)xfer_mode, mask, x); + + for (i = 0; i < ATA_MAX_DEVICES; i++) { + struct ata_device *dev = &ap->device[i]; + if (ata_dev_present(dev)) { + dev->pio_mode = xfer_mode; + dev->xfer_mode = xfer_mode; + dev->xfer_shift = ATA_SHIFT_PIO; + if (ap->ops->set_piomode) + ap->ops->set_piomode(ap, dev); + } + } + + return 0; +} + +static void ata_host_set_dma(struct ata_port *ap, u8 xfer_mode, + unsigned int xfer_shift) +{ + int i; + + for (i = 0; i < ATA_MAX_DEVICES; i++) { + struct ata_device *dev = &ap->device[i]; + if (ata_dev_present(dev)) { + dev->dma_mode = xfer_mode; + dev->xfer_mode = xfer_mode; + dev->xfer_shift = xfer_shift; + if (ap->ops->set_dmamode) + ap->ops->set_dmamode(ap, dev); + } + } +} + /** * ata_set_mode - Program timings and issue SET FEATURES - XFER * @ap: port on which timings will be programmed @@ -1290,29 +1367,28 @@ */ static void ata_set_mode(struct ata_port *ap) { - unsigned int force_pio, i; - - ata_host_set_pio(ap); - if (ap->flags & ATA_FLAG_PORT_DISABLED) - return; + unsigned int i, xfer_shift; + u8 xfer_mode; + int rc; - ata_host_set_udma(ap); - if (ap->flags & ATA_FLAG_PORT_DISABLED) - return; + /* step 1: always set host PIO timings */ + rc = ata_host_set_pio(ap); + if (rc) + goto err_out; -#ifdef ATA_FORCE_PIO - force_pio = 1; -#else - force_pio = 0; -#endif + /* step 2: choose the best data xfer mode */ + xfer_mode = xfer_shift = 0; + rc = ata_choose_xfer_mode(ap, &xfer_mode, &xfer_shift); + if (rc) + goto err_out; - if (force_pio) { - ata_dev_set_pio(ap, 0); - ata_dev_set_pio(ap, 1); - } else { - ata_dev_set_udma(ap, 0); - ata_dev_set_udma(ap, 1); - } + /* step 3: if that xfer mode isn't PIO, set host DMA timings */ + if (xfer_shift != ATA_SHIFT_PIO) + ata_host_set_dma(ap, xfer_mode, xfer_shift); + + /* step 4: update devices' xfer mode */ + ata_dev_set_mode(ap, &ap->device[0]); + ata_dev_set_mode(ap, &ap->device[1]); if (ap->flags & ATA_FLAG_PORT_DISABLED) return; @@ -1324,6 +1400,11 @@ struct ata_device *dev = &ap->device[i]; ata_dev_set_protocol(dev); } + + return; + +err_out: + ata_port_disable(ap); } /** @@ -1585,116 +1666,102 @@ DPRINTK("EXIT\n"); } -/** - * ata_host_set_pio - - * @ap: - * - * LOCKING: - */ - -static void ata_host_set_pio(struct ata_port *ap) +static unsigned int ata_get_mode_mask(struct ata_port *ap, int shift) { struct ata_device *master, *slave; - unsigned int pio, i; - u16 mask; + unsigned int mask; master = &ap->device[0]; slave = &ap->device[1]; assert (ata_dev_present(master) || ata_dev_present(slave)); - mask = ap->pio_mask; - if (ata_dev_present(master)) - mask &= (master->id[ATA_ID_PIO_MODES] & 0x03); - if (ata_dev_present(slave)) - mask &= (slave->id[ATA_ID_PIO_MODES] & 0x03); - - /* require pio mode 3 or 4 support for host and all devices */ - if (mask == 0) { - printk(KERN_WARNING "ata%u: no PIO3/4 support, ignoring\n", - ap->id); - goto err_out; + if (shift == ATA_SHIFT_UDMA) { + mask = ap->udma_mask; + if (ata_dev_present(master)) + mask &= (master->id[ATA_ID_UDMA_MODES] & 0xff); + if (ata_dev_present(slave)) + mask &= (slave->id[ATA_ID_UDMA_MODES] & 0xff); + } + else if (shift == ATA_SHIFT_MWDMA) { + mask = ap->mwdma_mask; + if (ata_dev_present(master)) + mask &= (master->id[ATA_ID_MWDMA_MODES] & 0x07); + if (ata_dev_present(slave)) + mask &= (slave->id[ATA_ID_MWDMA_MODES] & 0x07); + } + else if (shift == ATA_SHIFT_PIO) { + mask = ap->pio_mask; + if (ata_dev_present(master)) { + /* spec doesn't return explicit support for + * PIO0-2, so we fake it + */ + u16 tmp_mode = master->id[ATA_ID_PIO_MODES] & 0x03; + tmp_mode <<= 3; + tmp_mode |= 0x7; + mask &= tmp_mode; + } + if (ata_dev_present(slave)) { + /* spec doesn't return explicit support for + * PIO0-2, so we fake it + */ + u16 tmp_mode = slave->id[ATA_ID_PIO_MODES] & 0x03; + tmp_mode <<= 3; + tmp_mode |= 0x7; + mask &= tmp_mode; + } + } + else { + mask = 0xffffffff; /* shut up compiler warning */ + BUG(); } - pio = (mask & ATA_ID_PIO4) ? 4 : 3; - for (i = 0; i < ATA_MAX_DEVICES; i++) - if (ata_dev_present(&ap->device[i])) { - ap->device[i].pio_mode = (pio == 3) ? - XFER_PIO_3 : XFER_PIO_4; - if (ap->ops->set_piomode) - ap->ops->set_piomode(ap, &ap->device[i], pio); - } + return mask; +} - return; +/* find greatest bit */ +static int fgb(u32 bitmap) +{ + unsigned int i; + int x = -1; -err_out: - ap->ops->port_disable(ap); + for (i = 0; i < 32; i++) + if (bitmap & (1 << i)) + x = i; + + return x; } /** - * ata_host_set_udma - + * ata_choose_xfer_mode - * @ap: * * LOCKING: + * + * RETURNS: + * Zero on success, negative on error. */ -static void ata_host_set_udma(struct ata_port *ap) -{ - struct ata_device *master, *slave; - u16 mask; - unsigned int i, j; - int udma_mode = -1; - - master = &ap->device[0]; - slave = &ap->device[1]; - - assert (ata_dev_present(master) || ata_dev_present(slave)); - assert ((ap->flags & ATA_FLAG_PORT_DISABLED) == 0); - - DPRINTK("udma masks: host 0x%X, master 0x%X, slave 0x%X\n", - ap->udma_mask, - (!ata_dev_present(master)) ? 0xff : - (master->id[ATA_ID_UDMA_MODES] & 0xff), - (!ata_dev_present(slave)) ? 0xff : - (slave->id[ATA_ID_UDMA_MODES] & 0xff)); - - mask = ap->udma_mask; - if (ata_dev_present(master)) - mask &= (master->id[ATA_ID_UDMA_MODES] & 0xff); - if (ata_dev_present(slave)) - mask &= (slave->id[ATA_ID_UDMA_MODES] & 0xff); - - i = XFER_UDMA_7; - while (i >= XFER_UDMA_0) { - j = i - XFER_UDMA_0; - DPRINTK("mask 0x%X i 0x%X j %u\n", mask, i, j); - if (mask & (1 << j)) { - udma_mode = i; - break; +static int ata_choose_xfer_mode(struct ata_port *ap, + u8 *xfer_mode_out, + unsigned int *xfer_shift_out) +{ + unsigned int mask, shift; + int x, i; + + for (i = 0; i < ARRAY_SIZE(xfer_mode_classes); i++) { + shift = xfer_mode_classes[i].shift; + mask = ata_get_mode_mask(ap, shift); + + x = fgb(mask); + if (x >= 0) { + *xfer_mode_out = xfer_mode_classes[i].base + x; + *xfer_shift_out = shift; + return 0; } - - i--; } - /* require udma for host and all attached devices */ - if (udma_mode < 0) { - printk(KERN_WARNING "ata%u: no UltraDMA support, ignoring\n", - ap->id); - goto err_out; - } - - for (i = 0; i < ATA_MAX_DEVICES; i++) - if (ata_dev_present(&ap->device[i])) { - ap->device[i].udma_mode = udma_mode; - if (ap->ops->set_udmamode) - ap->ops->set_udmamode(ap, &ap->device[i], - udma_mode); - } - - return; - -err_out: - ap->ops->port_disable(ap); + return -1; } /** @@ -1707,89 +1774,39 @@ static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev) { - struct ata_taskfile tf; + DECLARE_COMPLETION(wait); + struct ata_queued_cmd *qc; + int rc; + unsigned long flags; /* set up set-features taskfile */ DPRINTK("set features - xfer mode\n"); - ata_tf_init(ap, &tf, dev->devno); - tf.ctl |= ATA_NIEN; - tf.command = ATA_CMD_SET_FEATURES; - tf.feature = SETFEATURES_XFER; - tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - tf.protocol = ATA_PROT_NODATA; - if (dev->flags & ATA_DFLAG_PIO) - tf.nsect = dev->pio_mode; - else - tf.nsect = dev->udma_mode; - /* do bus reset */ - ata_tf_to_host(ap, &tf); + qc = ata_qc_new_init(ap, dev); + BUG_ON(qc == NULL); - /* crazy ATAPI devices... */ - if (dev->class == ATA_DEV_ATAPI) - msleep(150); + qc->tf.command = ATA_CMD_SET_FEATURES; + qc->tf.feature = SETFEATURES_XFER; + qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + qc->tf.protocol = ATA_PROT_NODATA; + qc->tf.nsect = dev->xfer_mode; - ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); + qc->waiting = &wait; + qc->complete_fn = ata_qc_complete_noop; - ata_irq_on(ap); /* re-enable interrupts */ + spin_lock_irqsave(&ap->host_set->lock, flags); + rc = ata_qc_issue(qc); + spin_unlock_irqrestore(&ap->host_set->lock, flags); - ata_wait_idle(ap); + if (rc) + ata_port_disable(ap); + else + wait_for_completion(&wait); DPRINTK("EXIT\n"); } /** - * ata_dev_set_udma - Set ATA device's transfer mode to Ultra DMA - * @ap: Port associated with device @dev - * @device: Device whose mode will be set - * - * LOCKING: - */ - -static void ata_dev_set_udma(struct ata_port *ap, unsigned int device) -{ - struct ata_device *dev = &ap->device[device]; - - if (!ata_dev_present(dev) || (ap->flags & ATA_FLAG_PORT_DISABLED)) - return; - - ata_dev_set_xfermode(ap, dev); - - assert((dev->udma_mode >= XFER_UDMA_0) && - (dev->udma_mode <= XFER_UDMA_7)); - printk(KERN_INFO "ata%u: dev %u configured for %s\n", - ap->id, device, - udma_str[dev->udma_mode - XFER_UDMA_0]); -} - -/** - * ata_dev_set_pio - Set ATA device's transfer mode to PIO - * @ap: Port associated with device @dev - * @device: Device whose mode will be set - * - * LOCKING: - */ - -static void ata_dev_set_pio(struct ata_port *ap, unsigned int device) -{ - struct ata_device *dev = &ap->device[device]; - - if (!ata_dev_present(dev) || (ap->flags & ATA_FLAG_PORT_DISABLED)) - return; - - /* force PIO mode */ - dev->flags |= ATA_DFLAG_PIO; - - ata_dev_set_xfermode(ap, dev); - - assert((dev->pio_mode >= XFER_PIO_3) && - (dev->pio_mode <= XFER_PIO_4)); - printk(KERN_INFO "ata%u: dev %u configured for PIO%c\n", - ap->id, device, - dev->pio_mode == 3 ? '3' : '4'); -} - -/** * ata_sg_clean - * @qc: * @@ -1799,37 +1816,35 @@ static void ata_sg_clean(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - struct scsi_cmnd *cmd = qc->scsicmd; struct scatterlist *sg = qc->sg; - int dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); + int dir = qc->pci_dma_dir; - assert(dir == SCSI_DATA_READ || dir == SCSI_DATA_WRITE); - assert(qc->flags & ATA_QCFLAG_SG); + assert(qc->flags & ATA_QCFLAG_DMAMAP); assert(sg != NULL); - if (!cmd->use_sg) + if (qc->flags & ATA_QCFLAG_SINGLE) assert(qc->n_elem == 1); DPRINTK("unmapping %u sg elements\n", qc->n_elem); - if (cmd->use_sg) + if (qc->flags & ATA_QCFLAG_SG) pci_unmap_sg(ap->host_set->pdev, sg, qc->n_elem, dir); else pci_unmap_single(ap->host_set->pdev, sg_dma_address(&sg[0]), sg_dma_len(&sg[0]), dir); - qc->flags &= ~ATA_QCFLAG_SG; + qc->flags &= ~ATA_QCFLAG_DMAMAP; qc->sg = NULL; } /** - * ata_fill_sg - - * @qc: + * ata_fill_sg - Fill PCI IDE PRD table + * @qc: Metadata associated with taskfile to be transferred * * LOCKING: * */ -void ata_fill_sg(struct ata_queued_cmd *qc) +static void ata_fill_sg(struct ata_queued_cmd *qc) { struct scatterlist *sg = qc->sg; struct ata_port *ap = qc->ap; @@ -1871,6 +1886,48 @@ } /** + * ata_qc_prep - Prepare taskfile for submission + * @qc: Metadata associated with taskfile to be prepared + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + */ +void ata_qc_prep(struct ata_queued_cmd *qc) +{ + if (!(qc->flags & ATA_QCFLAG_DMAMAP)) + return; + + ata_fill_sg(qc); +} + +void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, unsigned int buflen) +{ + struct scatterlist *sg; + + qc->flags |= ATA_QCFLAG_SINGLE; + + memset(&qc->sgent, 0, sizeof(qc->sgent)); + qc->sg = &qc->sgent; + qc->n_elem = 1; + qc->buf_virt = buf; + + sg = qc->sg; + sg->page = virt_to_page(buf); + sg->offset = (unsigned long) buf & ~PAGE_MASK; + sg_dma_len(sg) = buflen; + + WARN_ON(buflen > PAGE_SIZE); +} + +void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg, + unsigned int n_elem) +{ + qc->flags |= ATA_QCFLAG_SG; + qc->sg = sg; + qc->n_elem = n_elem; +} + +/** * ata_sg_setup_one - * @qc: * @@ -1884,29 +1941,16 @@ static int ata_sg_setup_one(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - struct scsi_cmnd *cmd = qc->scsicmd; - int dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); + int dir = qc->pci_dma_dir; struct scatterlist *sg = qc->sg; - unsigned int have_sg = (qc->flags & ATA_QCFLAG_SG); dma_addr_t dma_address; - assert(sg == &qc->sgent); - assert(qc->n_elem == 1); - - sg->address = cmd->request_buffer; - sg->page = virt_to_page(cmd->request_buffer); - sg->offset = (unsigned long) cmd->request_buffer & ~PAGE_MASK; - sg_dma_len(sg) = cmd->request_bufflen; - - if (!have_sg) - return 0; - - dma_address = pci_map_single(ap->host_set->pdev, cmd->request_buffer, - cmd->request_bufflen, dir); + dma_address = pci_map_single(ap->host_set->pdev, qc->buf_virt, + sg_dma_len(sg), dir); sg_dma_address(sg) = dma_address; - DPRINTK("mapped buffer of %d bytes for %s\n", cmd->request_bufflen, + DPRINTK("mapped buffer of %d bytes for %s\n", sg_dma_len(sg), qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read"); return 0; @@ -1926,24 +1970,19 @@ static int ata_sg_setup(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - struct scsi_cmnd *cmd = qc->scsicmd; - struct scatterlist *sg; - int n_elem; - unsigned int have_sg = (qc->flags & ATA_QCFLAG_SG); + struct scatterlist *sg = qc->sg; + int n_elem, dir; - VPRINTK("ENTER, ata%u, use_sg %d\n", ap->id, cmd->use_sg); - assert(cmd->use_sg > 0); + VPRINTK("ENTER, ata%u\n", ap->id); + assert(qc->flags & ATA_QCFLAG_SG); + + dir = qc->pci_dma_dir; + n_elem = pci_map_sg(ap->host_set->pdev, sg, qc->n_elem, dir); + if (n_elem < 1) + return -1; + + DPRINTK("%d sg elements mapped\n", n_elem); - sg = (struct scatterlist *)cmd->request_buffer; - if (have_sg) { - int dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); - n_elem = pci_map_sg(ap->host_set->pdev, sg, cmd->use_sg, dir); - if (n_elem < 1) - return -1; - DPRINTK("%d sg elements mapped\n", n_elem); - } else { - n_elem = cmd->use_sg; - } qc->n_elem = n_elem; return 0; @@ -2028,7 +2067,7 @@ } drv_stat = ata_wait_idle(ap); - if (drv_stat & (ATA_BUSY | ATA_DRQ)) { + if (!ata_ok(drv_stat)) { ap->pio_task_state = PIO_ST_ERR; return; } @@ -2043,6 +2082,43 @@ ata_qc_complete(qc, drv_stat); } +static void ata_mmio_data_xfer(struct ata_port *ap, unsigned char *buf, + unsigned int buflen, int write_data) +{ + unsigned int i; + unsigned int words = buflen >> 1; + u16 *buf16 = (u16 *) buf; + void *mmio = (void *)ap->ioaddr.data_addr; + + if (write_data) { + for (i = 0; i < words; i++) + writew(buf16[i], mmio); + } else { + for (i = 0; i < words; i++) + buf16[i] = readw(mmio); + } +} + +static void ata_pio_data_xfer(struct ata_port *ap, unsigned char *buf, + unsigned int buflen, int write_data) +{ + unsigned int dwords = buflen >> 2; + + if (write_data) + outsl(ap->ioaddr.data_addr, buf, dwords); + else + insl(ap->ioaddr.data_addr, buf, dwords); +} + +static void ata_data_xfer(struct ata_port *ap, unsigned char *buf, + unsigned int buflen, int do_write) +{ + if (ap->flags & ATA_FLAG_MMIO) + ata_mmio_data_xfer(ap, buf, buflen, do_write); + else + ata_pio_data_xfer(ap, buf, buflen, do_write); +} + /** * ata_pio_sector - * @ap: @@ -2054,9 +2130,10 @@ { struct ata_queued_cmd *qc; struct scatterlist *sg; - struct scsi_cmnd *cmd; + struct page *page; unsigned char *buf; u8 status; + int do_write; /* * This is purely hueristic. This is a fast path. @@ -2086,36 +2163,51 @@ qc = ata_qc_from_tag(ap, ap->active_tag); assert(qc != NULL); - cmd = qc->scsicmd; sg = qc->sg; if (qc->cursect == (qc->nsect - 1)) ap->pio_task_state = PIO_ST_LAST; - buf = kmap(sg[qc->cursg].page) + + page = sg[qc->cursg].page; + buf = kmap(page) + sg[qc->cursg].offset + (qc->cursg_ofs * ATA_SECT_SIZE); qc->cursect++; qc->cursg_ofs++; - if (cmd->use_sg) - if ((qc->cursg_ofs * ATA_SECT_SIZE) == sg_dma_len(&sg[qc->cursg])) { - qc->cursg++; - qc->cursg_ofs = 0; - } + if ((qc->cursg_ofs * ATA_SECT_SIZE) == sg_dma_len(&sg[qc->cursg])) { + qc->cursg++; + qc->cursg_ofs = 0; + } DPRINTK("data %s, drv_stat 0x%X\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read", status); /* do the actual data transfer */ - /* FIXME: mmio-ize */ - if (qc->tf.flags & ATA_TFLAG_WRITE) - outsl(ap->ioaddr.data_addr, buf, ATA_SECT_DWORDS); - else - insl(ap->ioaddr.data_addr, buf, ATA_SECT_DWORDS); + do_write = (qc->tf.flags & ATA_TFLAG_WRITE); + ata_data_xfer(ap, buf, ATA_SECT_SIZE, do_write); + + kunmap(page); +} + +static void ata_pio_error(struct ata_port *ap) +{ + struct ata_queued_cmd *qc; + u8 drv_stat; + + qc = ata_qc_from_tag(ap, ap->active_tag); + assert(qc != NULL); + + drv_stat = ata_chk_status(ap); + printk(KERN_WARNING "ata%u: PIO error, drv_stat 0x%x\n", + ap->id, drv_stat); + + ap->pio_task_state = PIO_ST_IDLE; + + ata_irq_on(ap); - kunmap(sg[qc->cursg].page); + ata_qc_complete(qc, drv_stat | ATA_ERR); } static void ata_pio_task(void *_data) @@ -2138,15 +2230,8 @@ break; case PIO_ST_TMOUT: - printk(KERN_ERR "ata%d: FIXME: PIO_ST_TMOUT\n", /* FIXME */ - ap->id); - timeout = 11 * HZ; - break; - case PIO_ST_ERR: - printk(KERN_ERR "ata%d: FIXME: PIO_ST_ERR\n", /* FIXME */ - ap->id); - timeout = 11 * HZ; + ata_pio_error(ap); break; } @@ -2162,8 +2247,8 @@ } /** - * ata_eng_timeout - Handle timeout of queued command - * @ap: Port on which timed-out command is active + * ata_qc_timeout - Handle timeout of queued command + * @qc: Command that timed out * * Some part of the kernel (currently, only the SCSI layer) * has noticed that the active command on port @ap has not @@ -2177,23 +2262,15 @@ * transaction completed successfully. * * LOCKING: - * Inherited from SCSI layer (none, can sleep) */ -void ata_eng_timeout(struct ata_port *ap) +static void ata_qc_timeout(struct ata_queued_cmd *qc) { - u8 host_stat, drv_stat; - struct ata_queued_cmd *qc; + struct ata_port *ap = qc->ap; + u8 host_stat = 0, drv_stat; DPRINTK("ENTER\n"); - qc = ata_qc_from_tag(ap, ap->active_tag); - if (!qc) { - printk(KERN_ERR "ata%u: BUG: timeout without command\n", - ap->id); - goto out; - } - /* hack alert! We cannot use the supplied completion * function from inside the ->eh_strategy_handler() thread. * libata is the only user of ->eh_strategy_handler() in @@ -2203,38 +2280,68 @@ qc->scsidone = scsi_finish_command; switch (qc->tf.protocol) { + case ATA_PROT_DMA: - if (ap->flags & ATA_FLAG_MMIO) { - void *mmio = (void *) ap->ioaddr.bmdma_addr; - host_stat = readb(mmio + ATA_DMA_STATUS); - } else - host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); + case ATA_PROT_ATAPI_DMA: + host_stat = ata_bmdma_status(ap); - printk(KERN_ERR "ata%u: DMA timeout, stat 0x%x\n", - ap->id, host_stat); + /* before we do anything else, clear DMA-Start bit */ + ata_bmdma_stop(ap); - ata_dma_complete(qc, host_stat); - break; + /* fall through */ - case ATA_PROT_NODATA: - drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); + default: + ata_altstatus(ap); + drv_stat = ata_chk_status(ap); + + /* ack bmdma irq events */ + ata_bmdma_ack_irq(ap); - printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x\n", - ap->id, qc->tf.command, drv_stat); + printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x host_stat 0x%x\n", + ap->id, qc->tf.command, drv_stat, host_stat); + /* complete taskfile transaction */ ata_qc_complete(qc, drv_stat); break; + } - default: - drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); + DPRINTK("EXIT\n"); +} + +/** + * ata_eng_timeout - Handle timeout of queued command + * @ap: Port on which timed-out command is active + * + * Some part of the kernel (currently, only the SCSI layer) + * has noticed that the active command on port @ap has not + * completed after a specified length of time. Handle this + * condition by disabling DMA (if necessary) and completing + * transactions, with error if necessary. + * + * This also handles the case of the "lost interrupt", where + * for some reason (possibly hardware bug, possibly driver bug) + * an interrupt was not delivered to the driver, even though the + * transaction completed successfully. + * + * LOCKING: + * Inherited from SCSI layer (none, can sleep) + */ - printk(KERN_ERR "ata%u: unknown timeout, cmd 0x%x stat 0x%x\n", - ap->id, qc->tf.command, drv_stat); +void ata_eng_timeout(struct ata_port *ap) +{ + struct ata_queued_cmd *qc; - ata_qc_complete(qc, drv_stat); - break; + DPRINTK("ENTER\n"); + + qc = ata_qc_from_tag(ap, ap->active_tag); + if (!qc) { + printk(KERN_ERR "ata%u: BUG: timeout without command\n", + ap->id); + goto out; } + ata_qc_timeout(qc); + out: DPRINTK("EXIT\n"); } @@ -2289,8 +2396,6 @@ ata_tf_init(ap, &qc->tf, dev->devno); - if (likely((dev->flags & ATA_DFLAG_PIO) == 0)) - qc->flags |= ATA_QCFLAG_DMA; if (dev->flags & ATA_DFLAG_LBA48) qc->tf.flags |= ATA_TFLAG_LBA48; } @@ -2298,6 +2403,11 @@ return qc; } +static int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat) +{ + return 0; +} + /** * ata_qc_complete - Complete an active ATA command * @qc: Command to complete @@ -2310,29 +2420,25 @@ void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) { struct ata_port *ap = qc->ap; - struct scsi_cmnd *cmd = qc->scsicmd; unsigned int tag, do_clear = 0; + int rc; assert(qc != NULL); /* ata_qc_from_tag _might_ return NULL */ assert(qc->flags & ATA_QCFLAG_ACTIVE); - if (likely(qc->flags & ATA_QCFLAG_SG)) + if (likely(qc->flags & ATA_QCFLAG_DMAMAP)) ata_sg_clean(qc); - if (cmd) { - if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) { - if (is_atapi_taskfile(&qc->tf)) - cmd->result = SAM_STAT_CHECK_CONDITION; - else - ata_to_sense_error(qc); - } else { - cmd->result = SAM_STAT_GOOD; - } + /* call completion callback */ + rc = qc->complete_fn(qc, drv_stat); - qc->scsidone(cmd); - } + /* if callback indicates not to complete command (non-zero), + * return immediately + */ + if (rc != 0) + return; - qc->flags &= ~ATA_QCFLAG_ACTIVE; + qc->flags = 0; tag = qc->tag; if (likely(ata_tag_valid(tag))) { if (tag == ap->active_tag) @@ -2341,11 +2447,16 @@ do_clear = 1; } - if (qc->waiting) - complete(qc->waiting); + if (qc->waiting) { + struct completion *waiting = qc->waiting; + qc->waiting = NULL; + complete(waiting); + } if (likely(do_clear)) clear_bit(tag, &ap->qactive); + + VPRINTK("EXIT\n"); } /** @@ -2367,25 +2478,21 @@ int ata_qc_issue(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - struct scsi_cmnd *cmd = qc->scsicmd; if (qc->flags & ATA_QCFLAG_SG) { - /* set up SG table */ - if (cmd->use_sg) { - if (ata_sg_setup(qc)) - goto err_out; - } else { - if (ata_sg_setup_one(qc)) - goto err_out; - } - - ap->ops->fill_sg(qc); + if (ata_sg_setup(qc)) + goto err_out; + } else if (qc->flags & ATA_QCFLAG_SINGLE) { + if (ata_sg_setup_one(qc)) + goto err_out; } + ap->ops->qc_prep(qc); + qc->ap->active_tag = qc->tag; qc->flags |= ATA_QCFLAG_ACTIVE; - return ata_qc_issue_prot(qc); + return ap->ops->qc_issue(qc); err_out: return -1; @@ -2407,7 +2514,7 @@ * Zero on success, negative on error. */ -static int ata_qc_issue_prot(struct ata_queued_cmd *qc) +int ata_qc_issue_prot(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; @@ -2432,6 +2539,12 @@ break; case ATA_PROT_ATAPI: + ata_qc_set_polling(qc); + ata_tf_to_host_nolock(ap, &qc->tf); + schedule_task(&ap->packet_task); + break; + + case ATA_PROT_ATAPI_NODATA: ata_tf_to_host_nolock(ap, &qc->tf); schedule_task(&ap->packet_task); break; @@ -2461,7 +2574,7 @@ { struct ata_port *ap = qc->ap; unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); - u8 host_stat, dmactl; + u8 dmactl; void *mmio = (void *) ap->ioaddr.bmdma_addr; /* load PRD table addr. */ @@ -2475,10 +2588,6 @@ dmactl |= ATA_DMA_WR; writeb(dmactl, mmio + ATA_DMA_CMD); - /* clear interrupt, error bits */ - host_stat = readb(mmio + ATA_DMA_STATUS); - writeb(host_stat | ATA_DMA_INTR | ATA_DMA_ERR, mmio + ATA_DMA_STATUS); - /* issue r/w command */ ap->ops->exec_command(ap, &qc->tf); } @@ -2526,7 +2635,7 @@ { struct ata_port *ap = qc->ap; unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); - u8 host_stat, dmactl; + u8 dmactl; /* load PRD table addr. */ outl(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS); @@ -2538,11 +2647,6 @@ dmactl |= ATA_DMA_WR; outb(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD); - /* clear interrupt, error bits */ - host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); - outb(host_stat | ATA_DMA_INTR | ATA_DMA_ERR, - ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); - /* issue r/w command */ ap->ops->exec_command(ap, &qc->tf); } @@ -2566,48 +2670,9 @@ ap->ioaddr.bmdma_addr + ATA_DMA_CMD); } -/** - * ata_dma_complete - Complete an active ATA BMDMA command - * @qc: Command to complete - * @host_stat: BMDMA status register contents - * - * LOCKING: - */ - -static void ata_dma_complete(struct ata_queued_cmd *qc, u8 host_stat) +void ata_bmdma_irq_clear(struct ata_port *ap) { - struct ata_port *ap = qc->ap; - VPRINTK("ENTER\n"); - - if (ap->flags & ATA_FLAG_MMIO) { - void *mmio = (void *) ap->ioaddr.bmdma_addr; - - /* clear start/stop bit */ - writeb(readb(mmio + ATA_DMA_CMD) & ~ATA_DMA_START, - mmio + ATA_DMA_CMD); - - /* ack intr, err bits */ - writeb(host_stat | ATA_DMA_INTR | ATA_DMA_ERR, - mmio + ATA_DMA_STATUS); - } else { - /* clear start/stop bit */ - outb(inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START, - ap->ioaddr.bmdma_addr + ATA_DMA_CMD); - - /* ack intr, err bits */ - outb(host_stat | ATA_DMA_INTR | ATA_DMA_ERR, - ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); - } - - - /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */ - ata_altstatus(ap); /* dummy read */ - - DPRINTK("host %u, host_stat==0x%X, drv_stat==0x%X\n", - ap->id, (u32) host_stat, (u32) ata_chk_status(ap)); - - /* get drive status; clear intr; complete txn */ - ata_qc_complete(qc, ata_wait_idle(ap)); + ata_bmdma_ack_irq(ap); } /** @@ -2630,59 +2695,63 @@ struct ata_queued_cmd *qc) { u8 status, host_stat; - unsigned int handled = 0; switch (qc->tf.protocol) { - /* BMDMA completion */ case ATA_PROT_DMA: case ATA_PROT_ATAPI_DMA: - if (ap->flags & ATA_FLAG_MMIO) { - void *mmio = (void *) ap->ioaddr.bmdma_addr; - host_stat = readb(mmio + ATA_DMA_STATUS); - } else - host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); - VPRINTK("BUS_DMA (host_stat 0x%X)\n", host_stat); + case ATA_PROT_ATAPI: + /* check status of DMA engine */ + host_stat = ata_bmdma_status(ap); + VPRINTK("ata%u: host_stat 0x%X\n", ap->id, host_stat); - if (!(host_stat & ATA_DMA_INTR)) { - ap->stats.idle_irq++; - break; - } + /* if it's not our irq... */ + if (!(host_stat & ATA_DMA_INTR)) + goto idle_irq; - ata_dma_complete(qc, host_stat); - handled = 1; - break; + /* before we do anything else, clear DMA-Start bit */ + ata_bmdma_stop(ap); - /* command completion, but no data xfer */ - /* FIXME: a shared interrupt _will_ cause a non-data command - * to be completed prematurely, with an error. - * - * This doesn't matter right now, since we aren't sending - * non-data commands down this pipe except in development - * situations. - */ - case ATA_PROT_ATAPI: + /* fall through */ + + case ATA_PROT_ATAPI_NODATA: case ATA_PROT_NODATA: - status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); - DPRINTK("BUS_NODATA (drv_stat 0x%X)\n", status); + /* check altstatus */ + status = ata_altstatus(ap); + if (status & ATA_BUSY) + goto idle_irq; + + /* check main status, clearing INTRQ */ + status = ata_chk_status(ap); + if (unlikely(status & ATA_BUSY)) + goto idle_irq; + DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n", + ap->id, qc->tf.protocol, status); + + /* ack bmdma irq events */ + ata_bmdma_ack_irq(ap); + + /* complete taskfile transaction */ ata_qc_complete(qc, status); - handled = 1; break; default: - ap->stats.idle_irq++; + goto idle_irq; + } + + return 1; /* irq handled */ + +idle_irq: + ap->stats.idle_irq++; #ifdef ATA_IRQ_TRAP - if ((ap->stats.idle_irq % 1000) == 0) { - handled = 1; - ata_irq_ack(ap, 0); /* debug trap */ - printk(KERN_WARNING "ata%d: irq trap\n", ap->id); - } -#endif - break; + if ((ap->stats.idle_irq % 1000) == 0) { + handled = 1; + ata_irq_ack(ap, 0); /* debug trap */ + printk(KERN_WARNING "ata%d: irq trap\n", ap->id); } - - return handled; +#endif + return 0; /* irq not handled */ } /** @@ -2716,7 +2785,7 @@ qc = ata_qc_from_tag(ap, ap->active_tag); if (qc && (!(qc->tf.ctl & ATA_NIEN))) - handled += ata_host_intr(ap, qc); + handled |= ata_host_intr(ap, qc); } } @@ -2726,62 +2795,6 @@ } /** - * ata_thread_iter - - * @ap: - * - * LOCKING: - * - * RETURNS: - * - */ - -static unsigned long ata_thread_iter(struct ata_port *ap) -{ - long timeout = 0; - - DPRINTK("ata%u: thr_state %s\n", - ap->id, ata_thr_state_name(ap->thr_state)); - - switch (ap->thr_state) { - case THR_UNKNOWN: - ap->thr_state = THR_PORT_RESET; - break; - - case THR_PROBE_START: - ap->thr_state = THR_PORT_RESET; - break; - - case THR_PORT_RESET: - ata_port_reset(ap); - break; - - case THR_PROBE_SUCCESS: - up(&ap->probe_sem); - ap->thr_state = THR_IDLE; - break; - - case THR_PROBE_FAILED: - up(&ap->probe_sem); - ap->thr_state = THR_AWAIT_DEATH; - break; - - case THR_AWAIT_DEATH: - case THR_IDLE: - timeout = -1; - break; - - default: - printk(KERN_DEBUG "ata%u: unknown thr state %s\n", - ap->id, ata_thr_state_name(ap->thr_state)); - break; - } - - DPRINTK("ata%u: new thr_state %s, returning %ld\n", - ap->id, ata_thr_state_name(ap->thr_state), timeout); - return timeout; -} - -/** * atapi_packet_task - Write CDB bytes to hardware * @_data: Port to which ATAPI device is attached. * @@ -2812,21 +2825,20 @@ /* make sure DRQ is set */ status = ata_chk_status(ap); - if ((status & ATA_DRQ) == 0) + if ((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ) goto err_out; /* send SCSI cdb */ - /* FIXME: mmio-ize */ DPRINTK("send cdb\n"); - outsl(ap->ioaddr.data_addr, - qc->scsicmd->cmnd, ap->host->max_cmd_len / 4); + assert(ap->cdb_len >= 12); + ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1); /* if we are DMA'ing, irq handler takes over from here */ if (qc->tf.protocol == ATA_PROT_ATAPI_DMA) ap->ops->bmdma_start(qc); /* initiate bmdma */ /* non-data commands are also handled via irq */ - else if (qc->scsicmd->sc_data_direction == SCSI_DATA_NONE) { + else if (qc->tf.protocol == ATA_PROT_ATAPI_NODATA) { /* do nothing */ } @@ -2862,23 +2874,6 @@ pci_free_consistent(pdev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma); } -static void ata_probe_task(void *_data) -{ - struct ata_port *ap = _data; - long timeout; - - timeout = ata_thread_iter(ap); - if (timeout < 0) - return; - - if (timeout > 0) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(timeout); - } - - schedule_task(&ap->probe_task); -} - /** * ata_host_remove - Unregister SCSI host structure with upper layers * @ap: Port to unregister @@ -2931,24 +2926,20 @@ ap->host_set = host_set; ap->port_no = port_no; ap->pio_mask = ent->pio_mask; + ap->mwdma_mask = ent->mwdma_mask; ap->udma_mask = ent->udma_mask; ap->flags |= ent->host_flags; ap->ops = ent->port_ops; - ap->thr_state = THR_PROBE_START; ap->cbl = ATA_CBL_NONE; - ap->device[0].flags = ATA_DFLAG_MASTER; ap->active_tag = ATA_TAG_POISON; ap->last_ctl = 0xFF; INIT_TQUEUE(&ap->packet_task, atapi_packet_task, ap); INIT_TQUEUE(&ap->pio_task, ata_pio_task, ap); - INIT_TQUEUE(&ap->probe_task, ata_probe_task, ap); for (i = 0; i < ATA_MAX_DEVICES; i++) ap->device[i].devno = i; - init_MUTEX_LOCKED(&ap->probe_sem); - #ifdef ATA_IRQ_TRAP ap->stats.unhandled_irq = 1; ap->stats.idle_irq = 1; @@ -3027,28 +3018,35 @@ host_set->irq = ent->irq; host_set->mmio_base = ent->mmio_base; host_set->private_data = ent->private_data; + host_set->ops = ent->port_ops; /* register each port bound to this device */ for (i = 0; i < ent->n_ports; i++) { struct ata_port *ap; + unsigned long xfer_mode_mask; ap = ata_host_add(ent, host_set, i); if (!ap) goto err_out; host_set->ports[i] = ap; + xfer_mode_mask =(ap->udma_mask << ATA_SHIFT_UDMA) | + (ap->mwdma_mask << ATA_SHIFT_MWDMA) | + (ap->pio_mask << ATA_SHIFT_PIO); /* print per-port info to dmesg */ printk(KERN_INFO "ata%u: %cATA max %s cmd 0x%lX ctl 0x%lX " "bmdma 0x%lX irq %lu\n", ap->id, ap->flags & ATA_FLAG_SATA ? 'S' : 'P', - ata_udma_string(ent->udma_mask), + ata_mode_string(xfer_mode_mask), ap->ioaddr.cmd_addr, ap->ioaddr.ctl_addr, ap->ioaddr.bmdma_addr, ent->irq); + ata_chk_status(ap); + host_set->ops->irq_clear(ap); count++; } @@ -3066,16 +3064,22 @@ DPRINTK("probe begin\n"); for (i = 0; i < count; i++) { struct ata_port *ap; + int rc; ap = host_set->ports[i]; DPRINTK("ata%u: probe begin\n", ap->id); - schedule_task(&ap->probe_task); /* start probe */ - - DPRINTK("ata%u: probe-wait begin\n", ap->id); - down(&ap->probe_sem); /* wait for end */ + rc = ata_bus_probe(ap); + DPRINTK("ata%u: probe end\n", ap->id); - DPRINTK("ata%u: probe-wait end\n", ap->id); + if (rc) { + /* FIXME: do something useful here? + * Current libata behavior will + * tear down everything when + * the module is removed + * or the h/w is unplugged. + */ + } } pci_set_drvdata(pdev, host_set); @@ -3276,6 +3280,7 @@ probe_ent->sht = port0->sht; probe_ent->host_flags = port0->host_flags; probe_ent->pio_mask = port0->pio_mask; + probe_ent->mwdma_mask = port0->mwdma_mask; probe_ent->udma_mask = port0->udma_mask; probe_ent->port_ops = port0->port_ops; @@ -3298,6 +3303,7 @@ probe_ent2->sht = port1->sht; probe_ent2->host_flags = port1->host_flags; probe_ent2->pio_mask = port1->pio_mask; + probe_ent2->mwdma_mask = port1->mwdma_mask; probe_ent2->udma_mask = port1->udma_mask; probe_ent2->port_ops = port1->port_ops; } else { @@ -3383,10 +3389,10 @@ /* FIXME: handle 'rc' failure? */ free_irq(host_set->irq, host_set); + if (host_set->ops->host_stop) + host_set->ops->host_stop(host_set); if (host_set->mmio_base) iounmap(host_set->mmio_base); - if (host_set->ports[0]->ops->host_stop) - host_set->ports[0]->ops->host_stop(host_set); pci_release_regions(pdev); @@ -3492,7 +3498,10 @@ EXPORT_SYMBOL_GPL(ata_std_bios_param); EXPORT_SYMBOL_GPL(ata_std_ports); EXPORT_SYMBOL_GPL(ata_device_add); +EXPORT_SYMBOL_GPL(ata_sg_init); +EXPORT_SYMBOL_GPL(ata_sg_init_one); EXPORT_SYMBOL_GPL(ata_qc_complete); +EXPORT_SYMBOL_GPL(ata_qc_issue_prot); EXPORT_SYMBOL_GPL(ata_eng_timeout); EXPORT_SYMBOL_GPL(ata_tf_load_pio); EXPORT_SYMBOL_GPL(ata_tf_load_mmio); @@ -3507,11 +3516,12 @@ EXPORT_SYMBOL_GPL(ata_port_start); EXPORT_SYMBOL_GPL(ata_port_stop); EXPORT_SYMBOL_GPL(ata_interrupt); -EXPORT_SYMBOL_GPL(ata_fill_sg); +EXPORT_SYMBOL_GPL(ata_qc_prep); EXPORT_SYMBOL_GPL(ata_bmdma_setup_pio); EXPORT_SYMBOL_GPL(ata_bmdma_start_pio); EXPORT_SYMBOL_GPL(ata_bmdma_setup_mmio); EXPORT_SYMBOL_GPL(ata_bmdma_start_mmio); +EXPORT_SYMBOL_GPL(ata_bmdma_irq_clear); EXPORT_SYMBOL_GPL(ata_port_probe); EXPORT_SYMBOL_GPL(sata_phy_reset); EXPORT_SYMBOL_GPL(ata_bus_reset); @@ -3523,5 +3533,6 @@ EXPORT_SYMBOL_GPL(ata_scsi_detect); EXPORT_SYMBOL_GPL(ata_add_to_probe_list); EXPORT_SYMBOL_GPL(ata_scsi_release); +EXPORT_SYMBOL_GPL(libata_msleep); EXPORT_SYMBOL_GPL(ata_host_intr); EXPORT_SYMBOL_GPL(ata_dev_id_string); diff -Nru a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c --- a/drivers/scsi/libata-scsi.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/scsi/libata-scsi.c 2004-08-14 12:02:30 -07:00 @@ -295,6 +295,20 @@ return 1; } +static int ata_scsi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) +{ + struct scsi_cmnd *cmd = qc->scsicmd; + + if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) + ata_to_sense_error(qc); + else + cmd->result = SAM_STAT_GOOD; + + qc->scsidone(cmd); + + return 0; +} + /** * ata_scsi_translate - Translate then issue SCSI command to ATA device * @ap: ATA port to which the command is addressed @@ -328,6 +342,7 @@ if (!qc) return; + /* data is present; dma-map it */ if (cmd->sc_data_direction == SCSI_DATA_READ || cmd->sc_data_direction == SCSI_DATA_WRITE) { if (unlikely(cmd->request_bufflen < 1)) { @@ -336,9 +351,17 @@ goto err_out; } - qc->flags |= ATA_QCFLAG_SG; /* data is present; dma-map it */ + if (cmd->use_sg) + ata_sg_init(qc, cmd->request_buffer, cmd->use_sg); + else + ata_sg_init_one(qc, cmd->request_buffer, + cmd->request_bufflen); + + qc->pci_dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); } + qc->complete_fn = ata_scsi_qc_complete; + if (xlat_func(qc, scsicmd)) goto err_out; @@ -897,6 +920,31 @@ done(cmd); } +static int atapi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) +{ + struct scsi_cmnd *cmd = qc->scsicmd; + + if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) + cmd->result = SAM_STAT_CHECK_CONDITION; + else { + u8 *scsicmd = cmd->cmnd; + + if (scsicmd[0] == INQUIRY) { + u8 *buf = NULL; + unsigned int buflen; + + buflen = ata_scsi_rbuf_get(cmd, &buf); + buf[2] = 0x5; + buf[3] = (buf[3] & 0xf0) | 2; + ata_scsi_rbuf_put(cmd); + } + cmd->result = SAM_STAT_GOOD; + } + + qc->scsidone(cmd); + + return 0; +} /** * atapi_xlat - Initialize PACKET taskfile * @qc: command structure to be initialized @@ -912,6 +960,13 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) { struct scsi_cmnd *cmd = qc->scsicmd; + struct ata_device *dev = qc->dev; + int using_pio = (dev->flags & ATA_DFLAG_PIO); + int nodata = (cmd->sc_data_direction == SCSI_DATA_NONE); + + memcpy(&qc->cdb, scsicmd, qc->ap->cdb_len); + + qc->complete_fn = atapi_qc_complete; qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; if (cmd->sc_data_direction == SCSI_DATA_WRITE) { @@ -921,19 +976,18 @@ qc->tf.command = ATA_CMD_PACKET; - /* no data - interrupt-driven */ - if (cmd->sc_data_direction == SCSI_DATA_NONE) - qc->tf.protocol = ATA_PROT_ATAPI; - - /* PIO data xfer - polling */ - else if ((qc->flags & ATA_QCFLAG_DMA) == 0) { - ata_qc_set_polling(qc); - qc->tf.protocol = ATA_PROT_ATAPI; + /* no data, or PIO data xfer */ + if (using_pio || nodata) { + if (nodata) + qc->tf.protocol = ATA_PROT_ATAPI_NODATA; + else + qc->tf.protocol = ATA_PROT_ATAPI; qc->tf.lbam = (8 * 1024) & 0xff; qc->tf.lbah = (8 * 1024) >> 8; + } - /* DMA data xfer - interrupt-driven */ - } else { + /* DMA data xfer */ + else { qc->tf.protocol = ATA_PROT_ATAPI_DMA; qc->tf.feature |= ATAPI_PKT_DMA; diff -Nru a/drivers/scsi/pluto.c b/drivers/scsi/pluto.c --- a/drivers/scsi/pluto.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/scsi/pluto.c 2004-08-14 12:02:30 -07:00 @@ -339,4 +339,4 @@ #include "scsi_module.c" -EXPORT_NO_SYMBOLS; +MODULE_LICENSE("GPL"); diff -Nru a/drivers/scsi/qlogicfc.c b/drivers/scsi/qlogicfc.c --- a/drivers/scsi/qlogicfc.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/scsi/qlogicfc.c 2004-08-14 12:02:30 -07:00 @@ -722,7 +722,7 @@ continue; /* Try to configure DMA attributes. */ - if (pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff) && + if (pci_set_dma_mask(pdev, (u64) 0xffffffffffffffffULL) && pci_set_dma_mask(pdev, (u64) 0xffffffff)) continue; diff -Nru a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c --- a/drivers/scsi/qlogicpti.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/scsi/qlogicpti.c 2004-08-14 12:02:30 -07:00 @@ -1533,4 +1533,4 @@ #include "scsi_module.c" -EXPORT_NO_SYMBOLS; +MODULE_LICENSE("GPL"); diff -Nru a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/scsi/sata_nv.c 2004-08-14 12:02:31 -07:00 @@ -0,0 +1,365 @@ +/* + * sata_nv.c - NVIDIA nForce SATA + * + * Copyright 2004 NVIDIA Corp. All rights reserved. + * Copyright 2004 Andrew Chew + * + * The contents of this file are subject to the Open + * Software License version 1.1 that can be found at + * http://www.opensource.org/licenses/osl-1.1.txt and is included herein + * by reference. + * + * Alternatively, the contents of this file may be used under the terms + * of the GNU General Public License version 2 (the "GPL") as distributed + * in the kernel source COPYING file, in which case the provisions of + * the GPL are applicable instead of the above. If you wish to allow + * the use of your version of this file only under the terms of the + * GPL and not to allow others to use your version of this file under + * the OSL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the GPL. + * If you do not delete the provisions above, a recipient may use your + * version of this file under either the OSL or the GPL. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "scsi.h" +#include +#include + +#define DRV_NAME "sata_nv" +#define DRV_VERSION "0.01" + +#define NV_PORTS 2 +#define NV_PIO_MASK 0x1f +#define NV_MWDMA_MASK 0x07 +#define NV_UDMA_MASK 0x7f +#define NV_PORT0_BMDMA_REG_OFFSET 0x00 +#define NV_PORT1_BMDMA_REG_OFFSET 0x08 +#define NV_PORT0_SCR_REG_OFFSET 0x00 +#define NV_PORT1_SCR_REG_OFFSET 0x40 + +#define NV_INT_STATUS 0x10 +#define NV_INT_STATUS_PDEV_INT 0x01 +#define NV_INT_STATUS_PDEV_PM 0x02 +#define NV_INT_STATUS_PDEV_ADDED 0x04 +#define NV_INT_STATUS_PDEV_REMOVED 0x08 +#define NV_INT_STATUS_SDEV_INT 0x10 +#define NV_INT_STATUS_SDEV_PM 0x20 +#define NV_INT_STATUS_SDEV_ADDED 0x40 +#define NV_INT_STATUS_SDEV_REMOVED 0x80 +#define NV_INT_STATUS_PDEV_HOTPLUG (NV_INT_STATUS_PDEV_ADDED | \ + NV_INT_STATUS_PDEV_REMOVED) +#define NV_INT_STATUS_SDEV_HOTPLUG (NV_INT_STATUS_SDEV_ADDED | \ + NV_INT_STATUS_SDEV_REMOVED) +#define NV_INT_STATUS_HOTPLUG (NV_INT_STATUS_PDEV_HOTPLUG | \ + NV_INT_STATUS_SDEV_HOTPLUG) + +#define NV_INT_ENABLE 0x11 +#define NV_INT_ENABLE_PDEV_MASK 0x01 +#define NV_INT_ENABLE_PDEV_PM 0x02 +#define NV_INT_ENABLE_PDEV_ADDED 0x04 +#define NV_INT_ENABLE_PDEV_REMOVED 0x08 +#define NV_INT_ENABLE_SDEV_MASK 0x10 +#define NV_INT_ENABLE_SDEV_PM 0x20 +#define NV_INT_ENABLE_SDEV_ADDED 0x40 +#define NV_INT_ENABLE_SDEV_REMOVED 0x80 +#define NV_INT_ENABLE_PDEV_HOTPLUG (NV_INT_ENABLE_PDEV_ADDED | \ + NV_INT_ENABLE_PDEV_REMOVED) +#define NV_INT_ENABLE_SDEV_HOTPLUG (NV_INT_ENABLE_SDEV_ADDED | \ + NV_INT_ENABLE_SDEV_REMOVED) +#define NV_INT_ENABLE_HOTPLUG (NV_INT_ENABLE_PDEV_HOTPLUG | \ + NV_INT_ENABLE_SDEV_HOTPLUG) + +#define NV_INT_CONFIG 0x12 +#define NV_INT_CONFIG_METHD 0x01 // 0 = INT, 1 = SMI + +static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); +irqreturn_t nv_interrupt (int irq, void *dev_instance, struct pt_regs *regs); +static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg); +static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); +static void nv_host_stop (struct ata_host_set *host_set); + +static struct pci_device_id nv_pci_tbl[] = { + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA, + PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA, + PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2, + PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA, + PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2, + PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA, + PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2, + PCI_ANY_ID, PCI_ANY_ID, }, + { 0, } /* terminate list */ +}; + +static struct pci_driver nv_pci_driver = { + .name = DRV_NAME, + .id_table = nv_pci_tbl, + .probe = nv_init_one, + .remove = ata_pci_remove_one, +}; + +static Scsi_Host_Template nv_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .detect = ata_scsi_detect, + .release = ata_scsi_release, + .queuecommand = ata_scsi_queuecmd, + .eh_strategy_handler = ata_scsi_error, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = LIBATA_MAX_PRD, + .max_sectors = ATA_MAX_SECTORS, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .use_new_eh_code = ATA_SHT_NEW_EH_CODE, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .bios_param = ata_std_bios_param, +}; + +static struct ata_port_operations nv_ops = { + .port_disable = ata_port_disable, + .tf_load = ata_tf_load_pio, + .tf_read = ata_tf_read_pio, + .exec_command = ata_exec_command_pio, + .check_status = ata_check_status_pio, + .phy_reset = sata_phy_reset, + .bmdma_setup = ata_bmdma_setup_pio, + .bmdma_start = ata_bmdma_start_pio, + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + .eng_timeout = ata_eng_timeout, + .irq_handler = nv_interrupt, + .irq_clear = ata_bmdma_irq_clear, + .scr_read = nv_scr_read, + .scr_write = nv_scr_write, + .port_start = ata_port_start, + .port_stop = ata_port_stop, + .host_stop = nv_host_stop, +}; + +MODULE_AUTHOR("NVIDIA"); +MODULE_DESCRIPTION("low-level driver for NVIDIA nForce SATA controller"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, nv_pci_tbl); + +irqreturn_t nv_interrupt (int irq, void *dev_instance, struct pt_regs *regs) +{ + struct ata_host_set *host_set = dev_instance; + unsigned int i; + unsigned int handled = 0; + unsigned long flags; + u8 intr_status; + u8 intr_enable; + + spin_lock_irqsave(&host_set->lock, flags); + + for (i = 0; i < host_set->n_ports; i++) { + struct ata_port *ap; + + ap = host_set->ports[i]; + if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) { + struct ata_queued_cmd *qc; + + qc = ata_qc_from_tag(ap, ap->active_tag); + if (qc && (!(qc->tf.ctl & ATA_NIEN))) + handled += ata_host_intr(ap, qc); + } + + intr_status = inb(ap->ioaddr.scr_addr + NV_INT_STATUS); + intr_enable = inb(ap->ioaddr.scr_addr + NV_INT_ENABLE); + + // Clear interrupt status. + outb(0xff, ap->ioaddr.scr_addr + NV_INT_STATUS); + + if (intr_status & NV_INT_STATUS_HOTPLUG) { + if (intr_status & NV_INT_STATUS_PDEV_ADDED) { + printk(KERN_WARNING "ata%u: " + "Primary device added\n", ap->id); + } + + if (intr_status & NV_INT_STATUS_PDEV_REMOVED) { + printk(KERN_WARNING "ata%u: " + "Primary device removed\n", ap->id); + } + + if (intr_status & NV_INT_STATUS_SDEV_ADDED) { + printk(KERN_WARNING "ata%u: " + "Secondary device added\n", ap->id); + } + + if (intr_status & NV_INT_STATUS_SDEV_REMOVED) { + printk(KERN_WARNING "ata%u: " + "Secondary device removed\n", ap->id); + } + } + } + + spin_unlock_irqrestore(&host_set->lock, flags); + + return IRQ_RETVAL(handled); +} + +static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg) +{ + if (sc_reg > SCR_CONTROL) + return 0xffffffffU; + + return inl(ap->ioaddr.scr_addr + (sc_reg * 4)); +} + +static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) +{ + if (sc_reg > SCR_CONTROL) + return; + + outl(val, ap->ioaddr.scr_addr + (sc_reg * 4)); +} + +static void nv_host_stop (struct ata_host_set *host_set) +{ + int i; + + for (i=0; in_ports; i++) { + u8 intr_mask; + + // Disable hotplug event interrupts. + intr_mask = inb(host_set->ports[i]->ioaddr.scr_addr + + NV_INT_ENABLE); + intr_mask &= ~(NV_INT_ENABLE_HOTPLUG); + outb(intr_mask, host_set->ports[i]->ioaddr.scr_addr + + NV_INT_ENABLE); + } +} + +static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) +{ + static int printed_version = 0; + struct ata_probe_ent *probe_ent = NULL; + int i; + int rc; + + if (!printed_version++) + printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + + rc = pci_enable_device(pdev); + if (rc) + return rc; + + rc = pci_request_regions(pdev, DRV_NAME); + if (rc) + goto err_out; + + rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + goto err_out_regions; + + probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); + if (!probe_ent) { + rc = -ENOMEM; + goto err_out_regions; + } + + memset(probe_ent, 0, sizeof(*probe_ent)); + INIT_LIST_HEAD(&probe_ent->node); + + probe_ent->pdev = pdev; + probe_ent->sht = &nv_sht; + probe_ent->host_flags = ATA_FLAG_SATA | + ATA_FLAG_SATA_RESET | + ATA_FLAG_SRST | + ATA_FLAG_NO_LEGACY; + probe_ent->port_ops = &nv_ops; + probe_ent->n_ports = NV_PORTS; + probe_ent->irq = pdev->irq; + probe_ent->irq_flags = SA_SHIRQ; + probe_ent->pio_mask = NV_PIO_MASK; + probe_ent->mwdma_mask = NV_MWDMA_MASK; + probe_ent->udma_mask = NV_UDMA_MASK; + + probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0); + ata_std_ports(&probe_ent->port[0]); + probe_ent->port[0].altstatus_addr = + probe_ent->port[0].ctl_addr = + pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS; + probe_ent->port[0].bmdma_addr = + pci_resource_start(pdev, 4) | NV_PORT0_BMDMA_REG_OFFSET; + probe_ent->port[0].scr_addr = + pci_resource_start(pdev, 5) | NV_PORT0_SCR_REG_OFFSET; + + probe_ent->port[1].cmd_addr = pci_resource_start(pdev, 2); + ata_std_ports(&probe_ent->port[1]); + probe_ent->port[1].altstatus_addr = + probe_ent->port[1].ctl_addr = + pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS; + probe_ent->port[1].bmdma_addr = + pci_resource_start(pdev, 4) | NV_PORT1_BMDMA_REG_OFFSET; + probe_ent->port[1].scr_addr = + pci_resource_start(pdev, 5) | NV_PORT1_SCR_REG_OFFSET; + + pci_set_master(pdev); + + // Enable hotplug event interrupts. + for (i=0; in_ports; i++) { + u8 intr_mask; + + outb(NV_INT_STATUS_HOTPLUG, probe_ent->port[i].scr_addr + + NV_INT_STATUS); + + intr_mask = inb(probe_ent->port[i].scr_addr + NV_INT_ENABLE); + intr_mask |= NV_INT_ENABLE_HOTPLUG; + outb(intr_mask, probe_ent->port[i].scr_addr + NV_INT_ENABLE); + } + + ata_add_to_probe_list(probe_ent); + + return 0; + +err_out_regions: + pci_release_regions(pdev); + +err_out: + pci_disable_device(pdev); + return rc; +} + +static int __init nv_init(void) +{ + int rc; + + rc = pci_module_init(&nv_pci_driver); + if (rc) + return rc; + + rc = scsi_register_module(MODULE_SCSI_HA, &nv_sht); + if (rc) { + pci_unregister_driver(&nv_pci_driver); + /* TODO: does scsi_register_module return errno val? */ + return -ENODEV; + } + + return 0; +} + +static void __exit nv_exit(void) +{ + scsi_unregister_module(MODULE_SCSI_HA, &nv_sht); + pci_unregister_driver(&nv_pci_driver); +} + +module_init(nv_init); +module_exit(nv_exit); diff -Nru a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c --- a/drivers/scsi/sata_promise.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/scsi/sata_promise.c 2004-08-14 12:02:30 -07:00 @@ -42,6 +42,7 @@ #define DRV_NAME "sata_promise" #define DRV_VERSION "1.00" +#define msleep libata_msleep /* 2.4-specific */ enum { PDC_PKT_SUBMIT = 0x40, /* Command packet pointer addr */ @@ -74,18 +75,16 @@ static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg); static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); -static void pdc_dma_setup(struct ata_queued_cmd *qc); -static void pdc_dma_start(struct ata_queued_cmd *qc); static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *regs); static void pdc_eng_timeout(struct ata_port *ap); static int pdc_port_start(struct ata_port *ap); static void pdc_port_stop(struct ata_port *ap); static void pdc_phy_reset(struct ata_port *ap); -static void pdc_fill_sg(struct ata_queued_cmd *qc); +static void pdc_qc_prep(struct ata_queued_cmd *qc); static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf); static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf); -static inline void pdc_dma_complete (struct ata_port *ap, - struct ata_queued_cmd *qc, int have_err); +static void pdc_irq_clear(struct ata_port *ap); +static int pdc_qc_issue_prot(struct ata_queued_cmd *qc); static Scsi_Host_Template pdc_sata_sht = { .module = THIS_MODULE, @@ -113,11 +112,11 @@ .check_status = ata_check_status_mmio, .exec_command = pdc_exec_command_mmio, .phy_reset = pdc_phy_reset, - .bmdma_setup = pdc_dma_setup, - .bmdma_start = pdc_dma_start, - .fill_sg = pdc_fill_sg, + .qc_prep = pdc_qc_prep, + .qc_issue = pdc_qc_issue_prot, .eng_timeout = pdc_eng_timeout, .irq_handler = pdc_interrupt, + .irq_clear = pdc_irq_clear, .scr_read = pdc_sata_scr_read, .scr_write = pdc_sata_scr_write, .port_start = pdc_port_start, @@ -130,7 +129,8 @@ .sht = &pdc_sata_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST | ATA_FLAG_MMIO, - .pio_mask = 0x03, /* pio3-4 */ + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ .port_ops = &pdc_sata_ops, }, @@ -140,7 +140,8 @@ .sht = &pdc_sata_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST | ATA_FLAG_MMIO, - .pio_mask = 0x03, /* pio3-4 */ + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ .port_ops = &pdc_sata_ops, }, @@ -262,33 +263,33 @@ writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4)); } -static void pdc_fill_sg(struct ata_queued_cmd *qc) +static void pdc_qc_prep(struct ata_queued_cmd *qc) { struct pdc_port_priv *pp = qc->ap->private_data; unsigned int i; VPRINTK("ENTER\n"); - ata_fill_sg(qc); - - i = pdc_pkt_header(&qc->tf, qc->ap->prd_dma, qc->dev->devno, pp->pkt); + switch (qc->tf.protocol) { + case ATA_PROT_DMA: + ata_qc_prep(qc); + /* fall through */ - if (qc->tf.flags & ATA_TFLAG_LBA48) - i = pdc_prep_lba48(&qc->tf, pp->pkt, i); - else - i = pdc_prep_lba28(&qc->tf, pp->pkt, i); + case ATA_PROT_NODATA: + i = pdc_pkt_header(&qc->tf, qc->ap->prd_dma, + qc->dev->devno, pp->pkt); - pdc_pkt_footer(&qc->tf, pp->pkt, i); -} + if (qc->tf.flags & ATA_TFLAG_LBA48) + i = pdc_prep_lba48(&qc->tf, pp->pkt, i); + else + i = pdc_prep_lba28(&qc->tf, pp->pkt, i); -static inline void pdc_dma_complete (struct ata_port *ap, - struct ata_queued_cmd *qc, - int have_err) -{ - u8 err_bit = have_err ? ATA_ERR : 0; + pdc_pkt_footer(&qc->tf, pp->pkt, i); + break; - /* get drive status; clear intr; complete txn */ - ata_qc_complete(qc, ata_wait_idle(ap) | err_bit); + default: + break; + } } static void pdc_eng_timeout(struct ata_port *ap) @@ -315,17 +316,9 @@ switch (qc->tf.protocol) { case ATA_PROT_DMA: - printk(KERN_ERR "ata%u: DMA timeout\n", ap->id); - ata_qc_complete(qc, ata_wait_idle(ap) | ATA_ERR); - break; - case ATA_PROT_NODATA: - drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); - - printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x\n", - ap->id, qc->tf.command, drv_stat); - - ata_qc_complete(qc, drv_stat); + printk(KERN_ERR "ata%u: command timeout\n", ap->id); + ata_qc_complete(qc, ata_wait_idle(ap) | ATA_ERR); break; default: @@ -358,13 +351,8 @@ switch (qc->tf.protocol) { case ATA_PROT_DMA: - pdc_dma_complete(ap, qc, have_err); - handled = 1; - break; - - case ATA_PROT_NODATA: /* command completion, but no data xfer */ - status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); - DPRINTK("BUS_NODATA (drv_stat 0x%X)\n", status); + case ATA_PROT_NODATA: + status = ata_wait_idle(ap); if (have_err) status |= ATA_ERR; ata_qc_complete(qc, status); @@ -379,6 +367,14 @@ return handled; } +static void pdc_irq_clear(struct ata_port *ap) +{ + struct ata_host_set *host_set = ap->host_set; + void *mmio = host_set->mmio_base; + + readl(mmio + PDC_INT_SEQMASK); +} + static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) { struct ata_host_set *host_set = dev_instance; @@ -432,13 +428,7 @@ return IRQ_RETVAL(handled); } -static void pdc_dma_setup(struct ata_queued_cmd *qc) -{ - /* nothing for now. later, we will call standard - * code in libata-core for ATAPI here */ -} - -static void pdc_dma_start(struct ata_queued_cmd *qc) +static inline void pdc_packet_start(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct pdc_port_priv *pp = ap->private_data; @@ -456,17 +446,38 @@ readl((void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); /* flush */ } +static int pdc_qc_issue_prot(struct ata_queued_cmd *qc) +{ + switch (qc->tf.protocol) { + case ATA_PROT_DMA: + case ATA_PROT_NODATA: + pdc_packet_start(qc); + return 0; + + case ATA_PROT_ATAPI_DMA: + BUG(); + break; + + default: + break; + } + + return ata_qc_issue_prot(qc); +} + static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) { - if (tf->protocol != ATA_PROT_DMA) - ata_tf_load_mmio(ap, tf); + WARN_ON (tf->protocol == ATA_PROT_DMA || + tf->protocol == ATA_PROT_NODATA); + ata_tf_load_mmio(ap, tf); } static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf) { - if (tf->protocol != ATA_PROT_DMA) - ata_exec_command_mmio(ap, tf); + WARN_ON (tf->protocol == ATA_PROT_DMA || + tf->protocol == ATA_PROT_NODATA); + ata_exec_command_mmio(ap, tf); } @@ -519,8 +530,7 @@ writel(tmp, mmio + PDC_TBG_MODE); readl(mmio + PDC_TBG_MODE); /* flush */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(msecs_to_jiffies(10) + 1); + msleep(10); /* adjust slew rate control register. */ tmp = readl(mmio + PDC_SLEW_CTL); @@ -578,6 +588,7 @@ probe_ent->sht = pdc_port_info[board_idx].sht; probe_ent->host_flags = pdc_port_info[board_idx].host_flags; probe_ent->pio_mask = pdc_port_info[board_idx].pio_mask; + probe_ent->mwdma_mask = pdc_port_info[board_idx].mwdma_mask; probe_ent->udma_mask = pdc_port_info[board_idx].udma_mask; probe_ent->port_ops = pdc_port_info[board_idx].port_ops; diff -Nru a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c --- a/drivers/scsi/sata_sil.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/scsi/sata_sil.c 2004-08-14 12:02:30 -07:00 @@ -86,6 +86,7 @@ { "ST360015AS", SIL_QUIRK_MOD15WRITE }, { "ST380023AS", SIL_QUIRK_MOD15WRITE }, { "ST3120023AS", SIL_QUIRK_MOD15WRITE }, + { "ST3160023AS", SIL_QUIRK_MOD15WRITE }, { "ST340014ASL", SIL_QUIRK_MOD15WRITE }, { "ST360014ASL", SIL_QUIRK_MOD15WRITE }, { "ST380011ASL", SIL_QUIRK_MOD15WRITE }, @@ -132,9 +133,11 @@ .post_set_mode = sil_post_set_mode, .bmdma_setup = ata_bmdma_setup_mmio, .bmdma_start = ata_bmdma_start_mmio, - .fill_sg = ata_fill_sg, + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, .eng_timeout = ata_eng_timeout, .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, .scr_read = sil_scr_read, .scr_write = sil_scr_write, .port_start = ata_port_start, @@ -147,7 +150,8 @@ .sht = &sil_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST | ATA_FLAG_MMIO, - .pio_mask = 0x03, /* pio3-4 */ + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x3f, /* udma0-5 */ .port_ops = &sil_ops, }, /* sil_3114 */ @@ -155,7 +159,8 @@ .sht = &sil_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST | ATA_FLAG_MMIO, - .pio_mask = 0x03, /* pio3-4 */ + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x3f, /* udma0-5 */ .port_ops = &sil_ops, }, @@ -303,6 +308,7 @@ ap->id, dev->devno); ap->host->max_sectors = 15; ap->host->hostt->max_sectors = 15; + dev->flags |= ATA_DFLAG_LOCK_SECTORS; return; } @@ -357,6 +363,7 @@ probe_ent->sht = sil_port_info[ent->driver_data].sht; probe_ent->n_ports = (ent->driver_data == sil_3114) ? 4 : 2; probe_ent->pio_mask = sil_port_info[ent->driver_data].pio_mask; + probe_ent->mwdma_mask = sil_port_info[ent->driver_data].mwdma_mask; probe_ent->udma_mask = sil_port_info[ent->driver_data].udma_mask; probe_ent->irq = pdev->irq; probe_ent->irq_flags = SA_SHIRQ; diff -Nru a/drivers/scsi/sata_sis.c b/drivers/scsi/sata_sis.c --- a/drivers/scsi/sata_sis.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/scsi/sata_sis.c 2004-08-14 12:02:30 -07:00 @@ -101,9 +101,11 @@ .phy_reset = sata_phy_reset, .bmdma_setup = ata_bmdma_setup_pio, .bmdma_start = ata_bmdma_start_pio, - .fill_sg = ata_fill_sg, + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, .eng_timeout = ata_eng_timeout, .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, .scr_read = sis_scr_read, .scr_write = sis_scr_write, .port_start = ata_port_start, @@ -226,7 +228,8 @@ probe_ent->host_flags |= SIS_FLAG_CFGSCR; } - probe_ent->pio_mask = 0x03; + probe_ent->pio_mask = 0x1f; + probe_ent->mwdma_mask = 0x7; probe_ent->udma_mask = 0x7f; probe_ent->port_ops = &sis_ops; diff -Nru a/drivers/scsi/sata_svw.c b/drivers/scsi/sata_svw.c --- a/drivers/scsi/sata_svw.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/scsi/sata_svw.c 2004-08-14 12:02:30 -07:00 @@ -234,9 +234,11 @@ .phy_reset = sata_phy_reset, .bmdma_setup = ata_bmdma_setup_mmio, .bmdma_start = ata_bmdma_start_mmio, - .fill_sg = ata_fill_sg, + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, .eng_timeout = ata_eng_timeout, .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, .scr_read = k2_sata_scr_read, .scr_write = k2_sata_scr_write, .port_start = ata_port_start, @@ -339,6 +341,7 @@ * if we don't fill these */ probe_ent->pio_mask = 0x1f; + probe_ent->mwdma_mask = 0x7; probe_ent->udma_mask = 0x7f; /* We have 4 ports per PCI function */ diff -Nru a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c --- a/drivers/scsi/sata_sx4.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/scsi/sata_sx4.c 2004-08-14 12:02:30 -07:00 @@ -146,19 +146,15 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); -static void pdc20621_dma_setup(struct ata_queued_cmd *qc); -static void pdc20621_dma_start(struct ata_queued_cmd *qc); static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_regs *regs); static void pdc_eng_timeout(struct ata_port *ap); static void pdc_20621_phy_reset (struct ata_port *ap); static int pdc_port_start(struct ata_port *ap); static void pdc_port_stop(struct ata_port *ap); -static void pdc20621_fill_sg(struct ata_queued_cmd *qc); +static void pdc20621_qc_prep(struct ata_queued_cmd *qc); static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf); static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf); static void pdc20621_host_stop(struct ata_host_set *host_set); -static inline void pdc_dma_complete (struct ata_port *ap, - struct ata_queued_cmd *qc, int have_err); static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe); static int pdc20621_detect_dimm(struct ata_probe_ent *pe); static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, @@ -171,6 +167,8 @@ #endif static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource, u32 offset, u32 size); +static void pdc20621_irq_clear(struct ata_port *ap); +static int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc); static Scsi_Host_Template pdc_sata_sht = { @@ -199,11 +197,11 @@ .check_status = ata_check_status_mmio, .exec_command = pdc_exec_command_mmio, .phy_reset = pdc_20621_phy_reset, - .bmdma_setup = pdc20621_dma_setup, - .bmdma_start = pdc20621_dma_start, - .fill_sg = pdc20621_fill_sg, + .qc_prep = pdc20621_qc_prep, + .qc_issue = pdc20621_qc_issue_prot, .eng_timeout = pdc_eng_timeout, .irq_handler = pdc20621_interrupt, + .irq_clear = pdc20621_irq_clear, .port_start = pdc_port_start, .port_stop = pdc_port_stop, .host_stop = pdc20621_host_stop, @@ -215,7 +213,8 @@ .sht = &pdc_sata_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST | ATA_FLAG_MMIO, - .pio_mask = 0x03, /* pio3-4 */ + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ .port_ops = &pdc_20621_ops, }, @@ -375,7 +374,10 @@ /* dimm dma S/G, and next-pkt */ dw = i >> 2; - buf32[dw] = cpu_to_le32(dimm_sg); + if (tf->protocol == ATA_PROT_NODATA) + buf32[dw] = 0; + else + buf32[dw] = cpu_to_le32(dimm_sg); buf32[dw + 1] = 0; i += 8; @@ -435,7 +437,7 @@ buf32[dw + 3]); } -static void pdc20621_fill_sg(struct ata_queued_cmd *qc) +static void pdc20621_dma_prep(struct ata_queued_cmd *qc) { struct scatterlist *sg = qc->sg; struct ata_port *ap = qc->ap; @@ -447,6 +449,8 @@ unsigned int i, last, idx, total_len = 0, sgt_len; u32 *buf = (u32 *) &pp->dimm_buf[PDC_DIMM_HEADER_SZ]; + assert(qc->flags & ATA_QCFLAG_DMAMAP); + VPRINTK("ata%u: ENTER\n", ap->id); /* hard-code chip #0 */ @@ -496,6 +500,56 @@ VPRINTK("ata pkt buf ofs %u, prd size %u, mmio copied\n", i, sgt_len); } +static void pdc20621_nodata_prep(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct pdc_port_priv *pp = ap->private_data; + void *mmio = ap->host_set->mmio_base; + struct pdc_host_priv *hpriv = ap->host_set->private_data; + void *dimm_mmio = hpriv->dimm_mmio; + unsigned int portno = ap->port_no; + unsigned int i; + + VPRINTK("ata%u: ENTER\n", ap->id); + + /* hard-code chip #0 */ + mmio += PDC_CHIP0_OFS; + + i = pdc20621_ata_pkt(&qc->tf, qc->dev->devno, &pp->dimm_buf[0], portno); + + if (qc->tf.flags & ATA_TFLAG_LBA48) + i = pdc_prep_lba48(&qc->tf, &pp->dimm_buf[0], i); + else + i = pdc_prep_lba28(&qc->tf, &pp->dimm_buf[0], i); + + pdc_pkt_footer(&qc->tf, &pp->dimm_buf[0], i); + + /* copy three S/G tables and two packets to DIMM MMIO window */ + memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP), + &pp->dimm_buf, PDC_DIMM_HEADER_SZ); + + /* force host FIFO dump */ + writel(0x00000001, mmio + PDC_20621_GENERAL_CTL); + + readl(dimm_mmio); /* MMIO PCI posting flush */ + + VPRINTK("ata pkt buf ofs %u, prd size %u, mmio copied\n", i, sgt_len); +} + +static void pdc20621_qc_prep(struct ata_queued_cmd *qc) +{ + switch (qc->tf.protocol) { + case ATA_PROT_DMA: + pdc20621_dma_prep(qc); + break; + case ATA_PROT_NODATA: + pdc20621_nodata_prep(qc); + break; + default: + break; + } +} + static void __pdc20621_push_hdma(struct ata_queued_cmd *qc, unsigned int seq, u32 pkt_ofs) @@ -571,13 +625,7 @@ static inline void pdc20621_dump_hdma(struct ata_queued_cmd *qc) { } #endif /* ATA_VERBOSE_DEBUG */ -static void pdc20621_dma_setup(struct ata_queued_cmd *qc) -{ - /* nothing for now. later, we will call standard - * code in libata-core for ATAPI here */ -} - -static void pdc20621_dma_start(struct ata_queued_cmd *qc) +static void pdc20621_packet_start(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct ata_host_set *host_set = ap->host_set; @@ -585,24 +633,21 @@ void *mmio = host_set->mmio_base; unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); u8 seq = (u8) (port_no + 1); - unsigned int doing_hdma = 0, port_ofs; + unsigned int port_ofs; /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; VPRINTK("ata%u: ENTER\n", ap->id); + wmb(); /* flush PRD, pkt writes */ + port_ofs = PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * port_no); /* if writing, we (1) DMA to DIMM, then (2) do ATA command */ - if (rw) { - doing_hdma = 1; + if (rw && qc->tf.protocol == ATA_PROT_DMA) { seq += 4; - } - wmb(); /* flush PRD, pkt writes */ - - if (doing_hdma) { pdc20621_dump_hdma(qc); pdc20621_push_hdma(qc, seq, port_ofs + PDC_DIMM_HOST_PKT); VPRINTK("queued ofs 0x%x (%u), seq %u\n", @@ -623,6 +668,25 @@ } } +static int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc) +{ + switch (qc->tf.protocol) { + case ATA_PROT_DMA: + case ATA_PROT_NODATA: + pdc20621_packet_start(qc); + return 0; + + case ATA_PROT_ATAPI_DMA: + BUG(); + break; + + default: + break; + } + + return ata_qc_issue_prot(qc); +} + static inline unsigned int pdc20621_host_intr( struct ata_port *ap, struct ata_queued_cmd *qc, unsigned int doing_hdma, @@ -643,7 +707,8 @@ if (doing_hdma) { VPRINTK("ata%u: read hdma, 0x%x 0x%x\n", ap->id, readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT)); - pdc_dma_complete(ap, qc, 0); + /* get drive status; clear intr; complete txn */ + ata_qc_complete(qc, ata_wait_idle(ap)); pdc20621_pop_hdma(qc); } @@ -680,7 +745,8 @@ else { VPRINTK("ata%u: write ata, 0x%x 0x%x\n", ap->id, readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT)); - pdc_dma_complete(ap, qc, 0); + /* get drive status; clear intr; complete txn */ + ata_qc_complete(qc, ata_wait_idle(ap)); pdc20621_pop_hdma(qc); } handled = 1; @@ -700,6 +766,16 @@ return handled; } +static void pdc20621_irq_clear(struct ata_port *ap) +{ + struct ata_host_set *host_set = ap->host_set; + void *mmio = host_set->mmio_base; + + mmio += PDC_CHIP0_OFS; + + readl(mmio + PDC_20621_SEQMASK); +} + static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_regs *regs) { struct ata_host_set *host_set = dev_instance; @@ -764,16 +840,6 @@ return IRQ_RETVAL(handled); } -static inline void pdc_dma_complete (struct ata_port *ap, - struct ata_queued_cmd *qc, - int have_err) -{ - u8 err_bit = have_err ? ATA_ERR : 0; - - /* get drive status; clear intr; complete txn */ - ata_qc_complete(qc, ata_wait_idle(ap) | err_bit); -} - static void pdc_eng_timeout(struct ata_port *ap) { u8 drv_stat; @@ -798,17 +864,9 @@ switch (qc->tf.protocol) { case ATA_PROT_DMA: - printk(KERN_ERR "ata%u: DMA timeout\n", ap->id); - ata_qc_complete(qc, ata_wait_idle(ap) | ATA_ERR); - break; - case ATA_PROT_NODATA: - drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); - - printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x\n", - ap->id, qc->tf.command, drv_stat); - - ata_qc_complete(qc, drv_stat); + printk(KERN_ERR "ata%u: command timeout\n", ap->id); + ata_qc_complete(qc, ata_wait_idle(ap) | ATA_ERR); break; default: @@ -827,15 +885,17 @@ static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) { - if (tf->protocol != ATA_PROT_DMA) - ata_tf_load_mmio(ap, tf); + WARN_ON (tf->protocol == ATA_PROT_DMA || + tf->protocol == ATA_PROT_NODATA); + ata_tf_load_mmio(ap, tf); } static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf) { - if (tf->protocol != ATA_PROT_DMA) - ata_exec_command_mmio(ap, tf); + WARN_ON (tf->protocol == ATA_PROT_DMA || + tf->protocol == ATA_PROT_NODATA); + ata_exec_command_mmio(ap, tf); } @@ -1366,6 +1426,7 @@ probe_ent->sht = pdc_port_info[board_idx].sht; probe_ent->host_flags = pdc_port_info[board_idx].host_flags; probe_ent->pio_mask = pdc_port_info[board_idx].pio_mask; + probe_ent->mwdma_mask = pdc_port_info[board_idx].mwdma_mask; probe_ent->udma_mask = pdc_port_info[board_idx].udma_mask; probe_ent->port_ops = pdc_port_info[board_idx].port_ops; @@ -1376,21 +1437,11 @@ probe_ent->private_data = hpriv; base += PDC_CHIP0_OFS; + probe_ent->n_ports = 4; pdc_sata_setup_port(&probe_ent->port[0], base + 0x200); pdc_sata_setup_port(&probe_ent->port[1], base + 0x280); - - /* notice 4-port boards */ - switch (board_idx) { - case board_20621: - probe_ent->n_ports = 4; - - pdc_sata_setup_port(&probe_ent->port[2], base + 0x300); - pdc_sata_setup_port(&probe_ent->port[3], base + 0x380); - break; - default: - BUG(); - break; - } + pdc_sata_setup_port(&probe_ent->port[2], base + 0x300); + pdc_sata_setup_port(&probe_ent->port[3], base + 0x380); pci_set_master(pdev); diff -Nru a/drivers/scsi/sata_via.c b/drivers/scsi/sata_via.c --- a/drivers/scsi/sata_via.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/scsi/sata_via.c 2004-08-14 12:02:30 -07:00 @@ -109,10 +109,13 @@ .bmdma_setup = ata_bmdma_setup_pio, .bmdma_start = ata_bmdma_start_pio, - .fill_sg = ata_fill_sg, + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + .eng_timeout = ata_eng_timeout, .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, .scr_read = svia_scr_read, .scr_write = svia_scr_write, @@ -209,6 +212,7 @@ probe_ent->irq = pdev->irq; probe_ent->irq_flags = SA_SHIRQ; probe_ent->pio_mask = 0x1f; + probe_ent->mwdma_mask = 0x07; probe_ent->udma_mask = 0x7f; probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0); diff -Nru a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c --- a/drivers/scsi/sata_vsc.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/scsi/sata_vsc.c 2004-08-14 12:02:30 -07:00 @@ -216,9 +216,11 @@ .phy_reset = sata_phy_reset, .bmdma_setup = ata_bmdma_setup_mmio, .bmdma_start = ata_bmdma_start_mmio, - .fill_sg = ata_fill_sg, + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, .eng_timeout = ata_eng_timeout, .irq_handler = vsc_sata_interrupt, + .irq_clear = ata_bmdma_irq_clear, .scr_read = vsc_sata_scr_read, .scr_write = vsc_sata_scr_write, .port_start = ata_port_start, @@ -316,6 +318,7 @@ * if we don't fill these */ probe_ent->pio_mask = 0x1f; + probe_ent->mwdma_mask = 0x07; probe_ent->udma_mask = 0x7f; /* We have 4 ports per PCI function */ diff -Nru a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c --- a/drivers/scsi/scsi_scan.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/scsi/scsi_scan.c 2004-08-14 12:02:30 -07:00 @@ -157,6 +157,7 @@ {"TOSHIBA","CDROM","*", BLIST_ISROM}, {"TOSHIBA","CD-ROM","*", BLIST_ISROM}, {"MegaRAID", "LD", "*", BLIST_FORCELUN}, + {"3PARdata", "VV", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, // 3PARdata InServ Virtual Volume {"DGC", "RAID", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, // Dell PV 650F (tgt @ LUN 0) {"DGC", "DISK", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, // Dell PV 650F (no tgt @ LUN 0) {"DELL", "PV660F", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, @@ -208,6 +209,7 @@ {"SMSC", "USB 2 HS", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, {"XYRATEX", "RS", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, {"NEC", "iStorage", "*", BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN}, + {"Xyratex", "4200", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, /* * Must be at end of list... diff -Nru a/drivers/sound/ac97_codec.c b/drivers/sound/ac97_codec.c --- a/drivers/sound/ac97_codec.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/sound/ac97_codec.c 2004-08-14 12:02:30 -07:00 @@ -30,6 +30,9 @@ ************************************************************************** * * History + * Feb 25, 2004 Liam Girdwood + * Added support for codecs that require a warm reset to power up. + * Support for WM9713 * May 02, 2003 Liam Girdwood * Removed non existant WM9700 * Added support for WM9705, WM9708, WM9709, WM9710, WM9711 @@ -71,6 +74,7 @@ static int wolfson_init04(struct ac97_codec * codec); static int wolfson_init05(struct ac97_codec * codec); static int wolfson_init11(struct ac97_codec * codec); +static int wolfson_init13(struct ac97_codec * codec); static int tritech_init(struct ac97_codec * codec); static int tritech_maestro_init(struct ac97_codec * codec); static int sigmatel_9708_init(struct ac97_codec *codec); @@ -107,6 +111,7 @@ static struct ac97_ops wolfson_ops04 = { wolfson_init04, NULL, NULL }; static struct ac97_ops wolfson_ops05 = { wolfson_init05, NULL, NULL }; static struct ac97_ops wolfson_ops11 = { wolfson_init11, NULL, NULL }; +static struct ac97_ops wolfson_ops13 = { wolfson_init13, NULL, NULL }; static struct ac97_ops tritech_ops = { tritech_init, NULL, NULL }; static struct ac97_ops tritech_m_ops = { tritech_maestro_init, NULL, NULL }; static struct ac97_ops sigmatel_9708_ops = { sigmatel_9708_init, NULL, NULL }; @@ -168,6 +173,7 @@ {0x574D4C05, "Wolfson WM9705/WM9710", &wolfson_ops05}, {0x574D4C09, "Wolfson WM9709", &null_ops}, {0x574D4C12, "Wolfson WM9711/9712", &wolfson_ops11}, + {0x574D4C13, "Wolfson WM9713", &wolfson_ops13, AC97_DEFAULT_POWER_OFF}, {0x83847600, "SigmaTel STAC????", &null_ops}, {0x83847604, "SigmaTel STAC9701/3/4/5", &null_ops}, {0x83847605, "SigmaTel STAC9704", &null_ops}, @@ -793,6 +799,9 @@ * Currently codec_wait is used to wait for AC97 codec * reset to complete. * + * Some codecs will power down when a register reset is + * performed. We now check for such codecs. + * * Returns 1 (true) on success, or 0 (false) on failure. */ @@ -805,35 +814,18 @@ u16 f; struct list_head *l; struct ac97_driver *d; - - /* probing AC97 codec, AC97 2.0 says that bit 15 of register 0x00 (reset) should - * be read zero. - * - * FIXME: is the following comment outdated? -jgarzik - * Probing of AC97 in this way is not reliable, it is not even SAFE !! - */ - codec->codec_write(codec, AC97_RESET, 0L); - /* also according to spec, we wait for codec-ready state */ + /* wait for codec-ready state */ if (codec->codec_wait) codec->codec_wait(codec); else udelay(10); - - if ((audio = codec->codec_read(codec, AC97_RESET)) & 0x8000) { - printk(KERN_ERR "ac97_codec: %s ac97 codec not present\n", - (codec->id & 0x2) ? (codec->id&1 ? "4th" : "Tertiary") - : (codec->id&1 ? "Secondary": "Primary")); - return 0; - } - - /* probe for Modem Codec */ - codec->modem = ac97_check_modem(codec); - codec->name = NULL; - codec->codec_ops = &default_ops; - + + /* will the codec power down if register reset ? */ id1 = codec->codec_read(codec, AC97_VENDOR_ID1); id2 = codec->codec_read(codec, AC97_VENDOR_ID2); + codec->name = NULL; + codec->codec_ops = &null_ops; for (i = 0; i < ARRAY_SIZE(ac97_codec_ids); i++) { if (ac97_codec_ids[i].id == ((id1 << 16) | id2)) { codec->type = ac97_codec_ids[i].id; @@ -843,11 +835,35 @@ break; } } - codec->model = (id1 << 16) | id2; + if ((codec->flags & AC97_DEFAULT_POWER_OFF) == 0) { + /* reset codec and wait for the ready bit before we continue */ + codec->codec_write(codec, AC97_RESET, 0L); + if (codec->codec_wait) + codec->codec_wait(codec); + else + udelay(10); + } + /* probing AC97 codec, AC97 2.0 says that bit 15 of register 0x00 (reset) should + * be read zero. + * + * FIXME: is the following comment outdated? -jgarzik + * Probing of AC97 in this way is not reliable, it is not even SAFE !! + */ + if ((audio = codec->codec_read(codec, AC97_RESET)) & 0x8000) { + printk(KERN_ERR "ac97_codec: %s ac97 codec not present\n", + (codec->id & 0x2) ? (codec->id&1 ? "4th" : "Tertiary") + : (codec->id&1 ? "Secondary": "Primary")); + return 0; + } + + /* probe for Modem Codec */ + codec->modem = ac97_check_modem(codec); + + /* enable SPDIF */ f = codec->codec_read(codec, AC97_EXTENDED_STATUS); - if(f & 4) + if((codec->codec_ops == &null_ops) && (f & 4)) codec->codec_ops = &default_digital_ops; /* A device which thinks its a modem but isnt */ @@ -916,11 +932,6 @@ codec->recmask_io = ac97_recmask_io; codec->mixer_ioctl = ac97_mixer_ioctl; - /* codec specific initialization for 4-6 channel output or secondary codec stuff */ - if (codec->codec_ops->init != NULL) { - codec->codec_ops->init(codec); - } - /* initialize mixer channel volumes */ for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { struct mixer_defaults *md = &mixer_defaults[i]; @@ -930,6 +941,11 @@ continue; ac97_set_mixer(codec, md->mixer, md->value); } + + /* codec specific initialization for 4-6 channel output or secondary codec stuff */ + if (codec->codec_ops->init != NULL) { + codec->codec_ops->init(codec); + } /* * Volume is MUTE only on this device. We have to initialise @@ -1082,6 +1098,19 @@ /* set out3 volume */ codec->codec_write(codec, AC97_WM9711_OUT3VOL, 0x0808); + return 0; +} + +/* WM9713 */ +static int wolfson_init13(struct ac97_codec * codec) +{ + codec->codec_write(codec, AC97_RECORD_GAIN, 0x00a0); + codec->codec_write(codec, AC97_POWER_CONTROL, 0x0000); + codec->codec_write(codec, AC97_EXTENDED_MODEM_ID, 0xDA00); + codec->codec_write(codec, AC97_EXTEND_MODEM_STAT, 0x3810); + codec->codec_write(codec, AC97_PHONE_VOL, 0x0808); + codec->codec_write(codec, AC97_PCBEEP_VOL, 0x0808); + return 0; } diff -Nru a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c --- a/drivers/usb/host/ehci-hcd.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/usb/host/ehci-hcd.c 2004-08-14 12:02:30 -07:00 @@ -303,7 +303,8 @@ if (cap & (1 << 16)) { ehci_err (ehci, "BIOS handoff failed (%d, %04x)\n", where, cap); - return 1; + pci_write_config_dword (ehci->hcd.pdev, where, 0); + return 0; } ehci_dbg (ehci, "BIOS handoff succeeded\n"); } @@ -547,7 +548,8 @@ /* root hub is shut down separately (first, when possible) */ spin_lock_irq (&ehci->lock); - ehci_work (ehci, NULL); + if (ehci->async) + ehci_work (ehci, NULL); spin_unlock_irq (&ehci->lock); ehci_mem_cleanup (ehci); diff -Nru a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c --- a/drivers/usb/storage/sddr09.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/usb/storage/sddr09.c 2004-08-14 12:02:30 -07:00 @@ -444,6 +444,7 @@ * byte 0: opcode: 03 * byte 4: data length */ +#if 0 static int sddr09_request_sense(struct us_data *us, unsigned char *sensebuf, int buflen) { unsigned char command[12] = { @@ -465,7 +466,7 @@ return result; } - +#endif /* * Read Command: 12 bytes. * byte 0: opcode: E8 diff -Nru a/drivers/video/matrox/matroxfb_g450.c b/drivers/video/matrox/matroxfb_g450.c --- a/drivers/video/matrox/matroxfb_g450.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/video/matrox/matroxfb_g450.c 2004-08-14 12:02:30 -07:00 @@ -558,7 +558,7 @@ } static int matroxfb_g450_verify_mode(void* md, u_int32_t arg) { - MINFO_FROM(md); +// MINFO_FROM(md); switch (arg) { case MATROXFB_OUTPUT_MODE_PAL: diff -Nru a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c --- a/drivers/video/riva/fbdev.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/video/riva/fbdev.c 2004-08-14 12:02:30 -07:00 @@ -2221,7 +2221,6 @@ release_mem_region(rinfo->fb_base_phys, rinfo->base1_region_size); err_out_free_base0: release_mem_region(rinfo->ctrl_base_phys, rinfo->base0_region_size); -err_out_kfree: kfree(rinfo); err_out: return -ENODEV; diff -Nru a/drivers/video/sstfb.c b/drivers/video/sstfb.c --- a/drivers/video/sstfb.c 2004-08-14 12:02:30 -07:00 +++ b/drivers/video/sstfb.c 2004-08-14 12:02:30 -07:00 @@ -968,7 +968,6 @@ struct fb_info *info) { #define sst_info ((struct sstfb_info *) info) - int i; u_long p; u32 tmp, val; u32 fbiinit0; @@ -980,12 +979,14 @@ #if (SST_DEBUG_VAR >0) /* tmp ioctl : dumps fb_display[0-5] */ - case _IO('F', 0xdb): /* 0x46db */ + case _IO('F', 0xdb): /* 0x46db */ { + int i; f_dprintk("dumping fb_display[0-5].var\n"); for (i = 0 ; i< 6 ; i++) { print_var(&fb_display[i].var, "var(%d)", i); } return 0; + } #endif /* (SST_DEBUG_VAR >0) */ /* fills the lfb up to given count of pixels */ diff -Nru a/fs/befs/btree.c b/fs/befs/btree.c --- a/fs/befs/btree.c 2004-08-14 12:02:31 -07:00 +++ b/fs/befs/btree.c 2004-08-14 12:02:31 -07:00 @@ -85,7 +85,7 @@ } befs_btree_node; /* local constants */ -const static befs_off_t befs_bt_inval = 0xffffffffffffffff; +const static befs_off_t befs_bt_inval = 0xffffffffffffffffULL; /* local functions */ static int befs_btree_seekleaf(struct super_block *sb, befs_data_stream * ds, diff -Nru a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c --- a/fs/befs/linuxvfs.c 2004-08-14 12:02:31 -07:00 +++ b/fs/befs/linuxvfs.c 2004-08-14 12:02:31 -07:00 @@ -55,13 +55,6 @@ static int befs_statfs(struct super_block *, struct statfs *); static int parse_options(char *, befs_mount_options *); -static ssize_t befs_listxattr(struct dentry *dentry, char *buffer, size_t size); -static ssize_t befs_getxattr(struct dentry *dentry, const char *name, - void *buffer, size_t size); -static int befs_setxattr(struct dentry *dentry, const char *name, void *value, - size_t size, int flags); -static int befs_removexattr(struct dentry *dentry, const char *name); - /* slab cache for befs_inode_info objects */ static kmem_cache_t *befs_inode_cachep; @@ -584,11 +577,11 @@ } } result[o] = '\0'; + *out_len = o; befs_debug(sb, "<--- utf2nls()"); return o; - *out_len = o; conv_err: befs_error(sb, "Name using charecter set %s contains a charecter that " @@ -673,35 +666,6 @@ befs_debug(sb, "<--- nls2utf()"); kfree(result); return -EILSEQ; -} - -/****Xattr****/ - -static ssize_t -befs_listxattr(struct dentry *dentry, char *buffer, size_t size) -{ - printk(KERN_ERR "befs_listxattr called\n"); - return 0; -} - -static ssize_t -befs_getxattr(struct dentry *dentry, const char *name, - void *buffer, size_t size) -{ - return 0; -} - -static int -befs_setxattr(struct dentry *dentry, const char *name, - void *value, size_t size, int flags) -{ - return 0; -} - -static int -befs_removexattr(struct dentry *dentry, const char *name) -{ - return 0; } /****Superblock****/ diff -Nru a/fs/buffer.c b/fs/buffer.c --- a/fs/buffer.c 2004-08-14 12:02:30 -07:00 +++ b/fs/buffer.c 2004-08-14 12:02:30 -07:00 @@ -1260,8 +1260,9 @@ /* * If we need an async buffer, use the reserved buffer heads. + * Non-PF_MEMALLOC tasks can just loop in create_buffers(). */ - if (async) { + if (async && (current->flags & PF_MEMALLOC)) { spin_lock(&unused_list_lock); if (unused_list) { bh = unused_list; diff -Nru a/fs/partitions/ldm.h b/fs/partitions/ldm.h --- a/fs/partitions/ldm.h 2004-08-14 12:02:30 -07:00 +++ b/fs/partitions/ldm.h 2004-08-14 12:02:30 -07:00 @@ -38,8 +38,8 @@ /* Magic numbers in CPU format. */ #define MAGIC_VMDB 0x564D4442 /* VMDB */ #define MAGIC_VBLK 0x56424C4B /* VBLK */ -#define MAGIC_PRIVHEAD 0x5052495648454144 /* PRIVHEAD */ -#define MAGIC_TOCBLOCK 0x544F43424C4F434B /* TOCBLOCK */ +#define MAGIC_PRIVHEAD 0x5052495648454144ULL /* PRIVHEAD */ +#define MAGIC_TOCBLOCK 0x544F43424C4F434BULL /* TOCBLOCK */ /* The defined vblk types. */ #define VBLK_VOL5 0x51 /* Volume, version 5 */ diff -Nru a/include/asm-sparc64/asi.h b/include/asm-sparc64/asi.h --- a/include/asm-sparc64/asi.h 2004-08-14 12:02:30 -07:00 +++ b/include/asm-sparc64/asi.h 2004-08-14 12:02:30 -07:00 @@ -8,125 +8,138 @@ */ /* V9 Architecture mandary ASIs. */ -#define ASI_N 0x04 /* Nucleus */ -#define ASI_NL 0x0c /* Nucleus, little endian */ -#define ASI_AIUP 0x10 /* Primary, user */ -#define ASI_AIUS 0x11 /* Secondary, user */ -#define ASI_AIUPL 0x18 /* Primary, user, little endian */ -#define ASI_AIUSL 0x19 /* Secondary, user, little endian */ -#define ASI_P 0x80 /* Primary, implicit */ -#define ASI_S 0x81 /* Secondary, implicit */ -#define ASI_PNF 0x82 /* Primary, no fault */ -#define ASI_SNF 0x83 /* Secondary, no fault */ -#define ASI_PL 0x88 /* Primary, implicit, little endian */ -#define ASI_SL 0x89 /* Secondary, implicit, little endian */ -#define ASI_PNFL 0x8a /* Primary, no fault, little endian */ -#define ASI_SNFL 0x8b /* Secondary, no fault, little endian */ +#define ASI_N 0x04 /* Nucleus */ +#define ASI_NL 0x0c /* Nucleus, little endian */ +#define ASI_AIUP 0x10 /* Primary, user */ +#define ASI_AIUS 0x11 /* Secondary, user */ +#define ASI_AIUPL 0x18 /* Primary, user, little endian */ +#define ASI_AIUSL 0x19 /* Secondary, user, little endian */ +#define ASI_P 0x80 /* Primary, implicit */ +#define ASI_S 0x81 /* Secondary, implicit */ +#define ASI_PNF 0x82 /* Primary, no fault */ +#define ASI_SNF 0x83 /* Secondary, no fault */ +#define ASI_PL 0x88 /* Primary, implicit, l-endian */ +#define ASI_SL 0x89 /* Secondary, implicit, l-endian */ +#define ASI_PNFL 0x8a /* Primary, no fault, l-endian */ +#define ASI_SNFL 0x8b /* Secondary, no fault, l-endian */ /* SpitFire and later extended ASIs. The "(III)" marker designates - * UltraSparc-III specific ASIs. + * UltraSparc-III and later specific ASIs. The "(CMT)" marker designates + * Chip Multi Threading specific ASIs. */ -#define ASI_PHYS_USE_EC 0x14 /* PADDR, E-cachable */ -#define ASI_PHYS_BYPASS_EC_E 0x15 /* PADDR, E-bit */ -#define ASI_PHYS_USE_EC_L 0x1c /* PADDR, E-cachable, little endian */ -#define ASI_PHYS_BYPASS_EC_E_L 0x1d /* PADDR, E-bit, little endian */ -#define ASI_NUCLEUS_QUAD_LDD 0x24 /* Cachable, qword load */ -#define ASI_NUCLEUS_QUAD_LDD_L 0x2c /* Cachable, qword load, little endian */ -#define ASI_PCACHE_DATA_STATUS 0x30 /* (III) PCache data status RAM diag */ -#define ASI_PCACHE_DATA 0x31 /* (III) PCache data RAM diag */ -#define ASI_PCACHE_TAG 0x32 /* (III) PCache tag RAM diag */ -#define ASI_PCACHE_SNOOP_TAG 0x33 /* (III) PCache snoop tag RAM diag */ -#define ASI_QUAD_LDD_PHYS 0x34 /* (III+) PADDR, qword load */ -#define ASI_WCACHE_VALID_BITS 0x38 /* (III) WCache Valid Bits diag */ -#define ASI_WCACHE_DATA 0x39 /* (III) WCache data RAM diag */ -#define ASI_WCACHE_TAG 0x3a /* (III) WCache tag RAM diag */ -#define ASI_WCACHE_SNOOP_TAG 0x3b /* (III) WCache snoop tag RAM diag */ -#define ASI_QUAD_LDD_PHYS_L 0x3c /* (III+) PADDR, qword load, little endian */ -#define ASI_SRAM_FAST_INIT 0x40 /* (III+) Fast SRAM init */ -#define ASI_DCACHE_INVALIDATE 0x42 /* (III) DCache Invalidate diag */ -#define ASI_DCACHE_UTAG 0x43 /* (III) DCache uTag diag */ -#define ASI_DCACHE_SNOOP_TAG 0x44 /* (III) DCache snoop tag RAM diag */ -#define ASI_LSU_CONTROL 0x45 /* Load-store control unit */ -#define ASI_DCU_CONTROL_REG 0x45 /* (III) DCache Unit Control Register */ -#define ASI_DCACHE_DATA 0x46 /* Data cache data-ram diag access */ -#define ASI_DCACHE_TAG 0x47 /* Data cache tag/valid ram diag access */ -#define ASI_INTR_DISPATCH_STAT 0x48 /* IRQ vector dispatch status */ -#define ASI_INTR_RECEIVE 0x49 /* IRQ vector receive status */ -#define ASI_UPA_CONFIG 0x4a /* UPA config space */ -#define ASI_JBUS_CONFIG 0x4a /* (IIIi) JBUS Config Register */ -#define ASI_SAFARI_CONFIG 0x4a /* (III) Safari Config Register */ -#define ASI_SAFARI_ADDRESS 0x4a /* (III) Safari Address Register */ -#define ASI_ESTATE_ERROR_EN 0x4b /* E-cache error enable space */ -#define ASI_AFSR 0x4c /* Async fault status register */ -#define ASI_AFAR 0x4d /* Async fault address register */ -#define ASI_EC_TAG_DATA 0x4e /* E-cache tag/valid ram diag access */ -#define ASI_IMMU 0x50 /* Insn-MMU main register space */ -#define ASI_IMMU_TSB_8KB_PTR 0x51 /* Insn-MMU 8KB TSB pointer register */ -#define ASI_IMMU_TSB_64KB_PTR 0x52 /* Insn-MMU 64KB TSB pointer register */ -#define ASI_ITLB_DATA_IN 0x54 /* Insn-MMU TLB data in register */ -#define ASI_ITLB_DATA_ACCESS 0x55 /* Insn-MMU TLB data access register */ -#define ASI_ITLB_TAG_READ 0x56 /* Insn-MMU TLB tag read register */ -#define ASI_IMMU_DEMAP 0x57 /* Insn-MMU TLB demap */ -#define ASI_DMMU 0x58 /* Data-MMU main register space */ -#define ASI_DMMU_TSB_8KB_PTR 0x59 /* Data-MMU 8KB TSB pointer register */ -#define ASI_DMMU_TSB_64KB_PTR 0x5a /* Data-MMU 16KB TSB pointer register */ -#define ASI_DMMU_TSB_DIRECT_PTR 0x5b /* Data-MMU TSB direct pointer register */ -#define ASI_DTLB_DATA_IN 0x5c /* Data-MMU TLB data in register */ -#define ASI_DTLB_DATA_ACCESS 0x5d /* Data-MMU TLB data access register */ -#define ASI_DTLB_TAG_READ 0x5e /* Data-MMU TLB tag read register */ -#define ASI_DMMU_DEMAP 0x5f /* Data-MMU TLB demap */ -#define ASI_IIU_INST_TRAP 0x60 /* (III) Instruction Breakpoint register */ -#define ASI_IC_INSTR 0x66 /* Insn cache instrucion ram diag access */ -#define ASI_IC_TAG 0x67 /* Insn cache tag/valid ram diag access */ -#define ASI_IC_STAG 0x68 /* (III) Insn cache snoop tag ram diag */ -#define ASI_IC_PRE_DECODE 0x6e /* Insn cache pre-decode ram diag access */ -#define ASI_IC_NEXT_FIELD 0x6f /* Insn cache next-field ram diag access */ -#define ASI_BRPRED_ARRAY 0x6f /* (III) Branch Prediction RAM diag */ -#define ASI_BLK_AIUP 0x70 /* Primary, user, block load/store */ -#define ASI_BLK_AIUS 0x71 /* Secondary, user, block load/store */ -#define ASI_MCU_CTRL_REG 0x72 /* (III) Memory controller registers */ -#define ASI_EC_DATA 0x74 /* (III) E-cache data staging register */ -#define ASI_EC_CTRL 0x75 /* (III) E-cache control register */ -#define ASI_EC_W 0x76 /* E-cache diag write access */ -#define ASI_UDB_ERROR_W 0x77 /* External UDB error registers write */ -#define ASI_UDB_CONTROL_W 0x77 /* External UDB control registers write */ -#define ASI_INTR_W 0x77 /* IRQ vector dispatch write */ -#define ASI_INTR_DATAN_W 0x77 /* (III) Outgoing irq vector data reg N */ -#define ASI_INTR_DISPATCH_W 0x77 /* (III) Interrupt vector dispatch */ -#define ASI_BLK_AIUPL 0x78 /* Primary, user, little, blk ld/st */ -#define ASI_BLK_AIUSL 0x79 /* Secondary, user, little, blk ld/st */ -#define ASI_EC_R 0x7e /* E-cache diag read access */ -#define ASI_UDBH_ERROR_R 0x7f /* External UDB error registers read hi */ -#define ASI_UDBL_ERROR_R 0x7f /* External UDB error registers read low */ -#define ASI_UDBH_CONTROL_R 0x7f /* External UDB control registers read hi */ -#define ASI_UDBL_CONTROL_R 0x7f /* External UDB control registers read low */ -#define ASI_INTR_R 0x7f /* IRQ vector dispatch read */ -#define ASI_INTR_DATAN_R 0x7f /* (III) Incoming irq vector data reg N */ -#define ASI_PST8_P 0xc0 /* Primary, 8 8-bit, partial */ -#define ASI_PST8_S 0xc1 /* Secondary, 8 8-bit, partial */ -#define ASI_PST16_P 0xc2 /* Primary, 4 16-bit, partial */ -#define ASI_PST16_S 0xc3 /* Seconary, 4 16-bit, partial */ -#define ASI_PST32_P 0xc4 /* Primary, 2 32-bit, partial */ -#define ASI_PST32_S 0xc5 /* Secondary, 2 32-bit, partial */ -#define ASI_PST8_PL 0xc8 /* Primary, 8 8-bit, partial, little */ -#define ASI_PST8_SL 0xc9 /* Secondary, 8 8-bit, partial, little */ -#define ASI_PST16_PL 0xca /* Primary, 4 16-bit, partial, little */ -#define ASI_PST16_SL 0xcb /* Seconary, 4 16-bit, partial, little */ -#define ASI_PST32_PL 0xcc /* Primary, 2 32-bit, partial, little */ -#define ASI_PST32_SL 0xcd /* Secondary, 2 32-bit, partial, little */ -#define ASI_FL8_P 0xd0 /* Primary, 1 8-bit, fpu ld/st */ -#define ASI_FL8_S 0xd1 /* Secondary, 1 8-bit, fpu ld/st */ -#define ASI_FL16_P 0xd2 /* Primary, 1 16-bit, fpu ld/st */ -#define ASI_FL16_S 0xd3 /* Secondary, 1 16-bit, fpu ld/st */ -#define ASI_FL8_PL 0xd8 /* Primary, 1 8-bit, fpu ld/st, little */ -#define ASI_FL8_SL 0xd9 /* Secondary, 1 8-bit, fpu ld/st, little */ -#define ASI_FL16_PL 0xda /* Primary, 1 16-bit, fpu ld/st, little */ -#define ASI_FL16_SL 0xdb /* Secondary, 1 16-bit, fpu ld/st, little */ -#define ASI_BLK_COMMIT_P 0xe0 /* Primary, blk store commit */ -#define ASI_BLK_COMMIT_S 0xe1 /* Secondary, blk store commit */ -#define ASI_BLK_P 0xf0 /* Primary, blk ld/st */ -#define ASI_BLK_S 0xf1 /* Secondary, blk ld/st */ -#define ASI_BLK_PL 0xf8 /* Primary, blk ld/st, little */ -#define ASI_BLK_SL 0xf9 /* Secondary, blk ld/st, little */ +#define ASI_PHYS_USE_EC 0x14 /* PADDR, E-cachable */ +#define ASI_PHYS_BYPASS_EC_E 0x15 /* PADDR, E-bit */ +#define ASI_PHYS_USE_EC_L 0x1c /* PADDR, E-cachable, little endian*/ +#define ASI_PHYS_BYPASS_EC_E_L 0x1d /* PADDR, E-bit, little endian */ +#define ASI_NUCLEUS_QUAD_LDD 0x24 /* Cachable, qword load */ +#define ASI_NUCLEUS_QUAD_LDD_L 0x2c /* Cachable, qword load, l-endian */ +#define ASI_PCACHE_DATA_STATUS 0x30 /* (III) PCache data stat RAM diag */ +#define ASI_PCACHE_DATA 0x31 /* (III) PCache data RAM diag */ +#define ASI_PCACHE_TAG 0x32 /* (III) PCache tag RAM diag */ +#define ASI_PCACHE_SNOOP_TAG 0x33 /* (III) PCache snoop tag RAM diag */ +#define ASI_QUAD_LDD_PHYS 0x34 /* (III+) PADDR, qword load */ +#define ASI_WCACHE_VALID_BITS 0x38 /* (III) WCache Valid Bits diag */ +#define ASI_WCACHE_DATA 0x39 /* (III) WCache data RAM diag */ +#define ASI_WCACHE_TAG 0x3a /* (III) WCache tag RAM diag */ +#define ASI_WCACHE_SNOOP_TAG 0x3b /* (III) WCache snoop tag RAM diag */ +#define ASI_QUAD_LDD_PHYS_L 0x3c /* (III+) PADDR, qw-load, l-endian */ +#define ASI_SRAM_FAST_INIT 0x40 /* (III+) Fast SRAM init */ +#define ASI_CORE_AVAILABLE 0x41 /* (CMT) LP Available */ +#define ASI_CORE_ENABLE_STAT 0x41 /* (CMT) LP Enable Status */ +#define ASI_CORE_ENABLE 0x41 /* (CMT) LP Enable RW */ +#define ASI_XIR_STEERING 0x41 /* (CMT) XIR Steering RW */ +#define ASI_CORE_RUNNING_RW 0x41 /* (CMT) LP Running RW */ +#define ASI_CORE_RUNNING_W1S 0x41 /* (CMT) LP Running Write-One Set */ +#define ASI_CORE_RUNNING_W1C 0x41 /* (CMT) LP Running Write-One Clr */ +#define ASI_CORE_RUNNING_STAT 0x41 /* (CMT) LP Running Status */ +#define ASI_CMT_ERROR_STEERING 0x41 /* (CMT) Error Steering RW */ +#define ASI_DCACHE_INVALIDATE 0x42 /* (III) DCache Invalidate diag */ +#define ASI_DCACHE_UTAG 0x43 /* (III) DCache uTag diag */ +#define ASI_DCACHE_SNOOP_TAG 0x44 /* (III) DCache snoop tag RAM diag */ +#define ASI_LSU_CONTROL 0x45 /* Load-store control unit */ +#define ASI_DCU_CONTROL_REG 0x45 /* (III) DCache Unit Control reg */ +#define ASI_DCACHE_DATA 0x46 /* DCache data-ram diag access */ +#define ASI_DCACHE_TAG 0x47 /* Dcache tag/valid ram diag access*/ +#define ASI_INTR_DISPATCH_STAT 0x48 /* IRQ vector dispatch status */ +#define ASI_INTR_RECEIVE 0x49 /* IRQ vector receive status */ +#define ASI_UPA_CONFIG 0x4a /* UPA config space */ +#define ASI_JBUS_CONFIG 0x4a /* (IIIi) JBUS Config Register */ +#define ASI_SAFARI_CONFIG 0x4a /* (III) Safari Config Register */ +#define ASI_SAFARI_ADDRESS 0x4a /* (III) Safari Address Register */ +#define ASI_ESTATE_ERROR_EN 0x4b /* E-cache error enable space */ +#define ASI_AFSR 0x4c /* Async fault status register */ +#define ASI_AFAR 0x4d /* Async fault address register */ +#define ASI_EC_TAG_DATA 0x4e /* E-cache tag/valid ram diag acc */ +#define ASI_IMMU 0x50 /* Insn-MMU main register space */ +#define ASI_IMMU_TSB_8KB_PTR 0x51 /* Insn-MMU 8KB TSB pointer reg */ +#define ASI_IMMU_TSB_64KB_PTR 0x52 /* Insn-MMU 64KB TSB pointer reg */ +#define ASI_ITLB_DATA_IN 0x54 /* Insn-MMU TLB data in reg */ +#define ASI_ITLB_DATA_ACCESS 0x55 /* Insn-MMU TLB data access reg */ +#define ASI_ITLB_TAG_READ 0x56 /* Insn-MMU TLB tag read reg */ +#define ASI_IMMU_DEMAP 0x57 /* Insn-MMU TLB demap */ +#define ASI_DMMU 0x58 /* Data-MMU main register space */ +#define ASI_DMMU_TSB_8KB_PTR 0x59 /* Data-MMU 8KB TSB pointer reg */ +#define ASI_DMMU_TSB_64KB_PTR 0x5a /* Data-MMU 16KB TSB pointer reg */ +#define ASI_DMMU_TSB_DIRECT_PTR 0x5b /* Data-MMU TSB direct pointer reg */ +#define ASI_DTLB_DATA_IN 0x5c /* Data-MMU TLB data in reg */ +#define ASI_DTLB_DATA_ACCESS 0x5d /* Data-MMU TLB data access reg */ +#define ASI_DTLB_TAG_READ 0x5e /* Data-MMU TLB tag read reg */ +#define ASI_DMMU_DEMAP 0x5f /* Data-MMU TLB demap */ +#define ASI_IIU_INST_TRAP 0x60 /* (III) Instruction Breakpoint */ +#define ASI_INTR_ID 0x63 /* (CMT) Interrupt ID register */ +#define ASI_CORE_ID 0x63 /* (CMT) LP ID register */ +#define ASI_CESR_ID 0x63 /* (CMT) CESR ID register */ +#define ASI_IC_INSTR 0x66 /* Insn cache instrucion ram diag */ +#define ASI_IC_TAG 0x67 /* Insn cache tag/valid ram diag */ +#define ASI_IC_STAG 0x68 /* (III) Insn cache snoop tag ram */ +#define ASI_IC_PRE_DECODE 0x6e /* Insn cache pre-decode ram diag */ +#define ASI_IC_NEXT_FIELD 0x6f /* Insn cache next-field ram diag */ +#define ASI_BRPRED_ARRAY 0x6f /* (III) Branch Prediction RAM diag*/ +#define ASI_BLK_AIUP 0x70 /* Primary, user, block load/store */ +#define ASI_BLK_AIUS 0x71 /* Secondary, user, block ld/st */ +#define ASI_MCU_CTRL_REG 0x72 /* (III) Memory controller regs */ +#define ASI_EC_DATA 0x74 /* (III) E-cache data staging reg */ +#define ASI_EC_CTRL 0x75 /* (III) E-cache control reg */ +#define ASI_EC_W 0x76 /* E-cache diag write access */ +#define ASI_UDB_ERROR_W 0x77 /* External UDB error regs W */ +#define ASI_UDB_CONTROL_W 0x77 /* External UDB control regs W */ +#define ASI_INTR_W 0x77 /* IRQ vector dispatch write */ +#define ASI_INTR_DATAN_W 0x77 /* (III) Out irq vector data reg N */ +#define ASI_INTR_DISPATCH_W 0x77 /* (III) Interrupt vector dispatch */ +#define ASI_BLK_AIUPL 0x78 /* Primary, user, little, blk ld/st*/ +#define ASI_BLK_AIUSL 0x79 /* Secondary, user, little, blk ld/st*/ +#define ASI_EC_R 0x7e /* E-cache diag read access */ +#define ASI_UDBH_ERROR_R 0x7f /* External UDB error regs rd hi */ +#define ASI_UDBL_ERROR_R 0x7f /* External UDB error regs rd low */ +#define ASI_UDBH_CONTROL_R 0x7f /* External UDB control regs rd hi */ +#define ASI_UDBL_CONTROL_R 0x7f /* External UDB control regs rd low*/ +#define ASI_INTR_R 0x7f /* IRQ vector dispatch read */ +#define ASI_INTR_DATAN_R 0x7f /* (III) In irq vector data reg N */ +#define ASI_PST8_P 0xc0 /* Primary, 8 8-bit, partial */ +#define ASI_PST8_S 0xc1 /* Secondary, 8 8-bit, partial */ +#define ASI_PST16_P 0xc2 /* Primary, 4 16-bit, partial */ +#define ASI_PST16_S 0xc3 /* Secondary, 4 16-bit, partial */ +#define ASI_PST32_P 0xc4 /* Primary, 2 32-bit, partial */ +#define ASI_PST32_S 0xc5 /* Secondary, 2 32-bit, partial */ +#define ASI_PST8_PL 0xc8 /* Primary, 8 8-bit, partial, L */ +#define ASI_PST8_SL 0xc9 /* Secondary, 8 8-bit, partial, L */ +#define ASI_PST16_PL 0xca /* Primary, 4 16-bit, partial, L */ +#define ASI_PST16_SL 0xcb /* Secondary, 4 16-bit, partial, L */ +#define ASI_PST32_PL 0xcc /* Primary, 2 32-bit, partial, L */ +#define ASI_PST32_SL 0xcd /* Secondary, 2 32-bit, partial, L */ +#define ASI_FL8_P 0xd0 /* Primary, 1 8-bit, fpu ld/st */ +#define ASI_FL8_S 0xd1 /* Secondary, 1 8-bit, fpu ld/st */ +#define ASI_FL16_P 0xd2 /* Primary, 1 16-bit, fpu ld/st */ +#define ASI_FL16_S 0xd3 /* Secondary, 1 16-bit, fpu ld/st */ +#define ASI_FL8_PL 0xd8 /* Primary, 1 8-bit, fpu ld/st, L */ +#define ASI_FL8_SL 0xd9 /* Secondary, 1 8-bit, fpu ld/st, L*/ +#define ASI_FL16_PL 0xda /* Primary, 1 16-bit, fpu ld/st, L */ +#define ASI_FL16_SL 0xdb /* Secondary, 1 16-bit, fpu ld/st,L*/ +#define ASI_BLK_COMMIT_P 0xe0 /* Primary, blk store commit */ +#define ASI_BLK_COMMIT_S 0xe1 /* Secondary, blk store commit */ +#define ASI_BLK_P 0xf0 /* Primary, blk ld/st */ +#define ASI_BLK_S 0xf1 /* Secondary, blk ld/st */ +#define ASI_BLK_PL 0xf8 /* Primary, blk ld/st, little */ +#define ASI_BLK_SL 0xf9 /* Secondary, blk ld/st, little */ #endif /* _SPARC64_ASI_H */ diff -Nru a/include/asm-sparc64/cmt.h b/include/asm-sparc64/cmt.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/include/asm-sparc64/cmt.h 2004-08-14 12:02:31 -07:00 @@ -0,0 +1,59 @@ +#ifndef _SPARC64_CMT_H +#define _SPARC64_CMT_H + +/* cmt.h: Chip Multi-Threading register definitions + * + * Copyright (C) 2004 David S. Miller (davem@redhat.com) + */ + +/* ASI_CORE_ID - private */ +#define LP_ID 0x0000000000000010UL +#define LP_ID_MAX 0x00000000003f0000UL +#define LP_ID_ID 0x000000000000003fUL + +/* ASI_INTR_ID - private */ +#define LP_INTR_ID 0x0000000000000000UL +#define LP_INTR_ID_ID 0x00000000000003ffUL + +/* ASI_CESR_ID - private */ +#define CESR_ID 0x0000000000000040UL +#define CESR_ID_ID 0x00000000000000ffUL + +/* ASI_CORE_AVAILABLE - shared */ +#define LP_AVAIL 0x0000000000000000UL +#define LP_AVAIL_1 0x0000000000000002UL +#define LP_AVAIL_0 0x0000000000000001UL + +/* ASI_CORE_ENABLE_STATUS - shared */ +#define LP_ENAB_STAT 0x0000000000000010UL +#define LP_ENAB_STAT_1 0x0000000000000002UL +#define LP_ENAB_STAT_0 0x0000000000000001UL + +/* ASI_CORE_ENABLE - shared */ +#define LP_ENAB 0x0000000000000020UL +#define LP_ENAB_1 0x0000000000000002UL +#define LP_ENAB_0 0x0000000000000001UL + +/* ASI_CORE_RUNNING - shared */ +#define LP_RUNNING_RW 0x0000000000000050UL +#define LP_RUNNING_W1S 0x0000000000000060UL +#define LP_RUNNING_W1C 0x0000000000000068UL +#define LP_RUNNING_1 0x0000000000000002UL +#define LP_RUNNING_0 0x0000000000000001UL + +/* ASI_CORE_RUNNING_STAT - shared */ +#define LP_RUN_STAT 0x0000000000000058UL +#define LP_RUN_STAT_1 0x0000000000000002UL +#define LP_RUN_STAT_0 0x0000000000000001UL + +/* ASI_XIR_STEERING - shared */ +#define LP_XIR_STEER 0x0000000000000030UL +#define LP_XIR_STEER_1 0x0000000000000002UL +#define LP_XIR_STEER_0 0x0000000000000001UL + +/* ASI_CMT_ERROR_STEERING - shared */ +#define CMT_ER_STEER 0x0000000000000040UL +#define CMT_ER_STEER_1 0x0000000000000002UL +#define CMT_ER_STEER_0 0x0000000000000001UL + +#endif /* _SPARC64_CMT_H */ diff -Nru a/include/asm-sparc64/page.h b/include/asm-sparc64/page.h --- a/include/asm-sparc64/page.h 2004-08-14 12:02:30 -07:00 +++ b/include/asm-sparc64/page.h 2004-08-14 12:02:30 -07:00 @@ -36,7 +36,7 @@ extern void _clear_page(void *page); #define clear_page(X) _clear_page((void *)(X)) extern void clear_user_page(void *page, unsigned long vaddr); -#define copy_page(X,Y) __memcpy((void *)(X), (void *)(Y), PAGE_SIZE) +#define copy_page(X,Y) memcpy((void *)(X), (void *)(Y), PAGE_SIZE) extern void copy_user_page(void *to, void *from, unsigned long vaddr); /* GROSS, defining this makes gcc pass these types as aggregates, diff -Nru a/include/asm-sparc64/pgtable.h b/include/asm-sparc64/pgtable.h --- a/include/asm-sparc64/pgtable.h 2004-08-14 12:02:30 -07:00 +++ b/include/asm-sparc64/pgtable.h 2004-08-14 12:02:30 -07:00 @@ -101,32 +101,36 @@ #endif /* !(__ASSEMBLY__) */ /* Spitfire/Cheetah TTE bits. */ -#define _PAGE_VALID 0x8000000000000000 /* Valid TTE */ -#define _PAGE_R 0x8000000000000000 /* Used to keep ref bit up to date */ -#define _PAGE_SZ4MB 0x6000000000000000 /* 4MB Page */ -#define _PAGE_SZ512K 0x4000000000000000 /* 512K Page */ -#define _PAGE_SZ64K 0x2000000000000000 /* 64K Page */ -#define _PAGE_SZ8K 0x0000000000000000 /* 8K Page */ -#define _PAGE_NFO 0x1000000000000000 /* No Fault Only */ -#define _PAGE_IE 0x0800000000000000 /* Invert Endianness */ -#define _PAGE_SN 0x0000800000000000 /* (Cheetah) Snoop */ -#define _PAGE_PADDR_SF 0x000001FFFFFFE000 /* (Spitfire) Phys Address [40:13] */ -#define _PAGE_PADDR 0x000007FFFFFFE000 /* (Cheetah) Phys Address [42:13] */ -#define _PAGE_SOFT 0x0000000000001F80 /* Software bits */ -#define _PAGE_L 0x0000000000000040 /* Locked TTE */ -#define _PAGE_CP 0x0000000000000020 /* Cacheable in Physical Cache */ -#define _PAGE_CV 0x0000000000000010 /* Cacheable in Virtual Cache */ -#define _PAGE_E 0x0000000000000008 /* side-Effect */ -#define _PAGE_P 0x0000000000000004 /* Privileged Page */ -#define _PAGE_W 0x0000000000000002 /* Writable */ -#define _PAGE_G 0x0000000000000001 /* Global */ +#define _PAGE_VALID 0x8000000000000000 /* Valid TTE */ +#define _PAGE_R 0x8000000000000000 /* Keep ref bit up to date */ +#define _PAGE_SZ4MB 0x6000000000000000 /* 4MB Page */ +#define _PAGE_SZ512K 0x4000000000000000 /* 512K Page */ +#define _PAGE_SZ64K 0x2000000000000000 /* 64K Page */ +#define _PAGE_SZ8K 0x0000000000000000 /* 8K Page */ +#define _PAGE_NFO 0x1000000000000000 /* No Fault Only */ +#define _PAGE_IE 0x0800000000000000 /* Invert Endianness */ +#define _PAGE_SOFT2 0x07FC000000000000 /* Software bits, set 2 */ +#define _PAGE_RES1 0x0003000000000000 /* Reserved */ +#define _PAGE_SN 0x0000800000000000 /* (Cheetah) Snoop */ +#define _PAGE_RES2 0x0000780000000000 /* Reserved */ +#define _PAGE_PADDR_SF 0x000001FFFFFFE000 /* (Spitfire) paddr[40:13] */ +#define _PAGE_PADDR 0x000007FFFFFFE000 /* (Cheetah) paddr[42:13] */ +#define _PAGE_SOFT 0x0000000000001F80 /* Software bits */ +#define _PAGE_L 0x0000000000000040 /* Locked TTE */ +#define _PAGE_CP 0x0000000000000020 /* Cacheable in P-Cache */ +#define _PAGE_CV 0x0000000000000010 /* Cacheable in V-Cache */ +#define _PAGE_E 0x0000000000000008 /* side-Effect */ +#define _PAGE_P 0x0000000000000004 /* Privileged Page */ +#define _PAGE_W 0x0000000000000002 /* Writable */ +#define _PAGE_G 0x0000000000000001 /* Global */ /* Here are the SpitFire software bits we use in the TTE's. */ -#define _PAGE_MODIFIED 0x0000000000000800 /* Modified Page (ie. dirty) */ -#define _PAGE_ACCESSED 0x0000000000000400 /* Accessed Page (ie. referenced) */ -#define _PAGE_READ 0x0000000000000200 /* Readable SW Bit */ -#define _PAGE_WRITE 0x0000000000000100 /* Writable SW Bit */ -#define _PAGE_PRESENT 0x0000000000000080 /* Present Page (ie. not swapped out) */ +#define _PAGE_EXEC 0x0000000000001000 /* Executable SW bit */ +#define _PAGE_MODIFIED 0x0000000000000800 /* Modified Page (ie. dirty) */ +#define _PAGE_ACCESSED 0x0000000000000400 /* Accessed Page (ie. ref'd) */ +#define _PAGE_READ 0x0000000000000200 /* Readable SW Bit */ +#define _PAGE_WRITE 0x0000000000000100 /* Writable SW Bit */ +#define _PAGE_PRESENT 0x0000000000000080 /* Present */ #if PAGE_SHIFT == 13 #define _PAGE_SZBITS _PAGE_SZ8K @@ -150,16 +154,27 @@ /* Don't set the TTE _PAGE_W bit here, else the dirty bit never gets set. */ #define PAGE_SHARED __pgprot (_PAGE_PRESENT | _PAGE_VALID | _PAGE_CACHE | \ - __ACCESS_BITS | _PAGE_WRITE) + __ACCESS_BITS | _PAGE_WRITE | _PAGE_EXEC) #define PAGE_COPY __pgprot (_PAGE_PRESENT | _PAGE_VALID | _PAGE_CACHE | \ - __ACCESS_BITS) + __ACCESS_BITS | _PAGE_EXEC) #define PAGE_READONLY __pgprot (_PAGE_PRESENT | _PAGE_VALID | _PAGE_CACHE | \ - __ACCESS_BITS) + __ACCESS_BITS | _PAGE_EXEC) #define PAGE_KERNEL __pgprot (_PAGE_PRESENT | _PAGE_VALID | _PAGE_CACHE | \ - __PRIV_BITS | __ACCESS_BITS | __DIRTY_BITS) + __PRIV_BITS | \ + __ACCESS_BITS | __DIRTY_BITS | _PAGE_EXEC) + +#define PAGE_SHARED_NOEXEC __pgprot (_PAGE_PRESENT | _PAGE_VALID | \ + _PAGE_CACHE | \ + __ACCESS_BITS | _PAGE_WRITE) + +#define PAGE_COPY_NOEXEC __pgprot (_PAGE_PRESENT | _PAGE_VALID | \ + _PAGE_CACHE | __ACCESS_BITS) + +#define PAGE_READONLY_NOEXEC __pgprot (_PAGE_PRESENT | _PAGE_VALID | \ + _PAGE_CACHE | __ACCESS_BITS) #define PAGE_INVALID __pgprot (0) @@ -170,18 +185,18 @@ #define pg_iobits (_PAGE_VALID | _PAGE_PRESENT | __DIRTY_BITS | __ACCESS_BITS | _PAGE_E) #define __P000 PAGE_NONE -#define __P001 PAGE_READONLY -#define __P010 PAGE_COPY -#define __P011 PAGE_COPY +#define __P001 PAGE_READONLY_NOEXEC +#define __P010 PAGE_COPY_NOEXEC +#define __P011 PAGE_COPY_NOEXEC #define __P100 PAGE_READONLY #define __P101 PAGE_READONLY #define __P110 PAGE_COPY #define __P111 PAGE_COPY #define __S000 PAGE_NONE -#define __S001 PAGE_READONLY -#define __S010 PAGE_SHARED -#define __S011 PAGE_SHARED +#define __S001 PAGE_READONLY_NOEXEC +#define __S010 PAGE_SHARED_NOEXEC +#define __S011 PAGE_SHARED_NOEXEC #define __S100 PAGE_READONLY #define __S101 PAGE_READONLY #define __S110 PAGE_SHARED diff -Nru a/include/asm-sparc64/string.h b/include/asm-sparc64/string.h --- a/include/asm-sparc64/string.h 2004-08-14 12:02:30 -07:00 +++ b/include/asm-sparc64/string.h 2004-08-14 12:02:30 -07:00 @@ -16,9 +16,7 @@ #include extern void __memmove(void *,const void *,__kernel_size_t); -extern __kernel_size_t __memcpy(void *,const void *,__kernel_size_t); extern void *__memset(void *,int,__kernel_size_t); -extern void *__builtin_memcpy(void *,const void *,__kernel_size_t); extern void *__builtin_memset(void *,int,__kernel_size_t); #ifndef EXPORT_SYMTAB_STROPS @@ -37,29 +35,7 @@ #define __HAVE_ARCH_MEMCPY -static inline void *__constant_memcpy(void *to, const void *from, __kernel_size_t n) -{ - if(n) { - if(n <= 32) { - __builtin_memcpy(to, from, n); - } else { - __memcpy(to, from, n); - } - } - return to; -} - -static inline void *__nonconstant_memcpy(void *to, const void *from, __kernel_size_t n) -{ - __memcpy(to, from, n); - return to; -} - -#undef memcpy -#define memcpy(t, f, n) \ -(__builtin_constant_p(n) ? \ - __constant_memcpy((t),(f),(n)) : \ - __nonconstant_memcpy((t),(f),(n))) +extern void * memcpy(void *,const void *,__kernel_size_t); #define __HAVE_ARCH_MEMSET diff -Nru a/include/linux/ac97_codec.h b/include/linux/ac97_codec.h --- a/include/linux/ac97_codec.h 2004-08-14 12:02:30 -07:00 +++ b/include/linux/ac97_codec.h 2004-08-14 12:02:30 -07:00 @@ -290,6 +290,7 @@ #define AC97_DELUDED_MODEM 1 /* Audio codec reports its a modem */ #define AC97_NO_PCM_VOLUME 2 /* Volume control is missing */ +#define AC97_DEFAULT_POWER_OFF 4 /* Needs warm reset to power up */ }; extern int ac97_read_proc (char *page_out, char **start, off_t off, diff -Nru a/include/linux/agp_backend.h b/include/linux/agp_backend.h --- a/include/linux/agp_backend.h 2004-08-14 12:02:30 -07:00 +++ b/include/linux/agp_backend.h 2004-08-14 12:02:30 -07:00 @@ -55,6 +55,7 @@ INTEL_I855_PM, INTEL_I860, INTEL_I865_G, + INTEL_I915_G, INTEL_I7205, INTEL_I7505, INTEL_460GX, diff -Nru a/include/linux/ata.h b/include/linux/ata.h --- a/include/linux/ata.h 2004-08-14 12:02:30 -07:00 +++ b/include/linux/ata.h 2004-08-14 12:02:30 -07:00 @@ -42,6 +42,7 @@ ATA_ID_SERNO_OFS = 10, ATA_ID_MAJOR_VER = 80, ATA_ID_PIO_MODES = 64, + ATA_ID_MWDMA_MODES = 63, ATA_ID_UDMA_MODES = 88, ATA_ID_PIO4 = (1 << 1), @@ -78,9 +79,11 @@ ATA_NIEN = (1 << 1), /* disable-irq flag */ ATA_LBA = (1 << 6), /* LBA28 selector */ ATA_DEV1 = (1 << 4), /* Select Device 1 (slave) */ - ATA_BUSY = (1 << 7), /* BSY status bit */ ATA_DEVICE_OBS = (1 << 7) | (1 << 5), /* obs bits in dev reg */ ATA_DEVCTL_OBS = (1 << 3), /* obsolete bit in devctl reg */ + ATA_BUSY = (1 << 7), /* BSY status bit */ + ATA_DRDY = (1 << 6), /* device ready */ + ATA_DF = (1 << 5), /* device fault */ ATA_DRQ = (1 << 3), /* data request i/o */ ATA_ERR = (1 << 0), /* have an error */ ATA_SRST = (1 << 2), /* software reset */ @@ -131,13 +134,20 @@ XFER_UDMA_2 = 0x42, XFER_UDMA_1 = 0x41, XFER_UDMA_0 = 0x40, + XFER_MW_DMA_2 = 0x22, + XFER_MW_DMA_1 = 0x21, + XFER_MW_DMA_0 = 0x20, XFER_PIO_4 = 0x0C, XFER_PIO_3 = 0x0B, + XFER_PIO_2 = 0x0A, + XFER_PIO_1 = 0x09, + XFER_PIO_0 = 0x08, /* ATAPI stuff */ ATAPI_PKT_DMA = (1 << 0), ATAPI_DMADIR = (1 << 2), /* ATAPI data dir: 0=to device, 1=to host */ + ATAPI_CDB_LEN = 16, /* cable types */ ATA_CBL_NONE = 0, @@ -167,7 +177,8 @@ ATA_PROT_PIO, /* PIO single sector */ ATA_PROT_PIO_MULT, /* PIO multiple sector */ ATA_PROT_DMA, /* DMA */ - ATA_PROT_ATAPI, /* packet command */ + ATA_PROT_ATAPI, /* packet command, PIO data xfer*/ + ATA_PROT_ATAPI_NODATA, /* packet command, no data */ ATA_PROT_ATAPI_DMA, /* packet command with special DMA sauce */ }; @@ -207,8 +218,8 @@ #define ata_id_has_lba48(dev) ((dev)->id[83] & (1 << 10)) #define ata_id_has_wcache(dev) ((dev)->id[82] & (1 << 5)) #define ata_id_has_pm(dev) ((dev)->id[82] & (1 << 3)) -#define ata_id_has_lba(dev) ((dev)->id[49] & (1 << 8)) -#define ata_id_has_dma(dev) ((dev)->id[49] & (1 << 9)) +#define ata_id_has_lba(dev) ((dev)->id[49] & (1 << 9)) +#define ata_id_has_dma(dev) ((dev)->id[49] & (1 << 8)) #define ata_id_removeable(dev) ((dev)->id[0] & (1 << 7)) #define ata_id_u32(dev,n) \ (((u32) (dev)->id[(n) + 1] << 16) | ((u32) (dev)->id[(n)])) @@ -218,10 +229,27 @@ ((u64) dev->id[(n) + 1] << 16) | \ ((u64) dev->id[(n) + 0]) ) +static inline int atapi_cdb_len(u16 *dev_id) +{ + u16 tmp = dev_id[0] & 0x3; + switch (tmp) { + case 0: return 12; + case 1: return 16; + default: return -1; + } +} + static inline int is_atapi_taskfile(struct ata_taskfile *tf) { return (tf->protocol == ATA_PROT_ATAPI) || + (tf->protocol == ATA_PROT_ATAPI_NODATA) || (tf->protocol == ATA_PROT_ATAPI_DMA); +} + +static inline int ata_ok(u8 status) +{ + return ((status & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ | ATA_ERR)) + == ATA_DRDY); } #endif /* __LINUX_ATA_H__ */ diff -Nru a/include/linux/in6.h b/include/linux/in6.h --- a/include/linux/in6.h 2004-08-14 12:02:30 -07:00 +++ b/include/linux/in6.h 2004-08-14 12:02:30 -07:00 @@ -3,7 +3,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * * Sources: * IPv6 Program Interfaces for BSD Systems diff -Nru a/include/linux/ipv6_route.h b/include/linux/ipv6_route.h --- a/include/linux/ipv6_route.h 2004-08-14 12:02:30 -07:00 +++ b/include/linux/ipv6_route.h 2004-08-14 12:02:30 -07:00 @@ -2,7 +2,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff -Nru a/include/linux/libata.h b/include/linux/libata.h --- a/include/linux/libata.h 2004-08-14 12:02:30 -07:00 +++ b/include/linux/libata.h 2004-08-14 12:02:30 -07:00 @@ -32,7 +32,6 @@ /* * compile-time options */ -#undef ATA_FORCE_PIO /* do not configure or use DMA */ #undef ATA_DEBUG /* debugging output */ #undef ATA_VERBOSE_DEBUG /* yet more debugging output */ #undef ATA_IRQ_TRAP /* define to ack screaming irqs */ @@ -89,9 +88,7 @@ /* struct ata_device stuff */ ATA_DFLAG_LBA48 = (1 << 0), /* device supports LBA48 */ ATA_DFLAG_PIO = (1 << 1), /* device currently in PIO mode */ - ATA_DFLAG_MASTER = (1 << 2), /* is device 0? */ - ATA_DFLAG_WCACHE = (1 << 3), /* has write cache we can - * (hopefully) flush? */ + ATA_DFLAG_LOCK_SECTORS = (1 << 2), /* don't adjust max_sectors */ ATA_DEV_UNKNOWN = 0, /* unknown device */ ATA_DEV_ATA = 1, /* ATA device */ @@ -111,8 +108,9 @@ ATA_FLAG_SATA_RESET = (1 << 7), /* use COMRESET */ ATA_QCFLAG_ACTIVE = (1 << 1), /* cmd not yet ack'd to scsi lyer */ - ATA_QCFLAG_DMA = (1 << 2), /* data delivered via DMA */ - ATA_QCFLAG_SG = (1 << 4), /* have s/g table? */ + ATA_QCFLAG_SG = (1 << 3), /* have s/g table? */ + ATA_QCFLAG_SINGLE = (1 << 4), /* no s/g, just a single buffer */ + ATA_QCFLAG_DMAMAP = ATA_QCFLAG_SG | ATA_QCFLAG_SINGLE, /* various lengths of time */ ATA_TMOUT_EDD = 5 * HZ, /* hueristic */ @@ -134,24 +132,17 @@ BUS_IDENTIFY = 8, BUS_PACKET = 9, - /* thread states */ - THR_UNKNOWN = 0, - THR_PORT_RESET = (THR_UNKNOWN + 1), - THR_AWAIT_DEATH = (THR_PORT_RESET + 1), - THR_PROBE_FAILED = (THR_AWAIT_DEATH + 1), - THR_IDLE = (THR_PROBE_FAILED + 1), - THR_PROBE_SUCCESS = (THR_IDLE + 1), - THR_PROBE_START = (THR_PROBE_SUCCESS + 1), - /* SATA port states */ PORT_UNKNOWN = 0, PORT_ENABLED = 1, PORT_DISABLED = 2, - /* ata_qc_cb_t flags - note uses above ATA_QCFLAG_xxx namespace, - * but not numberspace + /* encoding various smaller bitmaps into a single + * unsigned long bitmap */ - ATA_QCFLAG_TIMEOUT = (1 << 0), + ATA_SHIFT_UDMA = 0, + ATA_SHIFT_MWDMA = 8, + ATA_SHIFT_PIO = 11, }; enum pio_task_states { @@ -171,7 +162,7 @@ struct ata_queued_cmd; /* typedefs */ -typedef void (*ata_qc_cb_t) (struct ata_queued_cmd *qc, unsigned int flags); +typedef int (*ata_qc_cb_t) (struct ata_queued_cmd *qc, u8 drv_stat); struct ata_ioports { unsigned long cmd_addr; @@ -199,6 +190,7 @@ struct ata_ioports port[ATA_MAX_PORTS]; unsigned int n_ports; unsigned int pio_mask; + unsigned int mwdma_mask; unsigned int udma_mask; unsigned int legacy_mode; unsigned long irq; @@ -215,6 +207,7 @@ void *mmio_base; unsigned int n_ports; void *private_data; + struct ata_port_operations *ops; struct ata_port * ports[0]; }; @@ -225,19 +218,26 @@ struct scsi_cmnd *scsicmd; void (*scsidone)(struct scsi_cmnd *); + struct ata_taskfile tf; + u8 cdb[ATAPI_CDB_LEN]; + unsigned long flags; /* ATA_QCFLAG_xxx */ unsigned int tag; unsigned int n_elem; + + int pci_dma_dir; + unsigned int nsect; unsigned int cursect; unsigned int cursg; unsigned int cursg_ofs; - struct ata_taskfile tf; + struct scatterlist sgent; + void *buf_virt; struct scatterlist *sg; - ata_qc_cb_t callback; + ata_qc_cb_t complete_fn; struct completion *waiting; @@ -256,8 +256,10 @@ unsigned int class; /* ATA_DEV_xxx */ unsigned int devno; /* 0 or 1 */ u16 id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */ - unsigned int pio_mode; - unsigned int udma_mode; + u8 pio_mode; + u8 dma_mode; + u8 xfer_mode; + unsigned int xfer_shift; /* ATA_SHIFT_xxx */ /* cache info about current transfer mode */ u8 xfer_protocol; /* taskfile xfer protocol */ @@ -282,8 +284,10 @@ unsigned int bus_state; unsigned int port_state; unsigned int pio_mask; + unsigned int mwdma_mask; unsigned int udma_mask; unsigned int cbl; /* cable type; ATA_CBL_xxx */ + unsigned int cdb_len; struct ata_device device[ATA_MAX_DEVICES]; @@ -294,18 +298,12 @@ struct ata_host_stats stats; struct ata_host_set *host_set; - struct semaphore probe_sem; - - unsigned int thr_state; - struct tq_struct packet_task; struct tq_struct pio_task; unsigned int pio_task_state; unsigned long pio_task_timeout; - struct tq_struct probe_task; - void *private_data; }; @@ -314,10 +312,8 @@ void (*dev_config) (struct ata_port *, struct ata_device *); - void (*set_piomode) (struct ata_port *, struct ata_device *, - unsigned int); - void (*set_udmamode) (struct ata_port *, struct ata_device *, - unsigned int); + void (*set_piomode) (struct ata_port *, struct ata_device *); + void (*set_dmamode) (struct ata_port *, struct ata_device *); void (*tf_load) (struct ata_port *ap, struct ata_taskfile *tf); void (*tf_read) (struct ata_port *ap, struct ata_taskfile *tf); @@ -330,10 +326,14 @@ void (*bmdma_setup) (struct ata_queued_cmd *qc); void (*bmdma_start) (struct ata_queued_cmd *qc); - void (*fill_sg) (struct ata_queued_cmd *qc); + + void (*qc_prep) (struct ata_queued_cmd *qc); + int (*qc_issue) (struct ata_queued_cmd *qc); + void (*eng_timeout) (struct ata_port *ap); irqreturn_t (*irq_handler)(int, void *, struct pt_regs *); + void (*irq_clear) (struct ata_port *); u32 (*scr_read) (struct ata_port *ap, unsigned int sc_reg); void (*scr_write) (struct ata_port *ap, unsigned int sc_reg, @@ -349,6 +349,7 @@ Scsi_Host_Template *sht; unsigned long host_flags; unsigned long pio_mask; + unsigned long mwdma_mask; unsigned long udma_mask; struct ata_port_operations *port_ops; }; @@ -390,18 +391,25 @@ extern int ata_port_start (struct ata_port *ap); extern void ata_port_stop (struct ata_port *ap); extern irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs); -extern void ata_fill_sg(struct ata_queued_cmd *qc); +extern void ata_qc_prep(struct ata_queued_cmd *qc); +extern int ata_qc_issue_prot(struct ata_queued_cmd *qc); +extern void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, + unsigned int buflen); +extern void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg, + unsigned int n_elem); extern void ata_dev_id_string(struct ata_device *dev, unsigned char *s, unsigned int ofs, unsigned int len); extern void ata_bmdma_setup_mmio (struct ata_queued_cmd *qc); extern void ata_bmdma_start_mmio (struct ata_queued_cmd *qc); extern void ata_bmdma_setup_pio (struct ata_queued_cmd *qc); extern void ata_bmdma_start_pio (struct ata_queued_cmd *qc); +extern void ata_bmdma_irq_clear(struct ata_port *ap); extern int pci_test_config_bits(struct pci_dev *pdev, struct pci_bits *bits); extern void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat); extern void ata_eng_timeout(struct ata_port *ap); extern void ata_add_to_probe_list (struct ata_probe_ent *probe_ent); extern int ata_std_bios_param(Disk * disk, kdev_t dev, int *ip); +extern void libata_msleep(unsigned long msecs); static inline unsigned long msecs_to_jiffies(unsigned long msecs) @@ -476,7 +484,6 @@ static inline void ata_qc_set_polling(struct ata_queued_cmd *qc) { - qc->flags &= ~ATA_QCFLAG_DMA; qc->tf.ctl |= ATA_NIEN; } @@ -502,6 +509,7 @@ static inline u8 ata_irq_on(struct ata_port *ap) { struct ata_ioports *ioaddr = &ap->ioaddr; + u8 tmp; ap->ctl &= ~ATA_NIEN; ap->last_ctl = ap->ctl; @@ -510,7 +518,11 @@ writeb(ap->ctl, ioaddr->ctl_addr); else outb(ap->ctl, ioaddr->ctl_addr); - return ata_wait_idle(ap); + tmp = ata_wait_idle(ap); + + ap->ops->irq_clear(ap); + + return tmp; } static inline u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq) @@ -557,6 +569,46 @@ static inline unsigned int sata_dev_present(struct ata_port *ap) { return ((scr_read(ap, SCR_STATUS) & 0xf) == 0x3) ? 1 : 0; +} + +static inline void ata_bmdma_stop(struct ata_port *ap) +{ + if (ap->flags & ATA_FLAG_MMIO) { + void *mmio = (void *) ap->ioaddr.bmdma_addr; + + /* clear start/stop bit */ + writeb(readb(mmio + ATA_DMA_CMD) & ~ATA_DMA_START, + mmio + ATA_DMA_CMD); + } else { + /* clear start/stop bit */ + outb(inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START, + ap->ioaddr.bmdma_addr + ATA_DMA_CMD); + } + + /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */ + ata_altstatus(ap); /* dummy read */ +} + +static inline void ata_bmdma_ack_irq(struct ata_port *ap) +{ + if (ap->flags & ATA_FLAG_MMIO) { + void *mmio = ((void *) ap->ioaddr.bmdma_addr) + ATA_DMA_STATUS; + writeb(readb(mmio), mmio); + } else { + unsigned long addr = ap->ioaddr.bmdma_addr + ATA_DMA_STATUS; + outb(inb(addr), addr); + } +} + +static inline u8 ata_bmdma_status(struct ata_port *ap) +{ + u8 host_stat; + if (ap->flags & ATA_FLAG_MMIO) { + void *mmio = (void *) ap->ioaddr.bmdma_addr; + host_stat = readb(mmio + ATA_DMA_STATUS); + } else + host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); + return host_stat; } #endif /* __LINUX_LIBATA_H__ */ diff -Nru a/include/net/if_inet6.h b/include/net/if_inet6.h --- a/include/net/if_inet6.h 2004-08-14 12:02:31 -07:00 +++ b/include/net/if_inet6.h 2004-08-14 12:02:31 -07:00 @@ -3,7 +3,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * * * This program is free software; you can redistribute it and/or diff -Nru a/include/net/ip6_fib.h b/include/net/ip6_fib.h --- a/include/net/ip6_fib.h 2004-08-14 12:02:30 -07:00 +++ b/include/net/ip6_fib.h 2004-08-14 12:02:30 -07:00 @@ -2,7 +2,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff -Nru a/include/net/ipv6.h b/include/net/ipv6.h --- a/include/net/ipv6.h 2004-08-14 12:02:30 -07:00 +++ b/include/net/ipv6.h 2004-08-14 12:02:30 -07:00 @@ -2,7 +2,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * * $Id: ipv6.h,v 1.23 2000/12/13 18:31:48 davem Exp $ * diff -Nru a/include/net/neighbour.h b/include/net/neighbour.h --- a/include/net/neighbour.h 2004-08-14 12:02:31 -07:00 +++ b/include/net/neighbour.h 2004-08-14 12:02:31 -07:00 @@ -5,7 +5,7 @@ * Generic neighbour manipulation * * Authors: - * Pedro Roque + * Pedro Roque * Alexey Kuznetsov */ diff -Nru a/include/net/sctp/command.h b/include/net/sctp/command.h --- a/include/net/sctp/command.h 2004-08-14 12:02:30 -07:00 +++ b/include/net/sctp/command.h 2004-08-14 12:02:30 -07:00 @@ -94,6 +94,9 @@ SCTP_CMD_REPORT_FWDTSN, /* Report new cumulative TSN Ack. */ SCTP_CMD_PROCESS_FWDTSN, /* Skips were reported, so process further. */ SCTP_CMD_CLEAR_INIT_TAG, /* Clears association peer's inittag. */ + SCTP_CMD_DEL_NON_PRIMARY, /* Removes non-primary peer transports. */ + SCTP_CMD_T3_RTX_TIMERS_STOP, /* Stops T3-rtx pending timers */ + SCTP_CMD_FORCE_PRIM_RETRAN, /* Forces retrans. over primary path. */ SCTP_CMD_LAST } sctp_verb_t; diff -Nru a/include/net/sctp/constants.h b/include/net/sctp/constants.h --- a/include/net/sctp/constants.h 2004-08-14 12:02:30 -07:00 +++ b/include/net/sctp/constants.h 2004-08-14 12:02:30 -07:00 @@ -175,6 +175,10 @@ SCTP_IERROR_BAD_TAG, SCTP_IERROR_BIG_GAP, SCTP_IERROR_DUP_TSN, + SCTP_IERROR_HIGH_TSN, + SCTP_IERROR_IGNORE_TSN, + SCTP_IERROR_NO_DATA, + SCTP_IERROR_BAD_STREAM, } sctp_ierror_t; diff -Nru a/include/net/sctp/sm.h b/include/net/sctp/sm.h --- a/include/net/sctp/sm.h 2004-08-14 12:02:30 -07:00 +++ b/include/net/sctp/sm.h 2004-08-14 12:02:30 -07:00 @@ -322,6 +322,9 @@ const struct sctp_chunk *chunk, sctp_cmd_seq_t *commands, struct sctp_chunk *err_chunk); +int sctp_eat_data(const struct sctp_association *asoc, + struct sctp_chunk *chunk, + sctp_cmd_seq_t *commands); /* 3rd level prototypes */ __u32 sctp_generate_tag(const struct sctp_endpoint *); diff -Nru a/kernel/panic.c b/kernel/panic.c --- a/kernel/panic.c 2004-08-14 12:02:30 -07:00 +++ b/kernel/panic.c 2004-08-14 12:02:30 -07:00 @@ -59,7 +59,7 @@ bust_spinlocks(1); va_start(args, fmt); - vsprintf(buf, fmt, args); + vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); printk(KERN_EMERG "Kernel panic: %s\n",buf); if (in_interrupt()) diff -Nru a/mm/oom_kill.c b/mm/oom_kill.c --- a/mm/oom_kill.c 2004-08-14 12:02:30 -07:00 +++ b/mm/oom_kill.c 2004-08-14 12:02:30 -07:00 @@ -141,7 +141,7 @@ * CAP_SYS_RAW_IO set, send SIGTERM instead (but it's unlikely that * we select a process with CAP_SYS_RAW_IO set). */ -void oom_kill_task(struct task_struct *p) +static void __oom_kill_task(struct task_struct *p) { printk(KERN_ERR "Out of Memory: Killed process %d (%s).\n", p->pid, p->comm); @@ -161,6 +161,26 @@ } } +static struct mm_struct *oom_kill_task(struct task_struct *p) +{ + struct mm_struct *mm; + + task_lock(p); + mm = p->mm; + if (mm) { + spin_lock(&mmlist_lock); + if (atomic_read(&mm->mm_users)) + atomic_inc(&mm->mm_users); + else + mm = NULL; + spin_unlock(&mmlist_lock); + } + task_unlock(p); + if (mm) + __oom_kill_task(p); + return mm; +} + /** * oom_kill - kill the "best" process when we run out of memory * @@ -172,21 +192,27 @@ static void oom_kill(void) { struct task_struct *p, *q; + struct mm_struct *mm; +retry: read_lock(&tasklist_lock); p = select_bad_process(); /* Found nothing?!?! Either we hang forever, or we panic. */ if (p == NULL) panic("Out of memory and no killable processes...\n"); - + mm = oom_kill_task(p); + if (!mm) { + read_unlock(&tasklist_lock); + goto retry; + } /* kill all processes that share the ->mm (i.e. all threads) */ for_each_task(q) { - if (q->mm == p->mm) - oom_kill_task(q); + if (q->mm == mm) + __oom_kill_task(q); } read_unlock(&tasklist_lock); - + mmput(mm); /* * Make kswapd go out of the way, so "p" has a good chance of * killing itself before someone else gets the chance to ask @@ -263,7 +289,7 @@ spin_lock(&oom_lock); reset: - if (first < now) + if ((long)first - (long)now < 0) first = now; count = 0; diff -Nru a/net/core/neighbour.c b/net/core/neighbour.c --- a/net/core/neighbour.c 2004-08-14 12:02:30 -07:00 +++ b/net/core/neighbour.c 2004-08-14 12:02:30 -07:00 @@ -2,7 +2,7 @@ * Generic address resolution entity * * Authors: - * Pedro Roque + * Pedro Roque * Alexey Kuznetsov * * This program is free software; you can redistribute it and/or diff -Nru a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c --- a/net/ipv6/addrconf.c 2004-08-14 12:02:30 -07:00 +++ b/net/ipv6/addrconf.c 2004-08-14 12:02:30 -07:00 @@ -3,7 +3,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * Alexey Kuznetsov * * $Id: addrconf.c,v 1.69 2001/10/31 21:55:54 davem Exp $ diff -Nru a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c --- a/net/ipv6/af_inet6.c 2004-08-14 12:02:30 -07:00 +++ b/net/ipv6/af_inet6.c 2004-08-14 12:02:30 -07:00 @@ -3,7 +3,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * * Adapted from linux/net/ipv4/af_inet.c * diff -Nru a/net/ipv6/datagram.c b/net/ipv6/datagram.c --- a/net/ipv6/datagram.c 2004-08-14 12:02:30 -07:00 +++ b/net/ipv6/datagram.c 2004-08-14 12:02:30 -07:00 @@ -3,7 +3,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * * $Id: datagram.c,v 1.23 2001/09/01 00:31:50 davem Exp $ * diff -Nru a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c --- a/net/ipv6/exthdrs.c 2004-08-14 12:02:30 -07:00 +++ b/net/ipv6/exthdrs.c 2004-08-14 12:02:30 -07:00 @@ -3,7 +3,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * Andi Kleen * Alexey Kuznetsov * diff -Nru a/net/ipv6/icmp.c b/net/ipv6/icmp.c --- a/net/ipv6/icmp.c 2004-08-14 12:02:30 -07:00 +++ b/net/ipv6/icmp.c 2004-08-14 12:02:30 -07:00 @@ -3,7 +3,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * * $Id: icmp.c,v 1.37 2001/09/18 22:29:10 davem Exp $ * diff -Nru a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c --- a/net/ipv6/ip6_fib.c 2004-08-14 12:02:30 -07:00 +++ b/net/ipv6/ip6_fib.c 2004-08-14 12:02:30 -07:00 @@ -3,7 +3,7 @@ * Forwarding Information Database * * Authors: - * Pedro Roque + * Pedro Roque * * $Id: ip6_fib.c,v 1.25 2001/10/31 21:55:55 davem Exp $ * diff -Nru a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c --- a/net/ipv6/ip6_input.c 2004-08-14 12:02:30 -07:00 +++ b/net/ipv6/ip6_input.c 2004-08-14 12:02:30 -07:00 @@ -3,7 +3,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * Ian P. Morris * * $Id: ip6_input.c,v 1.19 2000/12/13 18:31:50 davem Exp $ diff -Nru a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c --- a/net/ipv6/ip6_output.c 2004-08-14 12:02:30 -07:00 +++ b/net/ipv6/ip6_output.c 2004-08-14 12:02:30 -07:00 @@ -3,7 +3,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * * $Id: ip6_output.c,v 1.33 2001/09/20 00:35:35 davem Exp $ * diff -Nru a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c --- a/net/ipv6/ipv6_sockglue.c 2004-08-14 12:02:30 -07:00 +++ b/net/ipv6/ipv6_sockglue.c 2004-08-14 12:02:30 -07:00 @@ -3,7 +3,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * * Based on linux/net/ipv4/ip_sockglue.c * diff -Nru a/net/ipv6/mcast.c b/net/ipv6/mcast.c --- a/net/ipv6/mcast.c 2004-08-14 12:02:30 -07:00 +++ b/net/ipv6/mcast.c 2004-08-14 12:02:30 -07:00 @@ -3,7 +3,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * * $Id: mcast.c,v 1.38 2001/08/15 07:36:31 davem Exp $ * diff -Nru a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c --- a/net/ipv6/ndisc.c 2004-08-14 12:02:30 -07:00 +++ b/net/ipv6/ndisc.c 2004-08-14 12:02:30 -07:00 @@ -3,7 +3,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * Mike Shaver * * This program is free software; you can redistribute it and/or diff -Nru a/net/ipv6/protocol.c b/net/ipv6/protocol.c --- a/net/ipv6/protocol.c 2004-08-14 12:02:30 -07:00 +++ b/net/ipv6/protocol.c 2004-08-14 12:02:30 -07:00 @@ -7,7 +7,7 @@ * * Version: $Id: protocol.c,v 1.10 2001/05/18 02:25:49 davem Exp $ * - * Authors: Pedro Roque + * Authors: Pedro Roque * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff -Nru a/net/ipv6/raw.c b/net/ipv6/raw.c --- a/net/ipv6/raw.c 2004-08-14 12:02:30 -07:00 +++ b/net/ipv6/raw.c 2004-08-14 12:02:30 -07:00 @@ -3,7 +3,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * * Adapted from linux/net/ipv4/raw.c * diff -Nru a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c --- a/net/ipv6/reassembly.c 2004-08-14 12:02:30 -07:00 +++ b/net/ipv6/reassembly.c 2004-08-14 12:02:30 -07:00 @@ -3,7 +3,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * * $Id: reassembly.c,v 1.26 2001/03/07 22:00:57 davem Exp $ * diff -Nru a/net/ipv6/route.c b/net/ipv6/route.c --- a/net/ipv6/route.c 2004-08-14 12:02:30 -07:00 +++ b/net/ipv6/route.c 2004-08-14 12:02:30 -07:00 @@ -3,7 +3,7 @@ * FIB front-end. * * Authors: - * Pedro Roque + * Pedro Roque * * $Id: route.c,v 1.56 2001/10/31 21:55:55 davem Exp $ * diff -Nru a/net/ipv6/sit.c b/net/ipv6/sit.c --- a/net/ipv6/sit.c 2004-08-14 12:02:30 -07:00 +++ b/net/ipv6/sit.c 2004-08-14 12:02:30 -07:00 @@ -3,7 +3,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * Alexey Kuznetsov * * $Id: sit.c,v 1.53 2001/09/25 05:09:53 davem Exp $ diff -Nru a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c --- a/net/ipv6/tcp_ipv6.c 2004-08-14 12:02:30 -07:00 +++ b/net/ipv6/tcp_ipv6.c 2004-08-14 12:02:30 -07:00 @@ -3,7 +3,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * * $Id: tcp_ipv6.c,v 1.142.2.1 2001/12/21 05:06:08 davem Exp $ * diff -Nru a/net/ipv6/udp.c b/net/ipv6/udp.c --- a/net/ipv6/udp.c 2004-08-14 12:02:30 -07:00 +++ b/net/ipv6/udp.c 2004-08-14 12:02:30 -07:00 @@ -3,7 +3,7 @@ * Linux INET6 implementation * * Authors: - * Pedro Roque + * Pedro Roque * * Based on linux/ipv4/udp.c * diff -Nru a/net/sched/sch_htb.c b/net/sched/sch_htb.c --- a/net/sched/sch_htb.c 2004-08-14 12:02:30 -07:00 +++ b/net/sched/sch_htb.c 2004-08-14 12:02:30 -07:00 @@ -77,7 +77,7 @@ #define HTB_HYSTERESIS 1/* whether to use mode hysteresis for speedup */ #define HTB_QLOCK(S) spin_lock_bh(&(S)->dev->queue_lock) #define HTB_QUNLOCK(S) spin_unlock_bh(&(S)->dev->queue_lock) -#define HTB_VER 0x30010 /* major must be matched with number suplied by TC as version */ +#define HTB_VER 0x30011 /* major must be matched with number suplied by TC as version */ #if HTB_VER >> 16 != TC_HTB_PROTOVER #error "Mismatched sch_htb.c and pkt_sch.h" @@ -172,6 +172,11 @@ struct htb_class_inner { rb_root_t feed[TC_HTB_NUMPRIO]; /* feed trees */ rb_node_t *ptr[TC_HTB_NUMPRIO]; /* current class ptr */ + /* When class changes from state 1->2 and disconnects from + parent's feed then we lost ptr value and start from the + first child again. Here we store classid of the + last valid ptr (used when ptr is NULL). */ + u32 last_ptr_id[TC_HTB_NUMPRIO]; } inner; } un; rb_node_t node[TC_HTB_NUMPRIO]; /* node for self or feed tree */ @@ -218,6 +223,7 @@ rb_root_t row[TC_HTB_MAXDEPTH][TC_HTB_NUMPRIO]; int row_mask[TC_HTB_MAXDEPTH]; rb_node_t *ptr[TC_HTB_MAXDEPTH][TC_HTB_NUMPRIO]; + u32 last_ptr_id[TC_HTB_MAXDEPTH][TC_HTB_NUMPRIO]; /* self wait list - roots of wait PQs per row */ rb_root_t wait_pq[TC_HTB_MAXDEPTH]; @@ -576,8 +582,13 @@ int prio = ffz(~m); m &= ~(1 << prio); - if (p->un.inner.ptr[prio] == cl->node+prio) - htb_next_rb_node(p->un.inner.ptr + prio); + if (p->un.inner.ptr[prio] == cl->node+prio) { + /* we are removing child which is pointed to from + parent feed - forget the pointer but remember + classid */ + p->un.inner.last_ptr_id[prio] = cl->classid; + p->un.inner.ptr[prio] = NULL; + } htb_safe_rb_erase(cl->node + prio,p->un.inner.feed + prio); @@ -908,25 +919,56 @@ return HZ/10; } +/* Returns class->node+prio from id-tree where classe's id is >= id. NULL + is no such one exists. */ +static rb_node_t * +htb_id_find_next_upper(int prio,rb_node_t *n,u32 id) +{ + rb_node_t *r = NULL; + while (n) { + struct htb_class *cl = rb_entry(n,struct htb_class,node[prio]); + if (id == cl->classid) return n; + + if (id > cl->classid) { + n = n->rb_right; + } else { + r = n; + n = n->rb_left; + } + } + return r; +} + /** * htb_lookup_leaf - returns next leaf class in DRR order * * Find leaf where current feed pointers points to. */ static struct htb_class * -htb_lookup_leaf(rb_root_t *tree,int prio,rb_node_t **pptr) +htb_lookup_leaf(HTB_ARGQ rb_root_t *tree,int prio,rb_node_t **pptr,u32 *pid) { int i; struct { rb_node_t *root; rb_node_t **pptr; + u32 *pid; } stk[TC_HTB_MAXDEPTH],*sp = stk; BUG_TRAP(tree->rb_node); sp->root = tree->rb_node; sp->pptr = pptr; + sp->pid = pid; for (i = 0; i < 65535; i++) { + HTB_DBG(4,2,"htb_lleaf ptr=%p pid=%X\n",*sp->pptr,*sp->pid); + + if (!*sp->pptr && *sp->pid) { + /* ptr was invalidated but id is valid - try to recover + the original or next ptr */ + *sp->pptr = htb_id_find_next_upper(prio,sp->root,*sp->pid); + } + *sp->pid = 0; /* ptr is valid now so that remove this hint as it + can become out of date quickly */ if (!*sp->pptr) { /* we are at right end; rewind & go up */ *sp->pptr = sp->root; while ((*sp->pptr)->rb_left) @@ -944,6 +986,7 @@ return cl; (++sp)->root = cl->un.inner.feed[prio].rb_node; sp->pptr = cl->un.inner.ptr+prio; + sp->pid = cl->un.inner.last_ptr_id+prio; } } BUG_TRAP(0); @@ -958,7 +1001,8 @@ struct sk_buff *skb = NULL; struct htb_class *cl,*start; /* look initial class up in the row */ - start = cl = htb_lookup_leaf (q->row[level]+prio,prio,q->ptr[level]+prio); + start = cl = htb_lookup_leaf (HTB_PASSQ q->row[level]+prio,prio, + q->ptr[level]+prio,q->last_ptr_id[level]+prio); do { next: @@ -979,8 +1023,8 @@ if ((q->row_mask[level] & (1 << prio)) == 0) return NULL; - next = htb_lookup_leaf (q->row[level]+prio, - prio,q->ptr[level]+prio); + next = htb_lookup_leaf (HTB_PASSQ q->row[level]+prio, + prio,q->ptr[level]+prio,q->last_ptr_id[level]+prio); if (cl == start) /* fix start if we just deleted it */ start = next; cl = next; @@ -995,7 +1039,8 @@ } q->nwc_hit++; htb_next_rb_node((level?cl->parent->un.inner.ptr:q->ptr[0])+prio); - cl = htb_lookup_leaf (q->row[level]+prio,prio,q->ptr[level]+prio); + cl = htb_lookup_leaf (HTB_PASSQ q->row[level]+prio,prio,q->ptr[level]+prio, + q->last_ptr_id[level]+prio); } while (cl != start); if (likely(skb != NULL)) { diff -Nru a/net/sctp/associola.c b/net/sctp/associola.c --- a/net/sctp/associola.c 2004-08-14 12:02:30 -07:00 +++ b/net/sctp/associola.c 2004-08-14 12:02:30 -07:00 @@ -1108,6 +1108,7 @@ case SCTP_STATE_ESTABLISHED: case SCTP_STATE_SHUTDOWN_PENDING: case SCTP_STATE_SHUTDOWN_RECEIVED: + case SCTP_STATE_SHUTDOWN_SENT: if ((asoc->rwnd > asoc->a_rwnd) && ((asoc->rwnd - asoc->a_rwnd) >= min_t(__u32, (asoc->base.sk->sk_rcvbuf >> 1), asoc->pmtu))) diff -Nru a/net/sctp/inqueue.c b/net/sctp/inqueue.c --- a/net/sctp/inqueue.c 2004-08-14 12:02:30 -07:00 +++ b/net/sctp/inqueue.c 2004-08-14 12:02:30 -07:00 @@ -81,7 +81,7 @@ struct sctp_chunk *chunk; /* Empty the queue. */ - while ((chunk = (struct sctp_chunk *) skb_dequeue(&queue->in))) + while ((chunk = (struct sctp_chunk *) skb_dequeue(&queue->in)) != NULL) sctp_chunk_free(chunk); /* If there is a packet which is currently being worked on, diff -Nru a/net/sctp/output.c b/net/sctp/output.c --- a/net/sctp/output.c 2004-08-14 12:02:30 -07:00 +++ b/net/sctp/output.c 2004-08-14 12:02:30 -07:00 @@ -133,7 +133,7 @@ SCTP_DEBUG_PRINTK("%s: packet:%p\n", __FUNCTION__, packet); - while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks))) + while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks)) != NULL) sctp_chunk_free(chunk); if (packet->malloced) @@ -370,7 +370,7 @@ * [This whole comment explains WORD_ROUND() below.] */ SCTP_DEBUG_PRINTK("***sctp_transmit_packet***\n"); - while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks))) { + while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks)) != NULL) { if (sctp_chunk_is_data(chunk)) { if (!chunk->has_tsn) { @@ -511,7 +511,7 @@ * will get resent or dropped later. */ - while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks))) { + while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks)) != NULL) { if (!sctp_chunk_is_data(chunk)) sctp_chunk_free(chunk); } diff -Nru a/net/sctp/outqueue.c b/net/sctp/outqueue.c --- a/net/sctp/outqueue.c 2004-08-14 12:02:30 -07:00 +++ b/net/sctp/outqueue.c 2004-08-14 12:02:30 -07:00 @@ -245,7 +245,7 @@ /* Throw away unacknowledged chunks. */ list_for_each(pos, &q->asoc->peer.transport_addr_list) { transport = list_entry(pos, struct sctp_transport, transports); - while ((lchunk = sctp_list_dequeue(&transport->transmitted))) { + while ((lchunk = sctp_list_dequeue(&transport->transmitted)) != NULL) { chunk = list_entry(lchunk, struct sctp_chunk, transmitted_list); /* Mark as part of a failed message. */ @@ -282,7 +282,7 @@ } /* Throw away any leftover data chunks. */ - while ((chunk = sctp_outq_dequeue_data(q))) { + while ((chunk = sctp_outq_dequeue_data(q)) != NULL) { /* Mark as send failure. */ sctp_chunk_fail(chunk, q->error); @@ -292,7 +292,7 @@ q->error = 0; /* Throw away any leftover control chunks. */ - while ((chunk = (struct sctp_chunk *) skb_dequeue(&q->control))) + while ((chunk = (struct sctp_chunk *) skb_dequeue(&q->control)) != NULL) sctp_chunk_free(chunk); } @@ -525,10 +525,10 @@ int rtx_timeout, int *start_timer) { struct list_head *lqueue; - struct list_head *lchunk; + struct list_head *lchunk, *lchunk1; struct sctp_transport *transport = pkt->transport; sctp_xmit_t status; - struct sctp_chunk *chunk; + struct sctp_chunk *chunk, *chunk1; struct sctp_association *asoc; int error = 0; @@ -615,6 +615,12 @@ * the transmitted list. */ list_add_tail(lchunk, &transport->transmitted); + + /* Mark the chunk as ineligible for fast retransmit + * after it is retransmitted. + */ + chunk->fast_retransmit = 0; + *start_timer = 1; q->empty = 0; @@ -622,6 +628,18 @@ lchunk = sctp_list_dequeue(lqueue); break; }; + + /* If we are here due to a retransmit timeout or a fast + * retransmit and if there are any chunks left in the retransmit + * queue that could not fit in the PMTU sized packet, they need * to be marked as ineligible for a subsequent fast retransmit. + */ + if (rtx_timeout && !lchunk) { + list_for_each(lchunk1, lqueue) { + chunk1 = list_entry(lchunk1, struct sctp_chunk, + transmitted_list); + chunk1->fast_retransmit = 0; + } + } } return error; @@ -681,7 +699,7 @@ */ queue = &q->control; - while ((chunk = (struct sctp_chunk *)skb_dequeue(queue))) { + while ((chunk = (struct sctp_chunk *)skb_dequeue(queue)) != NULL) { /* Pick the right transport to use. */ new_transport = chunk->transport; @@ -812,7 +830,7 @@ start_timer = 0; queue = &q->out; - while ((chunk = sctp_outq_dequeue_data(q))) { + while ((chunk = sctp_outq_dequeue_data(q)) != NULL) { /* RFC 2960 6.5 Every DATA chunk MUST carry a valid * stream identifier. */ @@ -866,7 +884,7 @@ SCTP_DEBUG_PRINTK("TX TSN 0x%x skb->head " "%p skb->users %d.\n", ntohl(chunk->subh.data_hdr->tsn), - chunk->skb ?chunk->skb->head : 0, + chunk->skb ?chunk->skb->head : NULL, chunk->skb ? atomic_read(&chunk->skb->users) : -1); diff -Nru a/net/sctp/protocol.c b/net/sctp/protocol.c --- a/net/sctp/protocol.c 2004-08-14 12:02:30 -07:00 +++ b/net/sctp/protocol.c 2004-08-14 12:02:30 -07:00 @@ -97,7 +97,7 @@ { if (!proc_net_sctp) { struct proc_dir_entry *ent; - ent = proc_mkdir("net/sctp", 0); + ent = proc_mkdir("net/sctp", NULL); if (ent) { ent->owner = THIS_MODULE; proc_net_sctp = ent; diff -Nru a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c --- a/net/sctp/sm_sideeffect.c 2004-08-14 12:02:30 -07:00 +++ b/net/sctp/sm_sideeffect.c 2004-08-14 12:02:30 -07:00 @@ -529,6 +529,23 @@ } } +/* Helper function to stop any pending T3-RTX timers */ +static void sctp_cmd_t3_rtx_timers_stop(sctp_cmd_seq_t *cmds, + struct sctp_association *asoc) +{ + struct sctp_transport *t; + struct list_head *pos; + + list_for_each(pos, &asoc->peer.transport_addr_list) { + t = list_entry(pos, struct sctp_transport, transports); + if (timer_pending(&t->T3_rtx_timer) && + del_timer(&t->T3_rtx_timer)) { + sctp_transport_put(t); + } + } +} + + /* Helper function to update the heartbeat timer. */ static void sctp_cmd_hb_timer_update(sctp_cmd_seq_t *cmds, struct sctp_association *asoc, @@ -749,6 +766,26 @@ return; } +/* Helper function to remove the association non-primary peer + * transports. + */ +static void sctp_cmd_del_non_primary(struct sctp_association *asoc) +{ + struct sctp_transport *t; + struct list_head *pos; + struct list_head *temp; + + list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { + t = list_entry(pos, struct sctp_transport, transports); + if (!sctp_cmp_addr_exact(&t->ipaddr, + &asoc->peer.primary_addr)) { + sctp_assoc_del_peer(asoc, &t->ipaddr); + } + } + + return; +} + /* These three macros allow us to pull the debugging code out of the * main flow of sctp_do_sm() to keep attention focused on the real * functionality there. @@ -1048,6 +1085,27 @@ if (cmd->obj.ptr) sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(cmd->obj.ptr)); + + /* FIXME - Eventually come up with a cleaner way to + * enabling COOKIE-ECHO + DATA bundling during + * multihoming stale cookie scenarios, the following + * command plays with asoc->peer.retran_path to + * avoid the problem of sending the COOKIE-ECHO and + * DATA in different paths, which could result + * in the association being ABORTed if the DATA chunk + * is processed first by the server. Checking the + * init error counter simply causes this command + * to be executed only during failed attempts of + * association establishment. + */ + if ((asoc->peer.retran_path != + asoc->peer.primary_path) && + (asoc->counters[SCTP_COUNTER_INIT_ERROR] > 0)) { + sctp_add_cmd_sf(commands, + SCTP_CMD_FORCE_PRIM_RETRAN, + SCTP_NULL()); + } + break; case SCTP_CMD_GEN_SHUTDOWN: @@ -1281,6 +1339,19 @@ break; case SCTP_CMD_CLEAR_INIT_TAG: asoc->peer.i.init_tag = 0; + break; + case SCTP_CMD_DEL_NON_PRIMARY: + sctp_cmd_del_non_primary(asoc); + break; + case SCTP_CMD_T3_RTX_TIMERS_STOP: + sctp_cmd_t3_rtx_timers_stop(commands, asoc); + break; + case SCTP_CMD_FORCE_PRIM_RETRAN: + t = asoc->peer.retran_path; + asoc->peer.retran_path = asoc->peer.primary_path; + error = sctp_outq_uncork(&asoc->outqueue); + local_cork = 0; + asoc->peer.retran_path = t; break; default: printk(KERN_WARNING "Impossible command: %u, %p\n", diff -Nru a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c --- a/net/sctp/sm_statefuns.c 2004-08-14 12:02:30 -07:00 +++ b/net/sctp/sm_statefuns.c 2004-08-14 12:02:30 -07:00 @@ -472,8 +472,6 @@ */ sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT)); - sctp_add_cmd_sf(commands, SCTP_CMD_COUNTER_RESET, - SCTP_COUNTER(SCTP_COUNTER_INIT_ERROR)); sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START, SCTP_TO(SCTP_EVENT_TIMEOUT_T1_COOKIE)); sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, @@ -674,6 +672,15 @@ if (!sctp_vtag_verify(chunk, asoc)) return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + /* Reset init error count upon receipt of COOKIE-ACK, + * to avoid problems with the managemement of this + * counter in stale cookie situations when a transition back + * from the COOKIE-ECHOED state to the COOKIE-WAIT + * state is performed. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_COUNTER_RESET, + SCTP_COUNTER(SCTP_COUNTER_INIT_ERROR)); + /* RFC 2960 5.1 Normal Establishment of an Association * * E) Upon reception of the COOKIE ACK, endpoint "A" will move @@ -995,7 +1002,7 @@ /* Search through all current addresses and make sure * we aren't adding any new ones. */ - new_addr = 0; + new_addr = NULL; found = 0; list_for_each(pos, &new_asoc->peer.transport_addr_list) { @@ -1872,8 +1879,6 @@ time_t stale; sctp_cookie_preserve_param_t bht; sctp_errhdr_t *err; - struct list_head *pos; - struct sctp_transport *t; struct sctp_chunk *reply; struct sctp_bind_addr *bp; int attempts; @@ -1920,20 +1925,27 @@ /* Clear peer's init_tag cached in assoc as we are sending a new INIT */ sctp_add_cmd_sf(commands, SCTP_CMD_CLEAR_INIT_TAG, SCTP_NULL()); + /* Stop pending T3-rtx and heartbeat timers */ + sctp_add_cmd_sf(commands, SCTP_CMD_T3_RTX_TIMERS_STOP, SCTP_NULL()); + sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_STOP, SCTP_NULL()); + + /* Delete non-primary peer ip addresses since we are transitioning + * back to the COOKIE-WAIT state + */ + sctp_add_cmd_sf(commands, SCTP_CMD_DEL_NON_PRIMARY, SCTP_NULL()); + + /* If we've sent any data bundled with COOKIE-ECHO we will need to + * resend + */ + sctp_add_cmd_sf(commands, SCTP_CMD_RETRAN, + SCTP_TRANSPORT(asoc->peer.primary_path)); + /* Cast away the const modifier, as we want to just * rerun it through as a sideffect. */ sctp_add_cmd_sf(commands, SCTP_CMD_COUNTER_INC, SCTP_COUNTER(SCTP_COUNTER_INIT_ERROR)); - /* If we've sent any data bundled with COOKIE-ECHO we need to - * resend. - */ - list_for_each(pos, &asoc->peer.transport_addr_list) { - t = list_entry(pos, struct sctp_transport, transports); - sctp_add_cmd_sf(commands, SCTP_CMD_RETRAN, SCTP_TRANSPORT(t)); - } - sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, SCTP_TO(SCTP_EVENT_TIMEOUT_T1_COOKIE)); sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, @@ -2321,12 +2333,7 @@ sctp_cmd_seq_t *commands) { struct sctp_chunk *chunk = arg; - sctp_datahdr_t *data_hdr; - struct sctp_chunk *err; - size_t datalen; - sctp_verb_t deliver; - int tmp; - __u32 tsn; + int error; if (!sctp_vtag_verify(chunk, asoc)) { sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG, @@ -2334,158 +2341,22 @@ return sctp_sf_pdiscard(ep, asoc, type, arg, commands); } - data_hdr = chunk->subh.data_hdr = (sctp_datahdr_t *)chunk->skb->data; - skb_pull(chunk->skb, sizeof(sctp_datahdr_t)); - - tsn = ntohl(data_hdr->tsn); - SCTP_DEBUG_PRINTK("eat_data: TSN 0x%x.\n", tsn); - - /* ASSERT: Now skb->data is really the user data. */ - - /* Process ECN based congestion. - * - * Since the chunk structure is reused for all chunks within - * a packet, we use ecn_ce_done to track if we've already - * done CE processing for this packet. - * - * We need to do ECN processing even if we plan to discard the - * chunk later. - */ - - if (!chunk->ecn_ce_done) { - struct sctp_af *af; - chunk->ecn_ce_done = 1; - - af = sctp_get_af_specific( - ipver2af(chunk->skb->nh.iph->version)); - - if (af && af->is_ce(chunk->skb) && asoc->peer.ecn_capable) { - /* Do real work as sideffect. */ - sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CE, - SCTP_U32(tsn)); - } - } - - tmp = sctp_tsnmap_check(&asoc->peer.tsn_map, tsn); - if (tmp < 0) { - /* The TSN is too high--silently discard the chunk and - * count on it getting retransmitted later. - */ + error = sctp_eat_data(asoc, chunk, commands ); + switch (error) { + case SCTP_IERROR_NO_ERROR: + break; + case SCTP_IERROR_HIGH_TSN: + case SCTP_IERROR_BAD_STREAM: goto discard_noforce; - } else if (tmp > 0) { - /* This is a duplicate. Record it. */ - sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_DUP, SCTP_U32(tsn)); + case SCTP_IERROR_DUP_TSN: + case SCTP_IERROR_IGNORE_TSN: goto discard_force; + case SCTP_IERROR_NO_DATA: + goto consume; + default: + BUG(); } - /* This is a new TSN. */ - - /* Discard if there is no room in the receive window. - * Actually, allow a little bit of overflow (up to a MTU). - */ - datalen = ntohs(chunk->chunk_hdr->length); - datalen -= sizeof(sctp_data_chunk_t); - - deliver = SCTP_CMD_CHUNK_ULP; - - /* Think about partial delivery. */ - if ((datalen >= asoc->rwnd) && (!asoc->ulpq.pd_mode)) { - - /* Even if we don't accept this chunk there is - * memory pressure. - */ - sctp_add_cmd_sf(commands, SCTP_CMD_PART_DELIVER, SCTP_NULL()); - } - - /* Spill over rwnd a little bit. Note: While allowed, this spill over - * seems a bit troublesome in that frag_point varies based on - * PMTU. In cases, such as loopback, this might be a rather - * large spill over. - */ - if (!asoc->rwnd || asoc->rwnd_over || - (datalen > asoc->rwnd + asoc->frag_point)) { - - /* If this is the next TSN, consider reneging to make - * room. Note: Playing nice with a confused sender. A - * malicious sender can still eat up all our buffer - * space and in the future we may want to detect and - * do more drastic reneging. - */ - if (sctp_tsnmap_has_gap(&asoc->peer.tsn_map) && - (sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + 1) == tsn) { - SCTP_DEBUG_PRINTK("Reneging for tsn:%u\n", tsn); - deliver = SCTP_CMD_RENEGE; - } else { - SCTP_DEBUG_PRINTK("Discard tsn: %u len: %Zd, " - "rwnd: %d\n", tsn, datalen, - asoc->rwnd); - goto discard_force; - } - } - - /* - * Section 3.3.10.9 No User Data (9) - * - * Cause of error - * --------------- - * No User Data: This error cause is returned to the originator of a - * DATA chunk if a received DATA chunk has no user data. - */ - if (unlikely(0 == datalen)) { - err = sctp_make_abort_no_data(asoc, chunk, tsn); - if (err) { - sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, - SCTP_CHUNK(err)); - } - /* We are going to ABORT, so we might as well stop - * processing the rest of the chunks in the packet. - */ - sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL()); - sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, - SCTP_U32(SCTP_ERROR_NO_DATA)); - SCTP_INC_STATS(SctpAborteds); - SCTP_DEC_STATS(SctpCurrEstab); - return SCTP_DISPOSITION_CONSUME; - } - - /* If definately accepting the DATA chunk, record its TSN, otherwise - * wait for renege processing. - */ - if (SCTP_CMD_CHUNK_ULP == deliver) - sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn)); - - /* Note: Some chunks may get overcounted (if we drop) or overcounted - * if we renege and the chunk arrives again. - */ - if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) - SCTP_INC_STATS(SctpInUnorderChunks); - else - SCTP_INC_STATS(SctpInOrderChunks); - - /* RFC 2960 6.5 Stream Identifier and Stream Sequence Number - * - * If an endpoint receive a DATA chunk with an invalid stream - * identifier, it shall acknowledge the reception of the DATA chunk - * following the normal procedure, immediately send an ERROR chunk - * with cause set to "Invalid Stream Identifier" (See Section 3.3.10) - * and discard the DATA chunk. - */ - if (ntohs(data_hdr->stream) >= asoc->c.sinit_max_instreams) { - err = sctp_make_op_error(asoc, chunk, SCTP_ERROR_INV_STRM, - &data_hdr->stream, - sizeof(data_hdr->stream)); - if (err) - sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, - SCTP_CHUNK(err)); - goto discard_noforce; - } - - /* Send the data up to the user. Note: Schedule the - * SCTP_CMD_CHUNK_ULP cmd before the SCTP_CMD_GEN_SACK, as the SACK - * chunk needs the updated rwnd. - */ - sctp_add_cmd_sf(commands, deliver, SCTP_CHUNK(chunk)); - if (asoc->autoclose) { sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART, SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE)); @@ -2551,6 +2422,9 @@ SCTP_TO(SCTP_EVENT_TIMEOUT_SACK)); } return SCTP_DISPOSITION_DISCARD; +consume: + return SCTP_DISPOSITION_CONSUME; + } /* @@ -2576,11 +2450,7 @@ sctp_cmd_seq_t *commands) { struct sctp_chunk *chunk = arg; - sctp_datahdr_t *data_hdr; - struct sctp_chunk *err; - size_t datalen; - int tmp; - __u32 tsn; + int error; if (!sctp_vtag_verify(chunk, asoc)) { sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG, @@ -2588,110 +2458,23 @@ return sctp_sf_pdiscard(ep, asoc, type, arg, commands); } - data_hdr = chunk->subh.data_hdr = (sctp_datahdr_t *) chunk->skb->data; - skb_pull(chunk->skb, sizeof(sctp_datahdr_t)); - - tsn = ntohl(data_hdr->tsn); - - SCTP_DEBUG_PRINTK("eat_data: TSN 0x%x.\n", tsn); - - /* ASSERT: Now skb->data is really the user data. */ - - /* Process ECN based congestion. - * - * Since the chunk structure is reused for all chunks within - * a packet, we use ecn_ce_done to track if we've already - * done CE processing for this packet. - * - * We need to do ECN processing even if we plan to discard the - * chunk later. - */ - if (!chunk->ecn_ce_done) { - struct sctp_af *af; - chunk->ecn_ce_done = 1; - - af = sctp_get_af_specific( - ipver2af(chunk->skb->nh.iph->version)); - - if (af && af->is_ce(chunk->skb) && asoc->peer.ecn_capable) { - /* Do real work as sideffect. */ - sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CE, - SCTP_U32(tsn)); - } - } - - tmp = sctp_tsnmap_check(&asoc->peer.tsn_map, tsn); - if (tmp < 0) { - /* The TSN is too high--silently discard the chunk and - * count on it getting retransmitted later. - */ - goto gen_shutdown; - } else if (tmp > 0) { - /* This is a duplicate. Record it. */ - sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_DUP, SCTP_U32(tsn)); - goto gen_shutdown; - } - - /* This is a new TSN. */ - datalen = ntohs(chunk->chunk_hdr->length); - datalen -= sizeof(sctp_data_chunk_t); - - /* - * Section 3.3.10.9 No User Data (9) - * - * Cause of error - * --------------- - * No User Data: This error cause is returned to the originator of a - * DATA chunk if a received DATA chunk has no user data. - */ - if (unlikely(0 == datalen)) { - err = sctp_make_abort_no_data(asoc, chunk, tsn); - if (err) { - sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, - SCTP_CHUNK(err)); - } - /* We are going to ABORT, so we might as well stop - * processing the rest of the chunks in the packet. - */ - sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL()); - sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, - SCTP_U32(SCTP_ERROR_NO_DATA)); - SCTP_INC_STATS(SctpAborteds); - SCTP_DEC_STATS(SctpCurrEstab); - return SCTP_DISPOSITION_CONSUME; - } - - /* We are accepting this DATA chunk. */ - - /* Record the fact that we have received this TSN. */ - sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn)); - - if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) - SCTP_INC_STATS(SctpInUnorderChunks); - else - SCTP_INC_STATS(SctpInOrderChunks); - - /* RFC 2960 6.5 Stream Identifier and Stream Sequence Number - * - * If an endpoint receive a DATA chunk with an invalid stream - * identifier, it shall acknowledge the reception of the DATA chunk - * following the normal procedure, immediately send an ERROR chunk - * with cause set to "Invalid Stream Identifier" (See Section 3.3.10) - * and discard the DATA chunk. - */ - if (ntohs(data_hdr->stream) >= asoc->c.sinit_max_instreams) { - err = sctp_make_op_error(asoc, chunk, SCTP_ERROR_INV_STRM, - &data_hdr->stream, - sizeof(data_hdr->stream)); - if (err) { - sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, - SCTP_CHUNK(err)); - } + error = sctp_eat_data(asoc, chunk, commands ); + switch (error) { + case SCTP_IERROR_NO_ERROR: + case SCTP_IERROR_HIGH_TSN: + case SCTP_IERROR_DUP_TSN: + case SCTP_IERROR_IGNORE_TSN: + case SCTP_IERROR_BAD_STREAM: + break; + case SCTP_IERROR_NO_DATA: + goto consume; + default: + BUG(); } /* Go a head and force a SACK, since we are shutting down. */ -gen_shutdown: + /* Implementor's Guide. * * While in SHUTDOWN-SENT state, the SHUTDOWN sender MUST immediately @@ -2707,6 +2490,8 @@ sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART, SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN)); } + +consume: return SCTP_DISPOSITION_CONSUME; } @@ -4709,7 +4494,7 @@ num_blocks = ntohs(sack->num_gap_ack_blocks); num_dup_tsns = ntohs(sack->num_dup_tsns); len = sizeof(struct sctp_sackhdr); - len = (num_blocks + num_dup_tsns) * sizeof(__u32); + len += (num_blocks + num_dup_tsns) * sizeof(__u32); if (len > chunk->skb->len) return NULL; @@ -4847,4 +4632,172 @@ } else sctp_chunk_free (err_chunk); } +} + + +/* Process a data chunk */ +int sctp_eat_data(const struct sctp_association *asoc, + struct sctp_chunk *chunk, + sctp_cmd_seq_t *commands) +{ + sctp_datahdr_t *data_hdr; + struct sctp_chunk *err; + size_t datalen; + sctp_verb_t deliver; + int tmp; + __u32 tsn; + + data_hdr = chunk->subh.data_hdr = (sctp_datahdr_t *)chunk->skb->data; + skb_pull(chunk->skb, sizeof(sctp_datahdr_t)); + + tsn = ntohl(data_hdr->tsn); + SCTP_DEBUG_PRINTK("eat_data: TSN 0x%x.\n", tsn); + + /* ASSERT: Now skb->data is really the user data. */ + + /* Process ECN based congestion. + * + * Since the chunk structure is reused for all chunks within + * a packet, we use ecn_ce_done to track if we've already + * done CE processing for this packet. + * + * We need to do ECN processing even if we plan to discard the + * chunk later. + */ + + if (!chunk->ecn_ce_done) { + struct sctp_af *af; + chunk->ecn_ce_done = 1; + + af = sctp_get_af_specific( + ipver2af(chunk->skb->nh.iph->version)); + + if (af && af->is_ce(chunk->skb) && asoc->peer.ecn_capable) { + /* Do real work as sideffect. */ + sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CE, + SCTP_U32(tsn)); + } + } + + tmp = sctp_tsnmap_check(&asoc->peer.tsn_map, tsn); + if (tmp < 0) { + /* The TSN is too high--silently discard the chunk and + * count on it getting retransmitted later. + */ + return SCTP_IERROR_HIGH_TSN; + } else if (tmp > 0) { + /* This is a duplicate. Record it. */ + sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_DUP, SCTP_U32(tsn)); + return SCTP_IERROR_DUP_TSN; + } + + /* This is a new TSN. */ + + /* Discard if there is no room in the receive window. + * Actually, allow a little bit of overflow (up to a MTU). + */ + datalen = ntohs(chunk->chunk_hdr->length); + datalen -= sizeof(sctp_data_chunk_t); + + deliver = SCTP_CMD_CHUNK_ULP; + + /* Think about partial delivery. */ + if ((datalen >= asoc->rwnd) && (!asoc->ulpq.pd_mode)) { + + /* Even if we don't accept this chunk there is + * memory pressure. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_PART_DELIVER, SCTP_NULL()); + } + + /* Spill over rwnd a little bit. Note: While allowed, this spill over + * seems a bit troublesome in that frag_point varies based on + * PMTU. In cases, such as loopback, this might be a rather + * large spill over. + */ + if (!asoc->rwnd || asoc->rwnd_over || + (datalen > asoc->rwnd + asoc->frag_point)) { + + /* If this is the next TSN, consider reneging to make + * room. Note: Playing nice with a confused sender. A + * malicious sender can still eat up all our buffer + * space and in the future we may want to detect and + * do more drastic reneging. + */ + if (sctp_tsnmap_has_gap(&asoc->peer.tsn_map) && + (sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + 1) == tsn) { + SCTP_DEBUG_PRINTK("Reneging for tsn:%u\n", tsn); + deliver = SCTP_CMD_RENEGE; + } else { + SCTP_DEBUG_PRINTK("Discard tsn: %u len: %Zd, " + "rwnd: %d\n", tsn, datalen, + asoc->rwnd); + return SCTP_IERROR_IGNORE_TSN; + } + } + + /* + * Section 3.3.10.9 No User Data (9) + * + * Cause of error + * --------------- + * No User Data: This error cause is returned to the originator of a + * DATA chunk if a received DATA chunk has no user data. + */ + if (unlikely(0 == datalen)) { + err = sctp_make_abort_no_data(asoc, chunk, tsn); + if (err) { + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, + SCTP_CHUNK(err)); + } + /* We are going to ABORT, so we might as well stop + * processing the rest of the chunks in the packet. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL()); + sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, + SCTP_U32(SCTP_ERROR_NO_DATA)); + SCTP_INC_STATS(SctpAborteds); + SCTP_DEC_STATS(SctpCurrEstab); + return SCTP_IERROR_NO_DATA; + } + + /* If definately accepting the DATA chunk, record its TSN, otherwise + * wait for renege processing. + */ + if (SCTP_CMD_CHUNK_ULP == deliver) + sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn)); + + /* Note: Some chunks may get overcounted (if we drop) or overcounted + * if we renege and the chunk arrives again. + */ + if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) + SCTP_INC_STATS(SctpInUnorderChunks); + else + SCTP_INC_STATS(SctpInOrderChunks); + + /* RFC 2960 6.5 Stream Identifier and Stream Sequence Number + * + * If an endpoint receive a DATA chunk with an invalid stream + * identifier, it shall acknowledge the reception of the DATA chunk + * following the normal procedure, immediately send an ERROR chunk + * with cause set to "Invalid Stream Identifier" (See Section 3.3.10) + * and discard the DATA chunk. + */ + if (ntohs(data_hdr->stream) >= asoc->c.sinit_max_instreams) { + err = sctp_make_op_error(asoc, chunk, SCTP_ERROR_INV_STRM, + &data_hdr->stream, + sizeof(data_hdr->stream)); + if (err) + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, + SCTP_CHUNK(err)); + return SCTP_IERROR_BAD_STREAM; + } + + /* Send the data up to the user. Note: Schedule the + * SCTP_CMD_CHUNK_ULP cmd before the SCTP_CMD_GEN_SACK, as the SACK + * chunk needs the updated rwnd. + */ + sctp_add_cmd_sf(commands, deliver, SCTP_CHUNK(chunk)); + + return SCTP_IERROR_NO_ERROR; } diff -Nru a/net/sctp/socket.c b/net/sctp/socket.c --- a/net/sctp/socket.c 2004-08-14 12:02:30 -07:00 +++ b/net/sctp/socket.c 2004-08-14 12:02:30 -07:00 @@ -86,8 +86,6 @@ /* Forward declarations for internal helper functions. */ static int sctp_writeable(struct sock *sk); -static inline int sctp_wspace(struct sctp_association *asoc); -static inline void sctp_set_owner_w(struct sctp_chunk *chunk); static void sctp_wfree(struct sk_buff *skb); static int sctp_wait_for_sndbuf(struct sctp_association *, long *timeo_p, size_t msg_len); @@ -95,7 +93,8 @@ static int sctp_wait_for_connect(struct sctp_association *, long *timeo_p); static int sctp_wait_for_accept(struct sock *sk, long timeo); static void sctp_wait_for_close(struct sock *sk, long timeo); -static inline int sctp_verify_addr(struct sock *, union sctp_addr *, int); +static struct sctp_af *sctp_sockaddr_af(struct sctp_opt *opt, + union sctp_addr *addr, int len); static int sctp_bindx_add(struct sock *, struct sockaddr *, int); static int sctp_bindx_rem(struct sock *, struct sockaddr *, int); static int sctp_send_asconf_add_ip(struct sock *, struct sockaddr *, int); @@ -111,6 +110,64 @@ extern kmem_cache_t *sctp_bucket_cachep; extern int sctp_assoc_valid(struct sock *sk, struct sctp_association *asoc); +/* Get the sndbuf space available at the time on the association. */ +static inline int sctp_wspace(struct sctp_association *asoc) +{ + struct sock *sk = asoc->base.sk; + int amt = 0; + + amt = sk->sk_sndbuf - asoc->sndbuf_used; + if (amt < 0) + amt = 0; + return amt; +} + +/* Increment the used sndbuf space count of the corresponding association by + * the size of the outgoing data chunk. + * Also, set the skb destructor for sndbuf accounting later. + * + * Since it is always 1-1 between chunk and skb, and also a new skb is always + * allocated for chunk bundling in sctp_packet_transmit(), we can use the + * destructor in the data chunk skb for the purpose of the sndbuf space + * tracking. + */ +static inline void sctp_set_owner_w(struct sctp_chunk *chunk) +{ + struct sctp_association *asoc = chunk->asoc; + struct sock *sk = asoc->base.sk; + + /* The sndbuf space is tracked per association. */ + sctp_association_hold(asoc); + + chunk->skb->destructor = sctp_wfree; + /* Save the chunk pointer in skb for sctp_wfree to use later. */ + *((struct sctp_chunk **)(chunk->skb->cb)) = chunk; + + asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk); + sk->sk_wmem_queued += SCTP_DATA_SNDSIZE(chunk); +} + +/* Verify that this is a valid address. */ +static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr, + int len) +{ + struct sctp_af *af; + + /* Verify basic sockaddr. */ + af = sctp_sockaddr_af(sctp_sk(sk), addr, len); + if (!af) + return -EINVAL; + + /* Is this a valid SCTP address? */ + if (!af->addr_valid(addr, sctp_sk(sk))) + return -EINVAL; + + if (!sctp_sk(sk)->pf->send_verify(sctp_sk(sk), (addr))) + return -EINVAL; + + return 0; +} + /* Look up the association by its id. If this is not a UDP-style * socket, the ID field is always ignored. */ @@ -999,7 +1056,7 @@ struct sctp_sndrcvinfo *sinfo; struct sctp_initmsg *sinit; sctp_assoc_t associd = NULL; - sctp_cmsgs_t cmsgs = { 0 }; + sctp_cmsgs_t cmsgs = { NULL }; int err; sctp_scope_t scope; long timeo; @@ -1630,6 +1687,32 @@ if (copy_from_user(¶ms, optval, optlen)) return -EFAULT; + /* + * API 7. Socket Options (setting the default value for the endpoint) + * All options that support specific settings on an association by + * filling in either an association id variable or a sockaddr_storage + * SHOULD also support setting of the same value for the entire endpoint + * (i.e. future associations). To accomplish this the following logic is + * used when setting one of these options: + + * c) If neither the sockaddr_storage or association identification is + * set i.e. the sockaddr_storage is set to all 0's (INADDR_ANY) and + * the association identification is 0, the settings are a default + * and to be applied to the endpoint (all future associations). + */ + + /* update default value for endpoint (all future associations) */ + if (!params.spp_assoc_id && + sctp_is_any(( union sctp_addr *)¶ms.spp_address)) { + if (params.spp_hbinterval) + sctp_sk(sk)->paddrparam.spp_hbinterval = + params.spp_hbinterval; + if (sctp_max_retrans_path) + sctp_sk(sk)->paddrparam.spp_pathmaxrxt = + params.spp_pathmaxrxt; + return 0; + } + trans = sctp_addr_id2transport(sk, ¶ms.spp_address, params.spp_assoc_id); if (!trans) @@ -2795,6 +2878,17 @@ if (copy_from_user(¶ms, optval, *optlen)) return -EFAULT; + /* If no association id is specified retrieve the default value + * for the endpoint that will be used for all future associations + */ + if (!params.spp_assoc_id && + sctp_is_any(( union sctp_addr *)¶ms.spp_address)) { + params.spp_hbinterval = sctp_sk(sk)->paddrparam.spp_hbinterval; + params.spp_pathmaxrxt = sctp_sk(sk)->paddrparam.spp_pathmaxrxt; + + goto done; + } + trans = sctp_addr_id2transport(sk, ¶ms.spp_address, params.spp_assoc_id); if (!trans) @@ -2814,6 +2908,7 @@ */ params.spp_pathmaxrxt = trans->error_threshold; +done: if (copy_to_user(optval, ¶ms, len)) return -EFAULT; @@ -4136,64 +4231,6 @@ no_packet: *err = error; return NULL; -} - -/* Verify that this is a valid address. */ -static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr, - int len) -{ - struct sctp_af *af; - - /* Verify basic sockaddr. */ - af = sctp_sockaddr_af(sctp_sk(sk), addr, len); - if (!af) - return -EINVAL; - - /* Is this a valid SCTP address? */ - if (!af->addr_valid(addr, sctp_sk(sk))) - return -EINVAL; - - if (!sctp_sk(sk)->pf->send_verify(sctp_sk(sk), (addr))) - return -EINVAL; - - return 0; -} - -/* Get the sndbuf space available at the time on the association. */ -static inline int sctp_wspace(struct sctp_association *asoc) -{ - struct sock *sk = asoc->base.sk; - int amt = 0; - - amt = sk->sk_sndbuf - asoc->sndbuf_used; - if (amt < 0) - amt = 0; - return amt; -} - -/* Increment the used sndbuf space count of the corresponding association by - * the size of the outgoing data chunk. - * Also, set the skb destructor for sndbuf accounting later. - * - * Since it is always 1-1 between chunk and skb, and also a new skb is always - * allocated for chunk bundling in sctp_packet_transmit(), we can use the - * destructor in the data chunk skb for the purpose of the sndbuf space - * tracking. - */ -static inline void sctp_set_owner_w(struct sctp_chunk *chunk) -{ - struct sctp_association *asoc = chunk->asoc; - struct sock *sk = asoc->base.sk; - - /* The sndbuf space is tracked per association. */ - sctp_association_hold(asoc); - - chunk->skb->destructor = sctp_wfree; - /* Save the chunk pointer in skb for sctp_wfree to use later. */ - *((struct sctp_chunk **)(chunk->skb->cb)) = chunk; - - asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk); - sk->sk_wmem_queued += SCTP_DATA_SNDSIZE(chunk); } /* If sndbuf has changed, wake up per association sndbuf waiters. */ diff -Nru a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c --- a/net/sctp/ulpevent.c 2004-08-14 12:02:30 -07:00 +++ b/net/sctp/ulpevent.c 2004-08-14 12:02:30 -07:00 @@ -48,13 +48,23 @@ #include #include -static inline void sctp_ulpevent_set_owner(struct sctp_ulpevent *event, - const struct sctp_association *asoc); -static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event); static void sctp_ulpevent_receive_data(struct sctp_ulpevent *event, struct sctp_association *asoc); static void sctp_ulpevent_release_data(struct sctp_ulpevent *event); +/* Stub skb destructor. */ +static void sctp_stub_rfree(struct sk_buff *skb) +{ +/* WARNING: This function is just a warning not to use the + * skb destructor. If the skb is shared, we may get the destructor + * callback on some processor that does not own the sock_lock. This + * was occuring with PACKET socket applications that were monitoring + * our skbs. We can't take the sock_lock, because we can't risk + * recursing if we do really own the sock lock. Instead, do all + * of our rwnd manipulation while we own the sock_lock outright. + */ +} + /* Create a new sctp_ulpevent. */ struct sctp_ulpevent *sctp_ulpevent_new(int size, int msg_flags, int gfp) { @@ -87,6 +97,30 @@ return MSG_NOTIFICATION == (event->msg_flags & MSG_NOTIFICATION); } +/* Hold the association in case the msg_name needs read out of + * the association. + */ +static inline void sctp_ulpevent_set_owner(struct sctp_ulpevent *event, + const struct sctp_association *asoc) +{ + struct sk_buff *skb; + + /* Cast away the const, as we are just wanting to + * bump the reference count. + */ + sctp_association_hold((struct sctp_association *)asoc); + skb = sctp_event2skb(event); + skb->sk = asoc->base.sk; + event->asoc = (struct sctp_association *)asoc; + skb->destructor = sctp_stub_rfree; +} + +/* A simple destructor to give up the reference to the association. */ +static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event) +{ + sctp_association_put(event->asoc); +} + /* Create and initialize an SCTP_ASSOC_CHANGE event. * * 5.3.1.1 SCTP_ASSOC_CHANGE @@ -787,43 +821,6 @@ put_cmsg(msghdr, IPPROTO_SCTP, SCTP_SNDRCV, sizeof(struct sctp_sndrcvinfo), (void *)&sinfo); -} - -/* Stub skb destructor. */ -static void sctp_stub_rfree(struct sk_buff *skb) -{ -/* WARNING: This function is just a warning not to use the - * skb destructor. If the skb is shared, we may get the destructor - * callback on some processor that does not own the sock_lock. This - * was occuring with PACKET socket applications that were monitoring - * our skbs. We can't take the sock_lock, because we can't risk - * recursing if we do really own the sock lock. Instead, do all - * of our rwnd manipulation while we own the sock_lock outright. - */ -} - -/* Hold the association in case the msg_name needs read out of - * the association. - */ -static inline void sctp_ulpevent_set_owner(struct sctp_ulpevent *event, - const struct sctp_association *asoc) -{ - struct sk_buff *skb; - - /* Cast away the const, as we are just wanting to - * bump the reference count. - */ - sctp_association_hold((struct sctp_association *)asoc); - skb = sctp_event2skb(event); - skb->sk = asoc->base.sk; - event->asoc = (struct sctp_association *)asoc; - skb->destructor = sctp_stub_rfree; -} - -/* A simple destructor to give up the reference to the association. */ -static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event) -{ - sctp_association_put(event->asoc); } /* Do accounting for bytes received and hold a reference to the association diff -Nru a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c --- a/net/sctp/ulpqueue.c 2004-08-14 12:02:30 -07:00 +++ b/net/sctp/ulpqueue.c 2004-08-14 12:02:30 -07:00 @@ -49,10 +49,10 @@ #include /* Forward declarations for internal helpers. */ -static inline struct sctp_ulpevent * sctp_ulpq_reasm(struct sctp_ulpq *ulpq, - struct sctp_ulpevent *); -static inline struct sctp_ulpevent *sctp_ulpq_order(struct sctp_ulpq *, - struct sctp_ulpevent *); +static struct sctp_ulpevent * sctp_ulpq_reasm(struct sctp_ulpq *ulpq, + struct sctp_ulpevent *); +static struct sctp_ulpevent * sctp_ulpq_order(struct sctp_ulpq *, + struct sctp_ulpevent *); /* 1st Level Abstractions */ @@ -97,12 +97,12 @@ struct sk_buff *skb; struct sctp_ulpevent *event; - while ((skb = __skb_dequeue(&ulpq->lobby))) { + while ((skb = __skb_dequeue(&ulpq->lobby)) != NULL) { event = sctp_skb2event(skb); sctp_ulpevent_free(event); } - while ((skb = __skb_dequeue(&ulpq->reasm))) { + while ((skb = __skb_dequeue(&ulpq->reasm)) != NULL) { event = sctp_skb2event(skb); sctp_ulpevent_free(event); } @@ -466,8 +466,8 @@ /* Helper function to reassemble chunks. Hold chunks on the reasm queue that * need reassembling. */ -static inline struct sctp_ulpevent *sctp_ulpq_reasm(struct sctp_ulpq *ulpq, - struct sctp_ulpevent *event) +static struct sctp_ulpevent *sctp_ulpq_reasm(struct sctp_ulpq *ulpq, + struct sctp_ulpevent *event) { struct sctp_ulpevent *retval = NULL; @@ -645,8 +645,8 @@ } -static inline struct sctp_ulpevent *sctp_ulpq_order(struct sctp_ulpq *ulpq, - struct sctp_ulpevent *event) +static struct sctp_ulpevent *sctp_ulpq_order(struct sctp_ulpq *ulpq, + struct sctp_ulpevent *event) { __u16 sid, ssn; struct sctp_stream *in; @@ -756,7 +756,7 @@ tsnmap = &ulpq->asoc->peer.tsn_map; - while ((skb = __skb_dequeue_tail(&ulpq->lobby))) { + while ((skb = __skb_dequeue_tail(&ulpq->lobby)) != NULL) { freed += skb_headlen(skb); event = sctp_skb2event(skb); tsn = event->tsn; @@ -782,7 +782,7 @@ tsnmap = &ulpq->asoc->peer.tsn_map; /* Walk backwards through the list, reneges the newest tsns. */ - while ((skb = __skb_dequeue_tail(&ulpq->reasm))) { + while ((skb = __skb_dequeue_tail(&ulpq->reasm)) != NULL) { freed += skb_headlen(skb); event = sctp_skb2event(skb); tsn = event->tsn;